Skip to content

Commit

Permalink
fix(ffi, ios): generateProof should accept 254-bit elements (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
vivianjeng authored Nov 2, 2023
1 parent 1f4a1d0 commit 1a40b5a
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 44 deletions.
33 changes: 24 additions & 9 deletions mopro-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use mopro_core::MoproError;
use num_bigint::BigInt;

use std::collections::HashMap;
use std::str::FromStr;
use std::sync::RwLock;

#[derive(Debug)]
Expand Down Expand Up @@ -65,14 +66,21 @@ impl MoproCircom {

pub fn generate_proof(
&self,
inputs: HashMap<String, Vec<i32>>,
inputs: HashMap<String, Vec<String>>,
) -> Result<GenerateProofResult, MoproError> {
let mut state_guard = self.state.write().unwrap();

// Convert inputs to BigInt
let bigint_inputs = inputs
.into_iter()
.map(|(k, v)| (k, v.into_iter().map(|i| BigInt::from(i)).collect()))
.map(|(k, v)| {
(
k,
v.into_iter()
.map(|i| BigInt::from_str(&i).unwrap())
.collect(),
)
})
.collect();

let (proof, inputs) = state_guard.generate_proof(bigint_inputs)?;
Expand Down Expand Up @@ -119,10 +127,14 @@ uniffi::include_scaffolding!("mopro");
mod tests {
use super::*;
use ark_bn254::Fr;
use num_bigint::BigUint;

fn bytes_to_circuit_inputs(input_vec: &Vec<u8>) -> HashMap<String, Vec<i32>> {
fn bytes_to_circuit_inputs(input_vec: &Vec<u8>) -> HashMap<String, Vec<String>> {
let bits = circom::utils::bytes_to_bits(&input_vec);
let converted_vec: Vec<i32> = bits.into_iter().map(|bit| bit as i32).collect();
let converted_vec: Vec<String> = bits
.into_iter()
.map(|bit| (bit as i32).to_string())
.collect();
let mut inputs = HashMap::new();
inputs.insert("in".to_string(), converted_vec);
inputs
Expand Down Expand Up @@ -156,11 +168,14 @@ mod tests {
assert!(setup_result.provingKey.len() > 0);

let mut inputs = HashMap::new();
let a = 3;
let b = 5;
let c = a * b;
inputs.insert("a".to_string(), vec![a]);
inputs.insert("b".to_string(), vec![b]);
let a = BigUint::from_str(
"21888242871839275222246405745257275088548364400416034343698204186575808495616",
)
.unwrap();
let b = BigUint::from(1u8);
let c = a.clone() * b.clone();
inputs.insert("a".to_string(), vec![a.to_string()]);
inputs.insert("b".to_string(), vec![b.to_string()]);
// output = [public output c, public input a]
let expected_output = vec![Fr::from(c), Fr::from(a)];
let circom_outputs = circom::serialization::SerializableInputs(expected_output);
Expand Down
4 changes: 2 additions & 2 deletions mopro-ffi/src/mopro.udl
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ interface MoproCircom {
SetupResult setup(string wasm_path, string r1cs_path);

[Throws=MoproError]
GenerateProofResult generate_proof(record<string, sequence<i32>> circuit_inputs);
GenerateProofResult generate_proof(record<string, sequence<string>> circuit_inputs);

[Throws=MoproError]
boolean verify_proof(bytes proof, bytes public_input);
};
};
21 changes: 12 additions & 9 deletions mopro-ffi/tests/bindings/test_mopro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,17 @@ let moproCircom = MoproCircom()
let wasmPath = "./../../../../mopro-core/examples/circom/multiplier2/target/multiplier2_js/multiplier2.wasm"
let r1csPath = "./../../../../mopro-core/examples/circom/multiplier2/target/multiplier2.r1cs"

// TODO: should handle 254-bit input
func serializeOutputs(_ int32Array: [Int32]) -> [UInt8] {
func serializeOutputs(_ stringArray: [String]) -> [UInt8] {
var bytesArray: [UInt8] = []
let length = int32Array.count
let length = stringArray.count
var littleEndianLength = length.littleEndian
let targetLength = 32
withUnsafeBytes(of: &littleEndianLength) {
bytesArray.append(contentsOf: $0)
}
for value in int32Array {
var littleEndian = value.littleEndian
for value in stringArray {
// TODO: should handle 254-bit input
var littleEndian = Int32(value)!.littleEndian
var byteLength = 0
withUnsafeBytes(of: &littleEndian) {
bytesArray.append(contentsOf: $0)
Expand All @@ -37,12 +37,15 @@ do {
assert(!setupResult.provingKey.isEmpty, "Proving key should not be empty")

// Prepare inputs
var inputs = [String: [Int32]]()
inputs["a"] = [3]
inputs["b"] = [5]
var inputs = [String: [String]]()
let a = 3
let b = 5
let c = a*b
inputs["a"] = [String(a)]
inputs["b"] = [String(b)]

// Expected outputs
let outputs: [Int32] = [15, 3]
let outputs: [String] = [String(c), String(a)]
let expectedOutput: [UInt8] = serializeOutputs(outputs)

// Generate Proof
Expand Down
20 changes: 10 additions & 10 deletions mopro-ffi/tests/bindings/test_mopro_keccak.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,28 @@ let wasmPath = "./../../../../mopro-core/examples/circom/keccak256/target/keccak
let r1csPath = "./../../../../mopro-core/examples/circom/keccak256/target/keccak256_256_test.r1cs"

// Helper function to convert bytes to bits
func bytesToBits(bytes: [UInt8]) -> [Int32] {
var bits = [Int32]()
func bytesToBits(bytes: [UInt8]) -> [String] {
var bits = [String]()
for byte in bytes {
for j in 0..<8 {
let bit = (byte >> j) & 1
bits.append(Int32(bit))
bits.append(String(bit))
}
}
return bits
}

// TODO: should handle 254-bit input
func serializeOutputs(_ int32Array: [Int32]) -> [UInt8] {
func serializeOutputs(_ stringArray: [String]) -> [UInt8] {
var bytesArray: [UInt8] = []
let length = int32Array.count
let length = stringArray.count
var littleEndianLength = length.littleEndian
let targetLength = 32
withUnsafeBytes(of: &littleEndianLength) {
bytesArray.append(contentsOf: $0)
}
for value in int32Array {
var littleEndian = value.littleEndian
for value in stringArray {
// TODO: should handle 254-bit input
var littleEndian = Int32(value)!.littleEndian
var byteLength = 0
withUnsafeBytes(of: &littleEndian) {
bytesArray.append(contentsOf: $0)
Expand All @@ -54,15 +54,15 @@ do {
0, 0, 0, 0, 0, 0,
]
let bits = bytesToBits(bytes: inputVec)
var inputs = [String: [Int32]]()
var inputs = [String: [String]]()
inputs["in"] = bits

// Expected outputs
let outputVec: [UInt8] = [
37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88,
212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21,
]
let outputBits: [Int32] = bytesToBits(bytes: outputVec)
let outputBits: [String] = bytesToBits(bytes: outputVec)
let expectedOutput: [UInt8] = serializeOutputs(outputBits)

// Generate Proof
Expand Down
31 changes: 17 additions & 14 deletions mopro-ios/MoproKit/Example/MoproKit/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,22 +91,25 @@ class ViewController: UIViewController {
0, 0, 0, 0, 0, 0,
]
let bits = bytesToBits(bytes: inputVec)
var inputs = [String: [Int32]]()
var inputs = [String: [String]]()
inputs["in"] = bits

// Expected outputs
let outputVec: [UInt8] = [
37, 17, 98, 135, 161, 178, 88, 97, 125, 150, 143, 65, 228, 211, 170, 133, 153, 9, 88,
212, 4, 212, 175, 238, 249, 210, 214, 116, 170, 85, 45, 21,
]
let outputBits: [Int32] = bytesToBits(bytes: outputVec)
let outputBits: [String] = bytesToBits(bytes: outputVec)
let expectedOutput: [UInt8] = serializeOutputs(outputBits)

// Multiplier example
// var inputs = [String: [Int32]]()
// inputs["a"] = [3]
// inputs["b"] = [5]
// let outputs: [Int32] = [15, 3]
// var inputs = [String: [String]]()
// let a = 3
// let b = 5
// let c = a*b
// inputs["a"] = [String(a)]
// inputs["b"] = [String(b)]
// let outputs: [String] = [String(c), String(a)]
// let expectedOutput: [UInt8] = serializeOutputs(outputs)

// Record start time
Expand Down Expand Up @@ -161,28 +164,28 @@ class ViewController: UIViewController {

}

func bytesToBits(bytes: [UInt8]) -> [Int32] {
var bits = [Int32]()
func bytesToBits(bytes: [UInt8]) -> [String] {
var bits = [String]()
for byte in bytes {
for j in 0..<8 {
let bit = (byte >> j) & 1
bits.append(Int32(bit))
bits.append(String(bit))
}
}
return bits
}

// TODO: should handle 254-bit input
func serializeOutputs(_ int32Array: [Int32]) -> [UInt8] {
func serializeOutputs(_ stringArray: [String]) -> [UInt8] {
var bytesArray: [UInt8] = []
let length = int32Array.count
let length = stringArray.count
var littleEndianLength = length.littleEndian
let targetLength = 32
withUnsafeBytes(of: &littleEndianLength) {
bytesArray.append(contentsOf: $0)
}
for value in int32Array {
var littleEndian = value.littleEndian
for value in stringArray {
// TODO: should handle 254-bit input
var littleEndian = Int32(value)!.littleEndian
var byteLength = 0
withUnsafeBytes(of: &littleEndian) {
bytesArray.append(contentsOf: $0)
Expand Down

0 comments on commit 1a40b5a

Please sign in to comment.