diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md new file mode 100755 index 0000000000..791f3c57bf --- /dev/null +++ b/.chglog/CHANGELOG.tpl.md @@ -0,0 +1,49 @@ +{{ if .Versions -}} + +## [Unreleased] + +{{ if .Unreleased.CommitGroups -}} +{{ range .Unreleased.CommitGroups -}} +### {{ .Title }} +{{ range .Commits -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} + +{{ range .Versions }} + +## {{ if .Tag.Previous }}[{{ .Tag.Name }}]{{ else }}{{ .Tag.Name }}{{ end }} - {{ datetime "2006-01-02" .Tag.Date }} +{{ range .CommitGroups -}} +### {{ .Title }} +{{ range .Commits -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{ end }} +{{ end -}} + +{{- if .MergeCommits -}} +### Pull Requests +{{ range .MergeCommits -}} +- {{ .Header }} +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} + +{{- if .Versions }} +[Unreleased]: {{ .Info.RepositoryURL }}/compare/{{ $latest := index .Versions 0 }}{{ $latest.Tag.Name }}...HEAD +{{ range .Versions -}} +{{ if .Tag.Previous -}} +[{{ .Tag.Name }}]: {{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }} +{{ end -}} +{{ end -}} +{{ end -}} \ No newline at end of file diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100755 index 0000000000..2df0aa33e7 --- /dev/null +++ b/.chglog/config.yml @@ -0,0 +1,28 @@ +style: github +template: CHANGELOG.tpl.md +info: + title: CHANGELOG + repository_url: https://github.com/ConsenSys/gnark-crypto +options: + commits: + # filters: + # Type: + # - feat + # - fix + # - perf + # - refactor + commit_groups: + # title_maps: + # feat: Features + # fix: Bug Fixes + # perf: Performance Improvements + # refactor: Code Refactoring + header: + pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" + pattern_maps: + - Type + - Scope + - Subject + notes: + keywords: + - BREAKING CHANGE \ No newline at end of file diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 2f0869e58b..fbe49fc7e4 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -30,6 +30,8 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- + - name: install deps + run: go get golang.org/x/tools/cmd/goimports && go get github.com/klauspost/asmfmt/cmd/asmfmt - name: gofmt run: if [[ -n $(gofmt -l .) ]]; then echo "please run gofmt"; exit 1; fi - name: go vet @@ -41,9 +43,7 @@ jobs: - name: gosec run: | go get -u github.com/securego/gosec/cmd/gosec - gosec bls377/... bn256/... bls371/... bw761/... utils/... - - name: install deps - run: go get golang.org/x/tools/cmd/goimports && go get github.com/klauspost/asmfmt/cmd/asmfmt + gosec -exclude G204 ./... - name: generated files should not be modified run: | go generate ./... @@ -76,6 +76,8 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- + - name: install deps + run: go get golang.org/x/tools/cmd/goimports && go get github.com/klauspost/asmfmt/cmd/asmfmt - name: Test run: | go test -v -short ./... @@ -84,8 +86,8 @@ jobs: - name: Test (32bits) if: matrix.os == 'ubuntu-latest' run: | - GOARCH=386 go test -v -short ./bn256/... - GOARCH=386 go test -v -short ./bls381/... + GOARCH=386 go test -v -short ./ecc/bn254/... + GOARCH=386 go test -v -short ./ecc/bls12-381/... slack-workflow-status: if: always() diff --git a/.gitignore b/.gitignore index 3dfe09793b..eb61cf8f82 100644 --- a/.gitignore +++ b/.gitignore @@ -28,14 +28,8 @@ tasks.txt # generated files during integratrion tests internal/tests/integration/ -# binary -/gurvy/utils/ -playground .vscode # compiled sage -> python code *.sage.py - - -bn256/benchesres/** \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..05371e9dee --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,60 @@ + +## [v0.4.0] - 2021-03-31 + +### Refactor +- gurvy -> gnark-crypto +- moved interop tests under github.com/consensys/gnark-tests +- bls381 -> bls12-381 +- bls377 -> bls12-377 +- bn256 -> bn254 +- migrated MiMC and EdDSA from gnark into gnark-crypto +- migrated gnark/backend/fft into gnark-crypto +- migrated goff packages into ./field/... +- cleaning internal/generator pattern + +### Ci +- testing with go 1.15, go 1.16 on Windows, MacOS, Linux (+arch=32bits) + +### Docs +- added ecc/ecc.md and field/field.md + +### Feat +- multiExp in full extended jacobian coordinates + +### Fix +- handle case where numCPU < 4 in precomputeExpTable +- incorrect comment and size returned in twistededwards SetBytes fixes [#34](https://github.com/ConsenSys/gnark-crypto/issues/34) +- point.SetBytes can now be called concurently with same byte slice input + + + + +## [v0.3.8] - 2021-02-01 + +### Bls377 +- final exp hard part eprint 2020/875 +- ML entirely on the twist (ABLR) + +### Bls381 +- final exp hard part eprint 2020/875 +- ML entirely on the twist (ABLR) +- change G1 and G2 generators for interop + +### Bn256 +- inline lineEval() in MilleLoop +- ML entirely on the twist (ABLR) +- change G1 and G2 generators for interop + +### Bw6 +- add E6 and pairing tests +- correct comments in FinalExp +- fix bw6 pairing API to take slices of points and mutualize squares +- change G1 and G2 generators for interop + +### Pull Requests +- Merge pull request [#29](https://github.com/ConsenSys/gnark-crypto/issues/29) from ConsenSys/youssef/bls12-finalExp +- Merge pull request [#27](https://github.com/ConsenSys/gnark-crypto/issues/27) from ConsenSys/experimental/pairing +- Merge pull request [#26](https://github.com/ConsenSys/gnark-crypto/issues/26) from ConsenSys/youssef/ML-ABLR +- Merge pull request [#25](https://github.com/ConsenSys/gnark-crypto/issues/25) from ConsenSys/csquare +- Merge pull request [#23](https://github.com/ConsenSys/gnark-crypto/issues/23) from ConsenSys/youssef/bw6-API-pairing + diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..dd8617f47b --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor gnark-crypto Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at [zkteam@consensys.net]. +All complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..de40ffd26c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,67 @@ +# Contributing to gnark-crypto + +### Table of Contents + +[Code of Conduct](#code-of-conduct) + +[How to Contribute](#how-to-contribute) + +* [Reporting Bugs](#reporting-bugs) +* [Suggesting Enhancements](#suggesting-enhancements) +* [Pull Requests](#pull-requests) + + + +## Code of Conduct +* This project is governed by the [gnark-crypto Code of Conduct](CODE_OF_CONDUCT.md). By participating, +you are agreeing to uphold this code. Please report unacceptable behavior. +## How to Contribute + +### Reporting Bugs +#### Before Submitting A Bug +* Ensure the bug is not already reported by searching on GitHub under +[Issues](https://github.com/consensys/gnark-crypto/issues). +#### How Do I Submit a (Good) Bug? +* If you are unable to find an open issue addressing the problem, open a new one. Be sure to include a +**title and clear description**, as much relevant information as possible, and a **code sample** or +an **executable test case** demonstrating the unexpected behavior. +* Describe the **exact steps** to **reproduce the problem** in as many details as possible. When +listing steps, don't just say what you did, but explain how you did it. +* Provide **specific examples** to demonstrate the steps. Include links to files or GitHub projects, or +copy/pasteable snippets, which you use in those examples. If you're providing snippets in the issue, +use [Markdown code blocks](https://help.github.com/articles/getting-started-with-writing-and-formatting-on-github/). +* Describe the **behavior you observed** after following the steps and explain the +problem with that behavior. +* Explain the **behavior you expected** instead and why. +* **Can you reliably reproduce the issue?** If not, provide details about how often the problem +happens and under which conditions it normally happens. + +### Suggesting Enhancements +#### Before Submitting An Enhancement Suggestion +* [Search](https://github.com/consensys/gnark-crypto/issues) to see if the enhancement has already been +suggested. If it has, add a comment to the existing issue instead of opening a new one. + +#### How Do I Submit A (Good) Enhancement Suggestion? +Enhancement suggestions are tracked as GitHub issues. Create an issue on and provide +the following information: + +* Use a **clear and descriptive title** for the issue to identify the suggestion. +* Provide a **step-by-step description** of the suggested enhancement in as much detail as possible. +* Describe the **current behavior** and explain the **behavior you expect** instead and why. +* Explain why this enhancement would be useful to other users. +* Specify the **name and version of the OS** you're using. +* Specify the **name and version of any relevant packages**. + +### Pull Requests +There are a number of automated checks: +* `go fmt` +* `go vet` + +If these checks pass, pull requests will be reviewed by the project team against criteria including: +* purpose - is this change useful +* test coverage - are there unit/integration/acceptance tests demonstrating the change is effective +* code consistency - naming, comments, design +* changes that are solely formatting are likely to be rejected + +Always write a clear log message for your commits. One-line messages are fine for small changes, but +bigger changes should contain more detail. \ No newline at end of file diff --git a/README.md b/README.md index aea08ed599..28272555a5 100644 --- a/README.md +++ b/README.md @@ -1,93 +1,70 @@ -# gurvy +# gnark-crypto -[![License](https://img.shields.io/badge/license-Apache%202-blue)](LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/consensys/gurvy)](https://goreportcard.com/badge/github.com/consensys/gurvy) [![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/consensys/gurvy)](https://pkg.go.dev/mod/github.com/consensys/gurvy) +[![License](https://img.shields.io/badge/license-Apache%202-blue)](LICENSE) [![Go Report Card](https://goreportcard.com/badge/github.com/consensys/gnark-crypto)](https://goreportcard.com/badge/github.com/consensys/gnark-crypto) [![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/consensys/gnark-crypto)](https://pkg.go.dev/mod/github.com/consensys/gnark-crypto) +`gnark-crypto` provides: +* [Elliptic curve cryptography](ecc/ecc.md) (+pairing) on BN254, BLS12-381, BLS12-377 and BW6-761 +* [Finite field arithmetic](field/field.md) (fast big.Int) +* FFT +* Polynomial commitment schemes +* MiMC +* EdDSA (on the "companion" twisted edwards curves) -`gurvy` implements Elliptic Curve Cryptography (+Pairing) for BLS381, BLS377 and BN256. + -It is actively developed and maintained by the team (zkteam@consensys.net) behind: +`gnark-crypto` is actively developed and maintained by the team (zkteam@consensys.net | [HackMD](https://hackmd.io/@zkteam)) behind: * [`gnark`: a framework to execute (and verify) algorithms in zero-knowledge](https://github.com/consensys/gnark) -* [`goff`: fast finite field arithmetic in Golang](https://github.com/consensys/goff) ## Warning -**`gurvy` has not been audited and is provided as-is, use at your own risk. In particular, `gurvy` makes no security guarantees such as constant time implementation or side-channel attack resistance.** +**`gnark-crypto` has not been audited and is provided as-is, use at your own risk. In particular, `gnark-crypto` makes no security guarantees such as constant time implementation or side-channel attack resistance.** -`gurvy` is optimized for 64bits architectures (x86 `amd64`) and tested on Unix (Linux / macOS). - -## Curves supported - -* BLS12-381 (Zcash) -* BN256 (Ethereum) -* BLS377 (ZEXE) -* BW6-761 (EC supporting pairing on BLS377 field of definition) +`gnark-crypto` packages are optimized for 64bits architectures (x86 `amd64`) and tested on Unix (Linux / macOS). ## Getting started ### Go version -`gurvy` is tested with the last 2 major releases of Go (1.14 and 1.15). +`gnark-crypto` is tested with the last 2 major releases of Go (1.15 and 1.16). -### Install `gurvy` +### Install `gnark-crypto` ```bash -go get github.com/consensys/gurvy +go get github.com/consensys/gnark-crypto ``` Note if that if you use go modules, in `go.mod` the module path is case sensitive (use `consensys` and not `ConsenSys`). ### Documentation -[![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/consensys/gurvy)](https://pkg.go.dev/mod/github.com/consensys/gurvy) - -The APIs are consistent accross the curves. For example, [here is `bn256` godoc](https://pkg.go.dev/github.com/consensys/gurvy/bn256#pkg-overview). -## Benchmarks +[![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/consensys/gnark-crypto)](https://pkg.go.dev/mod/github.com/consensys/gnark-crypto) -Here are our measurements comparing `gurvy` (and [`goff` our finite field library](https://github.com/consensys/gurvy)) with [`mcl`](https://github.com/herumi/mcl). +The APIs are consistent accross the curves. For example, [here is `bn254` godoc](https://pkg.go.dev/github.com/consensys/gnark-crypto/ecc/bn254#pkg-overview). -These benchmarks ran on a AWS z1d.3xlarge instance, with hyperthreading disabled. +### Development -|bn256|mcl(ns/op)|gurvy & goff (ns/op)| -| -------- | -------- | -------- | -|Fp::Add |3.32| 3.44| -|Fp::Mul |18.43| 16.1| -|Fp::Square |18.64| 15.1| -|Fp::Inv |690.55 |2080*| -|Fp::Pow |6485| 7440*| -|G1::ScalarMul| 41394| 56900| -|G1::Add |213| 224| -|G1::Double |155| 178| -|G2::ScalarMul| 88423| 141000| -|G2::Add |598| 871| -|G2::Double |371| 386| -|Pairing |478244 |489258| +Most (but not all) of the code is generated from the templates in `internal/generator`. +The generated code contains little to no interfaces and is strongly typed with a base field (generated by the `gnark-crypto/field`). The two main factors driving this design choice are: ----- +1. Performance: `gnark-crypto` algorithms manipulates millions (if not billions) of field elements. Interface indirection at this level, plus garbage collection indexing takes a heavy toll on perf. +2. No generics in Go: need to derive (mostly) identical code for various moduli and curves, with consistent APIs +To regenerate the files, see `internal/generator/main.go`. Run: +``` +go generate ./internal/... +``` -|bls381|mcl(ns/op)|gurvy & goff (ns/op)| -| -------- | -------- | -------- | -|Fp::Add |5.42| 4.6| -|Fp::Mul |33.63| 29.3| -|Fp::Square |33.86| 27| -|Fp::Inv |1536 |4390*| -|Fp::Pow |18039| 18300*| -|G1::ScalarMul| 76799| 91500| -|G1::Add |424| 389| -|G1::Double |308| 301| -|G2::ScalarMul| 159068| 273000| -|G2::Add |1162| 1240| -|G2::Double |727| 799| -|Pairing |676513 |707984| +## Benchmarks -*note that some routines don't have assembly implementation in `goff` yet. +[Benchmarking pairing-friendly elliptic curves libraries](https://hackmd.io/@zkteam/eccbench) +>The libraries are implemented in different languages and some use more assembly code than others. Besides the different algorithmic and software optimizations used across, it should be noted also that some libraries target constant-time implementation for some operations making it de facto slower. However, it can be clear that consensys/gnark-crypto is one of the fastest pairing-friendly elliptic curve libraries to be used in zkp projects with different curves. ## Versioning -We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/consensys/gurvy/tags). +We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/consensys/gnark-crypto/tags). ## License diff --git a/crypto/hash/hashes.go b/crypto/hash/hashes.go new file mode 100644 index 0000000000..2b46e82995 --- /dev/null +++ b/crypto/hash/hashes.go @@ -0,0 +1,83 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package hash gathers the different custom hash functions (which +// are not available in golang's crypto library) built for being +// within a ZKP scheme. The structure of the package is similar to what +// can be found in golang's crypto/ package. +package hash + +import ( + "hash" + + bls377 "github.com/consensys/gnark-crypto/ecc/bls12-377/fr/mimc" + bls381 "github.com/consensys/gnark-crypto/ecc/bls12-381/fr/mimc" + bn254 "github.com/consensys/gnark-crypto/ecc/bn254/fr/mimc" + bw761 "github.com/consensys/gnark-crypto/ecc/bw6-761/fr/mimc" +) + +type Hash uint + +const ( + MIMC_BN254 Hash = iota + MIMC_BLS12_381 + MIMC_BLS12_377 + MIMC_BW6_761 +) + +// size of digests in bytes +var digestSize = []uint8{ + MIMC_BN254: 32, + MIMC_BLS12_381: 48, + MIMC_BLS12_377: 48, + MIMC_BW6_761: 96, +} + +// New creates the corresponding mimc hash function. +func (m Hash) New(seed string) hash.Hash { + switch m { + case MIMC_BN254: + return bn254.NewMiMC(seed) + case MIMC_BLS12_381: + return bls381.NewMiMC(seed) + case MIMC_BLS12_377: + return bls377.NewMiMC(seed) + case MIMC_BW6_761: + return bw761.NewMiMC(seed) + default: + panic("Unknown mimc ID") + } +} + +// String returns the mimc ID to string format. +func (m Hash) String() string { + switch m { + case MIMC_BN254: + return "MIMC_BN254" + case MIMC_BLS12_381: + return "MIMC_BLS381" + case MIMC_BLS12_377: + return "MIMC_BLS377" + case MIMC_BW6_761: + return "MIMC_BW761" + default: + panic("Unknown mimc ID") + } +} + +// Size returns the size of the digest of +// the corresponding hash function +func (m Hash) Size() int { + return int(digestSize[m]) +} diff --git a/crypto/signature/signature.go b/crypto/signature/signature.go new file mode 100644 index 0000000000..5eb773e41e --- /dev/null +++ b/crypto/signature/signature.go @@ -0,0 +1,102 @@ +/* +Copyright © 2020 ConsenSys + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package signature defines interfaces for a signer, +// a verifier and a signature. It eases up testing the +// corresponding ZK implementations accross different +// curves. +package signature + +import ( + "hash" + "io" +) + +// PublicKey public key interface. +// The public key has a Verify function to check signatures. +type PublicKey interface { + + // Verify verifies a signature of a message + // If hFunc is not provided, implementation may consider the message + // to be pre-hashed, else, will use hFunc to hash the message. + Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) + + // SetBytes sets p from binary representation in buf. + // buf represents a public key as x||y where x, y are + // interpreted as big endian binary numbers corresponding + // to the coordinates of a point on the twisted Edwards. + // It returns the number of bytes read from the buffer. + SetBytes(buf []byte) (int, error) + + // Bytes returns the binary representation of pk + // as x||y where x, y are the coordinates of the point + // on the twisted Edwards as big endian integers. + Bytes() []byte + + // Equal compares the public key to other. + Equal(other PublicKey) bool +} + +// Signer signer interface. +type Signer interface { + + // Public returns the public key associated to + // the signer's private key. + Public() PublicKey + + // Sign signs a message. If hFunc is not provided, implementation may consider the message + // to be pre-hashed, else, will use hFunc to hash the message. + // Returns Signature or error + Sign(message []byte, hFunc hash.Hash) ([]byte, error) + + // Bytes returns the binary representation of pk, + // as byte array publicKey||scalar||randSrc + // where publicKey is as publicKey.Bytes(), and + // scalar is in big endian, of size sizeFr. + Bytes() []byte + + // SetBytes sets pk from buf, where buf is interpreted + // as publicKey||scalar||randSrc + // where publicKey is as publicKey.Bytes(), and + // scalar is in big endian, of size sizeFr. + // It returns the number byte read. + SetBytes(buf []byte) (int, error) +} + +type SignatureScheme uint + +const maxSignatures = 4 + +const ( + EDDSA_BN254 SignatureScheme = iota + EDDSA_BLS12_381 + EDDSA_BLS12_377 + EDDSA_BW6_761 +) + +var signatures = make([]func(io.Reader) (Signer, error), maxSignatures) + +// Register registers a key pair generating function for a given signature scheme. +// We cannot import the corresponding constructors directly due to import cycles. +func Register(ss SignatureScheme, f func(io.Reader) (Signer, error)) { + signatures[ss] = f +} + +// New takes a source of randomness and returns a new key pair +func (ss SignatureScheme) New(r io.Reader) (Signer, error) { + f := signatures[ss] + return f(r) +} diff --git a/bls377/bls377.go b/ecc/bls12-377/bls12-377.go similarity index 92% rename from bls377/bls377.go rename to ecc/bls12-377/bls12-377.go index 50031e96ee..7f650cf1d1 100644 --- a/bls377/bls377.go +++ b/ecc/bls12-377/bls12-377.go @@ -1,13 +1,12 @@ -package bls377 +package bls12377 import ( "math/big" - "github.com/consensys/gurvy" - "github.com/consensys/gurvy/bls377/fp" - "github.com/consensys/gurvy/bls377/fr" - "github.com/consensys/gurvy/bls377/internal/fptower" - "github.com/consensys/gurvy/utils" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" ) // E: y**2=x**3+1 @@ -20,7 +19,7 @@ import ( // Fr: r=8444461749428370424248824938781546531375899335154063827935233455917409239041 (x**4-x**2+1) // ID bls377 ID -const ID = gurvy.BLS377 +const ID = ecc.BLS12_377 // bCurveCoeff b coeff of the curve var bCurveCoeff fp.Element @@ -59,7 +58,7 @@ var lambdaGLV big.Int // glvBasis stores R-linearly independant vectors (a,b), (c,d) // in ker((u,v)->u+vlambda[r]), and their determinant -var glvBasis utils.Lattice +var glvBasis ecc.Lattice // psi o pi o psi**-1, where psi:E->E' is the degree 6 iso defined over Fp12 var endo struct { @@ -112,7 +111,7 @@ func init() { thirdRootOneG2.Square(&thirdRootOneG1) lambdaGLV.SetString("91893752504881257701523279626832445440", 10) //(x**2-1) _r := fr.Modulus() - utils.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) endo.u.A0.SetString("80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410946") endo.v.A0.SetString("216465761340224619389371505802605247630151569547285782856803747159100223055385581585702401816380679166954762214499") diff --git a/bls381/fp/arith.go b/ecc/bls12-377/fp/arith.go similarity index 96% rename from bls381/fp/arith.go rename to ecc/bls12-377/fp/arith.go index a055885c03..66fa667482 100644 --- a/bls381/fp/arith.go +++ b/ecc/bls12-377/fp/arith.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bn256/fp/asm.go b/ecc/bls12-377/fp/asm.go similarity index 92% rename from bn256/fp/asm.go rename to ecc/bls12-377/fp/asm.go index 04495b0cfc..715bc7ac12 100644 --- a/bn256/fp/asm.go +++ b/ecc/bls12-377/fp/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bn256/fp/asm_noadx.go b/ecc/bls12-377/fp/asm_noadx.go similarity index 93% rename from bn256/fp/asm_noadx.go rename to ecc/bls12-377/fp/asm_noadx.go index e878f3473d..371bfeaeb3 100644 --- a/bn256/fp/asm_noadx.go +++ b/ecc/bls12-377/fp/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bls377/fp/element.go b/ecc/bls12-377/fp/element.go similarity index 99% rename from bls377/fp/element.go rename to ecc/bls12-377/fp/element.go index c19e4a74ff..332659643a 100644 --- a/bls377/fp/element.go +++ b/ecc/bls12-377/fp/element.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT // Package fp contains field arithmetic operations for modulus 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 package fp diff --git a/bls377/fp/element_mul_adx_amd64.s b/ecc/bls12-377/fp/element_mul_adx_amd64.s similarity index 100% rename from bls377/fp/element_mul_adx_amd64.s rename to ecc/bls12-377/fp/element_mul_adx_amd64.s diff --git a/bls377/fp/element_mul_amd64.s b/ecc/bls12-377/fp/element_mul_amd64.s similarity index 100% rename from bls377/fp/element_mul_amd64.s rename to ecc/bls12-377/fp/element_mul_amd64.s diff --git a/bls377/fp/element_ops_amd64.go b/ecc/bls12-377/fp/element_ops_amd64.go similarity index 94% rename from bls377/fp/element_ops_amd64.go rename to ecc/bls12-377/fp/element_ops_amd64.go index 7c3aa757be..71b26855b4 100644 --- a/bls377/fp/element_ops_amd64.go +++ b/ecc/bls12-377/fp/element_ops_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bls377/fp/element_ops_amd64.s b/ecc/bls12-377/fp/element_ops_amd64.s similarity index 100% rename from bls377/fp/element_ops_amd64.s rename to ecc/bls12-377/fp/element_ops_amd64.s diff --git a/bls381/fp/element_ops_noasm.go b/ecc/bls12-377/fp/element_ops_noasm.go similarity index 96% rename from bls381/fp/element_ops_noasm.go rename to ecc/bls12-377/fp/element_ops_noasm.go index 5563ce93fe..e6ced1bf56 100644 --- a/bls381/fp/element_ops_noasm.go +++ b/ecc/bls12-377/fp/element_ops_noasm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bls377/fp/element_test.go b/ecc/bls12-377/fp/element_test.go similarity index 99% rename from bls377/fp/element_test.go rename to ecc/bls12-377/fp/element_test.go index 17a72d9c64..93430fff59 100644 --- a/bls377/fp/element_test.go +++ b/ecc/bls12-377/fp/element_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp @@ -210,11 +210,6 @@ func TestElementCmp(t *testing.T) { } } -func TestElementSetInterface(t *testing.T) { - // TODO - t.Skip("not implemented") -} - func TestElementIsRandom(t *testing.T) { for i := 0; i < 50; i++ { var x, y Element diff --git a/bn256/fr/arith.go b/ecc/bls12-377/fr/arith.go similarity index 96% rename from bn256/fr/arith.go rename to ecc/bls12-377/fr/arith.go index 9f42f6641f..83c9fd9ef9 100644 --- a/bn256/fr/arith.go +++ b/ecc/bls12-377/fr/arith.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bn256/fr/asm.go b/ecc/bls12-377/fr/asm.go similarity index 92% rename from bn256/fr/asm.go rename to ecc/bls12-377/fr/asm.go index 7c77fecb17..f859dd8731 100644 --- a/bn256/fr/asm.go +++ b/ecc/bls12-377/fr/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bls377/fr/asm_noadx.go b/ecc/bls12-377/fr/asm_noadx.go similarity index 93% rename from bls377/fr/asm_noadx.go rename to ecc/bls12-377/fr/asm_noadx.go index 3b2f49bd87..ab9b869b5b 100644 --- a/bls377/fr/asm_noadx.go +++ b/ecc/bls12-377/fr/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bls377/fr/element.go b/ecc/bls12-377/fr/element.go similarity index 99% rename from bls377/fr/element.go rename to ecc/bls12-377/fr/element.go index 7d36ab8333..bbbb80acef 100644 --- a/bls377/fr/element.go +++ b/ecc/bls12-377/fr/element.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT // Package fr contains field arithmetic operations for modulus 8444461749428370424248824938781546531375899335154063827935233455917409239041 package fr diff --git a/bls377/fr/element_mul_adx_amd64.s b/ecc/bls12-377/fr/element_mul_adx_amd64.s similarity index 100% rename from bls377/fr/element_mul_adx_amd64.s rename to ecc/bls12-377/fr/element_mul_adx_amd64.s diff --git a/bls377/fr/element_mul_amd64.s b/ecc/bls12-377/fr/element_mul_amd64.s similarity index 100% rename from bls377/fr/element_mul_amd64.s rename to ecc/bls12-377/fr/element_mul_amd64.s diff --git a/bn256/fr/element_ops_amd64.go b/ecc/bls12-377/fr/element_ops_amd64.go similarity index 94% rename from bn256/fr/element_ops_amd64.go rename to ecc/bls12-377/fr/element_ops_amd64.go index 73ae624914..f0d8316e52 100644 --- a/bn256/fr/element_ops_amd64.go +++ b/ecc/bls12-377/fr/element_ops_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bls377/fr/element_ops_amd64.s b/ecc/bls12-377/fr/element_ops_amd64.s similarity index 100% rename from bls377/fr/element_ops_amd64.s rename to ecc/bls12-377/fr/element_ops_amd64.s diff --git a/bn256/fr/element_ops_noasm.go b/ecc/bls12-377/fr/element_ops_noasm.go similarity index 96% rename from bn256/fr/element_ops_noasm.go rename to ecc/bls12-377/fr/element_ops_noasm.go index e902f2906a..e7daa4d40e 100644 --- a/bn256/fr/element_ops_noasm.go +++ b/ecc/bls12-377/fr/element_ops_noasm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bls377/fr/element_test.go b/ecc/bls12-377/fr/element_test.go similarity index 99% rename from bls377/fr/element_test.go rename to ecc/bls12-377/fr/element_test.go index 21414f3ed1..aa43c1a393 100644 --- a/bls377/fr/element_test.go +++ b/ecc/bls12-377/fr/element_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr @@ -206,11 +206,6 @@ func TestElementCmp(t *testing.T) { } } -func TestElementSetInterface(t *testing.T) { - // TODO - t.Skip("not implemented") -} - func TestElementIsRandom(t *testing.T) { for i := 0; i < 50; i++ { var x, y Element diff --git a/ecc/bls12-377/fr/fft/domain.go b/ecc/bls12-377/fr/fft/domain.go new file mode 100644 index 0000000000..e0a13580d4 --- /dev/null +++ b/ecc/bls12-377/fr/fft/domain.go @@ -0,0 +1,271 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "io" + "math/big" + "math/bits" + "runtime" + "sync" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" +) + +// Domain with a power of 2 cardinality +// compute a field element of order 2x and store it in FinerGenerator +// all other values can be derived from x, GeneratorSqrt +type Domain struct { + Cardinality uint64 + Depth uint64 + CardinalityInv fr.Element + Generator fr.Element + GeneratorInv fr.Element + FinerGenerator fr.Element + FinerGeneratorInv fr.Element + + // the following slices are not serialized and are (re)computed through domain.preComputeTwiddles() + + // Twiddles factor for the FFT using Generator for each stage of the recursive FFT + Twiddles [][]fr.Element + + // Twiddles factor for the FFT using GeneratorInv for each stage of the recursive FFT + TwiddlesInv [][]fr.Element + + // we precompute these mostly to avoid the memory intensive bit reverse permutation in the groth16.Prover + + // CosetTable[i][j] = domain.Generator(i-th)Sqrt ^ j + // CosetTable = fft.BitReverse(CosetTable) + CosetTable [][]fr.Element + + // CosetTable[i][j] = domain.Generator(i-th)SqrtInv ^ j + // CosetTableInv = fft.BitReverse(CosetTableInv) + CosetTableInv [][]fr.Element +} + +// NewDomain returns a subgroup with a power of 2 cardinality +// cardinality >= m +// If depth>0, the Domain will also store a primitive (2**depth)*m root +// of 1, with associated precomputed data. This allows to perform shifted +// FFT/FFTInv. +// +// example: +// -------- +// +// NewDomain(m, 2) outputs a new domain to perform fft on Z/mZ, plus a primitive +// 2**2*m=4m-th root of 1 and associated data to compute fft/fftinv on the cosets of +// (Z/4mZ)/(Z/mZ). +func NewDomain(m, depth uint64) *Domain { + + // generator of the largest 2-adic subgroup + var rootOfUnity fr.Element + + rootOfUnity.SetString("8065159656716812877374967518403273466521432693661810619979959746626482506078") + const maxOrderRoot uint64 = 47 + + subGroup := &Domain{} + x := nextPowerOfTwo(m) + subGroup.Cardinality = uint64(x) + subGroup.Depth = depth + + // find generator for Z/2^(log(m))Z and Z/2^(log(m)+cosets)Z + logx := uint64(bits.TrailingZeros64(x)) + if logx > maxOrderRoot { + panic("m is too big: the required root of unity does not exist") + } + logGen := logx + depth + if logGen > maxOrderRoot { + panic("log(m) + cosets is too big: the required root of unity does not exist") + } + + expo := uint64(1 << (maxOrderRoot - logGen)) + bExpo := new(big.Int).SetUint64(expo) + subGroup.FinerGenerator.Exp(rootOfUnity, bExpo) + subGroup.FinerGeneratorInv.Inverse(&subGroup.FinerGenerator) + + // Generator = FinerGenerator^2 has order x + expo = uint64(1 << (maxOrderRoot - logx)) + bExpo.SetUint64(expo) + subGroup.Generator.Exp(rootOfUnity, bExpo) // order x + subGroup.GeneratorInv.Inverse(&subGroup.Generator) + subGroup.CardinalityInv.SetUint64(uint64(x)).Inverse(&subGroup.CardinalityInv) + + // twiddle factors + subGroup.preComputeTwiddles() + + return subGroup +} + +func (d *Domain) preComputeTwiddles() { + + // nb fft stages + nbStages := uint64(bits.TrailingZeros64(d.Cardinality)) + nbCosets := (1 << d.Depth) - 1 + + d.Twiddles = make([][]fr.Element, nbStages) + d.TwiddlesInv = make([][]fr.Element, nbStages) + d.CosetTable = make([][]fr.Element, nbCosets) + d.CosetTableInv = make([][]fr.Element, nbCosets) + for i := 0; i < nbCosets; i++ { + d.CosetTable[i] = make([]fr.Element, d.Cardinality) + d.CosetTableInv[i] = make([]fr.Element, d.Cardinality) + } + + var wg sync.WaitGroup + + // for each fft stage, we pre compute the twiddle factors + twiddles := func(t [][]fr.Element, omega fr.Element) { + for i := uint64(0); i < nbStages; i++ { + t[i] = make([]fr.Element, 1+(1<<(nbStages-i-1))) + var w fr.Element + if i == 0 { + w = omega + } else { + w = t[i-1][2] + } + t[i][0] = fr.One() + t[i][1] = w + for j := 2; j < len(t[i]); j++ { + t[i][j].Mul(&t[i][j-1], &w) + } + } + wg.Done() + } + + expTable := func(sqrt fr.Element, t []fr.Element) { + t[0] = fr.One() + precomputeExpTable(sqrt, t) + wg.Done() + } + + if nbCosets > 0 { + cosetGens := make([]fr.Element, nbCosets) + cosetGensInv := make([]fr.Element, nbCosets) + cosetGens[0].Set(&d.FinerGenerator) + cosetGensInv[0].Set(&d.FinerGeneratorInv) + for i := 1; i < nbCosets; i++ { + cosetGens[i].Mul(&cosetGens[i-1], &d.FinerGenerator) + cosetGensInv[i].Mul(&cosetGensInv[1], &d.FinerGeneratorInv) + } + wg.Add(2 + 2*nbCosets) + go twiddles(d.Twiddles, d.Generator) + go twiddles(d.TwiddlesInv, d.GeneratorInv) + for i := 0; i < nbCosets-1; i++ { + go expTable(cosetGens[i], d.CosetTable[i]) + go expTable(cosetGensInv[i], d.CosetTableInv[i]) + } + go expTable(cosetGens[nbCosets-1], d.CosetTable[nbCosets-1]) + expTable(cosetGensInv[nbCosets-1], d.CosetTableInv[nbCosets-1]) + + wg.Wait() + + } else { + wg.Add(2) + go twiddles(d.Twiddles, d.Generator) + twiddles(d.TwiddlesInv, d.GeneratorInv) + wg.Wait() + } + +} + +func precomputeExpTable(w fr.Element, table []fr.Element) { + n := len(table) + + // see if it makes sense to parallelize exp tables pre-computation + interval := 0 + if runtime.NumCPU() >= 4 { + interval = (n - 1) / (runtime.NumCPU() / 4) + } + + // this ratio roughly correspond to the number of multiplication one can do in place of a Exp operation + const ratioExpMul = 6000 / 17 + + if interval < ratioExpMul { + precomputeExpTableChunk(w, 1, table[1:]) + return + } + + // we parallelize + var wg sync.WaitGroup + for i := 1; i < n; i += interval { + start := i + end := i + interval + if end > n { + end = n + } + wg.Add(1) + go func() { + precomputeExpTableChunk(w, uint64(start), table[start:end]) + wg.Done() + }() + } + wg.Wait() +} + +func precomputeExpTableChunk(w fr.Element, power uint64, table []fr.Element) { + table[0].Exp(w, new(big.Int).SetUint64(power)) + for i := 1; i < len(table); i++ { + table[i].Mul(&table[i-1], &w) + } +} + +func nextPowerOfTwo(n uint64) uint64 { + p := uint64(1) + if (n & (n - 1)) == 0 { + return n + } + for p < n { + p <<= 1 + } + return p +} + +// WriteTo writes a binary representation of the domain (without the precomputed twiddle factors) +// to the provided writer +func (d *Domain) WriteTo(w io.Writer) (int64, error) { + + enc := curve.NewEncoder(w) + + toEncode := []interface{}{d.Cardinality, d.Depth, &d.CardinalityInv, &d.Generator, &d.GeneratorInv, &d.FinerGenerator, &d.FinerGeneratorInv} + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom attempts to decode a domain from Reader +func (d *Domain) ReadFrom(r io.Reader) (int64, error) { + + dec := curve.NewDecoder(r) + + toDecode := []interface{}{&d.Cardinality, &d.Depth, &d.CardinalityInv, &d.Generator, &d.GeneratorInv, &d.FinerGenerator, &d.FinerGeneratorInv} + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + d.preComputeTwiddles() + return dec.BytesRead(), nil +} diff --git a/ecc/bls12-377/fr/fft/domain_test.go b/ecc/bls12-377/fr/fft/domain_test.go new file mode 100644 index 0000000000..e3c1d71978 --- /dev/null +++ b/ecc/bls12-377/fr/fft/domain_test.go @@ -0,0 +1,47 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "bytes" + "reflect" + "testing" +) + +func TestDomainSerialization(t *testing.T) { + + domain := NewDomain(1<<6, 1) + var reconstructed Domain + + var buf bytes.Buffer + written, err := domain.WriteTo(&buf) + if err != nil { + t.Fatal(err) + } + var read int64 + read, err = reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal(err) + } + + if written != read { + t.Fatal("didn't read as many bytes as we wrote") + } + if !reflect.DeepEqual(domain, &reconstructed) { + t.Fatal("Domain.SetBytes(Bytes()) failed") + } +} diff --git a/ecc/bls12-377/fr/fft/fft.go b/ecc/bls12-377/fr/fft/fft.go new file mode 100644 index 0000000000..413014c7c5 --- /dev/null +++ b/ecc/bls12-377/fr/fft/fft.go @@ -0,0 +1,265 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/internal/parallel" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +) + +// Decimation is used in the FFT call to select decimation in time or in frequency +type Decimation uint8 + +const ( + DIT Decimation = iota + DIF +) + +// parallelize threshold for a single butterfly op, if the fft stage is not parallelized already +const butterflyThreshold = 16 + +// FFT computes (recursively) the discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +// +// example: +// ------- +// domain := NewDomain(m, 2) --> contains precomputed data for Z/mZ, and Z/4mZ +// FFT(pol, DIT, 1) --> evaluates pol on the coset 1 in (Z/4mZ)/(Z/mZ) +func (domain *Domain) FFT(a []fr.Element, decimation Decimation, coset uint64) { + + numCPU := uint64(runtime.NumCPU()) + + if coset != 0 { + if decimation == DIT { + BitReverse(domain.CosetTable[coset-1]) + } + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].Mul(&a[i], &domain.CosetTable[coset-1][i]) + } + }) + // put it back as we found it + if decimation == DIT { + BitReverse(domain.CosetTable[coset-1]) + } + } + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(nextPowerOfTwo(numCPU)) + if numCPU <= 1 { + maxSplits = -1 + } + + switch decimation { + case DIF: + difFFT(a, domain.Twiddles, 0, maxSplits, nil) + case DIT: + ditFFT(a, domain.Twiddles, 0, maxSplits, nil) + default: + panic("not implemented") + } +} + +// FFTInverse computes (recursively) the inverse discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +func (domain *Domain) FFTInverse(a []fr.Element, decimation Decimation, coset uint64) { + + numCPU := uint64(runtime.NumCPU()) + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(nextPowerOfTwo(numCPU)) + if numCPU <= 1 { + maxSplits = -1 + } + switch decimation { + case DIF: + difFFT(a, domain.TwiddlesInv, 0, maxSplits, nil) + case DIT: + ditFFT(a, domain.TwiddlesInv, 0, maxSplits, nil) + default: + panic("not implemented") + } + + // scale by CardinalityInv (+ cosetTableInv is coset!=0) + if coset != 0 { + if decimation == DIF { + BitReverse(domain.CosetTableInv[coset-1]) + } + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].Mul(&a[i], &domain.CosetTableInv[coset-1][i]). + MulAssign(&domain.CardinalityInv) + } + }) + // put it back as we found it + if decimation == DIF { + BitReverse(domain.CosetTableInv[coset-1]) + } + } else { + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].MulAssign(&domain.CardinalityInv) + } + }) + } +} + +func difFFT(a []fr.Element, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer func() { + chDone <- struct{}{} + }() + } + n := len(a) + if n == 1 { + return + } + m := n >> 1 + + // if stage < maxSplits, we parallelize this butterfly + // but we have only numCPU / stage cpus available + if (m > butterflyThreshold) && (stage < maxSplits) { + // 1 << stage == estimated used CPUs + numCPU := runtime.NumCPU() / (1 << (stage)) + parallel.Execute(m, func(start, end int) { + var t fr.Element + for i := start; i < end; i++ { + t = a[i] + a[i].Add(&a[i], &a[i+m]) + + a[i+m]. + Sub(&t, &a[i+m]). + Mul(&a[i+m], &twiddles[stage][i]) + } + }, numCPU) + } else { + var t fr.Element + + // i == 0 + t = a[0] + a[0].Add(&a[0], &a[m]) + a[m].Sub(&t, &a[m]) + + for i := 1; i < m; i++ { + t = a[i] + a[i].Add(&a[i], &a[i+m]) + + a[i+m]. + Sub(&t, &a[i+m]). + Mul(&a[i+m], &twiddles[stage][i]) + } + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFT(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFT(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} + +func ditFFT(a []fr.Element, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer func() { + chDone <- struct{}{} + }() + } + n := len(a) + if n == 1 { + return + } + m := n >> 1 + + nextStage := stage + 1 + + if stage < maxSplits { + // that's the only time we fire go routines + chDone := make(chan struct{}, 1) + go ditFFT(a[m:], twiddles, nextStage, maxSplits, chDone) + ditFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + ditFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + ditFFT(a[m:n], twiddles, nextStage, maxSplits, nil) + + } + + // if stage < maxSplits, we parallelize this butterfly + // but we have only numCPU / stage cpus available + if (m > butterflyThreshold) && (stage < maxSplits) { + // 1 << stage == estimated used CPUs + numCPU := runtime.NumCPU() / (1 << (stage)) + parallel.Execute(m, func(start, end int) { + var t, tm fr.Element + for k := start; k < end; k++ { + t = a[k] + tm.Mul(&a[k+m], &twiddles[stage][k]) + a[k].Add(&a[k], &tm) + a[k+m].Sub(&t, &tm) + } + }, numCPU) + + } else { + var t, tm fr.Element + // k == 0 + // wPow == 1 + t = a[0] + a[0].Add(&a[0], &a[m]) + a[m].Sub(&t, &a[m]) + + for k := 1; k < m; k++ { + t = a[k] + tm.Mul(&a[k+m], &twiddles[stage][k]) + a[k].Add(&a[k], &tm) + a[k+m].Sub(&t, &tm) + } + } +} + +// BitReverse applies the bit-reversal permutation to a. +// len(a) must be a power of 2 (as in every single function in this file) +func BitReverse(a []fr.Element) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} diff --git a/ecc/bls12-377/fr/fft/fft_test.go b/ecc/bls12-377/fr/fft/fft_test.go new file mode 100644 index 0000000000..a20b7474aa --- /dev/null +++ b/ecc/bls12-377/fr/fft/fft_test.go @@ -0,0 +1,205 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "math/big" + "strconv" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" + "github.com/leanovate/gopter/prop" +) + +func TestFFT(t *testing.T) { + const maxSize = 1 << 10 + + domain := NewDomain(maxSize, 0) + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 5 + + properties := gopter.NewProperties(parameters) + + properties.Property("DIF FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domain.FFT(pol, DIF, 0) + BitReverse(pol) + + sample := domain.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := evaluatePolynomial(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("DIT FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverse(pol) + domain.FFT(pol, DIT, 0) + + sample := domain.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := evaluatePolynomial(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("bitReverse(DIF FFT(DIT FFT (bitReverse))))==id", prop.ForAll( + + func() bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverse(pol) + domain.FFT(pol, DIT, 0) + domain.FFTInverse(pol, DIF, 0) + BitReverse(pol) + + check := true + for i := 0; i < len(pol); i++ { + check = check && pol[i].Equal(&backupPol[i]) + } + return check + }, + )) + + properties.Property("DIT FFT(DIF FFT)==id", prop.ForAll( + + func() bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domain.FFTInverse(pol, DIF, 0) + domain.FFT(pol, DIT, 0) + + check := true + for i := 0; i < len(pol); i++ { + check = check && (pol[i] == backupPol[i]) + } + return check + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + +} + +// -------------------------------------------------------------------- +// benches +func BenchmarkBitReverse(b *testing.B) { + + const maxSize = 1 << 20 + + pol := make([]fr.Element, maxSize) + for i := uint64(0); i < maxSize; i++ { + pol[i].SetRandom() + } + + for i := 8; i < 20; i++ { + b.Run("bit reversing 2**"+strconv.Itoa(i)+"bits", func(b *testing.B) { + _pol := make([]fr.Element, 1< .. || 0x0000...0af8 + if len(d.data)%BlockSize != 0 { + q := len(d.data) / BlockSize + r := len(d.data) % BlockSize + sliceq := make([]byte, q*BlockSize) + copy(sliceq, d.data) + slicer := make([]byte, r) + copy(slicer, d.data[q*BlockSize:]) + sliceremainder := make([]byte, BlockSize-r) + d.data = append(sliceq, sliceremainder...) + d.data = append(d.data, slicer...) + } + + if len(d.data) == 0 { + d.data = make([]byte, 32) + } + + nbChunks := len(d.data) / BlockSize + + for i := 0; i < nbChunks; i++ { + copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) + x.SetBytes(buffer[:]) + d.encrypt(x) + d.h.Add(&x, &d.h) + } + + return d.h +} + +// plain execution of a mimc run +// m: message +// k: encryption key +func (d *digest) encrypt(m fr.Element) { + + for i := 0; i < len(d.Params); i++ { + // m = (m+k+c)^**-1 + m.Add(&m, &d.h).Add(&m, &d.Params[i]).Inverse(&m) + } + m.Add(&m, &d.h) + d.h = m +} + +// Sum computes the mimc hash of msg from seed +func Sum(seed string, msg []byte) ([]byte, error) { + params := NewParams(seed) + var d digest + d.Params = params + if _, err := d.Write(msg); err != nil { + return nil, err + } + h := d.checksum() + bytes := h.Bytes() + return bytes[:], nil +} diff --git a/ecc/bls12-377/fr/polynomial/polynomial.go b/ecc/bls12-377/fr/polynomial/polynomial.go new file mode 100644 index 0000000000..c7cddf3b51 --- /dev/null +++ b/ecc/bls12-377/fr/polynomial/polynomial.go @@ -0,0 +1,43 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package polynomial + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +) + +// Polynomial polynomial represented by coefficients bls12-377 fr field. +type Polynomial []fr.Element + +// Degree returns the degree of the polynomial, which is the length of Data. +func (p Polynomial) Degree() uint64 { + res := uint64(len(p) - 1) + return res +} + +// Eval evaluates p at v +func (p Polynomial) Eval(v interface{}) interface{} { + var res, _v fr.Element + _v.Set(v.(*fr.Element)) + s := len(p) + res.Set(&p[s-1]) + for i := s - 2; i >= 0; i-- { + res.Mul(&res, &_v) + res.Add(&res, &p[i]) + } + return &res +} diff --git a/bls377/g1.go b/ecc/bls12-377/g1.go similarity index 98% rename from bls377/g1.go rename to ecc/bls12-377/g1.go index 3776d71a16..6ce98e9136 100644 --- a/bls377/g1.go +++ b/ecc/bls12-377/g1.go @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls377 +package bls12377 import ( "math/big" - "github.com/consensys/gurvy/bls377/fp" - "github.com/consensys/gurvy/bls377/fr" - "github.com/consensys/gurvy/utils" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/internal/parallel" ) // G1Affine point in affine coordinates @@ -411,7 +411,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { table[3].phi(a) // split the scalar, modifies +-a, phi(a) accordingly - k := utils.SplitScalar(s, &glvBasis) + k := ecc.SplitScalar(s, &glvBasis) if k[0].Cmp(&zero) == -1 { k[0].Neg(&k[0]) diff --git a/bls381/g1_test.go b/ecc/bls12-377/g1_test.go similarity index 83% rename from bls381/g1_test.go rename to ecc/bls12-377/g1_test.go index eae6d35303..715ac51a04 100644 --- a/bls381/g1_test.go +++ b/ecc/bls12-377/g1_test.go @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls381 +package bls12377 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bls381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" - "github.com/consensys/gurvy/bls381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -86,7 +86,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { properties := gopter.NewProperties(parameters) genFuzz1 := GenFp() - properties.Property("[BLS381] g1Gen (affine) should be on the curve", prop.ForAll( + properties.Property("[BLS12-377] g1Gen (affine) should be on the curve", prop.ForAll( func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) @@ -97,7 +97,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] g1Gen (Jacobian) should be on the curve", prop.ForAll( + properties.Property("[BLS12-377] g1Gen (Jacobian) should be on the curve", prop.ForAll( func(a fp.Element) bool { var op1, op2, op3 G1Jac op1.Set(&g1Gen) @@ -122,7 +122,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1 := GenFp() genFuzz2 := GenFp() - properties.Property("[BLS381] Affine representation should be independent of the Jacobian representative", prop.ForAll( + properties.Property("[BLS12-377] Affine representation should be independent of the Jacobian representative", prop.ForAll( func(a fp.Element) bool { g := fuzzJacobianG1Affine(&g1Gen, a) var op1 G1Affine @@ -132,7 +132,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( + properties.Property("[BLS12-377] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( func(a fp.Element) bool { var g g1JacExtended g.X.Set(&g1Gen.X) @@ -148,7 +148,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] Jacobian representation should be the same as the affine representative", prop.ForAll( + properties.Property("[BLS12-377] Jacobian representation should be the same as the affine representative", prop.ForAll( func(a fp.Element) bool { var g G1Jac var op1 G1Affine @@ -165,7 +165,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( + properties.Property("[BLS12-377] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( func() bool { var g G1Affine g.X.SetZero() @@ -178,7 +178,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS381] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( + properties.Property("[BLS12-377] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( func() bool { var g G1Affine var op1 g1JacExtended @@ -190,7 +190,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS381] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( + properties.Property("[BLS12-377] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( func() bool { var g G1Jac var op1 g1JacExtended @@ -203,7 +203,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS381] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( func(a, b fp.Element) bool { op1 := fuzzJacobianG1Affine(&g1Gen, a) op2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -227,7 +227,7 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() - properties.Property("[BLS381] [Jacobian] Add should call double when having adding the same point", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -240,7 +240,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BLS381] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -252,7 +252,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BLS381] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop1.AddAssign(&g1Infinity) @@ -264,7 +264,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) var p1, p1Neg G1Affine @@ -283,7 +283,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) var p1, p1Neg G1Affine @@ -302,7 +302,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop1.Neg(&fop1) @@ -314,7 +314,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BLS12-377] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -337,7 +337,7 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BLS381] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BLS12-377] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -360,7 +360,7 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BLS381] GLV and Double and Add should output the same result", prop.ForAll( + properties.Property("[BLS12-377] GLV and Double and Add should output the same result", prop.ForAll( func(s fr.Element) bool { var r big.Int @@ -384,7 +384,7 @@ func TestG1AffineCofactorCleaning(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BLS381] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( + properties.Property("[BLS12-377] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( func() bool { var a, x, b fp.Element a.SetRandom() @@ -424,7 +424,7 @@ func TestG1AffineBatchScalarMultiplication(t *testing.T) { // size of the multiExps const nbSamples = 10 - properties.Property("[BLS381] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( + properties.Property("[BLS12-377] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( func(mixer fr.Element) bool { // mixer ensures that all the words of a fpElement are set var sampleScalars [nbSamples]fr.Element diff --git a/bls377/g2.go b/ecc/bls12-377/g2.go similarity index 98% rename from bls377/g2.go rename to ecc/bls12-377/g2.go index 4dfb199cb5..a39e634884 100644 --- a/bls377/g2.go +++ b/ecc/bls12-377/g2.go @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls377 +package bls12377 import ( "math/big" - "github.com/consensys/gurvy/bls377/fr" - "github.com/consensys/gurvy/bls377/internal/fptower" - "github.com/consensys/gurvy/utils" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" ) // G2Affine point in affine coordinates @@ -425,7 +425,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { table[3].phi(a) // split the scalar, modifies +-a, phi(a) accordingly - k := utils.SplitScalar(s, &glvBasis) + k := ecc.SplitScalar(s, &glvBasis) if k[0].Cmp(&zero) == -1 { k[0].Neg(&k[0]) diff --git a/bls377/g2_test.go b/ecc/bls12-377/g2_test.go similarity index 82% rename from bls377/g2_test.go rename to ecc/bls12-377/g2_test.go index 2cf8031719..ddde32e0ec 100644 --- a/bls377/g2_test.go +++ b/ecc/bls12-377/g2_test.go @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls377 +package bls12377 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bls377/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" - "github.com/consensys/gurvy/bls377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -86,7 +86,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { properties := gopter.NewProperties(parameters) genFuzz1 := GenE2() - properties.Property("[BLS377] g2Gen (affine) should be on the curve", prop.ForAll( + properties.Property("[BLS12-377] g2Gen (affine) should be on the curve", prop.ForAll( func(a *fptower.E2) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) @@ -97,7 +97,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] g2Gen (Jacobian) should be on the curve", prop.ForAll( + properties.Property("[BLS12-377] g2Gen (Jacobian) should be on the curve", prop.ForAll( func(a *fptower.E2) bool { var op1, op2, op3 G2Jac op1.Set(&g2Gen) @@ -122,7 +122,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1 := GenE2() genFuzz2 := GenE2() - properties.Property("[BLS377] Affine representation should be independent of the Jacobian representative", prop.ForAll( + properties.Property("[BLS12-377] Affine representation should be independent of the Jacobian representative", prop.ForAll( func(a *fptower.E2) bool { g := fuzzJacobianG2Affine(&g2Gen, a) var op1 G2Affine @@ -132,7 +132,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( + properties.Property("[BLS12-377] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( func(a *fptower.E2) bool { var g g2JacExtended g.X.Set(&g2Gen.X) @@ -148,7 +148,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] Jacobian representation should be the same as the affine representative", prop.ForAll( + properties.Property("[BLS12-377] Jacobian representation should be the same as the affine representative", prop.ForAll( func(a *fptower.E2) bool { var g G2Jac var op1 G2Affine @@ -165,7 +165,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( + properties.Property("[BLS12-377] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( func() bool { var g G2Affine g.X.SetZero() @@ -178,7 +178,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS377] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( + properties.Property("[BLS12-377] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( func() bool { var g G2Affine var op1 g2JacExtended @@ -190,7 +190,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS377] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( + properties.Property("[BLS12-377] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( func() bool { var g G2Jac var op1 g2JacExtended @@ -203,7 +203,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS377] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( func(a, b *fptower.E2) bool { op1 := fuzzJacobianG2Affine(&g2Gen, a) op2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -227,7 +227,7 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() - properties.Property("[BLS377] [Jacobian] Add should call double when having adding the same point", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -240,7 +240,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BLS377] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( func(a, b *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -252,7 +252,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BLS377] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop1.AddAssign(&g2Infinity) @@ -264,7 +264,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) var p1, p1Neg G2Affine @@ -283,7 +283,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) var p1, p1Neg G2Affine @@ -302,7 +302,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( + properties.Property("[BLS12-377] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop1.Neg(&fop1) @@ -314,7 +314,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BLS12-377] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -337,7 +337,7 @@ func TestG2AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BLS377] psi should map points from E' to itself", prop.ForAll( + properties.Property("[BLS12-377] psi should map points from E' to itself", prop.ForAll( func() bool { var a G2Jac a.psi(&g2Gen) @@ -345,7 +345,7 @@ func TestG2AffineOps(t *testing.T) { }, )) - properties.Property("[BLS377] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BLS12-377] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -368,7 +368,7 @@ func TestG2AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BLS377] GLV and Double and Add should output the same result", prop.ForAll( + properties.Property("[BLS12-377] GLV and Double and Add should output the same result", prop.ForAll( func(s fr.Element) bool { var r big.Int @@ -392,7 +392,7 @@ func TestG2AffineCofactorCleaning(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BLS377] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( + properties.Property("[BLS12-377] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( func() bool { var a, x, b fptower.E2 a.SetRandom() @@ -429,7 +429,7 @@ func TestG2AffineBatchScalarMultiplication(t *testing.T) { // size of the multiExps const nbSamples = 10 - properties.Property("[BLS377] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( + properties.Property("[BLS12-377] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( func(mixer fr.Element) bool { // mixer ensures that all the words of a fpElement are set var sampleScalars [nbSamples]fr.Element diff --git a/bls377/hash_to_curve.go b/ecc/bls12-377/hash_to_curve.go similarity index 97% rename from bls377/hash_to_curve.go rename to ecc/bls12-377/hash_to_curve.go index 07e2ad1f35..e112cbf22c 100644 --- a/bls377/hash_to_curve.go +++ b/ecc/bls12-377/hash_to_curve.go @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bls377 +package bls12377 import ( "math/big" - "github.com/consensys/gurvy/bls377/fp" - "github.com/consensys/gurvy/bls377/internal/fptower" - "github.com/consensys/gurvy/utils" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" ) // hashToFp hashes msg to count prime field elements. @@ -31,7 +31,7 @@ func hashToFp(msg, dst []byte, count int) ([]fp.Element, error) { L := 64 lenInBytes := count * L - pseudoRandomBytes, err := utils.ExpandMsgXmd(msg, dst, lenInBytes) + pseudoRandomBytes, err := ecc.ExpandMsgXmd(msg, dst, lenInBytes) if err != nil { return nil, err } diff --git a/bls377/internal/fptower/asm.go b/ecc/bls12-377/internal/fptower/asm.go similarity index 93% rename from bls377/internal/fptower/asm.go rename to ecc/bls12-377/internal/fptower/asm.go index 1458123a3d..c7bb911dfb 100644 --- a/bls377/internal/fptower/asm.go +++ b/ecc/bls12-377/internal/fptower/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bls381/internal/fptower/asm_noadx.go b/ecc/bls12-377/internal/fptower/asm_noadx.go similarity index 93% rename from bls381/internal/fptower/asm_noadx.go rename to ecc/bls12-377/internal/fptower/asm_noadx.go index cea2d1b95a..f09b13900c 100644 --- a/bls381/internal/fptower/asm_noadx.go +++ b/ecc/bls12-377/internal/fptower/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bls377/internal/fptower/e12.go b/ecc/bls12-377/internal/fptower/e12.go similarity index 98% rename from bls377/internal/fptower/e12.go rename to ecc/bls12-377/internal/fptower/e12.go index 0a831d329e..d0d9bb66f0 100644 --- a/bls377/internal/fptower/e12.go +++ b/ecc/bls12-377/internal/fptower/e12.go @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower import ( "encoding/binary" "errors" - "github.com/consensys/gurvy/bls377/fp" - "github.com/consensys/gurvy/bls377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "math/big" ) diff --git a/bls377/internal/fptower/e12_pairing.go b/ecc/bls12-377/internal/fptower/e12_pairing.go similarity index 100% rename from bls377/internal/fptower/e12_pairing.go rename to ecc/bls12-377/internal/fptower/e12_pairing.go diff --git a/bls377/internal/fptower/e12_test.go b/ecc/bls12-377/internal/fptower/e12_test.go similarity index 74% rename from bls377/internal/fptower/e12_test.go rename to ecc/bls12-377/internal/fptower/e12_test.go index 90973a0fd0..7cae098c36 100644 --- a/bls377/internal/fptower/e12_test.go +++ b/ecc/bls12-377/internal/fptower/e12_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower @@ -35,7 +35,7 @@ func TestE12Serialization(t *testing.T) { genA := GenE12() - properties.Property("[BLS377] SetBytes(Bytes()) should stay constant", prop.ForAll( + properties.Property("[BLS12-377] SetBytes(Bytes()) should stay constant", prop.ForAll( func(a *E12) bool { var b E12 buf := a.Bytes() @@ -60,7 +60,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA := GenE12() genB := GenE12() - properties.Property("[BLS377] Having the receiver as operand (addition) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (addition) should output the same result", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Set(a) @@ -73,7 +73,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS377] Having the receiver as operand (sub) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (sub) should output the same result", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Set(a) @@ -86,7 +86,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS377] Having the receiver as operand (mul) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (mul) should output the same result", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Set(a) @@ -99,7 +99,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS377] Having the receiver as operand (square) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (square) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Square(a) @@ -109,7 +109,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (double) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (double) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Double(a) @@ -119,7 +119,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Inverse(a) @@ -129,7 +129,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (Cyclotomic square) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (Cyclotomic square) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.CyclotomicSquare(a) @@ -139,7 +139,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Conjugate(a) @@ -149,7 +149,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (Frobenius) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (Frobenius) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Frobenius(a) @@ -159,7 +159,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (FrobeniusSquare) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (FrobeniusSquare) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusSquare(a) @@ -169,7 +169,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (FrobeniusCube) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (FrobeniusCube) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusCube(a) @@ -192,7 +192,7 @@ func TestE12Ops(t *testing.T) { genA := GenE12() genB := GenE12() - properties.Property("[BLS377] sub & add should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] sub & add should leave an element invariant", prop.ForAll( func(a, b *E12) bool { var c E12 c.Set(a) @@ -203,7 +203,7 @@ func TestE12Ops(t *testing.T) { genB, )) - properties.Property("[BLS377] mul & inverse should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] mul & inverse should leave an element invariant", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Inverse(b) @@ -215,7 +215,7 @@ func TestE12Ops(t *testing.T) { genB, )) - properties.Property("[BLS377] inverse twice should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] inverse twice should leave an element invariant", prop.ForAll( func(a *E12) bool { var b E12 b.Inverse(a).Inverse(&b) @@ -224,7 +224,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] square and mul should output the same result", prop.ForAll( + properties.Property("[BLS12-377] square and mul should output the same result", prop.ForAll( func(a *E12) bool { var b, c E12 b.Mul(a, a) @@ -234,7 +234,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] a + pi(a), a-pi(a) should be real", prop.ForAll( + properties.Property("[BLS12-377] a + pi(a), a-pi(a) should be real", prop.ForAll( func(a *E12) bool { var b, c, d E12 var e, f, g E6 @@ -248,7 +248,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] pi**12=id", prop.ForAll( + properties.Property("[BLS12-377] pi**12=id", prop.ForAll( func(a *E12) bool { var b E12 b.Frobenius(a). @@ -268,7 +268,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] (pi**2)**6=id", prop.ForAll( + properties.Property("[BLS12-377] (pi**2)**6=id", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusSquare(a). @@ -282,7 +282,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] (pi**3)**4=id", prop.ForAll( + properties.Property("[BLS12-377] (pi**3)**4=id", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusCube(a). @@ -294,7 +294,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] cyclotomic square and square should be the same in the cyclotomic subgroup", prop.ForAll( + properties.Property("[BLS12-377] cyclotomic square and square should be the same in the cyclotomic subgroup", prop.ForAll( func(a *E12) bool { var b, c, d E12 b.FrobeniusCube(a). diff --git a/bls377/internal/fptower/e2.go b/ecc/bls12-377/internal/fptower/e2.go similarity index 95% rename from bls377/internal/fptower/e2.go rename to ecc/bls12-377/internal/fptower/e2.go index def9d173c7..6c364298b9 100644 --- a/bls377/internal/fptower/e2.go +++ b/ecc/bls12-377/internal/fptower/e2.go @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower import ( - "github.com/consensys/gurvy/bls377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" "math/big" ) @@ -192,7 +192,8 @@ func (z *E2) Sqrt(x *E2) *E2 { var b, c, d, e, f, x0 E2 var _b, o fp.Element - c.A1.SetOne() // c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently) + // c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently) + c.A1.SetOne() q := fp.Modulus() var exp, one big.Int diff --git a/bls377/internal/fptower/e2_amd64.go b/ecc/bls12-377/internal/fptower/e2_amd64.go similarity index 95% rename from bls377/internal/fptower/e2_amd64.go rename to ecc/bls12-377/internal/fptower/e2_amd64.go index 02ef13b55d..556e5eef0c 100644 --- a/bls377/internal/fptower/e2_amd64.go +++ b/ecc/bls12-377/internal/fptower/e2_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bls377/internal/fptower/e2_amd64.s b/ecc/bls12-377/internal/fptower/e2_amd64.s similarity index 100% rename from bls377/internal/fptower/e2_amd64.s rename to ecc/bls12-377/internal/fptower/e2_amd64.s diff --git a/bls377/internal/fptower/e2_bls377.go b/ecc/bls12-377/internal/fptower/e2_bls377.go similarity index 97% rename from bls377/internal/fptower/e2_bls377.go rename to ecc/bls12-377/internal/fptower/e2_bls377.go index 0961e3df9f..ba5cb0b86a 100644 --- a/bls377/internal/fptower/e2_bls377.go +++ b/ecc/bls12-377/internal/fptower/e2_bls377.go @@ -15,7 +15,7 @@ package fptower import ( - "github.com/consensys/gurvy/bls377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" ) // Mul sets z to the E2-product of x,y, returns z diff --git a/bn256/internal/fptower/e2_fallback.go b/ecc/bls12-377/internal/fptower/e2_fallback.go similarity index 94% rename from bn256/internal/fptower/e2_fallback.go rename to ecc/bls12-377/internal/fptower/e2_fallback.go index 262d778027..eada4c6b58 100644 --- a/bn256/internal/fptower/e2_fallback.go +++ b/ecc/bls12-377/internal/fptower/e2_fallback.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bls377/internal/fptower/e2_test.go b/ecc/bls12-377/internal/fptower/e2_test.go similarity index 72% rename from bls377/internal/fptower/e2_test.go rename to ecc/bls12-377/internal/fptower/e2_test.go index f75455775d..ab419aedd7 100644 --- a/bls377/internal/fptower/e2_test.go +++ b/ecc/bls12-377/internal/fptower/e2_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower @@ -20,7 +20,7 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gurvy/bls377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -39,7 +39,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB := GenE2() genfp := GenFp() - properties.Property("[BLS377] Having the receiver as operand (addition) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (addition) should output the same result", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Set(a) @@ -52,7 +52,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS377] Having the receiver as operand (sub) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (sub) should output the same result", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Set(a) @@ -65,7 +65,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS377] Having the receiver as operand (mul) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (mul) should output the same result", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Set(a) @@ -78,7 +78,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS377] Having the receiver as operand (square) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (square) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Square(a) @@ -88,7 +88,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (neg) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (neg) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Neg(a) @@ -98,7 +98,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (double) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (double) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Double(a) @@ -108,7 +108,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.MulByNonResidue(a) @@ -118,7 +118,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (mul by non residue inverse) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (mul by non residue inverse) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.MulByNonResidueInv(a) @@ -128,7 +128,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Inverse(a) @@ -138,7 +138,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Conjugate(a) @@ -148,7 +148,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (mul by element) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (mul by element) should output the same result", prop.ForAll( func(a *E2, b fp.Element) bool { var c E2 c.MulByElement(a, &b) @@ -159,7 +159,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genfp, )) - properties.Property("[BLS377] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( func(a *E2) bool { var b, c, d, s E2 @@ -205,7 +205,7 @@ func TestE2MulMaxed(t *testing.T) { b.A0 = fpMaxValue b.A1 = fpMaxValue - // [BN256] mul & inverse should leave an element invariant", prop.ForAll( + // [BN254] mul & inverse should leave an element invariant", prop.ForAll( var c, d E2 d.Inverse(&b) c.Set(&a) @@ -226,7 +226,7 @@ func TestE2Ops(t *testing.T) { genB := GenE2() genfp := GenFp() - properties.Property("[BLS377] sub & add should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] sub & add should leave an element invariant", prop.ForAll( func(a, b *E2) bool { var c E2 c.Set(a) @@ -237,7 +237,7 @@ func TestE2Ops(t *testing.T) { genB, )) - properties.Property("[BLS377] mul & inverse should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] mul & inverse should leave an element invariant", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Inverse(b) @@ -249,7 +249,7 @@ func TestE2Ops(t *testing.T) { genB, )) - properties.Property("[BLS377] inverse twice should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] inverse twice should leave an element invariant", prop.ForAll( func(a *E2) bool { var b E2 b.Inverse(a).Inverse(&b) @@ -258,7 +258,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] neg twice should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] neg twice should leave an element invariant", prop.ForAll( func(a *E2) bool { var b E2 b.Neg(a).Neg(&b) @@ -267,7 +267,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] square and mul should output the same result", prop.ForAll( + properties.Property("[BLS12-377] square and mul should output the same result", prop.ForAll( func(a *E2) bool { var b, c E2 b.Mul(a, a) @@ -277,7 +277,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] MulByElement MulByElement inverse should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] MulByElement MulByElement inverse should leave an element invariant", prop.ForAll( func(a *E2, b fp.Element) bool { var c E2 var d fp.Element @@ -289,7 +289,7 @@ func TestE2Ops(t *testing.T) { genfp, )) - properties.Property("[BLS377] Double and mul by 2 should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Double and mul by 2 should output the same result", prop.ForAll( func(a *E2) bool { var b E2 var c fp.Element @@ -301,7 +301,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] Mulbynonres mulbynonresinv should leave the element invariant", prop.ForAll( + properties.Property("[BLS12-377] Mulbynonres mulbynonresinv should leave the element invariant", prop.ForAll( func(a *E2) bool { var b E2 b.MulByNonResidue(a).MulByNonResidueInv(&b) @@ -310,7 +310,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] a + pi(a), a-pi(a) should be real", prop.ForAll( + properties.Property("[BLS12-377] a + pi(a), a-pi(a) should be real", prop.ForAll( func(a *E2) bool { var b, c, d E2 var e, f fp.Element @@ -324,7 +324,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] Legendre on square should output 1", prop.ForAll( + properties.Property("[BLS12-377] Legendre on square should output 1", prop.ForAll( func(a *E2) bool { var b E2 b.Square(a) @@ -334,7 +334,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] square(sqrt) should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] square(sqrt) should leave an element invariant", prop.ForAll( func(a *E2) bool { var b, c, d, e E2 b.Square(a) @@ -346,7 +346,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] Cmp and LexicographicallyLargest should be consistant", prop.ForAll( + properties.Property("[BLS12-377] Cmp and LexicographicallyLargest should be consistant", prop.ForAll( func(a *E2) bool { var negA E2 negA.Neg(a) diff --git a/bls377/internal/fptower/e6.go b/ecc/bls12-377/internal/fptower/e6.go similarity index 98% rename from bls377/internal/fptower/e6.go rename to ecc/bls12-377/internal/fptower/e6.go index b29e6f9869..5ba35cf020 100644 --- a/bls377/internal/fptower/e6.go +++ b/ecc/bls12-377/internal/fptower/e6.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bls377/internal/fptower/e6_test.go b/ecc/bls12-377/internal/fptower/e6_test.go similarity index 69% rename from bls377/internal/fptower/e6_test.go rename to ecc/bls12-377/internal/fptower/e6_test.go index f9192fa9d5..a9d536ff55 100644 --- a/bls377/internal/fptower/e6_test.go +++ b/ecc/bls12-377/internal/fptower/e6_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower @@ -36,7 +36,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA := GenE6() genB := GenE6() - properties.Property("[BLS377] Having the receiver as operand (addition) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (addition) should output the same result", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Set(a) @@ -49,7 +49,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS377] Having the receiver as operand (sub) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (sub) should output the same result", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Set(a) @@ -62,7 +62,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS377] Having the receiver as operand (mul) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (mul) should output the same result", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Set(a) @@ -75,7 +75,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS377] Having the receiver as operand (square) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (square) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Square(a) @@ -85,7 +85,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (neg) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (neg) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Neg(a) @@ -95,7 +95,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (double) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (double) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Double(a) @@ -105,7 +105,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.MulByNonResidue(a) @@ -115,7 +115,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS377] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Inverse(a) @@ -138,7 +138,7 @@ func TestE6Ops(t *testing.T) { genA := GenE6() genB := GenE6() - properties.Property("[BLS377] sub & add should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] sub & add should leave an element invariant", prop.ForAll( func(a, b *E6) bool { var c E6 c.Set(a) @@ -149,7 +149,7 @@ func TestE6Ops(t *testing.T) { genB, )) - properties.Property("[BLS377] mul & inverse should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] mul & inverse should leave an element invariant", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Inverse(b) @@ -161,7 +161,7 @@ func TestE6Ops(t *testing.T) { genB, )) - properties.Property("[BLS377] inverse twice should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] inverse twice should leave an element invariant", prop.ForAll( func(a *E6) bool { var b E6 b.Inverse(a).Inverse(&b) @@ -170,7 +170,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] neg twice should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-377] neg twice should leave an element invariant", prop.ForAll( func(a *E6) bool { var b E6 b.Neg(a).Neg(&b) @@ -179,7 +179,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] square and mul should output the same result", prop.ForAll( + properties.Property("[BLS12-377] square and mul should output the same result", prop.ForAll( func(a *E6) bool { var b, c E6 b.Mul(a, a) @@ -189,7 +189,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] Double and add twice should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Double and add twice should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Add(a, a) @@ -199,7 +199,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BLS377] Mul by non residue should be the same as multiplying by (0,1,0)", prop.ForAll( + properties.Property("[BLS12-377] Mul by non residue should be the same as multiplying by (0,1,0)", prop.ForAll( func(a *E6) bool { var b, c E6 b.B1.A0.SetOne() diff --git a/bls377/internal/fptower/frobenius.go b/ecc/bls12-377/internal/fptower/frobenius.go similarity index 99% rename from bls377/internal/fptower/frobenius.go rename to ecc/bls12-377/internal/fptower/frobenius.go index ebdbfcb790..d5b8350129 100644 --- a/bls377/internal/fptower/frobenius.go +++ b/ecc/bls12-377/internal/fptower/frobenius.go @@ -14,7 +14,7 @@ package fptower -import "github.com/consensys/gurvy/bls377/fp" +import "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" // Frobenius set z to Frobenius(x), return z func (z *E12) Frobenius(x *E12) *E12 { diff --git a/bls377/internal/fptower/generators_test.go b/ecc/bls12-377/internal/fptower/generators_test.go similarity index 95% rename from bls377/internal/fptower/generators_test.go rename to ecc/bls12-377/internal/fptower/generators_test.go index 0a50da59ce..2a548a2f56 100644 --- a/bls377/internal/fptower/generators_test.go +++ b/ecc/bls12-377/internal/fptower/generators_test.go @@ -3,7 +3,7 @@ package fptower import ( "crypto/rand" - "github.com/consensys/gurvy/bls377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" "github.com/leanovate/gopter" ) diff --git a/bls377/marshal.go b/ecc/bls12-377/marshal.go similarity index 96% rename from bls377/marshal.go rename to ecc/bls12-377/marshal.go index c86988f17a..0850b5e413 100644 --- a/bls377/marshal.go +++ b/ecc/bls12-377/marshal.go @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -// Package bls377 provides efficient elliptic curve and pairing implementation for bls377 -package bls377 +// Package bls12377 provides efficient elliptic curve and pairing implementation for bls12-377 +package bls12377 import ( "encoding/binary" @@ -24,15 +24,15 @@ import ( "reflect" "sync/atomic" - "github.com/consensys/gurvy/bls377/fp" - "github.com/consensys/gurvy/bls377/fr" - "github.com/consensys/gurvy/bls377/internal/fptower" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" ) // To encode G1Affine and G2Affine points, we mask the most significant bits with these bits to specify without ambiguity // metadata needed for point (de)compression -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. @@ -48,20 +48,20 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT -// Encoder writes bls377 object values to an output stream +// Encoder writes bls12-377 object values to an output stream type Encoder struct { w io.Writer n int64 // written bytes raw bool // raw vs compressed encoding } -// Decoder reads bls377 object values from an inbound stream +// Decoder reads bls12-377 object values from an inbound stream type Decoder struct { r io.Reader n int64 // read bytes } -// NewDecoder returns a binary decoder supporting curve bls377 objects in both +// NewDecoder returns a binary decoder supporting curve bls12-377 objects in both // compressed and uncompressed (raw) forms func NewDecoder(r io.Reader) *Decoder { return &Decoder{r: r} @@ -72,7 +72,7 @@ func NewDecoder(r io.Reader) *Decoder { func (dec *Decoder) Decode(v interface{}) (err error) { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr || rv.IsNil() || !rv.Elem().CanSet() { - return errors.New("bls377 decoder: unsupported type, need pointer") + return errors.New("bls12-377 decoder: unsupported type, need pointer") } // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap @@ -249,7 +249,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return nil default: - return errors.New("bls377 encoder: unsupported type") + return errors.New("bls12-377 encoder: unsupported type") } } @@ -287,7 +287,7 @@ func isCompressed(msb byte) bool { return !((mData == mUncompressed) || (mData == mUncompressedInfinity)) } -// NewEncoder returns a binary encoder supporting curve bls377 objects +// NewEncoder returns a binary encoder supporting curve bls12-377 objects func NewEncoder(w io.Writer, options ...func(*Encoder)) *Encoder { // default settings enc := &Encoder{ @@ -494,7 +494,7 @@ func (p *G1Affine) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. @@ -749,7 +749,7 @@ func (p *G2Affine) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. diff --git a/bn256/marshal_test.go b/ecc/bls12-377/marshal_test.go similarity index 97% rename from bn256/marshal_test.go rename to ecc/bls12-377/marshal_test.go index 56c706adbb..8b26f9378c 100644 --- a/bn256/marshal_test.go +++ b/ecc/bls12-377/marshal_test.go @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bn256 +package bls12377 import ( "bytes" @@ -26,8 +26,8 @@ import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" - "github.com/consensys/gurvy/bn256/fp" - "github.com/consensys/gurvy/bn256/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" ) func TestEncoder(t *testing.T) { diff --git a/bls377/multiexp.go b/ecc/bls12-377/multiexp.go similarity index 99% rename from bls377/multiexp.go rename to ecc/bls12-377/multiexp.go index a6e56f807e..3d89cf79d9 100644 --- a/bls377/multiexp.go +++ b/ecc/bls12-377/multiexp.go @@ -12,20 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls377 +package bls12377 import ( - "github.com/consensys/gurvy/bls377/fr" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/internal/parallel" "math" "runtime" "sync" ) // CPUSemaphore enables users to set optional number of CPUs the multiexp will use -// this is thread safe and can be used accross parallel calls of gurvy.MultiExp +// this is thread safe and can be used accross parallel calls of MultiExp type CPUSemaphore struct { chCpus chan struct{} // semaphore to limit number of cpus iterating through points and scalrs at the same time lock sync.Mutex @@ -160,7 +160,7 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, opts ...*CPUSe // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 // * number of CPUs // * cache friendliness (which depends on the host, G1 or G2... ) - // --> for example, on BN256, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. // for each msmCX // step 1 @@ -995,7 +995,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, opts ...*CPUSe // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 // * number of CPUs // * cache friendliness (which depends on the host, G1 or G2... ) - // --> for example, on BN256, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. // for each msmCX // step 1 diff --git a/bls381/multiexp_test.go b/ecc/bls12-377/multiexp_test.go similarity index 99% rename from bls381/multiexp_test.go rename to ecc/bls12-377/multiexp_test.go index 84bf487f62..bb62152422 100644 --- a/bls381/multiexp_test.go +++ b/ecc/bls12-377/multiexp_test.go @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls381 +package bls12377 import ( "fmt" @@ -23,7 +23,7 @@ import ( "runtime" "testing" - "github.com/consensys/gurvy/bls381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) diff --git a/bls377/pairing.go b/ecc/bls12-377/pairing.go similarity index 98% rename from bls377/pairing.go rename to ecc/bls12-377/pairing.go index 30c1483d3c..09aab77bd5 100644 --- a/bls377/pairing.go +++ b/ecc/bls12-377/pairing.go @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bls377 +package bls12377 import ( "errors" "sync" - "github.com/consensys/gurvy/bls377/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" ) // GT target group of the pairing diff --git a/bls381/pairing_test.go b/ecc/bls12-377/pairing_test.go similarity index 88% rename from bls381/pairing_test.go rename to ecc/bls12-377/pairing_test.go index 42d8a49b36..54b7417fab 100644 --- a/bls381/pairing_test.go +++ b/ecc/bls12-377/pairing_test.go @@ -12,16 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls381 +package bls12377 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bls381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -69,7 +69,7 @@ func TestPairing(t *testing.T) { genR1 := GenFr() genR2 := GenFr() - properties.Property("[BLS381] Having the receiver as operand (final expo) should output the same result", prop.ForAll( + properties.Property("[BLS12-377] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a *GT) bool { var b GT b.Set(a) @@ -80,7 +80,7 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BLS381] Exponentiating FinalExpo(a) to r should output 1", prop.ForAll( + properties.Property("[BLS12-377] Exponentiating FinalExpo(a) to r should output 1", prop.ForAll( func(a *GT) bool { var one GT e := fr.Modulus() @@ -92,7 +92,7 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BLS381] bilinearity", prop.ForAll( + properties.Property("[BLS12-377] bilinearity", prop.ForAll( func(a, b fr.Element) bool { var res, resa, resb, resab, zero GT @@ -124,7 +124,7 @@ func TestPairing(t *testing.T) { genR2, )) - properties.Property("[BLS381] MillerLoop of pairs should be equal to the product of MillerLoops", prop.ForAll( + properties.Property("[BLS12-377] MillerLoop of pairs should be equal to the product of MillerLoops", prop.ForAll( func(a, b fr.Element) bool { var simpleProd, factorizedProd GT @@ -165,7 +165,7 @@ func TestPairing(t *testing.T) { genR2, )) - properties.Property("[BLS381] PairingCheck", prop.ForAll( + properties.Property("[BLS12-377] PairingCheck", prop.ForAll( func(a, b fr.Element) bool { var g1GenAffNeg G1Affine diff --git a/ecc/bls12-377/twistededwards/eddsa/eddsa.go b/ecc/bls12-377/twistededwards/eddsa/eddsa.go new file mode 100644 index 0000000000..63c64ab178 --- /dev/null +++ b/ecc/bls12-377/twistededwards/eddsa/eddsa.go @@ -0,0 +1,265 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/crypto/signature" + "github.com/consensys/gnark-crypto/ecc/bls12-377/twistededwards" + + "golang.org/x/crypto/blake2b" +) + +var errNotOnCurve = errors.New("point not on curve") + +const ( + sizeFr = 32 + sizePublicKey = sizeFr + sizeSignature = 2 * sizeFr + sizePrivateKey = 2*sizeFr + 32 +) + +// PublicKey eddsa signature object +// cf https://en.wikipedia.org/wiki/EdDSA for notation +type PublicKey struct { + A twistededwards.PointAffine +} + +// PrivateKey private key of an eddsa instance +type PrivateKey struct { + PublicKey PublicKey // copy of the associated public key + scalar [sizeFr]byte // secret scalar, in big Endian + randSrc [32]byte // source +} + +// Signature represents an eddsa signature +// cf https://en.wikipedia.org/wiki/EdDSA for notation +type Signature struct { + R twistededwards.PointAffine + S [sizeFr]byte +} + +func init() { + signature.Register(signature.EDDSA_BLS12_377, GenerateKeyInterfaces) +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(r io.Reader) (PrivateKey, error) { + + c := twistededwards.GetEdwardsCurve() + + var pub PublicKey + var priv PrivateKey + + // hash(h) = private_key || random_source, on 32 bytes each + seed := make([]byte, 32) + _, err := r.Read(seed) + if err != nil { + return priv, err + } + h := blake2b.Sum512(seed[:]) + for i := 0; i < 32; i++ { + priv.randSrc[i] = h[i+32] + } + + // prune the key + // https://tools.ietf.org/html/rfc8032#section-5.1.5, key generation + + h[0] &= 0xF8 + h[31] &= 0x7F + h[31] |= 0x40 + + // reverse first bytes because setBytes interpret stream as big endian + // but in eddsa specs s is the first 32 bytes in little endian + for i, j := 0, sizeFr; i < j; i, j = i+1, j-1 { + + h[i], h[j] = h[j], h[i] + + } + + copy(priv.scalar[:], h[:sizeFr]) + + var bscalar big.Int + bscalar.SetBytes(priv.scalar[:]) + pub.A.ScalarMul(&c.Base, &bscalar) + + priv.PublicKey = pub + + return priv, nil +} + +// GenerateKeyInterfaces generate interfaces for the public/private key. +// This purpose of this function is to be registered in the list of signature schemes. +func GenerateKeyInterfaces(r io.Reader) (signature.Signer, error) { + priv, err := GenerateKey(r) + return &priv, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(other signature.PublicKey) bool { + bpk := pub.Bytes() + bother := other.Bytes() + return subtle.ConstantTimeCompare(bpk, bother) == 1 +} + +// Public returns the public key associated to the private key. +// From Signer interface defined in gnark/crypto/signature. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign sign a message +// Pure Eddsa version (see https://tools.ietf.org/html/rfc8032#page-8) +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + curveParams := twistededwards.GetEdwardsCurve() + + var res Signature + + // blinding factor for the private key + // blindingFactorBigInt must be the same size as the private key, + // blindingFactorBigInt = h(randomness_source||message)[:sizeFr] + var blindingFactorBigInt big.Int + + // randSrc = privKey.randSrc || msg (-> message = MSB message .. LSB message) + randSrc := make([]byte, 32+len(message)) + for i, v := range privKey.randSrc { + randSrc[i] = v + } + copy(randSrc[32:], message) + + // randBytes = H(randSrc) + blindingFactorBytes := blake2b.Sum512(randSrc[:]) // TODO ensures that the hash used to build the key and the one used here is the same + blindingFactorBigInt.SetBytes(blindingFactorBytes[:sizeFr]) + + // compute R = randScalar*Base + res.R.ScalarMul(&curveParams.Base, &blindingFactorBigInt) + if !res.R.IsOnCurve() { + return nil, errNotOnCurve + } + + // compute H(R, A, M), all parameters in data are in Montgomery form + resRX := res.R.X.Bytes() + resRY := res.R.Y.Bytes() + resAX := privKey.PublicKey.A.X.Bytes() + resAY := privKey.PublicKey.A.Y.Bytes() + sizeDataToHash := 4*sizeFr + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], resRX[:]) + copy(dataToHash[sizeFr:], resRY[:]) + copy(dataToHash[2*sizeFr:], resAX[:]) + copy(dataToHash[3*sizeFr:], resAY[:]) + copy(dataToHash[4*sizeFr:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + var hramInt big.Int + hramBin := hFunc.Sum(nil) + hramInt.SetBytes(hramBin) + + // Compute s = randScalarInt + H(R,A,M)*S + // going with big int to do ops mod curve order + var bscalar, bs big.Int + bscalar.SetBytes(privKey.scalar[:]) + bs.Mul(&hramInt, &bscalar). + Add(&bs, &blindingFactorBigInt). + Mod(&bs, &curveParams.Order) + sb := bs.Bytes() + if len(sb) < sizeFr { + offset := make([]byte, sizeFr-len(sb)) + sb = append(offset, sb...) + } + copy(res.S[:], sb[:]) + + return res.Bytes(), nil +} + +// Verify verifies an eddsa signature +func (pub *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + curveParams := twistededwards.GetEdwardsCurve() + + // verify that pubKey and R are on the curve + if !pub.A.IsOnCurve() { + return false, errNotOnCurve + } + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + // compute H(R, A, M), all parameters in data are in Montgomery form + sigRX := sig.R.X.Bytes() + sigRY := sig.R.Y.Bytes() + sigAX := pub.A.X.Bytes() + sigAY := pub.A.Y.Bytes() + sizeDataToHash := 4*sizeFr + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], sigRX[:]) + copy(dataToHash[sizeFr:], sigRY[:]) + copy(dataToHash[2*sizeFr:], sigAX[:]) + copy(dataToHash[3*sizeFr:], sigAY[:]) + copy(dataToHash[4*sizeFr:], message) + hFunc.Reset() + if _, err := hFunc.Write(dataToHash[:]); err != nil { + return false, err + } + + var hramInt big.Int + hramBin := hFunc.Sum(nil) + hramInt.SetBytes(hramBin) + + // lhs = cofactor*S*Base + var lhs twistededwards.PointAffine + var bCofactor, bs big.Int + curveParams.Cofactor.ToBigInt(&bCofactor) + bs.SetBytes(sig.S[:]) + lhs.ScalarMul(&curveParams.Base, &bs). + ScalarMul(&lhs, &bCofactor) + + if !lhs.IsOnCurve() { + return false, errNotOnCurve + } + + // rhs = cofactor*(R + H(R,A,M)*A) + var rhs twistededwards.PointAffine + rhs.ScalarMul(&pub.A, &hramInt). + Add(&rhs, &sig.R). + ScalarMul(&rhs, &bCofactor) + if !rhs.IsOnCurve() { + return false, errNotOnCurve + } + + // verifies that cofactor*S*Base=cofactor*(R + H(R,A,M)*A) + if !lhs.X.Equal(&rhs.X) || !lhs.Y.Equal(&rhs.Y) { + return false, nil + } + + return true, nil +} diff --git a/ecc/bls12-377/twistededwards/eddsa/eddsa_test.go b/ecc/bls12-377/twistededwards/eddsa/eddsa_test.go new file mode 100644 index 0000000000..09ee25a198 --- /dev/null +++ b/ecc/bls12-377/twistededwards/eddsa/eddsa_test.go @@ -0,0 +1,179 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/sha256" + "math/rand" + "testing" + + "github.com/consensys/gnark-crypto/crypto/hash" + "github.com/consensys/gnark-crypto/crypto/signature" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +) + +func TestSerialization(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + privKey1, err := signature.EDDSA_BLS12_377.New(r) + if err != nil { + t.Fatal(err) + } + pubKey1 := privKey1.Public() + + privKey2, err := signature.EDDSA_BLS12_377.New(r) + if err != nil { + t.Fatal(err) + } + pubKey2 := privKey2.Public() + + pubKeyBin1 := pubKey1.Bytes() + pubKey2.SetBytes(pubKeyBin1) + pubKeyBin2 := pubKey2.Bytes() + if len(pubKeyBin1) != len(pubKeyBin2) { + t.Fatal("Inconistent size") + } + for i := 0; i < len(pubKeyBin1); i++ { + if pubKeyBin1[i] != pubKeyBin2[i] { + t.Fatal("Error serialize(deserialize(.))") + } + } + + privKeyBin1 := privKey1.Bytes() + privKey2.SetBytes(privKeyBin1) + privKeyBin2 := privKey2.Bytes() + if len(privKeyBin1) != len(privKeyBin2) { + t.Fatal("Inconistent size") + } + for i := 0; i < len(privKeyBin1); i++ { + if privKeyBin1[i] != privKeyBin2[i] { + t.Fatal("Error serialize(deserialize(.))") + } + } +} + +func TestEddsaMIMC(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + // create eddsa obj and sign a message + privKey, err := signature.EDDSA_BLS12_377.New(r) + if err != nil { + t.Fatal(nil) + } + pubKey := privKey.Public() + hFunc := hash.MIMC_BLS12_377.New("seed") + + var frMsg fr.Element + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035978") + msgBin := frMsg.Bytes() + signature, err := privKey.Sign(msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + + // verifies correct msg + res, err := pubKey.Verify(signature, msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + if !res { + t.Fatal("Verifiy correct signature should return true") + } + + // verifies wrong msg + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035979") + msgBin = frMsg.Bytes() + res, err = pubKey.Verify(signature, msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + if res { + t.Fatal("Verfiy wrong signature should be false") + } + +} + +func TestEddsaSHA256(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + hFunc := sha256.New() + + // create eddsa obj and sign a message + // create eddsa obj and sign a message + + privKey, err := signature.EDDSA_BLS12_377.New(r) + pubKey := privKey.Public() + if err != nil { + t.Fatal(err) + } + + signature, err := privKey.Sign([]byte("message"), hFunc) + if err != nil { + t.Fatal(err) + } + + // verifies correct msg + res, err := pubKey.Verify(signature, []byte("message"), hFunc) + if err != nil { + t.Fatal(err) + } + if !res { + t.Fatal("Verifiy correct signature should return true") + } + + // verifies wrong msg + res, err = pubKey.Verify(signature, []byte("wrong_message"), hFunc) + if err != nil { + t.Fatal(err) + } + if res { + t.Fatal("Verfiy wrong signature should be false") + } + +} + +// benchmarks + +func BenchmarkVerify(b *testing.B) { + + src := rand.NewSource(0) + r := rand.New(src) + + hFunc := hash.MIMC_BLS12_377.New("seed") + + // create eddsa obj and sign a message + privKey, err := signature.EDDSA_BLS12_377.New(r) + pubKey := privKey.Public() + if err != nil { + b.Fatal(err) + } + var frMsg fr.Element + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035978") + msgBin := frMsg.Bytes() + signature, _ := privKey.Sign(msgBin[:], hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + pubKey.Verify(signature, msgBin[:], hFunc) + } +} diff --git a/ecc/bls12-377/twistededwards/eddsa/marshal.go b/ecc/bls12-377/twistededwards/eddsa/marshal.go new file mode 100644 index 0000000000..97267823e1 --- /dev/null +++ b/ecc/bls12-377/twistededwards/eddsa/marshal.go @@ -0,0 +1,129 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of pk +// as x||y where x, y are the coordinates of the point +// on the twisted Edwards as big endian integers. +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the twisted Edwards. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !pk.A.IsOnCurve() { + return n, errNotOnCurve + } + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar||randSrc +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:2*sizeFr], privKey.scalar[:]) + subtle.ConstantTimeCopy(1, res[2*sizeFr:], privKey.randSrc[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar||randSrc +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !privKey.PublicKey.A.IsOnCurve() { + return n, errNotOnCurve + } + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, privKey.randSrc[:], buf[2*sizeFr:]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 3*sizeFr x||y||s where +// * x, y are the coordinates of a point on the twisted +// Edwards represented in big endian +// * s=r+h(r,a,m) mod l, the Hasse bound guarantess that +// s is smaller than sizeFr (in particular it is supposed +// s is NOT blinded) +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + sigRBin := sig.R.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], sigRBin[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as x||y||s where +// * x,y are the coordinates of a point on the twisted +// Edwards represented in big endian +// * s=r+h(r,a,m) mod l, the Hasse bound guarantess that +// s is smaller than sizeFr (in particular it is supposed +// s is NOT blinded) +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + if _, err := sig.R.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !sig.R.IsOnCurve() { + return n, errNotOnCurve + } + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/bw761/twistededwards/point.go b/ecc/bls12-377/twistededwards/point.go similarity index 91% rename from bw761/twistededwards/point.go rename to ecc/bls12-377/twistededwards/point.go index ae6234d76d..b5067319a2 100644 --- a/bw761/twistededwards/point.go +++ b/ecc/bls12-377/twistededwards/point.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package twistededwards @@ -22,7 +22,7 @@ import ( "math/big" "math/bits" - "github.com/consensys/gurvy/bw761/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" ) // PointAffine point on a twisted Edwards curve @@ -43,12 +43,11 @@ const ( mCompressedPositive = 0x00 mUnmask = 0x7f - // size in byte of (x,y) + // size in byte of a compressed point (point.Y --> fr.Element) sizePointCompressed = fr.Limbs * 8 ) -// Bytes returns the point as bytes array x||y, where -// x and y are in big endian. +// Bytes returns the compressed point as a byte array // Follows https://tools.ietf.org/html/rfc8032#section-3.1, // as the twisted Edwards implementation is primarily used // for eddsa. @@ -91,15 +90,11 @@ func computeX(y *fr.Element) (x fr.Element) { return } -// SetBytes sets p from the buf, where bug is interpreted -// as a sizePointCompressed+ byte slice, where the first 32 bytes -// are interpreted as x in big endian, the next 32 bytes are -// interpreted as y in big endian. Returns the number of read bytes -// and an error if the buffer is too short. -// Returns the number of bytes read. -// Follows https://tools.ietf.org/html/rfc8032#section-3.1, -// as the twisted Edwards implementation is primarily used -// for eddsa. +// SetBytes sets p from buf +// len(buf) >= sizePointCompressed +// buf contains the Y coordinate masked with a parity bit to recompute the X coordinate +// from the curve equation. See Bytes() and https://tools.ietf.org/html/rfc8032#section-3.1 +// Returns the number of read bytes and an error if the buffer is too short. func (p *PointAffine) SetBytes(buf []byte) (int, error) { if len(buf) < sizePointCompressed { @@ -124,7 +119,7 @@ func (p *PointAffine) SetBytes(buf []byte) (int, error) { } } - return 32, nil + return sizePointCompressed, nil } // Unmarshal alias to SetBytes() diff --git a/bls377/twistededwards/twistededwards.go b/ecc/bls12-377/twistededwards/twistededwards.go similarity index 89% rename from bls377/twistededwards/twistededwards.go rename to ecc/bls12-377/twistededwards/twistededwards.go index 1f05c625b5..d5d303bba3 100644 --- a/bls377/twistededwards/twistededwards.go +++ b/ecc/bls12-377/twistededwards/twistededwards.go @@ -3,7 +3,7 @@ package twistededwards import ( "math/big" - "github.com/consensys/gurvy/bls377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" ) // CurveParams curve parameters: ax^2 + y^2 = 1 + d*x^2*y^2 @@ -16,7 +16,7 @@ type CurveParams struct { var edwards CurveParams -// GetEdwardsCurve returns the twisted Edwards curve on BN256's Fr +// GetEdwardsCurve returns the twisted Edwards curve on BN254's Fr func GetEdwardsCurve() CurveParams { // copy to keep Order private diff --git a/bls377/twistededwards/twistededwards_test.go b/ecc/bls12-377/twistededwards/twistededwards_test.go similarity index 98% rename from bls377/twistededwards/twistededwards_test.go rename to ecc/bls12-377/twistededwards/twistededwards_test.go index a03e6d50b6..b4199ab256 100644 --- a/bls377/twistededwards/twistededwards_test.go +++ b/ecc/bls12-377/twistededwards/twistededwards_test.go @@ -20,7 +20,7 @@ import ( "math/big" "testing" - "github.com/consensys/gurvy/bls377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" ) func TestMarshal(t *testing.T) { diff --git a/bls377/utils_test.go b/ecc/bls12-377/utils_test.go similarity index 88% rename from bls377/utils_test.go rename to ecc/bls12-377/utils_test.go index a791c719de..9942e4daa5 100644 --- a/bls377/utils_test.go +++ b/ecc/bls12-377/utils_test.go @@ -1,11 +1,11 @@ -package bls377 +package bls12377 import ( "math/rand" - "github.com/consensys/gurvy/bls377/fp" - "github.com/consensys/gurvy/bls377/fr" - "github.com/consensys/gurvy/bls377/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-377/internal/fptower" "github.com/leanovate/gopter" ) diff --git a/bls381/bls381.go b/ecc/bls12-381/bls12-381.go similarity index 92% rename from bls381/bls381.go rename to ecc/bls12-381/bls12-381.go index 94fc94347c..75b6c5e15d 100644 --- a/bls381/bls381.go +++ b/ecc/bls12-381/bls12-381.go @@ -1,13 +1,12 @@ -package bls381 +package bls12381 import ( "math/big" - "github.com/consensys/gurvy" - "github.com/consensys/gurvy/bls381/fp" - "github.com/consensys/gurvy/bls381/fr" - "github.com/consensys/gurvy/bls381/internal/fptower" - "github.com/consensys/gurvy/utils" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" ) // E: y**2=x**3+4 @@ -20,7 +19,7 @@ import ( // Fr: r=52435875175126190479447740508185965837690552500527637822603658699938581184513 (x**4-x**2+1) // ID bls381 ID -const ID = gurvy.BLS381 +const ID = ecc.BLS12_381 // bCurveCoeff b coeff of the curve var bCurveCoeff fp.Element @@ -59,7 +58,7 @@ var lambdaGLV big.Int // glvBasis stores R-linearly independant vectors (a,b), (c,d) // in ker((u,v)->u+vlambda[r]), and their determinant -var glvBasis utils.Lattice +var glvBasis ecc.Lattice // psi o pi o psi**-1, where psi:E->E' is the degree 6 iso defined over Fp12 var endo struct { @@ -102,7 +101,7 @@ func init() { thirdRootOneG2.Square(&thirdRootOneG1) lambdaGLV.SetString("228988810152649578064853576960394133503", 10) //(x**2-1) _r := fr.Modulus() - utils.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) endo.u.A0.SetString("0") endo.u.A1.SetString("4002409555221667392624310435006688643935503118305586438271171395842971157480381377015405980053539358417135540939437") diff --git a/bls377/fp/arith.go b/ecc/bls12-381/fp/arith.go similarity index 96% rename from bls377/fp/arith.go rename to ecc/bls12-381/fp/arith.go index a055885c03..66fa667482 100644 --- a/bls377/fp/arith.go +++ b/ecc/bls12-381/fp/arith.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bw761/fp/asm.go b/ecc/bls12-381/fp/asm.go similarity index 92% rename from bw761/fp/asm.go rename to ecc/bls12-381/fp/asm.go index 04495b0cfc..715bc7ac12 100644 --- a/bw761/fp/asm.go +++ b/ecc/bls12-381/fp/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bw761/fp/asm_noadx.go b/ecc/bls12-381/fp/asm_noadx.go similarity index 93% rename from bw761/fp/asm_noadx.go rename to ecc/bls12-381/fp/asm_noadx.go index e878f3473d..371bfeaeb3 100644 --- a/bw761/fp/asm_noadx.go +++ b/ecc/bls12-381/fp/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bls381/fp/element.go b/ecc/bls12-381/fp/element.go similarity index 99% rename from bls381/fp/element.go rename to ecc/bls12-381/fp/element.go index 7e0b37e692..da5a0e8842 100644 --- a/bls381/fp/element.go +++ b/ecc/bls12-381/fp/element.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT // Package fp contains field arithmetic operations for modulus 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787 package fp diff --git a/bls381/fp/element_mul_adx_amd64.s b/ecc/bls12-381/fp/element_mul_adx_amd64.s similarity index 100% rename from bls381/fp/element_mul_adx_amd64.s rename to ecc/bls12-381/fp/element_mul_adx_amd64.s diff --git a/bls381/fp/element_mul_amd64.s b/ecc/bls12-381/fp/element_mul_amd64.s similarity index 100% rename from bls381/fp/element_mul_amd64.s rename to ecc/bls12-381/fp/element_mul_amd64.s diff --git a/bn256/fp/element_ops_amd64.go b/ecc/bls12-381/fp/element_ops_amd64.go similarity index 94% rename from bn256/fp/element_ops_amd64.go rename to ecc/bls12-381/fp/element_ops_amd64.go index 7c3aa757be..71b26855b4 100644 --- a/bn256/fp/element_ops_amd64.go +++ b/ecc/bls12-381/fp/element_ops_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bls381/fp/element_ops_amd64.s b/ecc/bls12-381/fp/element_ops_amd64.s similarity index 100% rename from bls381/fp/element_ops_amd64.s rename to ecc/bls12-381/fp/element_ops_amd64.s diff --git a/bls377/fp/element_ops_noasm.go b/ecc/bls12-381/fp/element_ops_noasm.go similarity index 96% rename from bls377/fp/element_ops_noasm.go rename to ecc/bls12-381/fp/element_ops_noasm.go index 5563ce93fe..e6ced1bf56 100644 --- a/bls377/fp/element_ops_noasm.go +++ b/ecc/bls12-381/fp/element_ops_noasm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bls381/fp/element_test.go b/ecc/bls12-381/fp/element_test.go similarity index 99% rename from bls381/fp/element_test.go rename to ecc/bls12-381/fp/element_test.go index 5b8a0bc63b..e2ecd197b7 100644 --- a/bls381/fp/element_test.go +++ b/ecc/bls12-381/fp/element_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp @@ -210,11 +210,6 @@ func TestElementCmp(t *testing.T) { } } -func TestElementSetInterface(t *testing.T) { - // TODO - t.Skip("not implemented") -} - func TestElementIsRandom(t *testing.T) { for i := 0; i < 50; i++ { var x, y Element diff --git a/bw761/fr/arith.go b/ecc/bls12-381/fr/arith.go similarity index 96% rename from bw761/fr/arith.go rename to ecc/bls12-381/fr/arith.go index 9f42f6641f..83c9fd9ef9 100644 --- a/bw761/fr/arith.go +++ b/ecc/bls12-381/fr/arith.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bls377/fr/asm.go b/ecc/bls12-381/fr/asm.go similarity index 92% rename from bls377/fr/asm.go rename to ecc/bls12-381/fr/asm.go index 7c77fecb17..f859dd8731 100644 --- a/bls377/fr/asm.go +++ b/ecc/bls12-381/fr/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bls381/fr/asm_noadx.go b/ecc/bls12-381/fr/asm_noadx.go similarity index 93% rename from bls381/fr/asm_noadx.go rename to ecc/bls12-381/fr/asm_noadx.go index 3b2f49bd87..ab9b869b5b 100644 --- a/bls381/fr/asm_noadx.go +++ b/ecc/bls12-381/fr/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bls381/fr/element.go b/ecc/bls12-381/fr/element.go similarity index 99% rename from bls381/fr/element.go rename to ecc/bls12-381/fr/element.go index 6173ffb824..79900605dc 100644 --- a/bls381/fr/element.go +++ b/ecc/bls12-381/fr/element.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT // Package fr contains field arithmetic operations for modulus 52435875175126190479447740508185965837690552500527637822603658699938581184513 package fr diff --git a/bls381/fr/element_mul_adx_amd64.s b/ecc/bls12-381/fr/element_mul_adx_amd64.s similarity index 100% rename from bls381/fr/element_mul_adx_amd64.s rename to ecc/bls12-381/fr/element_mul_adx_amd64.s diff --git a/bls381/fr/element_mul_amd64.s b/ecc/bls12-381/fr/element_mul_amd64.s similarity index 100% rename from bls381/fr/element_mul_amd64.s rename to ecc/bls12-381/fr/element_mul_amd64.s diff --git a/bw761/fr/element_ops_amd64.go b/ecc/bls12-381/fr/element_ops_amd64.go similarity index 94% rename from bw761/fr/element_ops_amd64.go rename to ecc/bls12-381/fr/element_ops_amd64.go index 73ae624914..f0d8316e52 100644 --- a/bw761/fr/element_ops_amd64.go +++ b/ecc/bls12-381/fr/element_ops_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bls381/fr/element_ops_amd64.s b/ecc/bls12-381/fr/element_ops_amd64.s similarity index 100% rename from bls381/fr/element_ops_amd64.s rename to ecc/bls12-381/fr/element_ops_amd64.s diff --git a/bw761/fr/element_ops_noasm.go b/ecc/bls12-381/fr/element_ops_noasm.go similarity index 96% rename from bw761/fr/element_ops_noasm.go rename to ecc/bls12-381/fr/element_ops_noasm.go index e902f2906a..e7daa4d40e 100644 --- a/bw761/fr/element_ops_noasm.go +++ b/ecc/bls12-381/fr/element_ops_noasm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bls381/fr/element_test.go b/ecc/bls12-381/fr/element_test.go similarity index 99% rename from bls381/fr/element_test.go rename to ecc/bls12-381/fr/element_test.go index 98931c7455..76e94bf5b2 100644 --- a/bls381/fr/element_test.go +++ b/ecc/bls12-381/fr/element_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr @@ -206,11 +206,6 @@ func TestElementCmp(t *testing.T) { } } -func TestElementSetInterface(t *testing.T) { - // TODO - t.Skip("not implemented") -} - func TestElementIsRandom(t *testing.T) { for i := 0; i < 50; i++ { var x, y Element diff --git a/ecc/bls12-381/fr/fft/domain.go b/ecc/bls12-381/fr/fft/domain.go new file mode 100644 index 0000000000..67266eb968 --- /dev/null +++ b/ecc/bls12-381/fr/fft/domain.go @@ -0,0 +1,271 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "io" + "math/big" + "math/bits" + "runtime" + "sync" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" +) + +// Domain with a power of 2 cardinality +// compute a field element of order 2x and store it in FinerGenerator +// all other values can be derived from x, GeneratorSqrt +type Domain struct { + Cardinality uint64 + Depth uint64 + CardinalityInv fr.Element + Generator fr.Element + GeneratorInv fr.Element + FinerGenerator fr.Element + FinerGeneratorInv fr.Element + + // the following slices are not serialized and are (re)computed through domain.preComputeTwiddles() + + // Twiddles factor for the FFT using Generator for each stage of the recursive FFT + Twiddles [][]fr.Element + + // Twiddles factor for the FFT using GeneratorInv for each stage of the recursive FFT + TwiddlesInv [][]fr.Element + + // we precompute these mostly to avoid the memory intensive bit reverse permutation in the groth16.Prover + + // CosetTable[i][j] = domain.Generator(i-th)Sqrt ^ j + // CosetTable = fft.BitReverse(CosetTable) + CosetTable [][]fr.Element + + // CosetTable[i][j] = domain.Generator(i-th)SqrtInv ^ j + // CosetTableInv = fft.BitReverse(CosetTableInv) + CosetTableInv [][]fr.Element +} + +// NewDomain returns a subgroup with a power of 2 cardinality +// cardinality >= m +// If depth>0, the Domain will also store a primitive (2**depth)*m root +// of 1, with associated precomputed data. This allows to perform shifted +// FFT/FFTInv. +// +// example: +// -------- +// +// NewDomain(m, 2) outputs a new domain to perform fft on Z/mZ, plus a primitive +// 2**2*m=4m-th root of 1 and associated data to compute fft/fftinv on the cosets of +// (Z/4mZ)/(Z/mZ). +func NewDomain(m, depth uint64) *Domain { + + // generator of the largest 2-adic subgroup + var rootOfUnity fr.Element + + rootOfUnity.SetString("10238227357739495823651030575849232062558860180284477541189508159991286009131") + const maxOrderRoot uint64 = 32 + + subGroup := &Domain{} + x := nextPowerOfTwo(m) + subGroup.Cardinality = uint64(x) + subGroup.Depth = depth + + // find generator for Z/2^(log(m))Z and Z/2^(log(m)+cosets)Z + logx := uint64(bits.TrailingZeros64(x)) + if logx > maxOrderRoot { + panic("m is too big: the required root of unity does not exist") + } + logGen := logx + depth + if logGen > maxOrderRoot { + panic("log(m) + cosets is too big: the required root of unity does not exist") + } + + expo := uint64(1 << (maxOrderRoot - logGen)) + bExpo := new(big.Int).SetUint64(expo) + subGroup.FinerGenerator.Exp(rootOfUnity, bExpo) + subGroup.FinerGeneratorInv.Inverse(&subGroup.FinerGenerator) + + // Generator = FinerGenerator^2 has order x + expo = uint64(1 << (maxOrderRoot - logx)) + bExpo.SetUint64(expo) + subGroup.Generator.Exp(rootOfUnity, bExpo) // order x + subGroup.GeneratorInv.Inverse(&subGroup.Generator) + subGroup.CardinalityInv.SetUint64(uint64(x)).Inverse(&subGroup.CardinalityInv) + + // twiddle factors + subGroup.preComputeTwiddles() + + return subGroup +} + +func (d *Domain) preComputeTwiddles() { + + // nb fft stages + nbStages := uint64(bits.TrailingZeros64(d.Cardinality)) + nbCosets := (1 << d.Depth) - 1 + + d.Twiddles = make([][]fr.Element, nbStages) + d.TwiddlesInv = make([][]fr.Element, nbStages) + d.CosetTable = make([][]fr.Element, nbCosets) + d.CosetTableInv = make([][]fr.Element, nbCosets) + for i := 0; i < nbCosets; i++ { + d.CosetTable[i] = make([]fr.Element, d.Cardinality) + d.CosetTableInv[i] = make([]fr.Element, d.Cardinality) + } + + var wg sync.WaitGroup + + // for each fft stage, we pre compute the twiddle factors + twiddles := func(t [][]fr.Element, omega fr.Element) { + for i := uint64(0); i < nbStages; i++ { + t[i] = make([]fr.Element, 1+(1<<(nbStages-i-1))) + var w fr.Element + if i == 0 { + w = omega + } else { + w = t[i-1][2] + } + t[i][0] = fr.One() + t[i][1] = w + for j := 2; j < len(t[i]); j++ { + t[i][j].Mul(&t[i][j-1], &w) + } + } + wg.Done() + } + + expTable := func(sqrt fr.Element, t []fr.Element) { + t[0] = fr.One() + precomputeExpTable(sqrt, t) + wg.Done() + } + + if nbCosets > 0 { + cosetGens := make([]fr.Element, nbCosets) + cosetGensInv := make([]fr.Element, nbCosets) + cosetGens[0].Set(&d.FinerGenerator) + cosetGensInv[0].Set(&d.FinerGeneratorInv) + for i := 1; i < nbCosets; i++ { + cosetGens[i].Mul(&cosetGens[i-1], &d.FinerGenerator) + cosetGensInv[i].Mul(&cosetGensInv[1], &d.FinerGeneratorInv) + } + wg.Add(2 + 2*nbCosets) + go twiddles(d.Twiddles, d.Generator) + go twiddles(d.TwiddlesInv, d.GeneratorInv) + for i := 0; i < nbCosets-1; i++ { + go expTable(cosetGens[i], d.CosetTable[i]) + go expTable(cosetGensInv[i], d.CosetTableInv[i]) + } + go expTable(cosetGens[nbCosets-1], d.CosetTable[nbCosets-1]) + expTable(cosetGensInv[nbCosets-1], d.CosetTableInv[nbCosets-1]) + + wg.Wait() + + } else { + wg.Add(2) + go twiddles(d.Twiddles, d.Generator) + twiddles(d.TwiddlesInv, d.GeneratorInv) + wg.Wait() + } + +} + +func precomputeExpTable(w fr.Element, table []fr.Element) { + n := len(table) + + // see if it makes sense to parallelize exp tables pre-computation + interval := 0 + if runtime.NumCPU() >= 4 { + interval = (n - 1) / (runtime.NumCPU() / 4) + } + + // this ratio roughly correspond to the number of multiplication one can do in place of a Exp operation + const ratioExpMul = 6000 / 17 + + if interval < ratioExpMul { + precomputeExpTableChunk(w, 1, table[1:]) + return + } + + // we parallelize + var wg sync.WaitGroup + for i := 1; i < n; i += interval { + start := i + end := i + interval + if end > n { + end = n + } + wg.Add(1) + go func() { + precomputeExpTableChunk(w, uint64(start), table[start:end]) + wg.Done() + }() + } + wg.Wait() +} + +func precomputeExpTableChunk(w fr.Element, power uint64, table []fr.Element) { + table[0].Exp(w, new(big.Int).SetUint64(power)) + for i := 1; i < len(table); i++ { + table[i].Mul(&table[i-1], &w) + } +} + +func nextPowerOfTwo(n uint64) uint64 { + p := uint64(1) + if (n & (n - 1)) == 0 { + return n + } + for p < n { + p <<= 1 + } + return p +} + +// WriteTo writes a binary representation of the domain (without the precomputed twiddle factors) +// to the provided writer +func (d *Domain) WriteTo(w io.Writer) (int64, error) { + + enc := curve.NewEncoder(w) + + toEncode := []interface{}{d.Cardinality, d.Depth, &d.CardinalityInv, &d.Generator, &d.GeneratorInv, &d.FinerGenerator, &d.FinerGeneratorInv} + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom attempts to decode a domain from Reader +func (d *Domain) ReadFrom(r io.Reader) (int64, error) { + + dec := curve.NewDecoder(r) + + toDecode := []interface{}{&d.Cardinality, &d.Depth, &d.CardinalityInv, &d.Generator, &d.GeneratorInv, &d.FinerGenerator, &d.FinerGeneratorInv} + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + d.preComputeTwiddles() + return dec.BytesRead(), nil +} diff --git a/ecc/bls12-381/fr/fft/domain_test.go b/ecc/bls12-381/fr/fft/domain_test.go new file mode 100644 index 0000000000..e3c1d71978 --- /dev/null +++ b/ecc/bls12-381/fr/fft/domain_test.go @@ -0,0 +1,47 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "bytes" + "reflect" + "testing" +) + +func TestDomainSerialization(t *testing.T) { + + domain := NewDomain(1<<6, 1) + var reconstructed Domain + + var buf bytes.Buffer + written, err := domain.WriteTo(&buf) + if err != nil { + t.Fatal(err) + } + var read int64 + read, err = reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal(err) + } + + if written != read { + t.Fatal("didn't read as many bytes as we wrote") + } + if !reflect.DeepEqual(domain, &reconstructed) { + t.Fatal("Domain.SetBytes(Bytes()) failed") + } +} diff --git a/ecc/bls12-381/fr/fft/fft.go b/ecc/bls12-381/fr/fft/fft.go new file mode 100644 index 0000000000..0c71603cfa --- /dev/null +++ b/ecc/bls12-381/fr/fft/fft.go @@ -0,0 +1,265 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/internal/parallel" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" +) + +// Decimation is used in the FFT call to select decimation in time or in frequency +type Decimation uint8 + +const ( + DIT Decimation = iota + DIF +) + +// parallelize threshold for a single butterfly op, if the fft stage is not parallelized already +const butterflyThreshold = 16 + +// FFT computes (recursively) the discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +// +// example: +// ------- +// domain := NewDomain(m, 2) --> contains precomputed data for Z/mZ, and Z/4mZ +// FFT(pol, DIT, 1) --> evaluates pol on the coset 1 in (Z/4mZ)/(Z/mZ) +func (domain *Domain) FFT(a []fr.Element, decimation Decimation, coset uint64) { + + numCPU := uint64(runtime.NumCPU()) + + if coset != 0 { + if decimation == DIT { + BitReverse(domain.CosetTable[coset-1]) + } + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].Mul(&a[i], &domain.CosetTable[coset-1][i]) + } + }) + // put it back as we found it + if decimation == DIT { + BitReverse(domain.CosetTable[coset-1]) + } + } + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(nextPowerOfTwo(numCPU)) + if numCPU <= 1 { + maxSplits = -1 + } + + switch decimation { + case DIF: + difFFT(a, domain.Twiddles, 0, maxSplits, nil) + case DIT: + ditFFT(a, domain.Twiddles, 0, maxSplits, nil) + default: + panic("not implemented") + } +} + +// FFTInverse computes (recursively) the inverse discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +func (domain *Domain) FFTInverse(a []fr.Element, decimation Decimation, coset uint64) { + + numCPU := uint64(runtime.NumCPU()) + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(nextPowerOfTwo(numCPU)) + if numCPU <= 1 { + maxSplits = -1 + } + switch decimation { + case DIF: + difFFT(a, domain.TwiddlesInv, 0, maxSplits, nil) + case DIT: + ditFFT(a, domain.TwiddlesInv, 0, maxSplits, nil) + default: + panic("not implemented") + } + + // scale by CardinalityInv (+ cosetTableInv is coset!=0) + if coset != 0 { + if decimation == DIF { + BitReverse(domain.CosetTableInv[coset-1]) + } + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].Mul(&a[i], &domain.CosetTableInv[coset-1][i]). + MulAssign(&domain.CardinalityInv) + } + }) + // put it back as we found it + if decimation == DIF { + BitReverse(domain.CosetTableInv[coset-1]) + } + } else { + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].MulAssign(&domain.CardinalityInv) + } + }) + } +} + +func difFFT(a []fr.Element, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer func() { + chDone <- struct{}{} + }() + } + n := len(a) + if n == 1 { + return + } + m := n >> 1 + + // if stage < maxSplits, we parallelize this butterfly + // but we have only numCPU / stage cpus available + if (m > butterflyThreshold) && (stage < maxSplits) { + // 1 << stage == estimated used CPUs + numCPU := runtime.NumCPU() / (1 << (stage)) + parallel.Execute(m, func(start, end int) { + var t fr.Element + for i := start; i < end; i++ { + t = a[i] + a[i].Add(&a[i], &a[i+m]) + + a[i+m]. + Sub(&t, &a[i+m]). + Mul(&a[i+m], &twiddles[stage][i]) + } + }, numCPU) + } else { + var t fr.Element + + // i == 0 + t = a[0] + a[0].Add(&a[0], &a[m]) + a[m].Sub(&t, &a[m]) + + for i := 1; i < m; i++ { + t = a[i] + a[i].Add(&a[i], &a[i+m]) + + a[i+m]. + Sub(&t, &a[i+m]). + Mul(&a[i+m], &twiddles[stage][i]) + } + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFT(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFT(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} + +func ditFFT(a []fr.Element, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer func() { + chDone <- struct{}{} + }() + } + n := len(a) + if n == 1 { + return + } + m := n >> 1 + + nextStage := stage + 1 + + if stage < maxSplits { + // that's the only time we fire go routines + chDone := make(chan struct{}, 1) + go ditFFT(a[m:], twiddles, nextStage, maxSplits, chDone) + ditFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + ditFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + ditFFT(a[m:n], twiddles, nextStage, maxSplits, nil) + + } + + // if stage < maxSplits, we parallelize this butterfly + // but we have only numCPU / stage cpus available + if (m > butterflyThreshold) && (stage < maxSplits) { + // 1 << stage == estimated used CPUs + numCPU := runtime.NumCPU() / (1 << (stage)) + parallel.Execute(m, func(start, end int) { + var t, tm fr.Element + for k := start; k < end; k++ { + t = a[k] + tm.Mul(&a[k+m], &twiddles[stage][k]) + a[k].Add(&a[k], &tm) + a[k+m].Sub(&t, &tm) + } + }, numCPU) + + } else { + var t, tm fr.Element + // k == 0 + // wPow == 1 + t = a[0] + a[0].Add(&a[0], &a[m]) + a[m].Sub(&t, &a[m]) + + for k := 1; k < m; k++ { + t = a[k] + tm.Mul(&a[k+m], &twiddles[stage][k]) + a[k].Add(&a[k], &tm) + a[k+m].Sub(&t, &tm) + } + } +} + +// BitReverse applies the bit-reversal permutation to a. +// len(a) must be a power of 2 (as in every single function in this file) +func BitReverse(a []fr.Element) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} diff --git a/ecc/bls12-381/fr/fft/fft_test.go b/ecc/bls12-381/fr/fft/fft_test.go new file mode 100644 index 0000000000..720c92f384 --- /dev/null +++ b/ecc/bls12-381/fr/fft/fft_test.go @@ -0,0 +1,205 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "math/big" + "strconv" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" + "github.com/leanovate/gopter/prop" +) + +func TestFFT(t *testing.T) { + const maxSize = 1 << 10 + + domain := NewDomain(maxSize, 0) + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 5 + + properties := gopter.NewProperties(parameters) + + properties.Property("DIF FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domain.FFT(pol, DIF, 0) + BitReverse(pol) + + sample := domain.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := evaluatePolynomial(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("DIT FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverse(pol) + domain.FFT(pol, DIT, 0) + + sample := domain.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := evaluatePolynomial(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("bitReverse(DIF FFT(DIT FFT (bitReverse))))==id", prop.ForAll( + + func() bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverse(pol) + domain.FFT(pol, DIT, 0) + domain.FFTInverse(pol, DIF, 0) + BitReverse(pol) + + check := true + for i := 0; i < len(pol); i++ { + check = check && pol[i].Equal(&backupPol[i]) + } + return check + }, + )) + + properties.Property("DIT FFT(DIF FFT)==id", prop.ForAll( + + func() bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domain.FFTInverse(pol, DIF, 0) + domain.FFT(pol, DIT, 0) + + check := true + for i := 0; i < len(pol); i++ { + check = check && (pol[i] == backupPol[i]) + } + return check + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + +} + +// -------------------------------------------------------------------- +// benches +func BenchmarkBitReverse(b *testing.B) { + + const maxSize = 1 << 20 + + pol := make([]fr.Element, maxSize) + for i := uint64(0); i < maxSize; i++ { + pol[i].SetRandom() + } + + for i := 8; i < 20; i++ { + b.Run("bit reversing 2**"+strconv.Itoa(i)+"bits", func(b *testing.B) { + _pol := make([]fr.Element, 1< .. || 0x0000...0af8 + if len(d.data)%BlockSize != 0 { + q := len(d.data) / BlockSize + r := len(d.data) % BlockSize + sliceq := make([]byte, q*BlockSize) + copy(sliceq, d.data) + slicer := make([]byte, r) + copy(slicer, d.data[q*BlockSize:]) + sliceremainder := make([]byte, BlockSize-r) + d.data = append(sliceq, sliceremainder...) + d.data = append(d.data, slicer...) + } + + if len(d.data) == 0 { + d.data = make([]byte, 32) + } + + nbChunks := len(d.data) / BlockSize + + for i := 0; i < nbChunks; i++ { + copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) + x.SetBytes(buffer[:]) + d.encrypt(x) + d.h.Add(&x, &d.h) + } + + return d.h +} + +// plain execution of a mimc run +// m: message +// k: encryption key +func (d *digest) encrypt(m fr.Element) { + + for i := 0; i < len(d.Params); i++ { + // m = (m+k+c)^5 + var tmp fr.Element + tmp.Add(&m, &d.h).Add(&tmp, &d.Params[i]) + m.Square(&tmp). + Square(&m). + Mul(&m, &tmp) + } + m.Add(&m, &d.h) + d.h = m +} + +// Sum computes the mimc hash of msg from seed +func Sum(seed string, msg []byte) ([]byte, error) { + params := NewParams(seed) + var d digest + d.Params = params + if _, err := d.Write(msg); err != nil { + return nil, err + } + h := d.checksum() + bytes := h.Bytes() + return bytes[:], nil +} diff --git a/ecc/bls12-381/fr/polynomial/polynomial.go b/ecc/bls12-381/fr/polynomial/polynomial.go new file mode 100644 index 0000000000..a290264184 --- /dev/null +++ b/ecc/bls12-381/fr/polynomial/polynomial.go @@ -0,0 +1,43 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package polynomial + +import ( + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" +) + +// Polynomial polynomial represented by coefficients bls12-381 fr field. +type Polynomial []fr.Element + +// Degree returns the degree of the polynomial, which is the length of Data. +func (p Polynomial) Degree() uint64 { + res := uint64(len(p) - 1) + return res +} + +// Eval evaluates p at v +func (p Polynomial) Eval(v interface{}) interface{} { + var res, _v fr.Element + _v.Set(v.(*fr.Element)) + s := len(p) + res.Set(&p[s-1]) + for i := s - 2; i >= 0; i-- { + res.Mul(&res, &_v) + res.Add(&res, &p[i]) + } + return &res +} diff --git a/bls381/g1.go b/ecc/bls12-381/g1.go similarity index 98% rename from bls381/g1.go rename to ecc/bls12-381/g1.go index b8d5a099a8..10b4e00729 100644 --- a/bls381/g1.go +++ b/ecc/bls12-381/g1.go @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls381 +package bls12381 import ( "math/big" - "github.com/consensys/gurvy/bls381/fp" - "github.com/consensys/gurvy/bls381/fr" - "github.com/consensys/gurvy/utils" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/internal/parallel" ) // G1Affine point in affine coordinates @@ -411,7 +411,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { table[3].phi(a) // split the scalar, modifies +-a, phi(a) accordingly - k := utils.SplitScalar(s, &glvBasis) + k := ecc.SplitScalar(s, &glvBasis) if k[0].Cmp(&zero) == -1 { k[0].Neg(&k[0]) diff --git a/bls377/g1_test.go b/ecc/bls12-381/g1_test.go similarity index 83% rename from bls377/g1_test.go rename to ecc/bls12-381/g1_test.go index f31266f348..bd9a0752d0 100644 --- a/bls377/g1_test.go +++ b/ecc/bls12-381/g1_test.go @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls377 +package bls12381 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bls377/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" - "github.com/consensys/gurvy/bls377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -86,7 +86,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { properties := gopter.NewProperties(parameters) genFuzz1 := GenFp() - properties.Property("[BLS377] g1Gen (affine) should be on the curve", prop.ForAll( + properties.Property("[BLS12-381] g1Gen (affine) should be on the curve", prop.ForAll( func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) @@ -97,7 +97,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] g1Gen (Jacobian) should be on the curve", prop.ForAll( + properties.Property("[BLS12-381] g1Gen (Jacobian) should be on the curve", prop.ForAll( func(a fp.Element) bool { var op1, op2, op3 G1Jac op1.Set(&g1Gen) @@ -122,7 +122,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1 := GenFp() genFuzz2 := GenFp() - properties.Property("[BLS377] Affine representation should be independent of the Jacobian representative", prop.ForAll( + properties.Property("[BLS12-381] Affine representation should be independent of the Jacobian representative", prop.ForAll( func(a fp.Element) bool { g := fuzzJacobianG1Affine(&g1Gen, a) var op1 G1Affine @@ -132,7 +132,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( + properties.Property("[BLS12-381] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( func(a fp.Element) bool { var g g1JacExtended g.X.Set(&g1Gen.X) @@ -148,7 +148,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] Jacobian representation should be the same as the affine representative", prop.ForAll( + properties.Property("[BLS12-381] Jacobian representation should be the same as the affine representative", prop.ForAll( func(a fp.Element) bool { var g G1Jac var op1 G1Affine @@ -165,7 +165,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( + properties.Property("[BLS12-381] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( func() bool { var g G1Affine g.X.SetZero() @@ -178,7 +178,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS377] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( + properties.Property("[BLS12-381] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( func() bool { var g G1Affine var op1 g1JacExtended @@ -190,7 +190,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS377] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( + properties.Property("[BLS12-381] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( func() bool { var g G1Jac var op1 g1JacExtended @@ -203,7 +203,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS377] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( func(a, b fp.Element) bool { op1 := fuzzJacobianG1Affine(&g1Gen, a) op2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -227,7 +227,7 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() - properties.Property("[BLS377] [Jacobian] Add should call double when having adding the same point", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -240,7 +240,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BLS377] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -252,7 +252,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BLS377] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop1.AddAssign(&g1Infinity) @@ -264,7 +264,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) var p1, p1Neg G1Affine @@ -283,7 +283,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) var p1, p1Neg G1Affine @@ -302,7 +302,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop1.Neg(&fop1) @@ -314,7 +314,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS377] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BLS12-381] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -337,7 +337,7 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BLS377] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BLS12-381] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -360,7 +360,7 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BLS377] GLV and Double and Add should output the same result", prop.ForAll( + properties.Property("[BLS12-381] GLV and Double and Add should output the same result", prop.ForAll( func(s fr.Element) bool { var r big.Int @@ -384,7 +384,7 @@ func TestG1AffineCofactorCleaning(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BLS377] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( + properties.Property("[BLS12-381] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( func() bool { var a, x, b fp.Element a.SetRandom() @@ -424,7 +424,7 @@ func TestG1AffineBatchScalarMultiplication(t *testing.T) { // size of the multiExps const nbSamples = 10 - properties.Property("[BLS377] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( + properties.Property("[BLS12-381] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( func(mixer fr.Element) bool { // mixer ensures that all the words of a fpElement are set var sampleScalars [nbSamples]fr.Element diff --git a/bls381/g2.go b/ecc/bls12-381/g2.go similarity index 98% rename from bls381/g2.go rename to ecc/bls12-381/g2.go index bb4af5176d..0752c4d328 100644 --- a/bls381/g2.go +++ b/ecc/bls12-381/g2.go @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls381 +package bls12381 import ( "math/big" - "github.com/consensys/gurvy/bls381/fr" - "github.com/consensys/gurvy/bls381/internal/fptower" - "github.com/consensys/gurvy/utils" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" ) // G2Affine point in affine coordinates @@ -425,7 +425,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { table[3].phi(a) // split the scalar, modifies +-a, phi(a) accordingly - k := utils.SplitScalar(s, &glvBasis) + k := ecc.SplitScalar(s, &glvBasis) if k[0].Cmp(&zero) == -1 { k[0].Neg(&k[0]) diff --git a/bls381/g2_test.go b/ecc/bls12-381/g2_test.go similarity index 82% rename from bls381/g2_test.go rename to ecc/bls12-381/g2_test.go index 26861ff5d4..d67b9bfda6 100644 --- a/bls381/g2_test.go +++ b/ecc/bls12-381/g2_test.go @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls381 +package bls12381 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bls381/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" - "github.com/consensys/gurvy/bls381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -86,7 +86,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { properties := gopter.NewProperties(parameters) genFuzz1 := GenE2() - properties.Property("[BLS381] g2Gen (affine) should be on the curve", prop.ForAll( + properties.Property("[BLS12-381] g2Gen (affine) should be on the curve", prop.ForAll( func(a *fptower.E2) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) @@ -97,7 +97,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] g2Gen (Jacobian) should be on the curve", prop.ForAll( + properties.Property("[BLS12-381] g2Gen (Jacobian) should be on the curve", prop.ForAll( func(a *fptower.E2) bool { var op1, op2, op3 G2Jac op1.Set(&g2Gen) @@ -122,7 +122,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1 := GenE2() genFuzz2 := GenE2() - properties.Property("[BLS381] Affine representation should be independent of the Jacobian representative", prop.ForAll( + properties.Property("[BLS12-381] Affine representation should be independent of the Jacobian representative", prop.ForAll( func(a *fptower.E2) bool { g := fuzzJacobianG2Affine(&g2Gen, a) var op1 G2Affine @@ -132,7 +132,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( + properties.Property("[BLS12-381] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( func(a *fptower.E2) bool { var g g2JacExtended g.X.Set(&g2Gen.X) @@ -148,7 +148,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] Jacobian representation should be the same as the affine representative", prop.ForAll( + properties.Property("[BLS12-381] Jacobian representation should be the same as the affine representative", prop.ForAll( func(a *fptower.E2) bool { var g G2Jac var op1 G2Affine @@ -165,7 +165,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( + properties.Property("[BLS12-381] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( func() bool { var g G2Affine g.X.SetZero() @@ -178,7 +178,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS381] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( + properties.Property("[BLS12-381] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( func() bool { var g G2Affine var op1 g2JacExtended @@ -190,7 +190,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS381] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( + properties.Property("[BLS12-381] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( func() bool { var g G2Jac var op1 g2JacExtended @@ -203,7 +203,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BLS381] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( func(a, b *fptower.E2) bool { op1 := fuzzJacobianG2Affine(&g2Gen, a) op2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -227,7 +227,7 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() - properties.Property("[BLS381] [Jacobian] Add should call double when having adding the same point", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -240,7 +240,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BLS381] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( func(a, b *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -252,7 +252,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BLS381] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop1.AddAssign(&g2Infinity) @@ -264,7 +264,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) var p1, p1Neg G2Affine @@ -283,7 +283,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) var p1, p1Neg G2Affine @@ -302,7 +302,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( + properties.Property("[BLS12-381] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop1.Neg(&fop1) @@ -314,7 +314,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BLS381] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BLS12-381] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -337,7 +337,7 @@ func TestG2AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BLS381] psi should map points from E' to itself", prop.ForAll( + properties.Property("[BLS12-381] psi should map points from E' to itself", prop.ForAll( func() bool { var a G2Jac a.psi(&g2Gen) @@ -345,7 +345,7 @@ func TestG2AffineOps(t *testing.T) { }, )) - properties.Property("[BLS381] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BLS12-381] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -368,7 +368,7 @@ func TestG2AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BLS381] GLV and Double and Add should output the same result", prop.ForAll( + properties.Property("[BLS12-381] GLV and Double and Add should output the same result", prop.ForAll( func(s fr.Element) bool { var r big.Int @@ -392,7 +392,7 @@ func TestG2AffineCofactorCleaning(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BLS381] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( + properties.Property("[BLS12-381] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( func() bool { var a, x, b fptower.E2 a.SetRandom() @@ -429,7 +429,7 @@ func TestG2AffineBatchScalarMultiplication(t *testing.T) { // size of the multiExps const nbSamples = 10 - properties.Property("[BLS381] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( + properties.Property("[BLS12-381] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( func(mixer fr.Element) bool { // mixer ensures that all the words of a fpElement are set var sampleScalars [nbSamples]fr.Element diff --git a/bls381/hash_to_curve.go b/ecc/bls12-381/hash_to_curve.go similarity index 97% rename from bls381/hash_to_curve.go rename to ecc/bls12-381/hash_to_curve.go index c19a3c5aa3..69554d55fe 100644 --- a/bls381/hash_to_curve.go +++ b/ecc/bls12-381/hash_to_curve.go @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bls381 +package bls12381 import ( "math/big" - "github.com/consensys/gurvy/bls381/fp" - "github.com/consensys/gurvy/bls381/internal/fptower" - "github.com/consensys/gurvy/utils" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" ) // hashToFp hashes msg to count prime field elements. @@ -31,7 +31,7 @@ func hashToFp(msg, dst []byte, count int) ([]fp.Element, error) { L := 64 lenInBytes := count * L - pseudoRandomBytes, err := utils.ExpandMsgXmd(msg, dst, lenInBytes) + pseudoRandomBytes, err := ecc.ExpandMsgXmd(msg, dst, lenInBytes) if err != nil { return nil, err } diff --git a/bls381/internal/fptower/asm.go b/ecc/bls12-381/internal/fptower/asm.go similarity index 93% rename from bls381/internal/fptower/asm.go rename to ecc/bls12-381/internal/fptower/asm.go index 1458123a3d..c7bb911dfb 100644 --- a/bls381/internal/fptower/asm.go +++ b/ecc/bls12-381/internal/fptower/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bn256/internal/fptower/asm_noadx.go b/ecc/bls12-381/internal/fptower/asm_noadx.go similarity index 93% rename from bn256/internal/fptower/asm_noadx.go rename to ecc/bls12-381/internal/fptower/asm_noadx.go index cea2d1b95a..f09b13900c 100644 --- a/bn256/internal/fptower/asm_noadx.go +++ b/ecc/bls12-381/internal/fptower/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bls381/internal/fptower/e12.go b/ecc/bls12-381/internal/fptower/e12.go similarity index 98% rename from bls381/internal/fptower/e12.go rename to ecc/bls12-381/internal/fptower/e12.go index 5f752cfdbd..69046fa42a 100644 --- a/bls381/internal/fptower/e12.go +++ b/ecc/bls12-381/internal/fptower/e12.go @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower import ( "encoding/binary" "errors" - "github.com/consensys/gurvy/bls381/fp" - "github.com/consensys/gurvy/bls381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "math/big" ) diff --git a/bls381/internal/fptower/e12_pairing.go b/ecc/bls12-381/internal/fptower/e12_pairing.go similarity index 100% rename from bls381/internal/fptower/e12_pairing.go rename to ecc/bls12-381/internal/fptower/e12_pairing.go diff --git a/bls381/internal/fptower/e12_test.go b/ecc/bls12-381/internal/fptower/e12_test.go similarity index 74% rename from bls381/internal/fptower/e12_test.go rename to ecc/bls12-381/internal/fptower/e12_test.go index fc6c0880f8..5a40ae0a21 100644 --- a/bls381/internal/fptower/e12_test.go +++ b/ecc/bls12-381/internal/fptower/e12_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower @@ -35,7 +35,7 @@ func TestE12Serialization(t *testing.T) { genA := GenE12() - properties.Property("[BLS381] SetBytes(Bytes()) should stay constant", prop.ForAll( + properties.Property("[BLS12-381] SetBytes(Bytes()) should stay constant", prop.ForAll( func(a *E12) bool { var b E12 buf := a.Bytes() @@ -60,7 +60,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA := GenE12() genB := GenE12() - properties.Property("[BLS381] Having the receiver as operand (addition) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (addition) should output the same result", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Set(a) @@ -73,7 +73,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS381] Having the receiver as operand (sub) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (sub) should output the same result", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Set(a) @@ -86,7 +86,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS381] Having the receiver as operand (mul) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (mul) should output the same result", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Set(a) @@ -99,7 +99,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS381] Having the receiver as operand (square) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (square) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Square(a) @@ -109,7 +109,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (double) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (double) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Double(a) @@ -119,7 +119,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Inverse(a) @@ -129,7 +129,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (Cyclotomic square) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (Cyclotomic square) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.CyclotomicSquare(a) @@ -139,7 +139,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Conjugate(a) @@ -149,7 +149,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (Frobenius) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (Frobenius) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Frobenius(a) @@ -159,7 +159,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (FrobeniusSquare) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (FrobeniusSquare) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusSquare(a) @@ -169,7 +169,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (FrobeniusCube) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (FrobeniusCube) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusCube(a) @@ -192,7 +192,7 @@ func TestE12Ops(t *testing.T) { genA := GenE12() genB := GenE12() - properties.Property("[BLS381] sub & add should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] sub & add should leave an element invariant", prop.ForAll( func(a, b *E12) bool { var c E12 c.Set(a) @@ -203,7 +203,7 @@ func TestE12Ops(t *testing.T) { genB, )) - properties.Property("[BLS381] mul & inverse should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] mul & inverse should leave an element invariant", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Inverse(b) @@ -215,7 +215,7 @@ func TestE12Ops(t *testing.T) { genB, )) - properties.Property("[BLS381] inverse twice should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] inverse twice should leave an element invariant", prop.ForAll( func(a *E12) bool { var b E12 b.Inverse(a).Inverse(&b) @@ -224,7 +224,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] square and mul should output the same result", prop.ForAll( + properties.Property("[BLS12-381] square and mul should output the same result", prop.ForAll( func(a *E12) bool { var b, c E12 b.Mul(a, a) @@ -234,7 +234,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] a + pi(a), a-pi(a) should be real", prop.ForAll( + properties.Property("[BLS12-381] a + pi(a), a-pi(a) should be real", prop.ForAll( func(a *E12) bool { var b, c, d E12 var e, f, g E6 @@ -248,7 +248,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] pi**12=id", prop.ForAll( + properties.Property("[BLS12-381] pi**12=id", prop.ForAll( func(a *E12) bool { var b E12 b.Frobenius(a). @@ -268,7 +268,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] (pi**2)**6=id", prop.ForAll( + properties.Property("[BLS12-381] (pi**2)**6=id", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusSquare(a). @@ -282,7 +282,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] (pi**3)**4=id", prop.ForAll( + properties.Property("[BLS12-381] (pi**3)**4=id", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusCube(a). @@ -294,7 +294,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] cyclotomic square and square should be the same in the cyclotomic subgroup", prop.ForAll( + properties.Property("[BLS12-381] cyclotomic square and square should be the same in the cyclotomic subgroup", prop.ForAll( func(a *E12) bool { var b, c, d E12 b.FrobeniusCube(a). diff --git a/bls381/internal/fptower/e2.go b/ecc/bls12-381/internal/fptower/e2.go similarity index 97% rename from bls381/internal/fptower/e2.go rename to ecc/bls12-381/internal/fptower/e2.go index c24507fa4d..a7a17d467b 100644 --- a/bls381/internal/fptower/e2.go +++ b/ecc/bls12-381/internal/fptower/e2.go @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower import ( - "github.com/consensys/gurvy/bls381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "math/big" ) diff --git a/bls381/internal/fptower/e2_adx_amd64.s b/ecc/bls12-381/internal/fptower/e2_adx_amd64.s similarity index 100% rename from bls381/internal/fptower/e2_adx_amd64.s rename to ecc/bls12-381/internal/fptower/e2_adx_amd64.s diff --git a/bls381/internal/fptower/e2_amd64.go b/ecc/bls12-381/internal/fptower/e2_amd64.go similarity index 96% rename from bls381/internal/fptower/e2_amd64.go rename to ecc/bls12-381/internal/fptower/e2_amd64.go index 00e9c90e98..7614c75169 100644 --- a/bls381/internal/fptower/e2_amd64.go +++ b/ecc/bls12-381/internal/fptower/e2_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bls381/internal/fptower/e2_amd64.s b/ecc/bls12-381/internal/fptower/e2_amd64.s similarity index 100% rename from bls381/internal/fptower/e2_amd64.s rename to ecc/bls12-381/internal/fptower/e2_amd64.s diff --git a/bls381/internal/fptower/e2_bls381.go b/ecc/bls12-381/internal/fptower/e2_bls381.go similarity index 97% rename from bls381/internal/fptower/e2_bls381.go rename to ecc/bls12-381/internal/fptower/e2_bls381.go index 3a9f8923af..61f5e924da 100644 --- a/bls381/internal/fptower/e2_bls381.go +++ b/ecc/bls12-381/internal/fptower/e2_bls381.go @@ -14,7 +14,7 @@ package fptower -import "github.com/consensys/gurvy/bls381/fp" +import "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" // used with !amd64, make staticcheck happier. var ( diff --git a/bls381/internal/fptower/e2_bls381_fallback.go b/ecc/bls12-381/internal/fptower/e2_bls381_fallback.go similarity index 94% rename from bls381/internal/fptower/e2_bls381_fallback.go rename to ecc/bls12-381/internal/fptower/e2_bls381_fallback.go index 94af082a42..a53ebd1a66 100644 --- a/bls381/internal/fptower/e2_bls381_fallback.go +++ b/ecc/bls12-381/internal/fptower/e2_bls381_fallback.go @@ -16,7 +16,7 @@ package fptower -import "github.com/consensys/gurvy/bls381/fp" +import "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" // MulByNonResidue multiplies a E2 by (1,1) func (z *E2) MulByNonResidue(x *E2) *E2 { diff --git a/bls377/internal/fptower/e2_fallback.go b/ecc/bls12-381/internal/fptower/e2_fallback.go similarity index 94% rename from bls377/internal/fptower/e2_fallback.go rename to ecc/bls12-381/internal/fptower/e2_fallback.go index 262d778027..eada4c6b58 100644 --- a/bls377/internal/fptower/e2_fallback.go +++ b/ecc/bls12-381/internal/fptower/e2_fallback.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bls381/internal/fptower/e2_test.go b/ecc/bls12-381/internal/fptower/e2_test.go similarity index 72% rename from bls381/internal/fptower/e2_test.go rename to ecc/bls12-381/internal/fptower/e2_test.go index 194cf1a154..af4d8b4a44 100644 --- a/bls381/internal/fptower/e2_test.go +++ b/ecc/bls12-381/internal/fptower/e2_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower @@ -20,7 +20,7 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gurvy/bls381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -39,7 +39,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB := GenE2() genfp := GenFp() - properties.Property("[BLS381] Having the receiver as operand (addition) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (addition) should output the same result", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Set(a) @@ -52,7 +52,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS381] Having the receiver as operand (sub) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (sub) should output the same result", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Set(a) @@ -65,7 +65,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS381] Having the receiver as operand (mul) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (mul) should output the same result", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Set(a) @@ -78,7 +78,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS381] Having the receiver as operand (square) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (square) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Square(a) @@ -88,7 +88,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (neg) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (neg) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Neg(a) @@ -98,7 +98,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (double) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (double) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Double(a) @@ -108,7 +108,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.MulByNonResidue(a) @@ -118,7 +118,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (mul by non residue inverse) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (mul by non residue inverse) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.MulByNonResidueInv(a) @@ -128,7 +128,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Inverse(a) @@ -138,7 +138,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Conjugate(a) @@ -148,7 +148,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (mul by element) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (mul by element) should output the same result", prop.ForAll( func(a *E2, b fp.Element) bool { var c E2 c.MulByElement(a, &b) @@ -159,7 +159,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genfp, )) - properties.Property("[BLS381] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( func(a *E2) bool { var b, c, d, s E2 @@ -205,7 +205,7 @@ func TestE2MulMaxed(t *testing.T) { b.A0 = fpMaxValue b.A1 = fpMaxValue - // [BN256] mul & inverse should leave an element invariant", prop.ForAll( + // [BN254] mul & inverse should leave an element invariant", prop.ForAll( var c, d E2 d.Inverse(&b) c.Set(&a) @@ -226,7 +226,7 @@ func TestE2Ops(t *testing.T) { genB := GenE2() genfp := GenFp() - properties.Property("[BLS381] sub & add should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] sub & add should leave an element invariant", prop.ForAll( func(a, b *E2) bool { var c E2 c.Set(a) @@ -237,7 +237,7 @@ func TestE2Ops(t *testing.T) { genB, )) - properties.Property("[BLS381] mul & inverse should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] mul & inverse should leave an element invariant", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Inverse(b) @@ -249,7 +249,7 @@ func TestE2Ops(t *testing.T) { genB, )) - properties.Property("[BLS381] inverse twice should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] inverse twice should leave an element invariant", prop.ForAll( func(a *E2) bool { var b E2 b.Inverse(a).Inverse(&b) @@ -258,7 +258,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] neg twice should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] neg twice should leave an element invariant", prop.ForAll( func(a *E2) bool { var b E2 b.Neg(a).Neg(&b) @@ -267,7 +267,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] square and mul should output the same result", prop.ForAll( + properties.Property("[BLS12-381] square and mul should output the same result", prop.ForAll( func(a *E2) bool { var b, c E2 b.Mul(a, a) @@ -277,7 +277,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] MulByElement MulByElement inverse should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] MulByElement MulByElement inverse should leave an element invariant", prop.ForAll( func(a *E2, b fp.Element) bool { var c E2 var d fp.Element @@ -289,7 +289,7 @@ func TestE2Ops(t *testing.T) { genfp, )) - properties.Property("[BLS381] Double and mul by 2 should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Double and mul by 2 should output the same result", prop.ForAll( func(a *E2) bool { var b E2 var c fp.Element @@ -301,7 +301,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] Mulbynonres mulbynonresinv should leave the element invariant", prop.ForAll( + properties.Property("[BLS12-381] Mulbynonres mulbynonresinv should leave the element invariant", prop.ForAll( func(a *E2) bool { var b E2 b.MulByNonResidue(a).MulByNonResidueInv(&b) @@ -310,7 +310,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] a + pi(a), a-pi(a) should be real", prop.ForAll( + properties.Property("[BLS12-381] a + pi(a), a-pi(a) should be real", prop.ForAll( func(a *E2) bool { var b, c, d E2 var e, f fp.Element @@ -324,7 +324,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] Legendre on square should output 1", prop.ForAll( + properties.Property("[BLS12-381] Legendre on square should output 1", prop.ForAll( func(a *E2) bool { var b E2 b.Square(a) @@ -334,7 +334,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] square(sqrt) should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] square(sqrt) should leave an element invariant", prop.ForAll( func(a *E2) bool { var b, c, d, e E2 b.Square(a) @@ -346,7 +346,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] Cmp and LexicographicallyLargest should be consistant", prop.ForAll( + properties.Property("[BLS12-381] Cmp and LexicographicallyLargest should be consistant", prop.ForAll( func(a *E2) bool { var negA E2 negA.Neg(a) diff --git a/bn256/internal/fptower/e6.go b/ecc/bls12-381/internal/fptower/e6.go similarity index 98% rename from bn256/internal/fptower/e6.go rename to ecc/bls12-381/internal/fptower/e6.go index b29e6f9869..5ba35cf020 100644 --- a/bn256/internal/fptower/e6.go +++ b/ecc/bls12-381/internal/fptower/e6.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bls381/internal/fptower/e6_test.go b/ecc/bls12-381/internal/fptower/e6_test.go similarity index 69% rename from bls381/internal/fptower/e6_test.go rename to ecc/bls12-381/internal/fptower/e6_test.go index 95e30afb6b..3beb651685 100644 --- a/bls381/internal/fptower/e6_test.go +++ b/ecc/bls12-381/internal/fptower/e6_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower @@ -36,7 +36,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA := GenE6() genB := GenE6() - properties.Property("[BLS381] Having the receiver as operand (addition) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (addition) should output the same result", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Set(a) @@ -49,7 +49,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS381] Having the receiver as operand (sub) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (sub) should output the same result", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Set(a) @@ -62,7 +62,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS381] Having the receiver as operand (mul) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (mul) should output the same result", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Set(a) @@ -75,7 +75,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BLS381] Having the receiver as operand (square) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (square) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Square(a) @@ -85,7 +85,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (neg) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (neg) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Neg(a) @@ -95,7 +95,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (double) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (double) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Double(a) @@ -105,7 +105,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.MulByNonResidue(a) @@ -115,7 +115,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BLS381] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Inverse(a) @@ -138,7 +138,7 @@ func TestE6Ops(t *testing.T) { genA := GenE6() genB := GenE6() - properties.Property("[BLS381] sub & add should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] sub & add should leave an element invariant", prop.ForAll( func(a, b *E6) bool { var c E6 c.Set(a) @@ -149,7 +149,7 @@ func TestE6Ops(t *testing.T) { genB, )) - properties.Property("[BLS381] mul & inverse should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] mul & inverse should leave an element invariant", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Inverse(b) @@ -161,7 +161,7 @@ func TestE6Ops(t *testing.T) { genB, )) - properties.Property("[BLS381] inverse twice should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] inverse twice should leave an element invariant", prop.ForAll( func(a *E6) bool { var b E6 b.Inverse(a).Inverse(&b) @@ -170,7 +170,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] neg twice should leave an element invariant", prop.ForAll( + properties.Property("[BLS12-381] neg twice should leave an element invariant", prop.ForAll( func(a *E6) bool { var b E6 b.Neg(a).Neg(&b) @@ -179,7 +179,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] square and mul should output the same result", prop.ForAll( + properties.Property("[BLS12-381] square and mul should output the same result", prop.ForAll( func(a *E6) bool { var b, c E6 b.Mul(a, a) @@ -189,7 +189,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] Double and add twice should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Double and add twice should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Add(a, a) @@ -199,7 +199,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BLS381] Mul by non residue should be the same as multiplying by (0,1,0)", prop.ForAll( + properties.Property("[BLS12-381] Mul by non residue should be the same as multiplying by (0,1,0)", prop.ForAll( func(a *E6) bool { var b, c E6 b.B1.A0.SetOne() diff --git a/bls381/internal/fptower/frobenius.go b/ecc/bls12-381/internal/fptower/frobenius.go similarity index 99% rename from bls381/internal/fptower/frobenius.go rename to ecc/bls12-381/internal/fptower/frobenius.go index d2581258a0..a4f189ff1b 100644 --- a/bls381/internal/fptower/frobenius.go +++ b/ecc/bls12-381/internal/fptower/frobenius.go @@ -14,7 +14,7 @@ package fptower -import "github.com/consensys/gurvy/bls381/fp" +import "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" // Frobenius set z to Frobenius(x), return z func (z *E12) Frobenius(x *E12) *E12 { diff --git a/bls381/internal/fptower/generators_test.go b/ecc/bls12-381/internal/fptower/generators_test.go similarity index 95% rename from bls381/internal/fptower/generators_test.go rename to ecc/bls12-381/internal/fptower/generators_test.go index d6b0d49e1e..8bf58a6b49 100644 --- a/bls381/internal/fptower/generators_test.go +++ b/ecc/bls12-381/internal/fptower/generators_test.go @@ -3,7 +3,7 @@ package fptower import ( "crypto/rand" - "github.com/consensys/gurvy/bls381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" "github.com/leanovate/gopter" ) diff --git a/bls381/marshal.go b/ecc/bls12-381/marshal.go similarity index 96% rename from bls381/marshal.go rename to ecc/bls12-381/marshal.go index 97758cd49c..2d65c042f1 100644 --- a/bls381/marshal.go +++ b/ecc/bls12-381/marshal.go @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -// Package bls381 provides efficient elliptic curve and pairing implementation for bls381 -package bls381 +// Package bls12381 provides efficient elliptic curve and pairing implementation for bls12-381 +package bls12381 import ( "encoding/binary" @@ -24,15 +24,15 @@ import ( "reflect" "sync/atomic" - "github.com/consensys/gurvy/bls381/fp" - "github.com/consensys/gurvy/bls381/fr" - "github.com/consensys/gurvy/bls381/internal/fptower" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" ) // To encode G1Affine and G2Affine points, we mask the most significant bits with these bits to specify without ambiguity // metadata needed for point (de)compression -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. @@ -48,20 +48,20 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT -// Encoder writes bls381 object values to an output stream +// Encoder writes bls12-381 object values to an output stream type Encoder struct { w io.Writer n int64 // written bytes raw bool // raw vs compressed encoding } -// Decoder reads bls381 object values from an inbound stream +// Decoder reads bls12-381 object values from an inbound stream type Decoder struct { r io.Reader n int64 // read bytes } -// NewDecoder returns a binary decoder supporting curve bls381 objects in both +// NewDecoder returns a binary decoder supporting curve bls12-381 objects in both // compressed and uncompressed (raw) forms func NewDecoder(r io.Reader) *Decoder { return &Decoder{r: r} @@ -72,7 +72,7 @@ func NewDecoder(r io.Reader) *Decoder { func (dec *Decoder) Decode(v interface{}) (err error) { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr || rv.IsNil() || !rv.Elem().CanSet() { - return errors.New("bls381 decoder: unsupported type, need pointer") + return errors.New("bls12-381 decoder: unsupported type, need pointer") } // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap @@ -249,7 +249,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return nil default: - return errors.New("bls381 encoder: unsupported type") + return errors.New("bls12-381 encoder: unsupported type") } } @@ -287,7 +287,7 @@ func isCompressed(msb byte) bool { return !((mData == mUncompressed) || (mData == mUncompressedInfinity)) } -// NewEncoder returns a binary encoder supporting curve bls381 objects +// NewEncoder returns a binary encoder supporting curve bls12-381 objects func NewEncoder(w io.Writer, options ...func(*Encoder)) *Encoder { // default settings enc := &Encoder{ @@ -494,7 +494,7 @@ func (p *G1Affine) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. @@ -749,7 +749,7 @@ func (p *G2Affine) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. diff --git a/bls381/marshal_test.go b/ecc/bls12-381/marshal_test.go similarity index 97% rename from bls381/marshal_test.go rename to ecc/bls12-381/marshal_test.go index d97a9e35f6..2cf04df6eb 100644 --- a/bls381/marshal_test.go +++ b/ecc/bls12-381/marshal_test.go @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls381 +package bls12381 import ( "bytes" @@ -26,8 +26,8 @@ import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" - "github.com/consensys/gurvy/bls381/fp" - "github.com/consensys/gurvy/bls381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" ) func TestEncoder(t *testing.T) { diff --git a/bn256/multiexp.go b/ecc/bls12-381/multiexp.go similarity index 99% rename from bn256/multiexp.go rename to ecc/bls12-381/multiexp.go index 74316eb25e..bfe68cfc8c 100644 --- a/bn256/multiexp.go +++ b/ecc/bls12-381/multiexp.go @@ -12,20 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bn256 +package bls12381 import ( - "github.com/consensys/gurvy/bn256/fr" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/internal/parallel" "math" "runtime" "sync" ) // CPUSemaphore enables users to set optional number of CPUs the multiexp will use -// this is thread safe and can be used accross parallel calls of gurvy.MultiExp +// this is thread safe and can be used accross parallel calls of MultiExp type CPUSemaphore struct { chCpus chan struct{} // semaphore to limit number of cpus iterating through points and scalrs at the same time lock sync.Mutex @@ -160,7 +160,7 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, opts ...*CPUSe // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 // * number of CPUs // * cache friendliness (which depends on the host, G1 or G2... ) - // --> for example, on BN256, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. // for each msmCX // step 1 @@ -995,7 +995,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, opts ...*CPUSe // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 // * number of CPUs // * cache friendliness (which depends on the host, G1 or G2... ) - // --> for example, on BN256, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. // for each msmCX // step 1 diff --git a/bls377/multiexp_test.go b/ecc/bls12-381/multiexp_test.go similarity index 99% rename from bls377/multiexp_test.go rename to ecc/bls12-381/multiexp_test.go index 5d9a44ba45..ec5a6f2d93 100644 --- a/bls377/multiexp_test.go +++ b/ecc/bls12-381/multiexp_test.go @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls377 +package bls12381 import ( "fmt" @@ -23,7 +23,7 @@ import ( "runtime" "testing" - "github.com/consensys/gurvy/bls377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) diff --git a/bls381/pairing.go b/ecc/bls12-381/pairing.go similarity index 98% rename from bls381/pairing.go rename to ecc/bls12-381/pairing.go index 4b1bbcc69e..bb99340896 100644 --- a/bls381/pairing.go +++ b/ecc/bls12-381/pairing.go @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bls381 +package bls12381 import ( "errors" - "github.com/consensys/gurvy/bls381/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" ) // GT target group of the pairing diff --git a/bls377/pairing_test.go b/ecc/bls12-381/pairing_test.go similarity index 88% rename from bls377/pairing_test.go rename to ecc/bls12-381/pairing_test.go index dd472a0b34..5f466a06ac 100644 --- a/bls377/pairing_test.go +++ b/ecc/bls12-381/pairing_test.go @@ -12,16 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls377 +package bls12381 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bls377/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -69,7 +69,7 @@ func TestPairing(t *testing.T) { genR1 := GenFr() genR2 := GenFr() - properties.Property("[BLS377] Having the receiver as operand (final expo) should output the same result", prop.ForAll( + properties.Property("[BLS12-381] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a *GT) bool { var b GT b.Set(a) @@ -80,7 +80,7 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BLS377] Exponentiating FinalExpo(a) to r should output 1", prop.ForAll( + properties.Property("[BLS12-381] Exponentiating FinalExpo(a) to r should output 1", prop.ForAll( func(a *GT) bool { var one GT e := fr.Modulus() @@ -92,7 +92,7 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BLS377] bilinearity", prop.ForAll( + properties.Property("[BLS12-381] bilinearity", prop.ForAll( func(a, b fr.Element) bool { var res, resa, resb, resab, zero GT @@ -124,7 +124,7 @@ func TestPairing(t *testing.T) { genR2, )) - properties.Property("[BLS377] MillerLoop of pairs should be equal to the product of MillerLoops", prop.ForAll( + properties.Property("[BLS12-381] MillerLoop of pairs should be equal to the product of MillerLoops", prop.ForAll( func(a, b fr.Element) bool { var simpleProd, factorizedProd GT @@ -165,7 +165,7 @@ func TestPairing(t *testing.T) { genR2, )) - properties.Property("[BLS377] PairingCheck", prop.ForAll( + properties.Property("[BLS12-381] PairingCheck", prop.ForAll( func(a, b fr.Element) bool { var g1GenAffNeg G1Affine diff --git a/ecc/bls12-381/twistededwards/eddsa/eddsa.go b/ecc/bls12-381/twistededwards/eddsa/eddsa.go new file mode 100644 index 0000000000..e47d17e240 --- /dev/null +++ b/ecc/bls12-381/twistededwards/eddsa/eddsa.go @@ -0,0 +1,265 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/crypto/signature" + "github.com/consensys/gnark-crypto/ecc/bls12-381/twistededwards" + + "golang.org/x/crypto/blake2b" +) + +var errNotOnCurve = errors.New("point not on curve") + +const ( + sizeFr = 32 + sizePublicKey = sizeFr + sizeSignature = 2 * sizeFr + sizePrivateKey = 2*sizeFr + 32 +) + +// PublicKey eddsa signature object +// cf https://en.wikipedia.org/wiki/EdDSA for notation +type PublicKey struct { + A twistededwards.PointAffine +} + +// PrivateKey private key of an eddsa instance +type PrivateKey struct { + PublicKey PublicKey // copy of the associated public key + scalar [sizeFr]byte // secret scalar, in big Endian + randSrc [32]byte // source +} + +// Signature represents an eddsa signature +// cf https://en.wikipedia.org/wiki/EdDSA for notation +type Signature struct { + R twistededwards.PointAffine + S [sizeFr]byte +} + +func init() { + signature.Register(signature.EDDSA_BLS12_381, GenerateKeyInterfaces) +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(r io.Reader) (PrivateKey, error) { + + c := twistededwards.GetEdwardsCurve() + + var pub PublicKey + var priv PrivateKey + + // hash(h) = private_key || random_source, on 32 bytes each + seed := make([]byte, 32) + _, err := r.Read(seed) + if err != nil { + return priv, err + } + h := blake2b.Sum512(seed[:]) + for i := 0; i < 32; i++ { + priv.randSrc[i] = h[i+32] + } + + // prune the key + // https://tools.ietf.org/html/rfc8032#section-5.1.5, key generation + + h[0] &= 0xF8 + h[31] &= 0x7F + h[31] |= 0x40 + + // reverse first bytes because setBytes interpret stream as big endian + // but in eddsa specs s is the first 32 bytes in little endian + for i, j := 0, sizeFr; i < j; i, j = i+1, j-1 { + + h[i], h[j] = h[j], h[i] + + } + + copy(priv.scalar[:], h[:sizeFr]) + + var bscalar big.Int + bscalar.SetBytes(priv.scalar[:]) + pub.A.ScalarMul(&c.Base, &bscalar) + + priv.PublicKey = pub + + return priv, nil +} + +// GenerateKeyInterfaces generate interfaces for the public/private key. +// This purpose of this function is to be registered in the list of signature schemes. +func GenerateKeyInterfaces(r io.Reader) (signature.Signer, error) { + priv, err := GenerateKey(r) + return &priv, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(other signature.PublicKey) bool { + bpk := pub.Bytes() + bother := other.Bytes() + return subtle.ConstantTimeCompare(bpk, bother) == 1 +} + +// Public returns the public key associated to the private key. +// From Signer interface defined in gnark/crypto/signature. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign sign a message +// Pure Eddsa version (see https://tools.ietf.org/html/rfc8032#page-8) +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + curveParams := twistededwards.GetEdwardsCurve() + + var res Signature + + // blinding factor for the private key + // blindingFactorBigInt must be the same size as the private key, + // blindingFactorBigInt = h(randomness_source||message)[:sizeFr] + var blindingFactorBigInt big.Int + + // randSrc = privKey.randSrc || msg (-> message = MSB message .. LSB message) + randSrc := make([]byte, 32+len(message)) + for i, v := range privKey.randSrc { + randSrc[i] = v + } + copy(randSrc[32:], message) + + // randBytes = H(randSrc) + blindingFactorBytes := blake2b.Sum512(randSrc[:]) // TODO ensures that the hash used to build the key and the one used here is the same + blindingFactorBigInt.SetBytes(blindingFactorBytes[:sizeFr]) + + // compute R = randScalar*Base + res.R.ScalarMul(&curveParams.Base, &blindingFactorBigInt) + if !res.R.IsOnCurve() { + return nil, errNotOnCurve + } + + // compute H(R, A, M), all parameters in data are in Montgomery form + resRX := res.R.X.Bytes() + resRY := res.R.Y.Bytes() + resAX := privKey.PublicKey.A.X.Bytes() + resAY := privKey.PublicKey.A.Y.Bytes() + sizeDataToHash := 4*sizeFr + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], resRX[:]) + copy(dataToHash[sizeFr:], resRY[:]) + copy(dataToHash[2*sizeFr:], resAX[:]) + copy(dataToHash[3*sizeFr:], resAY[:]) + copy(dataToHash[4*sizeFr:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + var hramInt big.Int + hramBin := hFunc.Sum(nil) + hramInt.SetBytes(hramBin) + + // Compute s = randScalarInt + H(R,A,M)*S + // going with big int to do ops mod curve order + var bscalar, bs big.Int + bscalar.SetBytes(privKey.scalar[:]) + bs.Mul(&hramInt, &bscalar). + Add(&bs, &blindingFactorBigInt). + Mod(&bs, &curveParams.Order) + sb := bs.Bytes() + if len(sb) < sizeFr { + offset := make([]byte, sizeFr-len(sb)) + sb = append(offset, sb...) + } + copy(res.S[:], sb[:]) + + return res.Bytes(), nil +} + +// Verify verifies an eddsa signature +func (pub *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + curveParams := twistededwards.GetEdwardsCurve() + + // verify that pubKey and R are on the curve + if !pub.A.IsOnCurve() { + return false, errNotOnCurve + } + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + // compute H(R, A, M), all parameters in data are in Montgomery form + sigRX := sig.R.X.Bytes() + sigRY := sig.R.Y.Bytes() + sigAX := pub.A.X.Bytes() + sigAY := pub.A.Y.Bytes() + sizeDataToHash := 4*sizeFr + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], sigRX[:]) + copy(dataToHash[sizeFr:], sigRY[:]) + copy(dataToHash[2*sizeFr:], sigAX[:]) + copy(dataToHash[3*sizeFr:], sigAY[:]) + copy(dataToHash[4*sizeFr:], message) + hFunc.Reset() + if _, err := hFunc.Write(dataToHash[:]); err != nil { + return false, err + } + + var hramInt big.Int + hramBin := hFunc.Sum(nil) + hramInt.SetBytes(hramBin) + + // lhs = cofactor*S*Base + var lhs twistededwards.PointAffine + var bCofactor, bs big.Int + curveParams.Cofactor.ToBigInt(&bCofactor) + bs.SetBytes(sig.S[:]) + lhs.ScalarMul(&curveParams.Base, &bs). + ScalarMul(&lhs, &bCofactor) + + if !lhs.IsOnCurve() { + return false, errNotOnCurve + } + + // rhs = cofactor*(R + H(R,A,M)*A) + var rhs twistededwards.PointAffine + rhs.ScalarMul(&pub.A, &hramInt). + Add(&rhs, &sig.R). + ScalarMul(&rhs, &bCofactor) + if !rhs.IsOnCurve() { + return false, errNotOnCurve + } + + // verifies that cofactor*S*Base=cofactor*(R + H(R,A,M)*A) + if !lhs.X.Equal(&rhs.X) || !lhs.Y.Equal(&rhs.Y) { + return false, nil + } + + return true, nil +} diff --git a/ecc/bls12-381/twistededwards/eddsa/eddsa_test.go b/ecc/bls12-381/twistededwards/eddsa/eddsa_test.go new file mode 100644 index 0000000000..8030f318e1 --- /dev/null +++ b/ecc/bls12-381/twistededwards/eddsa/eddsa_test.go @@ -0,0 +1,179 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/sha256" + "math/rand" + "testing" + + "github.com/consensys/gnark-crypto/crypto/hash" + "github.com/consensys/gnark-crypto/crypto/signature" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" +) + +func TestSerialization(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + privKey1, err := signature.EDDSA_BLS12_381.New(r) + if err != nil { + t.Fatal(err) + } + pubKey1 := privKey1.Public() + + privKey2, err := signature.EDDSA_BLS12_381.New(r) + if err != nil { + t.Fatal(err) + } + pubKey2 := privKey2.Public() + + pubKeyBin1 := pubKey1.Bytes() + pubKey2.SetBytes(pubKeyBin1) + pubKeyBin2 := pubKey2.Bytes() + if len(pubKeyBin1) != len(pubKeyBin2) { + t.Fatal("Inconistent size") + } + for i := 0; i < len(pubKeyBin1); i++ { + if pubKeyBin1[i] != pubKeyBin2[i] { + t.Fatal("Error serialize(deserialize(.))") + } + } + + privKeyBin1 := privKey1.Bytes() + privKey2.SetBytes(privKeyBin1) + privKeyBin2 := privKey2.Bytes() + if len(privKeyBin1) != len(privKeyBin2) { + t.Fatal("Inconistent size") + } + for i := 0; i < len(privKeyBin1); i++ { + if privKeyBin1[i] != privKeyBin2[i] { + t.Fatal("Error serialize(deserialize(.))") + } + } +} + +func TestEddsaMIMC(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + // create eddsa obj and sign a message + privKey, err := signature.EDDSA_BLS12_381.New(r) + if err != nil { + t.Fatal(nil) + } + pubKey := privKey.Public() + hFunc := hash.MIMC_BLS12_381.New("seed") + + var frMsg fr.Element + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035978") + msgBin := frMsg.Bytes() + signature, err := privKey.Sign(msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + + // verifies correct msg + res, err := pubKey.Verify(signature, msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + if !res { + t.Fatal("Verifiy correct signature should return true") + } + + // verifies wrong msg + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035979") + msgBin = frMsg.Bytes() + res, err = pubKey.Verify(signature, msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + if res { + t.Fatal("Verfiy wrong signature should be false") + } + +} + +func TestEddsaSHA256(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + hFunc := sha256.New() + + // create eddsa obj and sign a message + // create eddsa obj and sign a message + + privKey, err := signature.EDDSA_BLS12_381.New(r) + pubKey := privKey.Public() + if err != nil { + t.Fatal(err) + } + + signature, err := privKey.Sign([]byte("message"), hFunc) + if err != nil { + t.Fatal(err) + } + + // verifies correct msg + res, err := pubKey.Verify(signature, []byte("message"), hFunc) + if err != nil { + t.Fatal(err) + } + if !res { + t.Fatal("Verifiy correct signature should return true") + } + + // verifies wrong msg + res, err = pubKey.Verify(signature, []byte("wrong_message"), hFunc) + if err != nil { + t.Fatal(err) + } + if res { + t.Fatal("Verfiy wrong signature should be false") + } + +} + +// benchmarks + +func BenchmarkVerify(b *testing.B) { + + src := rand.NewSource(0) + r := rand.New(src) + + hFunc := hash.MIMC_BLS12_381.New("seed") + + // create eddsa obj and sign a message + privKey, err := signature.EDDSA_BLS12_381.New(r) + pubKey := privKey.Public() + if err != nil { + b.Fatal(err) + } + var frMsg fr.Element + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035978") + msgBin := frMsg.Bytes() + signature, _ := privKey.Sign(msgBin[:], hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + pubKey.Verify(signature, msgBin[:], hFunc) + } +} diff --git a/ecc/bls12-381/twistededwards/eddsa/marshal.go b/ecc/bls12-381/twistededwards/eddsa/marshal.go new file mode 100644 index 0000000000..97267823e1 --- /dev/null +++ b/ecc/bls12-381/twistededwards/eddsa/marshal.go @@ -0,0 +1,129 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of pk +// as x||y where x, y are the coordinates of the point +// on the twisted Edwards as big endian integers. +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the twisted Edwards. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !pk.A.IsOnCurve() { + return n, errNotOnCurve + } + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar||randSrc +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:2*sizeFr], privKey.scalar[:]) + subtle.ConstantTimeCopy(1, res[2*sizeFr:], privKey.randSrc[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar||randSrc +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !privKey.PublicKey.A.IsOnCurve() { + return n, errNotOnCurve + } + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, privKey.randSrc[:], buf[2*sizeFr:]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 3*sizeFr x||y||s where +// * x, y are the coordinates of a point on the twisted +// Edwards represented in big endian +// * s=r+h(r,a,m) mod l, the Hasse bound guarantess that +// s is smaller than sizeFr (in particular it is supposed +// s is NOT blinded) +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + sigRBin := sig.R.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], sigRBin[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as x||y||s where +// * x,y are the coordinates of a point on the twisted +// Edwards represented in big endian +// * s=r+h(r,a,m) mod l, the Hasse bound guarantess that +// s is smaller than sizeFr (in particular it is supposed +// s is NOT blinded) +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + if _, err := sig.R.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !sig.R.IsOnCurve() { + return n, errNotOnCurve + } + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/bn256/twistededwards/point.go b/ecc/bls12-381/twistededwards/point.go similarity index 91% rename from bn256/twistededwards/point.go rename to ecc/bls12-381/twistededwards/point.go index 42fbd5d2ef..60096f87ff 100644 --- a/bn256/twistededwards/point.go +++ b/ecc/bls12-381/twistededwards/point.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package twistededwards @@ -22,7 +22,7 @@ import ( "math/big" "math/bits" - "github.com/consensys/gurvy/bn256/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" ) // PointAffine point on a twisted Edwards curve @@ -43,12 +43,11 @@ const ( mCompressedPositive = 0x00 mUnmask = 0x7f - // size in byte of (x,y) + // size in byte of a compressed point (point.Y --> fr.Element) sizePointCompressed = fr.Limbs * 8 ) -// Bytes returns the point as bytes array x||y, where -// x and y are in big endian. +// Bytes returns the compressed point as a byte array // Follows https://tools.ietf.org/html/rfc8032#section-3.1, // as the twisted Edwards implementation is primarily used // for eddsa. @@ -91,15 +90,11 @@ func computeX(y *fr.Element) (x fr.Element) { return } -// SetBytes sets p from the buf, where bug is interpreted -// as a sizePointCompressed+ byte slice, where the first 32 bytes -// are interpreted as x in big endian, the next 32 bytes are -// interpreted as y in big endian. Returns the number of read bytes -// and an error if the buffer is too short. -// Returns the number of bytes read. -// Follows https://tools.ietf.org/html/rfc8032#section-3.1, -// as the twisted Edwards implementation is primarily used -// for eddsa. +// SetBytes sets p from buf +// len(buf) >= sizePointCompressed +// buf contains the Y coordinate masked with a parity bit to recompute the X coordinate +// from the curve equation. See Bytes() and https://tools.ietf.org/html/rfc8032#section-3.1 +// Returns the number of read bytes and an error if the buffer is too short. func (p *PointAffine) SetBytes(buf []byte) (int, error) { if len(buf) < sizePointCompressed { @@ -124,7 +119,7 @@ func (p *PointAffine) SetBytes(buf []byte) (int, error) { } } - return 32, nil + return sizePointCompressed, nil } // Unmarshal alias to SetBytes() diff --git a/bls381/twistededwards/twistededwards.go b/ecc/bls12-381/twistededwards/twistededwards.go similarity index 97% rename from bls381/twistededwards/twistededwards.go rename to ecc/bls12-381/twistededwards/twistededwards.go index 58373b2c6d..8840243e7e 100644 --- a/bls381/twistededwards/twistededwards.go +++ b/ecc/bls12-381/twistededwards/twistededwards.go @@ -19,7 +19,7 @@ package twistededwards import ( "math/big" - "github.com/consensys/gurvy/bls381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" ) // CurveParams curve parameters: ax^2 + y^2 = 1 + d*x^2*y^2 diff --git a/bls381/twistededwards/twistededwards_test.go b/ecc/bls12-381/twistededwards/twistededwards_test.go similarity index 98% rename from bls381/twistededwards/twistededwards_test.go rename to ecc/bls12-381/twistededwards/twistededwards_test.go index 22857e46b1..b2f35026d7 100644 --- a/bls381/twistededwards/twistededwards_test.go +++ b/ecc/bls12-381/twistededwards/twistededwards_test.go @@ -3,7 +3,7 @@ package twistededwards import ( "math/big" - "github.com/consensys/gurvy/bls381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" "testing" ) diff --git a/bls381/utils_test.go b/ecc/bls12-381/utils_test.go similarity index 89% rename from bls381/utils_test.go rename to ecc/bls12-381/utils_test.go index 2a297e186d..fce6de34c7 100644 --- a/bls381/utils_test.go +++ b/ecc/bls12-381/utils_test.go @@ -1,11 +1,11 @@ -package bls381 +package bls12381 import ( "math/rand" - "github.com/consensys/gurvy/bls381/fp" - "github.com/consensys/gurvy/bls381/fr" - "github.com/consensys/gurvy/bls381/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fp" + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" + "github.com/consensys/gnark-crypto/ecc/bls12-381/internal/fptower" "github.com/leanovate/gopter" ) diff --git a/bn256/bn256.go b/ecc/bn254/bn254.go similarity index 90% rename from bn256/bn256.go rename to ecc/bn254/bn254.go index d21b7f75ed..e27e9177a4 100644 --- a/bn256/bn256.go +++ b/ecc/bn254/bn254.go @@ -1,13 +1,12 @@ -package bn256 +package bn254 import ( "math/big" - "github.com/consensys/gurvy" - "github.com/consensys/gurvy/bn256/fp" - "github.com/consensys/gurvy/bn256/fr" - "github.com/consensys/gurvy/bn256/internal/fptower" - "github.com/consensys/gurvy/utils" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" ) // E: y**2=x**3+3 @@ -19,8 +18,8 @@ import ( // Fp: p=21888242871839275222246405745257275088696311157297823662689037894645226208583 // Fr: r=21888242871839275222246405745257275088548364400416034343698204186575808495617 -// ID bn256 ID -const ID = gurvy.BN256 +// ID bn254 ID +const ID = ecc.BN254 // bCurveCoeff b coeff of the curve var bCurveCoeff fp.Element @@ -59,7 +58,7 @@ var lambdaGLV big.Int // glvBasis stores R-linearly independant vectors (a,b), (c,d) // in ker((u,v)->u+vlambda[r]), and their determinant -var glvBasis utils.Lattice +var glvBasis ecc.Lattice // psi o pi o psi**-1, where psi:E->E' is the degree 6 iso defined over Fp12 var endo struct { @@ -102,7 +101,7 @@ func init() { thirdRootOneG2.Square(&thirdRootOneG1) lambdaGLV.SetString("4407920970296243842393367215006156084916469457145843978461", 10) // (36*x**3+18*x**2+6*x+1) _r := fr.Modulus() - utils.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) endo.u.A0.SetString("21575463638280843010398324269430826099269044274347216827212613867836435027261") endo.u.A1.SetString("10307601595873709700152284273816112264069230130616436755625194854815875713954") @@ -111,7 +110,7 @@ func init() { // binary decomposition of 15132376222941642752 little endian optimaAteLoop, _ := new(big.Int).SetString("29793968203157093288", 10) - utils.NafDecomposition(optimaAteLoop, loopCounter[:]) + ecc.NafDecomposition(optimaAteLoop, loopCounter[:]) xGen.SetString("4965661367192848881", 10) diff --git a/bn256/fp/arith.go b/ecc/bn254/fp/arith.go similarity index 96% rename from bn256/fp/arith.go rename to ecc/bn254/fp/arith.go index a055885c03..66fa667482 100644 --- a/bn256/fp/arith.go +++ b/ecc/bn254/fp/arith.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bls377/fp/asm.go b/ecc/bn254/fp/asm.go similarity index 92% rename from bls377/fp/asm.go rename to ecc/bn254/fp/asm.go index 04495b0cfc..715bc7ac12 100644 --- a/bls377/fp/asm.go +++ b/ecc/bn254/fp/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bls381/fp/asm_noadx.go b/ecc/bn254/fp/asm_noadx.go similarity index 93% rename from bls381/fp/asm_noadx.go rename to ecc/bn254/fp/asm_noadx.go index e878f3473d..371bfeaeb3 100644 --- a/bls381/fp/asm_noadx.go +++ b/ecc/bn254/fp/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bn256/fp/element.go b/ecc/bn254/fp/element.go similarity index 99% rename from bn256/fp/element.go rename to ecc/bn254/fp/element.go index 4c66bc477e..8123dbe14c 100644 --- a/bn256/fp/element.go +++ b/ecc/bn254/fp/element.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT // Package fp contains field arithmetic operations for modulus 21888242871839275222246405745257275088696311157297823662689037894645226208583 package fp diff --git a/bn256/fp/element_mul_adx_amd64.s b/ecc/bn254/fp/element_mul_adx_amd64.s similarity index 100% rename from bn256/fp/element_mul_adx_amd64.s rename to ecc/bn254/fp/element_mul_adx_amd64.s diff --git a/bn256/fp/element_mul_amd64.s b/ecc/bn254/fp/element_mul_amd64.s similarity index 100% rename from bn256/fp/element_mul_amd64.s rename to ecc/bn254/fp/element_mul_amd64.s diff --git a/bls381/fp/element_ops_amd64.go b/ecc/bn254/fp/element_ops_amd64.go similarity index 94% rename from bls381/fp/element_ops_amd64.go rename to ecc/bn254/fp/element_ops_amd64.go index 7c3aa757be..71b26855b4 100644 --- a/bls381/fp/element_ops_amd64.go +++ b/ecc/bn254/fp/element_ops_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bn256/fp/element_ops_amd64.s b/ecc/bn254/fp/element_ops_amd64.s similarity index 100% rename from bn256/fp/element_ops_amd64.s rename to ecc/bn254/fp/element_ops_amd64.s diff --git a/bn256/fp/element_ops_noasm.go b/ecc/bn254/fp/element_ops_noasm.go similarity index 96% rename from bn256/fp/element_ops_noasm.go rename to ecc/bn254/fp/element_ops_noasm.go index 5563ce93fe..e6ced1bf56 100644 --- a/bn256/fp/element_ops_noasm.go +++ b/ecc/bn254/fp/element_ops_noasm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bn256/fp/element_test.go b/ecc/bn254/fp/element_test.go similarity index 99% rename from bn256/fp/element_test.go rename to ecc/bn254/fp/element_test.go index cb7963e0e1..ed70d780e6 100644 --- a/bn256/fp/element_test.go +++ b/ecc/bn254/fp/element_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp @@ -206,11 +206,6 @@ func TestElementCmp(t *testing.T) { } } -func TestElementSetInterface(t *testing.T) { - // TODO - t.Skip("not implemented") -} - func TestElementIsRandom(t *testing.T) { for i := 0; i < 50; i++ { var x, y Element diff --git a/bls381/fr/arith.go b/ecc/bn254/fr/arith.go similarity index 96% rename from bls381/fr/arith.go rename to ecc/bn254/fr/arith.go index 9f42f6641f..83c9fd9ef9 100644 --- a/bls381/fr/arith.go +++ b/ecc/bn254/fr/arith.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bw761/fr/asm.go b/ecc/bn254/fr/asm.go similarity index 92% rename from bw761/fr/asm.go rename to ecc/bn254/fr/asm.go index 7c77fecb17..f859dd8731 100644 --- a/bw761/fr/asm.go +++ b/ecc/bn254/fr/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bn256/fr/asm_noadx.go b/ecc/bn254/fr/asm_noadx.go similarity index 93% rename from bn256/fr/asm_noadx.go rename to ecc/bn254/fr/asm_noadx.go index 3b2f49bd87..ab9b869b5b 100644 --- a/bn256/fr/asm_noadx.go +++ b/ecc/bn254/fr/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bn256/fr/element.go b/ecc/bn254/fr/element.go similarity index 99% rename from bn256/fr/element.go rename to ecc/bn254/fr/element.go index 8e44f35135..3759baa584 100644 --- a/bn256/fr/element.go +++ b/ecc/bn254/fr/element.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT // Package fr contains field arithmetic operations for modulus 21888242871839275222246405745257275088548364400416034343698204186575808495617 package fr diff --git a/bn256/fr/element_mul_adx_amd64.s b/ecc/bn254/fr/element_mul_adx_amd64.s similarity index 100% rename from bn256/fr/element_mul_adx_amd64.s rename to ecc/bn254/fr/element_mul_adx_amd64.s diff --git a/bn256/fr/element_mul_amd64.s b/ecc/bn254/fr/element_mul_amd64.s similarity index 100% rename from bn256/fr/element_mul_amd64.s rename to ecc/bn254/fr/element_mul_amd64.s diff --git a/bls377/fr/element_ops_amd64.go b/ecc/bn254/fr/element_ops_amd64.go similarity index 94% rename from bls377/fr/element_ops_amd64.go rename to ecc/bn254/fr/element_ops_amd64.go index 73ae624914..f0d8316e52 100644 --- a/bls377/fr/element_ops_amd64.go +++ b/ecc/bn254/fr/element_ops_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bn256/fr/element_ops_amd64.s b/ecc/bn254/fr/element_ops_amd64.s similarity index 100% rename from bn256/fr/element_ops_amd64.s rename to ecc/bn254/fr/element_ops_amd64.s diff --git a/bls377/fr/element_ops_noasm.go b/ecc/bn254/fr/element_ops_noasm.go similarity index 96% rename from bls377/fr/element_ops_noasm.go rename to ecc/bn254/fr/element_ops_noasm.go index e902f2906a..e7daa4d40e 100644 --- a/bls377/fr/element_ops_noasm.go +++ b/ecc/bn254/fr/element_ops_noasm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bn256/fr/element_test.go b/ecc/bn254/fr/element_test.go similarity index 99% rename from bn256/fr/element_test.go rename to ecc/bn254/fr/element_test.go index 59033b33eb..7ba46e5da2 100644 --- a/bn256/fr/element_test.go +++ b/ecc/bn254/fr/element_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr @@ -206,11 +206,6 @@ func TestElementCmp(t *testing.T) { } } -func TestElementSetInterface(t *testing.T) { - // TODO - t.Skip("not implemented") -} - func TestElementIsRandom(t *testing.T) { for i := 0; i < 50; i++ { var x, y Element diff --git a/ecc/bn254/fr/fft/domain.go b/ecc/bn254/fr/fft/domain.go new file mode 100644 index 0000000000..7ec3a365c3 --- /dev/null +++ b/ecc/bn254/fr/fft/domain.go @@ -0,0 +1,271 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "io" + "math/big" + "math/bits" + "runtime" + "sync" + + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + + curve "github.com/consensys/gnark-crypto/ecc/bn254" +) + +// Domain with a power of 2 cardinality +// compute a field element of order 2x and store it in FinerGenerator +// all other values can be derived from x, GeneratorSqrt +type Domain struct { + Cardinality uint64 + Depth uint64 + CardinalityInv fr.Element + Generator fr.Element + GeneratorInv fr.Element + FinerGenerator fr.Element + FinerGeneratorInv fr.Element + + // the following slices are not serialized and are (re)computed through domain.preComputeTwiddles() + + // Twiddles factor for the FFT using Generator for each stage of the recursive FFT + Twiddles [][]fr.Element + + // Twiddles factor for the FFT using GeneratorInv for each stage of the recursive FFT + TwiddlesInv [][]fr.Element + + // we precompute these mostly to avoid the memory intensive bit reverse permutation in the groth16.Prover + + // CosetTable[i][j] = domain.Generator(i-th)Sqrt ^ j + // CosetTable = fft.BitReverse(CosetTable) + CosetTable [][]fr.Element + + // CosetTable[i][j] = domain.Generator(i-th)SqrtInv ^ j + // CosetTableInv = fft.BitReverse(CosetTableInv) + CosetTableInv [][]fr.Element +} + +// NewDomain returns a subgroup with a power of 2 cardinality +// cardinality >= m +// If depth>0, the Domain will also store a primitive (2**depth)*m root +// of 1, with associated precomputed data. This allows to perform shifted +// FFT/FFTInv. +// +// example: +// -------- +// +// NewDomain(m, 2) outputs a new domain to perform fft on Z/mZ, plus a primitive +// 2**2*m=4m-th root of 1 and associated data to compute fft/fftinv on the cosets of +// (Z/4mZ)/(Z/mZ). +func NewDomain(m, depth uint64) *Domain { + + // generator of the largest 2-adic subgroup + var rootOfUnity fr.Element + + rootOfUnity.SetString("19103219067921713944291392827692070036145651957329286315305642004821462161904") + const maxOrderRoot uint64 = 28 + + subGroup := &Domain{} + x := nextPowerOfTwo(m) + subGroup.Cardinality = uint64(x) + subGroup.Depth = depth + + // find generator for Z/2^(log(m))Z and Z/2^(log(m)+cosets)Z + logx := uint64(bits.TrailingZeros64(x)) + if logx > maxOrderRoot { + panic("m is too big: the required root of unity does not exist") + } + logGen := logx + depth + if logGen > maxOrderRoot { + panic("log(m) + cosets is too big: the required root of unity does not exist") + } + + expo := uint64(1 << (maxOrderRoot - logGen)) + bExpo := new(big.Int).SetUint64(expo) + subGroup.FinerGenerator.Exp(rootOfUnity, bExpo) + subGroup.FinerGeneratorInv.Inverse(&subGroup.FinerGenerator) + + // Generator = FinerGenerator^2 has order x + expo = uint64(1 << (maxOrderRoot - logx)) + bExpo.SetUint64(expo) + subGroup.Generator.Exp(rootOfUnity, bExpo) // order x + subGroup.GeneratorInv.Inverse(&subGroup.Generator) + subGroup.CardinalityInv.SetUint64(uint64(x)).Inverse(&subGroup.CardinalityInv) + + // twiddle factors + subGroup.preComputeTwiddles() + + return subGroup +} + +func (d *Domain) preComputeTwiddles() { + + // nb fft stages + nbStages := uint64(bits.TrailingZeros64(d.Cardinality)) + nbCosets := (1 << d.Depth) - 1 + + d.Twiddles = make([][]fr.Element, nbStages) + d.TwiddlesInv = make([][]fr.Element, nbStages) + d.CosetTable = make([][]fr.Element, nbCosets) + d.CosetTableInv = make([][]fr.Element, nbCosets) + for i := 0; i < nbCosets; i++ { + d.CosetTable[i] = make([]fr.Element, d.Cardinality) + d.CosetTableInv[i] = make([]fr.Element, d.Cardinality) + } + + var wg sync.WaitGroup + + // for each fft stage, we pre compute the twiddle factors + twiddles := func(t [][]fr.Element, omega fr.Element) { + for i := uint64(0); i < nbStages; i++ { + t[i] = make([]fr.Element, 1+(1<<(nbStages-i-1))) + var w fr.Element + if i == 0 { + w = omega + } else { + w = t[i-1][2] + } + t[i][0] = fr.One() + t[i][1] = w + for j := 2; j < len(t[i]); j++ { + t[i][j].Mul(&t[i][j-1], &w) + } + } + wg.Done() + } + + expTable := func(sqrt fr.Element, t []fr.Element) { + t[0] = fr.One() + precomputeExpTable(sqrt, t) + wg.Done() + } + + if nbCosets > 0 { + cosetGens := make([]fr.Element, nbCosets) + cosetGensInv := make([]fr.Element, nbCosets) + cosetGens[0].Set(&d.FinerGenerator) + cosetGensInv[0].Set(&d.FinerGeneratorInv) + for i := 1; i < nbCosets; i++ { + cosetGens[i].Mul(&cosetGens[i-1], &d.FinerGenerator) + cosetGensInv[i].Mul(&cosetGensInv[1], &d.FinerGeneratorInv) + } + wg.Add(2 + 2*nbCosets) + go twiddles(d.Twiddles, d.Generator) + go twiddles(d.TwiddlesInv, d.GeneratorInv) + for i := 0; i < nbCosets-1; i++ { + go expTable(cosetGens[i], d.CosetTable[i]) + go expTable(cosetGensInv[i], d.CosetTableInv[i]) + } + go expTable(cosetGens[nbCosets-1], d.CosetTable[nbCosets-1]) + expTable(cosetGensInv[nbCosets-1], d.CosetTableInv[nbCosets-1]) + + wg.Wait() + + } else { + wg.Add(2) + go twiddles(d.Twiddles, d.Generator) + twiddles(d.TwiddlesInv, d.GeneratorInv) + wg.Wait() + } + +} + +func precomputeExpTable(w fr.Element, table []fr.Element) { + n := len(table) + + // see if it makes sense to parallelize exp tables pre-computation + interval := 0 + if runtime.NumCPU() >= 4 { + interval = (n - 1) / (runtime.NumCPU() / 4) + } + + // this ratio roughly correspond to the number of multiplication one can do in place of a Exp operation + const ratioExpMul = 6000 / 17 + + if interval < ratioExpMul { + precomputeExpTableChunk(w, 1, table[1:]) + return + } + + // we parallelize + var wg sync.WaitGroup + for i := 1; i < n; i += interval { + start := i + end := i + interval + if end > n { + end = n + } + wg.Add(1) + go func() { + precomputeExpTableChunk(w, uint64(start), table[start:end]) + wg.Done() + }() + } + wg.Wait() +} + +func precomputeExpTableChunk(w fr.Element, power uint64, table []fr.Element) { + table[0].Exp(w, new(big.Int).SetUint64(power)) + for i := 1; i < len(table); i++ { + table[i].Mul(&table[i-1], &w) + } +} + +func nextPowerOfTwo(n uint64) uint64 { + p := uint64(1) + if (n & (n - 1)) == 0 { + return n + } + for p < n { + p <<= 1 + } + return p +} + +// WriteTo writes a binary representation of the domain (without the precomputed twiddle factors) +// to the provided writer +func (d *Domain) WriteTo(w io.Writer) (int64, error) { + + enc := curve.NewEncoder(w) + + toEncode := []interface{}{d.Cardinality, d.Depth, &d.CardinalityInv, &d.Generator, &d.GeneratorInv, &d.FinerGenerator, &d.FinerGeneratorInv} + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom attempts to decode a domain from Reader +func (d *Domain) ReadFrom(r io.Reader) (int64, error) { + + dec := curve.NewDecoder(r) + + toDecode := []interface{}{&d.Cardinality, &d.Depth, &d.CardinalityInv, &d.Generator, &d.GeneratorInv, &d.FinerGenerator, &d.FinerGeneratorInv} + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + d.preComputeTwiddles() + return dec.BytesRead(), nil +} diff --git a/ecc/bn254/fr/fft/domain_test.go b/ecc/bn254/fr/fft/domain_test.go new file mode 100644 index 0000000000..e3c1d71978 --- /dev/null +++ b/ecc/bn254/fr/fft/domain_test.go @@ -0,0 +1,47 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "bytes" + "reflect" + "testing" +) + +func TestDomainSerialization(t *testing.T) { + + domain := NewDomain(1<<6, 1) + var reconstructed Domain + + var buf bytes.Buffer + written, err := domain.WriteTo(&buf) + if err != nil { + t.Fatal(err) + } + var read int64 + read, err = reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal(err) + } + + if written != read { + t.Fatal("didn't read as many bytes as we wrote") + } + if !reflect.DeepEqual(domain, &reconstructed) { + t.Fatal("Domain.SetBytes(Bytes()) failed") + } +} diff --git a/ecc/bn254/fr/fft/fft.go b/ecc/bn254/fr/fft/fft.go new file mode 100644 index 0000000000..a51bfc5cf6 --- /dev/null +++ b/ecc/bn254/fr/fft/fft.go @@ -0,0 +1,265 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/internal/parallel" + + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +// Decimation is used in the FFT call to select decimation in time or in frequency +type Decimation uint8 + +const ( + DIT Decimation = iota + DIF +) + +// parallelize threshold for a single butterfly op, if the fft stage is not parallelized already +const butterflyThreshold = 16 + +// FFT computes (recursively) the discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +// +// example: +// ------- +// domain := NewDomain(m, 2) --> contains precomputed data for Z/mZ, and Z/4mZ +// FFT(pol, DIT, 1) --> evaluates pol on the coset 1 in (Z/4mZ)/(Z/mZ) +func (domain *Domain) FFT(a []fr.Element, decimation Decimation, coset uint64) { + + numCPU := uint64(runtime.NumCPU()) + + if coset != 0 { + if decimation == DIT { + BitReverse(domain.CosetTable[coset-1]) + } + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].Mul(&a[i], &domain.CosetTable[coset-1][i]) + } + }) + // put it back as we found it + if decimation == DIT { + BitReverse(domain.CosetTable[coset-1]) + } + } + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(nextPowerOfTwo(numCPU)) + if numCPU <= 1 { + maxSplits = -1 + } + + switch decimation { + case DIF: + difFFT(a, domain.Twiddles, 0, maxSplits, nil) + case DIT: + ditFFT(a, domain.Twiddles, 0, maxSplits, nil) + default: + panic("not implemented") + } +} + +// FFTInverse computes (recursively) the inverse discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +func (domain *Domain) FFTInverse(a []fr.Element, decimation Decimation, coset uint64) { + + numCPU := uint64(runtime.NumCPU()) + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(nextPowerOfTwo(numCPU)) + if numCPU <= 1 { + maxSplits = -1 + } + switch decimation { + case DIF: + difFFT(a, domain.TwiddlesInv, 0, maxSplits, nil) + case DIT: + ditFFT(a, domain.TwiddlesInv, 0, maxSplits, nil) + default: + panic("not implemented") + } + + // scale by CardinalityInv (+ cosetTableInv is coset!=0) + if coset != 0 { + if decimation == DIF { + BitReverse(domain.CosetTableInv[coset-1]) + } + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].Mul(&a[i], &domain.CosetTableInv[coset-1][i]). + MulAssign(&domain.CardinalityInv) + } + }) + // put it back as we found it + if decimation == DIF { + BitReverse(domain.CosetTableInv[coset-1]) + } + } else { + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].MulAssign(&domain.CardinalityInv) + } + }) + } +} + +func difFFT(a []fr.Element, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer func() { + chDone <- struct{}{} + }() + } + n := len(a) + if n == 1 { + return + } + m := n >> 1 + + // if stage < maxSplits, we parallelize this butterfly + // but we have only numCPU / stage cpus available + if (m > butterflyThreshold) && (stage < maxSplits) { + // 1 << stage == estimated used CPUs + numCPU := runtime.NumCPU() / (1 << (stage)) + parallel.Execute(m, func(start, end int) { + var t fr.Element + for i := start; i < end; i++ { + t = a[i] + a[i].Add(&a[i], &a[i+m]) + + a[i+m]. + Sub(&t, &a[i+m]). + Mul(&a[i+m], &twiddles[stage][i]) + } + }, numCPU) + } else { + var t fr.Element + + // i == 0 + t = a[0] + a[0].Add(&a[0], &a[m]) + a[m].Sub(&t, &a[m]) + + for i := 1; i < m; i++ { + t = a[i] + a[i].Add(&a[i], &a[i+m]) + + a[i+m]. + Sub(&t, &a[i+m]). + Mul(&a[i+m], &twiddles[stage][i]) + } + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFT(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFT(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} + +func ditFFT(a []fr.Element, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer func() { + chDone <- struct{}{} + }() + } + n := len(a) + if n == 1 { + return + } + m := n >> 1 + + nextStage := stage + 1 + + if stage < maxSplits { + // that's the only time we fire go routines + chDone := make(chan struct{}, 1) + go ditFFT(a[m:], twiddles, nextStage, maxSplits, chDone) + ditFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + ditFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + ditFFT(a[m:n], twiddles, nextStage, maxSplits, nil) + + } + + // if stage < maxSplits, we parallelize this butterfly + // but we have only numCPU / stage cpus available + if (m > butterflyThreshold) && (stage < maxSplits) { + // 1 << stage == estimated used CPUs + numCPU := runtime.NumCPU() / (1 << (stage)) + parallel.Execute(m, func(start, end int) { + var t, tm fr.Element + for k := start; k < end; k++ { + t = a[k] + tm.Mul(&a[k+m], &twiddles[stage][k]) + a[k].Add(&a[k], &tm) + a[k+m].Sub(&t, &tm) + } + }, numCPU) + + } else { + var t, tm fr.Element + // k == 0 + // wPow == 1 + t = a[0] + a[0].Add(&a[0], &a[m]) + a[m].Sub(&t, &a[m]) + + for k := 1; k < m; k++ { + t = a[k] + tm.Mul(&a[k+m], &twiddles[stage][k]) + a[k].Add(&a[k], &tm) + a[k+m].Sub(&t, &tm) + } + } +} + +// BitReverse applies the bit-reversal permutation to a. +// len(a) must be a power of 2 (as in every single function in this file) +func BitReverse(a []fr.Element) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} diff --git a/ecc/bn254/fr/fft/fft_test.go b/ecc/bn254/fr/fft/fft_test.go new file mode 100644 index 0000000000..5bd2c035b8 --- /dev/null +++ b/ecc/bn254/fr/fft/fft_test.go @@ -0,0 +1,205 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "math/big" + "strconv" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" + "github.com/leanovate/gopter/prop" +) + +func TestFFT(t *testing.T) { + const maxSize = 1 << 10 + + domain := NewDomain(maxSize, 0) + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 5 + + properties := gopter.NewProperties(parameters) + + properties.Property("DIF FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domain.FFT(pol, DIF, 0) + BitReverse(pol) + + sample := domain.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := evaluatePolynomial(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("DIT FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverse(pol) + domain.FFT(pol, DIT, 0) + + sample := domain.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := evaluatePolynomial(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("bitReverse(DIF FFT(DIT FFT (bitReverse))))==id", prop.ForAll( + + func() bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverse(pol) + domain.FFT(pol, DIT, 0) + domain.FFTInverse(pol, DIF, 0) + BitReverse(pol) + + check := true + for i := 0; i < len(pol); i++ { + check = check && pol[i].Equal(&backupPol[i]) + } + return check + }, + )) + + properties.Property("DIT FFT(DIF FFT)==id", prop.ForAll( + + func() bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domain.FFTInverse(pol, DIF, 0) + domain.FFT(pol, DIT, 0) + + check := true + for i := 0; i < len(pol); i++ { + check = check && (pol[i] == backupPol[i]) + } + return check + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + +} + +// -------------------------------------------------------------------- +// benches +func BenchmarkBitReverse(b *testing.B) { + + const maxSize = 1 << 20 + + pol := make([]fr.Element, maxSize) + for i := uint64(0); i < maxSize; i++ { + pol[i].SetRandom() + } + + for i := 8; i < 20; i++ { + b.Run("bit reversing 2**"+strconv.Itoa(i)+"bits", func(b *testing.B) { + _pol := make([]fr.Element, 1< .. || 0x0000...0af8 + if len(d.data)%BlockSize != 0 { + q := len(d.data) / BlockSize + r := len(d.data) % BlockSize + sliceq := make([]byte, q*BlockSize) + copy(sliceq, d.data) + slicer := make([]byte, r) + copy(slicer, d.data[q*BlockSize:]) + sliceremainder := make([]byte, BlockSize-r) + d.data = append(sliceq, sliceremainder...) + d.data = append(d.data, slicer...) + } + + if len(d.data) == 0 { + d.data = make([]byte, 32) + } + + nbChunks := len(d.data) / BlockSize + + for i := 0; i < nbChunks; i++ { + copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) + x.SetBytes(buffer[:]) + d.encrypt(x) + d.h.Add(&x, &d.h) + } + + return d.h +} + +// plain execution of a mimc run +// m: message +// k: encryption key +func (d *digest) encrypt(m fr.Element) { + + for i := 0; i < len(d.Params); i++ { + // m = (m+k+c)^5 + var tmp fr.Element + tmp.Add(&m, &d.h).Add(&tmp, &d.Params[i]) + m.Square(&tmp). + Square(&m). + Mul(&m, &tmp) + } + m.Add(&m, &d.h) + d.h = m +} + +// Sum computes the mimc hash of msg from seed +func Sum(seed string, msg []byte) ([]byte, error) { + params := NewParams(seed) + var d digest + d.Params = params + if _, err := d.Write(msg); err != nil { + return nil, err + } + h := d.checksum() + bytes := h.Bytes() + return bytes[:], nil +} diff --git a/ecc/bn254/fr/polynomial/polynomial.go b/ecc/bn254/fr/polynomial/polynomial.go new file mode 100644 index 0000000000..a615e2c42b --- /dev/null +++ b/ecc/bn254/fr/polynomial/polynomial.go @@ -0,0 +1,43 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package polynomial + +import ( + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +// Polynomial polynomial represented by coefficients bn254 fr field. +type Polynomial []fr.Element + +// Degree returns the degree of the polynomial, which is the length of Data. +func (p Polynomial) Degree() uint64 { + res := uint64(len(p) - 1) + return res +} + +// Eval evaluates p at v +func (p Polynomial) Eval(v interface{}) interface{} { + var res, _v fr.Element + _v.Set(v.(*fr.Element)) + s := len(p) + res.Set(&p[s-1]) + for i := s - 2; i >= 0; i-- { + res.Mul(&res, &_v) + res.Add(&res, &p[i]) + } + return &res +} diff --git a/bn256/g1.go b/ecc/bn254/g1.go similarity index 98% rename from bn256/g1.go rename to ecc/bn254/g1.go index df15990e6d..787bdc0411 100644 --- a/bn256/g1.go +++ b/ecc/bn254/g1.go @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bn256 +package bn254 import ( "math/big" - "github.com/consensys/gurvy/bn256/fp" - "github.com/consensys/gurvy/bn256/fr" - "github.com/consensys/gurvy/utils" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/internal/parallel" ) // G1Affine point in affine coordinates @@ -402,7 +402,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { table[3].phi(a) // split the scalar, modifies +-a, phi(a) accordingly - k := utils.SplitScalar(s, &glvBasis) + k := ecc.SplitScalar(s, &glvBasis) if k[0].Cmp(&zero) == -1 { k[0].Neg(&k[0]) diff --git a/bn256/g1_test.go b/ecc/bn254/g1_test.go similarity index 90% rename from bn256/g1_test.go rename to ecc/bn254/g1_test.go index 87da99e69c..d5e1c16561 100644 --- a/bn256/g1_test.go +++ b/ecc/bn254/g1_test.go @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bn256 +package bn254 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bn256/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" - "github.com/consensys/gurvy/bn256/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -86,7 +86,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { properties := gopter.NewProperties(parameters) genFuzz1 := GenFp() - properties.Property("[BN256] g1Gen (affine) should be on the curve", prop.ForAll( + properties.Property("[BN254] g1Gen (affine) should be on the curve", prop.ForAll( func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) @@ -97,7 +97,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] g1Gen (Jacobian) should be on the curve", prop.ForAll( + properties.Property("[BN254] g1Gen (Jacobian) should be on the curve", prop.ForAll( func(a fp.Element) bool { var op1, op2, op3 G1Jac op1.Set(&g1Gen) @@ -122,7 +122,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1 := GenFp() genFuzz2 := GenFp() - properties.Property("[BN256] Affine representation should be independent of the Jacobian representative", prop.ForAll( + properties.Property("[BN254] Affine representation should be independent of the Jacobian representative", prop.ForAll( func(a fp.Element) bool { g := fuzzJacobianG1Affine(&g1Gen, a) var op1 G1Affine @@ -132,7 +132,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( + properties.Property("[BN254] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( func(a fp.Element) bool { var g g1JacExtended g.X.Set(&g1Gen.X) @@ -148,7 +148,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] Jacobian representation should be the same as the affine representative", prop.ForAll( + properties.Property("[BN254] Jacobian representation should be the same as the affine representative", prop.ForAll( func(a fp.Element) bool { var g G1Jac var op1 G1Affine @@ -165,7 +165,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( + properties.Property("[BN254] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( func() bool { var g G1Affine g.X.SetZero() @@ -178,7 +178,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BN256] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( + properties.Property("[BN254] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( func() bool { var g G1Affine var op1 g1JacExtended @@ -190,7 +190,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BN256] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( + properties.Property("[BN254] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( func() bool { var g G1Jac var op1 g1JacExtended @@ -203,7 +203,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BN256] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( + properties.Property("[BN254] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( func(a, b fp.Element) bool { op1 := fuzzJacobianG1Affine(&g1Gen, a) op2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -227,7 +227,7 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() - properties.Property("[BN256] [Jacobian] Add should call double when having adding the same point", prop.ForAll( + properties.Property("[BN254] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -240,7 +240,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BN256] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( + properties.Property("[BN254] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -252,7 +252,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BN256] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( + properties.Property("[BN254] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop1.AddAssign(&g1Infinity) @@ -264,7 +264,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( + properties.Property("[BN254] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) var p1, p1Neg G1Affine @@ -283,7 +283,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( + properties.Property("[BN254] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) var p1, p1Neg G1Affine @@ -302,7 +302,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( + properties.Property("[BN254] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop1.Neg(&fop1) @@ -314,7 +314,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BN254] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -337,7 +337,7 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BN256] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BN254] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -360,7 +360,7 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BN256] GLV and Double and Add should output the same result", prop.ForAll( + properties.Property("[BN254] GLV and Double and Add should output the same result", prop.ForAll( func(s fr.Element) bool { var r big.Int @@ -389,7 +389,7 @@ func TestG1AffineBatchScalarMultiplication(t *testing.T) { // size of the multiExps const nbSamples = 10 - properties.Property("[BN256] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( + properties.Property("[BN254] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( func(mixer fr.Element) bool { // mixer ensures that all the words of a fpElement are set var sampleScalars [nbSamples]fr.Element diff --git a/bn256/g2.go b/ecc/bn254/g2.go similarity index 98% rename from bn256/g2.go rename to ecc/bn254/g2.go index 06c50a3374..a037b71513 100644 --- a/bn256/g2.go +++ b/ecc/bn254/g2.go @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bn256 +package bn254 import ( "math/big" - "github.com/consensys/gurvy/bn256/fr" - "github.com/consensys/gurvy/bn256/internal/fptower" - "github.com/consensys/gurvy/utils" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" ) // G2Affine point in affine coordinates @@ -427,7 +427,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { table[3].phi(a) // split the scalar, modifies +-a, phi(a) accordingly - k := utils.SplitScalar(s, &glvBasis) + k := ecc.SplitScalar(s, &glvBasis) if k[0].Cmp(&zero) == -1 { k[0].Neg(&k[0]) diff --git a/bn256/g2_test.go b/ecc/bn254/g2_test.go similarity index 90% rename from bn256/g2_test.go rename to ecc/bn254/g2_test.go index 1c7b930e3f..f95b091081 100644 --- a/bn256/g2_test.go +++ b/ecc/bn254/g2_test.go @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bn256 +package bn254 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bn256/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" - "github.com/consensys/gurvy/bn256/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -86,7 +86,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { properties := gopter.NewProperties(parameters) genFuzz1 := GenE2() - properties.Property("[BN256] g2Gen (affine) should be on the curve", prop.ForAll( + properties.Property("[BN254] g2Gen (affine) should be on the curve", prop.ForAll( func(a *fptower.E2) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) @@ -97,7 +97,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] g2Gen (Jacobian) should be on the curve", prop.ForAll( + properties.Property("[BN254] g2Gen (Jacobian) should be on the curve", prop.ForAll( func(a *fptower.E2) bool { var op1, op2, op3 G2Jac op1.Set(&g2Gen) @@ -122,7 +122,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1 := GenE2() genFuzz2 := GenE2() - properties.Property("[BN256] Affine representation should be independent of the Jacobian representative", prop.ForAll( + properties.Property("[BN254] Affine representation should be independent of the Jacobian representative", prop.ForAll( func(a *fptower.E2) bool { g := fuzzJacobianG2Affine(&g2Gen, a) var op1 G2Affine @@ -132,7 +132,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( + properties.Property("[BN254] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( func(a *fptower.E2) bool { var g g2JacExtended g.X.Set(&g2Gen.X) @@ -148,7 +148,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] Jacobian representation should be the same as the affine representative", prop.ForAll( + properties.Property("[BN254] Jacobian representation should be the same as the affine representative", prop.ForAll( func(a *fptower.E2) bool { var g G2Jac var op1 G2Affine @@ -165,7 +165,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( + properties.Property("[BN254] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( func() bool { var g G2Affine g.X.SetZero() @@ -178,7 +178,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BN256] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( + properties.Property("[BN254] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( func() bool { var g G2Affine var op1 g2JacExtended @@ -190,7 +190,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BN256] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( + properties.Property("[BN254] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( func() bool { var g G2Jac var op1 g2JacExtended @@ -203,7 +203,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BN256] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( + properties.Property("[BN254] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( func(a, b *fptower.E2) bool { op1 := fuzzJacobianG2Affine(&g2Gen, a) op2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -227,7 +227,7 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() - properties.Property("[BN256] [Jacobian] Add should call double when having adding the same point", prop.ForAll( + properties.Property("[BN254] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -240,7 +240,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BN256] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( + properties.Property("[BN254] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( func(a, b *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -252,7 +252,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BN256] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( + properties.Property("[BN254] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop1.AddAssign(&g2Infinity) @@ -264,7 +264,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( + properties.Property("[BN254] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) var p1, p1Neg G2Affine @@ -283,7 +283,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( + properties.Property("[BN254] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) var p1, p1Neg G2Affine @@ -302,7 +302,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( + properties.Property("[BN254] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( func(a *fptower.E2) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop1.Neg(&fop1) @@ -314,7 +314,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BN256] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BN254] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -337,7 +337,7 @@ func TestG2AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BN256] psi should map points from E' to itself", prop.ForAll( + properties.Property("[BN254] psi should map points from E' to itself", prop.ForAll( func() bool { var a G2Jac a.psi(&g2Gen) @@ -345,7 +345,7 @@ func TestG2AffineOps(t *testing.T) { }, )) - properties.Property("[BN256] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BN254] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -368,7 +368,7 @@ func TestG2AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BN256] GLV and Double and Add should output the same result", prop.ForAll( + properties.Property("[BN254] GLV and Double and Add should output the same result", prop.ForAll( func(s fr.Element) bool { var r big.Int @@ -392,7 +392,7 @@ func TestG2AffineCofactorCleaning(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BN256] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( + properties.Property("[BN254] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( func() bool { var a, x, b fptower.E2 a.SetRandom() @@ -429,7 +429,7 @@ func TestG2AffineBatchScalarMultiplication(t *testing.T) { // size of the multiExps const nbSamples = 10 - properties.Property("[BN256] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( + properties.Property("[BN254] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( func(mixer fr.Element) bool { // mixer ensures that all the words of a fpElement are set var sampleScalars [nbSamples]fr.Element diff --git a/bn256/hash_to_curve.go b/ecc/bn254/hash_to_curve.go similarity index 97% rename from bn256/hash_to_curve.go rename to ecc/bn254/hash_to_curve.go index f175d75737..14fe62a070 100644 --- a/bn256/hash_to_curve.go +++ b/ecc/bn254/hash_to_curve.go @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bn256 +package bn254 import ( "math/big" - "github.com/consensys/gurvy/bn256/fp" - "github.com/consensys/gurvy/bn256/internal/fptower" - "github.com/consensys/gurvy/utils" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" ) // hashToFp hashes msg to count prime field elements. @@ -31,7 +31,7 @@ func hashToFp(msg, dst []byte, count int) ([]fp.Element, error) { L := 48 lenInBytes := count * L - pseudoRandomBytes, err := utils.ExpandMsgXmd(msg, dst, lenInBytes) + pseudoRandomBytes, err := ecc.ExpandMsgXmd(msg, dst, lenInBytes) if err != nil { return nil, err } diff --git a/bn256/internal/fptower/asm.go b/ecc/bn254/internal/fptower/asm.go similarity index 93% rename from bn256/internal/fptower/asm.go rename to ecc/bn254/internal/fptower/asm.go index 1458123a3d..c7bb911dfb 100644 --- a/bn256/internal/fptower/asm.go +++ b/ecc/bn254/internal/fptower/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bls377/internal/fptower/asm_noadx.go b/ecc/bn254/internal/fptower/asm_noadx.go similarity index 93% rename from bls377/internal/fptower/asm_noadx.go rename to ecc/bn254/internal/fptower/asm_noadx.go index cea2d1b95a..f09b13900c 100644 --- a/bls377/internal/fptower/asm_noadx.go +++ b/ecc/bn254/internal/fptower/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bn256/internal/fptower/e12.go b/ecc/bn254/internal/fptower/e12.go similarity index 98% rename from bn256/internal/fptower/e12.go rename to ecc/bn254/internal/fptower/e12.go index 075fb5fc59..ef2c170e43 100644 --- a/bn256/internal/fptower/e12.go +++ b/ecc/bn254/internal/fptower/e12.go @@ -12,15 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower import ( "encoding/binary" "errors" - "github.com/consensys/gurvy/bn256/fp" - "github.com/consensys/gurvy/bn256/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" "math/big" ) diff --git a/bn256/internal/fptower/e12_pairing.go b/ecc/bn254/internal/fptower/e12_pairing.go similarity index 100% rename from bn256/internal/fptower/e12_pairing.go rename to ecc/bn254/internal/fptower/e12_pairing.go diff --git a/bn256/internal/fptower/e12_test.go b/ecc/bn254/internal/fptower/e12_test.go similarity index 83% rename from bn256/internal/fptower/e12_test.go rename to ecc/bn254/internal/fptower/e12_test.go index 29167eec5f..806ecdea6a 100644 --- a/bn256/internal/fptower/e12_test.go +++ b/ecc/bn254/internal/fptower/e12_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower @@ -35,7 +35,7 @@ func TestE12Serialization(t *testing.T) { genA := GenE12() - properties.Property("[BN256] SetBytes(Bytes()) should stay constant", prop.ForAll( + properties.Property("[BN254] SetBytes(Bytes()) should stay constant", prop.ForAll( func(a *E12) bool { var b E12 buf := a.Bytes() @@ -60,7 +60,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA := GenE12() genB := GenE12() - properties.Property("[BN256] Having the receiver as operand (addition) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (addition) should output the same result", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Set(a) @@ -73,7 +73,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BN256] Having the receiver as operand (sub) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (sub) should output the same result", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Set(a) @@ -86,7 +86,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BN256] Having the receiver as operand (mul) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (mul) should output the same result", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Set(a) @@ -99,7 +99,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BN256] Having the receiver as operand (square) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (square) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Square(a) @@ -109,7 +109,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (double) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (double) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Double(a) @@ -119,7 +119,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Inverse(a) @@ -129,7 +129,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (Cyclotomic square) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (Cyclotomic square) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.CyclotomicSquare(a) @@ -139,7 +139,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Conjugate(a) @@ -149,7 +149,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (Frobenius) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (Frobenius) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.Frobenius(a) @@ -159,7 +159,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (FrobeniusSquare) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (FrobeniusSquare) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusSquare(a) @@ -169,7 +169,7 @@ func TestE12ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (FrobeniusCube) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (FrobeniusCube) should output the same result", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusCube(a) @@ -192,7 +192,7 @@ func TestE12Ops(t *testing.T) { genA := GenE12() genB := GenE12() - properties.Property("[BN256] sub & add should leave an element invariant", prop.ForAll( + properties.Property("[BN254] sub & add should leave an element invariant", prop.ForAll( func(a, b *E12) bool { var c E12 c.Set(a) @@ -203,7 +203,7 @@ func TestE12Ops(t *testing.T) { genB, )) - properties.Property("[BN256] mul & inverse should leave an element invariant", prop.ForAll( + properties.Property("[BN254] mul & inverse should leave an element invariant", prop.ForAll( func(a, b *E12) bool { var c, d E12 d.Inverse(b) @@ -215,7 +215,7 @@ func TestE12Ops(t *testing.T) { genB, )) - properties.Property("[BN256] inverse twice should leave an element invariant", prop.ForAll( + properties.Property("[BN254] inverse twice should leave an element invariant", prop.ForAll( func(a *E12) bool { var b E12 b.Inverse(a).Inverse(&b) @@ -224,7 +224,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BN256] square and mul should output the same result", prop.ForAll( + properties.Property("[BN254] square and mul should output the same result", prop.ForAll( func(a *E12) bool { var b, c E12 b.Mul(a, a) @@ -234,7 +234,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BN256] a + pi(a), a-pi(a) should be real", prop.ForAll( + properties.Property("[BN254] a + pi(a), a-pi(a) should be real", prop.ForAll( func(a *E12) bool { var b, c, d E12 var e, f, g E6 @@ -248,7 +248,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BN256] pi**12=id", prop.ForAll( + properties.Property("[BN254] pi**12=id", prop.ForAll( func(a *E12) bool { var b E12 b.Frobenius(a). @@ -268,7 +268,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BN256] (pi**2)**6=id", prop.ForAll( + properties.Property("[BN254] (pi**2)**6=id", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusSquare(a). @@ -282,7 +282,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BN256] (pi**3)**4=id", prop.ForAll( + properties.Property("[BN254] (pi**3)**4=id", prop.ForAll( func(a *E12) bool { var b E12 b.FrobeniusCube(a). @@ -294,7 +294,7 @@ func TestE12Ops(t *testing.T) { genA, )) - properties.Property("[BN256] cyclotomic square and square should be the same in the cyclotomic subgroup", prop.ForAll( + properties.Property("[BN254] cyclotomic square and square should be the same in the cyclotomic subgroup", prop.ForAll( func(a *E12) bool { var b, c, d E12 b.FrobeniusCube(a). diff --git a/bn256/internal/fptower/e2.go b/ecc/bn254/internal/fptower/e2.go similarity index 97% rename from bn256/internal/fptower/e2.go rename to ecc/bn254/internal/fptower/e2.go index ceb1c9fc68..76b508bd32 100644 --- a/bn256/internal/fptower/e2.go +++ b/ecc/bn254/internal/fptower/e2.go @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower import ( - "github.com/consensys/gurvy/bn256/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" "math/big" ) diff --git a/bn256/internal/fptower/e2_adx_amd64.s b/ecc/bn254/internal/fptower/e2_adx_amd64.s similarity index 100% rename from bn256/internal/fptower/e2_adx_amd64.s rename to ecc/bn254/internal/fptower/e2_adx_amd64.s diff --git a/bn256/internal/fptower/e2_amd64.go b/ecc/bn254/internal/fptower/e2_amd64.go similarity index 96% rename from bn256/internal/fptower/e2_amd64.go rename to ecc/bn254/internal/fptower/e2_amd64.go index 1a99cf1b2c..7f5b3d3f5e 100644 --- a/bn256/internal/fptower/e2_amd64.go +++ b/ecc/bn254/internal/fptower/e2_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bn256/internal/fptower/e2_amd64.s b/ecc/bn254/internal/fptower/e2_amd64.s similarity index 100% rename from bn256/internal/fptower/e2_amd64.s rename to ecc/bn254/internal/fptower/e2_amd64.s diff --git a/bn256/internal/fptower/e2_bn256.go b/ecc/bn254/internal/fptower/e2_bn254.go similarity index 97% rename from bn256/internal/fptower/e2_bn256.go rename to ecc/bn254/internal/fptower/e2_bn254.go index d8f3805b8f..0a120c4e68 100644 --- a/bn256/internal/fptower/e2_bn256.go +++ b/ecc/bn254/internal/fptower/e2_bn254.go @@ -15,7 +15,7 @@ package fptower import ( - "github.com/consensys/gurvy/bn256/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" ) // declaring nonResInverse as global makes MulByNonResInv inlinable diff --git a/bn256/internal/fptower/e2_bn256_fallback.go b/ecc/bn254/internal/fptower/e2_bn254_fallback.go similarity index 95% rename from bn256/internal/fptower/e2_bn256_fallback.go rename to ecc/bn254/internal/fptower/e2_bn254_fallback.go index 8174c2bba7..8c04804b23 100644 --- a/bn256/internal/fptower/e2_bn256_fallback.go +++ b/ecc/bn254/internal/fptower/e2_bn254_fallback.go @@ -16,7 +16,7 @@ package fptower -import "github.com/consensys/gurvy/bn256/fp" +import "github.com/consensys/gnark-crypto/ecc/bn254/fp" // MulByNonResidue multiplies a E2 by (9,1) func (z *E2) MulByNonResidue(x *E2) *E2 { diff --git a/bn256/internal/fptower/e2_bn256_test.go b/ecc/bn254/internal/fptower/e2_bn254_test.go similarity index 84% rename from bn256/internal/fptower/e2_bn256_test.go rename to ecc/bn254/internal/fptower/e2_bn254_test.go index 71d00ad11a..7b1ea41e89 100644 --- a/bn256/internal/fptower/e2_bn256_test.go +++ b/ecc/bn254/internal/fptower/e2_bn254_test.go @@ -17,7 +17,7 @@ func TestE2AssemblyOps(t *testing.T) { genA := GenE2() genB := GenE2() - properties.Property("[BN256] mulAsm & mulGeneric should output same result", prop.ForAll( + properties.Property("[BN254] mulAsm & mulGeneric should output same result", prop.ForAll( func(a, b *E2) bool { var c, d E2 c.Mul(a, b) @@ -28,7 +28,7 @@ func TestE2AssemblyOps(t *testing.T) { genB, )) - properties.Property("[BN256] squareAsm & squareGeneric should output same result", prop.ForAll( + properties.Property("[BN254] squareAsm & squareGeneric should output same result", prop.ForAll( func(a *E2) bool { var c, d E2 c.Square(a) diff --git a/bls381/internal/fptower/e2_fallback.go b/ecc/bn254/internal/fptower/e2_fallback.go similarity index 94% rename from bls381/internal/fptower/e2_fallback.go rename to ecc/bn254/internal/fptower/e2_fallback.go index 262d778027..eada4c6b58 100644 --- a/bls381/internal/fptower/e2_fallback.go +++ b/ecc/bn254/internal/fptower/e2_fallback.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bn256/internal/fptower/e2_test.go b/ecc/bn254/internal/fptower/e2_test.go similarity index 82% rename from bn256/internal/fptower/e2_test.go rename to ecc/bn254/internal/fptower/e2_test.go index f7ad22f5e8..b8988169a2 100644 --- a/bn256/internal/fptower/e2_test.go +++ b/ecc/bn254/internal/fptower/e2_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower @@ -20,7 +20,7 @@ import ( "crypto/rand" "testing" - "github.com/consensys/gurvy/bn256/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -39,7 +39,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB := GenE2() genfp := GenFp() - properties.Property("[BN256] Having the receiver as operand (addition) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (addition) should output the same result", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Set(a) @@ -52,7 +52,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BN256] Having the receiver as operand (sub) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (sub) should output the same result", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Set(a) @@ -65,7 +65,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BN256] Having the receiver as operand (mul) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (mul) should output the same result", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Set(a) @@ -78,7 +78,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BN256] Having the receiver as operand (square) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (square) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Square(a) @@ -88,7 +88,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (neg) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (neg) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Neg(a) @@ -98,7 +98,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (double) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (double) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Double(a) @@ -108,7 +108,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.MulByNonResidue(a) @@ -118,7 +118,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (mul by non residue inverse) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (mul by non residue inverse) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.MulByNonResidueInv(a) @@ -128,7 +128,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Inverse(a) @@ -138,7 +138,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (Conjugate) should output the same result", prop.ForAll( func(a *E2) bool { var b E2 b.Conjugate(a) @@ -148,7 +148,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (mul by element) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (mul by element) should output the same result", prop.ForAll( func(a *E2, b fp.Element) bool { var c E2 c.MulByElement(a, &b) @@ -159,7 +159,7 @@ func TestE2ReceiverIsOperand(t *testing.T) { genfp, )) - properties.Property("[BN256] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (Sqrt) should output the same result", prop.ForAll( func(a *E2) bool { var b, c, d, s E2 @@ -203,7 +203,7 @@ func TestE2MulMaxed(t *testing.T) { b.A0 = fpMaxValue b.A1 = fpMaxValue - // [BN256] mul & inverse should leave an element invariant", prop.ForAll( + // [BN254] mul & inverse should leave an element invariant", prop.ForAll( var c, d E2 d.Inverse(&b) c.Set(&a) @@ -224,7 +224,7 @@ func TestE2Ops(t *testing.T) { genB := GenE2() genfp := GenFp() - properties.Property("[BN256] sub & add should leave an element invariant", prop.ForAll( + properties.Property("[BN254] sub & add should leave an element invariant", prop.ForAll( func(a, b *E2) bool { var c E2 c.Set(a) @@ -235,7 +235,7 @@ func TestE2Ops(t *testing.T) { genB, )) - properties.Property("[BN256] mul & inverse should leave an element invariant", prop.ForAll( + properties.Property("[BN254] mul & inverse should leave an element invariant", prop.ForAll( func(a, b *E2) bool { var c, d E2 d.Inverse(b) @@ -247,7 +247,7 @@ func TestE2Ops(t *testing.T) { genB, )) - properties.Property("[BN256] inverse twice should leave an element invariant", prop.ForAll( + properties.Property("[BN254] inverse twice should leave an element invariant", prop.ForAll( func(a *E2) bool { var b E2 b.Inverse(a).Inverse(&b) @@ -256,7 +256,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BN256] neg twice should leave an element invariant", prop.ForAll( + properties.Property("[BN254] neg twice should leave an element invariant", prop.ForAll( func(a *E2) bool { var b E2 b.Neg(a).Neg(&b) @@ -265,7 +265,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BN256] square and mul should output the same result", prop.ForAll( + properties.Property("[BN254] square and mul should output the same result", prop.ForAll( func(a *E2) bool { var b, c E2 b.Mul(a, a) @@ -275,7 +275,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BN256] MulByElement MulByElement inverse should leave an element invariant", prop.ForAll( + properties.Property("[BN254] MulByElement MulByElement inverse should leave an element invariant", prop.ForAll( func(a *E2, b fp.Element) bool { var c E2 var d fp.Element @@ -287,7 +287,7 @@ func TestE2Ops(t *testing.T) { genfp, )) - properties.Property("[BN256] Double and mul by 2 should output the same result", prop.ForAll( + properties.Property("[BN254] Double and mul by 2 should output the same result", prop.ForAll( func(a *E2) bool { var b E2 var c fp.Element @@ -299,7 +299,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BN256] Mulbynonres mulbynonresinv should leave the element invariant", prop.ForAll( + properties.Property("[BN254] Mulbynonres mulbynonresinv should leave the element invariant", prop.ForAll( func(a *E2) bool { var b E2 b.MulByNonResidue(a).MulByNonResidueInv(&b) @@ -308,7 +308,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BN256] a + pi(a), a-pi(a) should be real", prop.ForAll( + properties.Property("[BN254] a + pi(a), a-pi(a) should be real", prop.ForAll( func(a *E2) bool { var b, c, d E2 var e, f fp.Element @@ -322,7 +322,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BN256] Legendre on square should output 1", prop.ForAll( + properties.Property("[BN254] Legendre on square should output 1", prop.ForAll( func(a *E2) bool { var b E2 b.Square(a) @@ -332,7 +332,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BN256] square(sqrt) should leave an element invariant", prop.ForAll( + properties.Property("[BN254] square(sqrt) should leave an element invariant", prop.ForAll( func(a *E2) bool { var b, c, d, e E2 b.Square(a) @@ -344,7 +344,7 @@ func TestE2Ops(t *testing.T) { genA, )) - properties.Property("[BN256] Cmp and LexicographicallyLargest should be consistant", prop.ForAll( + properties.Property("[BN254] Cmp and LexicographicallyLargest should be consistant", prop.ForAll( func(a *E2) bool { var negA E2 negA.Neg(a) diff --git a/bls381/internal/fptower/e6.go b/ecc/bn254/internal/fptower/e6.go similarity index 98% rename from bls381/internal/fptower/e6.go rename to ecc/bn254/internal/fptower/e6.go index b29e6f9869..5ba35cf020 100644 --- a/bls381/internal/fptower/e6.go +++ b/ecc/bn254/internal/fptower/e6.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower diff --git a/bn256/internal/fptower/e6_test.go b/ecc/bn254/internal/fptower/e6_test.go similarity index 81% rename from bn256/internal/fptower/e6_test.go rename to ecc/bn254/internal/fptower/e6_test.go index 93e8727162..72d467b126 100644 --- a/bn256/internal/fptower/e6_test.go +++ b/ecc/bn254/internal/fptower/e6_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fptower @@ -36,7 +36,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA := GenE6() genB := GenE6() - properties.Property("[BN256] Having the receiver as operand (addition) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (addition) should output the same result", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Set(a) @@ -49,7 +49,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BN256] Having the receiver as operand (sub) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (sub) should output the same result", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Set(a) @@ -62,7 +62,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BN256] Having the receiver as operand (mul) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (mul) should output the same result", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Set(a) @@ -75,7 +75,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genB, )) - properties.Property("[BN256] Having the receiver as operand (square) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (square) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Square(a) @@ -85,7 +85,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (neg) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (neg) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Neg(a) @@ -95,7 +95,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (double) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (double) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Double(a) @@ -105,7 +105,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (mul by non residue) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.MulByNonResidue(a) @@ -115,7 +115,7 @@ func TestE6ReceiverIsOperand(t *testing.T) { genA, )) - properties.Property("[BN256] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (Inverse) should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Inverse(a) @@ -138,7 +138,7 @@ func TestE6Ops(t *testing.T) { genA := GenE6() genB := GenE6() - properties.Property("[BN256] sub & add should leave an element invariant", prop.ForAll( + properties.Property("[BN254] sub & add should leave an element invariant", prop.ForAll( func(a, b *E6) bool { var c E6 c.Set(a) @@ -149,7 +149,7 @@ func TestE6Ops(t *testing.T) { genB, )) - properties.Property("[BN256] mul & inverse should leave an element invariant", prop.ForAll( + properties.Property("[BN254] mul & inverse should leave an element invariant", prop.ForAll( func(a, b *E6) bool { var c, d E6 d.Inverse(b) @@ -161,7 +161,7 @@ func TestE6Ops(t *testing.T) { genB, )) - properties.Property("[BN256] inverse twice should leave an element invariant", prop.ForAll( + properties.Property("[BN254] inverse twice should leave an element invariant", prop.ForAll( func(a *E6) bool { var b E6 b.Inverse(a).Inverse(&b) @@ -170,7 +170,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BN256] neg twice should leave an element invariant", prop.ForAll( + properties.Property("[BN254] neg twice should leave an element invariant", prop.ForAll( func(a *E6) bool { var b E6 b.Neg(a).Neg(&b) @@ -179,7 +179,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BN256] square and mul should output the same result", prop.ForAll( + properties.Property("[BN254] square and mul should output the same result", prop.ForAll( func(a *E6) bool { var b, c E6 b.Mul(a, a) @@ -189,7 +189,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BN256] Double and add twice should output the same result", prop.ForAll( + properties.Property("[BN254] Double and add twice should output the same result", prop.ForAll( func(a *E6) bool { var b E6 b.Add(a, a) @@ -199,7 +199,7 @@ func TestE6Ops(t *testing.T) { genA, )) - properties.Property("[BN256] Mul by non residue should be the same as multiplying by (0,1,0)", prop.ForAll( + properties.Property("[BN254] Mul by non residue should be the same as multiplying by (0,1,0)", prop.ForAll( func(a *E6) bool { var b, c E6 b.B1.A0.SetOne() diff --git a/bn256/internal/fptower/frobenius.go b/ecc/bn254/internal/fptower/frobenius.go similarity index 99% rename from bn256/internal/fptower/frobenius.go rename to ecc/bn254/internal/fptower/frobenius.go index 6138a9f787..18d8fef960 100644 --- a/bn256/internal/fptower/frobenius.go +++ b/ecc/bn254/internal/fptower/frobenius.go @@ -14,7 +14,7 @@ package fptower -import "github.com/consensys/gurvy/bn256/fp" +import "github.com/consensys/gnark-crypto/ecc/bn254/fp" // Frobenius set z to Frobenius(x), return z func (z *E12) Frobenius(x *E12) *E12 { diff --git a/bn256/internal/fptower/generators_test.go b/ecc/bn254/internal/fptower/generators_test.go similarity index 95% rename from bn256/internal/fptower/generators_test.go rename to ecc/bn254/internal/fptower/generators_test.go index 76ae072e74..f668d0fd34 100644 --- a/bn256/internal/fptower/generators_test.go +++ b/ecc/bn254/internal/fptower/generators_test.go @@ -3,7 +3,7 @@ package fptower import ( "crypto/rand" - "github.com/consensys/gurvy/bn256/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" "github.com/leanovate/gopter" ) diff --git a/bn256/marshal.go b/ecc/bn254/marshal.go similarity index 96% rename from bn256/marshal.go rename to ecc/bn254/marshal.go index b64c619959..68a0b40523 100644 --- a/bn256/marshal.go +++ b/ecc/bn254/marshal.go @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -// Package bn256 provides efficient elliptic curve and pairing implementation for bn256 -package bn256 +// Package bn254 provides efficient elliptic curve and pairing implementation for bn254 +package bn254 import ( "encoding/binary" @@ -24,15 +24,15 @@ import ( "reflect" "sync/atomic" - "github.com/consensys/gurvy/bn256/fp" - "github.com/consensys/gurvy/bn256/fr" - "github.com/consensys/gurvy/bn256/internal/fptower" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" ) // To encode G1Affine and G2Affine points, we mask the most significant bits with these bits to specify without ambiguity // metadata needed for point (de)compression -// we have less than 3 bits available on the msw, so we can't follow BLS381 style encoding. +// we have less than 3 bits available on the msw, so we can't follow BLS12-381 style encoding. // the difference is the case where a point is infinity and uncompressed is not flagged const ( mMask byte = 0b11 << 6 @@ -45,20 +45,20 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT -// Encoder writes bn256 object values to an output stream +// Encoder writes bn254 object values to an output stream type Encoder struct { w io.Writer n int64 // written bytes raw bool // raw vs compressed encoding } -// Decoder reads bn256 object values from an inbound stream +// Decoder reads bn254 object values from an inbound stream type Decoder struct { r io.Reader n int64 // read bytes } -// NewDecoder returns a binary decoder supporting curve bn256 objects in both +// NewDecoder returns a binary decoder supporting curve bn254 objects in both // compressed and uncompressed (raw) forms func NewDecoder(r io.Reader) *Decoder { return &Decoder{r: r} @@ -69,7 +69,7 @@ func NewDecoder(r io.Reader) *Decoder { func (dec *Decoder) Decode(v interface{}) (err error) { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr || rv.IsNil() || !rv.Elem().CanSet() { - return errors.New("bn256 decoder: unsupported type, need pointer") + return errors.New("bn254 decoder: unsupported type, need pointer") } // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap @@ -246,7 +246,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return nil default: - return errors.New("bn256 encoder: unsupported type") + return errors.New("bn254 encoder: unsupported type") } } @@ -284,7 +284,7 @@ func isCompressed(msb byte) bool { return !(mData == mUncompressed) } -// NewEncoder returns a binary encoder supporting curve bn256 objects +// NewEncoder returns a binary encoder supporting curve bn254 objects func NewEncoder(w io.Writer, options ...func(*Encoder)) *Encoder { // default settings enc := &Encoder{ @@ -491,7 +491,7 @@ func (p *G1Affine) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit -// as we have less than 3 bits available in our coordinate, we can't follow BLS381 style encoding (ZCash/IETF) +// as we have less than 3 bits available in our coordinate, we can't follow BLS12-381 style encoding (ZCash/IETF) // we use the 2 most significant bits instead // 00 -> uncompressed // 10 -> compressed, use smallest lexicographically square root of Y^2 @@ -738,7 +738,7 @@ func (p *G2Affine) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit -// as we have less than 3 bits available in our coordinate, we can't follow BLS381 style encoding (ZCash/IETF) +// as we have less than 3 bits available in our coordinate, we can't follow BLS12-381 style encoding (ZCash/IETF) // we use the 2 most significant bits instead // 00 -> uncompressed // 10 -> compressed, use smallest lexicographically square root of Y^2 diff --git a/bw761/marshal_test.go b/ecc/bn254/marshal_test.go similarity index 97% rename from bw761/marshal_test.go rename to ecc/bn254/marshal_test.go index 45e55194fc..1faa8c6537 100644 --- a/bw761/marshal_test.go +++ b/ecc/bn254/marshal_test.go @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bw761 +package bn254 import ( "bytes" @@ -26,8 +26,8 @@ import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" - "github.com/consensys/gurvy/bw761/fp" - "github.com/consensys/gurvy/bw761/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" ) func TestEncoder(t *testing.T) { diff --git a/bls381/multiexp.go b/ecc/bn254/multiexp.go similarity index 99% rename from bls381/multiexp.go rename to ecc/bn254/multiexp.go index b2d5fe6c9d..89d958a575 100644 --- a/bls381/multiexp.go +++ b/ecc/bn254/multiexp.go @@ -12,20 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls381 +package bn254 import ( - "github.com/consensys/gurvy/bls381/fr" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/internal/parallel" "math" "runtime" "sync" ) // CPUSemaphore enables users to set optional number of CPUs the multiexp will use -// this is thread safe and can be used accross parallel calls of gurvy.MultiExp +// this is thread safe and can be used accross parallel calls of MultiExp type CPUSemaphore struct { chCpus chan struct{} // semaphore to limit number of cpus iterating through points and scalrs at the same time lock sync.Mutex @@ -160,7 +160,7 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, opts ...*CPUSe // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 // * number of CPUs // * cache friendliness (which depends on the host, G1 or G2... ) - // --> for example, on BN256, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. // for each msmCX // step 1 @@ -995,7 +995,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, opts ...*CPUSe // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 // * number of CPUs // * cache friendliness (which depends on the host, G1 or G2... ) - // --> for example, on BN256, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. // for each msmCX // step 1 diff --git a/bn256/multiexp_test.go b/ecc/bn254/multiexp_test.go similarity index 99% rename from bn256/multiexp_test.go rename to ecc/bn254/multiexp_test.go index 3d5fd94863..66d89193bd 100644 --- a/bn256/multiexp_test.go +++ b/ecc/bn254/multiexp_test.go @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bn256 +package bn254 import ( "fmt" @@ -23,7 +23,7 @@ import ( "runtime" "testing" - "github.com/consensys/gurvy/bn256/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) diff --git a/bn256/pairing.go b/ecc/bn254/pairing.go similarity index 98% rename from bn256/pairing.go rename to ecc/bn254/pairing.go index cdbfa4e3c3..c73918f719 100644 --- a/bn256/pairing.go +++ b/ecc/bn254/pairing.go @@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bn256 +package bn254 import ( "errors" - "github.com/consensys/gurvy/bn256/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" ) // GT target group of the pairing diff --git a/bn256/pairing_test.go b/ecc/bn254/pairing_test.go similarity index 91% rename from bn256/pairing_test.go rename to ecc/bn254/pairing_test.go index 77791ae43c..662f0865a1 100644 --- a/bn256/pairing_test.go +++ b/ecc/bn254/pairing_test.go @@ -12,16 +12,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bn256 +package bn254 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bn256/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -69,7 +69,7 @@ func TestPairing(t *testing.T) { genR1 := GenFr() genR2 := GenFr() - properties.Property("[BN256] Having the receiver as operand (final expo) should output the same result", prop.ForAll( + properties.Property("[BN254] Having the receiver as operand (final expo) should output the same result", prop.ForAll( func(a *GT) bool { var b GT b.Set(a) @@ -80,7 +80,7 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BN256] Exponentiating FinalExpo(a) to r should output 1", prop.ForAll( + properties.Property("[BN254] Exponentiating FinalExpo(a) to r should output 1", prop.ForAll( func(a *GT) bool { var one GT e := fr.Modulus() @@ -92,7 +92,7 @@ func TestPairing(t *testing.T) { genA, )) - properties.Property("[BN256] bilinearity", prop.ForAll( + properties.Property("[BN254] bilinearity", prop.ForAll( func(a, b fr.Element) bool { var res, resa, resb, resab, zero GT @@ -124,7 +124,7 @@ func TestPairing(t *testing.T) { genR2, )) - properties.Property("[BN256] MillerLoop of pairs should be equal to the product of MillerLoops", prop.ForAll( + properties.Property("[BN254] MillerLoop of pairs should be equal to the product of MillerLoops", prop.ForAll( func(a, b fr.Element) bool { var simpleProd, factorizedProd GT @@ -165,7 +165,7 @@ func TestPairing(t *testing.T) { genR2, )) - properties.Property("[BN256] PairingCheck", prop.ForAll( + properties.Property("[BN254] PairingCheck", prop.ForAll( func(a, b fr.Element) bool { var g1GenAffNeg G1Affine diff --git a/ecc/bn254/twistededwards/eddsa/eddsa.go b/ecc/bn254/twistededwards/eddsa/eddsa.go new file mode 100644 index 0000000000..ad5b068b66 --- /dev/null +++ b/ecc/bn254/twistededwards/eddsa/eddsa.go @@ -0,0 +1,265 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/crypto/signature" + "github.com/consensys/gnark-crypto/ecc/bn254/twistededwards" + + "golang.org/x/crypto/blake2b" +) + +var errNotOnCurve = errors.New("point not on curve") + +const ( + sizeFr = 32 + sizePublicKey = sizeFr + sizeSignature = 2 * sizeFr + sizePrivateKey = 2*sizeFr + 32 +) + +// PublicKey eddsa signature object +// cf https://en.wikipedia.org/wiki/EdDSA for notation +type PublicKey struct { + A twistededwards.PointAffine +} + +// PrivateKey private key of an eddsa instance +type PrivateKey struct { + PublicKey PublicKey // copy of the associated public key + scalar [sizeFr]byte // secret scalar, in big Endian + randSrc [32]byte // source +} + +// Signature represents an eddsa signature +// cf https://en.wikipedia.org/wiki/EdDSA for notation +type Signature struct { + R twistededwards.PointAffine + S [sizeFr]byte +} + +func init() { + signature.Register(signature.EDDSA_BN254, GenerateKeyInterfaces) +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(r io.Reader) (PrivateKey, error) { + + c := twistededwards.GetEdwardsCurve() + + var pub PublicKey + var priv PrivateKey + + // hash(h) = private_key || random_source, on 32 bytes each + seed := make([]byte, 32) + _, err := r.Read(seed) + if err != nil { + return priv, err + } + h := blake2b.Sum512(seed[:]) + for i := 0; i < 32; i++ { + priv.randSrc[i] = h[i+32] + } + + // prune the key + // https://tools.ietf.org/html/rfc8032#section-5.1.5, key generation + + h[0] &= 0xF8 + h[31] &= 0x7F + h[31] |= 0x40 + + // reverse first bytes because setBytes interpret stream as big endian + // but in eddsa specs s is the first 32 bytes in little endian + for i, j := 0, sizeFr; i < j; i, j = i+1, j-1 { + + h[i], h[j] = h[j], h[i] + + } + + copy(priv.scalar[:], h[:sizeFr]) + + var bscalar big.Int + bscalar.SetBytes(priv.scalar[:]) + pub.A.ScalarMul(&c.Base, &bscalar) + + priv.PublicKey = pub + + return priv, nil +} + +// GenerateKeyInterfaces generate interfaces for the public/private key. +// This purpose of this function is to be registered in the list of signature schemes. +func GenerateKeyInterfaces(r io.Reader) (signature.Signer, error) { + priv, err := GenerateKey(r) + return &priv, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(other signature.PublicKey) bool { + bpk := pub.Bytes() + bother := other.Bytes() + return subtle.ConstantTimeCompare(bpk, bother) == 1 +} + +// Public returns the public key associated to the private key. +// From Signer interface defined in gnark/crypto/signature. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign sign a message +// Pure Eddsa version (see https://tools.ietf.org/html/rfc8032#page-8) +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + curveParams := twistededwards.GetEdwardsCurve() + + var res Signature + + // blinding factor for the private key + // blindingFactorBigInt must be the same size as the private key, + // blindingFactorBigInt = h(randomness_source||message)[:sizeFr] + var blindingFactorBigInt big.Int + + // randSrc = privKey.randSrc || msg (-> message = MSB message .. LSB message) + randSrc := make([]byte, 32+len(message)) + for i, v := range privKey.randSrc { + randSrc[i] = v + } + copy(randSrc[32:], message) + + // randBytes = H(randSrc) + blindingFactorBytes := blake2b.Sum512(randSrc[:]) // TODO ensures that the hash used to build the key and the one used here is the same + blindingFactorBigInt.SetBytes(blindingFactorBytes[:sizeFr]) + + // compute R = randScalar*Base + res.R.ScalarMul(&curveParams.Base, &blindingFactorBigInt) + if !res.R.IsOnCurve() { + return nil, errNotOnCurve + } + + // compute H(R, A, M), all parameters in data are in Montgomery form + resRX := res.R.X.Bytes() + resRY := res.R.Y.Bytes() + resAX := privKey.PublicKey.A.X.Bytes() + resAY := privKey.PublicKey.A.Y.Bytes() + sizeDataToHash := 4*sizeFr + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], resRX[:]) + copy(dataToHash[sizeFr:], resRY[:]) + copy(dataToHash[2*sizeFr:], resAX[:]) + copy(dataToHash[3*sizeFr:], resAY[:]) + copy(dataToHash[4*sizeFr:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + var hramInt big.Int + hramBin := hFunc.Sum(nil) + hramInt.SetBytes(hramBin) + + // Compute s = randScalarInt + H(R,A,M)*S + // going with big int to do ops mod curve order + var bscalar, bs big.Int + bscalar.SetBytes(privKey.scalar[:]) + bs.Mul(&hramInt, &bscalar). + Add(&bs, &blindingFactorBigInt). + Mod(&bs, &curveParams.Order) + sb := bs.Bytes() + if len(sb) < sizeFr { + offset := make([]byte, sizeFr-len(sb)) + sb = append(offset, sb...) + } + copy(res.S[:], sb[:]) + + return res.Bytes(), nil +} + +// Verify verifies an eddsa signature +func (pub *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + curveParams := twistededwards.GetEdwardsCurve() + + // verify that pubKey and R are on the curve + if !pub.A.IsOnCurve() { + return false, errNotOnCurve + } + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + // compute H(R, A, M), all parameters in data are in Montgomery form + sigRX := sig.R.X.Bytes() + sigRY := sig.R.Y.Bytes() + sigAX := pub.A.X.Bytes() + sigAY := pub.A.Y.Bytes() + sizeDataToHash := 4*sizeFr + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], sigRX[:]) + copy(dataToHash[sizeFr:], sigRY[:]) + copy(dataToHash[2*sizeFr:], sigAX[:]) + copy(dataToHash[3*sizeFr:], sigAY[:]) + copy(dataToHash[4*sizeFr:], message) + hFunc.Reset() + if _, err := hFunc.Write(dataToHash[:]); err != nil { + return false, err + } + + var hramInt big.Int + hramBin := hFunc.Sum(nil) + hramInt.SetBytes(hramBin) + + // lhs = cofactor*S*Base + var lhs twistededwards.PointAffine + var bCofactor, bs big.Int + curveParams.Cofactor.ToBigInt(&bCofactor) + bs.SetBytes(sig.S[:]) + lhs.ScalarMul(&curveParams.Base, &bs). + ScalarMul(&lhs, &bCofactor) + + if !lhs.IsOnCurve() { + return false, errNotOnCurve + } + + // rhs = cofactor*(R + H(R,A,M)*A) + var rhs twistededwards.PointAffine + rhs.ScalarMul(&pub.A, &hramInt). + Add(&rhs, &sig.R). + ScalarMul(&rhs, &bCofactor) + if !rhs.IsOnCurve() { + return false, errNotOnCurve + } + + // verifies that cofactor*S*Base=cofactor*(R + H(R,A,M)*A) + if !lhs.X.Equal(&rhs.X) || !lhs.Y.Equal(&rhs.Y) { + return false, nil + } + + return true, nil +} diff --git a/ecc/bn254/twistededwards/eddsa/eddsa_test.go b/ecc/bn254/twistededwards/eddsa/eddsa_test.go new file mode 100644 index 0000000000..1e3d0e8c46 --- /dev/null +++ b/ecc/bn254/twistededwards/eddsa/eddsa_test.go @@ -0,0 +1,179 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/sha256" + "math/rand" + "testing" + + "github.com/consensys/gnark-crypto/crypto/hash" + "github.com/consensys/gnark-crypto/crypto/signature" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +) + +func TestSerialization(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + privKey1, err := signature.EDDSA_BN254.New(r) + if err != nil { + t.Fatal(err) + } + pubKey1 := privKey1.Public() + + privKey2, err := signature.EDDSA_BN254.New(r) + if err != nil { + t.Fatal(err) + } + pubKey2 := privKey2.Public() + + pubKeyBin1 := pubKey1.Bytes() + pubKey2.SetBytes(pubKeyBin1) + pubKeyBin2 := pubKey2.Bytes() + if len(pubKeyBin1) != len(pubKeyBin2) { + t.Fatal("Inconistent size") + } + for i := 0; i < len(pubKeyBin1); i++ { + if pubKeyBin1[i] != pubKeyBin2[i] { + t.Fatal("Error serialize(deserialize(.))") + } + } + + privKeyBin1 := privKey1.Bytes() + privKey2.SetBytes(privKeyBin1) + privKeyBin2 := privKey2.Bytes() + if len(privKeyBin1) != len(privKeyBin2) { + t.Fatal("Inconistent size") + } + for i := 0; i < len(privKeyBin1); i++ { + if privKeyBin1[i] != privKeyBin2[i] { + t.Fatal("Error serialize(deserialize(.))") + } + } +} + +func TestEddsaMIMC(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + // create eddsa obj and sign a message + privKey, err := signature.EDDSA_BN254.New(r) + if err != nil { + t.Fatal(nil) + } + pubKey := privKey.Public() + hFunc := hash.MIMC_BN254.New("seed") + + var frMsg fr.Element + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035978") + msgBin := frMsg.Bytes() + signature, err := privKey.Sign(msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + + // verifies correct msg + res, err := pubKey.Verify(signature, msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + if !res { + t.Fatal("Verifiy correct signature should return true") + } + + // verifies wrong msg + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035979") + msgBin = frMsg.Bytes() + res, err = pubKey.Verify(signature, msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + if res { + t.Fatal("Verfiy wrong signature should be false") + } + +} + +func TestEddsaSHA256(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + hFunc := sha256.New() + + // create eddsa obj and sign a message + // create eddsa obj and sign a message + + privKey, err := signature.EDDSA_BN254.New(r) + pubKey := privKey.Public() + if err != nil { + t.Fatal(err) + } + + signature, err := privKey.Sign([]byte("message"), hFunc) + if err != nil { + t.Fatal(err) + } + + // verifies correct msg + res, err := pubKey.Verify(signature, []byte("message"), hFunc) + if err != nil { + t.Fatal(err) + } + if !res { + t.Fatal("Verifiy correct signature should return true") + } + + // verifies wrong msg + res, err = pubKey.Verify(signature, []byte("wrong_message"), hFunc) + if err != nil { + t.Fatal(err) + } + if res { + t.Fatal("Verfiy wrong signature should be false") + } + +} + +// benchmarks + +func BenchmarkVerify(b *testing.B) { + + src := rand.NewSource(0) + r := rand.New(src) + + hFunc := hash.MIMC_BN254.New("seed") + + // create eddsa obj and sign a message + privKey, err := signature.EDDSA_BN254.New(r) + pubKey := privKey.Public() + if err != nil { + b.Fatal(err) + } + var frMsg fr.Element + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035978") + msgBin := frMsg.Bytes() + signature, _ := privKey.Sign(msgBin[:], hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + pubKey.Verify(signature, msgBin[:], hFunc) + } +} diff --git a/ecc/bn254/twistededwards/eddsa/marshal.go b/ecc/bn254/twistededwards/eddsa/marshal.go new file mode 100644 index 0000000000..97267823e1 --- /dev/null +++ b/ecc/bn254/twistededwards/eddsa/marshal.go @@ -0,0 +1,129 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of pk +// as x||y where x, y are the coordinates of the point +// on the twisted Edwards as big endian integers. +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the twisted Edwards. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !pk.A.IsOnCurve() { + return n, errNotOnCurve + } + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar||randSrc +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:2*sizeFr], privKey.scalar[:]) + subtle.ConstantTimeCopy(1, res[2*sizeFr:], privKey.randSrc[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar||randSrc +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !privKey.PublicKey.A.IsOnCurve() { + return n, errNotOnCurve + } + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, privKey.randSrc[:], buf[2*sizeFr:]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 3*sizeFr x||y||s where +// * x, y are the coordinates of a point on the twisted +// Edwards represented in big endian +// * s=r+h(r,a,m) mod l, the Hasse bound guarantess that +// s is smaller than sizeFr (in particular it is supposed +// s is NOT blinded) +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + sigRBin := sig.R.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], sigRBin[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as x||y||s where +// * x,y are the coordinates of a point on the twisted +// Edwards represented in big endian +// * s=r+h(r,a,m) mod l, the Hasse bound guarantess that +// s is smaller than sizeFr (in particular it is supposed +// s is NOT blinded) +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + if _, err := sig.R.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !sig.R.IsOnCurve() { + return n, errNotOnCurve + } + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/bls381/twistededwards/point.go b/ecc/bn254/twistededwards/point.go similarity index 91% rename from bls381/twistededwards/point.go rename to ecc/bn254/twistededwards/point.go index 5972c19aac..9d9c6be514 100644 --- a/bls381/twistededwards/point.go +++ b/ecc/bn254/twistededwards/point.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package twistededwards @@ -22,7 +22,7 @@ import ( "math/big" "math/bits" - "github.com/consensys/gurvy/bls381/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" ) // PointAffine point on a twisted Edwards curve @@ -43,12 +43,11 @@ const ( mCompressedPositive = 0x00 mUnmask = 0x7f - // size in byte of (x,y) + // size in byte of a compressed point (point.Y --> fr.Element) sizePointCompressed = fr.Limbs * 8 ) -// Bytes returns the point as bytes array x||y, where -// x and y are in big endian. +// Bytes returns the compressed point as a byte array // Follows https://tools.ietf.org/html/rfc8032#section-3.1, // as the twisted Edwards implementation is primarily used // for eddsa. @@ -91,15 +90,11 @@ func computeX(y *fr.Element) (x fr.Element) { return } -// SetBytes sets p from the buf, where bug is interpreted -// as a sizePointCompressed+ byte slice, where the first 32 bytes -// are interpreted as x in big endian, the next 32 bytes are -// interpreted as y in big endian. Returns the number of read bytes -// and an error if the buffer is too short. -// Returns the number of bytes read. -// Follows https://tools.ietf.org/html/rfc8032#section-3.1, -// as the twisted Edwards implementation is primarily used -// for eddsa. +// SetBytes sets p from buf +// len(buf) >= sizePointCompressed +// buf contains the Y coordinate masked with a parity bit to recompute the X coordinate +// from the curve equation. See Bytes() and https://tools.ietf.org/html/rfc8032#section-3.1 +// Returns the number of read bytes and an error if the buffer is too short. func (p *PointAffine) SetBytes(buf []byte) (int, error) { if len(buf) < sizePointCompressed { @@ -124,7 +119,7 @@ func (p *PointAffine) SetBytes(buf []byte) (int, error) { } } - return 32, nil + return sizePointCompressed, nil } // Unmarshal alias to SetBytes() diff --git a/bn256/twistededwards/twistededwards.go b/ecc/bn254/twistededwards/twistededwards.go similarity index 89% rename from bn256/twistededwards/twistededwards.go rename to ecc/bn254/twistededwards/twistededwards.go index 38c158ba29..ad5c06813d 100644 --- a/bn256/twistededwards/twistededwards.go +++ b/ecc/bn254/twistededwards/twistededwards.go @@ -3,7 +3,7 @@ package twistededwards import ( "math/big" - "github.com/consensys/gurvy/bn256/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" ) // CurveParams curve parameters: ax^2 + y^2 = 1 + d*x^2*y^2 @@ -16,7 +16,7 @@ type CurveParams struct { var edwards CurveParams -// GetEdwardsCurve returns the twisted Edwards curve on BN256's Fr +// GetEdwardsCurve returns the twisted Edwards curve on BN254's Fr func GetEdwardsCurve() CurveParams { // copy to keep Order private var res CurveParams diff --git a/bn256/twistededwards/twistededwards_test.go b/ecc/bn254/twistededwards/twistededwards_test.go similarity index 99% rename from bn256/twistededwards/twistededwards_test.go rename to ecc/bn254/twistededwards/twistededwards_test.go index a2f9d4f4b8..9e2c505feb 100644 --- a/bn256/twistededwards/twistededwards_test.go +++ b/ecc/bn254/twistededwards/twistededwards_test.go @@ -20,7 +20,7 @@ import ( "math/big" "testing" - "github.com/consensys/gurvy/bn256/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" ) func TestMarshal(t *testing.T) { diff --git a/bn256/utils_test.go b/ecc/bn254/utils_test.go similarity index 89% rename from bn256/utils_test.go rename to ecc/bn254/utils_test.go index aa817f896c..03f7b6afc7 100644 --- a/bn256/utils_test.go +++ b/ecc/bn254/utils_test.go @@ -1,11 +1,11 @@ -package bn256 +package bn254 import ( "math/rand" - "github.com/consensys/gurvy/bn256/fp" - "github.com/consensys/gurvy/bn256/fr" - "github.com/consensys/gurvy/bn256/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" + "github.com/consensys/gnark-crypto/ecc/bn254/fr" + "github.com/consensys/gnark-crypto/ecc/bn254/internal/fptower" "github.com/leanovate/gopter" ) diff --git a/bw761/bw761.go b/ecc/bw6-761/bw6-761.go similarity index 93% rename from bw761/bw761.go rename to ecc/bw6-761/bw6-761.go index 0f7065bc5f..9089ce837b 100644 --- a/bw761/bw761.go +++ b/ecc/bw6-761/bw6-761.go @@ -12,15 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bw761 +package bw6761 import ( "math/big" - "github.com/consensys/gurvy" - "github.com/consensys/gurvy/bw761/fp" - "github.com/consensys/gurvy/bw761/fr" - "github.com/consensys/gurvy/utils" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" ) // https://eprint.iacr.org/2020/351.pdf @@ -33,8 +32,8 @@ import ( // Fp: p=6891450384315732539396789682275657542479668912536150109513790160209623422243491736087683183289411687640864567753786613451161759120554247759349511699125301598951605099378508850372543631423596795951899700429969112842764913119068299 // Fr: r=258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 -// ID bls377 ID -const ID = gurvy.BW761 +// ID BW6_761 ID +const ID = ecc.BW6_761 // bCurveCoeff b coeff of the curve var bCurveCoeff fp.Element @@ -70,7 +69,7 @@ var lambdaGLV big.Int // glvBasis stores R-linearly independant vectors (a,b), (c,d) // in ker((u,v)->u+vlambda[r]), and their determinant -var glvBasis utils.Lattice +var glvBasis ecc.Lattice // generator of the curve var xGen big.Int @@ -95,7 +94,7 @@ func init() { loopCounter1 = [64]int8{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1} T, _ := new(big.Int).SetString("91893752504881257691937156713741811711", 10) - utils.NafDecomposition(T, loopCounter2[:]) + ecc.NafDecomposition(T, loopCounter2[:]) g1Infinity.X.SetOne() g1Infinity.Y.SetOne() @@ -106,7 +105,7 @@ func init() { thirdRootOneG2.Square(&thirdRootOneG1) lambdaGLV.SetString("80949648264912719408558363140637477264845294720710499478137287262712535938301461879813459410945", 10) // (x**5-3*x**4+3*x**3-x+1) _r := fr.Modulus() - utils.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) + ecc.PrecomputeLattice(_r, &lambdaGLV, &glvBasis) xGen.SetString("9586122913090633729", 10) diff --git a/bw761/fp/arith.go b/ecc/bw6-761/fp/arith.go similarity index 96% rename from bw761/fp/arith.go rename to ecc/bw6-761/fp/arith.go index a055885c03..66fa667482 100644 --- a/bw761/fp/arith.go +++ b/ecc/bw6-761/fp/arith.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bls381/fp/asm.go b/ecc/bw6-761/fp/asm.go similarity index 92% rename from bls381/fp/asm.go rename to ecc/bw6-761/fp/asm.go index 04495b0cfc..715bc7ac12 100644 --- a/bls381/fp/asm.go +++ b/ecc/bw6-761/fp/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bls377/fp/asm_noadx.go b/ecc/bw6-761/fp/asm_noadx.go similarity index 93% rename from bls377/fp/asm_noadx.go rename to ecc/bw6-761/fp/asm_noadx.go index e878f3473d..371bfeaeb3 100644 --- a/bls377/fp/asm_noadx.go +++ b/ecc/bw6-761/fp/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bw761/fp/bw6_utils.go b/ecc/bw6-761/fp/bw6_utils.go similarity index 100% rename from bw761/fp/bw6_utils.go rename to ecc/bw6-761/fp/bw6_utils.go diff --git a/bw761/fp/element.go b/ecc/bw6-761/fp/element.go similarity index 99% rename from bw761/fp/element.go rename to ecc/bw6-761/fp/element.go index 2440f7b31d..7bd1f5a5ce 100644 --- a/bw761/fp/element.go +++ b/ecc/bw6-761/fp/element.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT // Package fp contains field arithmetic operations for modulus 6891450384315732539396789682275657542479668912536150109513790160209623422243491736087683183289411687640864567753786613451161759120554247759349511699125301598951605099378508850372543631423596795951899700429969112842764913119068299 package fp diff --git a/bw761/fp/element_mul_adx_amd64.s b/ecc/bw6-761/fp/element_mul_adx_amd64.s similarity index 100% rename from bw761/fp/element_mul_adx_amd64.s rename to ecc/bw6-761/fp/element_mul_adx_amd64.s diff --git a/bw761/fp/element_mul_amd64.s b/ecc/bw6-761/fp/element_mul_amd64.s similarity index 100% rename from bw761/fp/element_mul_amd64.s rename to ecc/bw6-761/fp/element_mul_amd64.s diff --git a/bw761/fp/element_ops_amd64.go b/ecc/bw6-761/fp/element_ops_amd64.go similarity index 94% rename from bw761/fp/element_ops_amd64.go rename to ecc/bw6-761/fp/element_ops_amd64.go index 7c3aa757be..71b26855b4 100644 --- a/bw761/fp/element_ops_amd64.go +++ b/ecc/bw6-761/fp/element_ops_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bw761/fp/element_ops_amd64.s b/ecc/bw6-761/fp/element_ops_amd64.s similarity index 100% rename from bw761/fp/element_ops_amd64.s rename to ecc/bw6-761/fp/element_ops_amd64.s diff --git a/bw761/fp/element_ops_noasm.go b/ecc/bw6-761/fp/element_ops_noasm.go similarity index 96% rename from bw761/fp/element_ops_noasm.go rename to ecc/bw6-761/fp/element_ops_noasm.go index 5563ce93fe..e6ced1bf56 100644 --- a/bw761/fp/element_ops_noasm.go +++ b/ecc/bw6-761/fp/element_ops_noasm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp diff --git a/bw761/fp/element_test.go b/ecc/bw6-761/fp/element_test.go similarity index 99% rename from bw761/fp/element_test.go rename to ecc/bw6-761/fp/element_test.go index ed66380cff..68936d9c5e 100644 --- a/bw761/fp/element_test.go +++ b/ecc/bw6-761/fp/element_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fp @@ -222,11 +222,6 @@ func TestElementCmp(t *testing.T) { } } -func TestElementSetInterface(t *testing.T) { - // TODO - t.Skip("not implemented") -} - func TestElementIsRandom(t *testing.T) { for i := 0; i < 50; i++ { var x, y Element diff --git a/bls377/fr/arith.go b/ecc/bw6-761/fr/arith.go similarity index 96% rename from bls377/fr/arith.go rename to ecc/bw6-761/fr/arith.go index 9f42f6641f..83c9fd9ef9 100644 --- a/bls377/fr/arith.go +++ b/ecc/bw6-761/fr/arith.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bls381/fr/asm.go b/ecc/bw6-761/fr/asm.go similarity index 92% rename from bls381/fr/asm.go rename to ecc/bw6-761/fr/asm.go index 7c77fecb17..f859dd8731 100644 --- a/bls381/fr/asm.go +++ b/ecc/bw6-761/fr/asm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bw761/fr/asm_noadx.go b/ecc/bw6-761/fr/asm_noadx.go similarity index 93% rename from bw761/fr/asm_noadx.go rename to ecc/bw6-761/fr/asm_noadx.go index 3b2f49bd87..ab9b869b5b 100644 --- a/bw761/fr/asm_noadx.go +++ b/ecc/bw6-761/fr/asm_noadx.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bw761/fr/element.go b/ecc/bw6-761/fr/element.go similarity index 99% rename from bw761/fr/element.go rename to ecc/bw6-761/fr/element.go index a811c6f733..efd2c542a1 100644 --- a/bw761/fr/element.go +++ b/ecc/bw6-761/fr/element.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT // Package fr contains field arithmetic operations for modulus 258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177 package fr diff --git a/bw761/fr/element_mul_adx_amd64.s b/ecc/bw6-761/fr/element_mul_adx_amd64.s similarity index 100% rename from bw761/fr/element_mul_adx_amd64.s rename to ecc/bw6-761/fr/element_mul_adx_amd64.s diff --git a/bw761/fr/element_mul_amd64.s b/ecc/bw6-761/fr/element_mul_amd64.s similarity index 100% rename from bw761/fr/element_mul_amd64.s rename to ecc/bw6-761/fr/element_mul_amd64.s diff --git a/bls381/fr/element_ops_amd64.go b/ecc/bw6-761/fr/element_ops_amd64.go similarity index 94% rename from bls381/fr/element_ops_amd64.go rename to ecc/bw6-761/fr/element_ops_amd64.go index 73ae624914..f0d8316e52 100644 --- a/bls381/fr/element_ops_amd64.go +++ b/ecc/bw6-761/fr/element_ops_amd64.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bw761/fr/element_ops_amd64.s b/ecc/bw6-761/fr/element_ops_amd64.s similarity index 100% rename from bw761/fr/element_ops_amd64.s rename to ecc/bw6-761/fr/element_ops_amd64.s diff --git a/bls381/fr/element_ops_noasm.go b/ecc/bw6-761/fr/element_ops_noasm.go similarity index 96% rename from bls381/fr/element_ops_noasm.go rename to ecc/bw6-761/fr/element_ops_noasm.go index e902f2906a..e7daa4d40e 100644 --- a/bls381/fr/element_ops_noasm.go +++ b/ecc/bw6-761/fr/element_ops_noasm.go @@ -14,7 +14,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr diff --git a/bw761/fr/element_test.go b/ecc/bw6-761/fr/element_test.go similarity index 99% rename from bw761/fr/element_test.go rename to ecc/bw6-761/fr/element_test.go index 577504388b..97101da568 100644 --- a/bw761/fr/element_test.go +++ b/ecc/bw6-761/fr/element_test.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by goff (v0.3.12) DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package fr @@ -210,11 +210,6 @@ func TestElementCmp(t *testing.T) { } } -func TestElementSetInterface(t *testing.T) { - // TODO - t.Skip("not implemented") -} - func TestElementIsRandom(t *testing.T) { for i := 0; i < 50; i++ { var x, y Element diff --git a/ecc/bw6-761/fr/fft/domain.go b/ecc/bw6-761/fr/fft/domain.go new file mode 100644 index 0000000000..8e2f22a706 --- /dev/null +++ b/ecc/bw6-761/fr/fft/domain.go @@ -0,0 +1,271 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "io" + "math/big" + "math/bits" + "runtime" + "sync" + + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" +) + +// Domain with a power of 2 cardinality +// compute a field element of order 2x and store it in FinerGenerator +// all other values can be derived from x, GeneratorSqrt +type Domain struct { + Cardinality uint64 + Depth uint64 + CardinalityInv fr.Element + Generator fr.Element + GeneratorInv fr.Element + FinerGenerator fr.Element + FinerGeneratorInv fr.Element + + // the following slices are not serialized and are (re)computed through domain.preComputeTwiddles() + + // Twiddles factor for the FFT using Generator for each stage of the recursive FFT + Twiddles [][]fr.Element + + // Twiddles factor for the FFT using GeneratorInv for each stage of the recursive FFT + TwiddlesInv [][]fr.Element + + // we precompute these mostly to avoid the memory intensive bit reverse permutation in the groth16.Prover + + // CosetTable[i][j] = domain.Generator(i-th)Sqrt ^ j + // CosetTable = fft.BitReverse(CosetTable) + CosetTable [][]fr.Element + + // CosetTable[i][j] = domain.Generator(i-th)SqrtInv ^ j + // CosetTableInv = fft.BitReverse(CosetTableInv) + CosetTableInv [][]fr.Element +} + +// NewDomain returns a subgroup with a power of 2 cardinality +// cardinality >= m +// If depth>0, the Domain will also store a primitive (2**depth)*m root +// of 1, with associated precomputed data. This allows to perform shifted +// FFT/FFTInv. +// +// example: +// -------- +// +// NewDomain(m, 2) outputs a new domain to perform fft on Z/mZ, plus a primitive +// 2**2*m=4m-th root of 1 and associated data to compute fft/fftinv on the cosets of +// (Z/4mZ)/(Z/mZ). +func NewDomain(m, depth uint64) *Domain { + + // generator of the largest 2-adic subgroup + var rootOfUnity fr.Element + + rootOfUnity.SetString("32863578547254505029601261939868325669770508939375122462904745766352256812585773382134936404344547323199885654433") + const maxOrderRoot uint64 = 46 + + subGroup := &Domain{} + x := nextPowerOfTwo(m) + subGroup.Cardinality = uint64(x) + subGroup.Depth = depth + + // find generator for Z/2^(log(m))Z and Z/2^(log(m)+cosets)Z + logx := uint64(bits.TrailingZeros64(x)) + if logx > maxOrderRoot { + panic("m is too big: the required root of unity does not exist") + } + logGen := logx + depth + if logGen > maxOrderRoot { + panic("log(m) + cosets is too big: the required root of unity does not exist") + } + + expo := uint64(1 << (maxOrderRoot - logGen)) + bExpo := new(big.Int).SetUint64(expo) + subGroup.FinerGenerator.Exp(rootOfUnity, bExpo) + subGroup.FinerGeneratorInv.Inverse(&subGroup.FinerGenerator) + + // Generator = FinerGenerator^2 has order x + expo = uint64(1 << (maxOrderRoot - logx)) + bExpo.SetUint64(expo) + subGroup.Generator.Exp(rootOfUnity, bExpo) // order x + subGroup.GeneratorInv.Inverse(&subGroup.Generator) + subGroup.CardinalityInv.SetUint64(uint64(x)).Inverse(&subGroup.CardinalityInv) + + // twiddle factors + subGroup.preComputeTwiddles() + + return subGroup +} + +func (d *Domain) preComputeTwiddles() { + + // nb fft stages + nbStages := uint64(bits.TrailingZeros64(d.Cardinality)) + nbCosets := (1 << d.Depth) - 1 + + d.Twiddles = make([][]fr.Element, nbStages) + d.TwiddlesInv = make([][]fr.Element, nbStages) + d.CosetTable = make([][]fr.Element, nbCosets) + d.CosetTableInv = make([][]fr.Element, nbCosets) + for i := 0; i < nbCosets; i++ { + d.CosetTable[i] = make([]fr.Element, d.Cardinality) + d.CosetTableInv[i] = make([]fr.Element, d.Cardinality) + } + + var wg sync.WaitGroup + + // for each fft stage, we pre compute the twiddle factors + twiddles := func(t [][]fr.Element, omega fr.Element) { + for i := uint64(0); i < nbStages; i++ { + t[i] = make([]fr.Element, 1+(1<<(nbStages-i-1))) + var w fr.Element + if i == 0 { + w = omega + } else { + w = t[i-1][2] + } + t[i][0] = fr.One() + t[i][1] = w + for j := 2; j < len(t[i]); j++ { + t[i][j].Mul(&t[i][j-1], &w) + } + } + wg.Done() + } + + expTable := func(sqrt fr.Element, t []fr.Element) { + t[0] = fr.One() + precomputeExpTable(sqrt, t) + wg.Done() + } + + if nbCosets > 0 { + cosetGens := make([]fr.Element, nbCosets) + cosetGensInv := make([]fr.Element, nbCosets) + cosetGens[0].Set(&d.FinerGenerator) + cosetGensInv[0].Set(&d.FinerGeneratorInv) + for i := 1; i < nbCosets; i++ { + cosetGens[i].Mul(&cosetGens[i-1], &d.FinerGenerator) + cosetGensInv[i].Mul(&cosetGensInv[1], &d.FinerGeneratorInv) + } + wg.Add(2 + 2*nbCosets) + go twiddles(d.Twiddles, d.Generator) + go twiddles(d.TwiddlesInv, d.GeneratorInv) + for i := 0; i < nbCosets-1; i++ { + go expTable(cosetGens[i], d.CosetTable[i]) + go expTable(cosetGensInv[i], d.CosetTableInv[i]) + } + go expTable(cosetGens[nbCosets-1], d.CosetTable[nbCosets-1]) + expTable(cosetGensInv[nbCosets-1], d.CosetTableInv[nbCosets-1]) + + wg.Wait() + + } else { + wg.Add(2) + go twiddles(d.Twiddles, d.Generator) + twiddles(d.TwiddlesInv, d.GeneratorInv) + wg.Wait() + } + +} + +func precomputeExpTable(w fr.Element, table []fr.Element) { + n := len(table) + + // see if it makes sense to parallelize exp tables pre-computation + interval := 0 + if runtime.NumCPU() >= 4 { + interval = (n - 1) / (runtime.NumCPU() / 4) + } + + // this ratio roughly correspond to the number of multiplication one can do in place of a Exp operation + const ratioExpMul = 6000 / 17 + + if interval < ratioExpMul { + precomputeExpTableChunk(w, 1, table[1:]) + return + } + + // we parallelize + var wg sync.WaitGroup + for i := 1; i < n; i += interval { + start := i + end := i + interval + if end > n { + end = n + } + wg.Add(1) + go func() { + precomputeExpTableChunk(w, uint64(start), table[start:end]) + wg.Done() + }() + } + wg.Wait() +} + +func precomputeExpTableChunk(w fr.Element, power uint64, table []fr.Element) { + table[0].Exp(w, new(big.Int).SetUint64(power)) + for i := 1; i < len(table); i++ { + table[i].Mul(&table[i-1], &w) + } +} + +func nextPowerOfTwo(n uint64) uint64 { + p := uint64(1) + if (n & (n - 1)) == 0 { + return n + } + for p < n { + p <<= 1 + } + return p +} + +// WriteTo writes a binary representation of the domain (without the precomputed twiddle factors) +// to the provided writer +func (d *Domain) WriteTo(w io.Writer) (int64, error) { + + enc := curve.NewEncoder(w) + + toEncode := []interface{}{d.Cardinality, d.Depth, &d.CardinalityInv, &d.Generator, &d.GeneratorInv, &d.FinerGenerator, &d.FinerGeneratorInv} + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom attempts to decode a domain from Reader +func (d *Domain) ReadFrom(r io.Reader) (int64, error) { + + dec := curve.NewDecoder(r) + + toDecode := []interface{}{&d.Cardinality, &d.Depth, &d.CardinalityInv, &d.Generator, &d.GeneratorInv, &d.FinerGenerator, &d.FinerGeneratorInv} + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + d.preComputeTwiddles() + return dec.BytesRead(), nil +} diff --git a/ecc/bw6-761/fr/fft/domain_test.go b/ecc/bw6-761/fr/fft/domain_test.go new file mode 100644 index 0000000000..e3c1d71978 --- /dev/null +++ b/ecc/bw6-761/fr/fft/domain_test.go @@ -0,0 +1,47 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "bytes" + "reflect" + "testing" +) + +func TestDomainSerialization(t *testing.T) { + + domain := NewDomain(1<<6, 1) + var reconstructed Domain + + var buf bytes.Buffer + written, err := domain.WriteTo(&buf) + if err != nil { + t.Fatal(err) + } + var read int64 + read, err = reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal(err) + } + + if written != read { + t.Fatal("didn't read as many bytes as we wrote") + } + if !reflect.DeepEqual(domain, &reconstructed) { + t.Fatal("Domain.SetBytes(Bytes()) failed") + } +} diff --git a/ecc/bw6-761/fr/fft/fft.go b/ecc/bw6-761/fr/fft/fft.go new file mode 100644 index 0000000000..724ff64fb1 --- /dev/null +++ b/ecc/bw6-761/fr/fft/fft.go @@ -0,0 +1,265 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/internal/parallel" + + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" +) + +// Decimation is used in the FFT call to select decimation in time or in frequency +type Decimation uint8 + +const ( + DIT Decimation = iota + DIF +) + +// parallelize threshold for a single butterfly op, if the fft stage is not parallelized already +const butterflyThreshold = 16 + +// FFT computes (recursively) the discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +// +// example: +// ------- +// domain := NewDomain(m, 2) --> contains precomputed data for Z/mZ, and Z/4mZ +// FFT(pol, DIT, 1) --> evaluates pol on the coset 1 in (Z/4mZ)/(Z/mZ) +func (domain *Domain) FFT(a []fr.Element, decimation Decimation, coset uint64) { + + numCPU := uint64(runtime.NumCPU()) + + if coset != 0 { + if decimation == DIT { + BitReverse(domain.CosetTable[coset-1]) + } + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].Mul(&a[i], &domain.CosetTable[coset-1][i]) + } + }) + // put it back as we found it + if decimation == DIT { + BitReverse(domain.CosetTable[coset-1]) + } + } + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(nextPowerOfTwo(numCPU)) + if numCPU <= 1 { + maxSplits = -1 + } + + switch decimation { + case DIF: + difFFT(a, domain.Twiddles, 0, maxSplits, nil) + case DIT: + ditFFT(a, domain.Twiddles, 0, maxSplits, nil) + default: + panic("not implemented") + } +} + +// FFTInverse computes (recursively) the inverse discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +func (domain *Domain) FFTInverse(a []fr.Element, decimation Decimation, coset uint64) { + + numCPU := uint64(runtime.NumCPU()) + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(nextPowerOfTwo(numCPU)) + if numCPU <= 1 { + maxSplits = -1 + } + switch decimation { + case DIF: + difFFT(a, domain.TwiddlesInv, 0, maxSplits, nil) + case DIT: + ditFFT(a, domain.TwiddlesInv, 0, maxSplits, nil) + default: + panic("not implemented") + } + + // scale by CardinalityInv (+ cosetTableInv is coset!=0) + if coset != 0 { + if decimation == DIF { + BitReverse(domain.CosetTableInv[coset-1]) + } + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].Mul(&a[i], &domain.CosetTableInv[coset-1][i]). + MulAssign(&domain.CardinalityInv) + } + }) + // put it back as we found it + if decimation == DIF { + BitReverse(domain.CosetTableInv[coset-1]) + } + } else { + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].MulAssign(&domain.CardinalityInv) + } + }) + } +} + +func difFFT(a []fr.Element, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer func() { + chDone <- struct{}{} + }() + } + n := len(a) + if n == 1 { + return + } + m := n >> 1 + + // if stage < maxSplits, we parallelize this butterfly + // but we have only numCPU / stage cpus available + if (m > butterflyThreshold) && (stage < maxSplits) { + // 1 << stage == estimated used CPUs + numCPU := runtime.NumCPU() / (1 << (stage)) + parallel.Execute(m, func(start, end int) { + var t fr.Element + for i := start; i < end; i++ { + t = a[i] + a[i].Add(&a[i], &a[i+m]) + + a[i+m]. + Sub(&t, &a[i+m]). + Mul(&a[i+m], &twiddles[stage][i]) + } + }, numCPU) + } else { + var t fr.Element + + // i == 0 + t = a[0] + a[0].Add(&a[0], &a[m]) + a[m].Sub(&t, &a[m]) + + for i := 1; i < m; i++ { + t = a[i] + a[i].Add(&a[i], &a[i+m]) + + a[i+m]. + Sub(&t, &a[i+m]). + Mul(&a[i+m], &twiddles[stage][i]) + } + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFT(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFT(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} + +func ditFFT(a []fr.Element, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer func() { + chDone <- struct{}{} + }() + } + n := len(a) + if n == 1 { + return + } + m := n >> 1 + + nextStage := stage + 1 + + if stage < maxSplits { + // that's the only time we fire go routines + chDone := make(chan struct{}, 1) + go ditFFT(a[m:], twiddles, nextStage, maxSplits, chDone) + ditFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + ditFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + ditFFT(a[m:n], twiddles, nextStage, maxSplits, nil) + + } + + // if stage < maxSplits, we parallelize this butterfly + // but we have only numCPU / stage cpus available + if (m > butterflyThreshold) && (stage < maxSplits) { + // 1 << stage == estimated used CPUs + numCPU := runtime.NumCPU() / (1 << (stage)) + parallel.Execute(m, func(start, end int) { + var t, tm fr.Element + for k := start; k < end; k++ { + t = a[k] + tm.Mul(&a[k+m], &twiddles[stage][k]) + a[k].Add(&a[k], &tm) + a[k+m].Sub(&t, &tm) + } + }, numCPU) + + } else { + var t, tm fr.Element + // k == 0 + // wPow == 1 + t = a[0] + a[0].Add(&a[0], &a[m]) + a[m].Sub(&t, &a[m]) + + for k := 1; k < m; k++ { + t = a[k] + tm.Mul(&a[k+m], &twiddles[stage][k]) + a[k].Add(&a[k], &tm) + a[k+m].Sub(&t, &tm) + } + } +} + +// BitReverse applies the bit-reversal permutation to a. +// len(a) must be a power of 2 (as in every single function in this file) +func BitReverse(a []fr.Element) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} diff --git a/ecc/bw6-761/fr/fft/fft_test.go b/ecc/bw6-761/fr/fft/fft_test.go new file mode 100644 index 0000000000..ef30c82123 --- /dev/null +++ b/ecc/bw6-761/fr/fft/fft_test.go @@ -0,0 +1,205 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package fft + +import ( + "math/big" + "strconv" + "testing" + + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/gen" + "github.com/leanovate/gopter/prop" +) + +func TestFFT(t *testing.T) { + const maxSize = 1 << 10 + + domain := NewDomain(maxSize, 0) + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 5 + + properties := gopter.NewProperties(parameters) + + properties.Property("DIF FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domain.FFT(pol, DIF, 0) + BitReverse(pol) + + sample := domain.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := evaluatePolynomial(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("DIT FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverse(pol) + domain.FFT(pol, DIT, 0) + + sample := domain.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := evaluatePolynomial(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("bitReverse(DIF FFT(DIT FFT (bitReverse))))==id", prop.ForAll( + + func() bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverse(pol) + domain.FFT(pol, DIT, 0) + domain.FFTInverse(pol, DIF, 0) + BitReverse(pol) + + check := true + for i := 0; i < len(pol); i++ { + check = check && pol[i].Equal(&backupPol[i]) + } + return check + }, + )) + + properties.Property("DIT FFT(DIF FFT)==id", prop.ForAll( + + func() bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domain.FFTInverse(pol, DIF, 0) + domain.FFT(pol, DIT, 0) + + check := true + for i := 0; i < len(pol); i++ { + check = check && (pol[i] == backupPol[i]) + } + return check + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + +} + +// -------------------------------------------------------------------- +// benches +func BenchmarkBitReverse(b *testing.B) { + + const maxSize = 1 << 20 + + pol := make([]fr.Element, maxSize) + for i := uint64(0); i < maxSize; i++ { + pol[i].SetRandom() + } + + for i := 8; i < 20; i++ { + b.Run("bit reversing 2**"+strconv.Itoa(i)+"bits", func(b *testing.B) { + _pol := make([]fr.Element, 1< .. || 0x0000...0af8 + if len(d.data)%BlockSize != 0 { + q := len(d.data) / BlockSize + r := len(d.data) % BlockSize + sliceq := make([]byte, q*BlockSize) + copy(sliceq, d.data) + slicer := make([]byte, r) + copy(slicer, d.data[q*BlockSize:]) + sliceremainder := make([]byte, BlockSize-r) + d.data = append(sliceq, sliceremainder...) + d.data = append(d.data, slicer...) + } + + if len(d.data) == 0 { + d.data = make([]byte, 32) + } + + nbChunks := len(d.data) / BlockSize + + for i := 0; i < nbChunks; i++ { + copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) + x.SetBytes(buffer[:]) + d.encrypt(x) + d.h.Add(&x, &d.h) + } + + return d.h +} + +// plain execution of a mimc run +// m: message +// k: encryption key +func (d *digest) encrypt(m fr.Element) { + + for i := 0; i < len(d.Params); i++ { + // m = (m+k+c)^5 + var tmp fr.Element + tmp.Add(&m, &d.h).Add(&tmp, &d.Params[i]) + m.Square(&tmp). + Square(&m). + Mul(&m, &tmp) + } + m.Add(&m, &d.h) + d.h = m +} + +// Sum computes the mimc hash of msg from seed +func Sum(seed string, msg []byte) ([]byte, error) { + params := NewParams(seed) + var d digest + d.Params = params + if _, err := d.Write(msg); err != nil { + return nil, err + } + h := d.checksum() + bytes := h.Bytes() + return bytes[:], nil +} diff --git a/ecc/bw6-761/fr/polynomial/polynomial.go b/ecc/bw6-761/fr/polynomial/polynomial.go new file mode 100644 index 0000000000..0e04fc3e88 --- /dev/null +++ b/ecc/bw6-761/fr/polynomial/polynomial.go @@ -0,0 +1,43 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package polynomial + +import ( + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" +) + +// Polynomial polynomial represented by coefficients bw6-761 fr field. +type Polynomial []fr.Element + +// Degree returns the degree of the polynomial, which is the length of Data. +func (p Polynomial) Degree() uint64 { + res := uint64(len(p) - 1) + return res +} + +// Eval evaluates p at v +func (p Polynomial) Eval(v interface{}) interface{} { + var res, _v fr.Element + _v.Set(v.(*fr.Element)) + s := len(p) + res.Set(&p[s-1]) + for i := s - 2; i >= 0; i-- { + res.Mul(&res, &_v) + res.Add(&res, &p[i]) + } + return &res +} diff --git a/bw761/g1.go b/ecc/bw6-761/g1.go similarity index 98% rename from bw761/g1.go rename to ecc/bw6-761/g1.go index d8cd00cb9c..20438785cc 100644 --- a/bw761/g1.go +++ b/ecc/bw6-761/g1.go @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bw761 +package bw6761 import ( "math/big" - "github.com/consensys/gurvy/bw761/fp" - "github.com/consensys/gurvy/bw761/fr" - "github.com/consensys/gurvy/utils" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/internal/parallel" ) // G1Affine point in affine coordinates @@ -415,7 +415,7 @@ func (p *G1Jac) mulGLV(a *G1Jac, s *big.Int) *G1Jac { table[3].phi(a) // split the scalar, modifies +-a, phi(a) accordingly - k := utils.SplitScalar(s, &glvBasis) + k := ecc.SplitScalar(s, &glvBasis) if k[0].Cmp(&zero) == -1 { k[0].Neg(&k[0]) diff --git a/bw761/g1_test.go b/ecc/bw6-761/g1_test.go similarity index 83% rename from bw761/g1_test.go rename to ecc/bw6-761/g1_test.go index 5819f1353a..84963540cd 100644 --- a/bw761/g1_test.go +++ b/ecc/bw6-761/g1_test.go @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bw761 +package bw6761 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bw761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" - "github.com/consensys/gurvy/bw761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -86,7 +86,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { properties := gopter.NewProperties(parameters) genFuzz1 := GenFp() - properties.Property("[BW761] g1Gen (affine) should be on the curve", prop.ForAll( + properties.Property("[BW6-761] g1Gen (affine) should be on the curve", prop.ForAll( func(a fp.Element) bool { var op1, op2 G1Affine op1.FromJacobian(&g1Gen) @@ -97,7 +97,7 @@ func TestG1AffineIsOnCurve(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] g1Gen (Jacobian) should be on the curve", prop.ForAll( + properties.Property("[BW6-761] g1Gen (Jacobian) should be on the curve", prop.ForAll( func(a fp.Element) bool { var op1, op2, op3 G1Jac op1.Set(&g1Gen) @@ -122,7 +122,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1 := GenFp() genFuzz2 := GenFp() - properties.Property("[BW761] Affine representation should be independent of the Jacobian representative", prop.ForAll( + properties.Property("[BW6-761] Affine representation should be independent of the Jacobian representative", prop.ForAll( func(a fp.Element) bool { g := fuzzJacobianG1Affine(&g1Gen, a) var op1 G1Affine @@ -132,7 +132,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( + properties.Property("[BW6-761] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( func(a fp.Element) bool { var g g1JacExtended g.X.Set(&g1Gen.X) @@ -148,7 +148,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] Jacobian representation should be the same as the affine representative", prop.ForAll( + properties.Property("[BW6-761] Jacobian representation should be the same as the affine representative", prop.ForAll( func(a fp.Element) bool { var g G1Jac var op1 G1Affine @@ -165,7 +165,7 @@ func TestG1AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( + properties.Property("[BW6-761] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( func() bool { var g G1Affine g.X.SetZero() @@ -178,7 +178,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BW761] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( + properties.Property("[BW6-761] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( func() bool { var g G1Affine var op1 g1JacExtended @@ -190,7 +190,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BW761] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( + properties.Property("[BW6-761] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( func() bool { var g G1Jac var op1 g1JacExtended @@ -203,7 +203,7 @@ func TestG1AffineConversions(t *testing.T) { }, )) - properties.Property("[BW761] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( + properties.Property("[BW6-761] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( func(a, b fp.Element) bool { op1 := fuzzJacobianG1Affine(&g1Gen, a) op2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -227,7 +227,7 @@ func TestG1AffineOps(t *testing.T) { genScalar := GenFr() - properties.Property("[BW761] [Jacobian] Add should call double when having adding the same point", prop.ForAll( + properties.Property("[BW6-761] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -240,7 +240,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BW761] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( + properties.Property("[BW6-761] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop2 := fuzzJacobianG1Affine(&g1Gen, b) @@ -252,7 +252,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BW761] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( + properties.Property("[BW6-761] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop1.AddAssign(&g1Infinity) @@ -264,7 +264,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( + properties.Property("[BW6-761] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) var p1, p1Neg G1Affine @@ -283,7 +283,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( + properties.Property("[BW6-761] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) var p1, p1Neg G1Affine @@ -302,7 +302,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( + properties.Property("[BW6-761] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG1Affine(&g1Gen, a) fop1.Neg(&fop1) @@ -314,7 +314,7 @@ func TestG1AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BW6-761] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -337,7 +337,7 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BW761] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BW6-761] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -360,7 +360,7 @@ func TestG1AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BW761] GLV and Double and Add should output the same result", prop.ForAll( + properties.Property("[BW6-761] GLV and Double and Add should output the same result", prop.ForAll( func(s fr.Element) bool { var r big.Int @@ -384,7 +384,7 @@ func TestG1AffineCofactorCleaning(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BW761] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( + properties.Property("[BW6-761] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( func() bool { var a, x, b fp.Element a.SetRandom() @@ -424,7 +424,7 @@ func TestG1AffineBatchScalarMultiplication(t *testing.T) { // size of the multiExps const nbSamples = 10 - properties.Property("[BW761] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( + properties.Property("[BW6-761] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( func(mixer fr.Element) bool { // mixer ensures that all the words of a fpElement are set var sampleScalars [nbSamples]fr.Element diff --git a/bw761/g2.go b/ecc/bw6-761/g2.go similarity index 98% rename from bw761/g2.go rename to ecc/bw6-761/g2.go index 6fd115931a..b2f8bffd13 100644 --- a/bw761/g2.go +++ b/ecc/bw6-761/g2.go @@ -12,17 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bw761 +package bw6761 import ( "math/big" - "github.com/consensys/gurvy/bw761/fp" - "github.com/consensys/gurvy/bw761/fr" - "github.com/consensys/gurvy/utils" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/internal/parallel" ) // G2Affine point in affine coordinates @@ -420,7 +420,7 @@ func (p *G2Jac) mulGLV(a *G2Jac, s *big.Int) *G2Jac { table[3].phi(a) // split the scalar, modifies +-a, phi(a) accordingly - k := utils.SplitScalar(s, &glvBasis) + k := ecc.SplitScalar(s, &glvBasis) if k[0].Cmp(&zero) == -1 { k[0].Neg(&k[0]) diff --git a/bw761/g2_test.go b/ecc/bw6-761/g2_test.go similarity index 83% rename from bw761/g2_test.go rename to ecc/bw6-761/g2_test.go index 666530f4f2..4584733408 100644 --- a/bw761/g2_test.go +++ b/ecc/bw6-761/g2_test.go @@ -12,18 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bw761 +package bw6761 import ( "fmt" "math/big" "testing" - "github.com/consensys/gurvy/bw761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" - "github.com/consensys/gurvy/bw761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -86,7 +86,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { properties := gopter.NewProperties(parameters) genFuzz1 := GenFp() - properties.Property("[BW761] g2Gen (affine) should be on the curve", prop.ForAll( + properties.Property("[BW6-761] g2Gen (affine) should be on the curve", prop.ForAll( func(a fp.Element) bool { var op1, op2 G2Affine op1.FromJacobian(&g2Gen) @@ -97,7 +97,7 @@ func TestG2AffineIsOnCurve(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] g2Gen (Jacobian) should be on the curve", prop.ForAll( + properties.Property("[BW6-761] g2Gen (Jacobian) should be on the curve", prop.ForAll( func(a fp.Element) bool { var op1, op2, op3 G2Jac op1.Set(&g2Gen) @@ -122,7 +122,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1 := GenFp() genFuzz2 := GenFp() - properties.Property("[BW761] Affine representation should be independent of the Jacobian representative", prop.ForAll( + properties.Property("[BW6-761] Affine representation should be independent of the Jacobian representative", prop.ForAll( func(a fp.Element) bool { g := fuzzJacobianG2Affine(&g2Gen, a) var op1 G2Affine @@ -132,7 +132,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( + properties.Property("[BW6-761] Affine representation should be independent of a Extended Jacobian representative", prop.ForAll( func(a fp.Element) bool { var g g2JacExtended g.X.Set(&g2Gen.X) @@ -148,7 +148,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] Jacobian representation should be the same as the affine representative", prop.ForAll( + properties.Property("[BW6-761] Jacobian representation should be the same as the affine representative", prop.ForAll( func(a fp.Element) bool { var g G2Jac var op1 G2Affine @@ -165,7 +165,7 @@ func TestG2AffineConversions(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( + properties.Property("[BW6-761] Converting affine symbol for infinity to Jacobian should output correct infinity in Jacobian", prop.ForAll( func() bool { var g G2Affine g.X.SetZero() @@ -178,7 +178,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BW761] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( + properties.Property("[BW6-761] Converting infinity in extended Jacobian to affine should output infinity symbol in Affine", prop.ForAll( func() bool { var g G2Affine var op1 g2JacExtended @@ -190,7 +190,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BW761] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( + properties.Property("[BW6-761] Converting infinity in extended Jacobian to Jacobian should output infinity in Jacobian", prop.ForAll( func() bool { var g G2Jac var op1 g2JacExtended @@ -203,7 +203,7 @@ func TestG2AffineConversions(t *testing.T) { }, )) - properties.Property("[BW761] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( + properties.Property("[BW6-761] [Jacobian] Two representatives of the same class should be equal", prop.ForAll( func(a, b fp.Element) bool { op1 := fuzzJacobianG2Affine(&g2Gen, a) op2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -227,7 +227,7 @@ func TestG2AffineOps(t *testing.T) { genScalar := GenFr() - properties.Property("[BW761] [Jacobian] Add should call double when having adding the same point", prop.ForAll( + properties.Property("[BW6-761] [Jacobian] Add should call double when having adding the same point", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -240,7 +240,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BW761] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( + properties.Property("[BW6-761] [Jacobian] Adding the opposite of a point to itself should output inf", prop.ForAll( func(a, b fp.Element) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop2 := fuzzJacobianG2Affine(&g2Gen, b) @@ -252,7 +252,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz2, )) - properties.Property("[BW761] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( + properties.Property("[BW6-761] [Jacobian] Adding the inf to a point should not modify the point", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop1.AddAssign(&g2Infinity) @@ -264,7 +264,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( + properties.Property("[BW6-761] [Jacobian Extended] addMixed (-G) should equal subMixed(G)", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) var p1, p1Neg G2Affine @@ -283,7 +283,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( + properties.Property("[BW6-761] [Jacobian Extended] doubleMixed (-G) should equal doubleNegMixed(G)", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) var p1, p1Neg G2Affine @@ -302,7 +302,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( + properties.Property("[BW6-761] [Jacobian] Addmix the negation to itself should output 0", prop.ForAll( func(a fp.Element) bool { fop1 := fuzzJacobianG2Affine(&g2Gen, a) fop1.Neg(&fop1) @@ -314,7 +314,7 @@ func TestG2AffineOps(t *testing.T) { genFuzz1, )) - properties.Property("[BW761] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BW6-761] scalar multiplication (double and add) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -337,7 +337,7 @@ func TestG2AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BW761] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( + properties.Property("[BW6-761] scalar multiplication (GLV) should depend only on the scalar mod r", prop.ForAll( func(s fr.Element) bool { r := fr.Modulus() @@ -360,7 +360,7 @@ func TestG2AffineOps(t *testing.T) { genScalar, )) - properties.Property("[BW761] GLV and Double and Add should output the same result", prop.ForAll( + properties.Property("[BW6-761] GLV and Double and Add should output the same result", prop.ForAll( func(s fr.Element) bool { var r big.Int @@ -384,7 +384,7 @@ func TestG2AffineCofactorCleaning(t *testing.T) { properties := gopter.NewProperties(parameters) - properties.Property("[BW761] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( + properties.Property("[BW6-761] Clearing the cofactor of a random point should set it in the r-torsion", prop.ForAll( func() bool { var a, x, b fp.Element a.SetRandom() @@ -424,7 +424,7 @@ func TestG2AffineBatchScalarMultiplication(t *testing.T) { // size of the multiExps const nbSamples = 10 - properties.Property("[BW761] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( + properties.Property("[BW6-761] BatchScalarMultiplication should be consistant with individual scalar multiplications", prop.ForAll( func(mixer fr.Element) bool { // mixer ensures that all the words of a fpElement are set var sampleScalars [nbSamples]fr.Element diff --git a/bw761/hash_to_curve.go b/ecc/bw6-761/hash_to_curve.go similarity index 98% rename from bw761/hash_to_curve.go rename to ecc/bw6-761/hash_to_curve.go index c878403345..60d79898cc 100644 --- a/bw761/hash_to_curve.go +++ b/ecc/bw6-761/hash_to_curve.go @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bw761 +package bw6761 import ( "math/big" - "github.com/consensys/gurvy/bw761/fp" - "github.com/consensys/gurvy/utils" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" ) // hashToFp hashes msg to count prime field elements. @@ -30,7 +30,7 @@ func hashToFp(msg, dst []byte, count int) ([]fp.Element, error) { L := 64 lenInBytes := count * L - pseudoRandomBytes, err := utils.ExpandMsgXmd(msg, dst, lenInBytes) + pseudoRandomBytes, err := ecc.ExpandMsgXmd(msg, dst, lenInBytes) if err != nil { return nil, err } diff --git a/bw761/internal/fptower/e2.go b/ecc/bw6-761/internal/fptower/e2.go similarity index 98% rename from bw761/internal/fptower/e2.go rename to ecc/bw6-761/internal/fptower/e2.go index 7c28925fad..e80e496ad5 100644 --- a/bw761/internal/fptower/e2.go +++ b/ecc/bw6-761/internal/fptower/e2.go @@ -15,7 +15,7 @@ package fptower import ( - "github.com/consensys/gurvy/bw761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" ) // E2 is a degree-two finite field extension of fp.Element diff --git a/bw761/internal/fptower/e2_test.go b/ecc/bw6-761/internal/fptower/e2_test.go similarity index 99% rename from bw761/internal/fptower/e2_test.go rename to ecc/bw6-761/internal/fptower/e2_test.go index 60b923b1b0..5c229da103 100644 --- a/bw761/internal/fptower/e2_test.go +++ b/ecc/bw6-761/internal/fptower/e2_test.go @@ -3,7 +3,7 @@ package fptower import ( "testing" - "github.com/consensys/gurvy/bw761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) diff --git a/bw761/internal/fptower/e6.go b/ecc/bw6-761/internal/fptower/e6.go similarity index 100% rename from bw761/internal/fptower/e6.go rename to ecc/bw6-761/internal/fptower/e6.go diff --git a/bw761/internal/fptower/e6_pairing.go b/ecc/bw6-761/internal/fptower/e6_pairing.go similarity index 98% rename from bw761/internal/fptower/e6_pairing.go rename to ecc/bw6-761/internal/fptower/e6_pairing.go index 1ce0c3033f..d00f0341e9 100644 --- a/bw761/internal/fptower/e6_pairing.go +++ b/ecc/bw6-761/internal/fptower/e6_pairing.go @@ -1,6 +1,6 @@ package fptower -import "github.com/consensys/gurvy/bw761/fp" +import "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" // Expt set z to x^t in E6 and return z func (z *E6) Expt(x *E6) *E6 { diff --git a/bw761/internal/fptower/e6_test.go b/ecc/bw6-761/internal/fptower/e6_test.go similarity index 99% rename from bw761/internal/fptower/e6_test.go rename to ecc/bw6-761/internal/fptower/e6_test.go index e0417ad93a..a81c97c204 100644 --- a/bw761/internal/fptower/e6_test.go +++ b/ecc/bw6-761/internal/fptower/e6_test.go @@ -4,7 +4,7 @@ import ( "math/big" "testing" - "github.com/consensys/gurvy/bw761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) diff --git a/bw761/internal/fptower/frobenius.go b/ecc/bw6-761/internal/fptower/frobenius.go similarity index 98% rename from bw761/internal/fptower/frobenius.go rename to ecc/bw6-761/internal/fptower/frobenius.go index d87465ea64..41074e7a1d 100644 --- a/bw761/internal/fptower/frobenius.go +++ b/ecc/bw6-761/internal/fptower/frobenius.go @@ -14,7 +14,7 @@ package fptower -import "github.com/consensys/gurvy/bw761/fp" +import "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" // Frobenius set z to Frobenius(x), return z func (z *E6) Frobenius(x *E6) *E6 { diff --git a/bw761/internal/fptower/generators_test.go b/ecc/bw6-761/internal/fptower/generators_test.go similarity index 94% rename from bw761/internal/fptower/generators_test.go rename to ecc/bw6-761/internal/fptower/generators_test.go index 85b69399da..5e050b92c9 100644 --- a/bw761/internal/fptower/generators_test.go +++ b/ecc/bw6-761/internal/fptower/generators_test.go @@ -3,7 +3,7 @@ package fptower import ( "crypto/rand" - "github.com/consensys/gurvy/bw761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" "github.com/leanovate/gopter" ) diff --git a/bw761/marshal.go b/ecc/bw6-761/marshal.go similarity index 96% rename from bw761/marshal.go rename to ecc/bw6-761/marshal.go index d5fb54ff8e..202b29a560 100644 --- a/bw761/marshal.go +++ b/ecc/bw6-761/marshal.go @@ -12,10 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -// Package bw761 provides efficient elliptic curve and pairing implementation for bw761 -package bw761 +// Package bw6761 provides efficient elliptic curve and pairing implementation for bw6-761 +package bw6761 import ( "encoding/binary" @@ -24,15 +24,15 @@ import ( "reflect" "sync/atomic" - "github.com/consensys/gurvy/bw761/fp" - "github.com/consensys/gurvy/bw761/fr" - "github.com/consensys/gurvy/bw761/internal/fptower" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/internal/fptower" + "github.com/consensys/gnark-crypto/internal/parallel" ) // To encode G1Affine and G2Affine points, we mask the most significant bits with these bits to specify without ambiguity // metadata needed for point (de)compression -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. @@ -48,20 +48,20 @@ const ( // SizeOfGT represents the size in bytes that a GT element need in binary form const SizeOfGT = fptower.SizeOfGT -// Encoder writes bw761 object values to an output stream +// Encoder writes bw6-761 object values to an output stream type Encoder struct { w io.Writer n int64 // written bytes raw bool // raw vs compressed encoding } -// Decoder reads bw761 object values from an inbound stream +// Decoder reads bw6-761 object values from an inbound stream type Decoder struct { r io.Reader n int64 // read bytes } -// NewDecoder returns a binary decoder supporting curve bw761 objects in both +// NewDecoder returns a binary decoder supporting curve bw6-761 objects in both // compressed and uncompressed (raw) forms func NewDecoder(r io.Reader) *Decoder { return &Decoder{r: r} @@ -72,7 +72,7 @@ func NewDecoder(r io.Reader) *Decoder { func (dec *Decoder) Decode(v interface{}) (err error) { rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr || rv.IsNil() || !rv.Elem().CanSet() { - return errors.New("bw761 decoder: unsupported type, need pointer") + return errors.New("bw6-761 decoder: unsupported type, need pointer") } // implementation note: code is a bit verbose (abusing code generation), but minimize allocations on the heap @@ -249,7 +249,7 @@ func (dec *Decoder) Decode(v interface{}) (err error) { return nil default: - return errors.New("bw761 encoder: unsupported type") + return errors.New("bw6-761 encoder: unsupported type") } } @@ -287,7 +287,7 @@ func isCompressed(msb byte) bool { return !((mData == mUncompressed) || (mData == mUncompressedInfinity)) } -// NewEncoder returns a binary encoder supporting curve bw761 objects +// NewEncoder returns a binary encoder supporting curve bw6-761 objects func NewEncoder(w io.Writer, options ...func(*Encoder)) *Encoder { // default settings enc := &Encoder{ @@ -494,7 +494,7 @@ func (p *G1Affine) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. @@ -767,7 +767,7 @@ func (p *G2Affine) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. diff --git a/bls377/marshal_test.go b/ecc/bw6-761/marshal_test.go similarity index 97% rename from bls377/marshal_test.go rename to ecc/bw6-761/marshal_test.go index 08a4c49387..913a60561e 100644 --- a/bls377/marshal_test.go +++ b/ecc/bw6-761/marshal_test.go @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bls377 +package bw6761 import ( "bytes" @@ -26,8 +26,8 @@ import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" - "github.com/consensys/gurvy/bls377/fp" - "github.com/consensys/gurvy/bls377/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" ) func TestEncoder(t *testing.T) { diff --git a/bw761/multiexp.go b/ecc/bw6-761/multiexp.go similarity index 98% rename from bw761/multiexp.go rename to ecc/bw6-761/multiexp.go index 7f8a73ce41..729d9b2cd0 100644 --- a/bw761/multiexp.go +++ b/ecc/bw6-761/multiexp.go @@ -12,20 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bw761 +package bw6761 import ( - "github.com/consensys/gurvy/bw761/fr" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/internal/parallel" "math" "runtime" "sync" ) // CPUSemaphore enables users to set optional number of CPUs the multiexp will use -// this is thread safe and can be used accross parallel calls of gurvy.MultiExp +// this is thread safe and can be used accross parallel calls of MultiExp type CPUSemaphore struct { chCpus chan struct{} // semaphore to limit number of cpus iterating through points and scalrs at the same time lock sync.Mutex @@ -160,7 +160,7 @@ func (p *G1Jac) MultiExp(points []G1Affine, scalars []fr.Element, opts ...*CPUSe // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 // * number of CPUs // * cache friendliness (which depends on the host, G1 or G2... ) - // --> for example, on BN256, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. // for each msmCX // step 1 @@ -467,7 +467,7 @@ func (p *G2Jac) MultiExp(points []G2Affine, scalars []fr.Element, opts ...*CPUSe // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 // * number of CPUs // * cache friendliness (which depends on the host, G1 or G2... ) - // --> for example, on BN256, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. // for each msmCX // step 1 diff --git a/bw761/multiexp_test.go b/ecc/bw6-761/multiexp_test.go similarity index 99% rename from bw761/multiexp_test.go rename to ecc/bw6-761/multiexp_test.go index b2247be5fc..7b4e9b9186 100644 --- a/bw761/multiexp_test.go +++ b/ecc/bw6-761/multiexp_test.go @@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT -package bw761 +package bw6761 import ( "fmt" @@ -23,7 +23,7 @@ import ( "runtime" "testing" - "github.com/consensys/gurvy/bw761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) diff --git a/bw761/pairing.go b/ecc/bw6-761/pairing.go similarity index 98% rename from bw761/pairing.go rename to ecc/bw6-761/pairing.go index 72044c8d5c..b7130b50fa 100644 --- a/bw761/pairing.go +++ b/ecc/bw6-761/pairing.go @@ -12,14 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bw761 +package bw6761 import ( "errors" "sync" - "github.com/consensys/gurvy/bw761/fp" - "github.com/consensys/gurvy/bw761/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/internal/fptower" ) // GT target group of the pairing diff --git a/bw761/pairing_test.go b/ecc/bw6-761/pairing_test.go similarity index 99% rename from bw761/pairing_test.go rename to ecc/bw6-761/pairing_test.go index faeb5f47e5..cc9a689669 100644 --- a/bw761/pairing_test.go +++ b/ecc/bw6-761/pairing_test.go @@ -12,13 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -package bw761 +package bw6761 import ( "math/big" "testing" - "github.com/consensys/gurvy/bw761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) diff --git a/ecc/bw6-761/twistededwards/eddsa/eddsa.go b/ecc/bw6-761/twistededwards/eddsa/eddsa.go new file mode 100644 index 0000000000..81413ad325 --- /dev/null +++ b/ecc/bw6-761/twistededwards/eddsa/eddsa.go @@ -0,0 +1,274 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/crypto/signature" + "github.com/consensys/gnark-crypto/ecc/bw6-761/twistededwards" + + "golang.org/x/crypto/blake2b" +) + +var errNotOnCurve = errors.New("point not on curve") + +const ( + sizeFr = 32 + 16 + sizePublicKey = sizeFr + sizeSignature = 2 * sizeFr + sizePrivateKey = 2*sizeFr + 32 +) + +// PublicKey eddsa signature object +// cf https://en.wikipedia.org/wiki/EdDSA for notation +type PublicKey struct { + A twistededwards.PointAffine +} + +// PrivateKey private key of an eddsa instance +type PrivateKey struct { + PublicKey PublicKey // copy of the associated public key + scalar [sizeFr]byte // secret scalar, in big Endian + randSrc [32]byte // source +} + +// Signature represents an eddsa signature +// cf https://en.wikipedia.org/wiki/EdDSA for notation +type Signature struct { + R twistededwards.PointAffine + S [sizeFr]byte +} + +func init() { + signature.Register(signature.EDDSA_BW6_761, GenerateKeyInterfaces) +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(r io.Reader) (PrivateKey, error) { + + c := twistededwards.GetEdwardsCurve() + + var pub PublicKey + var priv PrivateKey + + // The source of randomness and the secret scalar must come + // from 2 distincts sources. Since the scalar is the size of the + // field of definition (48 bytes), the scalar must come from a + // different digest so there is no overlap between the source of + // randomness and the scalar. + + // used for random scalar (aka private key) + seed := make([]byte, 32) + _, err := r.Read(seed) + if err != nil { + return priv, err + } + h1 := blake2b.Sum512(seed[:]) + + // used for the source of randomness when hashing the message + h2 := blake2b.Sum512(h1[:]) + for i := 0; i < 32; i++ { + priv.randSrc[i] = h2[i] + } + + // prune the key + // https://tools.ietf.org/html/rfc8032#section-5.1.5, key generation + + h1[0] &= 0xF8 + h1[sizeFr-1] &= 0x7F + h1[sizeFr-1] |= 0x40 + + // reverse first bytes because setBytes interpret stream as big endian + // but in eddsa specs s is the first 32 bytes in little endian + for i, j := 0, sizeFr; i < j; i, j = i+1, j-1 { + + h1[i], h1[j] = h1[j], h1[i] + + } + + copy(priv.scalar[:], h1[:sizeFr]) + + var bscalar big.Int + bscalar.SetBytes(priv.scalar[:]) + pub.A.ScalarMul(&c.Base, &bscalar) + + priv.PublicKey = pub + + return priv, nil +} + +// GenerateKeyInterfaces generate interfaces for the public/private key. +// This purpose of this function is to be registered in the list of signature schemes. +func GenerateKeyInterfaces(r io.Reader) (signature.Signer, error) { + priv, err := GenerateKey(r) + return &priv, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(other signature.PublicKey) bool { + bpk := pub.Bytes() + bother := other.Bytes() + return subtle.ConstantTimeCompare(bpk, bother) == 1 +} + +// Public returns the public key associated to the private key. +// From Signer interface defined in gnark/crypto/signature. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign sign a message +// Pure Eddsa version (see https://tools.ietf.org/html/rfc8032#page-8) +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + curveParams := twistededwards.GetEdwardsCurve() + + var res Signature + + // blinding factor for the private key + // blindingFactorBigInt must be the same size as the private key, + // blindingFactorBigInt = h(randomness_source||message)[:sizeFr] + var blindingFactorBigInt big.Int + + // randSrc = privKey.randSrc || msg (-> message = MSB message .. LSB message) + randSrc := make([]byte, 32+len(message)) + for i, v := range privKey.randSrc { + randSrc[i] = v + } + copy(randSrc[32:], message) + + // randBytes = H(randSrc) + blindingFactorBytes := blake2b.Sum512(randSrc[:]) // TODO ensures that the hash used to build the key and the one used here is the same + blindingFactorBigInt.SetBytes(blindingFactorBytes[:sizeFr]) + + // compute R = randScalar*Base + res.R.ScalarMul(&curveParams.Base, &blindingFactorBigInt) + if !res.R.IsOnCurve() { + return nil, errNotOnCurve + } + + // compute H(R, A, M), all parameters in data are in Montgomery form + resRX := res.R.X.Bytes() + resRY := res.R.Y.Bytes() + resAX := privKey.PublicKey.A.X.Bytes() + resAY := privKey.PublicKey.A.Y.Bytes() + sizeDataToHash := 4*sizeFr + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], resRX[:]) + copy(dataToHash[sizeFr:], resRY[:]) + copy(dataToHash[2*sizeFr:], resAX[:]) + copy(dataToHash[3*sizeFr:], resAY[:]) + copy(dataToHash[4*sizeFr:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + var hramInt big.Int + hramBin := hFunc.Sum(nil) + hramInt.SetBytes(hramBin) + + // Compute s = randScalarInt + H(R,A,M)*S + // going with big int to do ops mod curve order + var bscalar, bs big.Int + bscalar.SetBytes(privKey.scalar[:]) + bs.Mul(&hramInt, &bscalar). + Add(&bs, &blindingFactorBigInt). + Mod(&bs, &curveParams.Order) + sb := bs.Bytes() + if len(sb) < sizeFr { + offset := make([]byte, sizeFr-len(sb)) + sb = append(offset, sb...) + } + copy(res.S[:], sb[:]) + + return res.Bytes(), nil +} + +// Verify verifies an eddsa signature +func (pub *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + curveParams := twistededwards.GetEdwardsCurve() + + // verify that pubKey and R are on the curve + if !pub.A.IsOnCurve() { + return false, errNotOnCurve + } + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + // compute H(R, A, M), all parameters in data are in Montgomery form + sigRX := sig.R.X.Bytes() + sigRY := sig.R.Y.Bytes() + sigAX := pub.A.X.Bytes() + sigAY := pub.A.Y.Bytes() + sizeDataToHash := 4*sizeFr + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], sigRX[:]) + copy(dataToHash[sizeFr:], sigRY[:]) + copy(dataToHash[2*sizeFr:], sigAX[:]) + copy(dataToHash[3*sizeFr:], sigAY[:]) + copy(dataToHash[4*sizeFr:], message) + hFunc.Reset() + if _, err := hFunc.Write(dataToHash[:]); err != nil { + return false, err + } + + var hramInt big.Int + hramBin := hFunc.Sum(nil) + hramInt.SetBytes(hramBin) + + // lhs = cofactor*S*Base + var lhs twistededwards.PointAffine + var bCofactor, bs big.Int + curveParams.Cofactor.ToBigInt(&bCofactor) + bs.SetBytes(sig.S[:]) + lhs.ScalarMul(&curveParams.Base, &bs). + ScalarMul(&lhs, &bCofactor) + + if !lhs.IsOnCurve() { + return false, errNotOnCurve + } + + // rhs = cofactor*(R + H(R,A,M)*A) + var rhs twistededwards.PointAffine + rhs.ScalarMul(&pub.A, &hramInt). + Add(&rhs, &sig.R). + ScalarMul(&rhs, &bCofactor) + if !rhs.IsOnCurve() { + return false, errNotOnCurve + } + + // verifies that cofactor*S*Base=cofactor*(R + H(R,A,M)*A) + if !lhs.X.Equal(&rhs.X) || !lhs.Y.Equal(&rhs.Y) { + return false, nil + } + + return true, nil +} diff --git a/ecc/bw6-761/twistededwards/eddsa/eddsa_test.go b/ecc/bw6-761/twistededwards/eddsa/eddsa_test.go new file mode 100644 index 0000000000..78ab9f58f2 --- /dev/null +++ b/ecc/bw6-761/twistededwards/eddsa/eddsa_test.go @@ -0,0 +1,179 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/sha256" + "math/rand" + "testing" + + "github.com/consensys/gnark-crypto/crypto/hash" + "github.com/consensys/gnark-crypto/crypto/signature" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" +) + +func TestSerialization(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + privKey1, err := signature.EDDSA_BW6_761.New(r) + if err != nil { + t.Fatal(err) + } + pubKey1 := privKey1.Public() + + privKey2, err := signature.EDDSA_BW6_761.New(r) + if err != nil { + t.Fatal(err) + } + pubKey2 := privKey2.Public() + + pubKeyBin1 := pubKey1.Bytes() + pubKey2.SetBytes(pubKeyBin1) + pubKeyBin2 := pubKey2.Bytes() + if len(pubKeyBin1) != len(pubKeyBin2) { + t.Fatal("Inconistent size") + } + for i := 0; i < len(pubKeyBin1); i++ { + if pubKeyBin1[i] != pubKeyBin2[i] { + t.Fatal("Error serialize(deserialize(.))") + } + } + + privKeyBin1 := privKey1.Bytes() + privKey2.SetBytes(privKeyBin1) + privKeyBin2 := privKey2.Bytes() + if len(privKeyBin1) != len(privKeyBin2) { + t.Fatal("Inconistent size") + } + for i := 0; i < len(privKeyBin1); i++ { + if privKeyBin1[i] != privKeyBin2[i] { + t.Fatal("Error serialize(deserialize(.))") + } + } +} + +func TestEddsaMIMC(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + // create eddsa obj and sign a message + privKey, err := signature.EDDSA_BW6_761.New(r) + if err != nil { + t.Fatal(nil) + } + pubKey := privKey.Public() + hFunc := hash.MIMC_BW6_761.New("seed") + + var frMsg fr.Element + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035978") + msgBin := frMsg.Bytes() + signature, err := privKey.Sign(msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + + // verifies correct msg + res, err := pubKey.Verify(signature, msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + if !res { + t.Fatal("Verifiy correct signature should return true") + } + + // verifies wrong msg + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035979") + msgBin = frMsg.Bytes() + res, err = pubKey.Verify(signature, msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + if res { + t.Fatal("Verfiy wrong signature should be false") + } + +} + +func TestEddsaSHA256(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + hFunc := sha256.New() + + // create eddsa obj and sign a message + // create eddsa obj and sign a message + + privKey, err := signature.EDDSA_BW6_761.New(r) + pubKey := privKey.Public() + if err != nil { + t.Fatal(err) + } + + signature, err := privKey.Sign([]byte("message"), hFunc) + if err != nil { + t.Fatal(err) + } + + // verifies correct msg + res, err := pubKey.Verify(signature, []byte("message"), hFunc) + if err != nil { + t.Fatal(err) + } + if !res { + t.Fatal("Verifiy correct signature should return true") + } + + // verifies wrong msg + res, err = pubKey.Verify(signature, []byte("wrong_message"), hFunc) + if err != nil { + t.Fatal(err) + } + if res { + t.Fatal("Verfiy wrong signature should be false") + } + +} + +// benchmarks + +func BenchmarkVerify(b *testing.B) { + + src := rand.NewSource(0) + r := rand.New(src) + + hFunc := hash.MIMC_BW6_761.New("seed") + + // create eddsa obj and sign a message + privKey, err := signature.EDDSA_BW6_761.New(r) + pubKey := privKey.Public() + if err != nil { + b.Fatal(err) + } + var frMsg fr.Element + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035978") + msgBin := frMsg.Bytes() + signature, _ := privKey.Sign(msgBin[:], hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + pubKey.Verify(signature, msgBin[:], hFunc) + } +} diff --git a/ecc/bw6-761/twistededwards/eddsa/marshal.go b/ecc/bw6-761/twistededwards/eddsa/marshal.go new file mode 100644 index 0000000000..97267823e1 --- /dev/null +++ b/ecc/bw6-761/twistededwards/eddsa/marshal.go @@ -0,0 +1,129 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by consensys/gnark-crypto DO NOT EDIT + +package eddsa + +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of pk +// as x||y where x, y are the coordinates of the point +// on the twisted Edwards as big endian integers. +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the twisted Edwards. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !pk.A.IsOnCurve() { + return n, errNotOnCurve + } + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar||randSrc +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:2*sizeFr], privKey.scalar[:]) + subtle.ConstantTimeCopy(1, res[2*sizeFr:], privKey.randSrc[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar||randSrc +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !privKey.PublicKey.A.IsOnCurve() { + return n, errNotOnCurve + } + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, privKey.randSrc[:], buf[2*sizeFr:]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 3*sizeFr x||y||s where +// * x, y are the coordinates of a point on the twisted +// Edwards represented in big endian +// * s=r+h(r,a,m) mod l, the Hasse bound guarantess that +// s is smaller than sizeFr (in particular it is supposed +// s is NOT blinded) +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + sigRBin := sig.R.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], sigRBin[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as x||y||s where +// * x,y are the coordinates of a point on the twisted +// Edwards represented in big endian +// * s=r+h(r,a,m) mod l, the Hasse bound guarantess that +// s is smaller than sizeFr (in particular it is supposed +// s is NOT blinded) +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + if _, err := sig.R.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !sig.R.IsOnCurve() { + return n, errNotOnCurve + } + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} diff --git a/bls377/twistededwards/point.go b/ecc/bw6-761/twistededwards/point.go similarity index 91% rename from bls377/twistededwards/point.go rename to ecc/bw6-761/twistededwards/point.go index b61bc44b75..650048cc2c 100644 --- a/bls377/twistededwards/point.go +++ b/ecc/bw6-761/twistededwards/point.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Code generated by gurvy DO NOT EDIT +// Code generated by consensys/gnark-crypto DO NOT EDIT package twistededwards @@ -22,7 +22,7 @@ import ( "math/big" "math/bits" - "github.com/consensys/gurvy/bls377/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" ) // PointAffine point on a twisted Edwards curve @@ -43,12 +43,11 @@ const ( mCompressedPositive = 0x00 mUnmask = 0x7f - // size in byte of (x,y) + // size in byte of a compressed point (point.Y --> fr.Element) sizePointCompressed = fr.Limbs * 8 ) -// Bytes returns the point as bytes array x||y, where -// x and y are in big endian. +// Bytes returns the compressed point as a byte array // Follows https://tools.ietf.org/html/rfc8032#section-3.1, // as the twisted Edwards implementation is primarily used // for eddsa. @@ -91,15 +90,11 @@ func computeX(y *fr.Element) (x fr.Element) { return } -// SetBytes sets p from the buf, where bug is interpreted -// as a sizePointCompressed+ byte slice, where the first 32 bytes -// are interpreted as x in big endian, the next 32 bytes are -// interpreted as y in big endian. Returns the number of read bytes -// and an error if the buffer is too short. -// Returns the number of bytes read. -// Follows https://tools.ietf.org/html/rfc8032#section-3.1, -// as the twisted Edwards implementation is primarily used -// for eddsa. +// SetBytes sets p from buf +// len(buf) >= sizePointCompressed +// buf contains the Y coordinate masked with a parity bit to recompute the X coordinate +// from the curve equation. See Bytes() and https://tools.ietf.org/html/rfc8032#section-3.1 +// Returns the number of read bytes and an error if the buffer is too short. func (p *PointAffine) SetBytes(buf []byte) (int, error) { if len(buf) < sizePointCompressed { @@ -124,7 +119,7 @@ func (p *PointAffine) SetBytes(buf []byte) (int, error) { } } - return 32, nil + return sizePointCompressed, nil } // Unmarshal alias to SetBytes() diff --git a/bw761/twistededwards/twistededwards.go b/ecc/bw6-761/twistededwards/twistededwards.go similarity index 90% rename from bw761/twistededwards/twistededwards.go rename to ecc/bw6-761/twistededwards/twistededwards.go index 7780e7af4c..9c497544d0 100644 --- a/bw761/twistededwards/twistededwards.go +++ b/ecc/bw6-761/twistededwards/twistededwards.go @@ -3,7 +3,7 @@ package twistededwards import ( "math/big" - "github.com/consensys/gurvy/bw761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" ) // CurveParams curve parameters: ax^2 + y^2 = 1 + d*x^2*y^2 @@ -16,7 +16,7 @@ type CurveParams struct { var edwards CurveParams -// GetEdwardsCurve returns the twisted Edwards curve on BN256's Fr +// GetEdwardsCurve returns the twisted Edwards curve on BN254's Fr func GetEdwardsCurve() CurveParams { // copy to keep Order private var res CurveParams diff --git a/bw761/twistededwards/twistededwards_test.go b/ecc/bw6-761/twistededwards/twistededwards_test.go similarity index 99% rename from bw761/twistededwards/twistededwards_test.go rename to ecc/bw6-761/twistededwards/twistededwards_test.go index 984124c41b..9afaae4f79 100644 --- a/bw761/twistededwards/twistededwards_test.go +++ b/ecc/bw6-761/twistededwards/twistededwards_test.go @@ -20,7 +20,7 @@ import ( "math/big" "testing" - "github.com/consensys/gurvy/bw761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" ) func TestMarshal(t *testing.T) { diff --git a/bw761/utils_test.go b/ecc/bw6-761/utils_test.go similarity index 87% rename from bw761/utils_test.go rename to ecc/bw6-761/utils_test.go index f5e0613dbf..17d4f52621 100644 --- a/bw761/utils_test.go +++ b/ecc/bw6-761/utils_test.go @@ -1,11 +1,11 @@ -package bw761 +package bw6761 import ( "math/rand" - "github.com/consensys/gurvy/bw761/fp" - "github.com/consensys/gurvy/bw761/fr" - "github.com/consensys/gurvy/bw761/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fp" + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" + "github.com/consensys/gnark-crypto/ecc/bw6-761/internal/fptower" "github.com/leanovate/gopter" ) diff --git a/gurvy.go b/ecc/ecc.go similarity index 65% rename from gurvy.go rename to ecc/ecc.go index a6dd2009f8..f6afa3159c 100644 --- a/gurvy.go +++ b/ecc/ecc.go @@ -14,17 +14,17 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Package gurvy is an elliptic curve (+pairing) library. It currently expose efficient implementations for -// bls381, bls377, bn256 and bw761 -package gurvy +// Package ecc is an elliptic curve (+pairing) library. +// Provides implementation for bls12-381, bls12-377, bn254, bw6-761 and their twisted edwards "companion curves" +package ecc // do not modify the order of this enum const ( UNKNOWN ID = iota - BLS377 - BLS381 - BN256 - BW761 + BN254 + BLS12_377 + BLS12_381 + BW6_761 ) // ID represent a unique ID for a curve @@ -32,15 +32,15 @@ type ID uint16 func (id ID) String() string { switch id { - case BLS377: - return "bls377" - case BLS381: - return "bls381" - case BN256: - return "bn256" - case BW761: - return "bw761" + case BLS12_377: + return "bls12_377" + case BLS12_381: + return "bls12_381" + case BN254: + return "bn254" + case BW6_761: + return "bw6_761" default: - panic("unimplemented curve ID") + panic("unimplemented ecc ID") } } diff --git a/ecc/ecc.md b/ecc/ecc.md new file mode 100644 index 0000000000..11aec02698 --- /dev/null +++ b/ecc/ecc.md @@ -0,0 +1,13 @@ +## Supported curves + +* BLS12-381 (Zcash) +* BN254 (Ethereum) +* BLS12-377 (ZEXE) +* BW6-761 (EC supporting pairing on BLS12-377 field of definition) + +### Twisted edwards curves + +Each of these curve has a `twistededwards` sub-package with its companion curve. Also known as [Jubjub](https://z.cash/technology/jubjub/) (BLS12-381) or [Baby-Jubjub](https://iden3-docs.readthedocs.io/en/latest/_downloads/33717d75ab84e11313cc0d8a090b636f/Baby-Jubjub.pdf) (BN254). + +They are of particular interest as they allow efficient elliptic curve cryptography inside zkSNARK circuits. + diff --git a/utils/utils.go b/ecc/utils.go similarity index 63% rename from utils/utils.go rename to ecc/utils.go index 20a838dc40..44ecf200c3 100644 --- a/utils/utils.go +++ b/ecc/utils.go @@ -1,6 +1,8 @@ -package utils +package ecc import ( + "crypto/sha256" + "errors" "math/big" ) @@ -166,3 +168,84 @@ func getVector(l *Lattice, a, b *big.Int) [2]big.Int { res[1].Mul(a, &l.V1[1]).Add(&res[1], &tmp) return res } + +// ExpandMsgXmd expands msg to a slice of lenInBytes bytes. +// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5 +// https://tools.ietf.org/html/rfc8017#section-4.1 (I2OSP/O2ISP) +func ExpandMsgXmd(msg, dst []byte, lenInBytes int) ([]byte, error) { + + h := sha256.New() + ell := (lenInBytes + h.Size() - 1) / h.Size() // ceil(len_in_bytes / b_in_bytes) + if ell > 255 { + return nil, errors.New("invalid lenInBytes") + } + if len(dst) > 255 { + return nil, errors.New("invalid domain size (>255 bytes)") + } + sizeDomain := uint8(len(dst)) + + // Z_pad = I2OSP(0, r_in_bytes) + // l_i_b_str = I2OSP(len_in_bytes, 2) + // DST_prime = I2OSP(len(DST), 1) || DST + // b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime) + h.Reset() + if _, err := h.Write(make([]byte, h.BlockSize())); err != nil { + return nil, err + } + if _, err := h.Write(msg); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(lenInBytes >> 8), uint8(lenInBytes), uint8(0)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b0 := h.Sum(nil) + + // b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) + h.Reset() + if _, err := h.Write(b0); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(1)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b1 := h.Sum(nil) + + res := make([]byte, lenInBytes) + copy(res[:h.Size()], b1) + + for i := 2; i <= ell; i++ { + // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) + h.Reset() + strxor := make([]byte, h.Size()) + for j := 0; j < h.Size(); j++ { + strxor[j] = b0[j] ^ b1[j] + } + if _, err := h.Write(strxor); err != nil { + return nil, err + } + if _, err := h.Write([]byte{uint8(i)}); err != nil { + return nil, err + } + if _, err := h.Write(dst); err != nil { + return nil, err + } + if _, err := h.Write([]byte{sizeDomain}); err != nil { + return nil, err + } + b1 = h.Sum(nil) + copy(res[h.Size()*(i-1):h.Size()*i], b1) + } + return res, nil +} diff --git a/utils/utils_test.go b/ecc/utils_test.go similarity index 98% rename from utils/utils_test.go rename to ecc/utils_test.go index b9432dbd67..ff4badeb58 100644 --- a/utils/utils_test.go +++ b/ecc/utils_test.go @@ -1,4 +1,4 @@ -package utils +package ecc import ( "math/big" diff --git a/field/asm/amd64/asm_macros.go b/field/asm/amd64/asm_macros.go new file mode 100644 index 0000000000..bd27ab905f --- /dev/null +++ b/field/asm/amd64/asm_macros.go @@ -0,0 +1,259 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package amd64 + +import ( + "bytes" + "fmt" + "text/template" + + "github.com/consensys/bavard/amd64" +) + +// LabelRegisters write comment with friendler name to registers +func (f *FFAmd64) LabelRegisters(name string, r ...amd64.Register) { + switch len(r) { + case 0: + return + case 1: + f.Comment(fmt.Sprintf("%s -> %s", name, string(r[0]))) + default: + for i := 0; i < len(r); i++ { + f.Comment(fmt.Sprintf("%s[%d] -> %s", name, i, string(r[i]))) + } + } + // f.WriteLn("") +} + +func (f *FFAmd64) ReduceElement(t, scratch []amd64.Register) { + if len(t) != len(scratch) { + panic("invalid call") + } + + const tmplReduce = `// reduce element({{- range $i, $a := .A}}{{$a}}{{- if ne $.Last $i}},{{ end}}{{- end}}) using temp registers ({{- range $i, $b := .B}}{{$b}}{{- if ne $.Last $i}},{{ end}}{{- end}}) + REDUCE({{- range $i, $a := .A}}{{$a}},{{- end}} + {{- range $i, $b := .B}}{{$b}}{{- if ne $.Last $i}},{{ end}}{{- end}})` + + var buf bytes.Buffer + err := template.Must(template.New(""). + Parse(tmplReduce)).Execute(&buf, struct { + A, B []amd64.Register + Last int + }{t, scratch, len(scratch) - 1}) + + if err != nil { + panic(err) + } + + f.WriteLn(buf.String()) + f.WriteLn("") +} + +// TODO @gbotrel: figure out if interleaving MOVQ and SUBQ or CMOVQ and MOVQ instructions makes sense +const tmplDefines = ` + +// modulus q +{{- range $i, $w := .Q}} +DATA q<>+{{mul $i 8}}(SB)/8, {{imm $w}} +{{- end}} +GLOBL q<>(SB), (RODATA+NOPTR), ${{mul 8 $.NbWords}} + +// qInv0 q'[0] +DATA qInv0<>(SB)/8, {{$qinv0 := index .QInverse 0}}{{imm $qinv0}} +GLOBL qInv0<>(SB), (RODATA+NOPTR), $8 + +#define REDUCE( {{- range $i := .NbWordsIndexesFull}}ra{{$i}},{{- end}} + {{- range $i := .NbWordsIndexesFull}}rb{{$i}}{{- if ne $.NbWordsLastIndex $i}},{{- end}}{{- end}}) \ + MOVQ ra0, rb0; \ + SUBQ q<>(SB), ra0; \ + {{- range $i := .NbWordsIndexesNoZero}} + MOVQ ra{{$i}}, rb{{$i}}; \ + SBBQ q<>+{{mul $i 8}}(SB), ra{{$i}}; \ + {{- end}} + {{- range $i := .NbWordsIndexesFull}} + CMOVQCS rb{{$i}}, ra{{$i}}; \ + {{- end}} +` + +func (f *FFAmd64) GenerateDefines() { + tmpl := template.Must(template.New(""). + Funcs(helpers()). + Parse(tmplDefines)) + + // execute template + var buf bytes.Buffer + if err := tmpl.Execute(&buf, f); err != nil { + panic(err) + } + + f.WriteLn(buf.String()) +} + +func (f *FFAmd64) Mov(i1, i2 interface{}, offsets ...int) { + var o1, o2 int + if len(offsets) >= 1 { + o1 = offsets[0] + if len(offsets) >= 2 { + o2 = offsets[1] + } + } + switch c1 := i1.(type) { + case []uint64: + switch c2 := i2.(type) { + default: + panic("unsupported") + case []amd64.Register: + for i := 0; i < f.NbWords; i++ { + f.MOVQ(c1[i+o1], c2[i+o2]) + } + } + case amd64.Register: + switch c2 := i2.(type) { + case amd64.Register: + for i := 0; i < f.NbWords; i++ { + f.MOVQ(c1.At(i+o1), c2.At(i+o2)) + } + case []amd64.Register: + for i := 0; i < f.NbWords; i++ { + f.MOVQ(c1.At(i+o1), c2[i+o2]) + } + default: + panic("unsupported") + } + case []amd64.Register: + switch c2 := i2.(type) { + case amd64.Register: + for i := 0; i < f.NbWords; i++ { + f.MOVQ(c1[i+o1], c2.At(i+o2)) + } + case []amd64.Register: + // f.copyElement(c1[o1:], c2[o2:]) + for i := 0; i < f.NbWords; i++ { + f.MOVQ(c1[i+o1], c2[i+o2]) + } + default: + panic("unsupported") + } + default: + panic("unsupported") + } + +} + +func (f *FFAmd64) Add(i1, i2 interface{}, offsets ...int) { + var o1, o2 int + if len(offsets) >= 1 { + o1 = offsets[0] + if len(offsets) >= 2 { + o2 = offsets[1] + } + } + switch c1 := i1.(type) { + + case amd64.Register: + switch c2 := i2.(type) { + default: + panic("unsupported") + case []amd64.Register: + for i := 0; i < f.NbWords; i++ { + if i == 0 { + f.ADDQ(c1.At(i+o1), c2[i+o2]) + } else { + f.ADCQ(c1.At(i+o1), c2[i+o2]) + } + } + } + case []amd64.Register: + switch c2 := i2.(type) { + default: + panic("unsupported") + case []amd64.Register: + for i := 0; i < f.NbWords; i++ { + if i == 0 { + f.ADDQ(c1[i+o1], c2[i+o2]) + } else { + f.ADCQ(c1[i+o1], c2[i+o2]) + } + } + } + default: + panic("unsupported") + } +} + +func (f *FFAmd64) Sub(i1, i2 interface{}, offsets ...int) { + var o1, o2 int + if len(offsets) >= 1 { + o1 = offsets[0] + if len(offsets) >= 2 { + o2 = offsets[1] + } + } + switch c1 := i1.(type) { + + case amd64.Register: + switch c2 := i2.(type) { + default: + panic("unsupported") + case []amd64.Register: + for i := 0; i < f.NbWords; i++ { + if i == 0 { + f.SUBQ(c1.At(i+o1), c2[i+o2]) + } else { + f.SBBQ(c1.At(i+o1), c2[i+o2]) + } + } + } + case []amd64.Register: + switch c2 := i2.(type) { + default: + panic("unsupported") + case []amd64.Register: + for i := 0; i < f.NbWords; i++ { + if i == 0 { + f.SUBQ(c1[i+o1], c2[i+o2]) + } else { + f.SBBQ(c1[i+o1], c2[i+o2]) + } + } + } + default: + panic("unsupported") + } +} + +// Template helpers (txt/template) +func helpers() template.FuncMap { + // functions used in template + return template.FuncMap{ + "mul": mul, + "imm": imm, + } +} + +func mul(a, b int) int { + return a * b +} + +func imm(t uint64) string { + switch t { + case 0: + return "$0" + case 1: + return "$1" + default: + return fmt.Sprintf("$%#016x", t) + } +} diff --git a/field/asm/amd64/build.go b/field/asm/amd64/build.go new file mode 100644 index 0000000000..70448df77c --- /dev/null +++ b/field/asm/amd64/build.go @@ -0,0 +1,206 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package amd64 contains syntactic sugar to generate amd64 assembly code in goff +package amd64 + +import ( + "fmt" + "io" + "strings" + + "github.com/consensys/bavard" + + "github.com/consensys/bavard/amd64" + "github.com/consensys/gnark-crypto/field" +) + +const SmallModulus = 6 + +func NewFFAmd64(w io.Writer, F *field.Field) *FFAmd64 { + return &FFAmd64{F, amd64.NewAmd64(w), 0, 0} +} + +type FFAmd64 struct { + *field.Field + *amd64.Amd64 + nbElementsOnStack int + maxOnStack int +} + +func (f *FFAmd64) StackSize(maxNbRegistersNeeded, nbRegistersReserved, minStackSize int) int { + got := amd64.NbRegisters - nbRegistersReserved + r := got - maxNbRegistersNeeded + if r >= 0 { + return minStackSize + } + r *= -8 + return max(r, minStackSize) +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} + +func (f *FFAmd64) AssertCleanStack(reservedStackSize, minStackSize int) { + if f.nbElementsOnStack != 0 { + panic("missing f.Push stack elements") + } + if reservedStackSize < minStackSize { + panic("invalid minStackSize or reservedStackSize") + } + usedStackSize := f.maxOnStack * 8 + if usedStackSize > reservedStackSize { + panic("using more stack size than reserved") + } else if max(usedStackSize, minStackSize) < reservedStackSize { + // this panic is for dev purposes as this may be by design for aligment + panic("reserved more stack size than needed") + } + + f.maxOnStack = 0 +} + +func (f *FFAmd64) Push(registers *amd64.Registers, rIn ...amd64.Register) { + for _, r := range rIn { + if strings.HasPrefix(string(r), "s") { + // it's on the stack, decrease the offset + f.nbElementsOnStack-- + continue + } + registers.Push(r) + } +} + +func (f *FFAmd64) Pop(registers *amd64.Registers, forceStack ...bool) amd64.Register { + if registers.Available() >= 1 && !(len(forceStack) > 0 && forceStack[0]) { + return registers.Pop() + } + r := amd64.Register(fmt.Sprintf("s%d-%d(SP)", f.nbElementsOnStack, 8+f.nbElementsOnStack*8)) + f.nbElementsOnStack++ + if f.nbElementsOnStack > f.maxOnStack { + f.maxOnStack = f.nbElementsOnStack + } + return r +} + +func (f *FFAmd64) PopN(registers *amd64.Registers, forceStack ...bool) []amd64.Register { + if len(forceStack) > 0 && forceStack[0] { + nbStack := f.NbWords + var u []amd64.Register + + for i := f.nbElementsOnStack; i < nbStack+f.nbElementsOnStack; i++ { + u = append(u, amd64.Register(fmt.Sprintf("s%d-%d(SP)", i, 8+i*8))) + } + f.nbElementsOnStack += nbStack + if f.nbElementsOnStack > f.maxOnStack { + f.maxOnStack = f.nbElementsOnStack + } + return u + } + if registers.Available() >= f.NbWords { + return registers.PopN(f.NbWords) + } + nbStack := f.NbWords - registers.Available() + u := registers.PopN(registers.Available()) + + for i := f.nbElementsOnStack; i < nbStack+f.nbElementsOnStack; i++ { + u = append(u, amd64.Register(fmt.Sprintf("s%d-%d(SP)", i, 8+i*8))) + } + f.nbElementsOnStack += nbStack + if f.nbElementsOnStack > f.maxOnStack { + f.maxOnStack = f.nbElementsOnStack + } + return u +} + +func (f *FFAmd64) qAt(index int) string { + return fmt.Sprintf("q<>+%d(SB)", index*8) +} + +func (f *FFAmd64) qInv0() string { + return "qInv0<>(SB)" +} + +// Generate generates assembly code for the base field provided to goff +// see internal/templates/ops* +func Generate(w io.Writer, F *field.Field) error { + f := NewFFAmd64(w, F) + f.WriteLn(bavard.Apache2Header("ConsenSys Software Inc.", 2020)) + + f.WriteLn("#include \"textflag.h\"") + f.WriteLn("#include \"funcdata.h\"") + f.WriteLn("") + + f.GenerateDefines() + + // add + f.generateAdd() + + // sub + f.generateSub() + + // double + f.generateDouble() + + // neg + f.generateNeg() + + // reduce + f.generateReduce() + + // mul by constants + f.generateMulBy3() + f.generateMulBy5() + + return nil +} + +func GenerateMul(w io.Writer, F *field.Field) error { + f := NewFFAmd64(w, F) + f.WriteLn(bavard.Apache2Header("ConsenSys Software Inc.", 2020)) + + f.WriteLn("#include \"textflag.h\"") + f.WriteLn("#include \"funcdata.h\"") + f.WriteLn("") + f.GenerateDefines() + + // mul + f.generateMul(false) + + // from mont + f.generateFromMont(false) + + return nil +} + +func GenerateMulADX(w io.Writer, F *field.Field) error { + f := NewFFAmd64(w, F) + f.WriteLn(bavard.Apache2Header("ConsenSys Software Inc.", 2020)) + + f.WriteLn("#include \"textflag.h\"") + f.WriteLn("#include \"funcdata.h\"") + f.WriteLn("") + f.GenerateDefines() + + // mul + f.generateMul(true) + + // from mont + f.generateFromMont(true) + + return nil +} diff --git a/field/asm/amd64/element_add.go b/field/asm/amd64/element_add.go new file mode 100644 index 0000000000..eda00f073b --- /dev/null +++ b/field/asm/amd64/element_add.go @@ -0,0 +1,48 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package amd64 + +func (f *FFAmd64) generateAdd() { + f.Comment("add(res, x, y *Element)") + + stackSize := f.StackSize(f.NbWords*2, 0, 0) + registers := f.FnHeader("add", stackSize, 24) + defer f.AssertCleanStack(stackSize, 0) + + // registers + x := registers.Pop() + y := registers.Pop() + t := registers.PopN(f.NbWords) + + // t = x + f.MOVQ("x+8(FP)", x) + f.Mov(x, t) + registers.Push(x) + + // t = t + y = x + y + f.MOVQ("y+16(FP)", y) + f.Add(y, t) + registers.Push(y) + + // reduce t + f.Reduce(®isters, t) + + r := registers.Pop() + f.MOVQ("res+0(FP)", r) + f.Mov(t, r) + + f.RET() + +} diff --git a/field/asm/amd64/element_double.go b/field/asm/amd64/element_double.go new file mode 100644 index 0000000000..751bb9ce99 --- /dev/null +++ b/field/asm/amd64/element_double.go @@ -0,0 +1,40 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package amd64 + +func (f *FFAmd64) generateDouble() { + // func header + f.Comment("double(res, x *Element)") + stackSize := f.StackSize(f.NbWords*2, 0, 0) + registers := f.FnHeader("double", stackSize, 16) + defer f.AssertCleanStack(stackSize, 0) + + // registers + x := registers.Pop() + t := registers.PopN(f.NbWords) + + f.MOVQ("x+8(FP)", x) + f.Mov(x, t) + registers.Push(x) + + f.Add(t, t) + f.Reduce(®isters, t) + + r := registers.Pop() + f.MOVQ("res+0(FP)", r) + f.Mov(t, r) + + f.RET() +} diff --git a/field/asm/amd64/element_frommont.go b/field/asm/amd64/element_frommont.go new file mode 100644 index 0000000000..967a8b82e3 --- /dev/null +++ b/field/asm/amd64/element_frommont.go @@ -0,0 +1,115 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package amd64 + +import ( + "fmt" + + "github.com/consensys/bavard/amd64" +) + +func (f *FFAmd64) generateFromMont(forceADX bool) { + const argSize = 8 + minStackSize := argSize + if forceADX { + minStackSize = 0 + } + stackSize := f.StackSize(f.NbWords*2, 2, minStackSize) + registers := f.FnHeader("fromMont", stackSize, argSize, amd64.DX, amd64.AX) + defer f.AssertCleanStack(stackSize, minStackSize) + + if stackSize > 0 { + f.WriteLn("NO_LOCAL_POINTERS") + } + f.WriteLn(` + // the algorithm is described here + // https://hackmd.io/@zkteam/modular_multiplication + // when y = 1 we have: + // for i=0 to N-1 + // t[i] = x[i] + // for i=0 to N-1 + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C`) + + noAdx := f.NewLabel() + if !forceADX { + // check ADX instruction support + f.CMPB("·supportAdx(SB)", 1) + f.JNE(noAdx) + } + + // registers + t := registers.PopN(f.NbWords) + + f.MOVQ("res+0(FP)", amd64.DX) + + // for i=0 to N-1 + // t[i] = a[i] + f.Mov(amd64.DX, t) + + for i := 0; i < f.NbWords; i++ { + + f.XORQ(amd64.DX, amd64.DX) + + // m := t[0]*q'[0] mod W + f.Comment("m := t[0]*q'[0] mod W") + m := amd64.DX + f.MOVQ(f.qInv0(), m) + f.IMULQ(t[0], m) + + // clear the carry flags + f.XORQ(amd64.AX, amd64.AX) + + // C,_ := t[0] + m*q[0] + f.Comment("C,_ := t[0] + m*q[0]") + + f.MULXQ(f.qAt(0), amd64.AX, amd64.BP) + f.ADCXQ(t[0], amd64.AX) + f.MOVQ(amd64.BP, t[0]) + + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + for j := 1; j < f.NbWords; j++ { + f.Comment(fmt.Sprintf("(C,t[%[1]d]) := t[%[2]d] + m*q[%[2]d] + C", j-1, j)) + f.ADCXQ(t[j], t[j-1]) + f.MULXQ(f.qAt(j), amd64.AX, t[j]) + f.ADOXQ(amd64.AX, t[j-1]) + } + f.MOVQ(0, amd64.AX) + f.ADCXQ(amd64.AX, t[f.NbWordsLastIndex]) + f.ADOXQ(amd64.AX, t[f.NbWordsLastIndex]) + + } + + // --------------------------------------------------------------------------------------------- + // reduce + f.Reduce(®isters, t) + f.MOVQ("res+0(FP)", amd64.AX) + f.Mov(t, amd64.AX) + f.RET() + + // No adx + if !forceADX { + f.LABEL(noAdx) + f.MOVQ("res+0(FP)", amd64.AX) + f.MOVQ(amd64.AX, "(SP)") + f.WriteLn("CALL ·_fromMontGeneric(SB)") + f.RET() + } + +} diff --git a/field/asm/amd64/element_mul.go b/field/asm/amd64/element_mul.go new file mode 100644 index 0000000000..d58d19e187 --- /dev/null +++ b/field/asm/amd64/element_mul.go @@ -0,0 +1,327 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package amd64 + +import ( + "fmt" + + "github.com/consensys/bavard/amd64" +) + +// MulADX uses AX, DX and BP +// sets x * y into t, without modular reduction +// x() will have more accesses than y() +// (caller should store x in registers, if possible) +// if no (tmp) register is available, this uses one PUSH/POP on the stack in the hot loop. +func (f *FFAmd64) MulADX(registers *amd64.Registers, x, y func(int) string, t []amd64.Register) []amd64.Register { + // registers + var tr amd64.Register // temporary register + A := amd64.BP + + hasFreeRegister := registers.Available() > 0 + if hasFreeRegister { + tr = registers.Pop() + } else { + tr = A + } + + f.LabelRegisters("A", A) + f.LabelRegisters("t", t...) + + for i := 0; i < f.NbWords; i++ { + f.Comment("clear the flags") + f.XORQ(amd64.AX, amd64.AX) + + f.MOVQ(y(i), amd64.DX) + + // for j=0 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + if i == 0 { + for j := 0; j < f.NbWords; j++ { + f.Comment(fmt.Sprintf("(A,t[%[1]d]) := x[%[1]d]*y[%[2]d] + A", j, i)) + + if j == 0 { + f.MULXQ(x(j), t[j], t[j+1]) + } else { + highBits := A + if j != f.NbWordsLastIndex { + highBits = t[j+1] + } + f.MULXQ(x(j), amd64.AX, highBits) + f.ADOXQ(amd64.AX, t[j]) + } + } + } else { + for j := 0; j < f.NbWords; j++ { + f.Comment(fmt.Sprintf("(A,t[%[1]d]) := t[%[1]d] + x[%[1]d]*y[%[2]d] + A", j, i)) + + if j != 0 { + f.ADCXQ(A, t[j]) + } + f.MULXQ(x(j), amd64.AX, A) + f.ADOXQ(amd64.AX, t[j]) + } + } + + f.Comment("A += carries from ADCXQ and ADOXQ") + f.MOVQ(0, amd64.AX) + if i != 0 { + f.ADCXQ(amd64.AX, A) + } + f.ADOXQ(amd64.AX, A) + + if !hasFreeRegister { + f.PUSHQ(A) + } + + // m := t[0]*q'[0] mod W + f.Comment("m := t[0]*q'[0] mod W") + m := amd64.DX + // f.MOVQ(t[0], m) + // f.MULXQ(f.qInv0(), m, amd64.AX) + f.MOVQ(f.qInv0(), m) + f.IMULQ(t[0], m) + + // clear the carry flags + f.Comment("clear the flags") + f.XORQ(amd64.AX, amd64.AX) + + // C,_ := t[0] + m*q[0] + f.Comment("C,_ := t[0] + m*q[0]") + + f.MULXQ(f.qAt(0), amd64.AX, tr) + f.ADCXQ(t[0], amd64.AX) + f.MOVQ(tr, t[0]) + + if !hasFreeRegister { + f.POPQ(A) + } + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + for j := 1; j < f.NbWords; j++ { + f.Comment(fmt.Sprintf("(C,t[%[1]d]) := t[%[2]d] + m*q[%[2]d] + C", j-1, j)) + f.ADCXQ(t[j], t[j-1]) + f.MULXQ(f.qAt(j), amd64.AX, t[j]) + f.ADOXQ(amd64.AX, t[j-1]) + } + + f.Comment(fmt.Sprintf("t[%d] = C + A", f.NbWordsLastIndex)) + f.MOVQ(0, amd64.AX) + f.ADCXQ(amd64.AX, t[f.NbWordsLastIndex]) + f.ADOXQ(A, t[f.NbWordsLastIndex]) + + } + + if hasFreeRegister { + registers.Push(tr) + } + + return t +} + +func (f *FFAmd64) generateMul(forceADX bool) { + f.Comment("mul(res, x, y *Element)") + + const argSize = 3 * 8 + minStackSize := argSize + if forceADX { + minStackSize = 0 + } + stackSize := f.StackSize(f.NbWords*2, 2, minStackSize) + registers := f.FnHeader("mul", stackSize, argSize, amd64.DX, amd64.AX) + defer f.AssertCleanStack(stackSize, minStackSize) + + f.WriteLn(` + // the algorithm is described here + // https://hackmd.io/@zkteam/modular_multiplication + // however, to benefit from the ADCX and ADOX carry chains + // we split the inner loops in 2: + // for i=0 to N-1 + // for j=0 to N-1 + // (A,t[j]) := t[j] + x[j]*y[i] + A + // m := t[0]*q'[0] mod W + // C,_ := t[0] + m*q[0] + // for j=1 to N-1 + // (C,t[j-1]) := t[j] + m*q[j] + C + // t[N-1] = C + A + `) + if stackSize > 0 { + f.WriteLn("NO_LOCAL_POINTERS") + } + + noAdx := f.NewLabel() + + if !forceADX { + // check ADX instruction support + f.CMPB("·supportAdx(SB)", 1) + f.JNE(noAdx) + } + + { + // we need to access x and y words, per index + var xat, yat func(int) string + var gc func() + + // we need NbWords registers for t, plus optionally one for tmp register in mulADX if we want to avoid PUSH/POP + nbRegisters := registers.Available() + if nbRegisters < f.NbWords { + panic("not enough registers, not supported.") + } + + t := registers.PopN(f.NbWords) + nbRegisters = registers.Available() + switch nbRegisters { + case 0: + // y is access through use of AX/DX + yat = func(i int) string { + y := amd64.AX + f.MOVQ("y+16(FP)", y) + return y.At(i) + } + + // we move x on the stack. + f.MOVQ("x+8(FP)", amd64.AX) + _x := f.PopN(®isters, true) + f.LabelRegisters("x", _x...) + f.Mov(amd64.AX, t) + f.Mov(t, _x) + xat = func(i int) string { + return string(_x[i]) + } + gc = func() { + f.Push(®isters, _x...) + } + case 1: + // y is access through use of AX/DX + yat = func(i int) string { + y := amd64.AX + f.MOVQ("y+16(FP)", y) + return y.At(i) + } + // x uses the register + x := registers.Pop() + f.MOVQ("x+8(FP)", x) + xat = func(i int) string { + return x.At(i) + } + gc = func() { + registers.Push(x) + } + case 2, 3: + // x, y uses registers + x := registers.Pop() + y := registers.Pop() + + f.MOVQ("x+8(FP)", x) + f.MOVQ("y+16(FP)", y) + + xat = func(i int) string { + return x.At(i) + } + + yat = func(i int) string { + return y.At(i) + } + gc = func() { + registers.Push(x, y) + } + default: + // we have a least 4 registers. + // 1 for tmp. + nbRegisters-- + // 1 for y + nbRegisters-- + var y amd64.Register + + if nbRegisters >= f.NbWords { + // we store x fully in registers + x := registers.Pop() + f.MOVQ("x+8(FP)", x) + _x := registers.PopN(f.NbWords) + f.LabelRegisters("x", _x...) + f.Mov(x, _x) + + xat = func(i int) string { + return string(_x[i]) + } + registers.Push(x) + gc = func() { + registers.Push(y) + registers.Push(_x...) + } + } else { + // we take at least 1 register for x addr + nbRegisters-- + x := registers.Pop() + y = registers.Pop() // temporary lock 1 for y + f.MOVQ("x+8(FP)", x) + + // and use the rest for x0...xn + _x := registers.PopN(nbRegisters) + f.LabelRegisters("x", _x...) + for i := 0; i < len(_x); i++ { + f.MOVQ(x.At(i), _x[i]) + } + xat = func(i int) string { + if i < len(_x) { + return string(_x[i]) + } + return x.At(i) + } + registers.Push(y) + + gc = func() { + registers.Push(x, y) + registers.Push(_x...) + } + + } + y = registers.Pop() + + f.MOVQ("y+16(FP)", y) + yat = func(i int) string { + return y.At(i) + } + + } + + f.MulADX(®isters, xat, yat, t) + gc() + + // --------------------------------------------------------------------------------------------- + // reduce + f.Reduce(®isters, t) + + f.MOVQ("res+0(FP)", amd64.AX) + f.Mov(t, amd64.AX) + f.RET() + } + + // --------------------------------------------------------------------------------------------- + // no MULX, ADX instructions + if !forceADX { + f.LABEL(noAdx) + + f.MOVQ("res+0(FP)", amd64.AX) + f.MOVQ(amd64.AX, "(SP)") + f.MOVQ("x+8(FP)", amd64.AX) + f.MOVQ(amd64.AX, "8(SP)") + f.MOVQ("y+16(FP)", amd64.AX) + f.MOVQ(amd64.AX, "16(SP)") + f.WriteLn("CALL ·_mulGeneric(SB)") + f.RET() + + } +} diff --git a/field/asm/amd64/element_mul_constants.go b/field/asm/amd64/element_mul_constants.go new file mode 100644 index 0000000000..aaad904190 --- /dev/null +++ b/field/asm/amd64/element_mul_constants.go @@ -0,0 +1,61 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package amd64 + +func (f *FFAmd64) generateMulBy3() { + f.Comment("MulBy3(x *Element)") + stackSize := f.StackSize(1+f.NbWords*2, 0, 0) + registers := f.FnHeader("MulBy3", stackSize, 8) + defer f.AssertCleanStack(stackSize, 0) + // registers + x := registers.Pop() + t := registers.PopN(f.NbWords) + + f.MOVQ("x+0(FP)", x) + + f.Mov(x, t) + f.Add(t, t) + + f.Reduce(®isters, t) + f.Add(x, t) + f.Reduce(®isters, t) + f.Mov(t, x) + + f.RET() +} + +func (f *FFAmd64) generateMulBy5() { + f.Comment("MulBy5(x *Element)") + stackSize := f.StackSize(1+f.NbWords*2, 0, 0) + registers := f.FnHeader("MulBy5", stackSize, 8) + defer f.AssertCleanStack(stackSize, 0) + + // registers + x := registers.Pop() + t := registers.PopN(f.NbWords) + + f.MOVQ("x+0(FP)", x) + + f.Mov(x, t) + f.Add(t, t) + f.Reduce(®isters, t) + f.Add(t, t) + f.Reduce(®isters, t) + f.Add(x, t) + f.Reduce(®isters, t) + + f.Mov(t, x) + f.RET() +} diff --git a/field/asm/amd64/element_neg.go b/field/asm/amd64/element_neg.go new file mode 100644 index 0000000000..e040448921 --- /dev/null +++ b/field/asm/amd64/element_neg.go @@ -0,0 +1,68 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package amd64 + +func (f *FFAmd64) generateNeg() { + f.Comment("neg(res, x *Element)") + registers := f.FnHeader("neg", 0, 16) + defer f.AssertCleanStack(0, 0) + + // labels + zero := f.NewLabel() + + // registers + x := registers.Pop() + t := registers.PopN(f.NbWords) + r := registers.Pop() + + f.MOVQ("res+0(FP)", r) + f.MOVQ("x+8(FP)", x) + + // t = x + f.Mov(x, t) + + // x = t[0] | ... | t[n] + f.MOVQ(t[0], x) + for i := 1; i < f.NbWords; i++ { + f.ORQ(t[i], x) + } + + f.TESTQ(x, x) + + // if x == 0, we jump to nonzero label + f.JEQ(zero) + registers.Push(x) + q := registers.Pop() + // z = x - q + for i := 0; i < f.NbWords; i++ { + f.MOVQ(f.Q[i], q) + if i == 0 { + f.SUBQ(t[i], q) + } else { + f.SBBQ(t[i], q) + } + f.MOVQ(q, r.At(i)) + } + registers.Push(q) + f.RET() + + f.LABEL(zero) + // if x == 0, we set the result to zero and return + for i := 0; i < f.NbWords; i++ { + f.MOVQ(x, r.At(i)) + } + f.RET() + +} diff --git a/field/asm/amd64/element_reduce.go b/field/asm/amd64/element_reduce.go new file mode 100644 index 0000000000..70a566c3c8 --- /dev/null +++ b/field/asm/amd64/element_reduce.go @@ -0,0 +1,42 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package amd64 + +import ( + "github.com/consensys/bavard/amd64" +) + +func (f *FFAmd64) generateReduce() { + stackSize := f.StackSize(1+f.NbWords*2, 0, 0) + registers := f.FnHeader("reduce", stackSize, 8) + defer f.AssertCleanStack(stackSize, 0) + + // registers + r := registers.Pop() + t := registers.PopN(f.NbWords) + + f.MOVQ("res+0(FP)", r) + f.Mov(r, t) + f.Reduce(®isters, t) + f.Mov(t, r) + f.RET() +} + +// Reduce scratch can be on the stack or a set of registers. +func (f *FFAmd64) Reduce(registers *amd64.Registers, t []amd64.Register) { + scratch := f.PopN(registers) + f.ReduceElement(t, scratch) + f.Push(registers, scratch...) +} diff --git a/field/asm/amd64/element_sub.go b/field/asm/amd64/element_sub.go new file mode 100644 index 0000000000..95fb1b92a6 --- /dev/null +++ b/field/asm/amd64/element_sub.go @@ -0,0 +1,73 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package amd64 + +import "github.com/consensys/bavard/amd64" + +func (f *FFAmd64) generateSub() { + f.Comment("sub(res, x, y *Element)") + registers := f.FnHeader("sub", 0, 24) + defer f.AssertCleanStack(0, 0) + + // registers + var zero amd64.Register + t := registers.PopN(f.NbWords) + xy := registers.Pop() + + // set a register to zero if needed + if f.NbWords <= SmallModulus { + zero = registers.Pop() + f.XORQ(zero, zero) + } + + f.MOVQ("x+8(FP)", xy) + f.Mov(xy, t) + + // z = x - y mod q + f.MOVQ("y+16(FP)", xy) + f.Sub(xy, t) + registers.Push(xy) + + if f.NbWords > SmallModulus { + noReduce := f.NewLabel() + f.JCC(noReduce) + q := registers.Pop() + f.MOVQ(f.Q[0], q) + f.ADDQ(q, t[0]) + for i := 1; i < f.NbWords; i++ { + f.MOVQ(f.Q[i], q) + f.ADCQ(q, t[i]) + } + f.LABEL(noReduce) + registers.Push(q) + } else { + q := registers.PopN(f.NbWords) + f.Mov(f.Q, q) + for i := 0; i < f.NbWords; i++ { + f.CMOVQCC(zero, q[i]) + } + // add registers (q or 0) to t, and set to result + f.Add(q, t) + registers.Push(q...) + registers.Push(zero) + } + + r := registers.Pop() + f.MOVQ("res+0(FP)", r) + f.Mov(t, r) + + f.RET() + +} diff --git a/field/field.go b/field/field.go new file mode 100644 index 0000000000..732181d115 --- /dev/null +++ b/field/field.go @@ -0,0 +1,248 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package field + +import ( + "errors" + "math/big" +) + +var ( + errUnsupportedModulus = errors.New("unsupported modulus. goff only works for prime modulus w/ size > 64bits") + errParseModulus = errors.New("can't parse modulus") +) + +type Field struct { + PackageName string + ElementName string + Modulus string + NbWords int + NbBits int + NbWordsLastIndex int + NbWordsIndexesNoZero []int + NbWordsIndexesFull []int + Q []uint64 + QInverse []uint64 + QMinusOneHalvedP []uint64 // ((q-1) / 2 ) + 1 + ASM bool + RSquare []uint64 + One []uint64 + LegendreExponent string // big.Int to base16 string + NoCarry bool + NoCarrySquare bool // used if NoCarry is set, but some op may overflow in square optimization + SqrtQ3Mod4 bool + SqrtAtkin bool + SqrtTonelliShanks bool + SqrtE uint64 + SqrtS []uint64 + SqrtAtkinExponent string // big.Int to base16 string + SqrtSMinusOneOver2 string // big.Int to base16 string + SqrtQ3Mod4Exponent string // big.Int to base16 string + SqrtG []uint64 // NonResidue ^ SqrtR (montgomery form) + + NonResidue []uint64 // (montgomery form) +} + +// ------------------------------------------------------------------------------------------------- +// Field data precompute functions +func NewField(packageName, elementName, modulus string) (*Field, error) { + // parse modulus + var bModulus big.Int + if _, ok := bModulus.SetString(modulus, 10); !ok { + return nil, errParseModulus + } + + // field info + F := &Field{ + PackageName: packageName, + ElementName: elementName, + Modulus: modulus, + } + // pre compute field constants + F.NbBits = bModulus.BitLen() + F.NbWords = len(bModulus.Bits()) + if F.NbWords < 2 { + return nil, errUnsupportedModulus + } + + F.NbWordsLastIndex = F.NbWords - 1 + + // set q from big int repr + F.Q = toUint64Slice(&bModulus) + _qHalved := big.NewInt(0) + bOne := new(big.Int).SetUint64(1) + _qHalved.Sub(&bModulus, bOne).Rsh(_qHalved, 1).Add(_qHalved, bOne) + F.QMinusOneHalvedP = toUint64Slice(_qHalved, F.NbWords) + + // setting qInverse + _r := big.NewInt(1) + _r.Lsh(_r, uint(F.NbWords)*64) + _rInv := big.NewInt(1) + _qInv := big.NewInt(0) + extendedEuclideanAlgo(_r, &bModulus, _rInv, _qInv) + _qInv.Mod(_qInv, _r) + F.QInverse = toUint64Slice(_qInv, F.NbWords) + + // rsquare + _rSquare := big.NewInt(2) + exponent := big.NewInt(int64(F.NbWords) * 64 * 2) + _rSquare.Exp(_rSquare, exponent, &bModulus) + F.RSquare = toUint64Slice(_rSquare, F.NbWords) + + var one big.Int + one.SetUint64(1) + one.Lsh(&one, uint(F.NbWords)*64).Mod(&one, &bModulus) + F.One = toUint64Slice(&one, F.NbWords) + + // indexes (template helpers) + F.NbWordsIndexesFull = make([]int, F.NbWords) + F.NbWordsIndexesNoZero = make([]int, F.NbWords-1) + for i := 0; i < F.NbWords; i++ { + F.NbWordsIndexesFull[i] = i + if i > 0 { + F.NbWordsIndexesNoZero[i-1] = i + } + } + + // See https://hackmd.io/@zkteam/modular_multiplication + // if the last word of the modulus is smaller or equal to B, + // we can simplify the montgomery multiplication + const B = (^uint64(0) >> 1) - 1 + F.NoCarry = (F.Q[len(F.Q)-1] <= B) && F.NbWords <= 12 + const BSquare = (^uint64(0) >> 2) + F.NoCarrySquare = F.Q[len(F.Q)-1] <= BSquare + + // Legendre exponent (p-1)/2 + var legendreExponent big.Int + legendreExponent.SetUint64(1) + legendreExponent.Sub(&bModulus, &legendreExponent) + legendreExponent.Rsh(&legendreExponent, 1) + F.LegendreExponent = legendreExponent.Text(16) + + // Sqrt pre computes + var qMod big.Int + qMod.SetUint64(4) + if qMod.Mod(&bModulus, &qMod).Cmp(new(big.Int).SetUint64(3)) == 0 { + // q ≡ 3 (mod 4) + // using z ≡ ± x^((p+1)/4) (mod q) + F.SqrtQ3Mod4 = true + var sqrtExponent big.Int + sqrtExponent.SetUint64(1) + sqrtExponent.Add(&bModulus, &sqrtExponent) + sqrtExponent.Rsh(&sqrtExponent, 2) + F.SqrtQ3Mod4Exponent = sqrtExponent.Text(16) + } else { + // q ≡ 1 (mod 4) + qMod.SetUint64(8) + if qMod.Mod(&bModulus, &qMod).Cmp(new(big.Int).SetUint64(5)) == 0 { + // q ≡ 5 (mod 8) + // use Atkin's algorithm + // see modSqrt5Mod8Prime in math/big/int.go + F.SqrtAtkin = true + e := new(big.Int).Rsh(&bModulus, 3) // e = (q - 5) / 8 + F.SqrtAtkinExponent = e.Text(16) + } else { + // use Tonelli-Shanks + F.SqrtTonelliShanks = true + + // Write q-1 =2^e * s , s odd + var s big.Int + one.SetUint64(1) + s.Sub(&bModulus, &one) + + e := s.TrailingZeroBits() + s.Rsh(&s, e) + F.SqrtE = uint64(e) + F.SqrtS = toUint64Slice(&s) + + // find non residue + var nonResidue big.Int + nonResidue.SetInt64(2) + one.SetUint64(1) + for big.Jacobi(&nonResidue, &bModulus) != -1 { + nonResidue.Add(&nonResidue, &one) + } + + // g = nonresidue ^ s + var g big.Int + g.Exp(&nonResidue, &s, &bModulus) + // store g in montgomery form + g.Lsh(&g, uint(F.NbWords)*64).Mod(&g, &bModulus) + F.SqrtG = toUint64Slice(&g, F.NbWords) + + // store non residue in montgomery form + nonResidue.Lsh(&nonResidue, uint(F.NbWords)*64).Mod(&nonResidue, &bModulus) + F.NonResidue = toUint64Slice(&nonResidue) + + // (s+1) /2 + s.Sub(&s, &one).Rsh(&s, 1) + F.SqrtSMinusOneOver2 = s.Text(16) + } + } + + // note: to simplify output files generated, we generated ASM code only for + // moduli that meet the condition F.NoCarry + // asm code generation for moduli with more than 6 words can be optimized further + F.ASM = F.NoCarry && F.NbWords <= 12 + + return F, nil +} + +func toUint64Slice(b *big.Int, nbWords ...int) (s []uint64) { + if len(nbWords) > 0 && nbWords[0] > len(b.Bits()) { + s = make([]uint64, nbWords[0]) + } else { + s = make([]uint64, len(b.Bits())) + } + + for i, v := range b.Bits() { + s[i] = (uint64)(v) + } + return +} + +// https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm +// r > q, modifies rinv and qinv such that rinv.r - qinv.q = 1 +func extendedEuclideanAlgo(r, q, rInv, qInv *big.Int) { + var s1, s2, t1, t2, qi, tmpMuls, riPlusOne, tmpMult, a, b big.Int + t1.SetUint64(1) + rInv.Set(big.NewInt(1)) + qInv.Set(big.NewInt(0)) + a.Set(r) + b.Set(q) + + // r_i+1 = r_i-1 - q_i.r_i + // s_i+1 = s_i-1 - q_i.s_i + // t_i+1 = t_i-1 - q_i.s_i + for b.Sign() > 0 { + qi.Div(&a, &b) + riPlusOne.Mod(&a, &b) + + tmpMuls.Mul(&s1, &qi) + tmpMult.Mul(&t1, &qi) + + s2.Set(&s1) + t2.Set(&t1) + + s1.Sub(rInv, &tmpMuls) + t1.Sub(qInv, &tmpMult) + rInv.Set(&s2) + qInv.Set(&t2) + + a.Set(&b) + b.Set(&riPlusOne) + } + qInv.Neg(qInv) +} diff --git a/field/field.md b/field/field.md new file mode 100644 index 0000000000..4e9648ceb8 --- /dev/null +++ b/field/field.md @@ -0,0 +1,48 @@ + +# Usage + +At the root of your repo: +```bash +go get github.com/consensys/gnark-crypto/field +``` + +then in a `main.go` (that can be called using a `go:generate` workflow): + +``` +generator.GenerateFF(packageName, structName, modulus, destinationPath, false) +``` + +The generated type has an API that's similar with `big.Int` + +Example API signature +```go +// Mul z = x * y mod q +func (z *Element) Mul(x, y *Element) *Element +``` + +and can be used like so: + +```go +var a, b Element +a.SetUint64(2) +b.SetString("984896738") + +a.Mul(a, b) + +a.Sub(a, a) + .Add(a, b) + .Inv(a) + +b.Exp(b, 42) +b.Neg(b) +``` + +### Build tags + +Generates optimized assembly for `amd64` target. + +For the `Mul` operation, using `ADX` instructions and `ADOX/ADCX` result in a significant performance gain. + +The "default" target `amd64` checks if the running architecture supports these instruction, and reverts to generic path if not. This check adds a branch and forces the function to reserve some bytes on the frame to store the argument to call `_mulGeneric` . + +This package outputs code that can be compiled with `amd64_adx` flag which omits this check. Will crash if the platform running the binary doesn't support the `ADX` instructions (roughly, before 2016). \ No newline at end of file diff --git a/field/generator/generator.go b/field/generator/generator.go new file mode 100644 index 0000000000..2c9c38fb19 --- /dev/null +++ b/field/generator/generator.go @@ -0,0 +1,226 @@ +package generator + +import ( + "fmt" + "io" + "os" + "os/exec" + "path/filepath" + "strings" + "text/template" + + "github.com/consensys/bavard" + "github.com/consensys/gnark-crypto/field" + "github.com/consensys/gnark-crypto/field/asm/amd64" + "github.com/consensys/gnark-crypto/field/internal/templates/element" +) + +// TODO @gbotrel --> pattern for code generation is different than gnark-crypto/internal because a binary like goff can generate +// base field. in Go 1.16, can embed the template in the binary, and use same pattern than gnark-crypto/internal + +// GenerateFF will generate go (and .s) files in outputDir for modulus (in base 10) +func GenerateFF(F *field.Field, outputDir string) error { + // source file templates + src := []string{ + element.Base, + element.Reduce, + element.Exp, + element.Conv, + element.MulCIOS, + element.MulNoCarry, + element.Sqrt, + element.Inverse, + } + + // test file templates + tst := []string{ + element.MulCIOS, + element.MulNoCarry, + element.Reduce, + element.Test, + } + + // output files + eName := strings.ToLower(F.ElementName) + + pathSrc := filepath.Join(outputDir, eName+".go") + pathSrcArith := filepath.Join(outputDir, "arith.go") + pathTest := filepath.Join(outputDir, eName+"_test.go") + + // remove old format generated files + oldFiles := []string{"_mul.go", "_mul_amd64.go", + "_square.go", "_square_amd64.go", "_ops_decl.go", "_square_amd64.s", "_ops_amd64.go"} + for _, of := range oldFiles { + _ = os.Remove(filepath.Join(outputDir, eName+of)) + } + + bavardOpts := []func(*bavard.Bavard) error{ + bavard.Apache2("ConsenSys Software Inc.", 2020), + bavard.Package(F.PackageName), + bavard.GeneratedBy("consensys/gnark-crypto"), + bavard.Funcs(template.FuncMap{"toTitle": strings.Title}), + } + optsWithPackageDoc := append(bavardOpts, bavard.Package(F.PackageName, "contains field arithmetic operations for modulus "+F.Modulus)) + + // generate source file + if err := bavard.Generate(pathSrc, src, F, optsWithPackageDoc...); err != nil { + return err + } + // generate arithmetics source file + if err := bavard.Generate(pathSrcArith, []string{element.Arith}, F, bavardOpts...); err != nil { + return err + } + + // generate test file + if err := bavard.Generate(pathTest, tst, F, bavardOpts...); err != nil { + return err + } + + // if we generate assembly code + if F.ASM { + // generate ops.s + { + pathSrc := filepath.Join(outputDir, eName+"_ops_amd64.s") + fmt.Println("generating", pathSrc) + f, err := os.Create(pathSrc) + if err != nil { + return err + } + + if err := amd64.Generate(f, F); err != nil { + _ = f.Close() + return err + } + _ = f.Close() + + // run asmfmt + // run go fmt on whole directory + cmd := exec.Command("asmfmt", "-w", pathSrc) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return err + } + } + + { + pathSrc := filepath.Join(outputDir, eName+"_mul_amd64.s") + fmt.Println("generating", pathSrc) + f, err := os.Create(pathSrc) + if err != nil { + return err + } + + _, _ = io.WriteString(f, "// +build !amd64_adx\n") + + if err := amd64.GenerateMul(f, F); err != nil { + _ = f.Close() + return err + } + _ = f.Close() + + // run asmfmt + // run go fmt on whole directory + cmd := exec.Command("asmfmt", "-w", pathSrc) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return err + } + } + + { + pathSrc := filepath.Join(outputDir, eName+"_mul_adx_amd64.s") + fmt.Println("generating", pathSrc) + f, err := os.Create(pathSrc) + if err != nil { + return err + } + + _, _ = io.WriteString(f, "// +build amd64_adx\n") + + if err := amd64.GenerateMulADX(f, F); err != nil { + _ = f.Close() + return err + } + _ = f.Close() + + // run asmfmt + // run go fmt on whole directory + cmd := exec.Command("asmfmt", "-w", pathSrc) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return err + } + } + + } + + { + // generate ops_amd64.go + src := []string{ + element.OpsAMD64, + } + pathSrc := filepath.Join(outputDir, eName+"_ops_amd64.go") + if err := bavard.Generate(pathSrc, src, F, bavardOpts...); err != nil { + return err + } + } + + { + // generate ops.go + src := []string{ + element.OpsNoAsm, + element.MulCIOS, + element.MulNoCarry, + element.Reduce, + } + pathSrc := filepath.Join(outputDir, eName+"_ops_noasm.go") + bavardOptsCpy := make([]func(*bavard.Bavard) error, len(bavardOpts)) + copy(bavardOptsCpy, bavardOpts) + if F.ASM { + bavardOptsCpy = append(bavardOptsCpy, bavard.BuildTag("!amd64")) + } + if err := bavard.Generate(pathSrc, src, F, bavardOptsCpy...); err != nil { + return err + } + } + + { + // generate asm.go and asm_noadx.go + src := []string{ + element.Asm, + } + pathSrc := filepath.Join(outputDir, "asm.go") + bavardOptsCpy := make([]func(*bavard.Bavard) error, len(bavardOpts)) + copy(bavardOptsCpy, bavardOpts) + bavardOptsCpy = append(bavardOptsCpy, bavard.BuildTag("!noadx")) + if err := bavard.Generate(pathSrc, src, F, bavardOptsCpy...); err != nil { + return err + } + } + { + // generate asm.go and asm_noadx.go + src := []string{ + element.AsmNoAdx, + } + pathSrc := filepath.Join(outputDir, "asm_noadx.go") + bavardOptsCpy := make([]func(*bavard.Bavard) error, len(bavardOpts)) + copy(bavardOptsCpy, bavardOpts) + bavardOptsCpy = append(bavardOptsCpy, bavard.BuildTag("noadx")) + if err := bavard.Generate(pathSrc, src, F, bavardOptsCpy...); err != nil { + return err + } + } + + // run go fmt on whole directory + cmd := exec.Command("gofmt", "-s", "-w", outputDir) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + return err + } + + return nil +} diff --git a/field/generator/generator_test.go b/field/generator/generator_test.go new file mode 100644 index 0000000000..1baa062ee6 --- /dev/null +++ b/field/generator/generator_test.go @@ -0,0 +1,98 @@ +// Copyright 2020 ConsenSys Software Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package generator + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "os/exec" + "path/filepath" + "testing" + + "github.com/consensys/gnark-crypto/field" +) + +// integration test will create modulus for various field sizes and run tests + +const rootDir = "integration_test" + +func TestIntegration(t *testing.T) { + os.RemoveAll(rootDir) + err := os.MkdirAll(rootDir, 0700) + defer os.RemoveAll(rootDir) + if err != nil { + t.Fatal(err) + } + + var bits []int + if testing.Short() { + for i := 128; i <= 448; i += 64 { + bits = append(bits, i-3, i-2, i-1, i, i+1) + } + } else { + for i := 120; i < 704; i++ { + bits = append(bits, i) + } + } + + moduli := make(map[string]string) + for _, i := range bits { + var q *big.Int + var nbWords int + if i%64 == 0 { + q, _ = rand.Prime(rand.Reader, i) + moduli[fmt.Sprintf("e_cios_%04d", i)] = q.String() + } else { + for { + q, _ = rand.Prime(rand.Reader, i) + nbWords = len(q.Bits()) + const B = (^uint64(0) >> 1) - 1 + if uint64(q.Bits()[nbWords-1]) <= B { + break + } + } + moduli[fmt.Sprintf("e_nocarry_%04d", i)] = q.String() + } + + } + + for elementName, modulus := range moduli { + // generate field + childDir := filepath.Join(rootDir, elementName) + fIntegration, err := field.NewField("integration", elementName, modulus) + if err != nil { + t.Fatal(elementName, err) + } + if err := GenerateFF(fIntegration, childDir); err != nil { + t.Fatal(elementName, err) + } + } + + // run go test + wd, err := os.Getwd() + if err != nil { + t.Fatal(err) + } + packageDir := filepath.Join(wd, rootDir) + string(filepath.Separator) + "..." + cmd := exec.Command("go", "test", packageDir) + out, err := cmd.CombinedOutput() + fmt.Println(string(out)) + if err != nil { + t.Fatal(err) + } + +} diff --git a/field/internal/templates/element/arith.go b/field/internal/templates/element/arith.go new file mode 100644 index 0000000000..06a7805588 --- /dev/null +++ b/field/internal/templates/element/arith.go @@ -0,0 +1,49 @@ +package element + +const Arith = ` +import ( + "math/bits" +) + +// madd0 hi = a*b + c (discards lo bits) +func madd0(a, b, c uint64) (hi uint64) { + var carry, lo uint64 + hi, lo = bits.Mul64(a, b) + _, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd1 hi, lo = a*b + c +func madd1(a, b, c uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + +// madd2 hi, lo = a*b + c + d +func madd2(a, b, c, d uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, 0, carry) + return +} + + +func madd3(a, b, c, d, e uint64) (hi uint64, lo uint64) { + var carry uint64 + hi, lo = bits.Mul64(a, b) + c, carry = bits.Add64(c, d, 0) + hi, _ = bits.Add64(hi, 0, carry) + lo, carry = bits.Add64(lo, c, 0) + hi, _ = bits.Add64(hi, e, carry) + return +} + + +` diff --git a/field/internal/templates/element/asm.go b/field/internal/templates/element/asm.go new file mode 100644 index 0000000000..2f0103ea93 --- /dev/null +++ b/field/internal/templates/element/asm.go @@ -0,0 +1,17 @@ +package element + +// Asm ... +const Asm = ` +import "golang.org/x/sys/cpu" + +var supportAdx = cpu.X86.HasADX && cpu.X86.HasBMI2 +` + +// AsmNoAdx ... +const AsmNoAdx = ` + +// note: this is needed for test purposes, as dynamically changing supportAdx doesn't flag +// certain errors (like fatal error: missing stackmap) +// this ensures we test all asm path. +var supportAdx = false +` diff --git a/field/internal/templates/element/base.go b/field/internal/templates/element/base.go new file mode 100644 index 0000000000..f35491a686 --- /dev/null +++ b/field/internal/templates/element/base.go @@ -0,0 +1,436 @@ +package element + +const Base = ` + +// /!\ WARNING /!\ +// this code has not been audited and is provided as-is. In particular, +// there is no security guarantees such as constant time implementation +// or side-channel attack resistance +// /!\ WARNING /!\ + +import ( + "math/big" + "math/bits" + "crypto/rand" + "encoding/binary" + "io" + "sync" + "strconv" +) + +// {{.ElementName}} represents a field element stored on {{.NbWords}} words (uint64) +// {{.ElementName}} are assumed to be in Montgomery form in all methods +// field modulus q = +// +// {{.Modulus}} +type {{.ElementName}} [{{.NbWords}}]uint64 + +// Limbs number of 64 bits words needed to represent {{.ElementName}} +const Limbs = {{.NbWords}} + +// Bits number bits needed to represent {{.ElementName}} +const Bits = {{.NbBits}} + +// Bytes number bytes needed to represent {{.ElementName}} +const Bytes = Limbs * 8 + +// field modulus stored as big.Int +var _modulus big.Int + +// Modulus returns q as a big.Int +// q = +// +// {{.Modulus}} +func Modulus() *big.Int { + return new(big.Int).Set(&_modulus) +} + +// q (modulus) +var q{{.ElementName}} = {{.ElementName}}{ + {{- range $i := .NbWordsIndexesFull}} + {{index $.Q $i}},{{end}} +} + +// rSquare +var rSquare = {{.ElementName}}{ + {{- range $i := .RSquare}} + {{$i}},{{end}} +} + + +var bigIntPool = sync.Pool{ + New: func() interface{} { + return new(big.Int) + }, +} + +func init() { + _modulus.SetString("{{.Modulus}}", 10) +} + + +// SetUint64 z = v, sets z LSB to v (non-Montgomery form) and convert z to Montgomery form +func (z *{{.ElementName}}) SetUint64(v uint64) *{{.ElementName}} { + *z = {{.ElementName}}{v} + return z.Mul(z, &rSquare) // z.ToMont() +} + +// Set z = x +func (z *{{.ElementName}}) Set(x *{{.ElementName}}) *{{.ElementName}} { + {{- range $i := .NbWordsIndexesFull}} + z[{{$i}}] = x[{{$i}}] + {{- end}} + return z +} + +// SetInterface converts i1 from uint64, int, string, or {{.ElementName}}, big.Int into {{.ElementName}} +// panic if provided type is not supported +func (z *{{.ElementName}}) SetInterface(i1 interface{}) *{{.ElementName}} { + switch c1 := i1.(type) { + case {{.ElementName}}: + return z.Set(&c1) + case *{{.ElementName}}: + return z.Set(c1) + case uint64: + return z.SetUint64(c1) + case int: + return z.SetString(strconv.Itoa(c1)) + case string: + return z.SetString(c1) + case *big.Int: + return z.SetBigInt(c1) + case big.Int: + return z.SetBigInt(&c1) + case []byte: + return z.SetBytes(c1) + default: + panic("invalid type") + } +} + +// SetZero z = 0 +func (z *{{.ElementName}}) SetZero() *{{.ElementName}} { + {{- range $i := .NbWordsIndexesFull}} + z[{{$i}}] = 0 + {{- end}} + return z +} + +// SetOne z = 1 (in Montgomery form) +func (z *{{.ElementName}}) SetOne() *{{.ElementName}} { + {{- range $i := .NbWordsIndexesFull}} + z[{{$i}}] = {{index $.One $i}} + {{- end}} + return z +} + + +// Div z = x*y^-1 mod q +func (z *{{.ElementName}}) Div( x, y *{{.ElementName}}) *{{.ElementName}} { + var yInv {{.ElementName}} + yInv.Inverse( y) + z.Mul( x, &yInv) + return z +} + +// Equal returns z == x +func (z *{{.ElementName}}) Equal(x *{{.ElementName}}) bool { + return {{- range $i := reverse .NbWordsIndexesNoZero}}(z[{{$i}}] == x[{{$i}}]) &&{{end}}(z[0] == x[0]) +} + +// IsZero returns z == 0 +func (z *{{.ElementName}}) IsZero() bool { + return ( {{- range $i := reverse .NbWordsIndexesNoZero}} z[{{$i}}] | {{end}}z[0]) == 0 +} + +// Cmp compares (lexicographic order) z and x and returns: +// +// -1 if z < x +// 0 if z == x +// +1 if z > x +// +func (z *{{.ElementName}}) Cmp(x *{{.ElementName}}) int { + _z := *z + _x := *x + _z.FromMont() + _x.FromMont() + {{- range $i := reverse $.NbWordsIndexesFull}} + if _z[{{$i}}] > _x[{{$i}}] { + return 1 + } else if _z[{{$i}}] < _x[{{$i}}] { + return -1 + } + {{- end}} + return 0 +} + +// LexicographicallyLargest returns true if this element is strictly lexicographically +// larger than its negation, false otherwise +func (z *{{.ElementName}}) LexicographicallyLargest() bool { + // adapted from github.com/zkcrypto/bls12_381 + // we check if the element is larger than (q-1) / 2 + // if z - (((q -1) / 2) + 1) have no underflow, then z > (q-1) / 2 + + _z := *z + _z.FromMont() + + var b uint64 + _, b = bits.Sub64(_z[0], {{index .QMinusOneHalvedP 0}}, 0) + {{- range $i := .NbWordsIndexesNoZero}} + _, b = bits.Sub64(_z[{{$i}}], {{index $.QMinusOneHalvedP $i}}, b) + {{- end}} + + return b == 0 +} + + + + +// SetRandom sets z to a random element < q +func (z *{{.ElementName}}) SetRandom() (*{{.ElementName}}, error) { + var bytes [{{mul 8 .NbWords}}]byte + if _, err := io.ReadFull(rand.Reader, bytes[:]); err != nil { + return nil, err + } + {{- range $i := .NbWordsIndexesFull}} + {{- $k := add $i 1}} + z[{{$i}}] = binary.BigEndian.Uint64(bytes[{{mul $i 8}}:{{mul $k 8}}]) + {{- end}} + z[{{$.NbWordsLastIndex}}] %= {{index $.Q $.NbWordsLastIndex}} + + {{ template "reduce" . }} + + return z, nil +} + +// One returns 1 (in montgommery form) +func One() {{.ElementName}} { + var one {{.ElementName}} + one.SetOne() + return one +} + + +// MulAssign is deprecated +// Deprecated: use Mul instead +func (z *{{.ElementName}}) MulAssign(x *{{.ElementName}}) *{{.ElementName}} { + return z.Mul(z, x) +} + +// AddAssign is deprecated +// Deprecated: use Add instead +func (z *{{.ElementName}}) AddAssign(x *{{.ElementName}}) *{{.ElementName}} { + return z.Add(z, x) +} + +// SubAssign is deprecated +// Deprecated: use Sub instead +func (z *{{.ElementName}}) SubAssign(x *{{.ElementName}}) *{{.ElementName}} { + return z.Sub(z, x) +} + + +// API with assembly impl + +// Mul z = x * y mod q +// see https://hackmd.io/@zkteam/modular_multiplication +func (z *{{.ElementName}}) Mul(x, y *{{.ElementName}}) *{{.ElementName}} { + mul(z, x, y) + return z +} + +// Square z = x * x mod q +// see https://hackmd.io/@zkteam/modular_multiplication +func (z *{{.ElementName}}) Square(x *{{.ElementName}}) *{{.ElementName}} { + mul(z,x, x) + return z +} + +// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// sets and returns z = z * 1 +func (z *{{.ElementName}}) FromMont() *{{.ElementName}} { + fromMont(z) + return z +} + +// Add z = x + y mod q +func (z *{{.ElementName}}) Add( x, y *{{.ElementName}}) *{{.ElementName}} { + add(z, x, y) + return z +} + +// Double z = x + x mod q, aka Lsh 1 +func (z *{{.ElementName}}) Double( x *{{.ElementName}}) *{{.ElementName}} { + double(z, x) + return z +} + + +// Sub z = x - y mod q +func (z *{{.ElementName}}) Sub( x, y *{{.ElementName}}) *{{.ElementName}} { + sub(z, x, y) + return z +} + +// Neg z = q - x +func (z *{{.ElementName}}) Neg( x *{{.ElementName}}) *{{.ElementName}} { + neg(z, x) + return z +} + + + + +// Generic (no ADX instructions, no AMD64) versions of multiplication and squaring algorithms + +func _mulGeneric(z,x,y *{{.ElementName}}) { + {{ if .NoCarry}} + {{ template "mul_nocarry" dict "all" . "V1" "x" "V2" "y"}} + {{ else }} + {{ template "mul_cios" dict "all" . "V1" "x" "V2" "y" "NoReturn" true}} + {{ end }} + {{ template "reduce" . }} +} + + +func _fromMontGeneric(z *{{.ElementName}}) { + // the following lines implement z = z * 1 + // with a modified CIOS montgomery multiplication + {{- range $j := .NbWordsIndexesFull}} + { + // m = z[0]n'[0] mod W + m := z[0] * {{index $.QInverse 0}} + C := madd0(m, {{index $.Q 0}}, z[0]) + {{- range $i := $.NbWordsIndexesNoZero}} + C, z[{{sub $i 1}}] = madd2(m, {{index $.Q $i}}, z[{{$i}}], C) + {{- end}} + z[{{sub $.NbWords 1}}] = C + } + {{- end}} + + {{ template "reduce" .}} +} + + + +func _addGeneric(z, x, y *{{.ElementName}}) { + var carry uint64 + {{$k := sub $.NbWords 1}} + z[0], carry = bits.Add64(x[0], y[0], 0) + {{- range $i := .NbWordsIndexesNoZero}} + {{- if eq $i $.NbWordsLastIndex}} + {{- else}} + z[{{$i}}], carry = bits.Add64(x[{{$i}}], y[{{$i}}], carry) + {{- end}} + {{- end}} + {{- if .NoCarry}} + z[{{$k}}], _ = bits.Add64(x[{{$k}}], y[{{$k}}], carry) + {{- else }} + z[{{$k}}], carry = bits.Add64(x[{{$k}}], y[{{$k}}], carry) + // if we overflowed the last addition, z >= q + // if z >= q, z = z - q + if carry != 0 { + // we overflowed, so z >= q + z[0], carry = bits.Sub64(z[0], {{index $.Q 0}}, 0) + {{- range $i := .NbWordsIndexesNoZero}} + z[{{$i}}], carry = bits.Sub64(z[{{$i}}], {{index $.Q $i}}, carry) + {{- end}} + return + } + {{- end}} + + {{ template "reduce" .}} +} + +func _doubleGeneric(z, x *{{.ElementName}}) { + var carry uint64 + {{$k := sub $.NbWords 1}} + z[0], carry = bits.Add64(x[0], x[0], 0) + {{- range $i := .NbWordsIndexesNoZero}} + {{- if eq $i $.NbWordsLastIndex}} + {{- else}} + z[{{$i}}], carry = bits.Add64(x[{{$i}}], x[{{$i}}], carry) + {{- end}} + {{- end}} + {{- if .NoCarry}} + z[{{$k}}], _ = bits.Add64(x[{{$k}}], x[{{$k}}], carry) + {{- else }} + z[{{$k}}], carry = bits.Add64(x[{{$k}}], x[{{$k}}], carry) + // if we overflowed the last addition, z >= q + // if z >= q, z = z - q + if carry != 0 { + // we overflowed, so z >= q + z[0], carry = bits.Sub64(z[0], {{index $.Q 0}}, 0) + {{- range $i := .NbWordsIndexesNoZero}} + z[{{$i}}], carry = bits.Sub64(z[{{$i}}], {{index $.Q $i}}, carry) + {{- end}} + return + } + {{- end}} + + {{ template "reduce" .}} +} + + +func _subGeneric(z, x, y *{{.ElementName}}) { + var b uint64 + z[0], b = bits.Sub64(x[0], y[0], 0) + {{- range $i := .NbWordsIndexesNoZero}} + z[{{$i}}], b = bits.Sub64(x[{{$i}}], y[{{$i}}], b) + {{- end}} + if b != 0 { + var c uint64 + z[0], c = bits.Add64(z[0], {{index $.Q 0}}, 0) + {{- range $i := .NbWordsIndexesNoZero}} + {{- if eq $i $.NbWordsLastIndex}} + z[{{$i}}], _ = bits.Add64(z[{{$i}}], {{index $.Q $i}}, c) + {{- else}} + z[{{$i}}], c = bits.Add64(z[{{$i}}], {{index $.Q $i}}, c) + {{- end}} + {{- end}} + } +} + +func _negGeneric(z, x *{{.ElementName}}) { + if x.IsZero() { + z.SetZero() + return + } + var borrow uint64 + z[0], borrow = bits.Sub64({{index $.Q 0}}, x[0], 0) + {{- range $i := .NbWordsIndexesNoZero}} + {{- if eq $i $.NbWordsLastIndex}} + z[{{$i}}], _ = bits.Sub64({{index $.Q $i}}, x[{{$i}}], borrow) + {{- else}} + z[{{$i}}], borrow = bits.Sub64({{index $.Q $i}}, x[{{$i}}], borrow) + {{- end}} + {{- end}} +} + + +func _reduceGeneric(z *{{.ElementName}}) { + {{ template "reduce" . }} +} + +func mulByConstant(z *{{.ElementName}}, c uint8) { + switch c { + case 0: + z.SetZero() + return + case 1: + return + case 2: + z.Double(z) + return + case 3: + _z := *z + z.Double(z).Add(z, &_z) + case 5: + _z := *z + z.Double(z).Double(z).Add(z, &_z) + default: + panic("not implemented") + } +} + +` diff --git a/field/internal/templates/element/conv.go b/field/internal/templates/element/conv.go new file mode 100644 index 0000000000..feada1a07d --- /dev/null +++ b/field/internal/templates/element/conv.go @@ -0,0 +1,146 @@ +package element + +const Conv = ` + +// ToMont converts z to Montgomery form +// sets and returns z = z * r^2 +func (z *{{.ElementName}}) ToMont() *{{.ElementName}} { + return z.Mul(z, &rSquare) +} + +// ToRegular returns z in regular form (doesn't mutate z) +func (z {{.ElementName}}) ToRegular() {{.ElementName}} { + return *z.FromMont() +} + +// String returns the string form of an {{.ElementName}} in Montgomery form +func (z *{{.ElementName}}) String() string { + vv := bigIntPool.Get().(*big.Int) + defer bigIntPool.Put(vv) + return z.ToBigIntRegular(vv).String() +} + +// ToBigInt returns z as a big.Int in Montgomery form +func (z *{{.ElementName}}) ToBigInt(res *big.Int) *big.Int { + var b [Limbs*8]byte + {{- range $i := reverse .NbWordsIndexesFull}} + {{- $j := mul $i 8}} + {{- $k := sub $.NbWords 1}} + {{- $k := sub $k $i}} + {{- $jj := add $j 8}} + binary.BigEndian.PutUint64(b[{{$j}}:{{$jj}}], z[{{$k}}]) + {{- end}} + + return res.SetBytes(b[:]) +} + +// ToBigIntRegular returns z as a big.Int in regular form +func (z {{.ElementName}}) ToBigIntRegular(res *big.Int) *big.Int { + z.FromMont() + return z.ToBigInt(res) +} + + +// Bytes returns the regular (non montgomery) value +// of z as a big-endian byte array. +func (z *{{.ElementName}}) Bytes() (res [Limbs*8]byte) { + _z := z.ToRegular() + {{- range $i := reverse .NbWordsIndexesFull}} + {{- $j := mul $i 8}} + {{- $k := sub $.NbWords 1}} + {{- $k := sub $k $i}} + {{- $jj := add $j 8}} + binary.BigEndian.PutUint64(res[{{$j}}:{{$jj}}], _z[{{$k}}]) + {{- end}} + + return +} + + +// SetBytes interprets e as the bytes of a big-endian unsigned integer, +// sets z to that value (in Montgomery form), and returns z. +func (z *{{.ElementName}}) SetBytes(e []byte) *{{.ElementName}} { + // get a big int from our pool + vv := bigIntPool.Get().(*big.Int) + vv.SetBytes(e) + + // set big int + z.SetBigInt(vv) + + // put temporary object back in pool + bigIntPool.Put(vv) + + return z +} + + +// SetBigInt sets z to v (regular form) and returns z in Montgomery form +func (z *{{.ElementName}}) SetBigInt(v *big.Int) *{{.ElementName}} { + z.SetZero() + + var zero big.Int + + // fast path + c := v.Cmp(&_modulus) + if c == 0 { + // v == 0 + return z + } else if c != 1 && v.Cmp(&zero) != -1 { + // 0 < v < q + return z.setBigInt(v) + } + + // get temporary big int from the pool + vv := bigIntPool.Get().(*big.Int) + + // copy input + modular reduction + vv.Set(v) + vv.Mod(v, &_modulus) + + // set big int byte value + z.setBigInt(vv) + + // release object into pool + bigIntPool.Put(vv) + return z +} + +// setBigInt assumes 0 <= v < q +func (z *{{.ElementName}}) setBigInt(v *big.Int) *{{.ElementName}} { + vBits := v.Bits() + + if bits.UintSize == 64 { + for i := 0; i < len(vBits); i++ { + z[i] = uint64(vBits[i]) + } + } else { + for i := 0; i < len(vBits); i++ { + if i%2 == 0 { + z[i/2] = uint64(vBits[i]) + } else { + z[i/2] |= uint64(vBits[i]) << 32 + } + } + } + + return z.ToMont() +} + +// SetString creates a big.Int with s (in base 10) and calls SetBigInt on z +func (z *{{.ElementName}}) SetString( s string) *{{.ElementName}} { + // get temporary big int from the pool + vv := bigIntPool.Get().(*big.Int) + + if _, ok := vv.SetString(s, 10); !ok { + panic("{{.ElementName}}.SetString failed -> can't parse number in base10 into a big.Int") + } + z.SetBigInt(vv) + + // release object into pool + bigIntPool.Put(vv) + + + return z +} + +` diff --git a/field/internal/templates/element/exp.go b/field/internal/templates/element/exp.go new file mode 100644 index 0000000000..5221a3ac4d --- /dev/null +++ b/field/internal/templates/element/exp.go @@ -0,0 +1,23 @@ +package element + +const Exp = ` +// Exp z = x^exponent mod q +func (z *{{.ElementName}}) Exp(x {{.ElementName}}, exponent *big.Int) *{{.ElementName}} { + var bZero big.Int + if exponent.Cmp(&bZero) == 0 { + return z.SetOne() + } + + z.Set(&x) + + for i := exponent.BitLen() - 2; i >= 0; i-- { + z.Square(z) + if exponent.Bit(i) == 1 { + z.Mul(z, &x) + } + } + + return z +} + +` diff --git a/field/internal/templates/element/inverse.go b/field/internal/templates/element/inverse.go new file mode 100644 index 0000000000..a93bfdef29 --- /dev/null +++ b/field/internal/templates/element/inverse.go @@ -0,0 +1,139 @@ +package element + +const Inverse = ` + +{{/* We use big.Int for Inverse for these type of moduli */}} +{{if eq .NoCarry false}} + +// Inverse z = x^-1 mod q +// note: allocates a big.Int (math/big) +func (z *{{.ElementName}}) Inverse( x *{{.ElementName}}) *{{.ElementName}} { + var _xNonMont big.Int + x.ToBigIntRegular( &_xNonMont) + _xNonMont.ModInverse(&_xNonMont, Modulus()) + z.SetBigInt(&_xNonMont) + return z +} + +{{ else }} + +// Inverse z = x^-1 mod q +// Algorithm 16 in "Efficient Software-Implementation of Finite Fields with Applications to Cryptography" +// if x == 0, sets and returns z = x +func (z *{{.ElementName}}) Inverse(x *{{.ElementName}}) *{{.ElementName}} { + if x.IsZero() { + return z.Set(x) + } + + // initialize u = q + var u = {{.ElementName}}{ + {{- range $i := .NbWordsIndexesFull}} + {{index $.Q $i}},{{end}} + } + + // initialize s = r^2 + var s = {{.ElementName}}{ + {{- range $i := .RSquare}} + {{$i}},{{end}} + } + + // r = 0 + r := {{.ElementName}}{} + + v := *x + + var carry, borrow, t, t2 uint64 + var bigger bool + + for { + for v[0]&1 == 0 { + {{ template "div2" dict "all" . "V" "v"}} + if s[0]&1 == 1 { + {{ template "add_q" dict "all" . "V1" "s" }} + } + {{ template "div2" dict "all" . "V" "s"}} + } + for u[0]&1 == 0 { + {{ template "div2" dict "all" . "V" "u"}} + if r[0]&1 == 1 { + {{ template "add_q" dict "all" . "V1" "r" }} + } + {{ template "div2" dict "all" . "V" "r"}} + } + {{ template "bigger" dict "all" . "V1" "v" "V2" "u"}} + if bigger { + {{ template "sub_noborrow" dict "all" . "V1" "v" "V2" "u" "OmitLast" "true"}} + {{ template "sub_noborrow" dict "all" . "V1" "s" "V2" "r" "OmitLast" "false"}} + if borrow == 1 { + {{ template "add_q" dict "all" . "V1" "s" }} + } + } else { + {{ template "sub_noborrow" dict "all" . "V1" "u" "V2" "v" "OmitLast" "true"}} + {{ template "sub_noborrow" dict "all" . "V1" "r" "V2" "s" "OmitLast" "false"}} + if borrow == 1 { + {{ template "add_q" dict "all" . "V1" "r" }} + } + } + if (u[0] == 1) && ({{- range $i := reverse .NbWordsIndexesNoZero}}u[{{$i}}] {{if eq $i 1}}{{else}} | {{end}}{{end}} ) == 0 { + return z.Set(&r) + } + if (v[0] == 1) && ({{- range $i := reverse .NbWordsIndexesNoZero}}v[{{$i}}] {{if eq $i 1}}{{else}} | {{end}}{{end}} ) == 0 { + return z.Set(&s) + } + } + +} + +{{ end }} + + + + +{{ define "bigger" }} + // {{$.V1}} >= {{$.V2}} + bigger = !({{- range $i := reverse $.all.NbWordsIndexesNoZero}} {{$.V1}}[{{$i}}] < {{$.V2}}[{{$i}}] || ( {{$.V1}}[{{$i}}] == {{$.V2}}[{{$i}}] && ( + {{- end}}{{$.V1}}[0] < {{$.V2}}[0] {{- range $i := $.all.NbWordsIndexesNoZero}} )) {{- end}} ) +{{ end }} + +{{ define "add_q" }} + // {{$.V1}} = {{$.V1}} + q + {{$.V1}}[0], carry = bits.Add64({{$.V1}}[0], {{index $.all.Q 0}}, 0) + {{- range $i := .all.NbWordsIndexesNoZero}} + {{- if eq $i $.all.NbWordsLastIndex}} + {{$.V1}}[{{$i}}], _ = bits.Add64({{$.V1}}[{{$i}}], {{index $.all.Q $i}}, carry) + {{- else}} + {{$.V1}}[{{$i}}], carry = bits.Add64({{$.V1}}[{{$i}}], {{index $.all.Q $i}}, carry) + {{- end}} + {{- end}} +{{ end }} + +{{ define "sub_noborrow" }} + // {{$.V1}} = {{$.V1}} - {{$.V2}} + {{$.V1}}[0], borrow = bits.Sub64({{$.V1}}[0], {{$.V2}}[0], 0) + {{- range $i := .all.NbWordsIndexesNoZero}} + {{- if and (eq $i $.all.NbWordsLastIndex) (eq "true" $.OmitLast)}} + {{$.V1}}[{{$i}}], _ = bits.Sub64({{$.V1}}[{{$i}}], {{$.V2}}[{{$i}}], borrow) + {{- else}} + {{$.V1}}[{{$i}}], borrow = bits.Sub64({{$.V1}}[{{$i}}], {{$.V2}}[{{$i}}], borrow) + {{- end}} + {{- end}} +{{ end }} + + +{{ define "div2" }} + // {{$.V}} = {{$.V}} >> 1 + {{- range $i := reverse .all.NbWordsIndexesNoZero}} + {{- if eq $i $.all.NbWordsLastIndex}} + t2 = {{$.V}}[{{$i}}] << 63 + {{$.V}}[{{$i}}] >>= 1 + {{- else}} + t2 = {{$.V}}[{{$i}}] << 63 + {{$.V}}[{{$i}}] = ({{$.V}}[{{$i}}] >> 1) | t + {{- end}} + t = t2 + {{- end}} + {{$.V}}[0] = ({{$.V}}[0] >> 1) | t +{{ end }} + + +` diff --git a/field/internal/templates/element/mul_cios.go b/field/internal/templates/element/mul_cios.go new file mode 100644 index 0000000000..c7ec046ec2 --- /dev/null +++ b/field/internal/templates/element/mul_cios.go @@ -0,0 +1,66 @@ +package element + +const MulCIOS = ` +{{ define "mul_cios" }} + var t [{{add .all.NbWords 1}}]uint64 + var D uint64 + var m, C uint64 + + {{- range $j := .all.NbWordsIndexesFull}} + // ----------------------------------- + // First loop + {{ if eq $j 0}} + C, t[0] = bits.Mul64({{$.V2}}[{{$j}}], {{$.V1}}[0]) + {{- range $i := $.all.NbWordsIndexesNoZero}} + C, t[{{$i}}] = madd1({{$.V2}}[{{$j}}], {{$.V1}}[{{$i}}], C) + {{- end}} + {{ else }} + C, t[0] = madd1({{$.V2}}[{{$j}}], {{$.V1}}[0], t[0]) + {{- range $i := $.all.NbWordsIndexesNoZero}} + C, t[{{$i}}] = madd2({{$.V2}}[{{$j}}], {{$.V1}}[{{$i}}], t[{{$i}}], C) + {{- end}} + {{ end }} + D = C + + // m = t[0]n'[0] mod W + m = t[0] * {{index $.all.QInverse 0}} + + // ----------------------------------- + // Second loop + C = madd0(m, {{index $.all.Q 0}}, t[0]) + {{- range $i := $.all.NbWordsIndexesNoZero}} + {{if eq $i $.all.NbWordsLastIndex}} + C, t[{{sub $i 1}}] = madd3(m, {{index $.all.Q $i}}, t[{{$i}}], C, t[{{$.all.NbWords}}]) + {{else}} + C, t[{{sub $i 1}}] = madd2(m, {{index $.all.Q $i}}, t[{{$i}}], C) + {{- end}} + {{- end}} + t[{{sub $.all.NbWords 1}}], t[{{$.all.NbWords}}] = bits.Add64(D, C, 0) + {{- end}} + + + if t[{{$.all.NbWords}}] != 0 { + // we need to reduce, we have a result on {{add 1 $.all.NbWords}} words + var b uint64 + z[0], b = bits.Sub64(t[0], {{index $.all.Q 0}}, 0) + {{- range $i := .all.NbWordsIndexesNoZero}} + {{- if eq $i $.all.NbWordsLastIndex}} + z[{{$i}}], _ = bits.Sub64(t[{{$i}}], {{index $.all.Q $i}}, b) + {{- else }} + z[{{$i}}], b = bits.Sub64(t[{{$i}}], {{index $.all.Q $i}}, b) + {{- end}} + {{- end}} + {{if $.NoReturn }} + return + {{else}} + return z + {{end}} + } + + // copy t into z + {{- range $i := $.all.NbWordsIndexesFull}} + z[{{$i}}] = t[{{$i}}] + {{- end}} + +{{ end }} +` diff --git a/field/internal/templates/element/mul_nocarry.go b/field/internal/templates/element/mul_nocarry.go new file mode 100644 index 0000000000..53dea7d308 --- /dev/null +++ b/field/internal/templates/element/mul_nocarry.go @@ -0,0 +1,52 @@ +package element + +// MulNoCarry see https://hackmd.io/@zkteam/modular_multiplication for more info on the algorithm +const MulNoCarry = ` +{{ define "mul_nocarry" }} +var t [{{.all.NbWords}}]uint64 +var c [3]uint64 +{{- range $j := .all.NbWordsIndexesFull}} +{ + // round {{$j}} + v := {{$.V1}}[{{$j}}] + {{- if eq $j 0}} + c[1], c[0] = bits.Mul64(v, {{$.V2}}[0]) + m := c[0] * {{index $.all.QInverse 0}} + c[2] = madd0(m, {{index $.all.Q 0}}, c[0]) + {{- range $i := $.all.NbWordsIndexesNoZero}} + c[1], c[0] = madd1(v, {{$.V2}}[{{$i}}], c[1]) + {{- if eq $i $.all.NbWordsLastIndex}} + t[{{sub $.all.NbWords 1}}], t[{{sub $i 1}}] = madd3(m, {{index $.all.Q $i}}, c[0], c[2], c[1]) + {{- else}} + c[2], t[{{sub $i 1}}] = madd2(m, {{index $.all.Q $i}}, c[2], c[0]) + {{- end}} + {{- end}} + {{- else if eq $j $.all.NbWordsLastIndex}} + c[1], c[0] = madd1(v, {{$.V2}}[0], t[0]) + m := c[0] * {{index $.all.QInverse 0}} + c[2] = madd0(m, {{index $.all.Q 0}}, c[0]) + {{- range $i := $.all.NbWordsIndexesNoZero}} + c[1], c[0] = madd2(v, {{$.V2}}[{{$i}}], c[1], t[{{$i}}]) + {{- if eq $i $.all.NbWordsLastIndex}} + z[{{sub $.all.NbWords 1}}], z[{{sub $i 1}}] = madd3(m, {{index $.all.Q $i}}, c[0], c[2], c[1]) + {{- else}} + c[2], z[{{sub $i 1}}] = madd2(m, {{index $.all.Q $i}}, c[2], c[0]) + {{- end}} + {{- end}} + {{- else}} + c[1], c[0] = madd1(v, {{$.V2}}[0], t[0]) + m := c[0] * {{index $.all.QInverse 0}} + c[2] = madd0(m, {{index $.all.Q 0}}, c[0]) + {{- range $i := $.all.NbWordsIndexesNoZero}} + c[1], c[0] = madd2(v, {{$.V2}}[{{$i}}], c[1], t[{{$i}}]) + {{- if eq $i $.all.NbWordsLastIndex}} + t[{{sub $.all.NbWords 1}}], t[{{sub $i 1}}] = madd3(m, {{index $.all.Q $i}}, c[0], c[2], c[1]) + {{- else}} + c[2], t[{{sub $i 1}}] = madd2(m, {{index $.all.Q $i}}, c[2], c[0]) + {{- end}} + {{- end}} + {{- end }} +} +{{- end}} +{{ end }} +` diff --git a/field/internal/templates/element/ops.go b/field/internal/templates/element/ops.go new file mode 100644 index 0000000000..067e345b77 --- /dev/null +++ b/field/internal/templates/element/ops.go @@ -0,0 +1,40 @@ +package element + +// OpsAMD64 is included with AMD64 builds (regardless of architecture or if F.ASM is set) +const OpsAMD64 = ` + +{{if .ASM}} + +//go:noescape +func MulBy3(x *{{.ElementName}}) + +//go:noescape +func MulBy5(x *{{.ElementName}}) + +//go:noescape +func add(res,x,y *{{.ElementName}}) + +//go:noescape +func sub(res,x,y *{{.ElementName}}) + +//go:noescape +func neg(res,x *{{.ElementName}}) + +//go:noescape +func double(res,x *{{.ElementName}}) + +//go:noescape +func mul(res,x,y *{{.ElementName}}) + +//go:noescape +func fromMont(res *{{.ElementName}}) + +//go:noescape +func reduce(res *{{.ElementName}}) + + +{{end}} + + + +` diff --git a/field/internal/templates/element/ops_generic.go b/field/internal/templates/element/ops_generic.go new file mode 100644 index 0000000000..2cfd99380f --- /dev/null +++ b/field/internal/templates/element/ops_generic.go @@ -0,0 +1,55 @@ +package element + +const OpsNoAsm = ` +// /!\ WARNING /!\ +// this code has not been audited and is provided as-is. In particular, +// there is no security guarantees such as constant time implementation +// or side-channel attack resistance +// /!\ WARNING /!\ + + +// MulBy3 x *= 3 +func MulBy3(x *{{.ElementName}}) { + mulByConstant(x, 3) +} + +// MulBy5 x *= 5 +func MulBy5(x *{{.ElementName}}) { + mulByConstant(x, 5) +} + + +func mul(z, x, y *{{.ElementName}}) { + _mulGeneric(z, x, y) +} + +// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation +// sets and returns z = z * 1 +func fromMont(z *{{.ElementName}} ) { + _fromMontGeneric(z) +} + +func add(z, x, y *{{.ElementName}}) { + _addGeneric(z,x,y) +} + +func double(z, x *{{.ElementName}}) { + _doubleGeneric(z,x) +} + + +func sub(z, x, y *{{.ElementName}}) { + _subGeneric(z,x,y) +} + +func neg(z, x *{{.ElementName}}) { + _negGeneric(z,x) +} + + +func reduce(z *{{.ElementName}}) { + _reduceGeneric(z) +} + + +` diff --git a/field/internal/templates/element/reduce.go b/field/internal/templates/element/reduce.go new file mode 100644 index 0000000000..f1c9a75251 --- /dev/null +++ b/field/internal/templates/element/reduce.go @@ -0,0 +1,21 @@ +package element + +const Reduce = ` +{{ define "reduce" }} +// if z > q --> z -= q +// note: this is NOT constant time +if !({{- range $i := reverse .NbWordsIndexesNoZero}} z[{{$i}}] < {{index $.Q $i}} || ( z[{{$i}}] == {{index $.Q $i}} && ( +{{- end}}z[0] < {{index $.Q 0}} {{- range $i := .NbWordsIndexesNoZero}} )) {{- end}} ){ + var b uint64 + z[0], b = bits.Sub64(z[0], {{index $.Q 0}}, 0) + {{- range $i := .NbWordsIndexesNoZero}} + {{- if eq $i $.NbWordsLastIndex}} + z[{{$i}}], _ = bits.Sub64(z[{{$i}}], {{index $.Q $i}}, b) + {{- else }} + z[{{$i}}], b = bits.Sub64(z[{{$i}}], {{index $.Q $i}}, b) + {{- end}} + {{- end}} +} +{{- end }} + +` diff --git a/field/internal/templates/element/sqrt.go b/field/internal/templates/element/sqrt.go new file mode 100644 index 0000000000..16b219f5bf --- /dev/null +++ b/field/internal/templates/element/sqrt.go @@ -0,0 +1,139 @@ +package element + +const Sqrt = ` + +var ( + _bLegendreExponent{{.ElementName}} *big.Int + _bSqrtExponent{{.ElementName}} *big.Int +) + +func init() { + _bLegendreExponent{{.ElementName}}, _ = new(big.Int).SetString("{{.LegendreExponent}}", 16) + {{- if .SqrtQ3Mod4}} + const sqrtExponent{{.ElementName}} = "{{.SqrtQ3Mod4Exponent}}" + {{- else if .SqrtAtkin}} + const sqrtExponent{{.ElementName}} = "{{.SqrtAtkinExponent}}" + {{- else if .SqrtTonelliShanks}} + const sqrtExponent{{.ElementName}} = "{{.SqrtSMinusOneOver2}}" + {{- end }} + _bSqrtExponent{{.ElementName}}, _ = new(big.Int).SetString(sqrtExponent{{.ElementName}}, 16) +} + +// Legendre returns the Legendre symbol of z (either +1, -1, or 0.) +func (z *{{.ElementName}}) Legendre() int { + var l {{.ElementName}} + // z^((q-1)/2) + l.Exp(*z, _bLegendreExponent{{.ElementName}}) + + if l.IsZero() { + return 0 + } + + // if l == 1 + if {{- range $i := reverse .NbWordsIndexesNoZero}}(l[{{$i}}] == {{index $.One $i}}) &&{{end}}(l[0] == {{index $.One 0}}) { + return 1 + } + return -1 +} + +// Sqrt z = √x mod q +// if the square root doesn't exist (x is not a square mod q) +// Sqrt leaves z unchanged and returns nil +func (z *{{.ElementName}}) Sqrt(x *{{.ElementName}}) *{{.ElementName}} { + {{- if .SqrtQ3Mod4}} + // q ≡ 3 (mod 4) + // using z ≡ ± x^((p+1)/4) (mod q) + var y, square {{.ElementName}} + y.Exp(*x, _bSqrtExponent{{.ElementName}}) + // as we didn't compute the legendre symbol, ensure we found y such that y * y = x + square.Square(&y) + if square.Equal(x) { + return z.Set(&y) + } + return nil + {{- else if .SqrtAtkin}} + // q ≡ 5 (mod 8) + // see modSqrt5Mod8Prime in math/big/int.go + var one, alpha, beta, tx, square {{.ElementName}} + one.SetOne() + tx.Double(x) + alpha.Exp(tx, _bSqrtExponent{{.ElementName}}) + beta.Square(&alpha). + Mul(&beta, &tx). + Sub(&beta, &one). + Mul(&beta, x). + Mul(&beta, &alpha) + + // as we didn't compute the legendre symbol, ensure we found beta such that beta * beta = x + square.Square(&beta) + if square.Equal(x) { + return z.Set(&beta) + } + return nil + {{- else if .SqrtTonelliShanks}} + // q ≡ 1 (mod 4) + // see modSqrtTonelliShanks in math/big/int.go + // using https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf + + var y, b,t, w {{.ElementName}} + // w = x^((s-1)/2)) + w.Exp(*x, _bSqrtExponent{{.ElementName}}) + + // y = x^((s+1)/2)) = w * x + y.Mul(x, &w) + + // b = x^s = w * w * x = y * x + b.Mul(&w, &y) + + // g = nonResidue ^ s + var g = {{.ElementName}}{ + {{- range $i := .SqrtG}} + {{$i}},{{end}} + } + r := uint64({{.SqrtE}}) + + // compute legendre symbol + // t = x^((q-1)/2) = r-1 squaring of x^s + t = b + for i:=uint64(0); i < r-1; i++ { + t.Square(&t) + } + if t.IsZero() { + return z.SetZero() + } + if !({{- range $i := reverse .NbWordsIndexesNoZero}}(t[{{$i}}] == {{index $.One $i}}) &&{{end}}(t[0] == {{index $.One 0}})) { + // t != 1, we don't have a square root + return nil + } + for { + var m uint64 + t = b + + // for t != 1 + for !({{- range $i := reverse .NbWordsIndexesNoZero}}(t[{{$i}}] == {{index $.One $i}}) &&{{end}}(t[0] == {{index $.One 0}})) { + t.Square(&t) + m++ + } + + if m == 0 { + return z.Set(&y) + } + // t = g^(2^(r-m-1)) mod q + ge := int(r - m - 1) + t = g + for ge > 0 { + t.Square(&t) + ge-- + } + + g.Square(&t) + y.Mul(&y, &t) + b.Mul(&b, &g) + r = m + } + + {{- else}} + panic("not implemented") + {{- end}} +} +` diff --git a/field/internal/templates/element/tests.go b/field/internal/templates/element/tests.go new file mode 100644 index 0000000000..24425f068b --- /dev/null +++ b/field/internal/templates/element/tests.go @@ -0,0 +1,1009 @@ +package element + +const Test = ` + +import ( + "crypto/rand" + "math/big" + "math/bits" + "testing" + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" +) + + +// ------------------------------------------------------------------------------------------------- +// benchmarks +// most benchmarks are rudimentary and should sample a large number of random inputs +// or be run multiple times to ensure it didn't measure the fastest path of the function + +var benchRes{{.ElementName}} {{.ElementName}} + +func Benchmark{{toTitle .ElementName}}SetBytes(b *testing.B) { + var x {{.ElementName}} + x.SetRandom() + bb := x.Bytes() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.SetBytes(bb[:]) + } + +} + +func Benchmark{{toTitle .ElementName}}Inverse(b *testing.B) { + var x {{.ElementName}} + x.SetRandom() + benchRes{{.ElementName}}.SetRandom() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Inverse(&x) + } + +} + + +func Benchmark{{toTitle .ElementName}}Exp(b *testing.B) { + var x {{.ElementName}} + x.SetRandom() + benchRes{{.ElementName}}.SetRandom() + b1, _ := rand.Int(rand.Reader, Modulus()) + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Exp(x, b1) + } +} + + +func Benchmark{{toTitle .ElementName}}Double(b *testing.B) { + benchRes{{.ElementName}}.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Double(&benchRes{{.ElementName}}) + } +} + + +func Benchmark{{toTitle .ElementName}}Add(b *testing.B) { + var x {{.ElementName}} + x.SetRandom() + benchRes{{.ElementName}}.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Add(&x, &benchRes{{.ElementName}}) + } +} + +func Benchmark{{toTitle .ElementName}}Sub(b *testing.B) { + var x {{.ElementName}} + x.SetRandom() + benchRes{{.ElementName}}.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Sub(&x, &benchRes{{.ElementName}}) + } +} + +func Benchmark{{toTitle .ElementName}}Neg(b *testing.B) { + benchRes{{.ElementName}}.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Neg(&benchRes{{.ElementName}}) + } +} + +func Benchmark{{toTitle .ElementName}}Div(b *testing.B) { + var x {{.ElementName}} + x.SetRandom() + benchRes{{.ElementName}}.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Div(&x, &benchRes{{.ElementName}}) + } +} + + +func Benchmark{{toTitle .ElementName}}FromMont(b *testing.B) { + benchRes{{.ElementName}}.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.FromMont() + } +} + +func Benchmark{{toTitle .ElementName}}ToMont(b *testing.B) { + benchRes{{.ElementName}}.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.ToMont() + } +} +func Benchmark{{toTitle .ElementName}}Square(b *testing.B) { + benchRes{{.ElementName}}.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Square(&benchRes{{.ElementName}}) + } +} + +func Benchmark{{toTitle .ElementName}}Sqrt(b *testing.B) { + var a {{.ElementName}} + a.SetRandom() + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Sqrt(&a) + } +} + +func Benchmark{{toTitle .ElementName}}Mul(b *testing.B) { + x := {{.ElementName}}{ + {{- range $i := .RSquare}} + {{$i}},{{end}} + } + benchRes{{.ElementName}}.SetOne() + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Mul(&benchRes{{.ElementName}}, &x) + } +} + + + +func Benchmark{{toTitle .ElementName}}Cmp(b *testing.B) { + x := {{.ElementName}}{ + {{- range $i := .RSquare}} + {{$i}},{{end}} + } + benchRes{{.ElementName}} = x + benchRes{{.ElementName}}[0] = 0 + b.ResetTimer() + for i := 0; i < b.N; i++ { + benchRes{{.ElementName}}.Cmp(&x) + } +} + + +func Test{{toTitle .ElementName}}Cmp(t *testing.T) { + var x, y {{.ElementName}} + + if x.Cmp(&y) != 0 { + t.Fatal("x == y") + } + + one := One() + y.Sub(&y, &one) + + if x.Cmp(&y) != -1 { + t.Fatal("x < y") + } + if y.Cmp(&x) != 1 { + t.Fatal("x < y") + } + + x = y + if x.Cmp(&y) != 0 { + t.Fatal("x == y") + } + + x.Sub(&x, &one) + if x.Cmp(&y) != -1 { + t.Fatal("x < y") + } + if y.Cmp(&x) != 1 { + t.Fatal("x < y") + } +} + + +func Test{{toTitle .ElementName}}IsRandom(t *testing.T) { + for i := 0; i < 50; i++ { + var x, y {{.ElementName}} + x.SetRandom() + y.SetRandom() + if x.Equal(&y) { + t.Fatal("2 random numbers are unlikely to be equal") + } + } +} + + +// ------------------------------------------------------------------------------------------------- +// Gopter tests +// most of them are generated with a template + +{{ if gt .NbWords 6}} +const ( + nbFuzzShort = 20 + nbFuzz = 100 +) +{{else}} +const ( + nbFuzzShort = 200 + nbFuzz = 1000 +) +{{end}} + +// special values to be used in tests +var staticTestValues []{{.ElementName}} + +func init() { + staticTestValues = append(staticTestValues, {{.ElementName}}{}) // zero + staticTestValues = append(staticTestValues, One()) // one + staticTestValues = append(staticTestValues, rSquare) // r^2 + var e, one {{.ElementName}} + one.SetOne() + e.Sub(&q{{.ElementName}}, &one) + staticTestValues = append(staticTestValues, e) // q - 1 + e.Double(&one) + staticTestValues = append(staticTestValues, e) // 2 + + { + a := q{{.ElementName}} + a[{{.NbWordsLastIndex}}]-- + staticTestValues = append(staticTestValues, a) + } + { + a := q{{.ElementName}} + a[0]-- + staticTestValues = append(staticTestValues, a) + } + + for i:=0; i <=3 ; i++ { + staticTestValues = append(staticTestValues, {{.ElementName}}{uint64(i)}) + staticTestValues = append(staticTestValues, {{.ElementName}}{0, uint64(i)}) + } + + { + a := q{{.ElementName}} + a[{{.NbWordsLastIndex}}]-- + a[0]++ + staticTestValues = append(staticTestValues, a) + } + +} + +func Test{{toTitle .ElementName}}NegZero(t *testing.T) { + var a, b {{.ElementName}} + b.SetZero() + for a.IsZero() { + a.SetRandom() + } + a.Neg(&b) + if !a.IsZero() { + t.Fatal("neg(0) != 0") + } +} + +func Test{{toTitle .ElementName}}Reduce(t *testing.T) { + testValues := make([]{{.ElementName}}, len(staticTestValues)) + copy(testValues, staticTestValues) + + for _, s := range testValues { + expected := s + reduce(&s) + _reduceGeneric(&expected) + if !s.Equal(&expected) { + t.Fatal("reduce failed: asm and generic impl don't match") + } + } + + + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := genFull() + + properties.Property("reduce should output a result smaller than modulus", prop.ForAll( + func(a {{.ElementName}}) bool { + b := a + reduce(&a) + _reduceGeneric(&b) + return !a.biggerOrEqualModulus() && a.Equal(&b) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + // if we have ADX instruction enabled, test both path in assembly + if supportAdx { + t.Log("disabling ADX") + supportAdx = false + properties.TestingRun(t, gopter.ConsoleReporter(false)) + supportAdx = true + } + +} + +func Test{{toTitle .ElementName}}Bytes(t *testing.T) { + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := gen() + + properties.Property("SetBytes(Bytes()) should stayt constant", prop.ForAll( + func(a testPair{{.ElementName}}) bool { + var b {{.ElementName}} + bytes := a.element.Bytes() + b.SetBytes(bytes[:]) + return a.element.Equal(&b) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + +func Test{{toTitle .ElementName}}InverseExp(t *testing.T) { + // inverse must be equal to exp^-2 + exp := Modulus() + exp.Sub(exp, new(big.Int).SetUint64(2)) + + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := gen() + + properties.Property("inv == exp^-2", prop.ForAll( + func(a testPair{{.ElementName}}) bool { + var b {{.ElementName}} + b.Set(&a.element) + a.element.Inverse(&a.element) + b.Exp(b, exp) + + return a.element.Equal(&b) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + // if we have ADX instruction enabled, test both path in assembly + if supportAdx { + t.Log("disabling ADX") + supportAdx = false + properties.TestingRun(t, gopter.ConsoleReporter(false)) + supportAdx = true + } +} + +func Test{{toTitle .ElementName}}MulByConstants(t *testing.T) { + + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := gen() + + implemented := []uint8{0,1,2,3,5} + properties.Property("mulByConstant", prop.ForAll( + func(a testPair{{.ElementName}}) bool { + for _, c := range implemented { + var constant {{.ElementName}} + constant.SetUint64(uint64(c)) + + b := a.element + b.Mul(&b, &constant) + + aa := a.element + mulByConstant(&aa, c) + + if !aa.Equal(&b) { + return false + } + } + + return true + }, + genA, + )) + + + properties.Property("MulBy3(x) == Mul(x, 3)", prop.ForAll( + func(a testPair{{.ElementName}}) bool { + var constant {{.ElementName}} + constant.SetUint64(3) + + b := a.element + b.Mul(&b, &constant) + + MulBy3(&a.element) + + return a.element.Equal(&b) + }, + genA, + )) + + properties.Property("MulBy5(x) == Mul(x, 5)", prop.ForAll( + func(a testPair{{.ElementName}}) bool { + var constant {{.ElementName}} + constant.SetUint64(5) + + b := a.element + b.Mul(&b, &constant) + + MulBy5(&a.element) + + return a.element.Equal(&b) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + // if we have ADX instruction enabled, test both path in assembly + if supportAdx { + t.Log("disabling ADX") + supportAdx = false + properties.TestingRun(t, gopter.ConsoleReporter(false)) + supportAdx = true + } + +} + +func Test{{toTitle .ElementName}}Legendre(t *testing.T) { + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := gen() + + properties.Property("legendre should output same result than big.Int.Jacobi", prop.ForAll( + func(a testPair{{.ElementName}}) bool { + return a.element.Legendre() == big.Jacobi(&a.bigint, Modulus()) + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + // if we have ADX instruction enabled, test both path in assembly + if supportAdx { + t.Log("disabling ADX") + supportAdx = false + properties.TestingRun(t, gopter.ConsoleReporter(false)) + supportAdx = true + } + +} + +func Test{{toTitle .ElementName}}LexicographicallyLargest(t *testing.T) { + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := gen() + + properties.Property("element.Cmp should match LexicographicallyLargest output", prop.ForAll( + func(a testPair{{.ElementName}}) bool { + var negA {{.ElementName}} + negA.Neg(&a.element) + + cmpResult := a.element.Cmp(&negA) + lResult := a.element.LexicographicallyLargest() + + if lResult && cmpResult == 1 { + return true + } + if !lResult && cmpResult !=1 { + return true + } + return false + }, + genA, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + // if we have ADX instruction enabled, test both path in assembly + if supportAdx { + t.Log("disabling ADX") + supportAdx = false + properties.TestingRun(t, gopter.ConsoleReporter(false)) + supportAdx = true + } + +} + + +{{template "testBinaryOp" dict "all" . "Op" "Add" "GenericOp" "_addGeneric"}} +{{template "testBinaryOp" dict "all" . "Op" "Sub" "GenericOp" "_subGeneric"}} +{{template "testBinaryOp" dict "all" . "Op" "Mul" "GenericOp" "_mulGeneric"}} +{{template "testBinaryOp" dict "all" . "Op" "Div"}} +{{template "testBinaryOp" dict "all" . "Op" "Exp"}} + +{{template "testUnaryOp" dict "all" . "Op" "Square" }} +{{template "testUnaryOp" dict "all" . "Op" "Inverse"}} +{{template "testUnaryOp" dict "all" . "Op" "Sqrt"}} +{{template "testUnaryOp" dict "all" . "Op" "Double" "GenericOp" "_doubleGeneric"}} +{{template "testUnaryOp" dict "all" . "Op" "Neg" "GenericOp" "_negGeneric"}} + +{{ define "testBinaryOp" }} + +func Test{{toTitle .all.ElementName}}{{.Op}}(t *testing.T) { + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + + properties := gopter.NewProperties(parameters) + + genA := gen() + genB := gen() + + properties.Property("{{.Op}}: having the receiver as operand should output the same result", prop.ForAll( + func(a, b testPair{{.all.ElementName}}) bool { + var c, d {{.all.ElementName}} + d.Set(&a.element) + {{if eq .Op "Exp"}} + c.{{.Op}}(a.element, &b.bigint) + a.element.{{.Op}}(a.element, &b.bigint) + b.element.{{.Op}}(d, &b.bigint) + {{else}} + c.{{.Op}}(&a.element, &b.element) + a.element.{{.Op}}(&a.element, &b.element) + b.element.{{.Op}}(&d, &b.element) + {{end}} + return a.element.Equal(&b.element) && a.element.Equal(&c) && b.element.Equal(&c) + }, + genA, + genB, + )) + + properties.Property("{{.Op}}: operation result must match big.Int result", prop.ForAll( + func(a, b testPair{{.all.ElementName}}) bool { + { + var c {{.all.ElementName}} + {{if eq .Op "Exp"}} + c.{{.Op}}(a.element, &b.bigint) + {{else}} + c.{{.Op}}(&a.element, &b.element) + {{end}} + var d, e big.Int + {{- if eq .Op "Div"}} + d.ModInverse(&b.bigint, Modulus()) + d.Mul(&d, &a.bigint).Mod(&d, Modulus()) + {{- else if eq .Op "Exp"}} + d.Exp(&a.bigint, &b.bigint, Modulus()) + {{- else}} + d.{{.Op}}(&a.bigint, &b.bigint).Mod(&d, Modulus()) + {{- end }} + + + if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 { + return false + } + } + + // fixed elements + // a is random + // r takes special values + testValues := make([]{{.all.ElementName}}, len(staticTestValues)) + copy(testValues, staticTestValues) + + for _, r := range testValues { + var d, e, rb big.Int + r.ToBigIntRegular(&rb) + + var c {{.all.ElementName}} + {{- if eq .Op "Div"}} + c.{{.Op}}(&a.element, &r) + d.ModInverse(&rb, Modulus()) + d.Mul(&d, &a.bigint).Mod(&d, Modulus()) + {{- else if eq .Op "Exp"}} + c.{{.Op}}(a.element, &rb) + d.Exp(&a.bigint, &rb, Modulus()) + {{- else}} + c.{{.Op}}(&a.element, &r) + d.{{.Op}}(&a.bigint, &rb).Mod(&d, Modulus()) + {{- end }} + + {{if .GenericOp}} + // checking generic impl against asm path + var cGeneric {{.all.ElementName}} + {{.GenericOp}}(&cGeneric, &a.element, &r) + if !cGeneric.Equal(&c) { + // need to give context to failing error. + return false + } + {{end}} + + if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 { + return false + } + } + return true + }, + genA, + genB, + )) + + properties.Property("{{.Op}}: operation result must be smaller than modulus", prop.ForAll( + func(a, b testPair{{.all.ElementName}}) bool { + var c {{.all.ElementName}} + {{if eq .Op "Exp"}} + c.{{.Op}}(a.element, &b.bigint) + {{else}} + c.{{.Op}}(&a.element, &b.element) + {{end}} + return !c.biggerOrEqualModulus() + }, + genA, + genB, + )) + + {{if .GenericOp}} + properties.Property("{{.Op}}: assembly implementation must be consistent with generic one", prop.ForAll( + func(a, b testPair{{.all.ElementName}}) bool { + var c,d {{.all.ElementName}} + c.{{.Op}}(&a.element, &b.element) + {{.GenericOp}}(&d, &a.element, &b.element) + return c.Equal(&d) + }, + genA, + genB, + )) + + {{end}} + + + specialValueTest := func() { + // test special values against special values + testValues := make([]{{.all.ElementName}}, len(staticTestValues)) + copy(testValues, staticTestValues) + + for _, a := range testValues { + var aBig big.Int + a.ToBigIntRegular(&aBig) + for _, b := range testValues { + + var bBig, d, e big.Int + b.ToBigIntRegular(&bBig) + + var c {{.all.ElementName}} + + + + {{- if eq .Op "Div"}} + c.{{.Op}}(&a, &b) + d.ModInverse(&bBig, Modulus()) + d.Mul(&d, &aBig).Mod(&d, Modulus()) + {{- else if eq .Op "Exp"}} + c.{{.Op}}(a, &bBig) + d.Exp(&aBig, &bBig, Modulus()) + {{- else}} + c.{{.Op}}(&a, &b) + d.{{.Op}}(&aBig, &bBig).Mod(&d, Modulus()) + {{- end }} + + {{if .GenericOp}} + // checking asm against generic impl + var cGeneric {{.all.ElementName}} + {{.GenericOp}}(&cGeneric, &a, &b) + if !cGeneric.Equal(&c) { + t.Fatal("{{.Op}} failed special test values: asm and generic impl don't match") + } + {{end}} + + + if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 { + t.Fatal("{{.Op}} failed special test values") + } + } + } + } + + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + specialValueTest() + // if we have ADX instruction enabled, test both path in assembly + if supportAdx { + t.Log("disabling ADX") + supportAdx = false + properties.TestingRun(t, gopter.ConsoleReporter(false)) + specialValueTest() + supportAdx = true + } +} + +{{ end }} + + +{{ define "testUnaryOp" }} + +func Test{{toTitle .all.ElementName}}{{.Op}}(t *testing.T) { + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := gen() + + properties.Property("{{.Op}}: having the receiver as operand should output the same result", prop.ForAll( + func(a testPair{{.all.ElementName}}) bool { + {{if eq .Op "Sqrt"}} + b := a.element + {{else}} + var b {{.all.ElementName}} + {{end}} + b.{{.Op}}(&a.element) + a.element.{{.Op}}(&a.element) + return a.element.Equal(&b) + }, + genA, + )) + + properties.Property("{{.Op}}: operation result must match big.Int result", prop.ForAll( + func(a testPair{{.all.ElementName}}) bool { + var c {{.all.ElementName}} + c.{{.Op}}(&a.element) + + var d, e big.Int + {{- if eq .Op "Square"}} + d.Mul(&a.bigint, &a.bigint).Mod(&d, Modulus()) + {{- else if eq .Op "Inverse"}} + d.ModInverse(&a.bigint, Modulus()) + {{- else if eq .Op "Sqrt"}} + d.ModSqrt(&a.bigint, Modulus()) + {{- else if eq .Op "Double"}} + d.Lsh(&a.bigint, 1).Mod(&d, Modulus()) + {{- else if eq .Op "Neg"}} + d.Neg(&a.bigint).Mod(&d, Modulus()) + {{- end }} + + + return c.FromMont().ToBigInt(&e).Cmp(&d) == 0 + }, + genA, + )) + + properties.Property("{{.Op}}: operation result must be smaller than modulus", prop.ForAll( + func(a testPair{{.all.ElementName}}) bool { + var c {{.all.ElementName}} + c.{{.Op}}(&a.element) + return !c.biggerOrEqualModulus() + }, + genA, + )) + + {{if .GenericOp}} + properties.Property("{{.Op}}: assembly implementation must be consistent with generic one", prop.ForAll( + func(a testPair{{.all.ElementName}}) bool { + var c,d {{.all.ElementName}} + c.{{.Op}}(&a.element) + {{.GenericOp}}(&d, &a.element) + return c.Equal(&d) + }, + genA, + )) + + {{end}} + + + specialValueTest := func() { + // test special values + testValues := make([]{{.all.ElementName}}, len(staticTestValues)) + copy(testValues, staticTestValues) + + for _, a := range testValues { + var aBig big.Int + a.ToBigIntRegular(&aBig) + var c {{.all.ElementName}} + c.{{.Op}}(&a) + + var d, e big.Int + {{- if eq .Op "Square"}} + d.Mul(&aBig, &aBig).Mod(&d, Modulus()) + {{- else if eq .Op "Inverse"}} + d.ModInverse(&aBig, Modulus()) + {{- else if eq .Op "Sqrt"}} + d.ModSqrt(&aBig, Modulus()) + {{- else if eq .Op "Double"}} + d.Lsh(&aBig, 1).Mod(&d, Modulus()) + {{- else if eq .Op "Neg"}} + d.Neg(&aBig).Mod(&d, Modulus()) + {{- end }} + + {{if .GenericOp}} + // checking asm against generic impl + var cGeneric {{.all.ElementName}} + {{.GenericOp}}(&cGeneric, &a) + if !cGeneric.Equal(&c) { + t.Fatal("{{.Op}} failed special test values: asm and generic impl don't match") + } + {{end}} + + + if c.FromMont().ToBigInt(&e).Cmp(&d) != 0 { + t.Fatal("{{.Op}} failed special test values") + } + } + } + + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + specialValueTest() + // if we have ADX instruction enabled, test both path in assembly + if supportAdx { + supportAdx = false + t.Log("disabling ADX") + properties.TestingRun(t, gopter.ConsoleReporter(false)) + specialValueTest() + supportAdx = true + } +} + +{{ end }} + + +func Test{{toTitle .ElementName}}FromMont(t *testing.T) { + + parameters := gopter.DefaultTestParameters() + if testing.Short() { + parameters.MinSuccessfulTests = nbFuzzShort + } else { + parameters.MinSuccessfulTests = nbFuzz + } + + properties := gopter.NewProperties(parameters) + + genA := gen() + + properties.Property("Assembly implementation must be consistent with generic one", prop.ForAll( + func(a testPair{{.ElementName}}) bool { + c := a.element + d := a.element + c.FromMont() + _fromMontGeneric(&d) + return c.Equal(&d) + }, + genA, + )) + + properties.Property("x.FromMont().ToMont() == x", prop.ForAll( + func(a testPair{{.ElementName}}) bool { + c := a.element + c.FromMont().ToMont() + return c.Equal(&a.element) + }, + genA, + )) + + + properties.TestingRun(t, gopter.ConsoleReporter(false)) +} + + + + + +type testPair{{.ElementName}} struct { + element {{.ElementName}} + bigint big.Int +} + +func (z *{{.ElementName}}) biggerOrEqualModulus() bool { + {{- range $i := reverse .NbWordsIndexesNoZero}} + if z[{{$i}}] > q{{$.ElementName}}[{{$i}}] { + return true + } + if z[{{$i}}] < q{{$.ElementName}}[{{$i}}] { + return false + } + {{end}} + + return z[0] >= q{{.ElementName}}[0] +} + +func gen() gopter.Gen { + return func(genParams *gopter.GenParameters) *gopter.GenResult { + var g testPair{{.ElementName}} + + g.element = {{.ElementName}}{ + {{- range $i := .NbWordsIndexesFull}} + genParams.NextUint64(),{{end}} + } + if q{{.ElementName}}[{{.NbWordsLastIndex}}] != ^uint64(0) { + g.element[{{.NbWordsLastIndex}}] %= (q{{.ElementName}}[{{.NbWordsLastIndex}}] +1 ) + } + + + for g.element.biggerOrEqualModulus() { + g.element = {{.ElementName}}{ + {{- range $i := .NbWordsIndexesFull}} + genParams.NextUint64(),{{end}} + } + if q{{.ElementName}}[{{.NbWordsLastIndex}}] != ^uint64(0) { + g.element[{{.NbWordsLastIndex}}] %= (q{{.ElementName}}[{{.NbWordsLastIndex}}] +1 ) + } + } + + g.element.ToBigIntRegular(&g.bigint) + genResult := gopter.NewGenResult(g, gopter.NoShrinker) + return genResult + } +} + + +func genFull() gopter.Gen { + return func(genParams *gopter.GenParameters) *gopter.GenResult { + + genRandomFq := func() {{.ElementName}} { + var g {{.ElementName}} + + g = {{.ElementName}}{ + {{- range $i := .NbWordsIndexesFull}} + genParams.NextUint64(),{{end}} + } + + if q{{.ElementName}}[{{.NbWordsLastIndex}}] != ^uint64(0) { + g[{{.NbWordsLastIndex}}] %= (q{{.ElementName}}[{{.NbWordsLastIndex}}] +1 ) + } + + for g.biggerOrEqualModulus() { + g = {{.ElementName}}{ + {{- range $i := .NbWordsIndexesFull}} + genParams.NextUint64(),{{end}} + } + if q{{.ElementName}}[{{.NbWordsLastIndex}}] != ^uint64(0) { + g[{{.NbWordsLastIndex}}] %= (q{{.ElementName}}[{{.NbWordsLastIndex}}] +1 ) + } + } + + return g + } + a := genRandomFq() + + var carry uint64 + {{- range $i := .NbWordsIndexesFull}} + {{- if eq $i $.NbWordsLastIndex}} + a[{{$i}}], _ = bits.Add64(a[{{$i}}], q{{$.ElementName}}[{{$i}}], carry) + {{- else}} + a[{{$i}}], carry = bits.Add64(a[{{$i}}], q{{$.ElementName}}[{{$i}}], carry) + {{- end}} + {{- end}} + + genResult := gopter.NewGenResult(a, gopter.NoShrinker) + return genResult + } +} + + +` diff --git a/go.mod b/go.mod index e6e8056c41..1197dd86a8 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,10 @@ -module github.com/consensys/gurvy +module github.com/consensys/gnark-crypto -go 1.15 +go 1.16 require ( - github.com/consensys/bavard v0.1.8-0.20210302234946-daa97270b001 - github.com/consensys/goff v0.3.13-0.20210309040837-23eea852ae42 - github.com/ethereum/go-ethereum v1.9.25 - github.com/kilic/bls12-381 v0.0.0-20201226121925-69dacb279461 + github.com/consensys/bavard v0.1.8-0.20210329205436-c3e862ba4e5f github.com/leanovate/gopter v0.2.9 - golang.org/x/sys v0.0.0-20210303074136-134d130e1a04 - gopkg.in/yaml.v2 v2.4.0 // indirect + golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 + golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 ) diff --git a/go.sum b/go.sum index cdc8a717ed..34aef50864 100644 --- a/go.sum +++ b/go.sum @@ -1,437 +1,13 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -github.com/Azure/azure-pipeline-go v0.2.1/go.mod h1:UGSo8XybXnIGZ3epmeBw7Jdz+HiUVpqIlpz/HKHylF4= -github.com/Azure/azure-pipeline-go v0.2.2/go.mod h1:4rQ/NZncSvGqNkkOsNpOU1tgoNuIlp9AfUH5G1tvCHc= -github.com/Azure/azure-storage-blob-go v0.7.0/go.mod h1:f9YQKtsG1nMisotuTPpO0tjNuEjKRYAcJU8/ydDI++4= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= -github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= -github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/aws/aws-sdk-go v1.25.48/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= -github.com/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6/go.mod h1:Dmm/EzmjnCiweXmzRIAiUWCInVmPgjkzgv5k4tVyXiQ= -github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U= -github.com/consensys/bavard v0.1.8-0.20210302234946-daa97270b001 h1:cSgYnN5uuHVYk7M2npFshlObi/3onziDJ4wVcVBt7rQ= -github.com/consensys/bavard v0.1.8-0.20210302234946-daa97270b001/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= -github.com/consensys/goff v0.3.13-0.20210309040837-23eea852ae42 h1:ARDjZ9Y3bQHN7rNG0LLlju0PNhNIF/Vr3P0LjuBEtxQ= -github.com/consensys/goff v0.3.13-0.20210309040837-23eea852ae42/go.mod h1:kERj7hwojxxbBRcaicFF/gwINvzzNT0cpbGX4Wpv8TU= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= -github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= -github.com/dvyukov/go-fuzz v0.0.0-20200318091601-be3528f3a813/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= -github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= -github.com/ethereum/go-ethereum v1.9.25 h1:mMiw/zOOtCLdGLWfcekua0qPrJTe7FVIiHJ4IKNTfR0= -github.com/ethereum/go-ethereum v1.9.25/go.mod h1:vMkFiYLHI4tgPw4k2j4MHKoovchFE8plZ0M9VMk4/oM= -github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fjl/memsize v0.0.0-20180418122429-ca190fb6ffbc/go.mod h1:VvhXpOYNQvB+uIk2RvXzuaQtkQJzzIx6lSBe1xv7hi0= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= -github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/golang/snappy v0.0.3-0.20201103224600-674baa8c7fc3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.1.1-0.20200604201612-c04b05f3adfa/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= -github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= -github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/holiman/uint256 v1.1.1/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= -github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/influxdata/influxdb v1.2.3-0.20180221223340-01288bdb0883/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY= -github.com/jackpal/go-nat-pmp v1.0.2-0.20160603034137-1fa385a6f458/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jedisct1/go-minisign v0.0.0-20190909160543-45766022959e/go.mod h1:G1CVv03EnqU1wYL2dFwXxW2An0az9JTl/ZsqXQeBlkU= -github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU= -github.com/kilic/bls12-381 v0.0.0-20201226121925-69dacb279461 h1:eZB80d/IKkIPjCTLUBT6+Imzn2zLpXtJFzY986jlHV4= -github.com/kilic/bls12-381 v0.0.0-20201226121925-69dacb279461/go.mod h1:vDTTHJONJ6G+P2R74EhnyotQDTliQDnFEwhdmfzw1ig= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/consensys/bavard v0.1.8-0.20210329205436-c3e862ba4e5f h1:Smz/coLzPOgl74T1haF8SfqPAkB760cSO59+FyLPzG0= +github.com/consensys/bavard v0.1.8-0.20210329205436-c3e862ba4e5f/go.mod h1:Bpd0/3mZuaj6Sj+PqrmIquiOKy397AKGThQPaGzNXAQ= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.0/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-ieproxy v0.0.0-20190610004146-91bb50d98149/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-ieproxy v0.0.0-20190702010315-6dee0af9227d/go.mod h1:31jz6HNzdxOmlERGGEc4v/dMssOfmp2p5bT/okiKFFc= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5-0.20180830101745-3fb116b82035/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h1USek5+NqSA0= -github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= -github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= -github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/olekukonko/tablewriter v0.0.2-0.20190409134802-7e037d187b0c/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7/go.mod h1:CRroGNssyjTd/qIG2FyxByd2S8JEAZXBl4qUrZf8GS0= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rs/cors v0.0.0-20160617231935-a62a804a8a00/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= -github.com/rs/xhandler v0.0.0-20160618193221-ed27b6fd6521/go.mod h1:RvLn4FgxWubrpZHtQLnOf6EwhN2hEMusxZOhcW9H3UQ= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shirou/gopsutil v2.20.5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q= -github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw= -github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef/go.mod h1:sJ5fKU0s6JVwZjjcUEX2zFOnvq0ASQ2K9Zr6cf67kNs= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/wsddn/go-ecdh v0.0.0-20161211032359-48726bab9208/go.mod h1:IotVbo4F+mw0EzQ08zFqg7pK3FebNXpaMsRy2RT+Ees= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190909091759-094676da4a83/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200824131525-c12d262b63d8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04 h1:cEhElsAv9LUt9ZUUocxzWe05oFLVd+AA2nstydTeI8g= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210326220804-49726bf1d181 h1:64ChN/hjER/taL4YJuA+gpLfIMT+/NFherRZixbxOhg= +golang.org/x/sys v0.0.0-20210326220804-49726bf1d181/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/internal/apicheck_test.go b/internal/apicheck_test.go index 8188caba71..eebf5e3f6b 100644 --- a/internal/apicheck_test.go +++ b/internal/apicheck_test.go @@ -1,10 +1,10 @@ package main import ( - "github.com/consensys/gurvy/bls377" - "github.com/consensys/gurvy/bls381" - "github.com/consensys/gurvy/bn256" - "github.com/consensys/gurvy/bw761" + bls377 "github.com/consensys/gnark-crypto/ecc/bls12-377" + bls381 "github.com/consensys/gnark-crypto/ecc/bls12-381" + "github.com/consensys/gnark-crypto/ecc/bn254" + bw761 "github.com/consensys/gnark-crypto/ecc/bw6-761" ) // note: pairing API is not code generated, and don't use interfaces{} for performance reasons @@ -15,7 +15,7 @@ var err error var ( gtbls377 bls377.GT gtbls381 bls381.GT - gtbn256 bn256.GT + gtbn254 bn254.GT gtbw761 bw761.GT ) @@ -23,18 +23,18 @@ func init() { // Pair gtbls377, err = bls377.Pair([]bls377.G1Affine{}, []bls377.G2Affine{}) gtbls381, err = bls381.Pair([]bls381.G1Affine{}, []bls381.G2Affine{}) - gtbn256, err = bn256.Pair([]bn256.G1Affine{}, []bn256.G2Affine{}) + gtbn254, err = bn254.Pair([]bn254.G1Affine{}, []bn254.G2Affine{}) gtbw761, err = bw761.Pair([]bw761.G1Affine{}, []bw761.G2Affine{}) // MillerLoop gtbls377, err = bls377.MillerLoop([]bls377.G1Affine{}, []bls377.G2Affine{}) gtbls381, err = bls381.MillerLoop([]bls381.G1Affine{}, []bls381.G2Affine{}) - gtbn256, err = bn256.MillerLoop([]bn256.G1Affine{}, []bn256.G2Affine{}) + gtbn254, err = bn254.MillerLoop([]bn254.G1Affine{}, []bn254.G2Affine{}) gtbw761, err = bw761.MillerLoop([]bw761.G1Affine{}, []bw761.G2Affine{}) // FinalExp gtbls377 = bls377.FinalExponentiation(>bls377) gtbls381 = bls381.FinalExponentiation(>bls381) - gtbn256 = bn256.FinalExponentiation(>bn256) + gtbn254 = bn254.FinalExponentiation(>bn254) gtbw761 = bw761.FinalExponentiation(>bw761) } diff --git a/internal/generator.go b/internal/generator.go deleted file mode 100644 index 9cdcaf6f99..0000000000 --- a/internal/generator.go +++ /dev/null @@ -1,299 +0,0 @@ -package main - -import ( - "fmt" - "io" - "os" - "os/exec" - "path/filepath" - "sync" - - "github.com/consensys/bavard" - "github.com/consensys/goff/field" - "github.com/consensys/goff/generator" - "github.com/consensys/gurvy/internal/asm/amd64" -) - -var bgen = bavard.NewBatchGenerator(copyrightHolder, "gurvy") - -//go:generate go run generator.go -func main() { - var wg sync.WaitGroup - for _, conf := range []curveConfig{ - // BN256 - { - Name: "bn256", - fr: "21888242871839275222246405745257275088548364400416034343698204186575808495617", - fp: "21888242871839275222246405745257275088696311157297823662689037894645226208583", - G1: pointConfig{ - CoordType: "fp.Element", - PointName: "g1", - GLV: true, - CofactorCleaning: false, - CRange: defaultCRange(), - }, - G2: pointConfig{ - CoordType: "fptower.E2", - PointName: "g2", - GLV: true, - CofactorCleaning: true, - CRange: defaultCRange(), - }, - }, - - // BLS377 - { - Name: "bls377", - fr: "8444461749428370424248824938781546531375899335154063827935233455917409239041", - fp: "258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177", - G1: pointConfig{ - CoordType: "fp.Element", - PointName: "g1", - GLV: true, - CofactorCleaning: true, - CRange: defaultCRange(), - }, - G2: pointConfig{ - CoordType: "fptower.E2", - PointName: "g2", - GLV: true, - CofactorCleaning: true, - CRange: defaultCRange(), - }, - }, - - // BLS381 - { - Name: "bls381", - fr: "52435875175126190479447740508185965837690552500527637822603658699938581184513", - fp: "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", - G1: pointConfig{ - CoordType: "fp.Element", - PointName: "g1", - GLV: true, - CofactorCleaning: true, - CRange: defaultCRange(), - }, - G2: pointConfig{ - CoordType: "fptower.E2", - PointName: "g2", - GLV: true, - CofactorCleaning: true, - CRange: defaultCRange(), - }, - }, - - // BW761 - { - Name: "bw761", - fr: "258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177", - fp: "6891450384315732539396789682275657542479668912536150109513790160209623422243491736087683183289411687640864567753786613451161759120554247759349511699125301598951605099378508850372543631423596795951899700429969112842764913119068299", - G1: pointConfig{ - CoordType: "fp.Element", - PointName: "g1", - GLV: true, - CofactorCleaning: true, - CRange: []int{4, 5, 8, 16}, - }, - G2: pointConfig{ - CoordType: "fp.Element", - PointName: "g2", - GLV: true, - CofactorCleaning: true, - CRange: []int{4, 5, 8, 16}, - }, - }, - } { - wg.Add(1) - // for each curve, generate the needed files - go func(conf curveConfig) { - defer wg.Done() - doc := "provides efficient elliptic curve and pairing implementation for " + conf.Name - conf.Fp, _ = field.NewField("fp", "Element", conf.fp) - conf.Fr, _ = field.NewField("fr", "Element", conf.fr) - conf.FpUnusedBits = 64 - (conf.Fp.NbBits % 64) - dir := filepath.Join(baseDir, conf.Name) - conf.dir = dir - - // generate base fields - assertNoError(generator.GenerateFF(conf.Fr, filepath.Join(conf.dir, "fr"))) - assertNoError(generator.GenerateFF(conf.Fp, filepath.Join(conf.dir, "fp"))) - - g1 := pconf{conf, conf.G1} - g2 := pconf{conf, conf.G2} - - entriesF := []bavard.EntryF{ - {File: filepath.Join(dir, "multiexp.go"), TemplateF: []string{"multiexp.go.tmpl"}}, - {File: filepath.Join(dir, "multiexp_test.go"), TemplateF: []string{"tests/multiexp.go.tmpl"}}, - {File: filepath.Join(dir, "marshal.go"), TemplateF: []string{"marshal.go.tmpl"}, PackageDoc: doc}, - {File: filepath.Join(dir, "marshal_test.go"), TemplateF: []string{"tests/marshal.go.tmpl"}}, - } - if err := bgen.GenerateF(conf, conf.Name, "./templates/point", entriesF...); err != nil { - panic(err) - } - - // G1 - entriesF = []bavard.EntryF{ - {File: filepath.Join(dir, "g1.go"), TemplateF: []string{"point.go.tmpl"}}, - {File: filepath.Join(dir, "g1_test.go"), TemplateF: []string{"tests/point.go.tmpl"}}, - } - if err := bgen.GenerateF(g1, conf.Name, "./templates/point", entriesF...); err != nil { - panic(err) - } - - // G2 - entriesF = []bavard.EntryF{ - {File: filepath.Join(dir, "g2.go"), TemplateF: []string{"point.go.tmpl"}}, - {File: filepath.Join(dir, "g2_test.go"), TemplateF: []string{"tests/point.go.tmpl"}}, - } - if err := bgen.GenerateF(g2, conf.Name, "./templates/point", entriesF...); err != nil { - panic(err) - } - - if conf.Name != "bw761" { - assertNoError(GenerateFq12over6over2(conf)) - if err := bgen.GenerateF(conf, conf.Name, "./templates/pairing", bavard.EntryF{ - File: filepath.Join(dir, "pairing_test.go"), TemplateF: []string{"tests/pairing.go.tmpl"}, - }); err != nil { - panic(err) - } - } - - // twisted Edwards - if err := bgen.GenerateF(conf, "twistededwards", "./templates/point", bavard.EntryF{ - File: filepath.Join(dir, "/twistededwards/point.go"), TemplateF: []string{"pointtwistededwards.go.tmpl"}, - }); err != nil { - panic(err) - } - - }(conf) - - } - wg.Wait() - - // run go fmt on whole directory - cmd := exec.Command("gofmt", "-s", "-w", "../") - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - assertNoError(cmd.Run()) -} - -func assertNoError(err error) { - if err != nil { - fmt.Printf("\n%s\n", err.Error()) - os.Exit(-1) - } -} - -// curveConfig describes parameters of the curve useful for the templates -type curveConfig struct { - Name string - fp string - fr string - - Fp *field.Field - Fr *field.Field - FpUnusedBits int - G1 pointConfig - G2 pointConfig - dir string -} - -type pointConfig struct { - CoordType string - PointName string - GLV bool // scalar mulitplication using GLV - CofactorCleaning bool // flag telling if the Cofactor cleaning is available - CRange []int // multiexp bucket method: generate inner methods (with const arrays) for each c -} - -type pconf struct { - curveConfig - pointConfig -} - -const ( - fpTower = "fptower" - copyrightHolder = "ConsenSys Software Inc." - baseDir = "../" -) - -func defaultCRange() []int { - // default range for C values in the multiExp - return []int{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21, 22} -} - -// GenerateFq12over6over2 generates a tower 2->6->12 over fp -func GenerateFq12over6over2(conf curveConfig) error { - dir := filepath.Join(conf.dir, "internal", fpTower) - entries := []bavard.EntryF{ - {File: filepath.Join(dir, "e2.go"), TemplateF: []string{"fq2.go.tmpl"}}, - {File: filepath.Join(dir, "e6.go"), TemplateF: []string{"fq6.go.tmpl"}}, - {File: filepath.Join(dir, "e12.go"), TemplateF: []string{"fq12.go.tmpl"}}, - {File: filepath.Join(dir, "e2_amd64.go"), TemplateF: []string{"amd64.fq2.go.tmpl"}}, - {File: filepath.Join(dir, "e2_fallback.go"), TemplateF: []string{"fallback.fq2.go.tmpl"}, BuildTag: "!amd64"}, - {File: filepath.Join(dir, "e2_test.go"), TemplateF: []string{"tests/fq2.go.tmpl"}}, - {File: filepath.Join(dir, "e6_test.go"), TemplateF: []string{"tests/fq6.go.tmpl"}}, - {File: filepath.Join(dir, "e12_test.go"), TemplateF: []string{"tests/fq12.go.tmpl"}}, - {File: filepath.Join(dir, "asm.go"), TemplateF: []string{"asm.go.tmpl"}, BuildTag: "!noadx"}, - {File: filepath.Join(dir, "asm_noadx.go"), TemplateF: []string{"asm_noadx.go.tmpl"}, BuildTag: "noadx"}, - } - - if err := bgen.GenerateF(conf, fpTower, "./templates/fq12over6over2", entries...); err != nil { - return err - } - - { - // fq2 assembly - fName := filepath.Join(dir, "e2_amd64.s") - f, err := os.Create(fName) - if err != nil { - return err - } - - if conf.Name == "bn256" || conf.Name == "bls381" { - _, _ = io.WriteString(f, "// +build !amd64_adx\n") - } - Fq2Amd64 := amd64.NewFq2Amd64(f, conf.Fp, conf.Name) - if err := Fq2Amd64.Generate(true); err != nil { - _ = f.Close() - return err - } - _ = f.Close() - - cmd := exec.Command("asmfmt", "-w", fName) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return err - } - } - - if conf.Name == "bn256" || conf.Name == "bls381" { - { - // fq2 assembly - fName := filepath.Join(dir, "e2_adx_amd64.s") - f, err := os.Create(fName) - if err != nil { - return err - } - - _, _ = io.WriteString(f, "// +build amd64_adx\n") - Fq2Amd64 := amd64.NewFq2Amd64(f, conf.Fp, conf.Name) - if err := Fq2Amd64.Generate(false); err != nil { - _ = f.Close() - return err - } - _ = f.Close() - - cmd := exec.Command("asmfmt", "-w", fName) - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - if err := cmd.Run(); err != nil { - return err - } - } - } - - return nil -} diff --git a/internal/generator/config/bls12-377.go b/internal/generator/config/bls12-377.go new file mode 100644 index 0000000000..ed2909852f --- /dev/null +++ b/internal/generator/config/bls12-377.go @@ -0,0 +1,26 @@ +package config + +func init() { + Curves = append(Curves, Curve{ + Name: "bls12-377", + Package: "bls12377", + EnumID: "BLS12_377", + FrModulus: "8444461749428370424248824938781546531375899335154063827935233455917409239041", + FpModulus: "258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177", + G1: Point{ + CoordType: "fp.Element", + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + }, + G2: Point{ + CoordType: "fptower.E2", + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + }, + }) + +} diff --git a/internal/generator/config/bls12-381.go b/internal/generator/config/bls12-381.go new file mode 100644 index 0000000000..8c4d508abf --- /dev/null +++ b/internal/generator/config/bls12-381.go @@ -0,0 +1,26 @@ +package config + +func init() { + Curves = append(Curves, Curve{ + Name: "bls12-381", + Package: "bls12381", + EnumID: "BLS12_381", + FrModulus: "52435875175126190479447740508185965837690552500527637822603658699938581184513", + FpModulus: "4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559787", + G1: Point{ + CoordType: "fp.Element", + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + }, + G2: Point{ + CoordType: "fptower.E2", + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + }, + }) + +} diff --git a/internal/generator/config/bn254.go b/internal/generator/config/bn254.go new file mode 100644 index 0000000000..f8ffafc159 --- /dev/null +++ b/internal/generator/config/bn254.go @@ -0,0 +1,25 @@ +package config + +func init() { + Curves = append(Curves, Curve{ + Name: "bn254", + Package: "bn254", + EnumID: "BN254", + FrModulus: "21888242871839275222246405745257275088548364400416034343698204186575808495617", + FpModulus: "21888242871839275222246405745257275088696311157297823662689037894645226208583", + G1: Point{ + CoordType: "fp.Element", + PointName: "g1", + GLV: true, + CofactorCleaning: false, + CRange: defaultCRange(), + }, + G2: Point{ + CoordType: "fptower.E2", + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: defaultCRange(), + }, + }) +} diff --git a/internal/generator/config/bw6-761.go b/internal/generator/config/bw6-761.go new file mode 100644 index 0000000000..72b4ba934b --- /dev/null +++ b/internal/generator/config/bw6-761.go @@ -0,0 +1,26 @@ +package config + +func init() { + Curves = append(Curves, Curve{ + Name: "bw6-761", + Package: "bw6761", + EnumID: "BW6_761", + FrModulus: "258664426012969094010652733694893533536393512754914660539884262666720468348340822774968888139573360124440321458177", + FpModulus: "6891450384315732539396789682275657542479668912536150109513790160209623422243491736087683183289411687640864567753786613451161759120554247759349511699125301598951605099378508850372543631423596795951899700429969112842764913119068299", + G1: Point{ + CoordType: "fp.Element", + PointName: "g1", + GLV: true, + CofactorCleaning: true, + CRange: []int{4, 5, 8, 16}, + }, + G2: Point{ + CoordType: "fp.Element", + PointName: "g2", + GLV: true, + CofactorCleaning: true, + CRange: []int{4, 5, 8, 16}, + }, + }) + +} diff --git a/internal/generator/config/curve.go b/internal/generator/config/curve.go new file mode 100644 index 0000000000..930bf0dce2 --- /dev/null +++ b/internal/generator/config/curve.go @@ -0,0 +1,51 @@ +package config + +import ( + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field" +) + +// Curve describes parameters of the curve useful for the template +type Curve struct { + Name string + Package string + EnumID string + FpModulus string + FrModulus string + + Fp *field.Field + Fr *field.Field + FpUnusedBits int + G1 Point + G2 Point +} + +func (c *Curve) ID() ecc.ID { + switch c.Name { + case "bn254": + return ecc.BN254 + case "bls12-381": + return ecc.BLS12_381 + case "bls12-377": + return ecc.BLS12_377 + case "bw6-761": + return ecc.BW6_761 + default: + panic("not implemented") + } +} + +type Point struct { + CoordType string + PointName string + GLV bool // scalar mulitplication using GLV + CofactorCleaning bool // flag telling if the Cofactor cleaning is available + CRange []int // multiexp bucket method: generate inner methods (with const arrays) for each c +} + +var Curves []Curve + +func defaultCRange() []int { + // default range for C values in the multiExp + return []int{4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 21, 22} +} diff --git a/internal/generator/crypto/hash/mimc/generate.go b/internal/generator/crypto/hash/mimc/generate.go new file mode 100644 index 0000000000..3e9aa2ab66 --- /dev/null +++ b/internal/generator/crypto/hash/mimc/generate.go @@ -0,0 +1,16 @@ +package mimc + +import ( + "path/filepath" + + "github.com/consensys/bavard" + "github.com/consensys/gnark-crypto/internal/generator/config" +) + +func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) error { + entriesF := []bavard.EntryF{ + {File: filepath.Join(baseDir, "mimc.go"), TemplateF: []string{"mimc.go.tmpl"}}, + } + return bgen.GenerateF(conf, "mimc", "./crypto/hash/mimc/template", entriesF...) + +} diff --git a/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl b/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl new file mode 100644 index 0000000000..ce87c9d703 --- /dev/null +++ b/internal/generator/crypto/hash/mimc/template/mimc.go.tmpl @@ -0,0 +1,206 @@ +import ( + "hash" + "math/big" + + "github.com/consensys/gnark-crypto/ecc/{{ .Name }}/fr" + "golang.org/x/crypto/sha3" +) + +const mimcNbRounds = 91 + +// BlockSize size that mimc consumes +const BlockSize = 32{{ if eq .Name "bw6-761" }}+16{{ end }} + +// Params constants for the mimc hash function +type Params []fr.Element + +// NewParams creates new mimc object +func NewParams(seed string) Params { + + // set the constants + res := make(Params, mimcNbRounds) + + rnd := sha3.Sum256([]byte(seed)) + value := new(big.Int).SetBytes(rnd[:]) + + for i := 0; i < mimcNbRounds; i++ { + rnd = sha3.Sum256(value.Bytes()) + value.SetBytes(rnd[:]) + res[i].SetBigInt(value) + } + + return res +} + +// digest represents the partial evaluation of the checksum +// along with the params of the mimc function +type digest struct { + Params Params + h fr.Element + data []byte // data to hash +} + +// NewMiMC returns a MiMCImpl object, pure-go reference implementation +func NewMiMC(seed string) hash.Hash { + d := new(digest) + params := NewParams(seed) + //d.Reset() + d.Params = params + d.Reset() + return d +} + +// Reset resets the Hash to its initial state. +func (d *digest) Reset() { + d.data = nil + d.h = fr.Element{0, 0, 0, 0} +} + +// Sum appends the current hash to b and returns the resulting slice. +// It does not change the underlying hash state. +func (d *digest) Sum(b []byte) []byte { + buffer := d.checksum() + d.data = nil // flush the data already hashed + hash := buffer.Bytes() + b = append(b, hash[:]...) + return b +} + +// BlockSize returns the hash's underlying block size. +// The Write method must be able to accept any amount +// of data, but it may operate more efficiently if all writes +// are a multiple of the block size. +func (d *digest) Size() int { + return BlockSize +} + +// BlockSize returns the number of bytes Sum will return. +func (d *digest) BlockSize() int { + return BlockSize +} + +// Write (via the embedded io.Writer interface) adds more data to the running hash. +// It never returns an error. +func (d *digest) Write(p []byte) (n int, err error) { + n = len(p) + d.data = append(d.data, p...) + return +} + +// Hash hash using Miyaguchi–Preneel: +// https://en.wikipedia.org/wiki/One-way_compression_function +// The XOR operation is replaced by field addition, data is in Montgomery form +func (d *digest) checksum() fr.Element { + + var buffer [BlockSize]byte + var x fr.Element + + // if data size is not multiple of BlockSizes we padd: + // .. || 0xaf8 -> .. || 0x0000...0af8 + if len(d.data)%BlockSize != 0 { + q := len(d.data) / BlockSize + r := len(d.data) % BlockSize + sliceq := make([]byte, q*BlockSize) + copy(sliceq, d.data) + slicer := make([]byte, r) + copy(slicer, d.data[q*BlockSize:]) + sliceremainder := make([]byte, BlockSize-r) + d.data = append(sliceq, sliceremainder...) + d.data = append(d.data, slicer...) + } + + if len(d.data) == 0 { + d.data = make([]byte, 32) + } + + nbChunks := len(d.data) / BlockSize + + for i := 0; i < nbChunks; i++ { + copy(buffer[:], d.data[i*BlockSize:(i+1)*BlockSize]) + x.SetBytes(buffer[:]) + d.encrypt(x) + d.h.Add(&x, &d.h) + } + + return d.h +} + + +{{ if eq .Name "bn254" }} + // plain execution of a mimc run + // m: message + // k: encryption key + func (d *digest) encrypt(m fr.Element) { + + for i:=0; i < len(d.Params); i++ { + // m = (m+k+c)^5 + var tmp fr.Element + tmp.Add(&m, &d.h).Add(&tmp, &d.Params[i]) + m.Square(&tmp). + Square(&m). + Mul(&m, &tmp) + } + m.Add(&m, &d.h) + d.h = m + } +{{ else if eq .Name "bls12-381" }} + // plain execution of a mimc run + // m: message + // k: encryption key + func (d *digest) encrypt(m fr.Element) { + + for i:=0; i < len(d.Params); i++ { + // m = (m+k+c)^5 + var tmp fr.Element + tmp.Add(&m, &d.h).Add(&tmp, &d.Params[i]) + m.Square(&tmp). + Square(&m). + Mul(&m, &tmp) + } + m.Add(&m, &d.h) + d.h = m + } +{{ else if eq .Name "bls12-377" }} + // plain execution of a mimc run + // m: message + // k: encryption key + func (d *digest) encrypt(m fr.Element) { + + for i:=0; i < len(d.Params); i++ { + // m = (m+k+c)^**-1 + m.Add(&m, &d.h).Add(&m, &d.Params[i]).Inverse(&m) + } + m.Add(&m, &d.h) + d.h = m + } +{{ else if eq .Name "bw6-761" }} + // plain execution of a mimc run + // m: message + // k: encryption key + func (d *digest) encrypt(m fr.Element) { + + for i:=0; i < len(d.Params); i++ { + // m = (m+k+c)^5 + var tmp fr.Element + tmp.Add(&m, &d.h).Add(&tmp, &d.Params[i]) + m.Square(&tmp). + Square(&m). + Mul(&m, &tmp) + } + m.Add(&m, &d.h) + d.h = m + } +{{end}} + +// Sum computes the mimc hash of msg from seed +func Sum(seed string, msg []byte) ([]byte, error) { + params := NewParams(seed) + var d digest + d.Params = params + if _, err := d.Write(msg); err != nil { + return nil, err + } + h := d.checksum() + bytes := h.Bytes() + return bytes[:], nil +} diff --git a/internal/generator/crypto/signature/eddsa/generate.go b/internal/generator/crypto/signature/eddsa/generate.go new file mode 100644 index 0000000000..7594847dda --- /dev/null +++ b/internal/generator/crypto/signature/eddsa/generate.go @@ -0,0 +1,20 @@ +package eddsa + +import ( + "path/filepath" + + "github.com/consensys/bavard" + "github.com/consensys/gnark-crypto/internal/generator/config" +) + +func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) error { + + // eddsa + entriesF := []bavard.EntryF{ + {File: filepath.Join(baseDir, "eddsa.go"), TemplateF: []string{"eddsa.go.tmpl"}}, + {File: filepath.Join(baseDir, "eddsa_test.go"), TemplateF: []string{"eddsa.test.go.tmpl"}}, + {File: filepath.Join(baseDir, "marshal.go"), TemplateF: []string{"marshal.go.tmpl"}}, + } + return bgen.GenerateF(conf, "eddsa", "./crypto/signature/eddsa/template", entriesF...) + +} diff --git a/internal/generator/crypto/signature/eddsa/template/eddsa.go.tmpl b/internal/generator/crypto/signature/eddsa/template/eddsa.go.tmpl new file mode 100644 index 0000000000..ff81dd2403 --- /dev/null +++ b/internal/generator/crypto/signature/eddsa/template/eddsa.go.tmpl @@ -0,0 +1,280 @@ +import ( + "crypto/subtle" + "errors" + "hash" + "io" + "math/big" + + "github.com/consensys/gnark-crypto/crypto/signature" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/twistededwards" + + "golang.org/x/crypto/blake2b" +) + +var errNotOnCurve = errors.New("point not on curve") + +const ( + sizeFr = 32{{ if eq .Name "bw6-761" }}+16{{ end }} + sizePublicKey = sizeFr + sizeSignature = 2 * sizeFr + sizePrivateKey = 2 * sizeFr + 32 +) + +// PublicKey eddsa signature object +// cf https://en.wikipedia.org/wiki/EdDSA for notation +type PublicKey struct { + A twistededwards.PointAffine +} + +// PrivateKey private key of an eddsa instance +type PrivateKey struct { + PublicKey PublicKey // copy of the associated public key + scalar [sizeFr]byte // secret scalar, in big Endian + randSrc [32]byte // source +} + +// Signature represents an eddsa signature +// cf https://en.wikipedia.org/wiki/EdDSA for notation +type Signature struct { + R twistededwards.PointAffine + S [sizeFr]byte +} + +func init() { + signature.Register(signature.EDDSA_{{ .EnumID }}, GenerateKeyInterfaces) +} + +// GenerateKey generates a public and private key pair. +func GenerateKey(r io.Reader) (PrivateKey, error) { + + c := twistededwards.GetEdwardsCurve() + + var pub PublicKey + var priv PrivateKey + + {{ if eq .Name "bw6-761" }} + // The source of randomness and the secret scalar must come + // from 2 distincts sources. Since the scalar is the size of the + // field of definition (48 bytes), the scalar must come from a + // different digest so there is no overlap between the source of + // randomness and the scalar. + + // used for random scalar (aka private key) + seed := make([]byte, 32) + _, err := r.Read(seed) + if err != nil { + return priv, err + } + h1 := blake2b.Sum512(seed[:]) + + // used for the source of randomness when hashing the message + h2 := blake2b.Sum512(h1[:]) + for i := 0; i < 32; i++ { + priv.randSrc[i] = h2[i] + } + {{ else }} + // hash(h) = private_key || random_source, on 32 bytes each + seed := make([]byte, 32) + _, err := r.Read(seed) + if err != nil { + return priv, err + } + h := blake2b.Sum512(seed[:]) + for i := 0; i < 32; i++ { + priv.randSrc[i] = h[i+32] + } + {{ end }} + + // prune the key + // https://tools.ietf.org/html/rfc8032#section-5.1.5, key generation + {{ if eq .Name "bw6-761" }} + h1[0] &= 0xF8 + h1[sizeFr-1] &= 0x7F + h1[sizeFr-1] |= 0x40 + {{ else }} + h[0] &= 0xF8 + h[31] &= 0x7F + h[31] |= 0x40 + {{ end }} + + // reverse first bytes because setBytes interpret stream as big endian + // but in eddsa specs s is the first 32 bytes in little endian + for i, j := 0, sizeFr; i < j; i, j = i+1, j-1 { + {{ if eq .Name "bw6-761" }} + h1[i], h1[j] = h1[j], h1[i] + {{ else }} + h[i], h[j] = h[j], h[i] + {{ end }} + } + + {{ if eq .Name "bw6-761" }} + copy(priv.scalar[:], h1[:sizeFr]) + {{ else }} + copy(priv.scalar[:], h[:sizeFr]) + {{ end }} + + var bscalar big.Int + bscalar.SetBytes(priv.scalar[:]) + pub.A.ScalarMul(&c.Base, &bscalar) + + priv.PublicKey = pub + + return priv, nil +} + +// GenerateKeyInterfaces generate interfaces for the public/private key. +// This purpose of this function is to be registered in the list of signature schemes. +func GenerateKeyInterfaces(r io.Reader) (signature.Signer, error) { + priv, err := GenerateKey(r) + return &priv, err +} + +// Equal compares 2 public keys +func (pub *PublicKey) Equal(other signature.PublicKey) bool { + bpk := pub.Bytes() + bother := other.Bytes() + return subtle.ConstantTimeCompare(bpk, bother) == 1 +} + +// Public returns the public key associated to the private key. +// From Signer interface defined in gnark/crypto/signature. +func (privKey *PrivateKey) Public() signature.PublicKey { + var pub PublicKey + pub.A.Set(&privKey.PublicKey.A) + return &pub +} + +// Sign sign a message +// Pure Eddsa version (see https://tools.ietf.org/html/rfc8032#page-8) +func (privKey *PrivateKey) Sign(message []byte, hFunc hash.Hash) ([]byte, error) { + + curveParams := twistededwards.GetEdwardsCurve() + + var res Signature + + // blinding factor for the private key + // blindingFactorBigInt must be the same size as the private key, + // blindingFactorBigInt = h(randomness_source||message)[:sizeFr] + var blindingFactorBigInt big.Int + + // randSrc = privKey.randSrc || msg (-> message = MSB message .. LSB message) + randSrc := make([]byte, 32+len(message)) + for i, v := range privKey.randSrc { + randSrc[i] = v + } + copy(randSrc[32:], message) + + // randBytes = H(randSrc) + blindingFactorBytes := blake2b.Sum512(randSrc[:]) // TODO ensures that the hash used to build the key and the one used here is the same + blindingFactorBigInt.SetBytes(blindingFactorBytes[:sizeFr]) + + // compute R = randScalar*Base + res.R.ScalarMul(&curveParams.Base, &blindingFactorBigInt) + if !res.R.IsOnCurve() { + return nil, errNotOnCurve + } + + // compute H(R, A, M), all parameters in data are in Montgomery form + resRX := res.R.X.Bytes() + resRY := res.R.Y.Bytes() + resAX := privKey.PublicKey.A.X.Bytes() + resAY := privKey.PublicKey.A.Y.Bytes() + sizeDataToHash := 4*sizeFr + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], resRX[:]) + copy(dataToHash[sizeFr:], resRY[:]) + copy(dataToHash[2*sizeFr:], resAX[:]) + copy(dataToHash[3*sizeFr:], resAY[:]) + copy(dataToHash[4*sizeFr:], message) + hFunc.Reset() + _, err := hFunc.Write(dataToHash[:]) + if err != nil { + return nil, err + } + + var hramInt big.Int + hramBin := hFunc.Sum(nil) + hramInt.SetBytes(hramBin) + + // Compute s = randScalarInt + H(R,A,M)*S + // going with big int to do ops mod curve order + var bscalar, bs big.Int + bscalar.SetBytes(privKey.scalar[:]) + bs.Mul(&hramInt, &bscalar). + Add(&bs, &blindingFactorBigInt). + Mod(&bs, &curveParams.Order) + sb := bs.Bytes() + if len(sb) < sizeFr { + offset := make([]byte, sizeFr-len(sb)) + sb = append(offset, sb...) + } + copy(res.S[:], sb[:]) + + return res.Bytes(), nil +} + +// Verify verifies an eddsa signature +func (pub *PublicKey) Verify(sigBin, message []byte, hFunc hash.Hash) (bool, error) { + + curveParams := twistededwards.GetEdwardsCurve() + + // verify that pubKey and R are on the curve + if !pub.A.IsOnCurve() { + return false, errNotOnCurve + } + + // Deserialize the signature + var sig Signature + if _, err := sig.SetBytes(sigBin); err != nil { + return false, err + } + + // compute H(R, A, M), all parameters in data are in Montgomery form + sigRX := sig.R.X.Bytes() + sigRY := sig.R.Y.Bytes() + sigAX := pub.A.X.Bytes() + sigAY := pub.A.Y.Bytes() + sizeDataToHash := 4*sizeFr + len(message) + dataToHash := make([]byte, sizeDataToHash) + copy(dataToHash[:], sigRX[:]) + copy(dataToHash[sizeFr:], sigRY[:]) + copy(dataToHash[2*sizeFr:], sigAX[:]) + copy(dataToHash[3*sizeFr:], sigAY[:]) + copy(dataToHash[4*sizeFr:], message) + hFunc.Reset() + if _, err := hFunc.Write(dataToHash[:]); err != nil { + return false, err + } + + var hramInt big.Int + hramBin := hFunc.Sum(nil) + hramInt.SetBytes(hramBin) + + // lhs = cofactor*S*Base + var lhs twistededwards.PointAffine + var bCofactor, bs big.Int + curveParams.Cofactor.ToBigInt(&bCofactor) + bs.SetBytes(sig.S[:]) + lhs.ScalarMul(&curveParams.Base, &bs). + ScalarMul(&lhs, &bCofactor) + + if !lhs.IsOnCurve() { + return false, errNotOnCurve + } + + // rhs = cofactor*(R + H(R,A,M)*A) + var rhs twistededwards.PointAffine + rhs.ScalarMul(&pub.A, &hramInt). + Add(&rhs, &sig.R). + ScalarMul(&rhs, &bCofactor) + if !rhs.IsOnCurve() { + return false, errNotOnCurve + } + + // verifies that cofactor*S*Base=cofactor*(R + H(R,A,M)*A) + if !lhs.X.Equal(&rhs.X) || !lhs.Y.Equal(&rhs.Y) { + return false, nil + } + + return true, nil +} \ No newline at end of file diff --git a/internal/generator/crypto/signature/eddsa/template/eddsa.test.go.tmpl b/internal/generator/crypto/signature/eddsa/template/eddsa.test.go.tmpl new file mode 100644 index 0000000000..222a5249c2 --- /dev/null +++ b/internal/generator/crypto/signature/eddsa/template/eddsa.test.go.tmpl @@ -0,0 +1,162 @@ +import ( + "crypto/sha256" + "math/rand" + "testing" + + "github.com/consensys/gnark-crypto/crypto/signature" + "github.com/consensys/gnark-crypto/crypto/hash" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" +) + +func TestSerialization(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + privKey1, err := signature.EDDSA_{{ .EnumID }}.New(r) + if err != nil { + t.Fatal(err) + } + pubKey1 := privKey1.Public() + + privKey2, err := signature.EDDSA_{{ .EnumID }}.New(r) + if err != nil { + t.Fatal(err) + } + pubKey2 := privKey2.Public() + + pubKeyBin1 := pubKey1.Bytes() + pubKey2.SetBytes(pubKeyBin1) + pubKeyBin2 := pubKey2.Bytes() + if len(pubKeyBin1) != len(pubKeyBin2) { + t.Fatal("Inconistent size") + } + for i := 0; i < len(pubKeyBin1); i++ { + if pubKeyBin1[i] != pubKeyBin2[i] { + t.Fatal("Error serialize(deserialize(.))") + } + } + + privKeyBin1 := privKey1.Bytes() + privKey2.SetBytes(privKeyBin1) + privKeyBin2 := privKey2.Bytes() + if len(privKeyBin1) != len(privKeyBin2) { + t.Fatal("Inconistent size") + } + for i := 0; i < len(privKeyBin1); i++ { + if privKeyBin1[i] != privKeyBin2[i] { + t.Fatal("Error serialize(deserialize(.))") + } + } +} + +func TestEddsaMIMC(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + // create eddsa obj and sign a message + privKey, err := signature.EDDSA_{{ .EnumID }}.New(r) + if err != nil { + t.Fatal(nil) + } + pubKey := privKey.Public() + hFunc := hash.MIMC_{{ .EnumID }}.New("seed") + + var frMsg fr.Element + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035978") + msgBin := frMsg.Bytes() + signature, err := privKey.Sign(msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + + // verifies correct msg + res, err := pubKey.Verify(signature, msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + if !res { + t.Fatal("Verifiy correct signature should return true") + } + + // verifies wrong msg + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035979") + msgBin = frMsg.Bytes() + res, err = pubKey.Verify(signature, msgBin[:], hFunc) + if err != nil { + t.Fatal(err) + } + if res { + t.Fatal("Verfiy wrong signature should be false") + } + +} + +func TestEddsaSHA256(t *testing.T) { + + src := rand.NewSource(0) + r := rand.New(src) + + hFunc := sha256.New() + + // create eddsa obj and sign a message + // create eddsa obj and sign a message + + privKey, err := signature.EDDSA_{{ .EnumID }}.New(r) + pubKey := privKey.Public() + if err != nil { + t.Fatal(err) + } + + signature, err := privKey.Sign([]byte("message"), hFunc) + if err != nil { + t.Fatal(err) + } + + // verifies correct msg + res, err := pubKey.Verify(signature, []byte("message"), hFunc) + if err != nil { + t.Fatal(err) + } + if !res { + t.Fatal("Verifiy correct signature should return true") + } + + // verifies wrong msg + res, err = pubKey.Verify(signature, []byte("wrong_message"), hFunc) + if err != nil { + t.Fatal(err) + } + if res { + t.Fatal("Verfiy wrong signature should be false") + } + +} + +// benchmarks + +func BenchmarkVerify(b *testing.B) { + + src := rand.NewSource(0) + r := rand.New(src) + + hFunc := hash.MIMC_{{ .EnumID }}.New("seed") + + // create eddsa obj and sign a message + privKey, err := signature.EDDSA_{{ .EnumID }}.New(r) + pubKey := privKey.Public() + if err != nil { + b.Fatal(err) + } + var frMsg fr.Element + frMsg.SetString("44717650746155748460101257525078853138837311576962212923649547644148297035978") + msgBin := frMsg.Bytes() + signature, _ := privKey.Sign(msgBin[:], hFunc) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + pubKey.Verify(signature, msgBin[:], hFunc) + } +} + diff --git a/internal/generator/crypto/signature/eddsa/template/marshal.go.tmpl b/internal/generator/crypto/signature/eddsa/template/marshal.go.tmpl new file mode 100644 index 0000000000..bdbfa20399 --- /dev/null +++ b/internal/generator/crypto/signature/eddsa/template/marshal.go.tmpl @@ -0,0 +1,111 @@ +import ( + "crypto/subtle" + "io" +) + +// Bytes returns the binary representation of pk +// as x||y where x, y are the coordinates of the point +// on the twisted Edwards as big endian integers. +func (pk *PublicKey) Bytes() []byte { + var res [sizePublicKey]byte + pkBin := pk.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], pkBin[:]) + return res[:] +} + +// SetBytes sets p from binary representation in buf. +// buf represents a public key as x||y where x, y are +// interpreted as big endian binary numbers corresponding +// to the coordinates of a point on the twisted Edwards. +// It returns the number of bytes read from the buffer. +func (pk *PublicKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePublicKey { + return n, io.ErrShortBuffer + } + if _, err := pk.A.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !pk.A.IsOnCurve() { + return n, errNotOnCurve + } + return n, nil +} + +// Bytes returns the binary representation of pk, +// as byte array publicKey||scalar||randSrc +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +func (privKey *PrivateKey) Bytes() []byte { + var res [sizePrivateKey]byte + pubkBin := privKey.PublicKey.A.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], pubkBin[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:2*sizeFr], privKey.scalar[:]) + subtle.ConstantTimeCopy(1, res[2*sizeFr:], privKey.randSrc[:]) + return res[:] +} + +// SetBytes sets pk from buf, where buf is interpreted +// as publicKey||scalar||randSrc +// where publicKey is as publicKey.Bytes(), and +// scalar is in big endian, of size sizeFr. +// It returns the number byte read. +func (privKey *PrivateKey) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizePrivateKey { + return n, io.ErrShortBuffer + } + if _, err := privKey.PublicKey.A.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !privKey.PublicKey.A.IsOnCurve() { + return n, errNotOnCurve + } + subtle.ConstantTimeCopy(1, privKey.scalar[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + subtle.ConstantTimeCopy(1, privKey.randSrc[:], buf[2*sizeFr:]) + n += sizeFr + return n, nil +} + +// Bytes returns the binary representation of sig +// as a byte array of size 3*sizeFr x||y||s where +// * x, y are the coordinates of a point on the twisted +// Edwards represented in big endian +// * s=r+h(r,a,m) mod l, the Hasse bound guarantess that +// s is smaller than sizeFr (in particular it is supposed +// s is NOT blinded) +func (sig *Signature) Bytes() []byte { + var res [sizeSignature]byte + sigRBin := sig.R.Bytes() + subtle.ConstantTimeCopy(1, res[:sizeFr], sigRBin[:]) + subtle.ConstantTimeCopy(1, res[sizeFr:], sig.S[:]) + return res[:] +} + +// SetBytes sets sig from a buffer in binary. +// buf is read interpreted as x||y||s where +// * x,y are the coordinates of a point on the twisted +// Edwards represented in big endian +// * s=r+h(r,a,m) mod l, the Hasse bound guarantess that +// s is smaller than sizeFr (in particular it is supposed +// s is NOT blinded) +// It returns the number of bytes read from buf. +func (sig *Signature) SetBytes(buf []byte) (int, error) { + n := 0 + if len(buf) < sizeSignature { + return n, io.ErrShortBuffer + } + if _, err := sig.R.SetBytes(buf[:sizeFr]); err != nil { + return 0, err + } + n += sizeFr + if !sig.R.IsOnCurve() { + return n, errNotOnCurve + } + subtle.ConstantTimeCopy(1, sig.S[:], buf[sizeFr:2*sizeFr]) + n += sizeFr + return n, nil +} \ No newline at end of file diff --git a/internal/generator/ecc/generate.go b/internal/generator/ecc/generate.go new file mode 100644 index 0000000000..5a829185bb --- /dev/null +++ b/internal/generator/ecc/generate.go @@ -0,0 +1,49 @@ +package ecc + +import ( + "path/filepath" + "strings" + + "github.com/consensys/bavard" + "github.com/consensys/gnark-crypto/internal/generator/config" +) + +func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) error { + doc := "provides efficient elliptic curve and pairing implementation for " + conf.Name + packageName := strings.ReplaceAll(conf.Name, "-", "") + + g1 := pconf{conf, conf.G1} + g2 := pconf{conf, conf.G2} + + entriesF := []bavard.EntryF{ + {File: filepath.Join(baseDir, "multiexp.go"), TemplateF: []string{"multiexp.go.tmpl"}}, + {File: filepath.Join(baseDir, "multiexp_test.go"), TemplateF: []string{"tests/multiexp.go.tmpl"}}, + {File: filepath.Join(baseDir, "marshal.go"), TemplateF: []string{"marshal.go.tmpl"}, PackageDoc: doc}, + {File: filepath.Join(baseDir, "marshal_test.go"), TemplateF: []string{"tests/marshal.go.tmpl"}}, + } + if err := bgen.GenerateF(conf, packageName, "./ecc/template", entriesF...); err != nil { + return err + } + + // G1 + entriesF = []bavard.EntryF{ + {File: filepath.Join(baseDir, "g1.go"), TemplateF: []string{"point.go.tmpl"}}, + {File: filepath.Join(baseDir, "g1_test.go"), TemplateF: []string{"tests/point.go.tmpl"}}, + } + if err := bgen.GenerateF(g1, packageName, "./ecc/template", entriesF...); err != nil { + return err + } + + // G2 + entriesF = []bavard.EntryF{ + {File: filepath.Join(baseDir, "g2.go"), TemplateF: []string{"point.go.tmpl"}}, + {File: filepath.Join(baseDir, "g2_test.go"), TemplateF: []string{"tests/point.go.tmpl"}}, + } + return bgen.GenerateF(g2, packageName, "./ecc/template", entriesF...) + +} + +type pconf struct { + config.Curve + config.Point +} diff --git a/internal/templates/point/marshal.go.tmpl b/internal/generator/ecc/template/marshal.go.tmpl similarity index 97% rename from internal/templates/point/marshal.go.tmpl rename to internal/generator/ecc/template/marshal.go.tmpl index b3e99ac97c..033c41569b 100644 --- a/internal/templates/point/marshal.go.tmpl +++ b/internal/generator/ecc/template/marshal.go.tmpl @@ -14,17 +14,17 @@ import ( "encoding/binary" "sync/atomic" - "github.com/consensys/gurvy/{{ toLower .Name}}/internal/fptower" - "github.com/consensys/gurvy/{{ toLower .Name}}/fp" - "github.com/consensys/gurvy/{{ toLower .Name}}/fr" - "github.com/consensys/gurvy/utils/parallel" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fp" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" + "github.com/consensys/gnark-crypto/internal/parallel" ) // To encode G1Affine and G2Affine points, we mask the most significant bits with these bits to specify without ambiguity // metadata needed for point (de)compression {{- if ge .FpUnusedBits 3}} -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. @@ -37,7 +37,7 @@ const ( mCompressedInfinity byte = 0b110 << 5 ) {{- else}} -// we have less than 3 bits available on the msw, so we can't follow BLS381 style encoding. +// we have less than 3 bits available on the msw, so we can't follow BLS12-381 style encoding. // the difference is the case where a point is infinity and uncompressed is not flagged const ( mMask byte = 0b11 << 6 @@ -457,12 +457,12 @@ func (p *{{ $.TAffine }}) Unmarshal(buf []byte) error { // Bytes returns binary representation of p // will store X coordinate in regular form and a parity bit {{- if ge .all.FpUnusedBits 3}} -// we follow the BLS381 style encoding as specified in ZCash and now IETF +// we follow the BLS12-381 style encoding as specified in ZCash and now IETF // The most significant bit, when set, indicates that the point is in compressed form. Otherwise, the point is in uncompressed form. // The second-most significant bit indicates that the point is at infinity. If this bit is set, the remaining bits of the group element's encoding should be set to zero. // The third-most significant bit is set if (and only if) this point is in compressed form and it is not the point at infinity and its y-coordinate is the lexicographically largest of the two associated with the encoded x-coordinate. {{- else}} -// as we have less than 3 bits available in our coordinate, we can't follow BLS381 style encoding (ZCash/IETF) +// as we have less than 3 bits available in our coordinate, we can't follow BLS12-381 style encoding (ZCash/IETF) // we use the 2 most significant bits instead // 00 -> uncompressed // 10 -> compressed, use smallest lexicographically square root of Y^2 diff --git a/internal/templates/point/multiexp.go.tmpl b/internal/generator/ecc/template/multiexp.go.tmpl similarity index 98% rename from internal/templates/point/multiexp.go.tmpl rename to internal/generator/ecc/template/multiexp.go.tmpl index 313374d7c5..760874a722 100644 --- a/internal/templates/point/multiexp.go.tmpl +++ b/internal/generator/ecc/template/multiexp.go.tmpl @@ -8,15 +8,15 @@ import ( - "github.com/consensys/gurvy/utils/parallel" - "github.com/consensys/gurvy/{{ toLower .Name}}/fr" + "github.com/consensys/gnark-crypto/internal/parallel" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" "sync" "math" "runtime" ) // CPUSemaphore enables users to set optional number of CPUs the multiexp will use -// this is thread safe and can be used accross parallel calls of gurvy.MultiExp +// this is thread safe and can be used accross parallel calls of MultiExp type CPUSemaphore struct { chCpus chan struct{} // semaphore to limit number of cpus iterating through points and scalrs at the same time lock sync.Mutex @@ -162,7 +162,7 @@ func (p *{{ $.TJacobian }}) MultiExp(points []{{ $.TAffine }}, scalars []fr.Elem // * if c doesn't divide 64, the word size, then we're bound to select bits over 2 words of our scalars, instead of 1 // * number of CPUs // * cache friendliness (which depends on the host, G1 or G2... ) - // --> for example, on BN256, a G1 point fits into one cache line of 64bytes, but a G2 point don't. + // --> for example, on BN254, a G1 point fits into one cache line of 64bytes, but a G2 point don't. // for each msmCX // step 1 diff --git a/internal/templates/point/point.go.tmpl b/internal/generator/ecc/template/point.go.tmpl similarity index 97% rename from internal/templates/point/point.go.tmpl rename to internal/generator/ecc/template/point.go.tmpl index e7a5f4697a..5437b16d5f 100644 --- a/internal/templates/point/point.go.tmpl +++ b/internal/generator/ecc/template/point.go.tmpl @@ -8,13 +8,13 @@ import ( "math/big" - "github.com/consensys/gurvy/utils" - "github.com/consensys/gurvy/utils/parallel" - "github.com/consensys/gurvy/{{ toLower .Name}}/fr" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/internal/parallel" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" {{- if eq .CoordType "fptower.E2"}} - "github.com/consensys/gurvy/{{ toLower .Name}}/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/internal/fptower" {{else}} - "github.com/consensys/gurvy/{{ toLower .Name}}/fp" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fp" {{- end}} ) @@ -365,7 +365,7 @@ func (p *{{ $TJacobian }}) IsOnCurve() bool { -{{- if eq .Name "bn256" }} +{{- if eq .Name "bn254" }} {{- if eq .PointName "g1"}} // IsInSubGroup returns true if p is on the r-torsion, false otherwise. // For bn curves, the r-torsion in E(Fp) is the full group, so we just check that @@ -396,7 +396,7 @@ func (p *{{ $TJacobian }}) IsOnCurve() bool { } {{- end}} -{{else if eq .Name "bw761" }} +{{else if eq .Name "bw6-761" }} // IsInSubGroup returns true if p is on the r-torsion, false otherwise. // Z[r,0]+Z[-lambda{{ $TAffine }}, 1] is the kernel // of (u,v)->u+lambda{{ $TAffine }}v mod r. Expressing r, lambda{{ $TAffine }} as @@ -509,7 +509,7 @@ func (p *{{ $TJacobian }}) mulGLV(a *{{ $TJacobian }}, s *big.Int) *{{ $TJacobia table[3].phi(a) // split the scalar, modifies +-a, phi(a) accordingly - k := utils.SplitScalar(s, &glvBasis) + k := ecc.SplitScalar(s, &glvBasis) if k[0].Cmp(&zero) == -1 { k[0].Neg(&k[0]) @@ -577,20 +577,20 @@ func (p *{{ $TAffine }}) ClearCofactor(a *{{ $TAffine }}) *{{ $TAffine }} { // ClearCofactor maps a point in E(Fp) to E(Fp)[r] func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { -{{- if eq .Name "bn256"}} -{{else if eq .Name "bls381"}} +{{- if eq .Name "bn254"}} +{{else if eq .Name "bls12-381"}} // cf https://eprint.iacr.org/2019/403.pdf, 5 var res {{$TJacobian}} res.ScalarMultiplication(a, &xGen).AddAssign(a) p.Set(&res) return p -{{else if eq .Name "bls377"}} +{{else if eq .Name "bls12-377"}} // cf https://eprint.iacr.org/2019/403.pdf, 5 var res {{$TJacobian}} res.ScalarMultiplication(a, &xGen).Neg(&res).AddAssign(a) p.Set(&res) return p -{{else if eq .Name "bw761"}} +{{else if eq .Name "bw6-761"}} // https://eprint.iacr.org/2020/351.pdf var points [4]{{$TJacobian}} points[0].Set(a) @@ -635,7 +635,7 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { {{ else }} // ClearCofactor ... func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { -{{- if eq .Name "bn256"}} +{{- if eq .Name "bn254"}} // cf http://cacr.uwaterloo.ca/techreports/2011/cacr2011-26.pdf, 6.1 var points [4]{{$TJacobian}} @@ -657,7 +657,7 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { } p.Set(&res) return p -{{else if eq .Name "bls381"}} +{{else if eq .Name "bls12-381"}} // cf https://pdfs.semanticscholar.org/e305/a02d91f222de4fe62d4b5689d3b03c7db0c3.pdf, 3.1 var xg, xxg, xxxg, res, t {{$TJacobian}} xg.ScalarMultiplication(a, &xGen).Neg(&xg) @@ -687,7 +687,7 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { p.Set(&res) return p -{{else if eq .Name "bls377"}} +{{else if eq .Name "bls12-377"}} // cf https://pdfs.semanticscholar.org/e305/a02d91f222de4fe62d4b5689d3b03c7db0c3.pdf, 3.1 var xg, xxg, xxxg, res, t {{$TJacobian}} xg.ScalarMultiplication(a, &xGen) //.Neg(&xg) @@ -717,7 +717,7 @@ func (p *{{$TJacobian}}) ClearCofactor(a *{{$TJacobian}}) *{{$TJacobian}} { p.Set(&res) return p -{{else if eq .Name "bw761"}} +{{else if eq .Name "bw6-761"}} var points [4]{{$TJacobian}} points[0].Set(a) diff --git a/internal/templates/point/tests/marshal.go.tmpl b/internal/generator/ecc/template/tests/marshal.go.tmpl similarity index 98% rename from internal/templates/point/tests/marshal.go.tmpl rename to internal/generator/ecc/template/tests/marshal.go.tmpl index 74ef64ae57..dc5a212863 100644 --- a/internal/templates/point/tests/marshal.go.tmpl +++ b/internal/generator/ecc/template/tests/marshal.go.tmpl @@ -16,8 +16,8 @@ import ( "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" - "github.com/consensys/gurvy/{{ toLower .Name}}/fr" - "github.com/consensys/gurvy/{{ toLower .Name}}/fp" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fp" ) func TestEncoder(t *testing.T) { diff --git a/internal/templates/point/tests/multiexp.go.tmpl b/internal/generator/ecc/template/tests/multiexp.go.tmpl similarity index 99% rename from internal/templates/point/tests/multiexp.go.tmpl rename to internal/generator/ecc/template/tests/multiexp.go.tmpl index ead1a46393..0c744db0d7 100644 --- a/internal/templates/point/tests/multiexp.go.tmpl +++ b/internal/generator/ecc/template/tests/multiexp.go.tmpl @@ -14,7 +14,7 @@ import ( "runtime" "math/bits" - "github.com/consensys/gurvy/{{ toLower .Name}}/fr" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) diff --git a/internal/templates/point/tests/point.go.tmpl b/internal/generator/ecc/template/tests/point.go.tmpl similarity index 99% rename from internal/templates/point/tests/point.go.tmpl rename to internal/generator/ecc/template/tests/point.go.tmpl index 5deb97af07..0d646ba7cf 100644 --- a/internal/templates/point/tests/point.go.tmpl +++ b/internal/generator/ecc/template/tests/point.go.tmpl @@ -11,11 +11,11 @@ import ( "testing" {{if eq .CoordType "fptower.E2"}} - "github.com/consensys/gurvy/{{ toLower .Name}}/internal/fptower" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/internal/fptower" {{else}} - "github.com/consensys/gurvy/{{ toLower .Name}}/fp" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fp" {{end}} - "github.com/consensys/gurvy/{{ toLower .Name}}/fr" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) diff --git a/internal/generator/edwards/generate.go b/internal/generator/edwards/generate.go new file mode 100644 index 0000000000..4b5ca4f92c --- /dev/null +++ b/internal/generator/edwards/generate.go @@ -0,0 +1,15 @@ +package edwards + +import ( + "path/filepath" + + "github.com/consensys/bavard" + "github.com/consensys/gnark-crypto/internal/generator/config" +) + +func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) error { + return bgen.GenerateF(conf, "twistededwards", "./edwards/template", bavard.EntryF{ + File: filepath.Join(baseDir, "point.go"), TemplateF: []string{"pointtwistededwards.go.tmpl"}, + }) + +} diff --git a/internal/templates/point/pointtwistededwards.go.tmpl b/internal/generator/edwards/template/pointtwistededwards.go.tmpl similarity index 91% rename from internal/templates/point/pointtwistededwards.go.tmpl rename to internal/generator/edwards/template/pointtwistededwards.go.tmpl index 1ade27d453..56fbb77925 100644 --- a/internal/templates/point/pointtwistededwards.go.tmpl +++ b/internal/generator/edwards/template/pointtwistededwards.go.tmpl @@ -4,7 +4,7 @@ import ( "math/big" "math/bits" - "github.com/consensys/gurvy/{{ toLower .Name}}/fr" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" ) @@ -26,12 +26,11 @@ const ( mCompressedPositive = 0x00 mUnmask = 0x7f - // size in byte of (x,y) + // size in byte of a compressed point (point.Y --> fr.Element) sizePointCompressed = fr.Limbs * 8 ) -// Bytes returns the point as bytes array x||y, where -// x and y are in big endian. +// Bytes returns the compressed point as a byte array // Follows https://tools.ietf.org/html/rfc8032#section-3.1, // as the twisted Edwards implementation is primarily used // for eddsa. @@ -74,15 +73,11 @@ func computeX(y *fr.Element) (x fr.Element) { return } -// SetBytes sets p from the buf, where bug is interpreted -// as a sizePointCompressed+ byte slice, where the first 32 bytes -// are interpreted as x in big endian, the next 32 bytes are -// interpreted as y in big endian. Returns the number of read bytes -// and an error if the buffer is too short. -// Returns the number of bytes read. -// Follows https://tools.ietf.org/html/rfc8032#section-3.1, -// as the twisted Edwards implementation is primarily used -// for eddsa. +// SetBytes sets p from buf +// len(buf) >= sizePointCompressed +// buf contains the Y coordinate masked with a parity bit to recompute the X coordinate +// from the curve equation. See Bytes() and https://tools.ietf.org/html/rfc8032#section-3.1 +// Returns the number of read bytes and an error if the buffer is too short. func (p *PointAffine) SetBytes(buf []byte) (int, error) { if len(buf) < sizePointCompressed { @@ -107,7 +102,7 @@ func (p *PointAffine) SetBytes(buf []byte) (int, error) { } } - return 32, nil + return sizePointCompressed, nil } // Unmarshal alias to SetBytes() diff --git a/internal/generator/fft/generate.go b/internal/generator/fft/generate.go new file mode 100644 index 0000000000..abbd057081 --- /dev/null +++ b/internal/generator/fft/generate.go @@ -0,0 +1,18 @@ +package fft + +import ( + "path/filepath" + + "github.com/consensys/bavard" + "github.com/consensys/gnark-crypto/internal/generator/config" +) + +func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) error { + entries := []bavard.EntryF{ + {File: filepath.Join(baseDir, "domain_test.go"), TemplateF: []string{"tests/domain.go.tmpl", "imports.go.tmpl"}}, + {File: filepath.Join(baseDir, "domain.go"), TemplateF: []string{"domain.go.tmpl", "imports.go.tmpl"}}, + {File: filepath.Join(baseDir, "fft_test.go"), TemplateF: []string{"tests/fft.go.tmpl", "imports.go.tmpl"}}, + {File: filepath.Join(baseDir, "fft.go"), TemplateF: []string{"fft.go.tmpl", "imports.go.tmpl"}}, + } + return bgen.GenerateF(conf, "fft", "./fft/template/", entries...) +} diff --git a/internal/generator/fft/template/domain.go.tmpl b/internal/generator/fft/template/domain.go.tmpl new file mode 100644 index 0000000000..1fe3dd22cd --- /dev/null +++ b/internal/generator/fft/template/domain.go.tmpl @@ -0,0 +1,262 @@ +import ( + "math/big" + "math/bits" + "runtime" + "sync" + "io" + + {{ template "import_fr" . }} + {{ template "import_curve" . }} +) + +// Domain with a power of 2 cardinality +// compute a field element of order 2x and store it in FinerGenerator +// all other values can be derived from x, GeneratorSqrt +type Domain struct { + Cardinality uint64 + Depth uint64 + CardinalityInv fr.Element + Generator fr.Element + GeneratorInv fr.Element + FinerGenerator fr.Element + FinerGeneratorInv fr.Element + + // the following slices are not serialized and are (re)computed through domain.preComputeTwiddles() + + // Twiddles factor for the FFT using Generator for each stage of the recursive FFT + Twiddles [][]fr.Element + + // Twiddles factor for the FFT using GeneratorInv for each stage of the recursive FFT + TwiddlesInv [][]fr.Element + + // we precompute these mostly to avoid the memory intensive bit reverse permutation in the groth16.Prover + + // CosetTable[i][j] = domain.Generator(i-th)Sqrt ^ j + // CosetTable = fft.BitReverse(CosetTable) + CosetTable [][]fr.Element + + // CosetTable[i][j] = domain.Generator(i-th)SqrtInv ^ j + // CosetTableInv = fft.BitReverse(CosetTableInv) + CosetTableInv [][]fr.Element +} + +// NewDomain returns a subgroup with a power of 2 cardinality +// cardinality >= m +// If depth>0, the Domain will also store a primitive (2**depth)*m root +// of 1, with associated precomputed data. This allows to perform shifted +// FFT/FFTInv. +// +// example: +// -------- +// +// NewDomain(m, 2) outputs a new domain to perform fft on Z/mZ, plus a primitive +// 2**2*m=4m-th root of 1 and associated data to compute fft/fftinv on the cosets of +// (Z/4mZ)/(Z/mZ). +func NewDomain(m, depth uint64) *Domain { + + // generator of the largest 2-adic subgroup + var rootOfUnity fr.Element + {{if eq .Name "bls12-377"}} + rootOfUnity.SetString("8065159656716812877374967518403273466521432693661810619979959746626482506078") + const maxOrderRoot uint64 = 47 + {{else if eq .Name "bls12-381"}} + rootOfUnity.SetString("10238227357739495823651030575849232062558860180284477541189508159991286009131") + const maxOrderRoot uint64 = 32 + {{else if eq .Name "bn254"}} + rootOfUnity.SetString("19103219067921713944291392827692070036145651957329286315305642004821462161904") + const maxOrderRoot uint64 = 28 + {{else if eq .Name "bw6-761"}} + rootOfUnity.SetString("32863578547254505029601261939868325669770508939375122462904745766352256812585773382134936404344547323199885654433") + const maxOrderRoot uint64 = 46 + {{end}} + + subGroup := &Domain{} + x := nextPowerOfTwo(m) + subGroup.Cardinality = uint64(x) + subGroup.Depth = depth + + // find generator for Z/2^(log(m))Z and Z/2^(log(m)+cosets)Z + logx := uint64(bits.TrailingZeros64(x)) + if logx > maxOrderRoot { + panic("m is too big: the required root of unity does not exist") + } + logGen := logx + depth + if logGen > maxOrderRoot { + panic("log(m) + cosets is too big: the required root of unity does not exist") + } + + expo := uint64(1 << (maxOrderRoot - logGen)) + bExpo := new(big.Int).SetUint64(expo) + subGroup.FinerGenerator.Exp(rootOfUnity, bExpo) + subGroup.FinerGeneratorInv.Inverse(&subGroup.FinerGenerator) + + // Generator = FinerGenerator^2 has order x + expo = uint64(1 << (maxOrderRoot - logx)) + bExpo.SetUint64(expo) + subGroup.Generator.Exp(rootOfUnity, bExpo) // order x + subGroup.GeneratorInv.Inverse(&subGroup.Generator) + subGroup.CardinalityInv.SetUint64(uint64(x)).Inverse(&subGroup.CardinalityInv) + + // twiddle factors + subGroup.preComputeTwiddles() + + return subGroup +} + +func (d *Domain) preComputeTwiddles() { + + // nb fft stages + nbStages := uint64(bits.TrailingZeros64(d.Cardinality)) + nbCosets := (1 << d.Depth) - 1 + + d.Twiddles = make([][]fr.Element, nbStages) + d.TwiddlesInv = make([][]fr.Element, nbStages) + d.CosetTable = make([][]fr.Element, nbCosets) + d.CosetTableInv = make([][]fr.Element, nbCosets) + for i := 0; i < nbCosets; i++ { + d.CosetTable[i] = make([]fr.Element, d.Cardinality) + d.CosetTableInv[i] = make([]fr.Element, d.Cardinality) + } + + var wg sync.WaitGroup + + // for each fft stage, we pre compute the twiddle factors + twiddles := func(t [][]fr.Element, omega fr.Element) { + for i := uint64(0); i < nbStages; i++ { + t[i] = make([]fr.Element, 1+(1<<(nbStages-i-1))) + var w fr.Element + if i == 0 { + w = omega + } else { + w = t[i-1][2] + } + t[i][0] = fr.One() + t[i][1] = w + for j := 2; j < len(t[i]); j++ { + t[i][j].Mul(&t[i][j-1], &w) + } + } + wg.Done() + } + + expTable := func(sqrt fr.Element, t []fr.Element) { + t[0] = fr.One() + precomputeExpTable(sqrt, t) + wg.Done() + } + + if nbCosets > 0 { + cosetGens := make([]fr.Element, nbCosets) + cosetGensInv := make([]fr.Element, nbCosets) + cosetGens[0].Set(&d.FinerGenerator) + cosetGensInv[0].Set(&d.FinerGeneratorInv) + for i := 1; i < nbCosets; i++ { + cosetGens[i].Mul(&cosetGens[i-1], &d.FinerGenerator) + cosetGensInv[i].Mul(&cosetGensInv[1], &d.FinerGeneratorInv) + } + wg.Add(2 + 2*nbCosets) + go twiddles(d.Twiddles, d.Generator) + go twiddles(d.TwiddlesInv, d.GeneratorInv) + for i := 0; i < nbCosets-1; i++ { + go expTable(cosetGens[i], d.CosetTable[i]) + go expTable(cosetGensInv[i], d.CosetTableInv[i]) + } + go expTable(cosetGens[nbCosets-1], d.CosetTable[nbCosets-1]) + expTable(cosetGensInv[nbCosets-1], d.CosetTableInv[nbCosets-1]) + + wg.Wait() + + } else { + wg.Add(2) + go twiddles(d.Twiddles, d.Generator) + twiddles(d.TwiddlesInv, d.GeneratorInv) + wg.Wait() + } + +} + +func precomputeExpTable(w fr.Element, table []fr.Element) { + n := len(table) + + // see if it makes sense to parallelize exp tables pre-computation + interval := 0 + if runtime.NumCPU() >= 4 { + interval = (n - 1) / (runtime.NumCPU() / 4) + } + + // this ratio roughly correspond to the number of multiplication one can do in place of a Exp operation + const ratioExpMul = 6000 / 17 + + if interval < ratioExpMul { + precomputeExpTableChunk(w, 1, table[1:]) + return + } + + // we parallelize + var wg sync.WaitGroup + for i := 1; i < n; i += interval { + start := i + end := i + interval + if end > n { + end = n + } + wg.Add(1) + go func() { + precomputeExpTableChunk(w, uint64(start), table[start:end]) + wg.Done() + }() + } + wg.Wait() +} + +func precomputeExpTableChunk(w fr.Element, power uint64, table []fr.Element) { + table[0].Exp(w, new(big.Int).SetUint64(power)) + for i := 1; i < len(table); i++ { + table[i].Mul(&table[i-1], &w) + } +} + +func nextPowerOfTwo(n uint64) uint64 { + p := uint64(1) + if (n & (n - 1)) == 0 { + return n + } + for p < n { + p <<= 1 + } + return p +} + +// WriteTo writes a binary representation of the domain (without the precomputed twiddle factors) +// to the provided writer +func (d *Domain) WriteTo(w io.Writer) (int64, error) { + + enc := curve.NewEncoder(w) + + toEncode := []interface{}{d.Cardinality, d.Depth, &d.CardinalityInv, &d.Generator, &d.GeneratorInv, &d.FinerGenerator, &d.FinerGeneratorInv} + + for _, v := range toEncode { + if err := enc.Encode(v); err != nil { + return enc.BytesWritten(), err + } + } + + return enc.BytesWritten(), nil +} + +// ReadFrom attempts to decode a domain from Reader +func (d *Domain) ReadFrom(r io.Reader) (int64, error) { + + dec := curve.NewDecoder(r) + + toDecode := []interface{}{&d.Cardinality, &d.Depth, &d.CardinalityInv, &d.Generator, &d.GeneratorInv, &d.FinerGenerator, &d.FinerGeneratorInv} + + for _, v := range toDecode { + if err := dec.Decode(v); err != nil { + return dec.BytesRead(), err + } + } + + d.preComputeTwiddles() + return dec.BytesRead(), nil +} diff --git a/internal/generator/fft/template/fft.go.tmpl b/internal/generator/fft/template/fft.go.tmpl new file mode 100644 index 0000000000..0222874790 --- /dev/null +++ b/internal/generator/fft/template/fft.go.tmpl @@ -0,0 +1,246 @@ +import ( + "math/bits" + "runtime" + + "github.com/consensys/gnark-crypto/internal/parallel" + {{ template "import_fr" . }} +) + +// Decimation is used in the FFT call to select decimation in time or in frequency +type Decimation uint8 + +const ( + DIT Decimation = iota + DIF +) + +// parallelize threshold for a single butterfly op, if the fft stage is not parallelized already +const butterflyThreshold = 16 + +// FFT computes (recursively) the discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +// +// example: +// ------- +// domain := NewDomain(m, 2) --> contains precomputed data for Z/mZ, and Z/4mZ +// FFT(pol, DIT, 1) --> evaluates pol on the coset 1 in (Z/4mZ)/(Z/mZ) +func (domain *Domain) FFT(a []fr.Element, decimation Decimation, coset uint64) { + + numCPU := uint64(runtime.NumCPU()) + + if coset != 0 { + if decimation == DIT { + BitReverse(domain.CosetTable[coset-1]) + } + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].Mul(&a[i], &domain.CosetTable[coset-1][i]) + } + }) + // put it back as we found it + if decimation == DIT { + BitReverse(domain.CosetTable[coset-1]) + } + } + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(nextPowerOfTwo(numCPU)) + if numCPU <= 1 { + maxSplits = -1 + } + + switch decimation { + case DIF: + difFFT(a, domain.Twiddles, 0, maxSplits, nil) + case DIT: + ditFFT(a, domain.Twiddles, 0, maxSplits, nil) + default: + panic("not implemented") + } +} + +// FFTInverse computes (recursively) the inverse discrete Fourier transform of a and stores the result in a +// if decimation == DIT (decimation in time), the input must be in bit-reversed order +// if decimation == DIF (decimation in frequency), the output will be in bit-reversed order +// coset sets the shift of the fft (0 = no shift, standard fft) +// len(a) must be a power of 2, and w must be a len(a)th root of unity in field F. +func (domain *Domain) FFTInverse(a []fr.Element, decimation Decimation, coset uint64) { + + numCPU := uint64(runtime.NumCPU()) + + // find the stage where we should stop spawning go routines in our recursive calls + // (ie when we have as many go routines running as we have available CPUs) + maxSplits := bits.TrailingZeros64(nextPowerOfTwo(numCPU)) + if numCPU <= 1 { + maxSplits = -1 + } + switch decimation { + case DIF: + difFFT(a, domain.TwiddlesInv, 0, maxSplits, nil) + case DIT: + ditFFT(a, domain.TwiddlesInv, 0, maxSplits, nil) + default: + panic("not implemented") + } + + // scale by CardinalityInv (+ cosetTableInv is coset!=0) + if coset != 0 { + if decimation == DIF { + BitReverse(domain.CosetTableInv[coset-1]) + } + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].Mul(&a[i], &domain.CosetTableInv[coset-1][i]). + MulAssign(&domain.CardinalityInv) + } + }) + // put it back as we found it + if decimation == DIF { + BitReverse(domain.CosetTableInv[coset-1]) + } + } else { + parallel.Execute(len(a), func(start, end int) { + for i := start; i < end; i++ { + a[i].MulAssign(&domain.CardinalityInv) + } + }) + } +} + +func difFFT(a []fr.Element, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer func() { + chDone <- struct{}{} + }() + } + n := len(a) + if n == 1 { + return + } + m := n >> 1 + + // if stage < maxSplits, we parallelize this butterfly + // but we have only numCPU / stage cpus available + if (m > butterflyThreshold) && (stage < maxSplits) { + // 1 << stage == estimated used CPUs + numCPU := runtime.NumCPU() / (1 << (stage)) + parallel.Execute(m, func(start, end int) { + var t fr.Element + for i := start; i < end; i++ { + t = a[i] + a[i].Add(&a[i], &a[i+m]) + + a[i+m]. + Sub(&t, &a[i+m]). + Mul(&a[i+m], &twiddles[stage][i]) + } + }, numCPU) + } else { + var t fr.Element + + // i == 0 + t = a[0] + a[0].Add(&a[0], &a[m]) + a[m].Sub(&t, &a[m]) + + for i := 1; i < m; i++ { + t = a[i] + a[i].Add(&a[i], &a[i+m]) + + a[i+m]. + Sub(&t, &a[i+m]). + Mul(&a[i+m], &twiddles[stage][i]) + } + } + + if m == 1 { + return + } + + nextStage := stage + 1 + if stage < maxSplits { + chDone := make(chan struct{}, 1) + go difFFT(a[m:n], twiddles, nextStage, maxSplits, chDone) + difFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + difFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + difFFT(a[m:n], twiddles, nextStage, maxSplits, nil) + } +} + +func ditFFT(a []fr.Element, twiddles [][]fr.Element, stage, maxSplits int, chDone chan struct{}) { + if chDone != nil { + defer func() { + chDone <- struct{}{} + }() + } + n := len(a) + if n == 1 { + return + } + m := n >> 1 + + nextStage := stage + 1 + + if stage < maxSplits { + // that's the only time we fire go routines + chDone := make(chan struct{}, 1) + go ditFFT(a[m:], twiddles, nextStage, maxSplits, chDone) + ditFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + <-chDone + } else { + ditFFT(a[0:m], twiddles, nextStage, maxSplits, nil) + ditFFT(a[m:n], twiddles, nextStage, maxSplits, nil) + + } + + // if stage < maxSplits, we parallelize this butterfly + // but we have only numCPU / stage cpus available + if (m > butterflyThreshold) && (stage < maxSplits) { + // 1 << stage == estimated used CPUs + numCPU := runtime.NumCPU() / (1 << (stage)) + parallel.Execute(m, func(start, end int) { + var t, tm fr.Element + for k := start; k < end; k++ { + t = a[k] + tm.Mul(&a[k+m], &twiddles[stage][k]) + a[k].Add(&a[k], &tm) + a[k+m].Sub(&t, &tm) + } + }, numCPU) + + } else { + var t, tm fr.Element + // k == 0 + // wPow == 1 + t = a[0] + a[0].Add(&a[0], &a[m]) + a[m].Sub(&t, &a[m]) + + for k := 1; k < m; k++ { + t = a[k] + tm.Mul(&a[k+m], &twiddles[stage][k]) + a[k].Add(&a[k], &tm) + a[k+m].Sub(&t, &tm) + } + } +} + +// BitReverse applies the bit-reversal permutation to a. +// len(a) must be a power of 2 (as in every single function in this file) +func BitReverse(a []fr.Element) { + n := uint64(len(a)) + nn := uint64(64 - bits.TrailingZeros64(n)) + + for i := uint64(0); i < n; i++ { + irev := bits.Reverse64(i) >> nn + if irev > i { + a[i], a[irev] = a[irev], a[i] + } + } +} diff --git a/internal/generator/fft/template/imports.go.tmpl b/internal/generator/fft/template/imports.go.tmpl new file mode 100644 index 0000000000..b0138ef35b --- /dev/null +++ b/internal/generator/fft/template/imports.go.tmpl @@ -0,0 +1,27 @@ +{{ define "import_fr" }} + +{{ if eq .Name "bls12-377"}} + "github.com/consensys/gnark-crypto/ecc/bls12-377/fr" +{{ else if eq .Name "bls12-381"}} + "github.com/consensys/gnark-crypto/ecc/bls12-381/fr" +{{ else if eq .Name "bn254"}} + "github.com/consensys/gnark-crypto/ecc/bn254/fr" +{{ else if eq .Name "bw6-761"}} + "github.com/consensys/gnark-crypto/ecc/bw6-761/fr" +{{end}} + +{{end}} + +{{ define "import_curve" }} +{{if eq .Name "bls12-377"}} + curve "github.com/consensys/gnark-crypto/ecc/bls12-377" +{{else if eq .Name "bls12-381"}} + curve "github.com/consensys/gnark-crypto/ecc/bls12-381" +{{else if eq .Name "bn254"}} + curve "github.com/consensys/gnark-crypto/ecc/bn254" +{{else if eq .Name "bw6-761"}} + curve "github.com/consensys/gnark-crypto/ecc/bw6-761" +{{end}} + + +{{end}} \ No newline at end of file diff --git a/internal/generator/fft/template/tests/domain.go.tmpl b/internal/generator/fft/template/tests/domain.go.tmpl new file mode 100644 index 0000000000..92962a4036 --- /dev/null +++ b/internal/generator/fft/template/tests/domain.go.tmpl @@ -0,0 +1,30 @@ + +import ( + "reflect" + "testing" + "bytes" +) + +func TestDomainSerialization(t *testing.T) { + + domain := NewDomain(1<<6, 1) + var reconstructed Domain + + var buf bytes.Buffer + written, err := domain.WriteTo(&buf) + if err != nil { + t.Fatal(err) + } + var read int64 + read, err = reconstructed.ReadFrom(&buf) + if err != nil { + t.Fatal(err) + } + + if written != read { + t.Fatal("didn't read as many bytes as we wrote") + } + if !reflect.DeepEqual(domain, &reconstructed) { + t.Fatal("Domain.SetBytes(Bytes()) failed") + } +} \ No newline at end of file diff --git a/internal/generator/fft/template/tests/fft.go.tmpl b/internal/generator/fft/template/tests/fft.go.tmpl new file mode 100644 index 0000000000..a94c144741 --- /dev/null +++ b/internal/generator/fft/template/tests/fft.go.tmpl @@ -0,0 +1,188 @@ +import ( + "math/big" + "testing" + "strconv" + + {{ template "import_fr" . }} + + "github.com/leanovate/gopter" + "github.com/leanovate/gopter/prop" + "github.com/leanovate/gopter/gen" + +) + +func TestFFT(t *testing.T) { + const maxSize = 1 << 10 + + domain := NewDomain(maxSize, 0) + + parameters := gopter.DefaultTestParameters() + parameters.MinSuccessfulTests = 5 + + properties := gopter.NewProperties(parameters) + + properties.Property("DIF FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domain.FFT(pol, DIF, 0) + BitReverse(pol) + + sample := domain.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := evaluatePolynomial(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("DIT FFT should be consistent with dual basis", prop.ForAll( + + // checks that a random evaluation of a dual function eval(gen**ithpower) is consistent with the FFT result + func(ithpower int) bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverse(pol) + domain.FFT(pol, DIT, 0) + + sample := domain.Generator + sample.Exp(sample, big.NewInt(int64(ithpower))) + + eval := evaluatePolynomial(backupPol, sample) + + return eval.Equal(&pol[ithpower]) + + }, + gen.IntRange(0, maxSize-1), + )) + + properties.Property("bitReverse(DIF FFT(DIT FFT (bitReverse))))==id", prop.ForAll( + + func() bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + BitReverse(pol) + domain.FFT(pol, DIT, 0) + domain.FFTInverse(pol, DIF, 0) + BitReverse(pol) + + check := true + for i := 0; i < len(pol); i++ { + check = check && pol[i].Equal(&backupPol[i]) + } + return check + }, + )) + + properties.Property("DIT FFT(DIF FFT)==id", prop.ForAll( + + func() bool { + + pol := make([]fr.Element, maxSize) + backupPol := make([]fr.Element, maxSize) + + for i := 0; i < maxSize; i++ { + pol[i].SetRandom() + } + copy(backupPol, pol) + + domain.FFTInverse(pol, DIF, 0) + domain.FFT(pol, DIT, 0) + + check := true + for i := 0; i < len(pol); i++ { + check = check && (pol[i] == backupPol[i]) + } + return check + }, + )) + + properties.TestingRun(t, gopter.ConsoleReporter(false)) + +} + +// -------------------------------------------------------------------- +// benches +func BenchmarkBitReverse(b *testing.B) { + + const maxSize = 1 << 20 + + pol := make([]fr.Element, maxSize) + for i := uint64(0); i < maxSize; i++ { + pol[i].SetRandom() + } + + for i := 8; i < 20; i++ { + b.Run("bit reversing 2**"+strconv.Itoa(i)+"bits", func(b *testing.B) { + _pol := make([]fr.Element, 1<= 0; i-- { + res.Mul(&res, &_v) + res.Add(&res, &p[i]) + } + return &res +} diff --git a/internal/asm/amd64/e2.go b/internal/generator/tower/asm/amd64/e2.go similarity index 89% rename from internal/asm/amd64/e2.go rename to internal/generator/tower/asm/amd64/e2.go index b96d2e59e9..13fa552b90 100644 --- a/internal/asm/amd64/e2.go +++ b/internal/generator/tower/asm/amd64/e2.go @@ -16,27 +16,28 @@ package amd64 import ( "io" - "strings" "github.com/consensys/bavard" ramd64 "github.com/consensys/bavard/amd64" - "github.com/consensys/goff/asm/amd64" - "github.com/consensys/goff/field" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/field" + "github.com/consensys/gnark-crypto/field/asm/amd64" + "github.com/consensys/gnark-crypto/internal/generator/config" ) // Fq2Amd64 ... type Fq2Amd64 struct { *amd64.FFAmd64 - curveName string - w io.Writer - F *field.Field + config config.Curve + w io.Writer + F *field.Field } // NewFq2Amd64 ... -func NewFq2Amd64(w io.Writer, F *field.Field, curveName string) *Fq2Amd64 { +func NewFq2Amd64(w io.Writer, F *field.Field, config config.Curve) *Fq2Amd64 { return &Fq2Amd64{ amd64.NewFFAmd64(w, F), - curveName, + config, w, F, } @@ -50,7 +51,7 @@ func (fq2 *Fq2Amd64) Generate(forceADXCheck bool) error { fq2.WriteLn("#include \"funcdata.h\"") fq2.GenerateDefines() - if strings.ToLower(fq2.curveName) == "bn256" { + if fq2.config.ID() == ecc.BN254 { fq2.generateMulDefine() } @@ -59,12 +60,12 @@ func (fq2 *Fq2Amd64) Generate(forceADXCheck bool) error { fq2.generateSubE2() fq2.generateNegE2() - switch strings.ToLower(fq2.curveName) { - case "bn256": - fq2.generateMulByNonResidueE2BN256() - fq2.generateMulE2BN256(forceADXCheck) - fq2.generateSquareE2BN256(forceADXCheck) - case "bls381": + switch fq2.config.ID() { + case ecc.BN254: + fq2.generateMulByNonResidueE2BN254() + fq2.generateMulE2BN254(forceADXCheck) + fq2.generateSquareE2BN254(forceADXCheck) + case ecc.BLS12_381: fq2.generateMulByNonResidueE2BLS381() fq2.generateSquareE2BLS381(forceADXCheck) fq2.generateMulE2BLS381(forceADXCheck) diff --git a/internal/asm/amd64/e2_bls381.go b/internal/generator/tower/asm/amd64/e2_bls381.go similarity index 98% rename from internal/asm/amd64/e2_bls381.go rename to internal/generator/tower/asm/amd64/e2_bls381.go index ef97d23b77..57abf58a05 100644 --- a/internal/asm/amd64/e2_bls381.go +++ b/internal/generator/tower/asm/amd64/e2_bls381.go @@ -245,7 +245,6 @@ func (fq2 *Fq2Amd64) generateMulE2BLS381(forceCheck bool) { fq2.Mov(dx, op1) fq2.Add(dx, op1, fq2.NbWords) // --> note, we don't reduce, as this is used as input to the mul which accept input of size D-1/2 -1 - // TODO @gbotrel prove the upper bound / lower bound case for the no_carry mul // a = a * b = (x.a0 + x.a1) * (y.a0 + y.a1) fq2.MulADX(®isters, xat, func(i int) string { diff --git a/internal/asm/amd64/e2_bn256.go b/internal/generator/tower/asm/amd64/e2_bn254.go similarity index 95% rename from internal/asm/amd64/e2_bn256.go rename to internal/generator/tower/asm/amd64/e2_bn254.go index 61c6df4235..ec9dc3a364 100644 --- a/internal/asm/amd64/e2_bn256.go +++ b/internal/generator/tower/asm/amd64/e2_bn254.go @@ -21,10 +21,10 @@ import ( "strings" "github.com/consensys/bavard/amd64" - gamd64 "github.com/consensys/goff/asm/amd64" + gamd64 "github.com/consensys/gnark-crypto/field/asm/amd64" ) -func (fq2 *Fq2Amd64) generateMulByNonResidueE2BN256() { +func (fq2 *Fq2Amd64) generateMulByNonResidueE2BN254() { // var a, b fp.Element // a.Double(&x.A0).Double(&a).Double(&a).fq2.Add(&a, &x.A0).fq2.Sub(&a, &x.A1) // b.Double(&x.A1).Double(&b).Double(&b).fq2.Add(&b, &x.A1).fq2.Add(&b, &x.A0) @@ -79,7 +79,7 @@ func (fq2 *Fq2Amd64) generateMulByNonResidueE2BN256() { fq2.RET() } -func (fq2 *Fq2Amd64) generateSquareE2BN256(forceCheck bool) { +func (fq2 *Fq2Amd64) generateSquareE2BN254(forceCheck bool) { const argSize = 16 minStackSize := 0 @@ -170,7 +170,7 @@ func (fq2 *Fq2Amd64) generateSquareE2BN256(forceCheck bool) { } -func (fq2 *Fq2Amd64) generateMulE2BN256(forceCheck bool) { +func (fq2 *Fq2Amd64) generateMulE2BN254(forceCheck bool) { const argSize = 24 minStackSize := 0 if forceCheck { @@ -308,8 +308,8 @@ func (fq2 *Fq2Amd64) generateMulDefine() { wd := writerDefine{fq2.w} tw := gamd64.NewFFAmd64(&wd, fq2.F) - io.WriteString(fq2.w, "// this code is generated and identical to fp.Mul(...)\n") - io.WriteString(fq2.w, "#define MUL() \\ \n") + _, _ = io.WriteString(fq2.w, "// this code is generated and identical to fp.Mul(...)\n") + _, _ = io.WriteString(fq2.w, "#define MUL() \\ \n") tw.MulADX(&r, xat, yat, res) } diff --git a/internal/generator/tower/generate.go b/internal/generator/tower/generate.go new file mode 100644 index 0000000000..6b7926c8b0 --- /dev/null +++ b/internal/generator/tower/generate.go @@ -0,0 +1,79 @@ +package tower + +import ( + "io" + "os" + "path/filepath" + + "github.com/consensys/bavard" + "github.com/consensys/gnark-crypto/ecc" + "github.com/consensys/gnark-crypto/internal/generator/config" + "github.com/consensys/gnark-crypto/internal/generator/tower/asm/amd64" +) + +// Generate generates a tower 2->6->12 over fp +func Generate(conf config.Curve, baseDir string, bgen *bavard.BatchGenerator) error { + if conf.ID() == ecc.BW6_761 { + return nil + } + + entries := []bavard.EntryF{ + {File: filepath.Join(baseDir, "e2.go"), TemplateF: []string{"fq2.go.tmpl"}}, + {File: filepath.Join(baseDir, "e6.go"), TemplateF: []string{"fq6.go.tmpl"}}, + {File: filepath.Join(baseDir, "e12.go"), TemplateF: []string{"fq12.go.tmpl"}}, + {File: filepath.Join(baseDir, "e2_amd64.go"), TemplateF: []string{"amd64.fq2.go.tmpl"}}, + {File: filepath.Join(baseDir, "e2_fallback.go"), TemplateF: []string{"fallback.fq2.go.tmpl"}, BuildTag: "!amd64"}, + {File: filepath.Join(baseDir, "e2_test.go"), TemplateF: []string{"tests/fq2.go.tmpl"}}, + {File: filepath.Join(baseDir, "e6_test.go"), TemplateF: []string{"tests/fq6.go.tmpl"}}, + {File: filepath.Join(baseDir, "e12_test.go"), TemplateF: []string{"tests/fq12.go.tmpl"}}, + {File: filepath.Join(baseDir, "asm.go"), TemplateF: []string{"asm.go.tmpl"}, BuildTag: "!noadx"}, + {File: filepath.Join(baseDir, "asm_noadx.go"), TemplateF: []string{"asm_noadx.go.tmpl"}, BuildTag: "noadx"}, + } + + if err := bgen.GenerateF(conf, "fptower", "./tower/template/fq12over6over2", entries...); err != nil { + return err + } + + { + // fq2 assembly + fName := filepath.Join(baseDir, "e2_amd64.s") + f, err := os.Create(fName) + if err != nil { + return err + } + + if conf.ID() == ecc.BN254 || conf.ID() == ecc.BLS12_381 { + _, _ = io.WriteString(f, "// +build !amd64_adx\n") + } + Fq2Amd64 := amd64.NewFq2Amd64(f, conf.Fp, conf) + if err := Fq2Amd64.Generate(true); err != nil { + _ = f.Close() + return err + } + _ = f.Close() + + } + + if conf.ID() == ecc.BN254 || conf.ID() == ecc.BLS12_381 { + { + // fq2 assembly + fName := filepath.Join(baseDir, "e2_adx_amd64.s") + f, err := os.Create(fName) + if err != nil { + return err + } + + _, _ = io.WriteString(f, "// +build amd64_adx\n") + Fq2Amd64 := amd64.NewFq2Amd64(f, conf.Fp, conf) + if err := Fq2Amd64.Generate(false); err != nil { + _ = f.Close() + return err + } + _ = f.Close() + + } + } + + return nil + +} diff --git a/internal/templates/fq12over6over2/amd64.fq2.go.tmpl b/internal/generator/tower/template/fq12over6over2/amd64.fq2.go.tmpl similarity index 96% rename from internal/templates/fq12over6over2/amd64.fq2.go.tmpl rename to internal/generator/tower/template/fq12over6over2/amd64.fq2.go.tmpl index fd2ed89cb8..ab6fcf9279 100644 --- a/internal/templates/fq12over6over2/amd64.fq2.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/amd64.fq2.go.tmpl @@ -24,7 +24,7 @@ func doubleE2(res,x *E2) //go:noescape func negE2(res,x *E2) -{{if eq .Name "bn256"}} +{{if eq .Name "bn254"}} //go:noescape func mulNonResE2(res, x *E2) @@ -53,7 +53,7 @@ func (z *E2) Square(x *E2) *E2 { return z } -{{else if eq .Name "bls381"}} +{{else if eq .Name "bls12-381"}} //go:noescape func mulNonResE2(res, x *E2) diff --git a/internal/templates/fq12over6over2/asm.go.tmpl b/internal/generator/tower/template/fq12over6over2/asm.go.tmpl similarity index 100% rename from internal/templates/fq12over6over2/asm.go.tmpl rename to internal/generator/tower/template/fq12over6over2/asm.go.tmpl diff --git a/internal/templates/fq12over6over2/asm_noadx.go.tmpl b/internal/generator/tower/template/fq12over6over2/asm_noadx.go.tmpl similarity index 100% rename from internal/templates/fq12over6over2/asm_noadx.go.tmpl rename to internal/generator/tower/template/fq12over6over2/asm_noadx.go.tmpl diff --git a/internal/templates/fq12over6over2/fallback.fq2.go.tmpl b/internal/generator/tower/template/fq12over6over2/fallback.fq2.go.tmpl similarity index 100% rename from internal/templates/fq12over6over2/fallback.fq2.go.tmpl rename to internal/generator/tower/template/fq12over6over2/fallback.fq2.go.tmpl diff --git a/internal/templates/fq12over6over2/fq12.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl similarity index 98% rename from internal/templates/fq12over6over2/fq12.go.tmpl rename to internal/generator/tower/template/fq12over6over2/fq12.go.tmpl index 4106ca0068..f5776e5203 100644 --- a/internal/templates/fq12over6over2/fq12.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/fq12.go.tmpl @@ -2,8 +2,8 @@ import ( "math/big" "encoding/binary" "errors" - "github.com/consensys/gurvy/{{toLower .Name}}/fp" - "github.com/consensys/gurvy/{{toLower .Name}}/fr" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fp" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" ) // E12 is a degree two finite field extension of fp6 diff --git a/internal/templates/fq12over6over2/fq2.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq2.go.tmpl similarity index 96% rename from internal/templates/fq12over6over2/fq2.go.tmpl rename to internal/generator/tower/template/fq12over6over2/fq2.go.tmpl index 503f7b4250..6963f2de62 100644 --- a/internal/templates/fq12over6over2/fq2.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/fq2.go.tmpl @@ -1,7 +1,7 @@ import ( "math/big" - "github.com/consensys/gurvy/{{toLower .Name}}/fp" + "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fp" ) @@ -220,7 +220,8 @@ func (z *E2) Exp(x E2, exponent *big.Int) *E2 { var b, c, d, e, f, x0 E2 var _b, o fp.Element - c.A1.SetOne() // c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently) + // c must be a non square (works for p=1 mod 12 hence 1 mod 4, only bls377 has such a p currently) + c.A1.SetOne() q := fp.Modulus() var exp, one big.Int diff --git a/internal/templates/fq12over6over2/fq6.go.tmpl b/internal/generator/tower/template/fq12over6over2/fq6.go.tmpl similarity index 100% rename from internal/templates/fq12over6over2/fq6.go.tmpl rename to internal/generator/tower/template/fq12over6over2/fq6.go.tmpl diff --git a/internal/templates/fq12over6over2/tests/fq12.go.tmpl b/internal/generator/tower/template/fq12over6over2/tests/fq12.go.tmpl similarity index 100% rename from internal/templates/fq12over6over2/tests/fq12.go.tmpl rename to internal/generator/tower/template/fq12over6over2/tests/fq12.go.tmpl diff --git a/internal/templates/fq12over6over2/tests/fq2.go.tmpl b/internal/generator/tower/template/fq12over6over2/tests/fq2.go.tmpl similarity index 98% rename from internal/templates/fq12over6over2/tests/fq2.go.tmpl rename to internal/generator/tower/template/fq12over6over2/tests/fq2.go.tmpl index a305067248..97e707b03c 100644 --- a/internal/templates/fq12over6over2/tests/fq2.go.tmpl +++ b/internal/generator/tower/template/fq12over6over2/tests/fq2.go.tmpl @@ -2,7 +2,7 @@ import ( "testing" "crypto/rand" - "github.com/consensys/gurvy/{{toLower .Name}}/fp" + "github.com/consensys/gnark-crypto/ecc/{{toLower .Name}}/fp" "github.com/leanovate/gopter" "github.com/leanovate/gopter/prop" ) @@ -185,7 +185,7 @@ func TestE2MulMaxed(t *testing.T) { - // [BN256] mul & inverse should leave an element invariant", prop.ForAll( + // [BN254] mul & inverse should leave an element invariant", prop.ForAll( var c, d E2 d.Inverse(&b) c.Set(&a) diff --git a/internal/templates/fq12over6over2/tests/fq6.go.tmpl b/internal/generator/tower/template/fq12over6over2/tests/fq6.go.tmpl similarity index 100% rename from internal/templates/fq12over6over2/tests/fq6.go.tmpl rename to internal/generator/tower/template/fq12over6over2/tests/fq6.go.tmpl diff --git a/internal/interop/bls381/interop_test.go b/internal/interop/bls381/interop_test.go deleted file mode 100644 index ee02989126..0000000000 --- a/internal/interop/bls381/interop_test.go +++ /dev/null @@ -1,448 +0,0 @@ -package interop - -import ( - "bytes" - "crypto/rand" - "math/big" - "testing" - - bls12381 "github.com/kilic/bls12-381" - - "github.com/consensys/gurvy/bls381" - "github.com/consensys/gurvy/bls381/fp" - "github.com/leanovate/gopter" - "github.com/leanovate/gopter/prop" -) - -// Test against github.com/kilic/bls12-381 - -var ( - g1Gen bls381.G1Jac - g2Gen bls381.G2Jac - g1GenAff bls381.G1Affine - g2GenAff bls381.G2Affine -) - -func init() { - g1Gen, g2Gen, g1GenAff, g2GenAff = bls381.Generators() -} - -func TestG1AffineSerializationInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BLS381] G1: gurvy -> bls12-381 -> gurvy should stay constant", prop.ForAll( - func(a fp.Element) bool { - var start, end bls381.G1Affine - var ab big.Int - a.ToBigIntRegular(&ab) - start.ScalarMultiplication(&g1GenAff, &ab) - - g1 := bls12381.NewG1() - other, err := g1.FromBytes(start.Marshal()) - if err != nil { - t.Log(err) - return false - } - // reconstruct a gurvy point from bytes - err = end.Unmarshal(g1.ToBytes(other)) - if err != nil { - return false - } - return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) - }, - genFp(), - )) - - properties.Property("[BLS381] G1 compressed: gurvy -> bls12-381 -> gurvy should stay constant", prop.ForAll( - func(a fp.Element) bool { - var start, end bls381.G1Affine - var ab big.Int - a.ToBigIntRegular(&ab) - start.ScalarMultiplication(&g1GenAff, &ab) - - g1 := bls12381.NewG1() - b := start.Bytes() - other, err := g1.FromCompressed(b[:]) - if err != nil { - t.Log(err) - return false - } - // reconstruct a gurvy point from bytes - err = end.Unmarshal(g1.ToCompressed(other)) - if err != nil { - return false - } - return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) - }, - genFp(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) - -} - -func TestG2AffineSerializationInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BLS381] G2: gurvy -> bls12-381 -> gurvy should stay constant", prop.ForAll( - func(a fp.Element) bool { - var start, end bls381.G2Affine - var ab big.Int - a.ToBigIntRegular(&ab) - start.ScalarMultiplication(&g2GenAff, &ab) - - g2 := bls12381.NewG2() - other, err := g2.FromBytes(start.Marshal()) - if err != nil { - t.Log(err) - return false - } - // reconstruct a gurvy point from bytes - err = end.Unmarshal(g2.ToBytes(other)) - if err != nil { - return false - } - return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) - }, - genFp(), - )) - - properties.Property("[BLS381] G2 compressed: gurvy -> bls12-381 -> gurvy should stay constant", prop.ForAll( - func(a fp.Element) bool { - var start, end bls381.G2Affine - var ab big.Int - a.ToBigIntRegular(&ab) - start.ScalarMultiplication(&g2GenAff, &ab) - - g2 := bls12381.NewG2() - b := start.Bytes() - other, err := g2.FromCompressed(b[:]) - if err != nil { - t.Log(err) - return false - } - // reconstruct a gurvy point from bytes - err = end.Unmarshal(g2.ToCompressed(other)) - if err != nil { - return false - } - return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) - }, - genFp(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) - -} - -func TestGTSerializationInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 5 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BLS381] bls381.GT: gurvy -> bls12-381 -> gurvy should stay constant", prop.ForAll( - func(start *bls381.GT) bool { - var end bls381.GT - *start = bls381.FinalExponentiation(start) // ensure we are in correct subgroup.. - gt := bls12381.NewGT() - other, err := gt.FromBytes(start.Marshal()) - if err != nil { - t.Log(err) - return false - } - // reconstruct a bls381.GT from bytes - err = end.Unmarshal(gt.ToBytes(other)) - if err != nil { - return false - } - return start.Equal(&end) - }, - genGT(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) - -} - -func TestScalarMultiplicationInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BLS381] G1: scalarMultiplication interop", prop.ForAll( - func(a, exp fp.Element) bool { - var start, end bls381.G1Affine - var ab, bExp big.Int - a.ToBigIntRegular(&ab) - exp.ToBigIntRegular(&bExp) - start.ScalarMultiplication(&g1GenAff, &ab) - - g1 := bls12381.NewG1() - other, err := g1.FromBytes(start.Marshal()) - if err != nil { - t.Log(err) - return false - } - - // perform the scalar multiplications - otherRes := g1.MulScalarBig(g1.New(), other, &bExp) - end.ScalarMultiplication(&start, &bExp) - - if !(bytes.Equal(g1.ToBytes(otherRes), end.Marshal())) { - t.Log("scalar multiplication between bls12-381 and gurvy is different") - return false - } - - return true - }, - genFp(), - genFp(), - )) - - properties.Property("[BLS381] G2: scalarMultiplication interop", prop.ForAll( - func(a, exp fp.Element) bool { - var start, end bls381.G2Affine - var ab, bExp big.Int - a.ToBigIntRegular(&ab) - exp.ToBigIntRegular(&bExp) - start.ScalarMultiplication(&g2GenAff, &ab) - - g2 := bls12381.NewG2() - other, err := g2.FromBytes(start.Marshal()) - if err != nil { - t.Log(err) - return false - } - - // perform the scalar multiplications - otherRes := g2.MulScalarBig(g2.New(), other, &bExp) - end.ScalarMultiplication(&start, &bExp) - - if !(bytes.Equal(g2.ToBytes(otherRes), end.Marshal())) { - t.Log("scalar multiplication between bls12-381 and gurvy is different") - return false - } - - return true - }, - genFp(), - genFp(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} - -func TestPointAdditionInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BLS381] checking point addition", prop.ForAll( - func(a fp.Element) bool { - var g1 bls381.G1Affine - var g2 bls381.G2Affine - var ab big.Int - a.ToBigIntRegular(&ab) - g1.ScalarMultiplication(&g1GenAff, &ab) - g2.ScalarMultiplication(&g2GenAff, &ab) - - // do the same with other lib - bls12381g1 := bls12381.NewG1() - otherG1, err := bls12381g1.FromBytes(g1.Marshal()) - if err != nil { - return false - } - otherG1Gen, err := bls12381g1.FromBytes(g1GenAff.Marshal()) - if err != nil { - return false - } - bls12381g2 := bls12381.NewG2() - otherG2, err := bls12381g2.FromBytes(g2.Marshal()) - if err != nil { - return false - } - otherG2Gen, err := bls12381g2.FromBytes(g2GenAff.Marshal()) - if err != nil { - return false - } - - // add g1 to g1Gen and g2 to g2gen - var _g1 bls381.G1Jac - var _g2 bls381.G2Jac - _g1.FromAffine(&g1) - _g2.FromAffine(&g2) - - _g1.AddAssign(&g1Gen) - g1.FromJacobian(&_g1) - - _g2.AddAssign(&g2Gen) - g2.FromJacobian(&_g2) - - // results - r1 := bls12381g1.Add(bls12381g1.New(), otherG1, otherG1Gen) - r2 := bls12381g2.Add(bls12381g2.New(), otherG2, otherG2Gen) - - if !(bytes.Equal(g1.Marshal(), bls12381g1.ToBytes(r1))) { - t.Log("g1 point addition doesn't match other implementation") - return false - } - - if !(bytes.Equal(g2.Marshal(), bls12381g2.ToBytes(r2))) { - t.Log("g2 point addition doesn't match other implementation") - return false - } - - return true - }, - genFp(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} - -func TestPairingInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BLS381] pairing check interop", prop.ForAll( - func(a fp.Element) bool { - var g1 bls381.G1Affine - var g2 bls381.G2Affine - var ab big.Int - a.ToBigIntRegular(&ab) - g1.ScalarMultiplication(&g1GenAff, &ab) - g2.ScalarMultiplication(&g2GenAff, &ab) - - // do the same with other lib - otherG1, err := bls12381.NewG1().FromBytes(g1.Marshal()) - if err != nil { - return false - } - otherG2, err := bls12381.NewG2().FromBytes(g2.Marshal()) - if err != nil { - return false - } - - // pairings - engine := bls12381.NewEngine() - engine.AddPair(otherG1, otherG2) - otherResult := engine.Result() - c, _ := bls381.Pair([]bls381.G1Affine{g1}, []bls381.G2Affine{g2}) - - if !(bytes.Equal(c.Marshal(), bls12381.NewGT().ToBytes(otherResult))) { - t.Log("pairing doesn't match other implementation") - return false - } - - return true - }, - genFp(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} - -func BenchmarkPairingInterop(b *testing.B) { - var g1 bls381.G1Affine - var g2 bls381.G2Affine - var ab big.Int - ab.SetUint64(42) - g1.ScalarMultiplication(&g1GenAff, &ab) - g2.ScalarMultiplication(&g2GenAff, &ab) - - b.Run("[BLS381]bls12381_pairing", func(b *testing.B) { - otherG1, err := bls12381.NewG1().FromBytes(g1.Marshal()) - if err != nil { - b.Fatal(err) - } - otherG2, err := bls12381.NewG2().FromBytes(g2.Marshal()) - if err != nil { - b.Fatal(err) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - engine := bls12381.NewEngine() - engine.AddPair(otherG1, otherG2) - _ = engine.Result() - } - }) - - b.Run("[BLS381]gurvy_pairing", func(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = bls381.Pair([]bls381.G1Affine{g1}, []bls381.G2Affine{g2}) - } - }) - -} - -func genFp() gopter.Gen { - return func(genParams *gopter.GenParameters) *gopter.GenResult { - var elmt fp.Element - var b [fp.Bytes]byte - rand.Read(b[:]) - elmt.SetBytes(b[:]) - genResult := gopter.NewGenResult(elmt, gopter.NoShrinker) - return genResult - } -} - -func genGT() gopter.Gen { - return gopter.CombineGens( - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - ).Map(func(values []interface{}) *bls381.GT { - var b [fp.Bytes * 12]byte - rand.Read(b[:]) - var r bls381.GT - offset := 0 - r.C0.B0.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C0.B0.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C0.B1.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C0.B1.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C0.B2.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C0.B2.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - - r.C1.B0.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C1.B0.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C1.B1.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C1.B1.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C1.B2.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C1.B2.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - - return &r - }) -} diff --git a/internal/interop/bn256/interop_test.go b/internal/interop/bn256/interop_test.go deleted file mode 100644 index 860894b878..0000000000 --- a/internal/interop/bn256/interop_test.go +++ /dev/null @@ -1,606 +0,0 @@ -package interop - -import ( - "bytes" - "crypto/rand" - "math/big" - "testing" - - "github.com/consensys/gurvy/bn256" - "github.com/consensys/gurvy/bn256/fp" - "github.com/leanovate/gopter" - "github.com/leanovate/gopter/prop" - - cloudflare "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare" - google "github.com/ethereum/go-ethereum/crypto/bn256/google" -) - -// Test against go-ethereum/crypto/bn256 implementations (google and cloudflare) - -var ( - g1Gen bn256.G1Jac - g2Gen bn256.G2Jac - g1GenAff bn256.G1Affine - g2GenAff bn256.G2Affine -) - -func init() { - g1Gen, g2Gen, g1GenAff, g2GenAff = bn256.Generators() -} - -func TestG1AffineSerializationInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BN256] G1: gurvy -> cloudflare -> gurvy should stay constant", prop.ForAll( - func(a fp.Element) bool { - var start, end bn256.G1Affine - var ab big.Int - a.ToBigIntRegular(&ab) - start.ScalarMultiplication(&g1GenAff, &ab) - - other, err := cloudflareG1(&start) - if err != nil { - t.Log(err) - return false - } - - // reconstruct a gurvy point from bytes - err = end.Unmarshal(other.Marshal()) - if err != nil { - return false - } - return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) - }, - genFp(), - )) - - properties.Property("[BN256] G1: gurvy -> google -> gurvy should stay constant", prop.ForAll( - func(a fp.Element) bool { - var start, end bn256.G1Affine - var ab big.Int - a.ToBigIntRegular(&ab) - start.ScalarMultiplication(&g1GenAff, &ab) - - other, err := googleG1(&start) - if err != nil { - t.Log(err) - return false - } - - // reconstruct a gurvy point from bytes - err = end.Unmarshal(other.Marshal()) - if err != nil { - return false - } - return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) - }, - genFp(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) - -} - -func TestG2AffineSerializationInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BN256] G2: gurvy -> cloudflare -> gurvy should stay constant", prop.ForAll( - func(a fp.Element) bool { - var start, end bn256.G2Affine - var ab big.Int - a.ToBigIntRegular(&ab) - start.ScalarMultiplication(&g2GenAff, &ab) - - other, err := cloudflareG2(&start) - if err != nil { - t.Log(err) - return false - } - - // reconstruct a gurvy point from bytes - err = end.Unmarshal(other.Marshal()) - if err != nil { - return false - } - return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) - }, - genFp(), - )) - - properties.Property("[BN256] G2: gurvy -> google -> gurvy should stay constant", prop.ForAll( - func(a fp.Element) bool { - var start, end bn256.G2Affine - var ab big.Int - a.ToBigIntRegular(&ab) - start.ScalarMultiplication(&g2GenAff, &ab) - - other, err := googleG2(&start) - if err != nil { - t.Log(err) - return false - } - - // reconstruct a gurvy point from bytes - err = end.Unmarshal(other.Marshal()) - if err != nil { - return false - } - return start.X.Equal(&end.X) && start.Y.Equal(&end.Y) - }, - genFp(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) - -} - -func TestGTSerializationInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BN256] bn256.GT: gurvy -> cloudflare -> gurvy should stay constant", prop.ForAll( - func(start *bn256.GT) bool { - var end bn256.GT - cgt := new(cloudflare.GT) - - if _, err := cgt.Unmarshal(start.Marshal()); err != nil { - t.Log(err) - return false - } - - err := end.Unmarshal(cgt.Marshal()) - if err != nil { - return false - } - return start.Equal(&end) - }, - genGT(), - )) - - properties.Property("[BN256] bn256.GT: gurvy -> google -> gurvy should stay constant", prop.ForAll( - func(start *bn256.GT) bool { - var end bn256.GT - cgt := new(google.GT) - - if _, ok := cgt.Unmarshal(start.Marshal()); !ok { - return false - } - - err := end.Unmarshal(cgt.Marshal()) - if err != nil { - return false - } - return start.Equal(&end) - }, - genGT(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) - -} - -func TestScalarMultiplicationInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BN256] G1: scalarMultiplication interop", prop.ForAll( - func(a, exp fp.Element) bool { - var start, end bn256.G1Affine - var ab, bExp big.Int - a.ToBigIntRegular(&ab) - exp.ToBigIntRegular(&bExp) - start.ScalarMultiplication(&g1GenAff, &ab) - - gPoint, err := googleG1(&start) - if err != nil { - t.Log(err) - return false - } - cPoint, err := cloudflareG1(&start) - if err != nil { - t.Log(err) - return false - } - - // perform the scalar multiplications - gPoint.ScalarMult(gPoint, &bExp) - cPoint.ScalarMult(cPoint, &bExp) - end.ScalarMultiplication(&start, &bExp) - - if !(bytes.Equal(gPoint.Marshal(), end.Marshal())) { - t.Log("scalar multiplication between google and gurvy is different") - return false - } - - if !(bytes.Equal(cPoint.Marshal(), end.Marshal())) { - t.Log("scalar multiplication between cloudflare and gurvy is different") - return false - } - return true - }, - genFp(), - genFp(), - )) - - properties.Property("[BN256] G2: scalarMultiplication interop", prop.ForAll( - func(a, exp fp.Element) bool { - var start, end bn256.G2Affine - var ab, bExp big.Int - a.ToBigIntRegular(&ab) - exp.ToBigIntRegular(&bExp) - start.ScalarMultiplication(&g2GenAff, &ab) - - gPoint, err := googleG2(&start) - if err != nil { - t.Log(err) - return false - } - cPoint, err := cloudflareG2(&start) - if err != nil { - t.Log(err) - return false - } - // perform the scalar multiplications - gPoint.ScalarMult(gPoint, &bExp) - cPoint.ScalarMult(cPoint, &bExp) - end.ScalarMultiplication(&start, &bExp) - - if !(bytes.Equal(gPoint.Marshal(), end.Marshal())) { - t.Log("scalar multiplication between google and gurvy is different") - return false - } - - if !(bytes.Equal(cPoint.Marshal(), end.Marshal())) { - t.Log("scalar multiplication between cloudflare and gurvy is different") - return false - } - return true - }, - genFp(), - genFp(), - )) - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} - -func TestPointAdditionInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BN256] checking point addition", prop.ForAll( - func(a fp.Element) bool { - var g1 bn256.G1Affine - var g2 bn256.G2Affine - var ab big.Int - a.ToBigIntRegular(&ab) - g1.ScalarMultiplication(&g1GenAff, &ab) - g2.ScalarMultiplication(&g2GenAff, &ab) - - // do the same with google and cloud flare - g1g, err := googleG1(&g1) - if err != nil { - t.Log(err) - return false - } - g1c, err := cloudflareG1(&g1) - if err != nil { - t.Log(err) - return false - } - g2g, err := googleG2(&g2) - if err != nil { - t.Log(err) - return false - } - g2c, err := cloudflareG2(&g2) - if err != nil { - t.Log(err) - return false - } - g1gGen, err := googleG1(&g1GenAff) - if err != nil { - t.Log(err) - return false - } - g1cGen, err := cloudflareG1(&g1GenAff) - if err != nil { - t.Log(err) - return false - } - g2gGen, err := googleG2(&g2GenAff) - if err != nil { - t.Log(err) - return false - } - g2cGen, err := cloudflareG2(&g2GenAff) - if err != nil { - t.Log(err) - return false - } - - // add g1 to g1Gen and g2 to g2gen - var _g1 bn256.G1Jac - var _g2 bn256.G2Jac - _g1.FromAffine(&g1) - _g2.FromAffine(&g2) - - _g1.AddAssign(&g1Gen) - g1.FromJacobian(&_g1) - - _g2.AddAssign(&g2Gen) - g2.FromJacobian(&_g2) - - // results - g1c.Add(g1c, g1cGen) - g1g.Add(g1g, g1gGen) - g2c.Add(g2c, g2cGen) - g2g.Add(g2g, g2gGen) - - if !(bytes.Equal(g1.Marshal(), g1c.Marshal())) { - t.Log("g1 point addition doesn't match google implementation") - return false - } - - if !(bytes.Equal(g1.Marshal(), g1g.Marshal())) { - t.Log("g1 point addition doesn't match cloudflare implementation") - return false - } - - if !(bytes.Equal(g2.Marshal(), g2c.Marshal())) { - t.Log("g2 point addition doesn't match google implementation") - return false - } - - if !(bytes.Equal(g2.Marshal(), g2g.Marshal())) { - t.Log("g2 point addition doesn't match cloudflare implementation") - return false - } - - return true - }, - genFp(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} - -func TestPairingInterop(t *testing.T) { - parameters := gopter.DefaultTestParameters() - parameters.MinSuccessfulTests = 100 - - properties := gopter.NewProperties(parameters) - - properties.Property("[BN256] pairing check interop", prop.ForAll( - func(a fp.Element) bool { - var g1 bn256.G1Affine - var g2 bn256.G2Affine - var ab big.Int - a.ToBigIntRegular(&ab) - g1.ScalarMultiplication(&g1GenAff, &ab) - g2.ScalarMultiplication(&g2GenAff, &ab) - - g1g, err := googleG1(&g1) - if err != nil { - t.Log(err) - return false - } - g2g, err := googleG2(&g2) - if err != nil { - t.Log(err) - return false - } - - g1c, err := cloudflareG1(&g1) - if err != nil { - t.Log(err) - return false - } - g2c, err := cloudflareG2(&g2) - if err != nil { - t.Log(err) - return false - } - - // pairings - pc := cloudflare.Pair(g1c, g2c) - gc := google.Pair(g1g, g2g) - c, _ := bn256.Pair([]bn256.G1Affine{g1}, []bn256.G2Affine{g2}) - - if !(bytes.Equal(c.Marshal(), gc.Marshal())) { - t.Log("pairing doesn't match google implementation") - return false - } - - if !(bytes.Equal(c.Marshal(), pc.Marshal())) { - t.Log("pairing doesn't match cloudflare implementation") - return false - } - - return true - }, - genFp(), - )) - - properties.TestingRun(t, gopter.ConsoleReporter(false)) -} - -func BenchmarkPairingInteropBN256(b *testing.B) { - var g1 bn256.G1Affine - var g2 bn256.G2Affine - var ab big.Int - ab.SetUint64(42) - g1.ScalarMultiplication(&g1GenAff, &ab) - g2.ScalarMultiplication(&g2GenAff, &ab) - - b.Run("[bn256]google_pairing", func(b *testing.B) { - g1g, err := googleG1(&g1) - if err != nil { - b.Fatal(err) - } - g2g, err := googleG2(&g2) - if err != nil { - b.Fatal(err) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = google.Pair(g1g, g2g) - } - }) - b.Run("[bn256]cloudflare_pairing", func(b *testing.B) { - g1c, err := cloudflareG1(&g1) - if err != nil { - b.Fatal(err) - } - g2c, err := cloudflareG2(&g2) - if err != nil { - b.Fatal(err) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = cloudflare.Pair(g1c, g2c) - } - }) - - b.Run("[bn256]gurvy_pairing", func(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - _, _ = bn256.Pair([]bn256.G1Affine{g1}, []bn256.G2Affine{g2}) - } - }) - -} - -func BenchmarkPointAdditionInteropBN256(b *testing.B) { - var g1 bn256.G1Affine - var ab big.Int - ab.SetUint64(42) - g1.ScalarMultiplication(&g1GenAff, &ab) - - b.Run("[bn256]cloudflare_add_jacobian", func(b *testing.B) { - g1g, err := cloudflareG1(&g1) - if err != nil { - b.Fatal(err) - } - g1gen, err := cloudflareG1(&g1GenAff) - if err != nil { - b.Fatal(err) - } - b.ResetTimer() - for i := 0; i < b.N; i++ { - g1g.Add(g1g, g1gen) - } - }) - - b.Run("[bn256]gurvy_add_jacobian", func(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - var _g1 bn256.G1Jac - _g1.FromAffine(&g1) - _g1.AddAssign(&g1Gen) - } - }) - -} - -func cloudflareG1(p *bn256.G1Affine) (*cloudflare.G1, error) { - r := new(cloudflare.G1) - if _, err := r.Unmarshal(p.Marshal()); err != nil { - return nil, err - } - return r, nil -} - -func cloudflareG2(p *bn256.G2Affine) (*cloudflare.G2, error) { - r := new(cloudflare.G2) - if _, err := r.Unmarshal(p.Marshal()); err != nil { - return nil, err - } - return r, nil -} - -func googleG1(p *bn256.G1Affine) (*google.G1, error) { - r := new(google.G1) - if _, err := r.Unmarshal(p.Marshal()); err != nil { - return nil, err - } - return r, nil -} - -func googleG2(p *bn256.G2Affine) (*google.G2, error) { - r := new(google.G2) - if _, err := r.Unmarshal(p.Marshal()); err != nil { - return nil, err - } - return r, nil -} - -func genFp() gopter.Gen { - return func(genParams *gopter.GenParameters) *gopter.GenResult { - var elmt fp.Element - var b [fp.Bytes]byte - rand.Read(b[:]) - elmt.SetBytes(b[:]) - genResult := gopter.NewGenResult(elmt, gopter.NoShrinker) - return genResult - } -} - -func genGT() gopter.Gen { - return gopter.CombineGens( - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - genFp(), - ).Map(func(values []interface{}) *bn256.GT { - var b [fp.Bytes * 12]byte - rand.Read(b[:]) - var r bn256.GT - offset := 0 - r.C0.B0.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C0.B0.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C0.B1.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C0.B1.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C0.B2.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C0.B2.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - - r.C1.B0.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C1.B0.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C1.B1.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C1.B1.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C1.B2.A0.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - r.C1.B2.A1.SetBytes(b[offset : offset+fp.Bytes]) - offset += fp.Bytes - - return &r - }) -} diff --git a/internal/parallel/execute.go b/internal/parallel/execute.go new file mode 100644 index 0000000000..803de3c1b1 --- /dev/null +++ b/internal/parallel/execute.go @@ -0,0 +1,44 @@ +package parallel + +import ( + "runtime" + "sync" +) + +// Execute process in parallel the work function +func Execute(nbIterations int, work func(int, int), maxCpus ...int) { + + nbTasks := runtime.NumCPU() + if len(maxCpus) == 1 { + nbTasks = maxCpus[0] + } + nbIterationsPerCpus := nbIterations / nbTasks + + // more CPUs than tasks: a CPU will work on exactly one iteration + if nbIterationsPerCpus < 1 { + nbIterationsPerCpus = 1 + nbTasks = nbIterations + } + + var wg sync.WaitGroup + + extraTasks := nbIterations - (nbTasks * nbIterationsPerCpus) + extraTasksOffset := 0 + + for i := 0; i < nbTasks; i++ { + wg.Add(1) + _start := i*nbIterationsPerCpus + extraTasksOffset + _end := _start + nbIterationsPerCpus + if extraTasks > 0 { + _end++ + extraTasks-- + extraTasksOffset++ + } + go func() { + work(_start, _end) + wg.Done() + }() + } + + wg.Wait() +} diff --git a/utils/encoding.go b/utils/encoding.go deleted file mode 100644 index 4f43df5a94..0000000000 --- a/utils/encoding.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2020 ConsenSys AG -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package utils - -import ( - "crypto/sha256" - "errors" -) - -// ExpandMsgXmd expands msg to a slice of lenInBytes bytes. -// https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-06#section-5 -// https://tools.ietf.org/html/rfc8017#section-4.1 (I2OSP/O2ISP) -func ExpandMsgXmd(msg, dst []byte, lenInBytes int) ([]byte, error) { - - h := sha256.New() - ell := (lenInBytes + h.Size() - 1) / h.Size() // ceil(len_in_bytes / b_in_bytes) - if ell > 255 { - return nil, errors.New("invalid lenInBytes") - } - if len(dst) > 255 { - return nil, errors.New("invalid domain size (>255 bytes)") - } - sizeDomain := uint8(len(dst)) - - // Z_pad = I2OSP(0, r_in_bytes) - // l_i_b_str = I2OSP(len_in_bytes, 2) - // DST_prime = I2OSP(len(DST), 1) || DST - // b_0 = H(Z_pad || msg || l_i_b_str || I2OSP(0, 1) || DST_prime) - h.Reset() - if _, err := h.Write(make([]byte, h.BlockSize())); err != nil { - return nil, err - } - if _, err := h.Write(msg); err != nil { - return nil, err - } - if _, err := h.Write([]byte{uint8(lenInBytes >> 8), uint8(lenInBytes), uint8(0)}); err != nil { - return nil, err - } - if _, err := h.Write(dst); err != nil { - return nil, err - } - if _, err := h.Write([]byte{sizeDomain}); err != nil { - return nil, err - } - b0 := h.Sum(nil) - - // b_1 = H(b_0 || I2OSP(1, 1) || DST_prime) - h.Reset() - if _, err := h.Write(b0); err != nil { - return nil, err - } - if _, err := h.Write([]byte{uint8(1)}); err != nil { - return nil, err - } - if _, err := h.Write(dst); err != nil { - return nil, err - } - if _, err := h.Write([]byte{sizeDomain}); err != nil { - return nil, err - } - b1 := h.Sum(nil) - - res := make([]byte, lenInBytes) - copy(res[:h.Size()], b1) - - for i := 2; i <= ell; i++ { - // b_i = H(strxor(b_0, b_(i - 1)) || I2OSP(i, 1) || DST_prime) - h.Reset() - strxor := make([]byte, h.Size()) - for j := 0; j < h.Size(); j++ { - strxor[j] = b0[j] ^ b1[j] - } - if _, err := h.Write(strxor); err != nil { - return nil, err - } - if _, err := h.Write([]byte{uint8(i)}); err != nil { - return nil, err - } - if _, err := h.Write(dst); err != nil { - return nil, err - } - if _, err := h.Write([]byte{sizeDomain}); err != nil { - return nil, err - } - b1 = h.Sum(nil) - copy(res[h.Size()*(i-1):h.Size()*i], b1) - } - return res, nil -} diff --git a/utils/parallel/parallel.go b/utils/parallel/parallel.go deleted file mode 100644 index 7a93a900d3..0000000000 --- a/utils/parallel/parallel.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright © 2020 ConsenSys - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package parallel - -import ( - "runtime" - "sync" -) - -// Execute process in parallel the work function, using all available CPUs -func Execute(nbIterations int, work func(int, int)) { - - nbTasks := runtime.NumCPU() - nbIterationsPerCpus := nbIterations / nbTasks - - // more CPUs than tasks: a CPU will work on exactly one iteration - if nbIterationsPerCpus < 1 { - nbIterationsPerCpus = 1 - nbTasks = nbIterations - } - - var wg sync.WaitGroup - - extraTasks := nbIterations - (nbTasks * nbIterationsPerCpus) - extraTasksOffset := 0 - - for i := 0; i < nbTasks; i++ { - wg.Add(1) - _start := i*nbIterationsPerCpus + extraTasksOffset - _end := _start + nbIterationsPerCpus - if extraTasks > 0 { - _end++ - extraTasks-- - extraTasksOffset++ - } - go func() { - work(_start, _end) - wg.Done() - }() - } - - wg.Wait() -}