Skip to content

Commit

Permalink
chore: add gpu support for groth16
Browse files Browse the repository at this point in the history
  • Loading branch information
ibmp33 committed Jun 28, 2024
1 parent cd8845d commit 52cb5d1
Show file tree
Hide file tree
Showing 20 changed files with 1,249 additions and 1,195 deletions.
25 changes: 17 additions & 8 deletions algebraic/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "algebraic"
version = "0.0.1"
edition = "2021"
license = "Apache-2.0"
description = "Eigen Algbraic based on R1CS"
description = "Eigen Algebraic based on R1CS"
documentation = "eigen.cash"
homepage = "eigen.cash"

Expand All @@ -18,17 +18,24 @@ itertools = "0.8.1"
log = "0.4.11"
num-bigint = "0.3.3"
num-traits = "0.2.8"
serde = { version = "1.0", features = [ "derive" ] }
serde_json = { version = "1.0", features = [ "arbitrary_precision" ] }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0", features = ["arbitrary_precision"] }
hex = "*"
wasmer = { version = "4.3.2", default-features = false }
thiserror="1.0"
thiserror = "1.0"
anyhow = "1.0.79"
fnv = { version = "1.0.3", default-features = false }
num = { version = "0.4.0" }
byteorder = "1"
franklin-crypto = { git = "https://github.com/matter-labs/franklin-crypto", branch = "beta", features = [ "plonk" ], version = "0.0.5"}
#franklin-crypto = { path = "../../franklin-crypto", features = [ "plonk" ], version = "0.0.5"}

# Add cuda and opencl dependencies directly
ff = { version = "0.13.0", features = ["derive"], optional = true }
pairing = { version = "0.23.0", optional = true }
bellperson = { version = "0.25", default-features = true, optional = true }

[target.'cfg(not(any(feature = "cuda", feature = "opencl")))'.dependencies]
franklin-crypto = { git = "https://github.com/matter-labs/franklin-crypto", branch = "beta", features = ["plonk"], version = "0.0.5" }
# franklin-crypto = { path = "../../franklin-crypto", features = [ "plonk" ], version = "0.0.5"}

[dev-dependencies]
env_logger = "0.10"
Expand All @@ -37,13 +44,15 @@ env_logger = "0.10"
rand = "0.4"

