Skip to content

Commit

Permalink
feat: replace opaque witness maps with js Maps
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAFrench committed May 15, 2023
1 parent 12c9b4a commit c84ffd4
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 49 deletions.
104 changes: 74 additions & 30 deletions Cargo.lock

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

8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[package]
name = "noir_wasm"
name = "acvm-simulator"
version = "0.0.0"
authors = ["The Noir Team <[email protected]>"]
edition = "2021"
Expand All @@ -14,12 +14,16 @@ crate-type = ["cdylib"]
acvm = "0.10.3"
iter-extended = { git = "https://github.com/noir-lang/noir", rev = "7f6dede414c46790545b1994713d1976c5623711"}
noirc_abi = { git = "https://github.com/noir-lang/noir", rev = "7f6dede414c46790545b1994713d1976c5623711"}
wasm-bindgen = { version = "0.2.83", features = ["serde-serialize"] }
wasm-bindgen = { version = "0.2.85", features = ["serde-serialize"] }
serde = { version = "1.0.136", features = ["derive"] }
log = "0.4.17"
wasm-logger = "0.2.0"
console_error_panic_hook = "0.1.7"
gloo-utils = { version = "0.1", features = ["serde"] }
js-sys = "0.3.62"

[build-dependencies]
build-data = "0.1.3"

[dev-dependencies]
wasm-bindgen-test = "0.3.35"
12 changes: 7 additions & 5 deletions src/abi.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use acvm::{acir::native_types::Witness, FieldElement};
use iter_extended::{btree_map, try_btree_map};
use noirc_abi::{errors::InputParserError, input_parser::InputValue, Abi, MAIN_RETURN_NAME};
use serde::Serialize;
Expand All @@ -9,10 +8,12 @@ use wasm_bindgen::{prelude::wasm_bindgen, JsValue};

mod temp;

use crate::{js_map_to_witness_map, witness_map_to_js_map};

use self::temp::{input_value_from_json_type, JsonTypes};

