Browse Source

MiMC7 finite field over R comprovation moved inside hash, same approach as Poseidon impl

decompress-modsqrt v0.0.2
arnaucube 4 years ago
parent
commit
2b1935299c
3 changed files with 26 additions and 103 deletions
  1. +4
    -4
      babyjub/eddsa.go
  2. +15
    -45
      mimc7/mimc7.go
  3. +7
    -54
      mimc7/mimc7_test.go

+ 4
- 4
babyjub/eddsa.go

@ -180,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)
@ -196,11 +196,11 @@ 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)
}
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)

+ 15
- 45
mimc7/mimc7.go

@ -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 {
@ -45,36 +42,6 @@ func generateConstantsData() constantsData {
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 {
cts := make([]*big.Int, nRounds)
cts[0] = big.NewInt(int64(0))
@ -88,7 +55,7 @@ func getConstants(fqR field.Fq, seed string, nRounds int) []*big.Int {
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
// 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
@ -106,9 +73,11 @@ func MIMC7HashGeneric(fqR field.Fq, xIn, k *big.Int, nRounds int) *big.Int {
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++ {
@ -117,10 +86,10 @@ func HashGeneric(iv *big.Int, arrEl []RElem, fqR field.Fq, nRounds int) (RElem,
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++ {
@ -137,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(
@ -155,5 +125,5 @@ func Hash(arrEl []RElem, key *big.Int) RElem {
),
MIMC7Hash(arr[i], r))
}
return RElem(r)
return r, nil
}

+ 7
- 54
mimc7/mimc7_test.go

@ -10,40 +10,6 @@ import (
"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))
@ -61,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 := MIMC7HashGeneric(fqR, b1, b2, 91)
assert.Nil(t, err)
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())
}
@ -81,44 +44,36 @@ 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)
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")
@ -130,12 +85,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)
}

Loading…
Cancel
Save