controlBlockForLeaf method

Uint8List controlBlockForLeaf(
  1. TapLeaf leaf
)

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;

}