Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add BN254 Curve for Groth16 #961

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 30 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
[workspace]

members = ["math", "crypto", "gpu", "benches", "provers/plonk", "provers/stark", "provers/groth16", "provers/groth16/arkworks-adapter", "provers/groth16/circom-adapter", "examples/merkle-tree-cli", "examples/prove-miden", "provers/winterfell_adapter", "examples/shamir_secret_sharing","examples/pinocchio", "examples/prove-verify-circom", "examples/baby-snark"]
members = [
"math",
"crypto",
"gpu",
"benches",
"provers/plonk",
"provers/stark",
"provers/groth16/bn_254",
"provers/groth16/bn_254/circom-adapter",
"provers/groth16/bls12_381",
"provers/groth16/bls12_381/arkworks-adapter",
"provers/groth16/bls12_381/circom-adapter",
"examples/merkle-tree-cli",
"examples/prove-miden",
"provers/winterfell_adapter",
"examples/shamir_secret_sharing",
"examples/pinocchio",
"examples/prove-verify-circom",
"examples/baby-snark",
]
exclude = ["ensure-no_std"]
resolver = "2"

Expand All @@ -16,16 +35,18 @@ lambdaworks-crypto = { path = "./crypto", version = "0.11.0", default-features =
lambdaworks-gpu = { path = "./gpu", version = "0.11.0" }
lambdaworks-math = { path = "./math", version = "0.11.0", default-features = false }
stark-platinum-prover = { path = "./provers/stark" }
lambdaworks-winterfell-adapter = { path = "./provers/winterfell_adapter"}
lambdaworks-groth16 = { path = "./provers/groth16" }
lambdaworks-circom-adapter = { path = "./provers/groth16/circom-adapter" }
lambdaworks-winterfell-adapter = { path = "./provers/winterfell_adapter" }
lambdaworks-groth16-bn-254 = { path = "./provers/groth16/bn_254" }
lambdaworks-groth16-bls12-381 = { path = "./provers/groth16/bls12_381" }
lambdaworks-circom-adapter-bn-254 = { path = "./provers/groth16/bn_254/circom-adapter" }
lambdaworks-circom-adapter-bls12-381 = { path = "./provers/groth16/bls12_381/circom-adapter" }

[patch.crates-io]
winter-air = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4"}
winter-prover = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4"}
winter-math = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4"}
winter-utils = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4"}
winter-crypto = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4"}
winter-air = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4" }
winter-prover = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4" }
winter-math = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4" }
winter-utils = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4" }
winter-crypto = { git = "https://github.com/lambdaclass/winterfell-for-lambdaworks.git", branch = "derive-clone-v6.4" }
miden-air = { git = "https://github.com/lambdaclass/miden-vm" }
miden-core = { git = "https://github.com/lambdaclass/miden-vm" }
miden-assembly = { git = "https://github.com/lambdaclass/miden-vm" }
Expand Down
4 changes: 2 additions & 2 deletions examples/prove-verify-circom/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ path = "src/main.rs"

[dependencies]
lambdaworks-crypto = { workspace = true }
lambdaworks-groth16 = { workspace = true }
lambdaworks-groth16-bls12-381 = { workspace = true }
lambdaworks-math = { workspace = true, features = ["lambdaworks-serde-string"] }
lambdaworks-circom-adapter = { workspace = true }
lambdaworks-circom-adapter-bls12-381 = { workspace = true }
serde = { version = "1.0" }
serde_json = "1"
4 changes: 2 additions & 2 deletions examples/prove-verify-circom/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fs;

use lambdaworks_circom_adapter::*;
use lambdaworks_groth16::*;
use lambdaworks_circom_adapter_bls12_381::*;
use lambdaworks_groth16_bls12_381::*;

const TEST_DIR: &str = "input_files/";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ use crate::{
field::{
element::FieldElement,
fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField},
traits::IsFFTField,
},
unsigned_integer::element::U256,
unsigned_integer::element::{UnsignedInteger, U256},
};

#[derive(Clone, Debug)]
pub struct FrConfig;

