Poseidon Sponge Hash with different frame sizes (#52)

* Poseidon Sponge Hash with different frame sizes
* Update deps. Bump go version
* Update & fix linter.
* Refactor a bit.
* Reduce gc pressure
This commit is contained in:
Oleksandr Brezhniev
2023-03-08 13:18:55 -05:00
committed by GitHub
parent edc36bfa52
commit e5cf066b8b
19 changed files with 355 additions and 165 deletions

View File

@@ -1,16 +1,18 @@
name: Lint name: Lint
on: [ push, pull_request ] on:
push:
branches:
- main
pull_request:
jobs: jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install Go - uses: actions/checkout@v3
uses: actions/setup-go@v1 - uses: actions/setup-go@v3
with: with:
go-version: 1.16.x go-version: 1.20.x
- name: Checkout code - uses: golangci/golangci-lint-action@v3
uses: actions/checkout@v2 with:
- name: Lint version: v1.51.1
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

View File

@@ -4,7 +4,7 @@ jobs:
test: test:
strategy: strategy:
matrix: matrix:
go-version: [ 1.16.x, 1.17.x ] go-version: [ 1.18.x, 1.19.x, 1.20.x ]
goarch: [ "amd64", "386" ] goarch: [ "amd64", "386" ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

View File

@@ -1,17 +1,77 @@
issues: service:
max-same-issues: 0 golangci-lint-version: 1.51.x
exclude-use-default: false
linters: run:
enable: timeout: 2m
- whitespace skip-dirs:
- gosec - vendor
- gci
- misspell
- gomnd
- gofmt
- goimports
- lll
- golint
linters-settings: linters-settings:
lll: govet:
line-length: 100 check-shadowing: true
revive:
min-confidence: 0.1
rules:
- name: package-comments
disabled: true
maligned:
suggest-new: true
goconst:
min-len: 2
min-occurrences: 2
misspell:
locale: US
lll:
line-length: 140
gocritic:
enabled-tags:
- performance
- style
- experimental
disabled-checks:
- hugeParam
linters:
enable:
- bodyclose
- megacheck
- revive
- govet
- unconvert
- megacheck
- gas
- gocyclo
- dupl
- misspell
- unparam
- typecheck
- ineffassign
- stylecheck
- exportloopref
- nakedret
- gosimple
- prealloc
- unused
## format - fill free to fix
# - errcheck
# - gofmt
# - goimports
fast: false
disable-all: true
issues:
exclude-rules:
# - Fix and remove
- text: "at least one file in a package should have a package comment"
linters:
- stylecheck
# - Fix and remove
- text: "should have a package comment, unless it's in another file for this package"
linters:
- revive
- path: _test\.go
linters:
- gosec
- dupl
exclude-use-default: false

View File

@@ -87,7 +87,7 @@ func (p *PointProjective) Affine() *Point {
// Add computes the addition of two points in projective coordinates // Add computes the addition of two points in projective coordinates
// representation // representation
func (p *PointProjective) Add(q *PointProjective, o *PointProjective) *PointProjective { func (p *PointProjective) Add(q, o *PointProjective) *PointProjective {
// add-2008-bbjlp // add-2008-bbjlp
// https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp // https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp
a := ff.NewElement().Mul(q.Z, o.Z) a := ff.NewElement().Mul(q.Z, o.Z)
@@ -209,7 +209,7 @@ func PointCoordSign(c *big.Int) bool {
func PackSignY(sign bool, y *big.Int) [32]byte { func PackSignY(sign bool, y *big.Int) [32]byte {
leBuf := utils.BigIntLEBytes(y) leBuf := utils.BigIntLEBytes(y)
if sign { if sign {
leBuf[31] = leBuf[31] | 0x80 //nolint:gomnd leBuf[31] |= 0x80 //nolint:gomnd
} }
return leBuf return leBuf
} }
@@ -225,7 +225,7 @@ func UnpackSignY(leBuf [32]byte) (bool, *big.Int) {
y := big.NewInt(0) y := big.NewInt(0)
if (leBuf[31] & 0x80) != 0x00 { //nolint:gomnd if (leBuf[31] & 0x80) != 0x00 { //nolint:gomnd
sign = true sign = true
leBuf[31] = leBuf[31] & 0x7F //nolint:gomnd leBuf[31] &= 0x7F //nolint:gomnd
} }
utils.SetBigIntFromLEBytes(y, leBuf[:]) utils.SetBigIntFromLEBytes(y, leBuf[:])
return sign, y return sign, y

View File

@@ -1,4 +1,5 @@
// Package babyjub eddsa implements the EdDSA over the BabyJubJub curve // Package babyjub eddsa implements the EdDSA over the BabyJubJub curve
//
//nolint:gomnd //nolint:gomnd
package babyjub package babyjub
@@ -16,9 +17,9 @@ import (
// pruneBuffer prunes the buffer during key generation according to RFC 8032. // pruneBuffer prunes the buffer during key generation according to RFC 8032.
// https://tools.ietf.org/html/rfc8032#page-13 // https://tools.ietf.org/html/rfc8032#page-13
func pruneBuffer(buf *[32]byte) *[32]byte { func pruneBuffer(buf *[32]byte) *[32]byte {
buf[0] = buf[0] & 0xF8 buf[0] &= 0xF8
buf[31] = buf[31] & 0x7F buf[31] &= 0x7F
buf[31] = buf[31] | 0x40 buf[31] |= 0x40
return buf return buf
} }
@@ -210,7 +211,7 @@ func (sComp *SignatureComp) Scan(src interface{}) error {
if len(srcB) != 64 { if len(srcB) != 64 {
return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64) return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64)
} }
copy(sComp[:], srcB[:]) copy(sComp[:], srcB)
return nil return nil
} }
@@ -229,7 +230,7 @@ func (s *Signature) Scan(src interface{}) error {
return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64) return fmt.Errorf("can't scan []byte of len %d into Signature, want %d", len(srcB), 64)
} }
buf := [64]byte{} buf := [64]byte{}
copy(buf[:], srcB[:]) copy(buf[:], srcB)
_, err := s.Decompress(buf) _, err := s.Decompress(buf)
return err return err
} }

