Browse Source

RhoPi Circom circuit implemented

master
arnaucube 2 years ago
parent
commit
0a35c4463b
6 changed files with 366 additions and 178 deletions
  1. +185
    -0
      circuits/rhopi.circom
  2. +5
    -66
      circuits/theta.circom
  3. +81
    -0
      circuits/utils.circom
  4. +24
    -73
      go-keccak256-bits-impl/stepmappings.go
  5. +6
    -0
      test/circuits/rhopi_test.circom
  6. +65
    -39
      test/keccak256.js

+ 185
- 0
circuits/rhopi.circom

@ -0,0 +1,185 @@
pragma circom 2.0.0;
include "./utils.circom";
template step(shl, shr) {
// out = a<<shl|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];
}
}

+ 5
- 66
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<n; i++) {
xor3.a[i] <== a[i];
xor3.b[i] <== b[i];
xor3.c[i] <== c[i];
}
component xor4 = XorArray(n);
for (i=0; i<n; i++) {
xor4.a[i] <== xor3.out[i];
xor4.b[i] <== d[i];
}
component xor5 = XorArray(n);
for (i=0; i<n; i++) {
xor5.a[i] <== xor4.out[i];
xor5.b[i] <== e[i];
}
for (i=0; i<n; i++) {
out[i] <== xor5.out[i];
}
}
template XorArray(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] = XOR();
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) {
signal input in[n];
signal output out[n];
for (var i=0; i<n; i++) {
if (i < r) {
out[i] <== 0;
} else {
out[i] <== in[ i-r ];
}
}
}
template D(n, shl, shr) {
// d = b ^ (a<<shl | a>>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];

+ 81
- 0
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<n; i++) {
xor3.a[i] <== a[i];
xor3.b[i] <== b[i];
xor3.c[i] <== c[i];
}
component xor4 = XorArray(n);
for (i=0; i<n; i++) {
xor4.a[i] <== xor3.out[i];
xor4.b[i] <== d[i];
}
component xor5 = XorArray(n);
for (i=0; i<n; i++) {
xor5.a[i] <== xor4.out[i];
xor5.b[i] <== e[i];
}
for (i=0; i<n; i++) {
out[i] <== xor5.out[i];
}
}
template XorArray(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] = XOR();
aux[i].a <== a[i];
aux[i].b <== b[i];
}
for (i=0; i<n; i++) {
out[i] <== aux[i].out;
}
}
template OrArray(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] = OR();
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) {
signal input in[n];
signal output out[n];
for (var i=0; i<n; i++) {
if (i < r) {
out[i] <== 0;
} else {
out[i] <== in[ i-r ];
}
}
}

+ 24
- 73
go-keccak256-bits-impl/stepmappings.go

