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.

242 lines
5.4 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
  1. package poseidon
  2. import (
  3. "errors"
  4. "fmt"
  5. "math/big"
  6. "github.com/iden3/go-iden3-crypto/ff"
  7. "github.com/iden3/go-iden3-crypto/utils"
  8. )
  9. // NROUNDSF constant from Poseidon paper
  10. const NROUNDSF = 8
  11. // NROUNDSP constant from Poseidon paper
  12. var NROUNDSP = []int{56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68}
  13. const spongeChunkSize = 31
  14. const spongeInputs = 16
  15. func zero() *ff.Element {
  16. return ff.NewElement()
  17. }
  18. var big5 = big.NewInt(5)
  19. // exp5 performs x^5 mod p
  20. // https://eprint.iacr.org/2019/458.pdf page 8
  21. func exp5(a *ff.Element) {
  22. a.Exp(*a, big5)
  23. }
  24. // exp5state perform exp5 for whole state
  25. func exp5state(state []*ff.Element) {
  26. for i := 0; i < len(state); i++ {
  27. exp5(state[i])
  28. }
  29. }
  30. // ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
  31. func ark(state, c []*ff.Element, it int) {
  32. for i := 0; i < len(state); i++ {
  33. state[i].Add(state[i], c[it+i])
  34. }
  35. }
  36. // mix returns [[matrix]] * [vector]
  37. func mix(state []*ff.Element, t int, m [][]*ff.Element) []*ff.Element {
  38. mul := zero()
  39. newState := make([]*ff.Element, t)
  40. for i := 0; i < t; i++ {
  41. newState[i] = zero()
  42. }
  43. for i := 0; i < len(state); i++ {
  44. newState[i].SetUint64(0)
  45. for j := 0; j < len(state); j++ {
  46. mul.Mul(m[j][i], state[j])
  47. newState[i].Add(newState[i], mul)
  48. }
  49. }
  50. return newState
  51. }
  52. // Hash computes the Poseidon hash for the given inputs
  53. func Hash(inpBI []*big.Int) (*big.Int, error) {
  54. t := len(inpBI) + 1
  55. if len(inpBI) == 0 || len(inpBI) > len(NROUNDSP) {
  56. return nil, fmt.Errorf("invalid inputs length %d, max %d", len(inpBI), len(NROUNDSP))
  57. }
  58. if !utils.CheckBigIntArrayInField(inpBI) {
  59. return nil, errors.New("inputs values not inside Finite Field")
  60. }
  61. inp := utils.BigIntArrayToElementArray(inpBI)
  62. nRoundsF := NROUNDSF
  63. nRoundsP := NROUNDSP[t-2]
  64. C := c.c[t-2]
  65. S := c.s[t-2]
  66. M := c.m[t-2]
  67. P := c.p[t-2]
  68. state := make([]*ff.Element, t)
  69. state[0] = zero()
  70. copy(state[1:], inp)
  71. ark(state, C, 0)
  72. for i := 0; i < nRoundsF/2-1; i++ {
  73. exp5state(state)
  74. ark(state, C, (i+1)*t)
  75. state = mix(state, t, M)
  76. }
  77. exp5state(state)
  78. ark(state, C, (nRoundsF/2)*t)
  79. state = mix(state, t, P)
  80. mul := zero()
  81. for i := 0; i < nRoundsP; i++ {
  82. exp5(state[0])
  83. state[0].Add(state[0], C[(nRoundsF/2+1)*t+i])
  84. mul.SetZero()
  85. newState0 := zero()
  86. for j := 0; j < len(state); j++ {
  87. mul.Mul(S[(t*2-1)*i+j], state[j])
  88. newState0.Add(newState0, mul)
  89. }
  90. for k := 1; k < t; k++ {
  91. mul.SetZero()
  92. state[k] = state[k].Add(state[k], mul.Mul(state[0], S[(t*2-1)*i+t+k-1]))
  93. }
  94. state[0] = newState0
  95. }
  96. for i := 0; i < nRoundsF/2-1; i++ {
  97. exp5state(state)
  98. ark(state, C, (nRoundsF/2+1)*t+nRoundsP+i*t)
  99. state = mix(state, t, M)
  100. }
  101. exp5state(state)
  102. state = mix(state, t, M)
  103. rE := state[0]
  104. r := big.NewInt(0)
  105. rE.ToBigIntRegular(r)
  106. return r, nil
  107. }
  108. // HashBytes returns a sponge hash of a msg byte slice split into blocks of 31 bytes
  109. func HashBytes(msg []byte) (*big.Int, error) {
  110. return HashBytesX(msg, spongeInputs)
  111. }
  112. // HashBytesX returns a sponge hash of a msg byte slice split into blocks of 31 bytes
  113. func HashBytesX(msg []byte, frameSize int) (*big.Int, error) {
  114. if frameSize < 2 || frameSize > 16 {
  115. return nil, errors.New("incorrect frame size")
  116. }
  117. // not used inputs default to zero
  118. inputs := make([]*big.Int, frameSize)
  119. for j := 0; j < frameSize; j++ {
  120. inputs[j] = new(big.Int)
  121. }
  122. dirty := false
  123. var hash *big.Int
  124. var err error
  125. k := 0
  126. for i := 0; i < len(msg)/spongeChunkSize; i++ {
  127. dirty = true
  128. inputs[k].SetBytes(msg[spongeChunkSize*i : spongeChunkSize*(i+1)])
  129. if k == frameSize-1 {
  130. hash, err = Hash(inputs)
  131. dirty = false
  132. if err != nil {
  133. return nil, err
  134. }
  135. inputs = make([]*big.Int, frameSize)
  136. inputs[0] = hash
  137. for j := 1; j < frameSize; j++ {
  138. inputs[j] = new(big.Int)
  139. }
  140. k = 1
  141. } else {
  142. k++
  143. }
  144. }
  145. if len(msg)%spongeChunkSize != 0 {
  146. // the last chunk of the message is less than 31 bytes
  147. // zero padding it, so that 0xdeadbeaf becomes
  148. // 0xdeadbeaf000000000000000000000000000000000000000000000000000000
  149. var buf [spongeChunkSize]byte
  150. copy(buf[:], msg[(len(msg)/spongeChunkSize)*spongeChunkSize:])
  151. inputs[k] = new(big.Int).SetBytes(buf[:])
  152. dirty = true
  153. }
  154. if dirty {
  155. // we haven't hashed something in the main sponge loop and need to do hash here
  156. hash, err = Hash(inputs)
  157. if err != nil {
  158. return nil, err
  159. }
  160. }
  161. return hash, nil
  162. }
  163. // SpongeHash returns a sponge hash of inputs (using Poseidon with frame size of 16 inputs)
  164. func SpongeHash(inputs []*big.Int) (*big.Int, error) {
  165. return SpongeHashX(inputs, spongeInputs)
  166. }
  167. // SpongeHashX returns a sponge hash of inputs using Poseidon with configurable frame size
  168. func SpongeHashX(inputs []*big.Int, frameSize int) (*big.Int, error) {
  169. if frameSize < 2 || frameSize > 16 {
  170. return nil, errors.New("incorrect frame size")
  171. }
  172. // not used frame default to zero
  173. frame := make([]*big.Int, frameSize)
  174. for j := 0; j < frameSize; j++ {
  175. frame[j] = new(big.Int)
  176. }
  177. dirty := false
  178. var hash *big.Int
  179. var err error
  180. k := 0
  181. for i := 0; i < len(inputs); i++ {
  182. dirty = true
  183. frame[k] = inputs[i]
  184. if k == frameSize-1 {
  185. hash, err = Hash(frame)
  186. dirty = false
  187. if err != nil {
  188. return nil, err
  189. }
  190. frame = make([]*big.Int, frameSize)
  191. frame[0] = hash
  192. for j := 1; j < frameSize; j++ {
  193. frame[j] = new(big.Int)
  194. }
  195. k = 1
  196. } else {
  197. k++
  198. }
  199. }
  200. if dirty {
  201. // we haven't hashed something in the main sponge loop and need to do hash here
  202. hash, err = Hash(frame)
  203. if err != nil {
  204. return nil, err
  205. }
  206. }
  207. return hash, nil
  208. }