Skip to content
This repository has been archived by the owner on Oct 31, 2023. It is now read-only.

Commit

Permalink
feat!: merge barretenberg_static_lib and barretenberg_wasm (#117)
Browse files Browse the repository at this point in the history
* feat: merge `barretenberg_static_lib` and `barretenberg_wasm`

* fix: disable dead code warnings

* chore: run smoke test on both native and wasm backends

* chore: define proper interface for wasm internals of `Barretenberg`

* feat: run tests on both native and wasm backends

* chore: move barretenberg back up to crate root

* feat: standardise interface of `StandardComposer`

* feat: manage CRS on barretenberg struct

* feat: remove `StandardComposer`

* feat: disallow compiling for both native and wasm

* feat: make usage of `Barretenberg` struct immutable

* chore: comment nits

* feat!: implement `Backend` on `Barretenberg`

* chore: remove unused import

* feat: inline black box function logic from `common`

* fix: address compilation issues

* chore: clippy

* chore: use private traits to enforce interface on native/wasm code

* native build by default

* chore: misc changes

* feat: prefer `G2` over `CRS` where no g1 data is used

* chore: typo

* chore: run clippy on wasm feature

* chore: Update nix to expose wasm feature targets

* chore: Comment updates

* chore: replace cfg_if with modules

* feat: standardise pow2ceil implementation

* Update acvm_backend_barretenberg/src/composer.rs

---------

Co-authored-by: Blaine Bublitz <[email protected]>
  • Loading branch information
TomAFrench and phated authored Apr 25, 2023
1 parent 2ea62f0 commit ba1d0d6
Show file tree
Hide file tree
Showing 42 changed files with 1,259 additions and 2,086 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,5 @@ jobs:
- name: Export cache from nix store
if: steps.nix-store-cache.outputs.cache-hit != 'true'
run: |
nix copy --to "file:///tmp/nix-cache?compression=zstd&parallel-compression=true" .#cargo-artifacts
nix copy --to "file:///tmp/nix-cache?compression=zstd&parallel-compression=true" .#native-cargo-artifacts
nix copy --to "file:///tmp/nix-cache?compression=zstd&parallel-compression=true" .#wasm-cargo-artifacts
37 changes: 14 additions & 23 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]

members = ["common", "barretenberg_wasm", "barretenberg_static_lib", "aztec_backend_wasm"]
members = ["common", "acvm_backend_barretenberg", "aztec_backend_wasm"]

