Ragu & Tachyon
Home
  • Scaling Zcash
  • An Introduction to Proof-Carrying Data
  • Statements and Challenges
  • Arithmetization
  • QAP and Polynomial Encoding
  • Polynomial Commitments
  • The Inner Product Argument
  • Batched Openings
  • The Complete Proof
  • Recursive Proofs
  • Accumulation
  • Split Accumulation
  • Curve Cycles
  • Revdot Folding
  • Wiring and the Registry
  • Endoscalars
  • Staging
  • Recursion in Ragu
  • Notes, Nullifiers, and Tachygrams
  • Pool State and Anchors
  • Oblivious Sync
  • The Proof Tree
  • Aggregation and Bundles
Final Recap
  • Notation
  • Glossary
  • Curves
Home
  • Scaling Zcash
  • An Introduction to Proof-Carrying Data
  • Statements and Challenges
  • Arithmetization
  • QAP and Polynomial Encoding
  • Polynomial Commitments
  • The Inner Product Argument
  • Batched Openings
  • The Complete Proof
  • Recursive Proofs
  • Accumulation
  • Split Accumulation
  • Curve Cycles
  • Revdot Folding
  • Wiring and the Registry
  • Endoscalars
  • Staging
  • Recursion in Ragu
  • Notes, Nullifiers, and Tachygrams
  • Pool State and Anchors
  • Oblivious Sync
  • The Proof Tree
  • Aggregation and Bundles
Final Recap
  • Notation
  • Glossary
  • Curves
  • Scaling Zcash
  • An Introduction to Proof-Carrying Data
  • Statements and Challenges
  • Arithmetization
  • QAP and Polynomial Encoding
  • Polynomial Commitments
  • The Inner Product Argument
  • Batched Openings
  • The Complete Proof
  • Recursive Proofs
  • Accumulation
  • Split Accumulation
  • Curve Cycles
  • Revdot Folding
  • Wiring and the Registry
  • Endoscalars
  • Staging
  • Recursion in Ragu
  • Notes, Nullifiers, and Tachygrams
  • Pool State and Anchors
  • Oblivious Sync
  • The Proof Tree
  • Aggregation and Bundles
  • Final Recap
  • Appendix

    • Notation
    • Glossary
    • Curves

Endoscalars

The curve cycles chapter left a promise open. It split each fold between two circuits and let one transcript supply the challenges for both. In its toy run the challenges crossed between the circuits as small integers, and the secondary circuit used them in plain double-and-add. That chapter also noted that Ragu's code does something else, because in the code a short value maps to a scalar that is not the plain integer.

This chapter supplies that map. We start from a symmetry of the curves that makes one particular large scalar free to apply, and we build a way of reading a short bit string that uses this symmetry at every step. The same string then acts as one scalar in each field of the cycle, which is what lets a challenge cross. After that we count the gates, show why distinct strings stay distinct on Pasta and fail to on the toy curves, and rerun the fold from Chapter 13 with the real map.

Reconstructed from code at commit 3219e08, not confirmed by the authors

The radix-3 encoding, its cost and its injectivity argument come from the Ragu Book and the code, and our script reruns them. The toy fold in Sections 10 and 11 is our own small assembly of how the code uses them. Its width of 5 bits has no counterpart in Ragu.

Terminology

An endoscalar is the bit string itself, which the book writes s^. We write ℓ for its length, 143 in Ragu, because λ has another job in this chapter. Endoscaling means multiplying a point by the string. Lifting means computing the scalar that the string stands for in a given field. We print bit strings with the first bit on the left, and the first bit is the least significant, as in the code. We keep the names from Chapter 13, so the native side has wires in Fp​ and the nested side has wires in Fq​, and the toy cycle has F43​ and F31​ in those roles.

1. What the plain integer costs

A short integer does fit in both fields, so the plain approach of Chapter 13 can work in principle. Its trouble is the price. A fuse has to fold about a hundred commitments on each side, each fold multiplies a point by the challenge, and a Ragu circuit holds only 211 gates. The double-and-add from the recursive proofs chapter spends about ten gates on every bit, so one multiplication by a challenge of 143 bits would fill most of a circuit.

The way to reduce that price is to get several bits of scalar out of each point addition, and this needs a supply of multiples of the base point that cost nothing to compute. Curves of the form y2=x3+b have such a supply. Using it gives up the plain integer, though, so we then have to check that the circuits still agree on what the string means.

2. The curve's endomorphism

The equation y2=x3+b sees x only through its cube. So if ζ is a cube root of 1 in the coordinate field, then replacing x with ζx leaves the equation unchanged, and the map

ϕ(x,y)=(ζx,y)

sends points of the curve to points of the curve. A cube root other than 1 exists when the field size is 1 modulo 3, which holds for both toy fields and both Pasta fields.

The cube roots of 1 in F31​ are 1, 5 and 25, since 53=125=4⋅31+1 and 25=52. We take ζ=5. The generator G0​=(1,2) maps to ϕ(G0​)=(5,2), and this image is on E, because 22=4 and 53+3=128, which equals 4 modulo 31.

To be useful for scalar multiplication, the map has to respect addition. We can check this on the addition formula. For points with x1​=x2​, the sum has slope s=(y2​−y1​)/(x2​−x1​), with x3​=s2−x1​−x2​ and y3​=s(x1​−x3​)−y1​. Apply ϕ to both inputs. The new slope is

