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.

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