UPP — Universal Private PoolSTARK Vault

Field Arithmetic: M31 → CM31 → QM31

Deep dive into the Mersenne-31 field tower implementation in Solidity — M31 base field, CM31 complex extension, and QM31 quartic SecureField.

Overview

The Circle STARK verifier operates over a three-level algebraic extension tower built on the Mersenne-31 prime. This page covers the mathematical definitions, Solidity implementation details, packing conventions, and test vectors for each level.

All arithmetic is implemented in M31Lib.sol (311 lines).

1. M31 — The Base Field

Definition

Fp where p=2311=2,147,483,647\mathbb{F}_p \text{ where } p = 2^{31} - 1 = 2{,}147{,}483{,}647

This is the largest Mersenne prime that fits in 31 bits. Elements are integers in [0,p)[0, p).

Why Mersenne-31?

Mersenne primes enable shift-based modular reduction. For any product x=a×bx = a \times b (at most 62 bits):

xmod(2311)=(x31)+(x&(2311))x \bmod (2^{31} - 1) = (x \gg 31) + (x \mathbin{\&} (2^{31} - 1))

Proof: Write x=h231+x = h \cdot 2^{31} + \ell. Then x=h(p+1)+=hp+h+h+(modp)x = h \cdot (p+1) + \ell = h \cdot p + h + \ell \equiv h + \ell \pmod{p}.

The result may be p\geq p, requiring at most one subtraction. This is dramatically cheaper than general modular reduction.

Solidity Implementation

// M31 addition: single add + conditional subtract
function m31Add(uint32 a, uint32 b) internal pure returns (uint32) {
    uint256 sum = uint256(a) + uint256(b);
    if (sum >= P) sum -= P;
    return uint32(sum);
}

// M31 multiplication: Mersenne reduction
function m31Mul(uint32 a, uint32 b) internal pure returns (uint32) {
    uint256 product = uint256(a) * uint256(b);
    uint256 lo = product & P;     // low 31 bits
    uint256 hi = product >> 31;   // high bits
    uint256 r = lo + hi;
    if (r >= P) r -= P;
    return uint32(r);
}

// M31 inversion via Fermat: a^(p-2) mod p
function m31Inv(uint32 a) internal pure returns (uint32) {
    require(a != 0, "M31: division by zero");
    return m31Exp(a, P - 2);
}

Test Vectors

OperationInputResult
m31Add(P-1, 1)2147483646+12147483646 + 100
m31Add(P-1, P-1)2147483646+21474836462147483646 + 214748364621474836452147483645
m31Mul(2, 2)4444
m31Mul(P-1, P-1)(p1)2modp(p-1)^2 \bmod p11
m31Inv(2)2p2modp2^{p-2} \bmod p10737418241073741824

2. CM31 — Complex Extension

Definition

Fp2=Fp[i]  /  (i2+1)\mathbb{F}_{p^2} = \mathbb{F}_p[i] \;/\; (i^2 + 1)

Elements are a+bia + bi where a,bFpa, b \in \mathbb{F}_p and i2=1i^2 = -1.

This is the Gaussian integers modulo pp. The polynomial x2+1x^2 + 1 is irreducible over Fp\mathbb{F}_p because 1-1 is a quadratic non-residue modulo pp (since p3(mod4)p \equiv 3 \pmod 4).

Packing Convention

CM31 is packed into uint64:

  • Low 32 bits: real part (aa)
  • High 32 bits: imaginary part (bb)
function cm31Pack(uint32 real, uint32 imag) internal pure returns (uint64) {
    return uint64(real) | (uint64(imag) << 32);
}

Arithmetic

Multiplication: Standard complex multiplication

(a0+a1i)(b0+b1i)=(a0b0a1b1)+(a0b1+a1b0)i(a_0 + a_1 i)(b_0 + b_1 i) = (a_0 b_0 - a_1 b_1) + (a_0 b_1 + a_1 b_0)i

4 M31 multiplications + 1 addition + 1 subtraction.

