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.

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