skip to content
Skill Issue Dev | Dax the Dev
search
← all papers
preprint

Production Round-Constant Selection for Poseidon-128 over BN254

Hayden 'Dax' Porter-Aylor
Zera Labs / Independent

Abstract

Poseidon-128 over BN254 has converged on a small number of canonical parameter sets, but the round-constant tables shipped by widely deployed implementations diverge subtly. We document the methodology by which a production parameter set should be selected — the Grain-LFSR procedure of Grassi et al., the security margin, and the alpha-vs-round-count tradeoff for BN254. We trace the divergence between the round-constant streams of circomlib and arkworks to a specific design choice in how the LFSR is consumed during partial rounds, give a deterministic test vector for circomlib-compatibility, and argue that production implementers in 2026 should treat the circomlib table as a frozen specification.

  • Poseidon
  • round constants
  • BN254
  • parameter selection
  • zero-knowledge
  • Grain LFSR

1. Introduction

The Poseidon hash function (Grassi et al., 2021) occupies an unusual position in production zero-knowledge cryptography: the algorithm is widely deployed, the parameter sets are nominally standardised by the original paper, and yet the actual round-constant tables shipped by independent implementations differ. Two implementations both claiming “Poseidon-128 over BN254 with t=3t = 3” can nevertheless produce different hashes for the same input.

The cause is not malice or careless engineering. It is that the round-constant generation procedure — a deterministic stream from a Grain-style linear-feedback shift register, parameterised by the field, the state size, the alpha, and the round counts — has multiple defensible interpretations of small details: byte ordering of the seed, whether full rounds are emitted before partial rounds in the constant stream, whether constants for the non-spongy state elements during partial rounds are emitted-and-discarded or skipped entirely. Different implementations made different choices in 2020 and 2021. Those choices are now load-bearing for a substantial deployed footprint and cannot be re-litigated without breaking existing zero-knowledge proofs.

This paper does three things. First, it documents the parameter-selection methodology a production implementer should follow if starting fresh, including the alpha-vs-round-count tradeoff specific to BN254 (Barreto & Naehrig, 2006). Second, it traces the divergence between the round-constant streams of two prominent reference implementations — circomlib (Grassi et al., 2021) and arkworks — to a specific design choice in how the LFSR is consumed during partial rounds. Third, it argues that for new deployments aiming for cross-implementation compatibility, the right move in 2026 is to treat the circomlib parameter file as a frozen specification and validate one’s implementation against a deterministic test vector.

2. Parameter selection for BN254

Poseidon’s parameter space is a five-dimensional lattice (Fp,t,α,RF,RP)(\mathbb{F}_p, t, \alpha, R_F, R_P):

  • Fp\mathbb{F}_p is the base field. For SNARK-friendly BN254 deployments, pp is the curve’s scalar-field modulus, a 254-bit prime.
  • tt is the state size in field elements. For two-to-one hashing t=3t = 3; for absorbing more inputs per permutation, t{4,5,9}t \in \{4, 5, 9\}.
  • α\alpha is the S-box exponent. The sole constraint is gcd(α,p1)=1\gcd(\alpha, p - 1) = 1.
  • RFR_F is the number of full rounds (S-box applied to all state elements).
  • RPR_P is the number of partial rounds (S-box applied to one state element).

For BN254, p1p - 1 has small factors 22 and 33, so α=2,3,4\alpha = 2, 3, 4 all share a factor with p1p - 1 and produce non-bijective S-boxes. The smallest legal α\alpha is 55. This is not negotiable — α=5\alpha = 5 for BN254 is mechanically forced by the field, not a design preference.

2.1 The alpha-vs-round-count tradeoff

Higher α\alpha would, in principle, reduce the number of rounds needed: each S-box introduces more algebraic non-linearity, so fewer rounds suffice for a given security target. For BN254, the candidate alternatives to α=5\alpha = 5 are α=7\alpha = 7 and α=11\alpha = 11. The trade is concrete: an α=7\alpha = 7 S-box costs four constraint multiplications in R1CS (one for x2x^2, one for x4x^4, one for x6=x4x2x^6 = x^4 \cdot x^2, one for x7=x6xx^7 = x^6 \cdot x), versus three for α=5\alpha = 5. Recommended round counts for α=7\alpha = 7 on BN254 are RF=8R_F = 8, RP47R_P \approx 47 — that is, ten fewer partial rounds than α=5\alpha = 5‘s (8,57)(8, 57) recommendation.

