From 5e733121d582575a60e9d2f8256ad4fd6ae8f425 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Wed, 7 Feb 2024 11:49:57 +0100 Subject: [PATCH 01/13] circuit: remove unused includes --- circuit/merkle.circom | 1 - circuit/single_cell.circom | 2 -- 2 files changed, 3 deletions(-) diff --git a/circuit/merkle.circom b/circuit/merkle.circom index beab67b..833edd0 100644 --- a/circuit/merkle.circom +++ b/circuit/merkle.circom @@ -1,7 +1,6 @@ pragma circom 2.0.0; include "poseidon2_perm.circom"; -include "poseidon2_hash.circom"; include "misc.circom"; diff --git a/circuit/single_cell.circom b/circuit/single_cell.circom index 9d3bf4e..21c206d 100644 --- a/circuit/single_cell.circom +++ b/circuit/single_cell.circom @@ -1,10 +1,8 @@ pragma circom 2.0.0; -include "poseidon2_perm.circom"; include "poseidon2_hash.circom"; include "merkle.circom"; -include "misc.circom"; //------------------------------------------------------------------------------ From 2b88a00fb0df67acb8bc506bc0e408838496a48b Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Thu, 8 Feb 2024 13:39:21 +0100 Subject: [PATCH 02/13] circuit: remove unused functions --- circuit/misc.circom | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/circuit/misc.circom b/circuit/misc.circom index c120261..286f924 100644 --- a/circuit/misc.circom +++ b/circuit/misc.circom @@ -1,16 +1,5 @@ pragma circom 2.0.0; -//------------------------------------------------------------------------------ -// compute (compile time) the log2 of a number - -function FloorLog2(n) { - return (n==0) ? -1 : (1 + FloorLog2(n>>1)); -} - -function CeilLog2(n) { - return (n==0) ? 0 : (1 + FloorLog2(n-1)); -} - //------------------------------------------------------------------------------ // decompose an n-bit number into bits From bbc97a796a2ae677db7118fc6af7efaca77a9e07 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Thu, 8 Feb 2024 13:40:44 +0100 Subject: [PATCH 03/13] circuit: remove trailing spaces --- circuit/binary_compare.circom | 14 +++++++------- circuit/extract_bits.circom | 10 +++++----- circuit/log2.circom | 16 ++++++++-------- circuit/merkle.circom | 8 ++++---- circuit/misc.circom | 4 ++-- circuit/poseidon2_perm.circom | 20 ++++++++++---------- circuit/poseidon2_sponge.circom | 10 +++++----- circuit/sample_cells.circom | 14 +++++++------- 8 files changed, 48 insertions(+), 48 deletions(-) diff --git a/circuit/binary_compare.circom b/circuit/binary_compare.circom index b88b9be..9de09ea 100644 --- a/circuit/binary_compare.circom +++ b/circuit/binary_compare.circom @@ -3,8 +3,8 @@ pragma circom 2.0.0; //------------------------------------------------------------------------------ // -// given two numbers in `n`-bit binary decomposition (little-endian), we compute -// +// given two numbers in `n`-bit binary decomposition (little-endian), we compute +// // / -1 if A < B // out := { 0 if A == B // \ +1 if A > B @@ -12,7 +12,7 @@ pragma circom 2.0.0; // NOTE: we don't check that the digits are indeed binary; // that's the responsibility of the caller! // -// This version uses `(3*n-1)` nonlinear constraints. +// This version uses `(3*n-1)` nonlinear constraints. // Question: can we do better? (note that this has to work with n >= 254 digits too!) // @@ -42,11 +42,11 @@ template BinaryCompare(n) { //------------------------------------------------------------------------------ // -// given two numbers in `n`-bit binary decomposition (little-endian), we compute +// given two numbers in `n`-bit binary decomposition (little-endian), we compute // // out := (A <= B) ? 1 : 0 // -// NOTE: we don't check that the digits are indeed binary; +// NOTE: we don't check that the digits are indeed binary; // that's the responsibility of the caller! // @@ -69,11 +69,11 @@ template BinaryLessOrEqual(n) { //------------------------------------------------------------------------------ // -// given two numbers in `n`-bit binary decomposition (little-endian), we compute +// given two numbers in `n`-bit binary decomposition (little-endian), we compute // // out := (A >= B) ? 1 : 0 // -// NOTE: we don't check that the digits are indeed binary; +// NOTE: we don't check that the digits are indeed binary; // that's the responsibility of the caller! // diff --git a/circuit/extract_bits.circom b/circuit/extract_bits.circom index 6b28e6e..41d14bf 100644 --- a/circuit/extract_bits.circom +++ b/circuit/extract_bits.circom @@ -5,12 +5,12 @@ include "misc.circom"; //------------------------------------------------------------------------------ -// +// // extract the lowest `n` bits from a field element. // -// NOTE: this is rather nontrivial, as everything is computed modulo `r`, +// NOTE: this is rather nontrivial, as everything is computed modulo `r`, // so naive bit decomposition does not work (there are multiple solutions). -// +// // TODO: optimize this // @@ -33,7 +33,7 @@ template ExtractLowerBits(n) { le.out === -1; // enforce `A < B`, that is, `bits < prime` // extract the lowest `n` bits - for(var i=0; i out[i]; } @@ -66,7 +66,7 @@ template ExtractLowerBits_testfield65537(n) { le.out === -1; // enforce `A < B`, that is, `bits < prime` // extract the lowest `n` bits - for(var i=0; i out[i]; } diff --git a/circuit/log2.circom b/circuit/log2.circom index a0a6150..0442796 100644 --- a/circuit/log2.circom +++ b/circuit/log2.circom @@ -3,7 +3,7 @@ pragma circom 2.0.0; include "misc.circom"; //------------------------------------------------------------------------------ -// +// // given an input `inp`, this template checks that inp == 2^out // with 0 < out <= n // @@ -13,14 +13,14 @@ include "misc.circom"; template Log2(n) { signal input inp; - signal output out; + signal output out; signal output mask[n+1]; // mask will be a vector [1,1,1,...1,0,...,0,0] // which can change only where inp == 2^out var log2 = -1; - for(var i=0; i<=n; i++) { + for(var i=0; i<=n; i++) { mask[i] <-- ((2**i) < inp) ? 1 : 0; if (2**i == inp) { log2 = i; } } @@ -31,17 +31,17 @@ template Log2(n) { mask[n] === 0; var sum = 0; - for(var i=0; i bits; signal aux[n+1]; diff --git a/circuit/merkle.circom b/circuit/merkle.circom index 833edd0..a13e316 100644 --- a/circuit/merkle.circom +++ b/circuit/merkle.circom @@ -25,7 +25,7 @@ include "misc.circom"; // template RootFromMerklePath( maxDepth ) { - + signal input leaf; signal input pathBits[ maxDepth ]; // bits of the linear index signal input lastBits[ maxDepth ]; // bits of the last linear index `= size-1` @@ -37,14 +37,14 @@ template RootFromMerklePath( maxDepth ) { signal aux[ maxDepth+1 ]; aux[0] <== leaf; - // compute which prefixes (in big-endian) of the index is + // compute which prefixes (in big-endian) of the index is // the same as the corresponding prefix of the last index component eq[ maxDepth ]; signal isLast[ maxDepth+1 ]; isLast[ maxDepth ] <== 1; for(var i=maxDepth-1; i>=0; i--) { eq[i] = IsEqual(); - eq[i].A <== pathBits[i]; + eq[i].A <== pathBits[i]; eq[i].B <== lastBits[i]; isLast[i] <== isLast[i+1] * eq[i].out; } @@ -63,7 +63,7 @@ template RootFromMerklePath( maxDepth ) { var R = merklePath[i]; // based on pathBits[i], we switch or not - + switch[i] <== (R-L) * pathBits[i]; comp[i].key <== bottom + 2*odd; comp[i].inp[0] <== L + switch[i]; diff --git a/circuit/misc.circom b/circuit/misc.circom index 286f924..3feb175 100644 --- a/circuit/misc.circom +++ b/circuit/misc.circom @@ -33,11 +33,11 @@ template IsZero() { out <== 1 - inp * inv; // enfore that either `inp` or `out` must be zero - inp*out === 0; + inp*out === 0; } //------------------------------------------------------------------------------ -// check equality of two field elements; that is, computes `(A==B) ? 1 : 0` +// check equality of two field elements; that is, computes `(A==B) ? 1 : 0` template IsEqual() { signal input A,B; diff --git a/circuit/poseidon2_perm.circom b/circuit/poseidon2_perm.circom index c518378..0348d56 100644 --- a/circuit/poseidon2_perm.circom +++ b/circuit/poseidon2_perm.circom @@ -1,7 +1,7 @@ pragma circom 2.0.0; // -// The Poseidon2 permutation for bn128 and t=3 +// The Poseidon2 permutation for bn128 and t=3 // //------------------------------------------------------------------------------ @@ -24,7 +24,7 @@ template InternalRound(i) { signal input inp[3]; signal output out[3]; - var round_consts[56] = + var round_consts[56] = [ 0x15ce7e5ae220e8623a40b3a3b22d441eff0c9be1ae1d32f1b777af84eea7e38c , 0x1bf60ac8bfff0f631983c93e218ca0d4a4059c254b4299b1d9984a07edccfaf0 , 0x0fab0c9387cb2bec9dc11b2951088b9e1e1d2978542fc131f74a8f8fdac95b40 @@ -99,11 +99,11 @@ template ExternalRound(i) { signal input inp[3]; signal output out[3]; - var round_consts[8][3] = + var round_consts[8][3] = [ [ 0x2c4c51fd1bb9567c27e99f5712b49e0574178b41b6f0a476cddc41d242cf2b43 , 0x1c5f8d18acb9c61ec6fcbfcda5356f1b3fdee7dc22c99a5b73a2750e5b054104 - , 0x2d3c1988b4541e4c045595b8d574e98a7c2820314a82e67a4e380f1c4541ba90 + , 0x2d3c1988b4541e4c045595b8d574e98a7c2820314a82e67a4e380f1c4541ba90 ] , [ 0x052547dc9e6d936cab6680372f1734c39f490d0cb970e2077c82f7e4172943d3 , 0x29d967f4002adcbb5a6037d644d36db91f591b088f69d9b4257694f5f9456bc2 @@ -120,19 +120,19 @@ template ExternalRound(i) { , [ 0x25672a14b5d085e31a30a7e1d5675ebfab034fb04dc2ec5e544887523f98dede , 0x0cf702434b891e1b2f1d71883506d68cdb1be36fa125674a3019647b3a98accd , 0x1837e75235ff5d112a5eddf7a4939448748339e7b5f2de683cf0c0ae98bdfbb3 - ] + ] , [ 0x1cd8a14cff3a61f04197a083c6485581a7d836941f6832704837a24b2d15613a , 0x266f6d85be0cef2ece525ba6a54b647ff789785069882772e6cac8131eecc1e4 , 0x0538fde2183c3f5833ecd9e07edf30fe977d28dd6f246d7960889d9928b506b3 - ] + ] , [ 0x07a0693ff41476abb4664f3442596aa8399fdccf245d65882fce9a37c268aa04 , 0x11eb49b07d33de2bd60ea68e7f652beda15644ed7855ee5a45763b576d216e8e , 0x08f8887da6ce51a8c06041f64e22697895f34bacb8c0a39ec12bf597f7c67cfc - ] + ] , [ 0x2a912ec610191eb7662f86a52cc64c0122bd5ba762e1db8da79b5949fdd38092 , 0x2031d7fd91b80857aa1fef64e23cfad9a9ba8fe8c8d09de92b1edb592a44c290 , 0x0f81ebce43c47711751fa64d6c007221016d485641c28c507d04fd3dc7fba1d2 - ] + ] ]; component sb[3]; @@ -154,7 +154,7 @@ template LinearLayer() { signal output out[3]; out[0] <== 2*inp[0] + inp[1] + inp[2]; out[1] <== inp[0] + 2*inp[1] + inp[2]; - out[2] <== inp[0] + inp[1] + 2*inp[2]; + out[2] <== inp[0] + inp[1] + 2*inp[2]; } //------------------------------------------------------------------------------ @@ -172,7 +172,7 @@ template Permutation() { component ext[8]; for(var k=0; k<8; k++) { ext[k] = ExternalRound(k); } - + component int[56]; for(var k=0; k<56; k++) { int[k] = InternalRound(k); } diff --git a/circuit/poseidon2_sponge.circom b/circuit/poseidon2_sponge.circom index d7698bb..981bfc6 100644 --- a/circuit/poseidon2_sponge.circom +++ b/circuit/poseidon2_sponge.circom @@ -17,10 +17,10 @@ function min(a,b) { // c = capacity (1 or 2) // r = rate = t - c // -// everything is measured in number of field elements +// everything is measured in number of field elements // // we use the padding `10*` from the original Poseidon paper, -// and initial state constant zero. Note that this is different +// and initial state constant zero. Note that this is different // from the "SAFE padding" recommended in the Poseidon2 paper // (which uses `0*` padding and a nontrivial initial state) // @@ -47,7 +47,7 @@ template PoseidonSponge(t, capacity, input_len, output_len) { signal padded[padded_len]; for(var i=0; i Date: Mon, 12 Feb 2024 15:48:17 +0100 Subject: [PATCH 08/13] circuit: remove unused templates --- circuit/poseidon2_hash.circom | 14 -------------- circuit/poseidon2_perm.circom | 14 -------------- 2 files changed, 28 deletions(-) diff --git a/circuit/poseidon2_hash.circom b/circuit/poseidon2_hash.circom index 7e58725..ba20f91 100644 --- a/circuit/poseidon2_hash.circom +++ b/circuit/poseidon2_hash.circom @@ -2,20 +2,6 @@ pragma circom 2.0.0; include "poseidon2_sponge.circom"; -//------------------------------------------------------------------------------ -// Hash `n` field elements into 1, with approximately 127-254 bits of preimage security -// Note that the output size must be at least twice than the desired security level (?) -// (assuming bn128 scalar field. We use capacity=2, rate=1, t=3). - -template Poseidon2_hash_rate1(n) { - signal input inp[n]; - signal output out; - - component sponge = PoseidonSponge(3,2,n,1); - sponge.inp <== inp; - sponge.out[0] ==> out; -} - //------------------------------------------------------------------------------ // Hash `n` field elements into 1, with approximately 127 bits of preimage security // (assuming bn128 scalar field. We use capacity=1, rate=2, t=3). diff --git a/circuit/poseidon2_perm.circom b/circuit/poseidon2_perm.circom index 0348d56..ff789fa 100644 --- a/circuit/poseidon2_perm.circom +++ b/circuit/poseidon2_perm.circom @@ -201,20 +201,6 @@ template Permutation() { // the "compression function" takes 2 field elements as input and produces // 1 field element as output. It is a trivial application of the permutation. -template Compression() { - signal input inp[2]; - signal output out; - - component perm = Permutation(); - perm.inp[0] <== inp[0]; - perm.inp[1] <== inp[1]; - perm.inp[2] <== 0; - - perm.out[0] ==> out; -} - -//-------------------------------------- - template KeyedCompression() { signal input key; signal input inp[2]; From 6d4abb82153f8deab5789d9be86d6ca1b44a637d Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Mon, 12 Feb 2024 16:05:54 +0100 Subject: [PATCH 09/13] circuit: fix comment --- circuit/sample_cells.circom | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circuit/sample_cells.circom b/circuit/sample_cells.circom index 448e704..9d6c6e7 100644 --- a/circuit/sample_cells.circom +++ b/circuit/sample_cells.circom @@ -104,7 +104,7 @@ log("top root check = ", mtop.recRoot == dataSetRoot); lg.inp <== nCellsPerSlot; lg.out ==> log2N; - // NOTE: in general we need the for Merkle prover the binary decomposition + // NOTE: in general we need for the Merkle prover the binary decomposition // of `nLeaves - 1`. But currently this is in fact a power of two, so we // can reuse the binary mask for this. Later we may change this? // From 34cd599c38cf3ad1374da6c7d454e2928a04d2ee Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 13 Feb 2024 10:39:36 +0100 Subject: [PATCH 10/13] circuit: remove unused signal --- circuit/sample_cells.circom | 2 -- 1 file changed, 2 deletions(-) diff --git a/circuit/sample_cells.circom b/circuit/sample_cells.circom index 9d6c6e7..fbaa6f4 100644 --- a/circuit/sample_cells.circom +++ b/circuit/sample_cells.circom @@ -99,10 +99,8 @@ log("top root check = ", mtop.recRoot == dataSetRoot); // // then we prove the individual sampled cells - signal log2N; component lg = Log2(maxDepth); // we allow at most 2^32 cells per slot lg.inp <== nCellsPerSlot; - lg.out ==> log2N; // NOTE: in general we need for the Merkle prover the binary decomposition // of `nLeaves - 1`. But currently this is in fact a power of two, so we From 46c17fa2ceddd277a2b5e0b12d342f3dd839d1ff Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 12 Mar 2024 09:46:45 +0100 Subject: [PATCH 11/13] Revert "circuit: remove unused templates" This reverts commit 521619c65fd03b7f6f3f6a6ba490cf427ff6d9a8. Co-Authored-By: Balazs Komuves --- circuit/binary_compare.circom | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/circuit/binary_compare.circom b/circuit/binary_compare.circom index 5d1c7e1..472f0eb 100644 --- a/circuit/binary_compare.circom +++ b/circuit/binary_compare.circom @@ -41,3 +41,57 @@ template BinaryCompare(n) { } //------------------------------------------------------------------------------ + +// +// given two numbers in `n`-bit binary decomposition (little-endian), we compute +// +// out := (A <= B) ? 1 : 0 +// +// NOTE: we don't check that the digits are indeed binary; +// that's the responsibility of the caller! +// + +template BinaryLessOrEqual(n) { + signal input A[n]; + signal input B[n]; + signal output out; + + var phalf = 1/2; // +1/2 as field element + var mhalf = -phalf; // -1/2 as field element + + component cmp = BinaryCompare(n); + cmp.A <== A; + cmp.B <== B; + + var x = cmp.out; + out <== mhalf * (x-1) * (x+2); +} + +//------------------------------------------------------------------------------ + +// +// given two numbers in `n`-bit binary decomposition (little-endian), we compute +// +// out := (A >= B) ? 1 : 0 +// +// NOTE: we don't check that the digits are indeed binary; +// that's the responsibility of the caller! +// + +template BinaryGreaterOrEqual(n) { + signal input A[n]; + signal input B[n]; + signal output out; + + var phalf = 1/2; // +1/2 as field element + var mhalf = -phalf; // -1/2 as field element + + component cmp = BinaryCompare(n); + cmp.A <== A; + cmp.B <== B; + + var x = cmp.out; + out <== mhalf * (x+1) * (x-2); +} + +//------------------------------------------------------------------------------ From ded25f54c2cff0d563f53c62218431b02661e1a3 Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 12 Mar 2024 09:50:13 +0100 Subject: [PATCH 12/13] Revert "circuit: remove unused functions" This reverts commit 14c7c7a6d9ee24c6aded17ebfadbc7609465259c. Co-Authored-By: Balazs Komuves --- circuit/misc.circom | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/circuit/misc.circom b/circuit/misc.circom index c9065bc..d249553 100644 --- a/circuit/misc.circom +++ b/circuit/misc.circom @@ -1,5 +1,15 @@ pragma circom 2.0.0; +//------------------------------------------------------------------------------ + +function FloorLog2(n) { + return (n==0) ? -1 : (1 + FloorLog2(n>>1)); +} + +function CeilLog2(n) { + return (n==0) ? 0 : (1 + FloorLog2(n-1)); +} + //------------------------------------------------------------------------------ // decompose an n-bit number into bits (least significant bit first) From 447c8c772ffcdd40209d0968b653d95611df2c9f Mon Sep 17 00:00:00 2001 From: Mark Spanbroek Date: Tue, 12 Mar 2024 10:24:31 +0100 Subject: [PATCH 13/13] circuit: fix comment Co-Authored-By: Balazs Komuves --- circuit/merkle.circom | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/circuit/merkle.circom b/circuit/merkle.circom index b1f564c..0396436 100644 --- a/circuit/merkle.circom +++ b/circuit/merkle.circom @@ -37,8 +37,11 @@ template RootFromMerklePath( maxDepth ) { signal aux[ maxDepth+1 ]; aux[0] <== leaf; - // compute which binary postfixes of the index is the same as the - // corresponding postfix of the last index + // Determine whether nodes from the path are last in their row and are odd, + // by computing which binary prefixes of the index are the same as the + // corresponding prefix of the last index. + // This is done in reverse bit order, because pathBits and lastBits have the + // least significant bit first. component eq[ maxDepth ]; signal isLast[ maxDepth+1 ]; isLast[ maxDepth ] <== 1;