controlBlockForLeaf method
Given the exact leaf
object provided to this Taproot object, this
provides the control block data for inclusion in a script-path input.
Implementation
Uint8List controlBlockForLeaf(TapLeaf leaf) {
if (mast == null || !leaves.contains(leaf)) {
throw ArgumentError.value(leaf, "leaf", "not in MAST tree");
}
// Find path to leaf
final List<TapNode> path = [mast!];
while (path.last != leaf) {
if (path.last is TapLeaf) {
// Move back to last left movement
while (path.last == (path[path.length-2] as TapBranch).r) {
path.removeLast();
}
// Remove left movement
path.removeLast();
// Move over to the right
path.add((path.last as TapBranch).r);
} else {
// Is branch, move to the left-most
path.add((path.last as TapBranch).l);
}
}
final data = Uint8List(33+(path.length-1)*32);
final writer = BytesWriter(data);
// Control byte
writer.writeUInt8(
// Tapscript version
(path.last as TapLeaf).version
// Public key parity bit
+ (tweakedKey.yIsEven ? 0 : 1),
);
// Internal public key
writer.writeSlice(internalKey.x);
// Add path siblings, required for the merkle hash reconstruction
// Start from leaf node and move backwards, adding the siblings of each node
TapNode? prev;
for (final node in path.reversed) {
if (prev != null) {
node as TapBranch;
final sibling = node.l == prev ? node.r : node.l;
writer.writeSlice(sibling.hash);
}
prev = node;
}
return data;
}