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.

208 lines
5.0 KiB

  1. pragma circom 2.0.0;
  2. include "./poseidon_constants.circom";
  3. template Sigma() {
  4. signal input in;
  5. signal output out;
  6. signal in2;
  7. signal in4;
  8. in2 <== in*in;
  9. in4 <== in2*in2;
  10. out <== in4*in;
  11. }
  12. template Ark(t, C, r) {
  13. signal input in[t];
  14. signal output out[t];
  15. for (var i=0; i<t; i++) {
  16. out[i] <== in[i] + C[i + r];
  17. }
  18. }
  19. template Mix(t, M) {
  20. signal input in[t];
  21. signal output out[t];
  22. var lc;
  23. for (var i=0; i<t; i++) {
  24. lc = 0;
  25. for (var j=0; j<t; j++) {
  26. lc += M[j][i]*in[j];
  27. }
  28. out[i] <== lc;
  29. }
  30. }
  31. template MixLast(t, M, s) {
  32. signal input in[t];
  33. signal output out;
  34. var lc = 0;
  35. for (var j=0; j<t; j++) {
  36. lc += M[j][s]*in[j];
  37. }
  38. out <== lc;
  39. }
  40. template MixS(t, S, r) {
  41. signal input in[t];
  42. signal output out[t];
  43. var lc = 0;
  44. for (var i=0; i<t; i++) {
  45. lc += S[(t*2-1)*r+i]*in[i];
  46. }
  47. out[0] <== lc;
  48. for (var i=1; i<t; i++) {
  49. out[i] <== in[i] + in[0] * S[(t*2-1)*r + t + i -1];
  50. }
  51. }
  52. template PoseidonEx(nInputs, nOuts) {
  53. signal input inputs[nInputs];
  54. signal input initialState;
  55. signal output out[nOuts];
  56. // Using recommended parameters from whitepaper https://eprint.iacr.org/2019/458.pdf (table 2, table 8)
  57. // Generated by https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/calc_round_numbers.py
  58. // And rounded up to nearest integer that divides by t
  59. var N_ROUNDS_P[16] = [56, 57, 56, 60, 60, 63, 64, 63, 60, 66, 60, 65, 70, 60, 64, 68];
  60. var t = nInputs + 1;
  61. var nRoundsF = 8;
  62. var nRoundsP = N_ROUNDS_P[t - 2];
  63. var C[t*nRoundsF + nRoundsP] = POSEIDON_C(t);
  64. var S[ N_ROUNDS_P[t-2] * (t*2-1) ] = POSEIDON_S(t);
  65. var M[t][t] = POSEIDON_M(t);
  66. var P[t][t] = POSEIDON_P(t);
  67. component ark[nRoundsF];
  68. component sigmaF[nRoundsF][t];
  69. component sigmaP[nRoundsP];
  70. component mix[nRoundsF-1];
  71. component mixS[nRoundsP];
  72. component mixLast[nOuts];
  73. ark[0] = Ark(t, C, 0);
  74. for (var j=0; j<t; j++) {
  75. if (j>0) {
  76. ark[0].in[j] <== inputs[j-1];
  77. } else {
  78. ark[0].in[j] <== initialState;
  79. }
  80. }
  81. for (var r = 0; r < nRoundsF\2-1; r++) {
  82. for (var j=0; j<t; j++) {
  83. sigmaF[r][j] = Sigma();
  84. if(r==0) {
  85. sigmaF[r][j].in <== ark[0].out[j];
  86. } else {
  87. sigmaF[r][j].in <== mix[r-1].out[j];
  88. }
  89. }
  90. ark[r+1] = Ark(t, C, (r+1)*t);
  91. for (var j=0; j<t; j++) {
  92. ark[r+1].in[j] <== sigmaF[r][j].out;
  93. }
  94. mix[r] = Mix(t,M);
  95. for (var j=0; j<t; j++) {
  96. mix[r].in[j] <== ark[r+1].out[j];
  97. }
  98. }
  99. for (var j=0; j<t; j++) {
  100. sigmaF[nRoundsF\2-1][j] = Sigma();
  101. sigmaF[nRoundsF\2-1][j].in <== mix[nRoundsF\2-2].out[j];
  102. }
  103. ark[nRoundsF\2] = Ark(t, C, (nRoundsF\2)*t );
  104. for (var j=0; j<t; j++) {
  105. ark[nRoundsF\2].in[j] <== sigmaF[nRoundsF\2-1][j].out;
  106. }
  107. mix[nRoundsF\2-1] = Mix(t,P);
  108. for (var j=0; j<t; j++) {
  109. mix[nRoundsF\2-1].in[j] <== ark[nRoundsF\2].out[j];
  110. }
  111. for (var r = 0; r < nRoundsP; r++) {
  112. sigmaP[r] = Sigma();
  113. if (r==0) {
  114. sigmaP[r].in <== mix[nRoundsF\2-1].out[0];
  115. } else {
  116. sigmaP[r].in <== mixS[r-1].out[0];
  117. }
  118. mixS[r] = MixS(t, S, r);
  119. for (var j=0; j<t; j++) {
  120. if (j==0) {
  121. mixS[r].in[j] <== sigmaP[r].out + C[(nRoundsF\2+1)*t + r];
  122. } else {
  123. if (r==0) {
  124. mixS[r].in[j] <== mix[nRoundsF\2-1].out[j];
  125. } else {
  126. mixS[r].in[j] <== mixS[r-1].out[j];
  127. }
  128. }
  129. }
  130. }
  131. for (var r = 0; r < nRoundsF\2-1; r++) {
  132. for (var j=0; j<t; j++) {
  133. sigmaF[nRoundsF\2 + r][j] = Sigma();
  134. if (r==0) {
  135. sigmaF[nRoundsF\2 + r][j].in <== mixS[nRoundsP-1].out[j];
  136. } else {
  137. sigmaF[nRoundsF\2 + r][j].in <== mix[nRoundsF\2+r-1].out[j];
  138. }
  139. }
  140. ark[ nRoundsF\2 + r + 1] = Ark(t, C, (nRoundsF\2+1)*t + nRoundsP + r*t );
  141. for (var j=0; j<t; j++) {
  142. ark[nRoundsF\2 + r + 1].in[j] <== sigmaF[nRoundsF\2 + r][j].out;
  143. }
  144. mix[nRoundsF\2 + r] = Mix(t,M);
  145. for (var j=0; j<t; j++) {
  146. mix[nRoundsF\2 + r].in[j] <== ark[nRoundsF\2 + r + 1].out[j];
  147. }
  148. }
  149. for (var j=0; j<t; j++) {
  150. sigmaF[nRoundsF-1][j] = Sigma();
  151. sigmaF[nRoundsF-1][j].in <== mix[nRoundsF-2].out[j];
  152. }
  153. for (var i=0; i<nOuts; i++) {
  154. mixLast[i] = MixLast(t,M,i);
  155. for (var j=0; j<t; j++) {
  156. mixLast[i].in[j] <== sigmaF[nRoundsF-1][j].out;
  157. }
  158. out[i] <== mixLast[i].out;
  159. }
  160. }
  161. template Poseidon(nInputs) {
  162. signal input inputs[nInputs];
  163. signal output out;
  164. component pEx = PoseidonEx(nInputs, 1);
  165. pEx.initialState <== 0;
  166. for (var i=0; i<nInputs; i++) {
  167. pEx.inputs[i] <== inputs[i];
  168. }
  169. out <== pEx.out[0];
  170. }