Skip to main content

The Pasta Cycle of Curves

1. Why This Chapter Exists

Every field operation in Orchard happens in one of two prime fields, and every curve operation on one of two curves. Picking the wrong field on a single line silently corrupts the proof; the type system catches this only because pasta_curves distinguishes pallas::Base from pallas::Scalar at the type level. After this chapter the reader can read the type signatures of src/spec.rs and predict which field each variable lives in.

2. Definitions

Definition 2.1 (Cycle of Curves)

A pair of elliptic curves Ep/FpE_p / \mathbb{F}_p and Eq/FqE_q / \mathbb{F}_q over prime fields is a 2-cycle if

#Ep(Fp)=qand#Eq(Fq)=p.\#E_p(\mathbb{F}_p) = q \quad \text{and} \quad \#E_q(\mathbb{F}_q) = p.

The base field of one curve is then the scalar field of the other.

Definition 2.2 (Pasta Parameters)

The Pasta curves are defined by

p=0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001,q=0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001,\begin{aligned} p &= \mathtt{0x40000000000000000000000000000000\,224698fc094cf91b\,992d30ed00000001}, \\ q &= \mathtt{0x40000000000000000000000000000000\,224698fc0994a8dd\,8c46eb2100000001}, \end{aligned}

both 255-bit primes. Pallas is Ep:y2=x3+5E_p : y^2 = x^3 + 5 with order qq; Vesta is Eq:y2=x3+5E_q : y^2 = x^3 + 5 with order pp. Both have jj-invariant 00, which gives them an efficient endomorphism ϕ(x,y)=(ζx,y)\phi(x, y) = (\zeta x, y) with ζ\zeta a primitive cube root of unity.

Invariant 2.3 (Field Roles)

In Orchard:

  • Fp\mathbb{F}_p is the base field of Pallas. Note commitment outputs, nullifiers, anchors, and all "field-element-valued" hashes live in Fp\mathbb{F}_p.
  • Fq\mathbb{F}_q is the scalar field of Pallas. Spend authorising scalars (ask\mathsf{ask}, α\alpha, rcv\mathsf{rcv}, esk\mathsf{esk}) live in Fq\mathbb{F}_q.
  • Inside the Halo 2 circuit, polynomial identities are written over the Vesta scalar field, which is exactly Fp\mathbb{F}_p: the circuit and the Pallas base field share their type, which is why witness field elements assemble into Pallas points natively.

3. The Code

3.1 Where the Crate Imports Pasta

src/circuit.rs
loading...

pasta_curves::pallas exposes Base, Scalar, Point, Affine, and the hash-to-curve helpers. pasta_curves::vesta exposes the mirror types used by the IPA commitment scheme but is otherwise rarely visible.

3.2 Conversion Helpers

The spec-faithful field conversions live in src/spec.rs. to_base takes a 64-byte buffer (twice the field size) and reduces mod pp; to_scalar does the same mod qq. The 64-byte input lets the bias from naive mod p reduction be negligible (<2128< 2^{-128}).

3.3 The Endomorphism

The Pasta curves' j=0j = 0 form admits the endomorphism ϕ\phi above. halo2_gadgets uses GLV decomposition through this endomorphism in its ECC chip; the savings show up as fewer incomplete additions per scalar multiplication. The Orchard code does not invoke GLV directly but inherits the speed-up because the chip is loaded from halo2_gadgets.

3.4 Constant-Time Discipline

pasta_curves uses subtle primitives (Choice, CtOption, ConstantTimeEq) for every value-dependent branch in scalar multiplication and field inversion. The crate inherits this discipline transparently; see Chapter 15 (Dependencies).

4. Failure Modes

  • Field confusion. Computing [k]G[k] \mathcal{G} with k:pallas::Basek : \mathsf{pallas::Base} instead of k:pallas::Scalark : \mathsf{pallas::Scalar} is a type error in pasta_curves. PRs that work around this by calling to_scalar on the byte representation of a base-field element risk introducing a subtle reduction bias.
  • Identity points. Several Orchard operations require rkO\mathsf{rk} \neq \mathcal{O} (see #492). Failing to enforce non-identity in a constructor is a consensus bug: the verifier rejects, but a wallet can be tricked into building a bundle that no node will accept.
  • Endianness. pallas::Base::from_repr expects a little-endian 32-byte buffer. Test vectors from external sources sometimes arrive big-endian; reverse them before deserialisation.

5. Spec Pointers

6. Exercises

  1. Compute pmod4p \bmod 4 and qmod4q \bmod 4 from Definition 2.2 (a one-liner in any tool of your choice). State what this implies about quadratic residuosity of 1-1 in each field.
  2. Open src/circuit.rs and search for vesta::. Vesta appears in fewer than five places. Locate each one and explain in one sentence why Pallas dominates the file.
  3. Code task. Write a five-line Rust program that takes a random pallas::Scalar, multiplies a fixed pallas::Point by it, then prints the affine xx-coordinate. Verify that the coordinate type is pallas::Base. Commit nothing; this confirms the type-level distinction is real.

7. Further Reading

  • Halo 2 Book, Background: curve choice, GLV, the role of the endomorphism in scalar multiplication.
  • The pasta_curves README and the comments in src/arithmetic/curves.rs of that crate.