go-iden3-crypto/mimc7/mimc7.go
mimc7/mimc7.goRaw
1package mimc7
2
3import (
4 "errors"
5 "math/big"
6
7 "github.com/ethereum/go-ethereum/crypto"
8 _constants "github.com/iden3/go-iden3-crypto/constants"
9 "github.com/iden3/go-iden3-crypto/ff"
10 "github.com/iden3/go-iden3-crypto/utils"
11)
12
13const SEED = "mimc"
14
15var constants = generateConstantsData()
16
17type constantsData struct {
18 seedHash *big.Int
19 iv *big.Int
20 nRounds int
21 cts []*ff.Element
22}
23
24func generateConstantsData() constantsData {
25 var constants constantsData
26
27 constants.seedHash = new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
28 c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED + "_iv")))
29 constants.iv = new(big.Int).Mod(c, _constants.Q)
30
31 constants.nRounds = 91
32 cts := getConstants(SEED, constants.nRounds)
33 constants.cts = cts
34 return constants
35}
36
37func getConstants(seed string, nRounds int) []*ff.Element {
38 cts := make([]*ff.Element, nRounds)
39 cts[0] = ff.NewElement().SetZero()
40 c := new(big.Int).SetBytes(crypto.Keccak256([]byte(SEED)))
41 for i := 1; i < nRounds; i++ {
42 c = new(big.Int).SetBytes(crypto.Keccak256(c.Bytes()))
43
44 n := new(big.Int).Mod(c, _constants.Q)
45 cts[i] = ff.NewElement().SetBigInt(n)
46 }
47 return cts
48}
49
50// 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
51func MIMC7HashGeneric(xInBI, kBI *big.Int, nRounds int) *big.Int {
52 xIn := ff.NewElement().SetBigInt(xInBI)
53 k := ff.NewElement().SetBigInt(kBI)
54
55 cts := getConstants(SEED, nRounds)
56 var r *ff.Element
57 for i := 0; i < nRounds; i++ {
58 var t *ff.Element
59 if i == 0 {
60 t = ff.NewElement().Add(xIn, k)
61 } else {
62 t = ff.NewElement().Add(ff.NewElement().Add(r, k), cts[i])
63 }
64 t2 := ff.NewElement().Square(t)
65 t4 := ff.NewElement().Square(t2)
66 r = ff.NewElement().Mul(ff.NewElement().Mul(t4, t2), t)
67 }
68 rE := ff.NewElement().Add(r, k)
69
70 res := big.NewInt(0)
71 rE.ToBigIntRegular(res)
72 return res
73}
74
75// 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
76func HashGeneric(iv *big.Int, arr []*big.Int, nRounds int) (*big.Int, error) {
77 if !utils.CheckBigIntArrayInField(arr) {
78 return nil, errors.New("inputs values not inside Finite Field")
79 }
80 r := iv
81 var err error
82 for i := 0; i < len(arr); i++ {
83 r = MIMC7HashGeneric(r, arr[i], nRounds)
84 if err != nil {
85 return r, err
86 }
87 }
88 return r, nil
89}
90
91// 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
92func MIMC7Hash(xInBI, kBI *big.Int) *big.Int {
93 xIn := ff.NewElement().SetBigInt(xInBI)
94 k := ff.NewElement().SetBigInt(kBI)
95
96 var r *ff.Element
97 for i := 0; i < constants.nRounds; i++ {
98 var t *ff.Element
99 if i == 0 {
100 t = ff.NewElement().Add(xIn, k)
101 } else {
102 t = ff.NewElement().Add(ff.NewElement().Add(r, k), constants.cts[i])
103 }
104 t2 := ff.NewElement().Square(t)
105 t4 := ff.NewElement().Square(t2)
106 r = ff.NewElement().Mul(ff.NewElement().Mul(t4, t2), t)
107 }
108 rE := ff.NewElement().Add(r, k)
109
110 res := big.NewInt(0)
111 rE.ToBigIntRegular(res)
112 return res
113}
114
115// Hash performs the MIMC7 hash over a *big.Int array
116func Hash(arr []*big.Int, key *big.Int) (*big.Int, error) {
117 if !utils.CheckBigIntArrayInField(arr) {
118 return nil, errors.New("inputs values not inside Finite Field")
119 }
120 var r *big.Int
121 if key == nil {
122 r = big.NewInt(0)
123 } else {
124 r = key
125 }
126 for i := 0; i < len(arr); i++ {
127 r = new(big.Int).Add(
128 new(big.Int).Add(
129 r,
130 arr[i],
131 ),
132 MIMC7Hash(arr[i], r))
133 r = new(big.Int).Mod(r, _constants.Q)
134 }
135 return r, nil
136}
137
138// HashBytes hashes a msg byte slice by blocks of 31 bytes encoded as
139// little-endian
140func HashBytes(b []byte) (*big.Int, error) {
141 n := 31
142 bElems := make([]*big.Int, 0, len(b)/n+1)
143 for i := 0; i < len(b)/n; i++ {
144 v := new(big.Int)
145 utils.SetBigIntFromLEBytes(v, b[n*i:n*(i+1)])
146 bElems = append(bElems, v)
147 }
148 if len(b)%n != 0 {
149 v := new(big.Int)
150 utils.SetBigIntFromLEBytes(v, b[(len(b)/n)*n:])
151 bElems = append(bElems, v)
152 }
153 return Hash(bElems, nil)
154}