Field note
Poseidon2-M31: One Field-Native Sponge, Many Separated Meanings
Ordinary software treats a hash as a black-box byte function. A proof circuit must express every round as field arithmetic. Poseidon2 is designed for that environment: its permutation combines linear mixing with a small nonlinear S-box, avoiding the circuit cost of recreating a byte-oriented hash instruction by instruction.
The target pins a Poseidon2 instance over Mersenne-31 with width 16, exponent 5, eight external rounds, and the Architecture of Record's fixed internal-round constants. The exact constants, matrices, padding, rate/capacity split, and byte encoding are literal protocol data. Two implementations that “generate equivalent parameters” are not good enough if they produce different field elements.
A sponge, intuitively
A sponge owns a fixed-width state. It absorbs an input block into part of that state, permutes the whole state, repeats for the remaining blocks, then squeezes output. The rate is the part used for input and output. The capacity stays internal and supplies the security margin.
For PayMoney's payment commitment, width 16 splits into rate 8 and capacity 8. Eight M31 capacity elements provide about 248 capacity bits, giving an intended collision bound around 124 bits. That sits above the target STARK soundness level, so the commitment should not be the narrowest security margin.
Domain separation prevents semantic collisions
The same primitive derives resource commitments, nullifiers, values, account identifiers, authorization tags, kind identifiers, archive roots, and PayMoney payment facts. Each context begins with a fixed domain separator such as vault.cm.v1 or paymoney.payfact.v1.
Without domain separation, an input valid in one role might be replayed as an input in another. The separator makes “hash these bytes as a nullifier” a different function from “hash these bytes as a resource commitment,” even when the remaining data coincides.
Boundaries must be committed too
Concatenation is ambiguous: ab | c and a | bc are the same flat byte stream. That becomes a real attack when one range is an amount and another is a memo. A prover could slide a boundary while opening the same digest to a different parsed payment fact.
The PayMoney construction absorbs the number of ranges, each range index, each range length, the encoded data, and a fresh blinder. The encoding is prefix-free, so the same absorbed sequence cannot be re-partitioned into different fields. This is mandatory for the two-sided amount bound to mean anything.
One implementation twice
The commitment is computed inside the two-party TLS session and opened again inside the AIR. The two sides must agree at every partial block. Conformance vectors therefore test not only final digests but each boundary length and padding case. In cryptographic code, serialization is part of the primitive.