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.

198 lines
4.3 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. package poseidon
  2. import (
  3. "errors"
  4. "math/big"
  5. "strconv"
  6. "github.com/iden3/go-iden3-crypto/constants"
  7. "github.com/iden3/go-iden3-crypto/ff"
  8. "github.com/iden3/go-iden3-crypto/utils"
  9. "golang.org/x/crypto/blake2b"
  10. )
  11. const SEED = "poseidon"
  12. const NROUNDSF = 8
  13. const NROUNDSP = 57
  14. const T = 6
  15. var constC []*ff.Element
  16. var constM [T][T]*ff.Element
  17. func Zero() *ff.Element {
  18. return ff.NewElement().SetZero()
  19. }
  20. func modQ(v *big.Int) {
  21. v.Mod(v, constants.Q)
  22. }
  23. func init() {
  24. constC = getPseudoRandom(SEED+"_constants", NROUNDSF+NROUNDSP)
  25. constM = getMDS()
  26. }
  27. func getPseudoRandom(seed string, n int) []*ff.Element {
  28. res := make([]*ff.Element, n)
  29. hash := blake2b.Sum256([]byte(seed))
  30. for i := 0; i < n; i++ {
  31. hashBigInt := big.NewInt(int64(0))
  32. res[i] = ff.NewElement().SetBigInt(utils.SetBigIntFromLEBytes(hashBigInt, hash[:]))
  33. hash = blake2b.Sum256(hash[:])
  34. }
  35. return res
  36. }
  37. func nonceToString(n int) string {
  38. r := strconv.Itoa(n)
  39. for len(r) < 4 {
  40. r = "0" + r
  41. }
  42. return r
  43. }
  44. // https://eprint.iacr.org/2019/458.pdf pag.8
  45. func getMDS() [T][T]*ff.Element {
  46. nonce := 0
  47. cauchyMatrix := getPseudoRandom(SEED+"_matrix_"+nonceToString(nonce), T*2)
  48. for !checkAllDifferent(cauchyMatrix) {
  49. nonce += 1
  50. cauchyMatrix = getPseudoRandom(SEED+"_matrix_"+nonceToString(nonce), T*2)
  51. }
  52. var m [T][T]*ff.Element
  53. for i := 0; i < T; i++ {
  54. for j := 0; j < T; j++ {
  55. m[i][j] = ff.NewElement().Sub(cauchyMatrix[i], cauchyMatrix[T+j])
  56. m[i][j].Inverse(m[i][j])
  57. }
  58. }
  59. return m
  60. }
  61. func checkAllDifferent(v []*ff.Element) bool {
  62. for i := 0; i < len(v); i++ {
  63. if v[i].Equal(ff.NewElement().SetZero()) {
  64. return false
  65. }
  66. for j := i + 1; j < len(v); j++ {
  67. if v[i].Equal(v[j]) {
  68. return false
  69. }
  70. }
  71. }
  72. return true
  73. }
  74. // ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
  75. func ark(state [T]*ff.Element, c *ff.Element) {
  76. for i := 0; i < T; i++ {
  77. state[i].Add(state[i], c)
  78. }
  79. }
  80. // cubic performs x^5 mod p
  81. // https://eprint.iacr.org/2019/458.pdf page 8
  82. // var five = big.NewInt(5)
  83. func cubic(a *ff.Element) {
  84. a.Exp(*a, 5)
  85. }
  86. // sbox https://eprint.iacr.org/2019/458.pdf page 6
  87. func sbox(state [T]*ff.Element, i int) {
  88. if (i < NROUNDSF/2) || (i >= NROUNDSF/2+NROUNDSP) {
  89. for j := 0; j < T; j++ {
  90. cubic(state[j])
  91. }
  92. } else {
  93. cubic(state[0])
  94. }
  95. }
  96. // mix returns [[matrix]] * [vector]
  97. func mix(state [T]*ff.Element, newState [T]*ff.Element, m [T][T]*ff.Element) {
  98. mul := Zero()
  99. for i := 0; i < T; i++ {
  100. newState[i].SetUint64(0)
  101. for j := 0; j < T; j++ {
  102. mul.Mul(m[i][j], state[j])
  103. newState[i].Add(newState[i], mul)
  104. }
  105. }
  106. }
  107. // PoseidonHash computes the Poseidon hash for the given inputs
  108. func PoseidonHash(inpBI [T]*big.Int) (*big.Int, error) {
  109. if !utils.CheckBigIntArrayInField(inpBI[:]) {
  110. return nil, errors.New("inputs values not inside Finite Field")
  111. }
  112. inp := utils.BigIntArrayToElementArray(inpBI[:])
  113. state := [T]*ff.Element{}
  114. for i := 0; i < T; i++ {
  115. state[i] = ff.NewElement().Set(inp[i])
  116. }
  117. // ARK --> SBox --> M, https://eprint.iacr.org/2019/458.pdf pag.5
  118. var newState [T]*ff.Element
  119. for i := 0; i < T; i++ {
  120. newState[i] = Zero()
  121. }
  122. for i := 0; i < NROUNDSF+NROUNDSP; i++ {
  123. ark(state, constC[i])
  124. sbox(state, i)
  125. mix(state, newState, constM)
  126. state, newState = newState, state
  127. }
  128. rE := state[0]
  129. r := big.NewInt(0)
  130. rE.ToBigIntRegular(r)
  131. return r, nil
  132. }
  133. // Hash performs the Poseidon hash over a ff.Element array
  134. // in chunks of 5 elements
  135. func Hash(arr []*big.Int) (*big.Int, error) {
  136. r := big.NewInt(int64(1))
  137. for i := 0; i < len(arr); i = i + T - 1 {
  138. var toHash [T]*big.Int
  139. j := 0
  140. for ; j < T-1; j++ {
  141. if i+j >= len(arr) {
  142. break
  143. }
  144. toHash[j] = arr[i+j]
  145. }
  146. toHash[j] = r
  147. j++
  148. for ; j < T; j++ {
  149. toHash[j] = big.NewInt(0)
  150. }
  151. ph, err := PoseidonHash(toHash)
  152. if err != nil {
  153. return nil, err
  154. }
  155. modQ(r.Add(r, ph))
  156. }
  157. return r, nil
  158. }
  159. // HashBytes hashes a msg byte slice by blocks of 31 bytes encoded as
  160. // little-endian
  161. func HashBytes(b []byte) (*big.Int, error) {
  162. n := 31
  163. bElems := make([]*big.Int, 0, len(b)/n+1)
  164. for i := 0; i < len(b)/n; i++ {
  165. v := big.NewInt(int64(0))
  166. utils.SetBigIntFromLEBytes(v, b[n*i:n*(i+1)])
  167. bElems = append(bElems, v)
  168. }
  169. if len(b)%n != 0 {
  170. v := big.NewInt(int64(0))
  171. utils.SetBigIntFromLEBytes(v, b[(len(b)/n)*n:])
  172. bElems = append(bElems, v)
  173. }
  174. return Hash(bElems)
  175. }