From 8002f006fc3f788010a3f1d8d1eca2746b1498d9 Mon Sep 17 00:00:00 2001 From: Anubha Jain Date: Thu, 21 Nov 2024 16:52:00 +0530 Subject: [PATCH] added circom code Signed-off-by: Anubha Jain --- circom/.gitignore | 10 + circom/README.md | 40 +++ circom/circuits/base/fibonacci.circom | 19 ++ circom/circuits/base/merkle.circom | 63 ++++ circom/circuits/base/poseidon_sponge.circom | 52 +++ circom/circuits/base/sha256_bytes.circom | 39 +++ circom/package.json | 15 + circom/requirements.txt | 4 + circom/scripts/compile_circuit.sh | 47 +++ circom/scripts/proving_system/prover.sh | 18 ++ circom/scripts/proving_system/setup_prover.sh | 22 ++ circom/scripts/proving_system/verifier.sh | 23 ++ circom/scripts/util.py | 295 ++++++++++++++++++ circom/test_fibonacci.py | 61 ++++ circom/test_merkle.py | 84 +++++ circom/test_poseidon.py | 61 ++++ circom/test_sha256.py | 61 ++++ 17 files changed, 914 insertions(+) create mode 100644 circom/.gitignore create mode 100644 circom/README.md create mode 100644 circom/circuits/base/fibonacci.circom create mode 100644 circom/circuits/base/merkle.circom create mode 100644 circom/circuits/base/poseidon_sponge.circom create mode 100644 circom/circuits/base/sha256_bytes.circom create mode 100644 circom/package.json create mode 100644 circom/requirements.txt create mode 100755 circom/scripts/compile_circuit.sh create mode 100755 circom/scripts/proving_system/prover.sh create mode 100755 circom/scripts/proving_system/setup_prover.sh create mode 100755 circom/scripts/proving_system/verifier.sh create mode 100755 circom/scripts/util.py create mode 100644 circom/test_fibonacci.py create mode 100644 circom/test_merkle.py create mode 100644 circom/test_poseidon.py create mode 100755 circom/test_sha256.py diff --git a/circom/.gitignore b/circom/.gitignore new file mode 100644 index 0000000..21704cc --- /dev/null +++ b/circom/.gitignore @@ -0,0 +1,10 @@ +/input/ +/output/ +/powersoftau/ +/circuits/benchmark/ +/result/ +**/__pycache__ +/node_modules/ +package-lock.json +env/ +powersoftau diff --git a/circom/README.md b/circom/README.md new file mode 100644 index 0000000..b7896f5 --- /dev/null +++ b/circom/README.md @@ -0,0 +1,40 @@ +# Benchmark Circuits +[![Circom Badge](https://img.shields.io/badge/circuits-circom-black)](https://github.com/iden3/circom) +[![Snarkjs Badge](https://img.shields.io/badge/proof_system-snarkjs-yellow)](https://github.com/iden3/snarkjs) +![Python Badge](https://img.shields.io/badge/compile-python-green) + + + + + +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:** + +[![MIT License](https://img.shields.io/badge/License-MIT-red.svg)](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. + diff --git a/circom/circuits/base/fibonacci.circom b/circom/circuits/base/fibonacci.circom new file mode 100644 index 0000000..654ad8e --- /dev/null +++ b/circom/circuits/base/fibonacci.circom @@ -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); \ No newline at end of file diff --git a/circom/circuits/base/merkle.circom b/circom/circuits/base/merkle.circom new file mode 100644 index 0000000..a589902 --- /dev/null +++ b/circom/circuits/base/merkle.circom @@ -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); \ No newline at end of file diff --git a/circom/circuits/base/poseidon_sponge.circom b/circom/circuits/base/poseidon_sponge.circom new file mode 100644 index 0000000..a64e912 --- /dev/null +++ b/circom/circuits/base/poseidon_sponge.circom @@ -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 [--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]" diff --git a/circom/scripts/proving_system/prover.sh b/circom/scripts/proving_system/prover.sh new file mode 100755 index 0000000..e592ee5 --- /dev/null +++ b/circom/scripts/proving_system/prover.sh @@ -0,0 +1,18 @@ +if [ $# -ne 1 ]; then + echo "Usage: ./prover.sh " + 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 diff --git a/circom/scripts/proving_system/setup_prover.sh b/circom/scripts/proving_system/setup_prover.sh new file mode 100755 index 0000000..6dcff68 --- /dev/null +++ b/circom/scripts/proving_system/setup_prover.sh @@ -0,0 +1,22 @@ + +if [ $# -ne 2 ]; then + echo "Usage: ./setup_prover.sh " + 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 + diff --git a/circom/scripts/proving_system/verifier.sh b/circom/scripts/proving_system/verifier.sh new file mode 100755 index 0000000..1ab1113 --- /dev/null +++ b/circom/scripts/proving_system/verifier.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +if [ $# -lt 1 ]; then + echo "Usage: ./verifier.sh [--generate-contract ]" + 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 \ No newline at end of file diff --git a/circom/scripts/util.py b/circom/scripts/util.py new file mode 100755 index 0000000..226c0c7 --- /dev/null +++ b/circom/scripts/util.py @@ -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') \ No newline at end of file diff --git a/circom/test_fibonacci.py b/circom/test_fibonacci.py new file mode 100644 index 0000000..9a2e144 --- /dev/null +++ b/circom/test_fibonacci.py @@ -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) + + \ No newline at end of file diff --git a/circom/test_merkle.py b/circom/test_merkle.py new file mode 100644 index 0000000..d468328 --- /dev/null +++ b/circom/test_merkle.py @@ -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) + + \ No newline at end of file diff --git a/circom/test_poseidon.py b/circom/test_poseidon.py new file mode 100644 index 0000000..a098cec --- /dev/null +++ b/circom/test_poseidon.py @@ -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) + + \ No newline at end of file diff --git a/circom/test_sha256.py b/circom/test_sha256.py new file mode 100755 index 0000000..6da003f --- /dev/null +++ b/circom/test_sha256.py @@ -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) + + \ No newline at end of file