mirror of
https://github.com/arnaucube/gnark-plonky2-verifier.git
synced 2026-01-12 09:01:32 +01:00
Poseidon extension function versions, and finished PoseidonGate
This commit is contained in:
@@ -20,38 +20,40 @@ type TestChallengerCircuit struct {
|
||||
}
|
||||
|
||||
func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
|
||||
field := field.NewFieldAPI(api)
|
||||
poseidonChip := NewPoseidonChip(api, field)
|
||||
challengerChip := NewChallengerChip(api, field, poseidonChip)
|
||||
fieldAPI := field.NewFieldAPI(api)
|
||||
degreeBits := 3
|
||||
qeAPI := NewQuadraticExtensionAPI(fieldAPI, uint64(degreeBits))
|
||||
poseidonChip := NewPoseidonChip(api, fieldAPI, qeAPI)
|
||||
challengerChip := NewChallengerChip(api, fieldAPI, poseidonChip)
|
||||
|
||||
var circuitDigest [4]F
|
||||
for i := 0; i < len(circuitDigest); i++ {
|
||||
circuitDigest[i] = field.FromBinary(api.ToBinary(circuit.CircuitDigest[i], 64)).(F)
|
||||
circuitDigest[i] = fieldAPI.FromBinary(api.ToBinary(circuit.CircuitDigest[i], 64)).(F)
|
||||
}
|
||||
|
||||
var publicInputs [3]F
|
||||
for i := 0; i < len(publicInputs); i++ {
|
||||
publicInputs[i] = field.FromBinary(api.ToBinary(circuit.PublicInputs[i], 64)).(F)
|
||||
publicInputs[i] = fieldAPI.FromBinary(api.ToBinary(circuit.PublicInputs[i], 64)).(F)
|
||||
}
|
||||
|
||||
var wiresCap [16][4]F
|
||||
for i := 0; i < len(wiresCap); i++ {
|
||||
for j := 0; j < len(wiresCap[0]); j++ {
|
||||
wiresCap[i][j] = field.FromBinary(api.ToBinary(circuit.WiresCap[i][j], 64)).(F)
|
||||
wiresCap[i][j] = fieldAPI.FromBinary(api.ToBinary(circuit.WiresCap[i][j], 64)).(F)
|
||||
}
|
||||
}
|
||||
|
||||
var plonkZsPartialProductsCap [16][4]F
|
||||
for i := 0; i < len(plonkZsPartialProductsCap); i++ {
|
||||
for j := 0; j < len(plonkZsPartialProductsCap[0]); j++ {
|
||||
plonkZsPartialProductsCap[i][j] = field.FromBinary(api.ToBinary(circuit.PlonkZsPartialProductsCap[i][j], 64)).(F)
|
||||
plonkZsPartialProductsCap[i][j] = fieldAPI.FromBinary(api.ToBinary(circuit.PlonkZsPartialProductsCap[i][j], 64)).(F)
|
||||
}
|
||||
}
|
||||
|
||||
var quotientPolysCap [16][4]F
|
||||
for i := 0; i < len(quotientPolysCap); i++ {
|
||||
for j := 0; j < len(quotientPolysCap[0]); j++ {
|
||||
quotientPolysCap[i][j] = field.FromBinary(api.ToBinary(circuit.QuotientPolysCap[i][j], 64)).(F)
|
||||
quotientPolysCap[i][j] = fieldAPI.FromBinary(api.ToBinary(circuit.QuotientPolysCap[i][j], 64)).(F)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +74,7 @@ func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
|
||||
}
|
||||
|
||||
for i := 0; i < 4; i++ {
|
||||
field.AssertIsEqual(publicInputHash[i], expectedPublicInputHash[i])
|
||||
fieldAPI.AssertIsEqual(publicInputHash[i], expectedPublicInputHash[i])
|
||||
}
|
||||
|
||||
expectedPlonkBetas := [2]F{
|
||||
@@ -86,8 +88,8 @@ func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
|
||||
}
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
field.AssertIsEqual(plonkBetas[i], expectedPlonkBetas[i])
|
||||
field.AssertIsEqual(plonkGammas[i], expectedPlonkGammas[i])
|
||||
fieldAPI.AssertIsEqual(plonkBetas[i], expectedPlonkBetas[i])
|
||||
fieldAPI.AssertIsEqual(plonkGammas[i], expectedPlonkGammas[i])
|
||||
}
|
||||
|
||||
challengerChip.ObserveCap(plonkZsPartialProductsCap[:])
|
||||
@@ -99,7 +101,7 @@ func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
|
||||
}
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
field.AssertIsEqual(plonkAlphas[i], expectedPlonkAlphas[i])
|
||||
fieldAPI.AssertIsEqual(plonkAlphas[i], expectedPlonkAlphas[i])
|
||||
}
|
||||
|
||||
challengerChip.ObserveCap(quotientPolysCap[:])
|
||||
@@ -111,7 +113,7 @@ func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
|
||||
}
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
field.AssertIsEqual(plonkZeta[i], expectedPlonkZeta[i])
|
||||
fieldAPI.AssertIsEqual(plonkZeta[i], expectedPlonkZeta[i])
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -29,7 +29,7 @@ func (circuit *TestFriCircuit) Define(api frontend.API) error {
|
||||
fieldAPI := NewFieldAPI(api)
|
||||
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits)
|
||||
hashAPI := NewHashAPI(fieldAPI)
|
||||
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI)
|
||||
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI)
|
||||
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams)
|
||||
|
||||
friChallenges := FriChallenges{
|
||||
|
||||
@@ -23,8 +23,8 @@ func (circuit *TestPlonkCircuit) Define(api frontend.API) error {
|
||||
proofWithPis := DeserializeProofWithPublicInputs(circuit.proofWithPIsFilename)
|
||||
commonCircuitData := DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
|
||||
|
||||
field := NewFieldAPI(api)
|
||||
qe := NewQuadraticExtensionAPI(field, commonCircuitData.DegreeBits)
|
||||
fieldAPI := NewFieldAPI(api)
|
||||
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits)
|
||||
|
||||
proofChallenges := ProofChallenges{
|
||||
PlonkBetas: circuit.plonkBetas,
|
||||
@@ -33,9 +33,9 @@ func (circuit *TestPlonkCircuit) Define(api frontend.API) error {
|
||||
PlonkZeta: circuit.plonkZeta,
|
||||
}
|
||||
|
||||
plonkChip := NewPlonkChip(api, qe, commonCircuitData)
|
||||
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData)
|
||||
|
||||
poseidonChip := poseidon.NewPoseidonChip(api, field)
|
||||
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI)
|
||||
publicInputsHash := poseidonChip.HashNoPad(proofWithPis.PublicInputs)
|
||||
|
||||
plonkChip.Verify(proofChallenges, proofWithPis.Proof.Openings, publicInputsHash)
|
||||
|
||||
@@ -74,6 +74,8 @@ type PoseidonGate struct {
|
||||
func (p *PoseidonGate) EvalUnfiltered(pc *PlonkChip, vars EvaluationVars) []QuadraticExtension {
|
||||
constraints := []QuadraticExtension{}
|
||||
|
||||
poseidonChip := poseidon.NewPoseidonChip(pc.api, NewFieldAPI(pc.api), pc.qeAPI)
|
||||
|
||||
// Assert that `swap` is binary.
|
||||
swap := vars.localWires[p.WireSwap()]
|
||||
notSwap := pc.qeAPI.SubExtension(pc.qeAPI.FieldToQE(ONE_F), swap)
|
||||
@@ -90,7 +92,7 @@ func (p *PoseidonGate) EvalUnfiltered(pc *PlonkChip, vars EvaluationVars) []Quad
|
||||
}
|
||||
|
||||
// Compute the possibly-swapped input layer.
|
||||
state := make([]QuadraticExtension, poseidon.SPONGE_WIDTH)
|
||||
var state [poseidon.SPONGE_WIDTH]QuadraticExtension
|
||||
for i := uint64(0); i < 4; i++ {
|
||||
deltaI := vars.localWires[p.WireDelta(i)]
|
||||
inputLhs := vars.localWires[p.WireInput(i)]
|
||||
@@ -106,7 +108,7 @@ func (p *PoseidonGate) EvalUnfiltered(pc *PlonkChip, vars EvaluationVars) []Quad
|
||||
|
||||
// First set of full rounds.
|
||||
for r := uint64(0); r < poseidon.HALF_N_FULL_ROUNDS; r++ {
|
||||
// TODO: constantLayerField(state, round_ctr)
|
||||
state = poseidonChip.ConstantLayerExtension(state, &round_ctr)
|
||||
if r != 0 {
|
||||
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
|
||||
sBoxIn := vars.localWires[p.WireFullSBox0(r, i)]
|
||||
@@ -114,37 +116,37 @@ func (p *PoseidonGate) EvalUnfiltered(pc *PlonkChip, vars EvaluationVars) []Quad
|
||||
state[i] = sBoxIn
|
||||
}
|
||||
}
|
||||
// TODO: sboxLayerField(state)
|
||||
// TODO: state = mdsLayerField(state)
|
||||
state = poseidonChip.SBoxLayerExtension(state)
|
||||
state = poseidonChip.MdsLayerExtension(state)
|
||||
round_ctr++
|
||||
}
|
||||
|
||||
// Partial rounds.
|
||||
// TODO: partialFirstConstantLayer(state)
|
||||
// TODO: state = mdsParitalLayerInit(state)
|
||||
state = poseidonChip.PartialFirstConstantLayerExtension(state)
|
||||
state = poseidonChip.MdsPartialLayerInitExtension(state)
|
||||
for r := uint64(0); r < poseidon.N_PARTIAL_ROUNDS-1; r++ {
|
||||
sBoxIn := vars.localWires[p.WirePartialSBox(r)]
|
||||
constraints = append(constraints, pc.qeAPI.SubExtension(state[0], sBoxIn))
|
||||
// TODO: state[0] = sBoxMonomial(sBoxIn)
|
||||
// TODO: state[0] += NewFieldElement(FAST_PARTIAL_ROUND_CONSTANTS[r])
|
||||
// TODO: state = mdsParitalLayerFastField(state, r)
|
||||
state[0] = poseidonChip.SBoxMonomialExtension(sBoxIn)
|
||||
state[0] = pc.qeAPI.AddExtension(state[0], pc.qeAPI.FieldToQE(NewFieldElement(poseidon.FAST_PARTIAL_ROUND_CONSTANTS[r])))
|
||||
state = poseidonChip.MdsPartialLayerFastExtension(state, int(r))
|
||||
}
|
||||
sBoxIn := vars.localWires[p.WirePartialSBox(poseidon.N_PARTIAL_ROUNDS-1)]
|
||||
constraints = append(constraints, pc.qeAPI.SubExtension(state[0], sBoxIn))
|
||||
// TODO: state[0] = sBoxMonomial(sBoxIn)
|
||||
// TODO: state = mdsPartialLayerLastField(state, poseidon.N_PARTIAL_ROUNDS - 1)
|
||||
state[0] = poseidonChip.SBoxMonomialExtension(sBoxIn)
|
||||
state = poseidonChip.MdsPartialLayerFastExtension(state, poseidon.N_PARTIAL_ROUNDS-1)
|
||||
round_ctr += poseidon.N_PARTIAL_ROUNDS
|
||||
|
||||
// Second set of full rounds.
|
||||
for r := uint64(0); r < poseidon.HALF_N_FULL_ROUNDS; r++ {
|
||||
// TODO: constantLayerField(state, round_ctr)
|
||||
poseidonChip.ConstantLayerExtension(state, &round_ctr)
|
||||
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
|
||||
sBoxIn := vars.localWires[p.WireFullSBox1(r, i)]
|
||||
constraints = append(constraints, pc.qeAPI.SubExtension(state[i], sBoxIn))
|
||||
state[i] = sBoxIn
|
||||
}
|
||||
// TODO: sboxLayerField(state)
|
||||
// TODO: state = mdsLayerField(state)
|
||||
state = poseidonChip.MdsLayerExtension(state)
|
||||
state = poseidonChip.SBoxLayerExtension(state)
|
||||
round_ctr++
|
||||
}
|
||||
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
package plonky2_verifier
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
. "gnark-plonky2-verifier/field"
|
||||
"math/bits"
|
||||
|
||||
"github.com/consensys/gnark/frontend"
|
||||
)
|
||||
|
||||
type QuadraticExtensionAPI struct {
|
||||
fieldAPI frontend.API
|
||||
|
||||
W F
|
||||
DTH_ROOT F
|
||||
|
||||
ONE_QE QuadraticExtension
|
||||
ZERO_QE QuadraticExtension
|
||||
}
|
||||
|
||||
func NewQuadraticExtensionAPI(fieldAPI frontend.API, degreeBits uint64) *QuadraticExtensionAPI {
|
||||
// TODO: Should degreeBits be verified that it fits within the field and that degree is within uint64?
|
||||
|
||||
return &QuadraticExtensionAPI{
|
||||
fieldAPI: fieldAPI,
|
||||
|
||||
W: NewFieldElement(7),
|
||||
DTH_ROOT: NewFieldElement(18446744069414584320),
|
||||
|
||||
ONE_QE: QuadraticExtension{ONE_F, ZERO_F},
|
||||
ZERO_QE: QuadraticExtension{ZERO_F, ZERO_F},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) SquareExtension(a QuadraticExtension) QuadraticExtension {
|
||||
return c.MulExtension(a, a)
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) MulExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
|
||||
c_0 := c.fieldAPI.Add(c.fieldAPI.Mul(a[0], b[0]).(F), c.fieldAPI.Mul(c.W, a[1], b[1])).(F)
|
||||
c_1 := c.fieldAPI.Add(c.fieldAPI.Mul(a[0], b[1]).(F), c.fieldAPI.Mul(a[1], b[0])).(F)
|
||||
return QuadraticExtension{c_0, c_1}
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) AddExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
|
||||
c_0 := c.fieldAPI.Add(a[0], b[0]).(F)
|
||||
c_1 := c.fieldAPI.Add(a[1], b[1]).(F)
|
||||
return QuadraticExtension{c_0, c_1}
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) SubExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
|
||||
c_0 := c.fieldAPI.Sub(a[0], b[0]).(F)
|
||||
c_1 := c.fieldAPI.Sub(a[1], b[1]).(F)
|
||||
return QuadraticExtension{c_0, c_1}
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) DivExtension(a QuadraticExtension, b QuadraticExtension) QuadraticExtension {
|
||||
return c.MulExtension(a, c.InverseExtension(b))
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) IsZero(a QuadraticExtension) frontend.Variable {
|
||||
return c.fieldAPI.Mul(c.fieldAPI.IsZero(a[0]), c.fieldAPI.IsZero(a[1]))
|
||||
}
|
||||
|
||||
// TODO: Instead of calculating the inverse within the circuit, can witness the
|
||||
// inverse and assert that a_inverse * a = 1. Should reduce # of constraints.
|
||||
func (c *QuadraticExtensionAPI) InverseExtension(a QuadraticExtension) QuadraticExtension {
|
||||
// First assert that a doesn't have 0 value coefficients
|
||||
a0_is_zero := c.fieldAPI.IsZero(a[0])
|
||||
a1_is_zero := c.fieldAPI.IsZero(a[1])
|
||||
|
||||
// assert that a0_is_zero OR a1_is_zero == false
|
||||
c.fieldAPI.AssertIsEqual(c.fieldAPI.Mul(a0_is_zero, a1_is_zero).(F), ZERO_F)
|
||||
|
||||
a_pow_r_minus_1 := QuadraticExtension{a[0], c.fieldAPI.Mul(a[1], c.DTH_ROOT).(F)}
|
||||
a_pow_r := c.MulExtension(a_pow_r_minus_1, a)
|
||||
return c.ScalarMulExtension(a_pow_r_minus_1, c.fieldAPI.Inverse(a_pow_r[0]).(F))
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) ScalarMulExtension(a QuadraticExtension, scalar F) QuadraticExtension {
|
||||
return QuadraticExtension{c.fieldAPI.Mul(a[0], scalar).(F), c.fieldAPI.Mul(a[1], scalar).(F)}
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) FieldToQE(a F) QuadraticExtension {
|
||||
return QuadraticExtension{a, ZERO_F}
|
||||
}
|
||||
|
||||
// / Exponentiate `base` to the power of a known `exponent`.
|
||||
func (c *QuadraticExtensionAPI) ExpU64Extension(a QuadraticExtension, exponent uint64) QuadraticExtension {
|
||||
switch exponent {
|
||||
case 0:
|
||||
return c.ONE_QE
|
||||
case 1:
|
||||
return a
|
||||
case 2:
|
||||
return c.SquareExtension(a)
|
||||
default:
|
||||
}
|
||||
|
||||
current := a
|
||||
product := c.ONE_QE
|
||||
|
||||
for i := 0; i < bits.Len64(exponent); i++ {
|
||||
if i != 0 {
|
||||
current = c.SquareExtension(current)
|
||||
}
|
||||
|
||||
if (exponent >> i & 1) != 0 {
|
||||
product = c.MulExtension(product, current)
|
||||
}
|
||||
}
|
||||
|
||||
return product
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) ReduceWithPowers(terms []QuadraticExtension, scalar QuadraticExtension) QuadraticExtension {
|
||||
sum := c.ZERO_QE
|
||||
|
||||
for i := len(terms) - 1; i >= 0; i-- {
|
||||
sum = c.AddExtension(
|
||||
c.MulExtension(
|
||||
sum,
|
||||
scalar,
|
||||
),
|
||||
terms[i],
|
||||
)
|
||||
}
|
||||
|
||||
return sum
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) Select(b0 frontend.Variable, qe0, qe1 QuadraticExtension) QuadraticExtension {
|
||||
var retQE QuadraticExtension
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
retQE[i] = c.fieldAPI.Select(b0, qe0[i], qe1[i]).(F)
|
||||
}
|
||||
|
||||
return retQE
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) Lookup2(b0 frontend.Variable, b1 frontend.Variable, qe0, qe1, qe2, qe3 QuadraticExtension) QuadraticExtension {
|
||||
var retQE QuadraticExtension
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
retQE[i] = c.fieldAPI.Lookup2(b0, b1, qe0[i], qe1[i], qe2[i], qe3[i]).(F)
|
||||
}
|
||||
|
||||
return retQE
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) AssertIsEqual(a, b QuadraticExtension) {
|
||||
for i := 0; i < 2; i++ {
|
||||
c.fieldAPI.AssertIsEqual(a[0], b[0])
|
||||
}
|
||||
}
|
||||
|
||||
func (c *QuadraticExtensionAPI) Println(a QuadraticExtension) {
|
||||
fmt.Print("Degree 0 coefficient")
|
||||
c.fieldAPI.Println(a[0])
|
||||
|
||||
fmt.Print("Degree 1 coefficient")
|
||||
c.fieldAPI.Println(a[1])
|
||||
}
|
||||
@@ -21,14 +21,14 @@ type TestQuadraticExtensionMulCircuit struct {
|
||||
}
|
||||
|
||||
func (c *TestQuadraticExtensionMulCircuit) Define(api frontend.API) error {
|
||||
field := field.NewFieldAPI(api)
|
||||
fieldAPI := field.NewFieldAPI(api)
|
||||
degreeBits := 3
|
||||
c.qeAPI = NewQuadraticExtensionAPI(field, uint64(degreeBits))
|
||||
c.qeAPI = NewQuadraticExtensionAPI(fieldAPI, uint64(degreeBits))
|
||||
|
||||
actualRes := c.qeAPI.MulExtension(c.operand1, c.operand2)
|
||||
|
||||
field.AssertIsEqual(actualRes[0], c.expectedResult[0])
|
||||
field.AssertIsEqual(actualRes[1], c.expectedResult[1])
|
||||
fieldAPI.AssertIsEqual(actualRes[0], c.expectedResult[0])
|
||||
fieldAPI.AssertIsEqual(actualRes[1], c.expectedResult[1])
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -55,14 +55,14 @@ type TestQuadraticExtensionDivCircuit struct {
|
||||
}
|
||||
|
||||
func (c *TestQuadraticExtensionDivCircuit) Define(api frontend.API) error {
|
||||
field := field.NewFieldAPI(api)
|
||||
fieldAPI := field.NewFieldAPI(api)
|
||||
degreeBits := 3
|
||||
c.qeAPI = NewQuadraticExtensionAPI(field, uint64(degreeBits))
|
||||
c.qeAPI = NewQuadraticExtensionAPI(fieldAPI, uint64(degreeBits))
|
||||
|
||||
actualRes := c.qeAPI.DivExtension(c.operand1, c.operand2)
|
||||
|
||||
field.AssertIsEqual(actualRes[0], c.expectedResult[0])
|
||||
field.AssertIsEqual(actualRes[1], c.expectedResult[1])
|
||||
fieldAPI.AssertIsEqual(actualRes[0], c.expectedResult[0])
|
||||
fieldAPI.AssertIsEqual(actualRes[1], c.expectedResult[1])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user