Compare commits

...

62 Commits

Author SHA1 Message Date
arnaucube
590573a0af Update Poseidon last changes of the reference impl
Update Poseidon to last changes of the reference implementation from
26ddaa91db

Compatible with update at circomlib
(cf853c1cc9)
2021-03-08 14:59:42 +01:00
Eduard S
58e589b6eb Merge pull request #35 from iden3/feature/comp-point-test
Update and add test for PackSignY & UnpackSignY
2020-12-21 17:03:44 +01:00
arnaucube
2318fd7044 Update and add test for PackSignY & UnpackSignY
- Update PackSignY & UnpackSignY interface and description
- Add test for UnpackSignY & PackPoint
2020-12-21 16:58:13 +01:00
Eduard S
a0722b9e8f Merge pull request #34 from iden3/feature/exp-comppoint-signy
Abstract & expose CompressedPointToSignAndY
2020-12-21 16:21:27 +01:00
arnaucube
71dbddb5f1 Abstract & expose CompressedPointToSignAndY 2020-12-21 16:12:49 +01:00
Eduard S
0a5c6acba3 Merge pull request #33 from iden3/feature/pkcomp-scanvalue
Add scanner/valuer interface to babyjub.PublicKeyComp
2020-12-21 10:31:37 +01:00
arnaucube
a366175021 Add scanner/valuer interface to babyjub.PublicKeyComp 2020-12-18 20:44:29 +01:00
Eduard S
a2015adb2f Merge pull request #32 from iden3/feature/upgrade-linters
Upgrade linters
2020-12-18 12:11:45 +01:00
arnaucube
6d75396b4b Upgrade linters 2020-12-16 15:07:19 +01:00
Eduard S
821a601d20 Merge pull request #31 from iden3/feature/update-bbjjeddsa
Update BabyJubJub EdDSA to last circomlib version
2020-12-03 10:52:29 +01:00
arnaucube
5dd19b46dd Update BabyJubJub EdDSA to last circomlib version
- Update BabyJubJub EdDSA signature to last circomlib version (Poseidon
usage)
- Remove panic on hash error inside verification, to avoid panic due
field overflow of BabyJubJub signature verification
2020-12-02 19:57:27 +01:00
arnau
94e92e88fb Merge pull request #30 from iden3/feature/signaturecomp-scanner
Add scanner/valuer interface to babyjub.SignatureComp
2020-10-16 16:24:44 +02:00
Arnau B
5ef832f175 Add scanner/valuer interface to babyjub.SignatureComp 2020-10-16 16:22:18 +02:00
arnau
59d8c7a4ca Merge pull request #29 from iden3/feature/babyjubjub-optimization
- Add `add-2008-bbjlp` for point addition
- Add `goff` to BabyJubJub point addition

```
Benchmarks (On a Intel(R) Core(TM) i7-8705G CPU @ 3.10GHz, with 32 GB of RAM):

- Old (commit: e04ca5764a):
BenchmarkBabyjub/AddConst-8              1000000              1072 ns/op
BenchmarkBabyjub/AddRnd-8                  93417             12943 ns/op
BenchmarkBabyjub/MulRnd-8                    252           4797810 ns/op
BenchmarkBabyjub/Compress-8              7291580               166 ns/op
BenchmarkBabyjub/InCurve-8                611137              1999 ns/op
BenchmarkBabyjub/InSubGroup-8             615792              2021 ns/op
BenchmarkBabyjubEddsa/SignMimc7-8            126           9358542 ns/op
BenchmarkBabyjubEddsa/VerifyMimc7-8          124           9484005 ns/op
BenchmarkBabyjubEddsa/SignPoseidon-8                 126           9486484 ns/op
BenchmarkBabyjubEddsa/VerifyPoseidon-8               126           9622807 ns/op

- With new point addition algorithm (commit: aab1a681dd):
BenchmarkBabyjub/AddConst-8              1356836               881 ns/op
BenchmarkBabyjub/AddRnd-8                 274112              4220 ns/op
BenchmarkBabyjub/MulRnd-8                    492           2474412 ns/op
BenchmarkBabyjub/Compress-8              6964855               197 ns/op
BenchmarkBabyjub/InCurve-8                608169              2008 ns/op
BenchmarkBabyjub/InSubGroup-8             618772              1954 ns/op
BenchmarkBabyjubEddsa/SignMimc7-8            238           4962397 ns/op
BenchmarkBabyjubEddsa/VerifyMimc7-8          235           5234883 ns/op
BenchmarkBabyjubEddsa/SignPoseidon-8                 240           5028720 ns/op
BenchmarkBabyjubEddsa/VerifyPoseidon-8               243           5226654 ns/op

Point Addition: ~3x
Point scalar Mul: ~1.9x
Signature (poseidon): ~1.88x
Verification (poseidon): ~1.84x

- With new point addition algorithm & goff (current commit):
BenchmarkBabyjub/AddConst-8              3000531               400 ns/op
BenchmarkBabyjub/AddRnd-8                2770335               428 ns/op
BenchmarkBabyjub/MulRnd-8                   6636            175522 ns/op
BenchmarkBabyjub/Compress-8              7358768               180 ns/op
BenchmarkBabyjub/InCurve-8                539193              1950 ns/op
BenchmarkBabyjub/InSubGroup-8             601402              1958 ns/op
BenchmarkBabyjubEddsa/SignMimc7-8           2940            409487 ns/op
BenchmarkBabyjubEddsa/VerifyMimc7-8         2908            414407 ns/op
BenchmarkBabyjubEddsa/SignPoseidon-8                2395            493165 ns/op
BenchmarkBabyjubEddsa/VerifyPoseidon-8              2491            494849 ns/op

Point Addition: ~9.86x
Point scalar Mul: ~14x
Signature (poseidon): ~10.2x
Verification (poseidon): ~10.56x

---

Total improvement (from old to current):
Point Addition: ~30.24x
Point scalar Mul: ~27.33x
Signature (poseidon): ~19.24x
Verification (poseidon): ~19.44x
```
2020-09-13 20:05:04 +02:00
arnaucube
91767c7b61 Add goff to BabyJubJub point addition
```
Benchmarks (On a Intel(R) Core(TM) i7-8705G CPU @ 3.10GHz, with 32 GB of RAM):

- Old (commit: e04ca5764a):
BenchmarkBabyjub/AddConst-8              1000000              1072 ns/op
BenchmarkBabyjub/AddRnd-8                  93417             12943 ns/op
BenchmarkBabyjub/MulRnd-8                    252           4797810 ns/op
BenchmarkBabyjub/Compress-8              7291580               166 ns/op
BenchmarkBabyjub/InCurve-8                611137              1999 ns/op
BenchmarkBabyjub/InSubGroup-8             615792              2021 ns/op
BenchmarkBabyjubEddsa/SignMimc7-8            126           9358542 ns/op
BenchmarkBabyjubEddsa/VerifyMimc7-8          124           9484005 ns/op
BenchmarkBabyjubEddsa/SignPoseidon-8                 126           9486484 ns/op
BenchmarkBabyjubEddsa/VerifyPoseidon-8               126           9622807 ns/op

- With new point addition algorithm (commit: aab1a681dd):
BenchmarkBabyjub/AddConst-8              1356836               881 ns/op
BenchmarkBabyjub/AddRnd-8                 274112              4220 ns/op
BenchmarkBabyjub/MulRnd-8                    492           2474412 ns/op
BenchmarkBabyjub/Compress-8              6964855               197 ns/op
BenchmarkBabyjub/InCurve-8                608169              2008 ns/op
BenchmarkBabyjub/InSubGroup-8             618772              1954 ns/op
BenchmarkBabyjubEddsa/SignMimc7-8            238           4962397 ns/op
BenchmarkBabyjubEddsa/VerifyMimc7-8          235           5234883 ns/op
BenchmarkBabyjubEddsa/SignPoseidon-8                 240           5028720 ns/op
BenchmarkBabyjubEddsa/VerifyPoseidon-8               243           5226654 ns/op

Point Addition: ~3x
Point scalar Mul: ~1.9x
Signature (poseidon): ~1.88x
Verification (poseidon): ~1.84x

- With new point addition algorithm & goff (current commit):
BenchmarkBabyjub/AddConst-8              3000531               400 ns/op
BenchmarkBabyjub/AddRnd-8                2770335               428 ns/op
BenchmarkBabyjub/MulRnd-8                   6636            175522 ns/op
BenchmarkBabyjub/Compress-8              7358768               180 ns/op
BenchmarkBabyjub/InCurve-8                539193              1950 ns/op
BenchmarkBabyjub/InSubGroup-8             601402              1958 ns/op
BenchmarkBabyjubEddsa/SignMimc7-8           2940            409487 ns/op
BenchmarkBabyjubEddsa/VerifyMimc7-8         2908            414407 ns/op
BenchmarkBabyjubEddsa/SignPoseidon-8                2395            493165 ns/op
BenchmarkBabyjubEddsa/VerifyPoseidon-8              2491            494849 ns/op

Point Addition: ~9.86x
Point scalar Mul: ~14x
Signature (poseidon): ~10.2x
Verification (poseidon): ~10.56x

---

Total improvement (from old to current):
Point Addition: ~30.24x
Point scalar Mul: ~27.33x
Signature (poseidon): ~19.24x
Verification (poseidon): ~19.44x
```
2020-09-05 17:34:06 +02:00
arnaucube
aab1a681dd Add add-2008-bbjlp for point addition
Add `add-2008-bbjlp` for point addition

Benchmarks (On a Intel(R) Core(TM) i7-8705G CPU @ 3.10GHz, with 32 GB of RAM):

```
- Old:
BenchmarkBabyjub/AddConst-8              1000000              1072 ns/op
BenchmarkBabyjub/AddRnd-8                  93417             12943 ns/op
BenchmarkBabyjub/MulRnd-8                    252           4797810 ns/op
BenchmarkBabyjub/Compress-8              7291580               166 ns/op
BenchmarkBabyjub/InCurve-8                611137              1999 ns/op
BenchmarkBabyjub/InSubGroup-8             615792              2021 ns/op
BenchmarkBabyjubEddsa/SignMimc7-8            126           9358542 ns/op
BenchmarkBabyjubEddsa/VerifyMimc7-8          124           9484005 ns/op
BenchmarkBabyjubEddsa/SignPoseidon-8                 126           9486484 ns/op
BenchmarkBabyjubEddsa/VerifyPoseidon-8               126           9622807 ns/op

- With new point addition algorithm:
BenchmarkBabyjub/AddConst-8              1356836               881 ns/op
BenchmarkBabyjub/AddRnd-8                 274112              4220 ns/op
BenchmarkBabyjub/MulRnd-8                    492           2474412 ns/op
BenchmarkBabyjub/Compress-8              6964855               197 ns/op
BenchmarkBabyjub/InCurve-8                608169              2008 ns/op
BenchmarkBabyjub/InSubGroup-8             618772              1954 ns/op
BenchmarkBabyjubEddsa/SignMimc7-8            238           4962397 ns/op
BenchmarkBabyjubEddsa/VerifyMimc7-8          235           5234883 ns/op
BenchmarkBabyjubEddsa/SignPoseidon-8                 240           5028720 ns/op
BenchmarkBabyjubEddsa/VerifyPoseidon-8               243           5226654 ns/op
```

Point Addition: ~3x
Point scalar Mul: ~1.9x
Signature (poseidon): ~1.88x
Verification (poseidon): ~1.84x
2020-09-05 17:18:43 +02:00
arnaucube
e04ca5764a Update Poseidon to new circomlib version & https://extgit.iaik.tugraz.at/krypto/hadeshash 2020-08-23 19:40:58 +02:00
Eduard S
70841d78e7 Merge pull request #28 from iden3/feature/signature-sql-interface
Fix value sql interface
2020-08-14 13:03:25 +02:00
a_bennassar
674e8a6739 Fix value sql interface 2020-08-14 12:32:15 +02:00
arnau
66519124ca Merge pull request #27 from iden3/feature/signature-sql-interface
Add scanner/valuer interface to signature
2020-08-13 16:57:45 +02:00
a_bennassar
a86308cb0b Add scanner/valuer interface to PublicKey 2020-08-13 12:43:48 +02:00
a_bennassar
d91a4261f1 Add scanner/valuer interface to signature 2020-08-12 15:52:10 +02:00
Eduard S
327a8175d6 Merge pull request #26 from iden3/feature/pointfromsigny
Babyjubjub separate PointFromSignAndY from p.Decompress
2020-08-06 13:50:47 +02:00
arnaucube
833f68a614 Babyjubjub separate PointFromSignAndY from p.Decompress 2020-08-06 13:34:36 +02:00
Eduard S
29a66457f0 Merge pull request #25 from iden3/feature/poseidon-update
Update Poseidon Hash function names, rm HashBytes
2020-07-23 10:24:57 +02:00
arnaucube
f22be3cdee Update Poseidon Hash function names, rm HashBytes
Since Poseidon Hash is used because of compatibility in zkSNARK circuits, due
circuit constraints number, the hash method of [T]*big.Int is the one directly
compatible with the circuits, is the method which have the `Hash` name on it.
The method that can take arbitrary length of []*big.Int putting them in chunks
of [T]*big.Int and iterating, is called `HashSlice`. The `HashBytes` has been
removed, as is a method that will not be used in zkSNARK circuits due high
constraints number.

For zkSNARK circuits, should be used `poseidon.Hash([poseidon.T]*big.Int)`.
2020-07-23 07:59:59 +02:00
Eduard S
2c471ab545 Merge pull request #24 from iden3/fix/hashbytes-err
Poseidon & MiMC7 HashBytes remove return of err
2020-05-25 12:05:45 +02:00
arnaucube
e134988b1b Rm .travis.yml 2020-05-22 13:33:01 +02:00
arnaucube
3a9171000b Poseidon & MiMC7 HashBytes remove return of err 2020-05-22 00:42:14 +02:00
Eduard S
b1468fc076 Merge pull request #23 from iden3/feature/expose-method
Expose SkToBigInt for usage from other packages & repos
2020-04-28 18:31:15 +02:00
arnaucube
d189a6bedc Expose SkToBigInt for usage from other packages & repos 2020-04-22 14:53:31 +02:00
Eduard S
14c3144613 Merge pull request #22 from iden3/feature/utils-elembigintconv
Add utils.ElementArrayToBigIntArray
2020-04-21 15:31:34 +02:00
arnaucube
b98a9fe65a Add utils.ElementArrayToBigIntArray 2020-04-20 12:45:35 +02:00
arnau
4d1bbacd6c Merge pull request #21 from iden3/feature/githubactions
Add github actions and remove travis
2020-04-14 21:45:30 +02:00
Eduard S
0ac8b46493 Fix linters errors 2020-04-14 16:53:24 +02:00
Eduard S
14d09916cf Add github actions and remove travis 2020-04-14 16:53:15 +02:00
arnau
eb41fe0757 Merge pull request #18 from iden3/feature/fix32bits
Fix compat with 32 bit arch
2020-03-18 11:55:56 +01:00
Eduard S
e10db811aa Fix compat with 32 bit arch 2020-03-17 17:17:45 +01:00
Eduard S
ee467c6215 Merge pull request #16 from iden3/feature/mimc7-goff
Feature/mimc7 goff
2020-03-06 16:27:36 +01:00
arnaucube
4750e9c83c Remove field package which is no longer used 2020-03-06 16:24:41 +01:00
arnaucube
16a8a18a6d Optimize MiMC7 migrating from *big.Int to goff
Optimize MiMC7 migrating from *big.Int to goff generated finite field
operations.

There is still a lot of room for optimization for MiMC7 in the way that is done internally, but will be done in the future.

Benchmarks:
Tested on a Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz, with 16GB of RAM.

- Before:
```
BenchmarkMIMC7-4   	    1026	   1160298 ns/op
```

- After this commit:
```
BenchmarkMIMC7-4   	   19263	     61651 ns/op
```
2020-03-05 17:35:25 +01:00
arnau
e8be761ec7 Merge pull request #15 from iden3/feature/poseidon-opt-goff
Feature/poseidon opt goff
2020-03-04 18:34:17 +01:00
arnaucube
2a3f0d9ed5 Adapt babyjub/eddsa to new Poseidon methods 2020-03-04 12:57:20 +01:00
Eduard S
5d88f7c4cd Merge pull request #13 from iden3/feature/update-bbjj-sig
Update BabyJubJub signature with Poseidon
2020-03-03 17:57:27 +01:00
arnaucube
b45d8a582b Optimize Poseidon migrating from *big.Int to goff
Optimize Poseidon migrating from *big.Int to goff generated finite field
operations.

Benchmarks:
Tested on a Intel(R) Core(TM) i5-7200U CPU @ 2.50GHz, with 16GB of RAM.

- Before the optimizations:
```
BenchmarkPoseidon-4                  470           2489678 ns/op
BenchmarkPoseidonLarge-4             476           2530568 ns/op
```

- With the optimizations of #12:
```
BenchmarkPoseidon-4                  766           1550013 ns/op
BenchmarkPoseidonLarge-4             782           1547572 ns/op
```