#[wasm_bindgen]
pub fn abi_encode(abi: JsValue, inputs: JsValue, return_value: JsValue) -> Vec<u8> {
pub fn abi_encode(abi: JsValue, inputs: JsValue, return_value: JsValue) -> js_sys::Map {
console_error_panic_hook::set_once();
let abi: Abi = JsValueSerdeExt::into_serde(&abi).expect("could not decode abi");
let inputs: BTreeMap<String, JsonTypes> =
Expand Down Expand Up @@ -47,14 +48,15 @@ pub fn abi_encode(abi: JsValue, inputs: JsValue, return_value: JsValue) -> Vec<u

let witness_map = abi.encode(&parsed_inputs, return_value).expect("abi encoding error");

Witness::to_bytes(&witness_map)
witness_map_to_js_map(witness_map)
}

#[wasm_bindgen]
pub fn abi_decode(abi: JsValue, witness_map: Vec<u8>) -> JsValue {
pub fn abi_decode(abi: JsValue, witness_map: js_sys::Map) -> JsValue {
console_error_panic_hook::set_once();
let abi: Abi = JsValueSerdeExt::into_serde(&abi).expect("could not decode abi");
let witness_map: BTreeMap<Witness, FieldElement> = Witness::from_bytes(&witness_map);

let witness_map = js_map_to_witness_map(witness_map);

let (inputs, return_value) = abi.decode(&witness_map).expect("abi decoding error");

Expand Down
8 changes: 5 additions & 3 deletions src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use std::collections::BTreeMap;

use wasm_bindgen::prelude::wasm_bindgen;

use crate::{js_map_to_witness_map, witness_map_to_js_map};

struct SimulatedBackend;

impl PartialWitnessGenerator for SimulatedBackend {
Expand Down Expand Up @@ -46,16 +48,16 @@ impl PartialWitnessGenerator for SimulatedBackend {
}

#[wasm_bindgen]
pub fn execute_circuit(circuit: Vec<u8>, initial_witness: Vec<u8>) -> Vec<u8> {
pub fn execute_circuit(circuit: Vec<u8>, initial_witness: js_sys::Map) -> js_sys::Map {
console_error_panic_hook::set_once();
let circuit: Circuit = Circuit::read(&*circuit).expect("Failed to deserialize circuit");
let mut witness_map: BTreeMap<Witness, FieldElement> = Witness::from_bytes(&initial_witness);
let mut witness_map = js_map_to_witness_map(initial_witness);

let mut blocks = Blocks::default();
let solver_status = SimulatedBackend
.solve(&mut witness_map, &mut blocks, circuit.opcodes)
.expect("Threw error while executing circuit");
assert_eq!(solver_status, PartialWitnessGeneratorStatus::Solved);

Witness::to_bytes(&witness_map)
witness_map_to_js_map(witness_map)
}
63 changes: 62 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#![forbid(unsafe_code)]
#![warn(unused_crate_dependencies, unused_extern_crates)]
#![warn(unreachable_pub)]
use acvm::{acir::native_types::Witness, FieldElement};
use gloo_utils::format::JsValueSerdeExt;
use log::Level;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
use std::{collections::BTreeMap, str::FromStr};
use wasm_bindgen::prelude::*;

mod abi;
Expand Down Expand Up @@ -43,3 +44,63 @@ pub fn build_info() -> JsValue {
console_error_panic_hook::set_once();
<JsValue as JsValueSerdeExt>::from_serde(&BUILD_INFO).unwrap()
}

fn js_map_to_witness_map(js_map: js_sys::Map) -> BTreeMap<Witness, FieldElement> {
let mut witness_map: BTreeMap<Witness, FieldElement> = BTreeMap::new();
js_map.for_each(&mut |value, key| {
let witness_index = Witness(key.as_string().unwrap().parse::<u32>().unwrap());
// let witness_value: String = js_sys::BigInt::from(value)
// .to_string(16)
// .expect("Could not get value of witness")
// .into();
let witness_value: String = value.as_string().expect("Could not get value of witness");

let witness_value =
FieldElement::from_hex(&witness_value).expect("could not convert bigint to fields");
witness_map.insert(witness_index, witness_value);
});
witness_map
}

fn witness_map_to_js_map(witness_map: BTreeMap<Witness, FieldElement>) -> js_sys::Map {
let js_map = js_sys::Map::new();
for (key, value) in witness_map {
// This currently maps `0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000`
// to the bigint `-1n`. This fails when converting back to a `FieldElement`.

// let witness_bigint = js_sys::BigInt::from_str(&value.to_hex())
// .expect("could not convert field to bigint");

let witness_bigint = JsValue::from_str(&value.to_hex());

js_map.set(
&wasm_bindgen::JsValue::from_str(&key.witness_index().to_string()),
&witness_bigint,
);
}
js_map
}

#[cfg(test)]
mod test {
use std::collections::BTreeMap;

use acvm::{acir::native_types::Witness, FieldElement};
use wasm_bindgen::JsValue;
use wasm_bindgen_test::*;

use crate::witness_map_to_js_map;

#[wasm_bindgen_test]
fn test_witness_map_to_js() {
let witness_map = BTreeMap::from([
(Witness(1), FieldElement::one()),
(Witness(2), FieldElement::zero()),
(Witness(3), -FieldElement::one()),
]);

let js_map = witness_map_to_js_map(witness_map);

assert_eq!(js_map.get(&JsValue::from("1")), JsValue::from_str("1"));
}
}
12 changes: 8 additions & 4 deletions test/abi_encode.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { test } from "@jest/globals"
import { expect, test } from "@jest/globals"
import { abi_encode, abi_decode } from "../pkg/"

test('recovers original inputs when abi encoding and decoding', () => {
Expand All @@ -16,7 +16,11 @@ test('recovers original inputs when abi encoding and decoding', () => {
foo: "1",
bar: ["1", "2"]
};
const initial_witness = abi_encode(abi, inputs, null);
const decoded_inputs = abi_decode(abi, initial_witness);
console.log(decoded_inputs);
const initial_witness: Map<string, string> = abi_encode(abi, inputs, null);
const decoded_inputs: {inputs: Record<string, any>, return_value: any} = abi_decode(abi, initial_witness);

expect(BigInt(decoded_inputs.inputs.foo)).toBe(BigInt(inputs.foo))
expect(BigInt(decoded_inputs.inputs.bar[0])).toBe(BigInt(inputs.bar[0]))
expect(BigInt(decoded_inputs.inputs.bar[1])).toBe(BigInt(inputs.bar[1]))
expect(decoded_inputs.return_value).toBe(null)
});
Loading

0 comments on commit c84ffd4

Please sign in to comment.