mirror of
https://github.com/arnaucube/keccak256-circom.git
synced 2026-01-11 00:11:30 +01:00
KeccakRound circuit implemented
This commit is contained in:
@@ -1,12 +1,18 @@
|
|||||||
pragma circom 2.0.0;
|
pragma circom 2.0.0;
|
||||||
|
|
||||||
include "./utils.circom";
|
include "./utils.circom";
|
||||||
|
include "./theta.circom";
|
||||||
|
include "./rhopi.circom";
|
||||||
|
include "./chi.circom";
|
||||||
|
include "./iota.circom";
|
||||||
|
|
||||||
template Pad(nBits) {
|
template Pad(nBits) {
|
||||||
signal input in[nBits];
|
signal input in[nBits];
|
||||||
|
|
||||||
var blockSize=136*8;
|
var blockSize=136*8;
|
||||||
signal output out[blockSize];
|
signal output out[blockSize];
|
||||||
signal out2[blockSize];
|
signal out2[blockSize];
|
||||||
|
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
for (i=0; i<nBits; i++) {
|
for (i=0; i<nBits; i++) {
|
||||||
@@ -32,15 +38,29 @@ template Pad(nBits) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template Keccak256(nBits) {
|
template KeccakfRound(r) {
|
||||||
signal input in[nBits];
|
signal input in[25*64];
|
||||||
signal output out[256];
|
signal output out[25*64];
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
// pad
|
component theta = Theta();
|
||||||
component pad = Pad(nBits);
|
component rhopi = RhoPi();
|
||||||
for (i=0; i<nBits; i++) {
|
component chi = Chi();
|
||||||
pad.in[i] <== in[i];
|
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,12 +68,16 @@ func squeeze(s [25 * 64]bool) []bool {
|
|||||||
return b[:n]
|
return b[:n]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func keccakfRound(s [25 * 64]bool, r int) [25 * 64]bool {
|
||||||
|
s = theta(s)
|
||||||
|
s = rhopi(s)
|
||||||
|
s = chi(s)
|
||||||
|
s = iot(s, r)
|
||||||
|
return s
|
||||||
|
}
|
||||||
func keccakf(s [25 * 64]bool) [25 * 64]bool {
|
func keccakf(s [25 * 64]bool) [25 * 64]bool {
|
||||||
for r := 0; r < rounds; r++ {
|
for r := 0; r < rounds; r++ {
|
||||||
s = theta(s)
|
s = keccakfRound(s, r)
|
||||||
s = rhopi(s)
|
|
||||||
s = chi(s)
|
|
||||||
s = iot(s, r)
|
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package keccak
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
@@ -30,12 +29,71 @@ func TestPad(t *testing.T) {
|
|||||||
for i := 0; i < len(b); i++ {
|
for i := 0; i < len(b); i++ {
|
||||||
b[i] = byte(i)
|
b[i] = byte(i)
|
||||||
}
|
}
|
||||||
fmt.Println(b)
|
|
||||||
bBits := bytesToBits(b)
|
bBits := bytesToBits(b)
|
||||||
fBits := pad(bBits)
|
fBits := pad(bBits)
|
||||||
|
|
||||||
qt.Assert(t, bitsToBytes(fBits[:]), qt.DeepEquals,
|
qt.Assert(t, bitsToBytes(fBits[:]), qt.DeepEquals,
|
||||||
[]byte{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, 25, 26, 27, 28, 29, 30, 31, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128})
|
[]byte{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, 25, 26, 27, 28, 29, 30, 31,
|
||||||
|
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeccakfRound(t *testing.T) {
|
||||||
|
s, _ := newS()
|
||||||
|
|
||||||
|
s = keccakfRound(s, 0)
|
||||||
|
qt.Assert(t, bitsToU64Array(s[:]), qt.DeepEquals,
|
||||||
|
[]uint64{
|
||||||
|
26388279066651, 246290629787648, 26388279902208,
|
||||||
|
25165850, 246290605457408, 7784628352, 844424965783552,
|
||||||
|
2305843009213694083, 844432714760192,
|
||||||
|
2305843009249345539, 637534226, 14848, 641204224,
|
||||||
|
14354, 3670528, 6308236288, 2130304761856,
|
||||||
|
648518346341354496, 6309216256, 648520476645130240,
|
||||||
|
4611706359392501763, 792677514882318336,
|
||||||
|
20340965113972, 4611732197915754499,
|
||||||
|
792633534417207412})
|
||||||
|
|
||||||
|
s = keccakfRound(s, 20)
|
||||||
|
qt.Assert(t, bitsToU64Array(s[:]), qt.DeepEquals,
|
||||||
|
[]uint64{17728382861289829725, 13654073086381141005,
|
||||||
|
9912591532945168756, 2030068283137172501, 5084683018496047808,
|
||||||
|
151244976540463006, 11718217461613725815, 11636071286320763433,
|
||||||
|
15039144509240642782, 11629028282864249197,
|
||||||
|
2594633730779457624, 14005558505838459171, 4612881094252610438,
|
||||||
|
2828009553220809993, 4838578484623267135, 1006588603063111352,
|
||||||
|
11109191860075454495, 1187545859779038208,
|
||||||
|
14661669042642437042, 5345317080454741069, 8196674451365552863,
|
||||||
|
635818354583088260, 13515759754032305626, 1708499319988748543,
|
||||||
|
7509292798507899312})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestKeccakf(t *testing.T) {
|
||||||
|
s, _ := newS()
|
||||||
|
|
||||||
|
s = keccakf(s)
|
||||||
|
|
||||||
|
qt.Assert(t, bitsToU64Array(s[:]), qt.DeepEquals,
|
||||||
|
[]uint64{9472389783892099349, 2159377575142921216,
|
||||||
|
17826682512249813373, 2325963263767348549,
|
||||||
|
15086930817298358378, 11661812091723830419,
|
||||||
|
3517755057770134847, 5223775837645169598, 933274647126506074,
|
||||||
|
3451250694486589320, 825065683101361807, 6192414258352188799,
|
||||||
|
14426505790672879210, 3326742392640380689,
|
||||||
|
16749975585634164134, 17847697619892908514,
|
||||||
|
11598434253200954839, 6049795840392747215, 8610635351954084385,
|
||||||
|
18234131770974529925, 15330347418010067760,
|
||||||
|
12047099911907354591, 4763389569697138851, 6779624089296570504,
|
||||||
|
15083668107635345971})
|
||||||
|
|
||||||
|
// compute again keccakf on the current state
|
||||||
|
// s = keccakf(s)
|
||||||
|
// qt.Assert(t, bitsToU64Array(s[:]), qt.DeepEquals, []uint64{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFinal(t *testing.T) {
|
func TestFinal(t *testing.T) {
|
||||||
@@ -43,10 +101,19 @@ func TestFinal(t *testing.T) {
|
|||||||
for i := 0; i < len(b); i++ {
|
for i := 0; i < len(b); i++ {
|
||||||
b[i] = byte(i)
|
b[i] = byte(i)
|
||||||
}
|
}
|
||||||
fmt.Println(b)
|
|
||||||
bBits := bytesToBits(b)
|
bBits := bytesToBits(b)
|
||||||
fBits := final(bBits)
|
fBits := final(bBits)
|
||||||
|
|
||||||
qt.Assert(t, bitsToU64Array(fBits[:]), qt.DeepEquals,
|
qt.Assert(t, bitsToU64Array(fBits[:]), qt.DeepEquals,
|
||||||
[]uint64{16953415415620100490, 7495738965189503699, 12723370805759944158, 3295955328722933810, 12121371508560456016, 174876831679863147, 15944933357501475584, 7502339663607726274, 12048918224562833898, 16715284461100269102, 15582559130083209842, 1743886467337678829, 2424196198791253761, 1116417308245482383, 10367365997906434042, 1849801549382613906, 13294939539683415102, 4478091053375708790, 2969967870313332958, 14618962068930014237, 2721742233407503451, 12003265593030191290, 8109318293656735684, 6346795302983965746, 12210038122000333046})
|
[]uint64{16953415415620100490, 7495738965189503699,
|
||||||
|
12723370805759944158, 3295955328722933810,
|
||||||
|
12121371508560456016, 174876831679863147, 15944933357501475584,
|
||||||
|
7502339663607726274, 12048918224562833898,
|
||||||
|
16715284461100269102, 15582559130083209842,
|
||||||
|
1743886467337678829, 2424196198791253761, 1116417308245482383,
|
||||||
|
10367365997906434042, 1849801549382613906,
|
||||||
|
13294939539683415102, 4478091053375708790, 2969967870313332958,
|
||||||
|
14618962068930014237, 2721742233407503451,
|
||||||
|
12003265593030191290, 8109318293656735684, 6346795302983965746,
|
||||||
|
12210038122000333046})
|
||||||
}
|
}
|
||||||
|
|||||||
5
test/circuits/keccakfRound0_test.circom
Normal file
5
test/circuits/keccakfRound0_test.circom
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pragma circom 2.0.0;
|
||||||
|
|
||||||
|
include "../../circuits/keccak256.circom";
|
||||||
|
|
||||||
|
component main = KeccakfRound(0);
|
||||||
5
test/circuits/keccakfRound20_test.circom
Normal file
5
test/circuits/keccakfRound20_test.circom
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pragma circom 2.0.0;
|
||||||
|
|
||||||
|
include "../../circuits/keccak256.circom";
|
||||||
|
|
||||||
|
component main = KeccakfRound(20);
|
||||||
@@ -123,7 +123,7 @@ describe("Utils test", function () {
|
|||||||
aBits = u64ToBits(a);
|
aBits = u64ToBits(a);
|
||||||
a2 = bitsToU64(aBits);
|
a2 = bitsToU64(aBits);
|
||||||
assert.equal(a2, a);
|
assert.equal(a2, a);
|
||||||
|
|
||||||
a = intsToBigInts([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]);
|
a = intsToBigInts([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]);
|
||||||
aBits = u64ArrayToBits(a);
|
aBits = u64ArrayToBits(a);
|
||||||
a2 = bitsToU64Array(aBits);
|
a2 = bitsToU64Array(aBits);
|
||||||
@@ -137,14 +137,14 @@ describe("Theta test", function () {
|
|||||||
|
|
||||||
it ("Theta (testvector generated from go)", async () => {
|
it ("Theta (testvector generated from go)", async () => {
|
||||||
const cir = await wasm_tester(path.join(__dirname, "circuits", "theta_test.circom"));
|
const cir = await wasm_tester(path.join(__dirname, "circuits", "theta_test.circom"));
|
||||||
|
|
||||||
const input = intsToBigInts([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 input = intsToBigInts([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 = intsToBigInts([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 expectedOut = intsToBigInts([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 stateIn = u64ArrayToBits(input);
|
||||||
const expectedOutBits = u64ArrayToBits(expectedOut);
|
const expectedOutBits = u64ArrayToBits(expectedOut);
|
||||||
|
|
||||||
const witness = await cir.calculateWitness({ "in": stateIn }, true);
|
const witness = await cir.calculateWitness({ "in": stateIn }, true);
|
||||||
|
|
||||||
const stateOut = witness.slice(1, 1+(25*64));
|
const stateOut = witness.slice(1, 1+(25*64));
|
||||||
const stateOutU64 = bitsToU64Array(stateOut);
|
const stateOutU64 = bitsToU64Array(stateOut);
|
||||||
// console.log(stateOutU64, expectedOut);
|
// console.log(stateOutU64, expectedOut);
|
||||||
@@ -152,14 +152,14 @@ describe("Theta test", function () {
|
|||||||
});
|
});
|
||||||
it ("Theta (same test as previous, but using c_tester to ensure that circom_tester with c works as expected)", async () => {
|
it ("Theta (same test as previous, but using c_tester to ensure that circom_tester with c works as expected)", async () => {
|
||||||
const cir = await c_tester(path.join(__dirname, "circuits", "theta_test.circom"));
|
const cir = await c_tester(path.join(__dirname, "circuits", "theta_test.circom"));
|
||||||
|
|
||||||
const input = intsToBigInts([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 input = intsToBigInts([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 = intsToBigInts([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 expectedOut = intsToBigInts([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 stateIn = u64ArrayToBits(input);
|
||||||
const expectedOutBits = u64ArrayToBits(expectedOut);
|
const expectedOutBits = u64ArrayToBits(expectedOut);
|
||||||
|
|
||||||
const witness = await cir.calculateWitness({ "in": stateIn }, true);
|
const witness = await cir.calculateWitness({ "in": stateIn }, true);
|
||||||
|
|
||||||
const stateOut = witness.slice(1, 1+(25*64));
|
const stateOut = witness.slice(1, 1+(25*64));
|
||||||
const stateOutU64 = bitsToU64Array(stateOut);
|
const stateOutU64 = bitsToU64Array(stateOut);
|
||||||
// console.log(stateOutU64, expectedOut);
|
// console.log(stateOutU64, expectedOut);
|
||||||
@@ -232,7 +232,7 @@ describe("Chi test", function () {
|
|||||||
|
|
||||||
const input = intsToBigInts([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 input = intsToBigInts([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 = intsToBigInts([2, 0, 6, 3, 5, 4, 14, 6, 12, 11, 14, 10, 14, 13, 15,
|
const expectedOut = intsToBigInts([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]);
|
14, 18, 16, 30, 3, 22, 20, 30, 19, 25]);
|
||||||
const stateIn = u64ArrayToBits(input);
|
const stateIn = u64ArrayToBits(input);
|
||||||
const expectedOutBits = u64ArrayToBits(expectedOut);
|
const expectedOutBits = u64ArrayToBits(expectedOut);
|
||||||
|
|
||||||
@@ -299,3 +299,50 @@ describe("Keccak-Pad test", function () {
|
|||||||
assert.deepEqual(stateOutBytes, expectedOut);
|
assert.deepEqual(stateOutBytes, expectedOut);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("keccakf test", function () {
|
||||||
|
this.timeout(100000);
|
||||||
|
|
||||||
|
// apt install nlohmann-json3-dev
|
||||||
|
// apt install nasm
|
||||||
|
|
||||||
|
it ("keccakfRound (testvector generated from go)", async () => {
|
||||||
|
// const cir = await wasm_tester(path.join(__dirname, "circuits", "keccakf_test.circom"));
|
||||||
|
const cir = await c_tester(path.join(__dirname, "circuits", "keccakfRound0_test.circom"));
|
||||||
|
await cir.loadConstraints();
|
||||||
|
// console.log("n_constraints", cir.constraints.length);
|
||||||
|
|
||||||
|
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 = strsToBigInts(["26388279066651", "246290629787648", "26388279902208", "25165850", "246290605457408", "7784628352", "844424965783552", "2305843009213694083", "844432714760192", "2305843009249345539", "637534226", "14848", "641204224", "14354", "3670528", "6308236288", "2130304761856", "648518346341354496", "6309216256", "648520476645130240", "4611706359392501763", "792677514882318336", "20340965113972", "4611732197915754499", "792633534417207412"]);
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
|
||||||
|
it ("keccakfRound 20 (testvector generated from go)", async () => {
|
||||||
|
// const cir = await wasm_tester(path.join(__dirname, "circuits", "keccakf_test.circom"));
|
||||||
|
const cir = await c_tester(path.join(__dirname, "circuits", "keccakfRound20_test.circom"));
|
||||||
|
await cir.loadConstraints();
|
||||||
|
// console.log("n_constraints", cir.constraints.length);
|
||||||
|
|
||||||
|
const input = strsToBigInts(["26388279066651", "246290629787648", "26388279902208", "25165850", "246290605457408", "7784628352", "844424965783552", "2305843009213694083", "844432714760192", "2305843009249345539", "637534226", "14848", "641204224", "14354", "3670528", "6308236288", "2130304761856", "648518346341354496", "6309216256", "648520476645130240", "4611706359392501763", "792677514882318336", "20340965113972", "4611732197915754499", "792633534417207412"]);
|
||||||
|
const expectedOut = strsToBigInts(["17728382861289829725", "13654073086381141005", "9912591532945168756", "2030068283137172501", "5084683018496047808", "151244976540463006", "11718217461613725815", "11636071286320763433", "15039144509240642782", "11629028282864249197", "2594633730779457624", "14005558505838459171", "4612881094252610438", "2828009553220809993", "4838578484623267135", "1006588603063111352", "11109191860075454495", "1187545859779038208", "14661669042642437042", "5345317080454741069", "8196674451365552863", "635818354583088260", "13515759754032305626", "1708499319988748543", "7509292798507899312"]);
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user