s′=ζx2​−ζx1​y2​−y1​​=ζs​.

Since ζ3=1, we have 1/ζ2=ζ, and the new x-coordinate is

s′2−ζx1​−ζx2​=ζ2s2​−ζ(x1​+x2​)=ζ(s2−x1​−x2​)=ζx3​.

The new y-coordinate is

ζs​(ζx1​−ζx3​)−y1​=s(x1​−x3​)−y1​=y3​.

So ϕ(A)+ϕ(B)=(ζx3​,y3​)=ϕ(A+B). The tangent slope for doubling becomes 3ζ2x2/(2y)=s/ζ too, because ζ2=1/ζ, and the same two lines then cover doubling. A map from a group to itself that respects the operation is called an endomorphism.

Take A=(27,30) and B=(6,23) from chapter 08. Their sum is (5,29), which maps to (25,29). Mapping first gives ϕ(A)=(11,30) and ϕ(B)=(30,23), and these add to (25,29). We confirmed the identity on all 1,764 ordered pairs of affine points of E.

Now we use the fact that our curves have prime order. Every point is a multiple of one generator T0​, and ϕ(T0​) is some multiple λ⋅T0​. For any other point a⋅T0​, respecting addition gives

ϕ(a⋅T0​)=a⋅ϕ(T0​)=aλ⋅T0​=λ⋅(a⋅T0​).

So ϕ multiplies every point by one scalar λ, which we call its eigenvalue. Applying ϕ three times multiplies x by ζ3=1, so λ3=1 in the scalar field. Since ϕ is not the identity map, λ=1, and dividing λ3−1=(λ−1)(λ2+λ+1) by the first factor leaves

λ2+λ+1=0.

Point Tϕ(T)Multiple of T that equals ϕ(T)
G0​=(1,2)(5,2)6
G1​=(6,8)(30,8)6
G2​=(11,1)(24,1)6
G3​=(17,7)(23,7)6

Every row gives the same multiple, and the same holds for all 42 affine points. So on E with ζ=5 we have λ=6, and indeed 62+6+1=43=1⋅43.

This gives us what Section 1 asked for, since a circuit can compute a large multiple of a point at almost no cost:

Computing 6⋅G0​ by the double-and-add of the recursive proofs chapter would take 21 gates for a 3-bit scalar, while ϕ(G0​) takes no gates, because multiplying a wire by the constant 5 is part of a linear combination. The contrast is sharper on Pasta, where λ is a scalar of about 251 bits, and a multiplication by it would cost about 2,501 gates with the same method.

Negation is free as well, because it only flips the sign of y. So from one point we get the six multiples ±1, ±λ, ±λ2 with no gates beyond selecting among them.

3. One constant for each field

Each field has two cube roots other than 1, and the choice of ζ decides which root of the scalar field is the eigenvalue. Here are all the choices on the toy cycle:

CurveCoordinate fieldζScalar fieldλ
EF31​5F43​6
EF31​25F43​36
E′F43​6F31​5
E′F43​36F31​25

A circuit needs ζ on the coordinates of its curve, and it also needs λ when it does field arithmetic with the same challenge. On a cycle these two roles fall on the same field, because the coordinate field of one curve is the scalar field of the other. Ragu therefore keeps one constant per field, called ZETA, and uses it for both roles. That only works if the choices line up on both curves, and being a cube root other than 1 does not by itself decide this.

The table shows that the toy cycle has such a choice. We take the constant 5 for F31​ and the constant 6 for F43​, so that each is the coordinate constant of its own curve and the eigenvalue on the partner curve.

On Pasta, we tested this pair, taken from the pasta_curves crate:

ζp​ζq​​=0x12ccca834acdba712caad5dc57aab1b01d1f8bd237ad31491dad5ebdfdfe4ab9,=0x06819a58283e528e511db4d81cf70f5a0fed467d47c033af2aa9d2e050aa0e4f.​

We multiplied the point (−1,2) of Pallas by ζq​ and got (−ζp​,2), and we multiplied the point (−1,2) of Vesta by ζp​ and got (−ζq​,2). Replacing ζp​ with its square while ζq​ stays the same makes the first test fail.

Ragu reads its constants from a dependency, zakura-udon, which computes them with a macro that we did not evaluate. Ragu's consistency test checks the pairing on both curves. The other consistent pair, the squares of these two, passes our test as well.

4. Elements with two images

We now need a way to talk about a combination such as a⋅T+b⋅ϕ(T) without saying which curve T lies on. Treat λ as a formal symbol that obeys λ2=−1−λ, and work with pairs a+bλ of integers. These form a ring called Z[λ], the Eisenstein integers. Products follow from the rule for λ2:

(a+bλ)(c+dλ)=ac+(ad+bc)λ+bdλ2=(ac−bd)+(ad+bc−bd)λ.

An element of this ring acts on a point of either curve, and replacing the symbol with the curve's eigenvalue gives the same result as a scalar:

Take 3+2λ. With λ=6 it maps to 3+2⋅6=15 in F43​, and with λ=5 it maps to 3+2⋅5=13 in F31​. Applied to G0​ on E, the element means 3⋅G0​+2⋅ϕ(G0​)=(11,30), and 15⋅G0​ is the same point. Applied to G′=(32,3) on E′, it means 3⋅G′+2⋅ϕ(G′)=(40,18), and 13⋅G′ is the same point.

