From 0a35c4463b62229b008230f596003820de839dee Mon Sep 17 00:00:00 2001 From: arnaucube Date: Mon, 1 Nov 2021 20:33:52 +0100 Subject: [PATCH] RhoPi Circom circuit implemented --- circuits/rhopi.circom | 185 +++++++++++++++++++++++++ circuits/theta.circom | 71 +--------- circuits/utils.circom | 81 +++++++++++ go-keccak256-bits-impl/stepmappings.go | 97 ++++--------- test/circuits/rhopi_test.circom | 6 + test/keccak256.js | 104 ++++++++------ 6 files changed, 366 insertions(+), 178 deletions(-) create mode 100644 circuits/rhopi.circom create mode 100644 circuits/utils.circom create mode 100644 test/circuits/rhopi_test.circom diff --git a/circuits/rhopi.circom b/circuits/rhopi.circom new file mode 100644 index 0000000..fe21fc8 --- /dev/null +++ b/circuits/rhopi.circom @@ -0,0 +1,185 @@ +pragma circom 2.0.0; + +include "./utils.circom"; + +template step(shl, shr) { + // out = a<>shr + signal input a[64]; + signal output out[64]; + var i; + + component aux0 = ShR(64, shr); + for (i=0; i<64; i++) { + aux0.in[i] <== a[i]; + } + component aux1 = ShL(64, shl); + for (i=0; i<64; i++) { + aux1.in[i] <== a[i]; + } + component aux2 = OrArray(64); + for (i=0; i<64; i++) { + aux2.a[i] <== aux0.out[i]; + aux2.b[i] <== aux1.out[i]; + } + for (i=0; i<64; i++) { + out[i] <== aux2.out[i]; + } +} +template RhoPi() { + signal input in[25*64]; + signal output out[25*64]; + + var i; + + for (i=0; i<64; i++) { + out[i] <== in[i]; + } + + // r[10] = a[1]<<1|a[1]>>(64-1) + component s10 = step(1, 64-1); + for (i=0; i<64; i++) { + s10.a[i] <== in[1*64+i]; + } + // r[7] = a[10]<<3|a[10]>>(64-3) + component s7 = step(3, 64-3); + for (i=0; i<64; i++) { + s7.a[i] <== in[10*64+i]; + } + // r[11] = a[7]<<6|a[7]>>(64-6) + component s11 = step(6, 64-6); + for (i=0; i<64; i++) { + s11.a[i] <== in[7*64+i]; + } + // r[17] = a[11]<<10|a[11]>>(64-10) + component s17 = step(10, 64-10); + for (i=0; i<64; i++) { + s17.a[i] <== in[11*64+i]; + } + // r[18] = a[17]<<15|a[17]>>(64-15) + component s18 = step(15, 64-15); + for (i=0; i<64; i++) { + s18.a[i] <== in[17*64+i]; + } + // r[3] = a[18]<<21|a[18]>>(64-21) + component s3 = step(21, 64-21); + for (i=0; i<64; i++) { + s3.a[i] <== in[18*64+i]; + } + // r[5] = a[3]<<28|a[3]>>(64-28) + component s5 = step(28, 64-28); + for (i=0; i<64; i++) { + s5.a[i] <== in[3*64+i]; + } + // r[16] = a[5]<<36|a[5]>>(64-36) + component s16 = step(36, 64-36); + for (i=0; i<64; i++) { + s16.a[i] <== in[5*64+i]; + } + // r[8] = a[16]<<45|a[16]>>(64-45) + component s8 = step(45, 64-45); + for (i=0; i<64; i++) { + s8.a[i] <== in[16*64+i]; + } + // r[21] = a[8]<<55|a[8]>>(64-55) + component s21 = step(55, 64-55); + for (i=0; i<64; i++) { + s21.a[i] <== in[8*64+i]; + } + // r[24] = a[21]<<2|a[21]>>(64-2) + component s24 = step(2, 64-2); + for (i=0; i<64; i++) { + s24.a[i] <== in[21*64+i]; + } + // r[4] = a[24]<<14|a[24]>>(64-14) + component s4 = step(14, 64-14); + for (i=0; i<64; i++) { + s4.a[i] <== in[24*64+i]; + } + // r[15] = a[4]<<27|a[4]>>(64-27) + component s15 = step(27, 64-27); + for (i=0; i<64; i++) { + s15.a[i] <== in[4*64+i]; + } + // r[23] = a[15]<<41|a[15]>>(64-41) + component s23 = step(41, 64-41); + for (i=0; i<64; i++) { + s23.a[i] <== in[15*64+i]; + } + // r[19] = a[23]<<56|a[23]>>(64-56) + component s19 = step(56, 64-56); + for (i=0; i<64; i++) { + s19.a[i] <== in[23*64+i]; + } + // r[13] = a[19]<<8|a[19]>>(64-8) + component s13 = step(8, 64-8); + for (i=0; i<64; i++) { + s13.a[i] <== in[19*64+i]; + } + // r[12] = a[13]<<25|a[13]>>(64-25) + component s12 = step(25, 64-25); + for (i=0; i<64; i++) { + s12.a[i] <== in[13*64+i]; + } + // r[2] = a[12]<<43|a[12]>>(64-43) + component s2 = step(43, 64-43); + for (i=0; i<64; i++) { + s2.a[i] <== in[12*64+i]; + } + // r[20] = a[2]<<62|a[2]>>(64-62) + component s20 = step(62, 64-62); + for (i=0; i<64; i++) { + s20.a[i] <== in[2*64+i]; + } + // r[14] = a[20]<<18|a[20]>>(64-18) + component s14 = step(18, 64-18); + for (i=0; i<64; i++) { + s14.a[i] <== in[20*64+i]; + } + // r[22] = a[14]<<39|a[14]>>(64-39) + component s22 = step(39, 64-39); + for (i=0; i<64; i++) { + s22.a[i] <== in[14*64+i]; + } + // r[9] = a[22]<<61|a[22]>>(64-61) + component s9 = step(61, 64-61); + for (i=0; i<64; i++) { + s9.a[i] <== in[22*64+i]; + } + // r[6] = a[9]<<20|a[9]>>(64-20) + component s6 = step(20, 64-20); + for (i=0; i<64; i++) { + s6.a[i] <== in[9*64+i]; + } + // r[1] = a[6]<<44|a[6]>>(64-44) + component s1 = step(44, 64-44); + for (i=0; i<64; i++) { + s1.a[i] <== in[6*64+i]; + } + + for (i=0; i<64; i++) { + out[10*64+i] <== s10.out[i]; + out[7*64+i] <== s7.out[i]; + out[11*64+i] <== s11.out[i]; + out[17*64+i] <== s17.out[i]; + out[18*64+i] <== s18.out[i]; + out[3*64+i] <== s3.out[i]; + out[5*64+i] <== s5.out[i]; + out[16*64+i] <== s16.out[i]; + out[8*64+i] <== s8.out[i]; + out[21*64+i] <== s21.out[i]; + out[24*64+i] <== s24.out[i]; + out[4*64+i] <== s4.out[i]; + out[15*64+i] <== s15.out[i]; + out[23*64+i] <== s23.out[i]; + out[19*64+i] <== s19.out[i]; + out[13*64+i] <== s13.out[i]; + out[12*64+i] <== s12.out[i]; + out[2*64+i] <== s2.out[i]; + out[20*64+i] <== s20.out[i]; + out[14*64+i] <== s14.out[i]; + out[22*64+i] <== s22.out[i]; + out[9*64+i] <== s9.out[i]; + out[6*64+i] <== s6.out[i]; + out[1*64+i] <== s1.out[i]; + } +} diff --git a/circuits/theta.circom b/circuits/theta.circom index 8793104..aac2fd8 100644 --- a/circuits/theta.circom +++ b/circuits/theta.circom @@ -1,67 +1,7 @@ pragma circom 2.0.0; -include "../node_modules/circomlib/circuits/gates.circom"; -include "../node_modules/circomlib/circuits/sha256/xor3.circom"; -include "../node_modules/circomlib/circuits/sha256/shift.circom"; // contains ShiftRight +include "./utils.circom"; -template Xor5(n) { - signal input a[n]; - signal input b[n]; - signal input c[n]; - signal input d[n]; - signal input e[n]; - signal output out[n]; - var i; - - component xor3 = Xor3(n); - for (i=0; i>shr) @@ -78,16 +18,15 @@ template D(n, shl, shr) { for (i=0; i<64; i++) { aux1.in[i] <== a[i]; } - component aux2[64]; + component aux2 = OrArray(64); for (i=0; i<64; i++) { - aux2[i] = OR(); - aux2[i].a <== aux0.out[i]; - aux2[i].b <== aux1.out[i]; + aux2.a[i] <== aux0.out[i]; + aux2.b[i] <== aux1.out[i]; } component aux3 = XorArray(64); for (i=0; i<64; i++) { aux3.a[i] <== b[i]; - aux3.b[i] <== aux2[i].out; + aux3.b[i] <== aux2.out[i]; } for (i=0; i<64; i++) { out[i] <== aux3.out[i]; diff --git a/circuits/utils.circom b/circuits/utils.circom new file mode 100644 index 0000000..640d1f5 --- /dev/null +++ b/circuits/utils.circom @@ -0,0 +1,81 @@ +pragma circom 2.0.0; + +include "../node_modules/circomlib/circuits/gates.circom"; +include "../node_modules/circomlib/circuits/sha256/xor3.circom"; +include "../node_modules/circomlib/circuits/sha256/shift.circom"; // contains ShiftRight + +template Xor5(n) { + signal input a[n]; + signal input b[n]; + signal input c[n]; + signal input d[n]; + signal input e[n]; + signal output out[n]; + var i; + + component xor3 = Xor3(n); + for (i=0; i= 0; i--) { - value = (value * 256) + byteArray[i]; + value = (value * 256) + byteArray[i]; } return value; @@ -26,9 +26,9 @@ function u64ToBytes(long) { var byteArray = [0, 0, 0, 0, 0, 0, 0, 0]; for ( var index = 0; index < byteArray.length; index ++ ) { - var byte = long & 0xff; - byteArray [ index ] = byte; - long = (long - byte) / 256 ; + var byte = long & 0xff; + byteArray [ index ] = byte; + long = (long - byte) / 256 ; } return byteArray; @@ -39,39 +39,41 @@ function u64ToBits(a) { return bytesToBits(aBytes); } function bytesToBits(b) { - const bits = []; - for (let i = 0; i < b.length; i++) { - for (let j = 0; j < 8; j++) { - if ((b[i]&(1< 0) { - bits.push(Fr.e(1)); - } else { - bits.push(Fr.e(0)); - } - } + const bits = []; + for (let i = 0; i < b.length; i++) { + for (let j = 0; j < 8; j++) { + if ((b[i]&(1< 0) { + bits.push(Fr.e(1)); + } else { + bits.push(Fr.e(0)); + } } - return bits + } + return bits } function u64ArrayToBits(u) { - let r = []; - for (let i = 0; i < u.length; i++) { - r = r.concat(u64ToBits(u[i])); - } - return r + let r = []; + for (let i = 0; i < u.length; i++) { + r = r.concat(u64ToBits(u[i])); + } + return r } function bitsToU64(b) { - if (b.length != 64) { - console.log("b.length = ", b.length, " max=64"); - return; - } - const by = bitsToBytes(b) - return bytesToU64(by) + if (b.length != 64) { + console.log("b.length = ", b.length, " max=64"); + return; + } + const by = bitsToBytes(b) + return bytesToU64(by) } function bitsToBytes(a) { - const len = Math.floor((a.length -1 )/8)+1; const b = []; for (let i=0; i { - let a = 3; - let aBits = u64ToBits(a); + let a = 3; + let aBits = u64ToBits(a); let a2 = bitsToU64(aBits); assert.equal(a2, a); - a = 12345; - aBits = u64ToBits(a); + a = 12345; + aBits = u64ToBits(a); a2 = bitsToU64(aBits); assert.equal(a2, a); @@ -122,14 +124,38 @@ describe("Theta test", function () { it ("Theta (testvector generated from go)", async () => { const cir = await wasm_tester(path.join(__dirname, "circuits", "theta_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 = [26,9,13,29,47,31,14,8,22,34,16,3,3,19,37,21,24,30,12,56,14,29,25,9,51]; 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); + }); +}); + +describe("RhoPi test", function () { + this.timeout(100000); + + it ("RhoPi (testvector generated from go)", async () => { + const cir = await wasm_tester(path.join(__dirname, "circuits", "rhopi_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 = [0, 105553116266496, 105553116266496, 37748736, 393216, + 805306368, 9437184, 80, 562949953421312, 13835058055282163714, + 2, 448, 436207616, 4864, 5242880, 536870912, 343597383680, + 11264, 557056, 1657324662872342528, 9223372036854775808, + 288230376151711744, 7696581394432, 32985348833280, 84]; + 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);