aboutsummaryrefslogtreecommitdiff
path: root/pkg/types
diff options
context:
space:
mode:
authorRasmus Dahlberg <rasmus.dahlberg@kau.se>2021-09-13 19:53:17 +0200
committerRasmus Dahlberg <rasmus.dahlberg@kau.se>2021-09-13 19:53:17 +0200
commit26b786d9857db21fdf110eaf9cb6d1d6e4e68ef9 (patch)
tree92606f47a91ebcc9e3cb4258af7a9472fc6f2e07 /pkg/types
parentf34351da0731a11316e2266d2aadd62554a5b867 (diff)
updated (co)signed tree head structuresv0.2.0
- Added key_hash in tree head, see motivation in api.md - Added separate types for (co)signed tree heads - Refactored tree head HTTP APIs to be current, see api.md
Diffstat (limited to 'pkg/types')
-rw-r--r--pkg/types/ascii.go66
-rw-r--r--pkg/types/ascii_test.go34
-rw-r--r--pkg/types/trunnel.go7
-rw-r--r--pkg/types/trunnel_test.go4
-rw-r--r--pkg/types/types.go37
5 files changed, 50 insertions, 98 deletions
diff --git a/pkg/types/ascii.go b/pkg/types/ascii.go
index f0a96ad..72abfcb 100644
--- a/pkg/types/ascii.go
+++ b/pkg/types/ascii.go
@@ -18,7 +18,7 @@ const (
// NumField* is the number of unique keys in an incoming ASCII message
NumFieldLeaf = 4
- NumFieldSignedTreeHead = 5
+ NumFieldSignedTreeHead = 4
NumFieldConsistencyProof = 3
NumFieldInclusionProof = 3
NumFieldLeavesRequest = 2
@@ -28,11 +28,11 @@ const (
NumFieldCosignatureRequest = 2
// New leaf keys
- ShardHint = "shard_hint"
- Checksum = "checksum"
- Signature = "signature"
- VerificationKey = "verification_key"
- DomainHint = "domain_hint"
+ ShardHint = "shard_hint"
+ Checksum = "checksum"
+ Signature = "signature"
+ VerificationKey = "verification_key"
+ DomainHint = "domain_hint"
// Inclusion proof keys
LeafHash = "leaf_hash"
@@ -53,8 +53,9 @@ const (
TreeSize = "tree_size"
RootHash = "root_hash"
- // Signature and signer-identity keys
- KeyHash = "key_hash"
+ // Witness signature-identity keys
+ KeyHash = "key_hash"
+ Cosignature = "cosignature"
)
// MessageASCI is a wrapper that manages ASCII key-value pairs
@@ -219,19 +220,29 @@ func (sth *SignedTreeHead) MarshalASCII(w io.Writer) error {
if err := writeASCII(w, RootHash, hex.EncodeToString(sth.RootHash[:])); err != nil {
return fmt.Errorf("writeASCII: %v", err)
}
- for _, sigident := range sth.SigIdent {
- if err := sigident.MarshalASCII(w); err != nil {
- return fmt.Errorf("MarshalASCII: %v", err)
+ if err := writeASCII(w, Signature, hex.EncodeToString(sth.Signature[:])); err != nil {
+ return fmt.Errorf("writeASCII: %v", err)
+ }
+ return nil
+}
+
+func (cth *CosignedTreeHead) MarshalASCII(w io.Writer) error {
+ if err := cth.SignedTreeHead.MarshalASCII(w); err != nil {
+ return fmt.Errorf("writeASCII: %v", err)
+ }
+ for _, si := range cth.SigIdent {
+ if err := si.MarshalASCII(w); err != nil {
+ return fmt.Errorf("writeASCII: %v", err)
}
}
return nil
}
func (si *SigIdent) MarshalASCII(w io.Writer) error {
- if err := writeASCII(w, Signature, hex.EncodeToString(si.Signature[:])); err != nil {
+ if err := writeASCII(w, KeyHash, hex.EncodeToString(si.KeyHash[:])); err != nil {
return fmt.Errorf("writeASCII: %v", err)
}
- if err := writeASCII(w, KeyHash, hex.EncodeToString(si.KeyHash[:])); err != nil {
+ if err := writeASCII(w, Cosignature, hex.EncodeToString(si.Signature[:])); err != nil {
return fmt.Errorf("writeASCII: %v", err)
}
return nil
@@ -280,7 +291,6 @@ func (sth *SignedTreeHead) UnmarshalASCII(r io.Reader) error {
return fmt.Errorf("NewMessageASCII: %v", err)
}
- // TreeHead
if sth.Timestamp, err = msg.GetUint64(Timestamp); err != nil {
return fmt.Errorf("GetUint64(Timestamp): %v", err)
}
@@ -290,30 +300,8 @@ func (sth *SignedTreeHead) UnmarshalASCII(r io.Reader) error {
if sth.RootHash, err = msg.GetHash(RootHash); err != nil {
return fmt.Errorf("GetHash(RootHash): %v", err)
}
-
- // SigIdent
- signatures := msg.GetStrings(Signature)
- if len(signatures) == 0 {
- return fmt.Errorf("no signer")
- }
- keyHashes := msg.GetStrings(KeyHash)
- if len(signatures) != len(keyHashes) {
- return fmt.Errorf("mismatched signature-signer count")
- }
- sth.SigIdent = make([]*SigIdent, 0, len(signatures))
- for i, n := 0, len(signatures); i < n; i++ {
- var signature [SignatureSize]byte
- if err := decodeHex(signatures[i], signature[:]); err != nil {
- return fmt.Errorf("decodeHex: %v", err)
- }
- var hash [HashSize]byte
- if err := decodeHex(keyHashes[i], hash[:]); err != nil {
- return fmt.Errorf("decodeHex: %v", err)
- }
- sth.SigIdent = append(sth.SigIdent, &SigIdent{
- Signature: &signature,
- KeyHash: &hash,
- })
+ if sth.Signature, err = msg.GetSignature(Signature); err != nil {
+ return fmt.Errorf("GetHash(RootHash): %v", err)
}
return nil
}
@@ -401,7 +389,7 @@ func (req *CosignatureRequest) UnmarshalASCII(r io.Reader) error {
return fmt.Errorf("NewMessageASCII: %v", err)
}
- if req.Signature, err = msg.GetSignature(Signature); err != nil {
+ if req.Signature, err = msg.GetSignature(Cosignature); err != nil {
return fmt.Errorf("GetSignature: %v", err)
}
if req.KeyHash, err = msg.GetHash(KeyHash); err != nil {
diff --git a/pkg/types/ascii_test.go b/pkg/types/ascii_test.go
index c3f9e98..fc3f486 100644
--- a/pkg/types/ascii_test.go
+++ b/pkg/types/ascii_test.go
@@ -134,26 +134,14 @@ func TestSignedTreeHeadMarshalASCII(t *testing.T) {
TreeSize: 456,
RootHash: testBuffer32,
},
- SigIdent: []*SigIdent{
- &SigIdent{
- Signature: testBuffer64,
- KeyHash: testBuffer32,
- },
- &SigIdent{
- Signature: testBuffer64,
- KeyHash: testBuffer32,
- },
- },
+ Signature: testBuffer64,
}
wantBuf := bytes.NewBufferString(fmt.Sprintf(
- "%s%s%d%s"+"%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s",
+ "%s%s%d%s"+"%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s",
Timestamp, Delim, 123, EOL,
TreeSize, Delim, 456, EOL,
RootHash, Delim, testBuffer32[:], EOL,
Signature, Delim, testBuffer64[:], EOL,
- KeyHash, Delim, testBuffer32[:], EOL,
- Signature, Delim, testBuffer64[:], EOL,
- KeyHash, Delim, testBuffer32[:], EOL,
))
buf := bytes.NewBuffer(nil)
if err := sth.MarshalASCII(buf); err != nil {
@@ -236,14 +224,11 @@ func TestSignedTreeHeadUnmarshalASCII(t *testing.T) {
{
description: "valid",
buf: bytes.NewBufferString(fmt.Sprintf(
- "%s%s%d%s"+"%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s",
+ "%s%s%d%s"+"%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s",
Timestamp, Delim, 123, EOL,
TreeSize, Delim, 456, EOL,
RootHash, Delim, testBuffer32[:], EOL,
Signature, Delim, testBuffer64[:], EOL,
- KeyHash, Delim, testBuffer32[:], EOL,
- Signature, Delim, testBuffer64[:], EOL,
- KeyHash, Delim, testBuffer32[:], EOL,
)),
wantSth: &SignedTreeHead{
TreeHead: TreeHead{
@@ -251,16 +236,7 @@ func TestSignedTreeHeadUnmarshalASCII(t *testing.T) {
TreeSize: 456,
RootHash: testBuffer32,
},
- SigIdent: []*SigIdent{
- &SigIdent{
- Signature: testBuffer64,
- KeyHash: testBuffer32,
- },
- &SigIdent{
- Signature: testBuffer64,
- KeyHash: testBuffer32,
- },
- },
+ Signature: testBuffer64,
},
},
} {
@@ -436,7 +412,7 @@ func TestCosignatureRequestUnmarshalASCII(t *testing.T) {
description: "valid",
buf: bytes.NewBufferString(fmt.Sprintf(
"%s%s%x%s"+"%s%s%x%s",
- Signature, Delim, testBuffer64[:], EOL,
+ Cosignature, Delim, testBuffer64[:], EOL,
KeyHash, Delim, testBuffer32[:], EOL,
)),
wantReq: &CosignatureRequest{
diff --git a/pkg/types/trunnel.go b/pkg/types/trunnel.go
index 268f6f7..5350c5b 100644
--- a/pkg/types/trunnel.go
+++ b/pkg/types/trunnel.go
@@ -10,6 +10,8 @@ const (
MessageSize = 8 + HashSize
// LeafSize is the number of bytes in a Trunnel-encoded leaf
LeafSize = MessageSize + SignatureSize + HashSize
+ // TreeHeadSize is the number of bytes in a Trunnel-encoded tree head
+ TreeHeadSize = 8 + 8 + HashSize + HashSize
)
// Marshal returns a Trunnel-encoded message
@@ -30,10 +32,11 @@ func (l *Leaf) Marshal() []byte {
// Marshal returns a Trunnel-encoded tree head
func (th *TreeHead) Marshal() []byte {
- buf := make([]byte, 8+8+HashSize)
+ buf := make([]byte, TreeHeadSize)
binary.BigEndian.PutUint64(buf[0:8], th.Timestamp)
binary.BigEndian.PutUint64(buf[8:16], th.TreeSize)
- copy(buf[16:], th.RootHash[:])
+ copy(buf[16:16+HashSize], th.RootHash[:])
+ copy(buf[16+HashSize:], th.KeyHash[:])
return buf
}
diff --git a/pkg/types/trunnel_test.go b/pkg/types/trunnel_test.go
index 297578c..a3ae1ba 100644
--- a/pkg/types/trunnel_test.go
+++ b/pkg/types/trunnel_test.go
@@ -48,16 +48,18 @@ func TestMarshalLeaf(t *testing.T) {
}
func TestMarshalTreeHead(t *testing.T) {
- description := "valid: timestamp 16909060, tree size 72623859790382856, root hash 0x00,0x01,..."
+ description := "valid: timestamp 16909060, tree size 72623859790382856, root hash & key hash 0x00,0x01,..."
th := &TreeHead{
Timestamp: 16909060,
TreeSize: 72623859790382856,
RootHash: testBuffer32,
+ KeyHash: testBuffer32,
}
want := bytes.Join([][]byte{
[]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04},
[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},
testBuffer32[:],
+ testBuffer32[:],
}, nil)
if got := th.Marshal(); !bytes.Equal(got, want) {
t.Errorf("got tree head\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, description)
diff --git a/pkg/types/types.go b/pkg/types/types.go
index 96e2b18..bc58c98 100644
--- a/pkg/types/types.go
+++ b/pkg/types/types.go
@@ -32,78 +32,67 @@ 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
+ Signature *[SignatureSize]byte
+}
+
+type CosignedTreeHead struct {
+ SignedTreeHead
SigIdent []*SigIdent
}
-// TreeHead is the log's tree head.
type TreeHead struct {
Timestamp uint64
TreeSize uint64
RootHash *[HashSize]byte
+ KeyHash *[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
@@ -111,7 +100,6 @@ type LeafRequest struct {
DomainHint string
}
-// CosignatureRequest is an add-cosignature request
type CosignatureRequest struct {
SigIdent
}
@@ -123,17 +111,12 @@ func (th *TreeHead) Sign(signer crypto.Signer) (*SignedTreeHead, error) {
return nil, fmt.Errorf("Sign: %v", err)
}
- sigident := SigIdent{
- KeyHash: Hash(signer.Public().(ed25519.PublicKey)[:]),
+ sth := &SignedTreeHead{
+ TreeHead: *th,
Signature: &[SignatureSize]byte{},
}
- copy(sigident.Signature[:], sig)
- return &SignedTreeHead{
- TreeHead: *th,
- SigIdent: []*SigIdent{
- &sigident,
- },
- }, nil
+ copy(sth.Signature[:], sig)
+ return sth, nil
}
// Verify verifies the tree head signature using the log's signature scheme