Browse Source

Chi Circom circuit implemented

master
arnaucube 3 years ago
parent
commit
f8afdd5a88
7 changed files with 318 additions and 66 deletions
  1. +2
    -2
      README.md
  2. +227
    -0
      circuits/chi.circom
  3. +1
    -4
      circuits/rhopi.circom
  4. +34
    -0
      circuits/utils.circom
  5. +29
    -60
      go-keccak256-bits-impl/stepmappings.go
  6. +5
    -0
      test/circuits/chi_test.circom
  7. +20
    -0
      test/keccak256.js

+ 2
- 2
README.md

@ -1,5 +1,5 @@
# keccak256-circom # keccak256-circom
Spec: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
WIP repo. Once ready, will do a PR into [circomlib](https://github.com/iden3/circomlib). WIP repo. Once ready, will do a PR into [circomlib](https://github.com/iden3/circomlib).
Spec: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf

+ 227
- 0
circuits/chi.circom

@ -0,0 +1,227 @@
pragma circom 2.0.0;
include "./utils.circom";
template step() {
// out = a ^ (^b) & c
signal input a[64];
signal input b[64];
signal input c[64];
signal output out[64];
var i;
// ^b
component bXor = XorArraySingle(64);
for (i=0; i<64; i++) {
bXor.a[i] <== b[i];
}
// (^b)&c
component bc = AndArray(64);
for (i=0; i<64; i++) {
bc.a[i] <== bXor.out[i];
bc.b[i] <== c[i];
}
// a^(^b)&c
component abc = XorArray(64);
for (i=0; i<64; i++) {
abc.a[i] <== a[i];
abc.b[i] <== bc.out[i];
}
for (i=0; i<64; i++) {
out[i] <== abc.out[i];
}
}
template Chi() {
signal input in[25*64];
signal output out[25*64];
var i;
component r0 = step();
for (i=0; i<64; i++) {
r0.a[i] <== in[i];
r0.b[i] <== in[1*64+i];
r0.c[i] <== in[2*64+i];
}
component r1 = step();
for (i=0; i<64; i++) {
r1.a[i] <== in[1*64+i];
r1.b[i] <== in[2*64+i];
r1.c[i] <== in[3*64+i];
}
component r2 = step();
for (i=0; i<64; i++) {
r2.a[i] <== in[2*64+i];
r2.b[i] <== in[3*64+i];
r2.c[i] <== in[4*64+i];
}
component r3 = step();
for (i=0; i<64; i++) {
r3.a[i] <== in[3*64+i];
r3.b[i] <== in[4*64+i];
r3.c[i] <== in[0*64+i];
}
component r4 = step();
for (i=0; i<64; i++) {
r4.a[i] <== in[4*64+i];
r4.b[i] <== in[i];
r4.c[i] <== in[1*64+i];
}
component r5 = step();
for (i=0; i<64; i++) {
r5.a[i] <== in[5*64+i];
r5.b[i] <== in[6*64+i];
r5.c[i] <== in[7*64+i];
}
component r6 = step();
for (i=0; i<64; i++) {
r6.a[i] <== in[6*64+i];
r6.b[i] <== in[7*64+i];
r6.c[i] <== in[8*64+i];
}
component r7 = step();
for (i=0; i<64; i++) {
r7.a[i] <== in[7*64+i];
r7.b[i] <== in[8*64+i];
r7.c[i] <== in[9*64+i];
}
component r8 = step();
for (i=0; i<64; i++) {
r8.a[i] <== in[8*64+i];
r8.b[i] <== in[9*64+i];
r8.c[i] <== in[5*64+i];
}
component r9 = step();
for (i=0; i<64; i++) {
r9.a[i] <== in[9*64+i];
r9.b[i] <== in[5*64+i];
r9.c[i] <== in[6*64+i];
}
component r10 = step();
for (i=0; i<64; i++) {
r10.a[i] <== in[10*64+i];
r10.b[i] <== in[11*64+i];
r10.c[i] <== in[12*64+i];
}
component r11 = step();
for (i=0; i<64; i++) {
r11.a[i] <== in[11*64+i];
r11.b[i] <== in[12*64+i];
r11.c[i] <== in[13*64+i];
}
component r12 = step();
for (i=0; i<64; i++) {
r12.a[i] <== in[12*64+i];
r12.b[i] <== in[13*64+i];
r12.c[i] <== in[14*64+i];
}
component r13 = step();
for (i=0; i<64; i++) {
r13.a[i] <== in[13*64+i];
r13.b[i] <== in[14*64+i];
r13.c[i] <== in[10*64+i];
}
component r14 = step();
for (i=0; i<64; i++) {
r14.a[i] <== in[14*64+i];
r14.b[i] <== in[10*64+i];
r14.c[i] <== in[11*64+i];
}
component r15 = step();
for (i=0; i<64; i++) {
r15.a[i] <== in[15*64+i];
r15.b[i] <== in[16*64+i];
r15.c[i] <== in[17*64+i];
}
component r16 = step();
for (i=0; i<64; i++) {
r16.a[i] <== in[16*64+i];
r16.b[i] <== in[17*64+i];
r16.c[i] <== in[18*64+i];
}
component r17 = step();
for (i=0; i<64; i++) {
r17.a[i] <== in[17*64+i];
r17.b[i] <== in[18*64+i];
r17.c[i] <== in[19*64+i];
}
component r18 = step();
for (i=0; i<64; i++) {
r18.a[i] <== in[18*64+i];
r18.b[i] <== in[19*64+i];
r18.c[i] <== in[15*64+i];
}
component r19 = step();
for (i=0; i<64; i++) {
r19.a[i] <== in[19*64+i];
r19.b[i] <== in[15*64+i];
r19.c[i] <== in[16*64+i];
}
component r20 = step();
for (i=0; i<64; i++) {
r20.a[i] <== in[20*64+i];
r20.b[i] <== in[21*64+i];
r20.c[i] <== in[22*64+i];
}
component r21 = step();
for (i=0; i<64; i++) {
r21.a[i] <== in[21*64+i];
r21.b[i] <== in[22*64+i];
r21.c[i] <== in[23*64+i];
}
component r22 = step();
for (i=0; i<64; i++) {
r22.a[i] <== in[22*64+i];
r22.b[i] <== in[23*64+i];
r22.c[i] <== in[24*64+i];
}
component r23 = step();
for (i=0; i<64; i++) {
r23.a[i] <== in[23*64+i];
r23.b[i] <== in[24*64+i];
r23.c[i] <== in[20*64+i];
}
component r24 = step();
for (i=0; i<64; i++) {
r24.a[i] <== in[24*64+i];
r24.b[i] <== in[20*64+i];
r24.c[i] <== in[21*64+i];
}
for (i=0; i<64; i++) {
out[i] <== r0.out[i];
out[1*64+i] <== r1.out[i];
out[2*64+i] <== r2.out[i];
out[3*64+i] <== r3.out[i];
out[4*64+i] <== r4.out[i];
out[5*64+i] <== r5.out[i];
out[6*64+i] <== r6.out[i];
out[7*64+i] <== r7.out[i];
out[8*64+i] <== r8.out[i];
out[9*64+i] <== r9.out[i];
out[10*64+i] <== r10.out[i];
out[11*64+i] <== r11.out[i];
out[12*64+i] <== r12.out[i];
out[13*64+i] <== r13.out[i];
out[14*64+i] <== r14.out[i];
out[15*64+i] <== r15.out[i];
out[16*64+i] <== r16.out[i];
out[17*64+i] <== r17.out[i];
out[18*64+i] <== r18.out[i];
out[19*64+i] <== r19.out[i];
out[20*64+i] <== r20.out[i];
out[21*64+i] <== r21.out[i];
out[22*64+i] <== r22.out[i];
out[23*64+i] <== r23.out[i];
out[24*64+i] <== r24.out[i];
}
}

+ 1
- 4
circuits/rhopi.circom

@ -31,10 +31,6 @@ template RhoPi() {
var i; var i;
for (i=0; i<64; i++) {
out[i] <== in[i];
}
// r[10] = a[1]<<1|a[1]>>(64-1) // r[10] = a[1]<<1|a[1]>>(64-1)
component s10 = step(1, 64-1); component s10 = step(1, 64-1);
for (i=0; i<64; i++) { for (i=0; i<64; i++) {
@ -157,6 +153,7 @@ template RhoPi() {
} }
for (i=0; i<64; i++) { for (i=0; i<64; i++) {
out[i] <== in[i];
out[10*64+i] <== s10.out[i]; out[10*64+i] <== s10.out[i];
out[7*64+i] <== s7.out[i]; out[7*64+i] <== s7.out[i];
out[11*64+i] <== s11.out[i]; out[11*64+i] <== s11.out[i];

+ 34
- 0
circuits/utils.circom

@ -50,6 +50,23 @@ template XorArray(n) {
out[i] <== aux[i].out; out[i] <== aux[i].out;
} }
} }
template XorArraySingle(n) {
signal input a[n];
signal output out[n];
var i;
component aux[n];
for (i=0; i<n; i++) {
aux[i] = XOR();
aux[i].a <== a[i];
aux[i].b <== 1;
}
for (i=0; i<n; i++) {
out[i] <== aux[i].out;
}
}
template OrArray(n) { template OrArray(n) {
signal input a[n]; signal input a[n];
signal input b[n]; signal input b[n];
@ -67,6 +84,23 @@ template OrArray(n) {
} }
} }
template AndArray(n) {
signal input a[n];
signal input b[n];
signal output out[n];
var i;
component aux[n];
for (i=0; i<n; i++) {
aux[i] = AND();
aux[i].a <== a[i];
aux[i].b <== b[i];
}
for (i=0; i<n; i++) {
out[i] <== aux[i].out;
}
}
template ShL(n, r) { template ShL(n, r) {
signal input in[n]; signal input in[n];
signal output out[n]; signal output out[n];

+ 29
- 60
go-keccak256-bits-impl/stepmappings.go

@ -103,68 +103,37 @@ func rhopi(a [25 * 64]bool) [25 * 64]bool {
} }
func chi(a [25 * 64]bool) [25 * 64]bool { func chi(a [25 * 64]bool) [25 * 64]bool {
var c0, c1, c2, c3, c4 [64]bool
var r [25 * 64]bool var r [25 * 64]bool
copy(c0[:], a[0:1*64])
copy(c1[:], a[1*64:2*64])
copy(c2[:], a[2*64:3*64])
copy(c3[:], a[3*64:4*64])
copy(c4[:], a[4*64:5*64])
copy(r[0:1*64], xor(a[0:1*64], and(xorSingle(c1[:]), c2[:])))
copy(r[1*64:2*64], xor(a[1*64:2*64], and(xorSingle(c2[:]), c3[:])))
copy(r[2*64:3*64], xor(a[2*64:3*64], and(xorSingle(c3[:]), c4[:])))
copy(r[3*64:4*64], xor(a[3*64:4*64], and(xorSingle(c4[:]), c0[:])))
copy(r[4*64:5*64], xor(a[4*64:5*64], and(xorSingle(c0[:]), c1[:])))
copy(c0[:], a[5*64:6*64])
copy(c1[:], a[6*64:7*64])
copy(c2[:], a[7*64:8*64])
copy(c3[:], a[8*64:9*64])
copy(c4[:], a[9*64:10*64])
copy(r[5*64:6*64], xor(a[5*64:6*64], and(xorSingle(c1[:]), c2[:])))
copy(r[6*64:7*64], xor(a[6*64:7*64], and(xorSingle(c2[:]), c3[:])))
copy(r[7*64:8*64], xor(a[7*64:8*64], and(xorSingle(c3[:]), c4[:])))
copy(r[8*64:9*64], xor(a[8*64:9*64], and(xorSingle(c4[:]), c0[:])))
copy(r[9*64:10*64], xor(a[9*64:10*64], and(xorSingle(c0[:]), c1[:])))
copy(c0[:], a[10*64:11*64])
copy(c1[:], a[11*64:12*64])
copy(c2[:], a[12*64:13*64])
copy(c3[:], a[13*64:14*64])
copy(c4[:], a[14*64:15*64])
copy(r[10*64:11*64], xor(a[10*64:11*64], and(xorSingle(c1[:]), c2[:])))
copy(r[11*64:12*64], xor(a[11*64:12*64], and(xorSingle(c2[:]), c3[:])))
copy(r[12*64:13*64], xor(a[12*64:13*64], and(xorSingle(c3[:]), c4[:])))
copy(r[13*64:14*64], xor(a[13*64:14*64], and(xorSingle(c4[:]), c0[:])))
copy(r[14*64:15*64], xor(a[14*64:15*64], and(xorSingle(c0[:]), c1[:])))
copy(c0[:], a[15*64:16*64])
copy(c1[:], a[16*64:17*64])
copy(c2[:], a[17*64:18*64])
copy(c3[:], a[18*64:19*64])
copy(c4[:], a[19*64:20*64])
copy(r[15*64:16*64], xor(a[15*64:16*64], and(xorSingle(c1[:]), c2[:])))
copy(r[16*64:17*64], xor(a[16*64:17*64], and(xorSingle(c2[:]), c3[:])))
copy(r[17*64:18*64], xor(a[17*64:18*64], and(xorSingle(c3[:]), c4[:])))
copy(r[18*64:19*64], xor(a[18*64:19*64], and(xorSingle(c4[:]), c0[:])))
copy(r[19*64:20*64], xor(a[19*64:20*64], and(xorSingle(c0[:]), c1[:])))
copy(c0[:], a[20*64:21*64])
copy(c1[:], a[21*64:22*64])
copy(c2[:], a[22*64:23*64])
copy(c3[:], a[23*64:24*64])
copy(c4[:], a[24*64:25*64])
copy(r[20*64:21*64], xor(a[20*64:21*64], and(xorSingle(c1[:]), c2[:])))
copy(r[21*64:22*64], xor(a[21*64:22*64], and(xorSingle(c2[:]), c3[:])))
copy(r[22*64:23*64], xor(a[22*64:23*64], and(xorSingle(c3[:]), c4[:])))
copy(r[23*64:24*64], xor(a[23*64:24*64], and(xorSingle(c4[:]), c0[:])))
copy(r[24*64:25*64], xor(a[24*64:25*64], and(xorSingle(c0[:]), c1[:])))
copy(r[0:1*64], xor(a[0:1*64], and(xorSingle(a[1*64:2*64]), a[2*64:3*64])))
copy(r[1*64:2*64], xor(a[1*64:2*64], and(xorSingle(a[2*64:3*64]), a[3*64:4*64])))
copy(r[2*64:3*64], xor(a[2*64:3*64], and(xorSingle(a[3*64:4*64]), a[4*64:5*64])))
copy(r[3*64:4*64], xor(a[3*64:4*64], and(xorSingle(a[4*64:5*64]), a[0:1*64])))
copy(r[4*64:5*64], xor(a[4*64:5*64], and(xorSingle(a[0:1*64]), a[1*64:2*64])))
copy(r[5*64:6*64], xor(a[5*64:6*64], and(xorSingle(a[6*64:7*64]), a[7*64:8*64])))
copy(r[6*64:7*64], xor(a[6*64:7*64], and(xorSingle(a[7*64:8*64]), a[8*64:9*64])))
copy(r[7*64:8*64], xor(a[7*64:8*64], and(xorSingle(a[8*64:9*64]), a[9*64:10*64])))
copy(r[8*64:9*64], xor(a[8*64:9*64], and(xorSingle(a[9*64:10*64]), a[5*64:6*64])))
copy(r[9*64:10*64], xor(a[9*64:10*64], and(xorSingle(a[5*64:6*64]), a[6*64:7*64])))
copy(r[10*64:11*64], xor(a[10*64:11*64], and(xorSingle(a[11*64:12*64]), a[12*64:13*64])))
copy(r[11*64:12*64], xor(a[11*64:12*64], and(xorSingle(a[12*64:13*64]), a[13*64:14*64])))
copy(r[12*64:13*64], xor(a[12*64:13*64], and(xorSingle(a[13*64:14*64]), a[14*64:15*64])))
copy(r[13*64:14*64], xor(a[13*64:14*64], and(xorSingle(a[14*64:15*64]), a[10*64:11*64])))
copy(r[14*64:15*64], xor(a[14*64:15*64], and(xorSingle(a[10*64:11*64]), a[11*64:12*64])))
copy(r[15*64:16*64], xor(a[15*64:16*64], and(xorSingle(a[16*64:17*64]), a[17*64:18*64])))
copy(r[16*64:17*64], xor(a[16*64:17*64], and(xorSingle(a[17*64:18*64]), a[18*64:19*64])))
copy(r[17*64:18*64], xor(a[17*64:18*64], and(xorSingle(a[18*64:19*64]), a[19*64:20*64])))
copy(r[18*64:19*64], xor(a[18*64:19*64], and(xorSingle(a[19*64:20*64]), a[15*64:16*64])))
copy(r[19*64:20*64], xor(a[19*64:20*64], and(xorSingle(a[15*64:16*64]), a[16*64:17*64])))
copy(r[20*64:21*64], xor(a[20*64:21*64], and(xorSingle(a[21*64:22*64]), a[22*64:23*64])))
copy(r[21*64:22*64], xor(a[21*64:22*64], and(xorSingle(a[22*64:23*64]), a[23*64:24*64])))
copy(r[22*64:23*64], xor(a[22*64:23*64], and(xorSingle(a[23*64:24*64]), a[24*64:25*64])))
copy(r[23*64:24*64], xor(a[23*64:24*64], and(xorSingle(a[24*64:25*64]), a[20*64:21*64])))
copy(r[24*64:25*64], xor(a[24*64:25*64], and(xorSingle(a[20*64:21*64]), a[21*64:22*64])))
return r return r
} }

+ 5
- 0
test/circuits/chi_test.circom

@ -0,0 +1,5 @@
pragma circom 2.0.0;
include "../../circuits/chi.circom";
component main = Chi();

+ 20
- 0
test/keccak256.js

@ -163,3 +163,23 @@ describe("RhoPi test", function () {
}); });
}); });
describe("Chi test", function () {
this.timeout(100000);
it ("Chi (testvector generated from go)", async () => {
const cir = await wasm_tester(path.join(__dirname, "circuits", "chi_test.circom"));
const input = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];
const expectedOut = [2, 0, 6, 3, 5, 4, 14, 6, 12, 11, 14, 10, 14, 13, 15,
14, 18, 16, 30, 3, 22, 20, 30, 19, 25];
const stateIn = u64ArrayToBits(input);
const expectedOutBits = u64ArrayToBits(expectedOut);
const witness = await cir.calculateWitness({ "in": stateIn }, true);
const stateOut = witness.slice(1, 1+(25*64));
const stateOutU64 = bitsToU64Array(stateOut);
// console.log(stateOutU64, expectedOut);
assert.deepEqual(stateOutU64, expectedOut);
});
});

Loading…
Cancel
Save