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

Commit

Permalink
feat!: Update to ACVM v0.11.0 (#151)
Browse files Browse the repository at this point in the history
* feat!: Rework crate for fallible traits to avoid panic & unwrap

* Update to acvm 0.11

* implement TryFrom for circuit and bubble errors

* split wasm errors into a separate enum and handle transparently

* try_into for Value

* update for rebase

* fixing rebase problems

* Remove keccak code added before acvm v0.11.0

* issues with rebase

* tryfrom all the things

* move todos

* Move unsafe call

* remove unused error variants

* testing making bb debug

* update bb in lockfile

* hide error variants

* Condense blackbox errors to two variants

* Stop trying to combine sig_s and sig_e and then splitting

* cspell
  • Loading branch information
phated committed May 10, 2023
1 parent 677f10e commit 9202415
Show file tree
Hide file tree
Showing 16 changed files with 746 additions and 515 deletions.
19 changes: 10 additions & 9 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ license = "MIT OR Apache-2.0"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
acvm = { version = "0.10.3", features = ["bn254"] }
acvm = { version = "0.11.0", features = ["bn254"] }
thiserror = "1.0.21"

blake2 = "0.9.1"
sha3 = "0.9.1"
dirs = { version = "3.0", optional = true }
reqwest = { version = "0.11.16", optional = true, default-features = false, features = [
"stream",
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"nixpkgs",
"envrc",
"subshell",
"thiserror",
// In Solidity
//
"addmod",
Expand Down
6 changes: 3 additions & 3 deletions flake.lock

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

35 changes: 20 additions & 15 deletions src/acvm_interop/proof_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@ use std::collections::BTreeMap;

use crate::barretenberg_structures::Assignments;
use crate::composer::Composer;
use crate::Barretenberg;
use crate::{BackendError, Barretenberg};

impl ProofSystemCompiler for Barretenberg {
type Error = BackendError;

fn np_language(&self) -> Language {
Language::PLONKCSat { width: 3 }
}

fn get_exact_circuit_size(&self, circuit: &Circuit) -> u32 {
Composer::get_exact_circuit_size(self, &circuit.into())
fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result<u32, Self::Error> {
Ok(Composer::get_exact_circuit_size(
self,
&circuit.try_into()?,
)?)
}

fn black_box_function_supported(&self, opcode: &BlackBoxFunc) -> bool {
Expand All @@ -31,28 +36,28 @@ impl ProofSystemCompiler for Barretenberg {
| BlackBoxFunc::EcdsaSecp256k1
| BlackBoxFunc::FixedBaseScalarMul => true,

BlackBoxFunc::AES => false,
BlackBoxFunc::AES => false,
}
}

fn preprocess(&self, circuit: &Circuit) -> (Vec<u8>, Vec<u8>) {
let constraint_system = &circuit.into();
fn preprocess(&self, circuit: &Circuit) -> Result<(Vec<u8>, Vec<u8>), Self::Error> {
let constraint_system = &circuit.try_into()?;

let proving_key = self.compute_proving_key(constraint_system);
let verification_key = self.compute_verification_key(constraint_system, &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)
Ok((proving_key, verification_key))
}

fn prove_with_pk(
&self,
circuit: &Circuit,
witness_values: BTreeMap<Witness, FieldElement>,
proving_key: &[u8],
) -> Vec<u8> {
) -> Result<Vec<u8>, Self::Error> {
let assignments = flatten_witness_map(circuit, witness_values);

self.create_proof_with_pk(&circuit.into(), assignments, proving_key)
Ok(self.create_proof_with_pk(&circuit.try_into()?, assignments, proving_key)?)
}

fn verify_with_vk(
Expand All @@ -61,18 +66,18 @@ impl ProofSystemCompiler for Barretenberg {
public_inputs: BTreeMap<Witness, FieldElement>,
circuit: &Circuit,
verification_key: &[u8],
) -> bool {
) -> Result<bool, Self::Error> {
// 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(
Ok(Composer::verify_with_vk(
self,
&circuit.into(),
&circuit.try_into()?,
proof,
flattened_public_inputs.into(),
verification_key,
)
)?)
}
}

Expand Down
132 changes: 62 additions & 70 deletions src/acvm_interop/pwg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl PartialWitnessGenerator for Barretenberg {
match func_call.name {
BlackBoxFunc::SHA256 => hash::sha256(initial_witness, func_call),
BlackBoxFunc::Blake2s => hash::blake2s(initial_witness, func_call),
BlackBoxFunc::Keccak256 => keccak256(initial_witness, func_call),
BlackBoxFunc::Keccak256 => hash::keccak256(initial_witness, func_call),
BlackBoxFunc::EcdsaSecp256k1 => {
signature::ecdsa::secp256k1_prehashed(initial_witness, func_call)
}
Expand Down Expand Up @@ -54,7 +54,10 @@ impl PartialWitnessGenerator for Barretenberg {
hash_path?,
index,
leaf,
);
)
.map_err(|err| {
OpcodeResolutionError::BlackBoxFunctionFailed(func_call.name, err.to_string())
})?;

initial_witness.insert(func_call.outputs[0], computed_merkle_root);
Ok(OpcodeResolution::Solved)
Expand Down Expand Up @@ -82,25 +85,66 @@ impl PartialWitnessGenerator for Barretenberg {
.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 pub_key: [u8; 64] = pub_key_bytes.try_into().map_err(|v: Vec<u8>| {
OpcodeResolutionError::BlackBoxFunctionFailed(
func_call.name,
format!("expected pubkey size {} but received {}", 64, v.len()),
)
})?;

let mut sig_s: [u8; 32] = [0u8; 32];
for (i, sig) in sig_s.iter_mut().enumerate() {
let _sig_i = inputs_iter.next().ok_or_else(|| {
OpcodeResolutionError::BlackBoxFunctionFailed(
func_call.name,
format!("sig_s should be 32 bytes long, found only {i} bytes"),
)
})?;
let sig_i = witness_to_value(initial_witness, _sig_i.witness)?;
*sig = *sig_i.to_be_bytes().last().ok_or_else(|| {
OpcodeResolutionError::BlackBoxFunctionFailed(
func_call.name,
"could not get last bytes".into(),
)
})?;
}
let mut sig_e: [u8; 32] = [0u8; 32];
for (i, sig) in sig_e.iter_mut().enumerate() {
let _sig_i = inputs_iter.next().ok_or_else(|| {
OpcodeResolutionError::BlackBoxFunctionFailed(
func_call.name,
format!("sig_e should be 32 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()
*sig = *sig_i.to_be_bytes().last().ok_or_else(|| {
OpcodeResolutionError::BlackBoxFunctionFailed(
func_call.name,
"could not get last bytes".into(),
)
})?;
}

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();
let msg_i = *msg_i_field.to_be_bytes().last().ok_or_else(|| {
OpcodeResolutionError::BlackBoxFunctionFailed(
func_call.name,
"could not get last bytes".into(),
)
})?;
message.push(msg_i);
}

let valid_signature = self.verify_signature(pub_key, signature, &message);
let valid_signature = self
.verify_signature(pub_key, sig_s, sig_e, &message)
.map_err(|err| {
OpcodeResolutionError::BlackBoxFunctionFailed(
func_call.name,
err.to_string(),
)
})?;
if !valid_signature {
dbg!("signature has failed to verify");
}
Expand All @@ -122,7 +166,9 @@ impl PartialWitnessGenerator for Barretenberg {
.collect();
let scalars: Vec<_> = scalars?.into_iter().cloned().collect();

let (res_x, res_y) = self.encrypt(scalars);
let (res_x, res_y) = self.encrypt(scalars).map_err(|err| {
OpcodeResolutionError::BlackBoxFunctionFailed(func_call.name, err.to_string())
})?;
initial_witness.insert(func_call.outputs[0], res_x);
initial_witness.insert(func_call.outputs[1], res_y);
Ok(OpcodeResolution::Solved)
Expand Down Expand Up @@ -152,7 +198,9 @@ impl PartialWitnessGenerator for Barretenberg {
BlackBoxFunc::FixedBaseScalarMul => {
let scalar = witness_to_value(initial_witness, func_call.inputs[0].witness)?;

let (pub_x, pub_y) = self.fixed_base(scalar);
let (pub_x, pub_y) = self.fixed_base(scalar).map_err(|err| {
OpcodeResolutionError::BlackBoxFunctionFailed(func_call.name, err.to_string())
})?;

initial_witness.insert(func_call.outputs[0], pub_x);
initial_witness.insert(func_call.outputs[1], pub_y);
Expand All @@ -161,59 +209,3 @@ impl PartialWitnessGenerator for Barretenberg {
}
}
}

// All of the code below can be removed once we update to acvm 0.11 or greater.
use sha3::Keccak256;
fn keccak256(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let hash = generic_hash_256::<Keccak256>(initial_witness, func_call)?;

for (output_witness, value) in func_call.outputs.iter().zip(hash.iter()) {
insert_value(
output_witness,
FieldElement::from_be_bytes_reduce(&[*value]),
initial_witness,
)?;
}

Ok(OpcodeResolution::Solved)
}
fn insert_value(
witness: &Witness,
value_to_insert: FieldElement,
initial_witness: &mut BTreeMap<Witness, FieldElement>,
) -> Result<(), OpcodeResolutionError> {
let optional_old_value = initial_witness.insert(*witness, value_to_insert);

let old_value = match optional_old_value {
Some(old_value) => old_value,
None => return Ok(()),
};

if old_value != value_to_insert {
return Err(OpcodeResolutionError::UnsatisfiedConstrain);
}

Ok(())
}
fn generic_hash_256<D: Digest>(
initial_witness: &mut BTreeMap<Witness, FieldElement>,
func_call: &BlackBoxFuncCall,
) -> Result<[u8; 32], OpcodeResolutionError> {
let mut hasher = D::new();

// Read witness assignments into hasher.
for input in func_call.inputs.iter() {
let witness = input.witness;
let num_bits = input.num_bits as usize;

let witness_assignment = witness_to_value(initial_witness, witness)?;
let bytes = witness_assignment.fetch_nearest_bytes(num_bits);
hasher.update(bytes);
}

let result = hasher.finalize().as_slice().try_into().unwrap();
Ok(result)
}

0 comments on commit 9202415

Please sign in to comment.