mirror of
https://github.com/logos-storage/logos-storage-proofs-circuits.git
synced 2026-01-05 23:13:06 +00:00
Merge pull request #7 from codex-storage/circuit-refactor
Refactor the circuit
This commit is contained in:
commit
61789cadeb
2
.github/workflows/generate.yml
vendored
2
.github/workflows/generate.yml
vendored
@ -103,7 +103,7 @@ jobs:
|
|||||||
mkdir -p workflow/build
|
mkdir -p workflow/build
|
||||||
cd workflow/build
|
cd workflow/build
|
||||||
../../reference/nim/proof_input/cli $CLI_ARGS -v --circom="proof_main.circom"
|
../../reference/nim/proof_input/cli $CLI_ARGS -v --circom="proof_main.circom"
|
||||||
circom --r1cs --wasm --O2 -l../../circuit proof_main.circom
|
circom --r1cs --wasm --O2 -l../../circuit/lib -l../../circuit/poseidon2 -l../../circuit/codex proof_main.circom
|
||||||
|
|
||||||
- name: Circuit setup
|
- name: Circuit setup
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@ -6,19 +6,42 @@ See the [README in the parent dir](../README.md) for the (draft) specification.
|
|||||||
|
|
||||||
### Organization of the circuit code
|
### Organization of the circuit code
|
||||||
|
|
||||||
|
- `codex` - the storage proof circuit
|
||||||
|
- `poseidon2` - Poseidon2 hash function
|
||||||
|
- `lib` - general purpose, reusable circom templates ("circuit library")
|
||||||
|
|
||||||
|
In `codex`:
|
||||||
|
|
||||||
- `sample_cells.circom` - compute cell indices to sample, and prove those cells
|
- `sample_cells.circom` - compute cell indices to sample, and prove those cells
|
||||||
- `single_cell.circom` - prove a single cell
|
- `single_cell.circom` - prove a single cell
|
||||||
- `merkle.circom` - Merkle inclusion proof (using our custom Merkle tree convention)
|
- `merkle.circom` - Merkle inclusion proof (using our custom Merkle tree convention)
|
||||||
|
|
||||||
|
In `poseidon2`
|
||||||
|
|
||||||
|
- `poseidon2_hash.circom` - compute Poseidon2 hash with sponge construction
|
||||||
|
- `poseidon2_sponge.circom` - generic sponge construction
|
||||||
|
- `poseidon2_perm.circom` - the Poseidon2 permutation
|
||||||
|
- `poseidon2_compr.circom` - the compression function
|
||||||
|
|
||||||
|
In `lib`:
|
||||||
|
|
||||||
- `extract_bits.circom` - extract lower bits of the *standard representation* of a field element
|
- `extract_bits.circom` - extract lower bits of the *standard representation* of a field element
|
||||||
- `binary_compare.circom` - compare numbers given in binary representation (the point is that they can be bigger than the field size!)
|
- `binary_compare.circom` - compare numbers given in binary representation (the point is that they can be bigger than the field size!)
|
||||||
- `log2.circom` - circom code for computing base 2 logarithm
|
- `log2.circom` - circom code for computing base 2 logarithm
|
||||||
- `misc.circom` - miscellaneous helper funtions
|
- `misc.circom` - miscellaneous helper funtions
|
||||||
- `poseidon2_hash.circom` - compute Poseidon2 hash with sponge construction
|
|
||||||
- `poseidon2_sponge.circom` - generic sponge construction
|
|
||||||
- `poseidon2_perm.circom` - the Poseidon2 permutation
|
### Main component
|
||||||
|
|
||||||
Note: the main component is not included in the above, as it depends on the
|
Note: the main component is not included in the above, as it depends on the
|
||||||
parameters. You can use one of the reference input generators to create one;
|
parameters. You can use one of the reference input generators to create one;
|
||||||
or look at `deprecated/slot_main.circom` for an example.
|
if you want to do manually, it should look like this:
|
||||||
|
|
||||||
|
pragma circom 2.0.0;
|
||||||
|
include "sample_cells.circom";
|
||||||
|
|
||||||
|
// argument conventions:
|
||||||
|
// SampleAndProven( maxDepth, maxLog2NSlots, blockTreeDepth, nFieldElemsPerCell, nSamples )
|
||||||
|
component main {public [entropy,dataSetRoot,slotIndex]} = SampleAndProve(32, 8, 5, 67, 100);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
pragma circom 2.0.0;
|
pragma circom 2.0.0;
|
||||||
|
|
||||||
include "poseidon2_perm.circom";
|
include "poseidon2_compr.circom";
|
||||||
|
|
||||||
include "misc.circom";
|
include "misc.circom";
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@ -23,6 +22,24 @@ include "misc.circom";
|
|||||||
// NOTE: we don't check whether the bits are really bits, that's the
|
// NOTE: we don't check whether the bits are really bits, that's the
|
||||||
// responsability of the caller!
|
// responsability of the caller!
|
||||||
//
|
//
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
//
|
||||||
|
// Merkle tree convention: Here we use a Codex-specific "safe" Merkle tree convention.
|
||||||
|
//
|
||||||
|
// This uses a "keyed compression function", where the key depends on:
|
||||||
|
//
|
||||||
|
// - whether we are in the bottommost layer or not
|
||||||
|
// - whether the node we are dealing with has 1 or 2 children (odd or even node)
|
||||||
|
//
|
||||||
|
// These are two bits, encoded as numbers in the set {0,1,2,3}
|
||||||
|
// (the lowest bit is 1 if it's the bottom layer, 0 otherwise; the next bit
|
||||||
|
// is 1 if it's an odd node, 0 if even node). Furthermore:
|
||||||
|
//
|
||||||
|
// - in case of an odd node with leaf x, we apply the compression to the pair (x,0)
|
||||||
|
// - in case of a singleton input (the whole Merkle tree is built on a single field element), we also apply one compression
|
||||||
|
// - the keyed compression is defined as applying the permutation to the triple (x,y,key), and extracting the first component of the resulting triple
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
template RootFromMerklePath( maxDepth ) {
|
template RootFromMerklePath( maxDepth ) {
|
||||||
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
pragma circom 2.0.0;
|
|
||||||
|
|
||||||
include "binary_compare.circom";
|
|
||||||
|
|
||||||
component main {public [A,B]} = BinaryLessOrEqual(8);
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
pragma circom 2.0.0;
|
|
||||||
include "sample_cells.circom";
|
|
||||||
// SampleAndProven( maxDepth, maxLog2NSlots, blockTreeDepth, nFieldElemsPerCell, nSamples )
|
|
||||||
component main {public [entropy,dataSetRoot,slotIndex]} = SampleAndProve(16, 5, 3, 5, 10);
|
|
||||||
@ -1,14 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
NAME="main_test_compare"
|
|
||||||
INPUT="input_test_compare"
|
|
||||||
|
|
||||||
cd build
|
|
||||||
circom ../${NAME}.circom --r1cs --wasm || { echo "circom failed"; exit 102; }
|
|
||||||
|
|
||||||
echo "{ \"A\":[1,1,1,0,1,1,0,1], \"B\":[1,1,1,0,1,1,0,1] }" >${INPUT}.json
|
|
||||||
|
|
||||||
echo "generating witness... (WASM)"
|
|
||||||
cd ${NAME}_js
|
|
||||||
node generate_witness.js ${NAME}.wasm ../${INPUT}.json ../${NAME}_witness.wtns || { echo "witness gen failed"; exit 101; }
|
|
||||||
cd ..
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
ORIG=`pwd`
|
|
||||||
|
|
||||||
PTAU_DIR="/Users/bkomuves/zk/ptau/"
|
|
||||||
PTAU_FILE="${PTAU_DIR}/powersOfTau28_hez_final_20.ptau"
|
|
||||||
|
|
||||||
NAME="slot_main"
|
|
||||||
|
|
||||||
# --- setup ---
|
|
||||||
|
|
||||||
cd $ORIG/build
|
|
||||||
echo "circuit-specific ceremony..."
|
|
||||||
snarkjs groth16 setup ${NAME}.r1cs ${PTAU_FILE} ${NAME}_0000.zkey
|
|
||||||
echo "some_entropy_xxx" | snarkjs zkey contribute ${NAME}_0000.zkey ${NAME}_0001.zkey --name="1st Contributor Name"
|
|
||||||
rm ${NAME}_0000.zkey
|
|
||||||
mv ${NAME}_0001.zkey ${NAME}.zkey
|
|
||||||
snarkjs zkey export verificationkey ${NAME}.zkey ${NAME}_verification_key.json
|
|
||||||
|
|
||||||
# --- prove ---
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "trying to prove... (with snarkjs)"
|
|
||||||
|
|
||||||
cd $ORIG/build
|
|
||||||
time snarkjs groth16 prove ${NAME}.zkey ${NAME}.wtns ${NAME}_proof.json ${NAME}_public.json
|
|
||||||
|
|
||||||
# --- verify ---
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo "verifyng proof..."
|
|
||||||
snarkjs groth16 verify ${NAME}_verification_key.json ${NAME}_public.json ${NAME}_proof.json
|
|
||||||
|
|
||||||
cd $ORIG
|
|
||||||
cd $ORIG
|
|
||||||
@ -1,25 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
ORIG=`pwd`
|
|
||||||
mkdir -p build
|
|
||||||
|
|
||||||
cd ../reference/haskell
|
|
||||||
mkdir -p json
|
|
||||||
cabal v1-run cli/testMain.hs || { echo "ghc failed"; cd $ORIG; exit 101; }
|
|
||||||
|
|
||||||
mv json/input_example.json ${ORIG}/build/
|
|
||||||
mv json/slot_main.circom ${ORIG}
|
|
||||||
|
|
||||||
cd ${ORIG}/build
|
|
||||||
|
|
||||||
NAME="slot_main"
|
|
||||||
circom ../${NAME}.circom --r1cs --wasm || { echo "circom failed"; cd $ORIG; exit 102; }
|
|
||||||
|
|
||||||
echo "generating witness... (WASM)"
|
|
||||||
cd ${NAME}_js
|
|
||||||
node generate_witness.js ${NAME}.wasm ../input_example.json ../${NAME}.wtns || { echo "witness gen failed"; cd $ORIG; exit 101; }
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
echo "witness generation succeeded"
|
|
||||||
|
|
||||||
cd $ORIG
|
|
||||||
44
circuit/poseidon2/poseidon2_compr.circom
Normal file
44
circuit/poseidon2/poseidon2_compr.circom
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
pragma circom 2.0.0;
|
||||||
|
|
||||||
|
include "poseidon2_perm.circom";
|
||||||
|
|
||||||
|
//
|
||||||
|
// The Poseidon2 compression function (used when constructing binary Merkle trees)
|
||||||
|
//
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// the "keyed compression function" additionally takes a key parameter, resulting
|
||||||
|
// in a keyed family of compression functions. In practice we use 4 different
|
||||||
|
// keys (0,1,2, and 3).
|
||||||
|
|
||||||
|
template KeyedCompression() {
|
||||||
|
signal input key;
|
||||||
|
signal input inp[2];
|
||||||
|
signal output out;
|
||||||
|
|
||||||
|
component perm = Permutation();
|
||||||
|
perm.inp[0] <== inp[0];
|
||||||
|
perm.inp[1] <== inp[1];
|
||||||
|
perm.inp[2] <== key;
|
||||||
|
|
||||||
|
perm.out[0] ==> out;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -2,6 +2,21 @@ pragma circom 2.0.0;
|
|||||||
|
|
||||||
include "poseidon2_sponge.circom";
|
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
|
// 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).
|
// (assuming bn128 scalar field. We use capacity=1, rate=2, t=3).
|
||||||
@ -198,21 +198,4 @@ 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 KeyedCompression() {
|
|
||||||
signal input key;
|
|
||||||
signal input inp[2];
|
|
||||||
signal output out;
|
|
||||||
|
|
||||||
component perm = Permutation();
|
|
||||||
perm.inp[0] <== inp[0];
|
|
||||||
perm.inp[1] <== inp[1];
|
|
||||||
perm.inp[2] <== key;
|
|
||||||
|
|
||||||
perm.out[0] ==> out;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
@ -9,7 +9,7 @@ import CircuitCommon
|
|||||||
-- global parameters
|
-- global parameters
|
||||||
|
|
||||||
circomFile :: FilePath
|
circomFile :: FilePath
|
||||||
circomFile = circuitSourceDir </> "binary_compare.circom"
|
circomFile = circuitLibSourceDir </> "binary_compare.circom"
|
||||||
|
|
||||||
-- | comparing @n@-bit integers
|
-- | comparing @n@-bit integers
|
||||||
type GP = Int
|
type GP = Int
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import CircuitCommon
|
|||||||
-- global parameters
|
-- global parameters
|
||||||
|
|
||||||
circomFile :: FilePath
|
circomFile :: FilePath
|
||||||
circomFile = circuitSourceDir </> "binary_compare.circom"
|
circomFile = circuitLibSourceDir </> "binary_compare.circom"
|
||||||
|
|
||||||
-- | comparing @n@-bit integers
|
-- | comparing @n@-bit integers
|
||||||
type GP = Int
|
type GP = Int
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import CircuitCommon
|
|||||||
-- global parameters
|
-- global parameters
|
||||||
|
|
||||||
circomFile :: FilePath
|
circomFile :: FilePath
|
||||||
circomFile = circuitSourceDir </> "binary_compare.circom"
|
circomFile = circuitLibSourceDir </> "binary_compare.circom"
|
||||||
|
|
||||||
-- | comparing @n@-bit integers
|
-- | comparing @n@-bit integers
|
||||||
type GP = Int
|
type GP = Int
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import CircuitCommon
|
|||||||
-- global parameters
|
-- global parameters
|
||||||
|
|
||||||
circomFile :: FilePath
|
circomFile :: FilePath
|
||||||
circomFile = circuitSourceDir </> "log2.circom"
|
circomFile = circuitLibSourceDir </> "log2.circom"
|
||||||
|
|
||||||
-- `n` = maximum number of bits
|
-- `n` = maximum number of bits
|
||||||
type GP = Int
|
type GP = Int
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import CircuitCommon
|
|||||||
-- global parameters
|
-- global parameters
|
||||||
|
|
||||||
circomFile :: FilePath
|
circomFile :: FilePath
|
||||||
circomFile = circuitSourceDir </> "extract_bits.circom"
|
circomFile = circuitLibSourceDir </> "extract_bits.circom"
|
||||||
|
|
||||||
-- | extracting the lowest @n@-bit of the canonical representation of a field element
|
-- | extracting the lowest @n@-bit of the canonical representation of a field element
|
||||||
type GP = Int
|
type GP = Int
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import CircuitCommon
|
|||||||
-- global parameters
|
-- global parameters
|
||||||
|
|
||||||
circomFile :: FilePath
|
circomFile :: FilePath
|
||||||
circomFile = circuitSourceDir </> "log2.circom"
|
circomFile = circuitLibSourceDir </> "log2.circom"
|
||||||
|
|
||||||
-- `n` = maximum number of bits
|
-- `n` = maximum number of bits
|
||||||
type GP = Int
|
type GP = Int
|
||||||
|
|||||||
@ -2,7 +2,8 @@
|
|||||||
module CircuitCommon
|
module CircuitCommon
|
||||||
( module R1CS
|
( module R1CS
|
||||||
, module System.FilePath
|
, module System.FilePath
|
||||||
, circuitSourceDir
|
, circuitRootDir
|
||||||
|
, circuitLibSourceDir
|
||||||
, toBitsLE , toBitsLE'
|
, toBitsLE , toBitsLE'
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
@ -15,8 +16,11 @@ import R1CS
|
|||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
circuitSourceDir :: FilePath
|
circuitRootDir :: FilePath
|
||||||
circuitSourceDir = "../circuit"
|
circuitRootDir = "../circuit"
|
||||||
|
|
||||||
|
circuitLibSourceDir :: FilePath
|
||||||
|
circuitLibSourceDir = circuitRootDir </> "lib"
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@ -35,10 +35,10 @@ testSimple' verbosity = do
|
|||||||
runSpecMany BinaryLTE.specs
|
runSpecMany BinaryLTE.specs
|
||||||
runSpecMany BinaryGTE.specs
|
runSpecMany BinaryGTE.specs
|
||||||
|
|
||||||
runSpecMany ExtractBits.specs
|
-- runSpecMany ExtractBits.specs -- this test doesn't work currently?
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
main = do
|
main = do
|
||||||
testSimple' Info --Silent -- Verbose -- Silent
|
testSimple' Silent -- Info
|
||||||
|
|
||||||
|
|||||||
4
workflow/.gitignore
vendored
4
workflow/.gitignore
vendored
@ -1 +1,3 @@
|
|||||||
build/
|
build/
|
||||||
|
build_big/
|
||||||
|
tmp/
|
||||||
@ -3,9 +3,13 @@
|
|||||||
ORIG=`pwd`
|
ORIG=`pwd`
|
||||||
|
|
||||||
NIMCLI_DIR="${ORIG}/../reference/nim/proof_input/"
|
NIMCLI_DIR="${ORIG}/../reference/nim/proof_input/"
|
||||||
CIRCUIT_DIR="${ORIG}/../circuit/"
|
|
||||||
PTAU_DIR="${ORIG}/../ceremony"
|
PTAU_DIR="${ORIG}/../ceremony"
|
||||||
|
|
||||||
|
CIRCUIT_ROOT="${ORIG}/../circuit/"
|
||||||
|
CIRCUIT_PRF_DIR="${CIRCUIT_ROOT}/codex/"
|
||||||
|
CIRCUIT_POS_DIR="${CIRCUIT_ROOT}/poseidon2/"
|
||||||
|
CIRCUIT_LIB_DIR="${CIRCUIT_ROOT}/lib/"
|
||||||
|
|
||||||
PTAU_FILE="powersOfTau28_hez_final_21.ptau"
|
PTAU_FILE="powersOfTau28_hez_final_21.ptau"
|
||||||
PTAU_PATH="${PTAU_DIR}/${PTAU_FILE}"
|
PTAU_PATH="${PTAU_DIR}/${PTAU_FILE}"
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,8 @@ ${NIMCLI_DIR}/cli $CLI_ARGS -v --circom=${CIRCUIT_MAIN}.circom
|
|||||||
|
|
||||||
# --- compile the circuit ---
|
# --- compile the circuit ---
|
||||||
|
|
||||||
time circom --r1cs --wasm --O2 -l${CIRCUIT_DIR} ${CIRCUIT_MAIN}.circom
|
CIRCUIT_INCLUDES="-l${CIRCUIT_LIB_DIR} -l${CIRCUIT_POS_DIR} -l${CIRCUIT_PRF_DIR}"
|
||||||
|
time circom --r1cs --wasm --O2 ${CIRCUIT_INCLUDES} ${CIRCUIT_MAIN}.circom
|
||||||
|
|
||||||
# --- circuit specific setup ---
|
# --- circuit specific setup ---
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user