Browse Source

optimized goldilocks (#22)

* cleaned up qe api

* modified goldilocks poseidon to use optimized goldilocks operations

* better comment

* added goldilocks test cases

* some cleanup and comments

* changed poseidon constaints to frontend.Variable

* fixed double cast

* fixed bug in challenger
main
Kevin Jue 2 years ago
committed by GitHub
parent
commit
15b7dcbcdb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1569 additions and 1335 deletions
  1. +110
    -0
      field/goldilocks.go
  2. +72
    -0
      field/goldilocks_test.go
  3. +4
    -0
      field/quadratic_extension.go
  4. +70
    -61
      poseidon/poseidon.go
  5. +2
    -0
      poseidon/poseidon_bn128.go
  6. +1155
    -1156
      poseidon/poseidon_constants.go
  7. +2
    -5
      poseidon/poseidon_test.go
  8. +1
    -1
      verifier/internal/gates/poseidon_gate.go
  9. +2
    -2
      verifier/internal/gates/poseidon_mds_gate.go
  10. +7
    -6
      verifier/internal/plonk/challenger.go
  11. +144
    -104
      verifier/internal/plonk/challenger_test.go

+ 110
- 0
field/goldilocks.go

@ -1,9 +1,14 @@
package field package field
import ( import (
"fmt"
"math/big"
"github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark-crypto/field/goldilocks" "github.com/consensys/gnark-crypto/field/goldilocks"
"github.com/consensys/gnark/backend/hint"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/std/math/bits"
"github.com/consensys/gnark/std/math/emulated" "github.com/consensys/gnark/std/math/emulated"
) )
@ -38,6 +43,7 @@ var NEG_ONE_F = NewFieldConst(EmulatedField{}.Modulus().Uint64() - 1)
var GOLDILOCKS_MULTIPLICATIVE_GROUP_GENERATOR = goldilocks.NewElement(7) var GOLDILOCKS_MULTIPLICATIVE_GROUP_GENERATOR = goldilocks.NewElement(7)
var GOLDILOCKS_TWO_ADICITY = uint64(32) var GOLDILOCKS_TWO_ADICITY = uint64(32)
var GOLDILOCKS_POWER_OF_TWO_GENERATOR = goldilocks.NewElement(1753635133440165772) var GOLDILOCKS_POWER_OF_TWO_GENERATOR = goldilocks.NewElement(1753635133440165772)
var GOLDILOCKS_MODULUS = EmulatedField{}.Modulus()
func GoldilocksPrimitiveRootOfUnity(nLog uint64) goldilocks.Element { func GoldilocksPrimitiveRootOfUnity(nLog uint64) goldilocks.Element {
if nLog > GOLDILOCKS_TWO_ADICITY { if nLog > GOLDILOCKS_TWO_ADICITY {
@ -81,3 +87,107 @@ func IsZero(api frontend.API, fieldAPI *emulated.Field[emulated.Goldilocks], x F
return isZero return isZero
} }
func init() {
// register hints
hint.Register(GoldilocksMulAddHint)
}
func GoldilocksRangeCheck(api frontend.API, x frontend.Variable) {
// Goldilocks' modulus is 2^64 - 2^32 + 1,
// which is "1111111111111111111111111111111100000000000000000000000000000001' in big endian binary
// This function will first verify that x is at most 64 bits wide.
// Then it checks that if the bits[0:31] (in big-endian) are all 1, then bits[32:64] are all zero
// First decompose x into 64 bits. The bits will be in little-endian order.
bits, err := api.Compiler().NewHint(bits.NBits, 64, x)
if err != nil {
panic(err)
}
// Those bits should compose back to x
reconstructedX := frontend.Variable(0)
c := uint64(1)
for i := 0; i < 64; i++ {
reconstructedX = api.Add(reconstructedX, api.Mul(bits[i], c))
c = c << 1
api.AssertIsBoolean(bits[i])
}
api.AssertIsEqual(x, reconstructedX)
mostSigBits32Sum := frontend.Variable(0)
for i := 32; i < 64; i++ {
mostSigBits32Sum = api.Add(mostSigBits32Sum, bits[i])
}
leastSigBits32Sum := frontend.Variable(0)
for i := 0; i < 32; i++ {
leastSigBits32Sum = api.Add(leastSigBits32Sum, bits[i])
}
// If mostSigBits32Sum < 32, then we know that x < (2^63 + ... + 2^32 + 0 * 2^31 + ... + 0 * 2^0), which equals to 2^64 - 2^32
// So in that case, we don't need to do any more checks.
// If mostSigBits32Sum == 32, then we need to check that x == 2^64 - 2^32 (max GL value)
shouldCheck := api.IsZero(api.Sub(mostSigBits32Sum, 32))
api.AssertIsEqual(
api.Select(
shouldCheck,
leastSigBits32Sum,
frontend.Variable(0),
),
frontend.Variable(0),
)
}
// Calculates operands[0] * operands[1] + operands[2]
// This function assumes that all operands are within goldilocks, and will panic otherwise
// It will ensure that the result is within goldilocks
func GoldilocksMulAdd(api frontend.API, operand1, operand2, operand3 frontend.Variable) frontend.Variable {
result, err := api.Compiler().NewHint(GoldilocksMulAddHint, 2, operand1, operand2, operand3)
if err != nil {
panic(err)
}
quotient := result[0]
remainder := result[1]
// Verify the calculated value
lhs := api.Mul(operand1, operand2)
lhs = api.Add(lhs, operand3)
rhs := api.Add(api.Mul(quotient, GOLDILOCKS_MODULUS), remainder)
api.AssertIsEqual(lhs, rhs)
GoldilocksRangeCheck(api, quotient)
GoldilocksRangeCheck(api, remainder)
return remainder
}
func GoldilocksMulAddHint(_ *big.Int, inputs []*big.Int, results []*big.Int) error {
if len(inputs) != 3 {
return fmt.Errorf("GoldilocksMulAddHint expects 3 input operands")
}
for _, operand := range inputs {
if operand.Cmp(GOLDILOCKS_MODULUS) >= 0 {
return fmt.Errorf("%s is not in the field", operand.String())
}
}
product := new(big.Int).Mul(inputs[0], inputs[1])
sum := new(big.Int).Add(product, inputs[2])
quotient := new(big.Int).Div(sum, GOLDILOCKS_MODULUS)
remainder := new(big.Int).Rem(sum, GOLDILOCKS_MODULUS)
results[0] = quotient
results[1] = remainder
return nil
}
func GoldilocksReduce(api frontend.API, x frontend.Variable) frontend.Variable {
// Use gnark's emulated field library.
fieldAPI := NewFieldAPI(api)
element := fieldAPI.NewElement(x)
return fieldAPI.Reduce(element).Limbs[0]
}

+ 72
- 0
field/goldilocks_test.go

@ -0,0 +1,72 @@
package field
import (
"math/big"
"testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/test"
)
type TestGoldilocksRangeCheckCircuit struct {
X frontend.Variable
}
func (c *TestGoldilocksRangeCheckCircuit) Define(api frontend.API) error {
GoldilocksRangeCheck(api, c.X)
return nil
}
func TestGoldilocksRangeCheck(t *testing.T) {
assert := test.NewAssert(t)
var circuit, witness TestGoldilocksRangeCheckCircuit
witness.X = 1
assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoSerialization())
witness.X = 0
assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoSerialization())
witness.X = EmulatedField{}.Modulus()
assert.ProverFailed(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoSerialization())
one := big.NewInt(1)
maxValidVal := new(big.Int).Sub(EmulatedField{}.Modulus(), one)
witness.X = maxValidVal
assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16))
}
type TestGoldilocksMulAddCircuit struct {
X, Y, Z frontend.Variable
ExpectedResult frontend.Variable
}
func (c *TestGoldilocksMulAddCircuit) Define(api frontend.API) error {
calculateValue := GoldilocksMulAdd(api, c.X, c.Y, c.Z)
api.AssertIsEqual(calculateValue, c.ExpectedResult)
return nil
}
func TestGoldilocksMulAdd(t *testing.T) {
assert := test.NewAssert(t)
var circuit, witness TestGoldilocksMulAddCircuit
witness.X = 1
witness.Y = 2
witness.Z = 3
witness.ExpectedResult = 5
assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoFuzzing())
bigOperand := new(big.Int).SetUint64(9223372036854775808)
expectedValue, _ := new(big.Int).SetString("18446744068340842500", 10)
witness.X = bigOperand
witness.Y = bigOperand
witness.Z = 3
witness.ExpectedResult = expectedValue
assert.ProverSucceeded(&circuit, &witness, test.WithCurves(ecc.BN254), test.WithBackends(backend.GROTH16), test.NoFuzzing())
}

