Signature verification using a key commitment referenced from a relay block. Enables cross-rung key sharing without duplicating pubkey commitments, saving ~30 bytes per reference.
SignatureNon-Invertible
Ladder Diagram
Fields
Field
Data Type
Size
Side
Description
relay_index
NUMERIC
4 B
Conditions
Index into the rung's relay array. Value must fit uint16_t (≤ 0xFFFF) and must appear in the rung's relay_refs.
block_index
NUMERIC
4 B
Conditions
Index of the target block within the resolved relay. Value must fit uint16_t (≤ 0xFFFF).
signature
SIGNATURE
var
Witness
Signature over the sighash. Scheme is read from the resolved target relay block (Schnorr default if absent); Schnorr is 64-65 B, ECDSA 8-72 B, PQ schemes variable.
PubkeyCountForBlock = 0 for KEY_REF_SIG. No PUBKEY in conditions or witness — the key (and its SCHEME) is dereferenced from relays[relay_index].blocks[block_index], whose own Merkle leaf already binds it at MLSC-proof level.
Wire Format Breakdown
Conditions side (committed in the rung leaf):
0x000502NUMERIC · 4BNUMERIC · 4B= 14 bytes
Witness side (in input witness):
0x000501SIGNATURE · 64-65B≈ 70 bytes
Total (conditions + witness)≈ 84 bytes
KEY_REF_SIG resolves its public key from a relay block rather than folding it into the rung's own Merkle leaf. PubkeyCountForBlock = 0 for KEY_REF_SIG; the key is bound at MLSC-proof level by the target relay block's own Merkle leaf. Each additional rung referencing the same relay key avoids duplicating the key (~33 B) in multiple rung leaves and avoids re-revealing it in the witness.
Evaluation Logic
1.Read both conditions NUMERIC fields and decode them as little-endian 4-byte values relay_index and block_index. If either is absent or its decoded value exceeds 0xFFFF (uint16_t range) → ERROR
2.Require relay context to be available (ctx.relays and ctx.rung_relay_refs). If unavailable → ERROR
3.Validate relay_index appears in this rung's relay_refs. If it was not declared by the rung → ERROR
4.Bounds-check: relay_index < relays.size() and block_index < relay.blocks.size(). Out of range → ERROR
5.Resolve target_block = relays[relay_index].blocks[block_index] and read its PUBKEY field. If the target block has no PUBKEY → ERROR. (The target block's pubkey identity is already pinned by its own merkle_pub_key at MLSC-proof level — no leaf check is performed here.)
6.Read the optional SCHEME field from the target block. If absent, the scheme defaults to Schnorr.
7.Read this block's witness SIGNATURE. If missing → ERROR
8.Dispatch VerifySigWithScheme(target_pubkey, witness_sig, target_scheme, ...). Size checks for the resolved scheme apply here (Schnorr 64-65 B, ECDSA 8-72 B, PQ scheme-specific). Invalid → UNSATISFIED; valid → SATISFIED
Return Values
Condition
Result
Either NUMERIC field absent, or value > 0xFFFF (uint16_t cap)
ERROR
Relay context unavailable (no relays or rung_relay_refs)
ERROR
relay_index not declared in this rung's relay_refs
ERROR
relay_index or block_index out of bounds
ERROR
Target relay block has no PUBKEY field
ERROR
Witness SIGNATURE missing
ERROR
Resolved-scheme size check fails (e.g. Schnorr sig not 64-65 B)
A single key bound to a relay's Merkle leaf is referenced by multiple rungs via KEY_REF_SIG. For example, the same hot-wallet key can authorize both an immediate spend (rung 0) and a timelocked recovery (rung 1) without folding the key into each rung's leaf separately.
MLSC Witness Compression
In Merkelised Ladder Script trees with many spending paths, KEY_REF_SIG reduces the size of each rung by ~30 bytes. Since relays are revealed alongside the spending rung in the MLSC proof, the verifier always has access to the referenced key commitment.
Relay-Based Key Management
A relay defines the authorized signer (key folded into relay's Merkle leaf). Multiple rungs can reference the same relay via KEY_REF_SIG to enforce that the same key is used across different spending paths with different additional conditions (timelocks, hashlock, etc.).