pragma circom 2.0.0;
|
|
|
|
include "./utils.circom";
|
|
include "./theta.circom";
|
|
include "./rhopi.circom";
|
|
include "./chi.circom";
|
|
include "./iota.circom";
|
|
|
|
template Pad(nBits) {
|
|
signal input in[nBits];
|
|
|
|
var blockSize=136*8;
|
|
signal output out[blockSize];
|
|
signal out2[blockSize];
|
|
|
|
var i;
|
|
|
|
for (i=0; i<nBits; i++) {
|
|
out2[i] <== in[i];
|
|
}
|
|
var domain = 0x01;
|
|
for (i=0; i<8; i++) {
|
|
out2[nBits+i] <== (domain >> i) & 1;
|
|
}
|
|
for (i=nBits+8; i<blockSize; i++) {
|
|
out2[i] <== 0;
|
|
}
|
|
component aux = OrArray(8);
|
|
for (i=0; i<8; i++) {
|
|
aux.a[i] <== out2[blockSize-8+i];
|
|
aux.b[i] <== (0x80 >> i) & 1;
|
|
}
|
|
for (i=0; i<8; i++) {
|
|
out[blockSize-8+i] <== aux.out[i];
|
|
}
|
|
for (i=0; i<blockSize-8; i++) {
|
|
out[i]<==out2[i];
|
|
}
|
|
}
|
|
|
|
template KeccakfRound(r) {
|
|
signal input in[25*64];
|
|
signal output out[25*64];
|
|
var i;
|
|
|
|
component theta = Theta();
|
|
component rhopi = RhoPi();
|
|
component chi = Chi();
|
|
component iota = Iota(r);
|
|
|
|
for (i=0; i<25*64; i++) {
|
|
theta.in[i] <== in[i];
|
|
}
|
|
for (i=0; i<25*64; i++) {
|
|
rhopi.in[i] <== theta.out[i];
|
|
}
|
|
for (i=0; i<25*64; i++) {
|
|
chi.in[i] <== rhopi.out[i];
|
|
}
|
|
for (i=0; i<25*64; i++) {
|
|
iota.in[i] <== chi.out[i];
|
|
}
|
|
for (i=0; i<25*64; i++) {
|
|
out[i] <== iota.out[i];
|
|
}
|
|
}
|
|
|
|
template Absorb() {
|
|
var blockSizeBytes=136;
|
|
|
|
signal input s[25*64];
|
|
signal input block[blockSizeBytes*8];
|
|
signal output out[25*64];
|
|
var i;
|
|
var j;
|
|
|
|
component aux[blockSizeBytes/8];
|
|
component newS = Keccakf();
|
|
|
|
for (i=0; i<blockSizeBytes/8; i++) {
|
|
aux[i] = XorArray(64);
|
|
for (j=0; j<64; j++) {
|
|
aux[i].a[j] <== s[i*64+j];
|
|
aux[i].b[j] <== block[i*64+j];
|
|
}
|
|
for (j=0; j<64; j++) {
|
|
newS.in[i*64+j] <== aux[i].out[j];
|
|
}
|
|
}
|
|
// fill the missing s that was not covered by the loop over
|
|
// blockSizeBytes/8
|
|
for (i=(blockSizeBytes/8)*64; i<25*64; i++) {
|
|
newS.in[i] <== s[i];
|
|
}
|
|
for (i=0; i<25*64; i++) {
|
|
out[i] <== newS.out[i];
|
|
}
|
|
}
|
|
|
|
template Final(nBits) {
|
|
signal input in[nBits];
|
|
signal output out[25*64];
|
|
var blockSize=136*8;
|
|
var i;
|
|
|
|
// pad
|
|
component pad = Pad(nBits);
|
|
for (i=0; i<nBits; i++) {
|
|
pad.in[i] <== in[i];
|
|
}
|
|
// absorb
|
|
component abs = Absorb();
|
|
for (i=0; i<blockSize; i++) {
|
|
abs.block[i] <== pad.out[i];
|
|
}
|
|
for (i=0; i<25*64; i++) {
|
|
abs.s[i] <== 0;
|
|
}
|
|
for (i=0; i<25*64; i++) {
|
|
out[i] <== abs.out[i];
|
|
}
|
|
}
|
|
|
|
template Keccakf() {
|
|
signal input in[25*64];
|
|
signal output out[25*64];
|
|
var i;
|
|
var j;
|
|
|
|
// 24 rounds
|
|
component round[24];
|
|
signal midRound[24*25*64];
|
|
for (i=0; i<24; i++) {
|
|
round[i] = KeccakfRound(i);
|
|
if (i==0) {
|
|
for (j=0; j<25*64; j++) {
|
|
midRound[j] <== in[j];
|
|
}
|
|
}
|
|
for (j=0; j<25*64; j++) {
|
|
round[i].in[j] <== midRound[i*25*64+j];
|
|
}
|
|
if (i<23) {
|
|
for (j=0; j<25*64; j++) {
|
|
midRound[(i+1)*25*64+j] <== round[i].out[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i=0; i<25*64; i++) {
|
|
out[i] <== round[23].out[i];
|
|
}
|
|
}
|