- With the changes of this PR, where uses goff generated code instead of *big.Int:
```
BenchmarkPoseidon-4                 9638            121651 ns/op
BenchmarkPoseidonLarge-4            9781            119921 ns/op
```
2020-03-03 16:31:40 +01:00
arnaucube
83f87bfa46 Resolve #4 2020-03-03 16:31:09 +01:00
arnaucube
17bad75853 Add goff generated finite field arithmetic code for used field 2020-03-03 16:30:00 +01:00
arnaucube
97c76ce614 Update BabyJubJub signature with Poseidon 2020-03-03 12:42:18 +01:00
arnau
937500b203 Merge pull request #12 from iden3/feature/optimizeposeidon
Optimize Poseidon
2019-12-22 20:40:00 +01:00
Eduard S
c0c4ff2dd7 Optimize Poseidon 2019-12-18 11:46:17 +01:00
Eduard S
8d5a7a7ccb Merge pull request #11 from iden3/fix/issue-9
Fix/issue #9
2019-12-18 11:03:37 +01:00
arnaucube
c754d01ce0 poseidon consistent use of T 2019-12-17 18:15:22 +01:00
arnaucube
fcb586591a fix #9 2019-12-17 18:04:49 +01:00
Eduard S
7c6170453e Add test that breaks poseidion due to padding 2019-12-16 17:24:22 +01:00
Eduard S
27ec5b26df Add test that breaks poseidon due to a security issue 2019-12-16 16:48:38 +01:00
Eduard S
53b9050d0a Add babujub eddsa benchmarks 2019-12-16 13:36:43 +01:00
Eduard S
a5b6afcb16 Add poseidon and babyjub benchmarks 2019-12-16 13:08:34 +01:00
arnau
4356f44a3d Merge pull request #6 from iden3/feature/testBJPKField
Test that babyjub pk is always < Q
2019-12-09 15:59:10 +01:00
Eduard S
5ade04e079 Test that babyjub pk is always < Q 2019-12-09 12:30:50 +01:00
Eduard S
eb7d86c5b3 Merge pull request #5 from iden3/decompress-modsqrt
return error if no ModSqrt(x, q) exist in babyjubjub decompress point
2019-09-10 10:48:18 +02:00
arnaucube
a60e154d86 return error if no ModSqrt(x, q) exist in babyjubjub decompress point 2019-09-10 00:36:54 +02:00
arnaucube
c95c95b7b1 add Poseidon multihash ([]*big.Int), add HashBytes for MiMC7 & Poseidon 2019-08-31 20:07:03 +02:00
26 changed files with 5740 additions and 551 deletions

