Add Circom Pad impl
arnaucube root@arnaucube.com
Tue, 02 Nov 2021 20:17:36 +0100
5 files changed,
102 insertions(+),
2 deletions(-)
M
README.md
→
README.md
@@ -1,5 +1,6 @@
# keccak256-circom [](https://github.com/arnaucube/keccak256-circom/actions?query=workflow%3ATest) -WIP repo. Once ready, will do a PR into [circomlib](https://github.com/iden3/circomlib). +Keccak256 hash function (ethereum version) implemented in [circom](https://github.com/iden3/circom). Spec: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf + +**Warning**: WIP, this is an experimental repo. -Spec: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf
A
circuits/keccak256.circom
@@ -0,0 +1,46 @@
+pragma circom 2.0.0; + +include "./utils.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 Keccak256(nBits) { + signal input in[nBits]; + signal output out[256]; + var i; + + // pad + component pad = Pad(nBits); + for (i=0; i<nBits; i++) { + pad.in[i] <== in[i]; + } + +}
M
go-keccak256-bits-impl/keccak_test.go
→
go-keccak256-bits-impl/keccak_test.go
@@ -2,6 +2,7 @@ package keccak
import ( "encoding/hex" + "fmt" "testing" "github.com/ethereum/go-ethereum/crypto"@@ -23,3 +24,29 @@
qt.Assert(t, h, qt.DeepEquals, expected) qt.Assert(t, hex.EncodeToString(h), qt.Equals, expectedHex) } + +func TestPad(t *testing.T) { + b := make([]byte, 32) + for i := 0; i < len(b); i++ { + b[i] = byte(i) + } + fmt.Println(b) + bBits := bytesToBits(b) + fBits := pad(bBits) + + 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}) +} + +func TestFinal(t *testing.T) { + b := make([]byte, 32) + for i := 0; i < len(b); i++ { + b[i] = byte(i) + } + fmt.Println(b) + bBits := bytesToBits(b) + fBits := final(bBits) + + 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}) +}
A
test/circuits/pad_test.circom
@@ -0,0 +1,5 @@
+pragma circom 2.0.0; + +include "../../circuits/keccak256.circom"; + +component main = Pad(32*8);
M
test/keccak256.js
→
test/keccak256.js
@@ -218,3 +218,24 @@ // console.log(stateOutU64, expectedOut);
assert.deepEqual(stateOutU64, expectedOut); }); }); + +describe("Keccak-Pad test", function () { + this.timeout(100000); + + it ("Pad (testvector generated from go)", async () => { + const cir = await wasm_tester(path.join(__dirname, "circuits", "pad_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,25,26,27,28,29,30,31]; + const expectedOut = [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]; + + const stateIn = bytesToBits(input); + + const witness = await cir.calculateWitness({ "in": stateIn }, true); + + const stateOut = witness.slice(1, 1+(136*8)); + const stateOutBytes = bitsToBytes(stateOut); + // console.log(stateOutBytes, expectedOut); + assert.deepEqual(stateOutBytes, expectedOut); + }); +}); +