Conjugation: (a+bi)(abi)(a + bi) \mapsto (a - bi). Negates only the imaginary part.

Inversion: Uses the norm identity

1a+bi=abia2+b2\frac{1}{a + bi} = \frac{a - bi}{a^2 + b^2}

cm31Neg vs cm31Conj

These are distinct operations:

  • cm31Neg(a + bi) = (a,b)(-a, -b) — negates both parts
  • cm31Conj(a + bi) = (a,b)(a, -b) — negates only imaginary

This distinction is critical for QM31 complex conjugation (see Section 3).

3. QM31 — Quartic Extension (SecureField)

Definition

Fp4=Fp2[u]  /  (u2(2+i))\mathbb{F}_{p^4} = \mathbb{F}_{p^2}[u] \;/\; (u^2 - (2 + i))

Elements are a+bua + bu where a,bFp2a, b \in \mathbb{F}_{p^2} (CM31) and u2=2+iu^2 = 2 + i.

QM31 is Stwo's SecureField — the field used for all random challenges, ensuring they are drawn from a space of size 2124\sim 2^{124}.

Packing Convention

QM31 is packed into uint128:

  • Low 64 bits: first CM31 component (aa)
  • High 64 bits: second CM31 component (bb)

Which expands to four M31 values:

  • Bits [0..31]: m0m_0 (real part of aa)
  • Bits [32..63]: m1m_1 (imaginary part of aa)
  • Bits [64..95]: m2m_2 (real part of bb)
  • Bits [96..127]: m3m_3 (imaginary part of bb)

Complex Conjugation

Bug Alert: Common Mistake

The initial implementation performed element-wise CM31 conjugation: (m0,m1,m2,m3)(m_0, -m_1, m_2, -m_3). This is incorrect.

Stwo defines complex conjugation for QM31 as negating the entire second CM31:

For q=(m0,m1,m2,m3)q = (m_0, m_1, m_2, m_3):

OperationResultDescription
QM31 conjugate (correct)(m0,m1,m2,m3)(m_0, m_1, -m_2, -m_3)Negate entire second CM31
CM31 conjugate on each half (wrong)(m0,m1,m2,m3)(m_0, -m_1, m_2, -m_3)Negate imaginary of each CM31
function _conjQ(uint128 q) internal pure returns (uint128) {
    return M31Lib.qm31Pack(
        M31Lib.qm31First(q),                      // Keep first CM31 unchanged
        M31Lib.cm31Neg(M31Lib.qm31Second(q))       // Negate ENTIRE second CM31
    );
}

This matters because the complex conjugate appears in every DEEP quotient line equation — a wrong conjugate corrupts the entire FRI input.

4. Circle Point Arithmetic

Group Operation

(x1,y1)(x2,y2)=(x1x2y1y2,  x1y2+y1x2)(x_1, y_1) \circ (x_2, y_2) = (x_1 x_2 - y_1 y_2, \; x_1 y_2 + y_1 x_2)

The identity is (1,0)(1, 0). The generator is G=(2,1268011823)G = (2, 1268011823) with G=231=p+1|G| = 2^{31} = p + 1.

Doubling (x-coordinate only)

For FRI line domains, only the x-coordinate after doubling is needed:

doublex(x)=2x21\text{double}_x(x) = 2x^2 - 1

5. Gas Costs

OperationGasNotes
M31 add/sub~30Single conditional branch
M31 mul~50Mersenne reduction
M31 inv~4,00031 iterations of square-and-multiply
CM31 mul~2504 M31 muls + 2 M31 adds
CM31 inv~5,0002 M31 muls + 1 M31 inv
QM31 mul~1,2004 CM31 muls + CM31-by-R + 2 CM31 adds
QM31 inv~7,0002 CM31 muls + 1 CM31 inv + 1 CM31 neg
Circle point add~3004 M31 muls + 1 M31 add + 1 M31 sub
Circle scalar mul (31-bit)~10,000~31 iterations of add + double

QM31 multiplication is the dominant cost in the verifier — it appears in every quotient accumulation and every FRI fold.

On this page