The rest of the chapter builds on this fact. One element of Z[λ] has an image in each scalar field, and both images are computed by the same rule from the same pair of integers.

We also need to know when an element has image zero, since that decides when two different elements become the same scalar. The tool is the norm,

N(a+bλ)=a2−ab+b2.

It equals the squared absolute value of a+bλ when we read λ as the complex number e2πi/3, so it is never negative, it is zero only for the zero element, and the triangle inequality applies to its square root.

Suppose a+bλ maps to zero modulo a prime q, where λ now stands for a root in Fq​. Then a≡−bλ, and substituting into the norm gives

N(a+bλ)≡b2λ2+b2λ+b2=b2(λ2+λ+1)≡0(modq).

So the image can be zero only if q divides the norm. In particular, a nonzero element whose norm is below q cannot map to zero:

The element 5−λ has norm 25+5+1=31. With λ=5 it maps to 0 in F31​, while in F43​ it maps to 42. The element 1+7λ has norm 1−7+49=43, and it maps to 0 in F43​ and to 5 in F31​. We searched all coefficients from −40 to 40. Each of the 210 nonzero elements that map to 0 in F31​ has a norm divisible by 31, and each of the 152 that map to 0 in F43​ has a norm divisible by 43.

5. Reading a string as an element

We want a rule that reads bits into an element, using only cheap multiples, with a large number of bits per point addition. Suppose we walk the accumulator by repeated multiplication by a radix m, adding one digit multiple of the base point at each stage. The cleanest way to read the result back is to recognize the last digit from the residue of the element modulo m, and then repeat on what remains. So we look for a digit set with one digit for each nonzero residue.

The ring modulo 3 has nine residue classes, because a and b each have three residues. So a tripling walk can use eight nonzero digits, which is three bits for each tripling. The six free multiples fill six classes, and ±(1−λ) fills the other two:

(s,e1​,e2​)DigitAs (a,b)Modulo 3Norm
(0,0,0)1(1, 0)(1, 0)1
(1,0,0)−1(−1, 0)(2, 0)1
(0,1,0)λ(0, 1)(0, 1)1
(1,1,0)−λ(0, −1)(0, 2)1
(0,0,1)λ2(−1, −1)(2, 2)1
(1,0,1)−λ2(1, 1)(1, 1)1
(0,1,1)1−λ(1, −1)(1, 2)3
(1,1,1)−(1−λ)(−1, 1)(2, 1)3

The last two rows are not free multiples, but Section 7 shows that they still cost little. Halo's original walk uses doubling, with the digits ±1,±λ, which gives two bits for each doubling. A doubling walk cannot also use ±λ2, since the ring modulo 2 has only four classes and the extra digits let two strings reach one element:

For instance, 2⋅1+λ and 2⋅(−λ2)+(−λ) are both 2+λ, because −λ2=1+λ.

The layout in group_scale then reads as follows. Bits 0 and 1 are (s0​,e0​), and each later group of three bits is one digit (s,e1​,e2​) from the table. On a base point T, with n digits, the walk is

A0​=2⋅(−1)s0​ϕe0​(T),Ai+1​=3⋅Ai​+di​⋅T.

Expanding the recurrence shows which element the string names:

k=2⋅3n(−1)s0​λe0​+i=0∑n−1​3n−1−idi​.

Ragu uses n=47, and 2+3⋅47=143 accounts for the width. The doubling at the start uses the two leftover bits, and Section 8 shows why it also matters that A0​ is more than a single unit.

Because each digit has its own residue, the element determines the string. Here is the decoding on a small case:

Take the 11-bit string 01011100110, which has three digits. Its first two bits say s0​=0 and e0​=1, its digits are 1−λ, −1 and −λ, and Horner gives k=6+44λ. Starting from k alone, we read the last digit from its residue modulo 3, subtract it, and divide by 3:

Current valueModulo 3Digit it must end inAfter subtracting and dividing by 3
6+44λ(0, 2)−λ2+15λ
2+15λ(2, 0)−11+5λ
1+5λ(1, 2)1−λ2λ

The value that remains is 2λ, which is 2⋅(λ), so the first two bits are s0​=0 and e0​=1. The string comes back in full.

Every step of that decoding is forced, so two strings cannot name the same element of the ring:

We enumerated every string for n from 0 to 4, which at n=4 means 16,384 strings, and no two gave the same element of Z[λ].

6. One string, two scalars

Our toy endoscalar has one digit and therefore 5 bits. The lift function computes the element's image in a chosen field, by running the Horner form of the formula above with that field's ZETA.

Take the string 11111. Its first two bits are s0​=1 and e0​=1, so the initial unit is −λ. The remaining three bits are (s,e1​,e2​)=(1,1,1), so the digit is −(1−λ). The element is

k=2⋅3⋅(−λ)−(1−λ)=−6λ−1+λ=−1−5λ.

With λ=6 this is 12 in F43​, and with λ=5 it is 5 in F31​. As an integer, the string is 31, and neither scalar has any simple relation to that number.

A few more strings show that the two scalars vary independently of each other and of the integer:

