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.

142 lines
3.1 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. // arkOpt computes Add-Round Key, from the paper https://eprint.iacr.org/2019/458.pdf
  26. func arkOpt(state []*ffg.Element, it int) {
  27. for i := 0; i < len(state); i++ {
  28. state[i].Add(state[i], COpt[it+i])
  29. }
  30. }
  31. // mix returns [[matrix]] * [vector]
  32. func mix(state []*ffg.Element, opt bool) []*ffg.Element {
  33. mul := zero()
  34. newState := make([]*ffg.Element, mLen)
  35. for i := 0; i < mLen; i++ {
  36. newState[i] = zero()
  37. }
  38. for i := 0; i < mLen; i++ {
  39. newState[i].SetUint64(0)
  40. for j := 0; j < mLen; j++ {
  41. if opt {
  42. mul.Mul(P[j][i], state[j])
  43. } else {
  44. mul.Mul(M[j][i], state[j])
  45. }
  46. newState[i].Add(newState[i], mul)
  47. }
  48. }
  49. return newState
  50. }
  51. // Hash computes the Poseidon hash for the given inputs
  52. func Hash(inpBI [NROUNDSF]uint64, capBI [CAPLEN]uint64) ([CAPLEN]uint64, error) {
  53. state := make([]*ffg.Element, mLen)
  54. for i := 0; i < NROUNDSF; i++ {
  55. state[i] = ffg.NewElement().SetUint64(inpBI[i])
  56. }
  57. for i := 0; i < CAPLEN; i++ {
  58. state[i+NROUNDSF] = ffg.NewElement().SetUint64(capBI[i])
  59. }
  60. for r := 0; r < NROUNDSF+NROUNDSP; r++ {
  61. ark(state, r*mLen)
  62. if r < NROUNDSF/2 || r >= NROUNDSF/2+NROUNDSP {
  63. exp7state(state)
  64. } else {
  65. exp7(state[0])
  66. }
  67. state = mix(state, false)
  68. }
  69. return [CAPLEN]uint64{
  70. state[0].ToUint64Regular(),
  71. state[1].ToUint64Regular(),
  72. state[2].ToUint64Regular(),
  73. state[3].ToUint64Regular(),
  74. }, nil
  75. }
  76. // NeptuneHash computes the hash for the given inputs
  77. func NeptuneHash(inpBI [NROUNDSF]uint64, capBI [CAPLEN]uint64) ([CAPLEN]uint64, error) {
  78. state := make([]*ffg.Element, mLen)
  79. for i := 0; i < NROUNDSF; i++ {
  80. state[i] = ffg.NewElement().SetUint64(inpBI[i])
  81. }
  82. for i := 0; i < CAPLEN; i++ {
  83. state[i+NROUNDSF] = ffg.NewElement().SetUint64(capBI[i])
  84. }
  85. for i := 0; i < mLen; i++ {
  86. state[i].Add(state[i], COpt[i])
  87. }
  88. for r := 0; r < NROUNDSF/2; r++ {
  89. exp7state(state)
  90. arkOpt(state, (r+1)*mLen)
  91. state = mix(state, r == NROUNDSF/2-1)
  92. }
  93. for r := 0; r < NROUNDSP; r++ {
  94. exp7(state[0])
  95. state[0].Add(state[0], COpt[(NROUNDSF/2+1)*mLen+r])
  96. s0 := zero()
  97. mul := zero()
  98. mul.Mul(S[(mLen*2-1)*r], state[0])
  99. s0.Add(s0, mul)
  100. for i := 1; i < mLen; i++ {
  101. mul.Mul(S[(mLen*2-1)*r+i], state[i])
  102. s0.Add(s0, mul)
  103. mul.Mul(S[(mLen*2-1)*r+mLen+i-1], state[0])
  104. state[i].Add(state[i], mul)
  105. }
  106. state[0] = s0
  107. }
  108. for r := 0; r < NROUNDSF/2; r++ {
  109. exp7state(state)
  110. if r < NROUNDSF/2-1 {
  111. arkOpt(state, (NROUNDSF/2+1+r)*mLen+NROUNDSP)
  112. }
  113. state = mix(state, false)
  114. }
  115. return [CAPLEN]uint64{
  116. state[0].ToUint64Regular(),
  117. state[1].ToUint64Regular(),
  118. state[2].ToUint64Regular(),
  119. state[3].ToUint64Regular(),
  120. }, nil
  121. }