@@ -17,8 +17,8 @@ func TestAccumulatedSubtreeProof(t *testing.T) {
1717 for n := int64 (0 ); n <= 130 ; n ++ {
1818 th , err := tlog .TreeHash (n , tree )
1919 fatalIfErr (t , err )
20- for end := int64 (1 ); end <= n ; end ++ {
21- for start := int64 (0 ); start < end ; start ++ {
20+ for end := int64 (0 ); end <= n ; end ++ {
21+ for start := int64 (0 ); start <= end ; start ++ {
2222 if ! torchwood .ValidSubtree (start , end ) {
2323 continue
2424 }
@@ -43,7 +43,13 @@ func TestAccumulatedSubtreeProof(t *testing.T) {
4343 }
4444
4545 err = torchwood .CheckSubtree (p , n , flip (th ), start , end , sh )
46- if err == nil {
46+ if start == end {
47+ // An empty subtree is contained in every tree,
48+ // so the tree hash is not checked.
49+ if err != nil {
50+ t .Errorf ("CheckSubtree rejected wrong th for [%d, %d) in tree of size %d" , start , end , n )
51+ }
52+ } else if err == nil {
4753 t .Errorf ("CheckSubtree accepted wrong th for [%d, %d) in tree of size %d" , start , end , n )
4854 }
4955
@@ -76,7 +82,7 @@ func TestAccumulatedSubtreeProof(t *testing.T) {
7682 }
7783 }
7884 got := o .Sum (nil )
79- want := "c586ebbb73a5621baf2140095d87dde934e3b6503a562a1a5215b8209edd083d "
85+ want := "10fa99b37bf9bf9ffa26b412fbd98bd75363256d0b75d61bc4538b9c9c5a0a74 "
8086 if fmt .Sprintf ("%x" , got ) != want {
8187 t .Errorf ("AccumulatedSubtreeProof hash = %x; want %s" , got , want )
8288 }
@@ -85,8 +91,8 @@ func TestAccumulatedSubtreeProof(t *testing.T) {
8591func TestAccumulatedRecordInSubtreeProof (t * testing.T ) {
8692 o := sha256 .New ()
8793 leaves , tree := buildTree (t , 130 )
88- for end := int64 (1 ); end <= 130 ; end ++ {
89- for start := int64 (0 ); start < end ; start ++ {
94+ for end := int64 (0 ); end <= 130 ; end ++ {
95+ for start := int64 (0 ); start <= end ; start ++ {
9096 if ! torchwood .ValidSubtree (start , end ) {
9197 continue
9298 }
@@ -150,8 +156,8 @@ func mangleProof(p []tlog.Hash, i int) []tlog.Hash {
150156func TestAccumulatedSubtreeHash (t * testing.T ) {
151157 o := sha256 .New ()
152158 _ , tree := buildTree (t , 130 )
153- for end := int64 (1 ); end <= 130 ; end ++ {
154- for start := int64 (0 ); start < end ; start ++ {
159+ for end := int64 (0 ); end <= 130 ; end ++ {
160+ for start := int64 (0 ); start <= end ; start ++ {
155161 if ! torchwood .ValidSubtree (start , end ) {
156162 continue
157163 }
@@ -161,27 +167,23 @@ func TestAccumulatedSubtreeHash(t *testing.T) {
161167 }
162168 }
163169 got := o .Sum (nil )
164- want := "94a95384a8c69acea9b50d035a58285b3a777cb7a724005faa5e1f1e1190007f "
170+ want := "b82806ad4265bb151c1119c0f4db437bb4d1a1f887b3a7fba1cd4ebf552e3e81 "
165171 if fmt .Sprintf ("%x" , got ) != want {
166172 t .Errorf ("AccumulatedSubtreeHash hash = %x; want %s" , got , want )
167173 }
168174}
169175
170176func TestAccumulatedCoverInterval (t * testing.T ) {
171177 o := sha256 .New ()
172- for end := int64 (1 ); end <= 130 ; end ++ {
173- for start := int64 (0 ); start < end ; start ++ {
174- if torchwood .ValidSubtree (start , end ) {
175- fmt .Fprintf (o , "[%d, %d)\n " , start , end )
176- } else {
177- ls , mid , err := torchwood .CoverInterval (start , end )
178- fatalIfErr (t , err )
179- fmt .Fprintf (o , "[%d, %d) [%d, %d)\n " , ls , mid , mid , end )
180- }
178+ for end := int64 (0 ); end <= 130 ; end ++ {
179+ for start := int64 (0 ); start <= end ; start ++ {
180+ ls , mid , err := torchwood .CoverInterval (start , end )
181+ fatalIfErr (t , err )
182+ fmt .Fprintf (o , "[%d, %d) [%d, %d)\n " , ls , mid , mid , end )
181183 }
182184 }
183185 got := o .Sum (nil )
184- want := "e0aecb912a10c57d753b6ecc64db73217f9bc4ed10fcb4e9062be3b6fbe1ebfd "
186+ want := "7fd9c8b926e9d2b5cf831560e8ce295a5ef97ad5c5ede4ea0dea28a8c8fc8bb0 "
185187 if fmt .Sprintf ("%x" , got ) != want {
186188 t .Errorf ("AccumulatedCoverInterval hash = %x; want %s" , got , want )
187189 }
@@ -202,7 +204,8 @@ func TestValidSubtree(t *testing.T) {
202204 {5 , 13 , false }, // size 8, 5 not a multiple of 8
203205 {1 , 7 , false }, // size 6, 1 not a multiple of 8
204206 {7 , 9 , false }, // size 2, 7 not a multiple of 2
205- {0 , 0 , false }, // empty
207+ {0 , 0 , true }, // empty
208+ {5 , 5 , true }, // empty, non-zero start
206209 {5 , 3 , false }, // end < start
207210 {- 1 , 3 , false }, // negative start
208211 {0 , 1 << 62 , true }, // size 2^62, the maximum span
@@ -218,8 +221,8 @@ func TestValidSubtree(t *testing.T) {
218221// refFindSubtrees is a direct port of the find_subtrees Python reference in
219222// draft-ietf-plants-merkle-tree-certs, Section 4.5.
220223func refFindSubtrees (start , end int64 ) [][2 ]int64 {
221- if end - start = = 1 {
222- return [][2 ]int64 {{start , end }}
224+ if end - start < = 1 {
225+ return [][2 ]int64 {{start , end }, { end , end } }
223226 }
224227 last := end - 1
225228 split := bits .Len64 (uint64 (start ^ last )) - 1
@@ -231,8 +234,8 @@ func refFindSubtrees(start, end int64) [][2]int64 {
231234}
232235
233236func TestCoverInterval (t * testing.T ) {
234- // Error cases: bad range, and intervals that are already subtrees .
235- for _ , tt := range [][2 ]int64 {{- 1 , 5 }, {5 , 5 }, { 5 , 3 }, { 4 , 8 }, { 7 , 8 }, { 0 , 16 }} {
237+ // Error cases: bad ranges .
238+ for _ , tt := range [][2 ]int64 {{- 1 , 5 }, {5 , 3 }} {
236239 if _ , _ , err := torchwood .CoverInterval (tt [0 ], tt [1 ]); err == nil {
237240 t .Errorf ("CoverInterval(%d, %d) = nil error; want error" , tt [0 ], tt [1 ])
238241 }
@@ -243,32 +246,44 @@ func TestCoverInterval(t *testing.T) {
243246 t .Errorf ("CoverInterval(5, 13) = %d, %d, %v; want 4, 8, nil" , ls , mid , err )
244247 }
245248
249+ // Size-one and empty intervals are covered by themselves and an
250+ // empty subtree.
251+ if ls , mid , err := torchwood .CoverInterval (7 , 8 ); err != nil || ls != 7 || mid != 8 {
252+ t .Errorf ("CoverInterval(7, 8) = %d, %d, %v; want 7, 8, nil" , ls , mid , err )
253+ }
254+ if ls , mid , err := torchwood .CoverInterval (5 , 5 ); err != nil || ls != 5 || mid != 5 {
255+ t .Errorf ("CoverInterval(5, 5) = %d, %d, %v; want 5, 5, nil" , ls , mid , err )
256+ }
257+
258+ // A subtree of size larger than one is covered by its two children.
259+ if ls , mid , err := torchwood .CoverInterval (4 , 8 ); err != nil || ls != 4 || mid != 6 {
260+ t .Errorf ("CoverInterval(4, 8) = %d, %d, %v; want 4, 6, nil" , ls , mid , err )
261+ }
262+ if ls , mid , err := torchwood .CoverInterval (0 , 13 ); err != nil || ls != 0 || mid != 8 {
263+ t .Errorf ("CoverInterval(0, 13) = %d, %d, %v; want 0, 8, nil" , ls , mid , err )
264+ }
265+
246266 for start := range int64 (64 ) {
247- for end := start + 1 ; end <= 64 ; end ++ {
267+ for end := start ; end <= 64 ; end ++ {
248268 ls , mid , err := torchwood .CoverInterval (start , end )
249- if torchwood .ValidSubtree (start , end ) {
250- if err == nil {
251- t .Errorf ("CoverInterval(%d, %d) = nil error for a valid subtree" , start , end )
252- }
253- continue
254- }
255269 if err != nil {
256270 t .Errorf ("CoverInterval(%d, %d) = %v" , start , end , err )
257271 continue
258272 }
259273 // Matches the spec reference.
260- if want := refFindSubtrees (start , end ); ls != want [0 ][0 ] || mid != want [0 ][1 ] || want [1 ][1 ] != end {
274+ if want := refFindSubtrees (start , end ); ls != want [0 ][0 ] || mid != want [0 ][1 ] ||
275+ want [1 ][0 ] != mid || want [1 ][1 ] != end {
261276 t .Errorf ("CoverInterval(%d, %d) = %d, %d; want %v" , start , end , ls , mid , want )
262277 }
263278 // Both halves are valid subtrees.
264279 if ! torchwood .ValidSubtree (ls , mid ) || ! torchwood .ValidSubtree (mid , end ) {
265280 t .Errorf ("CoverInterval(%d, %d) = %d, %d: halves not valid subtrees" , start , end , ls , mid )
266281 }
267282 // Coverage and bounded excess.
268- if ! (ls <= start && start < mid && mid < end ) {
283+ if ! (ls <= start && start <= mid && mid <= end ) {
269284 t .Errorf ("CoverInterval(%d, %d) = %d, %d: bad coverage" , start , end , ls , mid )
270285 }
271- if ! (start - ls < mid - start ) {
286+ if start < end && ! (start - ls < mid - start ) {
272287 t .Errorf ("CoverInterval(%d, %d) = %d, %d: excess %d not less than half of left %d" ,
273288 start , end , ls , mid , start - ls , mid - ls )
274289 }
@@ -429,6 +444,54 @@ func TestRecordInSubtree(t *testing.T) {
429444 }
430445}
431446
447+ func TestEmptySubtree (t * testing.T ) {
448+ _ , r := buildTree (t , 16 )
449+ th , err := tlog .TreeHash (16 , r )
450+ fatalIfErr (t , err )
451+
452+ // An empty subtree hashes to the empty tree hash.
453+ sh , err := torchwood .SubtreeHash (5 , 5 , r )
454+ fatalIfErr (t , err )
455+ if empty , err := tlog .TreeHash (0 , r ); err != nil || sh != empty {
456+ t .Errorf ("SubtreeHash(5, 5) = %v, %v; want empty tree hash %v" , sh , err , empty )
457+ }
458+
459+ // The proof for an empty subtree is empty, and does not depend on the tree.
460+ p , err := torchwood .ProveSubtree (16 , 5 , 5 , r )
461+ fatalIfErr (t , err )
462+ if len (p ) != 0 {
463+ t .Errorf ("ProveSubtree(16, 5, 5) = %v; want empty proof" , p )
464+ }
465+ if err := torchwood .CheckSubtree (p , 16 , th , 5 , 5 , sh ); err != nil {
466+ t .Errorf ("CheckSubtree(16, [5, 5)) = %v" , err )
467+ }
468+ if err := torchwood .CheckSubtree (p , 16 , flip (th ), 5 , 5 , sh ); err != nil {
469+ t .Errorf ("CheckSubtree(16, [5, 5)) with different th = %v" , err )
470+ }
471+ if torchwood .CheckSubtree (p , 16 , th , 5 , 5 , flip (sh )) == nil {
472+ t .Errorf ("CheckSubtree accepted wrong hash for empty subtree" )
473+ }
474+ if torchwood .CheckSubtree (torchwood.SubtreeProof {th }, 16 , th , 5 , 5 , sh ) == nil {
475+ t .Errorf ("CheckSubtree accepted non-empty proof for empty subtree" )
476+ }
477+
478+ // An empty subtree must still be within the tree.
479+ if _ , err := torchwood .ProveSubtree (16 , 17 , 17 , r ); err == nil {
480+ t .Errorf ("ProveSubtree(16, 17, 17) = nil error" )
481+ }
482+ if err := torchwood .CheckSubtree (nil , 16 , th , 17 , 17 , sh ); err == nil {
483+ t .Errorf ("CheckSubtree(16, [17, 17)) = nil error" )
484+ }
485+
486+ // No record is contained in an empty subtree.
487+ if _ , err := torchwood .ProveRecordInSubtree (5 , 5 , 5 , r ); err == nil {
488+ t .Errorf ("ProveRecordInSubtree(5, 5, 5) = nil error" )
489+ }
490+ if err := torchwood .CheckRecordInSubtree (nil , 5 , 5 , sh , 5 , tlog.Hash {}); err == nil {
491+ t .Errorf ("CheckRecordInSubtree([5, 5)) = nil error" )
492+ }
493+ }
494+
432495func TestSubtreeInvalidInputs (t * testing.T ) {
433496 _ , r := buildTree (t , 16 )
434497 // end > t
0 commit comments