diff options
Diffstat (limited to 'pkg/types')
-rw-r--r-- | pkg/types/ascii.go | 399 | ||||
-rw-r--r-- | pkg/types/ascii_test.go | 438 | ||||
-rw-r--r-- | pkg/types/trunnel.go | 63 | ||||
-rw-r--r-- | pkg/types/trunnel_test.go | 116 | ||||
-rw-r--r-- | pkg/types/types.go | 138 | ||||
-rw-r--r-- | pkg/types/types_test.go | 58 | ||||
-rw-r--r-- | pkg/types/util.go | 21 |
7 files changed, 0 insertions, 1233 deletions
diff --git a/pkg/types/ascii.go b/pkg/types/ascii.go deleted file mode 100644 index 72abfcb..0000000 --- a/pkg/types/ascii.go +++ /dev/null @@ -1,399 +0,0 @@ -package types - -import ( - "bytes" - "encoding/hex" - "fmt" - "io" - "io/ioutil" - "strconv" -) - -const ( - // Delim is a key-value separator - Delim = "=" - - // EOL is a line sepator - EOL = "\n" - - // NumField* is the number of unique keys in an incoming ASCII message - NumFieldLeaf = 4 - NumFieldSignedTreeHead = 4 - NumFieldConsistencyProof = 3 - NumFieldInclusionProof = 3 - NumFieldLeavesRequest = 2 - NumFieldInclusionProofRequest = 2 - NumFieldConsistencyProofRequest = 2 - NumFieldLeafRequest = 5 - NumFieldCosignatureRequest = 2 - - // New leaf keys - ShardHint = "shard_hint" - Checksum = "checksum" - Signature = "signature" - VerificationKey = "verification_key" - DomainHint = "domain_hint" - - // Inclusion proof keys - LeafHash = "leaf_hash" - LeafIndex = "leaf_index" - InclusionPath = "inclusion_path" - - // Consistency proof keys - NewSize = "new_size" - OldSize = "old_size" - ConsistencyPath = "consistency_path" - - // Range of leaves keys - StartSize = "start_size" - EndSize = "end_size" - - // Tree head keys - Timestamp = "timestamp" - TreeSize = "tree_size" - RootHash = "root_hash" - - // Witness signature-identity keys - KeyHash = "key_hash" - Cosignature = "cosignature" -) - -// MessageASCI is a wrapper that manages ASCII key-value pairs -type MessageASCII struct { - m map[string][]string -} - -// NewMessageASCII unpacks an incoming ASCII message -func NewMessageASCII(r io.Reader, numFieldExpected int) (*MessageASCII, error) { - buf, err := ioutil.ReadAll(r) - if err != nil { - return nil, fmt.Errorf("ReadAll: %v", err) - } - lines := bytes.Split(buf, []byte(EOL)) - if len(lines) <= 1 { - return nil, fmt.Errorf("Not enough lines: empty") - } - lines = lines[:len(lines)-1] // valid message => split gives empty last line - - msg := MessageASCII{make(map[string][]string)} - for _, line := range lines { - split := bytes.Index(line, []byte(Delim)) - if split == -1 { - return nil, fmt.Errorf("invalid line: %v", string(line)) - } - - key := string(line[:split]) - value := string(line[split+len(Delim):]) - values, ok := msg.m[key] - if !ok { - values = nil - msg.m[key] = values - } - msg.m[key] = append(values, value) - } - - if msg.NumField() != numFieldExpected { - return nil, fmt.Errorf("Unexpected number of keys: %v", msg.NumField()) - } - return &msg, nil -} - -// NumField returns the number of unique keys -func (msg *MessageASCII) NumField() int { - return len(msg.m) -} - -// GetStrings returns a list of strings -func (msg *MessageASCII) GetStrings(key string) []string { - strs, ok := msg.m[key] - if !ok { - return nil - } - return strs -} - -// GetString unpacks a string -func (msg *MessageASCII) GetString(key string) (string, error) { - strs := msg.GetStrings(key) - if len(strs) != 1 { - return "", fmt.Errorf("expected one string: %v", strs) - } - return strs[0], nil -} - -// GetUint64 unpacks an uint64 -func (msg *MessageASCII) GetUint64(key string) (uint64, error) { - str, err := msg.GetString(key) - if err != nil { - return 0, fmt.Errorf("GetString: %v", err) - } - num, err := strconv.ParseUint(str, 10, 64) - if err != nil { - return 0, fmt.Errorf("ParseUint: %v", err) - } - return num, nil -} - -// GetHash unpacks a hash -func (msg *MessageASCII) GetHash(key string) (*[HashSize]byte, error) { - str, err := msg.GetString(key) - if err != nil { - return nil, fmt.Errorf("GetString: %v", err) - } - - var hash [HashSize]byte - if err := decodeHex(str, hash[:]); err != nil { - return nil, fmt.Errorf("decodeHex: %v", err) - } - return &hash, nil -} - -// GetSignature unpacks a signature -func (msg *MessageASCII) GetSignature(key string) (*[SignatureSize]byte, error) { - str, err := msg.GetString(key) - if err != nil { - return nil, fmt.Errorf("GetString: %v", err) - } - - var signature [SignatureSize]byte - if err := decodeHex(str, signature[:]); err != nil { - return nil, fmt.Errorf("decodeHex: %v", err) - } - return &signature, nil -} - -// GetVerificationKey unpacks a verification key -func (msg *MessageASCII) GetVerificationKey(key string) (*[VerificationKeySize]byte, error) { - str, err := msg.GetString(key) - if err != nil { - return nil, fmt.Errorf("GetString: %v", err) - } - - var vk [VerificationKeySize]byte - if err := decodeHex(str, vk[:]); err != nil { - return nil, fmt.Errorf("decodeHex: %v", err) - } - return &vk, nil -} - -// decodeHex decodes a hex-encoded string into an already-sized byte slice -func decodeHex(str string, out []byte) error { - buf, err := hex.DecodeString(str) - if err != nil { - return fmt.Errorf("DecodeString: %v", err) - } - if len(buf) != len(out) { - return fmt.Errorf("invalid length: %v", len(buf)) - } - copy(out, buf) - return nil -} - -/* - * - * MarshalASCII wrappers for types that the log server outputs - * - */ -func (l *Leaf) MarshalASCII(w io.Writer) error { - if err := writeASCII(w, ShardHint, strconv.FormatUint(l.ShardHint, 10)); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - if err := writeASCII(w, Checksum, hex.EncodeToString(l.Checksum[:])); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - if err := writeASCII(w, Signature, hex.EncodeToString(l.Signature[:])); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - if err := writeASCII(w, KeyHash, hex.EncodeToString(l.KeyHash[:])); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - return nil -} - -func (sth *SignedTreeHead) MarshalASCII(w io.Writer) error { - if err := writeASCII(w, Timestamp, strconv.FormatUint(sth.Timestamp, 10)); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - if err := writeASCII(w, TreeSize, strconv.FormatUint(sth.TreeSize, 10)); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - if err := writeASCII(w, RootHash, hex.EncodeToString(sth.RootHash[:])); err != nil { - return fmt.Errorf("writeASCII: %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, KeyHash, hex.EncodeToString(si.KeyHash[:])); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - if err := writeASCII(w, Cosignature, hex.EncodeToString(si.Signature[:])); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - return nil -} - -func (p *ConsistencyProof) MarshalASCII(w io.Writer) error { - for _, hash := range p.Path { - if err := writeASCII(w, ConsistencyPath, hex.EncodeToString(hash[:])); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - } - return nil -} - -func (p *InclusionProof) MarshalASCII(w io.Writer) error { - if err := writeASCII(w, LeafIndex, strconv.FormatUint(p.LeafIndex, 10)); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - for _, hash := range p.Path { - if err := writeASCII(w, InclusionPath, hex.EncodeToString(hash[:])); err != nil { - return fmt.Errorf("writeASCII: %v", err) - } - } - return nil -} - -func writeASCII(w io.Writer, key, value string) error { - if _, err := fmt.Fprintf(w, "%s%s%s%s", key, Delim, value, EOL); err != nil { - return fmt.Errorf("Fprintf: %v", err) - } - return nil -} - -/* - * - * Unmarshal ASCII wrappers that the log server and/or log clients receive. - * - */ -func (ll *LeafList) UnmarshalASCII(r io.Reader) error { - return nil -} - -func (sth *SignedTreeHead) UnmarshalASCII(r io.Reader) error { - msg, err := NewMessageASCII(r, NumFieldSignedTreeHead) - if err != nil { - return fmt.Errorf("NewMessageASCII: %v", err) - } - - if sth.Timestamp, err = msg.GetUint64(Timestamp); err != nil { - return fmt.Errorf("GetUint64(Timestamp): %v", err) - } - if sth.TreeSize, err = msg.GetUint64(TreeSize); err != nil { - return fmt.Errorf("GetUint64(TreeSize): %v", err) - } - if sth.RootHash, err = msg.GetHash(RootHash); err != nil { - return fmt.Errorf("GetHash(RootHash): %v", err) - } - if sth.Signature, err = msg.GetSignature(Signature); err != nil { - return fmt.Errorf("GetHash(RootHash): %v", err) - } - return nil -} - -func (p *InclusionProof) UnmarshalASCII(r io.Reader) error { - return nil -} - -func (p *ConsistencyProof) UnmarshalASCII(r io.Reader) error { - return nil -} - -func (req *InclusionProofRequest) UnmarshalASCII(r io.Reader) error { - msg, err := NewMessageASCII(r, NumFieldInclusionProofRequest) - if err != nil { - return fmt.Errorf("NewMessageASCII: %v", err) - } - - if req.LeafHash, err = msg.GetHash(LeafHash); err != nil { - return fmt.Errorf("GetHash(LeafHash): %v", err) - } - if req.TreeSize, err = msg.GetUint64(TreeSize); err != nil { - return fmt.Errorf("GetUint64(TreeSize): %v", err) - } - return nil -} - -func (req *ConsistencyProofRequest) UnmarshalASCII(r io.Reader) error { - msg, err := NewMessageASCII(r, NumFieldConsistencyProofRequest) - if err != nil { - return fmt.Errorf("NewMessageASCII: %v", err) - } - - if req.NewSize, err = msg.GetUint64(NewSize); err != nil { - return fmt.Errorf("GetUint64(NewSize): %v", err) - } - if req.OldSize, err = msg.GetUint64(OldSize); err != nil { - return fmt.Errorf("GetUint64(OldSize): %v", err) - } - return nil -} - -func (req *LeavesRequest) UnmarshalASCII(r io.Reader) error { - msg, err := NewMessageASCII(r, NumFieldLeavesRequest) - if err != nil { - return fmt.Errorf("NewMessageASCII: %v", err) - } - - if req.StartSize, err = msg.GetUint64(StartSize); err != nil { - return fmt.Errorf("GetUint64(StartSize): %v", err) - } - if req.EndSize, err = msg.GetUint64(EndSize); err != nil { - return fmt.Errorf("GetUint64(EndSize): %v", err) - } - return nil -} - -func (req *LeafRequest) UnmarshalASCII(r io.Reader) error { - msg, err := NewMessageASCII(r, NumFieldLeafRequest) - if err != nil { - return fmt.Errorf("NewMessageASCII: %v", err) - } - - if req.ShardHint, err = msg.GetUint64(ShardHint); err != nil { - return fmt.Errorf("GetUint64(ShardHint): %v", err) - } - if req.Checksum, err = msg.GetHash(Checksum); err != nil { - return fmt.Errorf("GetHash(Checksum): %v", err) - } - if req.Signature, err = msg.GetSignature(Signature); err != nil { - return fmt.Errorf("GetSignature: %v", err) - } - if req.VerificationKey, err = msg.GetVerificationKey(VerificationKey); err != nil { - return fmt.Errorf("GetVerificationKey: %v", err) - } - if req.DomainHint, err = msg.GetString(DomainHint); err != nil { - return fmt.Errorf("GetString(DomainHint): %v", err) - } - return nil -} - -func (req *CosignatureRequest) UnmarshalASCII(r io.Reader) error { - msg, err := NewMessageASCII(r, NumFieldCosignatureRequest) - if err != nil { - return fmt.Errorf("NewMessageASCII: %v", err) - } - - if req.Signature, err = msg.GetSignature(Cosignature); err != nil { - return fmt.Errorf("GetSignature: %v", err) - } - if req.KeyHash, err = msg.GetHash(KeyHash); err != nil { - return fmt.Errorf("GetHash(KeyHash): %v", err) - } - return nil -} diff --git a/pkg/types/ascii_test.go b/pkg/types/ascii_test.go deleted file mode 100644 index fc3f486..0000000 --- a/pkg/types/ascii_test.go +++ /dev/null @@ -1,438 +0,0 @@ -package types - -import ( - "bytes" - "fmt" - "io" - "reflect" - "testing" -) - -/* - * - * MessageASCII methods and helpers - * - */ -func TestNewMessageASCII(t *testing.T) { - for _, table := range []struct { - description string - input io.Reader - wantErr bool - wantMap map[string][]string - }{ - { - description: "invalid: not enough lines", - input: bytes.NewBufferString(""), - wantErr: true, - }, - { - description: "invalid: lines must end with new line", - input: bytes.NewBufferString("k1=v1\nk2=v2"), - wantErr: true, - }, - { - description: "invalid: lines must not be empty", - input: bytes.NewBufferString("k1=v1\n\nk2=v2\n"), - wantErr: true, - }, - { - description: "invalid: wrong number of fields", - input: bytes.NewBufferString("k1=v1\n"), - wantErr: true, - }, - { - description: "valid", - input: bytes.NewBufferString("k1=v1\nk2=v2\nk2=v3=4\n"), - wantMap: map[string][]string{ - "k1": []string{"v1"}, - "k2": []string{"v2", "v3=4"}, - }, - }, - } { - msg, err := NewMessageASCII(table.input, len(table.wantMap)) - if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) - } - if err != nil { - continue - } - if got, want := msg.m, table.wantMap; !reflect.DeepEqual(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description) - } - } -} - -func TestNumField(t *testing.T) {} -func TestGetStrings(t *testing.T) {} -func TestGetString(t *testing.T) {} -func TestGetUint64(t *testing.T) {} -func TestGetHash(t *testing.T) {} -func TestGetSignature(t *testing.T) {} -func TestGetVerificationKey(t *testing.T) {} -func TestDecodeHex(t *testing.T) {} - -/* - * - * MarshalASCII methods and helpers - * - */ -func TestLeafMarshalASCII(t *testing.T) { - description := "valid: two leaves" - leafList := []*Leaf{ - &Leaf{ - Message: Message{ - ShardHint: 123, - Checksum: testBuffer32, - }, - SigIdent: SigIdent{ - Signature: testBuffer64, - KeyHash: testBuffer32, - }, - }, - &Leaf{ - Message: Message{ - ShardHint: 456, - Checksum: testBuffer32, - }, - SigIdent: SigIdent{ - Signature: testBuffer64, - KeyHash: testBuffer32, - }, - }, - } - wantBuf := bytes.NewBufferString(fmt.Sprintf( - "%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s"+ - "%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s", - // Leaf 1 - ShardHint, Delim, 123, EOL, - Checksum, Delim, testBuffer32[:], EOL, - Signature, Delim, testBuffer64[:], EOL, - KeyHash, Delim, testBuffer32[:], EOL, - // Leaf 2 - ShardHint, Delim, 456, EOL, - Checksum, Delim, testBuffer32[:], EOL, - Signature, Delim, testBuffer64[:], EOL, - KeyHash, Delim, testBuffer32[:], EOL, - )) - buf := bytes.NewBuffer(nil) - for _, leaf := range leafList { - if err := leaf.MarshalASCII(buf); err != nil { - t.Errorf("expected error %v but got %v in test %q: %v", false, true, description, err) - return - } - } - if got, want := buf.Bytes(), wantBuf.Bytes(); !bytes.Equal(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", string(got), string(want), description) - } -} - -func TestSignedTreeHeadMarshalASCII(t *testing.T) { - description := "valid" - sth := &SignedTreeHead{ - TreeHead: TreeHead{ - Timestamp: 123, - TreeSize: 456, - RootHash: testBuffer32, - }, - Signature: testBuffer64, - } - wantBuf := bytes.NewBufferString(fmt.Sprintf( - "%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, - )) - buf := bytes.NewBuffer(nil) - if err := sth.MarshalASCII(buf); err != nil { - t.Errorf("expected error %v but got %v in test %q", false, true, description) - return - } - if got, want := buf.Bytes(), wantBuf.Bytes(); !bytes.Equal(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", string(got), string(want), description) - } -} - -func TestInclusionProofMarshalASCII(t *testing.T) { - description := "valid" - proof := InclusionProof{ - TreeSize: 321, - LeafIndex: 123, - Path: []*[HashSize]byte{ - testBuffer32, - testBuffer32, - }, - } - wantBuf := bytes.NewBufferString(fmt.Sprintf( - "%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s", - LeafIndex, Delim, 123, EOL, - InclusionPath, Delim, testBuffer32[:], EOL, - InclusionPath, Delim, testBuffer32[:], EOL, - )) - buf := bytes.NewBuffer(nil) - if err := proof.MarshalASCII(buf); err != nil { - t.Errorf("expected error %v but got %v in test %q", false, true, description) - return - } - if got, want := buf.Bytes(), wantBuf.Bytes(); !bytes.Equal(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", string(got), string(want), description) - } -} - -func TestConsistencyProofMarshalASCII(t *testing.T) { - description := "valid" - proof := ConsistencyProof{ - NewSize: 321, - OldSize: 123, - Path: []*[HashSize]byte{ - testBuffer32, - testBuffer32, - }, - } - wantBuf := bytes.NewBufferString(fmt.Sprintf( - "%s%s%x%s"+"%s%s%x%s", - ConsistencyPath, Delim, testBuffer32[:], EOL, - ConsistencyPath, Delim, testBuffer32[:], EOL, - )) - buf := bytes.NewBuffer(nil) - if err := proof.MarshalASCII(buf); err != nil { - t.Errorf("expected error %v but got %v in test %q", false, true, description) - return - } - if got, want := buf.Bytes(), wantBuf.Bytes(); !bytes.Equal(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", string(got), string(want), description) - } -} - -func TestWriteASCII(t *testing.T) { -} - -/* - * - * UnmarshalASCII methods and helpers - * - */ -func TestLeafListUnmarshalASCII(t *testing.T) {} - -func TestSignedTreeHeadUnmarshalASCII(t *testing.T) { - for _, table := range []struct { - description string - buf io.Reader - wantErr bool - wantSth *SignedTreeHead - }{ - { - description: "valid", - buf: bytes.NewBufferString(fmt.Sprintf( - "%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, - )), - wantSth: &SignedTreeHead{ - TreeHead: TreeHead{ - Timestamp: 123, - TreeSize: 456, - RootHash: testBuffer32, - }, - Signature: testBuffer64, - }, - }, - } { - var sth SignedTreeHead - err := sth.UnmarshalASCII(table.buf) - if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) - } - if err != nil { - continue - } - if got, want := &sth, table.wantSth; !reflect.DeepEqual(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description) - } - } -} - -func TestInclusionProofUnmarshalASCII(t *testing.T) {} -func TestConsistencyProofUnmarshalASCII(t *testing.T) {} - -func TestInclusionProofRequestUnmarshalASCII(t *testing.T) { - for _, table := range []struct { - description string - buf io.Reader - wantErr bool - wantReq *InclusionProofRequest - }{ - { - description: "valid", - buf: bytes.NewBufferString(fmt.Sprintf( - "%s%s%x%s"+"%s%s%d%s", - LeafHash, Delim, testBuffer32[:], EOL, - TreeSize, Delim, 123, EOL, - )), - wantReq: &InclusionProofRequest{ - LeafHash: testBuffer32, - TreeSize: 123, - }, - }, - } { - var req InclusionProofRequest - err := req.UnmarshalASCII(table.buf) - if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) - } - if err != nil { - continue - } - if got, want := &req, table.wantReq; !reflect.DeepEqual(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description) - } - } -} - -func TestConsistencyProofRequestUnmarshalASCII(t *testing.T) { - for _, table := range []struct { - description string - buf io.Reader - wantErr bool - wantReq *ConsistencyProofRequest - }{ - { - description: "valid", - buf: bytes.NewBufferString(fmt.Sprintf( - "%s%s%d%s"+"%s%s%d%s", - NewSize, Delim, 321, EOL, - OldSize, Delim, 123, EOL, - )), - wantReq: &ConsistencyProofRequest{ - NewSize: 321, - OldSize: 123, - }, - }, - } { - var req ConsistencyProofRequest - err := req.UnmarshalASCII(table.buf) - if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) - } - if err != nil { - continue - } - if got, want := &req, table.wantReq; !reflect.DeepEqual(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description) - } - } -} - -func TestLeavesRequestUnmarshalASCII(t *testing.T) { - for _, table := range []struct { - description string - buf io.Reader - wantErr bool - wantReq *LeavesRequest - }{ - { - description: "valid", - buf: bytes.NewBufferString(fmt.Sprintf( - "%s%s%d%s"+"%s%s%d%s", - StartSize, Delim, 123, EOL, - EndSize, Delim, 456, EOL, - )), - wantReq: &LeavesRequest{ - StartSize: 123, - EndSize: 456, - }, - }, - } { - var req LeavesRequest - err := req.UnmarshalASCII(table.buf) - if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) - } - if err != nil { - continue - } - if got, want := &req, table.wantReq; !reflect.DeepEqual(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description) - } - } -} - -func TestLeafRequestUnmarshalASCII(t *testing.T) { - for _, table := range []struct { - description string - buf io.Reader - wantErr bool - wantReq *LeafRequest - }{ - { - description: "valid", - buf: bytes.NewBufferString(fmt.Sprintf( - "%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%s%s", - ShardHint, Delim, 123, EOL, - Checksum, Delim, testBuffer32[:], EOL, - Signature, Delim, testBuffer64[:], EOL, - VerificationKey, Delim, testBuffer32[:], EOL, - DomainHint, Delim, "example.com", EOL, - )), - wantReq: &LeafRequest{ - Message: Message{ - ShardHint: 123, - Checksum: testBuffer32, - }, - Signature: testBuffer64, - VerificationKey: testBuffer32, - DomainHint: "example.com", - }, - }, - } { - var req LeafRequest - err := req.UnmarshalASCII(table.buf) - if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) - } - if err != nil { - continue - } - if got, want := &req, table.wantReq; !reflect.DeepEqual(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description) - } - } -} - -func TestCosignatureRequestUnmarshalASCII(t *testing.T) { - for _, table := range []struct { - description string - buf io.Reader - wantErr bool - wantReq *CosignatureRequest - }{ - { - description: "valid", - buf: bytes.NewBufferString(fmt.Sprintf( - "%s%s%x%s"+"%s%s%x%s", - Cosignature, Delim, testBuffer64[:], EOL, - KeyHash, Delim, testBuffer32[:], EOL, - )), - wantReq: &CosignatureRequest{ - SigIdent: SigIdent{ - Signature: testBuffer64, - KeyHash: testBuffer32, - }, - }, - }, - } { - var req CosignatureRequest - err := req.UnmarshalASCII(table.buf) - if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) - } - if err != nil { - continue - } - if got, want := &req, table.wantReq; !reflect.DeepEqual(got, want) { - t.Errorf("got\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description) - } - } -} diff --git a/pkg/types/trunnel.go b/pkg/types/trunnel.go deleted file mode 100644 index 5350c5b..0000000 --- a/pkg/types/trunnel.go +++ /dev/null @@ -1,63 +0,0 @@ -package types - -import ( - "encoding/binary" - "fmt" -) - -const ( - // MessageSize is the number of bytes in a Trunnel-encoded leaf message - 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 -func (m *Message) Marshal() []byte { - buf := make([]byte, MessageSize) - binary.BigEndian.PutUint64(buf, m.ShardHint) - copy(buf[8:], m.Checksum[:]) - return buf -} - -// Marshal returns a Trunnel-encoded leaf -func (l *Leaf) Marshal() []byte { - buf := l.Message.Marshal() - buf = append(buf, l.SigIdent.Signature[:]...) - buf = append(buf, l.SigIdent.KeyHash[:]...) - return buf -} - -// Marshal returns a Trunnel-encoded tree head -func (th *TreeHead) Marshal() []byte { - buf := make([]byte, TreeHeadSize) - binary.BigEndian.PutUint64(buf[0:8], th.Timestamp) - binary.BigEndian.PutUint64(buf[8:16], th.TreeSize) - copy(buf[16:16+HashSize], th.RootHash[:]) - copy(buf[16+HashSize:], th.KeyHash[:]) - return buf -} - -// Unmarshal parses the Trunnel-encoded buffer as a leaf -func (l *Leaf) Unmarshal(buf []byte) error { - if len(buf) != LeafSize { - return fmt.Errorf("invalid leaf size: %v", len(buf)) - } - // Shard hint - l.ShardHint = binary.BigEndian.Uint64(buf) - offset := 8 - // Checksum - l.Checksum = &[HashSize]byte{} - copy(l.Checksum[:], buf[offset:offset+HashSize]) - offset += HashSize - // Signature - l.Signature = &[SignatureSize]byte{} - copy(l.Signature[:], buf[offset:offset+SignatureSize]) - offset += SignatureSize - // KeyHash - l.KeyHash = &[HashSize]byte{} - copy(l.KeyHash[:], buf[offset:]) - return nil -} diff --git a/pkg/types/trunnel_test.go b/pkg/types/trunnel_test.go deleted file mode 100644 index a3ae1ba..0000000 --- a/pkg/types/trunnel_test.go +++ /dev/null @@ -1,116 +0,0 @@ -package types - -import ( - "bytes" - "reflect" - "testing" -) - -var ( - testBuffer32 = &[32]byte{0, 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} - testBuffer64 = &[64]byte{0, 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} -) - -func TestMarshalMessage(t *testing.T) { - description := "valid: shard hint 72623859790382856, checksum 0x00,0x01,..." - message := &Message{ - ShardHint: 72623859790382856, - Checksum: testBuffer32, - } - want := bytes.Join([][]byte{ - []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, - testBuffer32[:], - }, nil) - if got := message.Marshal(); !bytes.Equal(got, want) { - t.Errorf("got message\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, description) - } -} - -func TestMarshalLeaf(t *testing.T) { - description := "valid: shard hint 72623859790382856, buffers 0x00,0x01,..." - leaf := &Leaf{ - Message: Message{ - ShardHint: 72623859790382856, - Checksum: testBuffer32, - }, - SigIdent: SigIdent{ - Signature: testBuffer64, - KeyHash: testBuffer32, - }, - } - want := bytes.Join([][]byte{ - []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, - testBuffer32[:], testBuffer64[:], testBuffer32[:], - }, nil) - if got := leaf.Marshal(); !bytes.Equal(got, want) { - t.Errorf("got leaf\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, description) - } -} - -func TestMarshalTreeHead(t *testing.T) { - 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) - } -} - -func TestUnmarshalLeaf(t *testing.T) { - for _, table := range []struct { - description string - serialized []byte - wantErr bool - want *Leaf - }{ - { - description: "invalid: not enough bytes", - serialized: make([]byte, LeafSize-1), - wantErr: true, - }, - { - description: "invalid: too many bytes", - serialized: make([]byte, LeafSize+1), - wantErr: true, - }, - { - description: "valid: shard hint 72623859790382856, buffers 0x00,0x01,...", - serialized: bytes.Join([][]byte{ - []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}, - testBuffer32[:], testBuffer64[:], testBuffer32[:], - }, nil), - want: &Leaf{ - Message: Message{ - ShardHint: 72623859790382856, - Checksum: testBuffer32, - }, - SigIdent: SigIdent{ - Signature: testBuffer64, - KeyHash: testBuffer32, - }, - }, - }, - } { - var leaf Leaf - err := leaf.Unmarshal(table.serialized) - if got, want := err != nil, table.wantErr; got != want { - t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) - } - if err != nil { - continue - } - if got, want := &leaf, table.want; !reflect.DeepEqual(got, want) { - t.Errorf("got leaf\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.description) - } - } -} diff --git a/pkg/types/types.go b/pkg/types/types.go deleted file mode 100644 index bc58c98..0000000 --- a/pkg/types/types.go +++ /dev/null @@ -1,138 +0,0 @@ -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") - EndpointGetInclusionProof = Endpoint("get-inclusion-proof") - 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)), "/") -} - -type Leaf struct { - Message - SigIdent -} - -type Message struct { - ShardHint uint64 - Checksum *[HashSize]byte -} - -type SigIdent struct { - Signature *[SignatureSize]byte - KeyHash *[HashSize]byte -} - -type SignedTreeHead struct { - TreeHead - Signature *[SignatureSize]byte -} - -type CosignedTreeHead struct { - SignedTreeHead - SigIdent []*SigIdent -} - -type TreeHead struct { - Timestamp uint64 - TreeSize uint64 - RootHash *[HashSize]byte - KeyHash *[HashSize]byte -} - -type ConsistencyProof struct { - NewSize uint64 - OldSize uint64 - Path []*[HashSize]byte -} - -type InclusionProof struct { - TreeSize uint64 - LeafIndex uint64 - Path []*[HashSize]byte -} - -type LeafList []*Leaf - -type ConsistencyProofRequest struct { - NewSize uint64 - OldSize uint64 -} - -type InclusionProofRequest struct { - LeafHash *[HashSize]byte - TreeSize uint64 -} - -type LeavesRequest struct { - StartSize uint64 - EndSize uint64 -} - -type LeafRequest struct { - Message - Signature *[SignatureSize]byte - VerificationKey *[VerificationKeySize]byte - DomainHint string -} - -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) - } - - sth := &SignedTreeHead{ - TreeHead: *th, - Signature: &[SignatureSize]byte{}, - } - copy(sth.Signature[:], sig) - return sth, 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 -} diff --git a/pkg/types/types_test.go b/pkg/types/types_test.go deleted file mode 100644 index d823ea2..0000000 --- a/pkg/types/types_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package types - -import ( - "testing" -) - -func TestEndpointPath(t *testing.T) { - base, prefix, proto := "example.com", "log", "sigsum/v0" - for _, table := range []struct { - endpoint Endpoint - want string - }{ - { - endpoint: EndpointAddLeaf, - want: "example.com/log/sigsum/v0/add-leaf", - }, - { - endpoint: EndpointAddCosignature, - want: "example.com/log/sigsum/v0/add-cosignature", - }, - { - endpoint: EndpointGetTreeHeadLatest, - want: "example.com/log/sigsum/v0/get-tree-head-latest", - }, - { - endpoint: EndpointGetTreeHeadToSign, - want: "example.com/log/sigsum/v0/get-tree-head-to-sign", - }, - { - endpoint: EndpointGetTreeHeadCosigned, - want: "example.com/log/sigsum/v0/get-tree-head-cosigned", - }, - { - endpoint: EndpointGetConsistencyProof, - want: "example.com/log/sigsum/v0/get-consistency-proof", - }, - { - endpoint: EndpointGetInclusionProof, - want: "example.com/log/sigsum/v0/get-inclusion-proof", - }, - { - endpoint: EndpointGetLeaves, - want: "example.com/log/sigsum/v0/get-leaves", - }, - } { - if got, want := table.endpoint.Path(base+"/"+prefix+"/"+proto), table.want; got != want { - t.Errorf("got endpoint\n%s\n\tbut wanted\n%s\n\twith one component", got, want) - } - if got, want := table.endpoint.Path(base, prefix, proto), table.want; got != want { - t.Errorf("got endpoint\n%s\n\tbut wanted\n%s\n\tmultiple components", got, want) - } - } -} - -func TestTreeHeadSign(t *testing.T) {} -func TestTreeHeadVerify(t *testing.T) {} -func TestInclusionProofVerify(t *testing.T) {} -func TestConsistencyProofVerify(t *testing.T) {} diff --git a/pkg/types/util.go b/pkg/types/util.go deleted file mode 100644 index 3cd7dfa..0000000 --- a/pkg/types/util.go +++ /dev/null @@ -1,21 +0,0 @@ -package types - -import ( - "crypto/sha256" -) - -const ( - LeafHashPrefix = 0x00 -) - -func Hash(buf []byte) *[HashSize]byte { - var ret [HashSize]byte - hash := sha256.New() - hash.Write(buf) - copy(ret[:], hash.Sum(nil)) - return &ret -} - -func HashLeaf(buf []byte) *[HashSize]byte { - return Hash(append([]byte{LeafHashPrefix}, buf...)) -} |