16
.github/workflows/lint.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: Lint
on: [ push, pull_request ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v1
with:
go-version: 1.14.x
- name: Checkout code
uses: actions/checkout@v2
- name: Lint
run: |
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.30.0
$(go env GOPATH)/bin/golangci-lint run --timeout=5m -c .golangci.yml

28
.github/workflows/test.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
on: [ push, pull_request ]
name: Test
jobs:
test:
strategy:
matrix:
go-version: [ 1.13.x, 1.14.x ]
goarch: [ "amd64", "386" ]
runs-on: ubuntu-latest
steps:
- name: Install Go
uses: actions/setup-go@v1
with:
go-version: ${{ matrix.go-version }}
env:
GOARCH: ${{ matrix.goarch }}
- name: Checkout code
uses: actions/checkout@v2
- uses: actions/cache@v1
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-
- name: Test
env:
GOARCH: ${{ matrix.goarch }}
run: go test ./...

17
.golangci.yml Normal file
View File

@@ -0,0 +1,17 @@
issues:
max-same-issues: 0
exclude-use-default: false
linters:
enable:
- whitespace
- gosec
- gci
- misspell
- gomnd
- gofmt
- goimports
- lll
- golint
linters-settings:
lll:
line-length: 100

View File

@@ -1,8 +0,0 @@
dist: xenial
language: go
go:
- "1.12"
env:
- GO111MODULE=on

View File

@@ -1,4 +1,4 @@
# go-iden3-crypto [![Go Report Card](https://goreportcard.com/badge/github.com/iden3/go-iden3-crypto)](https://goreportcard.com/report/github.com/iden3/go-iden3-crypto) [![Build Status](https://travis-ci.org/iden3/go-iden3-crypto.svg?branch=master)](https://travis-ci.org/iden3/go-iden3-crypto) [![GoDoc](https://godoc.org/github.com/iden3/go-iden3-crypto?status.svg)](https://godoc.org/github.com/iden3/go-iden3-crypto) # go-iden3-crypto [![Go Report Card](https://goreportcard.com/badge/github.com/iden3/go-iden3-crypto)](https://goreportcard.com/report/github.com/iden3/go-iden3-crypto) [![Test Status](https://github.com/iden3/go-iden3-crypto/workflows/Test/badge.svg)](https://github.com/iden3/go-iden3-crypto/actions?query=workflow%3ATest) [![Lint Status](https://github.com/iden3/go-iden3-crypto/workflows/Lint/badge.svg)](https://github.com/iden3/go-iden3-crypto/actions?query=workflow%3ALint) [![GoDoc](https://godoc.org/github.com/iden3/go-iden3-crypto?status.svg)](https://godoc.org/github.com/iden3/go-iden3-crypto)
Go implementation of some cryptographic primitives (that fit inside the SNARK field) used in iden3 Go implementation of some cryptographic primitives (that fit inside the SNARK field) used in iden3

View File

@@ -5,15 +5,22 @@ import (
"math/big" "math/big"
"github.com/iden3/go-iden3-crypto/constants" "github.com/iden3/go-iden3-crypto/constants"
"github.com/iden3/go-iden3-crypto/ff"
"github.com/iden3/go-iden3-crypto/utils" "github.com/iden3/go-iden3-crypto/utils"
) )
// A is one of the babyjub constants. // A is one of the babyjub constants.
var A *big.Int var A *big.Int
// Aff is A value in *ff.Element representation
var Aff *ff.Element
// D is one of the babyjub constants. // D is one of the babyjub constants.
var D *big.Int var D *big.Int
// Dff is D value in *ff.Element representation
var Dff *ff.Element
// Order of the babyjub curve. // Order of the babyjub curve.
var Order *big.Int var Order *big.Int
@@ -29,6 +36,8 @@ var B8 *Point
func init() { func init() {
A = utils.NewIntFromString("168700") A = utils.NewIntFromString("168700")
D = utils.NewIntFromString("168696") D = utils.NewIntFromString("168696")
Aff = ff.NewElement().SetBigInt(A)
Dff = ff.NewElement().SetBigInt(D)
Order = utils.NewIntFromString( Order = utils.NewIntFromString(
"21888242871839275222246405745257275088614511777268538073601725287587578984328") "21888242871839275222246405745257275088614511777268538073601725287587578984328")
@@ -41,6 +50,73 @@ func init() {
"16950150798460657717958625567821834550301663161624707787222815936182638968203") "16950150798460657717958625567821834550301663161624707787222815936182638968203")
} }
// PointProjective is the Point representation in projective coordinates
type PointProjective struct {
X *ff.Element
Y *ff.Element
Z *ff.Element
}
// NewPointProjective creates a new Point in projective coordinates.
func NewPointProjective() *PointProjective {
return &PointProjective{X: ff.NewElement().SetZero(),
Y: ff.NewElement().SetOne(), Z: ff.NewElement().SetOne()}
}
// Affine returns the Point from the projective representation
func (p *PointProjective) Affine() *Point {
if p.Z.Equal(ff.NewElement().SetZero()) {
return &Point{
X: big.NewInt(0),
Y: big.NewInt(0),
}
}
zinv := ff.NewElement().Inverse(p.Z)
x := ff.NewElement().Mul(p.X, zinv)
y := ff.NewElement().Mul(p.Y, zinv)
xBig := big.NewInt(0)
x.ToBigIntRegular(xBig)
yBig := big.NewInt(0)
y.ToBigIntRegular(yBig)
return &Point{
X: xBig,
Y: yBig,
}
}
// Add computes the addition of two points in projective coordinates
// representation
func (p *PointProjective) Add(q *PointProjective, o *PointProjective) *PointProjective {
// add-2008-bbjlp
// https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp
a := ff.NewElement().Mul(q.Z, o.Z)
b := ff.NewElement().Square(a)
c := ff.NewElement().Mul(q.X, o.X)
d := ff.NewElement().Mul(q.Y, o.Y)
e := ff.NewElement().Mul(Dff, c)
e.MulAssign(d)
f := ff.NewElement().Sub(b, e)
g := ff.NewElement().Add(b, e)
x1y1 := ff.NewElement().Add(q.X, q.Y)
x2y2 := ff.NewElement().Add(o.X, o.Y)
x3 := ff.NewElement().Mul(x1y1, x2y2)
x3.SubAssign(c)
x3.SubAssign(d)
x3.MulAssign(a)
x3.MulAssign(f)
ac := ff.NewElement().Mul(Aff, c)
y3 := ff.NewElement().Sub(d, ac)
y3.MulAssign(a)
y3.MulAssign(g)
z3 := ff.NewElement().Mul(f, g)
p.X = x3
p.Y = y3
p.Z = z3
return p
}
// Point represents a point of the babyjub curve. // Point represents a point of the babyjub curve.
type Point struct { type Point struct {
X *big.Int X *big.Int
@@ -59,63 +135,33 @@ func (p *Point) Set(c *Point) *Point {
return p return p
} }
// Add adds Point a and b into res // Projective returns a PointProjective from the Point
func (res *Point) Add(a *Point, b *Point) *Point { func (p *Point) Projective() *PointProjective {
// x = (a.x * b.y + b.x * a.y) * (1 + D * a.x * b.x * a.y * b.y)^-1 mod q return &PointProjective{
x1a := new(big.Int).Mul(a.X, b.Y) X: ff.NewElement().SetBigInt(p.X),
x1b := new(big.Int).Mul(b.X, a.Y) Y: ff.NewElement().SetBigInt(p.Y),
x1a.Add(x1a, x1b) // x1a = a.x * b.y + b.x * a.y Z: ff.NewElement().SetOne(),
}
x2 := new(big.Int).Set(D)
x2.Mul(x2, a.X)
x2.Mul(x2, b.X)
x2.Mul(x2, a.Y)
x2.Mul(x2, b.Y)
x2.Add(constants.One, x2)
x2.Mod(x2, constants.Q)
x2.ModInverse(x2, constants.Q) // x2 = (1 + D * a.x * b.x * a.y * b.y)^-1
// y = (a.y * b.y - A * a.x * b.x) * (1 - D * a.x * b.x * a.y * b.y)^-1 mod q
y1a := new(big.Int).Mul(a.Y, b.Y)
y1b := new(big.Int).Set(A)
y1b.Mul(y1b, a.X)
y1b.Mul(y1b, b.X)
y1a.Sub(y1a, y1b) // y1a = a.y * b.y - A * a.x * b.x
y2 := new(big.Int).Set(D)
y2.Mul(y2, a.X)
y2.Mul(y2, b.X)
y2.Mul(y2, a.Y)
y2.Mul(y2, b.Y)
y2.Sub(constants.One, y2)
y2.Mod(y2, constants.Q)
y2.ModInverse(y2, constants.Q) // y2 = (1 - D * a.x * b.x * a.y * b.y)^-1
res.X = x1a.Mul(x1a, x2)
res.X = res.X.Mod(res.X, constants.Q)
res.Y = y1a.Mul(y1a, y2)
res.Y = res.Y.Mod(res.Y, constants.Q)
return res
} }
// Mul multiplies the Point p by the scalar s and stores the result in res, // Mul multiplies the Point q by the scalar s and stores the result in p,
// which is also returned. // which is also returned.
func (res *Point) Mul(s *big.Int, p *Point) *Point { func (p *Point) Mul(s *big.Int, q *Point) *Point {
res.X = big.NewInt(0) resProj := &PointProjective{
res.Y = big.NewInt(1) X: ff.NewElement().SetZero(),
exp := NewPoint().Set(p) Y: ff.NewElement().SetOne(),
Z: ff.NewElement().SetOne(),
}
exp := q.Projective()
for i := 0; i < s.BitLen(); i++ { for i := 0; i < s.BitLen(); i++ {
if s.Bit(i) == 1 { if s.Bit(i) == 1 {
res.Add(res, exp) resProj.Add(resProj, exp)
} }
exp.Add(exp, exp) exp = exp.Add(exp, exp)
} }
p = resProj.Affine()
return res return p
} }
// InCurve returns true when the Point p is in the babyjub curve. // InCurve returns true when the Point p is in the babyjub curve.
@@ -154,36 +200,57 @@ func (p *Point) InSubGroup() bool {
// PointCoordSign returns the sign of the curve point coordinate. It returns // PointCoordSign returns the sign of the curve point coordinate. It returns
// false if the sign is positive and false if the sign is negative. // false if the sign is positive and false if the sign is negative.
func PointCoordSign(c *big.Int) bool { func PointCoordSign(c *big.Int) bool {
if c.Cmp(new(big.Int).Rsh(constants.Q, 1)) == 1 { return c.Cmp(new(big.Int).Rsh(constants.Q, 1)) == 1
return true
}
return false
} }
func PackPoint(ay *big.Int, sign bool) [32]byte { // PackSignY packs the given sign and the coordinate Y of a point into a 32
leBuf := utils.BigIntLEBytes(ay) // byte array. This method does not check that the values belong to a valid
// Point in the curve.
func PackSignY(sign bool, y *big.Int) [32]byte {
leBuf := utils.BigIntLEBytes(y)
if sign { if sign {
leBuf[31] = leBuf[31] | 0x80 leBuf[31] = leBuf[31] | 0x80 //nolint:gomnd
} }
return leBuf return leBuf
} }
// UnpackSignY returns the sign and coordinate Y from a given compressed point.
// This method does not check that the Point belongs to the BabyJubJub curve,
// thus does not return error in such case. This method is intended to obtain
// the sign and the Y coordinate without checking if the point belongs to the
// curve, if the objective is to uncompress a point, Decompress method should
// be used instead.
func UnpackSignY(leBuf [32]byte) (bool, *big.Int) {
sign := false
y := big.NewInt(0)
if (leBuf[31] & 0x80) != 0x00 { //nolint:gomnd
sign = true
leBuf[31] = leBuf[31] & 0x7F //nolint:gomnd
}
utils.SetBigIntFromLEBytes(y, leBuf[:])
return sign, y
}
// Compress the point into a 32 byte array that contains the y coordinate in // Compress the point into a 32 byte array that contains the y coordinate in
// little endian and the sign of the x coordinate. // little endian and the sign of the x coordinate.
func (p *Point) Compress() [32]byte { func (p *Point) Compress() [32]byte {
sign := PointCoordSign(p.X) sign := PointCoordSign(p.X)
return PackPoint(p.Y, sign) return PackSignY(sign, p.Y)
} }
// Decompress a compressed Point into p, and also returns the decompressed // Decompress a compressed Point into p, and also returns the decompressed
// Point. Returns error if the compressed Point is invalid. // Point. Returns error if the compressed Point is invalid.
func (p *Point) Decompress(leBuf [32]byte) (*Point, error) { func (p *Point) Decompress(leBuf [32]byte) (*Point, error) {
sign := false var sign bool
if (leBuf[31] & 0x80) != 0x00 { sign, p.Y = UnpackSignY(leBuf)
sign = true return PointFromSignAndY(sign, p.Y)
leBuf[31] = leBuf[31] & 0x7F }
}
utils.SetBigIntFromLEBytes(p.Y, leBuf[:]) // PointFromSignAndY returns a Point from a Sign and the Y coordinate
func PointFromSignAndY(sign bool, y *big.Int) (*Point, error) {
var p Point
p.X = big.NewInt(0)
p.Y = y
if p.Y.Cmp(constants.Q) >= 0 { if p.Y.Cmp(constants.Q) >= 0 {
return nil, fmt.Errorf("p.y >= Q") return nil, fmt.Errorf("p.y >= Q")
} }
@@ -203,11 +270,14 @@ func (p *Point) Decompress(leBuf [32]byte) (*Point, error) {
xb.ModInverse(xb, constants.Q) xb.ModInverse(xb, constants.Q)
p.X.Mul(xa, xb) // xa / xb p.X.Mul(xa, xb) // xa / xb
p.X.Mod(p.X, constants.Q) p.X.Mod(p.X, constants.Q)
p.X.ModSqrt(p.X, constants.Q) noSqrt := p.X.ModSqrt(p.X, constants.Q)
if noSqrt == nil {
return nil, fmt.Errorf("x is not a square mod q")
}
if (sign && !PointCoordSign(p.X)) || (!sign && PointCoordSign(p.X)) { if (sign && !PointCoordSign(p.X)) || (!sign && PointCoordSign(p.X)) {
p.X.Mul(p.X, constants.MinusOne) p.X.Mul(p.X, constants.MinusOne)
} }
p.X.Mod(p.X, constants.Q) p.X.Mod(p.X, constants.Q)
return p, nil return &p, nil
} }

View File

@@ -3,8 +3,10 @@ package babyjub
import ( import (
"encoding/hex" "encoding/hex"
"math/big" "math/big"
"math/rand"
"testing" "testing"
"github.com/iden3/go-iden3-crypto/constants"
"github.com/iden3/go-iden3-crypto/utils" "github.com/iden3/go-iden3-crypto/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -13,7 +15,7 @@ func TestAdd1(t *testing.T) {
a := &Point{X: big.NewInt(0), Y: big.NewInt(1)} a := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
b := &Point{X: big.NewInt(0), Y: big.NewInt(1)} b := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
c := NewPoint().Add(a, b) c := NewPoint().Projective().Add(a.Projective(), b.Projective())
// fmt.Printf("%v = 2 * %v", *c, *a) // fmt.Printf("%v = 2 * %v", *c, *a)
assert.Equal(t, "0", c.X.String()) assert.Equal(t, "0", c.X.String())
assert.Equal(t, "1", c.Y.String()) assert.Equal(t, "1", c.Y.String())
@@ -32,7 +34,7 @@ func TestAdd2(t *testing.T) {
"2626589144620713026669568689430873010625803728049924121243784502389097019475") "2626589144620713026669568689430873010625803728049924121243784502389097019475")
b := &Point{X: bX, Y: bY} b := &Point{X: bX, Y: bY}
c := NewPoint().Add(a, b) c := NewPoint().Projective().Add(a.Projective(), b.Projective()).Affine()
// fmt.Printf("%v = 2 * %v", *c, *a) // fmt.Printf("%v = 2 * %v", *c, *a)
assert.Equal(t, assert.Equal(t,
"6890855772600357754907169075114257697580319025794532037257385534741338397365", "6890855772600357754907169075114257697580319025794532037257385534741338397365",
@@ -40,6 +42,18 @@ func TestAdd2(t *testing.T) {
assert.Equal(t, assert.Equal(t,
"4338620300185947561074059802482547481416142213883829469920100239455078257889", "4338620300185947561074059802482547481416142213883829469920100239455078257889",
c.Y.String()) c.Y.String())
d := NewPointProjective().Add(c.Projective(), c.Projective()).Affine()
assert.Equal(t,
"2f6458832049e917c95867185a96621336df33e13c98e81d1ef4928cdbb77772",
hex.EncodeToString(d.X.Bytes()))
// Projective
aP := a.Projective()
bP := b.Projective()
cP := NewPointProjective().Add(aP, bP)
c2 := cP.Affine()
assert.Equal(t, c, c2)
} }
func TestAdd3(t *testing.T) { func TestAdd3(t *testing.T) {
@@ -55,7 +69,7 @@ func TestAdd3(t *testing.T) {
"20819045374670962167435360035096875258406992893633759881276124905556507972311") "20819045374670962167435360035096875258406992893633759881276124905556507972311")
b := &Point{X: bX, Y: bY} b := &Point{X: bX, Y: bY}
c := NewPoint().Add(a, b) c := NewPoint().Projective().Add(a.Projective(), b.Projective()).Affine()
// fmt.Printf("%v = 2 * %v", *c, *a) // fmt.Printf("%v = 2 * %v", *c, *a)
assert.Equal(t, assert.Equal(t,
"7916061937171219682591368294088513039687205273691143098332585753343424131937", "7916061937171219682591368294088513039687205273691143098332585753343424131937",
@@ -78,7 +92,7 @@ func TestAdd4(t *testing.T) {
"20819045374670962167435360035096875258406992893633759881276124905556507972311") "20819045374670962167435360035096875258406992893633759881276124905556507972311")
b := &Point{X: bX, Y: bY} b := &Point{X: bX, Y: bY}
c := NewPoint().Add(a, b) c := NewPoint().Projective().Add(a.Projective(), b.Projective()).Affine()
// fmt.Printf("%v = 2 * %v", *c, *a) // fmt.Printf("%v = 2 * %v", *c, *a)
assert.Equal(t, assert.Equal(t,
"16540640123574156134436876038791482806971768689494387082833631921987005038935", "16540640123574156134436876038791482806971768689494387082833631921987005038935",
@@ -106,8 +120,8 @@ func TestMul0(t *testing.T) {
p := &Point{X: x, Y: y} p := &Point{X: x, Y: y}
s := utils.NewIntFromString("3") s := utils.NewIntFromString("3")
r2 := NewPoint().Add(p, p) r2 := NewPoint().Projective().Add(p.Projective(), p.Projective()).Affine()
r2 = NewPoint().Add(r2, p) r2 = NewPoint().Projective().Add(r2.Projective(), p.Projective()).Affine()
r := NewPoint().Mul(s, p) r := NewPoint().Mul(s, p)
assert.Equal(t, r2.X.String(), r.X.String()) assert.Equal(t, r2.X.String(), r.X.String())
assert.Equal(t, r2.Y.String(), r.Y.String()) assert.Equal(t, r2.Y.String(), r.Y.String())
@@ -190,6 +204,40 @@ func TestInSubGroup2(t *testing.T) {
assert.Equal(t, true, p.InSubGroup()) assert.Equal(t, true, p.InSubGroup())
} }
func TestPointFromSignAndy(t *testing.T) {
x := utils.NewIntFromString(
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
y := utils.NewIntFromString(
"2626589144620713026669568689430873010625803728049924121243784502389097019475")
p := &Point{X: x, Y: y}
sign := PointCoordSign(p.X)
p2, err := PointFromSignAndY(sign, p.Y)
assert.Equal(t, nil, err)
assert.Equal(t, p.X.String(), p2.X.String())
assert.Equal(t, p.Y.String(), p2.Y.String())
}
func TestPackAndUnpackSignY(t *testing.T) {
x := utils.NewIntFromString(
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
y := utils.NewIntFromString(
"2626589144620713026669568689430873010625803728049924121243784502389097019475")
p := &Point{X: x, Y: y}
pComp := p.Compress()
s, y := UnpackSignY(pComp)
pComp2 := PackSignY(s, y)
assert.Equal(t, pComp, pComp2)
emptyPointComp := [32]byte{}
s, y = UnpackSignY(emptyPointComp)
pComp2 = PackSignY(s, y)
assert.Equal(t, emptyPointComp, pComp2)
}
func TestCompressDecompress1(t *testing.T) { func TestCompressDecompress1(t *testing.T) {
x := utils.NewIntFromString( x := utils.NewIntFromString(
"17777552123799933955779906779655732241715742912184938656739573121738514868268") "17777552123799933955779906779655732241715742912184938656739573121738514868268")
@@ -198,7 +246,9 @@ func TestCompressDecompress1(t *testing.T) {
p := &Point{X: x, Y: y} p := &Point{X: x, Y: y}
buf := p.Compress() buf := p.Compress()
assert.Equal(t, "53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85", hex.EncodeToString(buf[:])) assert.Equal(t,
"53b81ed5bffe9545b54016234682e7b2f699bd42a5e9eae27ff4051bc698ce85",
hex.EncodeToString(buf[:]))
p2, err := NewPoint().Decompress(buf) p2, err := NewPoint().Decompress(buf)
assert.Equal(t, nil, err) assert.Equal(t, nil, err)
@@ -214,7 +264,9 @@ func TestCompressDecompress2(t *testing.T) {
p := &Point{X: x, Y: y} p := &Point{X: x, Y: y}
buf := p.Compress() buf := p.Compress()
assert.Equal(t, "e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709", hex.EncodeToString(buf[:])) assert.Equal(t,
"e114eb17eddf794f063a68fecac515e3620e131976108555735c8b0773929709",
hex.EncodeToString(buf[:]))
p2, err := NewPoint().Decompress(buf) p2, err := NewPoint().Decompress(buf)
assert.Equal(t, nil, err) assert.Equal(t, nil, err)
@@ -228,6 +280,82 @@ func TestCompressDecompressRnd(t *testing.T) {
buf := p1.Compress() buf := p1.Compress()
p2, err := NewPoint().Decompress(buf) p2, err := NewPoint().Decompress(buf)
assert.Equal(t, nil, err) assert.Equal(t, nil, err)
assert.Equal(t, p1, p2) assert.Equal(t, p1.X.Bytes(), p2.X.Bytes())
assert.Equal(t, p1.Y.Bytes(), p2.Y.Bytes())
} }
} }
func BenchmarkBabyjub(b *testing.B) {
const n = 256
rnd := rand.New(rand.NewSource(42)) //nolint:gosec
var badpoints [n]*Point
for i := 0; i < n; i++ {
x := new(big.Int).Rand(rnd, constants.Q)
y := new(big.Int).Rand(rnd, constants.Q)
badpoints[i] = &Point{X: x, Y: y}
}
var points [n]*Point
var pointsProj [n]*PointProjective
baseX := utils.NewIntFromString(
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
baseY := utils.NewIntFromString(
"2626589144620713026669568689430873010625803728049924121243784502389097019475")
base := &Point{X: baseX, Y: baseY}
for i := 0; i < n; i++ {
s := new(big.Int).Rand(rnd, constants.Q)
points[i] = NewPoint().Mul(s, base)
pointsProj[i] = NewPoint().Mul(s, base).Projective()
}
var scalars [n]*big.Int
for i := 0; i < n; i++ {
scalars[i] = new(big.Int).Rand(rnd, constants.Q)
}
b.Run("AddConst", func(b *testing.B) {
p0 := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
p1 := &Point{X: big.NewInt(0), Y: big.NewInt(1)}
p0Proj := p0.Projective()
p1Proj := p1.Projective()
p2 := NewPoint().Projective()
for i := 0; i < b.N; i++ {
p2.Add(p0Proj, p1Proj)
}
})
b.Run("AddRnd", func(b *testing.B) {
res := NewPoint().Projective()
for i := 0; i < b.N; i++ {
res.Add(pointsProj[i%(n/2)], pointsProj[i%(n/2)+1])
}
})
b.Run("MulRnd", func(b *testing.B) {
res := NewPoint()
for i := 0; i < b.N; i++ {
res.Mul(scalars[i%n], points[i%n])
}
})
b.Run("Compress", func(b *testing.B) {
for i := 0; i < b.N; i++ {
points[i%n].Compress()
}
})
b.Run("InCurve", func(b *testing.B) {
for i := 0; i < b.N; i++ {
badpoints[i%n].InCurve()
}
})
b.Run("InSubGroup", func(b *testing.B) {
for i := 0; i < b.N; i++ {
points[i%n].InCurve()
}
})
}

View File

@@ -1,13 +1,16 @@
// Package babyjub eddsa implements the EdDSA over the BabyJubJub curve
//nolint:gomnd
package babyjub package babyjub
import ( import (
"crypto/rand" "crypto/rand"
"database/sql/driver"
"fmt"
"math/big"
"github.com/iden3/go-iden3-crypto/mimc7" "github.com/iden3/go-iden3-crypto/mimc7"
"github.com/iden3/go-iden3-crypto/poseidon" "github.com/iden3/go-iden3-crypto/poseidon"
"github.com/iden3/go-iden3-crypto/utils" "github.com/iden3/go-iden3-crypto/utils"
"math/big"
) )
// pruneBuffer prunes the buffer during key generation according to RFC 8032. // pruneBuffer prunes the buffer during key generation according to RFC 8032.
@@ -36,6 +39,13 @@ func NewRandPrivKey() PrivateKey {
// Scalar converts a private key into the scalar value s following the EdDSA // Scalar converts a private key into the scalar value s following the EdDSA
// standard, and using blake-512 hash. // standard, and using blake-512 hash.
func (k *PrivateKey) Scalar() *PrivKeyScalar { func (k *PrivateKey) Scalar() *PrivKeyScalar {
s := SkToBigInt(k)
return NewPrivKeyScalar(s)
}
// SkToBigInt converts a private key into the *big.Int value following the
// EdDSA standard, and using blake-512 hash
func SkToBigInt(k *PrivateKey) *big.Int {
sBuf := Blake512(k[:]) sBuf := Blake512(k[:])
sBuf32 := [32]byte{} sBuf32 := [32]byte{}
copy(sBuf32[:], sBuf[:32]) copy(sBuf32[:], sBuf[:32])
@@ -43,10 +53,10 @@ func (k *PrivateKey) Scalar() *PrivKeyScalar {
s := new(big.Int) s := new(big.Int)
utils.SetBigIntFromLEBytes(s, sBuf32[:]) utils.SetBigIntFromLEBytes(s, sBuf32[:])
s.Rsh(s, 3) s.Rsh(s, 3)
return NewPrivKeyScalar(s) return s
} }
// Pub returns the public key corresponding to a private key. // Public returns the public key corresponding to a private key.
func (k *PrivateKey) Public() *PublicKey { func (k *PrivateKey) Public() *PublicKey {
return k.Scalar().Public() return k.Scalar().Public()
} }
@@ -60,8 +70,8 @@ func NewPrivKeyScalar(s *big.Int) *PrivKeyScalar {
return &sk return &sk
} }
// Pub returns the public key corresponding to the scalar value s of a private // Public returns the public key corresponding to the scalar value s of a
// key. // private key.
func (s *PrivKeyScalar) Public() *PublicKey { func (s *PrivKeyScalar) Public() *PublicKey {
p := NewPoint().Mul((*big.Int)(s), B8) p := NewPoint().Mul((*big.Int)(s), B8)
pk := PublicKey(*p) pk := PublicKey(*p)
@@ -76,16 +86,19 @@ func (s *PrivKeyScalar) BigInt() *big.Int {
// PublicKey represents an EdDSA public key, which is a curve point. // PublicKey represents an EdDSA public key, which is a curve point.
type PublicKey Point type PublicKey Point
// MarshalText implements the marshaler for PublicKey
func (pk PublicKey) MarshalText() ([]byte, error) { func (pk PublicKey) MarshalText() ([]byte, error) {
pkc := pk.Compress() pkc := pk.Compress()
return utils.Hex(pkc[:]).MarshalText() return utils.Hex(pkc[:]).MarshalText()
} }
// String returns the string representation of the PublicKey
func (pk PublicKey) String() string { func (pk PublicKey) String() string {
pkc := pk.Compress() pkc := pk.Compress()
return utils.Hex(pkc[:]).String() return utils.Hex(pkc[:]).String()
} }
// UnmarshalText implements the unmarshaler for the PublicKey
func (pk *PublicKey) UnmarshalText(h []byte) error { func (pk *PublicKey) UnmarshalText(h []byte) error {
var pkc PublicKeyComp var pkc PublicKeyComp
if err := utils.HexDecodeInto(pkc[:], h); err != nil { if err := utils.HexDecodeInto(pkc[:], h); err != nil {
@@ -100,24 +113,35 @@ func (pk *PublicKey) UnmarshalText(h []byte) error {
} }
// Point returns the Point corresponding to a PublicKey. // Point returns the Point corresponding to a PublicKey.
func (p *PublicKey) Point() *Point { func (pk *PublicKey) Point() *Point {
return (*Point)(p) return (*Point)(pk)
} }
// PublicKeyComp represents a compressed EdDSA Public key; it's a compressed curve // PublicKeyComp represents a compressed EdDSA Public key; it's a compressed curve
// point. // point.
type PublicKeyComp [32]byte type PublicKeyComp [32]byte
func (buf PublicKeyComp) MarshalText() ([]byte, error) { return utils.Hex(buf[:]).MarshalText() } // MarshalText implements the marshaler for the PublicKeyComp
func (buf PublicKeyComp) String() string { return utils.Hex(buf[:]).String() } func (pkComp PublicKeyComp) MarshalText() ([]byte, error) {
func (buf *PublicKeyComp) UnmarshalText(h []byte) error { return utils.HexDecodeInto(buf[:], h) } return utils.Hex(pkComp[:]).MarshalText()
func (p *PublicKey) Compress() PublicKeyComp {
return PublicKeyComp((*Point)(p).Compress())
} }
func (p *PublicKeyComp) Decompress() (*PublicKey, error) { // String returns the string representation of the PublicKeyComp
point, err := NewPoint().Decompress(*p) func (pkComp PublicKeyComp) String() string { return utils.Hex(pkComp[:]).String() }
// UnmarshalText implements the unmarshaler for the PublicKeyComp
func (pkComp *PublicKeyComp) UnmarshalText(h []byte) error {
return utils.HexDecodeInto(pkComp[:], h)
}
// Compress returns the PublicKeyCompr for the given PublicKey
func (pk *PublicKey) Compress() PublicKeyComp {
return PublicKeyComp((*Point)(pk).Compress())
}
// Decompress returns the PublicKey for the given PublicKeyComp
func (pkComp *PublicKeyComp) Decompress() (*PublicKey, error) {
point, err := NewPoint().Decompress(*pkComp)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -134,9 +158,18 @@ type Signature struct {
// SignatureComp represents a compressed EdDSA signature. // SignatureComp represents a compressed EdDSA signature.
type SignatureComp [64]byte type SignatureComp [64]byte
func (buf SignatureComp) MarshalText() ([]byte, error) { return utils.Hex(buf[:]).MarshalText() } // MarshalText implements the marshaler for the SignatureComp
func (buf SignatureComp) String() string { return utils.Hex(buf[:]).String() } func (sComp SignatureComp) MarshalText() ([]byte, error) {
func (buf *SignatureComp) UnmarshalText(h []byte) error { return utils.HexDecodeInto(buf[:], h) } return utils.Hex(sComp[:]).MarshalText()
}
// String returns the string representation of the SignatureComp
func (sComp SignatureComp) String() string { return utils.Hex(sComp[:]).String() }
// UnmarshalText implements the unmarshaler for the SignatureComp
func (sComp *SignatureComp) UnmarshalText(h []byte) error {
return utils.HexDecodeInto(sComp[:], h)
}
// Compress an EdDSA signature by concatenating the compression of // Compress an EdDSA signature by concatenating the compression of
// the point R8 and the Little-Endian encoding of S. // the point R8 and the Little-Endian encoding of S.
@@ -164,8 +197,47 @@ func (s *Signature) Decompress(buf [64]byte) (*Signature, error) {
// Decompress a compressed signature. Returns error if the Point decompression // Decompress a compressed signature. Returns error if the Point decompression
// fails. // fails.
func (s *SignatureComp) Decompress() (*Signature, error) { func (sComp *SignatureComp) Decompress() (*Signature, error) {
return new(Signature).Decompress(*s) return new(Signature).Decompress(*sComp)
}
// Scan implements Scanner for database/sql.
func (sComp *SignatureComp) Scan(src interface{}) error {
srcB, ok := src.([]byte)
if !ok {
return fmt.Errorf("can't scan %T into Signature", src)
}
if len(srcB) != 64 {
return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64)
}
copy(sComp[:], srcB[:])
return nil
}
// Value implements valuer for database/sql.
func (sComp SignatureComp) Value() (driver.Value, error) {
return sComp[:], nil
}
// Scan implements Scanner for database/sql.
func (s *Signature) Scan(src interface{}) error {
srcB, ok := src.([]byte)
if !ok {
return fmt.Errorf("can't scan %T into Signature", src)
}
if len(srcB) != 64 {
return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64)
}
buf := [64]byte{}
copy(buf[:], srcB[:])
_, err := s.Decompress(buf)
return err
}
// Value implements valuer for database/sql.
func (s Signature) Value() (driver.Value, error) {
comp := s.Compress()
return comp[:], nil
} }
// SignMimc7 signs a message encoded as a big.Int in Zq using blake-512 hash // SignMimc7 signs a message encoded as a big.Int in Zq using blake-512 hash
@@ -195,18 +267,20 @@ func (k *PrivateKey) SignMimc7(msg *big.Int) *Signature {
// VerifyMimc7 verifies the signature of a message encoded as a big.Int in Zq // VerifyMimc7 verifies the signature of a message encoded as a big.Int in Zq
// using blake-512 hash for buffer hashing and mimc7 for big.Int hashing. // using blake-512 hash for buffer hashing and mimc7 for big.Int hashing.
func (p *PublicKey) VerifyMimc7(msg *big.Int, sig *Signature) bool { func (pk *PublicKey) VerifyMimc7(msg *big.Int, sig *Signature) bool {
hmInput := []*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg} hmInput := []*big.Int{sig.R8.X, sig.R8.Y, pk.X, pk.Y, msg}
hm, err := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg) hm, err := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
if err != nil { if err != nil {
panic(err) return false
} }
left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
r1 := big.NewInt(8) r1 := big.NewInt(8)
r1.Mul(r1, hm) r1.Mul(r1, hm)
right := NewPoint().Mul(r1, p.Point()) right := NewPoint().Mul(r1, pk.Point())
right.Add(sig.R8, right) // right = 8 * R + 8 * hm * A rightProj := right.Projective()
rightProj.Add(sig.R8.Projective(), rightProj) // right = 8 * R + 8 * hm * A
right = rightProj.Affine()
return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0) return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
} }
@@ -222,11 +296,13 @@ func (k *PrivateKey) SignPoseidon(msg *big.Int) *Signature {
r.Mod(r, SubOrder) r.Mod(r, SubOrder)
R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
A := k.Public().Point() A := k.Public().Point()
hmInput := []*big.Int{R8.X, R8.Y, A.X, A.Y, msg} hmInput := []*big.Int{R8.X, R8.Y, A.X, A.Y, msg}
hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg) hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
if err != nil { if err != nil {
panic(err) panic(err)
} }
S := new(big.Int).Lsh(k.Scalar().BigInt(), 3) S := new(big.Int).Lsh(k.Scalar().BigInt(), 3)
S = S.Mul(hm, S) S = S.Mul(hm, S)
S.Add(r, S) S.Add(r, S)
@@ -237,17 +313,62 @@ func (k *PrivateKey) SignPoseidon(msg *big.Int) *Signature {
// VerifyPoseidon verifies the signature of a message encoded as a big.Int in Zq // VerifyPoseidon verifies the signature of a message encoded as a big.Int in Zq
// using blake-512 hash for buffer hashing and Poseidon for big.Int hashing. // using blake-512 hash for buffer hashing and Poseidon for big.Int hashing.
func (p *PublicKey) VerifyPoseidon(msg *big.Int, sig *Signature) bool { func (pk *PublicKey) VerifyPoseidon(msg *big.Int, sig *Signature) bool {
hmInput := []*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg} hmInput := []*big.Int{sig.R8.X, sig.R8.Y, pk.X, pk.Y, msg}
hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg) hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
if err != nil { if err != nil {
panic(err) return false
} }
left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
r1 := big.NewInt(8) r1 := big.NewInt(8)
r1.Mul(r1, hm) r1.Mul(r1, hm)
right := NewPoint().Mul(r1, p.Point()) right := NewPoint().Mul(r1, pk.Point())
right.Add(sig.R8, right) // right = 8 * R + 8 * hm * A rightProj := right.Projective()
rightProj.Add(sig.R8.Projective(), rightProj) // right = 8 * R + 8 * hm * A
right = rightProj.Affine()
return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0) return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
} }
// Scan implements Scanner for database/sql.
func (pk *PublicKey) Scan(src interface{}) error {
srcB, ok := src.([]byte)
if !ok {
return fmt.Errorf("can't scan %T into PublicKey", src)
}
if len(srcB) != 32 {
return fmt.Errorf("can't scan []byte of len %d into PublicKey, want %d", len(srcB), 32)
}
var comp PublicKeyComp
copy(comp[:], srcB)
decomp, err := comp.Decompress()
if err != nil {
return err
}
*pk = *decomp
return nil
}
// Value implements valuer for database/sql.
func (pk PublicKey) Value() (driver.Value, error) {
comp := pk.Compress()
return comp[:], nil
}
// Scan implements Scanner for database/sql.
func (pkComp *PublicKeyComp) Scan(src interface{}) error {
srcB, ok := src.([]byte)
if !ok {
return fmt.Errorf("can't scan %T into PublicKeyComp", src)
}
if len(srcB) != 32 {
return fmt.Errorf("can't scan []byte of len %d into PublicKeyComp, want %d", len(srcB), 32)
}
copy(pkComp[:], srcB)
return nil
}
// Value implements valuer for database/sql.
func (pkComp PublicKeyComp) Value() (driver.Value, error) {
return pkComp[:], nil
}

View File

@@ -1,7 +1,8 @@
package babyjub package babyjub
import ( import (
"crypto/rand" "database/sql"
"database/sql/driver"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"math/big" "math/big"
@@ -10,24 +11,24 @@ import (
"github.com/iden3/go-iden3-crypto/constants" "github.com/iden3/go-iden3-crypto/constants"
"github.com/iden3/go-iden3-crypto/utils" "github.com/iden3/go-iden3-crypto/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func genInputs() (*PrivateKey, *big.Int) { func TestPublicKey(t *testing.T) {
k := NewRandPrivKey() var k PrivateKey
fmt.Println("k", hex.EncodeToString(k[:])) for i := 0; i < 32; i++ {
k[i] = byte(i)
msgBuf := [32]byte{} }
rand.Read(msgBuf[:]) pk := k.Public()
msg := utils.SetBigIntFromLEBytes(new(big.Int), msgBuf[:]) assert.True(t, pk.X.Cmp(constants.Q) == -1)
msg.Mod(msg, constants.Q) assert.True(t, pk.Y.Cmp(constants.Q) == -1)
fmt.Println("msg", msg)
return &k, msg
} }
func TestSignVerifyMimc7(t *testing.T) { func TestSignVerifyMimc7(t *testing.T) {
var k PrivateKey var k PrivateKey
hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001")) _, err := hex.Decode(k[:],
[]byte("0001020304050607080900010203040506070809000102030405060708090001"))
require.Nil(t, err)
msgBuf, err := hex.DecodeString("00010203040506070809") msgBuf, err := hex.DecodeString("00010203040506070809")
if err != nil { if err != nil {
panic(err) panic(err)
@@ -71,7 +72,9 @@ func TestSignVerifyMimc7(t *testing.T) {
func TestSignVerifyPoseidon(t *testing.T) { func TestSignVerifyPoseidon(t *testing.T) {
var k PrivateKey var k PrivateKey
hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001")) _, err := hex.Decode(k[:],
[]byte("0001020304050607080900010203040506070809000102030405060708090001"))
require.Nil(t, err)
msgBuf, err := hex.DecodeString("00010203040506070809") msgBuf, err := hex.DecodeString("00010203040506070809")
if err != nil { if err != nil {
panic(err) panic(err)
@@ -94,7 +97,7 @@ func TestSignVerifyPoseidon(t *testing.T) {
"15383486972088797283337779941324724402501462225528836549661220478783371668959", "15383486972088797283337779941324724402501462225528836549661220478783371668959",
sig.R8.Y.String()) sig.R8.Y.String())
assert.Equal(t, assert.Equal(t,
"248298168863866362217836334079793350221620631973732197668910946177382043688", "1672775540645840396591609181675628451599263765380031905495115170613215233181",
sig.S.String()) sig.S.String())
ok := pk.VerifyPoseidon(msg, sig) ok := pk.VerifyPoseidon(msg, sig)
@@ -106,7 +109,7 @@ func TestSignVerifyPoseidon(t *testing.T) {
assert.Equal(t, ""+ assert.Equal(t, ""+
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+ "dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"28506bce274aa1b3f7e7c2fd7e4fe09bff8f9aa37a42def7994e98f322888c00", "9d043ece562a8f82bfc0adb640c0107a7d3a27c1c7c1a6179a0da73de5c1b203",
hex.EncodeToString(sigBuf[:])) hex.EncodeToString(sigBuf[:]))
ok = pk.VerifyPoseidon(msg, sig2) ok = pk.VerifyPoseidon(msg, sig2)
@@ -115,7 +118,9 @@ func TestSignVerifyPoseidon(t *testing.T) {
func TestCompressDecompress(t *testing.T) { func TestCompressDecompress(t *testing.T) {
var k PrivateKey var k PrivateKey
hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001")) _, err := hex.Decode(k[:],
[]byte("0001020304050607080900010203040506070809000102030405060708090001"))
require.Nil(t, err)
pk := k.Public() pk := k.Public()
for i := 0; i < 64; i++ { for i := 0; i < 64; i++ {
msgBuf, err := hex.DecodeString(fmt.Sprintf("000102030405060708%02d", i)) msgBuf, err := hex.DecodeString(fmt.Sprintf("000102030405060708%02d", i))
@@ -131,3 +136,109 @@ func TestCompressDecompress(t *testing.T) {
assert.Equal(t, true, ok) assert.Equal(t, true, ok)
} }
} }
func TestSignatureCompScannerValuer(t *testing.T) {
privK := NewRandPrivKey()
var value driver.Valuer //nolint:gosimple this is done to ensure interface compatibility
value = privK.SignPoseidon(big.NewInt(674238462)).Compress()
scan := privK.SignPoseidon(big.NewInt(1)).Compress()
fromDB, err := value.Value()
assert.Nil(t, err)
assert.Nil(t, scan.Scan(fromDB))
assert.Equal(t, value, scan)
}
func TestSignatureScannerValuer(t *testing.T) {
privK := NewRandPrivKey()
var value driver.Valuer
var scan sql.Scanner
value = privK.SignPoseidon(big.NewInt(674238462))
scan = privK.SignPoseidon(big.NewInt(1))
fromDB, err := value.Value()
assert.Nil(t, err)
assert.Nil(t, scan.Scan(fromDB))
assert.Equal(t, value, scan)
}
func TestPublicKeyScannerValuer(t *testing.T) {
privKValue := NewRandPrivKey()
pubKValue := privKValue.Public()
privKScan := NewRandPrivKey()
pubKScan := privKScan.Public()
var value driver.Valuer
var scan sql.Scanner
value = pubKValue
scan = pubKScan
fromDB, err := value.Value()
assert.Nil(t, err)
assert.Nil(t, scan.Scan(fromDB))
assert.Equal(t, value, scan)
}
func TestPublicKeyCompScannerValuer(t *testing.T) {
privKValue := NewRandPrivKey()
pubKCompValue := privKValue.Public().Compress()
privKScan := NewRandPrivKey()
pubKCompScan := privKScan.Public().Compress()
var value driver.Valuer
var scan sql.Scanner
value = &pubKCompValue
scan = &pubKCompScan
fromDB, err := value.Value()
assert.Nil(t, err)
assert.Nil(t, scan.Scan(fromDB))
assert.Equal(t, value, scan)
}
func BenchmarkBabyjubEddsa(b *testing.B) {
var k PrivateKey
_, err := hex.Decode(k[:],
[]byte("0001020304050607080900010203040506070809000102030405060708090001"))
require.Nil(b, err)
pk := k.Public()
const n = 256
msgBuf, err := hex.DecodeString("00010203040506070809")
if err != nil {
panic(err)
}
msg := utils.SetBigIntFromLEBytes(new(big.Int), msgBuf)
var msgs [n]*big.Int
for i := 0; i < n; i++ {
msgs[i] = new(big.Int).Add(msg, big.NewInt(int64(i)))
}
var sigs [n]*Signature
b.Run("SignMimc7", func(b *testing.B) {
for i := 0; i < b.N; i++ {
k.SignMimc7(msgs[i%n])
}
})
for i := 0; i < n; i++ {
sigs[i%n] = k.SignMimc7(msgs[i%n])
}
b.Run("VerifyMimc7", func(b *testing.B) {
for i := 0; i < b.N; i++ {
pk.VerifyMimc7(msgs[i%n], sigs[i%n])
}
})
b.Run("SignPoseidon", func(b *testing.B) {
for i := 0; i < b.N; i++ {
k.SignPoseidon(msgs[i%n])
}
})
for i := 0; i < n; i++ {
sigs[i%n] = k.SignPoseidon(msgs[i%n])
}
b.Run("VerifyPoseidon", func(b *testing.B) {
for i := 0; i < b.N; i++ {
pk.VerifyPoseidon(msgs[i%n], sigs[i%n])
}
})
}

View File

@@ -1,13 +1,20 @@
package babyjub package babyjub
import ( import (
"github.com/dchest/blake512" // I have personally reviewed that this module doesn't do anything suspicious "github.com/dchest/blake512"
) )
// Note on dchest/blake512: This specific blake512 module is compatible with
// the version of Blake512 used at circomlib, and this module has been reviewed
// to don't be doing do anything suspicious.
// Blake512 performs the blake-512 hash over the buffer m. Note that this is // Blake512 performs the blake-512 hash over the buffer m. Note that this is
// the original blake from the SHA3 competition and not the new blake2 version. // the original blake from the SHA3 competition and not the new blake2 version.
func Blake512(m []byte) []byte { func Blake512(m []byte) []byte {
h := blake512.New() h := blake512.New()
h.Write(m[:]) _, err := h.Write(m[:])
if err != nil {
panic(err)
}
return h.Sum(nil) return h.Sum(nil)
} }

View File

@@ -1,7 +1,7 @@
package constants package constants
import ( import (
"github.com/iden3/go-iden3-crypto/utils" "fmt"
"math/big" "math/big"
) )
@@ -21,6 +21,11 @@ func init() {
Zero = big.NewInt(0) Zero = big.NewInt(0)
One = big.NewInt(1) One = big.NewInt(1)
MinusOne = big.NewInt(-1) MinusOne = big.NewInt(-1)
Q = utils.NewIntFromString(
"21888242871839275222246405745257275088548364400416034343698204186575808495617") qString := "21888242871839275222246405745257275088548364400416034343698204186575808495617"
var ok bool
Q, ok = new(big.Int).SetString(qString, 10)
if !ok {
panic(fmt.Sprintf("Bad base 10 string %s", qString))
}
} }

122
ff/arith.go Normal file
View File

@@ -0,0 +1,122 @@
// 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.
// Code generated by goff DO NOT EDIT
package ff
import (
"math/bits"
)
func madd(a, b, t, u, v uint64) (uint64, uint64, uint64) {
var carry uint64
hi, lo := bits.Mul64(a, b)
v, carry = bits.Add64(lo, v, 0)
u, carry = bits.Add64(hi, u, carry)
t, _ = bits.Add64(t, 0, carry)
return t, u, v
}
// 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
}
// madd2s superhi, hi, lo = 2*a*b + c + d + e
func madd2s(a, b, c, d, e uint64) (superhi, hi, lo uint64) {
var carry, sum uint64
hi, lo = bits.Mul64(a, b)
lo, carry = bits.Add64(lo, lo, 0)
hi, superhi = bits.Add64(hi, hi, carry)
sum, carry = bits.Add64(c, e, 0)
hi, _ = bits.Add64(hi, 0, carry)
lo, carry = bits.Add64(lo, sum, 0)
hi, _ = bits.Add64(hi, 0, carry)
hi, _ = bits.Add64(hi, 0, d)
return
}
func madd1s(a, b, d, e uint64) (superhi, hi, lo uint64) {
var carry uint64
hi, lo = bits.Mul64(a, b)
lo, carry = bits.Add64(lo, lo, 0)
hi, superhi = bits.Add64(hi, hi, carry)
lo, carry = bits.Add64(lo, e, 0)
hi, _ = bits.Add64(hi, 0, carry)
hi, _ = bits.Add64(hi, 0, d)
return
}
func madd2sb(a, b, c, e uint64) (superhi, hi, lo uint64) {
var carry, sum uint64
hi, lo = bits.Mul64(a, b)
lo, carry = bits.Add64(lo, lo, 0)
hi, superhi = bits.Add64(hi, hi, carry)
sum, carry = bits.Add64(c, e, 0)
hi, _ = bits.Add64(hi, 0, carry)
lo, carry = bits.Add64(lo, sum, 0)
hi, _ = bits.Add64(hi, 0, carry)
return
}
func madd1sb(a, b, e uint64) (superhi, hi, lo uint64) {
var carry uint64
hi, lo = bits.Mul64(a, b)
lo, carry = bits.Add64(lo, lo, 0)
hi, superhi = bits.Add64(hi, hi, carry)
lo, carry = bits.Add64(lo, e, 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
}

792
ff/element.go Normal file
View File

@@ -0,0 +1,792 @@
// 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.
// field modulus q =
//
// 21888242871839275222246405745257275088548364400416034343698204186575808495617
// Code generated by goff DO NOT EDIT
// goff version: - build:
// Element are assumed to be in Montgomery form in all methods
// Package ff (generated by goff) contains field arithmetics operations
package ff
import (
"crypto/rand"
"encoding/binary"
"io"
"math/big"
"math/bits"
"sync"
"unsafe"
)
// Element represents a field element stored on 4 words (uint64)
// Element are assumed to be in Montgomery form in all methods
type Element [4]uint64
// ElementLimbs number of 64 bits words needed to represent Element
const ElementLimbs = 4
// ElementBits number bits needed to represent Element
const ElementBits = 254
// SetUint64 z = v, sets z LSB to v (non-Montgomery form) and convert z to Montgomery form
func (z *Element) SetUint64(v uint64) *Element {
z[0] = v
z[1] = 0
z[2] = 0
z[3] = 0
return z.ToMont()
}
// Set z = x
func (z *Element) Set(x *Element) *Element {
z[0] = x[0]
z[1] = x[1]
z[2] = x[2]
z[3] = x[3]
return z
}
// SetZero z = 0
func (z *Element) SetZero() *Element {
z[0] = 0
z[1] = 0
z[2] = 0
z[3] = 0
return z
}
// SetOne z = 1 (in Montgomery form)
func (z *Element) SetOne() *Element {
z[0] = 12436184717236109307
z[1] = 3962172157175319849
z[2] = 7381016538464732718
z[3] = 1011752739694698287
return z
}
// Neg z = q - x
func (z *Element) Neg(x *Element) *Element {
if x.IsZero() {
return z.SetZero()
}
var borrow uint64
z[0], borrow = bits.Sub64(4891460686036598785, x[0], 0)
z[1], borrow = bits.Sub64(2896914383306846353, x[1], borrow)
z[2], borrow = bits.Sub64(13281191951274694749, x[2], borrow)
z[3], _ = bits.Sub64(3486998266802970665, x[3], borrow)
return z
}
// Div z = x*y^-1 mod q
func (z *Element) Div(x, y *Element) *Element {
var yInv Element
yInv.Inverse(y)
z.Mul(x, &yInv)
return z
}
// Equal returns z == x
func (z *Element) Equal(x *Element) bool {
return (z[3] == x[3]) && (z[2] == x[2]) && (z[1] == x[1]) && (z[0] == x[0])
}
// IsZero returns z == 0
func (z *Element) IsZero() bool {
return (z[3] | z[2] | z[1] | z[0]) == 0
}
// field modulus stored as big.Int
var _elementModulusBigInt big.Int
var onceelementModulus sync.Once
func elementModulusBigInt() *big.Int {
onceelementModulus.Do(func() {
_elementModulusBigInt.SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
})
return &_elementModulusBigInt
}
// 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 *Element) Inverse(x *Element) *Element {
if x.IsZero() {
return z.Set(x)
}
// initialize u = q
var u = Element{
4891460686036598785,
2896914383306846353,
13281191951274694749,
3486998266802970665,
}
// initialize s = r^2
var s = Element{
1997599621687373223,
6052339484930628067,
10108755138030829701,
150537098327114917,
}
// r = 0
r := Element{}
v := *x
var carry, borrow, t, t2 uint64
var bigger, uIsOne, vIsOne bool
for !uIsOne && !vIsOne {
for v[0]&1 == 0 {
// v = v >> 1
t2 = v[3] << 63
v[3] >>= 1
t = t2
t2 = v[2] << 63
v[2] = (v[2] >> 1) | t
t = t2
t2 = v[1] << 63
v[1] = (v[1] >> 1) | t
t = t2
v[0] = (v[0] >> 1) | t
if s[0]&1 == 1 {
// s = s + q
s[0], carry = bits.Add64(s[0], 4891460686036598785, 0)
s[1], carry = bits.Add64(s[1], 2896914383306846353, carry)
s[2], carry = bits.Add64(s[2], 13281191951274694749, carry)
s[3], _ = bits.Add64(s[3], 3486998266802970665, carry)
}
// s = s >> 1
t2 = s[3] << 63
s[3] >>= 1
t = t2
t2 = s[2] << 63
s[2] = (s[2] >> 1) | t
t = t2
t2 = s[1] << 63
s[1] = (s[1] >> 1) | t
t = t2
s[0] = (s[0] >> 1) | t
}
for u[0]&1 == 0 {
// u = u >> 1
t2 = u[3] << 63
u[3] >>= 1
t = t2
t2 = u[2] << 63
u[2] = (u[2] >> 1) | t
t = t2
t2 = u[1] << 63
u[1] = (u[1] >> 1) | t
t = t2
u[0] = (u[0] >> 1) | t
if r[0]&1 == 1 {
// r = r + q
r[0], carry = bits.Add64(r[0], 4891460686036598785, 0)
r[1], carry = bits.Add64(r[1], 2896914383306846353, carry)
r[2], carry = bits.Add64(r[2], 13281191951274694749, carry)
r[3], _ = bits.Add64(r[3], 3486998266802970665, carry)
}
// r = r >> 1
t2 = r[3] << 63
r[3] >>= 1
t = t2
t2 = r[2] << 63
r[2] = (r[2] >> 1) | t
t = t2
t2 = r[1] << 63
r[1] = (r[1] >> 1) | t
t = t2
r[0] = (r[0] >> 1) | t
}
// v >= u
bigger = !(v[3] < u[3] || (v[3] == u[3] && (v[2] < u[2] || (v[2] == u[2] && (v[1] < u[1] || (v[1] == u[1] && (v[0] < u[0])))))))
if bigger {
// v = v - u
v[0], borrow = bits.Sub64(v[0], u[0], 0)
v[1], borrow = bits.Sub64(v[1], u[1], borrow)
v[2], borrow = bits.Sub64(v[2], u[2], borrow)
v[3], _ = bits.Sub64(v[3], u[3], borrow)
// r >= s
bigger = !(r[3] < s[3] || (r[3] == s[3] && (r[2] < s[2] || (r[2] == s[2] && (r[1] < s[1] || (r[1] == s[1] && (r[0] < s[0])))))))
if bigger {
// s = s + q
s[0], carry = bits.Add64(s[0], 4891460686036598785, 0)
s[1], carry = bits.Add64(s[1], 2896914383306846353, carry)
s[2], carry = bits.Add64(s[2], 13281191951274694749, carry)
s[3], _ = bits.Add64(s[3], 3486998266802970665, carry)
}
// s = s - r
s[0], borrow = bits.Sub64(s[0], r[0], 0)
s[1], borrow = bits.Sub64(s[1], r[1], borrow)
s[2], borrow = bits.Sub64(s[2], r[2], borrow)
s[3], _ = bits.Sub64(s[3], r[3], borrow)
} else {
// u = u - v
u[0], borrow = bits.Sub64(u[0], v[0], 0)
u[1], borrow = bits.Sub64(u[1], v[1], borrow)
u[2], borrow = bits.Sub64(u[2], v[2], borrow)
u[3], _ = bits.Sub64(u[3], v[3], borrow)
// s >= r
bigger = !(s[3] < r[3] || (s[3] == r[3] && (s[2] < r[2] || (s[2] == r[2] && (s[1] < r[1] || (s[1] == r[1] && (s[0] < r[0])))))))
if bigger {
// r = r + q
r[0], carry = bits.Add64(r[0], 4891460686036598785, 0)
r[1], carry = bits.Add64(r[1], 2896914383306846353, carry)
r[2], carry = bits.Add64(r[2], 13281191951274694749, carry)
r[3], _ = bits.Add64(r[3], 3486998266802970665, carry)
}
// r = r - s
r[0], borrow = bits.Sub64(r[0], s[0], 0)
r[1], borrow = bits.Sub64(r[1], s[1], borrow)
r[2], borrow = bits.Sub64(r[2], s[2], borrow)
r[3], _ = bits.Sub64(r[3], s[3], borrow)
}
uIsOne = (u[0] == 1) && (u[3]|u[2]|u[1]) == 0
vIsOne = (v[0] == 1) && (v[3]|v[2]|v[1]) == 0
}
if uIsOne {
z.Set(&r)
} else {
z.Set(&s)
}
return z
}
// SetRandom sets z to a random element < q
func (z *Element) SetRandom() *Element {
bytes := make([]byte, 32)
io.ReadFull(rand.Reader, bytes)
z[0] = binary.BigEndian.Uint64(bytes[0:8])
z[1] = binary.BigEndian.Uint64(bytes[8:16])
z[2] = binary.BigEndian.Uint64(bytes[16:24])
z[3] = binary.BigEndian.Uint64(bytes[24:32])
z[3] %= 3486998266802970665
// if z > q --> z -= q
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
}
return z
}
// Add z = x + y mod q
func (z *Element) Add(x, y *Element) *Element {
var carry uint64
z[0], carry = bits.Add64(x[0], y[0], 0)
z[1], carry = bits.Add64(x[1], y[1], carry)
z[2], carry = bits.Add64(x[2], y[2], carry)
z[3], _ = bits.Add64(x[3], y[3], carry)
// if z > q --> z -= q
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
}
return z
}
// AddAssign z = z + x mod q
func (z *Element) AddAssign(x *Element) *Element {
var carry uint64
z[0], carry = bits.Add64(z[0], x[0], 0)
z[1], carry = bits.Add64(z[1], x[1], carry)
z[2], carry = bits.Add64(z[2], x[2], carry)
z[3], _ = bits.Add64(z[3], x[3], carry)
// if z > q --> z -= q
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
}
return z
}
// Double z = x + x mod q, aka Lsh 1
func (z *Element) Double(x *Element) *Element {
var carry uint64
z[0], carry = bits.Add64(x[0], x[0], 0)
z[1], carry = bits.Add64(x[1], x[1], carry)
z[2], carry = bits.Add64(x[2], x[2], carry)
z[3], _ = bits.Add64(x[3], x[3], carry)
// if z > q --> z -= q
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
}
return z
}
// Sub z = x - y mod q
func (z *Element) Sub(x, y *Element) *Element {
var b uint64
z[0], b = bits.Sub64(x[0], y[0], 0)
z[1], b = bits.Sub64(x[1], y[1], b)
z[2], b = bits.Sub64(x[2], y[2], b)
z[3], b = bits.Sub64(x[3], y[3], b)
if b != 0 {
var c uint64
z[0], c = bits.Add64(z[0], 4891460686036598785, 0)
z[1], c = bits.Add64(z[1], 2896914383306846353, c)
z[2], c = bits.Add64(z[2], 13281191951274694749, c)
z[3], _ = bits.Add64(z[3], 3486998266802970665, c)
}
return z
}
// SubAssign z = z - x mod q
func (z *Element) SubAssign(x *Element) *Element {
var b uint64
z[0], b = bits.Sub64(z[0], x[0], 0)
z[1], b = bits.Sub64(z[1], x[1], b)
z[2], b = bits.Sub64(z[2], x[2], b)
z[3], b = bits.Sub64(z[3], x[3], b)
if b != 0 {
var c uint64
z[0], c = bits.Add64(z[0], 4891460686036598785, 0)
z[1], c = bits.Add64(z[1], 2896914383306846353, c)
z[2], c = bits.Add64(z[2], 13281191951274694749, c)
z[3], _ = bits.Add64(z[3], 3486998266802970665, c)
}
return z
}
// Exp z = x^e mod q
func (z *Element) Exp(x Element, e uint64) *Element {
if e == 0 {
return z.SetOne()
}
z.Set(&x)
l := bits.Len64(e) - 2
for i := l; i >= 0; i-- {
z.Square(z)
if e&(1<<uint(i)) != 0 {
z.MulAssign(&x)
}
}
return z
}
// FromMont converts z in place (i.e. mutates) from Montgomery to regular representation
// sets and returns z = z * 1
func (z *Element) FromMont() *Element {
// the following lines implement z = z * 1
// with a modified CIOS montgomery multiplication
{
// m = z[0]n'[0] mod W
m := z[0] * 14042775128853446655
C := madd0(m, 4891460686036598785, z[0])
C, z[0] = madd2(m, 2896914383306846353, z[1], C)
C, z[1] = madd2(m, 13281191951274694749, z[2], C)
C, z[2] = madd2(m, 3486998266802970665, z[3], C)
z[3] = C
}
{
// m = z[0]n'[0] mod W
m := z[0] * 14042775128853446655
C := madd0(m, 4891460686036598785, z[0])
C, z[0] = madd2(m, 2896914383306846353, z[1], C)
C, z[1] = madd2(m, 13281191951274694749, z[2], C)
C, z[2] = madd2(m, 3486998266802970665, z[3], C)
z[3] = C
}
{
// m = z[0]n'[0] mod W
m := z[0] * 14042775128853446655
C := madd0(m, 4891460686036598785, z[0])
C, z[0] = madd2(m, 2896914383306846353, z[1], C)
C, z[1] = madd2(m, 13281191951274694749, z[2], C)
C, z[2] = madd2(m, 3486998266802970665, z[3], C)
z[3] = C
}
{
// m = z[0]n'[0] mod W
m := z[0] * 14042775128853446655
C := madd0(m, 4891460686036598785, z[0])
C, z[0] = madd2(m, 2896914383306846353, z[1], C)
C, z[1] = madd2(m, 13281191951274694749, z[2], C)
C, z[2] = madd2(m, 3486998266802970665, z[3], C)
z[3] = C
}
// if z > q --> z -= q
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
}
return z
}
// ToMont converts z to Montgomery form
// sets and returns z = z * r^2
func (z *Element) ToMont() *Element {
var rSquare = Element{
1997599621687373223,
6052339484930628067,
10108755138030829701,
150537098327114917,
}
return z.MulAssign(&rSquare)
}
// ToRegular returns z in regular form (doesn't mutate z)
func (z Element) ToRegular() Element {
return *z.FromMont()
}
// String returns the string form of an Element in Montgomery form
func (z *Element) String() string {
var _z big.Int
return z.ToBigIntRegular(&_z).String()
}
// ToBigInt returns z as a big.Int in Montgomery form
func (z *Element) ToBigInt(res *big.Int) *big.Int {
if bits.UintSize == 64 {
bits := (*[4]big.Word)(unsafe.Pointer(z))
return res.SetBits(bits[:])
} else {
var bits [8]big.Word
for i := 0; i < len(z); i++ {
bits[i*2] = big.Word(z[i])
bits[i*2+1] = big.Word(z[i] >> 32)
}
return res.SetBits(bits[:])
}
}
// ToBigIntRegular returns z as a big.Int in regular form
func (z Element) ToBigIntRegular(res *big.Int) *big.Int {
z.FromMont()
if bits.UintSize == 64 {
bits := (*[4]big.Word)(unsafe.Pointer(&z))
return res.SetBits(bits[:])
} else {
var bits [8]big.Word
for i := 0; i < len(z); i++ {
bits[i*2] = big.Word(z[i])
bits[i*2+1] = big.Word(z[i] >> 32)
}
return res.SetBits(bits[:])
}
}
// SetBigInt sets z to v (regular form) and returns z in Montgomery form
func (z *Element) SetBigInt(v *big.Int) *Element {
z.SetZero()
zero := big.NewInt(0)
q := elementModulusBigInt()
// copy input
vv := new(big.Int).Set(v)
// while v < 0, v+=q
for vv.Cmp(zero) == -1 {
vv.Add(vv, q)
}
// while v > q, v-=q
for vv.Cmp(q) == 1 {
vv.Sub(vv, q)
}
// if v == q, return 0
if vv.Cmp(q) == 0 {
return z
}
// v should
vBits := vv.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 *Element) SetString(s string) *Element {
x, ok := new(big.Int).SetString(s, 10)
if !ok {
panic("Element.SetString failed -> can't parse number in base10 into a big.Int")
}
return z.SetBigInt(x)
}
// Mul z = x * y mod q
func (z *Element) Mul(x, y *Element) *Element {
var t [4]uint64
var c [3]uint64
{
// round 0
v := x[0]
c[1], c[0] = bits.Mul64(v, y[0])
m := c[0] * 14042775128853446655
c[2] = madd0(m, 4891460686036598785, c[0])
c[1], c[0] = madd1(v, y[1], c[1])
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
c[1], c[0] = madd1(v, y[2], c[1])
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
c[1], c[0] = madd1(v, y[3], c[1])
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
}
{
// round 1
v := x[1]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 14042775128853446655
c[2] = madd0(m, 4891460686036598785, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
}
{
// round 2
v := x[2]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 14042775128853446655
c[2] = madd0(m, 4891460686036598785, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
}
{
// round 3
v := x[3]
c[1], c[0] = madd1(v, y[0], t[0])
m := c[0] * 14042775128853446655
c[2] = madd0(m, 4891460686036598785, c[0])
c[1], c[0] = madd2(v, y[1], c[1], t[1])
c[2], z[0] = madd2(m, 2896914383306846353, c[2], c[0])
c[1], c[0] = madd2(v, y[2], c[1], t[2])
c[2], z[1] = madd2(m, 13281191951274694749, c[2], c[0])
c[1], c[0] = madd2(v, y[3], c[1], t[3])
z[3], z[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
}
// if z > q --> z -= q
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
}
return z
}
// MulAssign z = z * x mod q
func (z *Element) MulAssign(x *Element) *Element {
var t [4]uint64
var c [3]uint64
{
// round 0
v := z[0]
c[1], c[0] = bits.Mul64(v, x[0])
m := c[0] * 14042775128853446655
c[2] = madd0(m, 4891460686036598785, c[0])
c[1], c[0] = madd1(v, x[1], c[1])
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
c[1], c[0] = madd1(v, x[2], c[1])
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
c[1], c[0] = madd1(v, x[3], c[1])
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
}
{
// round 1
v := z[1]
c[1], c[0] = madd1(v, x[0], t[0])
m := c[0] * 14042775128853446655
c[2] = madd0(m, 4891460686036598785, c[0])
c[1], c[0] = madd2(v, x[1], c[1], t[1])
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
c[1], c[0] = madd2(v, x[2], c[1], t[2])
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
c[1], c[0] = madd2(v, x[3], c[1], t[3])
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
}
{
// round 2
v := z[2]
c[1], c[0] = madd1(v, x[0], t[0])
m := c[0] * 14042775128853446655
c[2] = madd0(m, 4891460686036598785, c[0])
c[1], c[0] = madd2(v, x[1], c[1], t[1])
c[2], t[0] = madd2(m, 2896914383306846353, c[2], c[0])
c[1], c[0] = madd2(v, x[2], c[1], t[2])
c[2], t[1] = madd2(m, 13281191951274694749, c[2], c[0])
c[1], c[0] = madd2(v, x[3], c[1], t[3])
t[3], t[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
}
{
// round 3
v := z[3]
c[1], c[0] = madd1(v, x[0], t[0])
m := c[0] * 14042775128853446655
c[2] = madd0(m, 4891460686036598785, c[0])
c[1], c[0] = madd2(v, x[1], c[1], t[1])
c[2], z[0] = madd2(m, 2896914383306846353, c[2], c[0])
c[1], c[0] = madd2(v, x[2], c[1], t[2])
c[2], z[1] = madd2(m, 13281191951274694749, c[2], c[0])
c[1], c[0] = madd2(v, x[3], c[1], t[3])
z[3], z[2] = madd3(m, 3486998266802970665, c[0], c[2], c[1])
}
// if z > q --> z -= q
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
}
return z
}
// Square z = x * x mod q
func (z *Element) Square(x *Element) *Element {
var p [4]uint64
var u, v uint64
{
// round 0
u, p[0] = bits.Mul64(x[0], x[0])
m := p[0] * 14042775128853446655
C := madd0(m, 4891460686036598785, p[0])
var t uint64
t, u, v = madd1sb(x[0], x[1], u)
C, p[0] = madd2(m, 2896914383306846353, v, C)
t, u, v = madd1s(x[0], x[2], t, u)
C, p[1] = madd2(m, 13281191951274694749, v, C)
_, u, v = madd1s(x[0], x[3], t, u)
p[3], p[2] = madd3(m, 3486998266802970665, v, C, u)
}
{
// round 1
m := p[0] * 14042775128853446655
C := madd0(m, 4891460686036598785, p[0])
u, v = madd1(x[1], x[1], p[1])
C, p[0] = madd2(m, 2896914383306846353, v, C)
var t uint64
t, u, v = madd2sb(x[1], x[2], p[2], u)
C, p[1] = madd2(m, 13281191951274694749, v, C)
_, u, v = madd2s(x[1], x[3], p[3], t, u)
p[3], p[2] = madd3(m, 3486998266802970665, v, C, u)
}
{
// round 2
m := p[0] * 14042775128853446655
C := madd0(m, 4891460686036598785, p[0])
C, p[0] = madd2(m, 2896914383306846353, p[1], C)
u, v = madd1(x[2], x[2], p[2])
C, p[1] = madd2(m, 13281191951274694749, v, C)
_, u, v = madd2sb(x[2], x[3], p[3], u)
p[3], p[2] = madd3(m, 3486998266802970665, v, C, u)
}
{
// round 3
m := p[0] * 14042775128853446655
C := madd0(m, 4891460686036598785, p[0])
C, z[0] = madd2(m, 2896914383306846353, p[1], C)
C, z[1] = madd2(m, 13281191951274694749, p[2], C)
u, v = madd1(x[3], x[3], p[3])
z[3], z[2] = madd3(m, 3486998266802970665, v, C, u)
}
// if z > q --> z -= q
if !(z[3] < 3486998266802970665 || (z[3] == 3486998266802970665 && (z[2] < 13281191951274694749 || (z[2] == 13281191951274694749 && (z[1] < 2896914383306846353 || (z[1] == 2896914383306846353 && (z[0] < 4891460686036598785))))))) {
var b uint64
z[0], b = bits.Sub64(z[0], 4891460686036598785, 0)
z[1], b = bits.Sub64(z[1], 2896914383306846353, b)
z[2], b = bits.Sub64(z[2], 13281191951274694749, b)
z[3], _ = bits.Sub64(z[3], 3486998266802970665, b)
}
return z
}

234
ff/element_test.go Normal file
View File

@@ -0,0 +1,234 @@
// Code generated by goff DO NOT EDIT
package ff
import (
"crypto/rand"
"math/big"
mrand "math/rand"
"testing"
)
func TestELEMENTCorrectnessAgainstBigInt(t *testing.T) {
modulus, _ := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
cmpEandB := func(e *Element, b *big.Int, name string) {
var _e big.Int
if e.FromMont().ToBigInt(&_e).Cmp(b) != 0 {
t.Fatal(name, "failed")
}
}
var modulusMinusOne, one big.Int
one.SetUint64(1)
modulusMinusOne.Sub(modulus, &one)
for i := 0; i < 1000; i++ {
// sample 2 random big int
b1, _ := rand.Int(rand.Reader, modulus)
b2, _ := rand.Int(rand.Reader, modulus)
rExp := mrand.Uint64()
// adding edge cases
// TODO need more edge cases
switch i {
case 0:
rExp = 0
b1.SetUint64(0)
case 1:
b2.SetUint64(0)
case 2:
b1.SetUint64(0)
b2.SetUint64(0)
case 3:
rExp = 0
case 4:
rExp = 1
case 5:
rExp = ^uint64(0) // max uint
case 6:
rExp = 2
b1.Set(&modulusMinusOne)
case 7:
b2.Set(&modulusMinusOne)
case 8:
b1.Set(&modulusMinusOne)
b2.Set(&modulusMinusOne)
}
rbExp := new(big.Int).SetUint64(rExp)
var bMul, bAdd, bSub, bDiv, bNeg, bLsh, bInv, bExp, bSquare big.Int
// e1 = mont(b1), e2 = mont(b2)
var e1, e2, eMul, eAdd, eSub, eDiv, eNeg, eLsh, eInv, eExp, eSquare, eMulAssign, eSubAssign, eAddAssign Element
e1.SetBigInt(b1)
e2.SetBigInt(b2)
// (e1*e2).FromMont() === b1*b2 mod q ... etc
eSquare.Square(&e1)
eMul.Mul(&e1, &e2)
eMulAssign.Set(&e1)
eMulAssign.MulAssign(&e2)
eAdd.Add(&e1, &e2)
eAddAssign.Set(&e1)
eAddAssign.AddAssign(&e2)
eSub.Sub(&e1, &e2)
eSubAssign.Set(&e1)
eSubAssign.SubAssign(&e2)
eDiv.Div(&e1, &e2)
eNeg.Neg(&e1)
eInv.Inverse(&e1)
eExp.Exp(e1, rExp)
eLsh.Double(&e1)
// same operations with big int
bAdd.Add(b1, b2).Mod(&bAdd, modulus)
bMul.Mul(b1, b2).Mod(&bMul, modulus)
bSquare.Mul(b1, b1).Mod(&bSquare, modulus)
bSub.Sub(b1, b2).Mod(&bSub, modulus)
bDiv.ModInverse(b2, modulus)
bDiv.Mul(&bDiv, b1).
Mod(&bDiv, modulus)
bNeg.Neg(b1).Mod(&bNeg, modulus)
bInv.ModInverse(b1, modulus)
bExp.Exp(b1, rbExp, modulus)
bLsh.Lsh(b1, 1).Mod(&bLsh, modulus)
cmpEandB(&eSquare, &bSquare, "Square")
cmpEandB(&eMul, &bMul, "Mul")
cmpEandB(&eMulAssign, &bMul, "MulAssign")
cmpEandB(&eAdd, &bAdd, "Add")
cmpEandB(&eAddAssign, &bAdd, "AddAssign")
cmpEandB(&eSub, &bSub, "Sub")
cmpEandB(&eSubAssign, &bSub, "SubAssign")
cmpEandB(&eDiv, &bDiv, "Div")
cmpEandB(&eNeg, &bNeg, "Neg")
cmpEandB(&eInv, &bInv, "Inv")
cmpEandB(&eExp, &bExp, "Exp")
cmpEandB(&eLsh, &bLsh, "Lsh")
}
}
func TestELEMENTIsRandom(t *testing.T) {
for i := 0; i < 1000; i++ {
var x, y Element
x.SetRandom()
y.SetRandom()
if x.Equal(&y) {
t.Fatal("2 random numbers are unlikely to be equal")
}
}
}
// -------------------------------------------------------------------------------------------------
// 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
// TODO: clean up and push benchmarking branch
var benchResElement Element
func BenchmarkInverseELEMENT(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Inverse(&x)
}
}
func BenchmarkExpELEMENT(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Exp(x, mrand.Uint64())
}
}
func BenchmarkDoubleELEMENT(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Double(&benchResElement)
}
}
func BenchmarkAddELEMENT(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Add(&x, &benchResElement)
}
}
func BenchmarkSubELEMENT(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Sub(&x, &benchResElement)
}
}
func BenchmarkNegELEMENT(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Neg(&benchResElement)
}
}
func BenchmarkDivELEMENT(b *testing.B) {
var x Element
x.SetRandom()
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Div(&x, &benchResElement)
}
}
func BenchmarkFromMontELEMENT(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.FromMont()
}
}
func BenchmarkToMontELEMENT(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.ToMont()
}
}
func BenchmarkSquareELEMENT(b *testing.B) {
benchResElement.SetRandom()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.Square(&benchResElement)
}
}
func BenchmarkMulAssignELEMENT(b *testing.B) {
x := Element{
1997599621687373223,
6052339484930628067,
10108755138030829701,
150537098327114917,
}
benchResElement.SetOne()
b.ResetTimer()
for i := 0; i < b.N; i++ {
benchResElement.MulAssign(&x)
}
}

6
ff/util.go Normal file
View File

@@ -0,0 +1,6 @@
package ff
// NewElement returns a new empty *Element
func NewElement() *Element {
return &Element{}
}

View File

@@ -1,152 +0,0 @@
// code originally taken from https://github.com/arnaucube/go-snark (https://github.com/arnaucube/go-snark/blob/master/fields/fq.go), pasted here to ensure compatibility among future changes
package field
import (
"bytes"
"crypto/rand"
"math/big"
)
// Fq is the Z field over modulus Q
type Fq struct {
Q *big.Int // Q
}
// NewFq generates a new Fq
func NewFq(q *big.Int) Fq {
return Fq{
q,
}
}
// Zero returns a Zero value on the Fq
func (fq Fq) Zero() *big.Int {
return big.NewInt(int64(0))
}
// One returns a One value on the Fq
func (fq Fq) One() *big.Int {
return big.NewInt(int64(1))
}
// Add performs an addition on the Fq
func (fq Fq) Add(a, b *big.Int) *big.Int {
r := new(big.Int).Add(a, b)
return new(big.Int).Mod(r, fq.Q)
}
// Double performs a doubling on the Fq
func (fq Fq) Double(a *big.Int) *big.Int {
r := new(big.Int).Add(a, a)
return new(big.Int).Mod(r, fq.Q)
}
// Sub performs a subtraction on the Fq
func (fq Fq) Sub(a, b *big.Int) *big.Int {
r := new(big.Int).Sub(a, b)
return new(big.Int).Mod(r, fq.Q)
}
// Neg performs a negation on the Fq
func (fq Fq) Neg(a *big.Int) *big.Int {
m := new(big.Int).Neg(a)
return new(big.Int).Mod(m, fq.Q)
}
// Mul performs a multiplication on the Fq
func (fq Fq) Mul(a, b *big.Int) *big.Int {
m := new(big.Int).Mul(a, b)
return new(big.Int).Mod(m, fq.Q)
}
func (fq Fq) MulScalar(base, e *big.Int) *big.Int {
return fq.Mul(base, e)
}
// Inverse returns the inverse on the Fq
func (fq Fq) Inverse(a *big.Int) *big.Int {
return new(big.Int).ModInverse(a, fq.Q)
}
// Div performs the division over the finite field
func (fq Fq) Div(a, b *big.Int) *big.Int {
d := fq.Mul(a, fq.Inverse(b))
return new(big.Int).Mod(d, fq.Q)
}
// Square performs a square operation on the Fq
func (fq Fq) Square(a *big.Int) *big.Int {
m := new(big.Int).Mul(a, a)
return new(big.Int).Mod(m, fq.Q)
}
// Exp performs the exponential over Fq
func (fq Fq) Exp(base *big.Int, e *big.Int) *big.Int {
res := fq.One()
rem := fq.Copy(e)
exp := base
for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
if BigIsOdd(rem) {
res = fq.Mul(res, exp)
}
exp = fq.Square(exp)
rem = new(big.Int).Rsh(rem, 1)
}
return res
}
func (fq Fq) Rand() (*big.Int, error) {
maxbits := fq.Q.BitLen()
b := make([]byte, (maxbits/8)-1)
_, err := rand.Read(b)
if err != nil {
return nil, err
}
r := new(big.Int).SetBytes(b)
rq := new(big.Int).Mod(r, fq.Q)
// r over q, nil
return rq, nil
}
func (fq Fq) IsZero(a *big.Int) bool {
return bytes.Equal(a.Bytes(), fq.Zero().Bytes())
}
func (fq Fq) Copy(a *big.Int) *big.Int {
return new(big.Int).SetBytes(a.Bytes())
}
func (fq Fq) Affine(a *big.Int) *big.Int {
nq := fq.Neg(fq.Q)
aux := a
if aux.Cmp(big.NewInt(int64(0))) == -1 { // negative value
if aux.Cmp(nq) != 1 { // aux less or equal nq
aux = new(big.Int).Mod(aux, fq.Q)
}
if aux.Cmp(big.NewInt(int64(0))) == -1 { // negative value
aux = new(big.Int).Add(aux, fq.Q)
}
} else {
if aux.Cmp(fq.Q) != -1 { // aux greater or equal nq
aux = new(big.Int).Mod(aux, fq.Q)
}
}
return aux
}
func (fq Fq) Equal(a, b *big.Int) bool {
aAff := fq.Affine(a)
bAff := fq.Affine(b)
return bytes.Equal(aAff.Bytes(), bAff.Bytes())
}
func BigIsOdd(n *big.Int) bool {
one := big.NewInt(int64(1))
and := new(big.Int).And(n, one)
return bytes.Equal(and.Bytes(), big.NewInt(int64(1)).Bytes())
}

View File

@@ -1,39 +0,0 @@
// code originally taken from https://github.com/arnaucube/go-snark (https://github.com/arnaucube/go-snark/blob/master/fields/fq.go), pasted here to ensure compatibility among future changes
package field
import (
"math/big"
"testing"
"github.com/stretchr/testify/assert"
)
func iToBig(a int) *big.Int {
return big.NewInt(int64(a))
}
func TestFq1(t *testing.T) {
fq1 := NewFq(iToBig(7))
res := fq1.Add(iToBig(4), iToBig(4))
assert.Equal(t, iToBig(1), fq1.Affine(res))
res = fq1.Double(iToBig(5))
assert.Equal(t, iToBig(3), fq1.Affine(res))
res = fq1.Sub(iToBig(5), iToBig(7))
assert.Equal(t, iToBig(5), fq1.Affine(res))
res = fq1.Neg(iToBig(5))
assert.Equal(t, iToBig(2), fq1.Affine(res))
res = fq1.Mul(iToBig(5), iToBig(11))
assert.Equal(t, iToBig(6), fq1.Affine(res))
res = fq1.Inverse(iToBig(4))
assert.Equal(t, iToBig(2), res)
res = fq1.Square(iToBig(5))
assert.Equal(t, iToBig(4), res)
}

7
go.mod
View File

@@ -4,7 +4,8 @@ go 1.12
require ( require (
github.com/dchest/blake512 v1.0.0 github.com/dchest/blake512 v1.0.0
github.com/ethereum/go-ethereum v1.8.27 github.com/ethereum/go-ethereum v1.9.12
github.com/stretchr/testify v1.3.0 github.com/stretchr/testify v1.4.0
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd // indirect
) )

163
go.sum
View File

@@ -1,20 +1,173 @@
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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/OneOfOne/xxhash v1.2.5/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 h1:fLjPD/aNc3UIOA6tDi6QXUemppXK3P9BI7mr2hd6gx8=
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/VictoriaMetrics/fastcache v1.5.3 h1:2odJnXLbFZcoV9KYtQ+7TH1UOq3dn3AssMgieaezkR4=
github.com/VictoriaMetrics/fastcache v1.5.3/go.mod h1:+jv9Ckb+za/P1ZRg/sulP5Ni1v49daAVERr0H3CuscE=
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 h1:rtI0fD4oG/8eVokGVPYJEW1F88p1ZNgXiEIs9thEE4A=
github.com/aristanetworks/goarista v0.0.0-20170210015632-ea17b1a17847/go.mod h1:D/tb0zPVXnP7fmsLZjtdUhSsumbK/ij54UXjjVgMGxQ=
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/btcsuite/btcd v0.0.0-20171128150713-2e60448ffcc6 h1:Eey/GGQ/E5Xp1P2Lyx1qj007hLZfbi0+CoVeJruGCtI=
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 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.0.1-0.20190104013014-3767db7a7e18/go.mod h1:HD5P3vAIAh+Y2GAxg0PrPN1P8WkepXGpjbUPDHJqqKM=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudflare/cloudflare-go v0.10.2-0.20190916151808-a80f83b9add9/go.mod h1:1MxXX1Ux4x6mqPmjkUgTP1CdXIBXKX7T+Jk9Gxrmx+U=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/dchest/blake512 v1.0.0 h1:oDFEQFIqFSeuA34xLtXZ/rWxCXdSjirjzPhey5EUvmA= github.com/dchest/blake512 v1.0.0 h1:oDFEQFIqFSeuA34xLtXZ/rWxCXdSjirjzPhey5EUvmA=
github.com/dchest/blake512 v1.0.0/go.mod h1:FV1x7xPPLWukZlpDpWQ88rF/SFwZ5qbskrzhLMB92JI= github.com/dchest/blake512 v1.0.0/go.mod h1:FV1x7xPPLWukZlpDpWQ88rF/SFwZ5qbskrzhLMB92JI=
github.com/ethereum/go-ethereum v1.8.27 h1:d+gkiLaBDk5fn3Pe/xNVaMrB/ozI+AUB2IlVBp29IrY= github.com/deckarep/golang-set v0.0.0-20180603214616-504e848d77ea/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/ethereum/go-ethereum v1.8.27/go.mod h1:PwpWDrCLZrV+tfrhqqF6kPknbISMHaJv9Ln3kPCZLwY= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/iden3/go-iden3 v0.0.5 h1:NV6HXnLmp+1YmKd2FmymzU6OAP77q1WWDcB/B+BUL9g= 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-20200219165308-d1232e640a87/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
github.com/edsrzf/mmap-go v0.0.0-20160512033002-935e0e8a636c/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa h1:XKAhUk/dtp+CV0VO6mhG2V7jA9vbcGcnYF/Ay9NjZrY=
github.com/elastic/gosigar v0.8.1-0.20180330100440-37f05ff46ffa/go.mod h1:cdorVVzy1fhmEqmtgqkoE3bYtCfSCkVyjTyCIo22xvs=
github.com/ethereum/go-ethereum v1.9.12 h1:EPtimwsp/KGDSiXcNunzsI4kefdsMHZGJntKx3fvbaI=
github.com/ethereum/go-ethereum v1.9.12/go.mod h1:PvsVkQmhZFx92Y+h2ylythYlheEDt/uBgFbl61Js/jo=
github.com/fatih/color v1.3.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/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff/go.mod h1:x7DCsMOv1taUwEWCzT4cmDeAkigA5/QCwUodaVOe8Ww=
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-ole/go-ole v1.2.1 h1:2lOsA72HgjxAuMlKpFiCbHTvu44PIVkZ5hqm3RSdI/E=
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 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
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/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2-0.20190517061210-b285ee9cfc6c/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/gorilla/websocket v1.4.1-0.20190629185528-ae1634f6a989/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/graph-gophers/graphql-go v0.0.0-20191115155744-f33e81362277/go.mod h1:9CQHMSxwO4MprSdzoIEobiHpoLtHm77vfxsvsIN5Vuc=
github.com/hashicorp/golang-lru v0.0.0-20160813221303-0a025b7e63ad/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v0.0.0-20161224104101-679507af18f3/go.mod h1:MZ2ZmwcBpvOoJ22IJsc7va19ZwoheaBk43rKg12SKag=
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/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/julienschmidt/httprouter v1.1.1-0.20170430222011-975b5c4c7c21/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karalabe/usb v0.0.0-20190919080040-51dc0efba356/go.mod h1:Od972xHfMJowv7NGVDiWVxk2zxnWgjLlJzE+F4F7AGU=
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/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.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/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/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.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/pborman/uuid v0.0.0-20170112150404-1b00554d8222/go.mod h1:VyrYX9gd7irzKovcSS6BIIEwPRkP2Wm2m9ufcdFSJ34=
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 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/tsdb v0.6.2-0.20190402121629-4f204dcbc150/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rjeczalik/notify v0.9.1/go.mod h1:rKwnCoCGeuQnwBtTSPL9Dad03Vh2n40ePRrjvIXnJho=
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/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spaolacci/murmur3 v1.0.1-0.20190317074736-539464a789e9/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
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 h1:gIlAHnH1vJb5vwEjIp5kBj/eu99p/bl0Ay2goiPe5xE=
github.com/steakknife/bloomfilter v0.0.0-20180922174646-6819c0d2a570/go.mod h1:8OR4w3TdeIHIh1g6EMY5p0gVNOovcWC+1vpc7naMuAw=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3 h1:njlZPzLwU639dk2kqnCPPv+wNjq7Xb6EfUxe/oX0/NM=
github.com/steakknife/hamming v0.0.0-20180906055917-c99c65617cd3/go.mod h1:hpGUWaI9xL8pRQCTXQgocU38Qw1g0Us7n5PxxTwTCYU=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/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 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 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/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
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=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A= golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4 h1:QmwruyY+bKbDDL0BaglrbZABEali68eoMFhTZpCjYVA=
golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200311171314-f7b00557c8c4/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
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/sys v0.0.0-20180909124046-d0be0721c37e/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-20190215142949-d0b11bdaac8a/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-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
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-20190213234257-ec84240a7772/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
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.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=

View File

@@ -6,82 +6,84 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
_constants "github.com/iden3/go-iden3-crypto/constants" _constants "github.com/iden3/go-iden3-crypto/constants"
"github.com/iden3/go-iden3-crypto/field" "github.com/iden3/go-iden3-crypto/ff"
"github.com/iden3/go-iden3-crypto/utils" "github.com/iden3/go-iden3-crypto/utils"
) )
// SEED defines the seed used to constants
const SEED = "mimc" const SEED = "mimc"
var constants = generateConstantsData() var constants = generateConstantsData()
type constantsData struct { type constantsData struct {
maxFieldVal *big.Int seedHash *big.Int
seedHash *big.Int iv *big.Int
iv *big.Int nRounds int
fqR field.Fq cts []*ff.Element
nRounds int
cts []*big.Int
} }
func generateConstantsData() constantsData { func generateConstantsData() constantsData {
var constants constantsData var constants constantsData
fqR := field.NewFq(_constants.Q)
constants.fqR = fqR
// maxFieldVal is the R value of the Finite Field
constants.maxFieldVal = constants.fqR.Q
constants.seedHash = new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED))) constants.seedHash = new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED + "_iv"))) c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED + "_iv")))
constants.iv = new(big.Int).Mod(c, constants.maxFieldVal) constants.iv = new(big.Int).Mod(c, _constants.Q)
constants.nRounds = 91 constants.nRounds = 91
cts := getConstants(constants.fqR, SEED, constants.nRounds) cts := getConstants(SEED, constants.nRounds)
constants.cts = cts constants.cts = cts
return constants return constants
} }
func getConstants(fqR field.Fq, seed string, nRounds int) []*big.Int { func getConstants(seed string, nRounds int) []*ff.Element {
cts := make([]*big.Int, nRounds) cts := make([]*ff.Element, nRounds)
cts[0] = big.NewInt(int64(0)) cts[0] = ff.NewElement()
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED))) c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
for i := 1; i < nRounds; i++ { for i := 1; i < nRounds; i++ {
c = new(big.Int).SetBytes(crypto.Keccak256(c.Bytes())) c = new(big.Int).SetBytes(crypto.Keccak256(c.Bytes()))
n := fqR.Affine(c) n := new(big.Int).Mod(c, _constants.Q)
cts[i] = n cts[i] = ff.NewElement().SetBigInt(n)
} }
return cts return cts
} }
// MIMC7HashGeneric performs the MIMC7 hash over a *big.Int, in a generic way, where it can be specified the Finite Field over R, and the number of rounds // MIMC7HashGeneric performs the MIMC7 hash over a *big.Int, in a generic way,
func MIMC7HashGeneric(fqR field.Fq, xIn, k *big.Int, nRounds int) *big.Int { // where it can be specified the Finite Field over R, and the number of rounds
cts := getConstants(fqR, SEED, nRounds) func MIMC7HashGeneric(xInBI, kBI *big.Int, nRounds int) *big.Int { //nolint:golint
var r *big.Int xIn := ff.NewElement().SetBigInt(xInBI)
k := ff.NewElement().SetBigInt(kBI)
cts := getConstants(SEED, nRounds)
var r *ff.Element
for i := 0; i < nRounds; i++ { for i := 0; i < nRounds; i++ {
var t *big.Int var t *ff.Element
if i == 0 { if i == 0 {
t = fqR.Add(xIn, k) t = ff.NewElement().Add(xIn, k)
} else { } else {
t = fqR.Add(fqR.Add(r, k), cts[i]) t = ff.NewElement().Add(ff.NewElement().Add(r, k), cts[i])
} }
t2 := fqR.Square(t) t2 := ff.NewElement().Square(t)
t4 := fqR.Square(t2) t4 := ff.NewElement().Square(t2)
r = fqR.Mul(fqR.Mul(t4, t2), t) r = ff.NewElement().Mul(ff.NewElement().Mul(t4, t2), t)
} }
return fqR.Affine(fqR.Add(r, k)) rE := ff.NewElement().Add(r, k)
res := big.NewInt(0)
rE.ToBigIntRegular(res)
return res
} }
// HashGeneric performs the MIMC7 hash over a *big.Int array, in a generic way, where it can be specified the Finite Field over R, and the number of rounds // HashGeneric performs the MIMC7 hash over a *big.Int array, in a generic way,
func HashGeneric(iv *big.Int, arr []*big.Int, fqR field.Fq, nRounds int) (*big.Int, error) { // where it can be specified the Finite Field over R, and the number of rounds
if !utils.CheckBigIntArrayInField(arr, constants.fqR.Q) { func HashGeneric(iv *big.Int, arr []*big.Int, nRounds int) (*big.Int, error) {
if !utils.CheckBigIntArrayInField(arr) {
return nil, errors.New("inputs values not inside Finite Field") return nil, errors.New("inputs values not inside Finite Field")
} }
r := iv r := iv
var err error var err error
for i := 0; i < len(arr); i++ { for i := 0; i < len(arr); i++ {
r = MIMC7HashGeneric(fqR, r, arr[i], nRounds) r = MIMC7HashGeneric(r, arr[i], nRounds)
if err != nil { if err != nil {
return r, err return r, err
} }
@@ -89,41 +91,72 @@ func HashGeneric(iv *big.Int, arr []*big.Int, fqR field.Fq, nRounds int) (*big.I
return r, nil return r, nil
} }
// MIMC7Hash performs the MIMC7 hash over a *big.Int, using the Finite Field over R and the number of rounds setted in the `constants` variable // MIMC7Hash performs the MIMC7 hash over a *big.Int, using the Finite Field
func MIMC7Hash(xIn, k *big.Int) *big.Int { // over R and the number of rounds setted in the `constants` variable
var r *big.Int func MIMC7Hash(xInBI, kBI *big.Int) *big.Int { //nolint:golint
xIn := ff.NewElement().SetBigInt(xInBI)
k := ff.NewElement().SetBigInt(kBI)
var r *ff.Element
for i := 0; i < constants.nRounds; i++ { for i := 0; i < constants.nRounds; i++ {
var t *big.Int var t *ff.Element
if i == 0 { if i == 0 {
t = constants.fqR.Add(xIn, k) t = ff.NewElement().Add(xIn, k)
} else { } else {
t = constants.fqR.Add(constants.fqR.Add(r, k), constants.cts[i]) t = ff.NewElement().Add(ff.NewElement().Add(r, k), constants.cts[i])
} }
t2 := constants.fqR.Square(t) t2 := ff.NewElement().Square(t)
t4 := constants.fqR.Square(t2) t4 := ff.NewElement().Square(t2)
r = constants.fqR.Mul(constants.fqR.Mul(t4, t2), t) r = ff.NewElement().Mul(ff.NewElement().Mul(t4, t2), t)
} }
return constants.fqR.Affine(constants.fqR.Add(r, k)) rE := ff.NewElement().Add(r, k)
res := big.NewInt(0)
rE.ToBigIntRegular(res)
return res
} }
// Hash performs the MIMC7 hash over a *big.Int array // Hash performs the MIMC7 hash over a *big.Int array
func Hash(arr []*big.Int, key *big.Int) (*big.Int, error) { func Hash(arr []*big.Int, key *big.Int) (*big.Int, error) {
if !utils.CheckBigIntArrayInField(arr, constants.fqR.Q) { if !utils.CheckBigIntArrayInField(arr) {
return nil, errors.New("inputs values not inside Finite Field") return nil, errors.New("inputs values not inside Finite Field")
} }
var r *big.Int var r *big.Int
if key == nil { if key == nil {
r = constants.fqR.Zero() r = big.NewInt(0)
} else { } else {
r = key r = key
} }
for i := 0; i < len(arr); i++ { for i := 0; i < len(arr); i++ {
r = constants.fqR.Add( r = new(big.Int).Add(
constants.fqR.Add( new(big.Int).Add(
r, r,
arr[i], arr[i],
), ),
MIMC7Hash(arr[i], r)) MIMC7Hash(arr[i], r))
r = new(big.Int).Mod(r, _constants.Q)
} }
return r, nil return r, nil
} }
// HashBytes hashes a msg byte slice by blocks of 31 bytes encoded as
// little-endian
func HashBytes(b []byte) *big.Int {
n := 31
bElems := make([]*big.Int, 0, len(b)/n+1)
for i := 0; i < len(b)/n; i++ {
v := new(big.Int)
utils.SetBigIntFromLEBytes(v, b[n*i:n*(i+1)])
bElems = append(bElems, v)
}
if len(b)%n != 0 {
v := new(big.Int)
utils.SetBigIntFromLEBytes(v, b[(len(b)/n)*n:])
bElems = append(bElems, v)
}
h, err := Hash(bElems, nil)
if err != nil {
panic(err)
}
return h
}

View File

@@ -6,15 +6,18 @@ import (
"testing" "testing"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/iden3/go-iden3-crypto/field"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestKeccak256(t *testing.T) { func TestKeccak256(t *testing.T) {
res := crypto.Keccak256([]byte(SEED)) res := crypto.Keccak256([]byte(SEED))
assert.Equal(t, "b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e", hex.EncodeToString(res)) assert.Equal(t,
"b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e",
hex.EncodeToString(res))
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED))) c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
assert.Equal(t, "82724731331859054037315113496710413141112897654334566532528783843265082629790", c.String()) assert.Equal(t,
"82724731331859054037315113496710413141112897654334566532528783843265082629790",
c.String())
} }
func TestMIMC7Generic(t *testing.T) { func TestMIMC7Generic(t *testing.T) {
@@ -22,18 +25,18 @@ func TestMIMC7Generic(t *testing.T) {
b2 := big.NewInt(int64(2)) b2 := big.NewInt(int64(2))
b3 := big.NewInt(int64(3)) b3 := big.NewInt(int64(3))
r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
assert.True(t, ok)
fqR := field.NewFq(r)
bigArray := []*big.Int{b1, b2, b3} bigArray := []*big.Int{b1, b2, b3}
// Generic Hash // Generic Hash
mhg := MIMC7HashGeneric(fqR, b1, b2, 91) mhg := MIMC7HashGeneric(b1, b2, 91)
assert.Equal(t, "10594780656576967754230020536574539122676596303354946869887184401991294982664", mhg.String()) assert.Equal(t,
hg, err := HashGeneric(fqR.Zero(), bigArray, fqR, 91) "10594780656576967754230020536574539122676596303354946869887184401991294982664",
mhg.String())
hg, err := HashGeneric(big.NewInt(0), bigArray, 91)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "6464402164086696096195815557694604139393321133243036833927490113253119343397", (*big.Int)(hg).String()) assert.Equal(t,
"6464402164086696096195815557694604139393321133243036833927490113253119343397",
(*big.Int)(hg).String())
} }
func TestMIMC7(t *testing.T) { func TestMIMC7(t *testing.T) {
@@ -48,7 +51,8 @@ func TestMIMC7(t *testing.T) {
h1, err := Hash(bigArray1, nil) h1, err := Hash(bigArray1, nil)
assert.Nil(t, err) assert.Nil(t, err)
// same hash value than the iden3js and circomlib tests: // same hash value than the iden3js and circomlib tests:
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h1).Bytes()), "0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd") assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h1).Bytes()),
"0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd")
// h2a, hash of 2 elements // h2a, hash of 2 elements
bigArray2a := []*big.Int{b78, b41} bigArray2a := []*big.Int{b78, b41}
@@ -56,19 +60,22 @@ func TestMIMC7(t *testing.T) {
h2a, err := Hash(bigArray2a, nil) h2a, err := Hash(bigArray2a, nil)
assert.Nil(t, err) assert.Nil(t, err)
// same hash value than the iden3js and circomlib tests: // same hash value than the iden3js and circomlib tests:
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h2a).Bytes()), "0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70") assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h2a).Bytes()),
"0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70")
// h2b, hash of 2 elements // h2b, hash of 2 elements
bigArray2b := []*big.Int{b12, b45} bigArray2b := []*big.Int{b12, b45}
mh2b := MIMC7Hash(b12, b45) mh2b := MIMC7Hash(b12, b45)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(mh2b).Bytes()), "0x2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4") assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(mh2b).Bytes()),
"0x2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4")
h2b, err := Hash(bigArray2b, nil) h2b, err := Hash(bigArray2b, nil)
assert.Nil(t, err) assert.Nil(t, err)
// same hash value than the iden3js and circomlib tests: // same hash value than the iden3js and circomlib tests:
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h2b).Bytes()), "0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879") assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h2b).Bytes()),
"0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879")
// h4, hash of 4 elements // h4, hash of 4 elements
bigArray4 := []*big.Int{b12, b45, b78, b41} bigArray4 := []*big.Int{b12, b45, b78, b41}
@@ -76,7 +83,14 @@ func TestMIMC7(t *testing.T) {
h4, err := Hash(bigArray4, nil) h4, err := Hash(bigArray4, nil)
assert.Nil(t, err) assert.Nil(t, err)
// same hash value than the iden3js and circomlib tests: // same hash value than the iden3js and circomlib tests:
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h4).Bytes()), "0x284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb") assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h4).Bytes()),
"0x284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb")
msg := []byte("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") //nolint:lll
hmsg := HashBytes(msg)
assert.Equal(t,
"16855787120419064316734350414336285711017110414939748784029922801367685456065",
hmsg.String())
} }
func BenchmarkMIMC7(b *testing.B) { func BenchmarkMIMC7(b *testing.B) {
@@ -86,9 +100,7 @@ func BenchmarkMIMC7(b *testing.B) {
b41 := big.NewInt(int64(41)) b41 := big.NewInt(int64(41))
bigArray4 := []*big.Int{b12, b45, b78, b41} bigArray4 := []*big.Int{b12, b45, b78, b41}
var h4 *big.Int
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
h4, _ = Hash(bigArray4, nil) Hash(bigArray4, nil) //nolint:errcheck,gosec
} }
println(h4)
} }