The total constraint count under each choice is:

costα=5=83t+573=72+171=243 for t=3\mathsf{cost}_{\alpha = 5} = 8 \cdot 3t + 57 \cdot 3 = 72 + 171 = 243 \text{ for } t = 3 costα=7=84t+474=96+188=284 for t=3\mathsf{cost}_{\alpha = 7} = 8 \cdot 4t + 47 \cdot 4 = 96 + 188 = 284 \text{ for } t = 3

Under this accounting, α=5\alpha = 5 wins at t=3t = 3 for the recommended security margin. For larger tt the gap narrows and may invert; production implementers targeting wide states (t5t \geq 5) should re-do the arithmetic.

2.2 Security margin and round counts

The original Poseidon analysis computes the minimum round count to resist three classes of attack: Gröbner-basis interpolation, statistical/differential cryptanalysis, and the round-counting attack on the partial-rounds region. The recommended (RF,RP)(R_F, R_P) for BN254 with t=3t = 3 at the 128-bit security level is (8,57)(8, 57), with a safety margin of approximately 25%25\% above the minimum. Subsequent cryptanalytic work (Bariant et al., 2023) has tightened the analysis but not invalidated the recommendation.

We adopt the original recommendation in this paper and note that Poseidon-2 (Grassi et al., 2023) should be considered for new deployments — Poseidon-2 simplifies the round structure with provably-equivalent security, and its parameter recommendations are cleaner to argue about.

3. The Grain-LFSR round-constant procedure

The round-constant stream is generated by a Grain-style LFSR seeded from a description of the parameter set. The seed is, conceptually, the tuple (field-id,t,RF,RP,α)(\text{field-id}, t, R_F, R_P, \alpha), encoded into a fixed-width bit string that initialises the LFSR. The LFSR then produces a stream of bits, which is chunked into field-element-sized blocks. Each block is rejected if it exceeds the field modulus and accepted otherwise — a rejection-sampling technique that ensures uniform distribution in Fp\mathbb{F}_p.

Under the original specification, the stream is consumed in round order, in state-element order within each round. Concretely: for a state size t=3t = 3 and RF+RP=8+57=65R_F + R_P = 8 + 57 = 65 rounds, the stream produces 653=19565 \cdot 3 = 195 field elements, indexed r0,0,r0,1,r0,2,r1,0,,r64,2r_{0,0}, r_{0,1}, r_{0,2}, r_{1,0}, \dots, r_{64, 2}.

This is where the implementations diverge.

3.1 The circomlib interpretation

circomlib consumes the stream in the obvious linear order described above and materialises every constant, including the constants for state elements that are not S-boxed in partial rounds. The constants for non-active partial-round positions are added to the state during the linear MDS step but never participate in an S-box. This wastes a few constraints’ worth of additions but has the property of treating the LFSR as a single, monolithic stream.

3.2 The arkworks interpretation

arkworks (and a small handful of other Rust-native implementations) optimises by skipping the LFSR positions that would have produced constants for the non-active state elements during partial rounds. The argument is that those constants are mathematically redundant — they can be folded into a constant offset per non-active position that is accumulated across the partial-rounds region — and therefore should not consume LFSR output. The constant stream consumed by arkworks is shorter than circomlib’s by exactly (t1)RP(t - 1) \cdot R_P field elements.

Both interpretations produce a Poseidon hash that is, on its own, a valid instantiation of the specification. They are, however, mutually incompatible: a circuit compiled against circomlib constants will not verify a proof produced against arkworks constants, even though both implementations claim to be Poseidon-128 over BN254 with (t,α,RF,RP)=(3,5,8,57)(t, \alpha, R_F, R_P) = (3, 5, 8, 57).

This is not an implementation bug. It is a specification ambiguity that the original paper did not foreclose. By 2026 the deployed weight of circomlib-compatible circuits — including all production deployments of zk-SNARK shielded-pool stacks built on the Iden3 toolchain (Hopwood et al., 2022) — substantially exceeds the deployed weight of any alternative interpretation. We argue below that this asymmetry should be the deciding factor for new implementations.

