CLSAG: Exact Construction & Domain Separation

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 x with P_π = xG (you own the output), and
  • the blinding factor z of 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 π:

  1. Pick a random nonce α. Compute the first challenge from commitments to α: c_{π+1} = Hs("CLSAG_round" ‖ {W} ‖ message ‖ αG ‖ α·Hp(P_π)).
  2. For every decoy index i (walking π+1, π+2, … around the ring) choose a random response s_i and derive the next challenge from points reconstructed using s_i, c_i, the aggregated key W_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)).
  3. Arriving back at π, solve the one unknown response so the loop is consistent: s_π = α + c_π·w (mod ) — using the real aggregated secret w. 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 (and D) 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.