@ -48,106 +48,57 @@ func theta(a [25 * 64]bool) [25 * 64]bool {
}
func rhopi(a [25 * 64]bool) [25 * 64]bool {
var t, tAux [64]bool
var r [25 * 64]bool
copy(r[0:1*64], a[0:1*64])
copy(t[:], a[1*64:2*64])
copy(r[10*64:11*64], or(leftShift(a[1*64:2*64], 1), rightShift(a[1*64:2*64], 64-1)))
copy(tAux[:], a[10*64:11*64])
copy(r[10*64:11*64], or(leftShift(t[:], 1), rightShift(t[:], 64-1)))
copy(t[:], tAux[:])
copy(r[7*64:8*64], or(leftShift(a[10*64:11*64], 3), rightShift(a[10*64:11*64], 64-3)))
copy(tAux[:], a[7*64:8*64])
copy(r[7*64:8*64], or(leftShift(t[:], 3), rightShift(t[:], 64-3)))
copy(t[:], tAux[:])
copy(r[11*64:12*64], or(leftShift(a[7*64:8*64], 6), rightShift(a[7*64:8*64], 64-6)))
copy(tAux[:], a[11*64:12*64])
copy(r[11*64:12*64], or(leftShift(t[:], 6), rightShift(t[:], 64-6)))
copy(t[:], tAux[:])
copy(r[17*64:18*64], or(leftShift(a[11*64:12*64], 10), rightShift(a[11*64:12*64], 64-10)))
copy(tAux[:], a[17*64:18*64])
copy(r[17*64:18*64], or(leftShift(t[:], 10), rightShift(t[:], 64-10)))
copy(t[:], tAux[:])
copy(r[18*64:19*64], or(leftShift(a[17*64:18*64], 15), rightShift(a[17*64:18*64], 64-15)))
copy(tAux[:], a[18*64:19*64])
copy(r[18*64:19*64], or(leftShift(t[:], 15), rightShift(t[:], 64-15)))
copy(t[:], tAux[:])
copy(r[3*64:4*64], or(leftShift(a[18*64:19*64], 21), rightShift(a[18*64:19*64], 64-21)))
copy(tAux[:], a[3*64:4*64])
copy(r[3*64:4*64], or(leftShift(t[:], 21), rightShift(t[:], 64-21)))
copy(t[:], tAux[:])
copy(r[5*64:6*64], or(leftShift(a[3*64:4*64], 28), rightShift(a[3*64:4*64], 64-28)))
copy(tAux[:], a[5*64:6*64])
copy(r[5*64:6*64], or(leftShift(t[:], 28), rightShift(t[:], 64-28)))
copy(t[:], tAux[:])
copy(r[16*64:17*64], or(leftShift(a[5*64:6*64], 36), rightShift(a[5*64:6*64], 64-36)))
copy(tAux[:], a[16*64:17*64])
copy(r[16*64:17*64], or(leftShift(t[:], 36), rightShift(t[:], 64-36)))
copy(t[:], tAux[:])
copy(r[8*64:9*64], or(leftShift(a[16*64:17*64], 45), rightShift(a[16*64:17*64], 64-45)))
copy(tAux[:], a[8*64:9*64])
copy(r[8*64:9*64], or(leftShift(t[:], 45), rightShift(t[:], 64-45)))
copy(t[:], tAux[:])
copy(r[21*64:22*64], or(leftShift(a[8*64:9*64], 55), rightShift(a[8*64:9*64], 64-55)))
copy(tAux[:], a[21*64:22*64])
copy(r[21*64:22*64], or(leftShift(t[:], 55), rightShift(t[:], 64-55)))
copy(t[:], tAux[:])
copy(r[24*64:25*64], or(leftShift(a[21*64:22*64], 2), rightShift(a[21*64:22*64], 64-2)))
copy(tAux[:], a[24*64:25*64])
copy(r[24*64:25*64], or(leftShift(t[:], 2), rightShift(t[:], 64-2)))
copy(t[:], tAux[:])
copy(r[4*64:5*64], or(leftShift(a[24*64:25*64], 14), rightShift(a[24*64:25*64], 64-14)))
copy(tAux[:], a[4*64:5*64])
copy(r[4*64:5*64], or(leftShift(t[:], 14), rightShift(t[:], 64-14)))
copy(t[:], tAux[:])
copy(r[15*64:16*64], or(leftShift(a[4*64:5*64], 27), rightShift(a[4*64:5*64], 64-27)))
copy(tAux[:], a[15*64:16*64])
copy(r[15*64:16*64], or(leftShift(t[:], 27), rightShift(t[:], 64-27)))
copy(t[:], tAux[:])
copy(r[23*64:24*64], or(leftShift(a[15*64:16*64], 41), rightShift(a[15*64:16*64], 64-41)))
copy(tAux[:], a[23*64:24*64])
copy(r[23*64:24*64], or(leftShift(t[:], 41), rightShift(t[:], 64-41)))
copy(t[:], tAux[:])
copy(r[19*64:20*64], or(leftShift(a[23*64:24*64], 56), rightShift(a[23*64:24*64], 64-56)))
copy(tAux[:], a[19*64:20*64])
copy(r[19*64:20*64], or(leftShift(t[:], 56), rightShift(t[:], 64-56)))
copy(t[:], tAux[:])
copy(r[13*64:14*64], or(leftShift(a[19*64:20*64], 8), rightShift(a[19*64:20*64], 64-8)))
copy(tAux[:], a[13*64:14*64])
copy(r[13*64:14*64], or(leftShift(t[:], 8), rightShift(t[:], 64-8)))
copy(t[:], tAux[:])
copy(r[12*64:13*64], or(leftShift(a[13*64:14*64], 25), rightShift(a[13*64:14*64], 64-25)))
copy(tAux[:], a[12*64:13*64])
copy(r[12*64:13*64], or(leftShift(t[:], 25), rightShift(t[:], 64-25)))
copy(t[:], tAux[:])
copy(r[2*64:3*64], or(leftShift(a[12*64:13*64], 43), rightShift(a[12*64:13*64], 64-43)))
copy(tAux[:], a[2*64:3*64])
copy(r[2*64:3*64], or(leftShift(t[:], 43), rightShift(t[:], 64-43)))
copy(t[:], tAux[:])
copy(r[20*64:21*64], or(leftShift(a[2*64:3*64], 62), rightShift(a[2*64:3*64], 64-62)))
copy(tAux[:], a[20*64:21*64])
copy(r[20*64:21*64], or(leftShift(t[:], 62), rightShift(t[:], 64-62)))
copy(t[:], tAux[:])
copy(r[14*64:15*64], or(leftShift(a[20*64:21*64], 18), rightShift(a[20*64:21*64], 64-18)))
copy(tAux[:], a[14*64:15*64])
copy(r[14*64:15*64], or(leftShift(t[:], 18), rightShift(t[:], 64-18)))
copy(t[:], tAux[:])
copy(r[22*64:23*64], or(leftShift(a[14*64:15*64], 39), rightShift(a[14*64:15*64], 64-39)))
copy(tAux[:], a[22*64:23*64])
copy(r[22*64:23*64], or(leftShift(t[:], 39), rightShift(t[:], 64-39)))
copy(t[:], tAux[:])
copy(r[9*64:10*64], or(leftShift(a[22*64:23*64], 61), rightShift(a[22*64:23*64], 64-61)))
copy(tAux[:], a[9*64:10*64])
copy(r[9*64:10*64], or(leftShift(t[:], 61), rightShift(t[:], 64-61)))
copy(t[:], tAux[:])
copy(r[6*64:7*64], or(leftShift(a[9*64:10*64], 20), rightShift(a[9*64:10*64], 64-20)))
copy(tAux[:], a[6*64:7*64])
copy(r[6*64:7*64], or(leftShift(t[:], 20), rightShift(t[:], 64-20)))
copy(t[:], tAux[:])
copy(r[1*64:2*64], or(leftShift(t[:], 44), rightShift(t[:], 64-44)))
copy(r[1*64:2*64], or(leftShift(a[6*64:7*64], 44), rightShift(a[6*64:7*64], 64-44)))
return r
}

