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.

105 lines
2.2 KiB

  1. package poseidon
  2. import (
  3. "math/big"
  4. "github.com/iden3/go-iden3-crypto/ffg"
  5. )
  6. func zero() *ffg.Element {
  7. return ffg.NewElement()
  8. }
  9. // exp7 performs x^7 mod p
  10. func exp7(a *ffg.Element) {
  11. a.Exp(*a, big.NewInt(7)) //nolint:gomnd
  12. }
  13. // exp7state perform exp7 for whole state
  14. func exp7state(state []*ffg.Element) {
  15. for i := 0; i < len(state); i++ {
  16. exp7(state[i])
  17. }
  18. }
  19. // ark computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
  20. func ark(state []*ffg.Element, it int) {
  21. for i := 0; i < len(state); i++ {
  22. state[i].Add(state[i], C[it+i])
  23. }
  24. }
  25. // mix returns [[matrix]] * [vector]
  26. func mix(state []*ffg.Element, opt bool) []*ffg.Element {
  27. mul := zero()
  28. newState := make([]*ffg.Element, mLen)
  29. for i := 0; i < mLen; i++ {
  30. newState[i] = zero()
  31. }
  32. for i := 0; i < mLen; i++ {
  33. newState[i].SetUint64(0)
  34. for j := 0; j < mLen; j++ {
  35. if opt {
  36. mul.Mul(P[j][i], state[j])
  37. } else {
  38. mul.Mul(M[j][i], state[j])
  39. }
  40. newState[i].Add(newState[i], mul)
  41. }
  42. }
  43. return newState
  44. }
  45. // Hash computes the hash for the given inputs
  46. func Hash(inpBI [NROUNDSF]uint64, capBI [CAPLEN]uint64) ([CAPLEN]uint64, error) {
  47. state := make([]*ffg.Element, mLen)
  48. for i := 0; i < NROUNDSF; i++ {
  49. state[i] = ffg.NewElement().SetUint64(inpBI[i])
  50. }
  51. for i := 0; i < CAPLEN; i++ {
  52. state[i+NROUNDSF] = ffg.NewElement().SetUint64(capBI[i])
  53. }
  54. for i := 0; i < mLen; i++ {
  55. state[i].Add(state[i], C[i])
  56. }
  57. for r := 0; r < NROUNDSF/2; r++ {
  58. exp7state(state)
  59. ark(state, (r+1)*mLen)
  60. state = mix(state, r == NROUNDSF/2-1)
  61. }
  62. for r := 0; r < NROUNDSP; r++ {
  63. exp7(state[0])
  64. state[0].Add(state[0], C[(NROUNDSF/2+1)*mLen+r])
  65. s0 := zero()
  66. mul := zero()
  67. mul.Mul(S[(mLen*2-1)*r], state[0])
  68. s0.Add(s0, mul)
  69. for i := 1; i < mLen; i++ {
  70. mul.Mul(S[(mLen*2-1)*r+i], state[i])
  71. s0.Add(s0, mul)
  72. mul.Mul(S[(mLen*2-1)*r+mLen+i-1], state[0])
  73. state[i].Add(state[i], mul)
  74. }
  75. state[0] = s0
  76. }
  77. for r := 0; r < NROUNDSF/2; r++ {
  78. exp7state(state)
  79. if r < NROUNDSF/2-1 {
  80. ark(state, (NROUNDSF/2+1+r)*mLen+NROUNDSP)
  81. }
  82. state = mix(state, false)
  83. }
  84. return [CAPLEN]uint64{
  85. state[0].ToUint64Regular(),
  86. state[1].ToUint64Regular(),
  87. state[2].ToUint64Regular(),
  88. state[3].ToUint64Regular(),
  89. }, nil
  90. }