Skip to content

Commit

Permalink
Merge branch 'master' into brillig
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAFrench committed Jul 6, 2023
2 parents 937c61f + de7c033 commit 025cff4
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 168 deletions.
24 changes: 14 additions & 10 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
Expand Up @@ -14,7 +14,7 @@ rust-version = "1.66"
crate-type = ["cdylib"]

[dependencies]
acvm = "0.15.1"
acvm = "0.16.0"
wasm-bindgen = { version = "0.2.86", features = ["serde-serialize"] }
wasm-bindgen-futures = "0.4.36"
serde = { version = "1.0.136", features = ["derive"] }
Expand Down
199 changes: 43 additions & 156 deletions src/execute.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
use acvm::{
acir::{
circuit::{opcodes::FunctionInput, Circuit, Opcode},
native_types::{Witness, WitnessMap},
BlackBoxFunc,
},
pwg::{
insert_value, witness_to_value, Blocks, OpcodeResolution, OpcodeResolutionError,
PartialWitnessGeneratorStatus, UnresolvedBrilligCall,
},
FieldElement, PartialWitnessGenerator,
acir::{circuit::Circuit, BlackBoxFunc},
pwg::{ACVMStatus, OpcodeResolutionError, ACVM},
BlackBoxFunctionSolver, FieldElement,
};

use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
use wasm_bindgen::prelude::wasm_bindgen;

use crate::{
barretenberg::{pedersen::Pedersen, scalar_mul::ScalarMul, schnorr::SchnorrSig, Barretenberg},
Expand All @@ -30,118 +23,49 @@ impl SimulatedBackend {
}
}