StringAs an integerElementScalar in F43​Scalar in F31​
1100031−6λ82
1101011−5λ136
1011013−6−λ3120
00101207+λ1312
01011261+5λ3126
1111131−1−5λ125

Endoscaling a point by this string means running the walk with ϕ and the digit multiples. It needs no knowledge of λ or of the scalar field, because the circuit only computes with coordinates. The result is still the multiple that the lift predicts, on each curve:

CurveBase pointA0​3⋅A0​Digit pointA1​Direct multiple that equals A1​
EG0​ =(1,2)(18,21)(25,29)(26,8)(18,10)12
E′G′ =(32,3)(13,22)(32,3)(2,31)(20,3)5

Both rows end at the multiple the lift predicts. On E′ the tripled point returns to G′ itself, because A0​ has index −2λ and 3⋅(−2⋅5)=−30, which is 1 modulo 31.

This matches the book's consistency property, and we can now say why a challenge can cross the cycle. Look at the two uses of each scalar. The scalar β in F43​ scales polynomials over F43​, whose commitments lie on E. A circuit over F43​ computes β directly by lifting, and it uses the result to fold values. A circuit over F31​ cannot hold β, but it does not need to, since it walks points of E by the bits, and the walk acts as β. The other pair works the same way in the opposite direction:

A bit string maps to one element of the ring, which maps to a scalar in each field. Each scalar is computed by lifting in the circuit over its own field, and it acts through a walk in the circuit over the other field.

The bits are all that the two circuits share, and a bit is 0 or 1 in any field. Neither circuit ever handles a number from the other's field.

The same equality holds at full size. We ran it with Ragu's own test value:

The code's consistency test uses the endoscalar 206786806484900909362154774549736492353. Our Python lift sends it to a scalar beginning 0x2d3c28380a8fb270... in Fq​ and a scalar beginning 0x26ea1541fb5a78a6... in Fp​. The walk on (−1,2) on Pallas, in gates over Fp​, gives the same point as a direct multiplication by the first, and the walk on (−1,2) on Vesta, in gates over Fq​, gives the same point as a direct multiplication by the second. Each walk took 480 gates.

7. The walk in gates

Now we count, using the gates from the recursive proofs chapter, where a gate is one multiplication and a division counts as one multiplication checked backwards. A digit step has two parts, which are picking the digit's point and computing 3⋅A+D.

Tripling and adding

Done naively, 3⋅A+D=((A+D)+A)+A is three additions at three gates each, or nine gates. Two of those gates compute y-coordinates of intermediate points that are never kept, so we try to remove them. Write A=(x,y). The first addition has slope t1​, with x1​=t12​−x−xD​ and y1​=t1​(x−x1​)−y. The second addition has slope

t2​=x1​−xy1​−y​=x1​−xt1​(x−x1​)−2y​=−t1​−x1​−x2y​.

So y1​ has disappeared, and the slope equation becomes (t1​+t2​)(x1​−x)=−2y. The third addition follows in the same way, and only its output needs a y-coordinate. The code ends up with seven gates.

Picking the digit

Choosing among eight points would normally cost gates for each coordinate of each option, and the base point's coordinates are arbitrary wires. The code avoids this by first moving the point to a curve where its two coordinates are equal. The map (x,y)↦(c2x,c3y) takes y2=x3+b to y2=x3+c6b, for any nonzero c. Choosing c=x/y makes both new coordinates equal to r=x3/y2, and the addition formulas never read b, so the walk can run on the new curve and move back at the end.

For G0​=(1,2) on E, we get c=1/2=16 and r=c2x=8. The new curve has constant c6⋅3=17, and (r,r)=(8,8) lies on it because 82=2 and 83+17=2 modulo 31.

On this curve the base point is (r,r), so its free multiples are (r,r), (ζr,r) and (ζ2r,r). For the fourth digit we add (r,r) and −ϕ(r,r)=(ζr,−r). The slope is the constant s=−2r/(ζr−r)=−2/(ζ−1). From ζ2+ζ+1=0 we get (ζ−1)2=−3ζ and 1/(ζ−1)=(ζ2−1)/3, so the x-coordinate is

s2−r−ζr=−3ζ4​+ζ2r=ζ2(r−34​).

The y-coordinate is s(r−x)−r. Expanding with s=−32​(ζ2−1) and using ζ4=ζ gives

y=−2ζ2r−r−98​(ζ−ζ2)=(1+2ζ)(r−98​),

where the last step uses −2ζ2−1=1+2ζ and ζ−ζ2=1+2ζ. All four digits therefore have coordinates that are affine in r:

(e1​,e2​)DigitxyAt r=8
(0,0)1rr(8,8)
(1,0)λζrr(9,8)
(0,1)λ2ζ2rr(14,8)
(1,1)1−λζ2(r−4/3)(1+2ζ)(r−8/9)(22,30)

Since each coordinate is r times a constant, plus a constant, a selection needs only one product with r per coordinate once the bits have been combined. Writing p=e1​e2​ and q=ps, we can read off an interpolation from the table:

xD​yD​​=r(1+(ζ−1)e1​+(ζ2−1)e2​+(1−ζ)p)−34​ζ2p,=r((1−2s)+2ζ(p−2q))−98​(1+2ζ)(p−2q).​

For e1​=e2​=1 the first line gives ζ2r−34​ζ2, and the second gives (1−2s)(1+2ζ)(r−98​), as the table requires. The products p and q would cost gates of their own. The plain gadget instead factors the selection so that it takes three gates in total, which we use here without deriving it:

We compared both selectors with direct point arithmetic for all eight digits at every affine point of both curves, which makes 576 comparisons, and they all agreed.

One digit step

Here is the tripling on the normalized curve:

Here is the digit step for our string on G0​. The normalized accumulator is A0​=(20,22) and the digit point is D=(22,1).

GateEquationValue
1t1​(xD​−x)=yD​−yt1​=5
2x1​=t12​−x−xD​x1​=14
3(t1​+t2​)(x1​−x)=−2yt2​=23
4x2​=t22​−x1​−xx2​=30
5(t2​+t3​)(x2​−x)=−2yt3​=16
6x3​=t32​−x2​−xx3​=20
7y3​=t3​(x−x3​)−yy3​=9

So the result on the normalized curve is (20,9), which three additions outside the circuit confirm. Dividing by c2=8 and c3=4 gives (18,10), and that is 12⋅G0​. The tracer counted 20 gates, namely 3 to normalize, 4 for the doubling, 10 for the digit and 3 to move back.

The start of the walk is cheap for a related reason. The tangent at (r,r) has slope 3r2/(2r)=3r/2, which is linear in r. Then two gates compute the doubled point and two more apply the sign and the twist. With 47 digits, the total is 3+4+10⋅47+3 gates.

Sharing the products

A fuse walks many points by one string, so each of those walks repeats the same products e1​e2​ and e1​e2​s. Ragu hoists them into a stage that the walk circuits share, and one circuit checks them once. Each digit then needs only the two products with r from the equations above, which saves one gate per digit. Here are the costs together:

MethodBitsGatesGates per bit
Double-and-add from Chapter 102552,5419.96
Double-and-add from Chapter 101431,4219.94
Radix 2 with the endomorphism, the book's figure1284553.55
Radix 3, plain selector1434803.36
Radix 3, hoisted selector1434333.03

The last two rows come from running our tracer on the point (−1,2) of Vesta with a 143-bit string, where it counted 480 and 433 gates and the result matched a direct multiplication by the lifted scalar. A circuit has 211=2,048 gates, so it holds 1 double-and-add multiplication or 4 hoisted walks.

The hoisted count fits the limit of four endoscalings per circuit that Chapter 13 mentioned.

8. Why distinct strings stay distinct

Section 5 showed that strings name distinct elements of the ring, but the circuits work in the fields, and a nonzero ring element can have image zero there. Section 4 tells us when this can happen, so we bound the norm of a difference.

Take two strings and subtract their elements:

k−k′=2⋅3n(u−u′)+i=0∑n−1​3n−1−i(di​−di′​),

where u and u′ are the initial units. Units have absolute value 1, so 2∣u−u′∣≤4, and digits have absolute value at most 3​, so ∣di​−di′​∣≤23​. Weakening the 4 to 43​ gives a tidier result, and the geometric sum ∑3n−1−i=(3n−1)/2 takes care of the rest:

∣k−k′∣≤43​⋅3n+23​⋅23n−1​=3​(5⋅3n−1).

Squaring gives the book's bound on the norm, N(k−k′)≤3(5⋅3n−1)2. The book states the bound without these steps, so the derivation is ours. If the bound is below the field size, the difference cannot have image zero, because of the divisibility rule in Section 4.

With 47 digits the bound is 3(5⋅347−1)2, which is about 2155.2, and the Pasta group orders are about 2254. A nonzero difference therefore cannot have a norm divisible by either order, and the 143-bit strings stay distinct in both fields.

The toy curves are far too small for this, and that makes them a useful illustration of what the bound prevents:

With one digit the bound is 3(5⋅3−1)2=588, and the largest norm that actually occurs among differences of our 32 strings is 228. Both exceed 31 and 43, so the argument does not apply on the toy curves.

The 32 strings reach 21 different scalars in F43​ and 21 in F31​. For one clash, the strings 00000 and 11101 give the elements 7 and 1−5λ, whose difference 6+5λ has norm 31, a multiple of 31. Both map to 7 in F31​.

There is also a second use of the norm. The walk uses incomplete additions, which divide by a difference of x-coordinates and so fail if the two inputs are equal or opposite. Let the accumulator have index a and the digit have index d. The three additions need a=±d, then 2a+d=0 and d=0, and then 3a+d=0 and a+d=0. Each accumulator has absolute value at least 2 because of the initial doubling, and each later one is ∣3a+d∣≥3∣a∣−3​>∣a∣, while digits have absolute value at most 3​. So none of these combinations is zero in the ring. Their norms are again below the Pasta group orders, so none has image zero, and the circuit does not need to check these denominators at all. The walk relies on this by using an unchecked bank. On the toy curves the argument does not apply, and we can watch it fail:

We ran all 32 strings on every affine point of both curves, which makes 2,304 walks. Every walk that finished gave the point the lift predicts. On E, 4 strings failed with equal x-coordinates in an addition, and on E′, 6 failed. One failure on E′ is the string 00011, with A0​=2⋅T and digit 1−λ. After the first addition the accumulator is A0​+D, and adding A0​ again would give the index 2⋅2+(1−λ)=5−λ, the norm-31 element from Section 4, which is the identity on E′.