[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = { version = "0.2.51", features = ["serde-serialize"] }
wasm-bindgen = { version = "0.2.51", features = ["serde-serialize"] }
wasm-bindgen-futures = "0.4.1"
rand = { version="0.6.5", features = ["wasm-bindgen"] }
rand = { version = "0.6.5", features = ["wasm-bindgen"] }

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3"

[features]
default = ["franklin-crypto/multicore", "wasmer/singlepass"]
wasm = ["wasmer/js-default"]
cuda = ["ff", "pairing", "bellperson/cuda", "wasmer/singlepass"]
opencl = ["ff", "pairing", "bellperson/opencl", "wasmer/singlepass"]
148 changes: 144 additions & 4 deletions algebraic/src/circom_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,23 @@
#![allow(clippy::needless_range_loop)]
extern crate rand;

use itertools::Itertools;
use std::collections::BTreeMap;
use std::str;

#[cfg(not(any(feature = "cuda", feature = "opencl")))]
use crate::bellman_ce::{
pairing::Engine, Circuit, ConstraintSystem, Index, LinearCombination, PrimeField, ScalarEngine,
SynthesisError, Variable,
};
#[cfg(any(feature = "cuda", feature = "opencl"))]
use crate::bellperson::{
Circuit, ConstraintSystem, Index, LinearCombination, SynthesisError, Variable,
};
#[cfg(any(feature = "cuda", feature = "opencl"))]
use ff::PrimeField;
use itertools::Itertools;
#[cfg(any(feature = "cuda", feature = "opencl"))]
pub use num_bigint::BigUint;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::str;

use crate::utils::repr_to_big;

Expand All @@ -24,19 +33,30 @@ pub struct CircuitJson {
pub num_variables: usize,
}

#[cfg(not(any(feature = "cuda", feature = "opencl")))]
pub type Constraint<E> = (
Vec<(usize, <E as ScalarEngine>::Fr)>,
Vec<(usize, <E as ScalarEngine>::Fr)>,
Vec<(usize, <E as ScalarEngine>::Fr)>,
);
#[cfg(any(feature = "cuda", feature = "opencl"))]
pub type Constraint<E> = (Vec<(usize, E)>, Vec<(usize, E)>, Vec<(usize, E)>);

// R1CSfile's CustomGates
#[cfg(not(any(feature = "cuda", feature = "opencl")))]
#[derive(Debug, Default, Clone)]
pub struct CustomGates<E: ScalarEngine> {
pub template_name: String,
pub parameters: Vec<E::Fr>,
}

#[cfg(any(feature = "cuda", feature = "opencl"))]
#[derive(Debug, Default, Clone)]
pub struct CustomGates<E: PrimeField> {
pub template_name: String,
pub parameters: Vec<E>,
}

// R1CSfile's CustomGatesUses
#[derive(Debug, Default, Clone)]
pub struct CustomGatesUses {
Expand All @@ -45,6 +65,19 @@ pub struct CustomGatesUses {
}

/// R1CS spec: https://www.sikoba.com/docs/SKOR_GD_R1CS_Format.pdf
#[cfg(any(feature = "cuda", feature = "opencl"))]
#[derive(Clone, Debug)]
pub struct R1CS<E: PrimeField> {
pub num_inputs: usize,
pub num_aux: usize,
pub num_variables: usize,
pub num_outputs: usize,
pub constraints: Vec<Constraint<E>>,
pub custom_gates: Vec<CustomGates<E>>,
pub custom_gates_uses: Vec<CustomGatesUses>,
}

#[cfg(not(any(feature = "cuda", feature = "opencl")))]
#[derive(Clone, Debug)]
pub struct R1CS<E: ScalarEngine> {
pub num_inputs: usize,
Expand All @@ -56,6 +89,7 @@ pub struct R1CS<E: ScalarEngine> {
pub custom_gates_uses: Vec<CustomGatesUses>,
}

#[cfg(not(any(feature = "cuda", feature = "opencl")))]
#[derive(Clone, Debug)]
pub struct CircomCircuit<E: ScalarEngine> {
pub r1cs: R1CS<E>,
Expand All @@ -64,7 +98,17 @@ pub struct CircomCircuit<E: ScalarEngine> {
pub aux_offset: usize,
// debug symbols
}
#[cfg(any(feature = "cuda", feature = "opencl"))]
#[derive(Clone, Debug)]
pub struct CircomCircuit<E: PrimeField> {
pub r1cs: R1CS<E>,
pub witness: Option<Vec<E>>,
pub wire_mapping: Option<Vec<usize>>,
pub aux_offset: usize,
// debug symbols
}

#[cfg(not(any(feature = "cuda", feature = "opencl")))]
impl<E: ScalarEngine> CircomCircuit<E> {
pub fn get_public_inputs(&self) -> Option<Vec<E::Fr>> {
match &self.witness {
Expand All @@ -91,9 +135,37 @@ impl<E: ScalarEngine> CircomCircuit<E> {
}
}

#[cfg(any(feature = "cuda", feature = "opencl"))]
impl<E: PrimeField> CircomCircuit<E> {
pub fn get_public_inputs(&self) -> Option<Vec<E>> {
match &self.witness {
None => None,
Some(w) => match &self.wire_mapping {
None => Some(w[1..self.r1cs.num_inputs].to_vec()),
Some(m) => Some(
m[1..self.r1cs.num_inputs]
.iter()
.map(|i| w[*i])
.collect_vec(),
),
},
}
}

pub fn get_public_inputs_json(&self) -> String {
let inputs = self.get_public_inputs();
let inputs = match inputs {
None => return String::from("[]"),
Some(inp) => inp.iter().map(|x| repr_to_big(x)).collect_vec(),
};
serde_json::to_string_pretty(&inputs).unwrap()
}
}

/// Our demo circuit implements this `Circuit` trait which
/// is used during paramgen and proving in order to
/// synthesize the constraint system.
#[cfg(not(any(feature = "cuda", feature = "opencl")))]
impl<E: Engine> Circuit<E> for CircomCircuit<E> {
//noinspection RsBorrowChecker
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
Expand Down Expand Up @@ -160,3 +232,71 @@ impl<E: Engine> Circuit<E> for CircomCircuit<E> {
Ok(())
}
}

#[cfg(any(feature = "cuda", feature = "opencl"))]
impl<E: PrimeField> Circuit<E> for CircomCircuit<E> {
//noinspection RsBorrowChecker
fn synthesize<CS: ConstraintSystem<E>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
let witness = &self.witness;
let wire_mapping = &self.wire_mapping;
for i in 1..self.r1cs.num_inputs {
cs.alloc_input(
|| format!("variable {}", i),
|| {
Ok(match witness {
None => E::from_str_vartime(&format!("alloc input {} error", i)).unwrap(),
Some(w) => match wire_mapping {
None => w[i],
Some(m) => w[m[i]],
},
})
},
)?;
}
for i in 0..self.r1cs.num_aux {
cs.alloc(
|| format!("aux {}", i + self.aux_offset),
|| {
Ok(match witness {
None => {
E::from_str_vartime(&format!("alloc aux {} error", i + self.aux_offset))
.unwrap()
}
Some(w) => match wire_mapping {
None => w[i + self.r1cs.num_inputs],
Some(m) => w[m[i + self.r1cs.num_inputs]],
},
})
},
)?;
}

let make_index = |index| {
if index < self.r1cs.num_inputs {
Index::Input(index)
} else {
Index::Aux(index - self.r1cs.num_inputs + self.aux_offset)
}
};
let make_lc = |lc_data: Vec<(usize, E)>| {
lc_data.iter().fold(
LinearCombination::<E>::zero(),
|lc: LinearCombination<E>, (index, coeff)| {
lc + (*coeff, Variable::new_unchecked(make_index(*index)))
},
)
};
for (i, constraint) in self.r1cs.constraints.iter().enumerate() {
// 0 * LC = 0 must be ignored
if !((constraint.0.is_empty() || constraint.1.is_empty()) && constraint.2.is_empty()) {
cs.enforce(
|| format!("{}", i),
|_| make_lc(constraint.0.clone()),
|_| make_lc(constraint.1.clone()),
|_| make_lc(constraint.2.clone()),
);
}
}
Ok(())
}
}
15 changes: 15 additions & 0 deletions algebraic/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,18 @@
extern crate serde;
#[macro_use]
extern crate hex_literal;
#[cfg(any(feature = "cuda", feature = "opencl"))]
extern crate bellperson;
extern crate byteorder;
#[cfg(any(feature = "cuda", feature = "opencl"))]
extern crate ff;
#[cfg(not(any(feature = "cuda", feature = "opencl")))]
extern crate franklin_crypto;
extern crate itertools;
extern crate num_bigint;
extern crate num_traits;
#[cfg(any(feature = "cuda", feature = "opencl"))]
extern crate pairing;
extern crate rand;

pub mod circom_circuit;
Expand All @@ -17,10 +24,18 @@ pub mod reader;
pub mod utils;
pub mod witness;

#[cfg(not(any(feature = "cuda", feature = "opencl")))]
pub use crate::ff::*;
#[cfg(not(any(feature = "cuda", feature = "opencl")))]
pub use bellman_ce::pairing::ff;
#[cfg(not(any(feature = "cuda", feature = "opencl")))]
pub use franklin_crypto::bellman as bellman_ce;

#[cfg(any(feature = "cuda", feature = "opencl"))]
pub use bellperson::groth16::*;
#[cfg(any(feature = "cuda", feature = "opencl"))]
pub use ff::*;

#[cfg(target_arch = "wasm32")]
extern crate wasm_bindgen;

Expand Down
Loading

0 comments on commit 52cb5d1

Please sign in to comment.