impl PartialWitnessGenerator for SimulatedBackend {
impl BlackBoxFunctionSolver for SimulatedBackend {
fn schnorr_verify(
&self,
initial_witness: &mut WitnessMap,
public_key_x: &FunctionInput,
public_key_y: &FunctionInput,
signature: &[FunctionInput],
message: &[FunctionInput],
output: &Witness,
) -> Result<OpcodeResolution, OpcodeResolutionError> {
// In barretenberg, if the signature fails, then the whole thing fails.

let pub_key_x = witness_to_value(initial_witness, public_key_x.witness)?.to_be_bytes();
let pub_key_y = witness_to_value(initial_witness, public_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().map_err(|v: Vec<u8>| {
OpcodeResolutionError::BlackBoxFunctionFailed(
BlackBoxFunc::SchnorrVerify,
format!("expected pubkey size {} but received {}", 64, v.len()),
)
})?;

let signature_bytes: Vec<u8> = signature
.iter()
.map(|sig_elem| {
witness_to_value(initial_witness, sig_elem.witness).map(|witness_value| {
*witness_value.to_be_bytes().last().expect("byte array is never empty")
})
})
.collect::<Result<_, _>>()?;

let sig_s = signature_bytes[0..32].try_into().map_err(|_| {
public_key_x: &FieldElement,
public_key_y: &FieldElement,
signature: &[u8],
message: &[u8],
) -> Result<bool, OpcodeResolutionError> {
let pub_key_bytes: Vec<u8> =
public_key_x.to_be_bytes().iter().copied().chain(public_key_y.to_be_bytes()).collect();

let pub_key: [u8; 64] = pub_key_bytes.try_into().unwrap();
let sig_s: [u8; 32] = signature[0..32].try_into().unwrap();
let sig_e: [u8; 32] = signature[32..64].try_into().unwrap();

self.blackbox_vendor.verify_signature(pub_key, sig_s, sig_e, message).map_err(|err| {
OpcodeResolutionError::BlackBoxFunctionFailed(
BlackBoxFunc::SchnorrVerify,
format!("signature should be 64 bytes long, found only {} bytes", signature.len()),
)
})?;
let sig_e = signature_bytes[32..64].try_into().map_err(|_| {
OpcodeResolutionError::BlackBoxFunctionFailed(
BlackBoxFunc::SchnorrVerify,
format!("signature should be 64 bytes long, found only {} bytes", signature.len()),
err.to_string(),
)
})?;

let message_bytes: Vec<u8> = message
.iter()
.map(|message_elem| {
witness_to_value(initial_witness, message_elem.witness).map(|witness_value| {
*witness_value.to_be_bytes().last().expect("byte array is never empty")
})
})
.collect::<Result<_, _>>()?;

let valid_signature = self
.blackbox_vendor
.verify_signature(pub_key, sig_s, sig_e, &message_bytes)
.map_err(|err| {
OpcodeResolutionError::BlackBoxFunctionFailed(
BlackBoxFunc::SchnorrVerify,
err.to_string(),
)
})?;
if !valid_signature {
dbg!("signature has failed to verify");
}

insert_value(output, FieldElement::from(valid_signature), initial_witness)?;
Ok(OpcodeResolution::Solved)
})
}

fn pedersen(
&self,
initial_witness: &mut WitnessMap,
inputs: &[FunctionInput],
inputs: &[FieldElement],
domain_separator: u32,
outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
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.blackbox_vendor.encrypt(scalars, domain_separator).map_err(|err| {
OpcodeResolutionError::BlackBoxFunctionFailed(
BlackBoxFunc::Pedersen,
err.to_string(),
)
})?;
insert_value(&outputs[0], res_x, initial_witness)?;
insert_value(&outputs[1], res_y, initial_witness)?;
Ok(OpcodeResolution::Solved)
) -> Result<(FieldElement, FieldElement), OpcodeResolutionError> {
self.blackbox_vendor.encrypt(inputs.to_vec(), domain_separator).map_err(|err| {
OpcodeResolutionError::BlackBoxFunctionFailed(BlackBoxFunc::Pedersen, err.to_string())
})
}

fn fixed_base_scalar_mul(
&self,
initial_witness: &mut WitnessMap,
input: &FunctionInput,
outputs: &[Witness],
) -> Result<OpcodeResolution, OpcodeResolutionError> {
let scalar = witness_to_value(initial_witness, input.witness)?;

let (pub_x, pub_y) = self.blackbox_vendor.fixed_base(scalar).map_err(|err| {
input: &FieldElement,
) -> Result<(FieldElement, FieldElement), OpcodeResolutionError> {
self.blackbox_vendor.fixed_base(input).map_err(|err| {
OpcodeResolutionError::BlackBoxFunctionFailed(
BlackBoxFunc::FixedBaseScalarMul,
err.to_string(),
)
})?;

insert_value(&outputs[0], pub_x, initial_witness)?;
insert_value(&outputs[1], pub_y, initial_witness)?;
Ok(OpcodeResolution::Solved)
})
}
}

Expand All @@ -156,69 +80,32 @@ pub async fn execute_circuit(
circuit: Vec<u8>,
initial_witness: JsWitnessMap,
foreign_call_handler: ForeignCallHandler,
) -> Result<JsWitnessMap, JsValue> {
) -> Result<JsWitnessMap, js_sys::JsString> {
console_error_panic_hook::set_once();
let circuit: Circuit = Circuit::read(&*circuit).expect("Failed to deserialize circuit");
let mut witness_map = WitnessMap::from(initial_witness);

let backend = SimulatedBackend::initialize().await;
let mut blocks = Blocks::default();
let mut opcodes = circuit.opcodes;
let mut acvm = ACVM::new(backend, circuit.opcodes, initial_witness.into());

loop {
let solver_status = acvm::pwg::solve(&backend, &mut witness_map, &mut blocks, opcodes)
.map_err(|err| err.to_string())?;
let solver_status = acvm.solve();

match solver_status {
PartialWitnessGeneratorStatus::Solved => break,
PartialWitnessGeneratorStatus::RequiresOracleData {
required_oracle_data: _,
unsolved_opcodes,
unresolved_brillig_calls,
} => {
// Brillig calls return a new set of opcodes which need to be executed.
let new_brillig_opcodes: Vec<Opcode> =
process_brillig_calls(&foreign_call_handler, unresolved_brillig_calls).await?;
ACVMStatus::Solved => break,
ACVMStatus::InProgress => {
unreachable!("Execution should not stop while in `InProgress` state.")
}
ACVMStatus::Failure(error) => return Err(error.to_string().into()),
ACVMStatus::RequiresForeignCall => {
while let Some(foreign_call) = acvm.get_pending_foreign_call() {
let result = resolve_brillig(&foreign_call_handler, foreign_call).await?;

// Use new opcodes as returned by ACVM.
opcodes = new_brillig_opcodes;
opcodes.extend(unsolved_opcodes);
acvm.resolve_pending_foreign_call(result);
}
}
}
}

let witness_map = acvm.finalize();
Ok(witness_map.into())
}

/// Peforms the foreign calls associated with [`brillig_foreign_calls`][UnresolvedBrilligCall] and returns a vector of updated
/// [Brillig][acvm::acir::circuit::brillig::Brillig] to execute.
async fn process_brillig_calls(
foreign_call_callback: &ForeignCallHandler,
brillig_foreign_calls: Vec<UnresolvedBrilligCall>,
) -> Result<Vec<Opcode>, String> {
// Pull out foreign call args (necessary to satisfy the borrow checker).
let foreign_call_wait_infos: Vec<_> = brillig_foreign_calls
.iter()
.map(|foreign_call| foreign_call.foreign_call_wait_info.clone())
.collect();

// Perform all foreign calls.
let foreign_call_futures: Vec<_> = foreign_call_wait_infos
.iter()
.map(|wait_info| resolve_brillig(foreign_call_callback, wait_info))
.collect();

// Apply results to Brillig opcodes.
let mut updated_brillig_opcodes = Vec::with_capacity(brillig_foreign_calls.len());
for (foreign_call, foreign_call_future) in
brillig_foreign_calls.into_iter().zip(foreign_call_futures.into_iter())
{
let foreign_call_result = foreign_call_future.await?;

let mut new_brillig = foreign_call.brillig;
new_brillig.foreign_call_results.push(foreign_call_result);
updated_brillig_opcodes.push(Opcode::Brillig(new_brillig));
}

Ok(updated_brillig_opcodes)
}
2 changes: 1 addition & 1 deletion test/browser/execute_circuit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,5 +117,5 @@ it("successfully executes a SchnorrVerify opcode", async () => {
}
);

expect(solvedWitness).to.be.eq(expectedWitnessMap);
expect(solvedWitness).to.be.deep.eq(expectedWitnessMap);
});

0 comments on commit 025cff4

Please sign in to comment.