[workspace.package]
authors = ["The Noir Team <[email protected]>"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "barretenberg_wasm"
name = "acvm-backend-barretenberg"
version = "0.1.0"
authors.workspace = true
license.workspace = true
Expand All @@ -9,21 +9,33 @@ rust-version.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wasmer = { version = "*", default-features = false }
blake2 = "0.9.1"
common = { path = "../common", default-features = false }
rust-embed = { version = "6.6.0", features = ["debug-embed", "interpolate-folder-path", "include-exclude"] }
getrandom = "0.2"

# Native
barretenberg-sys = { version = "0.1.2", optional = true }

# Wasm
wasmer = { version = "*", optional = true, default-features = false }
rust-embed = { version = "6.6.0", optional = true, features = ["debug-embed", "interpolate-folder-path", "include-exclude"] }
getrandom = { version = "0.2", optional = true }

[build-dependencies]
pkg-config = "0.3"

[dev-dependencies]
blake2 = "0.9.1"
tempfile = "*"

[features]
default = [
# "acvm/bn254",
default = ["native"]
native = [
"dep:barretenberg-sys",
"common/std",
]
wasm = [
"wasmer",
"dep:rust-embed",
"dep:getrandom",
"common/std",
"wasmer/sys-default",
"wasmer/cranelift",
Expand All @@ -32,7 +44,8 @@ default = [
"wasmer/default-universal",
]
js = [

# "acvm/bn254",
"wasmer",
"dep:rust-embed",
"dep:getrandom",
"wasmer/js-default",
]
31 changes: 31 additions & 0 deletions acvm_backend_barretenberg/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use std::env;

// Useful for printing debugging messages during the build
// macro_rules! p {
// ($($tokens: tt)*) => {
// println!("cargo:warning={}", format!($($tokens)*))
// }
// }

fn main() -> Result<(), String> {
let native_backend = env::var("CARGO_FEATURE_NATIVE").is_ok();

if native_backend {
Ok(())
} else {
match env::var("BARRETENBERG_BIN_DIR") {
Ok(bindir) => {
println!("cargo:rustc-env=BARRETENBERG_BIN_DIR={bindir}");
Ok(())
}
Err(_) => {
if let Ok(bindir) = pkg_config::get_variable("barretenberg", "bindir") {
println!("cargo:rustc-env=BARRETENBERG_BIN_DIR={bindir}");
Ok(())
} else {
Err("Unable to locate barretenberg.wasm - Please set the BARRETENBERG_BIN_DIR env var to the directory where it exists".into())
}
}
}
}
}
7 changes: 7 additions & 0 deletions acvm_backend_barretenberg/src/acvm_interop/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
use crate::Barretenberg;

mod proof_system;
mod pwg;
mod smart_contract;

impl common::acvm::Backend for Barretenberg {}
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
use super::Plonk;
use crate::composer::StandardComposer;
use crate::composer::Composer;
use crate::Barretenberg;
use common::acvm::acir::{circuit::Circuit, native_types::Witness, BlackBoxFunc};
use common::acvm::FieldElement;
use common::acvm::{Language, ProofSystemCompiler};
use common::proof;
use std::collections::BTreeMap;

impl ProofSystemCompiler for Plonk {
impl ProofSystemCompiler for Barretenberg {
fn np_language(&self) -> Language {
Language::PLONKCSat { width: 3 }
}

fn get_exact_circuit_size(&self, circuit: &Circuit) -> u32 {
StandardComposer::get_exact_circuit_size(&circuit.into())
Composer::get_exact_circuit_size(self, &circuit.into())
}

fn black_box_function_supported(&self, opcode: &BlackBoxFunc) -> bool {
Expand All @@ -34,10 +34,10 @@ impl ProofSystemCompiler for Plonk {
}

fn preprocess(&self, circuit: &Circuit) -> (Vec<u8>, Vec<u8>) {
let composer = StandardComposer::new(circuit.into());
let constraint_system = &circuit.into();

let proving_key = composer.compute_proving_key();
let verification_key = composer.compute_verification_key(&proving_key);
let proving_key = self.compute_proving_key(constraint_system);
let verification_key = self.compute_verification_key(constraint_system, &proving_key);

(proving_key, verification_key)
}
Expand All @@ -48,11 +48,9 @@ impl ProofSystemCompiler for Plonk {
witness_values: BTreeMap<Witness, FieldElement>,
proving_key: &[u8],
) -> Vec<u8> {
let mut composer = StandardComposer::new(circuit.into());

let assignments = proof::flatten_witness_map(circuit, witness_values);

composer.create_proof_with_pk(assignments, proving_key)
self.create_proof_with_pk(&circuit.into(), assignments, proving_key)
}

fn verify_with_vk(
Expand All @@ -62,12 +60,16 @@ impl ProofSystemCompiler for Plonk {
circuit: &Circuit,
verification_key: &[u8],
) -> bool {
let mut composer = StandardComposer::new(circuit.into());

// Unlike when proving, we omit any unassigned witnesses.
// Witness values should be ordered by their index but we skip over any indices without an assignment.
let flattened_public_inputs: Vec<FieldElement> = public_inputs.into_values().collect();

composer.verify_with_vk(proof, flattened_public_inputs.into(), verification_key)
Composer::verify_with_vk(
self,
&circuit.into(),
proof,
flattened_public_inputs.into(),
verification_key,
)
}
}
164 changes: 164 additions & 0 deletions acvm_backend_barretenberg/src/acvm_interop/pwg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use common::acvm::acir::BlackBoxFunc;
use common::acvm::acir::{circuit::opcodes::BlackBoxFuncCall, native_types::Witness};
use common::acvm::pwg::{hash, logic, range, signature, witness_to_value};
use common::acvm::{FieldElement, OpcodeResolution};
use common::acvm::{OpcodeResolutionError, PartialWitnessGenerator};

use std::collections::BTreeMap;

use crate::pedersen::Pedersen;
use crate::scalar_mul::ScalarMul;
use crate::schnorr::SchnorrSig;
use crate::Barretenberg;

use blake2::{Blake2s, Digest};

mod merkle;

impl PartialWitnessGenerator for Barretenberg {
fn solve_black_box_function_call(
&self,
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
) -> Result<OpcodeResolution, OpcodeResolutionError> {
match func_call.name {
BlackBoxFunc::SHA256 => hash::sha256(initial_witness, func_call),
BlackBoxFunc::Blake2s => hash::blake2s(initial_witness, func_call),
BlackBoxFunc::EcdsaSecp256k1 => {
signature::ecdsa::secp256k1_prehashed(initial_witness, func_call)?
}
BlackBoxFunc::AES | BlackBoxFunc::Keccak256 => {
return Err(OpcodeResolutionError::UnsupportedBlackBoxFunc(
func_call.name,
))
}
BlackBoxFunc::MerkleMembership => {
let mut inputs_iter = func_call.inputs.iter();

let _root = inputs_iter.next().expect("expected a root");
let root = witness_to_value(initial_witness, _root.witness)?;

let _leaf = inputs_iter.next().expect("expected a leaf");
let leaf = witness_to_value(initial_witness, _leaf.witness)?;

let _index = inputs_iter.next().expect("expected an index");
let index = witness_to_value(initial_witness, _index.witness)?;

let hash_path: Result<Vec<_>, _> = inputs_iter
.map(|input| witness_to_value(initial_witness, input.witness))
.collect();

let valid_proof = merkle::check_membership(self, hash_path?, root, index, leaf);

let result = if valid_proof {
FieldElement::one()
} else {
FieldElement::zero()
};

initial_witness.insert(func_call.outputs[0], result);
}
BlackBoxFunc::SchnorrVerify => {
// In barretenberg, if the signature fails, then the whole thing fails.
//

let mut inputs_iter = func_call.inputs.iter();

let _pub_key_x = inputs_iter
.next()
.expect("expected `x` component for public key");
let pub_key_x =
witness_to_value(initial_witness, _pub_key_x.witness)?.to_be_bytes();

let _pub_key_y = inputs_iter
.next()
.expect("expected `y` component for public key");
let pub_key_y =
witness_to_value(initial_witness, _pub_key_y.witness)?.to_be_bytes();

let pub_key_bytes: Vec<u8> = pub_key_x
.iter()
.copied()
.chain(pub_key_y.to_vec())
.collect();
let pub_key: [u8; 64] = pub_key_bytes.try_into().unwrap();

let mut signature = [0u8; 64];
for (i, sig) in signature.iter_mut().enumerate() {
let _sig_i = inputs_iter.next().unwrap_or_else(|| {
panic!("signature should be 64 bytes long, found only {i} bytes")
});
let sig_i = witness_to_value(initial_witness, _sig_i.witness)?;
*sig = *sig_i.to_be_bytes().last().unwrap()
}

let mut message = Vec::new();
for msg in inputs_iter {
let msg_i_field = witness_to_value(initial_witness, msg.witness)?;
let msg_i = *msg_i_field.to_be_bytes().last().unwrap();
message.push(msg_i);
}

let valid_signature = self.verify_signature(pub_key, signature, &message);
if !valid_signature {
dbg!("signature has failed to verify");
}

let result = if valid_signature {
FieldElement::one()
} else {
FieldElement::zero()
};

initial_witness.insert(func_call.outputs[0], result);
}
BlackBoxFunc::Pedersen => {
let inputs_iter = func_call.inputs.iter();

let scalars: Result<Vec<_>, _> = inputs_iter
.map(|input| witness_to_value(initial_witness, input.witness))
.collect();
let scalars: Vec<_> = scalars?.into_iter().cloned().collect();

let (res_x, res_y) = self.encrypt(scalars);
initial_witness.insert(func_call.outputs[0], res_x);
initial_witness.insert(func_call.outputs[1], res_y);
}
BlackBoxFunc::HashToField128Security => {
let mut hasher = <Blake2s as blake2::Digest>::new();

// 0. For each input in the vector of inputs, check if we have their witness assignments (Can do this outside of match, since they all have inputs)
for input_index in func_call.inputs.iter() {
let witness = &input_index.witness;
let num_bits = input_index.num_bits;

let assignment = witness_to_value(initial_witness, *witness)?;

let bytes = assignment.fetch_nearest_bytes(num_bits as usize);

hasher.update(bytes);
}
let result = hasher.finalize();

let reduced_res = FieldElement::from_be_bytes_reduce(&result);
assert_eq!(func_call.outputs.len(), 1);

initial_witness.insert(func_call.outputs[0], reduced_res);
}
BlackBoxFunc::FixedBaseScalarMul => {
let scalar = witness_to_value(initial_witness, func_call.inputs[0].witness)?;

let (pub_x, pub_y) = self.fixed_base(scalar);

initial_witness.insert(func_call.outputs[0], pub_x);
initial_witness.insert(func_call.outputs[1], pub_y);
}
BlackBoxFunc::AND | BlackBoxFunc::XOR => {
logic::solve_logic_opcode(initial_witness, func_call)?
}
BlackBoxFunc::RANGE => range::solve_range_opcode(initial_witness, func_call)?,
}

Ok(OpcodeResolution::Solved)
}
}
Loading

0 comments on commit ba1d0d6

Please sign in to comment.