mirror of
https://github.com/arnaucube/gnark-plonky2-verifier.git
synced 2026-01-12 09:01:32 +01:00
Merge pull request #2 from succinctlabs/npward-plonky2-gates
Plonky2 Gates
This commit is contained in:
@@ -28,7 +28,7 @@ func (circuit *BenchmarkPlonky2VerifierCircuit) Define(api frontend.API) error {
|
|||||||
fieldAPI := NewFieldAPI(api)
|
fieldAPI := NewFieldAPI(api)
|
||||||
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits)
|
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits)
|
||||||
hashAPI := NewHashAPI(fieldAPI)
|
hashAPI := NewHashAPI(fieldAPI)
|
||||||
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI)
|
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI)
|
||||||
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams)
|
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams)
|
||||||
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData)
|
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData)
|
||||||
circuit.verifierChip = NewVerifierChip(api, fieldAPI, qeAPI, poseidonChip, plonkChip, friChip)
|
circuit.verifierChip = NewVerifierChip(api, fieldAPI, qeAPI, poseidonChip, plonkChip, friChip)
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package plonky2_verifier
|
package field
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
. "gnark-plonky2-verifier/field"
|
|
||||||
"math/bits"
|
"math/bits"
|
||||||
|
|
||||||
"github.com/consensys/gnark/frontend"
|
"github.com/consensys/gnark/frontend"
|
||||||
58
plonky2_verifier/arithmetic_gate.go
Normal file
58
plonky2_verifier/arithmetic_gate.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package plonky2_verifier
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
. "gnark-plonky2-verifier/field"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ArithmeticGate struct {
|
||||||
|
numOps uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewArithmeticGate(numOps uint64) *ArithmeticGate {
|
||||||
|
return &ArithmeticGate{
|
||||||
|
numOps: numOps,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ArithmeticGate) Id() string {
|
||||||
|
return fmt.Sprintf("ArithmeticGate { num_ops: %d }", g.numOps)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ArithmeticGate) WireIthMultiplicand0(i uint64) uint64 {
|
||||||
|
return 4 * i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ArithmeticGate) WireIthMultiplicand1(i uint64) uint64 {
|
||||||
|
return 4*i + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ArithmeticGate) WireIthAddend(i uint64) uint64 {
|
||||||
|
return 4*i + 2
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ArithmeticGate) WireIthOutput(i uint64) uint64 {
|
||||||
|
return 4*i + 3
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ArithmeticGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension {
|
||||||
|
const0 := vars.localConstants[0]
|
||||||
|
const1 := vars.localConstants[1]
|
||||||
|
|
||||||
|
constraints := []QuadraticExtension{}
|
||||||
|
for i := uint64(0); i < g.numOps; i++ {
|
||||||
|
multiplicand0 := vars.localWires[g.WireIthMultiplicand0(i)]
|
||||||
|
multiplicand1 := vars.localWires[g.WireIthMultiplicand1(i)]
|
||||||
|
addend := vars.localWires[g.WireIthAddend(i)]
|
||||||
|
output := vars.localWires[g.WireIthOutput(i)]
|
||||||
|
|
||||||
|
computedOutput := p.qeAPI.AddExtension(
|
||||||
|
p.qeAPI.MulExtension(p.qeAPI.MulExtension(multiplicand0, multiplicand1), const0),
|
||||||
|
p.qeAPI.MulExtension(addend, const1),
|
||||||
|
)
|
||||||
|
|
||||||
|
constraints = append(constraints, p.qeAPI.SubExtension(output, computedOutput))
|
||||||
|
}
|
||||||
|
|
||||||
|
return constraints
|
||||||
|
}
|
||||||
@@ -126,7 +126,7 @@ func (c *ChallengerChip) GetFriChallenges(commitPhaseMerkleCaps []MerkleCap, fin
|
|||||||
FriAlpha: friAlpha,
|
FriAlpha: friAlpha,
|
||||||
FriBetas: friBetas,
|
FriBetas: friBetas,
|
||||||
FriPowResponse: friPowResponse,
|
FriPowResponse: friPowResponse,
|
||||||
FriQueryIndicies: friQueryIndices,
|
FriQueryIndices: friQueryIndices,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,38 +20,40 @@ type TestChallengerCircuit struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
|
func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
|
||||||
field := field.NewFieldAPI(api)
|
fieldAPI := field.NewFieldAPI(api)
|
||||||
poseidonChip := NewPoseidonChip(api, field)
|
degreeBits := 3
|
||||||
challengerChip := NewChallengerChip(api, field, poseidonChip)
|
qeAPI := NewQuadraticExtensionAPI(fieldAPI, uint64(degreeBits))
|
||||||
|
poseidonChip := NewPoseidonChip(api, fieldAPI, qeAPI)
|
||||||
|
challengerChip := NewChallengerChip(api, fieldAPI, poseidonChip)
|
||||||
|
|
||||||
var circuitDigest [4]F
|
var circuitDigest [4]F
|
||||||
for i := 0; i < len(circuitDigest); i++ {
|
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
|
var publicInputs [3]F
|
||||||
for i := 0; i < len(publicInputs); i++ {
|
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
|
var wiresCap [16][4]F
|
||||||
for i := 0; i < len(wiresCap); i++ {
|
for i := 0; i < len(wiresCap); i++ {
|
||||||
for j := 0; j < len(wiresCap[0]); j++ {
|
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
|
var plonkZsPartialProductsCap [16][4]F
|
||||||
for i := 0; i < len(plonkZsPartialProductsCap); i++ {
|
for i := 0; i < len(plonkZsPartialProductsCap); i++ {
|
||||||
for j := 0; j < len(plonkZsPartialProductsCap[0]); j++ {
|
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
|
var quotientPolysCap [16][4]F
|
||||||
for i := 0; i < len(quotientPolysCap); i++ {
|
for i := 0; i < len(quotientPolysCap); i++ {
|
||||||
for j := 0; j < len(quotientPolysCap[0]); j++ {
|
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++ {
|
for i := 0; i < 4; i++ {
|
||||||
field.AssertIsEqual(publicInputHash[i], expectedPublicInputHash[i])
|
fieldAPI.AssertIsEqual(publicInputHash[i], expectedPublicInputHash[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedPlonkBetas := [2]F{
|
expectedPlonkBetas := [2]F{
|
||||||
@@ -86,8 +88,8 @@ func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
field.AssertIsEqual(plonkBetas[i], expectedPlonkBetas[i])
|
fieldAPI.AssertIsEqual(plonkBetas[i], expectedPlonkBetas[i])
|
||||||
field.AssertIsEqual(plonkGammas[i], expectedPlonkGammas[i])
|
fieldAPI.AssertIsEqual(plonkGammas[i], expectedPlonkGammas[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
challengerChip.ObserveCap(plonkZsPartialProductsCap[:])
|
challengerChip.ObserveCap(plonkZsPartialProductsCap[:])
|
||||||
@@ -99,7 +101,7 @@ func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
field.AssertIsEqual(plonkAlphas[i], expectedPlonkAlphas[i])
|
fieldAPI.AssertIsEqual(plonkAlphas[i], expectedPlonkAlphas[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
challengerChip.ObserveCap(quotientPolysCap[:])
|
challengerChip.ObserveCap(quotientPolysCap[:])
|
||||||
@@ -111,7 +113,7 @@ func (circuit *TestChallengerCircuit) Define(api frontend.API) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
field.AssertIsEqual(plonkZeta[i], expectedPlonkZeta[i])
|
fieldAPI.AssertIsEqual(plonkZeta[i], expectedPlonkZeta[i])
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
44
plonky2_verifier/constant_gate.go
Normal file
44
plonky2_verifier/constant_gate.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package plonky2_verifier
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
. "gnark-plonky2-verifier/field"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ConstantGate struct {
|
||||||
|
numConsts uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewConstantGate(numConsts uint64) *ConstantGate {
|
||||||
|
return &ConstantGate{
|
||||||
|
numConsts: numConsts,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ConstantGate) Id() string {
|
||||||
|
return fmt.Sprintf("ConstantGate { num_consts: %d }", g.numConsts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ConstantGate) ConstInput(i uint64) uint64 {
|
||||||
|
if i > g.numConsts {
|
||||||
|
panic("Invalid constant index")
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ConstantGate) WireOutput(i uint64) uint64 {
|
||||||
|
if i > g.numConsts {
|
||||||
|
panic("Invalid wire index")
|
||||||
|
}
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *ConstantGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension {
|
||||||
|
constraints := []QuadraticExtension{}
|
||||||
|
|
||||||
|
for i := uint64(0); i < g.numConsts; i++ {
|
||||||
|
constraints = append(constraints, p.qeAPI.SubExtension(vars.localConstants[g.ConstInput(i)], vars.localWires[g.WireOutput(i)]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return constraints
|
||||||
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
{"config":{"num_wires":135,"num_routed_wires":80,"num_constants":2,"use_base_arithmetic_gate":true,"security_bits":100,"num_challenges":2,"zero_knowledge":false,"max_quotient_degree_factor":8,"fri_config":{"rate_bits":3,"cap_height":4,"proof_of_work_bits":16,"reduction_strategy":{"ConstantArityBits":[4,5]},"num_query_rounds":28}},"fri_params":{"config":{"rate_bits":3,"cap_height":4,"proof_of_work_bits":16,"reduction_strategy":{"ConstantArityBits":[4,5]},"num_query_rounds":28},"hiding":false,"degree_bits":3,"reduction_arity_bits":[]},"degree_bits":3,"selectors_info":{"selector_indices":[0,0,0,1],"groups":[{"start":0,"end":3},{"start":3,"end":4}]},"quotient_degree_factor":8,"num_gate_constraints":123,"num_constants":4,"num_public_inputs":3,"k_is":[1,7,49,343,2401,16807,117649,823543,5764801,40353607,282475249,1977326743,13841287201,96889010407,678223072849,4747561509943,33232930569601,232630513987207,1628413597910449,11398895185373143,79792266297612001,558545864083284007,3909821048582988049,8922003270666332022,7113790686420571191,12903046666114829695,16534350385145470581,5059988279530788141,16973173887300932666,8131752794619022736,1582037354089406189,11074261478625843323,3732854072722565977,7683234439643377518,16889152938674473984,7543606154233811962,15911754940807515092,701820169165099718,4912741184155698026,15942444219675301861,916645121239607101,6416515848677249707,8022122801911579307,814627405137302186,5702391835961115302,3023254712898638472,2716038920875884983,565528376716610560,3958698637016273920,9264146389699333119,9508792519651578870,11221315429317299127,4762231727562756605,14888878023524711914,11988425817600061793,10132004445542095267,15583798910550913906,16852872026783475737,7289639770996824233,14133990258148600989,6704211459967285318,10035992080941828584,14911712358349047125,12148266161370408270,11250886851934520606,4969231685883306958,16337877731768564385,3684679705892444769,7346013871832529062,14528608963998534792,9466542400916821939,10925564598174000610,2691975909559666986,397087297503084581,2779611082521592067,1010533508236560148,7073734557655921036,12622653764762278610,14571600075677612986,9767480182670369297],"num_partial_products":9,"circuit_digest":{"elements":[7754113318730736048,18436136620016916513,18054530212389526288,5893739326632906028]}}
|
{"config":{"num_wires":135,"num_routed_wires":80,"num_constants":2,"use_base_arithmetic_gate":true,"security_bits":100,"num_challenges":2,"zero_knowledge":false,"max_quotient_degree_factor":8,"fri_config":{"rate_bits":3,"cap_height":4,"proof_of_work_bits":16,"reduction_strategy":{"ConstantArityBits":[4,5]},"num_query_rounds":28}},"fri_params":{"config":{"rate_bits":3,"cap_height":4,"proof_of_work_bits":16,"reduction_strategy":{"ConstantArityBits":[4,5]},"num_query_rounds":28},"hiding":false,"degree_bits":3,"reduction_arity_bits":[]},"gates":["ConstantGate { num_consts: 2 }","PublicInputGate","ArithmeticGate { num_ops: 20 }","PoseidonGate(PhantomData<plonky2_field::goldilocks_field::GoldilocksField>)<WIDTH=12>"],"selectors_info":{"selector_indices":[0,0,0,1],"groups":[{"start":0,"end":3},{"start":3,"end":4}]},"quotient_degree_factor":8,"num_gate_constraints":123,"num_constants":4,"num_public_inputs":3,"k_is":[1,7,49,343,2401,16807,117649,823543,5764801,40353607,282475249,1977326743,13841287201,96889010407,678223072849,4747561509943,33232930569601,232630513987207,1628413597910449,11398895185373143,79792266297612001,558545864083284007,3909821048582988049,8922003270666332022,7113790686420571191,12903046666114829695,16534350385145470581,5059988279530788141,16973173887300932666,8131752794619022736,1582037354089406189,11074261478625843323,3732854072722565977,7683234439643377518,16889152938674473984,7543606154233811962,15911754940807515092,701820169165099718,4912741184155698026,15942444219675301861,916645121239607101,6416515848677249707,8022122801911579307,814627405137302186,5702391835961115302,3023254712898638472,2716038920875884983,565528376716610560,3958698637016273920,9264146389699333119,9508792519651578870,11221315429317299127,4762231727562756605,14888878023524711914,11988425817600061793,10132004445542095267,15583798910550913906,16852872026783475737,7289639770996824233,14133990258148600989,6704211459967285318,10035992080941828584,14911712358349047125,12148266161370408270,11250886851934520606,4969231685883306958,16337877731768564385,3684679705892444769,7346013871832529062,14528608963998534792,9466542400916821939,10925564598174000610,2691975909559666986,397087297503084581,2779611082521592067,1010533508236560148,7073734557655921036,12622653764762278610,14571600075677612986,9767480182670369297],"num_partial_products":9}
|
||||||
File diff suppressed because one or more lines are too long
11509
plonky2_verifier/data/fibonacci/proof_with_public_inputs_randomized.json
Normal file
11509
plonky2_verifier/data/fibonacci/proof_with_public_inputs_randomized.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
|||||||
{"constants_sigmas_cap":[{"elements":[2913805118787558759,15605217703384212484,9293436862297178555,10529947991695419448]},{"elements":[1937331278189251620,17537260089483183877,10458485670158100707,4116443229550247591]},{"elements":[8142760542024755709,3845244796524514577,16191049345326767258,7348433903875207214]},{"elements":[18274477257392359471,9341197367296335592,14314312946600883535,17431979896521737468]},{"elements":[12713790163422286570,9838614764658999419,3024549327814176904,6544549858431318793]},{"elements":[17461063081201329467,1929790214678747830,14738190695567211833,4502436664569676311]},{"elements":[17446087997043032816,17518692693064701003,4915378766449394412,10675325761198739044]},{"elements":[11349186227918507635,7105572536043210156,13296927306801261929,6138189381388819111]},{"elements":[17427080957162886576,4310228111529328877,16109317445338921222,11923676504992192083]},{"elements":[11292141569337462929,7213981967192374125,4837353949249389782,13157524938508720907]},{"elements":[17221477633935993097,7905315334616496868,2950048088611741910,16851660641249290423]},{"elements":[1918571898367258879,14473285549490778842,16456257732802770188,16611801325745795527]},{"elements":[7880989808200689690,16935107633380717766,8956194191973051375,1103945341495739535]},{"elements":[4501339912027744074,12142665268233044767,9270990890291324944,45374981263348191]},{"elements":[13657768796246999470,2899654677720502418,7228867285602519410,3363587770111123806]},{"elements":[18227101298896629706,12986849723013952028,16815808278639394978,16460725848109409638]}]}
|
{"constants_sigmas_cap":[{"elements":[2913805118787558759,15605217703384212484,9293436862297178555,10529947991695419448]},{"elements":[1937331278189251620,17537260089483183877,10458485670158100707,4116443229550247591]},{"elements":[8142760542024755709,3845244796524514577,16191049345326767258,7348433903875207214]},{"elements":[18274477257392359471,9341197367296335592,14314312946600883535,17431979896521737468]},{"elements":[12713790163422286570,9838614764658999419,3024549327814176904,6544549858431318793]},{"elements":[17461063081201329467,1929790214678747830,14738190695567211833,4502436664569676311]},{"elements":[17446087997043032816,17518692693064701003,4915378766449394412,10675325761198739044]},{"elements":[11349186227918507635,7105572536043210156,13296927306801261929,6138189381388819111]},{"elements":[17427080957162886576,4310228111529328877,16109317445338921222,11923676504992192083]},{"elements":[11292141569337462929,7213981967192374125,4837353949249389782,13157524938508720907]},{"elements":[17221477633935993097,7905315334616496868,2950048088611741910,16851660641249290423]},{"elements":[1918571898367258879,14473285549490778842,16456257732802770188,16611801325745795527]},{"elements":[7880989808200689690,16935107633380717766,8956194191973051375,1103945341495739535]},{"elements":[4501339912027744074,12142665268233044767,9270990890291324944,45374981263348191]},{"elements":[13657768796246999470,2899654677720502418,7228867285602519410,3363587770111123806]},{"elements":[18227101298896629706,12986849723013952028,16815808278639394978,16460725848109409638]}],"circuit_digest":{"elements":[15489309507512017401,16244437215982314072,10011620388767144997,15394117319313330212]}}
|
||||||
@@ -130,7 +130,7 @@ type CommonCircuitDataRaw struct {
|
|||||||
DegreeBits uint64 `json:"degree_bits"`
|
DegreeBits uint64 `json:"degree_bits"`
|
||||||
ReductionArityBits []uint64 `json:"reduction_arity_bits"`
|
ReductionArityBits []uint64 `json:"reduction_arity_bits"`
|
||||||
} `json:"fri_params"`
|
} `json:"fri_params"`
|
||||||
DegreeBits uint64 `json:"degree_bits"`
|
Gates []string `json:"gates"`
|
||||||
SelectorsInfo struct {
|
SelectorsInfo struct {
|
||||||
SelectorIndices []uint64 `json:"selector_indices"`
|
SelectorIndices []uint64 `json:"selector_indices"`
|
||||||
Groups []struct {
|
Groups []struct {
|
||||||
@@ -144,15 +144,28 @@ type CommonCircuitDataRaw struct {
|
|||||||
NumPublicInputs uint64 `json:"num_public_inputs"`
|
NumPublicInputs uint64 `json:"num_public_inputs"`
|
||||||
KIs []uint64 `json:"k_is"`
|
KIs []uint64 `json:"k_is"`
|
||||||
NumPartialProducts uint64 `json:"num_partial_products"`
|
NumPartialProducts uint64 `json:"num_partial_products"`
|
||||||
CircuitDigest struct {
|
}
|
||||||
Elements []uint64 `json:"elements"`
|
|
||||||
} `json:"circuit_digest"`
|
type ProofChallengesRaw struct {
|
||||||
|
PlonkBetas []uint64 `json:"plonk_betas"`
|
||||||
|
PlonkGammas []uint64 `json:"plonk_gammas"`
|
||||||
|
PlonkAlphas []uint64 `json:"plonk_alphas"`
|
||||||
|
PlonkZeta []uint64 `json:"plonk_zeta"`
|
||||||
|
FriChallenges struct {
|
||||||
|
FriAlpha []uint64 `json:"fri_alpha"`
|
||||||
|
FriBetas [][]uint64 `json:"fri_betas"`
|
||||||
|
FriPowResponse uint64 `json:"fri_pow_response"`
|
||||||
|
FriQueryIndices []uint64 `json:"fri_query_indices"`
|
||||||
|
} `json:"fri_challenges"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VerifierOnlyCircuitDataRaw struct {
|
type VerifierOnlyCircuitDataRaw struct {
|
||||||
ConstantsSigmasCap []struct {
|
ConstantsSigmasCap []struct {
|
||||||
Elements []uint64 `json:"elements"`
|
Elements []uint64 `json:"elements"`
|
||||||
} `json:"constants_sigmas_cap"`
|
} `json:"constants_sigmas_cap"`
|
||||||
|
CircuitDigest struct {
|
||||||
|
Elements []uint64 `json:"elements"`
|
||||||
|
} `json:"circuit_digest"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeserializeMerkleCap(merkleCapRaw []struct{ Elements []uint64 }) MerkleCap {
|
func DeserializeMerkleCap(merkleCapRaw []struct{ Elements []uint64 }) MerkleCap {
|
||||||
@@ -289,6 +302,34 @@ func DeserializeProofWithPublicInputs(path string) ProofWithPublicInputs {
|
|||||||
return proofWithPis
|
return proofWithPis
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DeserializeProofChallenges(path string) ProofChallenges {
|
||||||
|
jsonFile, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer jsonFile.Close()
|
||||||
|
rawBytes, _ := ioutil.ReadAll(jsonFile)
|
||||||
|
|
||||||
|
var raw ProofChallengesRaw
|
||||||
|
err = json.Unmarshal(rawBytes, &raw)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var proofChallenges ProofChallenges
|
||||||
|
proofChallenges.PlonkBetas = utils.Uint64ArrayToFArray(raw.PlonkBetas)
|
||||||
|
proofChallenges.PlonkGammas = utils.Uint64ArrayToFArray(raw.PlonkGammas)
|
||||||
|
proofChallenges.PlonkAlphas = utils.Uint64ArrayToFArray(raw.PlonkAlphas)
|
||||||
|
proofChallenges.PlonkZeta = utils.Uint64ArrayToQuadraticExtension(raw.PlonkZeta)
|
||||||
|
proofChallenges.FriChallenges.FriAlpha = utils.Uint64ArrayToQuadraticExtension(raw.FriChallenges.FriAlpha)
|
||||||
|
proofChallenges.FriChallenges.FriBetas = utils.Uint64ArrayToQuadraticExtensionArray(raw.FriChallenges.FriBetas)
|
||||||
|
proofChallenges.FriChallenges.FriPowResponse = NewFieldElement(raw.FriChallenges.FriPowResponse)
|
||||||
|
proofChallenges.FriChallenges.FriQueryIndices = utils.Uint64ArrayToFArray(raw.FriChallenges.FriQueryIndices)
|
||||||
|
|
||||||
|
return proofChallenges
|
||||||
|
}
|
||||||
|
|
||||||
func ReductionArityBits(
|
func ReductionArityBits(
|
||||||
arityBits uint64,
|
arityBits uint64,
|
||||||
finalPolyBits uint64,
|
finalPolyBits uint64,
|
||||||
@@ -340,20 +381,33 @@ func DeserializeCommonCircuitData(path string) CommonCircuitData {
|
|||||||
commonCircuitData.Config.FriConfig.NumQueryRounds = raw.Config.FriConfig.NumQueryRounds
|
commonCircuitData.Config.FriConfig.NumQueryRounds = raw.Config.FriConfig.NumQueryRounds
|
||||||
|
|
||||||
commonCircuitData.FriParams.DegreeBits = raw.FriParams.DegreeBits
|
commonCircuitData.FriParams.DegreeBits = raw.FriParams.DegreeBits
|
||||||
|
commonCircuitData.DegreeBits = raw.FriParams.DegreeBits
|
||||||
commonCircuitData.FriParams.Config.RateBits = raw.FriParams.Config.RateBits
|
commonCircuitData.FriParams.Config.RateBits = raw.FriParams.Config.RateBits
|
||||||
commonCircuitData.FriParams.Config.CapHeight = raw.FriParams.Config.CapHeight
|
commonCircuitData.FriParams.Config.CapHeight = raw.FriParams.Config.CapHeight
|
||||||
commonCircuitData.FriParams.Config.ProofOfWorkBits = raw.FriParams.Config.ProofOfWorkBits
|
commonCircuitData.FriParams.Config.ProofOfWorkBits = raw.FriParams.Config.ProofOfWorkBits
|
||||||
commonCircuitData.FriParams.Config.NumQueryRounds = raw.FriParams.Config.NumQueryRounds
|
commonCircuitData.FriParams.Config.NumQueryRounds = raw.FriParams.Config.NumQueryRounds
|
||||||
commonCircuitData.FriParams.ReductionArityBits = raw.FriParams.ReductionArityBits
|
commonCircuitData.FriParams.ReductionArityBits = raw.FriParams.ReductionArityBits
|
||||||
|
|
||||||
commonCircuitData.DegreeBits = raw.DegreeBits
|
commonCircuitData.Gates = []gate{}
|
||||||
|
for _, gate := range raw.Gates {
|
||||||
|
commonCircuitData.Gates = append(commonCircuitData.Gates, GateInstanceFromId(gate))
|
||||||
|
}
|
||||||
|
|
||||||
|
commonCircuitData.SelectorsInfo.selectorIndices = raw.SelectorsInfo.SelectorIndices
|
||||||
|
commonCircuitData.SelectorsInfo.groups = []Range{}
|
||||||
|
for _, group := range raw.SelectorsInfo.Groups {
|
||||||
|
commonCircuitData.SelectorsInfo.groups = append(commonCircuitData.SelectorsInfo.groups, Range{
|
||||||
|
start: group.Start,
|
||||||
|
end: group.End,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
commonCircuitData.QuotientDegreeFactor = raw.QuotientDegreeFactor
|
commonCircuitData.QuotientDegreeFactor = raw.QuotientDegreeFactor
|
||||||
commonCircuitData.NumGateConstraints = raw.NumGateConstraints
|
commonCircuitData.NumGateConstraints = raw.NumGateConstraints
|
||||||
commonCircuitData.NumConstants = raw.NumConstants
|
commonCircuitData.NumConstants = raw.NumConstants
|
||||||
commonCircuitData.NumPublicInputs = raw.NumPublicInputs
|
commonCircuitData.NumPublicInputs = raw.NumPublicInputs
|
||||||
commonCircuitData.KIs = utils.Uint64ArrayToFArray(raw.KIs)
|
commonCircuitData.KIs = utils.Uint64ArrayToFArray(raw.KIs)
|
||||||
commonCircuitData.NumPartialProducts = raw.NumPartialProducts
|
commonCircuitData.NumPartialProducts = raw.NumPartialProducts
|
||||||
copy(commonCircuitData.CircuitDigest[:], utils.Uint64ArrayToFArray(raw.CircuitDigest.Elements))
|
|
||||||
|
|
||||||
return commonCircuitData
|
return commonCircuitData
|
||||||
}
|
}
|
||||||
@@ -373,7 +427,9 @@ func DeserializeVerifierOnlyCircuitData(path string) VerifierOnlyCircuitData {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return VerifierOnlyCircuitData{
|
var verifierOnlyCircuitData VerifierOnlyCircuitData
|
||||||
ConstantSigmasCap: DeserializeMerkleCap([]struct{ Elements []uint64 }(raw.ConstantsSigmasCap)),
|
verifierOnlyCircuitData.ConstantSigmasCap = DeserializeMerkleCap([]struct{ Elements []uint64 }(raw.ConstantsSigmasCap))
|
||||||
}
|
copy(verifierOnlyCircuitData.CircuitDigest[:], utils.Uint64ArrayToFArray(raw.CircuitDigest.Elements))
|
||||||
|
|
||||||
|
return verifierOnlyCircuitData
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ func TestDeserializeProofWithPublicInputs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestDeserializeCommonCircuitData(t *testing.T) {
|
func TestDeserializeCommonCircuitData(t *testing.T) {
|
||||||
proofWithPis := DeserializeCommonCircuitData("./data/fibonacci/common_circuit_data.json")
|
commonCircuitData := DeserializeCommonCircuitData("./data/fibonacci/common_circuit_data.json")
|
||||||
fmt.Printf("%+v\n", proofWithPis)
|
fmt.Printf("%+v\n", commonCircuitData)
|
||||||
panic("look at stdout")
|
panic("look at stdout")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeserializeVerifierOnlyCircuitData(t *testing.T) {
|
func TestDeserializeVerifierOnlyCircuitData(t *testing.T) {
|
||||||
proofWithPis := DeserializeVerifierOnlyCircuitData("./data/fibonacci/verifier_only_circuit_data.json")
|
verifierOnlyCircuitData := DeserializeVerifierOnlyCircuitData("./data/fibonacci/verifier_only_circuit_data.json")
|
||||||
fmt.Printf("%+v\n", proofWithPis)
|
fmt.Printf("%+v\n", verifierOnlyCircuitData)
|
||||||
panic("look at stdout")
|
panic("look at stdout")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -546,15 +546,15 @@ func (f *FriChip) VerifyFriProof(
|
|||||||
nLog := f.friParams.DegreeBits + f.friParams.Config.RateBits
|
nLog := f.friParams.DegreeBits + f.friParams.Config.RateBits
|
||||||
n := uint64(math.Pow(2, float64(nLog)))
|
n := uint64(math.Pow(2, float64(nLog)))
|
||||||
|
|
||||||
if len(friChallenges.FriQueryIndicies) != len(friProof.QueryRoundProofs) {
|
if len(friChallenges.FriQueryIndices) != len(friProof.QueryRoundProofs) {
|
||||||
panic(fmt.Sprintf(
|
panic(fmt.Sprintf(
|
||||||
"Number of query indices (%d) should equal number of query round proofs (%d)",
|
"Number of query indices (%d) should equal number of query round proofs (%d)",
|
||||||
len(friChallenges.FriQueryIndicies),
|
len(friChallenges.FriQueryIndices),
|
||||||
len(friProof.QueryRoundProofs),
|
len(friProof.QueryRoundProofs),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx, xIndex := range friChallenges.FriQueryIndicies {
|
for idx, xIndex := range friChallenges.FriQueryIndices {
|
||||||
roundProof := friProof.QueryRoundProofs[idx]
|
roundProof := friProof.QueryRoundProofs[idx]
|
||||||
|
|
||||||
f.verifyQueryRound(
|
f.verifyQueryRound(
|
||||||
|
|||||||
@@ -29,14 +29,14 @@ func (circuit *TestFriCircuit) Define(api frontend.API) error {
|
|||||||
fieldAPI := NewFieldAPI(api)
|
fieldAPI := NewFieldAPI(api)
|
||||||
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits)
|
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits)
|
||||||
hashAPI := NewHashAPI(fieldAPI)
|
hashAPI := NewHashAPI(fieldAPI)
|
||||||
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI)
|
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI)
|
||||||
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams)
|
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams)
|
||||||
|
|
||||||
friChallenges := FriChallenges{
|
friChallenges := FriChallenges{
|
||||||
FriAlpha: circuit.friAlpha,
|
FriAlpha: circuit.friAlpha,
|
||||||
FriBetas: circuit.friBetas,
|
FriBetas: circuit.friBetas,
|
||||||
FriPowResponse: circuit.friPOWResponse,
|
FriPowResponse: circuit.friPOWResponse,
|
||||||
FriQueryIndicies: circuit.friQueryIndices,
|
FriQueryIndices: circuit.friQueryIndices,
|
||||||
}
|
}
|
||||||
|
|
||||||
initialMerkleCaps := []MerkleCap{
|
initialMerkleCaps := []MerkleCap{
|
||||||
|
|||||||
92
plonky2_verifier/gate.go
Normal file
92
plonky2_verifier/gate.go
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package plonky2_verifier
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
. "gnark-plonky2-verifier/field"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type gate interface {
|
||||||
|
Id() string
|
||||||
|
EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension
|
||||||
|
}
|
||||||
|
|
||||||
|
func GateInstanceFromId(gateId string) gate {
|
||||||
|
if strings.HasPrefix(gateId, "ArithmeticGate") {
|
||||||
|
numOpsRaw := strings.Split(gateId, ":")[1]
|
||||||
|
numOpsRaw = strings.Split(numOpsRaw, "}")[0]
|
||||||
|
numOpsRaw = strings.TrimSpace(numOpsRaw)
|
||||||
|
numOps, err := strconv.Atoi(numOpsRaw)
|
||||||
|
if err != nil {
|
||||||
|
panic("Invalid gate ID for ArithmeticGate")
|
||||||
|
}
|
||||||
|
return NewArithmeticGate(uint64(numOps))
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(gateId, "ConstantGate") {
|
||||||
|
numConstsRaw := strings.Split(gateId, ":")[1]
|
||||||
|
numConstsRaw = strings.Split(numConstsRaw, "}")[0]
|
||||||
|
numConstsRaw = strings.TrimSpace(numConstsRaw)
|
||||||
|
numConsts, err := strconv.Atoi(numConstsRaw)
|
||||||
|
if err != nil {
|
||||||
|
panic("Invalid gate ID")
|
||||||
|
}
|
||||||
|
return NewConstantGate(uint64(numConsts))
|
||||||
|
}
|
||||||
|
|
||||||
|
if gateId == "NoopGate" {
|
||||||
|
return NewNoopGate()
|
||||||
|
}
|
||||||
|
|
||||||
|
if gateId == "PublicInputGate" {
|
||||||
|
return NewPublicInputGate()
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(gateId, "PoseidonGate") {
|
||||||
|
return NewPoseidonGate()
|
||||||
|
}
|
||||||
|
|
||||||
|
panic(fmt.Sprintf("Unknown gate ID %s", gateId))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PlonkChip) computeFilter(
|
||||||
|
row uint64,
|
||||||
|
groupRange Range,
|
||||||
|
s QuadraticExtension,
|
||||||
|
manySelector bool,
|
||||||
|
) QuadraticExtension {
|
||||||
|
product := p.qeAPI.ONE_QE
|
||||||
|
for i := groupRange.start; i < groupRange.end; i++ {
|
||||||
|
if i == uint64(row) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
product = p.qeAPI.MulExtension(product, p.qeAPI.SubExtension(p.qeAPI.FieldToQE(NewFieldElement(i)), s))
|
||||||
|
}
|
||||||
|
|
||||||
|
if manySelector {
|
||||||
|
product = p.qeAPI.MulExtension(product, p.qeAPI.SubExtension(p.qeAPI.FieldToQE(NewFieldElement(UNUSED_SELECTOR)), s))
|
||||||
|
}
|
||||||
|
|
||||||
|
return product
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PlonkChip) evalFiltered(
|
||||||
|
g gate,
|
||||||
|
vars EvaluationVars,
|
||||||
|
row uint64,
|
||||||
|
selectorIndex uint64,
|
||||||
|
groupRange Range,
|
||||||
|
numSelectors uint64,
|
||||||
|
) []QuadraticExtension {
|
||||||
|
filter := p.computeFilter(row, groupRange, vars.localConstants[selectorIndex], numSelectors > 1)
|
||||||
|
|
||||||
|
vars.RemovePrefix(numSelectors)
|
||||||
|
|
||||||
|
unfiltered := g.EvalUnfiltered(p, vars)
|
||||||
|
for i := range unfiltered {
|
||||||
|
unfiltered[i] = p.qeAPI.MulExtension(unfiltered[i], filter)
|
||||||
|
}
|
||||||
|
return unfiltered
|
||||||
|
}
|
||||||
20
plonky2_verifier/noop_gate.go
Normal file
20
plonky2_verifier/noop_gate.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package plonky2_verifier
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "gnark-plonky2-verifier/field"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NoopGate struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewNoopGate() *NoopGate {
|
||||||
|
return &NoopGate{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *NoopGate) Id() string {
|
||||||
|
return "NoopGate"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *NoopGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension {
|
||||||
|
return []QuadraticExtension{}
|
||||||
|
}
|
||||||
@@ -116,8 +116,37 @@ func (p *PlonkChip) checkPartialProducts(
|
|||||||
return partialProductChecks
|
return partialProductChecks
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PlonkChip) evalVanishingPoly(proofChallenges ProofChallenges, openings OpeningSet, zetaPowN QuadraticExtension) []QuadraticExtension {
|
func (p *PlonkChip) evaluateGateConstraints(vars EvaluationVars) []QuadraticExtension {
|
||||||
// TODO: evaluate_gate_contraints logic should be implemented here. See https://github.com/mir-protocol/plonky2/blob/main/plonky2/src/plonk/vanishing_poly.rs#L39
|
constraints := make([]QuadraticExtension, p.commonData.NumGateConstraints)
|
||||||
|
for i, _ := range constraints {
|
||||||
|
constraints[i] = p.qeAPI.ZERO_QE
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, gate := range p.commonData.Gates {
|
||||||
|
selectorIndex := p.commonData.SelectorsInfo.selectorIndices[i]
|
||||||
|
|
||||||
|
gateConstraints := p.evalFiltered(
|
||||||
|
gate,
|
||||||
|
vars,
|
||||||
|
uint64(i),
|
||||||
|
selectorIndex,
|
||||||
|
p.commonData.SelectorsInfo.groups[selectorIndex],
|
||||||
|
p.commonData.SelectorsInfo.NumSelectors(),
|
||||||
|
)
|
||||||
|
|
||||||
|
for i, constraint := range gateConstraints {
|
||||||
|
if uint64(i) >= p.commonData.NumGateConstraints {
|
||||||
|
panic("num_constraints() gave too low of a number")
|
||||||
|
}
|
||||||
|
constraints[i] = p.qeAPI.AddExtension(constraints[i], constraint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return constraints
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PlonkChip) evalVanishingPoly(vars EvaluationVars, proofChallenges ProofChallenges, openings OpeningSet, zetaPowN QuadraticExtension) []QuadraticExtension {
|
||||||
|
constraintTerms := p.evaluateGateConstraints(vars)
|
||||||
|
|
||||||
// Calculate the k[i] * x
|
// Calculate the k[i] * x
|
||||||
sIDs := make([]QuadraticExtension, p.commonData.Config.NumRoutedWires)
|
sIDs := make([]QuadraticExtension, p.commonData.Config.NumRoutedWires)
|
||||||
@@ -143,7 +172,6 @@ func (p *PlonkChip) evalVanishingPoly(proofChallenges ProofChallenges, openings
|
|||||||
for j := uint64(0); j < p.commonData.Config.NumRoutedWires; j++ {
|
for j := uint64(0); j < p.commonData.Config.NumRoutedWires; j++ {
|
||||||
// The numerator is `beta * s_id + wire_value + gamma`, and the denominator is
|
// The numerator is `beta * s_id + wire_value + gamma`, and the denominator is
|
||||||
// `beta * s_sigma + wire_value + gamma`.
|
// `beta * s_sigma + wire_value + gamma`.
|
||||||
|
|
||||||
wireValuePlusGamma := p.qeAPI.AddExtension(
|
wireValuePlusGamma := p.qeAPI.AddExtension(
|
||||||
openings.Wires[j],
|
openings.Wires[j],
|
||||||
p.qeAPI.FieldToQE(proofChallenges.PlonkGammas[i]),
|
p.qeAPI.FieldToQE(proofChallenges.PlonkGammas[i]),
|
||||||
@@ -176,7 +204,7 @@ func (p *PlonkChip) evalVanishingPoly(proofChallenges ProofChallenges, openings
|
|||||||
}
|
}
|
||||||
|
|
||||||
vanishingTerms := append(vanishingZ1Terms, vanishingPartialProductsTerms...)
|
vanishingTerms := append(vanishingZ1Terms, vanishingPartialProductsTerms...)
|
||||||
vanishingTerms = append(vanishingTerms, []QuadraticExtension{p.qeAPI.ZERO_QE, p.qeAPI.ZERO_QE, p.qeAPI.ZERO_QE, p.qeAPI.ZERO_QE}...)
|
vanishingTerms = append(vanishingTerms, constraintTerms...)
|
||||||
|
|
||||||
reducedValues := make([]QuadraticExtension, p.commonData.Config.NumChallenges)
|
reducedValues := make([]QuadraticExtension, p.commonData.Config.NumChallenges)
|
||||||
for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
|
for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
|
||||||
@@ -199,11 +227,19 @@ func (p *PlonkChip) evalVanishingPoly(proofChallenges ProofChallenges, openings
|
|||||||
return reducedValues
|
return reducedValues
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PlonkChip) Verify(proofChallenges ProofChallenges, openings OpeningSet) {
|
func (p *PlonkChip) Verify(proofChallenges ProofChallenges, openings OpeningSet, publicInputsHash Hash) {
|
||||||
// Calculate zeta^n
|
// Calculate zeta^n
|
||||||
zetaPowN := p.expPowerOf2Extension(proofChallenges.PlonkZeta)
|
zetaPowN := p.expPowerOf2Extension(proofChallenges.PlonkZeta)
|
||||||
|
|
||||||
vanishingPolysZeta := p.evalVanishingPoly(proofChallenges, openings, zetaPowN)
|
localConstants := openings.Constants
|
||||||
|
localWires := openings.Wires
|
||||||
|
vars := EvaluationVars{
|
||||||
|
localConstants,
|
||||||
|
localWires,
|
||||||
|
publicInputsHash,
|
||||||
|
}
|
||||||
|
|
||||||
|
vanishingPolysZeta := p.evalVanishingPoly(vars, proofChallenges, openings, zetaPowN)
|
||||||
|
|
||||||
// Calculate Z(H)
|
// Calculate Z(H)
|
||||||
zHZeta := p.qeAPI.SubExtension(zetaPowN, p.qeAPI.ONE_QE)
|
zHZeta := p.qeAPI.SubExtension(zetaPowN, p.qeAPI.ONE_QE)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package plonky2_verifier
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
. "gnark-plonky2-verifier/field"
|
. "gnark-plonky2-verifier/field"
|
||||||
|
"gnark-plonky2-verifier/poseidon"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/consensys/gnark/frontend"
|
"github.com/consensys/gnark/frontend"
|
||||||
@@ -11,30 +12,26 @@ import (
|
|||||||
type TestPlonkCircuit struct {
|
type TestPlonkCircuit struct {
|
||||||
proofWithPIsFilename string `gnark:"-"`
|
proofWithPIsFilename string `gnark:"-"`
|
||||||
commonCircuitDataFilename string `gnark:"-"`
|
commonCircuitDataFilename string `gnark:"-"`
|
||||||
|
verifierOnlyCircuitDataFilename string `gnark:"-"`
|
||||||
plonkBetas []F
|
|
||||||
plonkGammas []F
|
|
||||||
plonkAlphas []F
|
|
||||||
plonkZeta QuadraticExtension
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (circuit *TestPlonkCircuit) Define(api frontend.API) error {
|
func (circuit *TestPlonkCircuit) Define(api frontend.API) error {
|
||||||
proofWithPis := DeserializeProofWithPublicInputs(circuit.proofWithPIsFilename)
|
proofWithPis := DeserializeProofWithPublicInputs(circuit.proofWithPIsFilename)
|
||||||
commonCircuitData := DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
|
commonCircuitData := DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
|
||||||
|
verifierOnlyCircuitData := DeserializeVerifierOnlyCircuitData(circuit.verifierOnlyCircuitDataFilename)
|
||||||
|
|
||||||
field := NewFieldAPI(api)
|
fieldAPI := NewFieldAPI(api)
|
||||||
qe := NewQuadraticExtensionAPI(field, commonCircuitData.DegreeBits)
|
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits)
|
||||||
|
hashAPI := NewHashAPI(fieldAPI)
|
||||||
|
poseidonChip := poseidon.NewPoseidonChip(api, fieldAPI, qeAPI)
|
||||||
|
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams)
|
||||||
|
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData)
|
||||||
|
|
||||||
proofChallenges := ProofChallenges{
|
verifierChip := NewVerifierChip(api, fieldAPI, qeAPI, poseidonChip, plonkChip, friChip)
|
||||||
PlonkBetas: circuit.plonkBetas,
|
publicInputsHash := verifierChip.GetPublicInputsHash(proofWithPis.PublicInputs)
|
||||||
PlonkGammas: circuit.plonkGammas,
|
proofChallenges := verifierChip.GetChallenges(proofWithPis, publicInputsHash, commonCircuitData, verifierOnlyCircuitData)
|
||||||
PlonkAlphas: circuit.plonkAlphas,
|
|
||||||
PlonkZeta: circuit.plonkZeta,
|
|
||||||
}
|
|
||||||
|
|
||||||
plonkChip := NewPlonkChip(api, qe, commonCircuitData)
|
plonkChip.Verify(proofChallenges, proofWithPis.Proof.Openings, publicInputsHash)
|
||||||
|
|
||||||
plonkChip.Verify(proofChallenges, proofWithPis.Proof.Openings)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,23 +42,7 @@ func TestPlonkFibonacci(t *testing.T) {
|
|||||||
circuit := TestPlonkCircuit{
|
circuit := TestPlonkCircuit{
|
||||||
proofWithPIsFilename: "./data/fibonacci/proof_with_public_inputs.json",
|
proofWithPIsFilename: "./data/fibonacci/proof_with_public_inputs.json",
|
||||||
commonCircuitDataFilename: "./data/fibonacci/common_circuit_data.json",
|
commonCircuitDataFilename: "./data/fibonacci/common_circuit_data.json",
|
||||||
|
verifierOnlyCircuitDataFilename: "./data/fibonacci/verifier_only_circuit_data.json",
|
||||||
plonkBetas: []F{
|
|
||||||
NewFieldElementFromString("4678728155650926271"),
|
|
||||||
NewFieldElementFromString("13611962404289024887"),
|
|
||||||
},
|
|
||||||
plonkGammas: []F{
|
|
||||||
NewFieldElementFromString("13237663823305715949"),
|
|
||||||
NewFieldElementFromString("15389314098328235145"),
|
|
||||||
},
|
|
||||||
plonkAlphas: []F{
|
|
||||||
NewFieldElementFromString("14505919539124304197"),
|
|
||||||
NewFieldElementFromString("1695455639263736117"),
|
|
||||||
},
|
|
||||||
plonkZeta: QuadraticExtension{
|
|
||||||
NewFieldElementFromString("14887793628029982930"),
|
|
||||||
NewFieldElementFromString("1136137158284059037"),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
witness := TestPlonkCircuit{}
|
witness := TestPlonkCircuit{}
|
||||||
err := test.IsSolved(&circuit, &witness, TEST_CURVE.ScalarField())
|
err := test.IsSolved(&circuit, &witness, TEST_CURVE.ScalarField())
|
||||||
@@ -78,23 +59,7 @@ func TestPlonkDummy(t *testing.T) {
|
|||||||
circuit := TestPlonkCircuit{
|
circuit := TestPlonkCircuit{
|
||||||
proofWithPIsFilename: "./data/dummy_2^14_gates/proof_with_public_inputs.json",
|
proofWithPIsFilename: "./data/dummy_2^14_gates/proof_with_public_inputs.json",
|
||||||
commonCircuitDataFilename: "./data/dummy_2^14_gates/common_circuit_data.json",
|
commonCircuitDataFilename: "./data/dummy_2^14_gates/common_circuit_data.json",
|
||||||
|
verifierOnlyCircuitDataFilename: "./data/dummy_2^14_gates/verifier_only_circuit_data.json",
|
||||||
plonkBetas: []F{
|
|
||||||
NewFieldElementFromString("11216469004148781751"),
|
|
||||||
NewFieldElementFromString("6201977337075152249"),
|
|
||||||
},
|
|
||||||
plonkGammas: []F{
|
|
||||||
NewFieldElementFromString("8369751006669847974"),
|
|
||||||
NewFieldElementFromString("3610024170884289835"),
|
|
||||||
},
|
|
||||||
plonkAlphas: []F{
|
|
||||||
NewFieldElementFromString("970160439138448145"),
|
|
||||||
NewFieldElementFromString("2402201283787401921"),
|
|
||||||
},
|
|
||||||
plonkZeta: QuadraticExtension{
|
|
||||||
NewFieldElementFromString("17377750363769967882"),
|
|
||||||
NewFieldElementFromString("11921191651424768462"),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
witness := TestPlonkCircuit{}
|
witness := TestPlonkCircuit{}
|
||||||
err := test.IsSolved(&circuit, &witness, TEST_CURVE.ScalarField())
|
err := test.IsSolved(&circuit, &witness, TEST_CURVE.ScalarField())
|
||||||
|
|||||||
167
plonky2_verifier/poseidon_gate.go
Normal file
167
plonky2_verifier/poseidon_gate.go
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
package plonky2_verifier
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "gnark-plonky2-verifier/field"
|
||||||
|
"gnark-plonky2-verifier/poseidon"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PoseidonGate struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPoseidonGate() *PoseidonGate {
|
||||||
|
return &PoseidonGate{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PoseidonGate) Id() string {
|
||||||
|
return "PoseidonGate"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PoseidonGate) WireInput(i uint64) uint64 {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PoseidonGate) WireOutput(i uint64) uint64 {
|
||||||
|
return poseidon.SPONGE_WIDTH + i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PoseidonGate) WireSwap() uint64 {
|
||||||
|
return 2 * poseidon.SPONGE_WIDTH
|
||||||
|
}
|
||||||
|
|
||||||
|
const START_DELTA = 2*poseidon.SPONGE_WIDTH + 1
|
||||||
|
|
||||||
|
func (g *PoseidonGate) WireDelta(i uint64) uint64 {
|
||||||
|
if i >= 4 {
|
||||||
|
panic("Delta index out of range")
|
||||||
|
}
|
||||||
|
return START_DELTA + i
|
||||||
|
}
|
||||||
|
|
||||||
|
const START_FULL_0 = START_DELTA + 4
|
||||||
|
|
||||||
|
func (g *PoseidonGate) WireFullSBox0(round uint64, i uint64) uint64 {
|
||||||
|
if round == 0 {
|
||||||
|
panic("First-round S-box inputs are not stored as wires")
|
||||||
|
}
|
||||||
|
if round >= poseidon.HALF_N_FULL_ROUNDS {
|
||||||
|
panic("S-box input round out of range")
|
||||||
|
}
|
||||||
|
if i >= poseidon.SPONGE_WIDTH {
|
||||||
|
panic("S-box input index out of range")
|
||||||
|
}
|
||||||
|
|
||||||
|
return START_FULL_0 + (round-1)*poseidon.SPONGE_WIDTH + i
|
||||||
|
}
|
||||||
|
|
||||||
|
const START_PARTIAL = START_FULL_0 + (poseidon.HALF_N_FULL_ROUNDS-1)*poseidon.SPONGE_WIDTH
|
||||||
|
|
||||||
|
func (g *PoseidonGate) WirePartialSBox(round uint64) uint64 {
|
||||||
|
if round >= poseidon.N_PARTIAL_ROUNDS {
|
||||||
|
panic("S-box input round out of range")
|
||||||
|
}
|
||||||
|
return START_PARTIAL + round
|
||||||
|
}
|
||||||
|
|
||||||
|
const START_FULL_1 = START_PARTIAL + poseidon.N_PARTIAL_ROUNDS
|
||||||
|
|
||||||
|
func (g *PoseidonGate) WireFullSBox1(round uint64, i uint64) uint64 {
|
||||||
|
if round >= poseidon.HALF_N_FULL_ROUNDS {
|
||||||
|
panic("S-box input round out of range")
|
||||||
|
}
|
||||||
|
if i >= poseidon.SPONGE_WIDTH {
|
||||||
|
panic("S-box input index out of range")
|
||||||
|
}
|
||||||
|
|
||||||
|
return START_FULL_1 + round*poseidon.SPONGE_WIDTH + i
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PoseidonGate) WiresEnd() uint64 {
|
||||||
|
return START_FULL_1 + poseidon.HALF_N_FULL_ROUNDS*poseidon.SPONGE_WIDTH
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PoseidonGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension {
|
||||||
|
constraints := []QuadraticExtension{}
|
||||||
|
|
||||||
|
poseidonChip := poseidon.NewPoseidonChip(p.api, NewFieldAPI(p.api), p.qeAPI)
|
||||||
|
|
||||||
|
// Assert that `swap` is binary.
|
||||||
|
swap := vars.localWires[g.WireSwap()]
|
||||||
|
swapMinusOne := p.qeAPI.SubExtension(swap, p.qeAPI.FieldToQE(ONE_F))
|
||||||
|
constraints = append(constraints, p.qeAPI.MulExtension(swap, swapMinusOne))
|
||||||
|
|
||||||
|
// Assert that each delta wire is set properly: `delta_i = swap * (rhs - lhs)`.
|
||||||
|
for i := uint64(0); i < 4; i++ {
|
||||||
|
inputLhs := vars.localWires[g.WireInput(i)]
|
||||||
|
inputRhs := vars.localWires[g.WireInput(i+4)]
|
||||||
|
deltaI := vars.localWires[g.WireDelta(i)]
|
||||||
|
diff := p.qeAPI.SubExtension(inputRhs, inputLhs)
|
||||||
|
expectedDeltaI := p.qeAPI.MulExtension(swap, diff)
|
||||||
|
constraints = append(constraints, p.qeAPI.SubExtension(expectedDeltaI, deltaI))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the possibly-swapped input layer.
|
||||||
|
var state [poseidon.SPONGE_WIDTH]QuadraticExtension
|
||||||
|
for i := uint64(0); i < 4; i++ {
|
||||||
|
deltaI := vars.localWires[g.WireDelta(i)]
|
||||||
|
inputLhs := vars.localWires[g.WireInput(i)]
|
||||||
|
inputRhs := vars.localWires[g.WireInput(i+4)]
|
||||||
|
state[i] = p.qeAPI.AddExtension(inputLhs, deltaI)
|
||||||
|
state[i+4] = p.qeAPI.SubExtension(inputRhs, deltaI)
|
||||||
|
}
|
||||||
|
for i := uint64(8); i < poseidon.SPONGE_WIDTH; i++ {
|
||||||
|
state[i] = vars.localWires[g.WireInput(i)]
|
||||||
|
}
|
||||||
|
|
||||||
|
roundCounter := 0
|
||||||
|
|
||||||
|
// First set of full rounds.
|
||||||
|
for r := uint64(0); r < poseidon.HALF_N_FULL_ROUNDS; r++ {
|
||||||
|
state = poseidonChip.ConstantLayerExtension(state, &roundCounter)
|
||||||
|
if r != 0 {
|
||||||
|
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
|
||||||
|
sBoxIn := vars.localWires[g.WireFullSBox0(r, i)]
|
||||||
|
constraints = append(constraints, p.qeAPI.SubExtension(state[i], sBoxIn))
|
||||||
|
state[i] = sBoxIn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state = poseidonChip.SBoxLayerExtension(state)
|
||||||
|
state = poseidonChip.MdsLayerExtension(state)
|
||||||
|
roundCounter++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Partial rounds.
|
||||||
|
state = poseidonChip.PartialFirstConstantLayerExtension(state)
|
||||||
|
state = poseidonChip.MdsPartialLayerInitExtension(state)
|
||||||
|
|
||||||
|
for r := uint64(0); r < poseidon.N_PARTIAL_ROUNDS-1; r++ {
|
||||||
|
sBoxIn := vars.localWires[g.WirePartialSBox(r)]
|
||||||
|
constraints = append(constraints, p.qeAPI.SubExtension(state[0], sBoxIn))
|
||||||
|
state[0] = poseidonChip.SBoxMonomialExtension(sBoxIn)
|
||||||
|
state[0] = p.qeAPI.AddExtension(state[0], p.qeAPI.FieldToQE(NewFieldElement(poseidon.FAST_PARTIAL_ROUND_CONSTANTS[r])))
|
||||||
|
state = poseidonChip.MdsPartialLayerFastExtension(state, int(r))
|
||||||
|
}
|
||||||
|
sBoxIn := vars.localWires[g.WirePartialSBox(poseidon.N_PARTIAL_ROUNDS-1)]
|
||||||
|
constraints = append(constraints, p.qeAPI.SubExtension(state[0], sBoxIn))
|
||||||
|
state[0] = poseidonChip.SBoxMonomialExtension(sBoxIn)
|
||||||
|
state = poseidonChip.MdsPartialLayerFastExtension(state, poseidon.N_PARTIAL_ROUNDS-1)
|
||||||
|
roundCounter += poseidon.N_PARTIAL_ROUNDS
|
||||||
|
|
||||||
|
// Second set of full rounds.
|
||||||
|
for r := uint64(0); r < poseidon.HALF_N_FULL_ROUNDS; r++ {
|
||||||
|
state = poseidonChip.ConstantLayerExtension(state, &roundCounter)
|
||||||
|
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
|
||||||
|
sBoxIn := vars.localWires[g.WireFullSBox1(r, i)]
|
||||||
|
constraints = append(constraints, p.qeAPI.SubExtension(state[i], sBoxIn))
|
||||||
|
state[i] = sBoxIn
|
||||||
|
}
|
||||||
|
state = poseidonChip.SBoxLayerExtension(state)
|
||||||
|
state = poseidonChip.MdsLayerExtension(state)
|
||||||
|
roundCounter++
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint64(0); i < poseidon.SPONGE_WIDTH; i++ {
|
||||||
|
constraints = append(constraints, p.qeAPI.SubExtension(state[i], vars.localWires[g.WireOutput(i)]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return constraints
|
||||||
|
}
|
||||||
36
plonky2_verifier/public_input_gate.go
Normal file
36
plonky2_verifier/public_input_gate.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package plonky2_verifier
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "gnark-plonky2-verifier/field"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PublicInputGate struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPublicInputGate() *PublicInputGate {
|
||||||
|
return &PublicInputGate{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PublicInputGate) Id() string {
|
||||||
|
return "PublicInputGate"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PublicInputGate) WiresPublicInputsHash() []uint64 {
|
||||||
|
return []uint64{0, 1, 2, 3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *PublicInputGate) EvalUnfiltered(p *PlonkChip, vars EvaluationVars) []QuadraticExtension {
|
||||||
|
constraints := []QuadraticExtension{}
|
||||||
|
|
||||||
|
wires := g.WiresPublicInputsHash()
|
||||||
|
hash_parts := vars.publicInputsHash
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
wire := wires[i]
|
||||||
|
hash_part := hash_parts[i]
|
||||||
|
|
||||||
|
diff := p.qeAPI.SubExtension(vars.localWires[wire], p.qeAPI.FieldToQE(hash_part))
|
||||||
|
constraints = append(constraints, diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
return constraints
|
||||||
|
}
|
||||||
@@ -21,14 +21,14 @@ type TestQuadraticExtensionMulCircuit struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *TestQuadraticExtensionMulCircuit) Define(api frontend.API) error {
|
func (c *TestQuadraticExtensionMulCircuit) Define(api frontend.API) error {
|
||||||
field := field.NewFieldAPI(api)
|
fieldAPI := field.NewFieldAPI(api)
|
||||||
degreeBits := 3
|
degreeBits := 3
|
||||||
c.qeAPI = NewQuadraticExtensionAPI(field, uint64(degreeBits))
|
c.qeAPI = NewQuadraticExtensionAPI(fieldAPI, uint64(degreeBits))
|
||||||
|
|
||||||
actualRes := c.qeAPI.MulExtension(c.operand1, c.operand2)
|
actualRes := c.qeAPI.MulExtension(c.operand1, c.operand2)
|
||||||
|
|
||||||
field.AssertIsEqual(actualRes[0], c.expectedResult[0])
|
fieldAPI.AssertIsEqual(actualRes[0], c.expectedResult[0])
|
||||||
field.AssertIsEqual(actualRes[1], c.expectedResult[1])
|
fieldAPI.AssertIsEqual(actualRes[1], c.expectedResult[1])
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -55,14 +55,14 @@ type TestQuadraticExtensionDivCircuit struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *TestQuadraticExtensionDivCircuit) Define(api frontend.API) error {
|
func (c *TestQuadraticExtensionDivCircuit) Define(api frontend.API) error {
|
||||||
field := field.NewFieldAPI(api)
|
fieldAPI := field.NewFieldAPI(api)
|
||||||
degreeBits := 3
|
degreeBits := 3
|
||||||
c.qeAPI = NewQuadraticExtensionAPI(field, uint64(degreeBits))
|
c.qeAPI = NewQuadraticExtensionAPI(fieldAPI, uint64(degreeBits))
|
||||||
|
|
||||||
actualRes := c.qeAPI.DivExtension(c.operand1, c.operand2)
|
actualRes := c.qeAPI.DivExtension(c.operand1, c.operand2)
|
||||||
|
|
||||||
field.AssertIsEqual(actualRes[0], c.expectedResult[0])
|
fieldAPI.AssertIsEqual(actualRes[0], c.expectedResult[0])
|
||||||
field.AssertIsEqual(actualRes[1], c.expectedResult[1])
|
fieldAPI.AssertIsEqual(actualRes[1], c.expectedResult[1])
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
17
plonky2_verifier/selectors.go
Normal file
17
plonky2_verifier/selectors.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package plonky2_verifier
|
||||||
|
|
||||||
|
const UNUSED_SELECTOR = uint64(^uint32(0)) // max uint32
|
||||||
|
|
||||||
|
type Range struct {
|
||||||
|
start uint64
|
||||||
|
end uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type SelectorsInfo struct {
|
||||||
|
selectorIndices []uint64
|
||||||
|
groups []Range
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SelectorsInfo) NumSelectors() uint64 {
|
||||||
|
return uint64(len(s.groups))
|
||||||
|
}
|
||||||
@@ -65,6 +65,7 @@ type ProofWithPublicInputs struct {
|
|||||||
|
|
||||||
type VerifierOnlyCircuitData struct {
|
type VerifierOnlyCircuitData struct {
|
||||||
ConstantSigmasCap MerkleCap
|
ConstantSigmasCap MerkleCap
|
||||||
|
CircuitDigest Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
type FriConfig struct {
|
type FriConfig struct {
|
||||||
@@ -101,6 +102,8 @@ type CircuitConfig struct {
|
|||||||
type CommonCircuitData struct {
|
type CommonCircuitData struct {
|
||||||
Config CircuitConfig
|
Config CircuitConfig
|
||||||
FriParams FriParams
|
FriParams FriParams
|
||||||
|
Gates []gate
|
||||||
|
SelectorsInfo SelectorsInfo
|
||||||
DegreeBits uint64
|
DegreeBits uint64
|
||||||
QuotientDegreeFactor uint64
|
QuotientDegreeFactor uint64
|
||||||
NumGateConstraints uint64
|
NumGateConstraints uint64
|
||||||
@@ -108,7 +111,6 @@ type CommonCircuitData struct {
|
|||||||
NumPublicInputs uint64
|
NumPublicInputs uint64
|
||||||
KIs []F
|
KIs []F
|
||||||
NumPartialProducts uint64
|
NumPartialProducts uint64
|
||||||
CircuitDigest Hash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProofChallenges struct {
|
type ProofChallenges struct {
|
||||||
@@ -123,5 +125,5 @@ type FriChallenges struct {
|
|||||||
FriAlpha QuadraticExtension
|
FriAlpha QuadraticExtension
|
||||||
FriBetas []QuadraticExtension
|
FriBetas []QuadraticExtension
|
||||||
FriPowResponse F
|
FriPowResponse F
|
||||||
FriQueryIndicies []F
|
FriQueryIndices []F
|
||||||
}
|
}
|
||||||
|
|||||||
15
plonky2_verifier/vars.go
Normal file
15
plonky2_verifier/vars.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package plonky2_verifier
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "gnark-plonky2-verifier/field"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EvaluationVars struct {
|
||||||
|
localConstants []QuadraticExtension
|
||||||
|
localWires []QuadraticExtension
|
||||||
|
publicInputsHash Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EvaluationVars) RemovePrefix(numSelectors uint64) {
|
||||||
|
e.localConstants = e.localConstants[numSelectors:]
|
||||||
|
}
|
||||||
@@ -31,12 +31,12 @@ func (c *VerifierChip) GetPublicInputsHash(publicInputs []F) Hash {
|
|||||||
return c.poseidonChip.HashNoPad(publicInputs)
|
return c.poseidonChip.HashNoPad(publicInputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *VerifierChip) GetChallenges(proofWithPis ProofWithPublicInputs, publicInputsHash Hash, commonData CommonCircuitData) ProofChallenges {
|
func (c *VerifierChip) GetChallenges(proofWithPis ProofWithPublicInputs, publicInputsHash Hash, commonData CommonCircuitData, verifierData VerifierOnlyCircuitData) ProofChallenges {
|
||||||
config := commonData.Config
|
config := commonData.Config
|
||||||
numChallenges := config.NumChallenges
|
numChallenges := config.NumChallenges
|
||||||
challenger := NewChallengerChip(c.api, c.fieldAPI, c.poseidonChip)
|
challenger := NewChallengerChip(c.api, c.fieldAPI, c.poseidonChip)
|
||||||
|
|
||||||
var circuitDigest = commonData.CircuitDigest
|
var circuitDigest = verifierData.CircuitDigest
|
||||||
|
|
||||||
challenger.ObserveHash(circuitDigest)
|
challenger.ObserveHash(circuitDigest)
|
||||||
challenger.ObserveHash(publicInputsHash)
|
challenger.ObserveHash(publicInputsHash)
|
||||||
@@ -71,9 +71,9 @@ func (c *VerifierChip) Verify(proofWithPis ProofWithPublicInputs, verifierData V
|
|||||||
// TODO: Verify shape of the proof?
|
// TODO: Verify shape of the proof?
|
||||||
|
|
||||||
publicInputsHash := c.GetPublicInputsHash(proofWithPis.PublicInputs)
|
publicInputsHash := c.GetPublicInputsHash(proofWithPis.PublicInputs)
|
||||||
proofChallenges := c.GetChallenges(proofWithPis, publicInputsHash, commonData)
|
proofChallenges := c.GetChallenges(proofWithPis, publicInputsHash, commonData, verifierData)
|
||||||
|
|
||||||
c.plonkChip.Verify(proofChallenges, proofWithPis.Proof.Openings)
|
c.plonkChip.Verify(proofChallenges, proofWithPis.Proof.Openings, publicInputsHash)
|
||||||
|
|
||||||
initialMerkleCaps := []MerkleCap{
|
initialMerkleCaps := []MerkleCap{
|
||||||
verifierData.ConstantSigmasCap,
|
verifierData.ConstantSigmasCap,
|
||||||
@@ -97,8 +97,8 @@ func (c *VerifierChip) Verify(proofWithPis ProofWithPublicInputs, verifierData V
|
|||||||
|
|
||||||
proofChallenges.FriChallenges.FriPowResponse = c.fieldAPI.Add(proofChallenges.FriChallenges.FriPowResponse, ZERO_F).(F)
|
proofChallenges.FriChallenges.FriPowResponse = c.fieldAPI.Add(proofChallenges.FriChallenges.FriPowResponse, ZERO_F).(F)
|
||||||
|
|
||||||
for i := 0; i < len(proofChallenges.FriChallenges.FriQueryIndicies); i++ {
|
for i := 0; i < len(proofChallenges.FriChallenges.FriQueryIndices); i++ {
|
||||||
proofChallenges.FriChallenges.FriQueryIndicies[i] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriQueryIndicies[i], ZERO_F).(F)
|
proofChallenges.FriChallenges.FriQueryIndices[i] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriQueryIndices[i], ZERO_F).(F)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.friChip.VerifyFriProof(
|
c.friChip.VerifyFriProof(
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func (c *TestVerifierChallengesCircuit) GetChallengesSanityCheck(
|
|||||||
commonData CommonCircuitData,
|
commonData CommonCircuitData,
|
||||||
) {
|
) {
|
||||||
publicInputsHash := c.verifierChip.GetPublicInputsHash(proofWithPis.PublicInputs)
|
publicInputsHash := c.verifierChip.GetPublicInputsHash(proofWithPis.PublicInputs)
|
||||||
proofChallenges := c.verifierChip.GetChallenges(proofWithPis, publicInputsHash, commonData)
|
proofChallenges := c.verifierChip.GetChallenges(proofWithPis, publicInputsHash, commonData, verifierData)
|
||||||
|
|
||||||
c.hashAPI.AssertIsEqualHash(publicInputsHash, c.expectedPublicInputsHash)
|
c.hashAPI.AssertIsEqualHash(publicInputsHash, c.expectedPublicInputsHash)
|
||||||
|
|
||||||
@@ -81,12 +81,12 @@ func (c *TestVerifierChallengesCircuit) GetChallengesSanityCheck(
|
|||||||
// expectedPowResponse := NewFieldElementFromString("92909863298412")
|
// expectedPowResponse := NewFieldElementFromString("92909863298412")
|
||||||
// c.field.AssertIsEqual(proofChallenges.FriChallenges.FriPowResponse, expectedPowResponse)
|
// c.field.AssertIsEqual(proofChallenges.FriChallenges.FriPowResponse, expectedPowResponse)
|
||||||
|
|
||||||
if len(proofChallenges.FriChallenges.FriQueryIndicies) != int(c.numFriQueries) {
|
if len(proofChallenges.FriChallenges.FriQueryIndices) != int(c.numFriQueries) {
|
||||||
c.t.Errorf("len(expectedFriQueryIndices) should equal num fri queries")
|
c.t.Errorf("len(expectedFriQueryIndices) should equal num fri queries")
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < int(c.numFriQueries); i++ {
|
for i := 0; i < int(c.numFriQueries); i++ {
|
||||||
c.fieldAPI.AssertIsEqual(c.expectedFriQueryIndices[i], proofChallenges.FriChallenges.FriQueryIndicies[i])
|
c.fieldAPI.AssertIsEqual(c.expectedFriQueryIndices[i], proofChallenges.FriChallenges.FriQueryIndices[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +101,7 @@ func (c *TestVerifierChallengesCircuit) Define(api frontend.API) error {
|
|||||||
c.fieldAPI = NewFieldAPI(api)
|
c.fieldAPI = NewFieldAPI(api)
|
||||||
c.qeAPI = NewQuadraticExtensionAPI(c.fieldAPI, commonCircuitData.DegreeBits)
|
c.qeAPI = NewQuadraticExtensionAPI(c.fieldAPI, commonCircuitData.DegreeBits)
|
||||||
c.hashAPI = NewHashAPI(c.fieldAPI)
|
c.hashAPI = NewHashAPI(c.fieldAPI)
|
||||||
poseidonChip := NewPoseidonChip(api, c.fieldAPI)
|
poseidonChip := NewPoseidonChip(api, c.fieldAPI, c.qeAPI)
|
||||||
c.verifierChip = &VerifierChip{api: api, fieldAPI: c.fieldAPI, qeAPI: c.qeAPI, poseidonChip: poseidonChip}
|
c.verifierChip = &VerifierChip{api: api, fieldAPI: c.fieldAPI, qeAPI: c.qeAPI, poseidonChip: poseidonChip}
|
||||||
|
|
||||||
c.GetChallengesSanityCheck(proofWithPis, verfierOnlyCircuitData, commonCircuitData)
|
c.GetChallengesSanityCheck(proofWithPis, verfierOnlyCircuitData, commonCircuitData)
|
||||||
@@ -301,7 +301,7 @@ func (c *TestVerifierCircuit) Define(api frontend.API) error {
|
|||||||
fieldAPI := NewFieldAPI(api)
|
fieldAPI := NewFieldAPI(api)
|
||||||
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits)
|
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits)
|
||||||
hashAPI := NewHashAPI(fieldAPI)
|
hashAPI := NewHashAPI(fieldAPI)
|
||||||
poseidonChip := NewPoseidonChip(api, fieldAPI)
|
poseidonChip := NewPoseidonChip(api, fieldAPI, qeAPI)
|
||||||
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData)
|
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData)
|
||||||
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams)
|
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams)
|
||||||
verifierChip := VerifierChip{
|
verifierChip := VerifierChip{
|
||||||
|
|||||||
@@ -11,33 +11,35 @@ const N_FULL_ROUNDS_TOTAL = 2 * HALF_N_FULL_ROUNDS
|
|||||||
const N_PARTIAL_ROUNDS = 22
|
const N_PARTIAL_ROUNDS = 22
|
||||||
const N_ROUNDS = N_FULL_ROUNDS_TOTAL + N_PARTIAL_ROUNDS
|
const N_ROUNDS = N_FULL_ROUNDS_TOTAL + N_PARTIAL_ROUNDS
|
||||||
const MAX_WIDTH = 12
|
const MAX_WIDTH = 12
|
||||||
const WIDTH = 12
|
|
||||||
const SPONGE_WIDTH = 12
|
const SPONGE_WIDTH = 12
|
||||||
const SPONGE_RATE = 8
|
const SPONGE_RATE = 8
|
||||||
|
|
||||||
type PoseidonState = [WIDTH]F
|
type PoseidonState = [SPONGE_WIDTH]F
|
||||||
|
type PoseidonStateExtension = [SPONGE_WIDTH]QuadraticExtension
|
||||||
|
|
||||||
type PoseidonChip struct {
|
type PoseidonChip struct {
|
||||||
api frontend.API `gnark:"-"`
|
api frontend.API `gnark:"-"`
|
||||||
field frontend.API `gnark:"-"`
|
fieldAPI frontend.API `gnark:"-"`
|
||||||
|
qeAPI *QuadraticExtensionAPI `gnark:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPoseidonChip(api frontend.API, field frontend.API) *PoseidonChip {
|
func NewPoseidonChip(api frontend.API, fieldAPI frontend.API, qeAPI *QuadraticExtensionAPI) *PoseidonChip {
|
||||||
return &PoseidonChip{api: api, field: field}
|
return &PoseidonChip{api: api, fieldAPI: fieldAPI, qeAPI: qeAPI}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.FullRounds(state, &roundCounter)
|
||||||
state = c.partialRounds(state, &roundCounter)
|
state = c.PartialRounds(state, &roundCounter)
|
||||||
state = c.fullRounds(state, &roundCounter)
|
state = c.FullRounds(state, &roundCounter)
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PoseidonChip) HashNToMNoPad(input []F, nbOutputs int) []F {
|
func (c *PoseidonChip) HashNToMNoPad(input []F, nbOutputs int) []F {
|
||||||
var state PoseidonState
|
var state PoseidonState
|
||||||
|
|
||||||
for i := 0; i < WIDTH; i++ {
|
for i := 0; i < SPONGE_WIDTH; i++ {
|
||||||
state[i] = ZERO_F
|
state[i] = ZERO_F
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,24 +71,24 @@ func (c *PoseidonChip) HashNoPad(input []F) Hash {
|
|||||||
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.ConstantLayer(state, roundCounter)
|
||||||
state = c.sBoxLayer(state)
|
state = c.SBoxLayer(state)
|
||||||
state = c.mdsLayer(state)
|
state = c.MdsLayer(state)
|
||||||
*roundCounter += 1
|
*roundCounter += 1
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PoseidonChip) partialRounds(state PoseidonState, roundCounter *int) PoseidonState {
|
func (c *PoseidonChip) PartialRounds(state PoseidonState, roundCounter *int) PoseidonState {
|
||||||
state = c.partialFirstConstantLayer(state)
|
state = c.PartialFirstConstantLayer(state)
|
||||||
state = c.mdsPartialLayerInit(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.SBoxMonomial(state[0])
|
||||||
state[0] = c.field.Add(state[0], FAST_PARTIAL_ROUND_CONSTANTS[i]).(F)
|
state[0] = c.fieldAPI.Add(state[0], FAST_PARTIAL_ROUND_CONSTANTS[i]).(F)
|
||||||
state = c.mdsPartialLayerFast(state, i)
|
state = c.MdsPartialLayerFast(state, i)
|
||||||
}
|
}
|
||||||
|
|
||||||
*roundCounter += N_PARTIAL_ROUNDS
|
*roundCounter += N_PARTIAL_ROUNDS
|
||||||
@@ -94,38 +96,64 @@ 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 < WIDTH {
|
if i < SPONGE_WIDTH {
|
||||||
roundConstant := NewFieldElement(ALL_ROUND_CONSTANTS[i+WIDTH*(*roundCounter)])
|
roundConstant := NewFieldElement(ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)])
|
||||||
state[i] = c.field.Add(state[i], roundConstant).(F)
|
state[i] = c.fieldAPI.Add(state[i], roundConstant).(F)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PoseidonChip) sBoxLayer(state PoseidonState) PoseidonState {
|
func (c *PoseidonChip) ConstantLayerExtension(state PoseidonStateExtension, roundCounter *int) PoseidonStateExtension {
|
||||||
for i := 0; i < 12; i++ {
|
for i := 0; i < 12; i++ {
|
||||||
if i < WIDTH {
|
if i < SPONGE_WIDTH {
|
||||||
state[i] = c.sBoxMonomial(state[i])
|
roundConstant := c.qeAPI.FieldToQE(NewFieldElement(ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)]))
|
||||||
|
state[i] = c.qeAPI.AddExtension(state[i], roundConstant)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PoseidonChip) sBoxMonomial(x F) F {
|
func (c *PoseidonChip) SBoxMonomial(x F) F {
|
||||||
x2 := c.field.Mul(x, x)
|
x2 := c.fieldAPI.Mul(x, x)
|
||||||
x4 := c.field.Mul(x2, x2)
|
x4 := c.fieldAPI.Mul(x2, x2)
|
||||||
x3 := c.field.Mul(x2, x)
|
x3 := c.fieldAPI.Mul(x, x2)
|
||||||
return c.field.Mul(x3, x4).(F)
|
return c.fieldAPI.Mul(x3, x4).(F)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PoseidonChip) mdsRowShf(r int, v [WIDTH]frontend.Variable) frontend.Variable {
|
func (c *PoseidonChip) SBoxMonomialExtension(x QuadraticExtension) QuadraticExtension {
|
||||||
|
x2 := c.qeAPI.SquareExtension(x)
|
||||||
|
x4 := c.qeAPI.SquareExtension(x2)
|
||||||
|
x3 := c.qeAPI.MulExtension(x, x2)
|
||||||
|
return c.qeAPI.MulExtension(x3, x4)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PoseidonChip) SBoxLayer(state PoseidonState) PoseidonState {
|
||||||
|
for i := 0; i < 12; i++ {
|
||||||
|
if i < SPONGE_WIDTH {
|
||||||
|
state[i] = c.SBoxMonomial(state[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PoseidonChip) SBoxLayerExtension(state PoseidonStateExtension) PoseidonStateExtension {
|
||||||
|
for i := 0; i < 12; i++ {
|
||||||
|
if i < SPONGE_WIDTH {
|
||||||
|
state[i] = c.SBoxMonomialExtension(state[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PoseidonChip) MdsRowShf(r int, v [SPONGE_WIDTH]frontend.Variable) frontend.Variable {
|
||||||
res := frontend.Variable(0)
|
res := frontend.Variable(0)
|
||||||
|
|
||||||
for i := 0; i < 12; i++ {
|
for i := 0; i < 12; i++ {
|
||||||
if i < WIDTH {
|
if i < SPONGE_WIDTH {
|
||||||
res1 := c.api.Mul(v[(i+r)%WIDTH], frontend.Variable(MDS_MATRIX_CIRC[i]))
|
res1 := c.api.Mul(v[(i+r)%SPONGE_WIDTH], frontend.Variable(MDS_MATRIX_CIRC[i]))
|
||||||
res = c.api.Add(res, res1)
|
res = c.api.Add(res, res1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,38 +162,76 @@ func (c *PoseidonChip) mdsRowShf(r int, v [WIDTH]frontend.Variable) frontend.Var
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PoseidonChip) mdsLayer(state_ PoseidonState) PoseidonState {
|
func (c *PoseidonChip) MdsRowShfExtension(r int, v [SPONGE_WIDTH]QuadraticExtension) QuadraticExtension {
|
||||||
|
res := c.qeAPI.FieldToQE(NewFieldElement(0))
|
||||||
|
|
||||||
|
for i := 0; i < 12; i++ {
|
||||||
|
if i < SPONGE_WIDTH {
|
||||||
|
matrixVal := c.qeAPI.FieldToQE(NewFieldElement(MDS_MATRIX_CIRC[i]))
|
||||||
|
res1 := c.qeAPI.MulExtension(v[(i+r)%SPONGE_WIDTH], matrixVal)
|
||||||
|
res = c.qeAPI.AddExtension(res, res1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
matrixVal := c.qeAPI.FieldToQE(NewFieldElement(MDS_MATRIX_DIAG[r]))
|
||||||
|
res = c.qeAPI.AddExtension(res, c.qeAPI.MulExtension(v[r], matrixVal))
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PoseidonChip) MdsLayer(state_ PoseidonState) PoseidonState {
|
||||||
var result PoseidonState
|
var result PoseidonState
|
||||||
for i := 0; i < WIDTH; i++ {
|
for i := 0; i < SPONGE_WIDTH; i++ {
|
||||||
result[i] = NewFieldElement(0)
|
result[i] = NewFieldElement(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
var state [WIDTH]frontend.Variable
|
var state [SPONGE_WIDTH]frontend.Variable
|
||||||
for i := 0; i < WIDTH; i++ {
|
for i := 0; i < SPONGE_WIDTH; i++ {
|
||||||
state[i] = c.api.FromBinary(c.field.ToBinary(state_[i])...)
|
state[i] = c.api.FromBinary(c.fieldAPI.ToBinary(state_[i])...)
|
||||||
}
|
}
|
||||||
|
|
||||||
for r := 0; r < 12; r++ {
|
for r := 0; r < 12; r++ {
|
||||||
if r < WIDTH {
|
if r < SPONGE_WIDTH {
|
||||||
sum := c.mdsRowShf(r, state)
|
sum := c.MdsRowShf(r, state)
|
||||||
bits := c.api.ToBinary(sum)
|
bits := c.api.ToBinary(sum)
|
||||||
result[r] = c.field.FromBinary(bits).(F)
|
result[r] = c.fieldAPI.FromBinary(bits).(F)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PoseidonChip) partialFirstConstantLayer(state PoseidonState) PoseidonState {
|
func (c *PoseidonChip) MdsLayerExtension(state_ PoseidonStateExtension) PoseidonStateExtension {
|
||||||
|
var result PoseidonStateExtension
|
||||||
|
|
||||||
|
for r := 0; r < 12; r++ {
|
||||||
|
if r < SPONGE_WIDTH {
|
||||||
|
sum := c.MdsRowShfExtension(r, state_)
|
||||||
|
result[r] = sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PoseidonChip) PartialFirstConstantLayer(state PoseidonState) PoseidonState {
|
||||||
for i := 0; i < 12; i++ {
|
for i := 0; i < 12; i++ {
|
||||||
if i < WIDTH {
|
if i < SPONGE_WIDTH {
|
||||||
state[i] = c.field.Add(state[i], NewFieldElement(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])).(F)
|
state[i] = c.fieldAPI.Add(state[i], NewFieldElement(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])).(F)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PoseidonChip) mdsPartialLayerInit(state PoseidonState) PoseidonState {
|
func (c *PoseidonChip) PartialFirstConstantLayerExtension(state PoseidonStateExtension) PoseidonStateExtension {
|
||||||
|
for i := 0; i < 12; i++ {
|
||||||
|
if i < SPONGE_WIDTH {
|
||||||
|
state[i] = c.qeAPI.AddExtension(state[i], c.qeAPI.FieldToQE(NewFieldElement(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
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] = NewFieldElement(0)
|
result[i] = NewFieldElement(0)
|
||||||
@@ -174,11 +240,11 @@ func (c *PoseidonChip) mdsPartialLayerInit(state PoseidonState) PoseidonState {
|
|||||||
result[0] = state[0]
|
result[0] = state[0]
|
||||||
|
|
||||||
for r := 1; r < 12; r++ {
|
for r := 1; r < 12; r++ {
|
||||||
if r < WIDTH {
|
if r < SPONGE_WIDTH {
|
||||||
for d := 1; d < 12; d++ {
|
for d := 1; d < 12; d++ {
|
||||||
if d < WIDTH {
|
if d < SPONGE_WIDTH {
|
||||||
t := NewFieldElement(FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1])
|
t := NewFieldElement(FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1])
|
||||||
result[d] = c.field.Add(result[d], c.field.Mul(state[r], t)).(F)
|
result[d] = c.fieldAPI.Add(result[d], c.fieldAPI.Mul(state[r], t)).(F)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,32 +253,77 @@ func (c *PoseidonChip) mdsPartialLayerInit(state PoseidonState) PoseidonState {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PoseidonChip) mdsPartialLayerFast(state PoseidonState, r int) PoseidonState {
|
func (c *PoseidonChip) MdsPartialLayerInitExtension(state PoseidonStateExtension) PoseidonStateExtension {
|
||||||
|
var result PoseidonStateExtension
|
||||||
|
for i := 0; i < 12; i++ {
|
||||||
|
result[i] = c.qeAPI.FieldToQE(NewFieldElement(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
result[0] = state[0]
|
||||||
|
|
||||||
|
for r := 1; r < 12; r++ {
|
||||||
|
if r < SPONGE_WIDTH {
|
||||||
|
for d := 1; d < 12; d++ {
|
||||||
|
if d < SPONGE_WIDTH {
|
||||||
|
t := c.qeAPI.FieldToQE(NewFieldElement(FAST_PARTIAL_ROUND_INITIAL_MATRIX[r-1][d-1]))
|
||||||
|
result[d] = c.qeAPI.AddExtension(result[d], c.qeAPI.MulExtension(state[r], t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PoseidonChip) MdsPartialLayerFast(state PoseidonState, r int) PoseidonState {
|
||||||
dSum := frontend.Variable(0)
|
dSum := frontend.Variable(0)
|
||||||
for i := 1; i < 12; i++ {
|
for i := 1; i < 12; i++ {
|
||||||
if i < WIDTH {
|
if i < SPONGE_WIDTH {
|
||||||
t := frontend.Variable(FAST_PARTIAL_ROUND_W_HATS[r][i-1])
|
t := frontend.Variable(FAST_PARTIAL_ROUND_W_HATS[r][i-1])
|
||||||
si := c.api.FromBinary(c.field.ToBinary(state[i])...)
|
si := c.api.FromBinary(c.fieldAPI.ToBinary(state[i])...)
|
||||||
dSum = c.api.Add(dSum, c.api.Mul(si, t))
|
dSum = c.api.Add(dSum, c.api.Mul(si, t))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s0 := c.api.FromBinary(c.field.ToBinary(state[0])...)
|
s0 := c.api.FromBinary(c.fieldAPI.ToBinary(state[0])...)
|
||||||
mds0to0 := frontend.Variable(MDS_MATRIX_CIRC[0] + MDS_MATRIX_DIAG[0])
|
mds0to0 := frontend.Variable(MDS_MATRIX_CIRC[0] + MDS_MATRIX_DIAG[0])
|
||||||
dSum = c.api.Add(dSum, c.api.Mul(s0, mds0to0))
|
dSum = c.api.Add(dSum, c.api.Mul(s0, mds0to0))
|
||||||
d := c.field.FromBinary(c.api.ToBinary(dSum))
|
d := c.fieldAPI.FromBinary(c.api.ToBinary(dSum))
|
||||||
|
|
||||||
var result PoseidonState
|
var result PoseidonState
|
||||||
for i := 0; i < WIDTH; i++ {
|
for i := 0; i < SPONGE_WIDTH; i++ {
|
||||||
result[i] = NewFieldElement(0)
|
result[i] = NewFieldElement(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
result[0] = d.(F)
|
result[0] = d.(F)
|
||||||
|
|
||||||
for i := 1; i < 12; i++ {
|
for i := 1; i < 12; i++ {
|
||||||
if i < WIDTH {
|
if i < SPONGE_WIDTH {
|
||||||
t := NewFieldElement(FAST_PARTIAL_ROUND_VS[r][i-1])
|
t := NewFieldElement(FAST_PARTIAL_ROUND_VS[r][i-1])
|
||||||
result[i] = c.field.Add(state[i], c.field.Mul(state[0], t)).(F)
|
result[i] = c.fieldAPI.Add(state[i], c.fieldAPI.Mul(state[0], t)).(F)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *PoseidonChip) MdsPartialLayerFastExtension(state PoseidonStateExtension, r int) PoseidonStateExtension {
|
||||||
|
s0 := state[0]
|
||||||
|
mds0to0 := c.qeAPI.FieldToQE(NewFieldElement(MDS_MATRIX_CIRC[0] + MDS_MATRIX_DIAG[0]))
|
||||||
|
d := c.qeAPI.MulExtension(s0, mds0to0)
|
||||||
|
for i := 1; i < 12; i++ {
|
||||||
|
if i < SPONGE_WIDTH {
|
||||||
|
t := c.qeAPI.FieldToQE(NewFieldElement(FAST_PARTIAL_ROUND_W_HATS[r][i-1]))
|
||||||
|
d = c.qeAPI.AddExtension(d, c.qeAPI.MulExtension(state[i], t))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result PoseidonStateExtension
|
||||||
|
result[0] = d
|
||||||
|
for i := 1; i < 12; i++ {
|
||||||
|
if i < SPONGE_WIDTH {
|
||||||
|
t := c.qeAPI.FieldToQE(NewFieldElement(FAST_PARTIAL_ROUND_VS[r][i-1]))
|
||||||
|
result[i] = c.qeAPI.AddExtension(c.qeAPI.MulExtension(state[0], t), state[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,14 @@ type TestPoseidonCircuit struct {
|
|||||||
|
|
||||||
func (circuit *TestPoseidonCircuit) Define(api frontend.API) error {
|
func (circuit *TestPoseidonCircuit) Define(api frontend.API) error {
|
||||||
goldilocksApi := field.NewFieldAPI(api)
|
goldilocksApi := field.NewFieldAPI(api)
|
||||||
|
qeAPI := NewQuadraticExtensionAPI(goldilocksApi, 3)
|
||||||
|
|
||||||
var input PoseidonState
|
var input PoseidonState
|
||||||
for i := 0; i < 12; i++ {
|
for i := 0; i < 12; i++ {
|
||||||
input[i] = goldilocksApi.FromBinary(api.ToBinary(circuit.In[i], 64)).(F)
|
input[i] = goldilocksApi.FromBinary(api.ToBinary(circuit.In[i], 64)).(F)
|
||||||
}
|
}
|
||||||
|
|
||||||
poseidonChip := NewPoseidonChip(api, goldilocksApi)
|
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++ {
|
||||||
|
|||||||
@@ -18,22 +18,22 @@ type TestPublicInputsHashCircuit struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (circuit *TestPublicInputsHashCircuit) Define(api frontend.API) error {
|
func (circuit *TestPublicInputsHashCircuit) Define(api frontend.API) error {
|
||||||
field := NewFieldAPI(api)
|
fieldAPI := NewFieldAPI(api)
|
||||||
|
|
||||||
// BN254 -> Binary(64) -> F
|
// BN254 -> Binary(64) -> F
|
||||||
var input [3]F
|
var input [3]F
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
input[i] = field.FromBinary(api.ToBinary(circuit.In[i], 64)).(F)
|
input[i] = fieldAPI.FromBinary(api.ToBinary(circuit.In[i], 64)).(F)
|
||||||
}
|
}
|
||||||
|
|
||||||
poseidonChip := &PoseidonChip{api: api, field: field}
|
poseidonChip := &PoseidonChip{api: api, fieldAPI: fieldAPI}
|
||||||
output := poseidonChip.HashNoPad(input[:])
|
output := poseidonChip.HashNoPad(input[:])
|
||||||
|
|
||||||
// Check that output is correct
|
// Check that output is correct
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
field.AssertIsEqual(
|
fieldAPI.AssertIsEqual(
|
||||||
output[i],
|
output[i],
|
||||||
field.FromBinary(api.ToBinary(circuit.Out[i])).(F),
|
fieldAPI.FromBinary(api.ToBinary(circuit.Out[i])).(F),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,10 @@ func Uint64ArrayToFArray(input []uint64) []F {
|
|||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Uint64ArrayToQuadraticExtension(input []uint64) QuadraticExtension {
|
||||||
|
return [2]F{NewFieldElement(input[0]), NewFieldElement(input[1])}
|
||||||
|
}
|
||||||
|
|
||||||
func Uint64ArrayToQuadraticExtensionArray(input [][]uint64) []QuadraticExtension {
|
func Uint64ArrayToQuadraticExtensionArray(input [][]uint64) []QuadraticExtension {
|
||||||
var output []QuadraticExtension
|
var output []QuadraticExtension
|
||||||
for i := 0; i < len(input); i++ {
|
for i := 0; i < len(input); i++ {
|
||||||
|
|||||||
Reference in New Issue
Block a user