+ 6
- 0
test/circuits/rhopi_test.circom

@ -0,0 +1,6 @@
pragma circom 2.0.0;
include "../../circuits/rhopi.circom";
component main = RhoPi();

+ 65
- 39
test/keccak256.js

@ -17,7 +17,7 @@ const wasm_tester = require("circom_tester").wasm;
function bytesToU64(byteArray) {
var value = 0;
for ( var i = byteArray.length - 1; 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<<j)) > 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<<j)) > 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<a.length; i++) {
const p = Math.floor(i/8);
if (b[p]==undefined) {
b[p] = 0;
}
if (a[i]==1) {
b[p] |= 1<<(i%8);
}
@ -80,17 +82,17 @@ function bitsToBytes(a) {
}
function bitsToU64Array(b) {
const r = [];
for (let i = 0; i < b.length/64; i++) {
r.push(bitsToU64(b.slice(i*64, i*64+64)));
}
return r
const r = [];
for (let i = 0; i < b.length/64; i++) {
r.push(bitsToU64(b.slice(i*64, i*64+64)));
}
return r
}
function intsToBigInts(a) {
let b = [];
for (let i=0; i<a.length; i++) {
b[i] = Fr.e(a[i]);
b[i] = Fr.e(a[i]);
}
return b;
}
@ -99,12 +101,12 @@ describe("Utils test", function () {
this.timeout(100000);
it ("utils", async () => {
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);

Loading…
Cancel
Save