The same reasoning needs a base point with nonzero coordinates, since normalization divides by y and by powers of c. A curve of prime order larger than 3 has no point with y=0, which would have order 2, and none with x=0, which would have order 3.

9. Extracting bits from a challenge

A transcript produces a field element, and the circuit needs its bits. A field element does not always have a unique bit decomposition inside a circuit, because a circuit checks ∑i​2ibi​=v modulo the field size. If the bits have enough room to exceed the field size, a prover can choose between spellings:

In F43​ a 6-bit string can name values up to 63, so 21 field elements have two spellings, one of them the value plus 43. The element 5 can be written as 101000 or as 000011, which is 48=5+43. These spellings have different low bits, 10100 and 00001, so they would name two different endoscalars. If we require the top bit to be 0, each of the 32 elements below 25 has one spelling, and the 11 elements from 32 to 42 have none and are rejected.

Ragu therefore requires the value to fit below 2CAPACITY, the largest power of 2 below the field size, and then takes the low 143 bits of the unique spelling. Extraction also gives the right distribution:

Both Pasta primes lie just above 2254, so the capacity is 254 bits. The rejected values make up about 2−128.9 of Fp​ and about 2−128.9 of Fq​, which is the figure of about 2−129 in the source. Each 143-bit string has exactly 2111 in-range values above it, so a uniform in-range value gives a uniform string.

An honest prover almost never meets a rejected value. The grinding that Chapter 03 mentioned deals with the rare case for pre_beta, the last challenge of the transcript and the one that becomes β. There the prover re-randomizes the eval commitment and squeezes again until the value is in range.

10. Folding with an endoscalar

Now we can rerun the fold of Chapter 13 with the real map. Before doing so, we should separate the challenges that act on foreign points from those that do not. In the fold on the first side, the values α and u only enter the computation of v, which is native to the circuit that folds values. Only β also scales commitments, so only β has to be applied through a walk. The code matches this on the native side, where it uses α and u as full field elements.

The nested accumulator needs challenges of its own in F31​, and it gets them by lifting the low bits of each native challenge. The nested α′ has no numeric relation to the native α, and it does not need one, since the two batch different polynomials. For β both sides lift the same string.

We keep Chapter 13's claims, namely p0​, p1​ on E and p0′​, p1′​ on E′. Section 8 showed that some toy strings hit an exceptional addition, so we picked a pre_beta whose walks all finish. Pasta needs no such choice.

Let the transcript give α=11, u=13 and pre_beta =31 in F43​, all below 32. The circuit over F43​ uses α and u as they are, and it lifts pre_beta to β=12. The circuit over F31​ uses only lifts of the same bit strings, which are α′=6, u′=20 and β′=5.

Each value follows from the formula of Chapter 13 with its own scalars. Each point follows the same Horner form, starting from the commitment to f, with a walk in place of the double-and-add:

OutputComputed inScalar usedOperationResultGates
v over F43​Circuit over F43​β=12Field arithmetic38
P′ on E′Circuit over F43​Bits, acting as β′=5Walk(12,12)46
v′ over F31​Circuit over F31​β′=5Field arithmetic98
P on ECircuit over F31​Bits, acting as β=12Walk(26,8)46

The decider then works directly with the polynomials, and it confirms the table:

The decider commits to the combined polynomials p=(0,6,21,40) and p′=(9,4,19,4), and gets (26,8) on E and (12,12) on E′. It evaluates them at u=13 and at u′=20, and gets 3 in F43​ and 9 in F31​. All four numbers match the table, although neither circuit ever computed in the other's field.

Here is how the cost compares with Chapter 13:

Each point now takes 46 gates, two walks of 20 and two additions of 3, where the 4-bit double-and-add of chapter 13 took 68 gates for a shorter challenge. Each circuit also pays 5 gates to show that the bits are bits and 3 gates to lift them.

The field value has to be the lift, because the walk acts as the lift. The plain integer now gives the wrong answer:

Suppose the circuit over F43​ used the integer 31 as β in its field arithmetic. The walk on E does not act as 31. It takes the commitment F=(28,10) to 12⋅F=(24,30), while 31⋅F=(24,1). The value and the point would then describe different polynomials, and the decider would reject.

11. Transcript bridging

The book's name for sharing one transcript between the two circuits is transcript bridging. Chapter 13 explained why it is sound only with input consistency. We now have the tools to say how the lifted values reach the nested side and how that side is held to them.

The nested circuits see no transcript. They read every challenge from a stage of their own trace, committed without blinding on the curve whose coordinates are native to the primary circuit. So its commitment is a known combination of generators, Cs​=∑i​lift(chi​)⋅Gi​.

The native circuit holds each chi​ in its own field, and it cannot compute the lift, which lies in the other field. But walking Gi​ by the bits of chi​ acts as exactly that lift, by the consistency property of Section 6, and Gi​ has coordinates in the native field. Section 9 of Chapter 13 did this check with plain integers, and here is the real version:

The stage holds (α′,u′,β′)=(6,20,5) with no blinding, on the generators (20,3),(21,18),(25,18) of E′ from chapter 13, and its commitment is Cs​=(2,31). The circuit over F43​ holds the three transcript values as wires in its own field, breaks each into bits, and walks each generator by those bits. The walks give (32,40), (13,22) and (21,18), which add to (2,31) in 66 gates. That circuit never computed 6, 20 or 5, because it has no wires modulo 31, and it still confirmed a commitment to exactly those values. If the prover puts any of the 30 other values in the place of β′, the stage commits to a different point and the comparison fails.

