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