3511
poseidon/constants.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,166 +1,89 @@
package poseidon package poseidon
import ( import (
"bytes"
"errors" "errors"
"fmt"
"math/big" "math/big"
"strconv"
_constants "github.com/iden3/go-iden3-crypto/constants" "github.com/iden3/go-iden3-crypto/ff"
"github.com/iden3/go-iden3-crypto/field"
"github.com/iden3/go-iden3-crypto/utils" "github.com/iden3/go-iden3-crypto/utils"
"golang.org/x/crypto/blake2b"
) )
const SEED = "poseidon" const NROUNDSF = 8 //nolint:golint
const NROUNDSF = 8
const NROUNDSP = 57
const T = 6
var constants = generateConstantsData() var NROUNDSP = []int{56, 57, 56, 60, 60, 63, 64, 63} //nolint:golint
type constantsData struct { func zero() *ff.Element {
fqR field.Fq return ff.NewElement()
c []*big.Int
m [][]*big.Int
}
func generateConstantsData() constantsData {
var constants constantsData
fqR := field.NewFq(_constants.Q)
constants.fqR = fqR
constants.c = getPseudoRandom(fqR, SEED+"_constants", NROUNDSF+NROUNDSP)
constants.m = getMDS(fqR)
return constants
}
func leByteArrayToBigInt(b []byte) *big.Int {
res := big.NewInt(0)
for i := 0; i < len(b); i++ {
n := big.NewInt(int64(b[i]))
res = new(big.Int).Add(res, new(big.Int).Lsh(n, uint(i*8)))
}
return res
}
func getPseudoRandom(fqR field.Fq, seed string, n int) []*big.Int {
var res []*big.Int
hash := blake2b.Sum256([]byte(seed))
for len(res) < n {
hashBigInt := new(big.Int)
newN := fqR.Affine(utils.SetBigIntFromLEBytes(hashBigInt, hash[:]))
// newN := fqR.Affine(leByteArrayToBigInt(hash[:]))
res = append(res, newN)
hash = blake2b.Sum256(hash[:])
}
return res
}
func nonceToString(n int) string {
r := strconv.Itoa(n)
for len(r) < 4 {
r = "0" + r
}
return r
}
// https://eprint.iacr.org/2019/458.pdf pag.8
func getMDS(fqR field.Fq) [][]*big.Int {
nonce := 0
cauchyMatrix := getPseudoRandom(fqR, SEED+"_matrix_"+nonceToString(nonce), T*2)
for !checkAllDifferent(cauchyMatrix) {
nonce += 1
cauchyMatrix = getPseudoRandom(fqR, SEED+"_matrix_"+nonceToString(nonce), T*2)
}
var m [][]*big.Int
for i := 0; i < T; i++ {
var mi []*big.Int
for j := 0; j < T; j++ {
mi = append(mi, fqR.Inverse(fqR.Sub(cauchyMatrix[i], cauchyMatrix[T+j])))
}
m = append(m, mi)
}
return m
}
func checkAllDifferent(v []*big.Int) bool {
for i := 0; i < len(v); i++ {
if bytes.Equal(v[i].Bytes(), big.NewInt(int64(0)).Bytes()) {
return false
}
for j := i + 1; j < len(v); j++ {
if bytes.Equal(v[i].Bytes(), v[j].Bytes()) {
return false
}
}
}
return true
} }
// ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf // ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
func ark(state []*big.Int, c *big.Int) []*big.Int { func ark(state []*ff.Element, c []*ff.Element, it int) {
for i := 0; i < len(state); i++ { for i := 0; i < len(state); i++ {
state[i] = constants.fqR.Add(state[i], c) state[i].Add(state[i], c[it+i])
} }
return state
} }
// cubic performs x^3 mod p // exp5 performs x^5 mod p
func cubic(a *big.Int) *big.Int { // https://eprint.iacr.org/2019/458.pdf page 8
return constants.fqR.Mul(a, constants.fqR.Square(constants.fqR.Square(a))) func exp5(a *ff.Element) {
a.Exp(*a, 5)
} }
// sbox https://eprint.iacr.org/2019/458.pdf pag.6 // sbox https://eprint.iacr.org/2019/458.pdf page 6
func sbox(state []*big.Int, i int) []*big.Int { func sbox(nRoundsF, nRoundsP int, state []*ff.Element, i int) {
if (i < NROUNDSF/2) || (i >= NROUNDSF/2+NROUNDSP) { if (i < nRoundsF/2) || (i >= nRoundsF/2+nRoundsP) {
for j := 0; j < T; j++ { for j := 0; j < len(state); j++ {
state[j] = cubic(state[j]) exp5(state[j])
} }
} else { } else {
state[0] = cubic(state[0]) exp5(state[0])
} }
return state
} }
// mix returns [[matrix]] * [vector] // mix returns [[matrix]] * [vector]
func mix(state []*big.Int, m [][]*big.Int) []*big.Int { func mix(state []*ff.Element, newState []*ff.Element, m [][]*ff.Element) {
var newState []*big.Int mul := zero()
for i := 0; i < len(state); i++ { for i := 0; i < len(state); i++ {
newState = append(newState, constants.fqR.Zero()) newState[i].SetUint64(0)
for j := 0; j < len(state); j++ { for j := 0; j < len(state); j++ {
newState[i] = constants.fqR.Add(newState[i], constants.fqR.Mul(m[i][j], state[j])) mul.Mul(m[i][j], state[j])
newState[i].Add(newState[i], mul)
} }
} }
for i := 0; i < len(state); i++ {
state[i] = newState[i]
}
return state
} }
// Hash computes the Poseidon hash for the given inputs // Hash computes the Poseidon hash for the given inputs
func Hash(inp []*big.Int) (*big.Int, error) { func Hash(inpBI []*big.Int) (*big.Int, error) {
var state []*big.Int t := len(inpBI) + 1
if len(inp) == 0 || len(inp) > T { if len(inpBI) == 0 || len(inpBI) >= len(NROUNDSP)-1 {
return nil, errors.New("wrong inputs length") return nil, fmt.Errorf("invalid inputs length %d, max %d", len(inpBI), len(NROUNDSP)-1)
} }
if !utils.CheckBigIntArrayInField(inp, constants.fqR.Q) { if !utils.CheckBigIntArrayInField(inpBI[:]) {
return nil, errors.New("inputs values not inside Finite Field") return nil, errors.New("inputs values not inside Finite Field")
} }
inp := utils.BigIntArrayToElementArray(inpBI[:])
state := make([]*ff.Element, t)
state[0] = zero()
copy(state[1:], inp[:])
for i := 0; i < len(inp); i++ { nRoundsF := NROUNDSF
state = append(state, inp[i]) nRoundsP := NROUNDSP[t-2]
}
for i := len(inp); i < T; i++ { newState := make([]*ff.Element, t)
state = append(state, constants.fqR.Zero()) for i := 0; i < t; i++ {
newState[i] = zero()
} }
// ARK --> SBox --> M, https://eprint.iacr.org/2019/458.pdf pag.5 // ARK --> SBox --> M, https://eprint.iacr.org/2019/458.pdf pag.5
for i := 0; i < NROUNDSF+NROUNDSP; i++ { for i := 0; i < nRoundsF+nRoundsP; i++ {
state = ark(state, constants.c[i]) ark(state, c.c[t-2], i*t)
state = sbox(state, i) sbox(nRoundsF, nRoundsP, state, i)
state = mix(state, constants.m) mix(state, newState, c.m[t-2])
state, newState = newState, state
} }
return state[0], nil rE := state[0]
r := big.NewInt(0)
rE.ToBigIntRegular(r)
return r, nil
} }

