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.

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