View File

@@ -12,7 +12,7 @@ import (
// 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()
_, err := h.Write(m[:]) _, err := h.Write(m)
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@@ -1,31 +1,19 @@
package constants package constants
import ( import (
"fmt"
"math/big" "math/big"
) )
const qString = "21888242871839275222246405745257275088548364400416034343698204186575808495617"
// Q is the order of the integer field (Zq) that fits inside the SNARK. // Q is the order of the integer field (Zq) that fits inside the SNARK.
var Q *big.Int var Q, _ = new(big.Int).SetString(qString, 10)
// Zero is 0. // Zero is 0.
var Zero *big.Int var Zero = big.NewInt(0)
// One is 1. // One is 1.
var One *big.Int var One = big.NewInt(1)
// MinusOne is -1. // MinusOne is -1.
var MinusOne *big.Int var MinusOne = big.NewInt(-1)
func init() {
Zero = big.NewInt(0)
One = big.NewInt(1)
MinusOne = big.NewInt(-1)
qString := "21888242871839275222246405745257275088548364400416034343698204186575808495617"
var ok bool
Q, ok = new(big.Int).SetString(qString, 10) //nolint:gomnd
if !ok {
panic(fmt.Sprintf("Bad base 10 string %s", qString))
}
}

19
go.mod
View File

@@ -1,14 +1,17 @@
module github.com/iden3/go-iden3-crypto module github.com/iden3/go-iden3-crypto
go 1.16 go 1.18
require ( require (
github.com/dchest/blake512 v1.0.0 github.com/dchest/blake512 v1.0.0
github.com/stretchr/testify v1.7.0 github.com/leanovate/gopter v0.2.9
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 github.com/stretchr/testify v1.8.2
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/crypto v0.7.0
github.com/davecgh/go-spew v1.1.0 // indirect golang.org/x/sys v0.6.0
github.com/leanovate/gopter v0.2.9 // indirect )
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )

30
go.sum
View File

@@ -1,5 +1,6 @@
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/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
@@ -7,21 +8,18 @@ github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2
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/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.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -3,10 +3,14 @@ package poseidon
import "github.com/iden3/go-iden3-crypto/ffg" import "github.com/iden3/go-iden3-crypto/ffg"
const ( const (
NROUNDSF = 8 //nolint:golint // NROUNDSF const from original paper
NROUNDSP = 22 //nolint:golint NROUNDSF = 8
CAPLEN = 4 //nolint:golint // NROUNDSP const from original paper
mLen = 12 NROUNDSP = 22
// CAPLEN const
CAPLEN = 4
// mLen const
mLen = 12
) )
var ( var (

View File

@@ -10,9 +10,11 @@ func zero() *ffg.Element {
return ffg.NewElement() return ffg.NewElement()
} }
var big7 = big.NewInt(7)
// exp7 performs x^7 mod p // exp7 performs x^7 mod p
func exp7(a *ffg.Element) { func exp7(a *ffg.Element) {
a.Exp(*a, big.NewInt(7)) //nolint:gomnd a.Exp(*a, big7)
} }
// exp7state perform exp7 for whole state // exp7state perform exp7 for whole state

View File

@@ -1,10 +1,8 @@
package poseidon package poseidon
import ( import (
"math/big"
"testing" "testing"
"github.com/iden3/go-iden3-crypto/poseidon"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@@ -99,32 +97,11 @@ func TestPoseidonHashCompare(t *testing.T) {
) )
} }
func BenchmarkPoseidonHash12Inputs(b *testing.B) {
bigArray12 := []*big.Int{
big.NewInt(1),
big.NewInt(2),
big.NewInt(3),
big.NewInt(4),
big.NewInt(5),
big.NewInt(6),
big.NewInt(7),
big.NewInt(8),
big.NewInt(9),
big.NewInt(10),
big.NewInt(11),
big.NewInt(12),
}
for i := 0; i < b.N; i++ {
poseidon.Hash(bigArray12) //nolint:errcheck,gosec
}
}
func BenchmarkNeptuneHash(b *testing.B) { func BenchmarkNeptuneHash(b *testing.B) {
inp := [NROUNDSF]uint64{1, 2, 3, 4, 5, 6, 7, 8} inp := [NROUNDSF]uint64{1, 2, 3, 4, 5, 6, 7, 8}
cap := [CAPLEN]uint64{10, 11, 12, 13} _cap := [CAPLEN]uint64{10, 11, 12, 13}
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
Hash(inp, cap) //nolint:errcheck,gosec _, _ = Hash(inp, _cap)
} }
} }