View File

@@ -5,25 +5,93 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/iden3/go-iden3-crypto/utils"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"golang.org/x/crypto/blake2b" "golang.org/x/crypto/blake2b"
) )
func TestBlake2bVersion(t *testing.T) { func TestBlake2bVersion(t *testing.T) {
h := blake2b.Sum256([]byte("poseidon_constants")) h := blake2b.Sum256([]byte("poseidon_constants"))
assert.Equal(t, "e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1", hex.EncodeToString(h[:])) assert.Equal(t,
"e57ba154fb2c47811dc1a2369b27e25a44915b4e4ece4eb8ec74850cb78e01b1",
hex.EncodeToString(h[:]))
} }
func TestPoseidon(t *testing.T) { func TestPoseidonHash(t *testing.T) {
b1 := big.NewInt(int64(1)) b0 := big.NewInt(0)
b2 := big.NewInt(int64(2)) b1 := big.NewInt(1)
h, err := Hash([]*big.Int{b1, b2}) b2 := big.NewInt(2)
assert.Nil(t, err)
assert.Equal(t, "12242166908188651009877250812424843524687801523336557272219921456462821518061", h.String())
b3 := big.NewInt(int64(3)) h, err := Hash([]*big.Int{b1})
b4 := big.NewInt(int64(4))
h, err = Hash([]*big.Int{b3, b4})
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "17185195740979599334254027721507328033796809509313949281114643312710535000993", h.String()) assert.Equal(t,
"18586133768512220936620570745912940619677854269274689475585506675881198879027",
h.String())
h, err = Hash([]*big.Int{b1, b2})
assert.Nil(t, err)
assert.Equal(t,
"7853200120776062878684798364095072458815029376092732009249414926327459813530",
h.String())
h, err = Hash([]*big.Int{b1, b2, b0, b0, b0})
assert.Nil(t, err)
assert.Equal(t,
"1018317224307729531995786483840663576608797660851238720571059489595066344487",
h.String())
h, err = Hash([]*big.Int{b1, b2, b0, b0, b0, b0})
assert.Nil(t, err)
assert.Equal(t,
"15336558801450556532856248569924170992202208561737609669134139141992924267169",
h.String())
b3 := big.NewInt(3)
b4 := big.NewInt(4)
h, err = Hash([]*big.Int{b3, b4, b0, b0, b0})
assert.Nil(t, err)
assert.Equal(t,
"5811595552068139067952687508729883632420015185677766880877743348592482390548",
h.String())
h, err = Hash([]*big.Int{b3, b4, b0, b0, b0, b0})
assert.Nil(t, err)
assert.Equal(t,
"12263118664590987767234828103155242843640892839966517009184493198782366909018",
h.String())
b5 := big.NewInt(5)
b6 := big.NewInt(6)
h, err = Hash([]*big.Int{b1, b2, b3, b4, b5, b6})
assert.Nil(t, err)
assert.Equal(t,
"20400040500897583745843009878988256314335038853985262692600694741116813247201",
h.String())
}
func TestErrorInputs(t *testing.T) {
b0 := big.NewInt(0)
b1 := big.NewInt(1)
b2 := big.NewInt(2)
_, err := Hash([]*big.Int{b1, b2, b0, b0, b0, b0})
assert.Nil(t, err)
_, err = Hash([]*big.Int{b1, b2, b0, b0, b0, b0, b0})
assert.NotNil(t, err)
assert.Equal(t, "invalid inputs length 7, max 7", err.Error())
_, err = Hash([]*big.Int{b1, b2, b0, b0, b0, b0, b0, b0})
assert.NotNil(t, err)
assert.Equal(t, "invalid inputs length 8, max 7", err.Error())
}
func BenchmarkPoseidonHash(b *testing.B) {
b0 := big.NewInt(0)
b1 := utils.NewIntFromString("12242166908188651009877250812424843524687801523336557272219921456462821518061") //nolint:lll
b2 := utils.NewIntFromString("12242166908188651009877250812424843524687801523336557272219921456462821518061") //nolint:lll
bigArray4 := []*big.Int{b1, b2, b0, b0, b0, b0}
for i := 0; i < b.N; i++ {
Hash(bigArray4) //nolint:errcheck,gosec
}
} }

