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.

158 lines
4.0 KiB

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