A proof is only useful if a verifier holding just the root can recompute it from one leaf. Today you build VerifyProof.
Recompute the root from a leaf and its proof, and compare to the trusted root.
Verification is the mirror of generation. Start by hashing the leaf data (with the
0x00 prefix, exactly as the tree did), then fold in each proof step: if the sibling
was on the right, compute HashNode(current, sibling); if on the left,
HashNode(sibling, current). After the last step you have recomputed a root, and if
it equals the trusted root, the leaf is proven to be in the tree.
This is the moment the whole structure pays off: the verifier never saw the other
leaves, never rebuilt the tree, and used only a handful of hashes, yet is certain
alice is leaf 0 under root 0xfd610c23. The SiblingRight flag is load-bearing -
get the order wrong on any step and the recomputed root will not match. Next you will
watch verification correctly reject forgeries.
func VerifyProof(root Hash, leaf []byte, proof []ProofStep) bool {h := HashLeaf(leaf)for _, s := range proof {if s.SiblingRight {h = HashNode(h, s.Sibling) // sibling on the right} else {h = HashNode(s.Sibling, h) // sibling on the left}}return h == root}