Merge pull request #42 from succinctlabs/kevjue/audit_fixes fix: Veridise audit fixes
jump to
@@ -15,13 +15,13 @@ type Chip struct {
api frontend.API `gnark:"-"` poseidonChip *poseidon.GoldilocksChip poseidonBN254Chip *poseidon.BN254Chip - spongeState [poseidon.SPONGE_WIDTH]gl.Variable + spongeState poseidon.GoldilocksState inputBuffer []gl.Variable outputBuffer []gl.Variable } func NewChip(api frontend.API) *Chip { - var spongeState [poseidon.SPONGE_WIDTH]gl.Variable + var spongeState poseidon.GoldilocksState var inputBuffer []gl.Variable var outputBuffer []gl.Variable for i := 0; i < poseidon.SPONGE_WIDTH; i++ {@@ -40,7 +40,8 @@ }
} func (c *Chip) ObserveElement(element gl.Variable) { - c.outputBuffer = clearBuffer(c.outputBuffer) + // Clear the output buffer + c.outputBuffer = make([]gl.Variable, 0) c.inputBuffer = append(c.inputBuffer, element) if len(c.inputBuffer) == poseidon.SPONGE_RATE { c.duplexing()@@ -110,14 +111,13 @@ return gl.QuadraticExtensionVariable{values[0], values[1]}
} func (c *Chip) GetHash() poseidon.GoldilocksHashOut { - return [4]gl.Variable{c.GetChallenge(), c.GetChallenge(), c.GetChallenge(), c.GetChallenge()} + return [poseidon.POSEIDON_GL_HASH_SIZE]gl.Variable{c.GetChallenge(), c.GetChallenge(), c.GetChallenge(), c.GetChallenge()} } func (c *Chip) GetFriChallenges( commitPhaseMerkleCaps []variables.FriMerkleCap, finalPoly variables.PolynomialCoeffs, powWitness gl.Variable, - degreeBits uint64, config types.FriConfig, ) variables.FriChallenges { numFriQueries := config.NumQueryRounds@@ -143,10 +143,6 @@ FriQueryIndices: friQueryIndices,
} } -func clearBuffer(buffer []gl.Variable) []gl.Variable { - return make([]gl.Variable, 0) -} - func (c *Chip) duplexing() { if len(c.inputBuffer) > poseidon.SPONGE_RATE { fmt.Println(len(c.inputBuffer))@@ -158,9 +154,12 @@
for i := 0; i < len(c.inputBuffer); i++ { c.spongeState[i] = glApi.Reduce(c.inputBuffer[i]) } - c.inputBuffer = clearBuffer(c.inputBuffer) + // Clear the input buffer + c.inputBuffer = make([]gl.Variable, 0) c.spongeState = c.poseidonChip.Poseidon(c.spongeState) - clearBuffer(c.outputBuffer) + + // Clear the output buffer + c.outputBuffer = make([]gl.Variable, 0) for i := 0; i < poseidon.SPONGE_RATE; i++ { c.outputBuffer = append(c.outputBuffer, c.spongeState[i]) }
@@ -49,14 +49,14 @@ gl.NewVariable(g.Uint64()).ToQuadraticExtension(),
zeta, ) - zetaNextBath := BatchInfo{ + zetaNextBatch := BatchInfo{ Point: zetaNext, Polynomials: friZSPolys(f.commonData), } return InstanceInfo{ Oracles: friOracles(f.commonData), - Batches: []BatchInfo{zetaBatch, zetaNextBath}, + Batches: []BatchInfo{zetaBatch, zetaNextBatch}, } }@@ -73,12 +73,10 @@ return Openings{Batches: []OpeningBatch{zetaBatch, zetaNextBatch}}
} func (f *Chip) assertLeadingZeros(powWitness gl.Variable, friConfig types.FriConfig) { - // Asserts that powWitness'es big-endian bit representation has at least `leading_zeros` leading zeros. + // Asserts that powWitness'es big-endian bit representation has at least friConfig.ProofOfWorkBits leading zeros. // Note that this is assuming that the Goldilocks field is being used. Specfically that the - // field is 64 bits long - maxPowWitness := uint64(math.Pow(2, float64(64-friConfig.ProofOfWorkBits))) - 1 - reducedPowWitness := f.gl.Reduce(powWitness) - f.api.AssertIsLessOrEqual(reducedPowWitness.Limb, frontend.Variable(maxPowWitness)) + // field is 64 bits long. + f.gl.RangeCheckWithMaxBits(powWitness, 64-friConfig.ProofOfWorkBits) } func (f *Chip) fromOpeningsAndAlpha(@@ -128,13 +126,15 @@ panic(errorMsg)
} const NUM_LEAF_LOOKUPS = 4 + // Each lookup gadget will connect to 4 merkleCap entries + const STRIDE_LENGTH = 4 var leafLookups [NUM_LEAF_LOOKUPS]poseidon.BN254HashOut // First create the "leaf" lookup2 circuits - // The will use the least significant bits of the capIndexBits array + // This will use the least significant bits of the capIndexBits array for i := 0; i < NUM_LEAF_LOOKUPS; i++ { leafLookups[i] = f.api.Lookup2( capIndexBits[0], capIndexBits[1], - merkleCap[i*NUM_LEAF_LOOKUPS], merkleCap[i*NUM_LEAF_LOOKUPS+1], merkleCap[i*NUM_LEAF_LOOKUPS+2], merkleCap[i*NUM_LEAF_LOOKUPS+3], + merkleCap[i*STRIDE_LENGTH], merkleCap[i*STRIDE_LENGTH+1], merkleCap[i*STRIDE_LENGTH+2], merkleCap[i*STRIDE_LENGTH+3], ) }@@ -162,7 +162,7 @@ exponentBits []frontend.Variable,
) gl.Variable { product := gl.One() for i, bit := range exponentBits { - // If the bit is on, we multiply product by base^pow. + // If the bit is 1, we multiply product by base^pow. // We can arithmetize this as: // product *= 1 + bit (base^pow - 1) // product = (base^pow - 1) product bit + product@@ -238,9 +238,11 @@ reducedEvals := f.gl.ReduceWithPowers(evals, friAlpha)
numerator := f.gl.SubExtensionNoReduce(reducedEvals, reducedOpenings) denominator := f.gl.SubExtension(subgroupX_QE, point) sum = f.gl.MulExtension(f.gl.ExpExtension(friAlpha, uint64(len(evals))), sum) + inv, hasInv := f.gl.InverseExtension(denominator) + f.api.AssertIsEqual(hasInv, frontend.Variable(1)) sum = f.gl.MulAddExtension( numerator, - f.gl.InverseExtension(denominator), + inv, sum, ) }@@ -272,17 +274,23 @@ lX = f.gl.SubMulExtension(x, xPoints[i], lX)
} sum := gl.ZeroExtension() + + lookupFromPoints := frontend.Variable(1) for i := 0; i < len(xPoints); i++ { + quotient, hasQuotient := f.gl.DivExtension( + barycentricWeights[i], + f.gl.SubExtension( + x, + xPoints[i], + ), + ) + + lookupFromPoints = f.api.Mul(hasQuotient, lookupFromPoints) + sum = f.gl.AddExtension( f.gl.MulExtension( - f.gl.DivExtension( - barycentricWeights[i], - f.gl.SubExtension( - x, - xPoints[i], - ), - ), yPoints[i], + quotient, ), sum, )@@ -290,17 +298,17 @@ }
interpolation := f.gl.MulExtension(lX, sum) - returnField := interpolation + lookupVal := gl.ZeroExtension() // Now check if x is already within the xPoints for i := 0; i < len(xPoints); i++ { - returnField = f.gl.Lookup( + lookupVal = f.gl.Lookup( f.gl.IsZero(f.gl.SubExtension(x, xPoints[i])), - returnField, + lookupVal, yPoints[i], ) } - return returnField + return f.gl.Lookup(lookupFromPoints, lookupVal, interpolation) } func (f *Chip) computeEvaluation(@@ -312,7 +320,7 @@ beta gl.QuadraticExtensionVariable,
) gl.QuadraticExtensionVariable { arity := 1 << arityBits if (len(evals)) != arity { - panic("len(evals) ! arity") + panic("len(evals) != arity") } if arityBits > 8 { panic("currently assuming that arityBits is <= 8")@@ -327,8 +335,8 @@ // element's new index is the bit reverse of it's original index.
// OPTIMIZE - Since the size of the evals array should be constant (e.g. 2^arityBits), // we can just hard code the permutation. permutedEvals := make([]gl.QuadraticExtensionVariable, len(evals)) - for i := uint8(0); i < uint8(len(evals)); i++ { - newIndex := bits.Reverse8(i) >> arityBits + for i := uint8(0); i <= uint8(len(evals)-1); i++ { + newIndex := bits.Reverse8(i) >> (8 - arityBits) permutedEvals[newIndex] = evals[i] }@@ -367,7 +375,9 @@ }
} // Take the inverse of the barycentric weights // OPTIMIZE: Can provide a witness to this value - barycentricWeights[i] = f.gl.InverseExtension(barycentricWeights[i]) + inv, hasInv := f.gl.InverseExtension(barycentricWeights[i]) + f.api.AssertIsEqual(hasInv, frontend.Variable(1)) + barycentricWeights[i] = inv } return f.interpolate(beta, xPoints, yPoints, barycentricWeights)
@@ -52,7 +52,6 @@ friChallenges := challengerChip.GetFriChallenges(
proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps, proofWithPis.Proof.OpeningProof.FinalPoly, proofWithPis.Proof.OpeningProof.PowWitness, - commonCircuitData.DegreeBits, commonCircuitData.Config.FriConfig, )
@@ -38,9 +38,6 @@
// The modulus of the field. var MODULUS *big.Int = emulated.Goldilocks{}.Modulus() -// The threshold maximum number of bits at which we must reduce the element. -var REDUCE_NB_BITS_THRESHOLD uint8 = 254 - 64 - // The number of bits to use for range checks on inner products of field elements. var RANGE_CHECK_NB_BITS int = 140@@ -90,38 +87,41 @@ rangeChecker := rangecheck.New(api)
return &Chip{api: api, rangeChecker: rangeChecker} } -// Adds two field elements such that x + y = z within the Golidlocks field. +// Adds two goldilocks field elements and returns a value within the goldilocks field. func (p *Chip) Add(a Variable, b Variable) Variable { return p.MulAdd(a, NewVariable(1), b) } -// Adds two field elements such that x + y = z within the Golidlocks field without reducing. +// Adds two goldilocks field elements and returns a value that may not be within the goldilocks field +// (e.g. the sum is not reduced). func (p *Chip) AddNoReduce(a Variable, b Variable) Variable { return NewVariable(p.api.Add(a.Limb, b.Limb)) } -// Subtracts two field elements such that x + y = z within the Golidlocks field. +// Subracts two goldilocks field elements and returns a value within the goldilocks field. func (p *Chip) Sub(a Variable, b Variable) Variable { - return p.MulAdd(b, NewVariable(MODULUS.Uint64()-1), a) + return p.MulAdd(b, NegOne(), a) } -// Subtracts two field elements such that x + y = z within the Golidlocks field without reducing. +// Subracts two goldilocks field elements and returns a value that may not be within the goldilocks field +// (e.g. the difference is not reduced). func (p *Chip) SubNoReduce(a Variable, b Variable) Variable { - return NewVariable(p.api.Add(a.Limb, p.api.Mul(b.Limb, MODULUS.Uint64()-1))) + return NewVariable(p.api.Add(a.Limb, p.api.Mul(b.Limb, NegOne().Limb))) } -// Multiplies two field elements such that x * y = z within the Golidlocks field. +// Multiplies two goldilocks field elements and returns a value within the goldilocks field. func (p *Chip) Mul(a Variable, b Variable) Variable { return p.MulAdd(a, b, Zero()) } -// Multiplies two field elements such that x * y = z within the Golidlocks field without reducing. +// Multiplies two goldilocks field elements and returns a value that may not be within the goldilocks field +// (e.g. the product is not reduced). func (p *Chip) MulNoReduce(a Variable, b Variable) Variable { return NewVariable(p.api.Mul(a.Limb, b.Limb)) } -// Multiplies two field elements and adds a field element such that x * y + z = c within the -// Golidlocks field. +// Multiplies two field elements and adds a field element (e.g. computes a * b + c). The returned value +// will be within the goldilocks field. func (p *Chip) MulAdd(a Variable, b Variable, c Variable) Variable { result, err := p.api.Compiler().NewHint(MulAddHint, 2, a.Limb, b.Limb, c.Limb) if err != nil {@@ -131,7 +131,8 @@
quotient := NewVariable(result[0]) remainder := NewVariable(result[1]) - lhs := p.api.MulAcc(c.Limb, a.Limb, b.Limb) + cLimbCopy := p.api.Mul(c.Limb, 1) + lhs := p.api.MulAcc(cLimbCopy, a.Limb, b.Limb) rhs := p.api.MulAcc(remainder.Limb, MODULUS, quotient.Limb) p.api.AssertIsEqual(lhs, rhs)@@ -140,10 +141,11 @@ p.RangeCheck(remainder)
return remainder } -// Multiplies two field elements and adds a field element such that x * y + z = c within the -// Golidlocks field without reducing. +// Multiplies two field elements and adds a field element (e.g. computes a * b + c). The returned value +// may no be within the goldilocks field (e.g. the result is not reduced). func (p *Chip) MulAddNoReduce(a Variable, b Variable, c Variable) Variable { - return NewVariable(p.api.MulAcc(c.Limb, a.Limb, b.Limb)) + cLimbCopy := p.api.Mul(c.Limb, 1) + return NewVariable(p.api.MulAcc(cLimbCopy, a.Limb, b.Limb)) } // The hint used to compute MulAdd.@@ -179,18 +181,7 @@ // Must check that offset \in [0, MODULUS) and carry \in [0, 2^RANGE_CHECK_NB_BITS) to ensure
// that this computation does not overflow. We use 2^RANGE_CHECK_NB_BITS to reduce the cost of the range check // // In other words, we assume that we at most compute a a dot product with dimension at most RANGE_CHECK_NB_BITS - 128. - - result, err := p.api.Compiler().NewHint(ReduceHint, 2, x.Limb) - if err != nil { - panic(err) - } - - quotient := result[0] - p.rangeChecker.Check(quotient, RANGE_CHECK_NB_BITS) - - remainder := NewVariable(result[1]) - p.RangeCheck(remainder) - return remainder + return p.ReduceWithMaxBits(x, uint64(RANGE_CHECK_NB_BITS)) } // Reduces a field element x such that x % MODULUS = y.@@ -212,6 +203,9 @@ p.rangeChecker.Check(quotient, int(maxNbBits))
remainder := NewVariable(result[1]) p.RangeCheck(remainder) + + p.api.AssertIsEqual(x.Limb, p.api.Add(p.api.Mul(quotient, MODULUS), remainder.Limb)) + return remainder }@@ -229,16 +223,22 @@ return nil
} // Computes the inverse of a field element x such that x * x^-1 = 1. -func (p *Chip) Inverse(x Variable) Variable { +func (p *Chip) Inverse(x Variable) (Variable, frontend.Variable) { result, err := p.api.Compiler().NewHint(InverseHint, 1, x.Limb) if err != nil { panic(err) } inverse := NewVariable(result[0]) + isZero := p.api.IsZero(x.Limb) + hasInv := p.api.Sub(1, isZero) + p.RangeCheck(inverse) + product := p.Mul(inverse, x) - p.api.AssertIsEqual(product.Limb, frontend.Variable(1)) - return inverse + productToCheck := p.api.Select(hasInv, product.Limb, frontend.Variable(1)) + p.api.AssertIsEqual(productToCheck, frontend.Variable(1)) + + return inverse, hasInv } // The hint used to compute Inverse.@@ -254,6 +254,8 @@ }
inputGl := goldilocks.NewElement(input.Uint64()) resultGl := goldilocks.NewElement(0) + + // Will set resultGL if inputGL == 0 resultGl.Inverse(&inputGl) result := big.NewInt(0)@@ -262,28 +264,6 @@
return nil } -// Computes a field element raised to some power. -func (p *Chip) Exp(x Variable, k *big.Int) Variable { - if k.IsUint64() && k.Uint64() == 0 { - return One() - } - - e := k - if k.Sign() == -1 { - panic("Unsupported negative exponent. Need to implement inversion.") - } - - z := x - for i := e.BitLen() - 2; i >= 0; i-- { - z = p.Mul(z, z) - if e.Bit(i) == 1 { - z = p.Mul(z, x) - } - } - - return z -} - // The hint used to split a GoldilocksVariable into 2 32 bit limbs. func SplitLimbsHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error { if len(inputs) != 1 {@@ -348,6 +328,11 @@ frontend.Variable(0),
) } +// This function will assert that the field element x is less than 2^maxNbBits. +func (p *Chip) RangeCheckWithMaxBits(x Variable, maxNbBits uint64) { + p.rangeChecker.Check(x.Limb, int(maxNbBits)) +} + func (p *Chip) AssertIsEqual(x, y Variable) { p.api.AssertIsEqual(x.Limb, y.Limb) }@@ -373,7 +358,7 @@ var res []goldilocks.Element
rootOfUnity := PrimitiveRootOfUnity(nLog) res = append(res, goldilocks.NewElement(1)) - for i := 0; i < (1 << nLog); i++ { + for i := 0; i < (1<<nLog)-1; i++ { lastElement := res[len(res)-1] res = append(res, *lastElement.Mul(&lastElement, &rootOfUnity)) }
@@ -58,15 +58,13 @@
// Multiplies quadratic extension variable in the Goldilocks field. func (p *Chip) MulExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable { product := p.MulExtensionNoReduce(a, b) - product[0] = p.Reduce(product[0]) - product[1] = p.Reduce(product[1]) - return product + return p.ReduceExtension(product) } // Multiplies quadratic extension variable in the Goldilocks field without reducing. func (p *Chip) MulExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable { c0o0 := p.MulNoReduce(a[0], b[0]) - c0o1 := p.MulNoReduce(p.MulNoReduce(NewVariable(7), a[1]), b[1]) + c0o1 := p.MulNoReduce(p.MulNoReduce(NewVariable(W), a[1]), b[1]) c0 := p.AddNoReduce(c0o0, c0o1) c1 := p.AddNoReduce(p.MulNoReduce(a[0], b[1]), p.MulNoReduce(a[1], b[0])) return NewQuadraticExtensionVariable(c0, c1)@@ -77,9 +75,7 @@ // be less than RANGE_CHECK_NB_BITS bits.
func (p *Chip) MulAddExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable { product := p.MulExtensionNoReduce(a, b) sum := p.AddExtensionNoReduce(product, c) - sum[0] = p.Reduce(sum[0]) - sum[1] = p.Reduce(sum[1]) - return sum + return p.ReduceExtension(sum) } func (p *Chip) MulAddExtensionNoReduce(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {@@ -88,14 +84,12 @@ sum := p.AddExtensionNoReduce(product, c)
return sum } -// Multiplies two operands a and b and subtracts to c in the Goldilocks extension field. a * b - c must +// Subtracts two operands a and b and multiplies the diff by c in the Goldilocks extension field. (a - b) * c must // be less than RANGE_CHECK_NB_BITS bits. func (p *Chip) SubMulExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable { difference := p.SubExtensionNoReduce(a, b) product := p.MulExtensionNoReduce(difference, c) - product[0] = p.Reduce(product[0]) - product[1] = p.Reduce(product[1]) - return product + return p.ReduceExtension(product) } // Multiplies quadratic extension variable in the Goldilocks field by a scalar.@@ -126,21 +120,23 @@ return p.ReduceExtension(acc)
} // Computes the inverse of a quadratic extension variable in the Goldilocks field. -func (p *Chip) InverseExtension(a QuadraticExtensionVariable) QuadraticExtensionVariable { - a0IsZero := p.api.IsZero(a[0].Limb) - a1IsZero := p.api.IsZero(a[1].Limb) - p.api.AssertIsEqual(p.api.Mul(a0IsZero, a1IsZero), frontend.Variable(0)) +func (p *Chip) InverseExtension(a QuadraticExtensionVariable) (QuadraticExtensionVariable, frontend.Variable) { + aIsZero := p.IsZero(a) + p.api.AssertIsEqual(aIsZero, frontend.Variable(0)) aPowRMinus1 := QuadraticExtensionVariable{ a[0], p.Mul(a[1], NewVariable(DTH_ROOT)), } aPowR := p.MulExtension(aPowRMinus1, a) - return p.ScalarMulExtension(aPowRMinus1, p.Inverse(aPowR[0])) + + aPowRInv, hasInv := p.Inverse(aPowR[0]) + return p.ScalarMulExtension(aPowRMinus1, aPowRInv), hasInv } // Divides two quadratic extension variables in the Goldilocks field. -func (p *Chip) DivExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable { - return p.MulExtension(a, p.InverseExtension(b)) +func (p *Chip) DivExtension(a, b QuadraticExtensionVariable) (QuadraticExtensionVariable, frontend.Variable) { + bInv, hasInv := p.InverseExtension(b) + return p.MulExtension(a, bInv), hasInv } // Exponentiates a quadratic extension variable to some exponent in the Golidlocks field.@@ -213,7 +209,7 @@ c1 := p.api.Select(b, y[1].Limb, x[1].Limb)
return NewQuadraticExtensionVariable(NewVariable(c0), NewVariable(c1)) } -// Lookup2 is similar to select2, but returns the first variable if the bit is zero and vice-versa. +// Lookup2 is similar to Lookup2. It returns the ith qe value (0 indexed) where i is bit decomposed to b0,b1 (little endian). func (p *Chip) Lookup2( b0 frontend.Variable, b1 frontend.Variable,
@@ -14,7 +14,7 @@ return QuadraticExtensionAlgebraVariable{a, b}
} func (p QuadraticExtensionVariable) ToQuadraticExtensionAlgebra() QuadraticExtensionAlgebraVariable { - return [2]QuadraticExtensionVariable{p, ZeroExtension()} + return [D]QuadraticExtensionVariable{p, ZeroExtension()} } func ZeroExtensionAlgebra() QuadraticExtensionAlgebraVariable {
@@ -59,7 +59,7 @@ }
func (c *TestQuadraticExtensionDivCircuit) Define(api frontend.API) error { glAPI := New(api) - actualRes := glAPI.DivExtension(c.Operand1, c.Operand2) + actualRes, _ := glAPI.DivExtension(c.Operand1, c.Operand2) glAPI.AssertIsEqual(actualRes[0], c.ExpectedResult[0]) glAPI.AssertIsEqual(actualRes[1], c.ExpectedResult[1]) return nil
@@ -9,7 +9,7 @@ "github.com/consensys/gnark/frontend"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" ) -var aritheticExtensionGateRegex = regexp.MustCompile("ArithmeticExtensionGate { num_ops: (?P<numOps>[0-9]+) }") +var arithmeticExtensionGateRegex = regexp.MustCompile("ArithmeticExtensionGate { num_ops: (?P<numOps>[0-9]+) }") func deserializeExtensionArithmeticGate(parameters map[string]string) Gate { // Has the format "ArithmeticExtensionGate { num_ops: 10 }"
@@ -9,7 +9,7 @@ "github.com/consensys/gnark/frontend"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" ) -var aritheticGateRegex = regexp.MustCompile("ArithmeticGate { num_ops: (?P<numOps>[0-9]+) }") +var arithmeticGateRegex = regexp.MustCompile("ArithmeticGate { num_ops: (?P<numOps>[0-9]+) }") func deserializeArithmeticGate(parameters map[string]string) Gate { // Has the format "ArithmeticGate { num_ops: 10 }"
@@ -51,7 +51,7 @@ }
} func (g *BaseSumGate) Id() string { - return fmt.Sprintf("BaseSumGate { num_ops: %d } + Base: %d", g.numLimbs, g.base) + return fmt.Sprintf("BaseSumGate { num_limbs: %d } + Base: %d", g.numLimbs, g.base) } func (g *BaseSumGate) limbs() []uint64 {
@@ -41,14 +41,14 @@ return fmt.Sprintf("ConstantGate { num_consts: %d }", g.numConsts)
} func (g *ConstantGate) ConstInput(i uint64) uint64 { - if i > g.numConsts { + if i >= g.numConsts { panic("Invalid constant index") } return i } func (g *ConstantGate) WireOutput(i uint64) uint64 { - if i > g.numConsts { + if i >= g.numConsts { panic("Invalid wire index") } return i
@@ -32,6 +32,9 @@ degreeInt, err := strconv.ParseUint(degree, 10, 64)
if err != nil { panic("invalid degree in CosetInterpolationGate") } + if degreeInt < 2 { + panic("degree must be at least 2 in CosetInterpolationGate") + } barycentricWeightsStr := strings.Split(barycentricWeights, ",") barycentricWeightsInt := make([]goldilocks.Element, len(barycentricWeightsStr))@@ -199,6 +202,10 @@ }
startIndex := 1 + (g.degree-1)*(i+1) endIndex := startIndex + g.degree - 1 + if endIndex > g.numPoints() { + endIndex = g.numPoints() + } + computedEval, computedProd = glApi.PartialInterpolateExtAlgebra( domain[startIndex:endIndex], values[startIndex:endIndex],
@@ -23,6 +23,20 @@ if err != nil {
panic("Invalid num_power_bits field in ExponentiationGate") } + base, hasBase := parameters["base"] + if !hasBase { + panic("Missing field base in ExponentiationGate") + } + + baseInt, err := strconv.Atoi(base) + if err != nil { + panic("Invalid base field in ExponentiationGate") + } + + if baseInt != gl.D { + panic("Expected base field in ExponentiationGate to equal gl.D") + } + return NewExponentiationGate(uint64(numPowerBitsInt)) }
@@ -18,20 +18,20 @@ ) []gl.QuadraticExtensionVariable
} var gateRegexHandlers = map[*regexp.Regexp]func(parameters map[string]string) Gate{ - aritheticGateRegex: deserializeArithmeticGate, - aritheticExtensionGateRegex: deserializeExtensionArithmeticGate, - baseSumGateRegex: deserializeBaseSumGate, - constantGateRegex: deserializeConstantGate, - cosetInterpolationGateRegex: deserializeCosetInterpolationGate, - exponentiationGateRegex: deserializeExponentiationGate, - mulExtensionGateRegex: deserializeMulExtensionGate, - noopGateRegex: deserializeNoopGate, - poseidonGateRegex: deserializePoseidonGate, - poseidonMdsGateRegex: deserializePoseidonMdsGate, - publicInputGateRegex: deserializePublicInputGate, - randomAccessGateRegex: deserializeRandomAccessGate, - reducingExtensionGateRegex: deserializeReducingExtensionGate, - reducingGateRegex: deserializeReducingGate, + arithmeticGateRegex: deserializeArithmeticGate, + arithmeticExtensionGateRegex: deserializeExtensionArithmeticGate, + baseSumGateRegex: deserializeBaseSumGate, + constantGateRegex: deserializeConstantGate, + cosetInterpolationGateRegex: deserializeCosetInterpolationGate, + exponentiationGateRegex: deserializeExponentiationGate, + mulExtensionGateRegex: deserializeMulExtensionGate, + noopGateRegex: deserializeNoopGate, + poseidonGateRegex: deserializePoseidonGate, + poseidonMdsGateRegex: deserializePoseidonMdsGate, + publicInputGateRegex: deserializePublicInputGate, + randomAccessGateRegex: deserializeRandomAccessGate, + reducingExtensionGateRegex: deserializeReducingExtensionGate, + reducingGateRegex: deserializeReducingGate, } func GateInstanceFromId(gateId string) Gate {
@@ -37,7 +37,7 @@ }
} func (g *MultiplicationExtensionGate) Id() string { - return fmt.Sprintf("ArithmeticExtensionGate { num_ops: %d }", g.numOps) + return fmt.Sprintf("MulExtensionGate { num_ops: %d }", g.numOps) } func (g *MultiplicationExtensionGate) wiresIthMultiplicand0(i uint64) Range {
@@ -90,7 +90,9 @@
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ { output := vars.GetLocalExtAlgebra(g.WireOutput(i)) diff := glApi.SubExtensionAlgebra(output, computed_outputs[i]) - constraints = append(constraints, diff[0], diff[1]) + for i := 0; i < gl.D; i++ { + constraints = append(constraints, diff[i]) + } } return constraints
@@ -38,7 +38,7 @@ constraints := []gl.QuadraticExtensionVariable{}
wires := g.WiresPublicInputsHash() hash_parts := vars.publicInputsHash - for i := 0; i < 4; i++ { + for i := 0; i < len(wires); i++ { wire := wires[i] hash_part := hash_parts[i]
@@ -36,6 +36,20 @@ if err != nil {
panic("invalid numExtraConstants in RandomAccessGate") } + base, hasBase := parameters["base"] + if !hasBase { + panic("Missing field base in RandomAccessGate") + } + + baseInt, err := strconv.Atoi(base) + if err != nil { + panic("Invalid base field in RandomAccessGate") + } + + if baseInt != gl.D { + panic("Expected base field in RandomAccessGate to equal gl.D") + } + return NewRandomAccessGate(bitsInt, numCopiesInt, numExtraConstantsInt) }@@ -151,14 +165,12 @@ x := listItems[i]
y := listItems[i+1] // This is computing `if b { x } else { y }` - // i.e. `bx - (by-y)`. - mul1 := glApi.MulExtension(b, x) - sub1 := glApi.SubExtension(mul1, x) - - mul2 := glApi.MulExtension(b, y) - sub2 := glApi.SubExtension(mul2, sub1) + // i.e. `x + b(y - x)`. + diff := glApi.SubExtension(y, x) + mul := glApi.MulExtension(b, diff) + add := glApi.AddExtension(x, mul) - listItemsTmp = append(listItemsTmp, sub2) + listItemsTmp = append(listItemsTmp, add) } listItems = listItemsTmp }
@@ -12,7 +12,7 @@
var reducingExtensionGateRegex = regexp.MustCompile("ReducingExtensionGate { num_coeffs: (?P<numCoeffs>[0-9]+) }") func deserializeReducingExtensionGate(parameters map[string]string) Gate { - // Has the format "ReducingGate { num_coeffs: 33 }" + // Has the format "ReducingExtensionGate { num_coeffs: 33 }" numCoeffs, hasNumCoeffs := parameters["numCoeffs"] if !hasNumCoeffs { panic("Missing field num_coeffs in ReducingExtensionGate")@@ -39,7 +39,7 @@ }
} func (g *ReducingExtensionGate) Id() string { - return fmt.Sprintf("ReducingExtensionGate { num_ops: %d }", g.numCoeffs) + return fmt.Sprintf("ReducingExtensionGate { num_coeffs: %d }", g.numCoeffs) } func (g *ReducingExtensionGate) wiresOutput() Range {
@@ -39,7 +39,7 @@ }
} func (g *ReducingGate) Id() string { - return fmt.Sprintf("ReducingExtensionGate { num_ops: %d }", g.numCoeffs) + return fmt.Sprintf("ReducingGate { num_coeffs: %d }", g.numCoeffs) } func (g *ReducingGate) wiresOutput() Range {@@ -96,11 +96,7 @@
constraints := []gl.QuadraticExtensionVariable{} acc := oldAcc for i := uint64(0); i < g.numCoeffs; i++ { - var coeff gl.QuadraticExtensionAlgebraVariable - for j := 0; j < gl.D; j++ { - coeff[j] = gl.ZeroExtension() - } - coeff[0] = coeffs[i] + coeff := coeffs[i].ToQuadraticExtensionAlgebra() tmp := glApi.MulExtensionAlgebra(acc, alpha) tmp = glApi.AddExtensionAlgebra(tmp, coeff) tmp = glApi.SubExtensionAlgebra(tmp, accs[i])
@@ -71,10 +71,15 @@ denominator := glApi.SubExtension(
glApi.ScalarMulExtension(x, p.DEGREE), p.DEGREE_QE, ) - return glApi.DivExtension( + + quotient, hasQuotient := glApi.DivExtension( evalZeroPoly, denominator, ) + + p.api.AssertIsEqual(hasQuotient, frontend.Variable(1)) + + return quotient } func (p *PlonkChip) checkPartialProducts(
@@ -10,6 +10,7 @@
import ( "math/big" + "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark/frontend" gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" )@@ -28,6 +29,10 @@ type BN254State = [BN254_SPONGE_WIDTH]frontend.Variable
type BN254HashOut = frontend.Variable func NewBN254Chip(api frontend.API) *BN254Chip { + if api.Compiler().Field().Cmp(bn254.ID.ScalarField()) != 0 { + panic("Gnark compiler not set to BN254 scalar field") + } + return &BN254Chip{api: api, gl: *gl.New(api)} }@@ -76,8 +81,10 @@ if len(input) <= 3 {
returnVal := frontend.Variable(0) alpha := new(big.Int).SetInt64(1 << 32) + alpha = new(big.Int).Mul(alpha, alpha) for i, inputElement := range input { - returnVal = c.api.MulAcc(returnVal, inputElement, alpha.Exp(alpha, big.NewInt(int64(i)), nil)) + mulFactor := new(big.Int).Exp(alpha, big.NewInt(int64(i)), nil) + returnVal = c.api.MulAcc(returnVal, inputElement.Limb, mulFactor) } return BN254HashOut(returnVal)
@@ -7,13 +7,13 @@ )
const HALF_N_FULL_ROUNDS = 4 const N_PARTIAL_ROUNDS = 22 -const MAX_WIDTH = 12 const SPONGE_WIDTH = 12 const SPONGE_RATE = 8 +const POSEIDON_GL_HASH_SIZE = 4 type GoldilocksState = [SPONGE_WIDTH]gl.Variable type GoldilocksStateExtension = [SPONGE_WIDTH]gl.QuadraticExtensionVariable -type GoldilocksHashOut = [4]gl.Variable +type GoldilocksHashOut = [POSEIDON_GL_HASH_SIZE]gl.Variable type GoldilocksChip struct { api frontend.API `gnark:"-"`@@ -77,8 +77,8 @@ for i := 0; i < len(input); i++ {
inputVars = append(inputVars, c.gl.Reduce(input[i])) } - outputVars := c.HashNToMNoPad(inputVars, 4) - for i := 0; i < 4; i++ { + outputVars := c.HashNToMNoPad(inputVars, len(hash)) + for i := 0; i < len(hash); i++ { hash[i] = outputVars[i] }@@ -118,7 +118,7 @@ func (c *GoldilocksChip) constantLayer(state GoldilocksState, roundCounter *int) GoldilocksState {
for i := 0; i < 12; i++ { if i < SPONGE_WIDTH { roundConstant := ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)] - state[i] = c.gl.MulAdd(state[i], gl.NewVariable(1), gl.NewVariable(roundConstant)) + state[i] = c.gl.Add(state[i], gl.NewVariable(roundConstant)) } } return state@@ -169,7 +169,7 @@ }
return state } -func (c *GoldilocksChip) mdsRowShf(r int, v [SPONGE_WIDTH]gl.Variable) gl.Variable { +func (c *GoldilocksChip) mdsRowShf(r int, v GoldilocksState) gl.Variable { res := gl.Zero() for i := 0; i < 12; i++ {@@ -182,7 +182,7 @@ res = c.gl.MulAddNoReduce(v[r], gl.NewVariable(MDS_MATRIX_DIAG_VARS[r]), res)
return c.gl.Reduce(res) } -func (c *GoldilocksChip) MdsRowShfExtension(r int, v [SPONGE_WIDTH]gl.QuadraticExtensionVariable) gl.QuadraticExtensionVariable { +func (c *GoldilocksChip) MdsRowShfExtension(r int, v GoldilocksStateExtension) gl.QuadraticExtensionVariable { res := gl.ZeroExtension() for i := 0; i < 12; i++ {@@ -251,7 +251,7 @@
func (c *GoldilocksChip) mdsPartialLayerInit(state GoldilocksState) GoldilocksState { var result GoldilocksState for i := 0; i < 12; i++ { - result[i] = gl.NewVariable(0) + result[i] = gl.Zero() } result[0] = state[0]
@@ -118,5 +118,10 @@ commonCircuitData.NumPublicInputs = raw.NumPublicInputs
commonCircuitData.KIs = raw.KIs commonCircuitData.NumPartialProducts = raw.NumPartialProducts + // Don't support circuits that have hiding enabled + if raw.FriParams.Hiding { + panic("Circuit has hiding enabled, which is not supported") + } + return commonCircuitData }
@@ -1,21 +0,0 @@
-package types - -func ReductionArityBits( - arityBits uint64, - finalPolyBits uint64, - degreeBits uint64, - rateBits uint64, - capHeight uint64, -) []uint64 { - returnArr := make([]uint64, 0) - - for degreeBits > finalPolyBits && degreeBits+rateBits-arityBits >= capHeight { - returnArr = append(returnArr, arityBits) - if degreeBits < arityBits { - panic("degreeBits < arityBits") - } - degreeBits -= arityBits - } - - return returnArr -}
@@ -12,18 +12,6 @@ PartialProducts []gl.QuadraticExtensionVariable // Length = CommonCircuitData.NumChallenges * CommonCircuitData.NumPartialProducts
QuotientPolys []gl.QuadraticExtensionVariable // Length = CommonCircuitData.NumChallenges * CommonCircuitData.QuotientDegreeFactor } -func NewOpeningSet(numConstants uint64, numRoutedWires uint64, numWires uint64, numChallenges uint64, numPartialProducts uint64, quotientDegreeFactor uint64) OpeningSet { - return OpeningSet{ - Constants: make([]gl.QuadraticExtensionVariable, numConstants), - PlonkSigmas: make([]gl.QuadraticExtensionVariable, numRoutedWires), - Wires: make([]gl.QuadraticExtensionVariable, numWires), - PlonkZs: make([]gl.QuadraticExtensionVariable, numChallenges), - PlonkZsNext: make([]gl.QuadraticExtensionVariable, numChallenges), - PartialProducts: make([]gl.QuadraticExtensionVariable, numChallenges*numPartialProducts), - QuotientPolys: make([]gl.QuadraticExtensionVariable, numChallenges*quotientDegreeFactor), - } -} - type ProofChallenges struct { PlonkBetas []gl.Variable PlonkGammas []gl.Variable
@@ -76,7 +76,6 @@ FriChallenges: challenger.GetFriChallenges(
proof.OpeningProof.CommitPhaseMerkleCaps, proof.OpeningProof.FinalPoly, proof.OpeningProof.PowWitness, - c.commonData.DegreeBits, config.FriConfig, ), }@@ -119,8 +118,10 @@ }
// Range check the openings proof. for _, queryRound := range proof.OpeningProof.QueryRoundProofs { - for _, initialTreesElement := range queryRound.InitialTreesProof.EvalsProofs[0].Elements { - c.glChip.RangeCheck(initialTreesElement) + for _, evalsProof := range queryRound.InitialTreesProof.EvalsProofs { + for _, evalsProofElement := range evalsProof.Elements { + c.glChip.RangeCheck(evalsProofElement) + } } for _, queryStep := range queryRound.Steps {