pub fn circuit_recover_public_key(
builder: &CircuitBuilder,
public_param: &[Wire; 2],
epoch: Wire,
chain_tips: &[[Wire; 2]; 42],
digits: &[Wire; 42],
) -> [[Wire; 2]; 42]Expand description
In-circuit form of recover_public_key, spending only the hashes a verifier walks.
A chain’s tail is CHAIN_LENGTH - 1 - digit hashes, and the target sum fixes the total across
all chains at NUM_CHAIN_HASHES however the digits fall. So rather than give every chain
room for its longest possible tail — V * (CHAIN_LENGTH - 1) hashes, two thirds of them
discarded — the tails are concatenated into one list of exactly that total, hinted, and pinned
by constraints. Each entry carries its input digest, its chain, its digit, and the number of
hashes that chain has already done; its output is the hash, not a hinted value, so nothing has
to check it.
§What pins the list
Walking the list, every rule is local, which is what leaves the entries with nothing to look up:
chainonly ever increases, so a chain’s entries are one contiguous run.- Within a run the step advances by one, the digit holds, and each input is the previous output.
- A run opens at step zero, and so does the list.
Then one lookup per chain finds that chain’s last entry, and checks it belongs to this chain,
carries this chain’s digit, and sits at the last position — digit + step == CHAIN_LENGTH - 2,
since the last hash of a chain starts one below the chain’s end. Its output is the chain’s end.
The offset is hinted; it needs no pinning of its own, because what it lands on is checked.
A run’s length is therefore exactly CHAIN_LENGTH - 1 - digit, and the list is exactly
NUM_CHAIN_HASHES long, which the target sum makes the sum of those lengths. No chain that
owes hashes can be missing a run: if one were, the entries would not add up.
What a run starts from is left free. The tip is a hint, and verification only needs some
preimage that walks a chain of the right length onto the committed public key — a prover with
nothing to reveal would have to invert the hash to find one. A chain whose digit is
CHAIN_LENGTH - 1 owes no hashes at all, and its end is simply the value the signature
revealed.