Browse Source

Merge pull request #42 from succinctlabs/kevjue/audit_fixes

fix: Veridise audit fixes
main
Kevin Jue 1 year ago
committed by GitHub
parent
commit
b064847007
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 203 additions and 198 deletions
  1. +1
    -1
      README.md
  2. +10
    -11
      challenger/challenger.go
  3. +36
    -26
      fri/fri.go
  4. +0
    -1
      fri/fri_test.go
  5. +40
    -55
      goldilocks/base.go
  6. +15
    -19
      goldilocks/quadratic_extension.go
  7. +1
    -1
      goldilocks/quadratic_extension_algebra.go
  8. +1
    -1
      goldilocks/quadratic_extension_test.go
  9. +1
    -1
      plonk/gates/arithmetic_extension_gate.go
  10. +1
    -1
      plonk/gates/arithmetic_gate.go
  11. +1
    -1
      plonk/gates/base_sum_gate.go
  12. +2
    -2
      plonk/gates/constant_gate.go
  13. +7
    -0
      plonk/gates/coset_interpolation_gate.go
  14. +14
    -0
      plonk/gates/exponentiation_gate.go
  15. +14
    -14
      plonk/gates/gates.go
  16. +1
    -1
      plonk/gates/multiplication_extension_gate.go
  17. +3
    -1
      plonk/gates/poseidon_mds_gate.go
  18. +1
    -1
      plonk/gates/public_input_gate.go
  19. +19
    -7
      plonk/gates/random_access_gate.go
  20. +2
    -2
      plonk/gates/reducing_extension_gate.go
  21. +2
    -6
      plonk/gates/reducing_gate.go
  22. +6
    -1
      plonk/plonk.go
  23. +8
    -1
      poseidon/bn254.go
  24. +8
    -8
      poseidon/goldilocks.go
  25. +5
    -0
      types/common_data.go
  26. +0
    -21
      types/utils.go
  27. +0
    -12
      variables/plonk.go
  28. +4
    -3
      verifier/verifier.go

+ 1
- 1
README.md

