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