You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
4.1 KiB

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