/// Modulus of bn 254 subgroup r = 21888242871839275222246405745257275088548364400416034343698204186575808495617, aka order
/// We define Fr where r is the number of points that the eliptic curve BN254 has.
/// I.e. r is the order of the group BN254 Curve.
/// r = 21888242871839275222246405745257275088548364400416034343698204186575808495617.
impl IsModulus<U256> for FrConfig {
const MODULUS: U256 = U256::from_hex_unchecked(
"30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001",
Expand All @@ -20,3 +23,16 @@ impl IsModulus<U256> for FrConfig {
pub type FrField = MontgomeryBackendPrimeField<FrConfig, 4>;
/// FrElement using MontgomeryBackend for Bn254
pub type FrElement = FieldElement<FrField>;

/// TWO_ADICITY is 28 because there is a subgroup of Fr of order 2^28.
/// Note that 2^28 divides r - 1.
/// (r - 1) / 2^28 mod r = 81540058820840996586704275553141814055101440848469862132140264610111.
/// We calculated the TWO_ADIC_PRIMITVE_ROOT_OF_UNITY in the following way:
/// g = 5 is a primitive root of order r - 1, that is, g^{r-1} = 1 and g^i != 1 for i < r-1.
/// Then g^{(r-1) / 2^28} is a primitive root of order 2^28.
impl IsFFTField for FrField {
const TWO_ADICITY: u64 = 28;
const TWO_ADIC_PRIMITVE_ROOT_OF_UNITY: Self::BaseType = UnsignedInteger::from_hex_unchecked(
"2A3C09F0A58A7E8500E0A7EB8EF62ABC402D111E41112ED49BD61B6E725B19F0",
);
}
16 changes: 16 additions & 0 deletions provers/groth16/bls12_381/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[package]
name = "lambdaworks-groth16-bls12-381"
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lambdaworks-math.workspace = true
lambdaworks-crypto.workspace = true
rand_chacha = "0.3.1"
serde = "1.0"
serde_json = "1.0"
rand = "0.8.5"
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "arkworks_adapter"
name = "arkworks_adapter_bls12_381"
version.workspace = true
edition.workspace = true
license.workspace = true
Expand All @@ -8,12 +8,12 @@ repository.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lambdaworks-math = { path = "../../../math" }
lambdaworks-groth16 = { path = "../" }
ark-r1cs-std = { version = "^0.3.1"}
ark-bls12-381 = { version = "0.4.0"}
lambdaworks-math = { path = "../../../../math" }
lambdaworks-groth16-bls12-381 = { path = "../" }
ark-r1cs-std = { version = "^0.3.1" }
ark-bls12-381 = { version = "0.4.0" }
ark-ff = { version = "^0.4.2" }
ark-relations = { version = "^0.4.0" }
ark-serialize = {version = "0.4.2"}
ark-serialize = { version = "0.4.2" }
num-bigint = { version = "0.4", default-features = false }
rand = "0.8.5"
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::arkworks_cs_to_lambda_cs;
use ark_bls12_381::Fr;
use ark_relations::{lc, r1cs::ConstraintSystem, r1cs::Variable};
use lambdaworks_groth16::{setup, verify, Prover, QuadraticArithmeticProgram};
use lambdaworks_groth16_bls12_381::{setup, verify, Prover, QuadraticArithmeticProgram};
use rand::Rng;

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ mod integration_tests;

use ark_ff::PrimeField;
use ark_relations::r1cs::{ConstraintSystemRef, Field};
use lambdaworks_groth16::{common::*, r1cs::R1CS, ConstraintSystem};
use lambdaworks_groth16_bls12_381::{common::*, r1cs::R1CS, ConstraintSystem};
use lambdaworks_math::traits::ByteConversion;

use std::ops::Deref;
Expand Down
14 changes: 14 additions & 0 deletions provers/groth16/bls12_381/circom-adapter/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "lambdaworks-circom-adapter-bls12-381"
version.workspace = true
edition.workspace = true
license.workspace = true
repository.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lambdaworks-math = { path = "../../../../math" }
lambdaworks-groth16-bls12-381 = { path = "../" }
serde = { version = "1.0" }
serde_json = "1"
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ This package allows one to perform trusted setup, prove, and verify constraints
circom test.circom --r1cs --wasm -p bls12381
```

This will create a **test_js** directory, and a **test.r1cs** file. Do not skip the **-p bls12381** flag as this is the only field supported by this adapter right now.
This will create a **test_js** directory, and a **test.r1cs** file. Do not skip the **-p bls12381** flag because the default curve is the bn-254.

3. ```bash
node test_js/generate_witness.js test_js/test.wasm input.json witness.wtns
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::fs;

use crate::*;
use lambdaworks_groth16::*;
use lambdaworks_groth16_bls12_381::*;

const TEST_DIR: &str = "test_files";

Expand Down
116 changes: 116 additions & 0 deletions provers/groth16/bls12_381/circom-adapter/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#[cfg(test)]
mod integration_tests;

use lambdaworks_groth16_bls12_381::{common::FrElement, QuadraticArithmeticProgram as QAP};
use lambdaworks_math::unsigned_integer::element::UnsignedInteger;
use serde_json::Value;

pub fn circom_to_lambda(
r1cs_file_content: &str,
witness_file_content: &str,
) -> (QAP, Vec<FrElement>) {
let circom_r1cs: Value = serde_json::from_str(r1cs_file_content).expect("Error parsing JSON");
let [mut l, mut r, mut o] = build_lro_from_circom_r1cs(&circom_r1cs);

let mut witness: Vec<_> = serde_json::from_str::<Vec<String>>(witness_file_content)
.expect("Error parsing JSON")
.iter()
.map(|num_str| circom_str_to_lambda_field_element(num_str))
.collect();
adjust_lro_and_witness(&circom_r1cs, &mut l, &mut r, &mut o, &mut witness);

// Lambdaworks considers "1" a public input, so compensate for it
let num_of_pub_inputs = circom_r1cs["nPubInputs"].as_u64().unwrap() as usize + 1;

(
QAP::from_variable_matrices(num_of_pub_inputs, &l, &r, &o),
witness,
)
}

/// Takes as input circom.r1cs.json file and outputs LRO matrices
#[inline]
fn build_lro_from_circom_r1cs(circom_r1cs: &Value) -> [Vec<Vec<FrElement>>; 3] {
let num_of_vars = circom_r1cs["nVars"].as_u64().unwrap() as usize; // Includes "1"
let num_of_gates = circom_r1cs["nConstraints"].as_u64().unwrap() as usize;

let mut l = vec![vec![FrElement::zero(); num_of_gates]; num_of_vars];
let mut r = vec![vec![FrElement::zero(); num_of_gates]; num_of_vars];
let mut o = vec![vec![FrElement::zero(); num_of_gates]; num_of_vars];

for (constraint_idx, constraint) in circom_r1cs["constraints"]
.as_array()
.unwrap()
.iter()
.enumerate()
{
let constraint = constraint.as_array().unwrap();
for (var_idx, str_val) in constraint[0].as_object().unwrap() {
l[var_idx.parse::<usize>().unwrap()][constraint_idx] =
circom_str_to_lambda_field_element(str_val.as_str().unwrap());
}
for (var_idx, str_val) in constraint[1].as_object().unwrap() {
r[var_idx.parse::<usize>().unwrap()][constraint_idx] =
circom_str_to_lambda_field_element(str_val.as_str().unwrap());
}
for (var_idx, str_val) in constraint[2].as_object().unwrap() {
o[var_idx.parse::<usize>().unwrap()][constraint_idx] =
circom_str_to_lambda_field_element(str_val.as_str().unwrap());
}
}

[l, r, o]
}

/// Circom witness ordering: ["1", ..outputs, ...inputs, ...other_signals]
/// Lambda witness ordering: ["1", ...inputs, ..outputs, ...other_signals]
/// Same applies to rows of LRO (each representing a variable)
/// This function compensates this difference
#[inline]
fn adjust_lro_and_witness(
circom_r1cs: &Value,
l: &mut [Vec<FrElement>],
r: &mut [Vec<FrElement>],
o: &mut [Vec<FrElement>],
witness: &mut [FrElement],
) {
let num_of_private_inputs = circom_r1cs["nPrvInputs"].as_u64().unwrap() as usize;
let num_of_pub_inputs = circom_r1cs["nPubInputs"].as_u64().unwrap() as usize;
let num_of_inputs = num_of_pub_inputs + num_of_private_inputs;
let num_of_outputs = circom_r1cs["nOutputs"].as_u64().unwrap() as usize;

let mut temp_l = Vec::with_capacity(num_of_inputs);
let mut temp_r = Vec::with_capacity(num_of_inputs);
let mut temp_o = Vec::with_capacity(num_of_inputs);
let mut temp_witness = Vec::with_capacity(num_of_inputs);

for i in 0..num_of_inputs {
temp_l.push(l[num_of_outputs + 1 + i].clone());
temp_r.push(r[num_of_outputs + 1 + i].clone());
temp_o.push(o[num_of_outputs + 1 + i].clone());
temp_witness.push(witness[num_of_outputs + 1 + i].clone());
}

for i in 0..num_of_inputs {
let temp_l_i = l[1 + i].clone();
l[1 + i].clone_from(&temp_l[i]);
l[num_of_outputs + 1 + i].clone_from(&temp_l_i);

let temp_r_i = r[1 + i].clone();
r[1 + i].clone_from(&temp_r[i]);
r[num_of_outputs + 1 + i].clone_from(&temp_r_i);

let temp_o_i = o[1 + i].clone();
o[1 + i].clone_from(&temp_o[i]);
o[num_of_outputs + 1 + i].clone_from(&temp_o_i);

let temp_witness_i = witness[1 + i].clone();
witness[1 + i].clone_from(&temp_witness[i]);
witness[num_of_outputs + 1 + i].clone_from(&temp_witness_i);
}
}

#[inline]
fn circom_str_to_lambda_field_element(value: &str) -> FrElement {
FrElement::from(&UnsignedInteger::<4>::from_dec_str(value).unwrap())
}
Loading
Loading