Skip to content

Commit 5afe747

Browse files
committed
SubtreeInclusion
1 parent 9092a0d commit 5afe747

1 file changed

Lines changed: 41 additions & 0 deletions

File tree

proof/proof.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)