Compare commits

...

5 Commits

7 changed files with 262 additions and 155 deletions

View File

@@ -2,9 +2,10 @@ package babyjub
import (
"fmt"
"math/big"
"github.com/iden3/go-iden3-crypto/constants"
"github.com/iden3/go-iden3-crypto/utils"
"math/big"
)
// A is one of the babyjub constants.
@@ -35,9 +36,9 @@ func init() {
B8 = NewPoint()
B8.X = utils.NewIntFromString(
"17777552123799933955779906779655732241715742912184938656739573121738514868268")
"5299619240641551281634865583518297030282874472190772894086521144482721001553")
B8.Y = utils.NewIntFromString(
"2626589144620713026669568689430873010625803728049924121243784502389097019475")
"16950150798460657717958625567821834550301663161624707787222815936182638968203")
}
// Point represents a point of the babyjub curve.
@@ -74,7 +75,7 @@ func (res *Point) Add(a *Point, b *Point) *Point {
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 * a.x) * (1 - D * a.x * b.x * a.y * b.y)^-1 mod q
// 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)
@@ -170,10 +171,7 @@ func PackPoint(ay *big.Int, sign bool) [32]byte {
// Compress the point into a 32 byte array that contains the y coordinate in
// little endian and the sign of the x coordinate.
func (p *Point) Compress() [32]byte {
sign := false
if PointCoordSign(p.X) {
sign = true
}
sign := PointCoordSign(p.X)
return PackPoint(p.Y, sign)
}
@@ -205,7 +203,10 @@ func (p *Point) Decompress(leBuf [32]byte) (*Point, error) {
xb.ModInverse(xb, constants.Q)
p.X.Mul(xa, xb) // xa / xb
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)) {
p.X.Mul(p.X, constants.MinusOne)
}

View File

