poseidon.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #!/usr/bin/env python3
  2. import numpy
  3. from finite_fields.finitefield import IntegersModP
  4. from constants import MDS_matrix, round_constants
  5. T = 3
  6. R_F = 8
  7. R_P = 56
  8. RATE = 2
  9. p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
  10. Fp = IntegersModP(p)
  11. MDS_MATRIX = numpy.array([[Fp(0)] * T] * T)
  12. ROUND_CONSTANTS = []
  13. for i in range(0, T):
  14. for j in range(0, T):
  15. MDS_MATRIX[i][j] = Fp(MDS_matrix[i][j])
  16. for i in range(0, R_F + R_P):
  17. for j in range(0, T):
  18. ROUND_CONSTANTS.append(Fp(round_constants[i][j]))
  19. def perm(inp):
  20. half_full_rounds = int(R_F / 2)
  21. state_words = numpy.array(inp)
  22. rcf = ROUND_CONSTANTS.copy()
  23. # First full rounds
  24. for _ in range(0, half_full_rounds):
  25. # Round constants, nonlinear layer, matrix multiplication
  26. for i in range(0, T):
  27. state_words[i] = state_words[i] + rcf[0]
  28. rcf.pop(0)
  29. for i in range(0, T):
  30. state_words[i] = (state_words[i])**5
  31. state_words = numpy.array(numpy.dot(MDS_MATRIX, state_words))
  32. # Middle partial rounds
  33. for _ in range(0, R_P):
  34. # Round constants, nonlinear layer, matrix multiplication
  35. for i in range(0, T):
  36. state_words[i] = state_words[i] + rcf[0]
  37. rcf.pop(0)
  38. state_words[0] = (state_words[0])**5
  39. state_words = numpy.array(numpy.dot(MDS_MATRIX, state_words))
  40. # Last full rounds
  41. for _ in range(0, half_full_rounds):
  42. # Round constants, nonlinear layer, matrix multiplication
  43. for i in range(0, T):
  44. state_words[i] = state_words[i] + rcf[0]
  45. rcf.pop(0)
  46. for i in range(0, T):
  47. state_words[i] = (state_words[i])**5
  48. state_words = numpy.array(numpy.dot(MDS_MATRIX, state_words))
  49. return state_words
  50. def debug(w, n, s, m):
  51. if enable_debug:
  52. print(f"State {w} {n} absorb:")
  53. pprint([hex(int(i)) for i in s])
  54. print(f"Mode {w} {n} absorb:")
  55. pprint([hex(int(i)) if i is not None else None for i in m])
  56. def poseidon_hash(messages):
  57. L = len(messages)
  58. k = int((L + RATE - 1) / RATE)
  59. padding = [Fp(0)] * (k * RATE - L)
  60. messages.extend(padding)
  61. # Sponge
  62. mode = [None] * RATE
  63. output = [None] * RATE
  64. state = [Fp(0)] * T
  65. initial_capacity_element = Fp(L << 64)
  66. state[RATE] = initial_capacity_element
  67. # absorb sponge
  68. for n, value in enumerate(messages):
  69. debug("before", n + 1, state, mode)
  70. loop = False # Use this to mark we should reiterate
  71. for i in range(0, len(mode)):
  72. if mode[i] is None:
  73. mode[i] = value
  74. loop = True
  75. break
  76. if loop:
  77. debug("after", n + 1, state, mode)
  78. continue
  79. # zip short-circuits when one iterator completes, so this will
  80. # only mutate the rate portion of the state.
  81. for i, _ in enumerate(zip(state, mode)):
  82. state[i] += mode[i]
  83. state = perm(state)
  84. output = [None] * RATE
  85. for i, _ in enumerate(zip(output, state)):
  86. output[i] = state[i]
  87. mode = [None] * RATE
  88. mode[0] = value
  89. debug("after", n + 1, state, mode)
  90. debug("before", "final", state, mode)
  91. for i, _ in enumerate(zip(state, mode)):
  92. state[i] += mode[i]
  93. state = perm(state)
  94. output = [None] * RATE
  95. for i, _ in enumerate(zip(output, state)):
  96. output[i] = state[i]
  97. mode = output
  98. debug("after", "final", state, mode)
  99. return output[0]
  100. if __name__ == "__main__":
  101. enable_debug = False
  102. if enable_debug:
  103. from pprint import pprint
  104. #input_words = []
  105. #for i in range(0, T):
  106. # input_words.append(Fp(i))
  107. #output_words = perm(input_words)
  108. #print([hex(int(i)) for i in output_words])
  109. words = [Fp(1), Fp(2)]
  110. #words = [Fp(1), Fp(2), Fp(3), Fp(4), Fp(5)]
  111. h = poseidon_hash(words)
  112. print(hex(int(h)))