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.

201 lines
4.2 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()
  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()) {
  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. func cubic(a *ff.Element) {
  83. a.Exp(*a, 5)
  84. }
  85. // sbox https://eprint.iacr.org/2019/458.pdf page 6
  86. func sbox(state [T]*ff.Element, i int) {
  87. if (i < NROUNDSF/2) || (i >= NROUNDSF/2+NROUNDSP) {
  88. for j := 0; j < T; j++ {
  89. cubic(state[j])
  90. }
  91. } else {
  92. cubic(state[0])
  93. }
  94. }
  95. // mix returns [[matrix]] * [vector]
  96. func mix(state [T]*ff.Element, newState [T]*ff.Element, m [T][T]*ff.Element) {
  97. mul := Zero()
  98. for i := 0; i < T; i++ {
  99. newState[i].SetUint64(0)
  100. for j := 0; j < T; j++ {
  101. mul.Mul(m[i][j], state[j])
  102. newState[i].Add(newState[i], mul)
  103. }
  104. }
  105. }
  106. // PoseidonHash computes the Poseidon hash for the given inputs
  107. func PoseidonHash(inpBI [T]*big.Int) (*big.Int, error) {
  108. if !utils.CheckBigIntArrayInField(inpBI[:]) {
  109. return nil, errors.New("inputs values not inside Finite Field")
  110. }
  111. inp := utils.BigIntArrayToElementArray(inpBI[:])
  112. state := [T]*ff.Element{}
  113. for i := 0; i < T; i++ {
  114. state[i] = ff.NewElement().Set(inp[i])
  115. }
  116. // ARK --> SBox --> M, https://eprint.iacr.org/2019/458.pdf pag.5
  117. var newState [T]*ff.Element
  118. for i := 0; i < T; i++ {
  119. newState[i] = Zero()
  120. }
  121. for i := 0; i < NROUNDSF+NROUNDSP; i++ {
  122. ark(state, constC[i])
  123. sbox(state, i)
  124. mix(state, newState, constM)
  125. state, newState = newState, state
  126. }
  127. rE := state[0]
  128. r := big.NewInt(0)
  129. rE.ToBigIntRegular(r)
  130. return r, nil
  131. }
  132. // Hash performs the Poseidon hash over a ff.Element array
  133. // in chunks of 5 elements
  134. func Hash(arr []*big.Int) (*big.Int, error) {
  135. r := big.NewInt(int64(1))
  136. for i := 0; i < len(arr); i = i + T - 1 {
  137. var toHash [T]*big.Int
  138. j := 0
  139. for ; j < T-1; j++ {
  140. if i+j >= len(arr) {
  141. break
  142. }
  143. toHash[j] = arr[i+j]
  144. }
  145. toHash[j] = r
  146. j++
  147. for ; j < T; j++ {
  148. toHash[j] = big.NewInt(0)
  149. }
  150. ph, err := PoseidonHash(toHash)
  151. if err != nil {
  152. return nil, err
  153. }
  154. modQ(r.Add(r, ph))
  155. }
  156. return r, nil
  157. }
  158. // HashBytes hashes a msg byte slice by blocks of 31 bytes encoded as
  159. // little-endian
  160. func HashBytes(b []byte) *big.Int {
  161. n := 31
  162. bElems := make([]*big.Int, 0, len(b)/n+1)
  163. for i := 0; i < len(b)/n; i++ {
  164. v := big.NewInt(int64(0))
  165. utils.SetBigIntFromLEBytes(v, b[n*i:n*(i+1)])
  166. bElems = append(bElems, v)
  167. }
  168. if len(b)%n != 0 {
  169. v := big.NewInt(int64(0))
  170. utils.SetBigIntFromLEBytes(v, b[(len(b)/n)*n:])
  171. bElems = append(bElems, v)
  172. }
  173. h, err := Hash(bElems)
  174. if err != nil {
  175. panic(err)
  176. }
  177. return h
  178. }