+ 4
- 0
field/quadratic_extension.go

@ -97,6 +97,10 @@ func (c *QuadraticExtensionAPI) ScalarMulExtension(a QuadraticExtension, scalar
return QuadraticExtension{c.fieldAPI.Mul(a[0], scalar), c.fieldAPI.Mul(a[1], scalar)} return QuadraticExtension{c.fieldAPI.Mul(a[0], scalar), c.fieldAPI.Mul(a[1], scalar)}
} }
func (c *QuadraticExtensionAPI) VarToQE(a frontend.Variable) QuadraticExtension {
return c.FieldToQE(c.fieldAPI.NewElement(a))
}
func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension { func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension {
return QuadraticExtension{a, ZERO_F} return QuadraticExtension{a, ZERO_F}
} }

+ 70
- 61
poseidon/poseidon.go

@ -11,7 +11,7 @@ const MAX_WIDTH = 12
const SPONGE_WIDTH = 12 const SPONGE_WIDTH = 12
const SPONGE_RATE = 8 const SPONGE_RATE = 8
type PoseidonState = [SPONGE_WIDTH]field.F
type PoseidonState = [SPONGE_WIDTH]frontend.Variable
type PoseidonStateExtension = [SPONGE_WIDTH]field.QuadraticExtension type PoseidonStateExtension = [SPONGE_WIDTH]field.QuadraticExtension
type PoseidonHashOut = [4]field.F type PoseidonHashOut = [4]field.F
@ -25,20 +25,25 @@ func NewPoseidonChip(api frontend.API, fieldAPI field.FieldAPI, qeAPI *field.Qua
return &PoseidonChip{api: api, fieldAPI: fieldAPI, qeAPI: qeAPI} return &PoseidonChip{api: api, fieldAPI: fieldAPI, qeAPI: qeAPI}
} }
// The permutation function.
// The input state MUST have all it's elements be within Goldilocks field (e.g. this function will not reduce the input elements).
// The returned state's elements will all be within Goldilocks field.
func (c *PoseidonChip) Poseidon(input PoseidonState) PoseidonState { func (c *PoseidonChip) Poseidon(input PoseidonState) PoseidonState {
state := input state := input
roundCounter := 0 roundCounter := 0
state = c.FullRounds(state, &roundCounter)
state = c.PartialRounds(state, &roundCounter)
state = c.FullRounds(state, &roundCounter)
state = c.fullRounds(state, &roundCounter)
state = c.partialRounds(state, &roundCounter)
state = c.fullRounds(state, &roundCounter)
return state return state
} }
func (c *PoseidonChip) HashNToMNoPad(input []field.F, nbOutputs int) []field.F {
// The input elements MUST have all it's elements be within Goldilocks field.
// The returned slice's elements will all be within Goldilocks field.
func (c *PoseidonChip) HashNToMNoPad(input []frontend.Variable, nbOutputs int) []frontend.Variable {
var state PoseidonState var state PoseidonState
for i := 0; i < SPONGE_WIDTH; i++ { for i := 0; i < SPONGE_WIDTH; i++ {
state[i] = field.ZERO_F
state[i] = frontend.Variable(0)
} }
for i := 0; i < len(input); i += SPONGE_RATE { for i := 0; i < len(input); i += SPONGE_RATE {
@ -50,7 +55,7 @@ func (c *PoseidonChip) HashNToMNoPad(input []field.F, nbOutputs int) []field.F {
state = c.Poseidon(state) state = c.Poseidon(state)
} }
var outputs []field.F
var outputs []frontend.Variable
for { for {
for i := 0; i < SPONGE_RATE; i++ { for i := 0; i < SPONGE_RATE; i++ {
@ -63,9 +68,21 @@ func (c *PoseidonChip) HashNToMNoPad(input []field.F, nbOutputs int) []field.F {
} }
} }
// The input elements can be outside of the Goldilocks field.
// The returned slice's elements will all be within Goldilocks field.
func (c *PoseidonChip) HashNoPad(input []field.F) PoseidonHashOut { func (c *PoseidonChip) HashNoPad(input []field.F) PoseidonHashOut {
var hash PoseidonHashOut var hash PoseidonHashOut
copy(hash[:], c.HashNToMNoPad(input, 4))
inputVars := []frontend.Variable{}
for i := 0; i < len(input); i++ {
inputVars = append(inputVars, c.fieldAPI.Reduce(input[i]).Limbs[0])
}
outputVars := c.HashNToMNoPad(inputVars, 4)
for i := 0; i < 4; i++ {
hash[i] = c.fieldAPI.NewElement(outputVars[i])
}
return hash return hash
} }
@ -73,24 +90,24 @@ func (c *PoseidonChip) ToVec(hash PoseidonHashOut) []field.F {
return hash[:] return hash[:]
} }
func (c *PoseidonChip) FullRounds(state PoseidonState, roundCounter *int) PoseidonState {
func (c *PoseidonChip) fullRounds(state PoseidonState, roundCounter *int) PoseidonState {
for i := 0; i < HALF_N_FULL_ROUNDS; i++ { for i := 0; i < HALF_N_FULL_ROUNDS; i++ {
state = c.ConstantLayer(state, roundCounter)
state = c.SBoxLayer(state)
state = c.MdsLayer(state)
state = c.constantLayer(state, roundCounter)
state = c.sBoxLayer(state)
state = c.mdsLayer(state)
*roundCounter += 1 *roundCounter += 1
} }
return state return state
} }
func (c *PoseidonChip) PartialRounds(state PoseidonState, roundCounter *int) PoseidonState {
state = c.PartialFirstConstantLayer(state)
state = c.MdsPartialLayerInit(state)
func (c *PoseidonChip) partialRounds(state PoseidonState, roundCounter *int) PoseidonState {
state = c.partialFirstConstantLayer(state)
state = c.mdsPartialLayerInit(state)
for i := 0; i < N_PARTIAL_ROUNDS; i++ { for i := 0; i < N_PARTIAL_ROUNDS; i++ {
state[0] = c.SBoxMonomial(state[0])
state[0] = c.fieldAPI.Add(state[0], FAST_PARTIAL_ROUND_CONSTANTS[i])
state = c.MdsPartialLayerFast(state, i)
state[0] = c.sBoxMonomial(state[0])
state[0] = field.GoldilocksMulAdd(c.api, frontend.Variable(1), state[0], FAST_PARTIAL_ROUND_CONSTANTS[i])
state = c.mdsPartialLayerFast(state, i)
} }
*roundCounter += N_PARTIAL_ROUNDS *roundCounter += N_PARTIAL_ROUNDS
@ -98,11 +115,11 @@ func (c *PoseidonChip) PartialRounds(state PoseidonState, roundCounter *int) Pos
return state return state
} }
func (c *PoseidonChip) ConstantLayer(state PoseidonState, roundCounter *int) PoseidonState {
func (c *PoseidonChip) constantLayer(state PoseidonState, roundCounter *int) PoseidonState {
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.fieldAPI.Add(state[i], roundConstant)
state[i] = field.GoldilocksMulAdd(c.api, frontend.Variable(1), state[i], roundConstant)
} }
} }
return state return state
@ -111,18 +128,18 @@ func (c *PoseidonChip) ConstantLayer(state PoseidonState, roundCounter *int) Pos
func (c *PoseidonChip) ConstantLayerExtension(state PoseidonStateExtension, roundCounter *int) PoseidonStateExtension { func (c *PoseidonChip) ConstantLayerExtension(state PoseidonStateExtension, roundCounter *int) PoseidonStateExtension {
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH { if i < SPONGE_WIDTH {
roundConstant := c.qeAPI.FieldToQE(ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)])
roundConstant := c.qeAPI.VarToQE(ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)])
state[i] = c.qeAPI.AddExtension(state[i], roundConstant) state[i] = c.qeAPI.AddExtension(state[i], roundConstant)
} }
} }
return state return state
} }
func (c *PoseidonChip) SBoxMonomial(x field.F) field.F {
x2 := c.fieldAPI.Mul(x, x)
x4 := c.fieldAPI.Mul(x2, x2)
x3 := c.fieldAPI.Mul(x, x2)
return c.fieldAPI.Mul(x3, x4)
func (c *PoseidonChip) sBoxMonomial(x frontend.Variable) frontend.Variable {
x2 := field.GoldilocksMulAdd(c.api, x, x, frontend.Variable(0))
x4 := field.GoldilocksMulAdd(c.api, x2, x2, frontend.Variable(0))
x6 := field.GoldilocksMulAdd(c.api, x4, x2, frontend.Variable(0))
return field.GoldilocksMulAdd(c.api, x6, x, frontend.Variable(0))
} }
func (c *PoseidonChip) SBoxMonomialExtension(x field.QuadraticExtension) field.QuadraticExtension { func (c *PoseidonChip) SBoxMonomialExtension(x field.QuadraticExtension) field.QuadraticExtension {
@ -132,10 +149,10 @@ func (c *PoseidonChip) SBoxMonomialExtension(x field.QuadraticExtension) field.Q
return c.qeAPI.MulExtension(x3, x4) return c.qeAPI.MulExtension(x3, x4)
} }
func (c *PoseidonChip) SBoxLayer(state PoseidonState) PoseidonState {
func (c *PoseidonChip) sBoxLayer(state PoseidonState) PoseidonState {
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH { if i < SPONGE_WIDTH {
state[i] = c.SBoxMonomial(state[i])
state[i] = c.sBoxMonomial(state[i])
} }
} }
return state return state
@ -150,7 +167,7 @@ func (c *PoseidonChip) SBoxLayerExtension(state PoseidonStateExtension) Poseidon
return state return state
} }
func (c *PoseidonChip) MdsRowShf(r int, v [SPONGE_WIDTH]frontend.Variable) frontend.Variable {
func (c *PoseidonChip) mdsRowShf(r int, v [SPONGE_WIDTH]frontend.Variable) frontend.Variable {
res := ZERO_VAR res := ZERO_VAR
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
@ -169,35 +186,32 @@ func (c *PoseidonChip) MdsRowShfExtension(r int, v [SPONGE_WIDTH]field.Quadratic
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH { if i < SPONGE_WIDTH {
matrixVal := c.qeAPI.FieldToQE(MDS_MATRIX_CIRC[i])
matrixVal := c.qeAPI.VarToQE(MDS_MATRIX_CIRC[i])
res1 := c.qeAPI.MulExtension(v[(i+r)%SPONGE_WIDTH], matrixVal) res1 := c.qeAPI.MulExtension(v[(i+r)%SPONGE_WIDTH], matrixVal)
res = c.qeAPI.AddExtension(res, res1) res = c.qeAPI.AddExtension(res, res1)
} }
} }
matrixVal := c.qeAPI.FieldToQE(MDS_MATRIX_DIAG[r])
matrixVal := c.qeAPI.VarToQE(MDS_MATRIX_DIAG[r])
res = c.qeAPI.AddExtension(res, c.qeAPI.MulExtension(v[r], matrixVal)) res = c.qeAPI.AddExtension(res, c.qeAPI.MulExtension(v[r], matrixVal))
return res return res
} }
func (c *PoseidonChip) MdsLayer(state_ PoseidonState) PoseidonState {
func (c *PoseidonChip) mdsLayer(state_ PoseidonState) PoseidonState {
var result PoseidonState var result PoseidonState
for i := 0; i < SPONGE_WIDTH; i++ { for i := 0; i < SPONGE_WIDTH; i++ {
result[i] = field.ZERO_F
result[i] = frontend.Variable(0)
} }
var state [SPONGE_WIDTH]frontend.Variable var state [SPONGE_WIDTH]frontend.Variable
for i := 0; i < SPONGE_WIDTH; i++ { for i := 0; i < SPONGE_WIDTH; i++ {
reducedState := c.fieldAPI.Reduce(state_[i])
//state[i] = c.api.FromBinary(c.fieldAPI.ToBits(reducedState)...)
state[i] = reducedState.Limbs[0]
state[i] = field.GoldilocksReduce(c.api, state_[i])
} }
for r := 0; r < 12; r++ { for r := 0; r < 12; r++ {
if r < SPONGE_WIDTH { if r < SPONGE_WIDTH {
sum := c.MdsRowShf(r, state)
bits := c.api.ToBinary(sum)
result[r] = c.fieldAPI.FromBits(bits...)
sum := c.mdsRowShf(r, state)
result[r] = field.GoldilocksReduce(c.api, sum)
} }
} }
@ -217,10 +231,10 @@ func (c *PoseidonChip) MdsLayerExtension(state_ PoseidonStateExtension) Poseidon
return result return result
} }
func (c *PoseidonChip) PartialFirstConstantLayer(state PoseidonState) PoseidonState {
func (c *PoseidonChip) partialFirstConstantLayer(state PoseidonState) PoseidonState {
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH { if i < SPONGE_WIDTH {
state[i] = c.fieldAPI.Add(state[i], FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])
state[i] = field.GoldilocksMulAdd(c.api, frontend.Variable(1), state[i], FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])
} }
} }
return state return state
@ -229,16 +243,16 @@ func (c *PoseidonChip) PartialFirstConstantLayer(state PoseidonState) PoseidonSt
func (c *PoseidonChip) PartialFirstConstantLayerExtension(state PoseidonStateExtension) PoseidonStateExtension { func (c *PoseidonChip) PartialFirstConstantLayerExtension(state PoseidonStateExtension) PoseidonStateExtension {
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
if i < SPONGE_WIDTH { if i < SPONGE_WIDTH {
state[i] = c.qeAPI.AddExtension(state[i], c.qeAPI.FieldToQE(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i]))
state[i] = c.qeAPI.AddExtension(state[i], c.qeAPI.VarToQE((FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])))
} }
} }
return state return state
} }
func (c *PoseidonChip) MdsPartialLayerInit(state PoseidonState) PoseidonState {
func (c *PoseidonChip) mdsPartialLayerInit(state PoseidonState) PoseidonState {
var result PoseidonState var result PoseidonState
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
result[i] = field.ZERO_F
result[i] = frontend.Variable(0)
} }
result[0] = state[0] result[0] = state[0]
@ -248,7 +262,7 @@ func (c *PoseidonChip) MdsPartialLayerInit(state PoseidonState) PoseidonState {
for d := 1; d < 12; d++ { for d := 1; d < 12; d++ {
if d < SPONGE_WIDTH { if d < SPONGE_WIDTH {
t := FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1] t := FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1]
result[d] = c.fieldAPI.Add(result[d], c.fieldAPI.Mul(state[r], t))
result[d] = field.GoldilocksMulAdd(c.api, state[r], t, result[d])
} }
} }
} }
@ -269,7 +283,7 @@ func (c *PoseidonChip) MdsPartialLayerInitExtension(state PoseidonStateExtension
if r < SPONGE_WIDTH { if r < SPONGE_WIDTH {
for d := 1; d < 12; d++ { for d := 1; d < 12; d++ {
if d < SPONGE_WIDTH { if d < SPONGE_WIDTH {
t := c.qeAPI.FieldToQE(FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1])
t := c.qeAPI.VarToQE(FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1])
result[d] = c.qeAPI.AddExtension(result[d], c.qeAPI.MulExtension(state[r], t)) result[d] = c.qeAPI.AddExtension(result[d], c.qeAPI.MulExtension(state[r], t))
} }
} }
@ -279,28 +293,23 @@ func (c *PoseidonChip) MdsPartialLayerInitExtension(state PoseidonStateExtension
return result return result
} }
func (c *PoseidonChip) MdsPartialLayerFast(state PoseidonState, r int) PoseidonState {
func (c *PoseidonChip) mdsPartialLayerFast(state PoseidonState, r int) PoseidonState {
dSum := ZERO_VAR dSum := ZERO_VAR
for i := 1; i < 12; i++ { for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH { if i < SPONGE_WIDTH {
t := FAST_PARTIAL_ROUND_W_HATS_VARS[r][i-1] t := FAST_PARTIAL_ROUND_W_HATS_VARS[r][i-1]
reducedState := c.fieldAPI.Reduce(state[i])
//si := c.api.FromBinary(c.fieldAPI.ToBits(reducedState)...)
si := reducedState.Limbs[0]
dSum = c.api.Add(dSum, c.api.Mul(si, t))
reducedState := field.GoldilocksReduce(c.api, state[i])
dSum = c.api.Add(dSum, c.api.Mul(reducedState, t))
} }
} }
reducedState := c.fieldAPI.Reduce(state[0])
//s0 := c.api.FromBinary(c.fieldAPI.ToBits(reducedState)...)
s0 := reducedState.Limbs[0]
s0 := field.GoldilocksReduce(c.api, state[0])
dSum = c.api.Add(dSum, c.api.Mul(s0, MDS0TO0_VAR)) dSum = c.api.Add(dSum, c.api.Mul(s0, MDS0TO0_VAR))
d := c.fieldAPI.FromBits(c.api.ToBinary(dSum)...)
//d := c.fieldAPI.NewElement(dSum)
d := field.GoldilocksReduce(c.api, dSum)
var result PoseidonState var result PoseidonState
for i := 0; i < SPONGE_WIDTH; i++ { for i := 0; i < SPONGE_WIDTH; i++ {
result[i] = field.ZERO_F
result[i] = frontend.Variable(0)
} }
result[0] = d result[0] = d
@ -308,7 +317,7 @@ func (c *PoseidonChip) MdsPartialLayerFast(state PoseidonState, r int) PoseidonS
for i := 1; i < 12; i++ { for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH { if i < SPONGE_WIDTH {
t := FAST_PARTIAL_ROUND_VS[r][i-1] t := FAST_PARTIAL_ROUND_VS[r][i-1]
result[i] = c.fieldAPI.Add(state[i], c.fieldAPI.Mul(state[0], t))
result[i] = field.GoldilocksMulAdd(c.api, state[0], t, state[i])
} }
} }
@ -317,11 +326,11 @@ func (c *PoseidonChip) MdsPartialLayerFast(state PoseidonState, r int) PoseidonS
func (c *PoseidonChip) MdsPartialLayerFastExtension(state PoseidonStateExtension, r int) PoseidonStateExtension { func (c *PoseidonChip) MdsPartialLayerFastExtension(state PoseidonStateExtension, r int) PoseidonStateExtension {
s0 := state[0] s0 := state[0]
mds0to0 := c.qeAPI.FieldToQE(MDS0TO0)
mds0to0 := c.qeAPI.VarToQE(MDS0TO0)
d := c.qeAPI.MulExtension(s0, mds0to0) d := c.qeAPI.MulExtension(s0, mds0to0)
for i := 1; i < 12; i++ { for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH { if i < SPONGE_WIDTH {
t := c.qeAPI.FieldToQE(FAST_PARTIAL_ROUND_W_HATS[r][i-1])
t := c.qeAPI.VarToQE(FAST_PARTIAL_ROUND_W_HATS[r][i-1])
d = c.qeAPI.AddExtension(d, c.qeAPI.MulExtension(state[i], t)) d = c.qeAPI.AddExtension(d, c.qeAPI.MulExtension(state[i], t))
} }
} }
@ -330,7 +339,7 @@ func (c *PoseidonChip) MdsPartialLayerFastExtension(state PoseidonStateExtension
result[0] = d result[0] = d
for i := 1; i < 12; i++ { for i := 1; i < 12; i++ {
if i < SPONGE_WIDTH { if i < SPONGE_WIDTH {
t := c.qeAPI.FieldToQE(FAST_PARTIAL_ROUND_VS[r][i-1])
t := c.qeAPI.VarToQE(FAST_PARTIAL_ROUND_VS[r][i-1])
result[i] = c.qeAPI.AddExtension(c.qeAPI.MulExtension(state[0], t), state[i]) result[i] = c.qeAPI.AddExtension(c.qeAPI.MulExtension(state[0], t), state[i])
} }
} }

+ 2
- 0
poseidon/poseidon_bn128.go

@ -20,6 +20,8 @@ type PoseidonBN128Chip struct {
type PoseidonBN128State = [spongeWidth]frontend.Variable type PoseidonBN128State = [spongeWidth]frontend.Variable
type PoseidonBN128HashOut = frontend.Variable type PoseidonBN128HashOut = frontend.Variable
// This implementation is based on the following implementation:
// https://github.com/iden3/go-iden3-crypto/blob/e5cf066b8be3da9a3df9544c65818df189fdbebe/poseidon/poseidon.go
func NewPoseidonBN128Chip(api frontend.API, fieldAPI field.FieldAPI) *PoseidonBN128Chip { func NewPoseidonBN128Chip(api frontend.API, fieldAPI field.FieldAPI) *PoseidonBN128Chip {
return &PoseidonBN128Chip{api: api, fieldAPI: fieldAPI} return &PoseidonBN128Chip{api: api, fieldAPI: fieldAPI}
} }

+ 1155
- 1156
poseidon/poseidon_constants.go
File diff suppressed because it is too large
View File


+ 2
- 5
poseidon/poseidon_test.go

@ -22,17 +22,14 @@ func (circuit *TestPoseidonCircuit) Define(api frontend.API) error {
var input PoseidonState var input PoseidonState
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
input[i] = goldilocksApi.FromBits(api.ToBinary(circuit.In[i], 64)...)
input[i] = circuit.In[i]
} }
poseidonChip := NewPoseidonChip(api, goldilocksApi, qeAPI) poseidonChip := NewPoseidonChip(api, goldilocksApi, qeAPI)
output := poseidonChip.Poseidon(input) output := poseidonChip.Poseidon(input)
for i := 0; i < 12; i++ { for i := 0; i < 12; i++ {
goldilocksApi.AssertIsEqual(
output[i],
goldilocksApi.FromBits(api.ToBinary(circuit.Out[i])...),
)
api.AssertIsEqual(output[i], circuit.Out[i])
} }
return nil return nil

+ 1
- 1
verifier/internal/gates/poseidon_gate.go

@ -147,7 +147,7 @@ func (g *PoseidonGate) EvalUnfiltered(api frontend.API, qeAPI *field.QuadraticEx
sBoxIn := vars.localWires[g.WirePartialSBox(r)] sBoxIn := vars.localWires[g.WirePartialSBox(r)]
constraints = append(constraints, qeAPI.SubExtension(state[0], sBoxIn)) constraints = append(constraints, qeAPI.SubExtension(state[0], sBoxIn))
state[0] = poseidonChip.SBoxMonomialExtension(sBoxIn) state[0] = poseidonChip.SBoxMonomialExtension(sBoxIn)
state[0] = qeAPI.AddExtension(state[0], qeAPI.FieldToQE(poseidon.FAST_PARTIAL_ROUND_CONSTANTS[r]))
state[0] = qeAPI.AddExtension(state[0], qeAPI.VarToQE(poseidon.FAST_PARTIAL_ROUND_CONSTANTS[r]))
state = poseidonChip.MdsPartialLayerFastExtension(state, int(r)) state = poseidonChip.MdsPartialLayerFastExtension(state, int(r))
} }
sBoxIn := vars.localWires[g.WirePartialSBox(poseidon.N_PARTIAL_ROUNDS-1)] sBoxIn := vars.localWires[g.WirePartialSBox(poseidon.N_PARTIAL_ROUNDS-1)]

+ 2
- 2
verifier/internal/gates/poseidon_mds_gate.go

@ -47,11 +47,11 @@ func (g *PoseidonMdsGate) mdsRowShfAlgebra(r uint64, v [poseidon.SPONGE_WIDTH]fi
res := qeAPI.ZERO_QE_ALGEBRA res := qeAPI.ZERO_QE_ALGEBRA
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ { for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
coeff := qeAPI.FieldToQE(poseidon.MDS_MATRIX_CIRC[i])
coeff := qeAPI.VarToQE(poseidon.MDS_MATRIX_CIRC[i])
res = qeAPI.AddExtensionAlgebra(res, qeAPI.ScalarMulExtensionAlgebra(coeff, v[(i+r)%poseidon.SPONGE_WIDTH])) res = qeAPI.AddExtensionAlgebra(res, qeAPI.ScalarMulExtensionAlgebra(coeff, v[(i+r)%poseidon.SPONGE_WIDTH]))
} }
coeff := qeAPI.FieldToQE(poseidon.MDS_MATRIX_DIAG[r])
coeff := qeAPI.VarToQE(poseidon.MDS_MATRIX_DIAG[r])
res = qeAPI.AddExtensionAlgebra(res, qeAPI.ScalarMulExtensionAlgebra(coeff, v[r])) res = qeAPI.AddExtensionAlgebra(res, qeAPI.ScalarMulExtensionAlgebra(coeff, v[r]))
return res return res

+ 7
- 6
verifier/internal/plonk/challenger.go

@ -15,18 +15,18 @@ type ChallengerChip struct {
field field.FieldAPI `gnark:"-"` field field.FieldAPI `gnark:"-"`
poseidonChip *poseidon.PoseidonChip poseidonChip *poseidon.PoseidonChip
poseidonBN128Chip *poseidon.PoseidonBN128Chip poseidonBN128Chip *poseidon.PoseidonBN128Chip
spongeState [poseidon.SPONGE_WIDTH]field.F
spongeState [poseidon.SPONGE_WIDTH]frontend.Variable
inputBuffer []field.F inputBuffer []field.F
outputBuffer []field.F outputBuffer []field.F
} }
func NewChallengerChip(api frontend.API, fieldAPI field.FieldAPI, poseidonChip *poseidon.PoseidonChip, poseidonBN128Chip *poseidon.PoseidonBN128Chip) *ChallengerChip { func NewChallengerChip(api frontend.API, fieldAPI field.FieldAPI, poseidonChip *poseidon.PoseidonChip, poseidonBN128Chip *poseidon.PoseidonBN128Chip) *ChallengerChip {
var spongeState [poseidon.SPONGE_WIDTH]field.F
var spongeState [poseidon.SPONGE_WIDTH]frontend.Variable
var inputBuffer []field.F var inputBuffer []field.F
var outputBuffer []field.F var outputBuffer []field.F
for i := 0; i < poseidon.SPONGE_WIDTH; i++ { for i := 0; i < poseidon.SPONGE_WIDTH; i++ {
spongeState[i] = field.ZERO_F
spongeState[i] = frontend.Variable(0)
} }
return &ChallengerChip{ return &ChallengerChip{
@ -148,12 +148,13 @@ func (c *ChallengerChip) duplexing() {
panic("something went wrong") panic("something went wrong")
} }
copy(c.spongeState[:], c.inputBuffer)
for i := 0; i < len(c.inputBuffer); i++ {
c.spongeState[i] = c.field.Reduce(c.inputBuffer[i]).Limbs[0]
}
c.inputBuffer = clearBuffer(c.inputBuffer) c.inputBuffer = clearBuffer(c.inputBuffer)
c.spongeState = c.poseidonChip.Poseidon(c.spongeState) c.spongeState = c.poseidonChip.Poseidon(c.spongeState)
clearBuffer(c.outputBuffer) clearBuffer(c.outputBuffer)
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[i] = c.spongeState[i]
c.outputBuffer = append(c.outputBuffer, c.field.NewElement(c.spongeState[i]))
} }
} }