View File

@@ -0,0 +1,21 @@
package keccak256
import (
"encoding/hex"
"math/big"
"testing"
"github.com/stretchr/testify/assert"
)
func TestKeccak256(t *testing.T) {
const SEED = "mimc"
res := Hash([]byte(SEED))
assert.Equal(t,
"b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e",
hex.EncodeToString(res))
c := new(big.Int).SetBytes(Hash([]byte(SEED)))
assert.Equal(t,
"82724731331859054037315113496710413141112897654334566532528783843265082629790",
c.String())
}

View File

@@ -23,22 +23,22 @@ type constantsData struct {
} }
func generateConstantsData() constantsData { func generateConstantsData() constantsData {
var constants constantsData var consts constantsData
constants.seedHash = new(big.Int).SetBytes(keccak256.Hash([]byte(SEED))) consts.seedHash = new(big.Int).SetBytes(keccak256.Hash([]byte(SEED)))
c := new(big.Int).SetBytes(keccak256.Hash([]byte(SEED + "_iv"))) c := new(big.Int).SetBytes(keccak256.Hash([]byte(SEED + "_iv")))
constants.iv = new(big.Int).Mod(c, _constants.Q) consts.iv = new(big.Int).Mod(c, _constants.Q)
constants.nRounds = 91 consts.nRounds = 91
cts := getConstants(SEED, constants.nRounds) cts := getConstants(SEED, consts.nRounds)
constants.cts = cts consts.cts = cts
return constants return consts
} }
func getConstants(seed string, nRounds int) []*ff.Element { func getConstants(seed string, nRounds int) []*ff.Element {
cts := make([]*ff.Element, nRounds) cts := make([]*ff.Element, nRounds)
cts[0] = ff.NewElement() cts[0] = ff.NewElement()
c := new(big.Int).SetBytes(keccak256.Hash([]byte(SEED))) c := new(big.Int).SetBytes(keccak256.Hash([]byte(seed)))
for i := 1; i < nRounds; i++ { for i := 1; i < nRounds; i++ {
c = new(big.Int).SetBytes(keccak256.Hash(c.Bytes())) c = new(big.Int).SetBytes(keccak256.Hash(c.Bytes()))

View File

@@ -5,21 +5,9 @@ import (
"math/big" "math/big"
"testing" "testing"
"github.com/iden3/go-iden3-crypto/keccak256"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestKeccak256(t *testing.T) {
res := keccak256.Hash([]byte(SEED))
assert.Equal(t,
"b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e",
hex.EncodeToString(res))
c := new(big.Int).SetBytes(keccak256.Hash([]byte(SEED)))
assert.Equal(t,
"82724731331859054037315113496710413141112897654334566532528783843265082629790",
c.String())
}
func TestMIMC7Generic(t *testing.T) { func TestMIMC7Generic(t *testing.T) {
b1 := big.NewInt(int64(1)) b1 := big.NewInt(int64(1))
b2 := big.NewInt(int64(2)) b2 := big.NewInt(int64(2))
@@ -36,7 +24,7 @@ func TestMIMC7Generic(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, assert.Equal(t,
"6464402164086696096195815557694604139393321133243036833927490113253119343397", "6464402164086696096195815557694604139393321133243036833927490113253119343397",
(*big.Int)(hg).String()) hg.String())
} }
func TestMIMC7(t *testing.T) { func TestMIMC7(t *testing.T) {
@@ -51,7 +39,7 @@ 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()), assert.Equal(t, "0x"+hex.EncodeToString(h1.Bytes()),
"0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd") "0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd")
// h2a, hash of 2 elements // h2a, hash of 2 elements
@@ -60,7 +48,7 @@ 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()), assert.Equal(t, "0x"+hex.EncodeToString(h2a.Bytes()),
"0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70") "0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70")
// h2b, hash of 2 elements // h2b, hash of 2 elements
@@ -68,13 +56,13 @@ func TestMIMC7(t *testing.T) {
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()), assert.Equal(t, "0x"+hex.EncodeToString(mh2b.Bytes()),
"0x2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4") "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()), assert.Equal(t, "0x"+hex.EncodeToString(h2b.Bytes()),
"0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879") "0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879")
// h4, hash of 4 elements // h4, hash of 4 elements
@@ -83,7 +71,7 @@ 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()), assert.Equal(t, "0x"+hex.EncodeToString(h4.Bytes()),
"0x284bc1f34f335933a23a433b6ff3ee179d682cd5e5e2fcdd2d964afa85104beb") "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 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
@@ -101,6 +89,6 @@ func BenchmarkMIMC7(b *testing.B) {
bigArray4 := []*big.Int{b12, b45, b78, b41} bigArray4 := []*big.Int{b12, b45, b78, b41}
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
Hash(bigArray4, nil) //nolint:errcheck,gosec _, _ = Hash(bigArray4, nil)
} }
} }

