@@ -52,6 +52,35 @@ func Inclusion(index, size uint64) (Nodes, error) {
5252 return nodes (index , 0 , size ).skipFirst (), nil
5353}
5454
55+ // SubtreeInclusion returns the information on how to fetch and construct an inclusion
56+ // proof for the given leaf index in a log Merkle subtree covering [start, end).
57+ // It requires:
58+ // - 0 <= start <= index < end
59+ // - start to be a multiple of the smallest power of two greater than or equal to
60+ // (end - start)
61+ func SubtreeInclusion (index , start , end uint64 ) (Nodes , error ) {
62+ if start >= end {
63+ return Nodes {}, fmt .Errorf ("start %d greater than or equal to end %d" , start , end )
64+ }
65+ if index < start || index > end {
66+ return Nodes {}, fmt .Errorf ("index %d out of bounds for subtree range [%d, %d)" , index , start , end )
67+ }
68+ if err := checkSubtreeAlignment (start , end ); err != nil {
69+ return Nodes {}, err
70+ }
71+
72+ // Shift the subtree to the left such that it starts at 0.
73+ p := nodes (index - start , 0 , end - start )
74+
75+ // Shift all nodes back to the right.
76+ for n := range p .IDs {
77+ p .IDs [n ].Index += start >> p .IDs [n ].Level
78+ }
79+ p .ephem .Index += start >> p .ephem .Level
80+
81+ return p .skipFirst (), nil
82+ }
83+
5584// Consistency returns the information on how to fetch and construct a
5685// consistency proof between the two given tree sizes of a log Merkle tree. It
5786// requires 0 <= size1 <= size2.
@@ -189,3 +218,15 @@ func reverse(ids []compact.NodeID) {
189218 ids [i ], ids [j ] = ids [j ], ids [i ]
190219 }
191220}
221+
222+ func checkSubtreeAlignment (start , end uint64 ) error {
223+ shift := bits .Len64 (end - start - 1 )
224+ if shift >= 64 {
225+ if start != 0 {
226+ return fmt .Errorf ("start %d not a multiple of bit_ceil(end - start)" , start )
227+ }
228+ } else if bc := uint64 (1 ) << shift ; start % bc != 0 {
229+ return fmt .Errorf ("start %d not a multiple of bit_ceil(end - start) = %d" , start , bc )
230+ }
231+ return nil
232+ }
0 commit comments