poseidon.sage 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #!/usr/bin/env python3
  2. import numpy
  3. from constants import round_constants, MDS_matrix
  4. # Width
  5. T = 3
  6. # Full rounds
  7. R_F = 8
  8. # Partial rounds
  9. R_P = 56
  10. # Sponge rate
  11. RATE = 2
  12. # pallas
  13. p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001
  14. Fp = GF(p)
  15. MDS_MATRIX = numpy.array([[Fp(0)] * T] * T)
  16. ROUND_CONSTANTS = []
  17. for i in range(0, T):
  18. for j in range(0, T):
  19. MDS_MATRIX[i][j] = Fp(MDS_matrix[i][j])
  20. for i in range(0, R_F + R_P):
  21. for j in range(0, T):
  22. ROUND_CONSTANTS.append(Fp(round_constants[i][j]))
  23. def perm(inp):
  24. half_full_rounds = int(R_F / 2)
  25. state_words = numpy.array(inp)
  26. rcf = ROUND_CONSTANTS.copy()
  27. # First full rounds
  28. for _ in range(0, half_full_rounds):
  29. # Round constants, nonlinear layer, matrix multiplication
  30. for i in range(0, T):
  31. state_words[i] = state_words[i] + rcf[0]
  32. rcf.pop(0)
  33. for i in range(0, T):
  34. state_words[i] = (state_words[i])**5 # sbox
  35. state_words = numpy.array(numpy.dot(MDS_MATRIX, state_words))
  36. # Middle partial rounds
  37. for _ in range(0, R_P):
  38. # Round constants, nonlinear layer, matrix multiplication
  39. for i in range(0, T):
  40. state_words[i] = state_words[i] + rcf[0]
  41. rcf.pop(0)
  42. state_words[0] = (state_words[0])**5 # sbox
  43. state_words = numpy.array(numpy.dot(MDS_MATRIX, state_words))
  44. # Last full rounds
  45. for _ in range(0, half_full_rounds):
  46. # Round constants, nonlinear layer, matrix multiplication
  47. for i in range(0, T):
  48. state_words[i] = state_words[i] + rcf[0]
  49. rcf.pop(0)
  50. for i in range(0, T):
  51. state_words[i] = (state_words[i])**5 # sbox
  52. state_words = numpy.array(numpy.dot(MDS_MATRIX, state_words))
  53. return state_words
  54. def poseidon_hash(messages):
  55. L = len(messages)
  56. k = int((L + RATE - 1) / RATE)
  57. padding = [Fp(0)] * (k * RATE - L)
  58. messages.extend(padding)
  59. # Sponge
  60. mode = [None] * RATE
  61. output = [None] * RATE
  62. state = [Fp(0)] * T
  63. # Capacity value is L ⋅ 2^64 + (o-1) where o is the output length
  64. initial_capacity_element = Fp(L << 64)
  65. state[RATE] = initial_capacity_element
  66. # This outermost loop absorbs the messages in the sponge.
  67. for n, value in enumerate(messages):
  68. loop = False # Use this to mark we should reiterate
  69. for i in range(0, len(mode)):
  70. if mode[i] is None:
  71. mode[i] = value
  72. loop = True
  73. break
  74. if loop:
  75. continue
  76. # zip short-circuits when one iterator completes, so this will
  77. # only mutate the rate portion of the state.
  78. for i, _ in enumerate(zip(state, mode)):
  79. state[i] += mode[i]
  80. # Permutation of the current state
  81. state = perm(state)
  82. for i, _ in enumerate(zip(output, state)):
  83. output[i] = state[i]
  84. # Reinit sponge with the current message as the first value.
  85. mode = [None] * RATE
  86. mode[0] = value
  87. for i, _ in enumerate(zip(state, mode)):
  88. state[i] += mode[i]
  89. # Permutation of the final state
  90. state = perm(state)
  91. for i, _ in enumerate(zip(output, state)):
  92. output[i] = state[i]
  93. # Sponge now has the output, so the first element is our hash.
  94. mode = output
  95. return output[0]
  96. if __name__ == "__main__":
  97. words = []
  98. for word in range(0, 10):
  99. words.append(Fp(word))
  100. h = poseidon_hash(words.copy())
  101. print(hex(int(h)))