1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
package types
import (
"crypto"
"crypto/ed25519"
"crypto/sha256"
"fmt"
"strings"
)
const (
HashSize = sha256.Size
SignatureSize = ed25519.SignatureSize
VerificationKeySize = ed25519.PublicKeySize
EndpointAddLeaf = Endpoint("add-leaf")
EndpointAddCosignature = Endpoint("add-cosignature")
EndpointGetTreeHeadLatest = Endpoint("get-tree-head-latest")
EndpointGetTreeHeadToSign = Endpoint("get-tree-head-to-sign")
EndpointGetTreeHeadCosigned = Endpoint("get-tree-head-cosigned")
EndpointGetProofByHash = Endpoint("get-proof-by-hash")
EndpointGetConsistencyProof = Endpoint("get-consistency-proof")
EndpointGetLeaves = Endpoint("get-leaves")
)
// Endpoint is a named HTTP API endpoint
type Endpoint string
// Path joins a number of components to form a full endpoint path. For example,
// EndpointAddLeaf.Path("example.com", "st/v0") -> example.com/st/v0/add-leaf.
func (e Endpoint) Path(components ...string) string {
return strings.Join(append(components, string(e)), "/")
}
// Leaf is the log's Merkle tree leaf.
type Leaf struct {
Message
SigIdent
}
// Message is composed of a shard hint and a checksum. The submitter selects
// these values to fit the log's shard interval and the opaque data in question.
type Message struct {
ShardHint uint64
Checksum *[HashSize]byte
}
// SigIdent is composed of a signature-signer pair. The signature is computed
// over the Trunnel-serialized leaf message. KeyHash identifies the signer.
type SigIdent struct {
Signature *[SignatureSize]byte
KeyHash *[HashSize]byte
}
// SignedTreeHead is composed of a tree head and a list of signature-signer
// pairs. Each signature is computed over the Trunnel-serialized tree head.
type SignedTreeHead struct {
TreeHead
SigIdent []*SigIdent
}
// TreeHead is the log's tree head.
type TreeHead struct {
Timestamp uint64
TreeSize uint64
RootHash *[HashSize]byte
}
// ConsistencyProof is a consistency proof that proves the log's append-only
// property.
type ConsistencyProof struct {
NewSize uint64
OldSize uint64
Path []*[HashSize]byte
}
// InclusionProof is an inclusion proof that proves a leaf is included in the
// log.
type InclusionProof struct {
TreeSize uint64
LeafIndex uint64
Path []*[HashSize]byte
}
// LeafList is a list of leaves
type LeafList []*Leaf
// ConsistencyProofRequest is a get-consistency-proof request
type ConsistencyProofRequest struct {
NewSize uint64
OldSize uint64
}
// InclusionProofRequest is a get-proof-by-hash request
type InclusionProofRequest struct {
LeafHash *[HashSize]byte
TreeSize uint64
}
// LeavesRequest is a get-leaves request
type LeavesRequest struct {
StartSize uint64
EndSize uint64
}
// LeafRequest is an add-leaf request
type LeafRequest struct {
Message
Signature *[SignatureSize]byte
VerificationKey *[VerificationKeySize]byte
DomainHint string
}
// CosignatureRequest is an add-cosignature request
type CosignatureRequest struct {
SigIdent
}
// Sign signs the tree head using the log's signature scheme
func (th *TreeHead) Sign(signer crypto.Signer) (*SignedTreeHead, error) {
sig, err := signer.Sign(nil, th.Marshal(), crypto.Hash(0))
if err != nil {
return nil, fmt.Errorf("Sign: %v", err)
}
sigident := SigIdent{
KeyHash: Hash(signer.Public().(ed25519.PublicKey)[:]),
Signature: &[SignatureSize]byte{},
}
copy(sigident.Signature[:], sig)
return &SignedTreeHead{
TreeHead: *th,
SigIdent: []*SigIdent{
&sigident,
},
}, nil
}
// Verify verifies the tree head signature using the log's signature scheme
func (th *TreeHead) Verify(vk *[VerificationKeySize]byte, sig *[SignatureSize]byte) error {
if !ed25519.Verify(ed25519.PublicKey(vk[:]), th.Marshal(), sig[:]) {
return fmt.Errorf("invalid tree head signature")
}
return nil
}
// Verify checks if a leaf is included in the log
func (p *InclusionProof) Verify(leaf *Leaf, th *TreeHead) error { // TODO
return nil
}
// Verify checks if two tree heads are consistent
func (p *ConsistencyProof) Verify(oldTH, newTH *TreeHead) error { // TODO
return nil
}
|