From 9e963933f9ee321e6a25fc2b298db6a25f61f97c Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 12:35:12 -0800 Subject: [PATCH 01/32] fix for V-SCT-VUL-001 --- goldilocks/base.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/goldilocks/base.go b/goldilocks/base.go index 8c9e1d6..457a118 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -236,6 +236,8 @@ func (p *Chip) Inverse(x Variable) Variable { } inverse := NewVariable(result[0]) + p.RangeCheck(inverse) + product := p.Mul(inverse, x) p.api.AssertIsEqual(product.Limb, frontend.Variable(1)) return inverse From 85d20ce6569aaa4c71454f7976c2a5a724dcd159 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 12:46:53 -0800 Subject: [PATCH 02/32] fix for V-SCT-VUL-002 --- goldilocks/base.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/goldilocks/base.go b/goldilocks/base.go index 457a118..aa59b20 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -190,6 +190,9 @@ func (p *Chip) Reduce(x Variable) Variable { remainder := NewVariable(result[1]) p.RangeCheck(remainder) + + p.api.AssertIsEqual(x, p.api.Add(p.api.Mul(quotient, MODULUS), remainder.Limb)) + return remainder } From 2c361fa5e3ff709d488c7f10ed2e853ca4136d5d Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 12:54:36 -0800 Subject: [PATCH 03/32] fix for V-SCT-VUL-003 --- goldilocks/base.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/goldilocks/base.go b/goldilocks/base.go index aa59b20..9a27802 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -215,6 +215,9 @@ func (p *Chip) ReduceWithMaxBits(x Variable, maxNbBits uint64) Variable { remainder := NewVariable(result[1]) p.RangeCheck(remainder) + + p.api.AssertIsEqual(x, p.api.Add(p.api.Mul(quotient, MODULUS), remainder.Limb)) + return remainder } From a6707ed714fb544934213d5f4b0afb3d5c1a7aea Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 13:04:43 -0800 Subject: [PATCH 04/32] fix for V-SCT-VUL-004 --- goldilocks/base.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/goldilocks/base.go b/goldilocks/base.go index 9a27802..2eae792 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -131,7 +131,8 @@ func (p *Chip) MulAdd(a Variable, b Variable, c Variable) Variable { 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) @@ -143,7 +144,8 @@ func (p *Chip) MulAdd(a Variable, b Variable, c Variable) Variable { // Multiplies two field elements and adds a field element such that x * y + z = c within the // Golidlocks field without reducing. 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. From 6af5b0ae93be22fb0502bfdcb05029e2ef8e893d Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 13:13:13 -0800 Subject: [PATCH 05/32] fix for V-SCT-VUL-005 --- verifier/verifier.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 2ec08e5..c02f1eb 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -119,8 +119,10 @@ func (c *VerifierChip) rangeCheckProof(proof variables.Proof) { // 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 { From 297a82025f476ac0268cfec3852735e06c637f31 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 15:42:09 -0800 Subject: [PATCH 06/32] fix for V-SCT-VUL-002 and V-SCT-VUL-003 --- goldilocks/base.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/goldilocks/base.go b/goldilocks/base.go index 2eae792..9a53ab6 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -193,7 +193,7 @@ func (p *Chip) Reduce(x Variable) Variable { remainder := NewVariable(result[1]) p.RangeCheck(remainder) - p.api.AssertIsEqual(x, p.api.Add(p.api.Mul(quotient, MODULUS), remainder.Limb)) + p.api.AssertIsEqual(x.Limb, p.api.Add(p.api.Mul(quotient, MODULUS), remainder.Limb)) return remainder } @@ -218,7 +218,7 @@ func (p *Chip) ReduceWithMaxBits(x Variable, maxNbBits uint64) Variable { remainder := NewVariable(result[1]) p.RangeCheck(remainder) - p.api.AssertIsEqual(x, p.api.Add(p.api.Mul(quotient, MODULUS), remainder.Limb)) + p.api.AssertIsEqual(x.Limb, p.api.Add(p.api.Mul(quotient, MODULUS), remainder.Limb)) return remainder } From cc51ec1815bc70b46b8fad274a4c408e59cfe9e7 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 16:09:08 -0800 Subject: [PATCH 07/32] fix for V-SCT-VUL-007 and V-SCT-VUL-011 --- fri/fri.go | 36 ++++++++++++++++---------- goldilocks/base.go | 19 +++++++++++--- goldilocks/quadratic_extension.go | 11 +++++--- goldilocks/quadratic_extension_test.go | 2 +- plonk/plonk.go | 7 ++++- 5 files changed, 52 insertions(+), 23 deletions(-) diff --git a/fri/fri.go b/fri/fri.go index 80d300f..b43eb2c 100644 --- a/fri/fri.go +++ b/fri/fri.go @@ -238,9 +238,11 @@ func (f *Chip) friCombineInitial( 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 @@ func (f *Chip) interpolate( } 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 @@ func (f *Chip) interpolate( 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( @@ -367,7 +375,9 @@ func (f *Chip) computeEvaluation( } // 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) diff --git a/goldilocks/base.go b/goldilocks/base.go index 9a53ab6..2bcd8cd 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -237,18 +237,21 @@ func ReduceHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error { } // Computes the inverse of a field element x such that x * x^-1 = 1. -func (p *Chip) Inverse(x Variable) Variable { - result, err := p.api.Compiler().NewHint(InverseHint, 1, x.Limb) +func (p *Chip) Inverse(x Variable) (Variable, frontend.Variable) { + result, err := p.api.Compiler().NewHint(InverseHint, 2, x.Limb) if err != nil { panic(err) } inverse := NewVariable(result[0]) + hasInv := frontend.Variable(result[1]) 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. @@ -264,11 +267,19 @@ func InverseHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error { inputGl := goldilocks.NewElement(input.Uint64()) resultGl := goldilocks.NewElement(0) + + // Will set resultGL if inputGL == 0 resultGl.Inverse(&inputGl) result := big.NewInt(0) results[0] = resultGl.BigInt(result) + hasInvInt64 := int64(0) + if !inputGl.IsZero() { + hasInvInt64 = 1 + } + results[1] = big.NewInt(hasInvInt64) + return nil } diff --git a/goldilocks/quadratic_extension.go b/goldilocks/quadratic_extension.go index d384300..38e77d3 100644 --- a/goldilocks/quadratic_extension.go +++ b/goldilocks/quadratic_extension.go @@ -126,7 +126,7 @@ func (p *Chip) InnerProductExtension( } // Computes the inverse of a quadratic extension variable in the Goldilocks field. -func (p *Chip) InverseExtension(a QuadraticExtensionVariable) QuadraticExtensionVariable { +func (p *Chip) InverseExtension(a QuadraticExtensionVariable) (QuadraticExtensionVariable, frontend.Variable) { 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)) @@ -135,12 +135,15 @@ func (p *Chip) InverseExtension(a QuadraticExtensionVariable) QuadraticExtension 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. diff --git a/goldilocks/quadratic_extension_test.go b/goldilocks/quadratic_extension_test.go index 9521daf..54e94ee 100644 --- a/goldilocks/quadratic_extension_test.go +++ b/goldilocks/quadratic_extension_test.go @@ -59,7 +59,7 @@ type TestQuadraticExtensionDivCircuit struct { 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 diff --git a/plonk/plonk.go b/plonk/plonk.go index 00cfc86..ac2348c 100644 --- a/plonk/plonk.go +++ b/plonk/plonk.go @@ -71,10 +71,15 @@ func (p *PlonkChip) evalL0(x gl.QuadraticExtensionVariable, xPowN gl.QuadraticEx 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( From c0cbac84232218d90b0ebcf90492afd63328ef0f Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 16:29:57 -0800 Subject: [PATCH 08/32] fix for V-SCT-VUL-008 --- fri/fri.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fri/fri.go b/fri/fri.go index b43eb2c..7b74c3a 100644 --- a/fri/fri.go +++ b/fri/fri.go @@ -335,7 +335,7 @@ func (f *Chip) computeEvaluation( // 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++ { + for i := uint8(0); i <= uint8(len(evals)-1); i++ { newIndex := bits.Reverse8(i) >> arityBits permutedEvals[newIndex] = evals[i] } From 5766879636cd88894976fe2db9a10c2684dda193 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 17:09:06 -0800 Subject: [PATCH 09/32] fix for V-SCT-VUL-00 and V-SCT-VUL-010 --- poseidon/bn254.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/poseidon/bn254.go b/poseidon/bn254.go index 77ac7ce..4291efd 100644 --- a/poseidon/bn254.go +++ b/poseidon/bn254.go @@ -76,8 +76,10 @@ func (c *BN254Chip) HashOrNoop(input []gl.Variable) BN254HashOut { 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, mulFactor) } return BN254HashOut(returnVal) From 5dd6da255e7058d9ccb38777c7f7082bac6ec477 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 17:19:15 -0800 Subject: [PATCH 10/32] fix for V-SCT-VUL-013 --- plonk/gates/coset_interpolation_gate.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plonk/gates/coset_interpolation_gate.go b/plonk/gates/coset_interpolation_gate.go index 58e53da..f8f2494 100644 --- a/plonk/gates/coset_interpolation_gate.go +++ b/plonk/gates/coset_interpolation_gate.go @@ -199,6 +199,10 @@ func (g *CosetInterpolationGate) EvalUnfiltered( 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], From 2043890a764027119a0a575696d14555c92bee56 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 17:23:58 -0800 Subject: [PATCH 11/32] fix for V-SCT-VUL-014 --- goldilocks/base.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/goldilocks/base.go b/goldilocks/base.go index 2bcd8cd..8cc16f9 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -394,7 +394,7 @@ func TwoAdicSubgroup(nLog uint64) []goldilocks.Element { rootOfUnity := PrimitiveRootOfUnity(nLog) res = append(res, goldilocks.NewElement(1)) - for i := 0; i < (1 << nLog); i++ { + for i := 0; i < (1< Date: Mon, 18 Dec 2023 17:58:56 -0800 Subject: [PATCH 12/32] fix for V-SCT-VUL-015 --- challenger/challenger.go | 4 ++-- goldilocks/base.go | 20 +++----------------- goldilocks/quadratic_extension.go | 19 ++++++------------- goldilocks/quadratic_extension_algebra.go | 2 +- plonk/gates/reducing_gate.go | 6 +----- poseidon/goldilocks.go | 12 ++++++------ 6 files changed, 19 insertions(+), 44 deletions(-) diff --git a/challenger/challenger.go b/challenger/challenger.go index b61f2a5..4827d8c 100644 --- a/challenger/challenger.go +++ b/challenger/challenger.go @@ -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++ { diff --git a/goldilocks/base.go b/goldilocks/base.go index 8cc16f9..5c64706 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -102,12 +102,12 @@ func (p *Chip) AddNoReduce(a Variable, b Variable) Variable { // Subtracts two field elements such that x + y = z within the Golidlocks 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. 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. @@ -181,21 +181,7 @@ func (p *Chip) Reduce(x Variable) Variable { // 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) - - p.api.AssertIsEqual(x.Limb, p.api.Add(p.api.Mul(quotient, MODULUS), remainder.Limb)) - - return remainder + return p.ReduceWithMaxBits(x, uint64(RANGE_CHECK_NB_BITS)) } // Reduces a field element x such that x % MODULUS = y. diff --git a/goldilocks/quadratic_extension.go b/goldilocks/quadratic_extension.go index 38e77d3..9b9fecc 100644 --- a/goldilocks/quadratic_extension.go +++ b/goldilocks/quadratic_extension.go @@ -58,15 +58,13 @@ func (p *Chip) SubExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticEx // 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 @@ func (p *Chip) MulExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticEx 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 { @@ -93,9 +89,7 @@ func (p *Chip) MulAddExtensionNoReduce(a, b, c QuadraticExtensionVariable) Quadr 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. @@ -127,9 +121,8 @@ func (p *Chip) InnerProductExtension( // Computes the inverse of a quadratic extension variable in the Goldilocks field. func (p *Chip) InverseExtension(a QuadraticExtensionVariable) (QuadraticExtensionVariable, frontend.Variable) { - 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)) + aIsZero := p.IsZero(a) + p.api.AssertIsEqual(aIsZero, frontend.Variable(0)) aPowRMinus1 := QuadraticExtensionVariable{ a[0], p.Mul(a[1], NewVariable(DTH_ROOT)), diff --git a/goldilocks/quadratic_extension_algebra.go b/goldilocks/quadratic_extension_algebra.go index 9ce1028..d3d5aa2 100644 --- a/goldilocks/quadratic_extension_algebra.go +++ b/goldilocks/quadratic_extension_algebra.go @@ -14,7 +14,7 @@ func NewQuadraticExtensionAlgebraVariable( } func (p QuadraticExtensionVariable) ToQuadraticExtensionAlgebra() QuadraticExtensionAlgebraVariable { - return [2]QuadraticExtensionVariable{p, ZeroExtension()} + return [D]QuadraticExtensionVariable{p, ZeroExtension()} } func ZeroExtensionAlgebra() QuadraticExtensionAlgebraVariable { diff --git a/plonk/gates/reducing_gate.go b/plonk/gates/reducing_gate.go index 2212f2b..56ed7ce 100644 --- a/plonk/gates/reducing_gate.go +++ b/plonk/gates/reducing_gate.go @@ -96,11 +96,7 @@ func (g *ReducingGate) EvalUnfiltered( 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]) diff --git a/poseidon/goldilocks.go b/poseidon/goldilocks.go index 7fd6c34..66e6b96 100644 --- a/poseidon/goldilocks.go +++ b/poseidon/goldilocks.go @@ -77,8 +77,8 @@ func (c *GoldilocksChip) HashNoPad(input []gl.Variable) GoldilocksHashOut { 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) 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 @@ func (c *GoldilocksChip) SBoxLayerExtension(state GoldilocksStateExtension) Gold 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 @@ func (c *GoldilocksChip) mdsRowShf(r int, v [SPONGE_WIDTH]gl.Variable) gl.Variab 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) PartialFirstConstantLayerExtension(state GoldilocksStat 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] From ac49898dd16a8b3983781780503e470de56656f4 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 18:02:01 -0800 Subject: [PATCH 13/32] fix for V-SCT-VUL-016 --- goldilocks/base.go | 3 --- poseidon/goldilocks.go | 1 - types/utils.go | 21 --------------------- variables/plonk.go | 12 ------------ 4 files changed, 37 deletions(-) delete mode 100644 types/utils.go diff --git a/goldilocks/base.go b/goldilocks/base.go index 5c64706..0c7477c 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -38,9 +38,6 @@ var POWER_OF_TWO_GENERATOR goldilocks.Element = goldilocks.NewElement(1753635133 // 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 diff --git a/poseidon/goldilocks.go b/poseidon/goldilocks.go index 66e6b96..68128f0 100644 --- a/poseidon/goldilocks.go +++ b/poseidon/goldilocks.go @@ -7,7 +7,6 @@ import ( const HALF_N_FULL_ROUNDS = 4 const N_PARTIAL_ROUNDS = 22 -const MAX_WIDTH = 12 const SPONGE_WIDTH = 12 const SPONGE_RATE = 8 diff --git a/types/utils.go b/types/utils.go deleted file mode 100644 index e7bcae5..0000000 --- a/types/utils.go +++ /dev/null @@ -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 -} diff --git a/variables/plonk.go b/variables/plonk.go index 1fc30f7..245a01e 100644 --- a/variables/plonk.go +++ b/variables/plonk.go @@ -12,18 +12,6 @@ type OpeningSet struct { 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 From 2fab6a94b00197999c5ca17c0502e5e515ddcb6e Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 18:03:48 -0800 Subject: [PATCH 14/32] fix for V-SCT-VUL-017 --- fri/fri.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fri/fri.go b/fri/fri.go index 7b74c3a..c1ce7a9 100644 --- a/fri/fri.go +++ b/fri/fri.go @@ -336,7 +336,7 @@ func (f *Chip) computeEvaluation( // we can just hard code the permutation. permutedEvals := make([]gl.QuadraticExtensionVariable, len(evals)) for i := uint8(0); i <= uint8(len(evals)-1); i++ { - newIndex := bits.Reverse8(i) >> arityBits + newIndex := bits.Reverse8(i) >> (8 - arityBits) permutedEvals[newIndex] = evals[i] } From 0f6466c0471cccd81b5885c62f3dc15c60f5c441 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 18:26:42 -0800 Subject: [PATCH 15/32] fix for V-SCT-VUL-018 --- challenger/challenger.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/challenger/challenger.go b/challenger/challenger.go index 4827d8c..eeb1c9e 100644 --- a/challenger/challenger.go +++ b/challenger/challenger.go @@ -40,7 +40,8 @@ func NewChip(api frontend.API) *Chip { } 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() @@ -143,10 +144,6 @@ func (c *Chip) GetFriChallenges( } } -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 +155,12 @@ func (c *Chip) duplexing() { 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]) } From 30d73dacea64a92d112da98fc6a27f5b898b1fc8 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Mon, 18 Dec 2023 18:31:56 -0800 Subject: [PATCH 16/32] fix for V-SCT-VUL-020 --- challenger/challenger.go | 1 - fri/fri_test.go | 1 - verifier/verifier.go | 1 - 3 files changed, 3 deletions(-) diff --git a/challenger/challenger.go b/challenger/challenger.go index eeb1c9e..008b6f7 100644 --- a/challenger/challenger.go +++ b/challenger/challenger.go @@ -118,7 +118,6 @@ func (c *Chip) GetFriChallenges( commitPhaseMerkleCaps []variables.FriMerkleCap, finalPoly variables.PolynomialCoeffs, powWitness gl.Variable, - degreeBits uint64, config types.FriConfig, ) variables.FriChallenges { numFriQueries := config.NumQueryRounds diff --git a/fri/fri_test.go b/fri/fri_test.go index 6634bdf..a094421 100644 --- a/fri/fri_test.go +++ b/fri/fri_test.go @@ -52,7 +52,6 @@ func (circuit *TestFriCircuit) Define(api frontend.API) error { proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps, proofWithPis.Proof.OpeningProof.FinalPoly, proofWithPis.Proof.OpeningProof.PowWitness, - commonCircuitData.DegreeBits, commonCircuitData.Config.FriConfig, ) diff --git a/verifier/verifier.go b/verifier/verifier.go index c02f1eb..0d47f23 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -76,7 +76,6 @@ func (c *VerifierChip) GetChallenges( proof.OpeningProof.CommitPhaseMerkleCaps, proof.OpeningProof.FinalPoly, proof.OpeningProof.PowWitness, - c.commonData.DegreeBits, config.FriConfig, ), } From cc064aeb3ea7b348dad43988d2b481de94c3faef Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 09:46:19 -0800 Subject: [PATCH 17/32] fix for V-SCT-VUL-021 --- plonk/gates/base_sum_gate.go | 2 +- plonk/gates/multiplication_extension_gate.go | 2 +- plonk/gates/reducing_extension_gate.go | 2 +- plonk/gates/reducing_gate.go | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plonk/gates/base_sum_gate.go b/plonk/gates/base_sum_gate.go index aff6db6..444d188 100644 --- a/plonk/gates/base_sum_gate.go +++ b/plonk/gates/base_sum_gate.go @@ -51,7 +51,7 @@ func NewBaseSumGate(numLimbs uint64, base uint64) *BaseSumGate { } 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 { diff --git a/plonk/gates/multiplication_extension_gate.go b/plonk/gates/multiplication_extension_gate.go index 37cec16..7948138 100644 --- a/plonk/gates/multiplication_extension_gate.go +++ b/plonk/gates/multiplication_extension_gate.go @@ -37,7 +37,7 @@ func NewMultiplicationExtensionGate(numOps uint64) *MultiplicationExtensionGate } 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 { diff --git a/plonk/gates/reducing_extension_gate.go b/plonk/gates/reducing_extension_gate.go index 2d71c07..51ad757 100644 --- a/plonk/gates/reducing_extension_gate.go +++ b/plonk/gates/reducing_extension_gate.go @@ -39,7 +39,7 @@ func NewReducingExtensionGate(numCoeffs uint64) *ReducingExtensionGate { } 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 { diff --git a/plonk/gates/reducing_gate.go b/plonk/gates/reducing_gate.go index 56ed7ce..cb212e6 100644 --- a/plonk/gates/reducing_gate.go +++ b/plonk/gates/reducing_gate.go @@ -39,7 +39,7 @@ func NewReducingGate(numCoeffs uint64) *ReducingGate { } 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 { From 318c3ce9de90eb1ac90a0acd70b21821d0fa2040 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 10:51:43 -0800 Subject: [PATCH 18/32] fix for V-SCT-VUL-022 --- fri/fri.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fri/fri.go b/fri/fri.go index c1ce7a9..fe1f6eb 100644 --- a/fri/fri.go +++ b/fri/fri.go @@ -128,13 +128,15 @@ func (f *Chip) verifyMerkleProofToCapWithCapIndex( } 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], ) } From 888b247e02007c70c00fa277bf96ae11c56773f0 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 10:56:25 -0800 Subject: [PATCH 19/32] fix for V-SCT-VUL-023 --- plonk/gates/coset_interpolation_gate.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plonk/gates/coset_interpolation_gate.go b/plonk/gates/coset_interpolation_gate.go index f8f2494..a9a835d 100644 --- a/plonk/gates/coset_interpolation_gate.go +++ b/plonk/gates/coset_interpolation_gate.go @@ -32,6 +32,9 @@ func deserializeCosetInterpolationGate(parameters map[string]string) Gate { 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)) From 7c7a01a3951876db1777ade08be3ed34c03c349a Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 11:04:30 -0800 Subject: [PATCH 20/32] fix for V-SCT-VUL-024 --- challenger/challenger.go | 2 +- poseidon/goldilocks.go | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/challenger/challenger.go b/challenger/challenger.go index 008b6f7..20da42a 100644 --- a/challenger/challenger.go +++ b/challenger/challenger.go @@ -111,7 +111,7 @@ func (c *Chip) GetExtensionChallenge() gl.QuadraticExtensionVariable { } 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( diff --git a/poseidon/goldilocks.go b/poseidon/goldilocks.go index 68128f0..7fe658c 100644 --- a/poseidon/goldilocks.go +++ b/poseidon/goldilocks.go @@ -9,10 +9,11 @@ const HALF_N_FULL_ROUNDS = 4 const N_PARTIAL_ROUNDS = 22 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:"-"` From 40d71e9e29c3c534f39323599c86d2333373ddcf Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 11:07:36 -0800 Subject: [PATCH 21/32] fix for V-SCT-VUL-025 --- poseidon/bn254.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/poseidon/bn254.go b/poseidon/bn254.go index 4291efd..4975415 100644 --- a/poseidon/bn254.go +++ b/poseidon/bn254.go @@ -79,7 +79,7 @@ func (c *BN254Chip) HashOrNoop(input []gl.Variable) BN254HashOut { alpha = new(big.Int).Mul(alpha, alpha) for i, inputElement := range input { mulFactor := new(big.Int).Exp(alpha, big.NewInt(int64(i)), nil) - returnVal = c.api.MulAcc(returnVal, inputElement, mulFactor) + returnVal = c.api.MulAcc(returnVal, inputElement.Limb, mulFactor) } return BN254HashOut(returnVal) From f256ca69f371476562509630768b7f4ad66e99cd Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 12:22:19 -0800 Subject: [PATCH 22/32] fix for V-SCT-VUL-027 --- README.md | 2 +- fri/fri.go | 6 +++++- goldilocks/base.go | 23 +++++++++++++---------- goldilocks/quadratic_extension.go | 4 ++-- plonk/gates/random_access_gate.go | 2 +- plonk/gates/reducing_extension_gate.go | 2 +- 6 files changed, 23 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 6279013..c9ad72f 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Besides the verifier, there are some Gnark implementation of circuits in this re ## Requirements -- [Go (1.20.1+)](https://go.dev/doc/install) +- [Go (1.19+)](https://go.dev/doc/install) ## Benchmark diff --git a/fri/fri.go b/fri/fri.go index fe1f6eb..5455578 100644 --- a/fri/fri.go +++ b/fri/fri.go @@ -73,11 +73,15 @@ func (f *Chip) ToOpenings(c variables.OpeningSet) Openings { } 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 + + // TODO: This does an un-nessary reduce, since powWitness is already range checked to be within GL field. reducedPowWitness := f.gl.Reduce(powWitness) + + // TODO: Can replace with with std.rangecheck.Check. Will probably be less contraints. f.api.AssertIsLessOrEqual(reducedPowWitness.Limb, frontend.Variable(maxPowWitness)) } diff --git a/goldilocks/base.go b/goldilocks/base.go index 0c7477c..ba8ac8b 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -87,38 +87,41 @@ func New(api frontend.API) *Chip { 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, 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, 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 { @@ -138,8 +141,8 @@ func (p *Chip) MulAdd(a Variable, b Variable, c Variable) Variable { 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 { cLimbCopy := p.api.Mul(c.Limb, 1) return NewVariable(p.api.MulAcc(cLimbCopy, a.Limb, b.Limb)) diff --git a/goldilocks/quadratic_extension.go b/goldilocks/quadratic_extension.go index 9b9fecc..e583165 100644 --- a/goldilocks/quadratic_extension.go +++ b/goldilocks/quadratic_extension.go @@ -84,7 +84,7 @@ func (p *Chip) MulAddExtensionNoReduce(a, b, c QuadraticExtensionVariable) Quadr 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) @@ -209,7 +209,7 @@ func (p *Chip) Lookup( 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, diff --git a/plonk/gates/random_access_gate.go b/plonk/gates/random_access_gate.go index 5d1e0a8..8c3c459 100644 --- a/plonk/gates/random_access_gate.go +++ b/plonk/gates/random_access_gate.go @@ -151,7 +151,7 @@ func (g *RandomAccessGate) EvalUnfiltered( y := listItems[i+1] // This is computing `if b { x } else { y }` - // i.e. `bx - (by-y)`. + // i.e. `by - (bx - x)`. mul1 := glApi.MulExtension(b, x) sub1 := glApi.SubExtension(mul1, x) diff --git a/plonk/gates/reducing_extension_gate.go b/plonk/gates/reducing_extension_gate.go index 51ad757..fd92f2d 100644 --- a/plonk/gates/reducing_extension_gate.go +++ b/plonk/gates/reducing_extension_gate.go @@ -12,7 +12,7 @@ import ( var reducingExtensionGateRegex = regexp.MustCompile("ReducingExtensionGate { num_coeffs: (?P[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") From de0ff4f698468801468be081abd72f6f1519a1fb Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 12:25:29 -0800 Subject: [PATCH 23/32] fix for V-SCT-VUL-028 --- fri/fri.go | 8 +++---- plonk/gates/arithmetic_extension_gate.go | 2 +- plonk/gates/arithmetic_gate.go | 2 +- plonk/gates/gates.go | 28 ++++++++++++------------ 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/fri/fri.go b/fri/fri.go index 5455578..a422d80 100644 --- a/fri/fri.go +++ b/fri/fri.go @@ -49,14 +49,14 @@ func (f *Chip) GetInstance(zeta gl.QuadraticExtensionVariable) InstanceInfo { 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}, } } @@ -168,7 +168,7 @@ func (f *Chip) expFromBitsConstBase( ) 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 @@ -326,7 +326,7 @@ func (f *Chip) computeEvaluation( ) 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") diff --git a/plonk/gates/arithmetic_extension_gate.go b/plonk/gates/arithmetic_extension_gate.go index e09ed2a..7391798 100644 --- a/plonk/gates/arithmetic_extension_gate.go +++ b/plonk/gates/arithmetic_extension_gate.go @@ -9,7 +9,7 @@ import ( gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" ) -var aritheticExtensionGateRegex = regexp.MustCompile("ArithmeticExtensionGate { num_ops: (?P[0-9]+) }") +var arithmeticExtensionGateRegex = regexp.MustCompile("ArithmeticExtensionGate { num_ops: (?P[0-9]+) }") func deserializeExtensionArithmeticGate(parameters map[string]string) Gate { // Has the format "ArithmeticExtensionGate { num_ops: 10 }" diff --git a/plonk/gates/arithmetic_gate.go b/plonk/gates/arithmetic_gate.go index 7867cb0..f248bc4 100644 --- a/plonk/gates/arithmetic_gate.go +++ b/plonk/gates/arithmetic_gate.go @@ -9,7 +9,7 @@ import ( gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" ) -var aritheticGateRegex = regexp.MustCompile("ArithmeticGate { num_ops: (?P[0-9]+) }") +var arithmeticGateRegex = regexp.MustCompile("ArithmeticGate { num_ops: (?P[0-9]+) }") func deserializeArithmeticGate(parameters map[string]string) Gate { // Has the format "ArithmeticGate { num_ops: 10 }" diff --git a/plonk/gates/gates.go b/plonk/gates/gates.go index edd98d4..a10aee8 100644 --- a/plonk/gates/gates.go +++ b/plonk/gates/gates.go @@ -18,20 +18,20 @@ type Gate interface { } 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 { From 06f91e4465966beec8fdb742db1afbef1ed17aeb Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 13:00:22 -0800 Subject: [PATCH 24/32] fix for V-SCT-VUL-029 --- plonk/gates/exponentiation_gate.go | 14 ++++++++++++++ plonk/gates/random_access_gate.go | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/plonk/gates/exponentiation_gate.go b/plonk/gates/exponentiation_gate.go index ccf02e6..eff38b4 100644 --- a/plonk/gates/exponentiation_gate.go +++ b/plonk/gates/exponentiation_gate.go @@ -23,6 +23,20 @@ func deserializeExponentiationGate(parameters map[string]string) Gate { 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)) } diff --git a/plonk/gates/random_access_gate.go b/plonk/gates/random_access_gate.go index 8c3c459..aba32d0 100644 --- a/plonk/gates/random_access_gate.go +++ b/plonk/gates/random_access_gate.go @@ -36,6 +36,20 @@ func deserializeRandomAccessGate(parameters map[string]string) Gate { 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) } From e3eff27eb14157ffbf86e40b5e559fe437ab520d Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 13:06:15 -0800 Subject: [PATCH 25/32] fix for V-SCT-VUL-030 --- plonk/gates/poseidon_mds_gate.go | 4 +++- plonk/gates/public_input_gate.go | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/plonk/gates/poseidon_mds_gate.go b/plonk/gates/poseidon_mds_gate.go index f03319d..db23e9a 100644 --- a/plonk/gates/poseidon_mds_gate.go +++ b/plonk/gates/poseidon_mds_gate.go @@ -90,7 +90,9 @@ func (g *PoseidonMdsGate) EvalUnfiltered( 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 diff --git a/plonk/gates/public_input_gate.go b/plonk/gates/public_input_gate.go index 9fad5e7..caf780e 100644 --- a/plonk/gates/public_input_gate.go +++ b/plonk/gates/public_input_gate.go @@ -38,7 +38,7 @@ func (g *PublicInputGate) EvalUnfiltered( 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] From 49511611b595db6597f4ab90d621876b067f1dbd Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 13:24:27 -0800 Subject: [PATCH 26/32] fix for V-SCT-VUL-031 --- poseidon/bn254.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/poseidon/bn254.go b/poseidon/bn254.go index 4975415..25ad83c 100644 --- a/poseidon/bn254.go +++ b/poseidon/bn254.go @@ -10,6 +10,7 @@ package poseidon 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)} } From 9e6d08b99c83a064c97c23a17f7968573d2230e0 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 13:27:00 -0800 Subject: [PATCH 27/32] fix for V-SCT-VUL-032 --- plonk/gates/constant_gate.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plonk/gates/constant_gate.go b/plonk/gates/constant_gate.go index e263139..da7d852 100644 --- a/plonk/gates/constant_gate.go +++ b/plonk/gates/constant_gate.go @@ -41,14 +41,14 @@ func (g *ConstantGate) Id() string { } 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 From 8567f335cb6d572e9a890d6fb65683f93b292fe3 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 13:31:36 -0800 Subject: [PATCH 28/32] fix for V-SCT-VUL-033 --- plonk/gates/random_access_gate.go | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/plonk/gates/random_access_gate.go b/plonk/gates/random_access_gate.go index aba32d0..ca49934 100644 --- a/plonk/gates/random_access_gate.go +++ b/plonk/gates/random_access_gate.go @@ -165,14 +165,12 @@ func (g *RandomAccessGate) EvalUnfiltered( y := listItems[i+1] // This is computing `if b { x } else { y }` - // i.e. `by - (bx - x)`. - mul1 := glApi.MulExtension(b, x) - sub1 := glApi.SubExtension(mul1, x) + // i.e. `x + b(y - x)`. + diff := glApi.SubExtension(y, x) + mul := glApi.MulExtension(b, diff) + add := glApi.AddExtension(x, mul) - mul2 := glApi.MulExtension(b, y) - sub2 := glApi.SubExtension(mul2, sub1) - - listItemsTmp = append(listItemsTmp, sub2) + listItemsTmp = append(listItemsTmp, add) } listItems = listItemsTmp } From f71795a697d57969e7e408e6bd3baa2a923804df Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 19 Dec 2023 15:49:01 -0800 Subject: [PATCH 29/32] fix for V-SCT-VUL-006 and V-SCT-VUL-012 --- types/common_data.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/types/common_data.go b/types/common_data.go index 9117e89..c3a6177 100644 --- a/types/common_data.go +++ b/types/common_data.go @@ -118,5 +118,10 @@ func ReadCommonCircuitData(path string) CommonCircuitData { 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 } From 1a0372621cbc4aa8f76623cae72caec04db530a3 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Thu, 21 Dec 2023 14:20:23 -0800 Subject: [PATCH 30/32] removed Exp in goldilocks/base.go per V-SCT-VUL-016 --- goldilocks/base.go | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/goldilocks/base.go b/goldilocks/base.go index ba8ac8b..e49eaf1 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -269,28 +269,6 @@ func InverseHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error { 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 { From daad394f734c7641625d1d2b573a13ad266001c2 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Fri, 22 Dec 2023 11:42:53 -0800 Subject: [PATCH 31/32] constraint optimizations for assertLeadingZeros --- fri/fri.go | 10 ++-------- goldilocks/base.go | 5 +++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/fri/fri.go b/fri/fri.go index a422d80..e71d6e3 100644 --- a/fri/fri.go +++ b/fri/fri.go @@ -75,14 +75,8 @@ func (f *Chip) ToOpenings(c variables.OpeningSet) Openings { func (f *Chip) assertLeadingZeros(powWitness gl.Variable, friConfig types.FriConfig) { // 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 - - // TODO: This does an un-nessary reduce, since powWitness is already range checked to be within GL field. - reducedPowWitness := f.gl.Reduce(powWitness) - - // TODO: Can replace with with std.rangecheck.Check. Will probably be less contraints. - f.api.AssertIsLessOrEqual(reducedPowWitness.Limb, frontend.Variable(maxPowWitness)) + // field is 64 bits long. + f.gl.RangeCheckWithMaxBits(powWitness, 64-friConfig.ProofOfWorkBits) } func (f *Chip) fromOpeningsAndAlpha( diff --git a/goldilocks/base.go b/goldilocks/base.go index e49eaf1..bc7b3bd 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -333,6 +333,11 @@ func (p *Chip) RangeCheck(x Variable) { ) } +// 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) } From d241f54f485be2ba27ee23642aa2090004ef8b83 Mon Sep 17 00:00:00 2001 From: Kevin Jue Date: Tue, 26 Dec 2023 07:49:55 -0800 Subject: [PATCH 32/32] address veridise feedback for V-SCT-VUL-007 and V-SCT-VUL-011 (hasInv needed to be constrained) --- goldilocks/base.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/goldilocks/base.go b/goldilocks/base.go index e49eaf1..4f4c96e 100644 --- a/goldilocks/base.go +++ b/goldilocks/base.go @@ -224,13 +224,14 @@ func ReduceHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error { // Computes the inverse of a field element x such that x * x^-1 = 1. func (p *Chip) Inverse(x Variable) (Variable, frontend.Variable) { - result, err := p.api.Compiler().NewHint(InverseHint, 2, x.Limb) + result, err := p.api.Compiler().NewHint(InverseHint, 1, x.Limb) if err != nil { panic(err) } inverse := NewVariable(result[0]) - hasInv := frontend.Variable(result[1]) + isZero := p.api.IsZero(x.Limb) + hasInv := p.api.Sub(1, isZero) p.RangeCheck(inverse) product := p.Mul(inverse, x) @@ -260,12 +261,6 @@ func InverseHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error { result := big.NewInt(0) results[0] = resultGl.BigInt(result) - hasInvInt64 := int64(0) - if !inputGl.IsZero() { - hasInvInt64 = 1 - } - results[1] = big.NewInt(hasInvInt64) - return nil }