mirror of
https://github.com/babybear-labs/benchmark.git
synced 2026-01-10 07:47:55 -05:00
10
circom/.gitignore
vendored
Normal file
10
circom/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/input/
|
||||
/output/
|
||||
/powersoftau/
|
||||
/circuits/benchmark/
|
||||
/result/
|
||||
**/__pycache__
|
||||
/node_modules/
|
||||
package-lock.json
|
||||
env/
|
||||
powersoftau
|
||||
40
circom/README.md
Normal file
40
circom/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Benchmark Circuits
|
||||
[](https://github.com/iden3/circom)
|
||||
[](https://github.com/iden3/snarkjs)
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
This repository is dedicated to a powerful and user-friendly framework designed for testing various circuits using Circom. Our main objective is to simplify the testing process, allowing developers to easily add new circuits and conduct reliable tests.
|
||||
|
||||
**Key features of the framework:**
|
||||
|
||||
1. **Extensibility:** The framework is highly extensible. To add new circuits, simply follow a few clear rules and place the circuits in the `circuits/base` folder. Additionally, provide a commented `main` file following the appropriate formatting.
|
||||
|
||||
2. **Easy Customization:** You can effortlessly customize circuit values using Python. Just make the necessary changes in the files `test_circuits.py` to adapt it to the new circuit.
|
||||
|
||||
|
||||
**Getting Started:**
|
||||
|
||||
1. Clone this repository to your local system.
|
||||
2. Add new circuits to the `circuits/base` folder.
|
||||
3. Modify the `main` line of the circuit with the correct formatting and values to be customized in Python.
|
||||
4. Edit the files `test_circuits.py` to adapt it to the new circuit, updating the circuit name, powersoftau, and other parameters as needed.
|
||||
5. Run the benchmark to ensure the circuit functions correctly.
|
||||
|
||||
**Troubleshooting**
|
||||
If you get any error, take care of properly set the following parameters:
|
||||
* In `scripts/compile_circuit.sh`, properly set `CIRCOMLIB_PATH` path. If `circomlib` is not installed, run: `npm install circomlib`.
|
||||
* In `test_circuits.py`, properly set `POT` variable with the path to the `*.ptau` file (download it from [here](https://github.com/iden3/snarkjs#7-prepare-phase-2)). It should be in `poweroftau` directory but it can be elsewhere.
|
||||
* In `scripts/proving_system/prover.sh`, properly set `RAPIDSNARK` variable with the path to the `build/prover` executable. For information on how to install Rapidsnark visit [here](https://github.com/iden3/rapidsnark)
|
||||
|
||||
**Contributions are Welcome:**
|
||||
|
||||
[](https://choosealicense.com/licenses/mit/)
|
||||
|
||||
We are open to contributions from the community to improve this framework and make it even more useful. Feel free to open issues, propose enhancements, or submit pull requests.
|
||||
|
||||
Thank you for choosing our framework. We hope it simplifies your Circom testing work and contributes to your success in developing secure and efficient circuits.
|
||||
|
||||
19
circom/circuits/base/fibonacci.circom
Normal file
19
circom/circuits/base/fibonacci.circom
Normal file
@@ -0,0 +1,19 @@
|
||||
pragma circom 2.0.3;
|
||||
|
||||
// Fibonacci with custom starting numbers
|
||||
template Fibonacci(n) {
|
||||
assert(n >= 2);
|
||||
signal input in[2];
|
||||
signal output out;
|
||||
|
||||
signal fib[n+1];
|
||||
fib[0] <== in[0];
|
||||
fib[1] <== in[1];
|
||||
for (var i = 2; i <= n; i++) {
|
||||
fib[i] <== fib[i-2] + fib[i-1];
|
||||
}
|
||||
|
||||
out <== fib[n];
|
||||
}
|
||||
|
||||
//MAIN component main = Fibonacci(NUM);
|
||||
63
circom/circuits/base/merkle.circom
Normal file
63
circom/circuits/base/merkle.circom
Normal file
@@ -0,0 +1,63 @@
|
||||
pragma circom 2.0.0;
|
||||
|
||||
include "../../node_modules/circomlib/circuits/switcher.circom";
|
||||
include "../../node_modules/circomlib/circuits/poseidon.circom";
|
||||
include "../../node_modules/circomlib/circuits/bitify.circom";
|
||||
|
||||
|
||||
template Mkt2VerifierLevel() {
|
||||
signal input sibling;
|
||||
signal input low;
|
||||
signal input selector;
|
||||
signal output root;
|
||||
|
||||
component sw = Switcher();
|
||||
component hash = Poseidon(2);
|
||||
|
||||
sw.sel <== selector;
|
||||
sw.L <== low;
|
||||
sw.R <== sibling;
|
||||
|
||||
log(sw.outL);
|
||||
log(sw.outR);
|
||||
|
||||
hash.inputs[0] <== sw.outL;
|
||||
hash.inputs[1] <== sw.outR;
|
||||
|
||||
root <== hash.out;
|
||||
}
|
||||
|
||||
template Mkt2Verifier(nLevels) {
|
||||
|
||||
signal input key;
|
||||
signal input value;
|
||||
signal input root;
|
||||
signal input siblings[nLevels];
|
||||
|
||||
component hashV = Poseidon(1);
|
||||
|
||||
hashV.inputs[0] <== value;
|
||||
|
||||
component n2b = Num2Bits(nLevels);
|
||||
component levels[nLevels];
|
||||
|
||||
|
||||
n2b.in <== key;
|
||||
|
||||
|
||||
for (var i=nLevels-1; i>=0; i--) {
|
||||
levels[i] = Mkt2VerifierLevel();
|
||||
levels[i].sibling <== siblings[i];
|
||||
levels[i].selector <== n2b.out[i];
|
||||
if (i==nLevels-1) {
|
||||
levels[i].low <== hashV.out;
|
||||
}
|
||||
else {
|
||||
levels[i].low <== levels[i+1].root;
|
||||
}
|
||||
}
|
||||
|
||||
root === levels[0].root;
|
||||
}
|
||||
|
||||
//MAIN component main = Mkt2Verifier(NUM);
|
||||
52
circom/circuits/base/poseidon_sponge.circom
Normal file
52
circom/circuits/base/poseidon_sponge.circom
Normal file
@@ -0,0 +1,52 @@
|
||||
pragma circom 2.0.0;
|
||||
include "../../node_modules/circomlib/circuits/poseidon.circom";
|
||||
|
||||
template SpongeHash(inputs_length){
|
||||
signal input in[inputs_length];
|
||||
signal output hash;
|
||||
|
||||
var k = 0;
|
||||
var hash_blocks = (inputs_length\15) + 1;
|
||||
var block_index = 0;
|
||||
|
||||
component poseidon_hash[hash_blocks];
|
||||
signal inside_hash[hash_blocks];
|
||||
signal frame[hash_blocks][16];
|
||||
|
||||
for (var i=0; i<inputs_length; i++) {
|
||||
frame[block_index][k] <== in[i];
|
||||
|
||||
if (k == 15){
|
||||
|
||||
//* START POSEIDON HASH
|
||||
poseidon_hash[block_index] = Poseidon(16);
|
||||
for (var j=0; j<16; j++)
|
||||
poseidon_hash[block_index].inputs[j] <== frame[block_index][j];
|
||||
inside_hash[block_index] <== poseidon_hash[block_index].out;
|
||||
block_index++;
|
||||
//*/ END POSEIDON HASH
|
||||
|
||||
frame[block_index][0] <== inside_hash[block_index - 1];
|
||||
k = 1;
|
||||
} else
|
||||
k++;
|
||||
|
||||
}
|
||||
|
||||
if (inputs_length%16 != 0){
|
||||
|
||||
//* START POSEIDON HASH
|
||||
poseidon_hash[block_index] = Poseidon(16);
|
||||
for (var j=0; j<16; j++)
|
||||
poseidon_hash[block_index].inputs[j] <== j<k ? frame[block_index][j] : 0;
|
||||
hash <== poseidon_hash[block_index].out;
|
||||
//*/ END POSEIDON HASH
|
||||
|
||||
}else
|
||||
hash <== frame[block_index][0];
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//MAIN component main = SpongeHash(NUM);
|
||||
39
circom/circuits/base/sha256_bytes.circom
Normal file
39
circom/circuits/base/sha256_bytes.circom
Normal file
@@ -0,0 +1,39 @@
|
||||
pragma circom 2.0.3;
|
||||
|
||||
include "../node_modules/circomlib/circuits/sha256/sha256.circom";
|
||||
include "../node_modules/circomlib/circuits/bitify.circom";
|
||||
|
||||
/**
|
||||
* Wrapper around SHA256 to support bytes as input instead of bits
|
||||
* @param n The number of input bytes
|
||||
* @input in The input bytes
|
||||
* @output out The SHA256 output of the n input bytes, in bytes
|
||||
*/
|
||||
template Sha256Bytes(n) {
|
||||
signal input in[n];
|
||||
signal output out[32];
|
||||
|
||||
component byte_to_bits[n];
|
||||
for (var i = 0; i < n; i++) {
|
||||
byte_to_bits[i] = Num2Bits(8);
|
||||
byte_to_bits[i].in <== in[i];
|
||||
}
|
||||
|
||||
component sha256 = Sha256(n*8);
|
||||
for (var i = 0; i < n; i++) {
|
||||
for (var j = 0; j < 8; j++) {
|
||||
sha256.in[i*8+j] <== byte_to_bits[i].out[7-j];
|
||||
}
|
||||
}
|
||||
|
||||
component bits_to_bytes[32];
|
||||
for (var i = 0; i < 32; i++) {
|
||||
bits_to_bytes[i] = Bits2Num(8);
|
||||
for (var j = 0; j < 8; j++) {
|
||||
bits_to_bytes[i].in[7-j] <== sha256.out[i*8+j];
|
||||
}
|
||||
out[i] <== bits_to_bytes[i].out;
|
||||
}
|
||||
}
|
||||
|
||||
//MAIN component main = Sha256Bytes(NUM);
|
||||
15
circom/package.json
Normal file
15
circom/package.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "benchmark_circuits",
|
||||
"version": "1.0.0",
|
||||
"description": "This repository contains the benchmark for circom circuits. In order to understand the time and memory consumption a report csv file is generated for each circuit. The report contains the following information:",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"circomlib": "^2.0.5",
|
||||
"circomlibjs": "^0.0.8"
|
||||
}
|
||||
}
|
||||
4
circom/requirements.txt
Normal file
4
circom/requirements.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
tensorflow
|
||||
numpy
|
||||
pandas
|
||||
psutil
|
||||
47
circom/scripts/compile_circuit.sh
Executable file
47
circom/scripts/compile_circuit.sh
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script is used to execute the circuits in the circuit directory
|
||||
#check if passed the correct number of arguments, one that is circom file name
|
||||
echo "In compile_circuit.sh command file"
|
||||
if [ $# -lt 2 ]; then
|
||||
echo "Usage: $0 <circom file name> <input file name> [--nodejs]"
|
||||
echo "[--nodejs] is optional, if not passed, the script will use Cpp to generate the witness"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
#define the base path for the circuit library
|
||||
CIRCOMLIB_PATH=./node_modules
|
||||
|
||||
#get the file name without the extension
|
||||
filename=$(basename -- "$1")
|
||||
CIRCOM_FILENAME=${filename%.*}
|
||||
|
||||
|
||||
|
||||
|
||||
echo "Compiling circuit [${CIRCOM_FILENAME}] ..."
|
||||
|
||||
# Create the output directory if it doesn't exist
|
||||
mkdir -p output/compiled_circuit > /dev/null
|
||||
mkdir -p output/compiled_circuit/compiled_${CIRCOM_FILENAME} > /dev/null
|
||||
|
||||
# Compile the circuits in the circuit directory
|
||||
|
||||
circom ${1} --r1cs --c --wasm --output output/compiled_circuit/compiled_${CIRCOM_FILENAME} -l ${CIRCOMLIB_PATH} -l ./circuits/base
|
||||
|
||||
# Generate the witness
|
||||
if [[ $* == *--nodejs* ]]; then
|
||||
echo "Compiling with [NodeJS] ..."
|
||||
cd output/compiled_circuit/compiled_${CIRCOM_FILENAME}/${CIRCOM_FILENAME}_js
|
||||
node generate_witness.js ${CIRCOM_FILENAME}.wasm /home/anubha/zkProjectEncodeG12/circom/${2} ../${CIRCOM_FILENAME}_witness.wtns
|
||||
|
||||
else
|
||||
echo "Compiling with [Cpp] ..."
|
||||
cd output/compiled_circuit/compiled_${CIRCOM_FILENAME}/${CIRCOM_FILENAME}_cpp
|
||||
make
|
||||
|
||||
./${CIRCOM_FILENAME} ../../../../${2} ../${CIRCOM_FILENAME}_witness.wtns
|
||||
fi
|
||||
|
||||
echo "Witness generated [${CIRCOM_FILENAME}_witness.wtns]"
|
||||
18
circom/scripts/proving_system/prover.sh
Executable file
18
circom/scripts/proving_system/prover.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Usage: ./prover.sh <circuit_name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CIRCUIT_NAME=$1
|
||||
CIRCUIT_DIR=$(readlink -f ./output/compiled_circuit/compiled_${CIRCUIT_NAME})
|
||||
WITNESS="${CIRCUIT_DIR}/${CIRCUIT_NAME}_witness.wtns"
|
||||
RAPIDSNARK=/bin/prover
|
||||
|
||||
cd output/snarkjs_circuit/${CIRCUIT_NAME}
|
||||
|
||||
if [ -f "$RAPIDSNARK" ]; then
|
||||
${RAPIDSNARK} circuit_final.zkey ${WITNESS} proof.json public.json
|
||||
else
|
||||
echo "RapidSnark not found, using snarkjs instead."
|
||||
snarkjs groth16 prove circuit_final.zkey ${WITNESS} proof.json public.json
|
||||
fi
|
||||
22
circom/scripts/proving_system/setup_prover.sh
Executable file
22
circom/scripts/proving_system/setup_prover.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
|
||||
if [ $# -ne 2 ]; then
|
||||
echo "Usage: ./setup_prover.sh <circuit_name> <pot_file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CIRCUIT_NAME=$1
|
||||
POT=$(readlink -f ${2})
|
||||
CIRCUIT_DIR=$(readlink -f ./output/compiled_circuit/compiled_${CIRCUIT_NAME})
|
||||
|
||||
R1CS="${CIRCUIT_DIR}/${CIRCUIT_NAME}.r1cs"
|
||||
|
||||
|
||||
mkdir -p output/snarkjs_circuit > /dev/null
|
||||
mkdir -p output/snarkjs_circuit/${CIRCUIT_NAME} > /dev/null
|
||||
|
||||
cd output/snarkjs_circuit/${CIRCUIT_NAME}
|
||||
|
||||
|
||||
snarkjs groth16 setup ${R1CS} ${POT} circuit_final.zkey
|
||||
snarkjs zkey export verificationkey circuit_final.zkey verification_key.json
|
||||
|
||||
23
circom/scripts/proving_system/verifier.sh
Executable file
23
circom/scripts/proving_system/verifier.sh
Executable file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo "Usage: ./verifier.sh <circuit_name> [--generate-contract <contract_name>]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
VERIFICATION_KEY=$(readlink -f ./output/snarkjs_circuit/${1}/verification_key.json)
|
||||
PUBLIC=$(readlink -f ./output/snarkjs_circuit/${1}/public.json)
|
||||
PROOF=$(readlink -f ./output/snarkjs_circuit/${1}/proof.json)
|
||||
|
||||
snarkjs groth16 verify ${VERIFICATION_KEY} ${PUBLIC} ${PROOF}
|
||||
|
||||
if [ "$2" == "--generate-contract" ]; then
|
||||
if [ -z "$3" ]; then
|
||||
echo "Missing contract name after --generate-contract option."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONTRACT_NAME="$3"
|
||||
ZKEY=$(readlink -f ./output/snarkjs_circuit/${1}/circuit_final.zkey)
|
||||
snarkjs zkey export solidityverifier ${ZKEY} ./output/snarkjs_circuit/${1}/Verifier_${CONTRACT_NAME}.sol
|
||||
fi
|
||||
295
circom/scripts/util.py
Executable file
295
circom/scripts/util.py
Executable file
@@ -0,0 +1,295 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from csv import DictWriter
|
||||
import json
|
||||
import os
|
||||
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
|
||||
import tensorflow as tf
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from math import sqrt
|
||||
import random
|
||||
import subprocess
|
||||
import psutil
|
||||
import re
|
||||
import hashlib
|
||||
|
||||
|
||||
|
||||
def measure_command(command, time = True, memory = True):
|
||||
"""
|
||||
Measure the time and memory usage of a specified command.
|
||||
|
||||
:param command: The command to execute and measure.
|
||||
:param time: True if you want to measure time, False otherwise.
|
||||
:param memory: True if you want to measure memory usage, False otherwise.
|
||||
|
||||
:return: A tuple containing the elapsed time (if time=True) and memory usage (if memory=True).
|
||||
"""
|
||||
command = f'/usr/bin/time -p -f "%e %M" {command} > /dev/null'
|
||||
# print("command: ",command)
|
||||
if memory:
|
||||
init_swap_used = psutil.swap_memory().used
|
||||
max_swap_used = init_swap_used
|
||||
# print("after memory check")
|
||||
process = subprocess.Popen(command,
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
if memory:
|
||||
while process.poll() is None:
|
||||
max_swap_used = max(max_swap_used, psutil.swap_memory().used)
|
||||
# print("After second memory check")
|
||||
command_output = process.communicate()[1].decode('utf-8')
|
||||
print("command_output: \n",command_output)
|
||||
# print("after command output")
|
||||
t,mem = command_output.split('\n')[0].split(' ')
|
||||
t = float(t)
|
||||
|
||||
if memory:
|
||||
swap = (max_swap_used-init_swap_used)/1024
|
||||
m = float(mem)+(swap if swap > 0 else 0)
|
||||
|
||||
return t if time else None, m if memory else None
|
||||
|
||||
|
||||
def measure_pagefault_time_command(command, password=None):
|
||||
"""
|
||||
Measure the time and number of page faults of a specified command.
|
||||
|
||||
:param command: The command to execute and measure.
|
||||
:param password: The password to pass to the command, if it necessitates sudo privileges.
|
||||
:return: A tuple containing the elapsed time and number of page faults.
|
||||
"""
|
||||
command = f'/usr/bin/time -p -f "%e %F %P %W %M" {command}'
|
||||
print(command)
|
||||
if password is not None:
|
||||
command = f'echo "{password}" | sudo -S {command}'
|
||||
|
||||
process = subprocess.Popen(command,
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE)
|
||||
|
||||
command_output = process.communicate()[1].decode('utf-8')
|
||||
|
||||
time, pagefaults, cpu_percentage, swap_out, mem = command_output.split('\n')[0].split(' ') if (len(command_output.split(": ")) == 1) else command_output.split(": ")[1].split('\n')[0].split(' ')
|
||||
|
||||
return float(time), int(pagefaults), cpu_percentage, int(swap_out), mem
|
||||
|
||||
|
||||
def generate_circuit(info, circuit_template, id = None):
|
||||
"""
|
||||
Generate a circuit from a template
|
||||
:param info: dictionary with the information to replace in the template
|
||||
:param circuit_template: path to the template
|
||||
:param id: id of the circuit
|
||||
|
||||
"""
|
||||
out_circuit = circuit_template.split('/')[-1].split('.')[0]
|
||||
print("out_circuit: {}",out_circuit)
|
||||
os.makedirs('circuits/benchmark',exist_ok=True)
|
||||
|
||||
with open(circuit_template, 'r') as infile:
|
||||
circuit = infile.read()
|
||||
for k,v in info.items():
|
||||
circuit = circuit.replace(k, str(v))
|
||||
circuit = circuit.replace('//MAIN', '')
|
||||
|
||||
id = f'_{id}' if id is not None else ''
|
||||
out_path = f'circuits/benchmark/{out_circuit}{id}.circom'
|
||||
print("out_path: {}",out_path)
|
||||
with open(out_path, 'w') as outfile:
|
||||
outfile.write(circuit)
|
||||
return out_path
|
||||
|
||||
|
||||
def append_to_csv(row,csv_path):
|
||||
"""
|
||||
Append a row to a csv file if it exists, otherwise create it
|
||||
:param row: dictionary with the row to append
|
||||
:param csv_path: path to the csv file
|
||||
"""
|
||||
with open(csv_path, 'a+', newline='') as csv_file:
|
||||
dict_writer = DictWriter(csv_file, fieldnames=list(row.keys()))
|
||||
if 0 == os.stat(csv_path).st_size:
|
||||
dict_writer.writeheader()
|
||||
dict_writer.writerow(row)
|
||||
|
||||
|
||||
def generate_input(output_path, size):
|
||||
"""
|
||||
Generate a random input for a circuit of a given size
|
||||
:param output_path: path to the output file
|
||||
:param size: size of the input
|
||||
"""
|
||||
json_input = {'in':[str(random.randint(0, 255)) for _ in range(size)] }
|
||||
os.makedirs('input',exist_ok=True)
|
||||
with open(output_path, 'w') as outfile:
|
||||
json.dump(json_input, outfile)
|
||||
|
||||
def generate_input_fibonnaci(output_path):
|
||||
"""
|
||||
Generate a random input for a circuit of a given size
|
||||
:param output_path: path to the output file
|
||||
:param size: size of the input
|
||||
"""
|
||||
json_input = {'in':['1','1'] }
|
||||
os.makedirs('input',exist_ok=True)
|
||||
with open(output_path, 'w') as outfile:
|
||||
json.dump(json_input, outfile)
|
||||
|
||||
def generate_input_merkle(output_path,chosen_key_index,chosen_key,merkle_root,merkle_proof):
|
||||
"""
|
||||
Generate a random input for a circuit of a given size
|
||||
:param output_path: path to the output file
|
||||
:param size: size of the input
|
||||
"""
|
||||
json_input = {'key': chosen_key_index,
|
||||
'value': chosen_key,
|
||||
'root': merkle_root,
|
||||
'siblings': merkle_proof
|
||||
}
|
||||
os.makedirs('input',exist_ok=True)
|
||||
with open(output_path, 'w') as outfile:
|
||||
json.dump(json_input, outfile)
|
||||
|
||||
def compute_input(GB):
|
||||
"""
|
||||
Compute the size of the input from a line, built with linear regression,
|
||||
measuring the number constraints from the input size
|
||||
:param GB: the amount of available memory
|
||||
"""
|
||||
# Read data from the CSV file
|
||||
data = pd.read_csv('./scripts/benchmark_circuits_resize.csv')
|
||||
|
||||
# Extract 'INPUT SIZE' and 'CONSTRAINTS' columns from the DataFrame
|
||||
input_size = data['INPUT SIZE']
|
||||
constraints = data['CONSTRAINTS']
|
||||
|
||||
# Perform linear regression
|
||||
slope, intercept = np.polyfit(input_size, constraints, 1)
|
||||
|
||||
best_constraints = 8388608 * GB / 8.996896768
|
||||
|
||||
return int(sqrt(abs(best_constraints / slope - intercept))), int(best_constraints)
|
||||
|
||||
|
||||
|
||||
def extract_contraints(r1cs_file):
|
||||
infos = subprocess.check_output(f'snarkjs r1cs info {r1cs_file}',shell=True).decode('utf-8')
|
||||
return int(re.search(r'# of Constraints: (\d+)',infos).group(1))
|
||||
|
||||
|
||||
|
||||
def resize_image(image, height, width):
|
||||
"""
|
||||
Resize an image to the given dimensions.
|
||||
:param image_path: Path to the image to resize.
|
||||
:param height: Height of the resized image.
|
||||
:param width: Width of the resized image.
|
||||
:return: the resized image.
|
||||
"""
|
||||
original_height, original_width, _ = image.shape
|
||||
|
||||
if (original_height-1) % (height-1) != 0 or (original_width-1) % (width-1) != 0:
|
||||
divisors_h = [v+1 for v in range(1, (original_height - 1)//2) if (original_height - 1) % v == 0]
|
||||
divisors_w = [v+1 for v in range(1, (original_width - 1)//2) if (original_width - 1) % v == 0]
|
||||
raise ValueError(f"The image cannot be resized to the given dimensions.\n The height must be one of this numbers: {divisors_h}\
|
||||
\n The width must be one of this numbers: {divisors_w}")
|
||||
|
||||
return (
|
||||
(
|
||||
tf.compat.v1.image.resize(
|
||||
image,
|
||||
[height, width],
|
||||
align_corners=True,
|
||||
method=tf.image.ResizeMethod.BILINEAR,
|
||||
)
|
||||
)
|
||||
.numpy()
|
||||
.round()
|
||||
.astype(np.uint8)
|
||||
)
|
||||
|
||||
|
||||
|
||||
def generate_random_image(height, width = None):
|
||||
"""
|
||||
Generate a random image.
|
||||
:param height: Height of the image.
|
||||
:param width: Width of the image.
|
||||
:return: the random image.
|
||||
"""
|
||||
if width is None:
|
||||
width = height
|
||||
rimg = np.random.randint(0, 256, size=(height, width, 3), dtype=np.uint8)
|
||||
return rimg
|
||||
|
||||
def generate_resize_input(output_path, f_height,f_width,r_height,r_width):
|
||||
"""
|
||||
Generate a random input that fits the cirtuit for the resize operation check.
|
||||
:param output_path: Path to the output file.
|
||||
:param f_height: Height of the full image.
|
||||
:param f_width: Width of the full image.
|
||||
:param r_height: Height of the resized image.
|
||||
:param r_width: Width of the resized image.
|
||||
"""
|
||||
img = generate_random_image(f_height,f_width)
|
||||
rsz = resize_image(img,r_height,r_width)
|
||||
|
||||
json_input = {'full_image':img.astype(str).tolist(), 'resize_image':rsz.astype(str).tolist() }
|
||||
os.makedirs('input',exist_ok=True)
|
||||
with open(output_path, 'w') as outfile:
|
||||
json.dump(json_input, outfile)
|
||||
|
||||
def create_merkle_tree(arr, n_levels):
|
||||
extended_len = 1 << n_levels
|
||||
|
||||
h_arr = []
|
||||
for i in range(extended_len):
|
||||
if i < len(arr):
|
||||
h_arr.append(hashlib.sha256(str(arr[i]).encode()).hexdigest())
|
||||
else:
|
||||
h_arr.append(0)
|
||||
|
||||
return __merkelize(h_arr)
|
||||
|
||||
def __merkelize(arr):
|
||||
if len(arr) == 1:
|
||||
return arr
|
||||
|
||||
h_arr = []
|
||||
for i in range(len(arr) // 2):
|
||||
combined = str(arr[2 * i]) + str(arr[2 * i + 1])
|
||||
h_arr.append(hashlib.sha256(combined.encode()).hexdigest())
|
||||
|
||||
m = __merkelize(h_arr)
|
||||
return m + arr
|
||||
|
||||
def generate_merkle_proof(m, key, n_levels):
|
||||
if n_levels == 0:
|
||||
return []
|
||||
|
||||
extended_len = 1 << n_levels
|
||||
top_siblings = generate_merkle_proof(m, key >> 1, n_levels - 1)
|
||||
cur_sibling = m[extended_len - 1 + (key ^ 1)]
|
||||
return top_siblings + [cur_sibling]
|
||||
|
||||
def validate_merkle_proof(F, hash_fn, key, value, root, proof):
|
||||
h = hash_fn([value])
|
||||
for i in range(len(proof) - 1, -1, -1):
|
||||
if (1 << (len(proof) - 1 - i)) & key:
|
||||
h = hash_fn([proof[i], h])
|
||||
else:
|
||||
h = hash_fn([h, proof[i]])
|
||||
|
||||
return F.eq(root, h)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise ValueError('This script is not meant to be executed directly')
|
||||
61
circom/test_fibonacci.py
Normal file
61
circom/test_fibonacci.py
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/python3.10
|
||||
|
||||
from scripts.util import extract_contraints, generate_circuit, generate_input, generate_input_fibonnaci, measure_command
|
||||
|
||||
def test_circuit(circuit_name, input_path,pot_path,verbose=True,time = True, memory = True):
|
||||
# print("inside test_circuit")
|
||||
r1cs_path = 'output/compiled_circuit/compiled_{}/{}.r1cs'
|
||||
# print("r1cs_path: ",r1cs_path)
|
||||
t_c,m_c = measure_command(f'./scripts/compile_circuit.sh ./circuits/benchmark/{circuit_name}.circom {input_path} --nodejs',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Compile Circuit: {"" if t_c is None else f"{t_c} seconds"} {"" if m_c is None else f"{m_c} KB"}')
|
||||
constraints = extract_contraints(r1cs_path.format(circuit_name,circuit_name))
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Constraints: {constraints}')
|
||||
# print("before setup prover")
|
||||
t_sp,m_sp = measure_command(f'./scripts/proving_system/setup_prover.sh {circuit_name} {pot_path}',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Setup Prover: {"" if t_sp is None else f"{t_sp} seconds"} {"" if m_sp is None else f"{m_sp} KB"}')
|
||||
# print("after setup prover")
|
||||
# print("before prove")
|
||||
t_p,m_p = measure_command(f'./scripts/proving_system/prover.sh {circuit_name} ',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Prover: {"" if t_p is None else f"{t_p} seconds"} {"" if m_p is None else f"{m_p} KB"}')
|
||||
# print("after prove")
|
||||
t_v,m_v = measure_command(f'./scripts/proving_system/verifier.sh {circuit_name}',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Verifier: {"" if t_v is None else f"{t_v} seconds"} {"" if m_v is None else f"{m_v} KB"}')
|
||||
|
||||
return {'CIRCUIT':circuit_name,
|
||||
'INPUT SIZE':input_path.split('_')[-1].split('.')[0],
|
||||
'CONSTRAINTS':constraints,
|
||||
'COMPILE_TIME':t_c,
|
||||
'COMPILE_MEMORY':m_c,
|
||||
'SETUP_TIME':t_sp,
|
||||
'SETUP_MEMORY':m_sp,
|
||||
'PROVER_TIME':t_p,
|
||||
'PROVER_MEMORY':m_p,
|
||||
'VERIFIER_TIME':t_v,
|
||||
'VERIFIER_MEMORY':m_v}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# test fibonacci circuit
|
||||
TIME, MEMORY = True, True
|
||||
POT = './powersoftau/28pot.ptau'
|
||||
NUM = 100000
|
||||
|
||||
circuit_name = f'fibonacci'
|
||||
|
||||
# print("before generate_circuit")
|
||||
generate_circuit({'NUM':NUM},f'./circuits/base/{circuit_name}.circom',id=NUM)
|
||||
# print("after generate_circuit")
|
||||
# print("before generate_input")
|
||||
generate_input_fibonnaci(f'./input/input_fibonacci.json')
|
||||
# print("after generate_input")
|
||||
# print("before test_circuit")
|
||||
|
||||
measures = test_circuit(f'{circuit_name}_{NUM}',f'/input/input_fibonacci.json',POT,time=TIME,memory=MEMORY)
|
||||
print("measures: ",measures)
|
||||
|
||||
|
||||
84
circom/test_merkle.py
Normal file
84
circom/test_merkle.py
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/python3.10
|
||||
import random
|
||||
# import node_modules.circomlib.test as nt
|
||||
# from node_modules.circomlib.test.eddsa import buildEddsa
|
||||
from scripts.util import extract_contraints, generate_circuit, generate_input, measure_command, create_merkle_tree, generate_merkle_proof, validate_merkle_proof, generate_input_merkle
|
||||
|
||||
def test_circuit(circuit_name, input_path,pot_path,verbose=True,time = True, memory = True):
|
||||
# print("inside test_circuit")
|
||||
r1cs_path = 'output/compiled_circuit/compiled_{}/{}.r1cs'
|
||||
# print("r1cs_path: ",r1cs_path)
|
||||
t_c,m_c = measure_command(f'./scripts/compile_circuit.sh ./circuits/benchmark/{circuit_name}.circom {input_path} --nodejs',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Compile Circuit: {"" if t_c is None else f"{t_c} seconds"} {"" if m_c is None else f"{m_c} KB"}')
|
||||
constraints = extract_contraints(r1cs_path.format(circuit_name,circuit_name))
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Constraints: {constraints}')
|
||||
# print("before setup prover")
|
||||
t_sp,m_sp = measure_command(f'./scripts/proving_system/setup_prover.sh {circuit_name} {pot_path}',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Setup Prover: {"" if t_sp is None else f"{t_sp} seconds"} {"" if m_sp is None else f"{m_sp} KB"}')
|
||||
# print("after setup prover")
|
||||
# print("before prove")
|
||||
t_p,m_p = measure_command(f'./scripts/proving_system/prover.sh {circuit_name} ',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Prover: {"" if t_p is None else f"{t_p} seconds"} {"" if m_p is None else f"{m_p} KB"}')
|
||||
# print("after prove")
|
||||
t_v,m_v = measure_command(f'./scripts/proving_system/verifier.sh {circuit_name}',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Verifier: {"" if t_v is None else f"{t_v} seconds"} {"" if m_v is None else f"{m_v} KB"}')
|
||||
|
||||
return {'CIRCUIT':circuit_name,
|
||||
'INPUT SIZE':input_path.split('_')[-1].split('.')[0],
|
||||
'CONSTRAINTS':constraints,
|
||||
'COMPILE_TIME':t_c,
|
||||
'COMPILE_MEMORY':m_c,
|
||||
'SETUP_TIME':t_sp,
|
||||
'SETUP_MEMORY':m_sp,
|
||||
'PROVER_TIME':t_p,
|
||||
'PROVER_MEMORY':m_p,
|
||||
'VERIFIER_TIME':t_v,
|
||||
'VERIFIER_MEMORY':m_v}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# test sha256 circuit given the size of an image as input
|
||||
TIME, MEMORY = True, True
|
||||
POT = './powersoftau/28pot.ptau'
|
||||
NUM = 3
|
||||
# Generate a random array of BigInt-like numbers
|
||||
def random_array(length):
|
||||
return [int(random.random() * 10 ** 45) for _ in range(length)]
|
||||
# Create the array of secret keys
|
||||
secret_keys = random_array(2 ** NUM)
|
||||
# Choose a random key from the array
|
||||
chosen_key = random.choice(secret_keys)
|
||||
# Get the index of the chosen key
|
||||
chosen_key_index = secret_keys.index(chosen_key)
|
||||
# Print the index of the chosen key
|
||||
print(chosen_key_index)
|
||||
|
||||
circuit_name = f'merkle'
|
||||
|
||||
# print("before generate_circuit")
|
||||
generate_circuit({'NUM':NUM},f'./circuits/base/{circuit_name}.circom',id=NUM)
|
||||
# print("after generate_circuit")
|
||||
# print("before generate_input")
|
||||
# eddsa = nt.eddsa.buildEddsa()
|
||||
# field = eddsa.baby_jub.F
|
||||
# hash_function = eddsa.poseidon
|
||||
|
||||
merkle_tree = create_merkle_tree(secret_keys, NUM)
|
||||
merkle_root = merkle_tree[0]
|
||||
merkle_proof = generate_merkle_proof(merkle_tree, chosen_key_index, NUM)
|
||||
print("merkle_root: ",merkle_root)
|
||||
print("merkle_proof: ",merkle_proof)
|
||||
|
||||
generate_input_merkle(f'./input/input_merkle_{NUM}.json',chosen_key_index,chosen_key,merkle_root,merkle_proof)
|
||||
# print("after generate_input")
|
||||
# print("before test_circuit")
|
||||
|
||||
measures = test_circuit(f'{circuit_name}_{NUM}',f'/input/input_merkle_{NUM}.json',POT,time=TIME,memory=MEMORY)
|
||||
print("measures: ",measures)
|
||||
|
||||
|
||||
61
circom/test_poseidon.py
Normal file
61
circom/test_poseidon.py
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/python3.10
|
||||
|
||||
from scripts.util import extract_contraints, generate_circuit, generate_input, measure_command
|
||||
|
||||
def test_circuit(circuit_name, input_path,pot_path,verbose=True,time = True, memory = True):
|
||||
# print("inside test_circuit")
|
||||
r1cs_path = 'output/compiled_circuit/compiled_{}/{}.r1cs'
|
||||
# print("r1cs_path: ",r1cs_path)
|
||||
t_c,m_c = measure_command(f'./scripts/compile_circuit.sh ./circuits/benchmark/{circuit_name}.circom {input_path} --nodejs',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Compile Circuit: {"" if t_c is None else f"{t_c} seconds"} {"" if m_c is None else f"{m_c} KB"}')
|
||||
constraints = extract_contraints(r1cs_path.format(circuit_name,circuit_name))
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Constraints: {constraints}')
|
||||
# print("before setup prover")
|
||||
t_sp,m_sp = measure_command(f'./scripts/proving_system/setup_prover.sh {circuit_name} {pot_path}',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Setup Prover: {"" if t_sp is None else f"{t_sp} seconds"} {"" if m_sp is None else f"{m_sp} KB"}')
|
||||
# print("after setup prover")
|
||||
# print("before prove")
|
||||
t_p,m_p = measure_command(f'./scripts/proving_system/prover.sh {circuit_name} ',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Prover: {"" if t_p is None else f"{t_p} seconds"} {"" if m_p is None else f"{m_p} KB"}')
|
||||
# print("after prove")
|
||||
t_v,m_v = measure_command(f'./scripts/proving_system/verifier.sh {circuit_name}',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Verifier: {"" if t_v is None else f"{t_v} seconds"} {"" if m_v is None else f"{m_v} KB"}')
|
||||
|
||||
return {'CIRCUIT':circuit_name,
|
||||
'INPUT SIZE':input_path.split('_')[-1].split('.')[0],
|
||||
'CONSTRAINTS':constraints,
|
||||
'COMPILE_TIME':t_c,
|
||||
'COMPILE_MEMORY':m_c,
|
||||
'SETUP_TIME':t_sp,
|
||||
'SETUP_MEMORY':m_sp,
|
||||
'PROVER_TIME':t_p,
|
||||
'PROVER_MEMORY':m_p,
|
||||
'VERIFIER_TIME':t_v,
|
||||
'VERIFIER_MEMORY':m_v}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# test sha256 circuit given the size of an image as input
|
||||
TIME, MEMORY = True, True
|
||||
POT = './powersoftau/28pot.ptau'
|
||||
NUM = 10240
|
||||
|
||||
circuit_name = f'poseidon_sponge'
|
||||
|
||||
# print("before generate_circuit")
|
||||
generate_circuit({'NUM':NUM},f'./circuits/base/{circuit_name}.circom',id=NUM)
|
||||
# print("after generate_circuit")
|
||||
# print("before generate_input")
|
||||
generate_input(f'./input/input_{NUM}.json',NUM)
|
||||
# print("after generate_input")
|
||||
# print("before test_circuit")
|
||||
|
||||
measures = test_circuit(f'{circuit_name}_{NUM}',f'/input/input_{NUM}.json',POT,time=TIME,memory=MEMORY)
|
||||
print("measures: ",measures)
|
||||
|
||||
|
||||
61
circom/test_sha256.py
Executable file
61
circom/test_sha256.py
Executable file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/python3.10
|
||||
|
||||
from scripts.util import extract_contraints, generate_circuit, generate_input, measure_command
|
||||
|
||||
def test_circuit(circuit_name, input_path,pot_path,verbose=True,time = True, memory = True):
|
||||
# print("inside test_circuit")
|
||||
r1cs_path = 'output/compiled_circuit/compiled_{}/{}.r1cs'
|
||||
# print("r1cs_path: ",r1cs_path)
|
||||
t_c,m_c = measure_command(f'./scripts/compile_circuit.sh ./circuits/benchmark/{circuit_name}.circom {input_path} --nodejs',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Compile Circuit: {"" if t_c is None else f"{t_c} seconds"} {"" if m_c is None else f"{m_c} KB"}')
|
||||
constraints = extract_contraints(r1cs_path.format(circuit_name,circuit_name))
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Constraints: {constraints}')
|
||||
# print("before setup prover")
|
||||
t_sp,m_sp = measure_command(f'./scripts/proving_system/setup_prover.sh {circuit_name} {pot_path}',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Setup Prover: {"" if t_sp is None else f"{t_sp} seconds"} {"" if m_sp is None else f"{m_sp} KB"}')
|
||||
# print("after setup prover")
|
||||
# print("before prove")
|
||||
t_p,m_p = measure_command(f'./scripts/proving_system/prover.sh {circuit_name} ',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Prover: {"" if t_p is None else f"{t_p} seconds"} {"" if m_p is None else f"{m_p} KB"}')
|
||||
# print("after prove")
|
||||
t_v,m_v = measure_command(f'./scripts/proving_system/verifier.sh {circuit_name}',time,memory)
|
||||
if verbose:
|
||||
print(f'[{circuit_name}] Verifier: {"" if t_v is None else f"{t_v} seconds"} {"" if m_v is None else f"{m_v} KB"}')
|
||||
|
||||
return {'CIRCUIT':circuit_name,
|
||||
'INPUT SIZE':input_path.split('_')[-1].split('.')[0],
|
||||
'CONSTRAINTS':constraints,
|
||||
'COMPILE_TIME':t_c,
|
||||
'COMPILE_MEMORY':m_c,
|
||||
'SETUP_TIME':t_sp,
|
||||
'SETUP_MEMORY':m_sp,
|
||||
'PROVER_TIME':t_p,
|
||||
'PROVER_MEMORY':m_p,
|
||||
'VERIFIER_TIME':t_v,
|
||||
'VERIFIER_MEMORY':m_v}
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# test sha256 circuit given the size of an image as input
|
||||
TIME, MEMORY = True, True
|
||||
POT = './powersoftau/28pot.ptau'
|
||||
NUM = 2048
|
||||
|
||||
circuit_name = f'sha256_bytes'
|
||||
|
||||
# print("before generate_circuit")
|
||||
generate_circuit({'NUM':NUM},f'./circuits/base/{circuit_name}.circom',id=NUM)
|
||||
# print("after generate_circuit")
|
||||
# print("before generate_input")
|
||||
generate_input(f'./input/input_{NUM}.json',NUM)
|
||||
# print("after generate_input")
|
||||
# print("before test_circuit")
|
||||
|
||||
measures = test_circuit(f'{circuit_name}_{NUM}',f'/input/input_{NUM}.json',POT,time=TIME,memory=MEMORY)
|
||||
print("measures: ",measures)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user