-
Notifications
You must be signed in to change notification settings - Fork 127
feat: implement P256Verify glue #1739
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ivokub
wants to merge
26
commits into
feat/bls-glue
Choose a base branch
from
feat/secp256r1
base: feat/bls-glue
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 25 commits
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
e19129c
chore: gnark update
ivokub cb05285
chore: implement p256verify glue
ivokub 332f497
fix: enforce public vars
ivokub 7620614
test: add testdata generator
ivokub 119bd71
feat: implement inputfiller
ivokub dae2651
test: do not write noop test cases
ivokub d4094d3
test: implement unit tests
ivokub 2aa908b
test: include generated tests
ivokub 1ae0acc
docs: refer to test vector location
ivokub bdfa261
chore: gnark update
ivokub 0aab08d
docs: circuit size
ivokub abedf2e
fix: correct instance number calculation
ivokub 81d6377
feat: loat p256 module
ivokub 1cf0482
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub 03437cf
feat: define p256 input instance count
ivokub 9c19167
fix: ensure assignment is called
ivokub 7b78570
chore: gnark update to master
ivokub d506919
fix: column names
ivokub 8fa0879
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub 4fbdc96
chore: connect zkevm p256 module with circuit
ivokub f6d1ddf
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub 766211d
feat: implement p256 circuits serialization types in registry
ivokub 984921e
fix: export types for serialization
ivokub ca69bc9
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub 798d22c
Merge branch 'feat/bls-glue' into feat/secp256r1
ivokub 20af8d8
fix: correct order of point coordinates in inputfiller
ivokub File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| package p256verify | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/consensys/gnark/frontend" | ||
| "github.com/consensys/gnark/std/evmprecompiles" | ||
| "github.com/consensys/gnark/std/math/bitslice" | ||
| "github.com/consensys/gnark/std/math/emulated" | ||
| "github.com/consensys/gnark/std/math/emulated/emparams" | ||
| ) | ||
|
|
||
| const ( | ||
| nbBits = 128 // for large-field we use 128-bit limbs both for base and scalar fields | ||
| nbBytes = nbBits / 8 | ||
|
|
||
| nbFrLimbs = 2 // P-256 scalar field represented with 2 limbs of 128 bits | ||
| nbFpLimbs = 2 // P-256 base field represented with 2 limbs of 128 bits | ||
| nbResLimbs = 2 | ||
|
|
||
| nbG1Limbs = 2 * nbFpLimbs // (Ax, Ay) | ||
|
|
||
| nbRows = 3*nbFrLimbs + nbG1Limbs + nbResLimbs // msg | ||
| ) | ||
|
|
||
| type scalarfield = emparams.P256Fr | ||
| type basefield = emparams.P256Fp | ||
|
|
||
| var fpParams basefield | ||
| var frParams scalarfield | ||
|
|
||
| type scalarElementWizard struct { | ||
| S [nbFrLimbs]frontend.Variable | ||
| } | ||
|
|
||
| func (c scalarElementWizard) ToElement(api frontend.API, fr *emulated.Field[scalarfield]) *emulated.Element[scalarfield] { | ||
| Slimbs := make([]frontend.Variable, frParams.NbLimbs()) | ||
| Slimbs[2], Slimbs[3] = bitslice.Partition(api, c.S[0], 64, bitslice.WithNbDigits(128)) | ||
| Slimbs[0], Slimbs[1] = bitslice.Partition(api, c.S[1], 64, bitslice.WithNbDigits(128)) | ||
| return fr.NewElement(Slimbs) | ||
| } | ||
|
|
||
| type baseElementWizard struct { | ||
| P [nbFpLimbs]frontend.Variable | ||
| } | ||
|
|
||
| func (c baseElementWizard) ToElement(api frontend.API, fp *emulated.Field[basefield]) *emulated.Element[basefield] { | ||
| Plimbs := make([]frontend.Variable, fpParams.NbLimbs()) | ||
| Plimbs[2], Plimbs[3] = bitslice.Partition(api, c.P[0], 64, bitslice.WithNbDigits(128)) | ||
| Plimbs[0], Plimbs[1] = bitslice.Partition(api, c.P[1], 64, bitslice.WithNbDigits(128)) | ||
| return fp.NewElement(Plimbs) | ||
| } | ||
|
|
||
| type P256VerifyInstance struct { | ||
| H scalarElementWizard `gnark:",public"` | ||
| R scalarElementWizard `gnark:",public"` | ||
| S scalarElementWizard `gnark:",public"` | ||
| Qx baseElementWizard `gnark:",public"` | ||
| Qy baseElementWizard `gnark:",public"` | ||
| Expected [nbResLimbs]frontend.Variable `gnark:",public"` | ||
| } | ||
|
|
||
| type multiP256VerifyInstanceCircuit struct { | ||
| Instances []P256VerifyInstance | ||
| } | ||
|
|
||
| func (c *multiP256VerifyInstanceCircuit) Define(api frontend.API) error { | ||
| scalarApi, err := emulated.NewField[scalarfield](api) | ||
| if err != nil { | ||
| return fmt.Errorf("new scalar field: %w", err) | ||
| } | ||
| baseApi, err := emulated.NewField[basefield](api) | ||
| if err != nil { | ||
| return fmt.Errorf("new base field: %w", err) | ||
| } | ||
|
|
||
| nbInstances := len(c.Instances) | ||
| for i := 0; i < nbInstances; i++ { | ||
| h := c.Instances[i].H.ToElement(api, scalarApi) | ||
| r := c.Instances[i].R.ToElement(api, scalarApi) | ||
| s := c.Instances[i].S.ToElement(api, scalarApi) | ||
| qx := c.Instances[i].Qx.ToElement(api, baseApi) | ||
| qy := c.Instances[i].Qy.ToElement(api, baseApi) | ||
| // the high limb of the result is always zero | ||
| api.AssertIsEqual(c.Instances[i].Expected[0], 0) | ||
| // the expected result should be boolean | ||
| expected := c.Instances[i].Expected[1] | ||
| api.AssertIsBoolean(expected) | ||
| res := evmprecompiles.P256Verify(api, h, r, s, qx, qy) | ||
| api.AssertIsEqual(res, expected) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| func newP256VerifyCircuit(limits *Limits) frontend.Circuit { | ||
| return &multiP256VerifyInstanceCircuit{ | ||
| Instances: make([]P256VerifyInstance, limits.NbInputInstances), | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| package p256verify | ||
|
|
||
| import ( | ||
| "github.com/consensys/linea-monorepo/prover/maths/field" | ||
| "github.com/consensys/linea-monorepo/prover/protocol/dedicated/plonk" | ||
| ) | ||
|
|
||
| const ( | ||
| input_filler_key = "p256-verify-input-filler" | ||
| ) | ||
|
|
||
| func init() { | ||
| plonk.RegisterInputFiller(input_filler_key, inputFiller) | ||
| } | ||
|
|
||
| func inputFiller(circuitInstance, inputIndex int) field.Element { | ||
| datas := []string{ | ||
| // h | ||
| "0", "0", | ||
| // r | ||
| "0", "1", | ||
| // s | ||
| "0", "1", | ||
| // qx | ||
| "0x77037d812deb33a0f4a13945d898c296", | ||
| "0x6b17d1f2e12c4247f8bce6e563a440f2", | ||
| // qy | ||
| "0x2bce33576b315ececbb6406837bf51f5", | ||
| "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e16", | ||
ivokub marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // expected result | ||
| "0", "0", | ||
| } | ||
| return field.NewFromString(datas[inputIndex%nbRows]) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package p256verify | ||
|
|
||
| // Limits defines limits for P256Verify module. | ||
| type Limits struct { | ||
| // NbInputInstances is the number of P256 input instances per a single | ||
| // verification circuit. gnark circuit size approximately 709k constraints | ||
| // and in Plonk-in-Wizard (with externalized range checks) approximately | ||
| // 183k rows per instance. | ||
| NbInputInstances int | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| package p256verify | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/consensys/linea-monorepo/prover/protocol/dedicated/plonk" | ||
| "github.com/consensys/linea-monorepo/prover/protocol/ifaces" | ||
| "github.com/consensys/linea-monorepo/prover/protocol/query" | ||
| "github.com/consensys/linea-monorepo/prover/protocol/wizard" | ||
| ) | ||
|
|
||
| const ( | ||
| NAME_P256_VERIFY = "P256_VERIFY" | ||
| moduleName = "ecdata" | ||
| ROUND_NR = 0 | ||
| ) | ||
|
|
||
| func colNameFn(colName string) ifaces.ColID { | ||
| return ifaces.ColID(fmt.Sprintf("%s.%s", moduleName, colName)) | ||
| } | ||
|
|
||
| type P256VerifyDataSource struct { | ||
| ID ifaces.Column | ||
| CS ifaces.Column | ||
| Limb ifaces.Column | ||
| Index ifaces.Column | ||
| IsData ifaces.Column | ||
| IsResult ifaces.Column | ||
| } | ||
|
|
||
| func newP256VerifyDataSource(comp *wizard.CompiledIOP) *P256VerifyDataSource { | ||
| return &P256VerifyDataSource{ | ||
| ID: comp.Columns.GetHandle(colNameFn("ID")), | ||
| CS: comp.Columns.GetHandle(colNameFn("CIRCUIT_SELECTOR_P256_VERIFY")), | ||
| Limb: comp.Columns.GetHandle(colNameFn("LIMB")), | ||
| Index: comp.Columns.GetHandle(colNameFn("INDEX")), | ||
| IsData: comp.Columns.GetHandle(colNameFn("IS_P256_VERIFY_DATA")), | ||
| IsResult: comp.Columns.GetHandle(colNameFn("IS_P256_VERIFY_RESULT")), | ||
| } | ||
| } | ||
|
|
||
| type P256Verify struct { | ||
| *P256VerifyDataSource | ||
| P256VerifyGnarkData *plonk.Alignment | ||
| *Limits | ||
| } | ||
|
|
||
| func newP256Verify(_ *wizard.CompiledIOP, limits *Limits, src *P256VerifyDataSource) *P256Verify { | ||
| res := &P256Verify{ | ||
| P256VerifyDataSource: src, | ||
| Limits: limits, | ||
| } | ||
|
|
||
| return res | ||
| } | ||
|
|
||
| func (pv *P256Verify) WithCircuit(comp *wizard.CompiledIOP, options ...query.PlonkOption) *P256Verify { | ||
| nbRowsPerCircuit := nbRows * pv.Limits.NbInputInstances | ||
| maxNbCircuits := (pv.P256VerifyDataSource.CS.Size() + nbRowsPerCircuit - 1) / nbRowsPerCircuit | ||
|
|
||
| toAlign := &plonk.CircuitAlignmentInput{ | ||
| Name: fmt.Sprintf("%s_ALIGNMENT", NAME_P256_VERIFY), | ||
| Round: ROUND_NR, | ||
| DataToCircuitMask: pv.P256VerifyDataSource.CS, | ||
| DataToCircuit: pv.P256VerifyDataSource.Limb, | ||
| Circuit: newP256VerifyCircuit(pv.Limits), | ||
| NbCircuitInstances: maxNbCircuits, | ||
| PlonkOptions: options, | ||
| InputFillerKey: input_filler_key, | ||
| } | ||
| pv.P256VerifyGnarkData = plonk.DefineAlignment(comp, toAlign) | ||
| return pv | ||
| } | ||
|
|
||
| func (pv *P256Verify) Assign(run *wizard.ProverRuntime) { | ||
| if pv.P256VerifyGnarkData != nil { | ||
| pv.P256VerifyGnarkData.Assign(run) | ||
| } | ||
| } | ||
|
|
||
| func NewP256VerifyZkEvm(comp *wizard.CompiledIOP, limits *Limits) *P256Verify { | ||
| return newP256Verify(comp, limits, newP256VerifyDataSource(comp)). | ||
| WithCircuit(comp, query.PlonkRangeCheckOption(16, 6, true)) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| package p256verify | ||
|
|
||
| import ( | ||
| "errors" | ||
| "os" | ||
| "testing" | ||
|
|
||
| "github.com/consensys/linea-monorepo/prover/protocol/compiler/dummy" | ||
| "github.com/consensys/linea-monorepo/prover/protocol/query" | ||
| "github.com/consensys/linea-monorepo/prover/protocol/wizard" | ||
| "github.com/consensys/linea-monorepo/prover/utils/csvtraces" | ||
| ) | ||
|
|
||
| func testP256Verify(t *testing.T, withCircuit bool, path string, limits *Limits) { | ||
| f, err := os.Open(path) | ||
| if errors.Is(err, os.ErrNotExist) { | ||
| t.Fatal("csv file does not exist, please run `go generate` to generate the test data") | ||
| } | ||
| if err != nil { | ||
| t.Fatal("failed to open csv file", err) | ||
| } | ||
| defer f.Close() | ||
| ct, err := csvtraces.NewCsvTrace(f) | ||
| if err != nil { | ||
| t.Fatal("failed to create csv trace", err) | ||
| } | ||
| var p256Verify *P256Verify | ||
| cmp := wizard.Compile( | ||
| func(b *wizard.Builder) { | ||
| p256VerifySource := &P256VerifyDataSource{ | ||
| ID: ct.GetCommit(b, "ID"), | ||
| CS: ct.GetCommit(b, "CIRCUIT_SELECTOR_P256_VERIFY"), | ||
| Limb: ct.GetCommit(b, "LIMB"), | ||
| Index: ct.GetCommit(b, "INDEX"), | ||
| IsData: ct.GetCommit(b, "DATA_P256_VERIFY_FLAG"), | ||
| IsResult: ct.GetCommit(b, "RSLT_P256_VERIFY_FLAG"), | ||
| } | ||
| p256Verify = newP256Verify(b.CompiledIOP, limits, p256VerifySource) | ||
| if withCircuit { | ||
| p256Verify = p256Verify. | ||
| WithCircuit(b.CompiledIOP, query.PlonkRangeCheckOption(16, 6, true)) | ||
| } | ||
| }, | ||
| dummy.Compile, | ||
| ) | ||
|
|
||
| proof := wizard.Prove(cmp, | ||
| func(run *wizard.ProverRuntime) { | ||
| ct.Assign(run, "ID", "CIRCUIT_SELECTOR_P256_VERIFY", "LIMB", "INDEX", "DATA_P256_VERIFY_FLAG", "RSLT_P256_VERIFY_FLAG") | ||
| p256Verify.Assign(run) | ||
| }) | ||
|
|
||
| if err := wizard.Verify(cmp, proof); err != nil { | ||
| t.Fatal("proof failed", err) | ||
| } | ||
| t.Log("proof succeeded") | ||
| } | ||
|
|
||
| func TestP256VerifyNoCircuit(t *testing.T) { | ||
| limits := &Limits{ | ||
| NbInputInstances: 6, | ||
| } | ||
| testP256Verify(t, false, "testdata/p256verify_inputs.csv", limits) | ||
| } | ||
|
|
||
| func TestP256VerifyWithCircuit(t *testing.T) { | ||
| limits := &Limits{ | ||
| NbInputInstances: 6, | ||
| } | ||
| testP256Verify(t, true, "testdata/p256verify_inputs.csv", limits) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| package p256verify | ||
|
|
||
| // Type alias for serialization registration | ||
| type MultiP256VerifyInstanceCircuit = multiP256VerifyInstanceCircuit |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.