View File

@@ -0,0 +1,11 @@
package utils
import (
"fmt"
"math/bits"
"testing"
)
func TestShowArchBits(t *testing.T) {
fmt.Printf("Architecture is %v bits\n", bits.UintSize)
}

View File

@@ -6,6 +6,9 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"strings" "strings"
"github.com/iden3/go-iden3-crypto/constants"
"github.com/iden3/go-iden3-crypto/ff"
) )
// NewIntFromString creates a new big.Int from a decimal integer encoded as a // NewIntFromString creates a new big.Int from a decimal integer encoded as a
@@ -63,9 +66,7 @@ func HexEncode(bs []byte) string {
// HexDecode decodes a hex string into an array of bytes. // HexDecode decodes a hex string into an array of bytes.
func HexDecode(h string) ([]byte, error) { func HexDecode(h string) ([]byte, error) {
if strings.HasPrefix(h, "0x") { h = strings.TrimPrefix(h, "0x")
h = h[2:]
}
return hex.DecodeString(h) return hex.DecodeString(h)
} }
@@ -76,7 +77,7 @@ func HexDecodeInto(dst []byte, h []byte) error {
h = h[2:] h = h[2:]
} }
if len(h)/2 != len(dst) { if len(h)/2 != len(dst) {
return fmt.Errorf("expected %v bytes in hex string, got %v", len(dst), len(h)/2) return fmt.Errorf("expected %v bytes in hex string, got %v", len(dst), len(h)/2) //nolint:gomnd
} }
n, err := hex.Decode(dst, h) n, err := hex.Decode(dst, h)
if err != nil { if err != nil {
@@ -87,20 +88,38 @@ func HexDecodeInto(dst []byte, h []byte) error {
return nil return nil
} }
// CheckBigIntInField checks if given big.Int fits in a Field Q element // CheckBigIntInField checks if given *big.Int fits in a Field Q element
func CheckBigIntInField(a *big.Int, q *big.Int) bool { func CheckBigIntInField(a *big.Int) bool {
if a.Cmp(q) != -1 { return a.Cmp(constants.Q) == -1
return false
}
return true
} }
// CheckBigIntArrayInField checks if given big.Int fits in a Field Q element // CheckBigIntArrayInField checks if given *big.Int fits in a Field Q element
func CheckBigIntArrayInField(arr []*big.Int, q *big.Int) bool { func CheckBigIntArrayInField(arr []*big.Int) bool {
for _, a := range arr { for _, a := range arr {
if !CheckBigIntInField(a, q) { if !CheckBigIntInField(a) {
return false return false
} }
} }
return true return true
} }
// BigIntArrayToElementArray converts an array of *big.Int into an array of *ff.Element
func BigIntArrayToElementArray(bi []*big.Int) []*ff.Element {
var o []*ff.Element
for i := range bi {
o = append(o, ff.NewElement().SetBigInt(bi[i]))
}
return o
}
// ElementArrayToBigIntArray converts an array of *ff.Element into an array of *big.Int
func ElementArrayToBigIntArray(e []*ff.Element) []*big.Int {
var o []*big.Int
for i := range e {
ei := e[i]
bi := big.NewInt(0)
ei.ToBigIntRegular(bi)
o = append(o, bi)
}
return o
}