├── .gitignore ├── src ├── Ref │ ├── README.md │ ├── Poseidon2 │ │ ├── Naive │ │ │ ├── Example.hs │ │ │ ├── Permutation.hs │ │ │ ├── BN256.hs │ │ │ ├── Merkle.hs │ │ │ ├── PrimeField.hs │ │ │ └── RoundConsts.hs │ │ └── Zikkurat │ │ │ ├── Sponge.hs │ │ │ ├── Merkle.hs │ │ │ ├── Permutation.hs │ │ │ ├── InvPerm.hs │ │ │ └── RoundConsts.hs │ ├── MiMC │ │ └── RoundConst.hs │ ├── Common.hs │ ├── Keccak │ │ └── Perm.hs │ ├── Griffin │ │ └── Permutation.hs │ └── Blake2 │ │ ├── BLAKE2s.hs │ │ └── BLAKE2b.hs ├── README.md ├── Test │ ├── Hash │ │ ├── Blake2.hs │ │ ├── Griffin.hs │ │ ├── Poseidon2.hs │ │ ├── Keccak.hs │ │ └── SHA2.hs │ └── Misc.hs ├── Vectors │ ├── Blake2.hs │ └── SHA2.hs └── Main.hs ├── circuits ├── blake2 │ ├── README.md │ ├── blake2_common.circom │ └── blake2s.circom ├── poseidon2 │ ├── poseidon2_hash.circom │ ├── README.md │ ├── poseidon2_merkle.circom │ ├── poseidon2_tests.circom │ └── poseidon2_sponge.circom ├── sha2 │ ├── sha224 │ │ ├── sha224_initial_value.circom │ │ ├── sha224_hash_bytes.circom │ │ └── sha224_hash_bits.circom │ ├── sha256 │ │ ├── sha256_initial_value.circom │ │ ├── README.md │ │ ├── sha256_padding.circom │ │ ├── sha256_round_const.circom │ │ ├── sha256_hash_chunk.circom │ │ ├── sha256_hash_bytes.circom │ │ ├── sha256_schedule.circom │ │ ├── sha256_hash_bits.circom │ │ ├── sha256_compress.circom │ │ └── sha256_rounds.circom │ ├── sha384 │ │ ├── sha384_initial_value.circom │ │ ├── sha384_hash_bytes.circom │ │ └── sha384_hash_bits.circom │ ├── sha512 │ │ ├── sha512_initial_value.circom │ │ ├── README.md │ │ ├── sha512_padding.circom │ │ ├── sha512_hash_chunk.circom │ │ ├── sha512_hash_bytes.circom │ │ ├── sha512_schedule.circom │ │ ├── sha512_hash_bits.circom │ │ ├── sha512_round_const.circom │ │ ├── sha512_compress.circom │ │ └── sha512_rounds.circom │ └── sha2_common.circom ├── keccak │ ├── README.md │ ├── keccak_bits.circom │ ├── sponge.circom │ ├── sha3_bits.circom │ ├── keccak_bytes.circom │ └── sha3_bytes.circom ├── mimc │ ├── README.md │ ├── mimc-stream-cipher.circom │ ├── mimc-roundfun.circom │ ├── mimc-feistel-2p-p.circom │ ├── mimc-p-p.circom │ └── mimc-test.circom └── griffin │ ├── griffin_tests.circom │ └── griffin_perm.circom ├── LICENSE ├── README.md └── hash-circuits.cabal /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | dist 3 | dist-newstyle 4 | build 5 | tmp 6 | *.hi 7 | *.o 8 | *.sym 9 | *.r1cs 10 | *.wtns 11 | -------------------------------------------------------------------------------- /src/Ref/README.md: -------------------------------------------------------------------------------- 1 | 2 | Haskell reference implementations of the hash functions 3 | ------------------------------------------------------- 4 | 5 | - `SHA256` 6 | - `Poseidon2` 7 | 8 | -------------------------------------------------------------------------------- /circuits/blake2/README.md: -------------------------------------------------------------------------------- 1 | 2 | BLAKE2 hash implementation in circom 3 | ------------------------------------ 4 | 5 | - `blake2_common.circom` - shared parts 6 | - `black2s.circom` - blake2s with 256 bit hash output 7 | - `black2b.circom` - blake2b with 256 bit hash output 8 | 9 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | 2 | Organization of the code: 3 | 4 | ### `Ref` 5 | 6 | Reference implementations: 7 | 8 | - SHA2-256 9 | - Keccak 10 | - Blake2 11 | - Poseidon2 12 | 13 | ### `Vectors` 14 | 15 | Some test vectors for hash functions: 16 | 17 | - SHA2 18 | - Keccak / SHA3 / SHAKE 19 | - Blake2 20 | 21 | ### `Test` 22 | 23 | - SHA2 24 | - Keccak / SHA3 25 | - Poseidon2 26 | 27 | 28 | -------------------------------------------------------------------------------- /circuits/poseidon2/poseidon2_hash.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "poseidon2_sponge.circom"; 4 | 5 | //------------------------------------------------------------------------------ 6 | // Hash `n` field elements into 1, with approximately 254 bits of preimage security (?) 7 | // (assuming bn128 scalar field. We use capacity=2, rate=1, t=3). 8 | 9 | template Poseidon2_hash(n) { 10 | signal input inp[n]; 11 | signal output out; 12 | 13 | component sponge = PoseidonSponge(3,2,n,1); 14 | sponge.inp <== inp; 15 | sponge.out[0] ==> out; 16 | } 17 | 18 | //------------------------------------------------------------------------------ 19 | -------------------------------------------------------------------------------- /circuits/sha2/sha224/sha224_initial_value.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | //------------------------------------------------------------------------------ 4 | // initial hash value for SHA2-224 5 | 6 | template Sha224_initial_value() { 7 | 8 | signal output out[8][32]; 9 | 10 | var initial_state[8] = 11 | [ 0xc1059ed8 12 | , 0x367cd507 13 | , 0x3070dd17 14 | , 0xf70e5939 15 | , 0xffc00b31 16 | , 0x68581511 17 | , 0x64f98fa7 18 | , 0xbefa4fa4 19 | ]; 20 | 21 | for(var k=0; k<8; k++) { 22 | for(var i=0; i<32; i++) { 23 | out[k][i] <== (initial_state[k] >> i) & 1; 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /circuits/sha2/sha256/sha256_initial_value.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | //------------------------------------------------------------------------------ 4 | // initial hash value for SHA2-256 5 | 6 | template Sha256_initial_value() { 7 | 8 | signal output out[8][32]; 9 | 10 | var initial_state[8] = 11 | [ 0x6a09e667 12 | , 0xbb67ae85 13 | , 0x3c6ef372 14 | , 0xa54ff53a 15 | , 0x510e527f 16 | , 0x9b05688c 17 | , 0x1f83d9ab 18 | , 0x5be0cd19 19 | ]; 20 | 21 | for(var k=0; k<8; k++) { 22 | for(var i=0; i<32; i++) { 23 | out[k][i] <== (initial_state[k] >> i) & 1; 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /circuits/poseidon2/README.md: -------------------------------------------------------------------------------- 1 | 2 | Poseidon2 hash function in circom (for the bn128 curve) 3 | ------------------------------------------------------- 4 | 5 | See the Poseidon2 paper here: 6 | 7 | The implementation is hardcoded for the bn128 (aka bn254 aka bn256...) 8 | curve's scalar field and `t=3`; that is, the state consists of 3 field elements 9 | of the prime field with 10 | 11 | p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 12 | 13 | TODO: 14 | 15 | - implement the [SAFE (Sponge API for Field Elements)](https://hackmd.io/bHgsH6mMStCVibM_wYvb2w) 16 | version of the sponge construction too 17 | - implement other fields and state sizes 18 | 19 | -------------------------------------------------------------------------------- /circuits/keccak/README.md: -------------------------------------------------------------------------------- 1 | 2 | Keccak implementation in circom 3 | ------------------------------- 4 | 5 | - `keccak-p.circom`: implementation of the Keccak permutation 6 | - `sponge.circom`: the sponge construction 7 | - `sha3_bits.circom`: the NIST standard SHA3 hash + XOF functions, with the input being an array of bits 8 | - `sha3_bytes.circom`: the SHA3 hash functions, with the input being an array of bytes 9 | - `keccak_bits.circom`: the original Keccak hash, bits version 10 | - `keccak_bytes.circom`: the original Keccak hash, bytes version 11 | 12 | Remark: The difference between the NIST standard and the original Keccak 13 | specification is some additional "domain separation" bits appended to the end 14 | of the message. 15 | -------------------------------------------------------------------------------- /circuits/sha2/sha384/sha384_initial_value.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | //------------------------------------------------------------------------------ 4 | // initial hash value for SHA2-384 5 | 6 | template Sha384_initial_value() { 7 | 8 | signal output out[8][64]; 9 | 10 | var initial_state[8] = 11 | [ 0xcbbb9d5dc1059ed8 12 | , 0x629a292a367cd507 13 | , 0x9159015a3070dd17 14 | , 0x152fecd8f70e5939 15 | , 0x67332667ffc00b31 16 | , 0x8eb44a8768581511 17 | , 0xdb0c2e0d64f98fa7 18 | , 0x47b5481dbefa4fa4 19 | ]; 20 | 21 | for(var k=0; k<8; k++) { 22 | for(var i=0; i<64; i++) { 23 | out[k][i] <== (initial_state[k] >> i) & 1; 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /circuits/sha2/sha512/sha512_initial_value.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | //------------------------------------------------------------------------------ 4 | // initial hash value for SHA2-512 5 | 6 | template Sha512_initial_value() { 7 | 8 | signal output out[8][64]; 9 | 10 | var initial_state[8] = 11 | [ 0x6a09e667f3bcc908 12 | , 0xbb67ae8584caa73b 13 | , 0x3c6ef372fe94f82b 14 | , 0xa54ff53a5f1d36f1 15 | , 0x510e527fade682d1 16 | , 0x9b05688c2b3e6c1f 17 | , 0x1f83d9abfb41bd6b 18 | , 0x5be0cd19137e2179 19 | ]; 20 | 21 | for(var k=0; k<8; k++) { 22 | for(var i=0; i<64; i++) { 23 | out[k][i] <== (initial_state[k] >> i) & 1; 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /circuits/sha2/sha256/README.md: -------------------------------------------------------------------------------- 1 | 2 | SHA2-256 implementation in circom 3 | --------------------------------- 4 | 5 | - `sha256_compress.circom`: inner loop of the compression functions 6 | - `sha256_schedule.circom`: the "message schedule", where the message chunk is 1024 bits 7 | - `sha256_round_const.circom`: the round constants (they are the same for SHA384 too) 8 | - `sha256_initial_value.circom`: the hash initialization vector 9 | - `sha256_rounds.circom`: the `n`-round compression function, where the hash state is 512 bits 10 | - `sha256_padding.circom`: the padding (it's the same for SHA384 too) 11 | - `sha256_hash_chunk.circom`: hash of a chunk (1024 bits), without applying any padding 12 | - `sha256_hash_bits.circom`: SHA512 hash of a sequence of bits 13 | - `sha256_hash_bytes.circom`: SHA512 hash of a sequence of bytes 14 | -------------------------------------------------------------------------------- /circuits/sha2/sha512/README.md: -------------------------------------------------------------------------------- 1 | 2 | SHA2-512 implementation in circom 3 | --------------------------------- 4 | 5 | - `sha512_compress.circom`: inner loop of the compression functions 6 | - `sha512_schedule.circom`: the "message schedule", where the message chunk is 1024 bits 7 | - `sha512_round_const.circom`: the round constants (they are the same for SHA384 too) 8 | - `sha512_initial_value.circom`: the hash initialization vector 9 | - `sha512_rounds.circom`: the `n`-round compression function, where the hash state is 512 bits 10 | - `sha512_padding.circom`: the padding (it's the same for SHA384 too) 11 | - `sha512_hash_chunk.circom`: hash of a chunk (1024 bits), without applying any padding 12 | - `sha512_hash_bits.circom`: SHA512 hash of a sequence of bits 13 | - `sha512_hash_bytes.circom`: SHA512 hash of a sequence of bytes 14 | -------------------------------------------------------------------------------- /src/Ref/Poseidon2/Naive/Example.hs: -------------------------------------------------------------------------------- 1 | 2 | module Ref.Poseidon2.Naive.Example where 3 | 4 | -------------------------------------------------------------------------------- 5 | 6 | import Ref.Poseidon2.Naive.Permutation 7 | import Ref.Poseidon2.Naive.BN256 8 | 9 | -------------------------------------------------------------------------------- 10 | 11 | -- BN256 example test vector 12 | exInput, exOutput :: Triple BN256 13 | exInput = (0,1,2) 14 | exOutput = 15 | ( 0x30610a447b7dec194697fb50786aa7421494bd64c221ba4d3b1af25fb07bd103 16 | , 0x13f731d6ffbad391be22d2ac364151849e19fa38eced4e761bcd21dbdc600288 17 | , 0x1433e2c8f68382c447c5c14b8b3df7cbfd9273dd655fe52f1357c27150da786f 18 | ) 19 | 20 | kats :: Bool 21 | kats = permutation exInput == exOutput 22 | 23 | -------------------------------------------------------------------------------- 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-2025 Faulhorn Zrt. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /circuits/sha2/sha256/sha256_padding.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | //------------------------------------------------------------------------------ 4 | // compute the number of chunks 5 | 6 | function SHA2_224_256_compute_number_of_chunks(len_bits) { 7 | var nchunks = ((len_bits + 1 + 64) + 511) \ 512; 8 | return nchunks; 9 | } 10 | 11 | //------------------------------------------------------------------------------ 12 | // padding for SHA2-224 and SHA2-256 (they are the same) 13 | // NOTE: `len` should be given as the number of *bits* 14 | 15 | template SHA2_224_256_padding(len) { 16 | 17 | var nchunks = SHA2_224_256_compute_number_of_chunks(len); 18 | var nbits = nchunks * 512; 19 | 20 | signal input inp[len]; 21 | signal output out[nchunks][512]; 22 | 23 | for(var i=0; i out[i\512][i%512]; 25 | } 26 | 27 | out[len\512][len%512] <== 1; 28 | for(var i=len+1; i out[i\1024][i%1024]; 25 | } 26 | 27 | out[len\1024][len%1024] <== 1; 28 | for(var i=len+1; i aux[b+ k ]; 37 | } 38 | 39 | a = b; 40 | u = v; 41 | } 42 | 43 | aux[2*nleaves-2] ==> out_root; 44 | } 45 | 46 | //------------------------------------------------------------------------------ 47 | -------------------------------------------------------------------------------- /circuits/sha2/sha256/sha256_round_const.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | //------------------------------------------------------------------------------ 4 | // round constants for SHA2-224 and SHA2-256 (they are the same) 5 | 6 | template SHA2_224_256_round_keys() { 7 | 8 | signal output out[64]; 9 | 10 | var round_keys[64] = 11 | [ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5 12 | , 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174 13 | , 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da 14 | , 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967 15 | , 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85 16 | , 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070 17 | , 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3 18 | , 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 19 | ]; 20 | 21 | for(var j=0; j<64; j++) { out[j] <== round_keys[j]; } 22 | 23 | } 24 | 25 | //------------------------------------------------------------------------------ 26 | -------------------------------------------------------------------------------- /circuits/sha2/sha256/sha256_hash_chunk.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "sha256_schedule.circom"; 5 | include "sha256_rounds.circom"; 6 | include "sha256_initial_value.circom"; 7 | 8 | //------------------------------------------------------------------------------ 9 | // hashes 512 bits into 256 bits, without applying any padding 10 | // this can be possibly useful for constructing a Merkle tree 11 | 12 | template Sha256_hash_chunk() { 13 | 14 | signal input inp_bits[512]; // 512 bits 15 | signal output out_hash[8][32]; // 256 bits, as 8 little-endian 32-bit words 16 | signal output out_bits[256]; // 256 flat bits, big-endian order 17 | 18 | component iv = Sha256_initial_value(); 19 | component sch = SHA2_224_256_schedule(); 20 | component rds = SHA2_224_256_rounds(64); 21 | 22 | for(var k=0; k<16; k++) { 23 | for(var i=0; i<32; i++) { 24 | sch.chunk_bits[k][i] <== inp_bits[ k*32 + (31-i) ]; 25 | } 26 | } 27 | 28 | iv.out ==> rds.inp_hash; 29 | sch.out_words ==> rds.words; 30 | rds.out_hash ==> out_hash; 31 | 32 | for(var k=0; k<8; k++) { 33 | for(var i=0; i<32; i++) { 34 | out_bits[ 32*k + i ] <== out_hash[k][31-i]; 35 | } 36 | } 37 | 38 | } 39 | 40 | //------------------------------------------------------------------------------ 41 | -------------------------------------------------------------------------------- /circuits/mimc/README.md: -------------------------------------------------------------------------------- 1 | 2 | MiMC cipher and hash function 3 | ----------------------------- 4 | 5 | MiMC-p/p and MiMC-2p/p block ciphers and permutations; and MiMC-Feistel-2p/p hash 6 | function. The implementation is specialized to the BN254 (alt-bn-128) curve's 7 | scalar field (the default field in `circom`): 8 | 9 | p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 10 | 11 | We use the parameters: exponent `d=5` and `r=ceil(log2(p)/log2(d))=110` rounds 12 | for MiMC-p/p, and `2*r=220` rounds for MiMC-2p/p (Feistel mode) 13 | 14 | The round constants are generated by the following algorithm: 15 | 16 | - take the largest prefix of the digits of pi=3.1415.., interpreted as an integer, 17 | which is less than `2^256`. Call this `seed`. 18 | - let the i-th round constant, starting from i=0, be the SHA256 hash `H(seed|i) mod p` 19 | where both `seed` and `i` and the hash are interpreted as a 256-bit little-endian 20 | numbers. 21 | 22 | For reference, 23 | 24 | seed = 31415926535897932384626433832795028841971693993751058209749445923078164062862 25 | = 0x4574c8c75d6e88acd28f7e467dac97b5c60c3838d9dad993900bdf402152228e 26 | 27 | All this is based on the paper "MiMC: Efficient Encryption and Cryptographic 28 | Hashing with Minimal Multiplicative Complexity", available at 29 | . 30 | 31 | 32 | -------------------------------------------------------------------------------- /circuits/sha2/sha512/sha512_hash_chunk.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "sha512_schedule.circom"; 5 | include "sha512_rounds.circom"; 6 | include "sha512_initial_value.circom"; 7 | 8 | //------------------------------------------------------------------------------ 9 | // hashes 1024 bits into 512 bits, without applying any padding 10 | // this can be possibly useful for constructing a Merkle tree 11 | 12 | template Sha512_hash_chunk() { 13 | 14 | signal input inp_bits[1024]; // 1024 bits 15 | signal output out_hash[8][64]; // 512 bits, as 8 little-endian 64-bit words 16 | signal output out_bits[512]; // 512 flat bits, big-endian order 17 | 18 | component iv = Sha512_initial_value(); 19 | component sch = SHA2_384_512_schedule(); 20 | component rds = SHA2_384_512_rounds(80); 21 | 22 | for(var k=0; k<16; k++) { 23 | for(var i=0; i<64; i++) { 24 | sch.chunk_bits[k][i] <== inp_bits[ k*64 + (63-i) ]; 25 | } 26 | } 27 | 28 | iv.out ==> rds.inp_hash; 29 | sch.out_words ==> rds.words; 30 | rds.out_hash ==> out_hash; 31 | 32 | for(var k=0; k<8; k++) { 33 | for(var i=0; i<64; i++) { 34 | out_bits[ 64*k + i ] <== out_hash[k][63-i]; 35 | } 36 | } 37 | 38 | } 39 | 40 | //------------------------------------------------------------------------------ 41 | -------------------------------------------------------------------------------- /circuits/keccak/keccak_bits.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "keccak-p.circom"; 4 | include "sponge.circom"; 5 | 6 | //------------------------------------------------------------------------------ 7 | // Keccak hash functions 8 | 9 | template Keccak_224(input_len) { 10 | signal input inp[input_len]; 11 | signal output out[224]; 12 | component sponge = KeccakSponge(6, 448, input_len, 224); 13 | sponge.inp <== inp; 14 | sponge.out ==> out; 15 | } 16 | 17 | //-------------------------------------- 18 | 19 | template Keccak_256(input_len) { 20 | signal input inp[input_len]; 21 | signal output out[256]; 22 | component sponge = KeccakSponge(6, 512, input_len, 256); 23 | sponge.inp <== inp; 24 | sponge.out ==> out; 25 | } 26 | 27 | //-------------------------------------- 28 | 29 | template Keccak_384(input_len) { 30 | signal input inp[input_len]; 31 | signal output out[384]; 32 | component sponge = KeccakSponge(6, 768, input_len, 384); 33 | sponge.inp <== inp; 34 | sponge.out ==> out; 35 | } 36 | 37 | //-------------------------------------- 38 | 39 | template Keccak_512(input_len) { 40 | signal input inp[input_len]; 41 | signal output out[512]; 42 | component sponge = KeccakSponge(6, 1024, input_len, 512); 43 | sponge.inp <== inp; 44 | sponge.out ==> out; 45 | } 46 | 47 | //------------------------------------------------------------------------------ 48 | 49 | -------------------------------------------------------------------------------- /src/Test/Hash/Blake2.hs: -------------------------------------------------------------------------------- 1 | 2 | module Test.Hash.Blake2 where 3 | 4 | -------------------------------------------------------------------------------- 5 | 6 | import R1CS 7 | import Test.Runner 8 | import Vectors.Blake2 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | blake2s_256_test :: SimpleHashTest 13 | blake2s_256_test = MkGenericHashTest 14 | { __circomFile = "circuits/blake2/blake2s.circom" 15 | , __templateName = "Blake2s_bytes" 16 | , __inputSignal = "inp_bytes" 17 | , __outputSignal = "hash_bytes" 18 | , __testCases = blake2s_256_vectors 19 | } 20 | 21 | blake2b_256_test :: SimpleHashTest 22 | blake2b_256_test = MkGenericHashTest 23 | { __circomFile = "circuits/blake2/blake2b.circom" 24 | , __templateName = "Blake2b_bytes" 25 | , __inputSignal = "inp_bytes" 26 | , __outputSignal = "hash_bytes" 27 | , __testCases = blake2b_256_vectors 28 | } 29 | 30 | -------------------------------------------------------------------------------- 31 | 32 | runTests_BLAKE2 :: Verbosity -> FilePath -> IO () 33 | runTests_BLAKE2 verbosity rootDir = do 34 | 35 | putStrLn "running test for BLAKE2..." 36 | 37 | runSimpleTestBytes verbosity rootDir blake2s_256_test 38 | runSimpleTestBytes verbosity rootDir blake2b_256_test 39 | 40 | -------------------------------------------------------------------------------- 41 | 42 | -------------------------------------------------------------------------------- /circuits/griffin/griffin_tests.circom: -------------------------------------------------------------------------------- 1 | 2 | // these are only wrappers to be compatible with right now very hackish 3 | // and limited test framework 4 | 5 | pragma circom 2.0.0; 6 | 7 | include "griffin_perm.circom"; 8 | 9 | //------------------------------------------------------------------------------ 10 | 11 | template Test_Griffin_permutation(dummy) { 12 | 13 | signal input inp[3]; 14 | signal output out; 15 | 16 | signal tmp[3]; 17 | 18 | component perm = Permutation(); 19 | perm.inp <== inp; 20 | perm.out ==> tmp; 21 | 22 | out <== tmp[0] + tmp[1] + tmp[2]; 23 | } 24 | 25 | //------------------------------------------------------------------------------ 26 | 27 | template Test_Griffin_compression(dummy) { 28 | 29 | signal input inp[2]; 30 | signal output out; 31 | 32 | component comp = Compression(); 33 | comp.inp <== inp; 34 | comp.out ==> out; 35 | } 36 | 37 | //------------------------------------------------------------------------------ 38 | 39 | template Test_Griffin_iterated_permutation(dummy) { 40 | 41 | signal input inp[3]; 42 | signal output out; 43 | 44 | signal aux[101][3]; 45 | 46 | component perm[100]; 47 | 48 | aux[0] <== inp; 49 | for(var i=0; i<100; i++) { 50 | perm[i] = Permutation(); 51 | perm[i].inp <== aux[i]; 52 | perm[i].out ==> aux[i+1]; 53 | } 54 | 55 | signal tmp[3]; 56 | tmp <== aux[100]; 57 | 58 | out <== tmp[0] + tmp[1] + tmp[2]; 59 | } 60 | 61 | //------------------------------------------------------------------------------ 62 | -------------------------------------------------------------------------------- /circuits/mimc/mimc-stream-cipher.circom: -------------------------------------------------------------------------------- 1 | 2 | // stream ciphers based on the MiMC-p/p block cipher 3 | 4 | pragma circom 2.0.0; 5 | 6 | include "mimc-p-p.circom"; 7 | 8 | //------------------------------------------------------------------------------ 9 | 10 | // 11 | // encrypt a sequence of `n` field elements using CFB (Cipher feedback) mode 12 | // 13 | 14 | template MiMC_p$p_CFB_encrypt(n) { 15 | signal input key; // encryption key 16 | signal input iv; // initialization vector (should be random and non-repeating) 17 | signal input inp[n]; 18 | signal output out[n]; 19 | 20 | component enc[n]; 21 | for(var i=0; i enc[i].key; 25 | out[i] <== enc[i].out + inp[i]; 26 | } 27 | } 28 | 29 | //-------------------------------------- 30 | 31 | // 32 | // decrypt a sequence of `n` field elements encrypted using CFB (Cipher feedback) mode 33 | // 34 | 35 | template MiMC_p$p_CFB_decrypt(n) { 36 | signal input key; // encryption key 37 | signal input iv; // initialization vector (should be random and non-repeating) 38 | signal input inp[n]; 39 | signal output out[n]; 40 | 41 | component enc[n]; 42 | for(var i=0; i enc[i].key; 46 | out[i] <== inp[i] - enc[i].out; 47 | } 48 | } 49 | 50 | //------------------------------------------------------------------------------ 51 | -------------------------------------------------------------------------------- /src/Ref/Poseidon2/Naive/Permutation.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | The Poseidon2 permutation 3 | 4 | module Ref.Poseidon2.Naive.Permutation where 5 | 6 | -------------------------------------------------------------------------------- 7 | 8 | import Ref.Poseidon2.Naive.RoundConsts 9 | import Ref.Poseidon2.Naive.BN256 10 | 11 | -------------------------------------------------------------------------------- 12 | 13 | type Triple a = (a,a,a) 14 | 15 | -------------------------------------------------------------------------------- 16 | 17 | sbox :: BN256 -> BN256 18 | sbox x = x4*x where 19 | x2 = x *x 20 | x4 = x2*x2 21 | 22 | internalRound :: BN256 -> Triple BN256 -> Triple BN256 23 | internalRound c (x,y,z) = 24 | ( 2*x' + y + z 25 | , x' + 2*y + z 26 | , x' + y + 3*z 27 | ) 28 | where 29 | x' = sbox (x + c) 30 | 31 | externalRound :: Triple BN256 -> Triple BN256 -> Triple BN256 32 | externalRound (cx,cy,cz) (x,y,z) = (x'+s , y'+s , z'+s) where 33 | x' = sbox (x + cx) 34 | y' = sbox (y + cy) 35 | z' = sbox (z + cz) 36 | s = x' + y' + z' 37 | 38 | linearLayer :: Triple BN256 -> Triple BN256 39 | linearLayer (x,y,z) = (x+s, y+s, z+s) where s = x+y+z 40 | 41 | -------------------------------------------------------------------------------- 42 | 43 | permutation :: Triple BN256 -> Triple BN256 44 | permutation 45 | = (\state -> foldl (flip externalRound) state finalRoundConsts ) 46 | . (\state -> foldl (flip internalRound) state internalRoundConsts) 47 | . (\state -> foldl (flip externalRound) state initialRoundConsts ) 48 | . linearLayer 49 | 50 | -------------------------------------------------------------------------------- 51 | -------------------------------------------------------------------------------- /circuits/sha2/sha224/sha224_hash_bytes.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "sha224_hash_bits.circom"; 5 | 6 | //------------------------------------------------------------------------------ 7 | // Computes the SHA224 hash of a sequence of bytes 8 | // The output is 7 little-endian 32-bit words. 9 | // See below for the more standard "digest" version 10 | 11 | template Sha224_hash_bytes(n) { 12 | 13 | signal input inp_bytes[n]; // `n` bytes 14 | signal output hash_dwords[7][32]; // 224 bits, as 7 little-endian 32-bit words 15 | 16 | signal inp_bits[8*n]; 17 | 18 | component sha = Sha224_hash_bits(8*n); 19 | component tobits[n]; 20 | 21 | for(var j=0; j inp_bits[ j*8 + 7-i ]; 26 | } 27 | } 28 | 29 | sha.inp_bits <== inp_bits; 30 | sha.hash_dwords ==> hash_dwords; 31 | } 32 | 33 | //------------------------------------------------------------------------------ 34 | // Computes the SHA224 hash of a sequence of bits 35 | // The output is 28 bytes in the standard order 36 | 37 | template Sha224_hash_bytes_digest(n) { 38 | 39 | signal input inp_bytes [n]; // `n` bytes 40 | signal output hash_bytes[28]; // 28 bytes 41 | 42 | component sha = Sha224_hash_bytes(n); 43 | component ser = DWordsToByteString(7); 44 | 45 | inp_bytes ==> sha.inp_bytes; 46 | sha.hash_dwords ==> ser.inp; 47 | ser.out ==> hash_bytes; 48 | } 49 | 50 | //------------------------------------------------------------------------------ 51 | -------------------------------------------------------------------------------- /circuits/sha2/sha256/sha256_hash_bytes.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "sha256_hash_bits.circom"; 5 | 6 | //------------------------------------------------------------------------------ 7 | // Computes the SHA256 hash of a sequence of bytes 8 | // The output is 8 little-endian 32-bit words. 9 | // See below for the more standard "digest" version 10 | 11 | template Sha256_hash_bytes(n) { 12 | 13 | signal input inp_bytes[n]; // `n` bytes 14 | signal output hash_dwords[8][32]; // 256 bits, as 8 little-endian 32-bit words 15 | 16 | signal inp_bits[8*n]; 17 | 18 | component sha = Sha256_hash_bits(8*n); 19 | component tobits[n]; 20 | 21 | for(var j=0; j inp_bits[ j*8 + 7-i ]; 26 | } 27 | } 28 | 29 | sha.inp_bits <== inp_bits; 30 | sha.hash_dwords ==> hash_dwords; 31 | } 32 | 33 | //------------------------------------------------------------------------------ 34 | // Computes the SHA256 hash of a sequence of bits 35 | // The output is 32 bytes in the standard order 36 | 37 | template Sha256_hash_bytes_digest(n) { 38 | 39 | signal input inp_bytes [n]; // `n` bytes 40 | signal output hash_bytes[32]; // 32 bytes 41 | 42 | component sha = Sha256_hash_bytes(n); 43 | component ser = DWordsToByteString(8); 44 | 45 | inp_bytes ==> sha.inp_bytes; 46 | sha.hash_dwords ==> ser.inp; 47 | ser.out ==> hash_bytes; 48 | } 49 | 50 | //------------------------------------------------------------------------------ 51 | -------------------------------------------------------------------------------- /circuits/sha2/sha384/sha384_hash_bytes.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "sha384_hash_bits.circom"; 5 | 6 | //------------------------------------------------------------------------------ 7 | // Computes the SHA384 hash of a sequence of bytes 8 | // The output is 6 little-endian 64-bit words. 9 | // See below for the more standard "digest" version 10 | 11 | template Sha384_hash_bytes(n) { 12 | 13 | signal input inp_bytes[n]; // `n` bytes 14 | signal output hash_qwords[6][64]; // 384 bits, as 6 little-endian 64-bit words 15 | 16 | signal inp_bits[8*n]; 17 | 18 | component sha = Sha384_hash_bits(8*n); 19 | component tobits[n]; 20 | 21 | for(var j=0; j inp_bits[ j*8 + 7-i ]; 26 | } 27 | } 28 | 29 | sha.inp_bits <== inp_bits; 30 | sha.hash_qwords ==> hash_qwords; 31 | } 32 | 33 | //------------------------------------------------------------------------------ 34 | // Computes the SHA384 hash of a sequence of bits 35 | // The output is 48 bytes in the standard order 36 | 37 | template Sha384_hash_bytes_digest(n) { 38 | 39 | signal input inp_bytes [n]; // `n` bytes 40 | signal output hash_bytes[48]; // 48 bytes 41 | 42 | component sha = Sha384_hash_bytes(n); 43 | component ser = QWordsToByteString(6); 44 | 45 | inp_bytes ==> sha.inp_bytes; 46 | sha.hash_qwords ==> ser.inp; 47 | ser.out ==> hash_bytes; 48 | } 49 | 50 | //------------------------------------------------------------------------------ 51 | -------------------------------------------------------------------------------- /circuits/sha2/sha512/sha512_hash_bytes.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "sha512_hash_bits.circom"; 5 | 6 | //------------------------------------------------------------------------------ 7 | // Computes the SHA512 hash of a sequence of bytes 8 | // The output is 8 little-endian 64-bit words. 9 | // See below for the more standard "digest" version 10 | 11 | template Sha512_hash_bytes(n) { 12 | 13 | signal input inp_bytes[n]; // `n` bytes 14 | signal output hash_qwords[8][64]; // 512 bits, as 8 little-endian 64-bit words 15 | 16 | signal inp_bits[8*n]; 17 | 18 | component sha = Sha512_hash_bits(8*n); 19 | component tobits[n]; 20 | 21 | for(var j=0; j inp_bits[ j*8 + 7-i ]; 26 | } 27 | } 28 | 29 | sha.inp_bits <== inp_bits; 30 | sha.hash_qwords ==> hash_qwords; 31 | } 32 | 33 | //------------------------------------------------------------------------------ 34 | // Computes the SHA512 hash of a sequence of bits 35 | // The output is 64 bytes in the standard order 36 | 37 | template Sha512_hash_bytes_digest(n) { 38 | 39 | signal input inp_bytes [n]; // `n` bytes 40 | signal output hash_bytes[64]; // 64 bytes 41 | 42 | component sha = Sha512_hash_bytes(n); 43 | component ser = QWordsToByteString(8); 44 | 45 | inp_bytes ==> sha.inp_bytes; 46 | sha.hash_qwords ==> ser.inp; 47 | ser.out ==> hash_bytes; 48 | } 49 | 50 | //------------------------------------------------------------------------------ 51 | -------------------------------------------------------------------------------- /src/Ref/Poseidon2/Naive/BN256.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | The bn256 (aka bn128 aka BN254) scalar field 3 | 4 | module Ref.Poseidon2.Naive.BN256 where 5 | 6 | -------------------------------------------------------------------------------- 7 | 8 | import Data.Bits 9 | import Data.Word 10 | import Data.Ratio 11 | 12 | import qualified Ref.Poseidon2.Naive.PrimeField as Gen 13 | 14 | -------------------------------------------------------------------------------- 15 | 16 | -- | BN256 scalar field 17 | newtype BN256 = MkBN256 Integer deriving (Eq,Show) 18 | 19 | unBN256 :: BN256 -> Integer 20 | unBN256 (MkBN256 x) = x 21 | 22 | toBN256 :: Integer -> BN256 23 | toBN256 = MkBN256 . modBN256 24 | 25 | modBN256 :: Integer -> Integer 26 | modBN256 x = mod x fieldPrimeBN256 27 | 28 | fieldPrimeBN256 :: Integer 29 | fieldPrimeBN256 = 21888242871839275222246405745257275088548364400416034343698204186575808495617 30 | 31 | instance Num BN256 where 32 | fromInteger = toBN256 . fromInteger 33 | negate (MkBN256 x) = MkBN256 $ Gen.neg fieldPrimeBN256 x 34 | (+) (MkBN256 x) (MkBN256 y) = MkBN256 $ Gen.add fieldPrimeBN256 x y 35 | (-) (MkBN256 x) (MkBN256 y) = MkBN256 $ Gen.sub fieldPrimeBN256 x y 36 | (*) (MkBN256 x) (MkBN256 y) = MkBN256 $ Gen.mul fieldPrimeBN256 x y 37 | abs x = x 38 | signum _ = toBN256 1 39 | 40 | instance Fractional BN256 where 41 | recip (MkBN256 x) = MkBN256 $ Gen.inv fieldPrimeBN256 x 42 | (/) (MkBN256 x) (MkBN256 y) = MkBN256 $ Gen.div fieldPrimeBN256 x y 43 | fromRational x = fromInteger (numerator x) / fromInteger (denominator x) 44 | 45 | -------------------------------------------------------------------------------- 46 | -------------------------------------------------------------------------------- /src/Ref/Poseidon2/Zikkurat/Sponge.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE NumericUnderscores #-} 3 | module Ref.Poseidon2.Zikkurat.Sponge where 4 | 5 | -------------------------------------------------------------------------------- 6 | 7 | import ZK.Algebra.Curves.BN128.Fr.Mont (Fr) 8 | 9 | import Ref.Poseidon2.Zikkurat.Permutation 10 | 11 | -------------------------------------------------------------------------------- 12 | 13 | -- | Sponge construction with rate=1 (capacity=2), zero IV and 10* padding 14 | spongeRate1 :: [Fr] -> Fr 15 | spongeRate1 input = go (0,0,civ) (pad input) where 16 | 17 | -- domain separation: 18 | -- capacity IV = (2^64 + 256*t + r) 19 | civ :: Fr 20 | civ = fromInteger $ 0x1_0000_0000_0000_0301 21 | 22 | pad :: [Fr] -> [Fr] 23 | pad (x:xs) = x : pad xs 24 | pad [] = [1] 25 | 26 | go (sx,_ ,_ ) [] = sx 27 | go (sx,sy,sz) (a:as) = go state' as where 28 | state' = permutation (sx+a, sy, sz) 29 | 30 | -------------------------------------------------------------------------------- 31 | 32 | -- | Sponge construction with rate=2 (capacity=1), zero IV and 10* padding 33 | spongeRate2 :: [Fr] -> Fr 34 | spongeRate2 input = go (0,0,civ) (pad input) where 35 | 36 | -- domain separation: 37 | -- capacity IV = (2^64 + 256*t + r) 38 | civ :: Fr 39 | civ = fromInteger $ 0x1_0000_0000_0000_0302 40 | 41 | pad :: [Fr] -> [Fr] 42 | pad (x:y:rest) = x : y : pad rest 43 | pad [x] = [x,1] 44 | pad [] = [1,0] 45 | 46 | go (sx,_ ,_ ) [] = sx 47 | go (sx,sy,sz) (a:b:rest) = go state' rest where 48 | state' = permutation (sx+a, sy+b, sz) 49 | 50 | -------------------------------------------------------------------------------- 51 | 52 | -------------------------------------------------------------------------------- /circuits/poseidon2/poseidon2_tests.circom: -------------------------------------------------------------------------------- 1 | 2 | // these are only wrappers to be compatible with right now very hackish 3 | // and limited test framework 4 | 5 | pragma circom 2.0.0; 6 | 7 | include "poseidon2_merkle.circom"; 8 | 9 | //------------------------------------------------------------------------------ 10 | 11 | template Test_Poseidon2_permutation(dummy) { 12 | 13 | signal input inp[3]; 14 | signal output out; 15 | 16 | signal tmp[3]; 17 | 18 | component perm = Permutation(); 19 | perm.inp <== inp; 20 | perm.out ==> tmp; 21 | 22 | out <== tmp[0] + tmp[1] + tmp[2]; 23 | } 24 | 25 | //------------------------------------------------------------------------------ 26 | 27 | template Test_Poseidon2_compression(dummy) { 28 | 29 | signal input inp[2]; 30 | signal output out; 31 | 32 | component comp = Compression(); 33 | comp.inp <== inp; 34 | comp.out ==> out; 35 | } 36 | 37 | //------------------------------------------------------------------------------ 38 | 39 | // compute (compile time) the log2 of a number 40 | 41 | function FloorLog2(n) { 42 | return (n==0) ? -1 : (1 + FloorLog2(n>>1)); 43 | } 44 | 45 | function CeilLog2(n) { 46 | return (n==0) ? 0 : (1 + FloorLog2(n-1)); 47 | } 48 | 49 | //------------------------------------------------------------------------------ 50 | 51 | template Test_Poseidon2_merkle_tree(n) { 52 | 53 | var log2n = CeilLog2(n); 54 | 55 | // for now this only works for power-of-two sized inputs 56 | assert( (1< out; 64 | 65 | } 66 | 67 | //------------------------------------------------------------------------------ 68 | -------------------------------------------------------------------------------- /src/Ref/Poseidon2/Naive/Merkle.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | Merkle tree built from Poseidon2 permutation 3 | 4 | module Ref.Poseidon2.Naive.Merkle where 5 | 6 | -------------------------------------------------------------------------------- 7 | 8 | import Ref.Poseidon2.Naive.Permutation 9 | import Ref.Poseidon2.Naive.BN256 10 | 11 | -------------------------------------------------------------------------------- 12 | 13 | merkleRoot :: [BN256] -> BN256 14 | merkleRoot [] = error "merkleRoot: input is empty" 15 | merkleRoot [x] = x 16 | merkleRoot xs = merkleRoot $ map compression $ pairs xs 17 | 18 | compression :: (BN256,BN256) -> BN256 19 | compression (x,y) = case permutation (x,y,0) of (z,_,_) -> z 20 | 21 | pairs :: [BN256] -> [(BN256,BN256)] 22 | pairs [] = [] 23 | pairs [x] = (x,x) : [] 24 | pairs (x:y:rest) = (x,y) : pairs rest 25 | 26 | -------------------------------------------------------------------------------- 27 | 28 | printExampleMerkleRoots :: IO () 29 | printExampleMerkleRoots = do 30 | putStrLn $ "Merkle root for [1.. 1] = " ++ show (merkleRoot $ map toBN256 [1.. 1]) 31 | putStrLn $ "Merkle root for [1.. 2] = " ++ show (merkleRoot $ map toBN256 [1.. 2]) 32 | putStrLn $ "Merkle root for [1.. 4] = " ++ show (merkleRoot $ map toBN256 [1.. 4]) 33 | putStrLn $ "Merkle root for [1.. 16] = " ++ show (merkleRoot $ map toBN256 [1.. 16]) 34 | putStrLn $ "Merkle root for [1.. 64] = " ++ show (merkleRoot $ map toBN256 [1.. 64]) 35 | putStrLn $ "Merkle root for [1.. 256] = " ++ show (merkleRoot $ map toBN256 [1.. 256]) 36 | putStrLn $ "Merkle root for [1..1024] = " ++ show (merkleRoot $ map toBN256 [1..1024]) 37 | -- putStrLn $ "merkle root for [1..4096] = " ++ show (merkleRoot $ map toBN256 [1..4096]) 38 | 39 | -------------------------------------------------------------------------------- 40 | -------------------------------------------------------------------------------- /src/Ref/Poseidon2/Zikkurat/Merkle.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | Merkle tree built from Poseidon2 permutation 3 | 4 | {-# LANGUAGE BangPatterns #-} 5 | module Ref.Poseidon2.Zikkurat.Merkle where 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | import Data.Array 10 | import Data.Bits 11 | 12 | import ZK.Algebra.Curves.BN128.Fr.Mont (Fr) 13 | 14 | import Ref.Poseidon2.Zikkurat.Permutation 15 | 16 | -------------------------------------------------------------------------------- 17 | 18 | calcMerkleRoot :: [Fr] -> Fr 19 | calcMerkleRoot = go where 20 | go [] = error "calcMerkleRoot: input is empty" 21 | go [x] = x 22 | go xs = go (map compressPair $ pairs xs) 23 | 24 | compressPair :: (Fr,Fr) -> Fr 25 | compressPair (x,y) = compression x y 26 | 27 | compression :: Fr -> Fr -> Fr 28 | compression x y = case permutation (x,y,0) of (z,_,_) -> z 29 | 30 | pairs :: [Fr] -> [(Fr,Fr)] 31 | pairs [] = [] 32 | pairs [x] = (x,x) : [] 33 | pairs (x:y:rest) = (x,y) : pairs rest 34 | 35 | -------------------------------------------------------------------------------- 36 | 37 | printExampleMerkleRoots :: IO () 38 | printExampleMerkleRoots = do 39 | putStrLn $ "Merkle root for [1.. 1] = " ++ show (calcMerkleRoot $ map fromInteger [1.. 1]) 40 | putStrLn $ "Merkle root for [1.. 2] = " ++ show (calcMerkleRoot $ map fromInteger [1.. 2]) 41 | putStrLn $ "Merkle root for [1.. 4] = " ++ show (calcMerkleRoot $ map fromInteger [1.. 4]) 42 | putStrLn $ "Merkle root for [1.. 16] = " ++ show (calcMerkleRoot $ map fromInteger [1.. 16]) 43 | putStrLn $ "Merkle root for [1.. 64] = " ++ show (calcMerkleRoot $ map fromInteger [1.. 64]) 44 | putStrLn $ "Merkle root for [1.. 256] = " ++ show (calcMerkleRoot $ map fromInteger [1.. 256]) 45 | putStrLn $ "Merkle root for [1..1024] = " ++ show (calcMerkleRoot $ map fromInteger [1..1024]) 46 | 47 | -------------------------------------------------------------------------------- 48 | -------------------------------------------------------------------------------- /src/Vectors/Blake2.hs: -------------------------------------------------------------------------------- 1 | 2 | module Vectors.Blake2 where 3 | 4 | -------------------------------------------------------------------------------- 5 | 6 | data HashFun 7 | = Blake2s_256 8 | | Blake2b_256 9 | -- | Blake2b_512 10 | deriving (Eq,Show) 11 | 12 | -------------------------------------------------------------------------------- 13 | 14 | testVectorsKeccak :: HashFun -> [(String,String)] 15 | testVectorsKeccak hashfun = case hashfun of 16 | Blake2s_256 -> blake2s_256_vectors 17 | Blake2b_256 -> blake2b_256_vectors 18 | 19 | -------------------------------------------------------------------------------- 20 | 21 | infix 1 ~> 22 | (~>) :: a -> b -> (a,b) 23 | (~>) x y = (x,y) 24 | 25 | -------------------------------------------------------------------------------- 26 | 27 | blake2s_256_vectors :: [(String,String)] 28 | blake2s_256_vectors = 29 | [ "" ~> "69217a3079908094e11121d042354a7c1f55b6482ca1a51e1b250dfd1ed0eef9" 30 | , "a" ~> "4a0d129873403037c2cd9b9048203687f6233fb6738956e0349bd4320fec3e90" 31 | , "abc" ~> "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982" 32 | , "foo" ~> "08d6cad88075de8f192db097573d0e829411cd91eb6ec65e8fc16c017edfdb74" 33 | , "alma" ~> "4c8d13703a43171f7effdad39f53198b6c94f813ec9d4fb220dfe03317830a63" 34 | , "almakorte" ~> "3fee862ff6790cdab0bb2023094003671022349e5fad110f8ef3a13c894e9ecc" 35 | ] 36 | 37 | blake2b_256_vectors :: [(String,String)] 38 | blake2b_256_vectors = 39 | [ "" ~> "0e5751c026e543b2e8ab2eb06099daa1d1e5df47778f7787faab45cdf12fe3a8" 40 | , "a" ~> "8928aae63c84d87ea098564d1e03ad813f107add474e56aedd286349c0c03ea4" 41 | , "abc" ~> "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319" 42 | , "foo" ~> "b8fe9f7f6255a6fa08f668ab632a8d081ad87983c77cd274e48ce450f0b349fd" 43 | , "alma" ~> "dabd580ce2f567a34034484016c9725a07efedaeda1108c96f2ffe5310b14cf5" 44 | , "almakorte" ~> "bf96756a8ec499c33ea0431ae8f6ebf6f7f91a2e2ad1846ae804aff2d82f0f2a" 45 | ] 46 | 47 | -------------------------------------------------------------------------------- 48 | -------------------------------------------------------------------------------- /src/Test/Misc.hs: -------------------------------------------------------------------------------- 1 | 2 | module Test.Misc where 3 | 4 | -------------------------------------------------------------------------------- 5 | 6 | import Data.Bits 7 | import Data.Char 8 | import Data.Word 9 | 10 | import R1CS 11 | 12 | -------------------------------------------------------------------------------- 13 | 14 | ordAscii :: Char -> Word8 15 | ordAscii = fromIntegral . ord 16 | 17 | -------------------------------------------------------------------------------- 18 | 19 | byteToBitsBE :: Word8 -> [Bit] 20 | byteToBitsBE k = [ case shiftR k (7-i) .&. 1 of { 0 -> Zero ; 1 -> One } | i <- [0..7] ] 21 | 22 | byteFromBitsBE :: [Bit] -> Word8 23 | byteFromBitsBE bs = sum $ zipWith f [0..7] (reverse bs) where 24 | f i One = shiftL 1 i 25 | f _ Zero = 0 26 | 27 | ---------------------------------------- 28 | 29 | word32ToBitsBE :: Word32 -> [Bit] 30 | word32ToBitsBE = reverse . word32ToBitsLE 31 | 32 | word32ToBitsLE :: Word32 -> [Bit] 33 | word32ToBitsLE = go 32 where 34 | go 0 _ = [] 35 | go k w = this : go (k-1) (shiftR w 1) where 36 | this = case (w .&. 1) of { 0 -> Zero ; 1 -> One } 37 | 38 | word32FromBitsBE :: [Bit] -> Word32 39 | word32FromBitsBE = go 0 where 40 | go acc [] = acc 41 | go acc (b:bs) = go acc' bs where acc' = 2*acc + case b of { Zero -> 0 ; One -> 1 } 42 | 43 | word32FromBitsLE :: [Bit] -> Word32 44 | word32FromBitsLE = go 1 where 45 | go mult [] = 0 46 | go mult (b:bs) = go (2*mult) bs + case b of { Zero -> 0 ; One -> mult } 47 | 48 | -------------------------------------------------------------------------------- 49 | 50 | partition :: Int -> [a] -> [[a]] 51 | partition _ [] = [] 52 | partition m xs = take m xs : partition m (drop m xs) 53 | 54 | -------------------------------------------------------------------------------- 55 | 56 | integerToBit :: Integer -> Bit 57 | integerToBit 0 = Zero 58 | integerToBit 1 = One 59 | integerToBit _ = error "integerToBit: expecting 0 or 1" 60 | 61 | bitToInteger :: Bit -> Integer 62 | bitToInteger Zero = 0 63 | bitToInteger One = 1 64 | 65 | -------------------------------------------------------------------------------- 66 | -------------------------------------------------------------------------------- /circuits/mimc/mimc-roundfun.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "mimc-roundconst.circom"; 4 | include "mimc-roundfun.circom"; 5 | 6 | //------------------------------------------------------------------------------ 7 | 8 | // 9 | // the function `x -> x^5` 10 | // 11 | template pow5() { 12 | signal input inp; 13 | signal output out; 14 | 15 | signal tmp2, tmp4; 16 | tmp2 <== inp * inp ; // x^2 17 | tmp4 <== tmp2 * tmp2; // x^4 18 | out <== tmp4 * inp ; // x^5 19 | } 20 | 21 | //-------------------------------------- 22 | 23 | // 24 | // inverse of `x -> x^5`, naive (large proof) implementation 25 | // 26 | template inv_pow5_naive() { 27 | signal input inp; 28 | signal output out; 29 | 30 | // (a^5)^invExpo === a (mod prime) 31 | var invExpo = 17510594297471420177797124596205820070838691520332827474958563349260646796493; 32 | 33 | signal pow[254]; // x,x^2,x^4,..x^(2^253) 34 | signal aux[255]; 35 | 36 | aux[0] <== 1; 37 | for(var i=0; i<254; i++) { 38 | if (i==0) { pow[i] <== inp; } else { pow[i] <== pow[i-1] * pow[i-1]; } 39 | if ((invExpo>>i)&1) { 40 | aux[i+1] <== aux[i] * pow[i]; 41 | } 42 | else { 43 | aux[i+1] <== aux[i]; 44 | } 45 | } 46 | 47 | out <== aux[254]; 48 | } 49 | 50 | //-------------------------------------- 51 | 52 | function func_inv_pow5(x) { 53 | // (a^5)^invExpo === a (mod prime) 54 | var invExpo = 17510594297471420177797124596205820070838691520332827474958563349260646796493; 55 | var pow = x; 56 | var aux = 1; 57 | for(var i=0; i<254; i++) { 58 | if ((invExpo>>i)&1) { aux = aux * pow; } 59 | pow = pow*pow; 60 | } 61 | return aux; 62 | } 63 | 64 | //-------------------------------------- 65 | 66 | template inv_pow5() { 67 | signal input inp; 68 | signal output out; 69 | 70 | out <-- func_inv_pow5(inp); // first we guess the result = inp^invExpo 71 | 72 | component pow = pow5(); 73 | pow.inp <== out; 74 | pow.out === inp; // then we check that result^5 == inp 75 | 76 | // since `x -> x^5` is a permutation, this proves our guess. 77 | } 78 | 79 | //------------------------------------------------------------------------------ 80 | 81 | -------------------------------------------------------------------------------- /src/Ref/Poseidon2/Zikkurat/Permutation.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | The Poseidon2 permutation 3 | 4 | module Ref.Poseidon2.Zikkurat.Permutation where 5 | 6 | -------------------------------------------------------------------------------- 7 | 8 | import ZK.Algebra.Curves.BN128.Fr.Mont (Fr,from) 9 | 10 | import Ref.Poseidon2.Zikkurat.RoundConsts 11 | 12 | -------------------------------------------------------------------------------- 13 | 14 | frToInteger :: Fr -> Integer 15 | frToInteger = ZK.Algebra.Curves.BN128.Fr.Mont.from 16 | 17 | -------------------------------------------------------------------------------- 18 | 19 | sbox :: Fr -> Fr 20 | sbox x = x4*x where 21 | x2 = x *x 22 | x4 = x2*x2 23 | 24 | internalRound :: Fr -> (Fr,Fr,Fr) -> (Fr,Fr,Fr) 25 | internalRound c (x,y,z) = 26 | ( 2*x' + y + z 27 | , x' + 2*y + z 28 | , x' + y + 3*z 29 | ) 30 | where 31 | x' = sbox (x + c) 32 | 33 | externalRound :: (Fr,Fr,Fr) -> (Fr,Fr,Fr) -> (Fr,Fr,Fr) 34 | externalRound (cx,cy,cz) (x,y,z) = (x'+s , y'+s , z'+s) where 35 | x' = sbox (x + cx) 36 | y' = sbox (y + cy) 37 | z' = sbox (z + cz) 38 | s = x' + y' + z' 39 | 40 | linearLayer :: (Fr,Fr,Fr) -> (Fr,Fr,Fr) 41 | linearLayer (x,y,z) = (x+s, y+s, z+s) where s = x+y+z 42 | 43 | -------------------------------------------------------------------------------- 44 | 45 | permutation :: (Fr,Fr,Fr) -> (Fr,Fr,Fr) 46 | permutation 47 | = (\state -> foldl (flip externalRound) state finalRoundConsts ) 48 | . (\state -> foldl (flip internalRound) state internalRoundConsts) 49 | . (\state -> foldl (flip externalRound) state initialRoundConsts ) 50 | . linearLayer 51 | 52 | -------------------------------------------------------------------------------- 53 | 54 | -- | BN254 example test vector 55 | exInput, exOutput :: (Fr,Fr,Fr) 56 | exInput = (0,1,2) 57 | exOutput = 58 | ( 0x30610a447b7dec194697fb50786aa7421494bd64c221ba4d3b1af25fb07bd103 59 | , 0x13f731d6ffbad391be22d2ac364151849e19fa38eced4e761bcd21dbdc600288 60 | , 0x1433e2c8f68382c447c5c14b8b3df7cbfd9273dd655fe52f1357c27150da786f 61 | ) 62 | 63 | kats :: Bool 64 | kats = permutation exInput == exOutput 65 | 66 | -------------------------------------------------------------------------------- 67 | -------------------------------------------------------------------------------- /circuits/sha2/sha256/sha256_schedule.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | 5 | //------------------------------------------------------------------------------ 6 | // message schedule for SHA224 / SHA256 7 | // 8 | // NOTE: the individual 64 bit words are in little-endian order 9 | // 10 | 11 | template SHA2_224_256_schedule() { 12 | 13 | signal input chunk_bits[16][32]; // 512 bits = 16 dwords = 64 bytes 14 | signal output out_words [64]; // 64 dwords 15 | signal out_bits [64][32]; // 2048 bits = 64 dwords = 256 bytes 16 | 17 | for(var k=0; k<16; k++) { 18 | var sum = 0; 19 | for(var i=0; i<32; i++) { sum += (1< out_bits [m]; 60 | modulo[r].out_word ==> out_words[m]; 61 | 62 | } 63 | } 64 | 65 | //------------------------------------------------------------------------------ 66 | -------------------------------------------------------------------------------- /circuits/sha2/sha512/sha512_schedule.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | 5 | //------------------------------------------------------------------------------ 6 | // message schedule for SHA384 / SHA512 7 | // 8 | // NOTE: the individual 64 bit words are in little-endian order 9 | // 10 | 11 | template SHA2_384_512_schedule() { 12 | 13 | signal input chunk_bits[16][64]; // 1024 bits = 16 qwords = 128 bytes 14 | signal output out_words [80]; // 80 words 15 | signal out_bits [80][64]; // 5120 bits = 80 qwords = 640 bytes 16 | 17 | for(var k=0; k<16; k++) { 18 | var sum = 0; 19 | for(var i=0; i<64; i++) { sum += (1< out_bits [m]; 60 | modulo[r].out_word ==> out_words[m]; 61 | 62 | } 63 | } 64 | 65 | //------------------------------------------------------------------------------ 66 | -------------------------------------------------------------------------------- /circuits/sha2/sha256/sha256_hash_bits.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "sha256_padding.circom"; 5 | include "sha256_initial_value.circom"; 6 | include "sha256_schedule.circom"; 7 | include "sha256_rounds.circom"; 8 | 9 | //------------------------------------------------------------------------------ 10 | // Computes the SHA256 hash of a sequence of bits 11 | // The output is 8 little-endian 32-bit words. 12 | // See below for the more standard "digest" version 13 | 14 | template Sha256_hash_bits(len) { 15 | 16 | signal input inp_bits[len]; // `len` bits 17 | signal output hash_dwords[8][32]; // 256 bits, as 8 little-endian 32-bit words 18 | 19 | var nchunks = SHA2_224_256_compute_number_of_chunks(len); 20 | 21 | signal chunks[nchunks ][512]; 22 | signal states[nchunks+1][8][32]; 23 | 24 | component pad = SHA2_224_256_padding(len); 25 | pad.inp <== inp_bits; 26 | pad.out ==> chunks; 27 | 28 | component iv = Sha256_initial_value(); 29 | iv.out ==> states[0]; 30 | 31 | component sch[nchunks]; 32 | component rds[nchunks]; 33 | 34 | for(var m=0; m rds[m].words; 46 | 47 | rds[m].inp_hash <== states[m ]; 48 | rds[m].out_hash ==> states[m+1]; 49 | } 50 | 51 | hash_dwords <== states[nchunks]; 52 | 53 | } 54 | 55 | //------------------------------------------------------------------------------ 56 | // Computes the SHA256 hash of a sequence of bits 57 | // The output is 32 bytes in the standard order 58 | 59 | template Sha256_hash_bits_digest(len) { 60 | 61 | signal input inp_bits[len]; // `len` bits 62 | signal output hash_bytes[32]; // 32 bytes 63 | 64 | component sha = Sha256_hash_bits(len); 65 | component ser = DWordsToByteString(8); 66 | 67 | inp_bits ==> sha.inp_bits; 68 | sha.hash_dwords ==> ser.inp; 69 | ser.out ==> hash_bytes; 70 | } 71 | 72 | //------------------------------------------------------------------------------ 73 | -------------------------------------------------------------------------------- /circuits/sha2/sha512/sha512_hash_bits.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "sha512_padding.circom"; 5 | include "sha512_initial_value.circom"; 6 | include "sha512_schedule.circom"; 7 | include "sha512_rounds.circom"; 8 | 9 | //------------------------------------------------------------------------------ 10 | // Computes the SHA512 hash of a sequence of bits 11 | // The output is 8 little-endian 64-bit words. 12 | // See below for the more standard "digest" version 13 | 14 | template Sha512_hash_bits(len) { 15 | 16 | signal input inp_bits[len]; // `len` bits 17 | signal output hash_qwords[8][64]; // 512 bits, as 8 little-endian 64-bit words 18 | 19 | var nchunks = SHA2_384_512_compute_number_of_chunks(len); 20 | 21 | signal chunks[nchunks ][1024]; 22 | signal states[nchunks+1][8][64]; 23 | 24 | component pad = SHA2_384_512_padding(len); 25 | pad.inp <== inp_bits; 26 | pad.out ==> chunks; 27 | 28 | component iv = Sha512_initial_value(); 29 | iv.out ==> states[0]; 30 | 31 | component sch[nchunks]; 32 | component rds[nchunks]; 33 | 34 | for(var m=0; m rds[m].words; 46 | 47 | rds[m].inp_hash <== states[m ]; 48 | rds[m].out_hash ==> states[m+1]; 49 | } 50 | 51 | hash_qwords <== states[nchunks]; 52 | 53 | } 54 | 55 | //------------------------------------------------------------------------------ 56 | // Computes the SHA512 hash of a sequence of bits 57 | // The output is 64 bytes in the standard order 58 | 59 | template Sha512_hash_bits_digest(len) { 60 | 61 | signal input inp_bits[len]; // `len` bits 62 | signal output hash_bytes[64]; // 64 bytes 63 | 64 | component sha = Sha512_hash_bits(len); 65 | component ser = QWordsToByteString(8); 66 | 67 | inp_bits ==> sha.inp_bits; 68 | sha.hash_qwords ==> ser.inp; 69 | ser.out ==> hash_bytes; 70 | } 71 | 72 | //------------------------------------------------------------------------------ 73 | -------------------------------------------------------------------------------- /circuits/sha2/sha224/sha224_hash_bits.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "../sha256/sha256_padding.circom"; 5 | include "../sha256/sha256_schedule.circom"; 6 | include "../sha256/sha256_rounds.circom"; 7 | include "sha224_initial_value.circom"; 8 | 9 | //------------------------------------------------------------------------------ 10 | // Computes the SHA224 hash of a sequence of bits 11 | // The output is 7 little-endian 32-bit words. 12 | // See below for the more standard "digest" version 13 | 14 | template Sha224_hash_bits(len) { 15 | 16 | signal input inp_bits[len]; // `len` bits 17 | signal output hash_dwords[7][32]; // 224 bits, as 7 little-endian 32-bit words 18 | 19 | var nchunks = SHA2_224_256_compute_number_of_chunks(len); 20 | 21 | signal chunks[nchunks ][512]; 22 | signal states[nchunks+1][8][32]; 23 | 24 | component pad = SHA2_224_256_padding(len); 25 | pad.inp <== inp_bits; 26 | pad.out ==> chunks; 27 | 28 | component iv = Sha224_initial_value(); 29 | iv.out ==> states[0]; 30 | 31 | component sch[nchunks]; 32 | component rds[nchunks]; 33 | 34 | for(var m=0; m rds[m].words; 46 | 47 | rds[m].inp_hash <== states[m ]; 48 | rds[m].out_hash ==> states[m+1]; 49 | } 50 | 51 | for(var j=0; j<7; j++) { 52 | hash_dwords[j] <== states[nchunks][j]; 53 | } 54 | 55 | } 56 | 57 | //------------------------------------------------------------------------------ 58 | // Computes the SHA224 hash of a sequence of bits 59 | // The output is 28 bytes in the standard order 60 | 61 | template Sha224_hash_bits_digest(len) { 62 | 63 | signal input inp_bits[len]; // `len` bits 64 | signal output hash_bytes[28]; // 28 bytes 65 | 66 | component sha = Sha224_hash_bits(len); 67 | component ser = DWordsToByteString(7); 68 | 69 | inp_bits ==> sha.inp_bits; 70 | sha.hash_dwords ==> ser.inp; 71 | ser.out ==> hash_bytes; 72 | } 73 | 74 | //------------------------------------------------------------------------------ 75 | -------------------------------------------------------------------------------- /circuits/sha2/sha384/sha384_hash_bits.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "../sha512/sha512_padding.circom"; 5 | include "../sha512/sha512_schedule.circom"; 6 | include "../sha512/sha512_rounds.circom"; 7 | include "sha384_initial_value.circom"; 8 | 9 | //------------------------------------------------------------------------------ 10 | // Computes the SHA384 hash of a sequence of bits 11 | // The output is 6 little-endian 64-bit words. 12 | // See below for the more standard "digest" version 13 | 14 | template Sha384_hash_bits(len) { 15 | 16 | signal input inp_bits[len]; // `len` bits 17 | signal output hash_qwords[6][64]; // 384 bits, as 5 little-endian 64-bit words 18 | 19 | var nchunks = SHA2_384_512_compute_number_of_chunks(len); 20 | 21 | signal chunks[nchunks ][1024]; 22 | signal states[nchunks+1][8][64]; 23 | 24 | component pad = SHA2_384_512_padding(len); 25 | pad.inp <== inp_bits; 26 | pad.out ==> chunks; 27 | 28 | component iv = Sha384_initial_value(); 29 | iv.out ==> states[0]; 30 | 31 | component sch[nchunks]; 32 | component rds[nchunks]; 33 | 34 | for(var m=0; m rds[m].words; 46 | 47 | rds[m].inp_hash <== states[m ]; 48 | rds[m].out_hash ==> states[m+1]; 49 | } 50 | 51 | for(var j=0; j<6; j++) { 52 | hash_qwords[j] <== states[nchunks][j]; 53 | } 54 | 55 | } 56 | 57 | //------------------------------------------------------------------------------ 58 | // Computes the SHA384 hash of a sequence of bits 59 | // The output is 48 bytes in the standard order 60 | 61 | template Sha384_hash_bits_digest(len) { 62 | 63 | signal input inp_bits[len]; // `len` bits 64 | signal output hash_bytes[48]; // 48 bytes 65 | 66 | component sha = Sha384_hash_bits(len); 67 | component ser = QWordsToByteString(6); 68 | 69 | inp_bits ==> sha.inp_bits; 70 | sha.hash_qwords ==> ser.inp; 71 | ser.out ==> hash_bytes; 72 | } 73 | 74 | //------------------------------------------------------------------------------ 75 | -------------------------------------------------------------------------------- /circuits/sha2/sha512/sha512_round_const.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | //------------------------------------------------------------------------------ 4 | // round constants for SHA2-384 and SHA2-512 (they are the same) 5 | 6 | template SHA2_384_512_round_keys() { 7 | 8 | signal output out[80]; 9 | 10 | var round_keys[80] = 11 | [ 0x428a2f98d728ae22 , 0x7137449123ef65cd , 0xb5c0fbcfec4d3b2f , 0xe9b5dba58189dbbc 12 | , 0x3956c25bf348b538 , 0x59f111f1b605d019 , 0x923f82a4af194f9b , 0xab1c5ed5da6d8118 13 | , 0xd807aa98a3030242 , 0x12835b0145706fbe , 0x243185be4ee4b28c , 0x550c7dc3d5ffb4e2 14 | , 0x72be5d74f27b896f , 0x80deb1fe3b1696b1 , 0x9bdc06a725c71235 , 0xc19bf174cf692694 15 | , 0xe49b69c19ef14ad2 , 0xefbe4786384f25e3 , 0x0fc19dc68b8cd5b5 , 0x240ca1cc77ac9c65 16 | , 0x2de92c6f592b0275 , 0x4a7484aa6ea6e483 , 0x5cb0a9dcbd41fbd4 , 0x76f988da831153b5 17 | , 0x983e5152ee66dfab , 0xa831c66d2db43210 , 0xb00327c898fb213f , 0xbf597fc7beef0ee4 18 | , 0xc6e00bf33da88fc2 , 0xd5a79147930aa725 , 0x06ca6351e003826f , 0x142929670a0e6e70 19 | , 0x27b70a8546d22ffc , 0x2e1b21385c26c926 , 0x4d2c6dfc5ac42aed , 0x53380d139d95b3df 20 | , 0x650a73548baf63de , 0x766a0abb3c77b2a8 , 0x81c2c92e47edaee6 , 0x92722c851482353b 21 | , 0xa2bfe8a14cf10364 , 0xa81a664bbc423001 , 0xc24b8b70d0f89791 , 0xc76c51a30654be30 22 | , 0xd192e819d6ef5218 , 0xd69906245565a910 , 0xf40e35855771202a , 0x106aa07032bbd1b8 23 | , 0x19a4c116b8d2d0c8 , 0x1e376c085141ab53 , 0x2748774cdf8eeb99 , 0x34b0bcb5e19b48a8 24 | , 0x391c0cb3c5c95a63 , 0x4ed8aa4ae3418acb , 0x5b9cca4f7763e373 , 0x682e6ff3d6b2b8a3 25 | , 0x748f82ee5defb2fc , 0x78a5636f43172f60 , 0x84c87814a1f0ab72 , 0x8cc702081a6439ec 26 | , 0x90befffa23631e28 , 0xa4506cebde82bde9 , 0xbef9a3f7b2c67915 , 0xc67178f2e372532b 27 | , 0xca273eceea26619c , 0xd186b8c721c0c207 , 0xeada7dd6cde0eb1e , 0xf57d4f7fee6ed178 28 | , 0x06f067aa72176fba , 0x0a637dc5a2c898a6 , 0x113f9804bef90dae , 0x1b710b35131c471b 29 | , 0x28db77f523047d84 , 0x32caab7b40c72493 , 0x3c9ebe0a15c9bebc , 0x431d67c49c100d4c 30 | , 0x4cc5d4becb3e42b6 , 0x597f299cfc657e2a , 0x5fcb6fab3ad6faec , 0x6c44198c4a475817 31 | ]; 32 | 33 | for(var j=0; j<80; j++) { out[j] <== round_keys[j]; } 34 | 35 | } 36 | 37 | //------------------------------------------------------------------------------ 38 | -------------------------------------------------------------------------------- /circuits/keccak/sponge.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "keccak-p.circom"; 4 | 5 | //------------------------------------------------------------------------------ 6 | 7 | function min(a,b) { 8 | return (a <= b) ? a : b; 9 | } 10 | 11 | //------------------------------------------------------------------------------ 12 | 13 | template KeccakSponge(level, capacity, input_len, output_len) { 14 | var w = (1< 0 ); 19 | assert(rate < bits); 20 | 21 | signal input inp[ input_len]; 22 | signal output out[output_len]; 23 | 24 | // round up to rate the input + 2 bits ("10*1" padding) 25 | var nblocks = ((input_len + 2) + (rate-1)) \ rate; 26 | var nout = (output_len + (rate-1)) \ rate; 27 | var padded_len = nblocks * rate; 28 | 29 | signal padded[padded_len]; 30 | for(var i=0; i state[m+1]; 56 | 57 | } 58 | 59 | var q = min(rate, output_len); 60 | for(var i=0; i out[i]; 62 | } 63 | var out_ptr = rate; 64 | 65 | for(var n=1; n state[nblocks+n ]; 69 | 70 | var q = min(rate, output_len-out_ptr); 71 | for(var i=0; i out[out_ptr+i]; 73 | } 74 | out_ptr += rate; 75 | } 76 | 77 | } 78 | 79 | //------------------------------------------------------------------------------ 80 | -------------------------------------------------------------------------------- /src/Main.hs: -------------------------------------------------------------------------------- 1 | 2 | module Main where 3 | 4 | -------------------------------------------------------------------------------- 5 | 6 | import Data.Char 7 | import System.Environment 8 | 9 | import R1CS.Misc ( Verbosity(..) ) 10 | 11 | import qualified Test.Hash.SHA2 as SHA2 12 | import qualified Test.Hash.Keccak as Keccak 13 | import qualified Test.Hash.Blake2 as Blake2 14 | import qualified Test.Hash.MiMC as MiMC 15 | import qualified Test.Hash.Poseidon2 as Poseidon2 16 | import qualified Test.Hash.Griffin as Griffin 17 | 18 | -------------------------------------------------------------------------------- 19 | 20 | help = do 21 | putStrLn "" 22 | putStrLn "usage:" 23 | putStrLn "" 24 | putStrLn "$ hash-circuit-tests " 25 | putStrLn "" 26 | putStrLn "where is one of the following:" 27 | putStrLn "" 28 | putStrLn " - sha2 (input = bytes)" 29 | putStrLn " - sha2-bits (input = bits)" 30 | putStrLn " - sha2-chunk (input = single chunk)" 31 | putStrLn " - keccak (original Keccak variant)" 32 | putStrLn " - sha3 (NIST Keccak variant)" 33 | putStrLn " - shake (NIST SHA3 XOFs)" 34 | putStrLn " - blake2" 35 | putStrLn " - poseidon2" 36 | putStrLn " - griffin" 37 | putStrLn " - mimc (MiMC and MiMC-Feistel hashes)" 38 | putStrLn " - mimc-comp (various MiMC components)" 39 | putStrLn " - mimc-stream (MiMC stream ciphers)" 40 | putStrLn "" 41 | 42 | main = do 43 | 44 | let verbosity = Silent 45 | let rootDir = "." 46 | 47 | args <- getArgs 48 | case args of 49 | 50 | [what] -> case map toLower what of 51 | 52 | "sha2" -> SHA2.runTests_SHA2_bytes verbosity rootDir 53 | "sha2-bits" -> SHA2.runTests_SHA2_bits verbosity rootDir 54 | "sha2-chunk" -> SHA2.runTests_SHA2_chunk verbosity rootDir 55 | "keccak" -> Keccak.runTests_Keccak verbosity rootDir 56 | "sha3" -> Keccak.runTests_SHA3 verbosity rootDir 57 | "shake" -> Keccak.runTests_SHAKE verbosity rootDir 58 | "blake2" -> Blake2.runTests_BLAKE2 verbosity rootDir 59 | "poseidon2" -> Poseidon2.runTests_Poseidon2 verbosity rootDir 60 | "griffin" -> Griffin.runTests_Griffin verbosity rootDir 61 | "mimc" -> MiMC.runTests_MiMC verbosity rootDir 62 | "mimc-comp" -> MiMC.runTests_MiMC_components verbosity rootDir 63 | "mimc-stream" -> MiMC.runTests_MiMC_stream verbosity rootDir 64 | 65 | _ -> do 66 | putStrLn $ "unknown testsuite `" ++ what ++ "`" 67 | help 68 | 69 | _ -> help 70 | -------------------------------------------------------------------------------- /circuits/sha2/sha256/sha256_compress.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | 5 | //------------------------------------------------------------------------------ 6 | // SHA256 (and also SHA224) compression function inner loop 7 | // 8 | // note: the d,h,inp,key inputs (and outputs) are 32 bit numbers; 9 | // the rest are little-endian bit vectors. 10 | 11 | template SHA2_224_256_compress_inner() { 12 | 13 | signal input inp; 14 | signal input key; 15 | 16 | signal input a[32]; 17 | signal input b[32]; 18 | signal input c[32]; 19 | signal input dd; 20 | signal input e[32]; 21 | signal input f[32]; 22 | signal input g[32]; 23 | signal input hh; 24 | 25 | signal output out_a[32]; 26 | signal output out_b[32]; 27 | signal output out_c[32]; 28 | signal output out_dd; 29 | signal output out_e[32]; 30 | signal output out_f[32]; 31 | signal output out_g[32]; 32 | signal output out_hh; 33 | 34 | out_g <== f; 35 | out_f <== e; 36 | out_c <== b; 37 | out_b <== a; 38 | 39 | var d_sum = 0; 40 | var h_sum = 0; 41 | for(var i=0; i<32; i++) { 42 | d_sum += (1< out_e; 90 | 91 | component decompose_a = Bits35(); 92 | decompose_a.inp <== overflow_a; 93 | decompose_a.out_bits ==> out_a; 94 | 95 | } 96 | 97 | //------------------------------------------------------------------------------ 98 | -------------------------------------------------------------------------------- /circuits/sha2/sha512/sha512_compress.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | 5 | //------------------------------------------------------------------------------ 6 | // SHA384 / SHA512 compression function inner loop 7 | // 8 | // note: the d,h,inp,key inputs (and outputs) are 64 bit numbers; 9 | // the rest are little-endian bit vectors. 10 | 11 | template SHA2_384_512_compress_inner() { 12 | 13 | signal input inp; 14 | signal input key; 15 | 16 | signal input a[64]; 17 | signal input b[64]; 18 | signal input c[64]; 19 | signal input dd; 20 | signal input e[64]; 21 | signal input f[64]; 22 | signal input g[64]; 23 | signal input hh; 24 | 25 | signal output out_a[64]; 26 | signal output out_b[64]; 27 | signal output out_c[64]; 28 | signal output out_dd; 29 | signal output out_e[64]; 30 | signal output out_f[64]; 31 | signal output out_g[64]; 32 | signal output out_hh; 33 | 34 | var d_sum = 0; 35 | var h_sum = 0; 36 | for(var i=0; i<64; i++) { 37 | out_g[i] <== f[i]; 38 | out_f[i] <== e[i]; 39 | out_c[i] <== b[i]; 40 | out_b[i] <== a[i]; 41 | d_sum += (1< out_e; 89 | 90 | component decompose_a = Bits67(); 91 | decompose_a.inp <== overflow_a; 92 | decompose_a.out_bits ==> out_a; 93 | 94 | } 95 | 96 | //------------------------------------------------------------------------------ 97 | -------------------------------------------------------------------------------- /circuits/keccak/sha3_bits.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "keccak-p.circom"; 4 | include "sponge.circom"; 5 | 6 | //------------------------------------------------------------------------------ 7 | // NIST SHA3 hash functions 8 | 9 | template SHA3_224(input_len) { 10 | signal input inp[input_len]; 11 | signal output out[224]; 12 | component sponge = KeccakSponge(6, 448, input_len+2, 224); 13 | for(var i=0; i out; 17 | } 18 | 19 | //-------------------------------------- 20 | 21 | template SHA3_256(input_len) { 22 | signal input inp[input_len]; 23 | signal output out[256]; 24 | component sponge = KeccakSponge(6, 512, input_len+2, 256); 25 | for(var i=0; i out; 29 | } 30 | 31 | //-------------------------------------- 32 | 33 | template SHA3_384(input_len) { 34 | signal input inp[input_len]; 35 | signal output out[384]; 36 | component sponge = KeccakSponge(6, 768, input_len+2, 384); 37 | for(var i=0; i out; 41 | } 42 | 43 | //-------------------------------------- 44 | 45 | template SHA3_512(input_len) { 46 | signal input inp[input_len]; 47 | signal output out[512]; 48 | component sponge = KeccakSponge(6, 1024, input_len+2, 512); 49 | for(var i=0; i out; 53 | } 54 | 55 | //------------------------------------------------------------------------------ 56 | // NIST SHA3 Extendable-Output Functions 57 | 58 | template SHAKE128(input_len, output_len) { 59 | signal input inp[input_len]; 60 | signal output out[output_len]; 61 | component sponge = KeccakSponge(6, 256, input_len+4, output_len); 62 | for(var i=0; i out; 68 | } 69 | 70 | //-------------------------------------- 71 | 72 | template SHAKE256(input_len, output_len) { 73 | signal input inp[input_len]; 74 | signal output out[output_len]; 75 | component sponge = KeccakSponge(6, 512, input_len+4, output_len); 76 | for(var i=0; i out; 82 | } 83 | 84 | //------------------------------------------------------------------------------ 85 | 86 | -------------------------------------------------------------------------------- /circuits/keccak/keccak_bytes.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "keccak_bits.circom"; 4 | 5 | //------------------------------------------------------------------------------ 6 | 7 | template UnpackBytes(n) { 8 | signal input bytes[n]; 9 | signal output bits[8*n]; 10 | 11 | component tobits[n]; 12 | 13 | for(var j=0; j bits[ j*8 + i ]; 18 | } 19 | } 20 | } 21 | 22 | //-------------------------------------- 23 | 24 | template PackBytes(n) { 25 | signal input bits[8*n]; 26 | signal output bytes[n]; 27 | 28 | for(var k=0; k unpack.bytes; 49 | unpack.bits ==> keccak.inp; 50 | keccak.out ==> pack.bits; 51 | pack.bytes ==> out_bytes; 52 | } 53 | 54 | //-------------------------------------- 55 | 56 | template Keccak_256_bytes(input_len) { 57 | signal input inp_bytes[input_len]; 58 | signal output out_bytes[32]; 59 | 60 | component unpack = UnpackBytes(input_len); 61 | component keccak = Keccak_256(input_len*8); 62 | component pack = PackBytes(32); 63 | 64 | inp_bytes ==> unpack.bytes; 65 | unpack.bits ==> keccak.inp; 66 | keccak.out ==> pack.bits; 67 | pack.bytes ==> out_bytes; 68 | } 69 | 70 | //-------------------------------------- 71 | 72 | template Keccak_384_bytes(input_len) { 73 | signal input inp_bytes[input_len]; 74 | signal output out_bytes[48]; 75 | 76 | component unpack = UnpackBytes(input_len); 77 | component keccak = Keccak_384(input_len*8); 78 | component pack = PackBytes(48); 79 | 80 | inp_bytes ==> unpack.bytes; 81 | unpack.bits ==> keccak.inp; 82 | keccak.out ==> pack.bits; 83 | pack.bytes ==> out_bytes; 84 | } 85 | 86 | //-------------------------------------- 87 | 88 | template Keccak_512_bytes(input_len) { 89 | signal input inp_bytes[input_len]; 90 | signal output out_bytes[64]; 91 | 92 | component unpack = UnpackBytes(input_len); 93 | component keccak = Keccak_512(input_len*8); 94 | component pack = PackBytes(64); 95 | 96 | inp_bytes ==> unpack.bytes; 97 | unpack.bits ==> keccak.inp; 98 | keccak.out ==> pack.bits; 99 | pack.bytes ==> out_bytes; 100 | } 101 | 102 | //------------------------------------------------------------------------------ 103 | -------------------------------------------------------------------------------- /src/Ref/Poseidon2/Zikkurat/InvPerm.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | The inverse of the Poseidon2 permutation 3 | 4 | module Ref.Poseidon2.Zikkurat.InvPerm where 5 | 6 | -------------------------------------------------------------------------------- 7 | 8 | import ZK.Algebra.Class.Field 9 | import ZK.Algebra.Curves.BN128.Fr.Mont (Fr) 10 | 11 | import Ref.Poseidon2.Zikkurat.RoundConsts 12 | import Ref.Poseidon2.Zikkurat.Permutation 13 | 14 | -------------------------------------------------------------------------------- 15 | 16 | invPermSanityCheck :: Bool 17 | invPermSanityCheck = invPermSanityCheck' (123456,78901234,567890123) 18 | 19 | invPermSanityCheck' :: (Fr,Fr,Fr) -> Bool 20 | invPermSanityCheck' xyz = (inversePermutation (permutation xyz) == xyz) 21 | 22 | -------------------------------------------------------------------------------- 23 | 24 | -- | @(a^5)^invExponent == a@ (modulo prime) 25 | invExponent :: Integer 26 | invExponent = 17510594297471420177797124596205820070838691520332827474958563349260646796493 27 | 28 | invSbox :: Fr -> Fr 29 | invSbox x = power x invExponent 30 | 31 | inverseInternalRound :: Fr -> (Fr,Fr,Fr) -> (Fr,Fr,Fr) 32 | inverseInternalRound c xyz = (u',v,w) where 33 | (u,v,w) = inverseInternalMatrix xyz 34 | u' = invSbox u - c 35 | 36 | inverseExternalRound :: (Fr,Fr,Fr) -> (Fr,Fr,Fr) -> (Fr,Fr,Fr) 37 | inverseExternalRound (cx,cy,cz) xyz = (u',v',w') where 38 | (u,v,w) = inverseExternalMatrix xyz 39 | u' = invSbox u - cx 40 | v' = invSbox v - cy 41 | w' = invSbox w - cz 42 | 43 | -------------------------------------------------------------------------------- 44 | 45 | inverseInternalMatrix :: (Fr,Fr,Fr) -> (Fr,Fr,Fr) 46 | inverseInternalMatrix (x,y,z) = (u,v,w) where 47 | u = plus_5over7*x + minus2over7*y + minus1over7*z 48 | v = minus2over7*x + plus_5over7*y + minus1over7*z 49 | w = minus1over7*x + minus1over7*y + plus_3over7*z 50 | 51 | inverseExternalMatrix :: (Fr,Fr,Fr) -> (Fr,Fr,Fr) 52 | inverseExternalMatrix = inverseLinearLayer 53 | 54 | inverseLinearLayer :: (Fr,Fr,Fr) -> (Fr,Fr,Fr) 55 | inverseLinearLayer (x,y,z) = (u,v,w) where 56 | u = plus_3over4*x + minus1over4*y + minus1over4*z 57 | v = minus1over4*x + plus_3over4*y + minus1over4*z 58 | w = minus1over4*x + minus1over4*y + plus_3over4*z 59 | 60 | minus1over4 :: Fr 61 | minus1over4 = - 1 / 4 62 | 63 | plus_3over4 :: Fr 64 | plus_3over4 = 3 / 4 65 | 66 | minus1over7 :: Fr 67 | minus1over7 = - 1 / 7 68 | 69 | minus2over7 :: Fr 70 | minus2over7 = - 2 / 7 71 | 72 | plus_3over7 :: Fr 73 | plus_3over7 = 3 / 7 74 | 75 | plus_5over7 :: Fr 76 | plus_5over7 = 5 / 7 77 | 78 | -------------------------------------------------------------------------------- 79 | 80 | inversePermutation :: (Fr,Fr,Fr) -> (Fr,Fr,Fr) 81 | inversePermutation 82 | = inverseLinearLayer 83 | . (\state -> foldl (flip inverseExternalRound) state (reverse initialRoundConsts )) 84 | . (\state -> foldl (flip inverseInternalRound) state (reverse internalRoundConsts)) 85 | . (\state -> foldl (flip inverseExternalRound) state (reverse finalRoundConsts )) 86 | 87 | -------------------------------------------------------------------------------- 88 | 89 | -------------------------------------------------------------------------------- /src/Test/Hash/Griffin.hs: -------------------------------------------------------------------------------- 1 | 2 | module Test.Hash.Griffin where 3 | 4 | -------------------------------------------------------------------------------- 5 | 6 | import R1CS 7 | import Test.Runner 8 | 9 | import Ref.Griffin.Permutation 10 | 11 | -------------------------------------------------------------------------------- 12 | -- * tests for the permutation 13 | 14 | griffin_perm_test :: ArithHashTest 15 | griffin_perm_test = MkGenericHashTest 16 | { __circomFile = "circuits/griffin/griffin_tests.circom" 17 | , __templateName = "Test_Griffin_permutation" 18 | , __inputSignal = "inp" 19 | , __outputSignal = "out" 20 | , __testCases = griffin_perm_vectors 21 | } 22 | 23 | griffin_perm_vectors :: [([Integer], Integer)] 24 | griffin_perm_vectors = 25 | [ ([x,y,z], frToInteger t) 26 | | i<-[0..10] 27 | , let x = 101 + 2*i 28 | , let y = 2002 - 3*i 29 | , let z = 30003 - 7*i 30 | , let (u,v,w) = permute (fromInteger x, fromInteger y, fromInteger z) 31 | , let t = u + v + w 32 | ] 33 | 34 | -------------------------------------------------------------------------------- 35 | 36 | griffin_iter_perm_test :: ArithHashTest 37 | griffin_iter_perm_test = MkGenericHashTest 38 | { __circomFile = "circuits/griffin/griffin_tests.circom" 39 | , __templateName = "Test_Griffin_iterated_permutation" 40 | , __inputSignal = "inp" 41 | , __outputSignal = "out" 42 | , __testCases = griffin_iter_perm_vectors 43 | } 44 | 45 | griffin_iter_perm_vectors :: [([Integer], Integer)] 46 | griffin_iter_perm_vectors = 47 | [ ([x,y,z], frToInteger t) 48 | | i<-[0..10] 49 | , let x = 505 + 2*i 50 | , let y = 606 - 3*i 51 | , let z = 707 - 7*i 52 | , let input = (fromInteger x, fromInteger y, fromInteger z) 53 | , let (u,v,w) = iter 100 permute input 54 | , let t = u + v + w 55 | ] 56 | 57 | -------------------------------------------------------------------------------- 58 | -- * tests for the remaining components 59 | 60 | griffin_compression_test :: ArithHashTest 61 | griffin_compression_test = MkGenericHashTest 62 | { __circomFile = "circuits/griffin/griffin_tests.circom" 63 | , __templateName = "Test_Griffin_compression" 64 | , __inputSignal = "inp" 65 | , __outputSignal = "out" 66 | , __testCases = griffin_compression_vectors 67 | } 68 | 69 | griffin_compression_vectors :: [([Integer], Integer)] 70 | griffin_compression_vectors = 71 | [ ([x,y], frToInteger z) 72 | | i<-[0..10] 73 | , let x = 555 + i 74 | , let y = 1001 + 2*i 75 | , let z = compress (fromInteger x) (fromInteger y) 76 | ] 77 | 78 | -------------------------------------------------------------------------------- 79 | 80 | runTests_Griffin :: Verbosity -> FilePath -> IO () 81 | runTests_Griffin verbosity rootDir = do 82 | 83 | putStrLn "running tests for Griffin..." 84 | 85 | runArithTest verbosity rootDir griffin_perm_test 86 | runArithTest verbosity rootDir griffin_compression_test 87 | 88 | putStrLn "running tests for 100x iterated Griffin..." 89 | 90 | runArithTest verbosity rootDir griffin_iter_perm_test 91 | 92 | -------------------------------------------------------------------------------- 93 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | hash-circuits 3 | ============= 4 | 5 | copyright: (c) 2023-2025 Faulhorn Labs 6 | author: Balazs Komuves 7 | license: MIT 8 | disclaimer: Experimental software, use at your own risk! 9 | 10 | 11 | What's this about? 12 | ------------------ 13 | 14 | This repository contains [`circom`](https://docs.circom.io/) implementations 15 | of some popular hash functions: 16 | 17 | - SHA2: SHA224 / SHA256 / SHA384 / SHA512 18 | - Keccak / SHA3: Keccak-224, Keccak-256, Keccak-384, Keccak-512 + the SHA3 versions 19 | - SHA3 XOFs: SHAKE128, SHAKE256 20 | - Blake2: BLAKE2s-256 and BLAKE2b-256 21 | - Poseidon2 (Merkle tree and sponge construction for the bn254 scalar field and t=3) 22 | - Griffin (permutation only; for the bn254 scalar field and t=3) 23 | - MiMC: MiMC and MiMC-Feistel block ciphers and hashes (Merkle-Damgard for MiMC and sponge for MiMC-Feistel; bn128 scalar field) 24 | 25 | Circom is a programming language describing arithmetic circuits and/or R1CS 26 | constraints. These are used in some constructions of zero-knowledge proofs 27 | and related technologies. 28 | 29 | 30 | Circuit sizes 31 | ------------- 32 | 33 | The author believes that the R1CS / arithmetic circuit format allows very limited 34 | opportunities for optimizing hash function circuits, nevertheless some effort 35 | was put into optimization (in particular for SHA256). 36 | 37 | Approximate counts of nonlinear R1CS constraints: 38 | 39 | - Permutation: 40 | - Keccak-f[1600]: 146000 (1600 bits) 41 | - Poseidon2: 240 (3 field elements; approx 760 bits) 42 | - Griffin: 96 (3 field elements; approx 760 bits) 43 | - MiMC: 330 (1 field element; approx 254 bits) 44 | - MiMC-Feistel: 660 (2 field elements; approx 507 bits) 45 | - Compression (two-to-one): 46 | - SHA256: 26170 47 | - Keccak256: 144830 48 | - Poseidon2: 240 49 | - Griffin: 96 50 | - MiMC: 330 51 | - Hashing (per native chunk): 52 | - SHA256: 26200 (about 13% less than the one in `circomlib`) 53 | - BLAKE2s: 32600 54 | - Keccak256: 147000 55 | - Poseidon2: 250 56 | - MiMC-MD: 330 57 | - MiMC-Feistel: 660 58 | - Hashing (per byte): 59 | - SHA256: 410 60 | - BLAKE2s: 509 61 | - Keccak256: 1100 62 | - Poseidon2: 8 63 | - MiMC-MD: 10.5 64 | - MiMC-Feistel 21 65 | 66 | 67 | Tests and reference implementation 68 | ---------------------------------- 69 | 70 | Reference implementations and tests are written in [Haskell](https://www.haskell.org/). 71 | The tests are using the [`r1cs-solver`](https://github.com/faulhornlabs/r1cs-solver/) 72 | testing framework (though we mostly only use to trivial part of that, automating the 73 | `circom` workflow). 74 | 75 | We also use the [`zikkurat-algebra`](https://github.com/faulhornlabs/zikkurat-algebra) 76 | algebra backend library for finite field computations. 77 | 78 | 79 | TODO 80 | ---- 81 | 82 | - more detailed tests for the individual components (permutation, compression, etc) 83 | - more comprehensive testing (using the reference implementations) 84 | - implement reference Poseidon2 for general parameter settings 85 | - implement the original Poseidon 86 | - test the R1CS equations (if possible in practice) 87 | - Haskell reference implementation for Keccak sponge 88 | - implement other hash functions 89 | 90 | -------------------------------------------------------------------------------- /circuits/mimc/mimc-feistel-2p-p.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "mimc-roundconst.circom"; 4 | include "mimc-roundfun.circom"; 5 | 6 | //------------------------------------------------------------------------------ 7 | 8 | // 9 | // MiMC-Feistel-2p/p block cipher encryption 10 | // 11 | 12 | template MiMC_Feistel_2p$p_encrypt_block() { 13 | signal input key; 14 | signal input inp[2]; 15 | signal output out[2]; 16 | 17 | signal rc[220]; 18 | component RC = MiMC_round_consts(220); 19 | rc <== RC.out; 20 | 21 | signal auxL[221]; 22 | signal auxR[221]; 23 | auxL[0] <== inp[0]; 24 | auxR[0] <== inp[1]; 25 | 26 | component pow[220]; 27 | for(var i=0; i<220; i++) { 28 | pow[i] = pow5(); 29 | pow[i].inp <== auxL[i] + key + rc[i]; 30 | auxL[i+1] <== pow[i].out + auxR[i]; 31 | auxR[i+1] <== auxL[i]; 32 | } 33 | 34 | out[0] <== auxL[220] + key; 35 | out[1] <== auxR[220]; 36 | } 37 | 38 | 39 | //-------------------------------------- 40 | 41 | // 42 | // MiMC-Feistel-2p/p block cipher decryption 43 | // 44 | 45 | template MiMC_Feistel_2p$p_decrypt_block() { 46 | signal input key; 47 | signal input inp[2]; 48 | signal output out[2]; 49 | 50 | signal rc[220]; 51 | component RC = MiMC_round_consts(220); 52 | rc <== RC.out; 53 | 54 | signal auxL[221]; 55 | signal auxR[221]; 56 | auxL[220] <== inp[0] - key; 57 | auxR[220] <== inp[1]; 58 | 59 | component pow[220]; 60 | for(var i=219; i>=0; i--) { 61 | pow[i] = pow5(); 62 | auxL[i] <== auxR[i+1]; 63 | pow[i].inp <== auxL[i] + key + rc[i]; 64 | auxR[i] <== auxL[i+1] - pow[i].out; 65 | } 66 | 67 | out[0] <== auxL[0]; 68 | out[1] <== auxR[0]; 69 | } 70 | 71 | //------------------------------------------------------------------------------ 72 | 73 | // 74 | // This is a permutation of F^2 where F is the scalar field. 75 | // 76 | 77 | template MiMC_Feistel_2p$p_permutation() { 78 | signal input inp[2]; 79 | signal output out[2]; 80 | 81 | component encrypt = MiMC_Feistel_2p$p_encrypt_block(); 82 | encrypt.key <== 0; 83 | encrypt.inp <== inp; 84 | encrypt.out ==> out; 85 | } 86 | 87 | //-------------------------------------- 88 | 89 | // 90 | // The inverse permutation. 91 | // 92 | 93 | template MiMC_Feistel_2p$p_inverse_permutation() { 94 | signal input inp[2]; 95 | signal output out[2]; 96 | 97 | component decrypt = MiMC_Feistel_2p$p_decrypt_block(); 98 | decrypt.key <== 0; 99 | decrypt.inp <== inp; 100 | decrypt.out ==> out; 101 | } 102 | 103 | //------------------------------------------------------------------------------ 104 | 105 | // 106 | // Hash using the sponge construction, with rate=capacity=1 107 | // 108 | // It should in theory provide approx 127 bit preimage and collision security 109 | // 110 | 111 | template MiMC_Feistel_2p$p_hash_sponge(n) { 112 | 113 | signal input inp[n]; 114 | signal output out; 115 | 116 | signal state[n+1][2]; 117 | 118 | state[0][0] <== 0; // we use the length to initialize the capacity 119 | state[0][1] <== n; // as an extra safety measure (prolly unnecessary as we have rate=1) 120 | 121 | component perm[n]; 122 | 123 | for(var i=0; i state[i+1]; 128 | } 129 | 130 | out <== state[n][0]; 131 | 132 | } 133 | 134 | //------------------------------------------------------------------------------ 135 | -------------------------------------------------------------------------------- /circuits/sha2/sha256/sha256_rounds.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "sha256_compress.circom"; 5 | include "sha256_round_const.circom"; 6 | 7 | //------------------------------------------------------------------------------ 8 | // execute `n` rounds of the SHA224 / SHA256 inner loop 9 | // NOTE: hash state is stored as 8 dwords, each little-endian 10 | 11 | template SHA2_224_256_rounds(n) { 12 | 13 | assert( n > 0 ); 14 | assert( n <= 64 ); 15 | 16 | signal input words[n]; // round words (32-bit words) 17 | signal input inp_hash[8][32]; // initial state 18 | signal output out_hash[8][32]; // final state after n rounds (n <= 64) 19 | 20 | signal a [n+1][32]; 21 | signal b [n+1][32]; 22 | signal c [n+1][32]; 23 | signal dd[n+1]; 24 | signal e [n+1][32]; 25 | signal f [n+1][32]; 26 | signal g [n+1][32]; 27 | signal hh[n+1]; 28 | 29 | signal round_keys[64]; 30 | component RC = SHA2_224_256_round_keys(); 31 | round_keys <== RC.out; 32 | 33 | a[0] <== inp_hash[0]; 34 | b[0] <== inp_hash[1]; 35 | c[0] <== inp_hash[2]; 36 | 37 | e[0] <== inp_hash[4]; 38 | f[0] <== inp_hash[5]; 39 | g[0] <== inp_hash[6]; 40 | 41 | var sum_dd = 0; 42 | var sum_hh = 0; 43 | for(var i=0; i<32; i++) { 44 | sum_dd += inp_hash[3][i] * (1< a [k+1]; 78 | compress[k].out_b ==> b [k+1]; 79 | compress[k].out_c ==> c [k+1]; 80 | compress[k].out_dd ==> dd[k+1]; 81 | compress[k].out_e ==> e [k+1]; 82 | compress[k].out_f ==> f [k+1]; 83 | compress[k].out_g ==> g [k+1]; 84 | compress[k].out_hh ==> hh[k+1]; 85 | } 86 | 87 | component modulo[8]; 88 | for(var j=0; j<8; j++) { 89 | modulo[j] = Bits33(); 90 | } 91 | 92 | var sum_a = 0; 93 | var sum_b = 0; 94 | var sum_c = 0; 95 | var sum_e = 0; 96 | var sum_f = 0; 97 | var sum_g = 0; 98 | for(var i=0; i<32; i++) { 99 | sum_a += (1< out_hash[j]; 118 | } 119 | 120 | } 121 | 122 | // ----------------------------------------------------------------------------- 123 | -------------------------------------------------------------------------------- /circuits/sha2/sha512/sha512_rounds.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "../sha2_common.circom"; 4 | include "sha512_compress.circom"; 5 | include "sha512_round_const.circom"; 6 | 7 | //------------------------------------------------------------------------------ 8 | // execute `n` rounds of the SHA384 / SHA512 inner loop 9 | // NOTE: hash state is stored as 8 qwords, each little-endian 10 | 11 | template SHA2_384_512_rounds(n) { 12 | 13 | assert( n > 0 ); 14 | assert( n <= 80 ); 15 | 16 | signal input words[n]; // round words (64-bit words) 17 | signal input inp_hash[8][64]; // initial state 18 | signal output out_hash[8][64]; // final state after n rounds (n <= 80) 19 | 20 | signal a [n+1][64]; 21 | signal b [n+1][64]; 22 | signal c [n+1][64]; 23 | signal dd[n+1]; 24 | signal e [n+1][64]; 25 | signal f [n+1][64]; 26 | signal g [n+1][64]; 27 | signal hh[n+1]; 28 | 29 | signal round_keys[80]; 30 | component RC = SHA2_384_512_round_keys(); 31 | round_keys <== RC.out; 32 | 33 | a[0] <== inp_hash[0]; 34 | b[0] <== inp_hash[1]; 35 | c[0] <== inp_hash[2]; 36 | 37 | e[0] <== inp_hash[4]; 38 | f[0] <== inp_hash[5]; 39 | g[0] <== inp_hash[6]; 40 | 41 | var sum_dd = 0; 42 | var sum_hh = 0; 43 | for(var i=0; i<64; i++) { 44 | sum_dd += inp_hash[3][i] * (1< a [k+1]; 78 | compress[k].out_b ==> b [k+1]; 79 | compress[k].out_c ==> c [k+1]; 80 | compress[k].out_dd ==> dd[k+1]; 81 | compress[k].out_e ==> e [k+1]; 82 | compress[k].out_f ==> f [k+1]; 83 | compress[k].out_g ==> g [k+1]; 84 | compress[k].out_hh ==> hh[k+1]; 85 | } 86 | 87 | component modulo[8]; 88 | for(var j=0; j<8; j++) { 89 | modulo[j] = Bits65(); 90 | } 91 | 92 | var sum_a = 0; 93 | var sum_b = 0; 94 | var sum_c = 0; 95 | var sum_e = 0; 96 | var sum_f = 0; 97 | var sum_g = 0; 98 | for(var i=0; i<64; i++) { 99 | sum_a += (1< out_hash[j]; 118 | } 119 | 120 | } 121 | 122 | // ----------------------------------------------------------------------------- 123 | -------------------------------------------------------------------------------- /circuits/poseidon2/poseidon2_sponge.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "poseidon2_perm.circom"; 4 | 5 | //------------------------------------------------------------------------------ 6 | 7 | function min(a,b) { 8 | return (a <= b) ? a : b; 9 | } 10 | 11 | //------------------------------------------------------------------------------ 12 | 13 | // 14 | // Poseidon sponge construction 15 | // 16 | // t = size of state (currently fixed to 3) 17 | // c = capacity (1 or 2) 18 | // r = rate = t - c 19 | // 20 | // everything is measured in number of field elements 21 | // 22 | // we use the padding `10*` from the original Poseidon paper, 23 | // and initial state constant zero. Note that this is different 24 | // from the "SAFE padding" recommended in the Poseidon2 paper 25 | // (which uses `0*` padding and a nontrivial initial state) 26 | // 27 | 28 | template PoseidonSponge(t, capacity, input_len, output_len) { 29 | 30 | var rate = t - capacity; 31 | 32 | assert( t == 3); 33 | 34 | assert( capacity > 0 ); 35 | assert( rate > 0 ); 36 | assert( capacity < t ); 37 | assert( rate < t ); 38 | 39 | signal input inp[ input_len]; 40 | signal output out[output_len]; 41 | 42 | // round up to rate the input + 1 field element ("10*" padding) 43 | var nblocks = ((input_len + 1) + (rate-1)) \ rate; 44 | var nout = (output_len + (rate-1)) \ rate; 45 | var padded_len = nblocks * rate; 46 | 47 | signal padded[padded_len]; 48 | for(var i=0; i F -> F -> F 60 | div !p !a !b 61 | | b == 0 = error "field division by zero (generic prime)" 62 | | otherwise = (euclid p a 0 b p) 63 | 64 | -- | Division via multiplying by the inverse 65 | div2 :: P -> F -> F -> F 66 | div2 !p !a !b = mul p a (inv p b) 67 | 68 | -------------------------------------------------------------------------------- 69 | -- * Euclidean algorithm 70 | 71 | -- | Extended binary Euclidean algorithm 72 | euclid :: Integer -> Integer -> Integer -> Integer -> Integer -> Integer 73 | euclid !p !x1 !x2 !u !v = go x1 x2 u v where 74 | 75 | halfp1 = shiftR (p+1) 1 76 | 77 | modp :: Integer -> Integer 78 | modp n = mod n p 79 | 80 | -- Inverse using the binary Euclidean algorithm 81 | euclid :: Integer -> Integer 82 | euclid a 83 | | a == 0 = 0 84 | | otherwise = go 1 0 a p 85 | 86 | go :: Integer -> Integer -> Integer -> Integer -> Integer 87 | go !x1 !x2 !u !v 88 | | u==1 = x1 89 | | v==1 = x2 90 | | otherwise = stepU x1 x2 u v 91 | 92 | stepU :: Integer -> Integer -> Integer -> Integer -> Integer 93 | stepU !x1 !x2 !u !v = if even u 94 | then let u' = shiftR u 1 95 | x1' = if even x1 then shiftR x1 1 else shiftR x1 1 + halfp1 96 | in stepU x1' x2 u' v 97 | else stepV x1 x2 u v 98 | 99 | stepV :: Integer -> Integer -> Integer -> Integer -> Integer 100 | stepV !x1 !x2 !u !v = if even v 101 | then let v' = shiftR v 1 102 | x2' = if even x2 then shiftR x2 1 else shiftR x2 1 + halfp1 103 | in stepV x1 x2' u v' 104 | else final x1 x2 u v 105 | 106 | final :: Integer -> Integer -> Integer -> Integer -> Integer 107 | final !x1 !x2 !u !v = if u>=v 108 | 109 | then let u' = u-v 110 | x1' = if x1 >= x2 then modp (x1-x2) else modp (x1+p-x2) 111 | in go x1' x2 u' v 112 | 113 | else let v' = v-u 114 | x2' = if x2 >= x1 then modp (x2-x1) else modp (x2+p-x1) 115 | in go x1 x2' u v' 116 | 117 | -------------------------------------------------------------------------------- 118 | -------------------------------------------------------------------------------- /circuits/mimc/mimc-p-p.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "mimc-roundconst.circom"; 4 | include "mimc-roundfun.circom"; 5 | 6 | //------------------------------------------------------------------------------ 7 | 8 | // 9 | // MiMC-p/p block cipher encryption 10 | // 11 | 12 | template MiMC_p$p_encrypt_block() { 13 | signal input key; 14 | signal input inp; 15 | signal output out; 16 | 17 | signal rc[110]; 18 | component RC = MiMC_round_consts(110); 19 | rc <== RC.out; 20 | 21 | signal aux[111]; 22 | aux[0] <== inp; 23 | component pow[110]; 24 | for(var i=0; i<110; i++) { 25 | pow[i] = pow5(); 26 | pow[i].inp <== aux[i] + key + rc[i]; 27 | pow[i].out ==> aux[i+1]; 28 | } 29 | 30 | out <== aux[110] + key; 31 | } 32 | 33 | //-------------------------------------- 34 | 35 | // 36 | // MiMC-p/p block cipher decryption 37 | // 38 | 39 | template MiMC_p$p_decrypt_block() { 40 | signal input key; 41 | signal input inp; 42 | signal output out; 43 | 44 | signal rc[110]; 45 | component RC = MiMC_round_consts(110); 46 | rc <== RC.out; 47 | 48 | signal aux[111]; 49 | aux[110] <== inp - key; 50 | component inv[110]; 51 | for(var i=109; i>=0; i--) { 52 | inv[i] = inv_pow5(); 53 | inv[i].inp <== aux[i+1]; 54 | aux[i] <== inv[i].out - key - rc[i]; 55 | } 56 | 57 | out <== aux[0]; 58 | } 59 | 60 | //------------------------------------------------------------------------------ 61 | 62 | // 63 | // This is a permutation of the scalar field. 64 | // 65 | 66 | template MiMC_p$p_permutation() { 67 | signal input inp; 68 | signal output out; 69 | 70 | component encrypt = MiMC_p$p_encrypt_block(); 71 | encrypt.key <== 0; 72 | encrypt.inp <== inp; 73 | encrypt.out ==> out; 74 | } 75 | 76 | //-------------------------------------- 77 | 78 | // 79 | // The inverse permutation. 80 | // 81 | // Note: this is _much slower_ to compute (though not much slower to prove) 82 | // than the forward permutations! 83 | // 84 | 85 | template MiMC_p$p_inverse_permutation() { 86 | signal input inp; 87 | signal output out; 88 | 89 | component decrypt = MiMC_p$p_decrypt_block(); 90 | decrypt.key <== 0; 91 | decrypt.inp <== inp; 92 | decrypt.out ==> out; 93 | } 94 | 95 | //------------------------------------------------------------------------------ 96 | 97 | // 98 | // `F^2 -> F` compression function using Davies-Meyer 99 | // 100 | 101 | template MiMC_p$p_compression() { 102 | signal input inp[2]; 103 | signal output out; 104 | 105 | component encrypt = MiMC_p$p_encrypt_block(); 106 | encrypt.key <== inp[0]; 107 | encrypt.inp <== inp[1]; 108 | out <== encrypt.out + inp[1]; 109 | 110 | // NOTE: The `+inp[1]` is called the "Davies-Meyer construction", and 111 | // apparently is very important. We could also argue that secretly this 112 | // is the "Miyaguchi–Preneel construction", as the `inp[0]=key` is already 113 | // added in the encrypt function. 114 | } 115 | 116 | //------------------------------------------------------------------------------ 117 | 118 | // 119 | // Merkel-Damgard hash built from the compression function above. 120 | // 121 | // NOTE: Consider using the 2p/p sponge hash instead of this one; 122 | // that is supposed to be a safer choice (?) 123 | // 124 | 125 | template MiMC_p$p_hash_MerkleDamgard(n) { 126 | signal input inp[n]; 127 | signal output out; 128 | 129 | signal aux[n+1]; 130 | aux[0] <== n; // we use the length as IV, so different lengths won't collide 131 | 132 | component compr[n]; 133 | for(var i=0; i aux[i+1]; 138 | } 139 | 140 | out <== aux[n]; 141 | } 142 | 143 | //------------------------------------------------------------------------------ 144 | 145 | -------------------------------------------------------------------------------- /circuits/keccak/sha3_bytes.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "sha3_bits.circom"; 4 | 5 | //------------------------------------------------------------------------------ 6 | 7 | template UnpackBytes(n) { 8 | signal input bytes[n]; 9 | signal output bits[8*n]; 10 | 11 | component tobits[n]; 12 | 13 | for(var j=0; j bits[ j*8 + i ]; 18 | } 19 | } 20 | } 21 | 22 | //-------------------------------------- 23 | 24 | template PackBytes(n) { 25 | signal input bits[8*n]; 26 | signal output bytes[n]; 27 | 28 | for(var k=0; k unpack.bytes; 49 | unpack.bits ==> sha3.inp; 50 | sha3.out ==> pack.bits; 51 | pack.bytes ==> out_bytes; 52 | } 53 | 54 | //-------------------------------------- 55 | 56 | template SHA3_256_bytes(input_len) { 57 | signal input inp_bytes[input_len]; 58 | signal output out_bytes[32]; 59 | 60 | component unpack = UnpackBytes(input_len); 61 | component sha3 = SHA3_256(input_len*8); 62 | component pack = PackBytes(32); 63 | 64 | inp_bytes ==> unpack.bytes; 65 | unpack.bits ==> sha3.inp; 66 | sha3.out ==> pack.bits; 67 | pack.bytes ==> out_bytes; 68 | } 69 | 70 | //-------------------------------------- 71 | 72 | template SHA3_384_bytes(input_len) { 73 | signal input inp_bytes[input_len]; 74 | signal output out_bytes[48]; 75 | 76 | component unpack = UnpackBytes(input_len); 77 | component sha3 = SHA3_384(input_len*8); 78 | component pack = PackBytes(48); 79 | 80 | inp_bytes ==> unpack.bytes; 81 | unpack.bits ==> sha3.inp; 82 | sha3.out ==> pack.bits; 83 | pack.bytes ==> out_bytes; 84 | } 85 | 86 | //-------------------------------------- 87 | 88 | template SHA3_512_bytes(input_len) { 89 | signal input inp_bytes[input_len]; 90 | signal output out_bytes[64]; 91 | 92 | component unpack = UnpackBytes(input_len); 93 | component sha3 = SHA3_512(input_len*8); 94 | component pack = PackBytes(64); 95 | 96 | inp_bytes ==> unpack.bytes; 97 | unpack.bits ==> sha3.inp; 98 | sha3.out ==> pack.bits; 99 | pack.bytes ==> out_bytes; 100 | } 101 | 102 | //------------------------------------------------------------------------------ 103 | // NIST SHA3 Extendable-Output Functions 104 | 105 | template SHAKE128_bytes(input_len, output_len) { 106 | signal input inp_bytes[input_len]; 107 | signal output out_bytes[output_len]; 108 | 109 | component unpack = UnpackBytes(input_len); 110 | component sha3 = SHAKE128(input_len*8, output_len*8); 111 | component pack = PackBytes(output_len); 112 | 113 | inp_bytes ==> unpack.bytes; 114 | unpack.bits ==> sha3.inp; 115 | sha3.out ==> pack.bits; 116 | pack.bytes ==> out_bytes; 117 | } 118 | 119 | //-------------------------------------- 120 | 121 | template SHAKE256_bytes(input_len, output_len) { 122 | signal input inp_bytes[input_len]; 123 | signal output out_bytes[output_len]; 124 | 125 | component unpack = UnpackBytes(input_len); 126 | component sha3 = SHAKE256(input_len*8, output_len*8); 127 | component pack = PackBytes(output_len); 128 | 129 | inp_bytes ==> unpack.bytes; 130 | unpack.bits ==> sha3.inp; 131 | sha3.out ==> pack.bits; 132 | pack.bytes ==> out_bytes; 133 | } 134 | 135 | //------------------------------------------------------------------------------ 136 | 137 | -------------------------------------------------------------------------------- /circuits/mimc/mimc-test.circom: -------------------------------------------------------------------------------- 1 | 2 | // simple wrappers for compatibility with the crappy hackish test framework 3 | 4 | pragma circom 2.0.0; 5 | 6 | include "mimc-p-p.circom"; 7 | include "mimc-feistel-2p-p.circom"; 8 | include "mimc-stream-cipher.circom"; 9 | 10 | //------------------------------------------------------------------------------ 11 | 12 | template Test_MiMC_permutation(dummy) { 13 | signal input inp[1]; 14 | signal output out; 15 | component perm = MiMC_p$p_permutation(); 16 | perm.inp <== inp[0]; 17 | perm.out ==> out; 18 | } 19 | 20 | template Test_MiMC_inverse_permutation(dummy) { 21 | signal input inp[1]; 22 | signal output out; 23 | component perm = MiMC_p$p_inverse_permutation(); 24 | perm.inp <== inp[0]; 25 | perm.out ==> out; 26 | } 27 | 28 | //------------------------------------------------------------------------------ 29 | 30 | template Test_MiMC_Feistel_permutation(dummy) { 31 | signal input inp[2]; 32 | signal output out; 33 | component perm = MiMC_Feistel_2p$p_permutation(); 34 | inp ==> perm.inp; 35 | out <== perm.out[0] + perm.out[1]; 36 | } 37 | 38 | template Test_MiMC_Feistel_inverse_permutation(dummy) { 39 | signal input inp[2]; 40 | signal output out; 41 | component perm = MiMC_Feistel_2p$p_inverse_permutation(); 42 | inp ==> perm.inp; 43 | out <== perm.out[0] + perm.out[1]; 44 | } 45 | 46 | //------------------------------------------------------------------------------ 47 | 48 | template Test_MiMC_compression(dummy) { 49 | signal input inp[2]; 50 | signal output out; 51 | component comp = MiMC_p$p_compression(); 52 | comp.inp <== inp; 53 | comp.out ==> out; 54 | } 55 | 56 | //------------------------------------------------------------------------------ 57 | 58 | template Test_MiMC_encrypt(dummy) { 59 | signal input inp[2]; 60 | signal output out; 61 | component enc = MiMC_p$p_encrypt_block(); 62 | enc.key <== inp[0]; 63 | enc.inp <== inp[1]; 64 | enc.out ==> out; 65 | } 66 | 67 | template Test_MiMC_decrypt(dummy) { 68 | signal input inp[2]; 69 | signal output out; 70 | component dec = MiMC_p$p_decrypt_block(); 71 | dec.key <== inp[0]; 72 | dec.inp <== inp[1]; 73 | dec.out ==> out; 74 | } 75 | 76 | //------------------------------------------------------------------------------ 77 | 78 | template Test_MiMC_Feistel_encrypt(dummy) { 79 | signal input inp[3]; 80 | signal output out; 81 | component enc = MiMC_Feistel_2p$p_encrypt_block(); 82 | inp[0] ==> enc.key; 83 | inp[1] ==> enc.inp[0]; 84 | inp[2] ==> enc.inp[1]; 85 | out <== enc.out[0] + enc.out[1]; 86 | } 87 | 88 | template Test_MiMC_Feistel_decrypt(dummy) { 89 | signal input inp[3]; 90 | signal output out; 91 | component dec = MiMC_Feistel_2p$p_decrypt_block(); 92 | inp[0] ==> dec.key; 93 | inp[1] ==> dec.inp[0]; 94 | inp[2] ==> dec.inp[1]; 95 | out <== dec.out[0] + dec.out[1]; 96 | } 97 | 98 | //------------------------------------------------------------------------------ 99 | 100 | template Test_MiMC_CFB_encrypt(n) { 101 | signal input inp[n]; 102 | signal output out; 103 | 104 | signal key; 105 | signal iv; 106 | signal xs[n-2]; 107 | 108 | for(var i=0; i [Word8] 57 | toBytes n = [ fromInteger (shiftR n (8*i) .&. 255) | i<-[0..31] ] 58 | 59 | fromBytes :: [Word8] -> Integer 60 | fromBytes ws = sum (zipWith f [0..] ws) where 61 | f i w = shiftL (fromIntegral w) (8*i) 62 | 63 | -- | Calculates the i-th round constant. Example: 64 | -- 65 | -- Preimage for @i=5@ is: 66 | -- 67 | -- > 00000000 8e 22 52 21 40 df 0b 90 93 d9 da d9 38 38 0c c6 68 | -- > 00000010 b5 97 ac 7d 46 7e 8f d2 ac 88 6e 5d c7 c8 74 45 69 | -- > 00000020 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70 | -- > 00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 71 | -- 72 | -- SHA256 of that is: 73 | -- 74 | -- > 8d905fff93665a967eebeeab69caf8fa3fc170954221012b4ea72d1906d1486e 75 | -- 76 | -- as little-endian integer, that is 77 | -- 78 | -- > a5 = 0x6e48d106192da74e2b0121429570c13ffaf8ca69abeeeb7e965a6693ff5f908d 79 | -- > = 49883068962221093690836652677075821172204594681873204573268154104756989563021 80 | -- 81 | -- so the corresponding round constant will be 82 | -- 83 | -- > rc[5] = a5 `mod` prime 84 | -- > = 6106583218542543246343841186561270995107865881041135885871745731605372571787 85 | -- 86 | ithRoundConst :: Int -> Integer 87 | ithRoundConst = fst . ithRoundConst' 88 | 89 | ithRoundConst' :: Int -> (Integer,(ByteString,ByteString)) 90 | ithRoundConst' i = (rc,(bs,hash)) where 91 | ws = toBytes seed ++ toBytes (fromIntegral i) 92 | bs = B.pack ws 93 | digest = sha256 bs 94 | hash = B.concat $ map toByteStringBE $ fromDigest digest 95 | rc = mod (fromBytes $ B.unpack hash) prime 96 | 97 | -------------------------------------------------------------------------------- 98 | 99 | roundConsts :: [Integer] 100 | roundConsts = [ ithRoundConst i | i<-[0..nrounds-1] ] 101 | 102 | showRoundConsts :: String 103 | showRoundConsts = unlines $ 104 | [ (" " ++ [c] ++ " " ++ show rc) 105 | | (c,rc) <- zip commas roundConsts 106 | ] ++ 107 | [ " ]" ] 108 | where 109 | commas = '[' : repeat ',' 110 | 111 | printRoundConsts :: IO () 112 | printRoundConsts = putStrLn showRoundConsts 113 | 114 | exportRoundConsts :: FilePath -> IO () 115 | exportRoundConsts fp = writeFile fp showRoundConsts 116 | 117 | -------------------------------------------------------------------------------- 118 | -------------------------------------------------------------------------------- /hash-circuits.cabal: -------------------------------------------------------------------------------- 1 | Cabal-Version: 2.4 2 | Name: hash-circuits 3 | Version: 0.1 4 | Synopsis: Hash circuits implemented in circom 5 | 6 | Description: Hash circuits (SHA2, Keccak / SHA3, Blake2, Poseidon2) 7 | implemented in circom (R1CS / arithmetic circuit) with tests 8 | and reference implementations in Haskell. 9 | 10 | License: MIT 11 | License-file: LICENSE 12 | Author: Balazs Komuves 13 | Copyright: (c) 2023 Faulhorn Labs 14 | Maintainer: balazs.komuves (at) faulhornlabs (dot) com 15 | Stability: Experimental 16 | Category: Math, Cryptography 17 | Tested-With: GHC == 8.6.5, GHC == 9.0.1 18 | Build-Type: Simple 19 | 20 | -------------------------------------------------------------------------------- 21 | 22 | Data-Files: circuits/sha2/*.circom 23 | circuits/sha2/sha224/*.circom 24 | circuits/sha2/sha256/*.circom 25 | circuits/sha2/sha384/*.circom 26 | circuits/sha2/sha512/*.circom 27 | circuits/keccak/*.circom 28 | circuits/blake2/*.circom 29 | circuits/poseidon2/*.circom 30 | circuits/mimc/*.circom 31 | 32 | extra-doc-files: README.md 33 | circuits/sha2/sha256/README.md 34 | circuits/sha2/sha512/README.md 35 | circuits/keccak/README.md 36 | circuits/blake2/README.md 37 | circuits/poseidon2/README.md 38 | circuits/mimc/README.md 39 | src/README.md 40 | src/ref/README.md 41 | 42 | -------------------------------------------------------------------------------- 43 | 44 | source-repository head 45 | type: git 46 | location: https://github.com/faulhornlabs/hash-circuits 47 | 48 | -------------------------------------------------------------------------------- 49 | 50 | executable hash-circuit-tests 51 | 52 | Build-Depends: base >= 4 && < 5, 53 | array >= 0.5, 54 | containers >= 0.6, 55 | filepath >= 1.2, 56 | bytestring >= 0.10, 57 | r1cs-solver == 0.1, 58 | zikkurat-algebra 59 | 60 | Hs-Source-Dirs: src 61 | 62 | main-is: Main.hs 63 | 64 | Other-Modules: Ref.SHA2.SHA256 65 | Ref.Blake2.BLAKE2s 66 | Ref.Blake2.BLAKE2b 67 | Ref.Keccak.Perm 68 | Ref.Poseidon2.Naive.Example 69 | Ref.Poseidon2.Naive.Merkle 70 | Ref.Poseidon2.Naive.Permutation 71 | Ref.Poseidon2.Naive.BN256 72 | Ref.Poseidon2.Naive.PrimeField 73 | Ref.Poseidon2.Naive.RoundConsts 74 | Ref.Poseidon2.Zikkurat.Sponge 75 | Ref.Poseidon2.Zikkurat.Merkle 76 | Ref.Poseidon2.Zikkurat.Permutation 77 | Ref.Poseidon2.Zikkurat.InvPerm 78 | Ref.Poseidon2.Zikkurat.RoundConsts 79 | Ref.Griffin.Permutation 80 | Ref.MiMC.MiMC 81 | Ref.MiMC.RoundConst 82 | Ref.Common 83 | Vectors.SHA2 84 | Vectors.Blake2 85 | Vectors.Keccak 86 | Test.Hash.SHA2 87 | Test.Hash.Keccak 88 | Test.Hash.Blake2 89 | Test.Hash.MiMC 90 | Test.Hash.Poseidon2 91 | Test.Hash.Griffin 92 | Test.Runner 93 | Test.Misc 94 | 95 | Default-Language: Haskell2010 96 | Default-Extensions: BangPatterns, TypeApplications, ScopedTypeVariables 97 | 98 | -------------------------------------------------------------------------------- 99 | 100 | -------------------------------------------------------------------------------- /src/Vectors/SHA2.hs: -------------------------------------------------------------------------------- 1 | 2 | module Vectors.SHA2 where 3 | 4 | -------------------------------------------------------------------------------- 5 | 6 | data HashFun 7 | = SHA2_224 8 | | SHA2_256 9 | | SHA2_384 10 | | SHA2_512 11 | deriving (Eq,Show) 12 | 13 | -------------------------------------------------------------------------------- 14 | 15 | testVectorsSHA2 :: HashFun -> [(String,String)] 16 | testVectorsSHA2 hashfun = case hashfun of 17 | SHA2_224 -> sha2_224_vectors 18 | SHA2_256 -> sha2_256_vectors 19 | SHA2_384 -> sha2_384_vectors 20 | SHA2_512 -> sha2_512_vectors 21 | 22 | -------------------------------------------------------------------------------- 23 | 24 | infix 1 ~> 25 | (~>) :: a -> b -> (a,b) 26 | (~>) x y = (x,y) 27 | 28 | -------------------------------------------------------------------------------- 29 | 30 | sha2_224_vectors :: [(String,String)] 31 | sha2_224_vectors = 32 | [ "" ~> "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f" 33 | , "a" ~> "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5" 34 | , "foo" ~> "0808f64e60d58979fcb676c96ec938270dea42445aeefcd3a4e6f8db" 35 | , "alma" ~> "20abd0d88f5df0ae7f0f2ee747c8f08dfffcade5c633d9b2219fd87a" 36 | , "almakorte" ~> "047a17d7886816ad6feca7200b4a1c1bf63291415ee035789254ed46" 37 | ] 38 | 39 | sha2_256_vectors :: [(String,String)] 40 | sha2_256_vectors = 41 | [ "" ~> "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" 42 | , "a" ~> "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb" 43 | , "foo" ~> "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae" 44 | , "alma" ~> "cf43e029efe6476e1f7f84691f89c876818610c2eaeaeb881103790a48745b82" 45 | , "almakorte" ~> "7bbf139acb8cd3d267b949f6744e8c5f67cfe77e23342572a4246d4ccd64631d" 46 | , "almakorteszilvabanan1almakorteszilvabanan2almakorteszilvabanan3almakorteszilvabanan4almakorteszilvabanan5" 47 | ~> "b828bb6d1554136752c989e7d35070781f89d54162c9e0f4dfdc68f68103a88d" 48 | , "almakorteszilvabanan1almakorteszilvabanan2almakorteszilvabanan3almakorteszilvabanan4almakorteszilvabanan5almakorteszilvabanan6almakorteszilvabanan7" 49 | ~> "c285283c95d1a95042742af7222a977b17f61fb7227e8f47afe519197513f213" 50 | , "almakorteszilvabanan1almakorteszilvabanan2almakorteszilvabanan3almakorteszilvabanan4almakorteszilvabanan5almakorteszilvabanan6almakorteszilvabanan7almakorteszilvabanan8almakorteszilvabanan9" 51 | ~> "69868fcb61eb4d4e7e6ee92aae5806665b5efe960af47b28345a38885d4b57e0" 52 | , "almakorteszilvabanan1almakorteszilvabanan2almakorteszilvabanan3almakorteszilvabanan4almakorteszilvabanan5almakorteszilvabanan6almakorteszilvabanan7almakorteszilvabanan8almakorteszilvabanan9almakorteszilvabanan10almakorteszilvabanan11" 53 | ~> "c55ee176cb826d63671c02c5cfe8492564251735d5e745481cae408924d450f2" 54 | ] 55 | 56 | sha2_384_vectors :: [(String,String)] 57 | sha2_384_vectors = 58 | [ "" ~> "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b" 59 | , "a" ~> "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31" 60 | , "foo" ~> "98c11ffdfdd540676b1a137cb1a22b2a70350c9a44171d6b1180c6be5cbb2ee3f79d532c8a1dd9ef2e8e08e752a3babb" 61 | , "alma" ~> "24c45c20efc2795d1737ecfd41f832a0215d2bea3bb86a3c57a27a7e4f1bcaba7cde5dc2ab8c3bea48690af5197c213b" 62 | , "almakorte" ~> "6e7353b52f8ec0d8e3182925b3199a39e6f8c866a1a80768c12d1043194c6e7812473e2bda30ab5aaa6be9c16aae6d9e" 63 | ] 64 | 65 | sha2_512_vectors :: [(String,String)] 66 | sha2_512_vectors = 67 | [ "" ~> "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" 68 | , "a" ~> "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75" 69 | , "foo" ~> "f7fbba6e0636f890e56fbbf3283e524c6fa3204ae298382d624741d0dc6638326e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7" 70 | , "alma" ~> "83b05d98186648cd5576ed158c9cf2174413b86d48720c3ffbe6452bc38a6527256ff3435eb1698f24efbc880c8ea870afe314f3004c71cfdd5f0e3c00e3979f" 71 | , "almakorte" ~> "826c1f003bf9835d84322150ca5d92b328465550e720fa2cc1c594957a962d089dcd581bf4e009c9c138faa18546879979fba58a091d38080af151a8ba6205d5" 72 | ] 73 | 74 | -------------------------------------------------------------------------------- 75 | -------------------------------------------------------------------------------- /src/Test/Hash/Poseidon2.hs: -------------------------------------------------------------------------------- 1 | 2 | module Test.Hash.Poseidon2 where 3 | 4 | -------------------------------------------------------------------------------- 5 | 6 | import R1CS 7 | import Test.Runner 8 | 9 | import Ref.Poseidon2.Zikkurat.Permutation 10 | import Ref.Poseidon2.Zikkurat.Merkle 11 | import Ref.Poseidon2.Zikkurat.Sponge 12 | 13 | -------------------------------------------------------------------------------- 14 | -- * tests for the hashes where the input is a sequence of field elements 15 | 16 | poseidon2_sponge_rate1_test :: ArithHashTest 17 | poseidon2_sponge_rate1_test = MkGenericHashTest 18 | { __circomFile = "circuits/poseidon2/poseidon2_sponge.circom" 19 | , __templateName = "Poseidon2_sponge_hash_rate_1" 20 | , __inputSignal = "inp" 21 | , __outputSignal = "out" 22 | , __testCases = poseidon2_sponge_rate1_vectors 23 | } 24 | 25 | poseidon2_sponge_rate2_test :: ArithHashTest 26 | poseidon2_sponge_rate2_test = MkGenericHashTest 27 | { __circomFile = "circuits/poseidon2/poseidon2_sponge.circom" 28 | , __templateName = "Poseidon2_sponge_hash_rate_2" 29 | , __inputSignal = "inp" 30 | , __outputSignal = "out" 31 | , __testCases = poseidon2_sponge_rate2_vectors 32 | } 33 | 34 | poseidon2_merkle_tree_test :: ArithHashTest 35 | poseidon2_merkle_tree_test = MkGenericHashTest 36 | { __circomFile = "circuits/poseidon2/poseidon2_tests.circom" 37 | , __templateName = "Test_Poseidon2_merkle_tree" 38 | , __inputSignal = "inp" 39 | , __outputSignal = "out" 40 | , __testCases = poseidon2_merkle_tree_vectors 41 | } 42 | 43 | -------------------------------------------------------------------------------- 44 | 45 | poseidon2_sponge_rate1_vectors :: [([Integer], Integer)] 46 | poseidon2_sponge_rate1_vectors = 47 | [ (inp, frToInteger hash) 48 | | k<-[0..10] 49 | , let inp = [1..k] 50 | , let hash = spongeRate1 (map fromInteger inp) 51 | ] 52 | 53 | poseidon2_sponge_rate2_vectors :: [([Integer], Integer)] 54 | poseidon2_sponge_rate2_vectors = 55 | [ (inp, frToInteger hash) 56 | | k<-[0..10] 57 | , let inp = [1..k] 58 | , let hash = spongeRate2 (map fromInteger inp) 59 | ] 60 | 61 | poseidon2_merkle_tree_vectors :: [([Integer], Integer)] 62 | poseidon2_merkle_tree_vectors = 63 | [ (inp, frToInteger hash) 64 | | k<-[0..4] 65 | , let inp = [1..2^k] 66 | , let hash = calcMerkleRoot (map fromInteger inp) 67 | ] 68 | 69 | -------------------------------------------------------------------------------- 70 | -- * tests for the permutation 71 | 72 | poseidon2_perm_test :: ArithHashTest 73 | poseidon2_perm_test = MkGenericHashTest 74 | { __circomFile = "circuits/poseidon2/poseidon2_tests.circom" 75 | , __templateName = "Test_Poseidon2_permutation" 76 | , __inputSignal = "inp" 77 | , __outputSignal = "out" 78 | , __testCases = poseidon2_perm_vectors 79 | } 80 | 81 | poseidon2_perm_vectors :: [([Integer], Integer)] 82 | poseidon2_perm_vectors = 83 | [ ([x,y,z], frToInteger t) 84 | | i<-[0..10] 85 | , let x = 101 + 2*i 86 | , let y = 2002 - 3*i 87 | , let z = 30003 - 7*i 88 | , let (u,v,w) = permutation (fromInteger x, fromInteger y, fromInteger z) 89 | , let t = u + v + w 90 | ] 91 | 92 | -------------------------------------------------------------------------------- 93 | -- * tests for the remaining components 94 | 95 | poseidon2_compression_test :: ArithHashTest 96 | poseidon2_compression_test = MkGenericHashTest 97 | { __circomFile = "circuits/poseidon2/poseidon2_tests.circom" 98 | , __templateName = "Test_Poseidon2_compression" 99 | , __inputSignal = "inp" 100 | , __outputSignal = "out" 101 | , __testCases = poseidon2_compression_vectors 102 | } 103 | 104 | poseidon2_compression_vectors :: [([Integer], Integer)] 105 | poseidon2_compression_vectors = 106 | [ ([x,y], frToInteger z) 107 | | i<-[0..10] 108 | , let x = 555 + i 109 | , let y = 1001 + 2*i 110 | , let z = compression (fromInteger x) (fromInteger y) 111 | ] 112 | 113 | -------------------------------------------------------------------------------- 114 | 115 | runTests_Poseidon2 :: Verbosity -> FilePath -> IO () 116 | runTests_Poseidon2 verbosity rootDir = do 117 | 118 | putStrLn "running tests for Poseidon2... (input = sequence of field elements)" 119 | 120 | runArithTest verbosity rootDir poseidon2_sponge_rate1_test 121 | runArithTest verbosity rootDir poseidon2_sponge_rate2_test 122 | runArithTest verbosity rootDir poseidon2_merkle_tree_test 123 | 124 | runArithTest verbosity rootDir poseidon2_compression_test 125 | runArithTest verbosity rootDir poseidon2_perm_test 126 | 127 | -------------------------------------------------------------------------------- 128 | -------------------------------------------------------------------------------- /src/Ref/Common.hs: -------------------------------------------------------------------------------- 1 | 2 | {-# LANGUAGE TypeApplications, FlexibleInstances, NumericUnderscores #-} 3 | module Ref.Common where 4 | 5 | -------------------------------------------------------------------------------- 6 | 7 | import Data.Bits 8 | import Data.Char 9 | import Data.List 10 | import Data.Word 11 | import Data.Array 12 | 13 | import Data.ByteString (ByteString) 14 | import qualified Data.ByteString as B 15 | import qualified Data.ByteString.Char8 as C 16 | 17 | -------------------------------------------------------------------------------- 18 | 19 | class ToHexString a where 20 | toHexStringBE :: a -> String 21 | toHexStringLE :: a -> String 22 | 23 | instance ToHexString Word8 where 24 | toHexStringBE w = showNibble (shiftR w 4) : showNibble (w .&. 15) : [] 25 | toHexStringLE w = showNibble (shiftR w 4) : showNibble (w .&. 15) : [] 26 | 27 | instance ToHexString Word16 where 28 | toHexStringBE w = 29 | (toHexStringBE @Word8 (fromIntegral (shiftR w 8))) ++ 30 | (toHexStringBE @Word8 (fromIntegral (w .&. 0xff))) 31 | toHexStringLE w = 32 | (toHexStringLE @Word8 (fromIntegral (w .&. 0xff))) ++ 33 | (toHexStringLE @Word8 (fromIntegral (shiftR w 8))) 34 | 35 | instance ToHexString Word32 where 36 | toHexStringBE w = 37 | (toHexStringBE @Word16 (fromIntegral (shiftR w 16 ))) ++ 38 | (toHexStringBE @Word16 (fromIntegral (w .&. 0xffff))) 39 | toHexStringLE w = 40 | (toHexStringLE @Word16 (fromIntegral (w .&. 0xffff))) ++ 41 | (toHexStringLE @Word16 (fromIntegral (shiftR w 16 ))) 42 | 43 | instance ToHexString Word64 where 44 | toHexStringBE w = 45 | (toHexStringBE @Word32 (fromIntegral (shiftR w 32 ))) ++ 46 | (toHexStringBE @Word32 (fromIntegral (w .&. 0xffff_ffff))) 47 | toHexStringLE w = 48 | (toHexStringLE @Word32 (fromIntegral (w .&. 0xffff_ffff))) ++ 49 | (toHexStringLE @Word32 (fromIntegral (shiftR w 32 ))) 50 | 51 | instance ToHexString a => ToHexString [a] where 52 | toHexStringBE xs = intercalate " " (map toHexStringBE xs) 53 | toHexStringLE xs = intercalate " " (map toHexStringLE xs) 54 | 55 | instance ToHexString a => ToHexString (Array Int a) where 56 | toHexStringBE arr = toHexStringBE (elems arr) 57 | toHexStringLE arr = toHexStringLE (elems arr) 58 | 59 | showNibble :: Word8 -> Char 60 | showNibble k 61 | | k < 10 = chr (48 + fromIntegral k) 62 | | k < 16 = chr (87 + fromIntegral k) 63 | | otherwise = error "showNibble: outside of range" 64 | 65 | -------------------------------------------------------------------------------- 66 | 67 | class ToByteString a where 68 | toByteStringBE :: a -> ByteString 69 | 70 | instance ToByteString Word8 where 71 | toByteStringBE w = B.singleton w 72 | 73 | instance ToByteString Word16 where 74 | toByteStringBE w = B.pack [ fromIntegral (shiftR w 8) , fromIntegral (w .&. 0xff) ] 75 | 76 | instance ToByteString Word32 where 77 | toByteStringBE w = B.append 78 | (toByteStringBE @Word16 (fromIntegral (shiftR w 16 ))) 79 | (toByteStringBE @Word16 (fromIntegral (w .&. 0xffff))) 80 | 81 | instance ToByteString Word64 where 82 | toByteStringBE w = B.append 83 | (toByteStringBE @Word32 (fromIntegral (shiftR w 32 ))) 84 | (toByteStringBE @Word32 (fromIntegral (w .&. 0xffffffff))) 85 | 86 | -------------------------------------------------------------------------------- 87 | 88 | class FromByteString a where 89 | fromByteStringBE :: ByteString -> (a,ByteString) 90 | 91 | fromByteStringBE_ :: FromByteString a => ByteString -> a 92 | fromByteStringBE_ bs = case fromByteStringBE bs of 93 | (y,rest) -> if B.null rest 94 | then y 95 | else error "fromByteStringBE_: cannot parse" 96 | 97 | instance FromByteString Word8 where 98 | fromByteStringBE bs = case B.unpack (B.take 1 bs) of 99 | [a] -> ( a , B.drop 1 bs ) 100 | _ -> error "fromByteStringBE/Word8: unexpected end of input" 101 | 102 | instance FromByteString Word16 where 103 | fromByteStringBE bs = case B.unpack (B.take 2 bs) of 104 | [a,b] -> let y = shiftL (fromIntegral a) 8 .|. (fromIntegral b) 105 | in ( y , B.drop 2 bs ) 106 | _ -> error "fromByteStringBE/Word16: unexpected end of input" 107 | 108 | instance FromByteString Word32 where 109 | fromByteStringBE bs = case B.unpack (B.take 4 bs) of 110 | [a,b,c,d] -> let y = shiftL (fromIntegral a) 24 .|. 111 | shiftL (fromIntegral b) 16 .|. 112 | shiftL (fromIntegral c) 8 .|. 113 | (fromIntegral d) 114 | in ( y , B.drop 4 bs ) 115 | _ -> error "fromByteStringBE/Word32: unexpected end of input" 116 | 117 | -------------------------------------------------------------------------------- 118 | -------------------------------------------------------------------------------- /src/Test/Hash/Keccak.hs: -------------------------------------------------------------------------------- 1 | 2 | module Test.Hash.Keccak where 3 | 4 | -------------------------------------------------------------------------------- 5 | 6 | import R1CS 7 | import Test.Runner 8 | import Vectors.Keccak 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | sha3_224_test :: SimpleHashTest 13 | sha3_224_test = MkGenericHashTest 14 | { __circomFile = "circuits/keccak/sha3_bytes.circom" 15 | , __templateName = "SHA3_224_bytes" 16 | , __inputSignal = "inp_bytes" 17 | , __outputSignal = "out_bytes" 18 | , __testCases = sha3_224_vectors 19 | } 20 | 21 | sha3_256_test :: SimpleHashTest 22 | sha3_256_test = MkGenericHashTest 23 | { __circomFile = "circuits/keccak/sha3_bytes.circom" 24 | , __templateName = "SHA3_256_bytes" 25 | , __inputSignal = "inp_bytes" 26 | , __outputSignal = "out_bytes" 27 | , __testCases = sha3_256_vectors 28 | } 29 | 30 | sha3_384_test :: SimpleHashTest 31 | sha3_384_test = MkGenericHashTest 32 | { __circomFile = "circuits/keccak/sha3_bytes.circom" 33 | , __templateName = "SHA3_384_bytes" 34 | , __inputSignal = "inp_bytes" 35 | , __outputSignal = "out_bytes" 36 | , __testCases = sha3_384_vectors 37 | } 38 | 39 | sha3_512_test :: SimpleHashTest 40 | sha3_512_test = MkGenericHashTest 41 | { __circomFile = "circuits/keccak/sha3_bytes.circom" 42 | , __templateName = "SHA3_512_bytes" 43 | , __inputSignal = "inp_bytes" 44 | , __outputSignal = "out_bytes" 45 | , __testCases = sha3_512_vectors 46 | } 47 | 48 | -------------------------------------------------------------------------------- 49 | 50 | keccak_224_test :: SimpleHashTest 51 | keccak_224_test = MkGenericHashTest 52 | { __circomFile = "circuits/keccak/keccak_bytes.circom" 53 | , __templateName = "Keccak_224_bytes" 54 | , __inputSignal = "inp_bytes" 55 | , __outputSignal = "out_bytes" 56 | , __testCases = keccak_224_vectors 57 | } 58 | 59 | keccak_256_test :: SimpleHashTest 60 | keccak_256_test = MkGenericHashTest 61 | { __circomFile = "circuits/keccak/keccak_bytes.circom" 62 | , __templateName = "Keccak_256_bytes" 63 | , __inputSignal = "inp_bytes" 64 | , __outputSignal = "out_bytes" 65 | , __testCases = keccak_256_vectors 66 | } 67 | 68 | keccak_384_test :: SimpleHashTest 69 | keccak_384_test = MkGenericHashTest 70 | { __circomFile = "circuits/keccak/keccak_bytes.circom" 71 | , __templateName = "Keccak_384_bytes" 72 | , __inputSignal = "inp_bytes" 73 | , __outputSignal = "out_bytes" 74 | , __testCases = keccak_384_vectors 75 | } 76 | 77 | keccak_512_test :: SimpleHashTest 78 | keccak_512_test = MkGenericHashTest 79 | { __circomFile = "circuits/keccak/keccak_bytes.circom" 80 | , __templateName = "Keccak_512_bytes" 81 | , __inputSignal = "inp_bytes" 82 | , __outputSignal = "out_bytes" 83 | , __testCases = keccak_512_vectors 84 | } 85 | 86 | -------------------------------------------------------------------------------- 87 | 88 | shake_128_test :: SimpleHashTest 89 | shake_128_test = MkGenericHashTest 90 | { __circomFile = "circuits/keccak/sha3_bytes.circom" 91 | , __templateName = "SHAKE128_bytes" 92 | , __inputSignal = "inp_bytes" 93 | , __outputSignal = "out_bytes" 94 | , __testCases = shake_128_5000 95 | } 96 | 97 | shake_256_test :: SimpleHashTest 98 | shake_256_test = MkGenericHashTest 99 | { __circomFile = "circuits/keccak/sha3_bytes.circom" 100 | , __templateName = "SHAKE256_bytes" 101 | , __inputSignal = "inp_bytes" 102 | , __outputSignal = "out_bytes" 103 | , __testCases = shake_256_5000 104 | } 105 | 106 | -------------------------------------------------------------------------------- 107 | 108 | runTests_SHA3 :: Verbosity -> FilePath -> IO () 109 | runTests_SHA3 verbosity rootDir = do 110 | 111 | putStrLn "running test for SHA3..." 112 | 113 | runSimpleTestBytes verbosity rootDir sha3_224_test 114 | runSimpleTestBytes verbosity rootDir sha3_256_test 115 | runSimpleTestBytes verbosity rootDir sha3_384_test 116 | runSimpleTestBytes verbosity rootDir sha3_512_test 117 | 118 | -------------------------------------------------------------------------------- 119 | 120 | runTests_Keccak :: Verbosity -> FilePath -> IO () 121 | runTests_Keccak verbosity rootDir = do 122 | 123 | putStrLn "running test for Keccak..." 124 | 125 | runSimpleTestBytes verbosity rootDir keccak_224_test 126 | runSimpleTestBytes verbosity rootDir keccak_256_test 127 | runSimpleTestBytes verbosity rootDir keccak_384_test 128 | runSimpleTestBytes verbosity rootDir keccak_512_test 129 | 130 | -------------------------------------------------------------------------------- 131 | 132 | runTests_SHAKE :: Verbosity -> FilePath -> IO () 133 | runTests_SHAKE verbosity rootDir = do 134 | 135 | putStrLn "running test for SHAKE..." 136 | 137 | runShakeTest verbosity rootDir shake_128_test 138 | runShakeTest verbosity rootDir shake_256_test 139 | 140 | -------------------------------------------------------------------------------- 141 | -------------------------------------------------------------------------------- /src/Ref/Keccak/Perm.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | Reference implementation of the Keccak-p[1600] permutations 3 | 4 | module Ref.Keccak.Perm where 5 | 6 | -------------------------------------------------------------------------------- 7 | 8 | import Data.Array hiding (index) 9 | import Data.Word 10 | import Data.Bits 11 | import Data.List 12 | 13 | -------------------------------------------------------------------------------- 14 | -- debugging 15 | 16 | ex :: State 17 | ex = listArray (0,24) [101..125] 18 | 19 | printState :: State -> IO () 20 | printState arr = mapM_ print $ elems arr 21 | 22 | -------------------------------------------------------------------------------- 23 | 24 | xors :: [Word64] -> Word64 25 | xors = foldl1' xor 26 | 27 | ors :: [Word64] -> Word64 28 | ors = foldl1' (.|.) 29 | 30 | -------------------------------------------------------------------------------- 31 | 32 | iter :: Int -> (a -> a) -> a -> a 33 | iter 0 _ = id 34 | iter k f = iter (k-1) f . f 35 | 36 | smallRC :: Int -> Word64 37 | smallRC t0 = (iter (mod t0 255) step 1) .&. 1 where 38 | step :: Word64 -> Word64 39 | step r = 40 | case r' .&. 0x100 of 41 | 0 -> r' .&. 0xff 42 | _ -> (r' `xor` 0x71) .&. 0xff 43 | where 44 | r' = shiftL r 1 45 | 46 | capitalRC :: Int -> Word64 47 | capitalRC idx = ors [ shiftL (smallRC (j+7*idx)) (2^j-1) | j<-[0..7] ] 48 | 49 | roundConstants24 :: Array Int Word64 50 | roundConstants24 = listArray (0,23) [ capitalRC i | i<-[0..23] ] 51 | 52 | roundConstants24_ref :: Array Int Word64 53 | roundConstants24_ref = listArray (0,23) 54 | [ 0x0000000000000001, 0x0000000000008082, 0x800000000000808a 55 | , 0x8000000080008000, 0x000000000000808b, 0x0000000080000001 56 | , 0x8000000080008081, 0x8000000000008009, 0x000000000000008a 57 | , 0x0000000000000088, 0x0000000080008009, 0x000000008000000a 58 | , 0x000000008000808b, 0x800000000000008b, 0x8000000000008089 59 | , 0x8000000000008003, 0x8000000000008002, 0x8000000000000080 60 | , 0x000000000000800a, 0x800000008000000a, 0x8000000080008081 61 | , 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 62 | ] 63 | 64 | sanityCheckRoundConstants :: Bool 65 | sanityCheckRoundConstants = (roundConstants24 == roundConstants24_ref) 66 | 67 | -------------------------------------------------------------------------------- 68 | 69 | type State = Array Int Word64 70 | 71 | index :: Int -> Int -> Int 72 | index x y = x + y*5 73 | 74 | -------------------------------------------------------------------------------- 75 | 76 | theta :: State -> State 77 | theta old = new where 78 | 79 | cs :: Array Int Word64 80 | cs = listArray (0,4) 81 | [ xors [ old!(index x y) | y <-[0..4] ] 82 | | x <- [0..4] 83 | ] 84 | 85 | new = array (0,24) 86 | [ ( index x y , (old!(index x y)) `xor` a `xor` b ) 87 | | x<-[0..4] 88 | , y<-[0..4] 89 | , let a = cs ! (mod (x-1) 5) 90 | , let b = rotateL (cs ! (mod (x+1) 5)) 1 91 | ] 92 | 93 | -------------------------------------------------------------------------------- 94 | 95 | rho :: State -> State 96 | rho old = new where 97 | new = array (0,24) 98 | [ ( index x y , rotateL (old!(index x y)) (rotationOffsets!(x,y)) ) 99 | | x<-[0..4] 100 | , y<-[0..4] 101 | ] 102 | 103 | rotationOffsets :: Array (Int,Int) Int 104 | rotationOffsets = array ((0,0),(4,4)) list where 105 | list = ((0,0),0) : go 0 (1,0) 106 | go 24 _ = [] 107 | go t (x,y) = ((x,y),ofs):rest where 108 | ofs0 = div ((t+1)*(t+2)) 2 109 | ofs = mod ofs0 64 110 | rest = go (t+1) (x',y') 111 | x' = y 112 | y' = mod (2*x+3*y) 5 113 | 114 | -------------------------------------------------------------------------------- 115 | 116 | pi_ :: State -> State 117 | pi_ old = new where 118 | new = array (0,24) 119 | [ ( index x y , old!(index (mod (x+3*y) 5) x) ) 120 | | x<-[0..4] 121 | , y<-[0..4] 122 | ] 123 | 124 | -------------------------------------------------------------------------------- 125 | 126 | chi :: State -> State 127 | chi old = new where 128 | new = array (0,24) 129 | [ ( index x y , a `xor` ((complement b) .&. c) ) 130 | | x<-[0..4] 131 | , y<-[0..4] 132 | , let a = old!(index x y) 133 | , let b = old!(index (mod (x+1) 5) y) 134 | , let c = old!(index (mod (x+2) 5) y) 135 | ] 136 | 137 | -------------------------------------------------------------------------------- 138 | 139 | iota' :: Word64 -> State -> State 140 | iota' rc old = old // [ (0, (old!0) `xor` rc) ] 141 | 142 | iota :: Int -> State -> State 143 | iota round_idx = iota' (roundConstants24 ! round_idx) 144 | 145 | -------------------------------------------------------------------------------- 146 | 147 | step :: Int -> State -> State 148 | step round_idx 149 | = iota round_idx 150 | . chi 151 | . pi_ 152 | . rho 153 | . theta 154 | 155 | -------------------------------------------------------------------------------- 156 | -- * Keccak-p[1600,nr] 157 | 158 | keccakP :: Int -> State -> State 159 | keccakP nrounds = foldr (.) id (map step $ reverse [0..nrounds-1]) 160 | 161 | keccakF :: State -> State 162 | keccakF = keccakP 24 163 | 164 | -------------------------------------------------------------------------------- 165 | -------------------------------------------------------------------------------- /src/Ref/Griffin/Permutation.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | The Griffin permutation 3 | 4 | {-# LANGUAGE BangPatterns #-} 5 | module Ref.Griffin.Permutation where 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | import Data.Array 10 | import Data.List 11 | 12 | import ZK.Algebra.Class.Field 13 | import ZK.Algebra.Curves.BN128.Fr.Mont (Fr,from) 14 | 15 | -------------------------------------------------------------------------------- 16 | 17 | -- used in the tests 18 | frToInteger :: Fr -> Integer 19 | frToInteger = asInteger 20 | 21 | -------------------------------------------------------------------------------- 22 | 23 | type State = (Fr,Fr,Fr) 24 | 25 | pow5 :: Fr -> Fr 26 | pow5 a = a*a4 where 27 | a2 = square a 28 | a4 = square a2 29 | 30 | powInv5 :: Fr -> Fr 31 | powInv5 a = power a expo_inv 32 | 33 | sanityCheckExpoInv = 34 | [ 13 - pow5 (powInv5 13) 35 | , 17 - powInv5 (pow5 17) 36 | ] 37 | 38 | sbox :: State -> State 39 | sbox (x,y,z) = (x',y',z') where 40 | x' = powInv5 x 41 | y' = pow5 y 42 | z' = z * (square u + alpha * u + beta) 43 | u = x' + y' 44 | 45 | addRC :: Int -> State -> State 46 | addRC 0 = id 47 | addRC i = let (a,b,c) = roundConstants!(i-1) in \(x,y,z) -> (x+a, y+b, z+c) 48 | 49 | linear :: State -> State 50 | linear (x,y,z) = let s = x+y+z in (x+s, y+s, z+s) 51 | 52 | singleRound :: Int -> State -> State 53 | singleRound i = linear . sbox . addRC i 54 | 55 | permute :: State -> State 56 | permute input = foldl' (flip singleRound) (linear input) [0..nrounds-1] 57 | 58 | compress :: Fr -> Fr -> Fr 59 | compress x y = case permute (x,y,0) of (z,_,_) -> z 60 | 61 | -------------------------------------------------------------------------------- 62 | 63 | iter :: Int -> (a -> a) -> a -> a 64 | iter n f = go n where 65 | go 0 !x = x 66 | go !n !x = go (n-1) (f x) 67 | 68 | -------------------------------------------------------------------------------- 69 | -- parameters from 70 | 71 | -- the permutation of (0,1,2) 72 | kat :: State 73 | kat = 74 | ( 0x2311cdb3076c3a7ee37fd5a271e0f3a8a3cc38057d0cea37b78951f43b1b6ff6 75 | , 0x1d3aaed9ea361e899e667abd18e5328555b97b5c3890d52b261f940d6ab4df58 76 | , 0x22614a0ac719cb623a636adac3bac1b85b5a7a418fcf8ab3a3ae0787fb4bed9d 77 | ) 78 | 79 | nrounds = 12 :: Int 80 | expo_inv = 0x26b6a528b427b35493736af8679aad17535cb9d394945a0dcfe7f7a98ccccccd :: Integer 81 | alpha = 0x146ecffb34a66316fae66609f78d1310bc14ad7208082ca7943afebb1da4aa4a :: Fr 82 | beta = 0x2b568115d544c7e941eff6ccc935384619b0fb7d2c5ba6c078c34cf81697ee1c :: Fr 83 | 84 | roundConstants :: Array Int State 85 | roundConstants = listArray (0,10) 86 | [ ( 0x2fb30cafdb1f76156dfabf0cd0af4b895e764ac2a84386c9d0d7aed6a7f4eac9 87 | , 0x282927892ce324572f19abb14871d2b539a80d8a5800cdb87a81e1697a94b6c9 88 | , 0x03d0f3f2711dd59e3d97fc797261300cd3fee33b95cf710a32edf42aa2bc0905 ) 89 | , ( 0x036a8b3eb9ef35c74ea5a367ed279ee6d043d4ff69817f192c7251b91dcbb03d 90 | , 0x2a626d396e7fa8ce8d6339bb37bd48491d56db0c7ac0afb5008a7464d5776a26 91 | , 0x0cc9dfabbeaef7982543453ea3ac37ef2bfefd35a7e7070aa39b021035852d5b ) 92 | , ( 0x2a1951149e2568ab28e972a2ceddc49eff0cae8e1cddcf4b0684a73a1b4ef61b 93 | , 0x2d0ff8e9158b2fd7ae3afe01cf09d4ce9ff81e6127e441eb6cbc79d21f22be9e 94 | , 0x1cc315b7ea0c1efb538f0c3248a7da062309a9e41af5a555c9ea9e8a10930cb5 ) 95 | , ( 0x03cb10093ea62fb3f6e5680a128d07112ee566f1b424558f2ec9d86892e13a80 96 | , 0x12e7bb50ae7e9e90f1765c073eb61c4be4956c424930233ce497d2722a458868 97 | , 0x006b1367547937ae71e2e9b55d2f90c90131f9e6784ce3de0eb314ec748871e7 ) 98 | , ( 0x1ffff572c53442c58809aeca02287839b11df1420deb0e99fde2baad8b86fa9c 99 | , 0x13aefd685e7739f9a8b4ccdbfc5ef9e566149af4d54d6b746058ea44cb422840 100 | , 0x1ea6c3ea93fe6f4ed0186941650de76ff94ab0e6e8a583996b67ba026dd2b7a5 ) 101 | , ( 0x288f120288f9225643de833c5c15e22aadd358132bbdc12c75109048a158c9f4 102 | , 0x0f638114cd7c781ab299e5233338b00cf2996df962347a00146a22103d9ad91a 103 | , 0x14eeca5fa2c18999ea25ddf44237d6ac3cb8757ea452f67e2590a46f7d5b1e4f ) 104 | , ( 0x102d1a099e8cd107dc056e72370e340b0316d237b72d99ef6261761f7eb2d61c 105 | , 0x0ef741fc2fcda50f207c759dbd844a4d630cc0e4062ca80f3ffba2cce2d3f51d 106 | , 0x0989b9f642485692a1f91a4b207db64f38ae545bf3e0622f3862967d27f563db ) 107 | , ( 0x1eb4d812c80ce04784a80c89fbcc5aab89db274c62602bdd30f3223655e6cf8a 108 | , 0x0124a9400253731facd46e21f41016aed69a79087f81665bc5d29a34e4e924dd 109 | , 0x2520bfa6b70e6ba7ad380aaf9015b71983868a9c53e66e685ed6e48692c185a8 ) 110 | , ( 0x1bd62b5bfa02667ac08d51d9e77bb3ab8dbd19e7a701442a20e23f7d3d6b28b4 111 | , 0x1ae2f0d09fffc6bb869ebc639484a7c2084cfa3c1f88a7440713b1b154e5f952 112 | , 0x0cd06e16a0d570c3799d800d92a25efbd44a795ed5b9114a28f5f869a57d9ba1 ) 113 | , ( 0x00691740e313922521fe8c4843355eff8de0f93d4f62df0fe48755b897881c39 114 | , 0x19903aa449fe9c27ee9c8320e6915b50c2822e61ce894be72b47a449c5705762 115 | , 0x126e801aae44016a35deceaa3eba6ccc341fa3c2a65ab3d021fcd39abd170e1b ) 116 | , ( 0x1b0a98be27b54ac9d5d72b94187c991c1872cb2c7777c0e880f439c133971e8d 117 | , 0x1e10a35afda2e5a173d4f3edecf29dacf51d8fac33d6bfb4088cc787ec647605 118 | , 0x1793cda85abe2782ea8e911ce92bab59a8c68e0dd561a57b064bb233f109cc57 ) 119 | ] 120 | 121 | -------------------------------------------------------------------------------- 122 | -------------------------------------------------------------------------------- /src/Test/Hash/SHA2.hs: -------------------------------------------------------------------------------- 1 | 2 | module Test.Hash.SHA2 where 3 | 4 | -------------------------------------------------------------------------------- 5 | 6 | import R1CS 7 | import Test.Runner 8 | import Vectors.SHA2 9 | 10 | -------------------------------------------------------------------------------- 11 | -- * tests for the version where the input is a sequence of bytes 12 | 13 | sha224_test :: SimpleHashTest 14 | sha224_test = MkGenericHashTest 15 | { __circomFile = "circuits/sha2/sha224/sha224_hash_bytes.circom" 16 | , __templateName = "Sha224_hash_bytes_digest" 17 | , __inputSignal = "inp_bytes" 18 | , __outputSignal = "hash_bytes" 19 | , __testCases = sha2_224_vectors 20 | } 21 | 22 | sha256_test :: SimpleHashTest 23 | sha256_test = MkGenericHashTest 24 | { __circomFile = "circuits/sha2/sha256/sha256_hash_bytes.circom" 25 | , __templateName = "Sha256_hash_bytes_digest" 26 | , __inputSignal = "inp_bytes" 27 | , __outputSignal = "hash_bytes" 28 | , __testCases = sha2_256_vectors 29 | } 30 | 31 | sha384_test :: SimpleHashTest 32 | sha384_test = MkGenericHashTest 33 | { __circomFile = "circuits/sha2/sha384/sha384_hash_bytes.circom" 34 | , __templateName = "Sha384_hash_bytes_digest" 35 | , __inputSignal = "inp_bytes" 36 | , __outputSignal = "hash_bytes" 37 | , __testCases = sha2_384_vectors 38 | } 39 | 40 | sha512_test :: SimpleHashTest 41 | sha512_test = MkGenericHashTest 42 | { __circomFile = "circuits/sha2/sha512/sha512_hash_bytes.circom" 43 | , __templateName = "Sha512_hash_bytes_digest" 44 | , __inputSignal = "inp_bytes" 45 | , __outputSignal = "hash_bytes" 46 | , __testCases = sha2_512_vectors 47 | } 48 | 49 | ---------------------------------------- 50 | 51 | runTests_SHA2_bytes :: Verbosity -> FilePath -> IO () 52 | runTests_SHA2_bytes verbosity rootDir = do 53 | 54 | putStrLn "running test for SHA2... (input = byte sequence versions)" 55 | 56 | runSimpleTestBytes verbosity rootDir sha224_test 57 | runSimpleTestBytes verbosity rootDir sha256_test 58 | runSimpleTestBytes verbosity rootDir sha384_test 59 | runSimpleTestBytes verbosity rootDir sha512_test 60 | 61 | -------------------------------------------------------------------------------- 62 | -- * tests for the version where the input is a sequence of bits 63 | 64 | sha224_test_bits :: SimpleHashTest 65 | sha224_test_bits = MkGenericHashTest 66 | { __circomFile = "circuits/sha2/sha224/sha224_hash_bits.circom" 67 | , __templateName = "Sha224_hash_bits_digest" 68 | , __inputSignal = "inp_bits" 69 | , __outputSignal = "hash_bytes" 70 | , __testCases = sha2_224_vectors 71 | } 72 | 73 | sha256_test_bits :: SimpleHashTest 74 | sha256_test_bits = MkGenericHashTest 75 | { __circomFile = "circuits/sha2/sha256/sha256_hash_bits.circom" 76 | , __templateName = "Sha256_hash_bits_digest" 77 | , __inputSignal = "inp_bits" 78 | , __outputSignal = "hash_bytes" 79 | , __testCases = sha2_256_vectors 80 | } 81 | 82 | sha384_test_bits :: SimpleHashTest 83 | sha384_test_bits = MkGenericHashTest 84 | { __circomFile = "circuits/sha2/sha384/sha384_hash_bits.circom" 85 | , __templateName = "Sha384_hash_bits_digest" 86 | , __inputSignal = "inp_bits" 87 | , __outputSignal = "hash_bytes" 88 | , __testCases = sha2_384_vectors 89 | } 90 | 91 | sha512_test_bits :: SimpleHashTest 92 | sha512_test_bits = MkGenericHashTest 93 | { __circomFile = "circuits/sha2/sha512/sha512_hash_bits.circom" 94 | , __templateName = "Sha512_hash_bits_digest" 95 | , __inputSignal = "inp_bits" 96 | , __outputSignal = "hash_bytes" 97 | , __testCases = sha2_512_vectors 98 | } 99 | 100 | ---------------------------------------- 101 | 102 | runTests_SHA2_bits :: Verbosity -> FilePath -> IO () 103 | runTests_SHA2_bits verbosity rootDir = do 104 | 105 | putStrLn "running test for SHA2... (input = bit sequence versions)" 106 | 107 | runSimpleTestBits verbosity rootDir sha224_test_bits 108 | runSimpleTestBits verbosity rootDir sha256_test_bits 109 | runSimpleTestBits verbosity rootDir sha384_test_bits 110 | runSimpleTestBits verbosity rootDir sha512_test_bits 111 | 112 | -------------------------------------------------------------------------------- 113 | -- * tests for the versions where the input is a single chunk 114 | 115 | sha256_test_chunk :: SimpleHashTest 116 | sha256_test_chunk = MkGenericHashTest 117 | { __circomFile = "circuits/sha2/sha256/sha256_hash_chunk.circom" 118 | , __templateName = "Sha256_hash_chunk" 119 | , __inputSignal = "inp_bits" 120 | , __outputSignal = "out_bits" 121 | , __testCases = sha2_256_vectors 122 | } 123 | 124 | sha512_test_chunk :: SimpleHashTest 125 | sha512_test_chunk = MkGenericHashTest 126 | { __circomFile = "circuits/sha2/sha512/sha512_hash_chunk.circom" 127 | , __templateName = "Sha512_hash_chunk" 128 | , __inputSignal = "inp_bits" 129 | , __outputSignal = "out_bits" 130 | , __testCases = sha2_512_vectors 131 | } 132 | 133 | ---------------------------------------- 134 | 135 | runTests_SHA2_chunk :: Verbosity -> FilePath -> IO () 136 | runTests_SHA2_chunk verbosity rootDir = do 137 | 138 | putStrLn "running test for SHA2... (input = single chunk version)" 139 | 140 | runChunkTest_SHA256 verbosity rootDir sha256_test_chunk 141 | runChunkTest_SHA512 verbosity rootDir sha512_test_chunk 142 | 143 | -------------------------------------------------------------------------------- 144 | -------------------------------------------------------------------------------- /circuits/blake2/blake2_common.circom: -------------------------------------------------------------------------------- 1 | 2 | pragma circom 2.0.0; 3 | 4 | //------------------------------------------------------------------------------ 5 | 6 | function Sigma(i0) { 7 | 8 | var out[16]; 9 | 10 | var sigma[160] = 11 | [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 12 | , 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 13 | , 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 14 | , 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 15 | , 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 16 | , 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 17 | , 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 18 | , 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 19 | , 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 20 | , 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 21 | ]; 22 | 23 | var i = i0 % 10; 24 | 25 | for(var j=0; j<16; j++) { out[j] = sigma[i*16+j]; } 26 | 27 | return out; 28 | } 29 | 30 | //------------------------------------------------------------------------------ 31 | // XOR 3 bits together 32 | 33 | template XOR3() { 34 | signal input x; 35 | signal input y; 36 | signal input z; 37 | signal output out; 38 | 39 | signal tmp <== y*z; 40 | out <== x * (1 - 2*y - 2*z + 4*tmp) + y + z - 2*tmp; 41 | } 42 | 43 | //------------------------------------------------------------------------------ 44 | // XOR 3 words together 45 | 46 | template XorWord3(n) { 47 | signal input x; 48 | signal input y; 49 | signal input z; 50 | signal output out_bits[n]; 51 | signal output out_word; 52 | 53 | component tb_x = ToBits(n); 54 | component tb_y = ToBits(n); 55 | component tb_z = ToBits(n); 56 | 57 | tb_x.inp <== x; 58 | tb_y.inp <== y; 59 | tb_z.inp <== z; 60 | 61 | component xor[n]; 62 | 63 | var acc = 0; 64 | for(var i=0; i out_bits[i]; 70 | acc += out_bits[i] * (2**i); 71 | } 72 | 73 | out_word <== acc; 74 | } 75 | 76 | //------------------------------------------------------------------------------ 77 | // XOR a word with a constant 78 | 79 | template XorWordConst(n, kst_word) { 80 | signal input inp_word; 81 | signal output out_bits[n]; 82 | signal output out_word; 83 | 84 | component tb = ToBits(n); 85 | tb.inp <== inp_word; 86 | 87 | var acc = 0; 88 | for(var i=0; i> i) & 1; 91 | out_bits[i] <== x + y - 2*x*y; 92 | acc += out_bits[i] * (2**i); 93 | } 94 | 95 | out_word <== acc; 96 | } 97 | 98 | //------------------------------------------------------------------------------ 99 | // decompose an n-bit number into bits 100 | 101 | template ToBits(n) { 102 | signal input inp; 103 | signal output out[n]; 104 | 105 | var sum = 0; 106 | for(var i=0; i> i) & 1; 108 | out[i] * (1-out[i]) === 0; 109 | sum += (1<> i) & 1; 127 | out_bits[i] * (1-out_bits[i]) === 0; 128 | sum += (1<> 32) & 1; 132 | u*(1-u) === 0; 133 | 134 | inp === sum + (1<<32)*u; 135 | out_word <== sum; 136 | } 137 | 138 | //------------------------------------------------------------------------------ 139 | // decompose a 34-bit number into the low 32 bits and the remaining 2 bits 140 | 141 | template Bits34() { 142 | signal input inp; 143 | signal output out_bits[32]; 144 | signal output out_word; 145 | signal u,v; 146 | 147 | var sum = 0; 148 | for(var i=0; i<32; i++) { 149 | out_bits[i] <-- (inp >> i) & 1; 150 | out_bits[i] * (1-out_bits[i]) === 0; 151 | sum += (1<> 32) & 1; 155 | v <-- (inp >> 33) & 1; 156 | u*(1-u) === 0; 157 | v*(1-v) === 0; 158 | 159 | inp === sum + (1<<32)*u + (1<<33)*v; 160 | out_word <== sum; 161 | } 162 | 163 | //------------------------------------------------------------------------------ 164 | // decompose a 65-bit number into the low 64 bits and the remaining 1 bit 165 | 166 | template Bits65() { 167 | signal input inp; 168 | signal output out_bits[64]; 169 | signal output out_word; 170 | signal u; 171 | 172 | var sum = 0; 173 | for(var i=0; i<64; i++) { 174 | out_bits[i] <-- (inp >> i) & 1; 175 | out_bits[i] * (1-out_bits[i]) === 0; 176 | sum += (1<> 64) & 1; 180 | u*(1-u) === 0; 181 | 182 | inp === sum + (1<<64)*u; 183 | out_word <== sum; 184 | } 185 | 186 | //------------------------------------------------------------------------------ 187 | // decompose a 66-bit number into the low 64 bits and the remaining 2 bit 188 | 189 | template Bits66() { 190 | signal input inp; 191 | signal output out_bits[64]; 192 | signal output out_word; 193 | signal u,v; 194 | 195 | var sum = 0; 196 | for(var i=0; i<64; i++) { 197 | out_bits[i] <-- (inp >> i) & 1; 198 | out_bits[i] * (1-out_bits[i]) === 0; 199 | sum += (1<> 64) & 1; 203 | v <-- (inp >> 65) & 1; 204 | u*(1-u) === 0; 205 | v*(1-v) === 0; 206 | 207 | inp === sum + (1<<64)*u + (1<<65)*v; 208 | out_word <== sum; 209 | } 210 | 211 | //------------------------------------------------------------------------------ -------------------------------------------------------------------------------- /circuits/griffin/griffin_perm.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | // 4 | // The Griffin permutation for bn128 and t=3 5 | // 6 | 7 | //------------------------------------------------------------------------------ 8 | // The S-box 9 | 10 | template Pow5() { 11 | signal input inp; 12 | signal output out; 13 | 14 | signal x2 <== inp*inp; 15 | signal x4 <== x2*x2; 16 | 17 | out <== inp*x4; 18 | } 19 | 20 | template PowInv5() { 21 | signal input inp; 22 | signal output out; 23 | 24 | var d_inv = 0x26b6a528b427b35493736af8679aad17535cb9d394945a0dcfe7f7a98ccccccd; 25 | out <-- (inp ** d_inv); 26 | 27 | // log("x = input = ",inp); 28 | // log("y = x^d_inv = ",out); 29 | // log("z = y^5 = ",out ** 5); 30 | 31 | component pow5 = Pow5(); 32 | pow5.inp <== out; 33 | pow5.out === inp; // note: x -> x^5 is a permutation, so this is enough 34 | } 35 | 36 | template Horst() { 37 | signal input inp; 38 | signal input y0; 39 | signal input y1; 40 | signal output out; 41 | 42 | var alpha = 0x146ecffb34a66316fae66609f78d1310bc14ad7208082ca7943afebb1da4aa4a; 43 | var beta = 0x2b568115d544c7e941eff6ccc935384619b0fb7d2c5ba6c078c34cf81697ee1c; 44 | 45 | signal u <== y0 + y1; 46 | signal u2 <== u*u; 47 | 48 | signal mult <== u2 + alpha*u + beta; 49 | out <== inp * mult; 50 | } 51 | 52 | template SBox() { 53 | signal input inp[3]; 54 | signal output out[3]; 55 | 56 | component nlin0 = PowInv5(); 57 | component nlin1 = Pow5(); 58 | component nlin2 = Horst(); 59 | 60 | nlin0.inp <== inp[0]; 61 | nlin0.out ==> out[0]; 62 | 63 | nlin1.inp <== inp[1]; 64 | nlin1.out ==> out[1]; 65 | 66 | nlin2.inp <== inp[2]; 67 | nlin2.y0 <== out[0]; 68 | nlin2.y1 <== out[1]; 69 | nlin2.out ==> out[2]; 70 | } 71 | 72 | //------------------------------------------------------------------------------ 73 | // the linear stuff 74 | 75 | template AddRC(i) { 76 | 77 | signal input inp[3]; 78 | signal output out[3]; 79 | 80 | var round_consts[36] = 81 | [ 0 82 | , 0 83 | , 0 84 | , 0x2fb30cafdb1f76156dfabf0cd0af4b895e764ac2a84386c9d0d7aed6a7f4eac9 85 | , 0x282927892ce324572f19abb14871d2b539a80d8a5800cdb87a81e1697a94b6c9 86 | , 0x03d0f3f2711dd59e3d97fc797261300cd3fee33b95cf710a32edf42aa2bc0905 87 | , 0x036a8b3eb9ef35c74ea5a367ed279ee6d043d4ff69817f192c7251b91dcbb03d 88 | , 0x2a626d396e7fa8ce8d6339bb37bd48491d56db0c7ac0afb5008a7464d5776a26 89 | , 0x0cc9dfabbeaef7982543453ea3ac37ef2bfefd35a7e7070aa39b021035852d5b 90 | , 0x2a1951149e2568ab28e972a2ceddc49eff0cae8e1cddcf4b0684a73a1b4ef61b 91 | , 0x2d0ff8e9158b2fd7ae3afe01cf09d4ce9ff81e6127e441eb6cbc79d21f22be9e 92 | , 0x1cc315b7ea0c1efb538f0c3248a7da062309a9e41af5a555c9ea9e8a10930cb5 93 | , 0x03cb10093ea62fb3f6e5680a128d07112ee566f1b424558f2ec9d86892e13a80 94 | , 0x12e7bb50ae7e9e90f1765c073eb61c4be4956c424930233ce497d2722a458868 95 | , 0x006b1367547937ae71e2e9b55d2f90c90131f9e6784ce3de0eb314ec748871e7 96 | , 0x1ffff572c53442c58809aeca02287839b11df1420deb0e99fde2baad8b86fa9c 97 | , 0x13aefd685e7739f9a8b4ccdbfc5ef9e566149af4d54d6b746058ea44cb422840 98 | , 0x1ea6c3ea93fe6f4ed0186941650de76ff94ab0e6e8a583996b67ba026dd2b7a5 99 | , 0x288f120288f9225643de833c5c15e22aadd358132bbdc12c75109048a158c9f4 100 | , 0x0f638114cd7c781ab299e5233338b00cf2996df962347a00146a22103d9ad91a 101 | , 0x14eeca5fa2c18999ea25ddf44237d6ac3cb8757ea452f67e2590a46f7d5b1e4f 102 | , 0x102d1a099e8cd107dc056e72370e340b0316d237b72d99ef6261761f7eb2d61c 103 | , 0x0ef741fc2fcda50f207c759dbd844a4d630cc0e4062ca80f3ffba2cce2d3f51d 104 | , 0x0989b9f642485692a1f91a4b207db64f38ae545bf3e0622f3862967d27f563db 105 | , 0x1eb4d812c80ce04784a80c89fbcc5aab89db274c62602bdd30f3223655e6cf8a 106 | , 0x0124a9400253731facd46e21f41016aed69a79087f81665bc5d29a34e4e924dd 107 | , 0x2520bfa6b70e6ba7ad380aaf9015b71983868a9c53e66e685ed6e48692c185a8 108 | , 0x1bd62b5bfa02667ac08d51d9e77bb3ab8dbd19e7a701442a20e23f7d3d6b28b4 109 | , 0x1ae2f0d09fffc6bb869ebc639484a7c2084cfa3c1f88a7440713b1b154e5f952 110 | , 0x0cd06e16a0d570c3799d800d92a25efbd44a795ed5b9114a28f5f869a57d9ba1 111 | , 0x00691740e313922521fe8c4843355eff8de0f93d4f62df0fe48755b897881c39 112 | , 0x19903aa449fe9c27ee9c8320e6915b50c2822e61ce894be72b47a449c5705762 113 | , 0x126e801aae44016a35deceaa3eba6ccc341fa3c2a65ab3d021fcd39abd170e1b 114 | , 0x1b0a98be27b54ac9d5d72b94187c991c1872cb2c7777c0e880f439c133971e8d 115 | , 0x1e10a35afda2e5a173d4f3edecf29dacf51d8fac33d6bfb4088cc787ec647605 116 | , 0x1793cda85abe2782ea8e911ce92bab59a8c68e0dd561a57b064bb233f109cc57 117 | ]; 118 | 119 | out[0] <== inp[0] + round_consts[3*i+0]; 120 | out[1] <== inp[1] + round_consts[3*i+1]; 121 | out[2] <== inp[2] + round_consts[3*i+2]; 122 | } 123 | 124 | template LinearLayer() { 125 | signal input inp[3]; 126 | signal output out[3]; 127 | out[0] <== 2*inp[0] + inp[1] + inp[2]; 128 | out[1] <== inp[0] + 2*inp[1] + inp[2]; 129 | out[2] <== inp[0] + inp[1] + 2*inp[2]; 130 | } 131 | 132 | //------------------------------------------------------------------------------ 133 | // full round function 134 | 135 | template RoundFun(i) { 136 | signal input inp[3]; 137 | signal output out[3]; 138 | 139 | signal aux1[3]; 140 | signal auz2[3]; 141 | 142 | component rc = AddRC(i); 143 | component sbox = SBox(); 144 | component mds = LinearLayer(); 145 | 146 | rc.inp <== inp; 147 | rc.out ==> sbox.inp; 148 | sbox.out ==> mds.inp; 149 | mds.out ==> out; 150 | } 151 | 152 | //------------------------------------------------------------------------------ 153 | 154 | // the Griffin permutation 155 | template Permutation() { 156 | signal input inp[3]; 157 | signal output out[3]; 158 | 159 | signal aux[13][3]; 160 | 161 | component lin = LinearLayer(); 162 | lin.inp <== inp; 163 | lin.out ==> aux[0]; 164 | 165 | component rfun[12]; 166 | for(var i=0; i<12; i++) { 167 | rfun[i] = RoundFun(i); 168 | rfun[i].inp <== aux[i]; 169 | rfun[i].out ==> aux[i+1]; 170 | } 171 | 172 | out <== aux[12]; 173 | } 174 | 175 | //------------------------------------------------------------------------------ 176 | 177 | // the "compression function" takes 2 field elements as input and produces 178 | // 1 field element as output. It is a trivial application of the permutation. 179 | template Compression() { 180 | signal input inp[2]; 181 | signal output out; 182 | 183 | component perm = Permutation(); 184 | perm.inp[0] <== inp[0]; 185 | perm.inp[1] <== inp[1]; 186 | perm.inp[2] <== 0; 187 | 188 | perm.out[0] ==> out; 189 | } 190 | 191 | //------------------------------------------------------------------------------ 192 | 193 | -------------------------------------------------------------------------------- /src/Ref/Poseidon2/Zikkurat/RoundConsts.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | BN254 (or alt-bn-128) prime, and t=3 3 | 4 | module Ref.Poseidon2.Zikkurat.RoundConsts where 5 | 6 | -------------------------------------------------------------------------------- 7 | 8 | import ZK.Algebra.Curves.BN128.Fr.Mont 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | initialRoundConsts :: [(Fr,Fr,Fr)] 13 | initialRoundConsts = 14 | [ ( 0x2c4c51fd1bb9567c27e99f5712b49e0574178b41b6f0a476cddc41d242cf2b43 15 | , 0x1c5f8d18acb9c61ec6fcbfcda5356f1b3fdee7dc22c99a5b73a2750e5b054104 16 | , 0x2d3c1988b4541e4c045595b8d574e98a7c2820314a82e67a4e380f1c4541ba90 17 | ) 18 | , ( 0x052547dc9e6d936cab6680372f1734c39f490d0cb970e2077c82f7e4172943d3 19 | , 0x29d967f4002adcbb5a6037d644d36db91f591b088f69d9b4257694f5f9456bc2 20 | , 0x0350084b8305b91c426c25aeeecafc83fc5feec44b9636cb3b17d2121ec5b88a 21 | ) 22 | , ( 0x1815d1e52a8196127530cc1e79f07a0ccd815fb5d94d070631f89f6c724d4cbe 23 | , 0x17b5ba882530af5d70466e2b434b0ccb15b7a8c0138d64455281e7724a066272 24 | , 0x1c859b60226b443767b73cd1b08823620de310bc49ea48662626014cea449aee 25 | ) 26 | , ( 0x1b26e7f0ac7dd8b64c2f7a1904c958bb48d2635478a90d926f5ff2364effab37 27 | , 0x2da7f36850e6c377bdcdd380efd9e7c419555d3062b0997952dfbe5c54b1a22e 28 | , 0x17803c56450e74bc6c7ff97275390c017f682db11f3f4ca6e1f714efdfb9bd66 29 | ) 30 | ] 31 | 32 | internalRoundConsts :: [Fr] 33 | internalRoundConsts = 34 | [ 0x15ce7e5ae220e8623a40b3a3b22d441eff0c9be1ae1d32f1b777af84eea7e38c 35 | , 0x1bf60ac8bfff0f631983c93e218ca0d4a4059c254b4299b1d9984a07edccfaf0 36 | , 0x0fab0c9387cb2bec9dc11b2951088b9e1e1d2978542fc131f74a8f8fdac95b40 37 | , 0x07d085a48750738019784663bccd460656dc62c1b18964a0d27a5bd0c27ee453 38 | , 0x10d57b1fad99da9d3fe16cf7f5dae05be844f67b2e7db3472a2e96e167578bc4 39 | , 0x0c36c40f7bd1934b7d5525031467aa39aeaea461996a70eda5a2a704e1733bb0 40 | , 0x0e4b65a0f3e1f9d3166a2145063c999bd08a4679676d765f4d11f97ed5c080ae 41 | , 0x1ce5561061120d5c7ea09da2528c4c041b9ad0f05d655f38b10d79878b69f29d 42 | , 0x2d323f651c3da8f0e0754391a10fa111b25dfa00471edf5493c44dfc3f28add6 43 | , 0x05a0741ee5bdc3e099fd6bdad9a0865bc9ceecd13ea4e702e536dd370b8f1953 44 | , 0x176a2ec4746fc0e0eca9e5e11d6facaee05524a92e5785c8b8161780a4435136 45 | , 0x0691faf0f42a9ed97629b1ae0dc7f1b019c06dd852cb6efe57f7eeb1aa865aef 46 | , 0x0e46cf138dad09d61b9a7cab95a23b5c8cb276874f3715598bacb55d5ad271de 47 | , 0x0f18c3d95bac1ac424160d240cdffc2c44f7b6315ba65ed3ff2eff5b3e48b4f2 48 | , 0x2eea6af14b592ec45a4119ac1e6e6f0312ecd090a096e340d472283e543ddff7 49 | , 0x06b0d7a8f4ce97d049ae994139f5f71dca4899d4f1cd3dd83a32a89a58c0a8e6 50 | , 0x019df0b9828eed5892dd55c1ad6408196f6293d600ef4491703a1b37e119ba8e 51 | , 0x08ca5e3c93817cdb1c2b2a12d02c779d74c1bb12b6668f3ab3ddd7837f3a4a00 52 | , 0x28382d747e3fd6cb2e0d8e8edd79c5313eed307a3517c11046245b1476e4f701 53 | , 0x0ca89aecd5675b77c8271765da98cfcb6875b3053d4742c9ff502861bd16ad28 54 | , 0x19046bc0b03ca90802ec83f212001e7ffd7f9224cfffae523451deb52eab3787 55 | , 0x036fd7dfa1c05110b3428e6abcc43e1de9abba915320c4a600f843bfb676ca51 56 | , 0x08f0a7abcb1a2f6595a9b7380c5028e3999db4fe5cb21892e5bb5cb11a7757ba 57 | , 0x0b614acc1ce3fbe9048f8385e4ee24c3843deea186bacea3c904c9f6340ad8cb 58 | , 0x00b2d98c5d988f9b41f2c98e017fc954a6ae423b2261575941f8eac8835d985c 59 | , 0x1457f18555b7973ba5b311d57ec5d77e936980b97f5973875f1f7cc765a4fc95 60 | , 0x002b453debc1bee525cb751bc10641a6b86f847d696418cf1144950982591bfa 61 | , 0x0c2af1abcc6ece77218315d2af445ccbfc6647b7af2510682882cc792c6bb8cf 62 | , 0x0e2825d9eb84b59902a1adb49ac0c2c291dee7c45d2e8c30369a4d595039e8ad 63 | , 0x297e2e86a8c672d39f3343b8dfce7a6f20f3571bfd5c8a28e3905aa2dcfeca44 64 | , 0x00d397281d902e49ec6504ba9186e806db9ad4fc8f86e7277aa7f1467eb6f9de 65 | , 0x2fb7c89c372d7e2050e7377ed471000c73544a2b9fd66557f3577c09cac98b4b 66 | , 0x16125247be4387a8c3e62490167f0cffdba02eda4f018d0b40639a13bb0cfef9 67 | , 0x2291fd9d442f2d9b97ab22f7d4d52c2a82e41f852cf620b144612650a39e26e8 68 | , 0x1eec61f16a275ae238540feaeeadfec56d32171b1cc393729d06f37f476fde71 69 | , 0x259ce871ba5dacbb48d8aed3d8513eef51558dc0b360f28c1a15dbfc5e7f6ca2 70 | , 0x2d3376a14ddbf95587e2f7567ff04fe13a3c7cb17363c8b9c5dd1d9262a210cb 71 | , 0x13b843d9f65f4cddd7ce10d9cad9b8b99ac5e9a8c4269288173a91c0f3c3b084 72 | , 0x0b52e9b2f1aa9fd204e4a42c481cc76c704783e34114b8e93e026a50fa9764e8 73 | , 0x1fd083229276c7f27d3ad941476b394ff37bd44d3a1e9caca1400d9077a2056c 74 | , 0x22743c328a6283f3ba7379af22c684c498568fd7ad9fad5151368c913197cbd9 75 | , 0x043007aefd9741070d95caaaba0c1b070e4eec8eef8c1e512c8e579c6ed64f76 76 | , 0x17ab175144f64bc843074f6b3a0c57c5dd2c954af8723c029ee642539496a7b3 77 | , 0x2befcad3d53fba5eeef8cae9668fed5c1e9e596a46e8458e218f7a665fddf4eb 78 | , 0x15151c4116d97de74bfa6ca3178f73c8fe8fe612c70c6f85a7a1551942cb71cc 79 | , 0x2ac40bf6c3176300a6835d5fc7cc4fd5e5d299fb1baa86487268ec1b9eedfa97 80 | , 0x0f151de1f01b4e24ffe04279318f0a68efabb485188f191e37e6915ff6059f6e 81 | , 0x2e43dffc34537535182aebac1ad7bf0a5533b88f65f9652f0ad584e2ffc4dd1f 82 | , 0x2ebabc2c37ef53d8b13b24a2a2b729d536735f58956125a3876da0664c2442d7 83 | , 0x0dc3beceb34e49f5ad7226dd202c5cf879dffcc9a6dd32a300e8f2a4b59edf03 84 | , 0x2f1ddeccce83adf68779c53b639871a8f81d4d00aefe1e812efce8ec999d457d 85 | , 0x1f63e41280ff5c021715d52b19780298ed8bd3d5eb506316b527e24149d4d4f1 86 | , 0x1b8c1252a5888f8cb2672effb5df49c633d3fd7183271488a1c40d0f88e7636e 87 | , 0x0f45697130f5498e2940568ef0d5e9e16b1095a6cdbb6411df20a973c605e70b 88 | , 0x0780ccc403cdd68983acbd34cda41cacfb2cf911a93076bc25587b4b0aed4929 89 | , 0x238d26ca97c691591e929f32199a643550f325f23a85d420080b289d7cecc9d4 90 | ] 91 | 92 | finalRoundConsts :: [(Fr,Fr,Fr)] 93 | finalRoundConsts = 94 | [ ( 0x25672a14b5d085e31a30a7e1d5675ebfab034fb04dc2ec5e544887523f98dede 95 | , 0x0cf702434b891e1b2f1d71883506d68cdb1be36fa125674a3019647b3a98accd 96 | , 0x1837e75235ff5d112a5eddf7a4939448748339e7b5f2de683cf0c0ae98bdfbb3 97 | ) 98 | , ( 0x1cd8a14cff3a61f04197a083c6485581a7d836941f6832704837a24b2d15613a 99 | , 0x266f6d85be0cef2ece525ba6a54b647ff789785069882772e6cac8131eecc1e4 100 | , 0x0538fde2183c3f5833ecd9e07edf30fe977d28dd6f246d7960889d9928b506b3 101 | ) 102 | , ( 0x07a0693ff41476abb4664f3442596aa8399fdccf245d65882fce9a37c268aa04 103 | , 0x11eb49b07d33de2bd60ea68e7f652beda15644ed7855ee5a45763b576d216e8e 104 | , 0x08f8887da6ce51a8c06041f64e22697895f34bacb8c0a39ec12bf597f7c67cfc 105 | ) 106 | , ( 0x2a912ec610191eb7662f86a52cc64c0122bd5ba762e1db8da79b5949fdd38092 107 | , 0x2031d7fd91b80857aa1fef64e23cfad9a9ba8fe8c8d09de92b1edb592a44c290 108 | , 0x0f81ebce43c47711751fa64d6c007221016d485641c28c507d04fd3dc7fba1d2 109 | ) 110 | ] 111 | 112 | -------------------------------------------------------------------------------- 113 | 114 | -------------------------------------------------------------------------------- /src/Ref/Poseidon2/Naive/RoundConsts.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | BN256 prime, and t = 3 3 | 4 | module Ref.Poseidon2.Naive.RoundConsts where 5 | 6 | -------------------------------------------------------------------------------- 7 | 8 | import Ref.Poseidon2.Naive.BN256 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | matDiag3 :: [[BN256]] 13 | matDiag3 = 14 | [ [1,0,0] 15 | , [0,1,0] 16 | , [0,0,2] 17 | ] 18 | 19 | matInternal3 :: [[BN256]] 20 | matInternal3 = 21 | [ [2,1,1] 22 | , [1,2,1] 23 | , [1,1,3] 24 | ] 25 | 26 | initialRoundConsts :: [(BN256,BN256,BN256)] 27 | initialRoundConsts = 28 | [ ( 0x2c4c51fd1bb9567c27e99f5712b49e0574178b41b6f0a476cddc41d242cf2b43 29 | , 0x1c5f8d18acb9c61ec6fcbfcda5356f1b3fdee7dc22c99a5b73a2750e5b054104 30 | , 0x2d3c1988b4541e4c045595b8d574e98a7c2820314a82e67a4e380f1c4541ba90 31 | ) 32 | , ( 0x052547dc9e6d936cab6680372f1734c39f490d0cb970e2077c82f7e4172943d3 33 | , 0x29d967f4002adcbb5a6037d644d36db91f591b088f69d9b4257694f5f9456bc2 34 | , 0x0350084b8305b91c426c25aeeecafc83fc5feec44b9636cb3b17d2121ec5b88a 35 | ) 36 | , ( 0x1815d1e52a8196127530cc1e79f07a0ccd815fb5d94d070631f89f6c724d4cbe 37 | , 0x17b5ba882530af5d70466e2b434b0ccb15b7a8c0138d64455281e7724a066272 38 | , 0x1c859b60226b443767b73cd1b08823620de310bc49ea48662626014cea449aee 39 | ) 40 | , ( 0x1b26e7f0ac7dd8b64c2f7a1904c958bb48d2635478a90d926f5ff2364effab37 41 | , 0x2da7f36850e6c377bdcdd380efd9e7c419555d3062b0997952dfbe5c54b1a22e 42 | , 0x17803c56450e74bc6c7ff97275390c017f682db11f3f4ca6e1f714efdfb9bd66 43 | ) 44 | ] 45 | 46 | internalRoundConsts :: [BN256] 47 | internalRoundConsts = 48 | [ 0x15ce7e5ae220e8623a40b3a3b22d441eff0c9be1ae1d32f1b777af84eea7e38c 49 | , 0x1bf60ac8bfff0f631983c93e218ca0d4a4059c254b4299b1d9984a07edccfaf0 50 | , 0x0fab0c9387cb2bec9dc11b2951088b9e1e1d2978542fc131f74a8f8fdac95b40 51 | , 0x07d085a48750738019784663bccd460656dc62c1b18964a0d27a5bd0c27ee453 52 | , 0x10d57b1fad99da9d3fe16cf7f5dae05be844f67b2e7db3472a2e96e167578bc4 53 | , 0x0c36c40f7bd1934b7d5525031467aa39aeaea461996a70eda5a2a704e1733bb0 54 | , 0x0e4b65a0f3e1f9d3166a2145063c999bd08a4679676d765f4d11f97ed5c080ae 55 | , 0x1ce5561061120d5c7ea09da2528c4c041b9ad0f05d655f38b10d79878b69f29d 56 | , 0x2d323f651c3da8f0e0754391a10fa111b25dfa00471edf5493c44dfc3f28add6 57 | , 0x05a0741ee5bdc3e099fd6bdad9a0865bc9ceecd13ea4e702e536dd370b8f1953 58 | , 0x176a2ec4746fc0e0eca9e5e11d6facaee05524a92e5785c8b8161780a4435136 59 | , 0x0691faf0f42a9ed97629b1ae0dc7f1b019c06dd852cb6efe57f7eeb1aa865aef 60 | , 0x0e46cf138dad09d61b9a7cab95a23b5c8cb276874f3715598bacb55d5ad271de 61 | , 0x0f18c3d95bac1ac424160d240cdffc2c44f7b6315ba65ed3ff2eff5b3e48b4f2 62 | , 0x2eea6af14b592ec45a4119ac1e6e6f0312ecd090a096e340d472283e543ddff7 63 | , 0x06b0d7a8f4ce97d049ae994139f5f71dca4899d4f1cd3dd83a32a89a58c0a8e6 64 | , 0x019df0b9828eed5892dd55c1ad6408196f6293d600ef4491703a1b37e119ba8e 65 | , 0x08ca5e3c93817cdb1c2b2a12d02c779d74c1bb12b6668f3ab3ddd7837f3a4a00 66 | , 0x28382d747e3fd6cb2e0d8e8edd79c5313eed307a3517c11046245b1476e4f701 67 | , 0x0ca89aecd5675b77c8271765da98cfcb6875b3053d4742c9ff502861bd16ad28 68 | , 0x19046bc0b03ca90802ec83f212001e7ffd7f9224cfffae523451deb52eab3787 69 | , 0x036fd7dfa1c05110b3428e6abcc43e1de9abba915320c4a600f843bfb676ca51 70 | , 0x08f0a7abcb1a2f6595a9b7380c5028e3999db4fe5cb21892e5bb5cb11a7757ba 71 | , 0x0b614acc1ce3fbe9048f8385e4ee24c3843deea186bacea3c904c9f6340ad8cb 72 | , 0x00b2d98c5d988f9b41f2c98e017fc954a6ae423b2261575941f8eac8835d985c 73 | , 0x1457f18555b7973ba5b311d57ec5d77e936980b97f5973875f1f7cc765a4fc95 74 | , 0x002b453debc1bee525cb751bc10641a6b86f847d696418cf1144950982591bfa 75 | , 0x0c2af1abcc6ece77218315d2af445ccbfc6647b7af2510682882cc792c6bb8cf 76 | , 0x0e2825d9eb84b59902a1adb49ac0c2c291dee7c45d2e8c30369a4d595039e8ad 77 | , 0x297e2e86a8c672d39f3343b8dfce7a6f20f3571bfd5c8a28e3905aa2dcfeca44 78 | , 0x00d397281d902e49ec6504ba9186e806db9ad4fc8f86e7277aa7f1467eb6f9de 79 | , 0x2fb7c89c372d7e2050e7377ed471000c73544a2b9fd66557f3577c09cac98b4b 80 | , 0x16125247be4387a8c3e62490167f0cffdba02eda4f018d0b40639a13bb0cfef9 81 | , 0x2291fd9d442f2d9b97ab22f7d4d52c2a82e41f852cf620b144612650a39e26e8 82 | , 0x1eec61f16a275ae238540feaeeadfec56d32171b1cc393729d06f37f476fde71 83 | , 0x259ce871ba5dacbb48d8aed3d8513eef51558dc0b360f28c1a15dbfc5e7f6ca2 84 | , 0x2d3376a14ddbf95587e2f7567ff04fe13a3c7cb17363c8b9c5dd1d9262a210cb 85 | , 0x13b843d9f65f4cddd7ce10d9cad9b8b99ac5e9a8c4269288173a91c0f3c3b084 86 | , 0x0b52e9b2f1aa9fd204e4a42c481cc76c704783e34114b8e93e026a50fa9764e8 87 | , 0x1fd083229276c7f27d3ad941476b394ff37bd44d3a1e9caca1400d9077a2056c 88 | , 0x22743c328a6283f3ba7379af22c684c498568fd7ad9fad5151368c913197cbd9 89 | , 0x043007aefd9741070d95caaaba0c1b070e4eec8eef8c1e512c8e579c6ed64f76 90 | , 0x17ab175144f64bc843074f6b3a0c57c5dd2c954af8723c029ee642539496a7b3 91 | , 0x2befcad3d53fba5eeef8cae9668fed5c1e9e596a46e8458e218f7a665fddf4eb 92 | , 0x15151c4116d97de74bfa6ca3178f73c8fe8fe612c70c6f85a7a1551942cb71cc 93 | , 0x2ac40bf6c3176300a6835d5fc7cc4fd5e5d299fb1baa86487268ec1b9eedfa97 94 | , 0x0f151de1f01b4e24ffe04279318f0a68efabb485188f191e37e6915ff6059f6e 95 | , 0x2e43dffc34537535182aebac1ad7bf0a5533b88f65f9652f0ad584e2ffc4dd1f 96 | , 0x2ebabc2c37ef53d8b13b24a2a2b729d536735f58956125a3876da0664c2442d7 97 | , 0x0dc3beceb34e49f5ad7226dd202c5cf879dffcc9a6dd32a300e8f2a4b59edf03 98 | , 0x2f1ddeccce83adf68779c53b639871a8f81d4d00aefe1e812efce8ec999d457d 99 | , 0x1f63e41280ff5c021715d52b19780298ed8bd3d5eb506316b527e24149d4d4f1 100 | , 0x1b8c1252a5888f8cb2672effb5df49c633d3fd7183271488a1c40d0f88e7636e 101 | , 0x0f45697130f5498e2940568ef0d5e9e16b1095a6cdbb6411df20a973c605e70b 102 | , 0x0780ccc403cdd68983acbd34cda41cacfb2cf911a93076bc25587b4b0aed4929 103 | , 0x238d26ca97c691591e929f32199a643550f325f23a85d420080b289d7cecc9d4 104 | ] 105 | 106 | finalRoundConsts :: [(BN256,BN256,BN256)] 107 | finalRoundConsts = 108 | [ ( 0x25672a14b5d085e31a30a7e1d5675ebfab034fb04dc2ec5e544887523f98dede 109 | , 0x0cf702434b891e1b2f1d71883506d68cdb1be36fa125674a3019647b3a98accd 110 | , 0x1837e75235ff5d112a5eddf7a4939448748339e7b5f2de683cf0c0ae98bdfbb3 111 | ) 112 | , ( 0x1cd8a14cff3a61f04197a083c6485581a7d836941f6832704837a24b2d15613a 113 | , 0x266f6d85be0cef2ece525ba6a54b647ff789785069882772e6cac8131eecc1e4 114 | , 0x0538fde2183c3f5833ecd9e07edf30fe977d28dd6f246d7960889d9928b506b3 115 | ) 116 | , ( 0x07a0693ff41476abb4664f3442596aa8399fdccf245d65882fce9a37c268aa04 117 | , 0x11eb49b07d33de2bd60ea68e7f652beda15644ed7855ee5a45763b576d216e8e 118 | , 0x08f8887da6ce51a8c06041f64e22697895f34bacb8c0a39ec12bf597f7c67cfc 119 | ) 120 | , ( 0x2a912ec610191eb7662f86a52cc64c0122bd5ba762e1db8da79b5949fdd38092 121 | , 0x2031d7fd91b80857aa1fef64e23cfad9a9ba8fe8c8d09de92b1edb592a44c290 122 | , 0x0f81ebce43c47711751fa64d6c007221016d485641c28c507d04fd3dc7fba1d2 123 | ) 124 | ] 125 | 126 | 127 | -------------------------------------------------------------------------------- /circuits/sha2/sha2_common.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | //------------------------------------------------------------------------------ 4 | // decompose a 2-bit number into a high and a low bit 5 | 6 | template Bits2() { 7 | signal input xy; 8 | signal output lo; 9 | signal output hi; 10 | 11 | lo <-- xy & 1; 12 | hi <-- (xy>>1) & 1; 13 | 14 | lo*(1-lo) === 0; 15 | hi*(1-hi) === 0; 16 | 17 | xy === 2*hi + lo; 18 | } 19 | 20 | //------------------------------------------------------------------------------ 21 | // XOR 3 bits together 22 | 23 | template XOR3_v1() { 24 | signal input x; 25 | signal input y; 26 | signal input z; 27 | signal output out; 28 | 29 | component bs = Bits2(); 30 | bs.xy <== x + y + z; 31 | bs.lo ==> out; 32 | } 33 | 34 | //------------------ 35 | // same number of constraints (that is, 2), in the general case 36 | // however circom can optimize y=0 or z=0, unlike with the above 37 | // and hopefully also x=0. 38 | 39 | template XOR3_v2() { 40 | signal input x; 41 | signal input y; 42 | signal input z; 43 | signal output out; 44 | 45 | signal tmp <== y*z; 46 | out <== x * (1 - 2*y - 2*z + 4*tmp) + y + z - 2*tmp; 47 | } 48 | 49 | //------------------------------------------------------------------------------ 50 | // decompose an n-bit number into bits 51 | 52 | template ToBits(n) { 53 | signal input inp; 54 | signal output out[n]; 55 | 56 | var sum = 0; 57 | for(var i=0; i> i) & 1; 59 | out[i] * (1-out[i]) === 0; 60 | sum += (1<> i) & 1; 78 | out_bits[i] * (1-out_bits[i]) === 0; 79 | sum += (1<> 32) & 1; 83 | u*(1-u) === 0; 84 | 85 | inp === sum + (1<<32)*u; 86 | out_word <== sum; 87 | } 88 | 89 | //------------------------------------------------------------------------------ 90 | // decompose a 34-bit number into the low 32 bits and the remaining 2 bits 91 | 92 | template Bits34() { 93 | signal input inp; 94 | signal output out_bits[32]; 95 | signal output out_word; 96 | signal u,v; 97 | 98 | var sum = 0; 99 | for(var i=0; i<32; i++) { 100 | out_bits[i] <-- (inp >> i) & 1; 101 | out_bits[i] * (1-out_bits[i]) === 0; 102 | sum += (1<> 32) & 1; 106 | v <-- (inp >> 33) & 1; 107 | u*(1-u) === 0; 108 | v*(1-v) === 0; 109 | 110 | inp === sum + (1<<32)*u + (1<<33)*v; 111 | out_word <== sum; 112 | } 113 | 114 | //------------------------------------------------------------------------------ 115 | // decompose a 35-bit number into the low 32 bits and the remaining 3 bits 116 | 117 | template Bits35() { 118 | signal input inp; 119 | signal output out_bits[32]; 120 | signal output out_word; 121 | signal u,v,w; 122 | 123 | var sum = 0; 124 | for(var i=0; i<32; i++) { 125 | out_bits[i] <-- (inp >> i) & 1; 126 | out_bits[i] * (1-out_bits[i]) === 0; 127 | sum += (1<> 32) & 1; 131 | v <-- (inp >> 33) & 1; 132 | w <-- (inp >> 34) & 1; 133 | u*(1-u) === 0; 134 | v*(1-v) === 0; 135 | w*(1-w) === 0; 136 | 137 | inp === sum + (1<<32)*u + (1<<33)*v + (1<<34)*w; 138 | out_word <== sum; 139 | } 140 | 141 | //------------------------------------------------------------------------------ 142 | // decompose a 65-bit number into the low 64 bits and the remaining 1 bit 143 | 144 | template Bits65() { 145 | signal input inp; 146 | signal output out_bits[64]; 147 | signal output out_word; 148 | signal u; 149 | 150 | var sum = 0; 151 | for(var i=0; i<64; i++) { 152 | out_bits[i] <-- (inp >> i) & 1; 153 | out_bits[i] * (1-out_bits[i]) === 0; 154 | sum += (1<> 64) & 1; 158 | u*(1-u) === 0; 159 | 160 | inp === sum + (1<<64)*u; 161 | out_word <== sum; 162 | } 163 | 164 | //------------------------------------------------------------------------------ 165 | // decompose a 66-bit number into the low 64 bits and the remaining 2 bit 166 | 167 | template Bits66() { 168 | signal input inp; 169 | signal output out_bits[64]; 170 | signal output out_word; 171 | signal u,v; 172 | 173 | var sum = 0; 174 | for(var i=0; i<64; i++) { 175 | out_bits[i] <-- (inp >> i) & 1; 176 | out_bits[i] * (1-out_bits[i]) === 0; 177 | sum += (1<> 64) & 1; 181 | v <-- (inp >> 65) & 1; 182 | u*(1-u) === 0; 183 | v*(1-v) === 0; 184 | 185 | inp === sum + (1<<64)*u + (1<<65)*v; 186 | out_word <== sum; 187 | } 188 | 189 | 190 | //------------------------------------------------------------------------------ 191 | // decompose a 67-bit number into the low 64 bits and the remaining 3 bit 192 | 193 | template Bits67() { 194 | signal input inp; 195 | signal output out_bits[64]; 196 | signal output out_word; 197 | signal u,v,w; 198 | 199 | var sum = 0; 200 | for(var i=0; i<64; i++) { 201 | out_bits[i] <-- (inp >> i) & 1; 202 | out_bits[i] * (1-out_bits[i]) === 0; 203 | sum += (1<> 64) & 1; 207 | v <-- (inp >> 65) & 1; 208 | w <-- (inp >> 66) & 1; 209 | u*(1-u) === 0; 210 | v*(1-v) === 0; 211 | w*(1-w) === 0; 212 | 213 | inp === sum + (1<<64)*u + (1<<65)*v + (1<<66)*w; 214 | out_word <== sum; 215 | } 216 | 217 | //------------------------------------------------------------------------------ 218 | // converts a sequence of `n` big-endian 32-bit words to `4n` bytes 219 | // (to be compatible with the output hex string of standard SHA2 tools) 220 | 221 | template DWordsToByteString(n) { 222 | 223 | signal input inp[n][32]; 224 | signal output out[4*n]; 225 | 226 | for(var k=0; k 5 | 6 | {-# LANGUAGE BangPatterns, TypeApplications, FlexibleInstances #-} 7 | module Ref.Blake2.BLAKE2s where 8 | 9 | -------------------------------------------------------------------------------- 10 | 11 | import Data.Array 12 | import Data.Word 13 | import Data.Bits 14 | import Data.Char 15 | import Data.List hiding (partition) 16 | 17 | import Ref.Common 18 | 19 | -------------------------------------------------------------------------------- 20 | 21 | kk = 0 -- key bytes 22 | nn = 32 -- output bytes 23 | 24 | -------------------------------------------------------------------------------- 25 | 26 | paramBlock :: [Word32] 27 | paramBlock = p0 : replicate 7 0 where 28 | p0 = nn + shiftL kk 8 + shiftL 0x0101 16 29 | 30 | -- IV[i] = floor(2**w * frac(sqrt(prime(i+1)))), where prime(i) 31 | -- is the i:th prime number ( 2, 3, 5, 7, 11, 13, 17, 19 ) 32 | -- and sqrt(x) is the square root of x. 33 | initializationVector :: [Word32] 34 | initializationVector = 35 | [ 0x6A09E667 , 0xBB67AE85 , 0x3C6EF372 , 0xA54FF53A 36 | , 0x510E527F , 0x9B05688C , 0x1F83D9AB , 0x5BE0CD19 37 | ] 38 | 39 | type SigmaVec = Array Int Int 40 | 41 | sigma :: [SigmaVec] 42 | sigma = map (listArray (0,15)) sigma' 43 | 44 | sigma' :: [[Int]] 45 | sigma' = 46 | [ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ] 47 | , [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ] 48 | , [ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ] 49 | , [ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ] 50 | , [ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ] 51 | , [ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ] 52 | , [ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ] 53 | , [ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ] 54 | , [ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ] 55 | , [ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ] 56 | ] 57 | 58 | -- an index between 0..15 59 | type Idx = Int 60 | 61 | -- an index between 0..7 62 | type Jdx = Int 63 | 64 | -- | Array of 16 words 65 | type WorkVec = Array Idx Word32 66 | 67 | -- | Array of 8 words 68 | type StateVec = Array Jdx Word32 69 | 70 | -------------------------------------------------------------------------------- 71 | 72 | -- rotation constants 73 | _R1 = 16 74 | _R2 = 12 75 | _R3 = 8 76 | _R4 = 7 77 | 78 | mixingFunG :: WorkVec -> (Idx,Idx,Idx,Idx) -> (Word32,Word32) -> WorkVec 79 | mixingFunG v0 (a,b,c,d) (x,y) = {- debug "G" (toHexString $ elems v8) -} v8 where 80 | 81 | v1 = op1 v0 82 | v2 = op2 v1 83 | v3 = op3 v2 84 | v4 = op4 v3 85 | v5 = op5 v4 86 | v6 = op6 v5 87 | v7 = op7 v6 88 | v8 = op8 v7 89 | 90 | replace v i y = v // [(i,y)] 91 | 92 | op1 v = replace v a $ v!a + v!b + x 93 | op2 v = replace v d $ rotateR (v!d `xor` v!a) _R1 94 | op3 v = replace v c $ v!c + v!d 95 | op4 v = replace v b $ rotateR (v!b `xor` v!c) _R2 96 | op5 v = replace v a $ v!a + v!b + y 97 | op6 v = replace v d $ rotateR (v!d `xor` v!a) _R3 98 | op7 v = replace v c $ v!c + v!d 99 | op8 v = replace v b $ rotateR (v!b `xor` v!c) _R4 100 | 101 | -------------------------------------------------------------------------------- 102 | 103 | -- | compression function inputs: 104 | -- 105 | -- * h = state (8 words) 106 | -- 107 | -- * m = current message block (16 words) 108 | -- 109 | -- * t = offset 110 | -- 111 | -- * f = final block flag 112 | -- 113 | compressionF :: StateVec -> WorkVec -> Word64 -> Bool -> StateVec 114 | compressionF !h !m !t !f = h' where 115 | 116 | v0 = listArray (0,15) (elems h ++ initializationVector) 117 | v1 = v0 // [ (12, v0!12 `xor` fromIntegral t ) 118 | , (13, v0!13 `xor` fromIntegral (shiftR t 32) ) ] 119 | v = if f then v1 // [ (14, complement (v1!14)) ] 120 | else v1 121 | 122 | rounds :: [WorkVec -> WorkVec] 123 | rounds = [ singleRound m i | i<-[0..9] ] 124 | 125 | tenRounds :: WorkVec -> WorkVec 126 | tenRounds = foldr (.) id (reverse rounds) 127 | 128 | v' = tenRounds v 129 | 130 | h' = listArray (0,7) [ h!i `xor` v'!i `xor` v'!(i+8) | i<-[0..7] ] 131 | 132 | -------------------------------------------------------------------------------- 133 | 134 | singleRound :: WorkVec -> Int -> WorkVec -> WorkVec 135 | singleRound msg i = singleRound' msg (sigma!!i) 136 | 137 | singleRound' :: WorkVec -> SigmaVec -> WorkVec -> WorkVec 138 | singleRound' m s v0 = v8 where 139 | v1 = mixingFunG v0 (0, 4, 8, 12) ( m!(s! 0) , m!(s! 1) ) 140 | v2 = mixingFunG v1 (1, 5, 9, 13) ( m!(s! 2) , m!(s! 3) ) 141 | v3 = mixingFunG v2 (2, 6, 10, 14) ( m!(s! 4) , m!(s! 5) ) 142 | v4 = mixingFunG v3 (3, 7, 11, 15) ( m!(s! 6) , m!(s! 7) ) 143 | 144 | v5 = mixingFunG v4 (0, 5, 10, 15) ( m!(s! 8) , m!(s! 9) ) 145 | v6 = mixingFunG v5 (1, 6, 11, 12) ( m!(s!10) , m!(s!11) ) 146 | v7 = mixingFunG v6 (2, 7, 8, 13) ( m!(s!12) , m!(s!13) ) 147 | v8 = mixingFunG v7 (3, 4, 9, 14) ( m!(s!14) , m!(s!15) ) 148 | 149 | -------------------------------------------------------------------------------- 150 | 151 | foldWithIndexAndLast :: (Int -> Bool -> a -> b -> a) -> a -> [b] -> a 152 | foldWithIndexAndLast f = go 0 where 153 | go i x [] = x 154 | go i x [y] = f i True x y 155 | go i x (y:ys) = go (i+1) (f i False x y) ys 156 | 157 | blake2s__ :: String -> String 158 | blake2s__ = blake2s_ . map (fromIntegral . ord) 159 | 160 | blake2s_ :: [Word8] -> String 161 | blake2s_ = concatMap toHexStringLE . elems . blake2s 162 | 163 | blake2s :: [Word8] -> StateVec 164 | blake2s msg = finalHash where 165 | 166 | finalHash = foldWithIndexAndLast g h0 (messageToBlocks msg) 167 | 168 | h0 = listArray (0,7) $ zipWith xor initializationVector paramBlock 169 | ll = length msg 170 | 171 | g i False h m = compressionF h m (fromIntegral (i+1) * 64 ) False 172 | g i True h m = compressionF h m (fromIntegral $ if kk==0 then ll else ll+64) True 173 | 174 | -------------------------------------------------------------------------------- 175 | 176 | -- | partitions a list into blocks of the given size 177 | partition :: Int -> a -> [a] -> [[a]] 178 | partition k x0 = go where 179 | go [] = [] 180 | go xs = case drop k xs of 181 | [] -> [ take k (xs ++ repeat x0) ] 182 | rest -> take k xs : go rest 183 | 184 | -- | converts 64 bytes to 16 little-endian words 185 | bytesToWordBlock :: [Word8] -> WorkVec 186 | bytesToWordBlock = listArray (0,15) . map toWord32 . partition 4 0 187 | 188 | toWord32 :: [Word8] -> Word32 189 | toWord32 [a,b,c,d] = fromIntegral a 190 | + shiftL (fromIntegral b) 8 191 | + shiftL (fromIntegral c) 16 192 | + shiftL (fromIntegral d) 24 193 | toWord32 _ = error "toWord32" 194 | 195 | -- Note: 196 | -- 197 | -- "However, in the special case of an unkeyed empty message (kk = 0 and 198 | -- ll = 0), we still set dd = 1 and d[0] consists of all zeros." 199 | messageToBlocks :: [Word8] -> [WorkVec] 200 | messageToBlocks [] = [ listArray (0,15) (replicate 16 0) ] 201 | messageToBlocks ws = (map bytesToWordBlock . partition 64 0) ws 202 | 203 | -------------------------------------------------------------------------------- 204 | 205 | {- 206 | testinput = "abc" 207 | -- testinput = "abcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijkl" 208 | -- testinput = "abcdefghijklmnopabcdefghijklmnopabcdefghijklmnopabcdefghijklmnopabcdefghijklmnop" 209 | 210 | testmain = do 211 | let input_str = testinput 212 | let input = map (fromIntegral . ord) input_str 213 | let !hash = blake2s_ input 214 | putStrLn $ "input len = " ++ show (length input_str) 215 | putStrLn $ "input = " ++ show input_str 216 | putStrLn $ "final hash = " ++ hash 217 | -} 218 | -------------------------------------------------------------------------------- /src/Ref/Blake2/BLAKE2b.hs: -------------------------------------------------------------------------------- 1 | 2 | -- | BLAKE2b-256 hash function, (slow) reference implementation. 3 | -- 4 | -- See 5 | 6 | {-# LANGUAGE BangPatterns, TypeApplications, FlexibleInstances, NumericUnderscores #-} 7 | module Ref.Blake2.BLAKE2b where 8 | 9 | -------------------------------------------------------------------------------- 10 | 11 | import Data.Array 12 | import Data.Word 13 | import Data.Bits 14 | import Data.Char 15 | import Data.List hiding (partition) 16 | 17 | import Ref.Common 18 | 19 | -------------------------------------------------------------------------------- 20 | 21 | kk = 0 -- key bytes 22 | nn = 32 -- output bytes 23 | 24 | -------------------------------------------------------------------------------- 25 | 26 | paramBlock :: [Word64] 27 | paramBlock = p0 : replicate 7 0 where 28 | p0 = nn + shiftL kk 8 + shiftL 0x0101 16 29 | 30 | -- IV[i] = floor(2**w * frac(sqrt(prime(i+1)))), where prime(i) 31 | -- is the i:th prime number ( 2, 3, 5, 7, 11, 13, 17, 19 ) 32 | -- and sqrt(x) is the square root of x. 33 | initializationVector :: [Word64] 34 | initializationVector = 35 | [ 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B 36 | , 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1 37 | , 0x510E527FADE682D1, 0x9B05688C2B3E6C1F 38 | , 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179 39 | ] 40 | 41 | type SigmaVec = Array Int Int 42 | 43 | sigma :: [SigmaVec] 44 | sigma = map (listArray (0,15)) sigma' 45 | 46 | sigma' :: [[Int]] 47 | sigma' = 48 | [ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ] 49 | , [ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 ] 50 | , [ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 ] 51 | , [ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 ] 52 | , [ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 ] 53 | , [ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 ] 54 | , [ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 ] 55 | , [ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 ] 56 | , [ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 ] 57 | , [ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 ] 58 | ] 59 | 60 | -- an index between 0..15 61 | type Idx = Int 62 | 63 | -- an index between 0..7 64 | type Jdx = Int 65 | 66 | -- | Array of 16 words 67 | type WorkVec = Array Idx Word64 68 | 69 | -- | Array of 8 words 70 | type StateVec = Array Jdx Word64 71 | 72 | -------------------------------------------------------------------------------- 73 | 74 | -- rotation constants 75 | _R1 = 32 76 | _R2 = 24 77 | _R3 = 16 78 | _R4 = 63 79 | 80 | mixingFunG :: WorkVec -> (Idx,Idx,Idx,Idx) -> (Word64,Word64) -> WorkVec 81 | mixingFunG v0 (a,b,c,d) (x,y) = v8 where 82 | 83 | v1 = op1 v0 84 | v2 = op2 v1 85 | v3 = op3 v2 86 | v4 = op4 v3 87 | v5 = op5 v4 88 | v6 = op6 v5 89 | v7 = op7 v6 90 | v8 = op8 v7 91 | 92 | replace v i y = v // [(i,y)] 93 | 94 | op1 v = replace v a $ v!a + v!b + x 95 | op2 v = replace v d $ rotateR (v!d `xor` v!a) _R1 96 | op3 v = replace v c $ v!c + v!d 97 | op4 v = replace v b $ rotateR (v!b `xor` v!c) _R2 98 | op5 v = replace v a $ v!a + v!b + y 99 | op6 v = replace v d $ rotateR (v!d `xor` v!a) _R3 100 | op7 v = replace v c $ v!c + v!d 101 | op8 v = replace v b $ rotateR (v!b `xor` v!c) _R4 102 | 103 | -------------------------------------------------------------------------------- 104 | 105 | -- | compression function inputs: 106 | -- 107 | -- * h = state (8 qwords) 108 | -- 109 | -- * m = current message block (16 qwords) 110 | -- 111 | -- * t = offset 112 | -- 113 | -- * f = final block flag 114 | -- 115 | compressionF :: StateVec -> WorkVec -> Word64 -> Bool -> StateVec 116 | compressionF !h !m !t !f = h' where 117 | 118 | v0 = listArray (0,15) (elems h ++ initializationVector) 119 | v1 = v0 // [ (12, v0!12 `xor` fromIntegral t ) 120 | , (13, v0!13 `xor` fromIntegral (shiftR t 64) ) ] 121 | v = if f then v1 // [ (14, complement (v1!14)) ] 122 | else v1 123 | 124 | rounds :: [WorkVec -> WorkVec] 125 | rounds = [ singleRound m i | i<-[0..11] ] 126 | 127 | tenRounds :: WorkVec -> WorkVec 128 | tenRounds = foldr (.) id (reverse rounds) 129 | 130 | v' = tenRounds v 131 | 132 | h' = listArray (0,7) [ h!i `xor` v'!i `xor` v'!(i+8) | i<-[0..7] ] 133 | 134 | -------------------------------------------------------------------------------- 135 | 136 | singleRound :: WorkVec -> Int -> WorkVec -> WorkVec 137 | singleRound msg i = singleRound' msg (sigma !! (mod i 10)) 138 | 139 | singleRound' :: WorkVec -> SigmaVec -> WorkVec -> WorkVec 140 | singleRound' m s v0 = v8 where 141 | v1 = mixingFunG v0 (0, 4, 8, 12) ( m!(s! 0) , m!(s! 1) ) 142 | v2 = mixingFunG v1 (1, 5, 9, 13) ( m!(s! 2) , m!(s! 3) ) 143 | v3 = mixingFunG v2 (2, 6, 10, 14) ( m!(s! 4) , m!(s! 5) ) 144 | v4 = mixingFunG v3 (3, 7, 11, 15) ( m!(s! 6) , m!(s! 7) ) 145 | 146 | v5 = mixingFunG v4 (0, 5, 10, 15) ( m!(s! 8) , m!(s! 9) ) 147 | v6 = mixingFunG v5 (1, 6, 11, 12) ( m!(s!10) , m!(s!11) ) 148 | v7 = mixingFunG v6 (2, 7, 8, 13) ( m!(s!12) , m!(s!13) ) 149 | v8 = mixingFunG v7 (3, 4, 9, 14) ( m!(s!14) , m!(s!15) ) 150 | 151 | -------------------------------------------------------------------------------- 152 | 153 | foldWithIndexAndLast :: (Int -> Bool -> a -> b -> a) -> a -> [b] -> a 154 | foldWithIndexAndLast f = go 0 where 155 | go i x [] = x 156 | go i x [y] = f i True x y 157 | go i x (y:ys) = go (i+1) (f i False x y) ys 158 | 159 | blake2b__ :: String -> String 160 | blake2b__ = blake2b_ . map (fromIntegral . ord) 161 | 162 | blake2b_ :: [Word8] -> String 163 | blake2b_ = concatMap toHexStringLE . take (fromIntegral $ div nn 8) . elems . blake2b 164 | 165 | blake2b :: [Word8] -> StateVec 166 | blake2b msg = finalHash where 167 | 168 | finalHash = foldWithIndexAndLast g h0 (messageToBlocks msg) 169 | 170 | h0 = listArray (0,7) $ zipWith xor initializationVector paramBlock 171 | ll = length msg 172 | 173 | g i False h m = compressionF h m (fromIntegral (i+1) * 128 ) False 174 | g i True h m = compressionF h m (fromIntegral $ if kk==0 then ll else ll+128) True 175 | 176 | -------------------------------------------------------------------------------- 177 | 178 | -- | partitions a list into blocks of the given size 179 | partition :: Int -> a -> [a] -> [[a]] 180 | partition k x0 = go where 181 | go [] = [] 182 | go xs = case drop k xs of 183 | [] -> [ take k (xs ++ repeat x0) ] 184 | rest -> take k xs : go rest 185 | 186 | -- | converts 64 bytes to 16 little-endian words 187 | bytesToWordBlock :: [Word8] -> WorkVec 188 | bytesToWordBlock = listArray (0,15) . map toWord64 . partition 8 0 189 | 190 | toWord64 :: [Word8] -> Word64 191 | toWord64 [a,b,c,d,e,f,g,h] 192 | = fromIntegral a 193 | + shiftL (fromIntegral b) 8 194 | + shiftL (fromIntegral c) 16 195 | + shiftL (fromIntegral d) 24 196 | + shiftL (fromIntegral e) 32 197 | + shiftL (fromIntegral f) 40 198 | + shiftL (fromIntegral g) 48 199 | + shiftL (fromIntegral h) 56 200 | toWord64 _ = error "toWord64" 201 | 202 | -- Note: 203 | -- 204 | -- "However, in the special case of an unkeyed empty message (kk = 0 and 205 | -- ll = 0), we still set dd = 1 and d[0] consists of all zeros." 206 | -- 207 | messageToBlocks :: [Word8] -> [WorkVec] 208 | messageToBlocks [] = [ listArray (0,15) (replicate 16 0) ] 209 | messageToBlocks ws = (map bytesToWordBlock . partition 128 0) ws 210 | 211 | -------------------------------------------------------------------------------- 212 | 213 | {- 214 | -- testinput = "abc" 215 | testinput = "abcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijkl" 216 | -- testinput = "abcdefghijklmnopabcdefghijklmnopabcdefghijklmnopabcdefghijklmnopabcdefghijklmnop" 217 | 218 | testmain = do 219 | let input_str = testinput 220 | let input = map (fromIntegral . ord) input_str 221 | let !hash = blake2b_ input 222 | putStrLn $ "input len = " ++ show (length input_str) 223 | putStrLn $ "input = " ++ show input_str 224 | putStrLn $ "final hash = " ++ hash 225 | -} 226 | -------------------------------------------------------------------------------- /circuits/blake2/blake2s.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "blake2_common.circom"; 4 | 5 | //------------------------------------------------------------------------------ 6 | 7 | template IV() { 8 | signal output out[8]; 9 | 10 | var initializationVector[8] = 11 | [ 0x6A09E667 , 0xBB67AE85 , 0x3C6EF372 , 0xA54FF53A 12 | , 0x510E527F , 0x9B05688C , 0x1F83D9AB , 0x5BE0CD19 13 | ]; 14 | 15 | for(var j=0; j<8; j++) { out[j] <== initializationVector[j]; } 16 | } 17 | 18 | //------------------------------------------------------------------------------ 19 | // XOR-s two 32-bit vectors and then rotates the result right by the given amount of bits 20 | 21 | template RotXorBits(R) { 22 | signal input inp1_bits[32]; 23 | signal input inp2_bits[32]; 24 | signal output out_bits[32]; 25 | signal output out_word; 26 | 27 | signal aux[32]; 28 | for(var i=0; i<32; i++) { 29 | aux[i] <== inp1_bits[i] + inp2_bits[i] - 2 * inp1_bits[i] * inp2_bits[i]; 30 | } 31 | 32 | var acc = 0; 33 | for(var i=0; i<32; i++) { 34 | out_bits[i] <== aux[ (i+R) % 32 ]; 35 | acc += out_bits[i] * (2**i); 36 | } 37 | 38 | out_word <== acc; 39 | } 40 | 41 | //-------------------------------------- 42 | // XOR-s a 32-bit word with a bit-vector 43 | // and then rotates the result right by the given amount of bits 44 | 45 | template RotXorWordBits(R) { 46 | signal input inp1_word; 47 | signal input inp2_bits[32]; 48 | signal output out_bits[32]; 49 | signal output out_word; 50 | 51 | component tb = ToBits(32); 52 | component rx = RotXorBits(R); 53 | 54 | tb.inp <== inp1_word; 55 | tb.out ==> rx.inp1_bits; 56 | inp2_bits ==> rx.inp2_bits; 57 | out_bits <== rx.out_bits; 58 | out_word <== rx.out_word; 59 | } 60 | 61 | //------------------------------------------------------------------------------ 62 | 63 | template HalfFunG(a,b,c,d, R1,R2) { 64 | signal input v[16]; 65 | signal input xy; 66 | signal output out[16]; 67 | 68 | for(var i=0; i<16; i++) { 69 | if ((i!=a) && (i!=b) && (i!=c) && (i!=d)) { 70 | out[i] <== v[i]; 71 | } 72 | } 73 | 74 | component add1 = Bits34(); // sum of three words needs 34 bits 75 | component add3 = Bits33(); // sum of two words only needs 33 bits 76 | 77 | component rxor2 = RotXorWordBits(R1); 78 | component rxor4 = RotXorWordBits(R2); 79 | 80 | add1.inp <== v[a] + v[b] + xy; 81 | v[d] ==> rxor2.inp1_word; 82 | add1.out_bits ==> rxor2.inp2_bits; 83 | add3.inp <== v[c] + rxor2.out_word; 84 | v[b] ==> rxor4.inp1_word; 85 | add3.out_bits ==> rxor4.inp2_bits; 86 | 87 | out[a] <== add1.out_word; 88 | out[d] <== rxor2.out_word; 89 | out[c] <== add3.out_word; 90 | out[b] <== rxor4.out_word; 91 | 92 | /* 93 | | v[a] := (v[a] + v[b] + xy) mod 2**w 94 | | v[d] := (v[d] ^ v[a]) >>> R1 95 | | v[c] := (v[c] + v[d]) mod 2**w 96 | | v[b] := (v[b] ^ v[c]) >>> R2 97 | */ 98 | 99 | } 100 | 101 | //------------------------------------------------------------------------------ 102 | // the mixing function G 103 | 104 | // inputs and output and x,y consists of 32 bit words 105 | template MixFunG(a,b,c,d) { 106 | signal input inp[16]; 107 | signal output out[16]; 108 | signal input x; 109 | signal input y; 110 | 111 | component half1 = HalfFunG(a,b,c,d, 16,12); 112 | component half2 = HalfFunG(a,b,c,d, 8, 7); 113 | 114 | half1.v <== inp; 115 | half1.xy <== x; 116 | half1.out ==> half2.v; 117 | half2.xy <== y; 118 | half2.out ==> out; 119 | 120 | /* 121 | | v[a] := (v[a] + v[b] + x) mod 2**w 122 | | v[d] := (v[d] ^ v[a]) >>> R1 123 | | v[c] := (v[c] + v[d]) mod 2**w 124 | | v[b] := (v[b] ^ v[c]) >>> R2 125 | 126 | | v[a] := (v[a] + v[b] + y) mod 2**w 127 | | v[d] := (v[d] ^ v[a]) >>> R3 128 | | v[c] := (v[c] + v[d]) mod 2**w 129 | | v[b] := (v[b] ^ v[c]) >>> R4 130 | */ 131 | 132 | 133 | // for(var i=0; i<16; i++) { 134 | // log("mixfun_output[", i, "] = ", out[i]); 135 | // } 136 | 137 | } 138 | 139 | //------------------------------------------------------------------------------ 140 | // a single round 141 | 142 | template SingleRound(round_idx) { 143 | signal input inp[16]; 144 | signal input msg[16]; 145 | signal output out[16]; 146 | 147 | var s[16]; 148 | s = Sigma(round_idx); 149 | 150 | component GS[8]; 151 | 152 | signal vs[9][16]; 153 | 154 | inp ==> vs[0]; 155 | 156 | GS[0] = MixFunG( 0 , 4 , 8 , 12 ) ; GS[0].x <== msg[s[ 0]] ; GS[0].y <== msg[s[ 1]] ; 157 | GS[1] = MixFunG( 1 , 5 , 9 , 13 ) ; GS[1].x <== msg[s[ 2]] ; GS[1].y <== msg[s[ 3]] ; 158 | GS[2] = MixFunG( 2 , 6 , 10 , 14 ) ; GS[2].x <== msg[s[ 4]] ; GS[2].y <== msg[s[ 5]] ; 159 | GS[3] = MixFunG( 3 , 7 , 11 , 15 ) ; GS[3].x <== msg[s[ 6]] ; GS[3].y <== msg[s[ 7]] ; 160 | 161 | GS[4] = MixFunG( 0 , 5 , 10 , 15 ) ; GS[4].x <== msg[s[ 8]] ; GS[4].y <== msg[s[ 9]] ; 162 | GS[5] = MixFunG( 1 , 6 , 11 , 12 ) ; GS[5].x <== msg[s[10]] ; GS[5].y <== msg[s[11]] ; 163 | GS[6] = MixFunG( 2 , 7 , 8 , 13 ) ; GS[6].x <== msg[s[12]] ; GS[6].y <== msg[s[13]] ; 164 | GS[7] = MixFunG( 3 , 4 , 9 , 14 ) ; GS[7].x <== msg[s[14]] ; GS[7].y <== msg[s[15]] ; 165 | 166 | for(var i=0; i<8; i++) { 167 | GS[i].inp <== vs[i]; 168 | GS[i].out ==> vs[i+1]; 169 | } 170 | 171 | out <== vs[8]; 172 | 173 | // for(var i=0; i<16; i++) { 174 | // log("round_output[", i, "] = ", out[i]); 175 | // } 176 | 177 | } 178 | 179 | //------------------------------------------------------------------------------ 180 | // the compression function F 181 | // 182 | // t is the offset counter 183 | // f should be 1 for the final block and 0 otherwise 184 | // 185 | template CompressionF(t,f) { 186 | signal input h[8]; // the state (8 words) 187 | signal input m[16]; // the message block (16 words) 188 | signal output out[8]; // new state 189 | 190 | component iv = IV(); 191 | signal init[16]; 192 | 193 | for(var i=0; i<8; i++) { init[i ] <== h[i]; } 194 | for(var i=0; i<8; i++) { init[i+8] <== iv.out[i]; } 195 | 196 | signal vs[11][16]; 197 | 198 | component xor1 = XorWordConst( 32 , t & 0xFFFFFFFF ); 199 | component xor2 = XorWordConst( 32 , t >> 32 ); 200 | component xor3 = XorWordConst( 32 , (f==0) ? 0 : 0xFFFFFFFF ); 201 | 202 | for(var i=0; i<12; i++) { vs[0][i] <== init[i]; } 203 | xor1.inp_word <== init[12]; xor1.out_word ==> vs[0][12]; 204 | xor2.inp_word <== init[13]; xor2.out_word ==> vs[0][13]; 205 | xor3.inp_word <== init[14]; xor3.out_word ==> vs[0][14]; 206 | vs[0][15] <== init[15]; 207 | 208 | component rounds[10]; 209 | 210 | for(var i=0; i<10; i++) { 211 | rounds[i] = SingleRound(i); 212 | rounds[i].msg <== m; 213 | rounds[i].inp <== vs[i]; 214 | rounds[i].out ==> vs[i+1]; 215 | } 216 | 217 | component fin[8]; 218 | for(var i=0; i<8; i++) { 219 | fin[i] = XorWord3(32); 220 | fin[i].x <== h[i]; 221 | fin[i].y <== vs[10][i]; 222 | fin[i].z <== vs[10][i+8]; 223 | fin[i].out_word ==> out[i]; 224 | } 225 | 226 | // for(var i=0; i<8; i++) { 227 | // log("compress_out[", i, "] = ", out[i]); 228 | // } 229 | 230 | } 231 | 232 | //------------------------------------------------------------------------------ 233 | // hash a sequence of `ll` bytes 234 | 235 | template Blake2s_bytes(ll) { 236 | signal input inp_bytes[ll]; 237 | signal output hash_words[8]; 238 | signal output hash_bytes[32]; 239 | signal output hash_bits[256]; 240 | 241 | var kk = 0; // key size in bytes 242 | var nn = 32; // final hash size in bytes 243 | var dd = (ll + 63) \ 64; // number of message blocks 244 | 245 | signal blocks[dd][16]; // message blocks 246 | 247 | var p0 = 0x01010000 ^ (kk << 8) ^ nn; 248 | 249 | signal hs[dd+1][8]; 250 | 251 | component iv = IV(); 252 | hs[0][0] <== (0x6A09E667 ^ p0); 253 | for(var i=1; i<8; i++) { hs[0][i] <== iv.out[i]; } 254 | 255 | component compr[dd]; 256 | 257 | for(var k=0; k hs[k+1]; 275 | } 276 | 277 | hs[dd] ==> hash_words; 278 | 279 | component tbs[8]; 280 | for(var j=0; j<8; j++) { 281 | tbs[j] = ToBits(32); 282 | tbs[j].inp <== hash_words[j]; 283 | for(var i=0; i<32; i++) { 284 | tbs[j].out[i] ==> hash_bits[j*32+i]; 285 | } 286 | } 287 | 288 | for(var j=0; j<32; j++) { 289 | var acc = 0; 290 | for(var i=0; i<8; i++) { acc += hash_bits[j*8+i] * (2**i); } 291 | hash_bytes[j] <== acc; 292 | } 293 | 294 | // for(var i=0; i<32; i++) { 295 | // log("hash[",i,"] = ",hash_bytes[i]); 296 | // } 297 | 298 | } 299 | 300 | //------------------------------------------------------------------------------ 301 | 302 | --------------------------------------------------------------------------------