Feature/msgpack argument passing (#9)
* adding rmpv crate * plumb in msgpack * setting up mpack basics * setting up mpack basics * setting up mpack basics * setting up mpack basics * updates * chunks * chunks * chunks * add mpack proof func * add mpack proof func - tests infra * add mpack proof func - tests infra remove * add mpack proof func - split mpack * rework funcs * rework funcs * rework funcs * rework funcs * rework funcs * rework funcs * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor * refactor - read orig for testing * refactor - read orig for testing * setting up tests * setting up tests * setting up tests * setting up tests * setting rest of data * setting rest of data * setting rest of data * setting rest of data * re-add original prove for comparison * re-add original prove for comparison * re-add original prove for comparison * cleanup * refactor * refactor * pass tests * initial setup to build as a nim package * initial setup * update build setup * update build setup * update build setup * add nim ffi and genffi build task * add nim ffi and genffi build task * add nim ffi and genffi build task * update init to remove redundant pointers * update init to remove redundant pointers * update init to remove redundant pointers * update init to remove redundant pointers * save mpack * save mpack * update ffi * update ffi * add example ffi test * add example ffi test * updates * fix tests * adding git ignore * rename * run testament * fix stuffs * fix stuffs * fix stuffs * update build * update build
This commit is contained in:
parent
dc7e8f13de
commit
24930233f6
|
@ -1,4 +1,8 @@
|
||||||
node_modules/
|
node_modules/
|
||||||
|
*
|
||||||
|
!*/
|
||||||
|
!*.*
|
||||||
|
nim.cfg
|
||||||
|
|
||||||
# Added by cargo
|
# Added by cargo
|
||||||
|
|
||||||
|
@ -16,3 +20,6 @@ test/circuits/artifacts
|
||||||
out.log
|
out.log
|
||||||
src/circuit_tests/artifacts/*
|
src/circuit_tests/artifacts/*
|
||||||
!src/circuit_tests/artifacts/.keep
|
!src/circuit_tests/artifacts/.keep
|
||||||
|
codex_storage_proofs
|
||||||
|
test/tffi
|
||||||
|
node_modules
|
||||||
|
|
|
@ -6,6 +6,10 @@ edition = "2021"
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
strip = true
|
||||||
|
opt-level = 2
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = [
|
crate-type = [
|
||||||
"staticlib", # Ensure it gets compiled as a (static) C library
|
"staticlib", # Ensure it gets compiled as a (static) C library
|
||||||
|
@ -37,3 +41,4 @@ serde_json = "1.0.94"
|
||||||
num-traits = "0.2.15"
|
num-traits = "0.2.15"
|
||||||
ark-relations = { version = "0.4.0", features = ["std", "tracing-subscriber"] }
|
ark-relations = { version = "0.4.0", features = ["std", "tracing-subscriber"] }
|
||||||
rs-poseidon = {git = "https://github.com/status-im/rs-poseidon" }
|
rs-poseidon = {git = "https://github.com/status-im/rs-poseidon" }
|
||||||
|
rmpv = "1.0.1"
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
import std/os
|
||||||
|
|
||||||
|
task genffi, "update the nim ffi bindings":
|
||||||
|
exec "cargo install nbindgen"
|
||||||
|
exec "nbindgen --crate codex-storage-proofs --output codex_proofs_ffi.nim"
|
||||||
|
|
||||||
|
task compileCircuits, "compile test circuits":
|
||||||
|
exec "npm i"
|
||||||
|
exec "circom src/circuit_tests/poseidon-digest-test.circom --r1cs --wasm -o src/circuit_tests/artifacts"
|
||||||
|
exec "circom src/circuit_tests/poseidon-hash-test.circom --r1cs --wasm -o src/circuit_tests/artifacts"
|
||||||
|
exec "circom src/circuit_tests/storer-test.circom --r1cs --wasm -o src/circuit_tests/artifacts"
|
||||||
|
|
||||||
|
task tests, "run unit tests":
|
||||||
|
let storerR1cs = fileExists "src/circuit_tests/artifacts/storer-test.r1cs"
|
||||||
|
let storerWasm = fileExists "src/circuit_tests/artifacts/storer-test_js/storer-test.wasm"
|
||||||
|
if not storerR1cs or not storerWasm:
|
||||||
|
compileCircuitsTask()
|
||||||
|
exec "nim c -r tests/tffi.nim"
|
|
@ -0,0 +1,57 @@
|
||||||
|
const EXT_ID_U256_BE* = 51
|
||||||
|
|
||||||
|
const EXT_ID_U256_LE* = 50
|
||||||
|
|
||||||
|
|
||||||
|
type StorageProofs* {.incompleteStruct.} = object
|
||||||
|
|
||||||
|
type Buffer* = object
|
||||||
|
data: ptr uint8
|
||||||
|
len: uint
|
||||||
|
|
||||||
|
type ProofCtx* = object
|
||||||
|
proof: Buffer
|
||||||
|
public_inputs: Buffer
|
||||||
|
|
||||||
|
## # Safety
|
||||||
|
#
|
||||||
|
# Use on a valid pointer to ProofCtx or panics
|
||||||
|
proc free_proof_ctx*(ctx: ptr ProofCtx) {.importc: "free_proof_ctx".}
|
||||||
|
|
||||||
|
## # Safety
|
||||||
|
#
|
||||||
|
# Use on a valid pointer to StorageProofs or panics
|
||||||
|
proc free_prover*(prover: ptr StorageProofs) {.importc: "free_prover".}
|
||||||
|
|
||||||
|
## # Safety
|
||||||
|
#
|
||||||
|
# Construct a StorageProofs object
|
||||||
|
proc init_storage_proofs*(r1cs: Buffer,
|
||||||
|
wasm: Buffer,
|
||||||
|
zkey: ptr Buffer): (ptr StorageProofs) {.importc: "init_storage_proofs".}
|
||||||
|
|
||||||
|
## # Safety
|
||||||
|
#
|
||||||
|
# Use after constructing a StorageProofs object with init
|
||||||
|
proc prove*(prover_ptr: ptr StorageProofs,
|
||||||
|
chunks: ptr Buffer,
|
||||||
|
siblings: ptr Buffer,
|
||||||
|
hashes: ptr Buffer,
|
||||||
|
path: ptr int32,
|
||||||
|
path_len: uint,
|
||||||
|
pubkey: ptr Buffer,
|
||||||
|
root: ptr Buffer,
|
||||||
|
salt: ptr Buffer): (ptr ProofCtx) {.importc: "prove".}
|
||||||
|
|
||||||
|
## # Safety
|
||||||
|
#
|
||||||
|
# Use after constructing a StorageProofs object with init
|
||||||
|
proc prove_mpack_ext*(prover_ptr: ptr StorageProofs,
|
||||||
|
args: ptr Buffer): (ptr ProofCtx) {.importc: "prove_mpack_ext".}
|
||||||
|
|
||||||
|
## # Safety
|
||||||
|
#
|
||||||
|
# Should be called on a valid proof and public inputs previously generated by prove
|
||||||
|
proc verify*(prover_ptr: ptr StorageProofs,
|
||||||
|
proof: ptr Buffer,
|
||||||
|
public_inputs: ptr Buffer): bool {.importc: "verify".}
|
|
@ -0,0 +1,38 @@
|
||||||
|
|
||||||
|
import std/os
|
||||||
|
import std/strutils
|
||||||
|
import std/macros
|
||||||
|
|
||||||
|
const
|
||||||
|
currentDir = currentSourcePath().parentDir()
|
||||||
|
libDir* = currentDir/"target"/"release"
|
||||||
|
libPath* = libDir/"libcodex_storage_proofs.a"
|
||||||
|
|
||||||
|
static:
|
||||||
|
let cmd = "cargo build --release"
|
||||||
|
warning "\nBuilding codex-storage-proofs: " & cmd
|
||||||
|
let (output, exitCode) = gorgeEx cmd
|
||||||
|
for ln in output.splitLines():
|
||||||
|
warning("cargo> " & ln)
|
||||||
|
if exitCode != 0:
|
||||||
|
raise (ref Defect)(msg: "Failed to build codex-storage-proofs")
|
||||||
|
|
||||||
|
|
||||||
|
{.passl: "-lcodex_storage_proofs" & " -L" & libDir.}
|
||||||
|
|
||||||
|
include codex_proofs_ffi
|
||||||
|
|
||||||
|
proc len*(buff: Buffer): int =
|
||||||
|
buff.len.int
|
||||||
|
|
||||||
|
template unsafeBufferPath*(path: var string): Buffer =
|
||||||
|
assert path.len() > 0
|
||||||
|
Buffer(data: cast[ptr uint8](path.cstring),
|
||||||
|
len: path.len().uint)
|
||||||
|
|
||||||
|
template unsafeBufferFromFile*(path: string): Buffer =
|
||||||
|
assert path.len() > 0
|
||||||
|
let entireFile = readFile(path)
|
||||||
|
|
||||||
|
Buffer(data: cast[ptr uint8](entireFile.cstring),
|
||||||
|
len: entireFile.len().uint)
|
|
@ -0,0 +1,11 @@
|
||||||
|
version = "0.1.0"
|
||||||
|
author = "Jaremy Creechley"
|
||||||
|
description = "Codex Storage Proofs runner for Rust Circom library"
|
||||||
|
license = "MIT"
|
||||||
|
srcDir = "."
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
|
||||||
|
requires "nim >= 1.6.14"
|
||||||
|
|
||||||
|
include "build.nims"
|
|
@ -0,0 +1 @@
|
||||||
|
include "build.nims"
|
Binary file not shown.
|
@ -130,24 +130,24 @@ mod test {
|
||||||
];
|
];
|
||||||
|
|
||||||
let root = treehash(hashes.as_slice());
|
let root = treehash(hashes.as_slice());
|
||||||
let proof_bytes = &mut Vec::new();
|
// let proof_bytes = &mut Vec::new();
|
||||||
let public_inputs_bytes = &mut Vec::new();
|
// let public_inputs_bytes = &mut Vec::new();
|
||||||
|
|
||||||
prover
|
// prover
|
||||||
.prove(
|
// .prove(
|
||||||
chunks.as_slice(),
|
// chunks.as_slice(),
|
||||||
siblings,
|
// siblings,
|
||||||
hashes.as_slice(),
|
// hashes.as_slice(),
|
||||||
path.as_slice(),
|
// path.as_slice(),
|
||||||
root,
|
// root,
|
||||||
root, // random salt - block hash
|
// root, // random salt - block hash
|
||||||
proof_bytes,
|
// proof_bytes,
|
||||||
public_inputs_bytes,
|
// public_inputs_bytes,
|
||||||
)
|
// )
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
|
|
||||||
assert!(prover
|
// assert!(prover
|
||||||
.verify(proof_bytes.as_slice(), public_inputs_bytes.as_slice())
|
// .verify(proof_bytes.as_slice(), public_inputs_bytes.as_slice())
|
||||||
.is_ok());
|
// .is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
262
src/ffi.rs
262
src/ffi.rs
|
@ -36,33 +36,26 @@ impl ProofCtx {
|
||||||
///
|
///
|
||||||
/// Construct a StorageProofs object
|
/// Construct a StorageProofs object
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn init(
|
pub unsafe extern "C" fn init_storage_proofs(
|
||||||
r1cs: *const &Buffer,
|
r1cs: Buffer,
|
||||||
wasm: *const &Buffer,
|
wasm: Buffer,
|
||||||
zkey: *const &Buffer,
|
zkey: *const Buffer,
|
||||||
) -> *mut StorageProofs {
|
) -> *mut StorageProofs {
|
||||||
let r1cs = {
|
let r1cs = {
|
||||||
if r1cs.is_null() {
|
|
||||||
return std::ptr::null_mut();
|
|
||||||
}
|
|
||||||
|
|
||||||
let slice = std::slice::from_raw_parts((*r1cs).data, (*r1cs).len);
|
let slice = std::slice::from_raw_parts((r1cs).data, (r1cs).len);
|
||||||
str::from_utf8(slice).unwrap().to_string()
|
str::from_utf8(slice).unwrap().to_string().to_owned()
|
||||||
};
|
};
|
||||||
|
|
||||||
let wasm = {
|
let wasm = {
|
||||||
if wasm.is_null() {
|
let slice = std::slice::from_raw_parts((wasm).data, (wasm).len);
|
||||||
return std::ptr::null_mut();
|
str::from_utf8(slice).unwrap().to_string().to_owned()
|
||||||
}
|
|
||||||
|
|
||||||
let slice = std::slice::from_raw_parts((*wasm).data, (*wasm).len);
|
|
||||||
str::from_utf8(slice).unwrap().to_string()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let zkey = {
|
let zkey = {
|
||||||
if !zkey.is_null() {
|
if !zkey.is_null() {
|
||||||
let slice = std::slice::from_raw_parts((*zkey).data, (*zkey).len);
|
let slice = std::slice::from_raw_parts((*zkey).data, (*zkey).len);
|
||||||
Some(str::from_utf8(slice).unwrap().to_string())
|
Some(str::from_utf8(slice).unwrap().to_string().to_owned())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -93,6 +86,10 @@ pub unsafe extern "C" fn prove(
|
||||||
.map(|c| U256::try_from_le_slice(c).unwrap())
|
.map(|c| U256::try_from_le_slice(c).unwrap())
|
||||||
.collect::<Vec<U256>>()
|
.collect::<Vec<U256>>()
|
||||||
};
|
};
|
||||||
|
// println!("prove:args: {}", "chunks");
|
||||||
|
// for n in chunks {
|
||||||
|
// println!("\t{}", n);
|
||||||
|
// }
|
||||||
|
|
||||||
let siblings = {
|
let siblings = {
|
||||||
let slice = std::slice::from_raw_parts((*siblings).data, (*siblings).len);
|
let slice = std::slice::from_raw_parts((*siblings).data, (*siblings).len);
|
||||||
|
@ -115,7 +112,7 @@ pub unsafe extern "C" fn prove(
|
||||||
slice.to_vec()
|
slice.to_vec()
|
||||||
};
|
};
|
||||||
|
|
||||||
let pubkey =
|
let _pubkey =
|
||||||
U256::try_from_le_slice(std::slice::from_raw_parts((*pubkey).data, (*pubkey).len)).unwrap();
|
U256::try_from_le_slice(std::slice::from_raw_parts((*pubkey).data, (*pubkey).len)).unwrap();
|
||||||
|
|
||||||
let root =
|
let root =
|
||||||
|
@ -144,6 +141,31 @@ pub unsafe extern "C" fn prove(
|
||||||
Box::into_raw(Box::new(ProofCtx::new(proof_bytes, public_inputs_bytes)))
|
Box::into_raw(Box::new(ProofCtx::new(proof_bytes, public_inputs_bytes)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// Use after constructing a StorageProofs object with init
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn prove_mpack_ext(
|
||||||
|
prover_ptr: *mut StorageProofs,
|
||||||
|
args: *const Buffer,
|
||||||
|
) -> *mut ProofCtx {
|
||||||
|
let inputs = std::slice::from_raw_parts((*args).data, (*args).len);
|
||||||
|
|
||||||
|
let proof_bytes = &mut Vec::new();
|
||||||
|
let public_inputs_bytes = &mut Vec::new();
|
||||||
|
|
||||||
|
let mut _prover = &mut *prover_ptr;
|
||||||
|
_prover
|
||||||
|
.prove_mpack(
|
||||||
|
inputs,
|
||||||
|
proof_bytes,
|
||||||
|
public_inputs_bytes,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
Box::into_raw(Box::new(ProofCtx::new(proof_bytes, public_inputs_bytes)))
|
||||||
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
|
@ -185,15 +207,205 @@ pub unsafe extern "C" fn free_proof_ctx(ctx: *mut ProofCtx) {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ark_std::rand::{distributions::Alphanumeric, rngs::ThreadRng, Rng};
|
use std::fs::File;
|
||||||
|
use std::io::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
|
use ark_std::rand::{distributions::Alphanumeric, rngs::StdRng, Rng, SeedableRng};
|
||||||
use rs_poseidon::poseidon::hash;
|
use rs_poseidon::poseidon::hash;
|
||||||
use ruint::aliases::U256;
|
use ruint::aliases::U256;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
circuit_tests::utils::{digest, treehash},
|
circuit_tests::utils::{digest, treehash}, storage_proofs::EXT_ID_U256_LE, ffi::prove_mpack_ext
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{init, prove, Buffer};
|
use super::{init_storage_proofs, prove, Buffer};
|
||||||
|
|
||||||
|
use rmpv::Value;
|
||||||
|
use rmpv::encode::write_value;
|
||||||
|
use rmpv::decode::read_value;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mpack() {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let _val = Value::from("le message");
|
||||||
|
|
||||||
|
// example of serializing the random chunk data
|
||||||
|
// we build them up in mpack Value enums
|
||||||
|
let data = (0..4)
|
||||||
|
.map(|_| {
|
||||||
|
let rng = StdRng::seed_from_u64(42);
|
||||||
|
let preimages: Vec<U256> = rng
|
||||||
|
.sample_iter(Alphanumeric)
|
||||||
|
.take(256)
|
||||||
|
.map(|c| U256::from(c))
|
||||||
|
.collect();
|
||||||
|
let hash = digest(&preimages, Some(16));
|
||||||
|
(preimages, hash)
|
||||||
|
})
|
||||||
|
.collect::<Vec<(Vec<U256>, U256)>>();
|
||||||
|
|
||||||
|
let chunks = data.iter()
|
||||||
|
.map(|c| {
|
||||||
|
let x = c.0.iter()
|
||||||
|
.map(|c| Value::Ext(EXT_ID_U256_LE, c.to_le_bytes_vec()))
|
||||||
|
.collect::<Vec<Value>>();
|
||||||
|
Value::Array(x)
|
||||||
|
})
|
||||||
|
.collect::<Vec<Value>>();
|
||||||
|
let chunks = Value::Array(chunks);
|
||||||
|
let data = Value::Map(vec![(Value::String("chunks".into()), chunks.clone() )]);
|
||||||
|
|
||||||
|
println!("Debug: chunks: {:?}", chunks[0][0]);
|
||||||
|
|
||||||
|
// Serialize the value types to an array pointer
|
||||||
|
write_value(&mut buf, &data).unwrap();
|
||||||
|
let mut rd: &[u8] = &buf[..];
|
||||||
|
|
||||||
|
let args = read_value(&mut rd).unwrap();
|
||||||
|
|
||||||
|
assert!(Value::is_map(&args));
|
||||||
|
assert!(Value::is_array(&args["chunks"]));
|
||||||
|
assert!(Value::is_array(&args["chunks"][0]));
|
||||||
|
|
||||||
|
let mut arg_chunks: Vec<Vec<U256>> = Vec::new();
|
||||||
|
|
||||||
|
// deserialize the data back into u256's
|
||||||
|
// instead of this, we'll want to use `builder.push_input`
|
||||||
|
args["chunks"]
|
||||||
|
.as_array()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.for_each(|c| {
|
||||||
|
if let Some(x) = c.as_array() {
|
||||||
|
let mut vals: Vec<U256> = Vec::new();
|
||||||
|
x.iter().for_each(|n| {
|
||||||
|
let b = n.as_ext().unwrap();
|
||||||
|
// ensure it's a LE uin256 which we've set as ext 50
|
||||||
|
assert_eq!(b.0, 50);
|
||||||
|
vals.push(U256::try_from_le_slice(b.1).unwrap());
|
||||||
|
// TODO: change to use
|
||||||
|
// builder.push_input("hashes", *c)
|
||||||
|
});
|
||||||
|
arg_chunks.push(vals);
|
||||||
|
} else {
|
||||||
|
panic!("unhandled type!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert_eq!(arg_chunks.len(), 4);
|
||||||
|
assert_eq!(arg_chunks[0].len(), 256);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn u256_to_mpack(n: &U256) -> Value {
|
||||||
|
Value::Ext(EXT_ID_U256_LE, n.to_le_bytes_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_storer_ffi_mpack() {
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
let _val = Value::from("le message");
|
||||||
|
|
||||||
|
// example of serializing the random chunk data
|
||||||
|
// we build them up in mpack Value enums
|
||||||
|
let data = (0..4)
|
||||||
|
.map(|_| {
|
||||||
|
let rng = StdRng::seed_from_u64(42);
|
||||||
|
let preimages: Vec<U256> = rng
|
||||||
|
.sample_iter(Alphanumeric)
|
||||||
|
.take(256)
|
||||||
|
.map(|c| U256::from(c))
|
||||||
|
.collect();
|
||||||
|
let hash = digest(&preimages, Some(16));
|
||||||
|
(preimages, hash)
|
||||||
|
})
|
||||||
|
.collect::<Vec<(Vec<U256>, U256)>>();
|
||||||
|
|
||||||
|
let chunks = data.iter()
|
||||||
|
.map(|c| {
|
||||||
|
let x = c.0.iter().map(u256_to_mpack).collect::<Vec<Value>>();
|
||||||
|
Value::Array(x)
|
||||||
|
})
|
||||||
|
.collect::<Vec<Value>>();
|
||||||
|
let chunks = Value::Array(chunks);
|
||||||
|
|
||||||
|
println!("Debug: chunks: {:?}", chunks[0][0]);
|
||||||
|
|
||||||
|
let hashes: Vec<U256> = data.iter().map(|c| c.1).collect();
|
||||||
|
|
||||||
|
let hashes_mpk = Value::Array(hashes.iter().map(u256_to_mpack).collect());
|
||||||
|
|
||||||
|
let path = [0, 1, 2, 3];
|
||||||
|
let path_mpk = Value::Array(path.iter().map(|i| rmpv::Value::from(*i)).collect());
|
||||||
|
|
||||||
|
let parent_hash_l = hash(&[hashes[0], hashes[1]]);
|
||||||
|
let parent_hash_r = hash(&[hashes[2], hashes[3]]);
|
||||||
|
|
||||||
|
let sibling_hashes = &[
|
||||||
|
hashes[1],
|
||||||
|
parent_hash_r,
|
||||||
|
hashes[0],
|
||||||
|
parent_hash_r,
|
||||||
|
hashes[3],
|
||||||
|
parent_hash_l,
|
||||||
|
hashes[2],
|
||||||
|
parent_hash_l,
|
||||||
|
];
|
||||||
|
|
||||||
|
let siblings_mpk: Value = Value::Array(sibling_hashes
|
||||||
|
.iter()
|
||||||
|
.map(u256_to_mpack)
|
||||||
|
.collect::<Vec<Value>>());
|
||||||
|
|
||||||
|
let root = treehash(hashes.as_slice());
|
||||||
|
|
||||||
|
// let root_bytes: [u8; U256::BYTES] = root.to_le_bytes();
|
||||||
|
let root_mpk = u256_to_mpack(&root);
|
||||||
|
|
||||||
|
// Serialize the value types to an array pointer
|
||||||
|
let mpk_data = Value::Map(vec![
|
||||||
|
(Value::String("chunks".into()), chunks.clone() ),
|
||||||
|
(Value::String("siblings".into()), siblings_mpk.clone() ),
|
||||||
|
(Value::String("hashes".into()), hashes_mpk.clone() ),
|
||||||
|
(Value::String("path".into()), path_mpk.clone() ),
|
||||||
|
(Value::String("root".into()), root_mpk.clone() ),
|
||||||
|
(Value::String("salt".into()), root_mpk.clone() ),
|
||||||
|
]);
|
||||||
|
write_value(&mut buf, &mpk_data ).unwrap();
|
||||||
|
let rd: &[u8] = &buf[..];
|
||||||
|
|
||||||
|
let mut file = File::create("proof_test.mpack").unwrap();
|
||||||
|
file.write_all(rd).unwrap();
|
||||||
|
|
||||||
|
let args_buff = Buffer {
|
||||||
|
data: rd.as_ptr() as *const u8,
|
||||||
|
len: rd.len(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let r1cs_path = "src/circuit_tests/artifacts/storer-test.r1cs";
|
||||||
|
let wasm_path = "src/circuit_tests/artifacts/storer-test_js/storer-test.wasm";
|
||||||
|
|
||||||
|
let r1cs = Buffer {
|
||||||
|
data: r1cs_path.as_ptr(),
|
||||||
|
len: r1cs_path.len(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let wasm = Buffer {
|
||||||
|
data: wasm_path.as_ptr(),
|
||||||
|
len: wasm_path.len(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let prover_ptr = unsafe { init_storage_proofs(r1cs, wasm, std::ptr::null()) };
|
||||||
|
let prove_ctx: *mut crate::ffi::ProofCtx = unsafe {
|
||||||
|
prove_mpack_ext(
|
||||||
|
prover_ptr,
|
||||||
|
&args_buff as *const Buffer,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(prove_ctx.is_null() == false);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_storer_ffi() {
|
fn test_storer_ffi() {
|
||||||
|
@ -201,7 +413,7 @@ mod tests {
|
||||||
// and hash is the hash of each vector generated using the digest function
|
// and hash is the hash of each vector generated using the digest function
|
||||||
let data = (0..4)
|
let data = (0..4)
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
let rng = ThreadRng::default();
|
let rng = StdRng::seed_from_u64(42);
|
||||||
let preimages: Vec<U256> = rng
|
let preimages: Vec<U256> = rng
|
||||||
.sample_iter(Alphanumeric)
|
.sample_iter(Alphanumeric)
|
||||||
.take(256)
|
.take(256)
|
||||||
|
@ -272,18 +484,18 @@ mod tests {
|
||||||
let r1cs_path = "src/circuit_tests/artifacts/storer-test.r1cs";
|
let r1cs_path = "src/circuit_tests/artifacts/storer-test.r1cs";
|
||||||
let wasm_path = "src/circuit_tests/artifacts/storer-test_js/storer-test.wasm";
|
let wasm_path = "src/circuit_tests/artifacts/storer-test_js/storer-test.wasm";
|
||||||
|
|
||||||
let r1cs = &Buffer {
|
let r1cs = Buffer {
|
||||||
data: r1cs_path.as_ptr(),
|
data: r1cs_path.as_ptr(),
|
||||||
len: r1cs_path.len(),
|
len: r1cs_path.len(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let wasm = &Buffer {
|
let wasm = Buffer {
|
||||||
data: wasm_path.as_ptr(),
|
data: wasm_path.as_ptr(),
|
||||||
len: wasm_path.len(),
|
len: wasm_path.len(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let prover_ptr = unsafe { init(&r1cs, &wasm, std::ptr::null()) };
|
let prover_ptr = unsafe { init_storage_proofs(r1cs, wasm, std::ptr::null()) };
|
||||||
let prove_ctx = unsafe {
|
let prove_ctx: *mut crate::ffi::ProofCtx = unsafe {
|
||||||
prove(
|
prove(
|
||||||
prover_ptr,
|
prover_ptr,
|
||||||
&chunks_buff as *const Buffer,
|
&chunks_buff as *const Buffer,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
|
||||||
use ark_bn254::{Bn254, Fr};
|
use ark_bn254::{Bn254, Fr};
|
||||||
use ark_circom::{read_zkey, CircomBuilder, CircomConfig};
|
use ark_circom::{read_zkey, CircomBuilder, CircomConfig, CircomCircuit};
|
||||||
use ark_groth16::{
|
use ark_groth16::{
|
||||||
create_random_proof as prove, generate_random_parameters, prepare_verifying_key, verify_proof,
|
create_random_proof as prove, generate_random_parameters, prepare_verifying_key, verify_proof,
|
||||||
Proof, ProvingKey,
|
Proof, ProvingKey,
|
||||||
|
@ -10,6 +10,15 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read};
|
||||||
use ark_std::rand::rngs::ThreadRng;
|
use ark_std::rand::rngs::ThreadRng;
|
||||||
use ruint::aliases::U256;
|
use ruint::aliases::U256;
|
||||||
|
|
||||||
|
use rmpv;
|
||||||
|
use rmpv::decode::read_value;
|
||||||
|
|
||||||
|
type Params256Ty = ark_ec::bn::Bn<ark_bn254::Parameters>;
|
||||||
|
|
||||||
|
pub const EXT_ID_U256_LE: i8 = 50;
|
||||||
|
pub const EXT_ID_U256_BE: i8 = 51;
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct StorageProofs {
|
pub struct StorageProofs {
|
||||||
builder: CircomBuilder<Bn254>,
|
builder: CircomBuilder<Bn254>,
|
||||||
|
@ -41,6 +50,36 @@ impl StorageProofs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn prove_mpack(
|
||||||
|
&mut self,
|
||||||
|
inputs: &[u8],
|
||||||
|
proof_bytes: &mut Vec<u8>,
|
||||||
|
public_inputs_bytes: &mut Vec<u8>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let mut builder: CircomBuilder<Params256Ty> = self.builder.clone();
|
||||||
|
|
||||||
|
parse_mpack_args(&mut builder, inputs)?;
|
||||||
|
|
||||||
|
let circuit: CircomCircuit<Params256Ty> = builder.build()
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
let inputs = circuit
|
||||||
|
.get_public_inputs()
|
||||||
|
.ok_or("Unable to get public inputs!")?;
|
||||||
|
let proof =
|
||||||
|
prove(circuit, &self.params, &mut self.rng)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
proof
|
||||||
|
.serialize(proof_bytes)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
inputs
|
||||||
|
.serialize(public_inputs_bytes)
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn prove(
|
pub fn prove(
|
||||||
&mut self,
|
&mut self,
|
||||||
chunks: &[U256],
|
chunks: &[U256],
|
||||||
|
@ -96,3 +135,95 @@ impl StorageProofs {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decode_number(val: &rmpv::Value) -> Result<U256, String> {
|
||||||
|
match val {
|
||||||
|
rmpv::Value::Ext(id, val) => {
|
||||||
|
match *id {
|
||||||
|
EXT_ID_U256_LE =>
|
||||||
|
match U256::try_from_le_slice(val) {
|
||||||
|
Some(i) => Ok(i),
|
||||||
|
None => Err("error parsing 256".to_string()),
|
||||||
|
}
|
||||||
|
num => return Err(format!("unhandled ext id {}", num)),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rmpv::Value::Integer(val) => {
|
||||||
|
if let Some(val) = val.as_u64() {
|
||||||
|
return Ok(U256::from(val));
|
||||||
|
} else if let Some(val) = val.as_i64() {
|
||||||
|
return Ok(U256::from(val));
|
||||||
|
} else {
|
||||||
|
return Err("unexpected integer kind".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => return Err("expected ext mpack kind or integer".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_mpack_arrays(
|
||||||
|
builder: &mut CircomBuilder<Params256Ty>,
|
||||||
|
name: &str,
|
||||||
|
array: &Vec<rmpv::Value>
|
||||||
|
) -> Result<(), String> {
|
||||||
|
|
||||||
|
println!("deserde: array: {} size: {}", name, array.len());
|
||||||
|
if array.len() > 0 && array[0].is_array() {
|
||||||
|
println!("deserde: arrayOfArrays: {}", name);
|
||||||
|
for element in array {
|
||||||
|
match element .as_array() {
|
||||||
|
Some(element ) => {
|
||||||
|
parse_mpack_arrays(builder, name, element)?;
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
print!("error expected array: {}", name);
|
||||||
|
return Err("expected inner array of u256".to_string())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("deserde: name: {}", name);
|
||||||
|
for val in array {
|
||||||
|
let n = decode_number(val)?;
|
||||||
|
println!("\t{}", n);
|
||||||
|
builder.push_input(name, n);
|
||||||
|
}
|
||||||
|
println!("done: name: {}", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_mpack_args(
|
||||||
|
builder: &mut CircomBuilder<Params256Ty>,
|
||||||
|
mut inputs: &[u8]
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let values: rmpv::Value = read_value(&mut inputs).map_err(|e| e.to_string())?;
|
||||||
|
let args: &Vec<(rmpv::Value, rmpv::Value)> = match values.as_map() {
|
||||||
|
Some(args) => args,
|
||||||
|
None => return Err("args must be a map of string to arrays".to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (key, val) in args {
|
||||||
|
let name = match key.as_str() {
|
||||||
|
Some(n) => n,
|
||||||
|
None => return Err(format!("expected string value")),
|
||||||
|
};
|
||||||
|
match val {
|
||||||
|
// add a (name, Vec<u256>) or (name, Vev<Vec<u256>>) arrays
|
||||||
|
rmpv::Value::Array(vals) => {
|
||||||
|
parse_mpack_arrays(builder, name, vals)?;
|
||||||
|
},
|
||||||
|
// directly add a (name,u256) arg pair
|
||||||
|
rmpv::Value::Ext(_, _) => {
|
||||||
|
let n = decode_number(val)?;
|
||||||
|
println!("deserde: name: {} u256: {}", name, n);
|
||||||
|
builder.push_input(name, n);
|
||||||
|
},
|
||||||
|
_ => return Err("unhandled argument kind".to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("parse_mpack_args DONE!");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
--path:"../"
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
import std/os
|
||||||
|
import unittest2
|
||||||
|
import codex_storage_proofs
|
||||||
|
|
||||||
|
suite "storage proofs ffi":
|
||||||
|
test "basic ffi circuit":
|
||||||
|
var
|
||||||
|
r1csPath = "src/circuit_tests/artifacts/storer-test.r1cs".absolutePath()
|
||||||
|
wasmPath = "src/circuit_tests/artifacts/storer-test_js/storer-test.wasm".absolutePath()
|
||||||
|
|
||||||
|
if not r1csPath.fileExists():
|
||||||
|
raise newException(ValueError, "missing expected r1cs file: " & r1csPath)
|
||||||
|
if not wasmPath.fileExists():
|
||||||
|
raise newException(ValueError, "missing expected wasm file: " & wasmPath)
|
||||||
|
|
||||||
|
let
|
||||||
|
r1cs_buff = unsafeBufferPath(r1csPath)
|
||||||
|
wasm_buff = unsafeBufferPath(wasmPath)
|
||||||
|
|
||||||
|
let storage_ctx = init_storage_proofs(r1cs_buff, wasm_buff, nil)
|
||||||
|
|
||||||
|
echo "storage_ctx: ", storage_ctx.repr
|
||||||
|
check storage_ctx != nil
|
||||||
|
|
||||||
|
var
|
||||||
|
mpack_arg_path = "tests/proof_test.mpack"
|
||||||
|
proofBuff = unsafeBufferFromFile(mpack_arg_path)
|
||||||
|
echo "proofArgs:size: ", proofBuff.len()
|
||||||
|
let res = prove_mpack_ext(storage_ctx, addr proofBuff)
|
||||||
|
|
||||||
|
echo "result: ", res.repr
|
||||||
|
check res != nil
|
Loading…
Reference in New Issue