So the endoscaling walk has two uses in a fuse. It folds commitments, and it also certifies foreign field values. The code divides the second use by timing. Four bind_challenges circuits handle two challenges each and export their partial sum. The challenge pre_beta comes last in the transcript, after the stage holding those partial sums has been committed, so its term has to wait. The next step's bind_beta adds it and compares the sum with the stage commitment, and for the root proof the verifier rederives the stage itself.

ChallengeNative circuit usesNested circuit usesWhat holds the nested copy
w,y,z,μ,μ′,x,α,uThe field elementIts lift, from the challenge stagebind_challenges
pre_betaβ, its lift in Fp​, and its bits for the walk on Pallasβn​, its lift in Fq​, and its bits for the walk on Vestabind_beta, then the lift check below

One gap remains. Each walk reads the bits from a stage as well, and we have to tie those bits to pre_beta. On the native side this is direct, because bind_endoscalar extracts the bits from pre_beta again and compares them wire by wire. The nested side cannot do this, because it holds no pre_beta. It has only the lifted βn​. So its compute_v circuit lifts its own bits and requires the result to equal βn​. This check is only as strong as the lift is injective, as the toy curves show:

The string 00100 also lifts to 5 in F31​, so a prover could load it into the circuit over F31​ and pass the comparison with β′. In F43​ that string lifts to 5 and not 12, so the walk on E now acts as 5 and produces P=(16,21) in place of (26,8). The false accumulator has a value computed with β=12 and a point computed with 5.

Among the 32 toy strings, 16 pairs agree in F31​ and disagree in F43​. On Pasta no such pair exists, by the norm bound of Section 8.

This is the reason the book cares about injectivity, beyond keeping the sample space large.

12. Why cheating fails

We go through what a cheater can try, in the order of the sections above.

A second spelling of the challenge. Section 9 showed that a value with two bit decompositions would let a prover pick its endoscalar after the hash. The range requirement leaves one spelling. The verifier rejects a proof whose challenge is out of range, and no in-circuit assignment exists for such a value.

Wrong lifts on the nested side. The stage is unblinded and its commitment is recomputed from the transcript's bits, as Section 11 showed. Any other value changes the point, under the discrete log relation assumption for the generators of that curve.

Other bits in a walk. The native side compares its bits directly with the transcript. The nested side compares a lift, and on Pasta only one string has that lift.

A lucky challenge. A short challenge has a smaller range, as Chapter 13 counted. The lift adds a condition, which is that distinct strings must not pile up on the same scalar:

Take a cheater whose error in v is the polynomial β−c, as in chapter 13. It passes when the string lifts to c. With an injective lift, one string out of the 32 would pass. On the toy cycle the lift is not injective, and the cheater does best with c=0, which 4 strings reach, for a chance of 4 in 32. So a collision in the lift directly raises a cheater's chance.

On Pasta the lift is injective in both fields, so each root of a fixed nonzero polynomial is hit by at most one string out of 2143.

The book adds up the roots charged to each challenge for one fuse step, and gets 66,477 over all nine challenges. We recomputed that sum and the resulting 2−126.98.

The book calls this a conditional accounting for one step and not a security theorem, and it lists what a full argument would still have to cover, including an adversary's repeated Fiat–Shamir trials. We do not go further than that here.

Using an endoscalar for a secret. All of the above concerns public challenges. For a secret, the structure of the expansion helps an attacker, which is why the book and the code restrict endoscalars to public values:

Suppose the secret string is 00111, and an attacker sees T=11⋅G0​=(14,22). The attacker tabulates the 8 possible digit points, tries the 4 possible values of the head 2⋅3⋅u, and looks up T minus each head in the table. That is 12 operations against 32 for trying every string, and the search finds the string. The saving grows with the width, because the expansion splits at any digit into a head and a tail that add up. At 143 bits the same idea takes roughly 271.5 work.

That is far below the roughly 2127 work of a generic discrete log search in a group of 2254 elements, so a blinding factor must not be an endoscalar. A public challenge faces a different event, in which a fresh value hits a root that was fixed beforehand, and a meet-in-the-middle search does not apply to that.

The argument rests on these assumptions, and it is informal. Discrete log has to be hard on both curves, and the transcript hash has to behave as a random oracle. Every commitment has to enter the transcript before the challenges that test it, which is the input consistency of Chapter 13. The base points have to lie on the curve, which the circuits enforce separately. Each check also depends on a later step, so the decider has to finish the work at the root.

13. Feedback between the walks

A circuit does at most four endoscalings, so a walk over many points spreads over several step circuits. These step circuits have traces, and those traces have commitments, and the other side then has to fold those commitments too. Adding circuits on one side therefore adds work on the other side, and we need to know whether this settles at a finite number. The book treats this as a convergence problem.

Let M and N be the base number of endoscalings on each curve, and let k be the capacity of one circuit. The book's model says that each circuit adds one endoscaling on the other curve. The first round needs M/k circuits on one side. They add M/k endoscalings on the other side, or M/k2 circuits there, which add M/k3 circuits back on the first side, and so on. Collecting the terms on one curve gives two geometric series with ratio 1/k2:

