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.

186 lines
4.0 KiB

  1. // Keccak256 hash function (ethereum version).
  2. // For LICENSE check https://github.com/vocdoni/keccak256-circom/blob/master/LICENSE
  3. pragma circom 2.0.0;
  4. include "./utils.circom";
  5. include "./permutations.circom";
  6. template Pad(nBits) {
  7. signal input in[nBits];
  8. var blockSize=136*8;
  9. signal output out[blockSize];
  10. signal out2[blockSize];
  11. var i;
  12. for (i=0; i<nBits; i++) {
  13. out2[i] <== in[i];
  14. }
  15. var domain = 0x01;
  16. for (i=0; i<8; i++) {
  17. out2[nBits+i] <== (domain >> i) & 1;
  18. }
  19. for (i=nBits+8; i<blockSize; i++) {
  20. out2[i] <== 0;
  21. }
  22. component aux = OrArray(8);
  23. for (i=0; i<8; i++) {
  24. aux.a[i] <== out2[blockSize-8+i];
  25. aux.b[i] <== (0x80 >> i) & 1;
  26. }
  27. for (i=0; i<8; i++) {
  28. out[blockSize-8+i] <== aux.out[i];
  29. }
  30. for (i=0; i<blockSize-8; i++) {
  31. out[i]<==out2[i];
  32. }
  33. }
  34. template KeccakfRound(r) {
  35. signal input in[25*64];
  36. signal output out[25*64];
  37. var i;
  38. component theta = Theta();
  39. component rhopi = RhoPi();
  40. component chi = Chi();
  41. component iota = Iota(r);
  42. for (i=0; i<25*64; i++) {
  43. theta.in[i] <== in[i];
  44. }
  45. for (i=0; i<25*64; i++) {
  46. rhopi.in[i] <== theta.out[i];
  47. }
  48. for (i=0; i<25*64; i++) {
  49. chi.in[i] <== rhopi.out[i];
  50. }
  51. for (i=0; i<25*64; i++) {
  52. iota.in[i] <== chi.out[i];
  53. }
  54. for (i=0; i<25*64; i++) {
  55. out[i] <== iota.out[i];
  56. }
  57. }
  58. template Absorb() {
  59. var blockSizeBytes=136;
  60. signal input s[25*64];
  61. signal input block[blockSizeBytes*8];
  62. signal output out[25*64];
  63. var i;
  64. var j;
  65. component aux[blockSizeBytes/8];
  66. component newS = Keccakf();
  67. for (i=0; i<blockSizeBytes/8; i++) {
  68. aux[i] = XorArray(64);
  69. for (j=0; j<64; j++) {
  70. aux[i].a[j] <== s[i*64+j];
  71. aux[i].b[j] <== block[i*64+j];
  72. }
  73. for (j=0; j<64; j++) {
  74. newS.in[i*64+j] <== aux[i].out[j];
  75. }
  76. }
  77. // fill the missing s that was not covered by the loop over
  78. // blockSizeBytes/8
  79. for (i=(blockSizeBytes/8)*64; i<25*64; i++) {
  80. newS.in[i] <== s[i];
  81. }
  82. for (i=0; i<25*64; i++) {
  83. out[i] <== newS.out[i];
  84. }
  85. }
  86. template Final(nBits) {
  87. signal input in[nBits];
  88. signal output out[25*64];
  89. var blockSize=136*8;
  90. var i;
  91. // pad
  92. component pad = Pad(nBits);
  93. for (i=0; i<nBits; i++) {
  94. pad.in[i] <== in[i];
  95. }
  96. // absorb
  97. component abs = Absorb();
  98. for (i=0; i<blockSize; i++) {
  99. abs.block[i] <== pad.out[i];
  100. }
  101. for (i=0; i<25*64; i++) {
  102. abs.s[i] <== 0;
  103. }
  104. for (i=0; i<25*64; i++) {
  105. out[i] <== abs.out[i];
  106. }
  107. }
  108. template Squeeze(nBits) {
  109. signal input s[25*64];
  110. signal output out[nBits];
  111. var i;
  112. var j;
  113. for (i=0; i<25; i++) {
  114. for (j=0; j<64; j++) {
  115. if (i*64+j<nBits) {
  116. out[i*64+j] <== s[i*64+j];
  117. }
  118. }
  119. }
  120. }
  121. template Keccakf() {
  122. signal input in[25*64];
  123. signal output out[25*64];
  124. var i;
  125. var j;
  126. // 24 rounds
  127. component round[24];
  128. signal midRound[24*25*64];
  129. for (i=0; i<24; i++) {
  130. round[i] = KeccakfRound(i);
  131. if (i==0) {
  132. for (j=0; j<25*64; j++) {
  133. midRound[j] <== in[j];
  134. }
  135. }
  136. for (j=0; j<25*64; j++) {
  137. round[i].in[j] <== midRound[i*25*64+j];
  138. }
  139. if (i<23) {
  140. for (j=0; j<25*64; j++) {
  141. midRound[(i+1)*25*64+j] <== round[i].out[j];
  142. }
  143. }
  144. }
  145. for (i=0; i<25*64; i++) {
  146. out[i] <== round[23].out[i];
  147. }
  148. }
  149. template Keccak(nBitsIn, nBitsOut) {
  150. signal input in[nBitsIn];
  151. signal output out[nBitsOut];
  152. var i;
  153. component f = Final(nBitsIn);
  154. for (i=0; i<nBitsIn; i++) {
  155. f.in[i] <== in[i];
  156. }
  157. component squeeze = Squeeze(nBitsOut);
  158. for (i=0; i<25*64; i++) {
  159. squeeze.s[i] <== f.out[i];
  160. }
  161. for (i=0; i<nBitsOut; i++) {
  162. out[i] <== squeeze.out[i];
  163. }
  164. }