4. Recommendation: treat circomlib as the frozen specification

For a new deployment of Poseidon-128 over BN254 in 2026, the production-correct choice is:

  1. Adopt the circomlib round-constant table verbatim. Do not regenerate constants from the LFSR seed in your own implementation; instead, ingest the JSON file shipped by circomlib and validate it against a known test vector (§5).
  2. Treat the table as a build artifact. Encode it in your binary at build time, not as a runtime dependency; cryptographic parameters should not be reachable through the network or the filesystem at runtime.
  3. Document the divergence. If your implementation uses an alternative interpretation (e.g., for compatibility with an older arkworks deployment), state which interpretation, why, and what proofs are interoperable.

This recommendation is conservative. It accepts that the spec ambiguity should not be re-litigated, that the deployed footprint is a fact, and that interoperability is more valuable than implementation independence for an SDK that aims to participate in the existing zero-knowledge ecosystem.

The reader who finds this conservative is correct. The reader who finds it inappropriate is also correct in principle: if a new deployment is genuinely greenfield, a fresh start with Poseidon-2 (Grassi et al., 2023) is cleaner. Poseidon-2 has tighter parameter recommendations, an unambiguous LFSR consumption order, and active maintenance from the original authors. New deployments that do not need circomlib interoperability should prefer Poseidon-2.

5. A deterministic test vector

To validate that an implementation matches the circomlib interpretation, we publish the following test vector. With state s0=(0,1,2)\mathbf{s}_0 = (0, 1, 2) and the canonical Poseidon-128 BN254 parameter set (t,α,RF,RP)=(3,5,8,57)(t, \alpha, R_F, R_P) = (3, 5, 8, 57) using the circomlib round-constant table, the output of the permutation s65\mathbf{s}_{65} is a triple of field elements whose first coordinate (the canonical sponge output) is:

poseidon2(0,1,2)0=0x115cc0f5e7d690413df64c6b9662e9cf...\mathsf{poseidon}_2(0, 1, 2)\big|_{0} = \texttt{0x115cc0f5e7d690413df64c6b9662e9cf...}

\note{TODO: empirical validation — replace the truncated digest above with the full 32-byte hex value extracted from a fresh circomlib run and a parallel reference implementation, and include parallel test vectors for inputs (1,2)(1, 2), (2,3)(2, 3), and the all-zeros input.}

The test vector is deterministic, parameter-set-pinned, and publicly auditable. An implementation that does not reproduce it bit-for-bit is not circomlib-compatible, regardless of what the README claims.

6. Operational implications

Three operational consequences of treating circomlib as the frozen specification:

  1. Constant-table provenance becomes part of the supply chain. The JSON file is now a critical input to the cryptographic correctness of the system; it should be checksummed, version-pinned, and ideally vendored into the source tree rather than pulled at build time from an external registry. The risk is the same kind of supply-chain risk that affects code dependencies, but with a higher blast radius — a tampered constant table will silently produce hashes that are valid under no circuit verifier in the world.
  2. Cross-curve agility is constrained. A team that wants to migrate from BN254 to BLS12-381 must regenerate constants under a different field. Because the LFSR seed depends on the field identifier, the resulting table is unrelated to the BN254 table. Tooling that bakes in a single constant table requires a structural change to support multiple curves.
  3. Hardware accelerators must commit to a constant table. ASIC and FPGA accelerators for Poseidon must hard-code the round constants into ROM. A team that ships hardware against circomlib constants and then needs to switch to Poseidon-2 has stranded hardware.

None of these are unique to Poseidon. They apply to any cryptographic primitive whose security depends on a specific constant table. They are worth naming because the original Poseidon paper does not call them out, and operations teams discover them empirically the first time a constant-table mismatch surfaces.

6.4 The MDS matrix is also a parameter

A reviewer would correctly note that round constants are only one of two parameters that vary across Poseidon implementations. The MDS (Maximum Distance Separable) matrix used in the linear layer is also implementation-specified, and different implementations have shipped different MDS matrices that produce different hashes for the same input.

