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.

166 lines
3.9 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
  1. package poseidon
  2. import (
  3. "bytes"
  4. "errors"
  5. "math/big"
  6. "strconv"
  7. _constants "github.com/iden3/go-iden3-crypto/constants"
  8. "github.com/iden3/go-iden3-crypto/field"
  9. "github.com/iden3/go-iden3-crypto/utils"
  10. "golang.org/x/crypto/blake2b"
  11. )
  12. const SEED = "poseidon"
  13. const NROUNDSF = 8
  14. const NROUNDSP = 57
  15. const T = 6
  16. var constants = generateConstantsData()
  17. type constantsData struct {
  18. fqR field.Fq
  19. c []*big.Int
  20. m [][]*big.Int
  21. }
  22. func generateConstantsData() constantsData {
  23. var constants constantsData
  24. fqR := field.NewFq(_constants.Q)
  25. constants.fqR = fqR
  26. constants.c = getPseudoRandom(fqR, SEED+"_constants", NROUNDSF+NROUNDSP)
  27. constants.m = getMDS(fqR)
  28. return constants
  29. }
  30. func leByteArrayToBigInt(b []byte) *big.Int {
  31. res := big.NewInt(0)
  32. for i := 0; i < len(b); i++ {
  33. n := big.NewInt(int64(b[i]))
  34. res = new(big.Int).Add(res, new(big.Int).Lsh(n, uint(i*8)))
  35. }
  36. return res
  37. }
  38. func getPseudoRandom(fqR field.Fq, seed string, n int) []*big.Int {
  39. var res []*big.Int
  40. hash := blake2b.Sum256([]byte(seed))
  41. for len(res) < n {
  42. hashBigInt := new(big.Int)
  43. newN := fqR.Affine(utils.SetBigIntFromLEBytes(hashBigInt, hash[:]))
  44. // newN := fqR.Affine(leByteArrayToBigInt(hash[:]))
  45. res = append(res, newN)
  46. hash = blake2b.Sum256(hash[:])
  47. }
  48. return res
  49. }
  50. func nonceToString(n int) string {
  51. r := strconv.Itoa(n)
  52. for len(r) < 4 {
  53. r = "0" + r
  54. }
  55. return r
  56. }
  57. // https://eprint.iacr.org/2019/458.pdf pag.8
  58. func getMDS(fqR field.Fq) [][]*big.Int {
  59. nonce := 0
  60. cauchyMatrix := getPseudoRandom(fqR, SEED+"_matrix_"+nonceToString(nonce), T*2)
  61. for !checkAllDifferent(cauchyMatrix) {
  62. nonce += 1
  63. cauchyMatrix = getPseudoRandom(fqR, SEED+"_matrix_"+nonceToString(nonce), T*2)
  64. }
  65. var m [][]*big.Int
  66. for i := 0; i < T; i++ {
  67. var mi []*big.Int
  68. for j := 0; j < T; j++ {
  69. mi = append(mi, fqR.Inverse(fqR.Sub(cauchyMatrix[i], cauchyMatrix[T+j])))
  70. }
  71. m = append(m, mi)
  72. }
  73. return m
  74. }
  75. func checkAllDifferent(v []*big.Int) bool {
  76. for i := 0; i < len(v); i++ {
  77. if bytes.Equal(v[i].Bytes(), big.NewInt(int64(0)).Bytes()) {
  78. return false
  79. }
  80. for j := i + 1; j < len(v); j++ {
  81. if bytes.Equal(v[i].Bytes(), v[j].Bytes()) {
  82. return false
  83. }
  84. }
  85. }
  86. return true
  87. }
  88. // ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
  89. func ark(state []*big.Int, c *big.Int) []*big.Int {
  90. for i := 0; i < len(state); i++ {
  91. state[i] = constants.fqR.Add(state[i], c)
  92. }
  93. return state
  94. }
  95. // cubic performs x^3 mod p
  96. func cubic(a *big.Int) *big.Int {
  97. return constants.fqR.Mul(a, constants.fqR.Square(constants.fqR.Square(a)))
  98. }
  99. // sbox https://eprint.iacr.org/2019/458.pdf pag.6
  100. func sbox(state []*big.Int, i int) []*big.Int {
  101. if (i < NROUNDSF/2) || (i >= NROUNDSF/2+NROUNDSP) {
  102. for j := 0; j < T; j++ {
  103. state[j] = cubic(state[j])
  104. }
  105. } else {
  106. state[0] = cubic(state[0])
  107. }
  108. return state
  109. }
  110. // mix returns [[matrix]] * [vector]
  111. func mix(state []*big.Int, m [][]*big.Int) []*big.Int {
  112. var newState []*big.Int
  113. for i := 0; i < len(state); i++ {
  114. newState = append(newState, constants.fqR.Zero())
  115. for j := 0; j < len(state); j++ {
  116. newState[i] = constants.fqR.Add(newState[i], constants.fqR.Mul(m[i][j], state[j]))
  117. }
  118. }
  119. for i := 0; i < len(state); i++ {
  120. state[i] = newState[i]
  121. }
  122. return state
  123. }
  124. // Hash computes the Poseidon hash for the given inputs
  125. func Hash(inp []*big.Int) (*big.Int, error) {
  126. var state []*big.Int
  127. if len(inp) == 0 || len(inp) > T {
  128. return nil, errors.New("wrong inputs length")
  129. }
  130. if !utils.CheckBigIntArrayInField(inp, constants.fqR.Q) {
  131. return nil, errors.New("inputs values not inside Finite Field")
  132. }
  133. for i := 0; i < len(inp); i++ {
  134. state = append(state, inp[i])
  135. }
  136. for i := len(inp); i < T; i++ {
  137. state = append(state, constants.fqR.Zero())
  138. }
  139. // ARK --> SBox --> M, https://eprint.iacr.org/2019/458.pdf pag.5
  140. for i := 0; i < NROUNDSF+NROUNDSP; i++ {
  141. state = ark(state, constants.c[i])
  142. state = sbox(state, i)
  143. state = mix(state, constants.m)
  144. }
  145. return state[0], nil
  146. }