Browse Source

Early exit in error callback from Wasm (#9)

* Early exit in error callback from Wasm

This avoids Wasm execution hanging due to problems such as wrong public
input.

Mimics circom_runtime behaviour with less detailed debug information.

See https://github.com/iden3/circom_runtime/blob/master/js/witness_calculator.js#L52-L64

Adds test for wrong public input. Without early exit, the test stalls.
With it, the Circom build step fails as expected.

* chore: clean up error handling

* ci: add caching

Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
pull/3/head
oskarth 3 years ago
committed by GitHub
parent
commit
b1daefca96
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 42 additions and 3 deletions
  1. +5
    -1
      .github/workflows/ci.yml
  2. +16
    -2
      src/witness/witness_calculator.rs
  3. +21
    -0
      tests/groth16.rs

+ 5
- 1
.github/workflows/ci.yml

@ -1,6 +1,6 @@
on: on:
push: push:
branches:
branches:
- master - master
pull_request: pull_request:
@ -35,6 +35,10 @@ jobs:
export PATH=$HOME/bin:$PATH export PATH=$HOME/bin:$PATH
solc --version solc --version
- uses: Swatinem/rust-cache@v1
with:
cache-on-failure: true
- name: cargo test - name: cargo test
run: | run: |
export PATH=$HOME/bin:$PATH export PATH=$HOME/bin:$PATH

+ 16
- 2
src/witness/witness_calculator.rs

@ -2,7 +2,7 @@ use color_eyre::Result;
use num_bigint::BigInt; use num_bigint::BigInt;
use num_traits::Zero; use num_traits::Zero;
use std::cell::Cell; use std::cell::Cell;
use wasmer::{imports, Function, Instance, Memory, MemoryType, Module, Store};
use wasmer::{imports, Function, Instance, Memory, MemoryType, Module, RuntimeError, Store};
use super::{fnv, SafeMemory, Wasm}; use super::{fnv, SafeMemory, Wasm};
@ -13,6 +13,12 @@ pub struct WitnessCalculator {
pub n64: i32, pub n64: i32,
} }
// Error type to signal end of execution.
// From https://docs.wasmer.io/integrations/examples/exit-early
#[derive(thiserror::Error, Debug, Clone, Copy)]
#[error("{0}")]
struct ExitCode(u32);
impl WitnessCalculator { impl WitnessCalculator {
pub fn new(path: impl AsRef<std::path::Path>) -> Result<Self> { pub fn new(path: impl AsRef<std::path::Path>) -> Result<Self> {
let store = Store::default(); let store = Store::default();
@ -144,7 +150,15 @@ mod runtime {
pub fn error(store: &Store) -> Function { pub fn error(store: &Store) -> Function {
#[allow(unused)] #[allow(unused)]
#[allow(clippy::many_single_char_names)] #[allow(clippy::many_single_char_names)]
fn func(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) {}
fn func(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32) {
// NOTE: We can also get more information why it is failing, see p2str etc here:
// https://github.com/iden3/circom_runtime/blob/master/js/witness_calculator.js#L52-L64
println!(
"runtime error, exiting early: {0} {1} {2} {3} {4} {5}",
a, b, c, d, e, f
);
RuntimeError::raise(Box::new(ExitCode(1)));
}
Function::new_native(store, func) Function::new_native(store, func)
} }

+ 21
- 0
tests/groth16.rs

@ -37,3 +37,24 @@ fn groth16_proof() -> Result<()> {
Ok(()) Ok(())
} }
#[test]
fn groth16_proof_wrong_input() {
let cfg = CircomConfig::<Bn254>::new(
"./test-vectors/mycircuit.wasm",
"./test-vectors/mycircuit.r1cs",
)
.unwrap();
let mut builder = CircomBuilder::new(cfg);
builder.push_input("a", 3);
// This isn't a public input to the circuit, should faild
builder.push_input("foo", 11);
// create an empty instance for setting it up
let circom = builder.setup();
let mut rng = thread_rng();
let _params = generate_random_parameters::<Bn254, _, _>(circom, &mut rng).unwrap();
builder.build().unwrap_err();
}

Loading…
Cancel
Save