mirror of
https://github.com/arnaucube/go-iden3-crypto.git
synced 2026-02-07 03:26:39 +01:00
Compare commits
5 Commits
v0.0.1
...
decompress
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a60e154d86 | ||
|
|
c95c95b7b1 | ||
|
|
2b1935299c | ||
|
|
0bac1c84ba | ||
|
|
c4b3b7a09c |
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"))
|
||||
|
||||
101
mimc7/mimc7.go
101
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 {
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user