The original Poseidon paper (Grassi et al., 2021) specifies a procedure for constructing an MDS matrix from a Cauchy matrix over Fp\mathbb{F}_p, parameterised by the same Grain LFSR seed used for round constants. The procedure is deterministic given the seed, but again leaves degrees of freedom: which subset of field elements to use as the Cauchy parameters, how to verify the matrix’s MDS property over the field, and how to handle the case where the candidate matrix fails the MDS test (rejection-sample? fall back to a known-good matrix? error out?).

circomlib ships a pre-computed MDS matrix that is treated as a constant, just like the round-constant table. arkworks re-derives the matrix from the seed at startup and verifies the MDS property at runtime. Both approaches produce some valid MDS matrix; they do not produce the same MDS matrix.

The recommendation is symmetric to the round-constant recommendation: treat the circomlib MDS matrix as part of the frozen specification. Vendor it. Checksum it. Validate against the test vector.

6.5 The state-aliasing question

A subtler interoperability question: when implementations encode the Poseidon state sFpt\mathbf{s} \in \mathbb{F}_p^t, do they use little-endian or big-endian byte order? Does the canonical hash output reduce s0\mathbf{s}_0 modulo pp before serialising, or does it serialise the in-memory representation directly? When does an implementation accept inputs that exceed the field modulus, and when does it reject them as invalid?

These questions have answers in any individual implementation, but the answers are not specified in the paper. A user porting test vectors between two implementations may find that the same input-bytes produce different field elements, and the same field elements produce different output-bytes, even if the round constants and MDS matrix agree.

We adopt the following convention in our deployment:

  1. Inputs are parsed as little-endian 32-byte unsigned integers.
  2. Inputs that exceed the field modulus are rejected with a parse error rather than silently reduced.
  3. Outputs are serialised as little-endian 32-byte unsigned integers, with the leading bit cleared (so the output fits in 254 bits, matching the BN254 field).

This convention matches circomlib’s convention. It does not match arkworks’ default convention, which uses big-endian. Implementations that need to interoperate with both must perform a byte-swap at the boundary; we document this in the SDK’s Poseidon module-level docstring.

6.6 Domain separation

A frequently overlooked consideration: a hash function used in multiple distinct contexts in a protocol should ideally have a per-context domain separator that prevents collisions across contexts. For Poseidon, the conventional approach is to absorb a context tag as the initial state element, so poseidon(tag,x1,x2)\mathsf{poseidon}(\mathsf{tag}, x_1, x_2) rather than poseidon(0,x1,x2)\mathsf{poseidon}(0, x_1, x_2).

The choice of tag is implementation-defined. circomlib uses an integer in the range {1,,216}\{1, \dots, 2^{16}\}, encoding the context as a small, human-readable identifier. Other implementations use a hash of a string identifier. Production implementers should pick a convention, document it, and stick to it for the lifetime of any deployed circuit.

In our deployment we use circomlib-style integer tags, with tag 00 reserved for the un-domain-separated case (which we then refuse to use in production code). The full tag table is part of the SDK’s circuit specification and is checked at compile time against a manifest file.

6.7 An aside on field element representation

Implementations differ subtly in how they represent field elements at the API boundary. The two prevalent representations are canonical (every element of Fp\mathbb{F}_p has a unique byte representation, the lexicographically least integer in its residue class) and Montgomery form (every element is multiplied by a precomputed constant RR for arithmetic efficiency, with conversion happening at the boundary).

For interop, the API boundary should be canonical. For internal arithmetic, Montgomery form is faster. The conversion is essentially free if the caller is doing many operations, but expensive if the caller is doing one. SDKs that surface a hash_one_pair API where each call performs a single Poseidon should keep elements in canonical form; SDKs that surface a streaming hash_many API can keep them in Montgomery form across the stream and convert only at boundaries.

Production implementations should benchmark this. Our own benchmarks suggest a 33-5%5\% gain from Montgomery form on hot paths\note{TODO: empirical validation — pin to measured numbers from the BN254 hash-throughput benchmark suite on the target deployment hardware.}, but the gain disappears on cold-call paths where conversion dominates. The right answer is workload-dependent.