View File

@@ -96,7 +96,7 @@ func init() {
} }
} }
//nolint:lll //nolint:lll,dupl // long lines, duplicated parts
var cs = constantsStr{ var cs = constantsStr{
C: [][]string{{ C: [][]string{{
"9c46e9ec68e9bd4fe1faaba294cba38a71aa177534cdd1b6c7dc0dbd0abd7a7", "9c46e9ec68e9bd4fe1faaba294cba38a71aa177534cdd1b6c7dc0dbd0abd7a7",

View File

@@ -9,9 +9,11 @@ import (
"github.com/iden3/go-iden3-crypto/utils" "github.com/iden3/go-iden3-crypto/utils"
) )
const NROUNDSF = 8 //nolint:golint // NROUNDSF constant from Poseidon paper
const NROUNDSF = 8
var NROUNDSP = []int{56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68} //nolint:golint // NROUNDSP constant from Poseidon paper
var NROUNDSP = []int{56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68}
const spongeChunkSize = 31 const spongeChunkSize = 31
const spongeInputs = 16 const spongeInputs = 16
@@ -20,10 +22,12 @@ func zero() *ff.Element {
return ff.NewElement() return ff.NewElement()
} }
var big5 = big.NewInt(5)
// exp5 performs x^5 mod p // exp5 performs x^5 mod p
// https://eprint.iacr.org/2019/458.pdf page 8 // https://eprint.iacr.org/2019/458.pdf page 8
func exp5(a *ff.Element) { func exp5(a *ff.Element) {
a.Exp(*a, big.NewInt(5)) //nolint:gomnd a.Exp(*a, big5)
} }
// exp5state perform exp5 for whole state // exp5state perform exp5 for whole state
@@ -34,7 +38,7 @@ func exp5state(state []*ff.Element) {
} }
// 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 []*ff.Element, c []*ff.Element, it int) { func ark(state, c []*ff.Element, it int) {
for i := 0; i < len(state); i++ { for i := 0; i < len(state); i++ {
state[i].Add(state[i], c[it+i]) state[i].Add(state[i], c[it+i])
} }
@@ -61,12 +65,12 @@ func mix(state []*ff.Element, t int, m [][]*ff.Element) []*ff.Element {
func Hash(inpBI []*big.Int) (*big.Int, error) { func Hash(inpBI []*big.Int) (*big.Int, error) {
t := len(inpBI) + 1 t := len(inpBI) + 1
if len(inpBI) == 0 || len(inpBI) > len(NROUNDSP) { if len(inpBI) == 0 || len(inpBI) > len(NROUNDSP) {
return nil, fmt.Errorf("invalid inputs length %d, max %d", len(inpBI), len(NROUNDSP)) //nolint:gomnd,lll return nil, fmt.Errorf("invalid inputs length %d, max %d", len(inpBI), len(NROUNDSP))
} }
if !utils.CheckBigIntArrayInField(inpBI[:]) { 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[:]) inp := utils.BigIntArrayToElementArray(inpBI)
nRoundsF := NROUNDSF nRoundsF := NROUNDSF
nRoundsP := NROUNDSP[t-2] nRoundsP := NROUNDSP[t-2]
@@ -77,7 +81,7 @@ func Hash(inpBI []*big.Int) (*big.Int, error) {
state := make([]*ff.Element, t) state := make([]*ff.Element, t)
state[0] = zero() state[0] = zero()
copy(state[1:], inp[:]) copy(state[1:], inp)
ark(state, C, 0) ark(state, C, 0)
@@ -90,11 +94,12 @@ func Hash(inpBI []*big.Int) (*big.Int, error) {
ark(state, C, (nRoundsF/2)*t) ark(state, C, (nRoundsF/2)*t)
state = mix(state, t, P) state = mix(state, t, P)
mul := zero()
for i := 0; i < nRoundsP; i++ { for i := 0; i < nRoundsP; i++ {
exp5(state[0]) exp5(state[0])
state[0].Add(state[0], C[(nRoundsF/2+1)*t+i]) state[0].Add(state[0], C[(nRoundsF/2+1)*t+i])
mul := zero() mul.SetZero()
newState0 := zero() newState0 := zero()
for j := 0; j < len(state); j++ { for j := 0; j < len(state); j++ {
mul.Mul(S[(t*2-1)*i+j], state[j]) mul.Mul(S[(t*2-1)*i+j], state[j])
@@ -102,7 +107,7 @@ func Hash(inpBI []*big.Int) (*big.Int, error) {
} }
for k := 1; k < t; k++ { for k := 1; k < t; k++ {
mul = zero() mul.SetZero()
state[k] = state[k].Add(state[k], mul.Mul(state[0], S[(t*2-1)*i+t+k-1])) state[k] = state[k].Add(state[k], mul.Mul(state[0], S[(t*2-1)*i+t+k-1]))
} }
state[0] = newState0 state[0] = newState0
@@ -124,9 +129,18 @@ func Hash(inpBI []*big.Int) (*big.Int, error) {
// HashBytes returns a sponge hash of a msg byte slice split into blocks of 31 bytes // HashBytes returns a sponge hash of a msg byte slice split into blocks of 31 bytes
func HashBytes(msg []byte) (*big.Int, error) { func HashBytes(msg []byte) (*big.Int, error) {
return HashBytesX(msg, spongeInputs)
}
// HashBytesX returns a sponge hash of a msg byte slice split into blocks of 31 bytes
func HashBytesX(msg []byte, frameSize int) (*big.Int, error) {
if frameSize < 2 || frameSize > 16 {
return nil, errors.New("incorrect frame size")
}
// not used inputs default to zero // not used inputs default to zero
inputs := make([]*big.Int, spongeInputs) inputs := make([]*big.Int, frameSize)
for j := 0; j < spongeInputs; j++ { for j := 0; j < frameSize; j++ {
inputs[j] = new(big.Int) inputs[j] = new(big.Int)
} }
dirty := false dirty := false
@@ -137,15 +151,15 @@ func HashBytes(msg []byte) (*big.Int, error) {
for i := 0; i < len(msg)/spongeChunkSize; i++ { for i := 0; i < len(msg)/spongeChunkSize; i++ {
dirty = true dirty = true
inputs[k].SetBytes(msg[spongeChunkSize*i : spongeChunkSize*(i+1)]) inputs[k].SetBytes(msg[spongeChunkSize*i : spongeChunkSize*(i+1)])
if k == spongeInputs-1 { if k == frameSize-1 {
hash, err = Hash(inputs) hash, err = Hash(inputs)
dirty = false dirty = false
if err != nil { if err != nil {
return nil, err return nil, err
} }
inputs = make([]*big.Int, spongeInputs) inputs = make([]*big.Int, frameSize)
inputs[0] = hash inputs[0] = hash
for j := 1; j < spongeInputs; j++ { for j := 1; j < frameSize; j++ {
inputs[j] = new(big.Int) inputs[j] = new(big.Int)
} }
k = 1 k = 1
@@ -174,3 +188,55 @@ func HashBytes(msg []byte) (*big.Int, error) {
return hash, nil return hash, nil
} }
// SpongeHash returns a sponge hash of inputs (using Poseidon with frame size of 16 inputs)
func SpongeHash(inputs []*big.Int) (*big.Int, error) {
return SpongeHashX(inputs, spongeInputs)
}
// SpongeHashX returns a sponge hash of inputs using Poseidon with configurable frame size
func SpongeHashX(inputs []*big.Int, frameSize int) (*big.Int, error) {
if frameSize < 2 || frameSize > 16 {
return nil, errors.New("incorrect frame size")
}
// not used frame default to zero
frame := make([]*big.Int, frameSize)
for j := 0; j < frameSize; j++ {
frame[j] = new(big.Int)
}
dirty := false
var hash *big.Int
var err error
k := 0
for i := 0; i < len(inputs); i++ {
dirty = true
frame[k] = inputs[i]
if k == frameSize-1 {
hash, err = Hash(frame)
dirty = false
if err != nil {
return nil, err
}
frame = make([]*big.Int, frameSize)
frame[0] = hash
for j := 1; j < frameSize; j++ {
frame[j] = new(big.Int)
}
k = 1
} else {
k++
}
}
if dirty {
// we haven't hashed something in the main sponge loop and need to do hash here
hash, err = Hash(frame)
if err != nil {
return nil, err
}
}
return hash, nil
}

File diff suppressed because one or more lines are too long

View File

@@ -46,7 +46,7 @@ func SetBigIntFromLEBytes(v *big.Int, leBuf []byte) *big.Int {
return v.SetBytes(beBuf) return v.SetBytes(beBuf)
} }
// Hex is a byte slice type that can be marshalled and unmarshaled in hex // Hex is a byte slice type that can be marshaled and unmarshaled in hex
type Hex []byte type Hex []byte
// MarshalText encodes buf as hex // MarshalText encodes buf as hex
@@ -72,7 +72,7 @@ func HexDecode(h string) ([]byte, error) {
// HexDecodeInto decodes a hex string into an array of bytes (dst), verifying // HexDecodeInto decodes a hex string into an array of bytes (dst), verifying
// that the decoded array has the same length as dst. // that the decoded array has the same length as dst.
func HexDecodeInto(dst []byte, h []byte) error { func HexDecodeInto(dst, h []byte) error {
if bytes.HasPrefix(h, []byte("0x")) { if bytes.HasPrefix(h, []byte("0x")) {
h = h[2:] h = h[2:]
} }
@@ -105,21 +105,21 @@ func CheckBigIntArrayInField(arr []*big.Int) bool {
// BigIntArrayToElementArray converts an array of *big.Int into an array of *ff.Element // BigIntArrayToElementArray converts an array of *big.Int into an array of *ff.Element
func BigIntArrayToElementArray(bi []*big.Int) []*ff.Element { func BigIntArrayToElementArray(bi []*big.Int) []*ff.Element {
var o []*ff.Element o := make([]*ff.Element, len(bi))
for i := range bi { for i := range bi {
o = append(o, ff.NewElement().SetBigInt(bi[i])) o[i] = ff.NewElement().SetBigInt(bi[i])
} }
return o return o
} }
// ElementArrayToBigIntArray converts an array of *ff.Element into an array of *big.Int // ElementArrayToBigIntArray converts an array of *ff.Element into an array of *big.Int
func ElementArrayToBigIntArray(e []*ff.Element) []*big.Int { func ElementArrayToBigIntArray(e []*ff.Element) []*big.Int {
var o []*big.Int o := make([]*big.Int, len(e))
for i := range e { for i := range e {
ei := e[i] ei := e[i]
bi := big.NewInt(0) bi := big.NewInt(0)
ei.ToBigIntRegular(bi) ei.ToBigIntRegular(bi)
o = append(o, bi) o[i] = bi
} }
return o return o
} }