+ 144
- 104
verifier/internal/plonk/challenger_test.go

@ -4,46 +4,63 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
"github.com/consensys/gnark/test" "github.com/consensys/gnark/test"
"github.com/succinctlabs/gnark-plonky2-verifier/field" "github.com/succinctlabs/gnark-plonky2-verifier/field"
"github.com/succinctlabs/gnark-plonky2-verifier/poseidon" "github.com/succinctlabs/gnark-plonky2-verifier/poseidon"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/common"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/internal/fri"
"github.com/succinctlabs/gnark-plonky2-verifier/verifier/utils"
) )
type TestChallengerCircuit struct { type TestChallengerCircuit struct {
PublicInputs []field.F
CircuitDigest poseidon.PoseidonBN128HashOut
WiresCap [16]poseidon.PoseidonBN128HashOut
PlonkZsPartialProductsCap [16]poseidon.PoseidonBN128HashOut
QuotientPolysCap [16]poseidon.PoseidonBN128HashOut
commonCircuitDataFilename string `gnark:"-"`
CircuitDigest frontend.Variable `gnark:",public"`
PublicInputs []field.F `gnark:",public"`
WiresCap []frontend.Variable
PlonkZsPartialProductsCap []frontend.Variable
QuotientPolysCap []frontend.Variable
FriOpenings fri.FriOpenings
CommitPhaseMerkleCaps [][]frontend.Variable
FinalPoly common.PolynomialCoeffs
PowWitness field.F
} }
func (circuit *TestChallengerCircuit) Define(api frontend.API) error { func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
commonCircuitData := utils.DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
config := commonCircuitData.Config
numChallenges := config.NumChallenges
fieldAPI := field.NewFieldAPI(api) fieldAPI := field.NewFieldAPI(api)
qeAPI := field.NewQuadraticExtensionAPI(api, fieldAPI) qeAPI := field.NewQuadraticExtensionAPI(api, fieldAPI)
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI) poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI)
poseidonBN128Chip := poseidon.NewPoseidonBN128Chip(api, fieldAPI) poseidonBN128Chip := poseidon.NewPoseidonBN128Chip(api, fieldAPI)
challengerChip := NewChallengerChip(api, fieldAPI, poseidonChip, poseidonBN128Chip)
challenger := NewChallengerChip(api, fieldAPI, poseidonChip, poseidonBN128Chip)
challengerChip.ObserveBN128Hash(circuit.CircuitDigest)
publicInputHash := poseidonChip.HashNoPad(circuit.PublicInputs[:])
challengerChip.ObserveHash(publicInputHash)
challengerChip.ObserveCap(circuit.WiresCap[:])
challenger.ObserveBN128Hash(circuit.CircuitDigest)
challenger.ObserveHash(poseidonChip.HashNoPad(circuit.PublicInputs))
challenger.ObserveCap(circuit.WiresCap)
plonkBetas := challenger.GetNChallenges(numChallenges)
plonkGammas := challenger.GetNChallenges(numChallenges)
numChallenges := uint64(2)
plonkBetas := challengerChip.GetNChallenges(numChallenges)
plonkGammas := challengerChip.GetNChallenges(numChallenges)
challenger.ObserveCap(circuit.PlonkZsPartialProductsCap)
plonkAlphas := challenger.GetNChallenges(numChallenges)
expectedPublicInputHash := [4]field.F{
field.NewFieldConstFromString("0"),
field.NewFieldConstFromString("0"),
field.NewFieldConstFromString("0"),
field.NewFieldConstFromString("0"),
}
challenger.ObserveCap(circuit.QuotientPolysCap)
plonkZeta := challenger.GetExtensionChallenge()
for i := 0; i < 4; i++ {
fieldAPI.AssertIsEqual(publicInputHash[i], expectedPublicInputHash[i])
}
challenger.ObserveOpenings(circuit.FriOpenings)
friChallenges := challenger.GetFriChallenges(
circuit.CommitPhaseMerkleCaps,
circuit.FinalPoly,
circuit.PowWitness,
commonCircuitData.DegreeBits,
config.FriConfig,
)
expectedPlonkBetas := [2]field.F{ expectedPlonkBetas := [2]field.F{
field.NewFieldConstFromString("17615363392879944733"), field.NewFieldConstFromString("17615363392879944733"),
@ -60,9 +77,6 @@ func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
fieldAPI.AssertIsEqual(plonkGammas[i], expectedPlonkGammas[i]) fieldAPI.AssertIsEqual(plonkGammas[i], expectedPlonkGammas[i])
} }
challengerChip.ObserveCap(circuit.PlonkZsPartialProductsCap[:])
plonkAlphas := challengerChip.GetNChallenges(numChallenges)
expectedPlonkAlphas := [2]field.F{ expectedPlonkAlphas := [2]field.F{
field.NewFieldConstFromString("9276470834414745550"), field.NewFieldConstFromString("9276470834414745550"),
field.NewFieldConstFromString("5302812342351431915"), field.NewFieldConstFromString("5302812342351431915"),
@ -72,9 +86,6 @@ func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
fieldAPI.AssertIsEqual(plonkAlphas[i], expectedPlonkAlphas[i]) fieldAPI.AssertIsEqual(plonkAlphas[i], expectedPlonkAlphas[i])
} }
challengerChip.ObserveCap(circuit.QuotientPolysCap[:])
plonkZeta := challengerChip.GetExtensionChallenge()
expectedPlonkZeta := field.QuadraticExtension{ expectedPlonkZeta := field.QuadraticExtension{
field.NewFieldConstFromString("3892795992421241388"), field.NewFieldConstFromString("3892795992421241388"),
field.NewFieldConstFromString("15786647757418200302"), field.NewFieldConstFromString("15786647757418200302"),
@ -84,6 +95,14 @@ func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
fieldAPI.AssertIsEqual(plonkZeta[i], expectedPlonkZeta[i]) fieldAPI.AssertIsEqual(plonkZeta[i], expectedPlonkZeta[i])
} }
fieldAPI.AssertIsEqual(friChallenges.FriAlpha[0], field.NewFieldConst(885535811531859621))
fieldAPI.AssertIsEqual(friChallenges.FriBetas[0][0], field.NewFieldConst(5231781384587895507))
fieldAPI.AssertIsEqual(friChallenges.FriPowResponse, field.NewFieldConst(70715523064019))
fieldAPI.AssertIsEqual(friChallenges.FriQueryIndices[0], field.NewFieldConst(11890500485816111017))
return nil return nil
} }
@ -100,88 +119,109 @@ func StringToBN128Hash(hashStr string) poseidon.PoseidonBN128HashOut {
func TestChallengerWitness(t *testing.T) { func TestChallengerWitness(t *testing.T) {
assert := test.NewAssert(t) assert := test.NewAssert(t)
testCase := func(
publicInputs []field.F,
circuitDigest poseidon.PoseidonBN128HashOut,
wiresCap [16]poseidon.PoseidonBN128HashOut,
plonkZsPartialProductsCap [16]poseidon.PoseidonBN128HashOut,
quotientPolysCap [16]poseidon.PoseidonBN128HashOut,
) {
testCase := func() {
proofWithPis := utils.DeserializeProofWithPublicInputs("../../data/decode_block/proof_with_public_inputs.json")
verifierData := utils.DeserializeVerifierOnlyCircuitData("../../data/decode_block/verifier_only_circuit_data.json")
circuit := TestChallengerCircuit{ circuit := TestChallengerCircuit{
PublicInputs: publicInputs,
CircuitDigest: circuitDigest,
WiresCap: wiresCap,
PlonkZsPartialProductsCap: plonkZsPartialProductsCap,
QuotientPolysCap: quotientPolysCap,
commonCircuitDataFilename: "../../data/decode_block/common_circuit_data.json",
CircuitDigest: verifierData.CircuitDigest,
PublicInputs: proofWithPis.PublicInputs,
WiresCap: proofWithPis.Proof.WiresCap,
PlonkZsPartialProductsCap: proofWithPis.Proof.PlonkZsPartialProductsCap,
QuotientPolysCap: proofWithPis.Proof.QuotientPolysCap,
FriOpenings: fri.ToFriOpenings(proofWithPis.Proof.Openings),
CommitPhaseMerkleCaps: proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
FinalPoly: proofWithPis.Proof.OpeningProof.FinalPoly,
PowWitness: proofWithPis.Proof.OpeningProof.PowWitness,
} }
witness := TestChallengerCircuit{ witness := TestChallengerCircuit{
PublicInputs: publicInputs,
CircuitDigest: circuitDigest,
WiresCap: wiresCap,
PlonkZsPartialProductsCap: plonkZsPartialProductsCap,
QuotientPolysCap: quotientPolysCap,
CircuitDigest: verifierData.CircuitDigest,
PublicInputs: proofWithPis.PublicInputs,
WiresCap: proofWithPis.Proof.WiresCap,
PlonkZsPartialProductsCap: proofWithPis.Proof.PlonkZsPartialProductsCap,
QuotientPolysCap: proofWithPis.Proof.QuotientPolysCap,
FriOpenings: fri.ToFriOpenings(proofWithPis.Proof.Openings),
CommitPhaseMerkleCaps: proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
FinalPoly: proofWithPis.Proof.OpeningProof.FinalPoly,
PowWitness: proofWithPis.Proof.OpeningProof.PowWitness,
} }
err := test.IsSolved(&circuit, &witness, field.TEST_CURVE.ScalarField()) err := test.IsSolved(&circuit, &witness, field.TEST_CURVE.ScalarField())
assert.NoError(err) assert.NoError(err)
} }
publicInputs := []field.F{}
circuitDigest := StringToBN128Hash("11532502846882484230992726008257788785937565673229400981185786126842727172973")
wiresCaps := [16]poseidon.PoseidonBN128HashOut{}
wiresCaps[0] = StringToBN128Hash("6232016528318542211523647364792867346449137823066292895075623303633330508214")
wiresCaps[1] = StringToBN128Hash("3849229275985461680629770572508259203226163621677714310355251582693130685288")
wiresCaps[2] = StringToBN128Hash("5987556171512366759354088598227343740440477791444099795740854232780130336082")
wiresCaps[3] = StringToBN128Hash("8523377779888975334090507575349048869294640263235559121841789718805736414837")
wiresCaps[4] = StringToBN128Hash("4173305429039088756536564029627250985745421317354666614089039608061166671898")
wiresCaps[5] = StringToBN128Hash("19514742808406256372169729907222415291809011606011679387563713660256488346125")
wiresCaps[6] = StringToBN128Hash("8519703011007005463193900985655355044586093539828702987016626948657512235078")
wiresCaps[7] = StringToBN128Hash("13337062986664638507390757043422262298890182385759661595000247205380836291424")
wiresCaps[8] = StringToBN128Hash("13956988298720968721248573872513053256190487207048215310365406791617256823071")
wiresCaps[9] = StringToBN128Hash("4139118776078237399422219240136866906229498819930564462151328936368637474741")
wiresCaps[10] = StringToBN128Hash("20010683036854145765538326917745039166608941517703057250025522185331298063240")
wiresCaps[11] = StringToBN128Hash("16542849340693186579674885260236043503488748690860552251132996633211111581047")
wiresCaps[12] = StringToBN128Hash("15340310232736118098606223218073833983285921571850333937460777227732109309104")
wiresCaps[13] = StringToBN128Hash("14370557250059545670244193708996703450518439828341533154117610442161777001185")
wiresCaps[14] = StringToBN128Hash("18844434454299441334771065219656682212700835025465734281792408139929868142021")
wiresCaps[15] = StringToBN128Hash("19676343740377898318702605893881480074303742058989194823248293456630167789460")
plonkZsPartialProductsCaps := [16]poseidon.PoseidonBN128HashOut{}
plonkZsPartialProductsCaps[0] = StringToBN128Hash("18630303757724954689095079665308152603926320437432442392614316813333911252124")
plonkZsPartialProductsCaps[1] = StringToBN128Hash("1941509032097423911575973752610668722198580889286836043016771886256831254944")
plonkZsPartialProductsCaps[2] = StringToBN128Hash("6147898094056673441182607282006528423230906496770003193057422314911254596722")
plonkZsPartialProductsCaps[3] = StringToBN128Hash("8711744418341460096856191310559061094028644913424948320707020455945693390966")
plonkZsPartialProductsCaps[4] = StringToBN128Hash("3170507894509162329082713944669012510679535839018490515228566075949014704871")
plonkZsPartialProductsCaps[5] = StringToBN128Hash("9513443633020527244719737008971091746535961947215556968735061932963144145728")
plonkZsPartialProductsCaps[6] = StringToBN128Hash("16440622144490342815400399751667969445057099157732990266662948140364680211732")
plonkZsPartialProductsCaps[7] = StringToBN128Hash("16904904288584890809819587275120157893767917607795020298373538872373275028362")
plonkZsPartialProductsCaps[8] = StringToBN128Hash("1322883689945010694042124537248103086068476085787048131689196755087178475099")
plonkZsPartialProductsCaps[9] = StringToBN128Hash("3859729225679954076862546769780866075152550721517632074656261209033111218654")
plonkZsPartialProductsCaps[10] = StringToBN128Hash("5995885491698588595978721670502011088690021401297557688057158353938846681398")
plonkZsPartialProductsCaps[11] = StringToBN128Hash("16957177478856199232404038751327729781816109007496656232207408246975862260922")
plonkZsPartialProductsCaps[12] = StringToBN128Hash("9422393668093911702915740702404346320943009100616501740579421944206639410155")
plonkZsPartialProductsCaps[13] = StringToBN128Hash("15680345727093646870610240619814271686346382346107751208797654607051065248818")
plonkZsPartialProductsCaps[14] = StringToBN128Hash("4939261448468032698521878059774016528161329965101885352386001950329280576201")
plonkZsPartialProductsCaps[15] = StringToBN128Hash("7003946111898359335505647195128523292498498760325513092978040051648331398446")
quotientPolysCaps := [16]poseidon.PoseidonBN128HashOut{}
quotientPolysCaps[0] = StringToBN128Hash("3918560082526903400389798118659365477465402367561322989181693953047280669646")
quotientPolysCaps[1] = StringToBN128Hash("496966935842756068593963213547105605432646958081400837931911611833297095727")
quotientPolysCaps[2] = StringToBN128Hash("8683297895986438077633020202252074142721819824824948690853505463451806801507")
quotientPolysCaps[3] = StringToBN128Hash("14623770060934618886104076268225324888644340537717836901769942847173950269850")
quotientPolysCaps[4] = StringToBN128Hash("902377468311802642056170073282349607767917979325737018777782566011948776523")
quotientPolysCaps[5] = StringToBN128Hash("12124340721627925810131860890689432371048624670798932303474977401990312142398")
quotientPolysCaps[6] = StringToBN128Hash("21656753786114693289615694183370749990935753681953197920766927707640495235100")
quotientPolysCaps[7] = StringToBN128Hash("4651674172794111060599611529192263627230814664669763852917839857516619530510")
quotientPolysCaps[8] = StringToBN128Hash("13161231355626784301812735677481006076469384200800574341495987998366265598910")
quotientPolysCaps[9] = StringToBN128Hash("20853590455948262404101100028402584187982204016660952863575312077951992942329")
quotientPolysCaps[10] = StringToBN128Hash("742867642166478273564934628555265381154191517824405375118170559554873960389")
quotientPolysCaps[11] = StringToBN128Hash("17617970388755497287414457313283777609067524774358298322461931046141926005038")
quotientPolysCaps[12] = StringToBN128Hash("55496208750959228576253470708262329602643441253143570259294790484739321332")
quotientPolysCaps[13] = StringToBN128Hash("18450079114184018679423491604333957974306902732410122012117555285853099024676")
quotientPolysCaps[14] = StringToBN128Hash("14403337493956171864251492809058241138806636992110526018123749007090024780352")
quotientPolysCaps[15] = StringToBN128Hash("252265115458024097842043026135110356285192501597856208375838682286051476335")
testCase(publicInputs, circuitDigest, wiresCaps, plonkZsPartialProductsCaps, quotientPolysCaps)
testCase()
}
func TestChallengerProver(t *testing.T) {
proofWithPis := utils.DeserializeProofWithPublicInputs("../../data/decode_block/proof_with_public_inputs.json")
verifierData := utils.DeserializeVerifierOnlyCircuitData("../../data/decode_block/verifier_only_circuit_data.json")
circuit := TestChallengerCircuit{
commonCircuitDataFilename: "../../data/decode_block/common_circuit_data.json",
CircuitDigest: verifierData.CircuitDigest,
PublicInputs: proofWithPis.PublicInputs,
WiresCap: proofWithPis.Proof.WiresCap,
PlonkZsPartialProductsCap: proofWithPis.Proof.PlonkZsPartialProductsCap,
QuotientPolysCap: proofWithPis.Proof.QuotientPolysCap,
FriOpenings: fri.ToFriOpenings(proofWithPis.Proof.Openings),
CommitPhaseMerkleCaps: proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
FinalPoly: proofWithPis.Proof.OpeningProof.FinalPoly,
PowWitness: proofWithPis.Proof.OpeningProof.PowWitness,
}
proofWithPis = utils.DeserializeProofWithPublicInputs("../../data/decode_block/proof_with_public_inputs.json")
verifierData = utils.DeserializeVerifierOnlyCircuitData("../../data/decode_block/verifier_only_circuit_data.json")
assignment := TestChallengerCircuit{
commonCircuitDataFilename: "../../data/decode_block/common_circuit_data.json",
CircuitDigest: verifierData.CircuitDigest,
PublicInputs: proofWithPis.PublicInputs,
WiresCap: proofWithPis.Proof.WiresCap,
PlonkZsPartialProductsCap: proofWithPis.Proof.PlonkZsPartialProductsCap,
QuotientPolysCap: proofWithPis.Proof.QuotientPolysCap,
FriOpenings: fri.ToFriOpenings(proofWithPis.Proof.Openings),
CommitPhaseMerkleCaps: proofWithPis.Proof.OpeningProof.CommitPhaseMerkleCaps,
FinalPoly: proofWithPis.Proof.OpeningProof.FinalPoly,
PowWitness: proofWithPis.Proof.OpeningProof.PowWitness,
}
r1cs, err := frontend.Compile(field.TEST_CURVE.ScalarField(), r1cs.NewBuilder, &circuit)
if err != nil {
panic(err)
}
println("num constraints is ", r1cs.GetNbConstraints())
assert := test.NewAssert(t)
err = test.IsSolved(&circuit, &assignment, field.TEST_CURVE.ScalarField())
assert.NoError(err)
witness, err := frontend.NewWitness(&assignment, field.TEST_CURVE.ScalarField())
if err != nil {
panic(err)
}
pk, vk, err := groth16.Setup(r1cs)
if err != nil {
panic(err)
}
proof, err := groth16.Prove(r1cs, pk, witness)
if err != nil {
panic(err)
}
publicWitness, err := witness.Public()
if err != nil {
panic(err)
}
err = groth16.Verify(proof, vk, publicWitness)
if err != nil {
panic(err)
}
} }

Loading…
Cancel
Save