Mtotal​=kM​(1+k21​+⋯)+k2N​(1+k21​+⋯).

For M=N the sum is M/3 against a first round of M/4, which is a factor of 1.33. The book also gives k=8, where the factor is 1.14.

The code's batch has a different count. Its point formula is 1+2(rx+4)+6, because a fuse folds the commitments of both children, so one more step circuit adds two points to the other walk rather than one. The other side's formula has the same shape. We can run the feedback from zero, with 22 fixed rx polynomials on the native side and 13 on the nested side:

RoundPoints the native walk foldsNative stepsPoints the nested walk foldsNested steps
141105915
271187920
381209524
489229925
5912310326
6932310526

The iteration stops at 23 native steps and 26 nested steps, the values that the code pins. With no feedback the first round would have been enough, with 25 steps in all, so the feedback multiplies the count by about 1.96.

Each step now adds 2 points to a walk that does 4 per step, so the ratio per round is 2/4 and not 1/4. For equal base counts the series sums to (M/4)/(1−1/2)=M/2, a factor of 2, which agrees with the count above.

So the process converges in either model, and the factor is a modest constant. Section 14 records the difference between the two factors.

14. Endoscalars in Ragu

Reconstructed from code at commit 3219e08, not confirmed by the authors

  • The gadgets. Endoscalar holds 143 Boolean wires, and HoistedEndoscalar adds the 2⋅47 product wires. EndoscalarChallenge carries the element together with its constrained decomposition.
  • Which gadget runs where. The native and nested step circuits walk with the hoisted gadget. The binders walk constant generators by different strings, so they use the plain gadget.
  • The native field value. compute_v extracts the string from pre_beta and lifts it for the Horner sum of v. The prover does the same outside the circuit.
  • Machine-checked parts. The book reports Lean proofs of the gadget contracts for the walk and the lift, and it says that the sharing of staged wires and the protocol's overall soundness lie outside them. We did not run those proofs.

Which challenges are endoscalars

Book: the transcript bridging section sets every verifier challenge to its extracted endoscalar, viewed as a subset of Fp​, and multiplies by it directly in the primary circuit.

Code at 3219e08: native challenges other than pre_beta stay full field elements, and a string never acts as its integer. The primary circuit multiplies by the lift. The book's endoscalar page agrees with the code on the nested lifts.

This site follows the code, which settles the difference that Chapter 13 recorded.

How a string reaches the other circuit

Book: the endoscalar page describes running extract with the endoscalar as a public output of the Fp​ circuit and using it as a public input of the Fq​ circuit.

Code at 3219e08: the bits are not a public input. The nested side holds them in a stage, and the checks of Section 11 tie them to pre_beta. The same page's later section on hoisting describes this design.

This site follows the code.

Out-of-range challenges

Book: a prover that derives a value from a transcript re-randomizes and tries again.

Code at 3219e08: only pre_beta is ground in this way. For the other challenges, the lift returns an error, an event the code puts at 2−129.

This site follows the code. The difference has little practical effect, given how rarely the event can occur.

The feedback factor

Book: each circuit adds one endoscaling on the other curve, which gives a factor of about 1.33 for k=4. The book's closing arithmetic for k=8 also writes the ratio inverted, although its value of 1.14 is correct for the ratio taken the other way.

Code at 3219e08: each step adds a point per child, and Section 13's iteration gives a factor near 2. The reading that this explains the difference is ours, and the book may intend its model only as a simplification.

This site uses the code's counts.

All of this describes the Ragu revision at 3219e08. Tachyon, which has not activated on mainnet and whose design is still changing, pins a different Ragu revision.

15. Where this chapter leaves us

This chapter took the following steps:

  1. On a curve y2=x3+b with a cube root ζ, the map (x,y)↦(ζx,y) respects addition, and on a curve of prime order it multiplies every point by one scalar λ with λ2+λ+1=0.
  2. Each field of a cycle keeps one constant, which acts on the coordinates of its own curve and as the eigenvalue on the partner curve, and these choices have to line up.
  3. Elements a+bλ have one image in each scalar field, and an image can be zero only when the field size divides the norm a2−ab+b2.
  4. A string of 2+3n bits reads as an element through a radix-3 walk, whose eight digits are the nonzero residues modulo 3, so the element determines the string.
  5. The walk costs ten gates per three bits, or nine with shared products, which makes 143 bits about three times cheaper than plain double-and-add.
  6. On Pasta the norm bound keeps strings distinct in both fields and rules out exceptional additions, and the toy curves show both failures.
  7. Extraction takes the low bits of the unique spelling of an in-range value, and a prover grinds pre_beta to stay in range.
  8. A circuit lifts a string to get a field value in its own field and walks the string to act on foreign points, so one string serves both circuits with no foreign arithmetic.
  9. The primary circuit holds the nested side to the lifted values by walking generators, and the nested side ties its bits to βn​ through injectivity.
  10. Step circuits feed work back to the other curve, and the count settles at 23 native steps and 26 nested steps.

Several of these mechanisms depended on stages, including the challenge stage, the walk stage and the bridge stages. The next chapter explains how a circuit commits to its trace in parts and how the partial commitments are checked.

Last Updated: 11/4/26, 12:56 PM
Contributors: Hanh
Prev
Wiring and the Registry
Next
Staging