diff --git a/Cargo.toml b/Cargo.toml index 8ff0730..2d03082 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,9 @@ edition = "2021" [lib] crate-type = ["cdylib", "rlib"] -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -ark-pallas = { version = "0.4.0", features = ["r1cs"] } -ark-vesta = {version="0.4.0", features=["r1cs"]} -ark-circom = { git = "https://github.com/arnaucube/circom-compat.git" } +ark-bn254 = { version = "0.4.0", features = ["r1cs"] } +ark-grumpkin = {version="0.4.0", features=["r1cs"]} ark-ec = "0.4.1" ark-ff = "0.4.1" ark-r1cs-std = { version = "0.4.0", default-features = false } @@ -24,9 +21,16 @@ ark-crypto-primitives = { version = "^0.4.0", default-features = false, features ark-std = "0.4.0" color-eyre = "0.6.2" num-bigint = "0.4.3" -sonobe = { git = "https://github.com/privacy-scaling-explorations/sonobe", package = "folding-schemes", branch = "main" } +sonobe = { git = "https://github.com/privacy-scaling-explorations/sonobe", package = "folding-schemes", branch = "circom-external-inputs" } serde = "1.0.198" serde_json = "1.0.116" [dev-dependencies] lazy_static = "1.4.0" + +[patch.crates-io] +# patch ark_curves to use a cherry-picked version which contains +# bn254::constraints & grumpkin for v0.4.0 (once arkworks v0.5.0 is released +# this will no longer be needed) +ark-bn254 = { git = "https://github.com/arnaucube/ark-curves-cherry-picked", branch="cherry-pick"} +ark-grumpkin = { git = "https://github.com/arnaucube/ark-curves-cherry-picked", branch="cherry-pick"} diff --git a/circom/grapevine.circom b/circom/grapevine.circom index cb363cb..e0f5d63 100644 --- a/circom/grapevine.circom +++ b/circom/grapevine.circom @@ -17,10 +17,18 @@ template grapevine(num_felts) { signal input ivc_input[4]; signal output ivc_output[4]; - // private inputs - signal input phrase[num_felts]; // secret phrase, if first iteration - signal input usernames[2]; // prev username, current username - signal input auth_secrets[2]; // prev degree's user secret, current degree's user secret + // external inputs at each folding step + signal input external_inputs[num_felts+2+2]; + signal phrase[num_felts]; // secret phrase, if first iteration + for (var i=0; i { - circom_wrapper: CircomWrapper, - private_input: CircomPrivateInput, -} - -impl GrapevineFCircuit { - pub fn set_private_input(&mut self, input: CircomPrivateInput) { - self.private_input = input; - } -} - -impl FCircuit for GrapevineFCircuit { - type Params = (PathBuf, PathBuf); - - fn new(params: Self::Params) -> Self { - let (r1cs_path, wasm_path) = params; - let circom_wrapper = CircomWrapper::new(r1cs_path, wasm_path); - Self { - circom_wrapper, - private_input: CircomPrivateInput::empty(false), - } - } - - fn state_len(&self) -> usize { - 4 - } - - fn step_native(&self, _i: usize, z_i: Vec) -> Result, SonobeError> { - // convert ivc_input from ark ff to BigInt - let ivc_input = z_i - .iter() - .map(|val| CircomWrapper::ark_primefield_to_num_bigint(*val)) - .collect::>(); - let mut inputs = vec![("ivc_input".to_string(), ivc_input)]; - - // set the private inputs - if self.private_input.uninitialized() { - return Err(SonobeError::Other("Private input not set".to_string())); - } - let private_input = CircomWrapper::::marshal_private_inputs(&self.private_input); - inputs.extend(private_input); - - // calculate witness - let witness = self.circom_wrapper.extract_witness(&inputs).map_err(|e| { - SonobeError::WitnessCalculationError(format!("Failed to calculate witness: {}", e)) - })?; - - // extract the z_i1 (next state) from witvec - let z_i1 = witness[1..1 + self.state_len()].to_vec(); - Ok(z_i1) - } - - fn generate_step_constraints( - &self, - cs: ConstraintSystemRef, - _i: usize, - z_i: Vec>, - ) -> Result>, SynthesisError> { - // convert ivc input from FpVar to ark ff to BigInt - let ivc_input: Vec = z_i - .iter() - .map(|val| CircomWrapper::ark_primefield_to_num_bigint(val.value().unwrap())) - .collect(); - let mut inputs = vec![("ivc_input".to_string(), ivc_input)]; - - // set the private inputs - if self.private_input.uninitialized() { - return Err(SynthesisError::AssignmentMissing); - } - let private_input = CircomWrapper::::marshal_private_inputs(&self.private_input); - inputs.extend(private_input); - - println!("Inputs: {:?}", inputs); - - // extract r1cs and witness - let (r1cs, witness) = self - .circom_wrapper - .extract_r1cs_and_witness(&inputs) - .map_err(|_| SynthesisError::AssignmentMissing)?; - - println!("Wire map len: {:?}", r1cs.clone().wire_mapping.unwrap().len()); - println!("Constraints len: {:?}", r1cs.clone().constraints.len()); - println!("Witness len: {:?}", witness.clone().unwrap().len()); - - // Initialize CircomCircuit - let circom_circuit = CircomCircuit { - r1cs, - witness: witness.clone(), - inputs_already_computed: false, - }; - - circom_circuit - .generate_constraints(cs.clone()) - .map_err(|_| SynthesisError::Unsatisfiable)?; - - if !cs.is_satisfied().unwrap() { - return Err(SynthesisError::Unsatisfiable); - }; - - let w = witness.ok_or(SynthesisError::Unsatisfiable)?; - - let z_i1: Vec> = - Vec::>::new_witness(cs.clone(), || Ok(w[1..1 + self.state_len()].to_vec()))?; - - Ok(z_i1) - } -} - #[cfg(test)] mod test { use super::*; use crate::params::test_nova_setup; - use crate::utils::{ - inputs::{get_z0, random_f_bigint}, - wrapper::CircomPrivateInput, + use crate::utils::inputs::{ + get_z0, prepare_external_inputs, random_f_bigint, CircomPrivateInput, }; - use ark_pallas::{constraints::GVar, Fr, Projective}; - use ark_r1cs_std::alloc::AllocVar; + use ark_bn254::{constraints::GVar, Fr, G1Projective as Projective}; + // use ark_circom::circom::CircomCircuit; + use ark_ff::PrimeField; + use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar}; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; - use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2}; use lazy_static::lazy_static; use num_bigint::BigInt; use sonobe::{ - commitment::pedersen::Pedersen, folding::nova::Nova, + commitment::pedersen::Pedersen, folding::nova::Nova, frontend::circom::CircomFCircuit, transcript::poseidon::poseidon_test_config, Error, FoldingScheme, }; + use sonobe::{frontend::FCircuit, Error as SonobeError}; use std::env::current_dir; + use std::path::PathBuf; use std::time::Instant; + use crate::errors::GrapevineError; + lazy_static! { pub static ref R1CS_PATH: PathBuf = PathBuf::from("./circom/artifacts/grapevine.r1cs"); pub static ref WASM_PATH: PathBuf = PathBuf::from("./circom/artifacts/grapevine.wasm"); @@ -168,21 +51,20 @@ mod test { auth_secrets: [None, Some(AUTH_SECRETS[0].clone())], chaff: false, }; - let z_0 = get_z0(); + let external_inputs = prepare_external_inputs::(&step_0_inputs); // initialize new Grapevine function circuit - let mut f_circuit = GrapevineFCircuit::::new((R1CS_PATH.clone(), WASM_PATH.clone())); - f_circuit.set_private_input(step_0_inputs); + let f_circuit = CircomFCircuit::::new((R1CS_PATH.clone(), WASM_PATH.clone(), 4, 6 + 4)); // 4=ivc_input.lenght, 6+4=external_inputs - let z_1 = f_circuit.step_native(0, z_0.to_vec()).unwrap(); + let z_0 = get_z0(); + let z_1 = f_circuit + .step_native(0, z_0.to_vec(), external_inputs) + .unwrap(); println!("z_1: {:?}", z_1); } #[test] fn test_step_constraints() { - // initialize new Grapevine function circuit - let mut f_circuit = GrapevineFCircuit::::new((R1CS_PATH.clone(), WASM_PATH.clone())); - // define inputs let step_0_inputs = CircomPrivateInput { phrase: Some(String::from(&*PHRASE)), @@ -190,22 +72,34 @@ mod test { auth_secrets: [None, Some(AUTH_SECRETS[0].clone())], chaff: false, }; - f_circuit.set_private_input(step_0_inputs); + let external_inputs = prepare_external_inputs::(&step_0_inputs); + + // initialize new Grapevine function circuit + let f_circuit = CircomFCircuit::::new((R1CS_PATH.clone(), WASM_PATH.clone(), 4, 6 + 4)); // 4=ivc_input.lenght, 6+4=external_inputs + + let z_0 = get_z0(); + let z_1 = f_circuit + .step_native(0, z_0.to_vec(), external_inputs.clone()) + .unwrap(); // assign z0 let cs = ConstraintSystem::::new_ref(); - let z_0_var = Vec::>::new_witness(cs.clone(), || Ok(get_z0())).unwrap(); + let z_0_var = Vec::>::new_witness(cs.clone(), || Ok(z_0)).unwrap(); + let external_inputs_var = + Vec::>::new_witness(cs.clone(), || Ok(external_inputs)).unwrap(); // compute constraints for step 0 let cs = ConstraintSystem::::new_ref(); let z_1_var = f_circuit - .generate_step_constraints(cs.clone(), 1, z_0_var) + .generate_step_constraints(cs.clone(), 1, z_0_var, external_inputs_var) .unwrap(); println!("z_1: {:?}", z_1_var); - // assert_eq!(z_i1_var.value().unwrap(), vec![Fr::from(38), Fr::from(1)]); + assert_eq!(z_1_var.value().unwrap(), z_1); } + // WIP + /* #[test] fn test_multiple_steps_native() { // initialize new Grapevine function circuit @@ -283,6 +177,7 @@ mod test { assert_eq!(z_i[0], Fr::from(3)); assert_eq!(z_i[3], Fr::from(0)); } + */ // #[test] // fn test_multiple_steps_constraints() { @@ -332,6 +227,7 @@ mod test { // // } + /* #[test] fn test_full_one_step() { // initialize new Grapevine function circuit @@ -340,7 +236,6 @@ mod test { // Get test params let (prover_params, verifier_params) = test_nova_setup::>(f_circuit.clone()); - // define inputs // define inputs @@ -406,4 +301,5 @@ mod test { .unwrap(); println!("Verified: {:?}", start.elapsed()); } + */ } diff --git a/src/nova.rs b/src/nova.rs index 906a961..af31d9f 100644 --- a/src/nova.rs +++ b/src/nova.rs @@ -1,3 +1,4 @@ +use ark_bn254::{constraints::GVar, Fr, G1Projective as Projective}; use ark_crypto_primitives::{ crh::{ poseidon::constraints::{CRHGadget, CRHParametersVar}, @@ -7,25 +8,22 @@ use ark_crypto_primitives::{ sponge::{poseidon::PoseidonConfig, Absorb}, }; use ark_ff::PrimeField; -use ark_pallas::{constraints::GVar, Fr, Projective}; -use ark_r1cs_std::{alloc::AllocVar, fields::FieldVar, fields::fp::FpVar}; +use ark_grumpkin::{constraints::GVar as Gvar2, Projective as Projective2}; +use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, fields::FieldVar}; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use ark_std::Zero; -use ark_vesta::{constraints::GVar as Gvar2, Projective as Projective2}; use core::marker::PhantomData; -use std::time::Instant; use sonobe::{ commitment::{pedersen::Pedersen, CommitmentScheme}, folding::nova::{get_r1cs, ProverParams, VerifierParams}, - frontend::FCircuit, - transcript::poseidon::poseidon_test_config + frontend::{circom::CircomFCircuit, FCircuit}, + transcript::poseidon::poseidon_test_config, }; +use std::time::Instant; -use crate::{ - params::test_nova_setup, - circom::GrapevineFCircuit, -}; +use crate::params::test_nova_setup; +/* WIP #[cfg(test)] mod test { use super::*; @@ -35,7 +33,8 @@ mod test { fn test_generate_params() { let r1cs_path = PathBuf::from("./circom/artifacts/circuit.r1cs"); let wasm_path = PathBuf::from("./circom/artifacts/circuit.wasm"); - let f_circuit = GrapevineFCircuit::::new((r1cs_path, wasm_path)); + let f_circuit = CircomFCircuit::::new((r1cs_path, wasm_path, 4, 6 + 4)); // 4=ivc_input.lenght, 6+4=external_inputs + let pre = Instant::now(); let (prover_params, verifier_params) = test_nova_setup::>(f_circuit); // let prover_params_str = serde_json::to_string(&prover_params).unwrap(); @@ -44,3 +43,4 @@ mod test { println!("Time to generate params: {:?}", pre.elapsed()); } } +*/ diff --git a/src/params.rs b/src/params.rs index f98cc65..a3094cf 100644 --- a/src/params.rs +++ b/src/params.rs @@ -1,45 +1,43 @@ -use ark_pallas::{constraints::GVar, Fr, Projective}; -use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2}; +use ark_bn254::{constraints::GVar, Fr, G1Projective as Projective}; +use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; use sonobe::{ commitment::{pedersen::Pedersen, CommitmentScheme}, folding::nova::{get_r1cs, ProverParams, VerifierParams}, frontend::FCircuit, - transcript::poseidon::poseidon_test_config + transcript::poseidon::poseidon_test_config, }; pub fn test_nova_setup>( - f_circuit: FC + f_circuit: FC, ) -> ( ProverParams, Pedersen>, - VerifierParams + VerifierParams, ) { let mut rng = ark_std::test_rng(); let poseidon_config = poseidon_test_config::(); // get CM & CF_CM len - let (r1cs, cf_r1cs) = get_r1cs::( - &poseidon_config, - f_circuit, - ).unwrap(); + let (r1cs, cf_r1cs) = + get_r1cs::(&poseidon_config, f_circuit).unwrap(); let cf_len = r1cs.A.n_rows; let cf_cf_len = cf_r1cs.A.n_rows; let (pedersen_params, _) = Pedersen::::setup(&mut rng, cf_len).unwrap(); let (cf_pedersen_params, _) = Pedersen::::setup(&mut rng, cf_cf_len).unwrap(); - let prover_params = - ProverParams::, Pedersen>{ - poseidon_config: poseidon_config.clone(), - cs_params: pedersen_params, - cf_cs_params: cf_pedersen_params + let prover_params = + ProverParams::, Pedersen> { + poseidon_config: poseidon_config.clone(), + cs_params: pedersen_params, + cf_cs_params: cf_pedersen_params, }; - - let verifier_params = VerifierParams::{ + + let verifier_params = VerifierParams:: { poseidon_config: poseidon_config.clone(), r1cs, - cf_r1cs + cf_r1cs, }; (prover_params, verifier_params) -} \ No newline at end of file +} diff --git a/src/utils/inputs.rs b/src/utils/inputs.rs index 18ebea2..157124f 100644 --- a/src/utils/inputs.rs +++ b/src/utils/inputs.rs @@ -1,14 +1,49 @@ -use ark_ff::{PrimeField, BigInteger}; -use ark_pallas::Fr; +use ark_bn254::Fr; +use ark_ff::{BigInteger, PrimeField}; use ark_std::rand::rngs::OsRng; +use num_bigint::{BigInt, RandBigInt, Sign::Plus}; use std::error::Error; -use num_bigint::{BigInt, Sign::Plus, RandBigInt}; use super::{MAX_SECRET_LENGTH, MAX_USERNAME_LENGTH, SECRET_FIELD_LENGTH}; +#[derive(Clone, Debug)] +pub struct CircomPrivateInput { + pub phrase: Option, + pub usernames: [Option; 2], + pub auth_secrets: [Option; 2], + pub chaff: bool, +} + +impl CircomPrivateInput { + /** + * Creates empty inputs + * + * @param chaff - if true, should compute random vars for chaff in circuit + */ + pub fn empty(chaff: bool) -> Self { + Self { + phrase: None, + usernames: [None, None], + auth_secrets: [None, None], + chaff, + } + } + + pub fn uninitialized(&self) -> bool { + let not_chaff = self.phrase.is_none() + && self.usernames.iter().all(|u| u.is_none()) + && self.auth_secrets.iter().all(|a| a.is_none()); + not_chaff && !self.chaff + } +} + /** Get the starting ivc inputs (z0) for the grapevine circuit */ pub fn get_z0() -> [F; 4] { - (0..4).map(|_| F::zero()).collect::>().try_into().unwrap() + (0..4) + .map(|_| F::zero()) + .collect::>() + .try_into() + .unwrap() } /** Generates a random field element for given field as bigint */ @@ -25,9 +60,7 @@ pub fn random_f_bigint() -> BigInt { * @param phrase - the string entered by user to compute hash for (will be length checked) * @return - array of 6 Fr elements */ -pub fn serialize_phrase( - phrase: &String, -) -> Result<[BigInt; SECRET_FIELD_LENGTH], Box> { +pub fn serialize_phrase(phrase: &String) -> Result<[BigInt; SECRET_FIELD_LENGTH], Box> { // check length if phrase.len() > MAX_SECRET_LENGTH { return Err("Phrase must be <= 180 characters".into()); @@ -69,3 +102,51 @@ pub fn serialize_username(username: &String) -> Result> { // convert to bigint Ok(BigInt::from_bytes_be(Plus, &bytes)) } + +pub fn prepare_external_inputs(inputs: &CircomPrivateInput) -> Vec { + // handle phrase presence (if not present infer chaff) + let phrase = match &inputs.phrase { + Some(phrase) => serialize_phrase(&phrase).unwrap().to_vec(), + None => (0..6) + .map(|_| random_f_bigint::()) + .collect::>(), + }; + + // determine inputs: first step ([0] = None), Nth step ([1] = Some), and chaff ([2] = None) + // marshal usernames + let usernames = match inputs.usernames[0] { + Some(_) => inputs + .usernames + .iter() + .map(|u| serialize_username(&u.clone().unwrap()).unwrap()) + .collect::>(), + None => match &inputs.usernames[1] { + Some(username) => vec![BigInt::from(0), serialize_username(&username).unwrap()], + None => vec![random_f_bigint::(), random_f_bigint::()], + }, + }; + + // marshal auth secrets + let auth_sec = match inputs.auth_secrets[0] { + Some(_) => inputs + .auth_secrets + .iter() + .map(|a| a.clone().unwrap()) + .collect::>(), + None => match &inputs.auth_secrets[1] { + Some(auth_secret) => vec![BigInt::from(0), auth_secret.clone()], + None => vec![random_f_bigint::(), random_f_bigint::()], + }, + }; + + // NOTE: probably wold be better that the inputs are prepared already as F instead of + // BigInt (at the methods serialize_phrase, serialize_username). + + let inp: Vec = [phrase, usernames, auth_sec].concat(); + inp.iter() + .map(|v| { + let (_, b) = v.to_bytes_le(); + F::from_le_bytes_mod_order(&b) + }) + .collect() +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 3d235b1..b16537f 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,8 +1,7 @@ -use ark_pallas::Fr; +use ark_bn254::Fr; use ark_ff::UniformRand; use ark_std::rand::rngs::OsRng; -pub mod wrapper; pub mod inputs; pub const SECRET_FIELD_LENGTH: usize = 6; @@ -10,6 +9,6 @@ pub const MAX_SECRET_LENGTH: usize = 180; pub const MAX_USERNAME_LENGTH: usize = 30; /** Get a random field element */ -pub fn random_fr() -> ark_pallas::Fr { +pub fn random_fr() -> ark_bn254::Fr { Fr::rand(&mut OsRng) -} \ No newline at end of file +} diff --git a/src/utils/wrapper.rs b/src/utils/wrapper.rs deleted file mode 100644 index e1f3149..0000000 --- a/src/utils/wrapper.rs +++ /dev/null @@ -1,177 +0,0 @@ -use crate::utils::inputs::{random_f_bigint, serialize_phrase, serialize_username}; -use ark_circom::{ - circom::{r1cs_reader, R1CS}, - WitnessCalculator, -}; -use ark_ff::{BigInteger, PrimeField}; -use color_eyre::Result; -use num_bigint::{BigInt, Sign}; -use sonobe::Error as SonobeError; -use std::{fs::File, io::BufReader, marker::PhantomData, path::PathBuf}; - -#[derive(Clone, Debug)] -pub struct CircomPrivateInput { - pub phrase: Option, - pub usernames: [Option; 2], - pub auth_secrets: [Option; 2], - pub chaff: bool, -} - -impl CircomPrivateInput { - - /** - * Creates empty inputs - * - * @param chaff - if true, should compute random vars for chaff in circuit - */ - pub fn empty(chaff: bool) -> Self { - Self { - phrase: None, - usernames: [None, None], - auth_secrets: [None, None], - chaff, - } - } - - pub fn uninitialized(&self) -> bool { - let not_chaff =self.phrase.is_none() - && self.usernames.iter().all(|u| u.is_none()) - && self.auth_secrets.iter().all(|a| a.is_none()); - not_chaff && !self.chaff - } -} - -// Wrapper for circom functionalities (extract R1CS and witness) -#[derive(Clone, Debug)] -pub struct CircomWrapper { - r1cs_path: PathBuf, - wc_path: PathBuf, - _marker: PhantomData, -} - -impl CircomWrapper { - // creates a new instance of the wrapper with filepaths - pub fn new(r1cs_path: PathBuf, wc_path: PathBuf) -> Self { - Self { - r1cs_path, - wc_path, - _marker: PhantomData, - } - } - - /** - * Marshals the private inputs into the format expected by circom - * - * @param inputs - the private inputs - * @return - the marshalled inputs - */ - pub fn marshal_private_inputs(inputs: &CircomPrivateInput) -> [(String, Vec); 3] { - // handle phrase presence (if not present infer chaff) - let phrase = match &inputs.phrase { - Some(phrase) => serialize_phrase(&phrase).unwrap().to_vec(), - None => (0..6) - .map(|_| random_f_bigint::()) - .collect::>(), - }; - - // determine inputs: first step ([0] = None), Nth step ([1] = Some), and chaff ([2] = None) - // marshal usernames - let usernames = match inputs.usernames[0] { - Some(_) => inputs - .usernames - .iter() - .map(|u| serialize_username(&u.clone().unwrap()).unwrap()) - .collect::>(), - None => match &inputs.usernames[1] { - Some(username) => vec![BigInt::from(0), serialize_username(&username).unwrap()], - None => vec![random_f_bigint::(), random_f_bigint::()], - }, - }; - - // marshal auth secrets - let auth_sec = match inputs.auth_secrets[0] { - Some(_) => inputs - .auth_secrets - .iter() - .map(|a| a.clone().unwrap()) - .collect::>(), - None => match &inputs.auth_secrets[1] { - Some(auth_secret) => vec![BigInt::from(0), auth_secret.clone()], - None => vec![random_f_bigint::(), random_f_bigint::()], - }, - }; - - // label the inputs for circom - [ - ("phrase".to_string(), phrase), - ("usernames".to_string(), usernames), - ("auth_secrets".to_string(), auth_sec), - ] - } - - // aggregated function to obtain r1cs and witness from circom - pub fn extract_r1cs_and_witness( - &self, - inputs: &[(String, Vec)], - ) -> Result<(R1CS, Option>), SonobeError> { - // extract R1CS - let file = File::open(&self.r1cs_path)?; - let reader = BufReader::new(file); - let r1cs_file = r1cs_reader::R1CSFile::::new(reader)?; - let r1cs = r1cs_reader::R1CS::::from(r1cs_file); - - // extract witness vector - let witness_vec = self.extract_witness(inputs)?; - - Ok((r1cs, Some(witness_vec))) - } - - pub fn extract_witness(&self, inputs: &[(String, Vec)]) -> Result, SonobeError> { - let witness_bigint = self.calculate_witness(inputs)?; - witness_bigint - .iter() - .map(|bigint| { - Self::num_bigint_to_ark_bigint(bigint) - .and_then(|ark_bigint| { - F::from_bigint(ark_bigint).ok_or_else(|| { - SonobeError::Other("Could not get F from bigint".to_string()) - }) - }) - }) - .collect() - } - - pub fn calculate_witness( - &self, - inputs: &[(String, Vec)], - ) -> Result, SonobeError> { - let mut calculator = WitnessCalculator::new(&self.wc_path).map_err(|e| { - SonobeError::WitnessCalculationError(format!( - "Failed to create WitnessCalculator: {}", - e - )) - })?; - calculator - .calculate_witness(inputs.iter().cloned(), true) - .map_err(|e| { - SonobeError::WitnessCalculationError(format!("Failed to calculate witness: {}", e)) - }) - } - - pub fn num_bigint_to_ark_bigint(value: &BigInt) -> Result { - let big_uint = value - .to_biguint() - .ok_or_else(|| SonobeError::BigIntConversionError("BigInt is negative".to_string()))?; - F::BigInt::try_from(big_uint).map_err(|_| { - SonobeError::BigIntConversionError( - "Failed to convert to Primefield::BigInt".to_string(), - ) - }) - } - - pub fn ark_primefield_to_num_bigint(value: F) -> BigInt { - let primefield_bigint: F::BigInt = value.into_bigint(); - let bytes = primefield_bigint.to_bytes_be(); - BigInt::from_bytes_be(Sign::Plus, &bytes) - } -}