@@ -4,6 +4,7 @@ import (
"crypto/rand"
"github.com/iden3/go-iden3-crypto/mimc7"
"github.com/iden3/go-iden3-crypto/poseidon"
"github.com/iden3/go-iden3-crypto/utils"
"math/big"
@@ -179,11 +180,11 @@ func (k *PrivateKey) SignMimc7(msg *big.Int) *Signature {
r.Mod(r, SubOrder)
R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
A := k.Public().Point()
hmInput, err := mimc7.BigIntsToRElems([]*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 := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
if err != nil {
panic(err)
}
hm := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
S := new(big.Int).Lsh(k.Scalar().BigInt(), 3)
S = S.Mul(hm, S)
S.Add(r, S)
@@ -195,11 +196,53 @@ func (k *PrivateKey) SignMimc7(msg *big.Int) *Signature {
// 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.
func (p *PublicKey) VerifyMimc7(msg *big.Int, sig *Signature) bool {
hmInput, err := mimc7.BigIntsToRElems([]*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg})
hmInput := []*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg}
hm, err := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
if err != nil {
panic(err)
}
left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
r1 := big.NewInt(8)
r1.Mul(r1, hm)
right := NewPoint().Mul(r1, p.Point())
right.Add(sig.R8, right) // right = 8 * R + 8 * hm * A
return (left.X.Cmp(right.X) == 0) && (left.Y.Cmp(right.Y) == 0)
}
// SignPoseidon signs a message encoded as a big.Int in Zq using blake-512 hash
// for buffer hashing and Poseidon for big.Int hashing.
func (k *PrivateKey) SignPoseidon(msg *big.Int) *Signature {
h1 := Blake512(k[:])
msgBuf := utils.BigIntLEBytes(msg)
msgBuf32 := [32]byte{}
copy(msgBuf32[:], msgBuf[:])
rBuf := Blake512(append(h1[32:], msgBuf32[:]...))
r := utils.SetBigIntFromLEBytes(new(big.Int), rBuf) // r = H(H_{32..63}(k), msg)
r.Mod(r, SubOrder)
R8 := NewPoint().Mul(r, B8) // R8 = r * 8 * B
A := k.Public().Point()
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)
if err != nil {
panic(err)
}
S := new(big.Int).Lsh(k.Scalar().BigInt(), 3)
S = S.Mul(hm, S)
S.Add(r, S)
S.Mod(S, SubOrder) // S = r + hm * 8 * s
return &Signature{R8: R8, S: S}
}
// 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.
func (p *PublicKey) VerifyPoseidon(msg *big.Int, sig *Signature) bool {
hmInput := []*big.Int{sig.R8.X, sig.R8.Y, p.X, p.Y, msg}
hm, err := poseidon.Hash(hmInput) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
if err != nil {
panic(err)
}
hm := mimc7.Hash(hmInput, nil) // hm = H1(8*R.x, 8*R.y, A.x, A.y, msg)
left := NewPoint().Mul(sig.S, B8) // left = s * 8 * B
r1 := big.NewInt(8)

View File

@@ -4,13 +4,12 @@ import (
"crypto/rand"
"encoding/hex"
"fmt"
"math/big"
"testing"
"github.com/iden3/go-iden3-crypto/constants"
"github.com/iden3/go-iden3-crypto/utils"
"github.com/stretchr/testify/assert"
"math/big"
"testing"
)
func genInputs() (*PrivateKey, *big.Int) {
@@ -26,7 +25,7 @@ func genInputs() (*PrivateKey, *big.Int) {
return &k, msg
}
func TestSignVerify1(t *testing.T) {
func TestSignVerifyMimc7(t *testing.T) {
var k PrivateKey
hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
msgBuf, err := hex.DecodeString("00010203040506070809")
@@ -37,21 +36,21 @@ func TestSignVerify1(t *testing.T) {
pk := k.Public()
assert.Equal(t,
"2610057752638682202795145288373380503107623443963127956230801721756904484787",
"13277427435165878497778222415993513565335242147425444199013288855685581939618",
pk.X.String())
assert.Equal(t,
"16617171478497210597712478520507818259149717466230047843969353176573634386897",
"13622229784656158136036771217484571176836296686641868549125388198837476602820",
pk.Y.String())
sig := k.SignMimc7(msg)
assert.Equal(t,
"4974729414807584049518234760796200867685098748448054182902488636762478901554",
"11384336176656855268977457483345535180380036354188103142384839473266348197733",
sig.R8.X.String())
assert.Equal(t,
"18714049394522540751536514815950425694461287643205706667341348804546050128733",
"15383486972088797283337779941324724402501462225528836549661220478783371668959",
sig.R8.Y.String())
assert.Equal(t,
"2171284143457722024136077617757713039502332290425057126942676527240038689549",
"2523202440825208709475937830811065542425109372212752003460238913256192595070",
sig.S.String())
ok := pk.VerifyMimc7(msg, sig)
@@ -62,14 +61,58 @@ func TestSignVerify1(t *testing.T) {
assert.Equal(t, nil, err)
assert.Equal(t, ""+
"5dfb6f843c023fe3e52548ccf22e55c81b426f7af81b4f51f7152f2fcfc65f29"+
"0dab19c5a0a75973cd75a54780de0c3a41ede6f57396fe99b5307fff3ce7cc04",
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"7ed40dab29bf993c928e789d007387998901a24913d44fddb64b1f21fc149405",
hex.EncodeToString(sigBuf[:]))
ok = pk.VerifyMimc7(msg, sig2)
assert.Equal(t, true, ok)
}
func TestSignVerifyPoseidon(t *testing.T) {
var k PrivateKey
hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))
msgBuf, err := hex.DecodeString("00010203040506070809")
if err != nil {
panic(err)
}
msg := utils.SetBigIntFromLEBytes(new(big.Int), msgBuf)
pk := k.Public()
assert.Equal(t,
"13277427435165878497778222415993513565335242147425444199013288855685581939618",
pk.X.String())
assert.Equal(t,
"13622229784656158136036771217484571176836296686641868549125388198837476602820",
pk.Y.String())
sig := k.SignPoseidon(msg)
assert.Equal(t,
"11384336176656855268977457483345535180380036354188103142384839473266348197733",
sig.R8.X.String())
assert.Equal(t,
"15383486972088797283337779941324724402501462225528836549661220478783371668959",
sig.R8.Y.String())
assert.Equal(t,
"248298168863866362217836334079793350221620631973732197668910946177382043688",
sig.S.String())
ok := pk.VerifyPoseidon(msg, sig)
assert.Equal(t, true, ok)
sigBuf := sig.Compress()
sig2, err := new(Signature).Decompress(sigBuf)
assert.Equal(t, nil, err)
assert.Equal(t, ""+
"dfedb4315d3f2eb4de2d3c510d7a987dcab67089c8ace06308827bf5bcbe02a2"+
"28506bce274aa1b3f7e7c2fd7e4fe09bff8f9aa37a42def7994e98f322888c00",
hex.EncodeToString(sigBuf[:]))
ok = pk.VerifyPoseidon(msg, sig2)
assert.Equal(t, true, ok)
}
func TestCompressDecompress(t *testing.T) {
var k PrivateKey
hex.Decode(k[:], []byte("0001020304050607080900010203040506070809000102030405060708090001"))

View File

@@ -2,19 +2,16 @@ package mimc7
import (
"errors"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/crypto"
_constants "github.com/iden3/go-iden3-crypto/constants"
"github.com/iden3/go-iden3-crypto/field"
"github.com/iden3/go-iden3-crypto/utils"
)
const SEED = "mimc"
// RElem is a big.Int of maximum 253 bits
type RElem *big.Int
var constants = generateConstantsData()
type constantsData struct {
@@ -26,9 +23,6 @@ type constantsData struct {
cts []*big.Int
}
func getIV(seed string) {
}
func generateConstantsData() constantsData {
var constants constantsData
@@ -43,45 +37,12 @@ func generateConstantsData() constantsData {
constants.iv = new(big.Int).Mod(c, constants.maxFieldVal)
constants.nRounds = 91
cts, err := getConstants(constants.fqR, SEED, constants.nRounds)
if err != nil {
panic(err)
}
cts := getConstants(constants.fqR, SEED, constants.nRounds)
constants.cts = cts
return constants
}
// BigIntToRElem checks if given big.Int fits in a Field R element, and returns the RElem type
func BigIntToRElem(a *big.Int) (RElem, error) {
if a.Cmp(constants.maxFieldVal) != -1 {
return RElem(a), errors.New("Given big.Int don't fits in the Finite Field over R")
}
return RElem(a), nil
}
//BigIntsToRElems converts from array of *big.Int to array of RElem
func BigIntsToRElems(arr []*big.Int) ([]RElem, error) {
o := make([]RElem, len(arr))
for i, a := range arr {
e, err := BigIntToRElem(a)
if err != nil {
return o, fmt.Errorf("element in position %v don't fits in Finite Field over R", i)
}
o[i] = e
}
return o, nil
}
// RElemsToBigInts converts from array of RElem to array of *big.Int
func RElemsToBigInts(arr []RElem) []*big.Int {
o := make([]*big.Int, len(arr))
for i, a := range arr {
o[i] = a
}
return o
}
func getConstants(fqR field.Fq, seed string, nRounds int) ([]*big.Int, error) {
func getConstants(fqR field.Fq, seed string, nRounds int) []*big.Int {
cts := make([]*big.Int, nRounds)
cts[0] = big.NewInt(int64(0))
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
@@ -91,15 +52,12 @@ func getConstants(fqR field.Fq, seed string, nRounds int) ([]*big.Int, error) {
n := fqR.Affine(c)
cts[i] = n
}
return cts, nil
return cts
}
// MIMC7HashGeneric performs the MIMC7 hash over a RElem, in a generic way, where it can be specified the Finite Field over R, and the number of rounds
func MIMC7HashGeneric(fqR field.Fq, xIn, k *big.Int, nRounds int) (*big.Int, error) {
cts, err := getConstants(fqR, SEED, nRounds)
if err != nil {
return &big.Int{}, err
}
// 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
func MIMC7HashGeneric(fqR field.Fq, xIn, k *big.Int, nRounds int) *big.Int {
cts := getConstants(fqR, SEED, nRounds)
var r *big.Int
for i := 0; i < nRounds; i++ {
var t *big.Int
@@ -112,24 +70,26 @@ func MIMC7HashGeneric(fqR field.Fq, xIn, k *big.Int, nRounds int) (*big.Int, err
t4 := fqR.Square(t2)
r = fqR.Mul(fqR.Mul(t4, t2), t)
}
return fqR.Affine(fqR.Add(r, k)), nil
return fqR.Affine(fqR.Add(r, k))
}
// HashGeneric performs the MIMC7 hash over a RElem array, in a generic way, where it can be specified the Finite Field over R, and the number of rounds
func HashGeneric(iv *big.Int, arrEl []RElem, fqR field.Fq, nRounds int) (RElem, error) {
arr := RElemsToBigInts(arrEl)
// 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
func HashGeneric(iv *big.Int, arr []*big.Int, fqR field.Fq, nRounds int) (*big.Int, error) {
if !utils.CheckBigIntArrayInField(arr, constants.fqR.Q) {
return nil, errors.New("inputs values not inside Finite Field")
}
r := iv
var err error
for i := 0; i < len(arr); i++ {
r, err = MIMC7HashGeneric(fqR, r, arr[i], nRounds)
r = MIMC7HashGeneric(fqR, r, arr[i], nRounds)
if err != nil {
return r, err
}
}
return RElem(r), nil
return r, nil
}
// MIMC7Hash performs the MIMC7 hash over a RElem, 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 over R and the number of rounds setted in the `constants` variable
func MIMC7Hash(xIn, k *big.Int) *big.Int {
var r *big.Int
for i := 0; i < constants.nRounds; i++ {
@@ -146,16 +106,17 @@ func MIMC7Hash(xIn, k *big.Int) *big.Int {
return constants.fqR.Affine(constants.fqR.Add(r, k))
}
// Hash performs the MIMC7 hash over a RElem array
func Hash(arrEl []RElem, key *big.Int) RElem {
arr := RElemsToBigInts(arrEl)
// Hash performs the MIMC7 hash over a *big.Int array
func Hash(arr []*big.Int, key *big.Int) (*big.Int, error) {
if !utils.CheckBigIntArrayInField(arr, constants.fqR.Q) {
return nil, errors.New("inputs values not inside Finite Field")
}
var r *big.Int
if key == nil {
r = constants.fqR.Zero()
} else {
r = key
}
// r := constants.iv
for i := 0; i < len(arr); i++ {
r = constants.fqR.Add(
constants.fqR.Add(
@@ -164,5 +125,23 @@ func Hash(arrEl []RElem, key *big.Int) RElem {
),
MIMC7Hash(arr[i], r))
}
return RElem(r)
return r, nil
}
// HashBytes hashes a msg byte slice by blocks of 31 bytes encoded as
// little-endian
func HashBytes(b []byte) (*big.Int, error) {
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)
}
return Hash(bElems, nil)
}

View File

@@ -5,42 +5,16 @@ import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/crypto"
"github.com/iden3/go-iden3-crypto/field"
"github.com/stretchr/testify/assert"
)
func TestUtils(t *testing.T) {
b1 := big.NewInt(int64(1))
b2 := big.NewInt(int64(2))
b3 := big.NewInt(int64(3))
arrBigInt := []*big.Int{b1, b2, b3}
// *big.Int array to RElem array
rElems, err := BigIntsToRElems(arrBigInt)
assert.Nil(t, err)
// RElem array to *big.Int array
bElems := RElemsToBigInts(rElems)
assert.Equal(t, arrBigInt, bElems)
r, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495617", 10)
assert.True(t, ok)
// greater or equal than R will give error when passing bigInts to RElems, to fit in the R Finite Field
overR, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495618", 10)
assert.True(t, ok)
_, err = BigIntsToRElems([]*big.Int{b1, overR, b2})
assert.True(t, err != nil)
_, err = BigIntsToRElems([]*big.Int{b1, r, b2})
assert.True(t, err != nil)
// smaller than R will not give error when passing bigInts to RElems, to fit in the R Finite Field
underR, ok := new(big.Int).SetString("21888242871839275222246405745257275088548364400416034343698204186575808495616", 10)
assert.True(t, ok)
_, err = BigIntsToRElems([]*big.Int{b1, underR, b2})
assert.Nil(t, err)
func TestKeccak256(t *testing.T) {
res := crypto.Keccak256([]byte(SEED))
assert.Equal(t, "b6e489e6b37224a50bebfddbe7d89fa8fdcaa84304a70bd13f79b5d9f7951e9e", hex.EncodeToString(res))
c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
assert.Equal(t, "82724731331859054037315113496710413141112897654334566532528783843265082629790", c.String())
}
func TestMIMC7Generic(t *testing.T) {
@@ -53,14 +27,11 @@ func TestMIMC7Generic(t *testing.T) {
fqR := field.NewFq(r)
bigArray := []*big.Int{b1, b2, b3}
elementsArray, err := BigIntsToRElems(bigArray)
assert.Nil(t, err)
// Generic Hash
mhg, err := MIMC7HashGeneric(fqR, b1, b2, 91)
assert.Nil(t, err)
mhg := MIMC7HashGeneric(fqR, b1, b2, 91)
assert.Equal(t, "10594780656576967754230020536574539122676596303354946869887184401991294982664", mhg.String())
hg, err := HashGeneric(fqR.Zero(), elementsArray, fqR, 91)
hg, err := HashGeneric(fqR.Zero(), bigArray, fqR, 91)
assert.Nil(t, err)
assert.Equal(t, "6464402164086696096195815557694604139393321133243036833927490113253119343397", (*big.Int)(hg).String())
}
@@ -73,51 +44,44 @@ func TestMIMC7(t *testing.T) {
// h1, hash of 1 elements
bigArray1 := []*big.Int{b12}
elementsArray1, err := BigIntsToRElems(bigArray1)
assert.Nil(t, err)
h1 := Hash(elementsArray1, nil)
h1, err := Hash(bigArray1, nil)
assert.Nil(t, err)
// same hash value than the iden3js and circomlib tests:
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h1).Bytes()), "0x237c92644dbddb86d8a259e0e923aaab65a93f1ec5758b8799988894ac0958fd")
// h2a, hash of 2 elements
bigArray2a := []*big.Int{b78, b41}
elementsArray2a, err := BigIntsToRElems(bigArray2a)
assert.Nil(t, err)
mh2a := MIMC7Hash(b12, b45)
assert.Nil(t, err)
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(mh2a).Bytes()), "0x2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4")
h2a := Hash(elementsArray2a, nil)
h2a, err := Hash(bigArray2a, nil)
assert.Nil(t, err)
// same hash value than the iden3js and circomlib tests:
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h2a).Bytes()), "0x067f3202335ea256ae6e6aadcd2d5f7f4b06a00b2d1e0de903980d5ab552dc70")
// h2b, hash of 2 elements
bigArray2b := []*big.Int{b12, b45}
elementsArray2b, err := BigIntsToRElems(bigArray2b)
assert.Nil(t, err)
mh2b := MIMC7Hash(b12, b45)
assert.Nil(t, err)
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(mh2b).Bytes()), "0x2ba7ebad3c6b6f5a20bdecba2333c63173ca1a5f2f49d958081d9fa7179c44e4")
h2b := Hash(elementsArray2b, nil)
h2b, err := Hash(bigArray2b, nil)
assert.Nil(t, err)
// same hash value than the iden3js and circomlib tests:
assert.Equal(t, "0x"+hex.EncodeToString((*big.Int)(h2b).Bytes()), "0x15ff7fe9793346a17c3150804bcb36d161c8662b110c50f55ccb7113948d8879")
// h4, hash of 4 elements
bigArray4 := []*big.Int{b12, b45, b78, b41}
elementsArray4, err := BigIntsToRElems(bigArray4)
assert.Nil(t, err)
h4 := Hash(elementsArray4, nil)
h4, err := Hash(bigArray4, nil)
assert.Nil(t, err)
// same hash value than the iden3js and circomlib tests:
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.")
hmsg, err := HashBytes(msg)
assert.Nil(t, err)
assert.Equal(t, "16855787120419064316734350414336285711017110414939748784029922801367685456065", hmsg.String())
}
func BenchmarkMIMC7(b *testing.B) {
@@ -126,12 +90,10 @@ func BenchmarkMIMC7(b *testing.B) {
b78 := big.NewInt(int64(78))
b41 := big.NewInt(int64(41))
bigArray4 := []*big.Int{b12, b45, b78, b41}
elementsArray4, err := BigIntsToRElems(bigArray4)
assert.Nil(b, err)
var h4 RElem
var h4 *big.Int
for i := 0; i < b.N; i++ {
h4 = Hash(elementsArray4, nil)
h4, _ = Hash(bigArray4, nil)
}
println(h4)
}

View File

@@ -107,12 +107,13 @@ func ark(state []*big.Int, c *big.Int) []*big.Int {
return state
}
// cubic performs x^3 mod p
// cubic performs x^5 mod p
// https://eprint.iacr.org/2019/458.pdf page 8
func cubic(a *big.Int) *big.Int {
return constants.fqR.Mul(a, constants.fqR.Square(constants.fqR.Square(a)))
}
// 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 {
if (i < NROUNDSF/2) || (i >= NROUNDSF/2+NROUNDSP) {
for j := 0; j < T; j++ {
@@ -133,25 +134,18 @@ func mix(state []*big.Int, m [][]*big.Int) []*big.Int {
newState[i] = constants.fqR.Add(newState[i], constants.fqR.Mul(m[i][j], state[j]))
}
}
for i := 0; i < len(state); i++ {
state[i] = newState[i]
}
return state
return newState
}
// Hash computes the Poseidon hash for the given inputs
func Hash(inp []*big.Int) (*big.Int, error) {
var state []*big.Int
// PoseidonHash computes the Poseidon hash for the given inputs
func PoseidonHash(inp []*big.Int) (*big.Int, error) {
if len(inp) == 0 || len(inp) > T {
return nil, errors.New("wrong inputs length")
}
if !utils.CheckBigIntArrayInField(inp, constants.fqR.Q) {
return nil, errors.New("inputs values not inside Finite Field")
}
for i := 0; i < len(inp); i++ {
state = append(state, inp[i])
}
state := inp
for i := len(inp); i < T; i++ {
state = append(state, constants.fqR.Zero())
}
@@ -164,3 +158,50 @@ func Hash(inp []*big.Int) (*big.Int, error) {
}
return state[0], nil
}
// Hash performs the Poseidon hash over a *big.Int array
// in chunks of 5 elements
func Hash(arr []*big.Int) (*big.Int, error) {
if !utils.CheckBigIntArrayInField(arr, constants.fqR.Q) {
return nil, errors.New("inputs values not inside Finite Field")
}
r := constants.fqR.Zero()
for i := 0; i < len(arr); i = i + 5 {
var fiveElems []*big.Int
for j := 0; j < 5; j++ {
if i+j < len(arr) {
fiveElems = append(fiveElems, arr[i+j])
} else {
fiveElems = append(fiveElems, big.NewInt(int64(0)))
}
}
ph, err := PoseidonHash(fiveElems)
if err != nil {
return nil, err
}
r = constants.fqR.Add(
r,
ph)
}
return r, nil
}
// HashBytes hashes a msg byte slice by blocks of 31 bytes encoded as
// little-endian
func HashBytes(b []byte) (*big.Int, error) {
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)
}
return Hash(bElems)
}

View File

@@ -5,6 +5,7 @@ import (
"math/big"
"testing"
"github.com/iden3/go-iden3-crypto/utils"
"github.com/stretchr/testify/assert"
"golang.org/x/crypto/blake2b"
)
@@ -26,4 +27,41 @@ func TestPoseidon(t *testing.T) {
h, err = Hash([]*big.Int{b3, b4})
assert.Nil(t, err)
assert.Equal(t, "17185195740979599334254027721507328033796809509313949281114643312710535000993", h.String())
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.")
n := 31
msgElems := make([]*big.Int, 0, len(msg)/n+1)
for i := 0; i < len(msg)/n; i++ {
v := new(big.Int)
utils.SetBigIntFromLEBytes(v, msg[n*i:n*(i+1)])
msgElems = append(msgElems, v)
}
if len(msg)%n != 0 {
v := new(big.Int)
utils.SetBigIntFromLEBytes(v, msg[(len(msg)/n)*n:])
msgElems = append(msgElems, v)
}
hmsg, err := Hash(msgElems)
assert.Nil(t, err)
assert.Equal(t, "11821124228916291136371255062457365369197326845706357273715164664419275913793", hmsg.String())
msg2 := []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. Lorem ipsum dolor sit amet.")
msg2Elems := make([]*big.Int, 0, len(msg2)/n+1)
for i := 0; i < len(msg2)/n; i++ {
v := new(big.Int)
utils.SetBigIntFromLEBytes(v, msg2[n*i:n*(i+1)])
msg2Elems = append(msg2Elems, v)
}
if len(msg2)%n != 0 {
v := new(big.Int)
utils.SetBigIntFromLEBytes(v, msg2[(len(msg2)/n)*n:])
msg2Elems = append(msg2Elems, v)
}
hmsg2, err := Hash(msg2Elems)
assert.Nil(t, err)
assert.Equal(t, "10747013384255785702102976082726575658403084163954725275481577373644732938016", hmsg2.String())
hmsg2, err = HashBytes(msg2)
assert.Nil(t, err)
assert.Equal(t, "10747013384255785702102976082726575658403084163954725275481577373644732938016", hmsg2.String())
}