Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions trees/mirror/mirror.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,33 @@ func AddCheckpointRequest(oldSize int64, proof []tlog.Hash, signedCheckpoint []b
return b.Bytes(), nil
}

// SignSubtreeRequest builds the sign-subtree request body per
// c2sp.org/tlog-witness. The proof must be a Subtree Consistency Proof from the
// subtree to the checkpoint, empty when the subtree is the whole tree.
func SignSubtreeRequest(start, end int64, subtreeHash tlog.Hash, proof []tlog.Hash, signedCheckpoint []byte) ([]byte, error) {
if start < 0 {
return nil, fmt.Errorf("negative subtree start %d", start)
}
if end <= start {
return nil, fmt.Errorf("subtree end %d not after start %d", end, start)
}
if len(proof) > maxProofLines {
return nil, fmt.Errorf("consistency proof has %d lines, want at most %d", len(proof), maxProofLines)
}
if len(signedCheckpoint) == 0 {
return nil, errors.New("empty checkpoint")
}
var b bytes.Buffer
fmt.Fprintf(&b, "subtree %d %d\n%s\n", start, end, subtreeHash)
for _, h := range proof {
b.WriteString(h.String())
b.WriteByte('\n')
}
b.WriteByte('\n')
b.Write(signedCheckpoint)
return b.Bytes(), nil
}

// parseDecimal parses an ASCII decimal string, accepting leading zeroes since
// the specs require canonical decimals only in request bodies.
func parseDecimal(s string) (int64, error) {
Expand Down
36 changes: 36 additions & 0 deletions trees/mirror/mirror_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,42 @@ func TestEntryPackage(t *testing.T) {
}
}

func TestSignSubtreeRequest(t *testing.T) {
hash := mustHash(t, "CsUYapGGPo4dkMgIAUqom/Xajj7h2fB2MPA3j2jxq2I=")
proof := []tlog.Hash{mustHash(t, "PlRNCrwHpqhGrupue0L7gxbjbMiKA9temvuZZDDpkaw=")}
note := []byte("example.com/log\n512\n" + hash.String() + "\n\n— example.com/log AAAA\n")

body, err := SignSubtreeRequest(256, 512, hash, proof, note)
if err != nil {
t.Fatalf("SignSubtreeRequest: %s", err)
}
expect := "subtree 256 512\n" + hash.String() + "\n" + proof[0].String() + "\n\n" + string(note)
if string(body) != expect {
t.Errorf("SignSubtreeRequest = %q, want %q", body, expect)
}

_, err = SignSubtreeRequest(-1, 512, hash, nil, note)
if err == nil {
t.Error("SignSubtreeRequest with a negative start = nil error, want error")
}
_, err = SignSubtreeRequest(512, 256, hash, nil, note)
if err == nil {
t.Error("SignSubtreeRequest with end before start = nil error, want error")
}
_, err = SignSubtreeRequest(512, 512, hash, nil, note)
if err == nil {
t.Error("SignSubtreeRequest with an empty subtree = nil error, want error")
}
_, err = SignSubtreeRequest(0, 512, hash, make([]tlog.Hash, 64), note)
if err == nil {
t.Error("SignSubtreeRequest with 64 proof lines = nil error, want error")
}
_, err = SignSubtreeRequest(0, 512, hash, nil, nil)
if err == nil {
t.Error("SignSubtreeRequest with an empty checkpoint = nil error, want error")
}
}

func TestAddEntriesRequest(t *testing.T) {
origin := "oid/1.3.6.1.4.1.44947.4.1.0.44"
pkg := []byte{0, 1, 'x', 0}
Expand Down