CLSAG: Exact Construction & Domain Separation
The aggregation coefficients, the domain-separated challenge hashes, and how one ring proves both key ownership and commitment opening — with the round-robin written out.
The internals course gave you the shape of a ring signature. This lesson is the construction at the level you'd need to implement or audit it: the two rings, the aggregation coefficients, the domain-separated hashes, and the round-robin written out.
What CLSAG Must Prove, Precisely
For each input, over a ring of n members at secret index π, CLSAG proves knowledge of two secrets at once:
- the output private key
xwithP_π = xG(you own the output), and - the blinding factor
zof the difference between the output's amount commitment and the input's pseudo-out commitment,C_π − C_π^offset = zG(the amounts balance and you can open them).
MLSAG proved these as a 2-row matrix (two parallel rings sharing one challenge). CLSAG's contribution is to aggregate them into a single ring, which is what makes it ~25% smaller and ~20% faster to verify.
Aggregation Coefficients
CLSAG forms per-ring aggregation coefficients by hashing the ring data with domain-separated prefixes — conceptually:
μ_P = Hs( "CLSAG_agg_0" ‖ {P_i} ‖ {C_i} ‖ I ‖ D ‖ pseudoOut )
μ_C = Hs( "CLSAG_agg_1" ‖ {P_i} ‖ {C_i} ‖ I ‖ D ‖ pseudoOut )
where I = x·Hp(P_π) is the key image and D = z·Hp(P_π) is an auxiliary "commitment key image". The signer then works in an aggregated key per ring member: W_i = μ_P·P_i + μ_C·(C_i − C^offset), with aggregated secret w = μ_P·x + μ_C·z at index π. One ring over the W_i now binds both statements. The distinct prefixes (_0, _1) are domain separation — they prevent an attacker from making the two coefficients collide or cross-using a hash from elsewhere in the protocol.
The Round-Robin
CLSAG is a Schnorr-style ring built on a per-round challenge hash (with its own domain prefix, e.g. "CLSAG_round"). To sign at secret index π:
- Pick a random nonce
α. Compute the first challenge from commitments toα:c_{π+1} = Hs("CLSAG_round" ‖ {W} ‖ message ‖ αG ‖ α·Hp(P_π)). - For every decoy index
i(walkingπ+1, π+2, …around the ring) choose a random responses_iand derive the next challenge from points reconstructed usings_i,c_i, the aggregated keyW_i, and the key images:c_{i+1} = Hs("CLSAG_round" ‖ … ‖ s_iG − c_i·W_i ‖ s_i·Hp(P_i) − c_i·(μ_P·I + μ_C·D)). - Arriving back at
π, solve the one unknown response so the loop is consistent:s_π = α + c_π·w(modℓ) — using the real aggregated secretw. This is the only step that needs a private key; it makes the ring close.
The published signature is (c_1, s_0 … s_{n−1}, I, D). A verifier recomputes the whole loop and checks it closes to c_1. It closes only if the signer knew (x, z) for some member, but every s_i is uniformly random, so π is hidden.
What Auditors Watch For
- Domain separation: every hash that could be confused with another must carry a unique prefix. Reusing a hash across contexts is a classic break.
- Key-image validity:
I(andD) must be checked for prime-order membership — torsion would let an output produce multiple images. - Nonce hygiene:
αmust be uniformly random and never reused; a repeated nonce across signatures leaks the private key (the classic Schnorr/ECDSA failure). - Canonical encodings: non-canonical scalars/points must be rejected so two encodings can't both verify.
Next, the other big proof in every transaction — Bulletproofs+: The Weighted Inner-Product Argument.
Comments
Log in or create a free account to comment.
No comments yet — be the first.