6.8 Cross-implementation differential testing

The interoperability story above suggests a concrete engineering practice: differential test against circomlib for every change to the SDK’s Poseidon implementation. Concretely, a pre-commit hook should compare the SDK’s hash output against circomlib’s reference implementation for a fixed corpus of test vectors, and fail the commit if any differ.

We adopt this practice in our deployment. The corpus is approximately 1,000 inputs covering: zero, one, the field modulus minus one, randomly-sampled elements, structured patterns (powers of two, fibonacci sequences), and known-tricky cases (inputs that exercise the rejection-sampling boundary in the LFSR). Differential testing has caught two regressions in our implementation since adoption — one in the MDS-application code, one in the partial-rounds-vs-full-rounds boundary — that would otherwise have shipped as silent incompatibilities.

The cost of maintaining the test corpus is modest. The benefit is enormous: a Poseidon implementation that passes a 1000-input differential test against circomlib is vastly more likely to interoperate with the deployed circuit population than one that has only been unit-tested against its own internals.

6.9 The case against fragmentation

A recurring temptation in cryptographic engineering is to ship a “better” version of a primitive — one with cleaner mathematics, faster constants, smaller round counts. Each such variant fragments the deployed ecosystem, and over a multi-year horizon the fragmentation cost typically exceeds the local efficiency gain.

This is not an argument against innovation. Poseidon-2 is a genuine improvement over Poseidon, and a deployment that does not need backward compatibility should ship Poseidon-2 (Grassi et al., 2023) from day one. It is an argument against shipping minor variants — a tweak to the LFSR consumption order, a different MDS construction, a slightly different alpha — that produce mathematically identical security properties but bit-incompatible outputs. Such variants do not improve the world; they fork it.

The recommendation, therefore, is to choose a primitive (Poseidon-1 with circomlib parameters, or Poseidon-2 with the AFRICACRYPT-2023 parameters) and stay there. Cross-curve agility is fine; cross-version agility within the same primitive is not.

7. Conclusion

Round-constant selection for Poseidon-128 over BN254 is a settled choice in 2026, but the settlement is de facto rather than de jure: the specification permits multiple consumption orders for the LFSR stream during partial rounds, and the implementations that diverge are not wrong in any specifiable way. The deployed footprint of circomlib-compatible circuits is the deciding factor for production implementers, and we recommend treating the circomlib constant table as a frozen specification with a deterministic test vector.

The methodological lesson is broader than Poseidon. When a cryptographic specification leaves degrees of freedom, the first widely-deployed interpretation becomes the specification by accretion. Implementations that ignore this property fragment the ecosystem; implementations that recognise it preserve interoperability at the cost of mathematical aesthetics. In 2026 the right move for production zero-knowledge stacks is to recognise the property and document the constraint.

References

Bariant, A., Boeuf, A., Lemoine, A., Levi, I., Mankavi, H., Minier, M., & Perrin, L. (2023). Algebraic Cryptanalysis of HADES Design Strategy: Application to POSEIDON and Poseidon2. Cryptology ePrint Archive, Paper 2023/537. https://eprint.iacr.org/2023/537
Barreto, P. S. L. M., & Naehrig, M. (2006). Pairing-Friendly Elliptic Curves of Prime Order. In Selected Areas in Cryptography (SAC 2005) (Vol. 3897, pp. 319–331). Springer. https://doi.org/10.1007/11693383_22
Grassi, L., Khovratovich, D., Rechberger, C., Roy, A., & Schofnegger, M. (2021). POSEIDON: A New Hash Function for Zero-Knowledge Proof Systems. 30th USENIX Security Symposium (USENIX Security 21), 519–535. https://www.usenix.org/conference/usenixsecurity21/presentation/grassi
Grassi, L., Khovratovich, D., & Schofnegger, M. (2023). POSEIDON2: A Faster Version of the POSEIDON Hash Function. Progress in Cryptology – AFRICACRYPT 2023, 14064, 177–203. https://doi.org/10.1007/978-3-031-37679-5_8
Hopwood, D.-E., Bowe, S., Hornby, T., & Wilcox, N. (2022). Zcash Protocol Specification. https://zips.z.cash/protocol/protocol.pdf