diff options
-rw-r--r-- | pkg/requests/requests.go | 75 | ||||
-rw-r--r-- | pkg/requests/requests_test.go | 359 |
2 files changed, 434 insertions, 0 deletions
diff --git a/pkg/requests/requests.go b/pkg/requests/requests.go new file mode 100644 index 0000000..26a5213 --- /dev/null +++ b/pkg/requests/requests.go @@ -0,0 +1,75 @@ +package requests + +import ( + "io" + + "git.sigsum.org/sigsum-lib-go/pkg/ascii" + "git.sigsum.org/sigsum-lib-go/pkg/types" +) + +type Leaf struct { + types.Statement + Signature types.Signature `ascii:"signature"` + VerificationKey types.PublicKey `ascii:"verification_key"` + DomainHint string `ascii:"domain_hint"` +} + +type Leaves struct { + StartSize uint64 `ascii:"start_size"` + EndSize uint64 `ascii:"end_size"` +} + +type InclusionProof struct { + LeafHash types.Hash `ascii:"leaf_hash"` + TreeSize uint64 `ascii:"tree_size"` +} + +type ConsistencyProof struct { + NewSize uint64 `ascii:"new_size"` + OldSize uint64 `ascii:"old_size"` +} + +type Cosignature struct { + Cosignature types.Signature `ascii:"cosignature"` + KeyHash types.Hash `ascii:"key_hash"` +} + +func (req *Leaf) ToASCII(w io.Writer) error { + return ascii.StdEncoding.Serialize(w, req) +} + +func (req *Leaves) ToASCII(w io.Writer) error { + return ascii.StdEncoding.Serialize(w, req) +} + +func (req *InclusionProof) ToASCII(w io.Writer) error { + return ascii.StdEncoding.Serialize(w, req) +} + +func (req *ConsistencyProof) ToASCII(w io.Writer) error { + return ascii.StdEncoding.Serialize(w, req) +} + +func (req *Cosignature) ToASCII(w io.Writer) error { + return ascii.StdEncoding.Serialize(w, req) +} + +func (req *Leaf) FromASCII(r io.Reader) error { + return ascii.StdEncoding.Deserialize(r, req) +} + +func (req *Leaves) FromASCII(r io.Reader) error { + return ascii.StdEncoding.Deserialize(r, req) +} + +func (req *InclusionProof) FromASCII(r io.Reader) error { + return ascii.StdEncoding.Deserialize(r, req) +} + +func (req *ConsistencyProof) FromASCII(r io.Reader) error { + return ascii.StdEncoding.Deserialize(r, req) +} + +func (req *Cosignature) FromASCII(r io.Reader) error { + return ascii.StdEncoding.Deserialize(r, req) +} diff --git a/pkg/requests/requests_test.go b/pkg/requests/requests_test.go new file mode 100644 index 0000000..7102714 --- /dev/null +++ b/pkg/requests/requests_test.go @@ -0,0 +1,359 @@ +package requests + +import ( + "bytes" + "fmt" + "io" + "reflect" + "testing" + + "git.sigsum.org/sigsum-lib-go/pkg/types" +) + +func TestLeafToASCII(t *testing.T) { + desc := "valid" + buf := bytes.NewBuffer(nil) + if err := validLeaf(t).ToASCII(buf); err != nil { + t.Fatalf("got error true but wanted false in test %q: %v", desc, err) + } + if got, want := string(buf.Bytes()), validLeafASCII(t); got != want { + t.Errorf("got leaf request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc) + } +} + +func TestLeavesToASCII(t *testing.T) { + desc := "valid" + buf := bytes.NewBuffer(nil) + if err := validLeaves(t).ToASCII(buf); err != nil { + t.Fatalf("got error true but wanted false in test %q: %v", desc, err) + } + if got, want := string(buf.Bytes()), validLeavesASCII(t); got != want { + t.Errorf("got leaves request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc) + } +} + +func TestInclusionProofToASCII(t *testing.T) { + desc := "valid" + buf := bytes.NewBuffer(nil) + if err := validInclusionProof(t).ToASCII(buf); err != nil { + t.Fatalf("got error true but wanted false in test %q: %v", desc, err) + } + if got, want := string(buf.Bytes()), validInclusionProofASCII(t); got != want { + t.Errorf("got inclusion proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc) + } +} + +func TestConsistencyProofToASCII(t *testing.T) { + desc := "valid" + buf := bytes.NewBuffer(nil) + if err := validConsistencyProof(t).ToASCII(buf); err != nil { + t.Fatalf("got error true but wanted false in test %q: %v", desc, err) + } + if got, want := string(buf.Bytes()), validConsistencyProofASCII(t); got != want { + t.Errorf("got consistency proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc) + } +} + +func TestCosignatureToASCII(t *testing.T) { + desc := "valid" + buf := bytes.NewBuffer(nil) + if err := validCosignature(t).ToASCII(buf); err != nil { + t.Fatalf("got error true but wanted false in test %q: %v", desc, err) + } + if got, want := string(buf.Bytes()), validCosignatureASCII(t); got != want { + t.Errorf("got cosignature request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, desc) + } +} + +func TestLeafFromASCII(t *testing.T) { + for _, table := range []struct { + desc string + serialized io.Reader + wantErr bool + want *Leaf + }{ + { + desc: "invalid: not a leaf request (unexpected key-value pair)", + serialized: bytes.NewBuffer( + append([]byte(validLeafASCII(t)), + []byte("key=4")...), + ), + wantErr: true, + }, + { + desc: "valid", + serialized: bytes.NewBuffer([]byte(validLeafASCII(t))), + want: validLeaf(t), + }, + } { + var proof Leaf + err := proof.FromASCII(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.desc, err) + } + if err != nil { + continue + } + if got, want := &proof, table.want; !reflect.DeepEqual(got, want) { + t.Errorf("got leaf request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc) + } + } +} + +func TestLeavesFromASCII(t *testing.T) { + for _, table := range []struct { + desc string + serialized io.Reader + wantErr bool + want *Leaves + }{ + { + desc: "invalid: not a leaves request (unexpected key-value pair)", + serialized: bytes.NewBuffer( + append([]byte(validLeavesASCII(t)), + []byte("key=4")...), + ), + wantErr: true, + }, + { + desc: "valid", + serialized: bytes.NewBuffer([]byte(validLeavesASCII(t))), + want: validLeaves(t), + }, + } { + var req Leaves + err := req.FromASCII(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.desc, err) + } + if err != nil { + continue + } + if got, want := &req, table.want; !reflect.DeepEqual(got, want) { + t.Errorf("got leaves request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc) + } + } +} + +func TestInclusionProofFromASCII(t *testing.T) { + for _, table := range []struct { + desc string + serialized io.Reader + wantErr bool + want *InclusionProof + }{ + { + desc: "invalid: not an inclusion proof request (unexpected key-value pair)", + serialized: bytes.NewBuffer(append( + []byte(validInclusionProofASCII(t)), + []byte("key=4")...), + ), + wantErr: true, + }, + { + desc: "valid", + serialized: bytes.NewBuffer([]byte(validInclusionProofASCII(t))), + want: validInclusionProof(t), + }, + } { + var req InclusionProof + err := req.FromASCII(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.desc, err) + } + if err != nil { + continue + } + if got, want := &req, table.want; !reflect.DeepEqual(got, want) { + t.Errorf("got inclusion proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc) + } + } +} + +func TestConsistencyProofFromASCII(t *testing.T) { + for _, table := range []struct { + desc string + serialized io.Reader + wantErr bool + want *ConsistencyProof + }{ + { + desc: "invalid: not a consistency proof request (unexpected key-value pair)", + serialized: bytes.NewBuffer( + append([]byte(validConsistencyProofASCII(t)), + []byte("tree_size=4")...), + ), + wantErr: true, + }, + { + desc: "valid", + serialized: bytes.NewBuffer([]byte(validConsistencyProofASCII(t))), + want: validConsistencyProof(t), + }, + } { + var req ConsistencyProof + err := req.FromASCII(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.desc, err) + } + if err != nil { + continue + } + if got, want := &req, table.want; !reflect.DeepEqual(got, want) { + t.Errorf("got consistency proof request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc) + } + } +} + +func TestCosignatureFromASCII(t *testing.T) { + for _, table := range []struct { + desc string + serialized io.Reader + wantErr bool + want *Cosignature + }{ + { + desc: "invalid: not a cosignature request (unexpected key-value pair)", + serialized: bytes.NewBuffer( + append([]byte(validCosignatureASCII(t)), + []byte("key=4")...), + ), + wantErr: true, + }, + { + desc: "valid", + serialized: bytes.NewBuffer([]byte(validCosignatureASCII(t))), + want: validCosignature(t), + }, + } { + var req Cosignature + err := req.FromASCII(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.desc, err) + } + if err != nil { + continue + } + if got, want := &req, table.want; !reflect.DeepEqual(got, want) { + t.Errorf("got cosignature request\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, table.desc) + } + } +} + +func validLeaf(t *testing.T) *Leaf { + t.Helper() + return &Leaf{ + Statement: types.Statement{ + ShardHint: 1, + Checksum: *newHashBufferInc(t), + }, + Signature: *newSigBufferInc(t), + VerificationKey: *newPubBufferInc(t), + DomainHint: "example.com", + } +} + +func validLeafASCII(t *testing.T) string { + t.Helper() + return fmt.Sprintf("%s=%d\n%s=%x\n%s=%x\n%s=%x\n%s=%s\n", + "shard_hint", 1, + "checksum", newHashBufferInc(t)[:], + "signature", newSigBufferInc(t)[:], + "verification_key", newPubBufferInc(t)[:], + "domain_hint", "example.com", + ) +} + +func validLeaves(t *testing.T) *Leaves { + t.Helper() + return &Leaves{ + StartSize: 1, + EndSize: 4, + } +} + +func validLeavesASCII(t *testing.T) string { + t.Helper() + return fmt.Sprintf("%s=%d\n%s=%d\n", + "start_size", 1, + "end_size", 4, + ) +} + +func validInclusionProof(t *testing.T) *InclusionProof { + t.Helper() + return &InclusionProof{ + LeafHash: *newHashBufferInc(t), + TreeSize: 4, + } +} + +func validInclusionProofASCII(t *testing.T) string { + t.Helper() + return fmt.Sprintf("%s=%x\n%s=%d\n", + "leaf_hash", newHashBufferInc(t)[:], + "tree_size", 4, + ) +} + +func validConsistencyProof(t *testing.T) *ConsistencyProof { + t.Helper() + return &ConsistencyProof{ + NewSize: 4, + OldSize: 1, + } +} + +func validConsistencyProofASCII(t *testing.T) string { + t.Helper() + return fmt.Sprintf("%s=%d\n%s=%d\n", + "new_size", 4, + "old_size", 1, + ) +} + +func validCosignature(t *testing.T) *Cosignature { + t.Helper() + return &Cosignature{ + Cosignature: *newSigBufferInc(t), + KeyHash: *newHashBufferInc(t), + } +} + +func validCosignatureASCII(t *testing.T) string { + t.Helper() + return fmt.Sprintf("%s=%x\n%s=%x\n", + "cosignature", newSigBufferInc(t)[:], + "key_hash", newHashBufferInc(t)[:], + ) +} + +func newHashBufferInc(t *testing.T) *types.Hash { + t.Helper() + + var buf types.Hash + for i := 0; i < len(buf); i++ { + buf[i] = byte(i) + } + return &buf +} + +func newSigBufferInc(t *testing.T) *types.Signature { + t.Helper() + + var buf types.Signature + for i := 0; i < len(buf); i++ { + buf[i] = byte(i) + } + return &buf +} + +func newPubBufferInc(t *testing.T) *types.PublicKey { + t.Helper() + + var buf types.PublicKey + for i := 0; i < len(buf); i++ { + buf[i] = byte(i) + } + return &buf +} |