From 2b2364102f03cbbc4a5e0cab9d4869551a400539 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Mon, 20 May 2024 22:40:53 +0200 Subject: [PATCH 01/22] feat: addition of export options for solidity verifiers --- backend/plonk/bn254/verify.go | 22 +++++++++++++++++++--- backend/solidity/solidity.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 backend/solidity/solidity.go diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 6f70830650..3120d480b6 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gnark DO NOT EDIT - package plonk import ( @@ -35,6 +33,7 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/kzg" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/solidity" "github.com/consensys/gnark/logger" ) @@ -369,7 +368,7 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu // See https://github.com/ConsenSys/gnark-tests for example usage. // // Code has not been audited and is provided as-is, we make no guarantees or warranties to its safety and reliability. -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { funcMap := template.FuncMap{ "hex": func(i int) string { return fmt.Sprintf("0x%x", i) @@ -401,5 +400,22 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { if err != nil { return err } + + cfg, err := solidity.NewExportConfig(exportOpts...) + return t.Execute(w, vk) } + +// verifyingKeyToExport stores the data needed to verify a proof: +// * The commitment scheme +// * Commitments of ql prepended with as many ones as there are public inputs +// * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs +// * Commitments to S1, S2, S3 +type VerifyingKeyToExport struct { + + // Cfg contains solidity specific customisation + Cfg solidity.ExportConfig + + // Copy of the verifying key + Vk VerifyingKey +} diff --git a/backend/solidity/solidity.go b/backend/solidity/solidity.go new file mode 100644 index 0000000000..c8b062105d --- /dev/null +++ b/backend/solidity/solidity.go @@ -0,0 +1,33 @@ +package solidity + +// ExportOption defines option for altering the behavior of the prover in +// Prove, ReadAndProve and IsSolved methods. See the descriptions of functions +// returning instances of this type for implemented options. +type ExportOption func(*ExportConfig) error + +// ExportConfig is the configuration for the prover with the options applied. +type ExportConfig struct { + PragmaVersion string +} + +// NewExportConfig returns a default ExportConfig with given export options opts +// applied. +func NewExportConfig(opts ...ExportOption) (ExportConfig, error) { + config := ExportConfig{ + PragmaVersion: "0.8.24", + } + for _, option := range opts { + if err := option(&config); err != nil { + return ExportConfig{}, err + } + } + return config, nil +} + +// WithPragmaVerions changes the pragma version used in the solidit verifier. +func WithPragmaVerions(version string) ExportOption { + return func(cfg *ExportConfig) error { + cfg.PragmaVersion = version + return nil + } +} From 65ea183d6058f8c9781ff4c0e6b88878e545d4ac Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Mon, 20 May 2024 22:54:52 +0200 Subject: [PATCH 02/22] feat: modified signature of ExportSolidity in template --- .../zkpschemes/plonk/plonk.verify.go.tmpl | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index 3f509fdfee..d37fde4dbb 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -354,13 +354,13 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu // See https://github.com/ConsenSys/gnark-tests for example usage. // // Code has not been audited and is provided as-is, we make no guarantees or warranties to its safety and reliability. -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { funcMap := template.FuncMap{ "hex": func(i int) string { return fmt.Sprintf("0x%x", i) }, "mul": func(a, b int) int { - return a*b + return a * b }, "inc": func(i int) int { return i + 1 @@ -386,12 +386,33 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { if err != nil { return err } - return t.Execute(w, vk) + + cfg, err := solidity.NewExportConfig(exportOpts...) + if err != nil { + return err + } + + vkToExport := VerifyingKeyToExport{ + Cfg: cfg, + Vk: *vk, + } + return t.Execute(w, vkToExport) +} + +// verifyingKeyToExport stores a Verifying key and a configuration object used for +// generating the solidity verifier. +type VerifyingKeyToExport struct { + + // Cfg contains solidity specific customisation + Cfg solidity.ExportConfig + + // Copy of the verifying key + Vk VerifyingKey } {{else}} // ExportSolidity not implemented for {{.Curve}} -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } {{end}} \ No newline at end of file From d49db77687642e5943fe99195adb231144b567a1 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Mon, 20 May 2024 22:57:41 +0200 Subject: [PATCH 03/22] fix: added missing import in template --- .../backend/template/zkpschemes/plonk/plonk.verify.go.tmpl | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index d37fde4dbb..a2e2235fac 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -7,6 +7,7 @@ import ( "text/template" {{- end }} "time" + "github.com/consensys/gnark/backend/solidity" "github.com/consensys/gnark-crypto/ecc" {{ template "import_curve" . }} From 5f172c91631517569ced5e5e3514cbc1cce2cb50 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Mon, 20 May 2024 23:09:19 +0200 Subject: [PATCH 04/22] feat: code gen --- backend/plonk/bls12-377/verify.go | 3 ++- backend/plonk/bls12-381/verify.go | 3 ++- backend/plonk/bls24-315/verify.go | 3 ++- backend/plonk/bls24-317/verify.go | 3 ++- backend/plonk/bn254/verify.go | 20 +++++++++++++------- backend/plonk/bw6-633/verify.go | 3 ++- backend/plonk/bw6-761/verify.go | 3 ++- backend/plonk/plonk.go | 3 ++- 8 files changed, 27 insertions(+), 14 deletions(-) diff --git a/backend/plonk/bls12-377/verify.go b/backend/plonk/bls12-377/verify.go index 1d5ae92d42..c3df8fc8c0 100644 --- a/backend/plonk/bls12-377/verify.go +++ b/backend/plonk/bls12-377/verify.go @@ -22,6 +22,7 @@ import ( "io" "math/big" + "github.com/consensys/gnark/backend/solidity" "time" "github.com/consensys/gnark-crypto/ecc" @@ -365,6 +366,6 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu } // ExportSolidity not implemented for BLS12-377 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/plonk/bls12-381/verify.go b/backend/plonk/bls12-381/verify.go index d16ed249fa..9fa93ce23a 100644 --- a/backend/plonk/bls12-381/verify.go +++ b/backend/plonk/bls12-381/verify.go @@ -22,6 +22,7 @@ import ( "io" "math/big" + "github.com/consensys/gnark/backend/solidity" "time" "github.com/consensys/gnark-crypto/ecc" @@ -365,6 +366,6 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu } // ExportSolidity not implemented for BLS12-381 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/plonk/bls24-315/verify.go b/backend/plonk/bls24-315/verify.go index 2b4089f3b6..3b1385b347 100644 --- a/backend/plonk/bls24-315/verify.go +++ b/backend/plonk/bls24-315/verify.go @@ -22,6 +22,7 @@ import ( "io" "math/big" + "github.com/consensys/gnark/backend/solidity" "time" "github.com/consensys/gnark-crypto/ecc" @@ -365,6 +366,6 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu } // ExportSolidity not implemented for BLS24-315 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/plonk/bls24-317/verify.go b/backend/plonk/bls24-317/verify.go index 9e4589b53f..c625bf83d5 100644 --- a/backend/plonk/bls24-317/verify.go +++ b/backend/plonk/bls24-317/verify.go @@ -22,6 +22,7 @@ import ( "io" "math/big" + "github.com/consensys/gnark/backend/solidity" "time" "github.com/consensys/gnark-crypto/ecc" @@ -365,6 +366,6 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu } // ExportSolidity not implemented for BLS24-317 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 3120d480b6..2d0bf5a770 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -12,11 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Code generated by gnark DO NOT EDIT + package plonk import ( "errors" "fmt" + "github.com/consensys/gnark/backend/solidity" "io" "math/big" "text/template" @@ -33,7 +36,6 @@ import ( "github.com/consensys/gnark-crypto/ecc/bn254/kzg" fiatshamir "github.com/consensys/gnark-crypto/fiat-shamir" "github.com/consensys/gnark/backend" - "github.com/consensys/gnark/backend/solidity" "github.com/consensys/gnark/logger" ) @@ -402,15 +404,19 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.Expor } cfg, err := solidity.NewExportConfig(exportOpts...) + if err != nil { + return err + } - return t.Execute(w, vk) + vkToExport := VerifyingKeyToExport{ + Cfg: cfg, + Vk: *vk, + } + return t.Execute(w, vkToExport) } -// verifyingKeyToExport stores the data needed to verify a proof: -// * The commitment scheme -// * Commitments of ql prepended with as many ones as there are public inputs -// * Commitments of qr, qm, qo, qk prepended with as many zeroes as there are public inputs -// * Commitments to S1, S2, S3 +// verifyingKeyToExport stores a Verifying key and a configuration object used for +// generating the solidity verifier. type VerifyingKeyToExport struct { // Cfg contains solidity specific customisation diff --git a/backend/plonk/bw6-633/verify.go b/backend/plonk/bw6-633/verify.go index d7d09efba1..831c11ec18 100644 --- a/backend/plonk/bw6-633/verify.go +++ b/backend/plonk/bw6-633/verify.go @@ -22,6 +22,7 @@ import ( "io" "math/big" + "github.com/consensys/gnark/backend/solidity" "time" "github.com/consensys/gnark-crypto/ecc" @@ -365,6 +366,6 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu } // ExportSolidity not implemented for BW6-633 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/plonk/bw6-761/verify.go b/backend/plonk/bw6-761/verify.go index 7709c1d0ab..c9f25260e5 100644 --- a/backend/plonk/bw6-761/verify.go +++ b/backend/plonk/bw6-761/verify.go @@ -22,6 +22,7 @@ import ( "io" "math/big" + "github.com/consensys/gnark/backend/solidity" "time" "github.com/consensys/gnark-crypto/ecc" @@ -365,6 +366,6 @@ func deriveRandomness(fs *fiatshamir.Transcript, challenge string, points ...*cu } // ExportSolidity not implemented for BW6-761 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/plonk/plonk.go b/backend/plonk/plonk.go index 1b615664ee..3b190658f2 100644 --- a/backend/plonk/plonk.go +++ b/backend/plonk/plonk.go @@ -27,6 +27,7 @@ import ( "github.com/consensys/gnark/backend" "github.com/consensys/gnark/constraint" + "github.com/consensys/gnark/backend/solidity" "github.com/consensys/gnark/backend/witness" cs_bls12377 "github.com/consensys/gnark/constraint/bls12-377" cs_bls12381 "github.com/consensys/gnark/constraint/bls12-381" @@ -92,7 +93,7 @@ type VerifyingKey interface { gnarkio.WriterRawTo gnarkio.UnsafeReaderFrom NbPublicWitness() int // number of elements expected in the public witness - ExportSolidity(w io.Writer) error + ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error } // Setup prepares the public data associated to a circuit + public inputs. From b9a340cd9e3bd60e3e3f76ddedbd4761a7872ae9 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Mon, 20 May 2024 23:16:47 +0200 Subject: [PATCH 05/22] feat: modified plonk template --- backend/plonk/bn254/solidity.go | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/backend/plonk/bn254/solidity.go b/backend/plonk/bn254/solidity.go index 08d0b47113..149a43f912 100644 --- a/backend/plonk/bn254/solidity.go +++ b/backend/plonk/bn254/solidity.go @@ -18,49 +18,49 @@ const tmplSolidityVerifier = `// SPDX-License-Identifier: Apache-2.0 // Code generated by gnark DO NOT EDIT -pragma solidity ^0.8.19; +pragma solidity {{ .Cfg.PragmaVersion }}; contract PlonkVerifier { uint256 private constant R_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617; uint256 private constant R_MOD_MINUS_ONE = 21888242871839275222246405745257275088548364400416034343698204186575808495616; uint256 private constant P_MOD = 21888242871839275222246405745257275088696311157297823662689037894645226208583; - {{ range $index, $element := .Kzg.G2 }} + {{ range $index, $element := .Vk.Kzg.G2 }} uint256 private constant G2_SRS_{{ $index }}_X_0 = {{ (fpstr $element.X.A1) }}; uint256 private constant G2_SRS_{{ $index }}_X_1 = {{ (fpstr $element.X.A0) }}; uint256 private constant G2_SRS_{{ $index }}_Y_0 = {{ (fpstr $element.Y.A1) }}; uint256 private constant G2_SRS_{{ $index }}_Y_1 = {{ (fpstr $element.Y.A0) }}; {{ end }} - uint256 private constant G1_SRS_X = {{ fpstr .Kzg.G1.X }}; - uint256 private constant G1_SRS_Y = {{ fpstr .Kzg.G1.Y }}; + uint256 private constant G1_SRS_X = {{ fpstr .Vk.Kzg.G1.X }}; + uint256 private constant G1_SRS_Y = {{ fpstr .Vk.Kzg.G1.Y }}; // ----------------------- vk --------------------- - uint256 private constant VK_NB_PUBLIC_INPUTS = {{ .NbPublicVariables }}; - uint256 private constant VK_DOMAIN_SIZE = {{ .Size }}; - uint256 private constant VK_INV_DOMAIN_SIZE = {{ (frstr .SizeInv) }}; - uint256 private constant VK_OMEGA = {{ (frstr .Generator) }}; - uint256 private constant VK_QL_COM_X = {{ (fpstr .Ql.X) }}; - uint256 private constant VK_QL_COM_Y = {{ (fpstr .Ql.Y) }}; - uint256 private constant VK_QR_COM_X = {{ (fpstr .Qr.X) }}; - uint256 private constant VK_QR_COM_Y = {{ (fpstr .Qr.Y) }}; - uint256 private constant VK_QM_COM_X = {{ (fpstr .Qm.X) }}; - uint256 private constant VK_QM_COM_Y = {{ (fpstr .Qm.Y) }}; - uint256 private constant VK_QO_COM_X = {{ (fpstr .Qo.X) }}; - uint256 private constant VK_QO_COM_Y = {{ (fpstr .Qo.Y) }}; - uint256 private constant VK_QK_COM_X = {{ (fpstr .Qk.X) }}; - uint256 private constant VK_QK_COM_Y = {{ (fpstr .Qk.Y) }}; - {{ range $index, $element := .S }} + uint256 private constant VK_NB_PUBLIC_INPUTS = {{ .Vk.NbPublicVariables }}; + uint256 private constant VK_DOMAIN_SIZE = {{ .Vk.Size }}; + uint256 private constant VK_INV_DOMAIN_SIZE = {{ (frstr .Vk.SizeInv) }}; + uint256 private constant VK_OMEGA = {{ (frstr .Vk.Generator) }}; + uint256 private constant VK_QL_COM_X = {{ (fpstr .Vk.Ql.X) }}; + uint256 private constant VK_QL_COM_Y = {{ (fpstr .Vk.Ql.Y) }}; + uint256 private constant VK_QR_COM_X = {{ (fpstr .Vk.Qr.X) }}; + uint256 private constant VK_QR_COM_Y = {{ (fpstr .Vk.Qr.Y) }}; + uint256 private constant VK_QM_COM_X = {{ (fpstr .Vk.Qm.X) }}; + uint256 private constant VK_QM_COM_Y = {{ (fpstr .Vk.Qm.Y) }}; + uint256 private constant VK_QO_COM_X = {{ (fpstr .Vk.Qo.X) }}; + uint256 private constant VK_QO_COM_Y = {{ (fpstr .Vk.Qo.Y) }}; + uint256 private constant VK_QK_COM_X = {{ (fpstr .Vk.Qk.X) }}; + uint256 private constant VK_QK_COM_Y = {{ (fpstr .Vk.Qk.Y) }}; + {{ range $index, $element := .Vk.S }} uint256 private constant VK_S{{ inc $index }}_COM_X = {{ (fpstr $element.X) }}; uint256 private constant VK_S{{ inc $index }}_COM_Y = {{ (fpstr $element.Y) }}; {{ end }} - uint256 private constant VK_COSET_SHIFT = 5; + uint256 private constant VK_COSET_SHIFT = {{ .Vk.CosetShift }}; - {{ range $index, $element := .Qcp}} + {{ range $index, $element := .Vk.Qcp}} uint256 private constant VK_QCP_{{ $index }}_X = {{ (fpstr $element.X) }}; uint256 private constant VK_QCP_{{ $index }}_Y = {{ (fpstr $element.Y) }}; {{ end }} - {{ range $index, $element := .CommitmentConstraintIndexes -}} + {{ range $index, $element := .Vk.CommitmentConstraintIndexes -}} uint256 private constant VK_INDEX_COMMIT_API_{{ $index }} = {{ $element }}; {{ end -}} uint256 private constant VK_NB_CUSTOM_GATES = {{ len .CommitmentConstraintIndexes }}; From c2a4a8e6bae0132eb44955ced5127ea1d7c1bec1 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 21 May 2024 15:44:16 +0200 Subject: [PATCH 06/22] fix: fixed solidity template --- backend/plonk/bn254/solidity.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/backend/plonk/bn254/solidity.go b/backend/plonk/bn254/solidity.go index 149a43f912..b4c8361400 100644 --- a/backend/plonk/bn254/solidity.go +++ b/backend/plonk/bn254/solidity.go @@ -53,7 +53,7 @@ contract PlonkVerifier { uint256 private constant VK_S{{ inc $index }}_COM_X = {{ (fpstr $element.X) }}; uint256 private constant VK_S{{ inc $index }}_COM_Y = {{ (fpstr $element.Y) }}; {{ end }} - uint256 private constant VK_COSET_SHIFT = {{ .Vk.CosetShift }}; + uint256 private constant VK_COSET_SHIFT = {{ frstr .Vk.CosetShift }}; {{ range $index, $element := .Vk.Qcp}} uint256 private constant VK_QCP_{{ $index }}_X = {{ (fpstr $element.X) }}; @@ -63,7 +63,7 @@ contract PlonkVerifier { {{ range $index, $element := .Vk.CommitmentConstraintIndexes -}} uint256 private constant VK_INDEX_COMMIT_API_{{ $index }} = {{ $element }}; {{ end -}} - uint256 private constant VK_NB_CUSTOM_GATES = {{ len .CommitmentConstraintIndexes }}; + uint256 private constant VK_NB_CUSTOM_GATES = {{ len .Vk.CommitmentConstraintIndexes }}; // ------------------------------------------------ @@ -107,7 +107,7 @@ contract PlonkVerifier { uint256 private constant PROOF_OPENING_AT_ZETA_OMEGA_Y = {{ hex $offset }};{{ $offset = add $offset 0x20}} uint256 private constant PROOF_OPENING_QCP_AT_ZETA = {{ hex $offset }}; - uint256 private constant PROOF_BSB_COMMITMENTS = {{ hex (add $offset (mul (len .CommitmentConstraintIndexes) 32 ) )}}; + uint256 private constant PROOF_BSB_COMMITMENTS = {{ hex (add $offset (mul (len .Vk.CommitmentConstraintIndexes) 32 ) )}}; // -> next part of proof is // [ openings_selector_commits || commitments_wires_commit_api] @@ -146,7 +146,7 @@ contract PlonkVerifier { // -------- errors uint256 private constant ERROR_STRING_ID = 0x08c379a000000000000000000000000000000000000000000000000000000000; // selector for function Error(string) - {{ if (gt (len .CommitmentConstraintIndexes) 0 )}} + {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} // -------- utils (for hash_fr) uint256 private constant HASH_FR_BB = 340282366920938463463374607431768211456; // 2**128 uint256 private constant HASH_FR_ZERO_UINT256 = 0; @@ -195,7 +195,7 @@ contract PlonkVerifier { // public inputs contribution let l_pi := sum_pi_wo_api_commit(public_inputs.offset, public_inputs.length, freeMem) - {{ if (gt (len .CommitmentConstraintIndexes) 0 ) -}} + {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 ) -}} let l_pi_commit := sum_pi_commit(proof.offset, public_inputs.length, freeMem) l_pi := addmod(l_pi_commit, l_pi, R_MOD) {{ end -}} @@ -424,12 +424,12 @@ contract PlonkVerifier { mstore(add(mPtr, 0x1c0), VK_QO_COM_Y) mstore(add(mPtr, 0x1e0), VK_QK_COM_X) mstore(add(mPtr, 0x200), VK_QK_COM_Y) - {{ range $index, $element := .CommitmentConstraintIndexes}} + {{ range $index, $element := .Vk.CommitmentConstraintIndexes}} mstore(add(mPtr, {{ hex (add 544 (mul $index 64)) }}), VK_QCP_{{ $index }}_X) mstore(add(mPtr, {{ hex (add 576 (mul $index 64)) }}), VK_QCP_{{ $index }}_Y) {{ end }} // public inputs - let _mPtr := add(mPtr, {{ hex (add (mul (len .CommitmentConstraintIndexes) 64) 544) }}) + let _mPtr := add(mPtr, {{ hex (add (mul (len .Vk.CommitmentConstraintIndexes) 64) 544) }}) let size_pi_in_bytes := mul(nb_pi, 0x20) calldatacopy(_mPtr, pi, size_pi_in_bytes) _mPtr := add(_mPtr, size_pi_in_bytes) @@ -444,7 +444,7 @@ contract PlonkVerifier { // + nb_public_inputs*0x20 // + nb_custom gates*0x40 let size := add(0x2c5, size_pi_in_bytes) - {{ if (gt (len .CommitmentConstraintIndexes) 0 )}} + {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} size := add(size, mul(VK_NB_CUSTOM_GATES, 0x40)) {{ end -}} let l_success := staticcall(gas(), 0x2, add(mPtr, 0x1b), size, mPtr, 0x20) //0x1b -> 000.."gamma" @@ -494,7 +494,7 @@ contract PlonkVerifier { let _mPtr := add(mPtr, 0x20) mstore(_mPtr, beta_not_reduced) _mPtr := add(_mPtr, 0x20) - {{ if (gt (len .CommitmentConstraintIndexes) 0 )}} + {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} // Bsb22Commitments let proof_bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS) let size_bsb_commitments := mul(0x40, VK_NB_CUSTOM_GATES) @@ -621,7 +621,7 @@ contract PlonkVerifier { } } - {{ if (gt (len .CommitmentConstraintIndexes) 0 )}} + {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} /// Public inputs (the ones coming from the custom gate) contribution /// @param aproof pointer to the proof /// @param nb_public_inputs number of public inputs @@ -637,7 +637,7 @@ contract PlonkVerifier { let h_fr, ith_lagrange - {{ range $index, $element := .CommitmentConstraintIndexes}} + {{ range $index, $element := .Vk.CommitmentConstraintIndexes}} h_fr := hash_fr(calldataload(p), calldataload(add(p, 0x20)), mPtr) ith_lagrange := compute_ith_lagrange_at_z(z, zpnmo, add(nb_public_inputs, VK_INDEX_COMMIT_API_{{ $index }}), mPtr) pi_commit := addmod(pi_commit, mulmod(h_fr, ith_lagrange, R_MOD), R_MOD) @@ -935,9 +935,9 @@ contract PlonkVerifier { point_acc_mul(state_folded_digests, mPtr, acc_gamma, mPtr40) fr_acc_mul_calldata(add(state, STATE_FOLDED_CLAIMED_VALUES), add(aproof, PROOF_S2_AT_ZETA), acc_gamma) - {{- if (gt (len .CommitmentConstraintIndexes) 0 ) }} + {{- if (gt (len .Vk.CommitmentConstraintIndexes) 0 ) }} let poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA) - {{ range $index, $element := .CommitmentConstraintIndexes }} + {{ range $index, $element := .Vk.CommitmentConstraintIndexes }} acc_gamma := mulmod(acc_gamma, l_gamma_kzg, R_MOD) mstore(mPtr, VK_QCP_{{ $index }}_X) mstore(mPtr20, VK_QCP_{{ $index }}_Y) @@ -979,7 +979,7 @@ contract PlonkVerifier { let offset := 0x1c0 - {{ range $index, $element := .CommitmentConstraintIndexes -}} + {{ range $index, $element := .Vk.CommitmentConstraintIndexes -}} mstore(add(mPtr,offset), VK_QCP_{{ $index }}_X) mstore(add(mPtr,add(offset, 0x20)), VK_QCP_{{ $index }}_Y) offset := add(offset, 0x40) @@ -994,7 +994,7 @@ contract PlonkVerifier { let _mPtr := add(mPtr, add(offset, 0xc0)) - {{ if (gt (len .CommitmentConstraintIndexes) 0 )}} + {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} let _poqaz := add(aproof, PROOF_OPENING_QCP_AT_ZETA) calldatacopy(_mPtr, _poqaz, mul(VK_NB_CUSTOM_GATES, 0x20)) _mPtr := add(_mPtr, mul(VK_NB_CUSTOM_GATES, 0x20)) @@ -1058,7 +1058,7 @@ contract PlonkVerifier { add(mPtr, 0x40) ) - {{ if (gt (len .CommitmentConstraintIndexes) 0 )}} + {{ if (gt (len .Vk.CommitmentConstraintIndexes) 0 )}} let qcp_opening_at_zeta := add(aproof, PROOF_OPENING_QCP_AT_ZETA) let bsb_commitments := add(aproof, PROOF_BSB_COMMITMENTS) for { From fe94e0dbdb77b0f61332903820200bb9cd135c53 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 21 May 2024 17:12:03 +0200 Subject: [PATCH 07/22] feat: code gen --- .../template/zkpschemes/groth16/groth16.verify.go.tmpl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index 257359beea..9881d1a3d1 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -2,6 +2,7 @@ import ( "errors" "fmt" "io" + "github.com/consensys/gnark/backend/solidity" {{- if eq .Curve "BN254"}} "text/template" {{- end}} @@ -130,7 +131,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...bac // This is an experimental feature and gnark solidity generator as not been thoroughly tested. // // See https://github.com/ConsenSys/gnark-tests for example usage. -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { helpers := template.FuncMap{ "sum": func(a, b int) int { return a + b @@ -183,7 +184,7 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { {{else}} // ExportSolidity not implemented for {{.Curve}} -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } {{end}} From 735fd2b19ca4eddc579106c52be16cefe034e85f Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 21 May 2024 17:12:59 +0200 Subject: [PATCH 08/22] feat: code gen --- backend/groth16/bls12-377/verify.go | 3 ++- backend/groth16/bls12-381/verify.go | 3 ++- backend/groth16/bls24-315/verify.go | 3 ++- backend/groth16/bls24-317/verify.go | 3 ++- backend/groth16/bn254/verify.go | 29 +++++++++++++++++++++++++---- backend/groth16/bw6-633/verify.go | 3 ++- backend/groth16/bw6-761/verify.go | 3 ++- 7 files changed, 37 insertions(+), 10 deletions(-) diff --git a/backend/groth16/bls12-377/verify.go b/backend/groth16/bls12-377/verify.go index 867ce56708..b8ac2625b6 100644 --- a/backend/groth16/bls12-377/verify.go +++ b/backend/groth16/bls12-377/verify.go @@ -19,6 +19,7 @@ package groth16 import ( "errors" "fmt" + "github.com/consensys/gnark/backend/solidity" "io" "time" @@ -140,6 +141,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...bac } // ExportSolidity not implemented for BLS12-377 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/groth16/bls12-381/verify.go b/backend/groth16/bls12-381/verify.go index 0bf293f1d3..f6a266807e 100644 --- a/backend/groth16/bls12-381/verify.go +++ b/backend/groth16/bls12-381/verify.go @@ -19,6 +19,7 @@ package groth16 import ( "errors" "fmt" + "github.com/consensys/gnark/backend/solidity" "io" "time" @@ -140,6 +141,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...bac } // ExportSolidity not implemented for BLS12-381 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/groth16/bls24-315/verify.go b/backend/groth16/bls24-315/verify.go index 2c95a54d0d..98a21fb52d 100644 --- a/backend/groth16/bls24-315/verify.go +++ b/backend/groth16/bls24-315/verify.go @@ -19,6 +19,7 @@ package groth16 import ( "errors" "fmt" + "github.com/consensys/gnark/backend/solidity" "io" "time" @@ -140,6 +141,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...bac } // ExportSolidity not implemented for BLS24-315 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/groth16/bls24-317/verify.go b/backend/groth16/bls24-317/verify.go index f4c92dc687..cbaa84e45a 100644 --- a/backend/groth16/bls24-317/verify.go +++ b/backend/groth16/bls24-317/verify.go @@ -19,6 +19,7 @@ package groth16 import ( "errors" "fmt" + "github.com/consensys/gnark/backend/solidity" "io" "time" @@ -140,6 +141,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...bac } // ExportSolidity not implemented for BLS24-317 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index f8e0927625..f3c7da2e1e 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -12,8 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gnark DO NOT EDIT - package groth16 import ( @@ -23,6 +21,8 @@ import ( "text/template" "time" + "github.com/consensys/gnark/backend/solidity" + "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" @@ -144,7 +144,7 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...bac // This is an experimental feature and gnark solidity generator as not been thoroughly tested. // // See https://github.com/ConsenSys/gnark-tests for example usage. -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { helpers := template.FuncMap{ "sum": func(a, b int) int { return a + b @@ -184,8 +184,18 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { vk.G2.Gamma, vk.G2.gammaNeg = vk.G2.gammaNeg, vk.G2.Gamma vk.G2.Delta, vk.G2.deltaNeg = vk.G2.deltaNeg, vk.G2.Delta + cfg, err := solidity.NewExportConfig(exportOpts...) + if err != nil { + return err + } + + vkToExport := VerifyingKeyToExport{ + Cfg: cfg, + Vk: *vk, + } + // execute template - err = tmpl.Execute(w, vk) + err = tmpl.Execute(w, vkToExport) // restore Beta, Gamma and Delta vk.G2.Beta = beta @@ -194,3 +204,14 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { return err } + +// verifyingKeyToExport stores a Verifying key and a configuration object used for +// generating the solidity verifier. +type VerifyingKeyToExport struct { + + // Cfg contains solidity specific customisation + Cfg solidity.ExportConfig + + // Copy of the verifying key + Vk VerifyingKey +} diff --git a/backend/groth16/bw6-633/verify.go b/backend/groth16/bw6-633/verify.go index 3bfaaffd39..e6d270455d 100644 --- a/backend/groth16/bw6-633/verify.go +++ b/backend/groth16/bw6-633/verify.go @@ -19,6 +19,7 @@ package groth16 import ( "errors" "fmt" + "github.com/consensys/gnark/backend/solidity" "io" "time" @@ -140,6 +141,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...bac } // ExportSolidity not implemented for BW6-633 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } diff --git a/backend/groth16/bw6-761/verify.go b/backend/groth16/bw6-761/verify.go index f08d631d62..3b81eaa85b 100644 --- a/backend/groth16/bw6-761/verify.go +++ b/backend/groth16/bw6-761/verify.go @@ -19,6 +19,7 @@ package groth16 import ( "errors" "fmt" + "github.com/consensys/gnark/backend/solidity" "io" "time" @@ -140,6 +141,6 @@ func Verify(proof *Proof, vk *VerifyingKey, publicWitness fr.Vector, opts ...bac } // ExportSolidity not implemented for BW6-761 -func (vk *VerifyingKey) ExportSolidity(w io.Writer) error { +func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { return errors.New("not implemented") } From b5511af0b4c4c55c69b0fe9e912099a25bdf5510 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 21 May 2024 17:13:18 +0200 Subject: [PATCH 09/22] feat: change signature ExportSolidity groth16 --- backend/groth16/groth16.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/groth16/groth16.go b/backend/groth16/groth16.go index 3b542f2afa..56129c40db 100644 --- a/backend/groth16/groth16.go +++ b/backend/groth16/groth16.go @@ -24,6 +24,7 @@ import ( "github.com/consensys/gnark-crypto/ecc" "github.com/consensys/gnark/backend" + "github.com/consensys/gnark/backend/solidity" "github.com/consensys/gnark/backend/witness" "github.com/consensys/gnark/constraint" cs_bls12377 "github.com/consensys/gnark/constraint/bls12-377" @@ -105,7 +106,7 @@ type VerifyingKey interface { // ExportSolidity writes a solidity Verifier contract from the VerifyingKey // this will return an error if not supported on the CurveID() - ExportSolidity(w io.Writer) error + ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error IsDifferent(interface{}) bool } From c163948b7f5f0072354daf0007a2a1c6ccc0fd89 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 21 May 2024 17:13:31 +0200 Subject: [PATCH 10/22] feat: update template --- .../zkpschemes/groth16/groth16.verify.go.tmpl | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index 9881d1a3d1..2d6f85f1d3 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -171,8 +171,18 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.Expor vk.G2.Gamma, vk.G2.gammaNeg = vk.G2.gammaNeg, vk.G2.Gamma vk.G2.Delta, vk.G2.deltaNeg = vk.G2.deltaNeg, vk.G2.Delta + cfg, err := solidity.NewExportConfig(exportOpts...) + if err != nil { + return err + } + + vkToExport := VerifyingKeyToExport{ + Cfg: cfg, + Vk: *vk, + } + // execute template - err = tmpl.Execute(w, vk) + err = tmpl.Execute(w, vkToExport) // restore Beta, Gamma and Delta vk.G2.Beta = beta @@ -182,6 +192,17 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.Expor return err } +// verifyingKeyToExport stores a Verifying key and a configuration object used for +// generating the solidity verifier. +type VerifyingKeyToExport struct { + + // Cfg contains solidity specific customisation + Cfg solidity.ExportConfig + + // Copy of the verifying key + Vk VerifyingKey +} + {{else}} // ExportSolidity not implemented for {{.Curve}} func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { From 299a7cd0a757198f215e739e0722b0505101b681 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 21 May 2024 17:13:47 +0200 Subject: [PATCH 11/22] feat: update solidity template groth16 --- backend/groth16/bn254/solidity.go | 54 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/backend/groth16/bn254/solidity.go b/backend/groth16/bn254/solidity.go index 32ccc55bbb..a98675cebb 100644 --- a/backend/groth16/bn254/solidity.go +++ b/backend/groth16/bn254/solidity.go @@ -9,10 +9,10 @@ import ( // solidityTemplate // this is an experimental feature and gnark solidity generator as not been thoroughly tested const solidityTemplate = ` -{{- $numPublic := sub (len .G1.K) 1 }} -{{- $numCommitments := len .PublicAndCommitmentCommitted }} +{{- $numPublic := sub (len .Vk.G1.K) 1 }} +{{- $numCommitments := len .Vk.PublicAndCommitmentCommitted }} {{- $numWitness := sub $numPublic $numCommitments }} -{{- $PublicAndCommitmentCommitted := .PublicAndCommitmentCommitted }} +{{- $PublicAndCommitmentCommitted := .Vk.PublicAndCommitmentCommitted }} // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; @@ -75,46 +75,46 @@ contract Verifier { uint256 constant EXP_SQRT_FP = 0xC19139CB84C680A6E14116DA060561765E05AA45A1C72A34F082305B61F3F52; // (P + 1) / 4; // Groth16 alpha point in G1 - uint256 constant ALPHA_X = {{.G1.Alpha.X.String}}; - uint256 constant ALPHA_Y = {{.G1.Alpha.Y.String}}; + uint256 constant ALPHA_X = {{.Vk.G1.Alpha.X.String}}; + uint256 constant ALPHA_Y = {{.Vk.G1.Alpha.Y.String}}; // Groth16 beta point in G2 in powers of i - uint256 constant BETA_NEG_X_0 = {{.G2.Beta.X.A0.String}}; - uint256 constant BETA_NEG_X_1 = {{.G2.Beta.X.A1.String}}; - uint256 constant BETA_NEG_Y_0 = {{.G2.Beta.Y.A0.String}}; - uint256 constant BETA_NEG_Y_1 = {{.G2.Beta.Y.A1.String}}; + uint256 constant BETA_NEG_X_0 = {{.Vk.G2.Beta.X.A0.String}}; + uint256 constant BETA_NEG_X_1 = {{.Vk.G2.Beta.X.A1.String}}; + uint256 constant BETA_NEG_Y_0 = {{.Vk.G2.Beta.Y.A0.String}}; + uint256 constant BETA_NEG_Y_1 = {{.Vk.G2.Beta.Y.A1.String}}; // Groth16 gamma point in G2 in powers of i - uint256 constant GAMMA_NEG_X_0 = {{.G2.Gamma.X.A0.String}}; - uint256 constant GAMMA_NEG_X_1 = {{.G2.Gamma.X.A1.String}}; - uint256 constant GAMMA_NEG_Y_0 = {{.G2.Gamma.Y.A0.String}}; - uint256 constant GAMMA_NEG_Y_1 = {{.G2.Gamma.Y.A1.String}}; + uint256 constant GAMMA_NEG_X_0 = {{.Vk.G2.Gamma.X.A0.String}}; + uint256 constant GAMMA_NEG_X_1 = {{.Vk.G2.Gamma.X.A1.String}}; + uint256 constant GAMMA_NEG_Y_0 = {{.Vk.G2.Gamma.Y.A0.String}}; + uint256 constant GAMMA_NEG_Y_1 = {{.Vk.G2.Gamma.Y.A1.String}}; // Groth16 delta point in G2 in powers of i - uint256 constant DELTA_NEG_X_0 = {{.G2.Delta.X.A0.String}}; - uint256 constant DELTA_NEG_X_1 = {{.G2.Delta.X.A1.String}}; - uint256 constant DELTA_NEG_Y_0 = {{.G2.Delta.Y.A0.String}}; - uint256 constant DELTA_NEG_Y_1 = {{.G2.Delta.Y.A1.String}}; + uint256 constant DELTA_NEG_X_0 = {{.Vk.G2.Delta.X.A0.String}}; + uint256 constant DELTA_NEG_X_1 = {{.Vk.G2.Delta.X.A1.String}}; + uint256 constant DELTA_NEG_Y_0 = {{.Vk.G2.Delta.Y.A0.String}}; + uint256 constant DELTA_NEG_Y_1 = {{.Vk.G2.Delta.Y.A1.String}}; {{- if gt $numCommitments 0 }} // Pedersen G point in G2 in powers of i - uint256 constant PEDERSEN_G_X_0 = {{.CommitmentKey.G.X.A0.String}}; - uint256 constant PEDERSEN_G_X_1 = {{.CommitmentKey.G.X.A1.String}}; - uint256 constant PEDERSEN_G_Y_0 = {{.CommitmentKey.G.Y.A0.String}}; - uint256 constant PEDERSEN_G_Y_1 = {{.CommitmentKey.G.Y.A1.String}}; + uint256 constant PEDERSEN_G_X_0 = {{.Vk.CommitmentKey.G.X.A0.String}}; + uint256 constant PEDERSEN_G_X_1 = {{.Vk.CommitmentKey.G.X.A1.String}}; + uint256 constant PEDERSEN_G_Y_0 = {{.Vk.CommitmentKey.G.Y.A0.String}}; + uint256 constant PEDERSEN_G_Y_1 = {{.Vk.CommitmentKey.G.Y.A1.String}}; // Pedersen GRootSigmaNeg point in G2 in powers of i - uint256 constant PEDERSEN_GROOTSIGMANEG_X_0 = {{.CommitmentKey.GRootSigmaNeg.X.A0.String}}; - uint256 constant PEDERSEN_GROOTSIGMANEG_X_1 = {{.CommitmentKey.GRootSigmaNeg.X.A1.String}}; - uint256 constant PEDERSEN_GROOTSIGMANEG_Y_0 = {{.CommitmentKey.GRootSigmaNeg.Y.A0.String}}; - uint256 constant PEDERSEN_GROOTSIGMANEG_Y_1 = {{.CommitmentKey.GRootSigmaNeg.Y.A1.String}}; + uint256 constant PEDERSEN_GROOTSIGMANEG_X_0 = {{.Vk.CommitmentKey.GRootSigmaNeg.X.A0.String}}; + uint256 constant PEDERSEN_GROOTSIGMANEG_X_1 = {{.Vk.CommitmentKey.GRootSigmaNeg.X.A1.String}}; + uint256 constant PEDERSEN_GROOTSIGMANEG_Y_0 = {{.Vk.CommitmentKey.GRootSigmaNeg.Y.A0.String}}; + uint256 constant PEDERSEN_GROOTSIGMANEG_Y_1 = {{.Vk.CommitmentKey.GRootSigmaNeg.Y.A1.String}}; {{- end }} // Constant and public input points - {{- $k0 := index .G1.K 0}} + {{- $k0 := index .Vk.G1.K 0}} uint256 constant CONSTANT_X = {{$k0.X.String}}; uint256 constant CONSTANT_Y = {{$k0.Y.String}}; - {{- range $i, $ki := .G1.K }} + {{- range $i, $ki := .Vk.G1.K }} {{- if gt $i 0 }} uint256 constant PUB_{{sub $i 1}}_X = {{$ki.X.String}}; uint256 constant PUB_{{sub $i 1}}_Y = {{$ki.Y.String}}; From 5f2e5be29eebba7336bcc473c0c64da0285c70c7 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Tue, 21 May 2024 18:50:54 +0200 Subject: [PATCH 12/22] feat: re ran code gen and add files --- backend/groth16/bn254/verify.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index f3c7da2e1e..bf972e7e94 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -12,17 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Code generated by gnark DO NOT EDIT + package groth16 import ( "errors" "fmt" + "github.com/consensys/gnark/backend/solidity" "io" "text/template" "time" - "github.com/consensys/gnark/backend/solidity" - "github.com/consensys/gnark-crypto/ecc" curve "github.com/consensys/gnark-crypto/ecc/bn254" "github.com/consensys/gnark-crypto/ecc/bn254/fr" From 6ceb9db30be3de57f18e7fa1269e50edfee36644 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Thu, 23 May 2024 14:20:09 +0200 Subject: [PATCH 13/22] feat: added version solidity template groth16 verifier --- backend/groth16/bn254/solidity.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/groth16/bn254/solidity.go b/backend/groth16/bn254/solidity.go index a98675cebb..97337c6507 100644 --- a/backend/groth16/bn254/solidity.go +++ b/backend/groth16/bn254/solidity.go @@ -15,7 +15,7 @@ const solidityTemplate = ` {{- $PublicAndCommitmentCommitted := .Vk.PublicAndCommitmentCommitted }} // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity {{ .Cfg.PragmaVersion }}; /// @title Groth16 verifier template. /// @author Remco Bloemen From d84f52a16ff161f93654698d4144f7f03ed13fe0 Mon Sep 17 00:00:00 2001 From: Ivo Kubjas Date: Mon, 27 May 2024 10:18:38 +0200 Subject: [PATCH 14/22] test: check errors in test circuit (#1140) --- std/commitments/kzg/verifier_test.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/std/commitments/kzg/verifier_test.go b/std/commitments/kzg/verifier_test.go index 40736ee983..a811e29eee 100644 --- a/std/commitments/kzg/verifier_test.go +++ b/std/commitments/kzg/verifier_test.go @@ -623,7 +623,9 @@ func (c *BatchVerifySinglePointTest[S, G1El, G2El, GTEl]) Define(api frontend.AP if err != nil { return fmt.Errorf("get pairing: %w", err) } - verifier.BatchVerifySinglePoint(c.Digests[:], c.BatchOpeningProof, c.Point, c.Vk) + if err := verifier.BatchVerifySinglePoint(c.Digests[:], c.BatchOpeningProof, c.Point, c.Vk); err != nil { + return fmt.Errorf("batch verify single point: %w", err) + } return nil } @@ -708,7 +710,9 @@ func (circuit *BatchVerifyMultiPointsTest[S, G1El, G2El, GTEl]) Define(api front return fmt.Errorf("get pairing: %w", err) } - verifier.BatchVerifyMultiPoints(circuit.Digests[:], circuit.Proofs[:], circuit.Points[:], circuit.Vk) + if err := verifier.BatchVerifyMultiPoints(circuit.Digests[:], circuit.Proofs[:], circuit.Points[:], circuit.Vk); err != nil { + return fmt.Errorf("batch verify multi points: %w", err) + } return nil } From 340a5f1e4da6adbd251f342edea8139f2c850102 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Fri, 31 May 2024 10:52:27 +0200 Subject: [PATCH 15/22] style: fixed typo --- backend/solidity/solidity.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/solidity/solidity.go b/backend/solidity/solidity.go index c8b062105d..afe3600b43 100644 --- a/backend/solidity/solidity.go +++ b/backend/solidity/solidity.go @@ -24,8 +24,8 @@ func NewExportConfig(opts ...ExportOption) (ExportConfig, error) { return config, nil } -// WithPragmaVerions changes the pragma version used in the solidit verifier. -func WithPragmaVerions(version string) ExportOption { +// WithPragmaVersion changes the pragma version used in the solidit verifier. +func WithPragmaVersion(version string) ExportOption { return func(cfg *ExportConfig) error { cfg.PragmaVersion = version return nil From 395dcc4814c4814f525950ff9905c96333bb2929 Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Fri, 31 May 2024 12:11:21 +0200 Subject: [PATCH 16/22] feat: use anonymous struct --- backend/plonk/bn254/verify.go | 19 +++++-------------- .../zkpschemes/plonk/plonk.verify.go.tmpl | 19 +++++-------------- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/backend/plonk/bn254/verify.go b/backend/plonk/bn254/verify.go index 2d0bf5a770..8c4fecbca5 100644 --- a/backend/plonk/bn254/verify.go +++ b/backend/plonk/bn254/verify.go @@ -408,20 +408,11 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.Expor return err } - vkToExport := VerifyingKeyToExport{ + return t.Execute(w, struct { + Cfg solidity.ExportConfig + Vk VerifyingKey + }{ Cfg: cfg, Vk: *vk, - } - return t.Execute(w, vkToExport) -} - -// verifyingKeyToExport stores a Verifying key and a configuration object used for -// generating the solidity verifier. -type VerifyingKeyToExport struct { - - // Cfg contains solidity specific customisation - Cfg solidity.ExportConfig - - // Copy of the verifying key - Vk VerifyingKey + }) } diff --git a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl index a2e2235fac..8b06dc097a 100644 --- a/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/plonk/plonk.verify.go.tmpl @@ -393,22 +393,13 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.Expor return err } - vkToExport := VerifyingKeyToExport{ + return t.Execute(w, struct { + Cfg solidity.ExportConfig + Vk VerifyingKey + }{ Cfg: cfg, Vk: *vk, - } - return t.Execute(w, vkToExport) -} - -// verifyingKeyToExport stores a Verifying key and a configuration object used for -// generating the solidity verifier. -type VerifyingKeyToExport struct { - - // Cfg contains solidity specific customisation - Cfg solidity.ExportConfig - - // Copy of the verifying key - Vk VerifyingKey + }) } {{else}} From 88e4571e386628f20ed477b38f8e8fb7ed3f780a Mon Sep 17 00:00:00 2001 From: Thomas Piellard Date: Fri, 31 May 2024 12:30:35 +0200 Subject: [PATCH 17/22] feat: code gen --- backend/groth16/bn254/verify.go | 22 +++++-------------- .../zkpschemes/groth16/groth16.verify.go.tmpl | 22 +++++-------------- 2 files changed, 12 insertions(+), 32 deletions(-) diff --git a/backend/groth16/bn254/verify.go b/backend/groth16/bn254/verify.go index bf972e7e94..b2decd60a3 100644 --- a/backend/groth16/bn254/verify.go +++ b/backend/groth16/bn254/verify.go @@ -190,13 +190,14 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.Expor return err } - vkToExport := VerifyingKeyToExport{ + // execute template + err = tmpl.Execute(w, struct { + Cfg solidity.ExportConfig + Vk VerifyingKey + }{ Cfg: cfg, Vk: *vk, - } - - // execute template - err = tmpl.Execute(w, vkToExport) + }) // restore Beta, Gamma and Delta vk.G2.Beta = beta @@ -205,14 +206,3 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.Expor return err } - -// verifyingKeyToExport stores a Verifying key and a configuration object used for -// generating the solidity verifier. -type VerifyingKeyToExport struct { - - // Cfg contains solidity specific customisation - Cfg solidity.ExportConfig - - // Copy of the verifying key - Vk VerifyingKey -} diff --git a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl index 2d6f85f1d3..d3e454eda2 100644 --- a/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl +++ b/internal/generator/backend/template/zkpschemes/groth16/groth16.verify.go.tmpl @@ -176,13 +176,14 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.Expor return err } - vkToExport := VerifyingKeyToExport{ + // execute template + err = tmpl.Execute(w, struct { + Cfg solidity.ExportConfig + Vk VerifyingKey + }{ Cfg: cfg, Vk: *vk, - } - - // execute template - err = tmpl.Execute(w, vkToExport) + }) // restore Beta, Gamma and Delta vk.G2.Beta = beta @@ -192,17 +193,6 @@ func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.Expor return err } -// verifyingKeyToExport stores a Verifying key and a configuration object used for -// generating the solidity verifier. -type VerifyingKeyToExport struct { - - // Cfg contains solidity specific customisation - Cfg solidity.ExportConfig - - // Copy of the verifying key - Vk VerifyingKey -} - {{else}} // ExportSolidity not implemented for {{.Curve}} func (vk *VerifyingKey) ExportSolidity(w io.Writer, exportOpts ...solidity.ExportOption) error { From 89b980930160b3a2a5762864d5974557e00b3d77 Mon Sep 17 00:00:00 2001 From: Arya Tabaie Date: Fri, 7 Jun 2024 16:27:10 -0500 Subject: [PATCH 18/22] Fix/neg factorial (#1158) * fix neg factorial * docs negFactorial * refactor remove "InterpolateOnRange" * style minimize PR diff * style mathfmt --- std/polynomial/polynomial.go | 4 +-- std/polynomial/polynomial_test.go | 6 ++--- std/sumcheck/lagrange.go | 45 ------------------------------- 3 files changed, 4 insertions(+), 51 deletions(-) delete mode 100644 std/sumcheck/lagrange.go diff --git a/std/polynomial/polynomial.go b/std/polynomial/polynomial.go index 0953cb3ac7..f6566c0ba0 100644 --- a/std/polynomial/polynomial.go +++ b/std/polynomial/polynomial.go @@ -87,8 +87,8 @@ func (p Polynomial) Eval(api frontend.API, at frontend.Variable) (pAt frontend.V return } -// negFactorial returns (-n)(-n+1)...(-2)(-1) -// There are more efficient algorithms, but we are talking small values here so it doesn't matter +// negFactorial returns (-n)(-n+1)...(-2)(-1) for n ≥ 1, and -n otherwise. +// This is not asymptotically efficient, but works for small values. func negFactorial(n int) int { n = -n result := n diff --git a/std/polynomial/polynomial_test.go b/std/polynomial/polynomial_test.go index 6ca33fcbb8..667825a6f9 100644 --- a/std/polynomial/polynomial_test.go +++ b/std/polynomial/polynomial_test.go @@ -3,6 +3,7 @@ package polynomial import ( "errors" "fmt" + "github.com/stretchr/testify/assert" "testing" "github.com/consensys/gnark-crypto/ecc" @@ -217,10 +218,7 @@ func TestInterpolateQuadraticExtension(t *testing.T) { func TestNegFactorial(t *testing.T) { for n, expected := range []int{0, -1, 2, -6, 24} { - - if observed := negFactorial(n); observed != expected { - t.Error("negFactorial at", n, "gave", observed, "rather than", expected) - } + assert.Equal(t, expected, negFactorial(n)) } } diff --git a/std/sumcheck/lagrange.go b/std/sumcheck/lagrange.go deleted file mode 100644 index 416a1e6559..0000000000 --- a/std/sumcheck/lagrange.go +++ /dev/null @@ -1,45 +0,0 @@ -package sumcheck - -import "github.com/consensys/gnark/frontend" - -// negFactorial returns (-n)(-n+1)...(-2)(-1) -// There are more efficient algorithms, but we are talking small values here so it doesn't matter -func negFactorial(n int) int { - result := n - n = -n - for n++; n < -1; n++ { - result *= n - } - return result -} - -// InterpolateOnRange fits a polynomial f of degree len(values)-1 such that f(i) = values[i] whenever defined. Returns f(at) -// Algorithm taken from https://people.cs.georgetown.edu/jthaler/ProofsArgsAndZK.pdf section 2.4 -func InterpolateOnRange(api frontend.API, at frontend.Variable, values ...frontend.Variable) frontend.Variable { - deltaAt := make([]frontend.Variable, len(values)) - deltaAt[0] = api.Inverse(negFactorial(len(values) - 1)) - for k := 1; k < len(values); k++ { - deltaAt[0] = api.Mul(deltaAt[0], api.Sub(at, k)) - } - - // Now recursively compute δᵢ(at) by noting it is equal to δᵢ(at) × (r-i+1) × (r-i)⁻¹ × i⁻¹ × (-len(values)+i) - for i := 1; i < len(values); i++ { - // @gbotrel Is it important to write shallow circuits, or does the compiler rearrange things for you? - // Is it important to cache inverses of numbers, or does the compiler do that for you? - removeFromNumeratorAddToDenominator := api.Mul(i, api.Sub(at, i)) - removeFromDenominatorAddToNumerator := api.Mul(api.Sub(at, i-1), i-len(values)) - adjustment := api.DivUnchecked(removeFromDenominatorAddToNumerator, removeFromNumeratorAddToDenominator) //TODO: May be shallower to mul removeFromDenominator and δᵢ₋₁ first and THEN divide - deltaAt[i] = api.Mul(deltaAt[i-1], adjustment) - } - - var res frontend.Variable - res = 0 // @gbotrel: does the API know x ↦ 0+x is a no-op? - - for i, c := range values { - res = api.Add(res, - api.Mul(c, deltaAt[i]), - ) - } - - return res -} From 945270151f03264abce12ee2a5bf15ebcd215da9 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Tue, 11 Jun 2024 10:14:42 -0500 Subject: [PATCH 19/22] =?UTF-8?q?fix:=20fixes=20#1157=20ensures=20calls=20?= =?UTF-8?q?to=20AttachDebugInfo=20are=20surrounded=20with=E2=80=A6=20(#116?= =?UTF-8?q?0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: fixes #1157 ensures calls to AttachDebugInfo are surrounded with compile time check on debug.Debug * fix: apply PR suggested diff --- debug_test.go | 3 +++ frontend/cs/r1cs/api.go | 13 ++++++++----- frontend/cs/r1cs/api_assertions.go | 13 ++++++------- frontend/cs/scs/api_assertions.go | 20 +++++++++++++------- 4 files changed, 30 insertions(+), 19 deletions(-) diff --git a/debug_test.go b/debug_test.go index e171942779..0b1548e66f 100644 --- a/debug_test.go +++ b/debug_test.go @@ -78,6 +78,9 @@ func (circuit *divBy0Trace) Define(api frontend.API) error { } func TestTraceDivBy0(t *testing.T) { + if !debug.Debug { + t.Skip("skipping test in non debug mode") + } assert := require.New(t) var circuit, witness divBy0Trace diff --git a/frontend/cs/r1cs/api.go b/frontend/cs/r1cs/api.go index 958741632d..a23665fbb8 100644 --- a/frontend/cs/r1cs/api.go +++ b/frontend/cs/r1cs/api.go @@ -294,12 +294,14 @@ func (builder *builder) Div(i1, i2 frontend.Variable) frontend.Variable { if !v2Constant { res := builder.newInternalVariable() - debug := builder.newDebugInfo("div", v1, "/", v2, " == ", res) v2Inv := builder.newInternalVariable() // note that here we ensure that v2 can't be 0, but it costs us one extra constraint c1 := builder.cs.AddR1C(builder.newR1C(v2, v2Inv, builder.cstOne()), builder.genericGate) c2 := builder.cs.AddR1C(builder.newR1C(v1, v2Inv, res), builder.genericGate) - builder.cs.AttachDebugInfo(debug, []int{c1, c2}) + if debug.Debug { + debug := builder.newDebugInfo("div", v1, "/", v2, " == ", res) + builder.cs.AttachDebugInfo(debug, []int{c1, c2}) + } return res } @@ -542,8 +544,6 @@ func (builder *builder) IsZero(i1 frontend.Variable) frontend.Variable { return builder.cstZero() } - debug := builder.newDebugInfo("isZero", a) - // x = 1/a // in a hint (x == 0 if a == 0) // m = -a*x + 1 // constrain m to be 1 if a == 0 // a * m = 0 // constrain m to be 0 if a != 0 @@ -563,7 +563,10 @@ func (builder *builder) IsZero(i1 frontend.Variable) frontend.Variable { // a * m = 0 // constrain m to be 0 if a != 0 c2 := builder.cs.AddR1C(builder.newR1C(a, m, builder.cstZero()), builder.genericGate) - builder.cs.AttachDebugInfo(debug, []int{c1, c2}) + if debug.Debug { + debug := builder.newDebugInfo("isZero", a) + builder.cs.AttachDebugInfo(debug, []int{c1, c2}) + } builder.MarkBoolean(m) diff --git a/frontend/cs/r1cs/api_assertions.go b/frontend/cs/r1cs/api_assertions.go index 530a5fe412..0fdc72be3c 100644 --- a/frontend/cs/r1cs/api_assertions.go +++ b/frontend/cs/r1cs/api_assertions.go @@ -132,8 +132,6 @@ func (builder *builder) mustBeLessOrEqVar(a, bound frontend.Variable) { _, aConst := builder.constantValue(a) - debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) - nbBits := builder.cs.FieldBitLen() aBits := bits.ToBinary(builder, a, bits.WithNbDigits(nbBits), bits.WithUnconstrainedOutputs(), bits.OmitModulusCheck()) @@ -179,7 +177,10 @@ func (builder *builder) mustBeLessOrEqVar(a, bound frontend.Variable) { } } - builder.cs.AttachDebugInfo(debug, added) + if debug.Debug { + debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) + builder.cs.AttachDebugInfo(debug, added) + } } @@ -204,9 +205,6 @@ func (builder *builder) MustBeLessOrEqCst(aBits []frontend.Variable, bound *big. panic("AssertIsLessOrEqual: bound is too large, constraint will never be satisfied") } - // debug info - debug := builder.newDebugInfo("mustBeLessOrEq", aForDebug, " <= ", builder.toVariable(bound)) - // t trailing bits in the bound t := 0 for i := 0; i < nbBits; i++ { @@ -243,7 +241,8 @@ func (builder *builder) MustBeLessOrEqCst(aBits []frontend.Variable, bound *big. } } - if len(added) != 0 { + if debug.Debug && len(added) != 0 { + debug := builder.newDebugInfo("mustBeLessOrEq", aForDebug, " <= ", builder.toVariable(bound)) builder.cs.AttachDebugInfo(debug, added) } } diff --git a/frontend/cs/scs/api_assertions.go b/frontend/cs/scs/api_assertions.go index 3fe9ef1d9a..56ba022157 100644 --- a/frontend/cs/scs/api_assertions.go +++ b/frontend/cs/scs/api_assertions.go @@ -20,6 +20,7 @@ import ( "fmt" "math/big" + "github.com/consensys/gnark/constraint" "github.com/consensys/gnark/debug" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/frontend/internal/expr" @@ -182,8 +183,10 @@ func (builder *builder) AssertIsLessOrEqual(v frontend.Variable, bound frontend. } func (builder *builder) mustBeLessOrEqVar(a frontend.Variable, bound expr.Term) { - - debug := builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound) + var debugInfo []constraint.DebugInfo + if debug.Debug { + debugInfo = []constraint.DebugInfo{builder.newDebugInfo("mustBeLessOrEq", a, " <= ", bound)} + } nbBits := builder.cs.FieldBitLen() @@ -219,14 +222,14 @@ func (builder *builder) mustBeLessOrEqVar(a frontend.Variable, bound expr.Term) builder.addPlonkConstraint(sparseR1C{ xa: l.VID, qL: l.Coeff, - }, debug) + }, debugInfo...) } else { // l * a[i] == 0 builder.addPlonkConstraint(sparseR1C{ xa: l.VID, xb: aBits[i].(expr.Term).VID, qM: l.Coeff, - }, debug) + }, debugInfo...) } } @@ -254,8 +257,11 @@ func (builder *builder) MustBeLessOrEqCst(aBits []frontend.Variable, bound *big. panic("AssertIsLessOrEqual: bound is too large, constraint will never be satisfied") } - // debug info - debug := builder.newDebugInfo("mustBeLessOrEq", aForDebug, " <= ", bound) + // debugInfo info + var debugInfo []constraint.DebugInfo + if debug.Debug { + debugInfo = []constraint.DebugInfo{builder.newDebugInfo("mustBeLessOrEq", aForDebug, " <= ", bound)} + } // t trailing bits in the bound t := 0 @@ -289,7 +295,7 @@ func (builder *builder) MustBeLessOrEqCst(aBits []frontend.Variable, bound *big. xa: l.VID, xb: aBits[i].(expr.Term).VID, qM: builder.tOne, - }, debug) + }, debugInfo...) } else { builder.AssertIsBoolean(aBits[i]) } From ccf02f97b2e9ef66de99a94af24e76f562d05470 Mon Sep 17 00:00:00 2001 From: threehonor Date: Wed, 12 Jun 2024 17:00:33 +0900 Subject: [PATCH 20/22] chore: make function comments match function names (#1163) Signed-off-by: threehonor --- constraint/string_utils.go | 2 +- examples/rollup/circuit.go | 2 +- examples/rollup/operator.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/constraint/string_utils.go b/constraint/string_utils.go index 427d5ed4e7..35740f417a 100644 --- a/constraint/string_utils.go +++ b/constraint/string_utils.go @@ -32,7 +32,7 @@ func (sbb *StringBuilder) WriteLinearExpression(l LinearExpression) { } } -// WriteLinearExpression appends the term to the current buffer +// WriteTerm appends the term to the current buffer func (sbb *StringBuilder) WriteTerm(t Term) { if t.CoeffID() == CoeffIdZero { sbb.WriteByte('0') diff --git a/examples/rollup/circuit.go b/examples/rollup/circuit.go index 27b47f4fda..6651a87440 100644 --- a/examples/rollup/circuit.go +++ b/examples/rollup/circuit.go @@ -172,7 +172,7 @@ func (circuit *Circuit) Define(api frontend.API) error { return nil } -// verifySignatureTransfer ensures that the signature of the transfer is valid +// verifyTransferSignature ensures that the signature of the transfer is valid func verifyTransferSignature(api frontend.API, t TransferConstraints, hFunc mimc.MiMC) error { // Reset the hash state! diff --git a/examples/rollup/operator.go b/examples/rollup/operator.go index c4bee69c1d..d906a1a9b4 100644 --- a/examples/rollup/operator.go +++ b/examples/rollup/operator.go @@ -92,7 +92,7 @@ func (o *Operator) readAccount(i uint64) (Account, error) { return res, nil } -// updateAccount updates the state according to transfer +// updateState updates the state according to transfer // numTransfer is the number of the transfer currently handled (between 0 and BatchSizeCircuit) func (o *Operator) updateState(t Transfer, numTransfer int) error { From 6abed5af59a0ee0ec1f093ab15dcf1751b54ae16 Mon Sep 17 00:00:00 2001 From: bernard-wagner Date: Wed, 12 Jun 2024 14:08:36 +0200 Subject: [PATCH 21/22] fix(uints): constrain valueOf (#1139) * fix(uints): constrain valueOf * chore: use existing method instead * chore: use the Long type restriction * test: add test case for add * feat: check carry correctness in Add * chore: use unified method for Long length * chore: use range --------- Co-authored-by: Ivo Kubjas --- std/math/uints/uint8.go | 44 +++++++++++++++++++++------------ std/math/uints/uint8_test.go | 47 ++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/std/math/uints/uint8.go b/std/math/uints/uint8.go index cec591d10c..adabe49483 100644 --- a/std/math/uints/uint8.go +++ b/std/math/uints/uint8.go @@ -24,6 +24,7 @@ package uints import ( "fmt" + "math/bits" "github.com/consensys/gnark/frontend" "github.com/consensys/gnark/std/internal/logderivprecomp" @@ -173,15 +174,18 @@ func (bf *BinaryField[T]) ValueOf(a frontend.Variable) T { if err != nil { panic(err) } - // TODO: add constraint which ensures that map back to + for i := range bts { r[i] = bf.ByteValueOf(bts[i]) } + expectedValue := bf.ToValue(r) + bf.api.AssertIsEqual(a, expectedValue) + return r } func (bf *BinaryField[T]) ToValue(a T) frontend.Variable { - v := make([]frontend.Variable, len(a)) + v := make([]frontend.Variable, bf.lenBts()) for i := range v { v[i] = bf.api.Mul(a[i].Val, 1<<(i*8)) } @@ -206,8 +210,8 @@ func (bf *BinaryField[T]) PackLSB(a ...U8) T { } func (bf *BinaryField[T]) UnpackMSB(a T) []U8 { - ret := make([]U8, len(a)) - for i := 0; i < len(a); i++ { + ret := make([]U8, bf.lenBts()) + for i := 0; i < len(ret); i++ { ret[len(a)-i-1] = a[i] } return ret @@ -215,8 +219,8 @@ func (bf *BinaryField[T]) UnpackMSB(a T) []U8 { func (bf *BinaryField[T]) UnpackLSB(a T) []U8 { // cannot deduce that a can be cast to []U8 - ret := make([]U8, len(a)) - for i := 0; i < len(a); i++ { + ret := make([]U8, bf.lenBts()) + for i := 0; i < len(ret); i++ { ret[i] = a[i] } return ret @@ -255,18 +259,22 @@ func (bf *BinaryField[T]) Not(a T) T { } func (bf *BinaryField[T]) Add(a ...T) T { - va := make([]frontend.Variable, len(a)) + tLen := bf.lenBts() * 8 + inLen := len(a) + va := make([]frontend.Variable, inLen) for i := range a { va[i] = bf.ToValue(a[i]) } vres := bf.api.Add(va[0], va[1], va[2:]...) - res := bf.ValueOf(vres) - // TODO: should also check the that carry we omitted is correct. + maxBitlen := bits.Len(uint(inLen)) + tLen + // bitslice.Partition below checks that the input is less than 2^maxBitlen and that we have omitted carry correctly + vreslow, _ := bitslice.Partition(bf.api, vres, uint(tLen), bitslice.WithNbDigits(maxBitlen), bitslice.WithUnconstrainedOutputs()) + res := bf.ValueOf(vreslow) return res } func (bf *BinaryField[T]) Lrot(a T, c int) T { - l := len(a) + l := bf.lenBts() if c < 0 { c = l*8 + c } @@ -293,23 +301,24 @@ func (bf *BinaryField[T]) Lrot(a T, c int) T { } func (bf *BinaryField[T]) Rshift(a T, c int) T { + lenB := bf.lenBts() shiftBl := c / 8 shiftBt := c % 8 - partitioned := make([][2]frontend.Variable, len(a)-shiftBl) + partitioned := make([][2]frontend.Variable, lenB-shiftBl) for i := range partitioned { lower, upper := bitslice.Partition(bf.api, a[i+shiftBl].Val, uint(shiftBt), bitslice.WithNbDigits(8)) partitioned[i] = [2]frontend.Variable{lower, upper} } var ret T - for i := 0; i < len(a)-shiftBl-1; i++ { + for i := 0; i < bf.lenBts()-shiftBl-1; i++ { if shiftBt != 0 { ret[i].Val = bf.api.Add(partitioned[i][1], bf.api.Mul(1<<(8-shiftBt), partitioned[i+1][0])) } else { ret[i].Val = partitioned[i][1] } } - ret[len(a)-shiftBl-1].Val = partitioned[len(a)-shiftBl-1][1] - for i := len(a) - shiftBl; i < len(ret); i++ { + ret[lenB-shiftBl-1].Val = partitioned[lenB-shiftBl-1][1] + for i := lenB - shiftBl; i < lenB; i++ { ret[i] = NewU8(0) } return ret @@ -320,11 +329,16 @@ func (bf *BinaryField[T]) ByteAssertEq(a, b U8) { } func (bf *BinaryField[T]) AssertEq(a, b T) { - for i := 0; i < len(a); i++ { + for i := 0; i < bf.lenBts(); i++ { bf.ByteAssertEq(a[i], b[i]) } } +func (bf *BinaryField[T]) lenBts() int { + var a T + return len(a) +} + func reslice[T U32 | U64](in []T) [][]U8 { if len(in) == 0 { panic("zero-length input") diff --git a/std/math/uints/uint8_test.go b/std/math/uints/uint8_test.go index bc24a8f4db..47145bfef4 100644 --- a/std/math/uints/uint8_test.go +++ b/std/math/uints/uint8_test.go @@ -79,3 +79,50 @@ func TestRshift(t *testing.T) { err = test.IsSolved(&rshiftCircuit{Shift: 11}, &rshiftCircuit{Shift: 11, In: NewU32(0x12345678), Expected: NewU32(0x12345678 >> 11)}, ecc.BN254.ScalarField()) assert.NoError(err) } + +type valueOfCircuit[T Long] struct { + In frontend.Variable + Expected T +} + +func (c *valueOfCircuit[T]) Define(api frontend.API) error { + uapi, err := New[T](api) + if err != nil { + return err + } + res := uapi.ValueOf(c.In) + uapi.AssertEq(res, c.Expected) + return nil +} + +func TestValueOf(t *testing.T) { + assert := test.NewAssert(t) + var err error + err = test.IsSolved(&valueOfCircuit[U64]{}, &valueOfCircuit[U64]{In: 0x12345678, Expected: [8]U8{NewU8(0x78), NewU8(0x56), NewU8(0x34), NewU8(0x12), NewU8(0), NewU8(0), NewU8(0), NewU8(0)}}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&valueOfCircuit[U32]{}, &valueOfCircuit[U32]{In: 0x12345678, Expected: [4]U8{NewU8(0x78), NewU8(0x56), NewU8(0x34), NewU8(0x12)}}, ecc.BN254.ScalarField()) + assert.NoError(err) + err = test.IsSolved(&valueOfCircuit[U32]{}, &valueOfCircuit[U32]{In: 0x1234567812345678, Expected: [4]U8{NewU8(0x78), NewU8(0x56), NewU8(0x34), NewU8(0x12)}}, ecc.BN254.ScalarField()) + assert.Error(err) +} + +type addCircuit struct { + In [2]U32 + Expected U32 +} + +func (c *addCircuit) Define(api frontend.API) error { + uapi, err := New[U32](api) + if err != nil { + return err + } + res := uapi.Add(c.In[0], c.In[1]) + uapi.AssertEq(res, c.Expected) + return nil +} + +func TestAdd(t *testing.T) { + assert := test.NewAssert(t) + err := test.IsSolved(&addCircuit{}, &addCircuit{In: [2]U32{NewU32(^uint32(0)), NewU32(2)}, Expected: NewU32(1)}, ecc.BN254.ScalarField()) + assert.NoError(err) +} From db299cef6c78dc5acff8453b66c910c15ea88123 Mon Sep 17 00:00:00 2001 From: Gautam Botrel Date: Wed, 12 Jun 2024 09:01:55 -0500 Subject: [PATCH 22/22] fix: fix #1149 by removing unused code (#1164) * fix: fix #1149 by removing unused code * fix: update stats without toNAF --- internal/stats/latest.stats | Bin 2246 -> 1934 bytes internal/stats/snippet.go | 6 ---- std/math/bits/hints.go | 53 ------------------------------------ std/math/bits/naf.go | 50 ---------------------------------- std/math/bits/naf_test.go | 32 ---------------------- 5 files changed, 141 deletions(-) delete mode 100644 std/math/bits/naf.go delete mode 100644 std/math/bits/naf_test.go diff --git a/internal/stats/latest.stats b/internal/stats/latest.stats index ca6fe17b4f47d4c447a251405df8fc6c5099c52d..f4d2c4761673b7b28104a4a7523fe95c6b628e42 100644 GIT binary patch delta 62 zcmV-E0Kxyp5snX#V+IE)|Aqh$ll23FlSu-tlLiK-0T+`F1s9QljFYVfev|eB|C0>` U`I9RLV3T(QmXoOgppz#EpURdOb^rhX delta 368 zcmeCZ zzzCv#L8yOl9t-0?rY{VPAgTf;$G`#7!1#~(8v{rSknst`077Pyo~$;oUz6JM{LoXGrtVrJ9iovhO)C$RjSJcDuhiLoN0A0?^!2kt7=dgYQVxT+!v3>yJcOVAPfvh0sz(qK2G5+JY0Tf|R1L72f8jydu sUjXqlpcwZZAif1+d;wyR#~>ooK$hSdAYKJz@Erl-LvTft-?A+P06J@mMgRZ+ diff --git a/internal/stats/snippet.go b/internal/stats/snippet.go index 839d9475e6..f6716a3bce 100644 --- a/internal/stats/snippet.go +++ b/internal/stats/snippet.go @@ -70,12 +70,6 @@ func initSnippets() { registerSnippet("math/bits.ToTernary/unconstrained", func(api frontend.API, newVariable func() frontend.Variable) { _ = bits.ToTernary(api, newVariable(), bits.WithUnconstrainedOutputs()) }) - registerSnippet("math/bits.ToNAF", func(api frontend.API, newVariable func() frontend.Variable) { - _ = bits.ToNAF(api, newVariable()) - }) - registerSnippet("math/bits.ToNAF/unconstrained", func(api frontend.API, newVariable func() frontend.Variable) { - _ = bits.ToNAF(api, newVariable(), bits.WithUnconstrainedOutputs()) - }) registerSnippet("hash/mimc", func(api frontend.API, newVariable func() frontend.Variable) { mimc, _ := mimc.NewMiMC(api) diff --git a/std/math/bits/hints.go b/std/math/bits/hints.go index bb3da6d13c..2266b4bb3a 100644 --- a/std/math/bits/hints.go +++ b/std/math/bits/hints.go @@ -1,7 +1,6 @@ package bits import ( - "errors" "math/big" "github.com/consensys/gnark/constraint/solver" @@ -12,7 +11,6 @@ func GetHints() []solver.Hint { ithBit, nBits, nTrits, - nNaf, } } @@ -61,54 +59,3 @@ func nTrits(_ *big.Int, inputs []*big.Int, results []*big.Int) error { return nil } - -// NNAF returns the NAF decomposition of the input. The number of digits is -// defined by the number of elements in the results slice. -func nNaf(_ *big.Int, inputs []*big.Int, results []*big.Int) error { - n := inputs[0] - return nafDecomposition(n, results) -} - -// nafDecomposition gets the naf decomposition of a big number -func nafDecomposition(a *big.Int, results []*big.Int) error { - if a == nil || a.Sign() == -1 { - return errors.New("invalid input to naf decomposition; negative (or nil) big.Int not supported") - } - - var zero, one, three big.Int - - one.SetUint64(1) - three.SetUint64(3) - - n := 0 - - // some buffers - var buf, aCopy big.Int - aCopy.Set(a) - - for aCopy.Cmp(&zero) != 0 && n < len(results) { - - // if aCopy % 2 == 0 - buf.And(&aCopy, &one) - - // aCopy even - if buf.Cmp(&zero) == 0 { - results[n].SetUint64(0) - } else { // aCopy odd - buf.And(&aCopy, &three) - if buf.IsUint64() && buf.Uint64() == 3 { - results[n].SetInt64(-1) - aCopy.Add(&aCopy, &one) - } else { - results[n].SetUint64(1) - } - } - aCopy.Rsh(&aCopy, 1) - n++ - } - for ; n < len(results); n++ { - results[n].SetUint64(0) - } - - return nil -} diff --git a/std/math/bits/naf.go b/std/math/bits/naf.go deleted file mode 100644 index 56b4b9e468..0000000000 --- a/std/math/bits/naf.go +++ /dev/null @@ -1,50 +0,0 @@ -package bits - -import ( - "math/big" - - "github.com/consensys/gnark/frontend" -) - -// ToNAF returns the NAF decomposition of given input. -// The non-adjacent form (NAF) of a number is a unique signed-digit representation, -// in which non-zero values cannot be adjacent. For example, NAF(13) = [1, 0, -1, 0, 1]. -func ToNAF(api frontend.API, v frontend.Variable, opts ...BaseConversionOption) []frontend.Variable { - // parse options - cfg := baseConversionConfig{ - NbDigits: api.Compiler().FieldBitLen(), - UnconstrainedOutputs: false, - } - - for _, o := range opts { - if err := o(&cfg); err != nil { - panic(err) - } - } - - c := big.NewInt(1) - - bits, err := api.Compiler().NewHint(nNaf, cfg.NbDigits, v) - if err != nil { - panic(err) - } - - var Σbi frontend.Variable - Σbi = 0 - for i := 0; i < cfg.NbDigits; i++ { - Σbi = api.Add(Σbi, api.Mul(bits[i], c)) - c.Lsh(c, 1) - if !cfg.UnconstrainedOutputs { - // b * (1 - b) * (1 + b) == 0 - // TODO this adds 3 constraint, not 2. Need api.Compiler().AddConstraint(...) - b := bits[i] - y := api.Mul(api.Sub(1, b), api.Add(1, b)) - api.AssertIsEqual(api.Mul(b, y), 0) - } - } - - // record the constraint Σ (2**i * b[i]) == v - api.AssertIsEqual(Σbi, v) - - return bits -} diff --git a/std/math/bits/naf_test.go b/std/math/bits/naf_test.go deleted file mode 100644 index 2ead74a682..0000000000 --- a/std/math/bits/naf_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package bits_test - -import ( - "testing" - - "github.com/consensys/gnark/frontend" - "github.com/consensys/gnark/std/math/bits" - "github.com/consensys/gnark/test" -) - -type toNAFCircuit struct { - A frontend.Variable - B0, B1, B2, B3, B4 frontend.Variable -} - -func (c *toNAFCircuit) Define(api frontend.API) error { - // to binary - b := bits.ToNAF(api, c.A, bits.WithNbDigits(6)) - api.AssertIsEqual(b[0], c.B0) - api.AssertIsEqual(b[1], c.B1) - api.AssertIsEqual(b[2], c.B2) - api.AssertIsEqual(b[3], c.B3) - api.AssertIsEqual(b[4], c.B4) - api.AssertIsEqual(b[5], 0) - - return nil -} - -func TestToNAF(t *testing.T) { - assert := test.NewAssert(t) - assert.ProverSucceeded(&toNAFCircuit{}, &toNAFCircuit{A: 13, B0: 1, B1: 0, B2: -1, B3: 0, B4: 1}) -}