Browse Source

Merge pull request #2 from succinctlabs/npward-plonky2-gates

Plonky2 Gates
main
Kevin Jue 2 years ago
committed by GitHub
parent
commit
2fbbcec029
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 12328 additions and 194 deletions
  1. +1
    -1
      benchmark.go
  2. +1
    -2
      field/quadratic_extension.go
  3. +58
    -0
      plonky2_verifier/arithmetic_gate.go
  4. +4
    -4
      plonky2_verifier/challenger.go
  5. +15
    -13
      plonky2_verifier/challenger_test.go
  6. +44
    -0
      plonky2_verifier/constant_gate.go
  7. +1
    -1
      plonky2_verifier/data/fibonacci/common_circuit_data.json
  8. +1
    -1
      plonky2_verifier/data/fibonacci/proof_with_public_inputs.json
  9. +11509
    -0
      plonky2_verifier/data/fibonacci/proof_with_public_inputs_randomized.json
  10. +1
    -1
      plonky2_verifier/data/fibonacci/verifier_only_circuit_data.json
  11. +65
    -9
      plonky2_verifier/deserialize.go
  12. +4
    -4
      plonky2_verifier/deserialize_test.go
  13. +3
    -3
      plonky2_verifier/fri.go
  14. +5
    -5
      plonky2_verifier/fri_test.go
  15. +92
    -0
      plonky2_verifier/gate.go
  16. +20
    -0
      plonky2_verifier/noop_gate.go
  17. +42
    -6
      plonky2_verifier/plonk.go
  18. +21
    -56
      plonky2_verifier/plonk_test.go
  19. +167
    -0
      plonky2_verifier/poseidon_gate.go
  20. +36
    -0
      plonky2_verifier/public_input_gate.go
  21. +8
    -8
      plonky2_verifier/quadratic_extension_test.go
  22. +17
    -0
      plonky2_verifier/selectors.go
  23. +7
    -5
      plonky2_verifier/structs.go
  24. +15
    -0
      plonky2_verifier/vars.go
  25. +6
    -6
      plonky2_verifier/verifier.go
  26. +5
    -5
      plonky2_verifier/verifier_test.go
  27. +169
    -58
      poseidon/poseidon.go
  28. +2
    -1
      poseidon/poseidon_test.go
  29. +5
    -5
      poseidon/public_inputs_hash_test.go
  30. +4
    -0
      utils/utils.go

+ 1
- 1
benchmark.go

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

plonky2_verifier/quadratic_extension.go → field/quadratic_extension.go

@ -1,8 +1,7 @@
package plonky2_verifier
package field
import (
"fmt"
. "gnark-plonky2-verifier/field"
"math/bits"
"github.com/consensys/gnark/frontend"

+ 58
- 0
plonky2_verifier/arithmetic_gate.go

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

+ 4
- 4
plonky2_verifier/challenger.go

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

+ 15
- 13
plonky2_verifier/challenger_test.go

@ -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
- 0
plonky2_verifier/constant_gate.go

@ -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
plonky2_verifier/data/fibonacci/common_circuit_data.json

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

+ 1
- 1
plonky2_verifier/data/fibonacci/proof_with_public_inputs.json
File diff suppressed because it is too large
View File


+ 11509
- 0
plonky2_verifier/data/fibonacci/proof_with_public_inputs_randomized.json
File diff suppressed because it is too large
View File


+ 1
- 1
plonky2_verifier/data/fibonacci/verifier_only_circuit_data.json

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

+ 65
- 9
plonky2_verifier/deserialize.go

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

+ 4
- 4
plonky2_verifier/deserialize_test.go

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

+ 3
- 3
plonky2_verifier/fri.go

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

+ 5
- 5
plonky2_verifier/fri_test.go

@ -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
- 0
plonky2_verifier/gate.go

@ -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
- 0
plonky2_verifier/noop_gate.go

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

+ 42
- 6
plonky2_verifier/plonk.go

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

+ 21
- 56
plonky2_verifier/plonk_test.go

@ -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)
proofChallenges := ProofChallenges{
PlonkBetas: circuit.plonkBetas,
PlonkGammas: circuit.plonkGammas,
PlonkAlphas: circuit.plonkAlphas,
PlonkZeta: circuit.plonkZeta,
}
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)
plonkChip := NewPlonkChip(api, qe, commonCircuitData)
verifierChip := NewVerifierChip(api, fieldAPI, qeAPI, poseidonChip, plonkChip, friChip)
publicInputsHash := verifierChip.GetPublicInputsHash(proofWithPis.PublicInputs)
proofChallenges := verifierChip.GetChallenges(proofWithPis, publicInputsHash, commonCircuitData, verifierOnlyCircuitData)
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
- 0
plonky2_verifier/poseidon_gate.go

@ -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
- 0
plonky2_verifier/public_input_gate.go

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

+ 8
- 8
plonky2_verifier/quadratic_extension_test.go

@ -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
- 0
plonky2_verifier/selectors.go

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

+ 7
- 5
plonky2_verifier/structs.go

@ -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
- 0
plonky2_verifier/vars.go

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

+ 6
- 6
plonky2_verifier/verifier.go

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

+ 5
- 5
plonky2_verifier/verifier_test.go

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

+ 169
- 58
poseidon/poseidon.go

@ -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 < 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) ConstantLayerExtension(state PoseidonStateExtension, roundCounter *int) PoseidonStateExtension {
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 := c.qeAPI.FieldToQE(NewFieldElement(ALL_ROUND_CONSTANTS[i+SPONGE_WIDTH*(*roundCounter)]))
state[i] = c.qeAPI.AddExtension(state[i], roundConstant)
}
}
return state
}
func (c *PoseidonChip) sBoxLayer(state PoseidonState) PoseidonState {
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) 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 < WIDTH {
state[i] = c.sBoxMonomial(state[i])
if i < SPONGE_WIDTH {
state[i] = c.SBoxMonomial(state[i])
}
}
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) 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 [WIDTH]frontend.Variable) frontend.Variable {
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) 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 {
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])
}
}

+ 2
- 1
poseidon/poseidon_test.go

@ -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++ {

+ 5
- 5
poseidon/public_inputs_hash_test.go

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

+ 4
- 0
utils/utils.go

@ -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…
Cancel
Save