@ -10,7 +10,7 @@ Besides the verifier, there are some Gnark implementation of circuits in this re
## Requirements ## Requirements
- [Go (1.20.1+)](https://go.dev/doc/install)
- [Go (1.19+)](https://go.dev/doc/install)
## Benchmark ## Benchmark

+ 10
- 11
challenger/challenger.go

@ -15,13 +15,13 @@ type Chip struct {
api frontend.API `gnark:"-"` api frontend.API `gnark:"-"`
poseidonChip *poseidon.GoldilocksChip poseidonChip *poseidon.GoldilocksChip
poseidonBN254Chip *poseidon.BN254Chip poseidonBN254Chip *poseidon.BN254Chip
spongeState [poseidon.SPONGE_WIDTH]gl.Variable
spongeState poseidon.GoldilocksState
inputBuffer []gl.Variable inputBuffer []gl.Variable
outputBuffer []gl.Variable outputBuffer []gl.Variable
} }
func NewChip(api frontend.API) *Chip { func NewChip(api frontend.API) *Chip {
var spongeState [poseidon.SPONGE_WIDTH]gl.Variable
var spongeState poseidon.GoldilocksState
var inputBuffer []gl.Variable var inputBuffer []gl.Variable
var outputBuffer []gl.Variable var outputBuffer []gl.Variable
for i := 0; i < poseidon.SPONGE_WIDTH; i++ { for i := 0; i < poseidon.SPONGE_WIDTH; i++ {
@ -40,7 +40,8 @@ func NewChip(api frontend.API) *Chip {
} }
func (c *Chip) ObserveElement(element gl.Variable) { 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) c.inputBuffer = append(c.inputBuffer, element)
if len(c.inputBuffer) == poseidon.SPONGE_RATE { if len(c.inputBuffer) == poseidon.SPONGE_RATE {
c.duplexing() c.duplexing()
@ -110,14 +111,13 @@ func (c *Chip) GetExtensionChallenge() gl.QuadraticExtensionVariable {
} }
func (c *Chip) GetHash() poseidon.GoldilocksHashOut { 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( func (c *Chip) GetFriChallenges(
commitPhaseMerkleCaps []variables.FriMerkleCap, commitPhaseMerkleCaps []variables.FriMerkleCap,
finalPoly variables.PolynomialCoeffs, finalPoly variables.PolynomialCoeffs,
powWitness gl.Variable, powWitness gl.Variable,
degreeBits uint64,
config types.FriConfig, config types.FriConfig,
) variables.FriChallenges { ) variables.FriChallenges {
numFriQueries := config.NumQueryRounds numFriQueries := config.NumQueryRounds
@ -143,10 +143,6 @@ func (c *Chip) GetFriChallenges(
} }
} }
func clearBuffer(buffer []gl.Variable) []gl.Variable {
return make([]gl.Variable, 0)
}
func (c *Chip) duplexing() { func (c *Chip) duplexing() {
if len(c.inputBuffer) > poseidon.SPONGE_RATE { if len(c.inputBuffer) > poseidon.SPONGE_RATE {
fmt.Println(len(c.inputBuffer)) fmt.Println(len(c.inputBuffer))
@ -158,9 +154,12 @@ func (c *Chip) duplexing() {
for i := 0; i < len(c.inputBuffer); i++ { for i := 0; i < len(c.inputBuffer); i++ {
c.spongeState[i] = glApi.Reduce(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) 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++ { for i := 0; i < poseidon.SPONGE_RATE; i++ {
c.outputBuffer = append(c.outputBuffer, c.spongeState[i]) c.outputBuffer = append(c.outputBuffer, c.spongeState[i])
} }

+ 36
- 26
fri/fri.go

@ -49,14 +49,14 @@ func (f *Chip) GetInstance(zeta gl.QuadraticExtensionVariable) InstanceInfo {
zeta, zeta,
) )
zetaNextBath := BatchInfo{
zetaNextBatch := BatchInfo{
Point: zetaNext, Point: zetaNext,
Polynomials: friZSPolys(f.commonData), Polynomials: friZSPolys(f.commonData),
} }
return InstanceInfo{ return InstanceInfo{
Oracles: friOracles(f.commonData), Oracles: friOracles(f.commonData),
Batches: []BatchInfo{zetaBatch, zetaNextBath},
Batches: []BatchInfo{zetaBatch, zetaNextBatch},
} }
} }
@ -73,12 +73,10 @@ func (f *Chip) ToOpenings(c variables.OpeningSet) Openings {
} }
func (f *Chip) assertLeadingZeros(powWitness gl.Variable, friConfig types.FriConfig) { 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 // 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( func (f *Chip) fromOpeningsAndAlpha(
@ -128,13 +126,15 @@ func (f *Chip) verifyMerkleProofToCapWithCapIndex(
} }
const NUM_LEAF_LOOKUPS = 4 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 var leafLookups [NUM_LEAF_LOOKUPS]poseidon.BN254HashOut
// First create the "leaf" lookup2 circuits // 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++ { for i := 0; i < NUM_LEAF_LOOKUPS; i++ {
leafLookups[i] = f.api.Lookup2( leafLookups[i] = f.api.Lookup2(
capIndexBits[0], capIndexBits[1], 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 @@ func (f *Chip) expFromBitsConstBase(
) gl.Variable { ) gl.Variable {
product := gl.One() product := gl.One()
for i, bit := range exponentBits { 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: // We can arithmetize this as:
// product *= 1 + bit (base^pow - 1) // product *= 1 + bit (base^pow - 1)
// product = (base^pow - 1) product bit + product // product = (base^pow - 1) product bit + product
@ -238,9 +238,11 @@ func (f *Chip) friCombineInitial(
numerator := f.gl.SubExtensionNoReduce(reducedEvals, reducedOpenings) numerator := f.gl.SubExtensionNoReduce(reducedEvals, reducedOpenings)
denominator := f.gl.SubExtension(subgroupX_QE, point) denominator := f.gl.SubExtension(subgroupX_QE, point)
sum = f.gl.MulExtension(f.gl.ExpExtension(friAlpha, uint64(len(evals))), sum) 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( sum = f.gl.MulAddExtension(
numerator, numerator,
f.gl.InverseExtension(denominator),
inv,
sum, sum,
) )
} }
@ -272,17 +274,23 @@ func (f *Chip) interpolate(
} }
sum := gl.ZeroExtension() sum := gl.ZeroExtension()
lookupFromPoints := frontend.Variable(1)
for i := 0; i < len(xPoints); i++ { 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( sum = f.gl.AddExtension(
f.gl.MulExtension( f.gl.MulExtension(
f.gl.DivExtension(
barycentricWeights[i],
f.gl.SubExtension(
x,
xPoints[i],
),
),
yPoints[i], yPoints[i],
quotient,
), ),
sum, sum,
) )
@ -290,17 +298,17 @@ func (f *Chip) interpolate(
interpolation := f.gl.MulExtension(lX, sum) interpolation := f.gl.MulExtension(lX, sum)
returnField := interpolation
lookupVal := gl.ZeroExtension()
// Now check if x is already within the xPoints // Now check if x is already within the xPoints
for i := 0; i < len(xPoints); i++ { for i := 0; i < len(xPoints); i++ {
returnField = f.gl.Lookup(
lookupVal = f.gl.Lookup(
f.gl.IsZero(f.gl.SubExtension(x, xPoints[i])), f.gl.IsZero(f.gl.SubExtension(x, xPoints[i])),
returnField,
lookupVal,
yPoints[i], yPoints[i],
) )
} }
return returnField
return f.gl.Lookup(lookupFromPoints, lookupVal, interpolation)
} }
func (f *Chip) computeEvaluation( func (f *Chip) computeEvaluation(
@ -312,7 +320,7 @@ func (f *Chip) computeEvaluation(
) gl.QuadraticExtensionVariable { ) gl.QuadraticExtensionVariable {
arity := 1 << arityBits arity := 1 << arityBits
if (len(evals)) != arity { if (len(evals)) != arity {
panic("len(evals) ! arity")
panic("len(evals) != arity")
} }
if arityBits > 8 { if arityBits > 8 {
panic("currently assuming that arityBits is <= 8") panic("currently assuming that arityBits is <= 8")
@ -327,8 +335,8 @@ func (f *Chip) computeEvaluation(
// OPTIMIZE - Since the size of the evals array should be constant (e.g. 2^arityBits), // OPTIMIZE - Since the size of the evals array should be constant (e.g. 2^arityBits),
// we can just hard code the permutation. // we can just hard code the permutation.
permutedEvals := make([]gl.QuadraticExtensionVariable, len(evals)) 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] permutedEvals[newIndex] = evals[i]
} }
@ -367,7 +375,9 @@ func (f *Chip) computeEvaluation(
} }
// Take the inverse of the barycentric weights // Take the inverse of the barycentric weights
// OPTIMIZE: Can provide a witness to this value // 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) return f.interpolate(beta, xPoints, yPoints, barycentricWeights)

+ 0
- 1
fri/fri_test.go

@ -52,7 +52,6 @@ func (circuit *TestFriCircuit) Define(api frontend.API) error {
proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps, proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
proofWithPis.Proof.OpeningProof.FinalPoly, proofWithPis.Proof.OpeningProof.FinalPoly,
proofWithPis.Proof.OpeningProof.PowWitness, proofWithPis.Proof.OpeningProof.PowWitness,
commonCircuitData.DegreeBits,
commonCircuitData.Config.FriConfig, commonCircuitData.Config.FriConfig,
) )

+ 40
- 55
goldilocks/base.go

@ -38,9 +38,6 @@ var POWER_OF_TWO_GENERATOR goldilocks.Element = goldilocks.NewElement(1753635133
// The modulus of the field. // The modulus of the field.
var MODULUS *big.Int = emulated.Goldilocks{}.Modulus() 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. // The number of bits to use for range checks on inner products of field elements.
var RANGE_CHECK_NB_BITS int = 140 var RANGE_CHECK_NB_BITS int = 140
@ -90,38 +87,41 @@ func New(api frontend.API) *Chip {
return &Chip{api: api, rangeChecker: rangeChecker} 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 { func (p *Chip) Add(a Variable, b Variable) Variable {
return p.MulAdd(a, NewVariable(1), b) 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 { func (p *Chip) AddNoReduce(a Variable, b Variable) Variable {
return NewVariable(p.api.Add(a.Limb, b.Limb)) 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 { 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 { 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 { func (p *Chip) Mul(a Variable, b Variable) Variable {
return p.MulAdd(a, b, Zero()) 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 { func (p *Chip) MulNoReduce(a Variable, b Variable) Variable {
return NewVariable(p.api.Mul(a.Limb, b.Limb)) 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 { 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) result, err := p.api.Compiler().NewHint(MulAddHint, 2, a.Limb, b.Limb, c.Limb)
if err != nil { if err != nil {
@ -131,7 +131,8 @@ func (p *Chip) MulAdd(a Variable, b Variable, c Variable) Variable {
quotient := NewVariable(result[0]) quotient := NewVariable(result[0])
remainder := NewVariable(result[1]) 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) rhs := p.api.MulAcc(remainder.Limb, MODULUS, quotient.Limb)
p.api.AssertIsEqual(lhs, rhs) p.api.AssertIsEqual(lhs, rhs)
@ -140,10 +141,11 @@ func (p *Chip) MulAdd(a Variable, b Variable, c Variable) Variable {
return 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 { 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. // The hint used to compute MulAdd.
@ -179,18 +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 // 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. // 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. // Reduces a field element x such that x % MODULUS = y.
@ -212,6 +203,9 @@ func (p *Chip) ReduceWithMaxBits(x Variable, maxNbBits uint64) Variable {
remainder := NewVariable(result[1]) remainder := NewVariable(result[1])
p.RangeCheck(remainder) p.RangeCheck(remainder)
p.api.AssertIsEqual(x.Limb, p.api.Add(p.api.Mul(quotient, MODULUS), remainder.Limb))
return remainder return remainder
} }
@ -229,16 +223,22 @@ 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. // 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) result, err := p.api.Compiler().NewHint(InverseHint, 1, x.Limb)
if err != nil { if err != nil {
panic(err) panic(err)
} }
inverse := NewVariable(result[0]) inverse := NewVariable(result[0])
isZero := p.api.IsZero(x.Limb)
hasInv := p.api.Sub(1, isZero)
p.RangeCheck(inverse)
product := p.Mul(inverse, x) 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. // The hint used to compute Inverse.
@ -254,6 +254,8 @@ func InverseHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error {
inputGl := goldilocks.NewElement(input.Uint64()) inputGl := goldilocks.NewElement(input.Uint64())
resultGl := goldilocks.NewElement(0) resultGl := goldilocks.NewElement(0)
// Will set resultGL if inputGL == 0
resultGl.Inverse(&inputGl) resultGl.Inverse(&inputGl)
result := big.NewInt(0) result := big.NewInt(0)
@ -262,28 +264,6 @@ func InverseHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error {
return nil 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. // The hint used to split a GoldilocksVariable into 2 32 bit limbs.
func SplitLimbsHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error { func SplitLimbsHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error {
if len(inputs) != 1 { if len(inputs) != 1 {
@ -348,6 +328,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) { func (p *Chip) AssertIsEqual(x, y Variable) {
p.api.AssertIsEqual(x.Limb, y.Limb) p.api.AssertIsEqual(x.Limb, y.Limb)
} }
@ -373,7 +358,7 @@ func TwoAdicSubgroup(nLog uint64) []goldilocks.Element {
rootOfUnity := PrimitiveRootOfUnity(nLog) rootOfUnity := PrimitiveRootOfUnity(nLog)
res = append(res, goldilocks.NewElement(1)) 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] lastElement := res[len(res)-1]
res = append(res, *lastElement.Mul(&lastElement, &rootOfUnity)) res = append(res, *lastElement.Mul(&lastElement, &rootOfUnity))
} }

+ 15
- 19
goldilocks/quadratic_extension.go

@ -58,15 +58,13 @@ func (p *Chip) SubExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticEx
// Multiplies quadratic extension variable in the Goldilocks field. // Multiplies quadratic extension variable in the Goldilocks field.
func (p *Chip) MulExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable { func (p *Chip) MulExtension(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
product := p.MulExtensionNoReduce(a, b) 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. // Multiplies quadratic extension variable in the Goldilocks field without reducing.
func (p *Chip) MulExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable { func (p *Chip) MulExtensionNoReduce(a, b QuadraticExtensionVariable) QuadraticExtensionVariable {
c0o0 := p.MulNoReduce(a[0], b[0]) 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) c0 := p.AddNoReduce(c0o0, c0o1)
c1 := p.AddNoReduce(p.MulNoReduce(a[0], b[1]), p.MulNoReduce(a[1], b[0])) c1 := p.AddNoReduce(p.MulNoReduce(a[0], b[1]), p.MulNoReduce(a[1], b[0]))
return NewQuadraticExtensionVariable(c0, c1) 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 { func (p *Chip) MulAddExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
product := p.MulExtensionNoReduce(a, b) product := p.MulExtensionNoReduce(a, b)
sum := p.AddExtensionNoReduce(product, c) 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 { func (p *Chip) MulAddExtensionNoReduce(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
@ -88,14 +84,12 @@ func (p *Chip) MulAddExtensionNoReduce(a, b, c QuadraticExtensionVariable) Quadr
return sum 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. // be less than RANGE_CHECK_NB_BITS bits.
func (p *Chip) SubMulExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable { func (p *Chip) SubMulExtension(a, b, c QuadraticExtensionVariable) QuadraticExtensionVariable {
difference := p.SubExtensionNoReduce(a, b) difference := p.SubExtensionNoReduce(a, b)
product := p.MulExtensionNoReduce(difference, c) 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. // Multiplies quadratic extension variable in the Goldilocks field by a scalar.
@ -126,21 +120,23 @@ func (p *Chip) InnerProductExtension(
} }
// Computes the inverse of a quadratic extension variable in the Goldilocks field. // 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{ aPowRMinus1 := QuadraticExtensionVariable{
a[0], a[0],
p.Mul(a[1], NewVariable(DTH_ROOT)), p.Mul(a[1], NewVariable(DTH_ROOT)),
} }
aPowR := p.MulExtension(aPowRMinus1, a) 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. // 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. // Exponentiates a quadratic extension variable to some exponent in the Golidlocks field.
@ -213,7 +209,7 @@ func (p *Chip) Lookup(
return NewQuadraticExtensionVariable(NewVariable(c0), NewVariable(c1)) 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( func (p *Chip) Lookup2(
b0 frontend.Variable, b0 frontend.Variable,
b1 frontend.Variable, b1 frontend.Variable,

+ 1
- 1
goldilocks/quadratic_extension_algebra.go

@ -14,7 +14,7 @@ func NewQuadraticExtensionAlgebraVariable(
} }
func (p QuadraticExtensionVariable) ToQuadraticExtensionAlgebra() QuadraticExtensionAlgebraVariable { func (p QuadraticExtensionVariable) ToQuadraticExtensionAlgebra() QuadraticExtensionAlgebraVariable {
return [2]QuadraticExtensionVariable{p, ZeroExtension()}
return [D]QuadraticExtensionVariable{p, ZeroExtension()}
} }
func ZeroExtensionAlgebra() QuadraticExtensionAlgebraVariable { func ZeroExtensionAlgebra() QuadraticExtensionAlgebraVariable {

+ 1
- 1
goldilocks/quadratic_extension_test.go

@ -59,7 +59,7 @@ type TestQuadraticExtensionDivCircuit struct {
func (c *TestQuadraticExtensionDivCircuit) Define(api frontend.API) error { func (c *TestQuadraticExtensionDivCircuit) Define(api frontend.API) error {
glAPI := New(api) 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[0], c.ExpectedResult[0])
glAPI.AssertIsEqual(actualRes[1], c.ExpectedResult[1]) glAPI.AssertIsEqual(actualRes[1], c.ExpectedResult[1])
return nil return nil

+ 1
- 1
plonk/gates/arithmetic_extension_gate.go

@ -9,7 +9,7 @@ import (
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" 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 { func deserializeExtensionArithmeticGate(parameters map[string]string) Gate {
// Has the format "ArithmeticExtensionGate { num_ops: 10 }" // Has the format "ArithmeticExtensionGate { num_ops: 10 }"

+ 1
- 1
plonk/gates/arithmetic_gate.go

@ -9,7 +9,7 @@ import (
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" 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 { func deserializeArithmeticGate(parameters map[string]string) Gate {
// Has the format "ArithmeticGate { num_ops: 10 }" // Has the format "ArithmeticGate { num_ops: 10 }"

+ 1
- 1
plonk/gates/base_sum_gate.go

@ -51,7 +51,7 @@ func NewBaseSumGate(numLimbs uint64, base uint64) *BaseSumGate {
} }
func (g *BaseSumGate) Id() string { 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 { func (g *BaseSumGate) limbs() []uint64 {

+ 2
- 2
plonk/gates/constant_gate.go

@ -41,14 +41,14 @@ func (g *ConstantGate) Id() string {
} }
func (g *ConstantGate) ConstInput(i uint64) uint64 { func (g *ConstantGate) ConstInput(i uint64) uint64 {
if i > g.numConsts {
if i >= g.numConsts {
panic("Invalid constant index") panic("Invalid constant index")
} }
return i return i
} }
func (g *ConstantGate) WireOutput(i uint64) uint64 { func (g *ConstantGate) WireOutput(i uint64) uint64 {
if i > g.numConsts {
if i >= g.numConsts {
panic("Invalid wire index") panic("Invalid wire index")
} }
return i return i

+ 7
- 0
plonk/gates/coset_interpolation_gate.go

@ -32,6 +32,9 @@ func deserializeCosetInterpolationGate(parameters map[string]string) Gate {
if err != nil { if err != nil {
panic("invalid degree in CosetInterpolationGate") panic("invalid degree in CosetInterpolationGate")
} }
if degreeInt < 2 {
panic("degree must be at least 2 in CosetInterpolationGate")
}
barycentricWeightsStr := strings.Split(barycentricWeights, ",") barycentricWeightsStr := strings.Split(barycentricWeights, ",")
barycentricWeightsInt := make([]goldilocks.Element, len(barycentricWeightsStr)) barycentricWeightsInt := make([]goldilocks.Element, len(barycentricWeightsStr))
@ -199,6 +202,10 @@ func (g *CosetInterpolationGate) EvalUnfiltered(
startIndex := 1 + (g.degree-1)*(i+1) startIndex := 1 + (g.degree-1)*(i+1)
endIndex := startIndex + g.degree - 1 endIndex := startIndex + g.degree - 1
if endIndex > g.numPoints() {
endIndex = g.numPoints()
}
computedEval, computedProd = glApi.PartialInterpolateExtAlgebra( computedEval, computedProd = glApi.PartialInterpolateExtAlgebra(
domain[startIndex:endIndex], domain[startIndex:endIndex],
values[startIndex:endIndex], values[startIndex:endIndex],

+ 14
- 0
plonk/gates/exponentiation_gate.go

@ -23,6 +23,20 @@ func deserializeExponentiationGate(parameters map[string]string) Gate {
panic("Invalid num_power_bits field in ExponentiationGate") 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)) return NewExponentiationGate(uint64(numPowerBitsInt))
} }

+ 14
- 14
plonk/gates/gates.go

@ -18,20 +18,20 @@ type Gate interface {
} }
var gateRegexHandlers = map[*regexp.Regexp]func(parameters map[string]string) Gate{ 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 { func GateInstanceFromId(gateId string) Gate {

+ 1
- 1
plonk/gates/multiplication_extension_gate.go

@ -37,7 +37,7 @@ func NewMultiplicationExtensionGate(numOps uint64) *MultiplicationExtensionGate
} }
func (g *MultiplicationExtensionGate) Id() string { 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 { func (g *MultiplicationExtensionGate) wiresIthMultiplicand0(i uint64) Range {

+ 3
- 1
plonk/gates/poseidon_mds_gate.go

@ -90,7 +90,9 @@ func (g *PoseidonMdsGate) EvalUnfiltered(
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ { for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
output := vars.GetLocalExtAlgebra(g.WireOutput(i)) output := vars.GetLocalExtAlgebra(g.WireOutput(i))
diff := glApi.SubExtensionAlgebra(output, computed_outputs[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 return constraints

+ 1
- 1
plonk/gates/public_input_gate.go

@ -38,7 +38,7 @@ func (g *PublicInputGate) EvalUnfiltered(
wires := g.WiresPublicInputsHash() wires := g.WiresPublicInputsHash()
hash_parts := vars.publicInputsHash hash_parts := vars.publicInputsHash
for i := 0; i < 4; i++ {
for i := 0; i < len(wires); i++ {
wire := wires[i] wire := wires[i]
hash_part := hash_parts[i] hash_part := hash_parts[i]

+ 19
- 7
plonk/gates/random_access_gate.go

@ -36,6 +36,20 @@ func deserializeRandomAccessGate(parameters map[string]string) Gate {
panic("invalid numExtraConstants in RandomAccessGate") 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) return NewRandomAccessGate(bitsInt, numCopiesInt, numExtraConstantsInt)
} }
@ -151,14 +165,12 @@ func (g *RandomAccessGate) EvalUnfiltered(
y := listItems[i+1] y := listItems[i+1]
// This is computing `if b { x } else { y }` // 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 listItems = listItemsTmp
} }

+ 2
- 2
plonk/gates/reducing_extension_gate.go

@ -12,7 +12,7 @@ import (
var reducingExtensionGateRegex = regexp.MustCompile("ReducingExtensionGate { num_coeffs: (?P<numCoeffs>[0-9]+) }") var reducingExtensionGateRegex = regexp.MustCompile("ReducingExtensionGate { num_coeffs: (?P<numCoeffs>[0-9]+) }")
func deserializeReducingExtensionGate(parameters map[string]string) Gate { 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"] numCoeffs, hasNumCoeffs := parameters["numCoeffs"]
if !hasNumCoeffs { if !hasNumCoeffs {
panic("Missing field num_coeffs in ReducingExtensionGate") panic("Missing field num_coeffs in ReducingExtensionGate")
@ -39,7 +39,7 @@ func NewReducingExtensionGate(numCoeffs uint64) *ReducingExtensionGate {
} }
func (g *ReducingExtensionGate) Id() string { 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 { func (g *ReducingExtensionGate) wiresOutput() Range {

+ 2
- 6
plonk/gates/reducing_gate.go

@ -39,7 +39,7 @@ func NewReducingGate(numCoeffs uint64) *ReducingGate {
} }
func (g *ReducingGate) Id() string { 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 { func (g *ReducingGate) wiresOutput() Range {
@ -96,11 +96,7 @@ func (g *ReducingGate) EvalUnfiltered(
constraints := []gl.QuadraticExtensionVariable{} constraints := []gl.QuadraticExtensionVariable{}
acc := oldAcc acc := oldAcc
for i := uint64(0); i < g.numCoeffs; i++ { 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.MulExtensionAlgebra(acc, alpha)
tmp = glApi.AddExtensionAlgebra(tmp, coeff) tmp = glApi.AddExtensionAlgebra(tmp, coeff)
tmp = glApi.SubExtensionAlgebra(tmp, accs[i]) tmp = glApi.SubExtensionAlgebra(tmp, accs[i])

+ 6
- 1
plonk/plonk.go

@ -71,10 +71,15 @@ func (p *PlonkChip) evalL0(x gl.QuadraticExtensionVariable, xPowN gl.QuadraticEx
glApi.ScalarMulExtension(x, p.DEGREE), glApi.ScalarMulExtension(x, p.DEGREE),
p.DEGREE_QE, p.DEGREE_QE,
) )
return glApi.DivExtension(
quotient, hasQuotient := glApi.DivExtension(
evalZeroPoly, evalZeroPoly,
denominator, denominator,
) )
p.api.AssertIsEqual(hasQuotient, frontend.Variable(1))
return quotient
} }
func (p *PlonkChip) checkPartialProducts( func (p *PlonkChip) checkPartialProducts(

+ 8
- 1
poseidon/bn254.go

@ -10,6 +10,7 @@ package poseidon
import ( import (
"math/big" "math/big"
"github.com/consensys/gnark-crypto/ecc/bn254"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks" gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
) )
@ -28,6 +29,10 @@ type BN254State = [BN254_SPONGE_WIDTH]frontend.Variable
type BN254HashOut = frontend.Variable type BN254HashOut = frontend.Variable
func NewBN254Chip(api frontend.API) *BN254Chip { 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)} return &BN254Chip{api: api, gl: *gl.New(api)}
} }
@ -76,8 +81,10 @@ func (c *BN254Chip) HashOrNoop(input []gl.Variable) BN254HashOut {
returnVal := frontend.Variable(0) returnVal := frontend.Variable(0)
alpha := new(big.Int).SetInt64(1 << 32) alpha := new(big.Int).SetInt64(1 << 32)
alpha = new(big.Int).Mul(alpha, alpha)
for i, inputElement := range input { 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) return BN254HashOut(returnVal)

+ 8
- 8
poseidon/goldilocks.go

@ -7,13 +7,13 @@ import (
const HALF_N_FULL_ROUNDS = 4 const HALF_N_FULL_ROUNDS = 4
const N_PARTIAL_ROUNDS = 22 const N_PARTIAL_ROUNDS = 22
const MAX_WIDTH = 12
const SPONGE_WIDTH = 12 const SPONGE_WIDTH = 12
const SPONGE_RATE = 8 const SPONGE_RATE = 8
const POSEIDON_GL_HASH_SIZE = 4
type GoldilocksState = [SPONGE_WIDTH]gl.Variable type GoldilocksState = [SPONGE_WIDTH]gl.Variable
type GoldilocksStateExtension = [SPONGE_WIDTH]gl.QuadraticExtensionVariable type GoldilocksStateExtension = [SPONGE_WIDTH]gl.QuadraticExtensionVariable
type GoldilocksHashOut = [4]gl.Variable
type GoldilocksHashOut = [POSEIDON_GL_HASH_SIZE]gl.Variable
type GoldilocksChip struct { type GoldilocksChip struct {
api frontend.API `gnark:"-"` api frontend.API `gnark:"-"`
@ -77,8 +77,8 @@ func (c *GoldilocksChip) HashNoPad(input []gl.Variable) GoldilocksHashOut {
inputVars = append(inputVars, c.gl.Reduce(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] hash[i] = outputVars[i]
} }
@ -118,7 +118,7 @@ func (c *GoldilocksChip) constantLayer(state GoldilocksState, roundCounter *int)
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH { if i < SPONGE_WIDTH {
roundConstant := ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)] 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 return state
@ -169,7 +169,7 @@ func (c *GoldilocksChip) SBoxLayerExtension(state GoldilocksStateExtension) Gold
return state 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() res := gl.Zero()
for i := 0; i < 12; i++ { 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) 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() res := gl.ZeroExtension()
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
@ -251,7 +251,7 @@ func (c *GoldilocksChip) PartialFirstConstantLayerExtension(state GoldilocksStat
func (c *GoldilocksChip) mdsPartialLayerInit(state GoldilocksState) GoldilocksState { func (c *GoldilocksChip) mdsPartialLayerInit(state GoldilocksState) GoldilocksState {
var result GoldilocksState var result GoldilocksState
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
result[i] = gl.NewVariable(0)
result[i] = gl.Zero()
} }
result[0] = state[0] result[0] = state[0]

+ 5
- 0
types/common_data.go

@ -118,5 +118,10 @@ func ReadCommonCircuitData(path string) CommonCircuitData {
commonCircuitData.KIs = raw.KIs commonCircuitData.KIs = raw.KIs
commonCircuitData.NumPartialProducts = raw.NumPartialProducts 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 return commonCircuitData
} }

+ 0
- 21
types/utils.go

@ -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
}

+ 0
- 12
variables/plonk.go

@ -12,18 +12,6 @@ type OpeningSet struct {
QuotientPolys []gl.QuadraticExtensionVariable // Length = CommonCircuitData.NumChallenges * CommonCircuitData.QuotientDegreeFactor 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 { type ProofChallenges struct {
PlonkBetas []gl.Variable PlonkBetas []gl.Variable
PlonkGammas []gl.Variable PlonkGammas []gl.Variable

+ 4
- 3
verifier/verifier.go

@ -76,7 +76,6 @@ func (c *VerifierChip) GetChallenges(
proof.OpeningProof.CommitPhaseMerkleCaps, proof.OpeningProof.CommitPhaseMerkleCaps,
proof.OpeningProof.FinalPoly, proof.OpeningProof.FinalPoly,
proof.OpeningProof.PowWitness, proof.OpeningProof.PowWitness,
c.commonData.DegreeBits,
config.FriConfig, config.FriConfig,
), ),
} }
@ -119,8 +118,10 @@ func (c *VerifierChip) rangeCheckProof(proof variables.Proof) {
// Range check the openings proof. // Range check the openings proof.
for _, queryRound := range proof.OpeningProof.QueryRoundProofs { 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 { for _, queryStep := range queryRound.Steps {

Loading…
Cancel
Save