mirror of
https://github.com/logos-storage/gnark-plonky2-verifier.git
synced 2026-01-04 22:23:11 +00:00
Merge pull request #2 from succinctlabs/npward-plonky2-gates
Plonky2 Gates
This commit is contained in:
commit
2fbbcec029
@ -28,7 +28,7 @@ func (circuit *BenchmarkPlonky2VerifierCircuit) 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)
|
||||
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData)
|
||||
circuit.verifierChip = NewVerifierChip(api, fieldAPI, qeAPI, poseidonChip, plonkChip, friChip)
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
package plonky2_verifier
|
||||
package field
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
. "gnark-plonky2-verifier/field"
|
||||
"math/bits"
|
||||
|
||||
"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
|
||||
}
|
||||
@ -123,10 +123,10 @@ func (c *ChallengerChip) GetFriChallenges(commitPhaseMerkleCaps []MerkleCap, fin
|
||||
friQueryIndices := c.GetNChallenges(numFriQueries)
|
||||
|
||||
return FriChallenges{
|
||||
FriAlpha: friAlpha,
|
||||
FriBetas: friBetas,
|
||||
FriPowResponse: friPowResponse,
|
||||
FriQueryIndicies: friQueryIndices,
|
||||
FriAlpha: friAlpha,
|
||||
FriBetas: friBetas,
|
||||
FriPowResponse: friPowResponse,
|
||||
FriQueryIndices: friQueryIndices,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
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"`
|
||||
ReductionArityBits []uint64 `json:"reduction_arity_bits"`
|
||||
} `json:"fri_params"`
|
||||
DegreeBits uint64 `json:"degree_bits"`
|
||||
Gates []string `json:"gates"`
|
||||
SelectorsInfo struct {
|
||||
SelectorIndices []uint64 `json:"selector_indices"`
|
||||
Groups []struct {
|
||||
@ -144,15 +144,28 @@ type CommonCircuitDataRaw struct {
|
||||
NumPublicInputs uint64 `json:"num_public_inputs"`
|
||||
KIs []uint64 `json:"k_is"`
|
||||
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 {
|
||||
ConstantsSigmasCap []struct {
|
||||
Elements []uint64 `json:"elements"`
|
||||
} `json:"constants_sigmas_cap"`
|
||||
CircuitDigest struct {
|
||||
Elements []uint64 `json:"elements"`
|
||||
} `json:"circuit_digest"`
|
||||
}
|
||||
|
||||
func DeserializeMerkleCap(merkleCapRaw []struct{ Elements []uint64 }) MerkleCap {
|
||||
@ -289,6 +302,34 @@ func DeserializeProofWithPublicInputs(path string) ProofWithPublicInputs {
|
||||
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(
|
||||
arityBits uint64,
|
||||
finalPolyBits uint64,
|
||||
@ -340,20 +381,33 @@ func DeserializeCommonCircuitData(path string) CommonCircuitData {
|
||||
commonCircuitData.Config.FriConfig.NumQueryRounds = raw.Config.FriConfig.NumQueryRounds
|
||||
|
||||
commonCircuitData.FriParams.DegreeBits = raw.FriParams.DegreeBits
|
||||
commonCircuitData.DegreeBits = raw.FriParams.DegreeBits
|
||||
commonCircuitData.FriParams.Config.RateBits = raw.FriParams.Config.RateBits
|
||||
commonCircuitData.FriParams.Config.CapHeight = raw.FriParams.Config.CapHeight
|
||||
commonCircuitData.FriParams.Config.ProofOfWorkBits = raw.FriParams.Config.ProofOfWorkBits
|
||||
commonCircuitData.FriParams.Config.NumQueryRounds = raw.FriParams.Config.NumQueryRounds
|
||||
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.NumGateConstraints = raw.NumGateConstraints
|
||||
commonCircuitData.NumConstants = raw.NumConstants
|
||||
commonCircuitData.NumPublicInputs = raw.NumPublicInputs
|
||||
commonCircuitData.KIs = utils.Uint64ArrayToFArray(raw.KIs)
|
||||
commonCircuitData.NumPartialProducts = raw.NumPartialProducts
|
||||
copy(commonCircuitData.CircuitDigest[:], utils.Uint64ArrayToFArray(raw.CircuitDigest.Elements))
|
||||
|
||||
return commonCircuitData
|
||||
}
|
||||
@ -373,7 +427,9 @@ func DeserializeVerifierOnlyCircuitData(path string) VerifierOnlyCircuitData {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return VerifierOnlyCircuitData{
|
||||
ConstantSigmasCap: DeserializeMerkleCap([]struct{ Elements []uint64 }(raw.ConstantsSigmasCap)),
|
||||
}
|
||||
var verifierOnlyCircuitData VerifierOnlyCircuitData
|
||||
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) {
|
||||
proofWithPis := DeserializeCommonCircuitData("./data/fibonacci/common_circuit_data.json")
|
||||
fmt.Printf("%+v\n", proofWithPis)
|
||||
commonCircuitData := DeserializeCommonCircuitData("./data/fibonacci/common_circuit_data.json")
|
||||
fmt.Printf("%+v\n", commonCircuitData)
|
||||
panic("look at stdout")
|
||||
}
|
||||
|
||||
func TestDeserializeVerifierOnlyCircuitData(t *testing.T) {
|
||||
proofWithPis := DeserializeVerifierOnlyCircuitData("./data/fibonacci/verifier_only_circuit_data.json")
|
||||
fmt.Printf("%+v\n", proofWithPis)
|
||||
verifierOnlyCircuitData := DeserializeVerifierOnlyCircuitData("./data/fibonacci/verifier_only_circuit_data.json")
|
||||
fmt.Printf("%+v\n", verifierOnlyCircuitData)
|
||||
panic("look at stdout")
|
||||
}
|
||||
|
||||
@ -546,15 +546,15 @@ func (f *FriChip) VerifyFriProof(
|
||||
nLog := f.friParams.DegreeBits + f.friParams.Config.RateBits
|
||||
n := uint64(math.Pow(2, float64(nLog)))
|
||||
|
||||
if len(friChallenges.FriQueryIndicies) != len(friProof.QueryRoundProofs) {
|
||||
if len(friChallenges.FriQueryIndices) != len(friProof.QueryRoundProofs) {
|
||||
panic(fmt.Sprintf(
|
||||
"Number of query indices (%d) should equal number of query round proofs (%d)",
|
||||
len(friChallenges.FriQueryIndicies),
|
||||
len(friChallenges.FriQueryIndices),
|
||||
len(friProof.QueryRoundProofs),
|
||||
))
|
||||
}
|
||||
|
||||
for idx, xIndex := range friChallenges.FriQueryIndicies {
|
||||
for idx, xIndex := range friChallenges.FriQueryIndices {
|
||||
roundProof := friProof.QueryRoundProofs[idx]
|
||||
|
||||
f.verifyQueryRound(
|
||||
|
||||
@ -29,14 +29,14 @@ 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{
|
||||
FriAlpha: circuit.friAlpha,
|
||||
FriBetas: circuit.friBetas,
|
||||
FriPowResponse: circuit.friPOWResponse,
|
||||
FriQueryIndicies: circuit.friQueryIndices,
|
||||
FriAlpha: circuit.friAlpha,
|
||||
FriBetas: circuit.friBetas,
|
||||
FriPowResponse: circuit.friPOWResponse,
|
||||
FriQueryIndices: circuit.friQueryIndices,
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (p *PlonkChip) evalVanishingPoly(proofChallenges ProofChallenges, openings OpeningSet, zetaPowN QuadraticExtension) []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
|
||||
func (p *PlonkChip) evaluateGateConstraints(vars EvaluationVars) []QuadraticExtension {
|
||||
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
|
||||
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++ {
|
||||
// The numerator is `beta * s_id + wire_value + gamma`, and the denominator is
|
||||
// `beta * s_sigma + wire_value + gamma`.
|
||||
|
||||
wireValuePlusGamma := p.qeAPI.AddExtension(
|
||||
openings.Wires[j],
|
||||
p.qeAPI.FieldToQE(proofChallenges.PlonkGammas[i]),
|
||||
@ -176,7 +204,7 @@ func (p *PlonkChip) evalVanishingPoly(proofChallenges ProofChallenges, openings
|
||||
}
|
||||
|
||||
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)
|
||||
for i := uint64(0); i < p.commonData.Config.NumChallenges; i++ {
|
||||
@ -199,11 +227,19 @@ func (p *PlonkChip) evalVanishingPoly(proofChallenges ProofChallenges, openings
|
||||
return reducedValues
|
||||
}
|
||||
|
||||
func (p *PlonkChip) Verify(proofChallenges ProofChallenges, openings OpeningSet) {
|
||||
func (p *PlonkChip) Verify(proofChallenges ProofChallenges, openings OpeningSet, publicInputsHash Hash) {
|
||||
// Calculate zeta^n
|
||||
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)
|
||||
zHZeta := p.qeAPI.SubExtension(zetaPowN, p.qeAPI.ONE_QE)
|
||||
|
||||
@ -2,6 +2,7 @@ package plonky2_verifier
|
||||
|
||||
import (
|
||||
. "gnark-plonky2-verifier/field"
|
||||
"gnark-plonky2-verifier/poseidon"
|
||||
"testing"
|
||||
|
||||
"github.com/consensys/gnark/frontend"
|
||||
@ -9,32 +10,28 @@ import (
|
||||
)
|
||||
|
||||
type TestPlonkCircuit struct {
|
||||
proofWithPIsFilename string `gnark:"-"`
|
||||
commonCircuitDataFilename string `gnark:"-"`
|
||||
|
||||
plonkBetas []F
|
||||
plonkGammas []F
|
||||
plonkAlphas []F
|
||||
plonkZeta QuadraticExtension
|
||||
proofWithPIsFilename string `gnark:"-"`
|
||||
commonCircuitDataFilename string `gnark:"-"`
|
||||
verifierOnlyCircuitDataFilename string `gnark:"-"`
|
||||
}
|
||||
|
||||
func (circuit *TestPlonkCircuit) Define(api frontend.API) error {
|
||||
proofWithPis := DeserializeProofWithPublicInputs(circuit.proofWithPIsFilename)
|
||||
commonCircuitData := DeserializeCommonCircuitData(circuit.commonCircuitDataFilename)
|
||||
verifierOnlyCircuitData := DeserializeVerifierOnlyCircuitData(circuit.verifierOnlyCircuitDataFilename)
|
||||
|
||||
field := NewFieldAPI(api)
|
||||
qe := NewQuadraticExtensionAPI(field, commonCircuitData.DegreeBits)
|
||||
fieldAPI := NewFieldAPI(api)
|
||||
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{
|
||||
PlonkBetas: circuit.plonkBetas,
|
||||
PlonkGammas: circuit.plonkGammas,
|
||||
PlonkAlphas: circuit.plonkAlphas,
|
||||
PlonkZeta: circuit.plonkZeta,
|
||||
}
|
||||
verifierChip := NewVerifierChip(api, fieldAPI, qeAPI, poseidonChip, plonkChip, friChip)
|
||||
publicInputsHash := verifierChip.GetPublicInputsHash(proofWithPis.PublicInputs)
|
||||
proofChallenges := verifierChip.GetChallenges(proofWithPis, publicInputsHash, commonCircuitData, verifierOnlyCircuitData)
|
||||
|
||||
plonkChip := NewPlonkChip(api, qe, commonCircuitData)
|
||||
|
||||
plonkChip.Verify(proofChallenges, proofWithPis.Proof.Openings)
|
||||
plonkChip.Verify(proofChallenges, proofWithPis.Proof.Openings, publicInputsHash)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -43,25 +40,9 @@ func TestPlonkFibonacci(t *testing.T) {
|
||||
|
||||
testCase := func() {
|
||||
circuit := TestPlonkCircuit{
|
||||
proofWithPIsFilename: "./data/fibonacci/proof_with_public_inputs.json",
|
||||
commonCircuitDataFilename: "./data/fibonacci/common_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"),
|
||||
},
|
||||
proofWithPIsFilename: "./data/fibonacci/proof_with_public_inputs.json",
|
||||
commonCircuitDataFilename: "./data/fibonacci/common_circuit_data.json",
|
||||
verifierOnlyCircuitDataFilename: "./data/fibonacci/verifier_only_circuit_data.json",
|
||||
}
|
||||
witness := TestPlonkCircuit{}
|
||||
err := test.IsSolved(&circuit, &witness, TEST_CURVE.ScalarField())
|
||||
@ -76,25 +57,9 @@ func TestPlonkDummy(t *testing.T) {
|
||||
|
||||
testCase := func() {
|
||||
circuit := TestPlonkCircuit{
|
||||
proofWithPIsFilename: "./data/dummy_2^14_gates/proof_with_public_inputs.json",
|
||||
commonCircuitDataFilename: "./data/dummy_2^14_gates/common_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"),
|
||||
},
|
||||
proofWithPIsFilename: "./data/dummy_2^14_gates/proof_with_public_inputs.json",
|
||||
commonCircuitDataFilename: "./data/dummy_2^14_gates/common_circuit_data.json",
|
||||
verifierOnlyCircuitDataFilename: "./data/dummy_2^14_gates/verifier_only_circuit_data.json",
|
||||
}
|
||||
witness := TestPlonkCircuit{}
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
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 {
|
||||
ConstantSigmasCap MerkleCap
|
||||
CircuitDigest Hash
|
||||
}
|
||||
|
||||
type FriConfig struct {
|
||||
@ -101,6 +102,8 @@ type CircuitConfig struct {
|
||||
type CommonCircuitData struct {
|
||||
Config CircuitConfig
|
||||
FriParams FriParams
|
||||
Gates []gate
|
||||
SelectorsInfo SelectorsInfo
|
||||
DegreeBits uint64
|
||||
QuotientDegreeFactor uint64
|
||||
NumGateConstraints uint64
|
||||
@ -108,7 +111,6 @@ type CommonCircuitData struct {
|
||||
NumPublicInputs uint64
|
||||
KIs []F
|
||||
NumPartialProducts uint64
|
||||
CircuitDigest Hash
|
||||
}
|
||||
|
||||
type ProofChallenges struct {
|
||||
@ -120,8 +122,8 @@ type ProofChallenges struct {
|
||||
}
|
||||
|
||||
type FriChallenges struct {
|
||||
FriAlpha QuadraticExtension
|
||||
FriBetas []QuadraticExtension
|
||||
FriPowResponse F
|
||||
FriQueryIndicies []F
|
||||
FriAlpha QuadraticExtension
|
||||
FriBetas []QuadraticExtension
|
||||
FriPowResponse 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)
|
||||
}
|
||||
|
||||
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
|
||||
numChallenges := config.NumChallenges
|
||||
challenger := NewChallengerChip(c.api, c.fieldAPI, c.poseidonChip)
|
||||
|
||||
var circuitDigest = commonData.CircuitDigest
|
||||
var circuitDigest = verifierData.CircuitDigest
|
||||
|
||||
challenger.ObserveHash(circuitDigest)
|
||||
challenger.ObserveHash(publicInputsHash)
|
||||
@ -71,9 +71,9 @@ func (c *VerifierChip) Verify(proofWithPis ProofWithPublicInputs, verifierData V
|
||||
// TODO: Verify shape of the proof?
|
||||
|
||||
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{
|
||||
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)
|
||||
|
||||
for i := 0; i < len(proofChallenges.FriChallenges.FriQueryIndicies); i++ {
|
||||
proofChallenges.FriChallenges.FriQueryIndicies[i] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriQueryIndicies[i], ZERO_F).(F)
|
||||
for i := 0; i < len(proofChallenges.FriChallenges.FriQueryIndices); i++ {
|
||||
proofChallenges.FriChallenges.FriQueryIndices[i] = c.fieldAPI.Add(proofChallenges.FriChallenges.FriQueryIndices[i], ZERO_F).(F)
|
||||
}
|
||||
|
||||
c.friChip.VerifyFriProof(
|
||||
|
||||
@ -41,7 +41,7 @@ func (c *TestVerifierChallengesCircuit) GetChallengesSanityCheck(
|
||||
commonData CommonCircuitData,
|
||||
) {
|
||||
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)
|
||||
|
||||
@ -81,12 +81,12 @@ func (c *TestVerifierChallengesCircuit) GetChallengesSanityCheck(
|
||||
// expectedPowResponse := NewFieldElementFromString("92909863298412")
|
||||
// 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")
|
||||
}
|
||||
|
||||
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.qeAPI = NewQuadraticExtensionAPI(c.fieldAPI, commonCircuitData.DegreeBits)
|
||||
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.GetChallengesSanityCheck(proofWithPis, verfierOnlyCircuitData, commonCircuitData)
|
||||
@ -301,7 +301,7 @@ func (c *TestVerifierCircuit) Define(api frontend.API) error {
|
||||
fieldAPI := NewFieldAPI(api)
|
||||
qeAPI := NewQuadraticExtensionAPI(fieldAPI, commonCircuitData.DegreeBits)
|
||||
hashAPI := NewHashAPI(fieldAPI)
|
||||
poseidonChip := NewPoseidonChip(api, fieldAPI)
|
||||
poseidonChip := NewPoseidonChip(api, fieldAPI, qeAPI)
|
||||
plonkChip := NewPlonkChip(api, qeAPI, commonCircuitData)
|
||||
friChip := NewFriChip(api, fieldAPI, qeAPI, hashAPI, poseidonChip, &commonCircuitData.FriParams)
|
||||
verifierChip := VerifierChip{
|
||||
|
||||
@ -11,33 +11,35 @@ const N_FULL_ROUNDS_TOTAL = 2 * HALF_N_FULL_ROUNDS
|
||||
const N_PARTIAL_ROUNDS = 22
|
||||
const N_ROUNDS = N_FULL_ROUNDS_TOTAL + N_PARTIAL_ROUNDS
|
||||
const MAX_WIDTH = 12
|
||||
const WIDTH = 12
|
||||
const SPONGE_WIDTH = 12
|
||||
const SPONGE_RATE = 8
|
||||
|
||||
type PoseidonState = [WIDTH]F
|
||||
type PoseidonState = [SPONGE_WIDTH]F
|
||||
type PoseidonStateExtension = [SPONGE_WIDTH]QuadraticExtension
|
||||
|
||||
type PoseidonChip struct {
|
||||
api frontend.API `gnark:"-"`
|
||||
field frontend.API `gnark:"-"`
|
||||
api frontend.API `gnark:"-"`
|
||||
fieldAPI frontend.API `gnark:"-"`
|
||||
qeAPI *QuadraticExtensionAPI `gnark:"-"`
|
||||
}
|
||||
|
||||
func NewPoseidonChip(api frontend.API, field frontend.API) *PoseidonChip {
|
||||
return &PoseidonChip{api: api, field: field}
|
||||
func NewPoseidonChip(api frontend.API, fieldAPI frontend.API, qeAPI *QuadraticExtensionAPI) *PoseidonChip {
|
||||
return &PoseidonChip{api: api, fieldAPI: fieldAPI, qeAPI: qeAPI}
|
||||
}
|
||||
|
||||
func (c *PoseidonChip) Poseidon(input PoseidonState) PoseidonState {
|
||||
state := input
|
||||
roundCounter := 0
|
||||
state = c.fullRounds(state, &roundCounter)
|
||||
state = c.partialRounds(state, &roundCounter)
|
||||
state = c.fullRounds(state, &roundCounter)
|
||||
state = c.FullRounds(state, &roundCounter)
|
||||
state = c.PartialRounds(state, &roundCounter)
|
||||
state = c.FullRounds(state, &roundCounter)
|
||||
return state
|
||||
}
|
||||
|
||||
func (c *PoseidonChip) HashNToMNoPad(input []F, nbOutputs int) []F {
|
||||
var state PoseidonState
|
||||
|
||||
for i := 0; i < WIDTH; i++ {
|
||||
for i := 0; i < SPONGE_WIDTH; i++ {
|
||||
state[i] = ZERO_F
|
||||
}
|
||||
|
||||
@ -69,24 +71,24 @@ func (c *PoseidonChip) HashNoPad(input []F) 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++ {
|
||||
state = c.constantLayer(state, roundCounter)
|
||||
state = c.sBoxLayer(state)
|
||||
state = c.mdsLayer(state)
|
||||
state = c.ConstantLayer(state, roundCounter)
|
||||
state = c.SBoxLayer(state)
|
||||
state = c.MdsLayer(state)
|
||||
*roundCounter += 1
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
func (c *PoseidonChip) partialRounds(state PoseidonState, roundCounter *int) PoseidonState {
|
||||
state = c.partialFirstConstantLayer(state)
|
||||
state = c.mdsPartialLayerInit(state)
|
||||
func (c *PoseidonChip) PartialRounds(state PoseidonState, roundCounter *int) PoseidonState {
|
||||
state = c.PartialFirstConstantLayer(state)
|
||||
state = c.MdsPartialLayerInit(state)
|
||||
|
||||
for i := 0; i < N_PARTIAL_ROUNDS; i++ {
|
||||
state[0] = c.sBoxMonomial(state[0])
|
||||
state[0] = c.field.Add(state[0], FAST_PARTIAL_ROUND_CONSTANTS[i]).(F)
|
||||
state = c.mdsPartialLayerFast(state, i)
|
||||
state[0] = c.SBoxMonomial(state[0])
|
||||
state[0] = c.fieldAPI.Add(state[0], FAST_PARTIAL_ROUND_CONSTANTS[i]).(F)
|
||||
state = c.MdsPartialLayerFast(state, i)
|
||||
}
|
||||
|
||||
*roundCounter += N_PARTIAL_ROUNDS
|
||||
@ -94,38 +96,64 @@ func (c *PoseidonChip) partialRounds(state PoseidonState, roundCounter *int) Pos
|
||||
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++ {
|
||||
if i < WIDTH {
|
||||
roundConstant := NewFieldElement(ALL_ROUND_CONSTANTS[i+WIDTH*(*roundCounter)])
|
||||
state[i] = c.field.Add(state[i], roundConstant).(F)
|
||||
if i < SPONGE_WIDTH {
|
||||
roundConstant := NewFieldElement(ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)])
|
||||
state[i] = c.fieldAPI.Add(state[i], roundConstant).(F)
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
func (c *PoseidonChip) sBoxLayer(state PoseidonState) PoseidonState {
|
||||
func (c *PoseidonChip) ConstantLayerExtension(state PoseidonStateExtension, roundCounter *int) PoseidonStateExtension {
|
||||
for i := 0; i < 12; i++ {
|
||||
if i < WIDTH {
|
||||
state[i] = c.sBoxMonomial(state[i])
|
||||
if i < SPONGE_WIDTH {
|
||||
roundConstant := c.qeAPI.FieldToQE(NewFieldElement(ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)]))
|
||||
state[i] = c.qeAPI.AddExtension(state[i], roundConstant)
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
func (c *PoseidonChip) sBoxMonomial(x F) F {
|
||||
x2 := c.field.Mul(x, x)
|
||||
x4 := c.field.Mul(x2, x2)
|
||||
x3 := c.field.Mul(x2, x)
|
||||
return c.field.Mul(x3, x4).(F)
|
||||
func (c *PoseidonChip) SBoxMonomial(x F) F {
|
||||
x2 := c.fieldAPI.Mul(x, x)
|
||||
x4 := c.fieldAPI.Mul(x2, x2)
|
||||
x3 := c.fieldAPI.Mul(x, x2)
|
||||
return c.fieldAPI.Mul(x3, x4).(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)
|
||||
|
||||
for i := 0; i < 12; i++ {
|
||||
if i < WIDTH {
|
||||
res1 := c.api.Mul(v[(i+r)%WIDTH], frontend.Variable(MDS_MATRIX_CIRC[i]))
|
||||
if i < SPONGE_WIDTH {
|
||||
res1 := c.api.Mul(v[(i+r)%SPONGE_WIDTH], frontend.Variable(MDS_MATRIX_CIRC[i]))
|
||||
res = c.api.Add(res, res1)
|
||||
}
|
||||
}
|
||||
@ -134,38 +162,76 @@ func (c *PoseidonChip) mdsRowShf(r int, v [WIDTH]frontend.Variable) frontend.Var
|
||||
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
|
||||
for i := 0; i < WIDTH; i++ {
|
||||
for i := 0; i < SPONGE_WIDTH; i++ {
|
||||
result[i] = NewFieldElement(0)
|
||||
}
|
||||
|
||||
var state [WIDTH]frontend.Variable
|
||||
for i := 0; i < WIDTH; i++ {
|
||||
state[i] = c.api.FromBinary(c.field.ToBinary(state_[i])...)
|
||||
var state [SPONGE_WIDTH]frontend.Variable
|
||||
for i := 0; i < SPONGE_WIDTH; i++ {
|
||||
state[i] = c.api.FromBinary(c.fieldAPI.ToBinary(state_[i])...)
|
||||
}
|
||||
|
||||
for r := 0; r < 12; r++ {
|
||||
if r < WIDTH {
|
||||
sum := c.mdsRowShf(r, state)
|
||||
if r < SPONGE_WIDTH {
|
||||
sum := c.MdsRowShf(r, state)
|
||||
bits := c.api.ToBinary(sum)
|
||||
result[r] = c.field.FromBinary(bits).(F)
|
||||
result[r] = c.fieldAPI.FromBinary(bits).(F)
|
||||
}
|
||||
}
|
||||
|
||||
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++ {
|
||||
if i < WIDTH {
|
||||
state[i] = c.field.Add(state[i], NewFieldElement(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])).(F)
|
||||
if i < SPONGE_WIDTH {
|
||||
state[i] = c.fieldAPI.Add(state[i], NewFieldElement(FAST_PARTIAL_FIRST_ROUND_CONSTANT[i])).(F)
|
||||
}
|
||||
}
|
||||
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
|
||||
for i := 0; i < 12; i++ {
|
||||
result[i] = NewFieldElement(0)
|
||||
@ -174,11 +240,11 @@ func (c *PoseidonChip) mdsPartialLayerInit(state PoseidonState) PoseidonState {
|
||||
result[0] = state[0]
|
||||
|
||||
for r := 1; r < 12; r++ {
|
||||
if r < WIDTH {
|
||||
if r < SPONGE_WIDTH {
|
||||
for d := 1; d < 12; d++ {
|
||||
if d < WIDTH {
|
||||
if d < SPONGE_WIDTH {
|
||||
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
|
||||
}
|
||||
|
||||
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)
|
||||
for i := 1; i < 12; i++ {
|
||||
if i < WIDTH {
|
||||
if i < SPONGE_WIDTH {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
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])
|
||||
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
|
||||
for i := 0; i < WIDTH; i++ {
|
||||
for i := 0; i < SPONGE_WIDTH; i++ {
|
||||
result[i] = NewFieldElement(0)
|
||||
}
|
||||
|
||||
result[0] = d.(F)
|
||||
|
||||
for i := 1; i < 12; i++ {
|
||||
if i < WIDTH {
|
||||
if i < SPONGE_WIDTH {
|
||||
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 {
|
||||
goldilocksApi := field.NewFieldAPI(api)
|
||||
qeAPI := NewQuadraticExtensionAPI(goldilocksApi, 3)
|
||||
|
||||
var input PoseidonState
|
||||
for i := 0; i < 12; i++ {
|
||||
input[i] = goldilocksApi.FromBinary(api.ToBinary(circuit.In[i], 64)).(F)
|
||||
}
|
||||
|
||||
poseidonChip := NewPoseidonChip(api, goldilocksApi)
|
||||
poseidonChip := NewPoseidonChip(api, goldilocksApi, qeAPI)
|
||||
output := poseidonChip.Poseidon(input)
|
||||
|
||||
for i := 0; i < 12; i++ {
|
||||
|
||||
@ -18,22 +18,22 @@ type TestPublicInputsHashCircuit struct {
|
||||
}
|
||||
|
||||
func (circuit *TestPublicInputsHashCircuit) Define(api frontend.API) error {
|
||||
field := NewFieldAPI(api)
|
||||
fieldAPI := NewFieldAPI(api)
|
||||
|
||||
// BN254 -> Binary(64) -> F
|
||||
var input [3]F
|
||||
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[:])
|
||||
|
||||
// Check that output is correct
|
||||
for i := 0; i < 4; i++ {
|
||||
field.AssertIsEqual(
|
||||
fieldAPI.AssertIsEqual(
|
||||
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
|
||||
}
|
||||
|
||||
func Uint64ArrayToQuadraticExtension(input []uint64) QuadraticExtension {
|
||||
return [2]F{NewFieldElement(input[0]), NewFieldElement(input[1])}
|
||||
}
|
||||
|
||||
func Uint64ArrayToQuadraticExtensionArray(input [][]uint64) []QuadraticExtension {
|
||||
var output []QuadraticExtension
|
||||
for i := 0; i < len(input); i++ {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user