mirror of
https://github.com/logos-blockchain/logos-blockchain-circuits.git
synced 2026-05-18 23:39:47 +00:00
Add pre-commit hooks and workspace lint config for formatting, linting, and dependency auditing.
This commit is contained in:
parent
8bee8c3137
commit
df0bcc16e7
32
.cargo-deny.toml
Normal file
32
.cargo-deny.toml
Normal file
@ -0,0 +1,32 @@
|
||||
# Config file reference can be found at https://embarkstudios.github.io/cargo-deny/checks/cfg.html.
|
||||
|
||||
[graph]
|
||||
all-features = true
|
||||
exclude-dev = true
|
||||
no-default-features = true
|
||||
|
||||
[advisories]
|
||||
ignore = []
|
||||
unused-ignored-advisory = "deny"
|
||||
yanked = "deny"
|
||||
|
||||
[bans]
|
||||
allow-wildcard-paths = false
|
||||
multiple-versions = "allow"
|
||||
|
||||
[licenses]
|
||||
allow = [
|
||||
"Apache-2.0 WITH LLVM-exception",
|
||||
"Apache-2.0",
|
||||
"BSD-3-Clause",
|
||||
"CDLA-Permissive-2.0",
|
||||
"ISC",
|
||||
"MIT",
|
||||
"Zlib",
|
||||
]
|
||||
private = { ignore = false }
|
||||
unused-allowed-license = "deny"
|
||||
|
||||
[sources]
|
||||
unknown-git = "deny"
|
||||
unknown-registry = "deny"
|
||||
46
.pre-commit-config.yaml
Normal file
46
.pre-commit-config.yaml
Normal file
@ -0,0 +1,46 @@
|
||||
repos:
|
||||
- repo: https://github.com/doublify/pre-commit-rust
|
||||
rev: eeee35a89e69d5772bdee97db1a6a898467b686e # 1.0
|
||||
hooks:
|
||||
- id: fmt
|
||||
entry: cargo +nightly-2026-02-28 fmt --manifest-path rust/Cargo.toml --all
|
||||
pass_filenames: false
|
||||
- id: clippy
|
||||
name: cargo clippy
|
||||
entry: cargo clippy --manifest-path rust/Cargo.toml
|
||||
args:
|
||||
["--all", "--all-targets", "--all-features", "--", "-D", "warnings"]
|
||||
pass_filenames: false
|
||||
- repo: https://github.com/EmbarkStudios/cargo-deny
|
||||
rev: 09faadcea2d0d1742492e6872b743d1e4d151a27 # 0.19.0
|
||||
hooks:
|
||||
- id: cargo-deny
|
||||
args:
|
||||
- --manifest-path
|
||||
- rust/Cargo.toml
|
||||
- --locked
|
||||
- --all-features
|
||||
- check
|
||||
- --hide-inclusion-graph
|
||||
- -c
|
||||
- .cargo-deny.toml
|
||||
- --show-stats
|
||||
- -D
|
||||
- warnings
|
||||
- repo: https://github.com/ComPWA/taplo-pre-commit
|
||||
rev: 6355f0e9a28a910b80c91f7f6521c03d0ea50fba # 0.9.3 # Can't update until: https://github.com/tamasfe/taplo/issues/805
|
||||
hooks:
|
||||
- id: taplo-format
|
||||
- id: taplo-lint
|
||||
- repo: https://github.com/bnjbvr/cargo-machete
|
||||
rev: 78beac95c8fd7c25bdfb194415128523e41512d5 # 0.19.1
|
||||
hooks:
|
||||
- id: cargo-machete
|
||||
args: ["rust/"]
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: cargo-hack-check
|
||||
language: script
|
||||
name: cargo hack check
|
||||
entry: ./hooks/cargo-hack.sh
|
||||
stages: [manual]
|
||||
3
hooks/cargo-hack.sh
Executable file
3
hooks/cargo-hack.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
RUSTFLAGS="-D warnings" cargo hack --feature-powerset --no-dev-deps --keep-going --all-targets check
|
||||
6
justfile
6
justfile
@ -1,3 +1,4 @@
|
||||
cargo_root := justfile_directory() + "/rust"
|
||||
src := justfile_directory() + "/src"
|
||||
ci_makefile := justfile_directory() + "/.github/resources/witness-generator/Makefile"
|
||||
circom_version := "2.2.2" # This version must match the version used in the CI
|
||||
@ -5,6 +6,11 @@ circom_version := "2.2.2" # This version must match the version used in the CI
|
||||
os := `uname -s`
|
||||
sed_i := if os == "Darwin" { "sed -i ''" } else { "sed -i" }
|
||||
|
||||
# Shortcut to run cargo commands from the repo root (the Cargo workspace lives under ./rust/).
|
||||
# Potentially temporary.
|
||||
cargo +args:
|
||||
cd {{cargo_root}} && cargo {{args}}
|
||||
|
||||
# Verify the installed circom matches the pinned version.
|
||||
check-circom:
|
||||
@circom --version | grep -qF "{{circom_version}}" || \
|
||||
|
||||
188
rust/Cargo.toml
188
rust/Cargo.toml
@ -1,32 +1,184 @@
|
||||
[workspace.package]
|
||||
categories = ["cryptography", "external-ffi-bindings"]
|
||||
categories = ["cryptography", "external-ffi-bindings"]
|
||||
description = "Rust bindings for the Logos Blockchain Circuits, providing a safe and efficient interface for interacting with the underlying cryptographic circuits."
|
||||
edition = "2024"
|
||||
keywords = ["blockchain", "privacy"]
|
||||
license = "MIT or Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/logos-blockchain/logos-blockchain-circuits"
|
||||
version = "0.4.2"
|
||||
edition = "2024"
|
||||
keywords = ["blockchain", "privacy"]
|
||||
license = "MIT or Apache-2.0"
|
||||
readme = "README.md"
|
||||
repository = "https://github.com/logos-blockchain/logos-blockchain-circuits"
|
||||
version = "0.4.2"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"logos-blockchain-circuits-poc-sys",
|
||||
"logos-blockchain-circuits-pol-sys",
|
||||
"logos-blockchain-circuits-poq-sys",
|
||||
"logos-blockchain-circuits-signature-sys",
|
||||
"logos-blockchain-circuits-types",
|
||||
"logos-blockchain-circuits-common"
|
||||
"logos-blockchain-circuits-poc-sys",
|
||||
"logos-blockchain-circuits-pol-sys",
|
||||
"logos-blockchain-circuits-poq-sys",
|
||||
"logos-blockchain-circuits-signature-sys",
|
||||
"logos-blockchain-circuits-types",
|
||||
"logos-blockchain-circuits-common",
|
||||
]
|
||||
resolver = "3"
|
||||
|
||||
# Sourced from https://github.com/logos-co/nomos/blob/main/Cargo.toml
|
||||
[workspace.lints.clippy]
|
||||
|
||||
# Cargo and allowed cargo warnings (new lints will warn by default)
|
||||
cargo = { level = "warn", priority = -1 }
|
||||
|
||||
# TODO: We should tackle this lint at some point, to reduce dependencies duplication, reduce compilation times and bring down our binary size.
|
||||
multiple_crate_versions = { level = "allow" }
|
||||
|
||||
# Nursery and allowed nursery warnings (new lints will warn by default)
|
||||
nursery = { level = "warn", priority = -1 }
|
||||
|
||||
# Pedantic and allowed pedantic warnings (new lints will warn by default)
|
||||
pedantic = { level = "warn", priority = -1 }
|
||||
|
||||
similar_names = { level = "allow" }
|
||||
|
||||
# Restriction and allowed restriction warnings (new lints will warn by default)
|
||||
restriction = { level = "warn", priority = -1 }
|
||||
|
||||
absolute_paths = { level = "allow" }
|
||||
alloc_instead_of_core = { level = "allow" }
|
||||
arbitrary_source_item_ordering = { level = "allow" }
|
||||
big_endian_bytes = { level = "allow" }
|
||||
blanket_clippy_restriction_lints = { level = "allow" }
|
||||
decimal_literal_representation = { level = "allow" }
|
||||
default_numeric_fallback = { level = "allow" }
|
||||
deref_by_slicing = { level = "allow" }
|
||||
else_if_without_else = { level = "allow" }
|
||||
exhaustive_enums = { level = "allow" }
|
||||
exhaustive_structs = { level = "allow" }
|
||||
exit = { level = "allow" }
|
||||
expect_used = { level = "allow" }
|
||||
field_scoped_visibility_modifiers = { level = "allow" }
|
||||
float_arithmetic = { level = "allow" }
|
||||
get_unwrap = { level = "allow" }
|
||||
host_endian_bytes = { level = "allow" }
|
||||
implicit_return = { level = "allow" }
|
||||
integer_division_remainder_used = { level = "allow" }
|
||||
iter_over_hash_type = { level = "allow" }
|
||||
let_underscore_must_use = { level = "allow" }
|
||||
let_underscore_untyped = { level = "allow" }
|
||||
little_endian_bytes = { level = "allow" }
|
||||
map_err_ignore = { level = "allow" }
|
||||
min_ident_chars = { level = "allow" }
|
||||
missing_asserts_for_indexing = { level = "allow" }
|
||||
missing_docs_in_private_items = { level = "allow" }
|
||||
missing_inline_in_public_items = { level = "allow" }
|
||||
missing_trait_methods = { level = "allow" }
|
||||
mixed_read_write_in_expression = { level = "allow" }
|
||||
mod_module_files = { level = "allow" }
|
||||
module_name_repetitions = { level = "allow" }
|
||||
modulo_arithmetic = { level = "allow" }
|
||||
panic = { level = "allow" }
|
||||
panic_in_result_fn = { level = "allow" }
|
||||
partial_pub_fields = { level = "allow" }
|
||||
print_stderr = { level = "allow" }
|
||||
print_stdout = { level = "allow" }
|
||||
pub_use = { level = "allow" }
|
||||
pub_with_shorthand = { level = "allow" }
|
||||
question_mark_used = { level = "allow" }
|
||||
self_named_module_files = { level = "allow" }
|
||||
semicolon_inside_block = { level = "allow" }
|
||||
single_call_fn = { level = "allow" }
|
||||
single_char_lifetime_names = { level = "allow" }
|
||||
std_instead_of_alloc = { level = "allow" }
|
||||
std_instead_of_core = { level = "allow" }
|
||||
struct_field_names = { level = "allow" }
|
||||
unseparated_literal_suffix = { level = "allow" }
|
||||
use_debug = { level = "allow" }
|
||||
wildcard_enum_match_arm = { level = "allow" }
|
||||
|
||||
# TODO: Address these lints at some point. To allow them, move them to the section where they belong (e.g., pedantic), and keep allowing them. To enforce them, since all lints are "warn" by default, just remove them from this list.
|
||||
arithmetic_side_effects = { level = "allow" }
|
||||
as_conversions = { level = "allow" }
|
||||
as_pointer_underscore = { level = "allow" }
|
||||
as_underscore = { level = "allow" }
|
||||
assertions_on_result_states = { level = "allow" }
|
||||
cast_possible_truncation = { level = "allow" }
|
||||
cast_possible_wrap = { level = "allow" }
|
||||
cast_precision_loss = { level = "allow" }
|
||||
cast_sign_loss = { level = "allow" }
|
||||
doc_paragraphs_missing_punctuation = { level = "allow" }
|
||||
error_impl_error = { level = "allow" }
|
||||
impl_trait_in_params = { level = "allow" }
|
||||
indexing_slicing = { level = "allow" }
|
||||
infinite_loop = { level = "allow" }
|
||||
integer_division = { level = "allow" }
|
||||
large_stack_frames = { level = "allow" }
|
||||
missing_assert_message = { level = "allow" }
|
||||
missing_errors_doc = { level = "allow" }
|
||||
missing_panics_doc = { level = "allow" }
|
||||
pattern_type_mismatch = { level = "allow" }
|
||||
redundant_test_prefix = { level = "allow" }
|
||||
ref_patterns = { level = "allow" }
|
||||
renamed_function_params = { level = "allow" }
|
||||
same_name_method = { level = "allow" }
|
||||
shadow_reuse = { level = "allow" }
|
||||
shadow_same = { level = "allow" }
|
||||
shadow_unrelated = { level = "allow" }
|
||||
tests_outside_test_module = { level = "allow" }
|
||||
todo = { level = "allow" }
|
||||
unchecked_time_subtraction = { level = "allow" }
|
||||
unimplemented = { level = "allow" }
|
||||
unreachable = { level = "allow" }
|
||||
unwrap_in_result = { level = "allow" }
|
||||
unwrap_used = { level = "allow" }
|
||||
|
||||
[workspace.lints.rust]
|
||||
|
||||
# Explicitly allowed lints
|
||||
|
||||
unused_crate_dependencies = { level = "allow" } # Too many false positives especially around benchmarking and binaries, which do not have their own `dependencies` section yet. Plus, we have cargo-machete checking unused deps.
|
||||
unused_results = { level = "allow" } # We have Clippy lints to warn on unused `must_use` results. This is too pedantic as it complains on EVERY unused result.
|
||||
|
||||
# Lints which are allow-by-default but have been changed to "warn"
|
||||
ambiguous_negative_literals = { level = "warn" }
|
||||
closure_returning_async_block = { level = "warn" }
|
||||
deref_into_dyn_supertrait = { level = "warn" }
|
||||
impl_trait_redundant_captures = { level = "warn" }
|
||||
let_underscore_drop = { level = "warn" }
|
||||
macro_use_extern_crate = { level = "warn" }
|
||||
missing_unsafe_on_extern = { level = "warn" }
|
||||
redundant_imports = { level = "warn" }
|
||||
redundant_lifetimes = { level = "warn" }
|
||||
single_use_lifetimes = { level = "warn" }
|
||||
tail_expr_drop_order = { level = "warn" }
|
||||
trivial_numeric_casts = { level = "warn" }
|
||||
unit_bindings = { level = "warn" }
|
||||
unsafe_attr_outside_unsafe = { level = "warn" }
|
||||
unsafe_op_in_unsafe_fn = { level = "warn" }
|
||||
unstable_features = { level = "warn" }
|
||||
unused_extern_crates = { level = "warn" }
|
||||
unused_import_braces = { level = "warn" }
|
||||
unused_lifetimes = { level = "warn" }
|
||||
unused_macro_rules = { level = "warn" }
|
||||
unused_qualifications = { level = "warn" }
|
||||
|
||||
# TODO: Address these allow-by-default Rustc lints at some point. To allow them, move them to the list of explicitly allowed lints. To enforce them, move them to the list of explicitly warned ones.
|
||||
absolute_paths_not_starting_with_crate = { level = "allow" }
|
||||
elided_lifetimes_in_paths = { level = "allow" }
|
||||
ffi_unwind_calls = { level = "allow" }
|
||||
impl_trait_overcaptures = { level = "allow" }
|
||||
linker_messages = { level = "allow" }
|
||||
missing_copy_implementations = { level = "allow" }
|
||||
missing_debug_implementations = { level = "allow" }
|
||||
missing_docs = { level = "allow" }
|
||||
trivial_casts = { level = "allow" }
|
||||
unreachable_pub = { level = "allow" }
|
||||
unsafe_code = { level = "allow" }
|
||||
variant_size_differences = { level = "allow" }
|
||||
|
||||
[workspace.dependencies]
|
||||
# Internal
|
||||
lbc-poc-sys = { default-features = false, package = "logos-blockchain-circuits-poc-sys", path = "./logos-blockchain-circuits-poc-sys" }
|
||||
lbc-pol-sys = { default-features = false, package = "logos-blockchain-circuits-pol-sys", path = "./logos-blockchain-circuits-pol-sys" }
|
||||
lbc-poq-sys = { default-features = false, package = "logos-blockchain-circuits-poq-sys", path = "./logos-blockchain-circuits-poq-sys" }
|
||||
lbc-poc-sys = { default-features = false, package = "logos-blockchain-circuits-poc-sys", path = "./logos-blockchain-circuits-poc-sys" }
|
||||
lbc-pol-sys = { default-features = false, package = "logos-blockchain-circuits-pol-sys", path = "./logos-blockchain-circuits-pol-sys" }
|
||||
lbc-poq-sys = { default-features = false, package = "logos-blockchain-circuits-poq-sys", path = "./logos-blockchain-circuits-poq-sys" }
|
||||
lbc-signature-sys = { default-features = false, package = "logos-blockchain-circuits-signature-sys", path = "./logos-blockchain-circuits-signature-sys" }
|
||||
lbc-types = { default-features = false, package = "logos-blockchain-circuits-types", path = "./logos-blockchain-circuits-types" }
|
||||
lbc-common = { default-features = false, package = "logos-blockchain-circuits-common", path = "./logos-blockchain-circuits-common" }
|
||||
lbc-types = { default-features = false, package = "logos-blockchain-circuits-types", path = "./logos-blockchain-circuits-types" }
|
||||
lbc-common = { default-features = false, package = "logos-blockchain-circuits-common", path = "./logos-blockchain-circuits-common" }
|
||||
|
||||
# External
|
||||
flate2 = "^1"
|
||||
|
||||
@ -9,5 +9,8 @@ readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
lbc-types = { workspace = true}
|
||||
lbc-types = { workspace = true }
|
||||
|
||||
@ -1,16 +1,20 @@
|
||||
use std::path::Path;
|
||||
use lbc_types::native::Error;
|
||||
use std::path::Path;
|
||||
|
||||
pub fn as_null_terminated_string(
|
||||
string: &str,
|
||||
) -> Result<std::ffi::CString, Error> {
|
||||
std::ffi::CString::new(string)
|
||||
.map_err(|error| Error::InvalidInput(Some(format!("Could not convert string to CString: {error}"))))
|
||||
pub fn as_null_terminated_string(string: &str) -> Result<std::ffi::CString, Error> {
|
||||
std::ffi::CString::new(string).map_err(|error| {
|
||||
Error::InvalidInput(Some(format!(
|
||||
"Could not convert string to CString: {error}"
|
||||
)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn path_as_null_terminated_string(
|
||||
path: &Path,
|
||||
) -> Result<std::ffi::CString, Error> {
|
||||
let path = path.to_str().ok_or(Error::InvalidInput(Some(format!("Could not convert the path to a string: {}", path.display()))))?;
|
||||
pub fn path_as_null_terminated_string(path: &Path) -> Result<std::ffi::CString, Error> {
|
||||
let path = path.to_str().ok_or_else(|| {
|
||||
Error::InvalidInput(Some(format!(
|
||||
"Could not convert the path to a string: {}",
|
||||
path.display()
|
||||
)))
|
||||
})?;
|
||||
as_null_terminated_string(path)
|
||||
}
|
||||
|
||||
@ -9,6 +9,9 @@ readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
lbc-types = { workspace = true }
|
||||
lbc-common = { workspace = true }
|
||||
|
||||
@ -5,7 +5,6 @@ use ureq::http::Response;
|
||||
static CIRCUIT_NAME: &str = "poc";
|
||||
static LIB_VAR_NAME: &str = "LBC_POC_LIB_DIR";
|
||||
|
||||
|
||||
fn get_artifact_name(version: &str, os: &str, arch: &str) -> String {
|
||||
format!("logos-blockchain-circuits-v{version}-{os}-{arch}")
|
||||
}
|
||||
@ -29,17 +28,27 @@ fn fetch_library(version: &str, os: &str, arch: &str) -> Response<Body> {
|
||||
})
|
||||
}
|
||||
|
||||
fn unpack_library(response: Response<Body>, version: &str, os: &str, arch: &str, output_dir: &Path) -> PathBuf {
|
||||
fn unpack_library(
|
||||
response: Response<Body>,
|
||||
version: &str,
|
||||
os: &str,
|
||||
arch: &str,
|
||||
output_dir: &Path,
|
||||
) -> PathBuf {
|
||||
let gz_decoder = flate2::read::GzDecoder::new(response.into_body().into_reader());
|
||||
let mut archive = tar::Archive::new(gz_decoder);
|
||||
archive.unpack(output_dir).expect("Failed to unpack the downloaded archive.");
|
||||
archive
|
||||
.unpack(output_dir)
|
||||
.expect("Failed to unpack the downloaded archive.");
|
||||
|
||||
let unpacked_artifact_path = output_dir.join(get_artifact_name(version, os, arch));
|
||||
let unpacked_library_directory = unpacked_artifact_path.join(CIRCUIT_NAME);
|
||||
|
||||
if !unpacked_library_directory.exists() {
|
||||
panic!("Failed to find the unpacked library at {}.", unpacked_library_directory.display());
|
||||
}
|
||||
assert!(
|
||||
unpacked_library_directory.is_dir(),
|
||||
"Failed to find the unpacked library at {}",
|
||||
unpacked_library_directory.display()
|
||||
);
|
||||
|
||||
unpacked_library_directory
|
||||
}
|
||||
@ -50,9 +59,14 @@ fn provision_library() -> PathBuf {
|
||||
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
||||
|
||||
let expected_library_directory = out_dir.join(get_artifact_name(version, &os, &arch)).join(CIRCUIT_NAME);
|
||||
let expected_library_directory = out_dir
|
||||
.join(get_artifact_name(version, &os, &arch))
|
||||
.join(CIRCUIT_NAME);
|
||||
if expected_library_directory.exists() {
|
||||
println!("Found an existing library at {}. Reusing it.", expected_library_directory.display());
|
||||
println!(
|
||||
"Found an existing library at {}. Reusing it.",
|
||||
expected_library_directory.display()
|
||||
);
|
||||
return expected_library_directory;
|
||||
}
|
||||
|
||||
@ -66,21 +80,23 @@ fn main() {
|
||||
println!("cargo:rerun-if-changed=Cargo.toml");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
let lib_dir = std::env::var(LIB_VAR_NAME).map(
|
||||
let lib_dir = std::env::var(LIB_VAR_NAME).map_or_else(
|
||||
|_| provision_library(),
|
||||
|lib_dir| {
|
||||
println!("Using a library directory from {LIB_VAR_NAME}: {lib_dir}");
|
||||
let lib_dir_path = PathBuf::from(lib_dir);
|
||||
if !lib_dir_path.exists() {
|
||||
panic!("The library directory specified in {LIB_VAR_NAME} at {} does not exist.", lib_dir_path.display());
|
||||
|
||||
}
|
||||
assert!(
|
||||
lib_dir_path.is_dir(),
|
||||
"The library directory specified in {LIB_VAR_NAME} at {} does not exist.",
|
||||
lib_dir_path.display()
|
||||
);
|
||||
lib_dir_path
|
||||
}
|
||||
).unwrap_or_else(|_| {
|
||||
provision_library()
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let lib_dir = lib_dir.to_str().expect("Failed to convert the library directory path to a string");
|
||||
let lib_dir = lib_dir
|
||||
.to_str()
|
||||
.expect("Failed to convert the library directory path to a string");
|
||||
println!("cargo:rustc-env={LIB_VAR_NAME}={lib_dir}");
|
||||
println!("cargo:rustc-link-search=native={lib_dir}");
|
||||
println!("cargo:rustc-link-lib=static={CIRCUIT_NAME}");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use std::ffi::c_char;
|
||||
use lbc_types::ffi::{Bytes, Status, WitnessInput};
|
||||
use std::ffi::c_char;
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn poc_generate_witness(input: *const WitnessInput, output: *mut Bytes) -> Status;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
mod ffi;
|
||||
pub mod native;
|
||||
|
||||
pub use native::{generate_witness, generate_witness_from_files, PocWitnessInput};
|
||||
pub use native::{PocWitnessInput, generate_witness, generate_witness_from_files};
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
use std::path::Path;
|
||||
use lbc_types::{ffi, native::{Bytes, Error}};
|
||||
use lbc_common::string::path_as_null_terminated_string;
|
||||
use crate::ffi::{poc_generate_witness, poc_generate_witness_from_files};
|
||||
use lbc_common::string::path_as_null_terminated_string;
|
||||
use lbc_types::{
|
||||
ffi,
|
||||
native::{Bytes, Error},
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
static RAW_CIRCUIT_DAT: &[u8] = include_bytes!(concat!(env!("LBC_POC_LIB_DIR"), "/witness_generator.dat"));
|
||||
static RAW_CIRCUIT_DAT: &[u8] =
|
||||
include_bytes!(concat!(env!("LBC_POC_LIB_DIR"), "/witness_generator.dat"));
|
||||
|
||||
pub struct PocDat;
|
||||
impl<'dat> lbc_types::CircuitDat<'dat> for PocDat {
|
||||
@ -12,74 +16,67 @@ impl<'dat> lbc_types::CircuitDat<'dat> for PocDat {
|
||||
|
||||
pub type PocWitnessInput<'dat> = lbc_types::CircuitWitnessInput<'dat, PocDat>;
|
||||
|
||||
pub fn generate_witness(
|
||||
input: PocWitnessInput,
|
||||
) -> Result<Bytes, Error> {
|
||||
pub fn generate_witness(input: &PocWitnessInput) -> Result<Bytes, Error> {
|
||||
let ffi_input_guard = input.as_ffi();
|
||||
let ffi_input = ffi_input_guard.as_ref();
|
||||
|
||||
let mut ffi_output_bytes = ffi::Bytes::null();
|
||||
|
||||
let status = unsafe {
|
||||
poc_generate_witness(
|
||||
ffi_input as *const ffi::WitnessInput,
|
||||
&mut ffi_output_bytes as *mut ffi::Bytes
|
||||
)
|
||||
};
|
||||
// SAFETY: ffi_input is a valid pointer and ffi_output_bytes is a locally initialized null Bytes.
|
||||
let status =
|
||||
unsafe { poc_generate_witness(std::ptr::from_ref(ffi_input), &raw mut ffi_output_bytes) };
|
||||
|
||||
status.try_into().map(|()| { Bytes::from(ffi_output_bytes) })
|
||||
status.try_into().map(|()| Bytes::from(ffi_output_bytes))
|
||||
}
|
||||
|
||||
pub fn generate_witness_from_files(
|
||||
dat: &Path,
|
||||
inputs: &Path,
|
||||
output: &Path,
|
||||
) -> Result<(), Error> {
|
||||
pub fn generate_witness_from_files(dat: &Path, inputs: &Path, output: &Path) -> Result<(), Error> {
|
||||
let c_dat = path_as_null_terminated_string(dat)?;
|
||||
let c_inputs = path_as_null_terminated_string(inputs)?;
|
||||
let c_output = path_as_null_terminated_string(output)?;
|
||||
|
||||
unsafe {
|
||||
poc_generate_witness_from_files(
|
||||
c_dat.as_ptr(),
|
||||
c_inputs.as_ptr(),
|
||||
c_output.as_ptr(),
|
||||
)
|
||||
}.try_into()
|
||||
// SAFETY: c_dat, c_inputs, and c_output are valid null-terminated C strings for the duration of the call.
|
||||
unsafe { poc_generate_witness_from_files(c_dat.as_ptr(), c_inputs.as_ptr(), c_output.as_ptr()) }
|
||||
.try_into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{PocWitnessInput, generate_witness, generate_witness_from_files};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::LazyLock;
|
||||
use super::{generate_witness, generate_witness_from_files, PocWitnessInput};
|
||||
|
||||
static LIB_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
const ENV_VAR: &str = "LBC_POC_LIB_DIR";
|
||||
PathBuf::from(
|
||||
std::env::var(ENV_VAR)
|
||||
.expect(format!("Environment variable '{ENV_VAR}' must be available, as provided by the build script.").as_str()),
|
||||
std::env::var(ENV_VAR).unwrap_or_else(
|
||||
|_| panic!("Environment variable '{ENV_VAR}' must be available, as provided by the build script."),
|
||||
)
|
||||
)
|
||||
});
|
||||
static INPUTS: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("sample.input.json")
|
||||
});
|
||||
static INPUTS: LazyLock<PathBuf> =
|
||||
LazyLock::new(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("sample.input.json"));
|
||||
|
||||
#[test]
|
||||
fn test_generate_witness() {
|
||||
let dat = LIB_DIR.join("witness_generator");
|
||||
let witness_output_path = std::env::temp_dir().join("poc_test_witness.wtns");
|
||||
|
||||
generate_witness_from_files(&dat, &*INPUTS, &witness_output_path)
|
||||
generate_witness_from_files(&dat, &INPUTS, &witness_output_path)
|
||||
.expect("generate_witness_from_files failed.");
|
||||
|
||||
let inputs_json = std::fs::read_to_string(&*INPUTS)
|
||||
.expect(format!("Failed to read {}.", INPUTS.display()).as_str());
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}.", INPUTS.display()));
|
||||
|
||||
let input = PocWitnessInput::new(inputs_json).expect("Failed to construct the input for the witness generator.");
|
||||
let output = generate_witness(input).expect("generate_witness failed.");
|
||||
let input = PocWitnessInput::new(inputs_json)
|
||||
.expect("Failed to construct the input for the witness generator.");
|
||||
let output = generate_witness(&input).expect("generate_witness failed.");
|
||||
|
||||
let expected = std::fs::read(&witness_output_path).expect(format!("Failed to read the generated witness from {}.", witness_output_path.display()).as_str());
|
||||
let expected = std::fs::read(&witness_output_path).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Failed to read the generated witness from {}.",
|
||||
witness_output_path.display()
|
||||
)
|
||||
});
|
||||
assert_eq!(output.as_slice(), expected.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,9 @@ readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
lbc-types = { workspace = true }
|
||||
lbc-common = { workspace = true }
|
||||
|
||||
@ -5,7 +5,6 @@ use ureq::http::Response;
|
||||
static CIRCUIT_NAME: &str = "pol";
|
||||
static LIB_VAR_NAME: &str = "LBC_POL_LIB_DIR";
|
||||
|
||||
|
||||
fn get_artifact_name(version: &str, os: &str, arch: &str) -> String {
|
||||
format!("logos-blockchain-circuits-v{version}-{os}-{arch}")
|
||||
}
|
||||
@ -29,17 +28,27 @@ fn fetch_library(version: &str, os: &str, arch: &str) -> Response<Body> {
|
||||
})
|
||||
}
|
||||
|
||||
fn unpack_library(response: Response<Body>, version: &str, os: &str, arch: &str, output_dir: &Path) -> PathBuf {
|
||||
fn unpack_library(
|
||||
response: Response<Body>,
|
||||
version: &str,
|
||||
os: &str,
|
||||
arch: &str,
|
||||
output_dir: &Path,
|
||||
) -> PathBuf {
|
||||
let gz_decoder = flate2::read::GzDecoder::new(response.into_body().into_reader());
|
||||
let mut archive = tar::Archive::new(gz_decoder);
|
||||
archive.unpack(output_dir).expect("Failed to unpack the downloaded archive.");
|
||||
archive
|
||||
.unpack(output_dir)
|
||||
.expect("Failed to unpack the downloaded archive.");
|
||||
|
||||
let unpacked_artifact_path = output_dir.join(get_artifact_name(version, os, arch));
|
||||
let unpacked_library_directory = unpacked_artifact_path.join(CIRCUIT_NAME);
|
||||
|
||||
if !unpacked_library_directory.exists() {
|
||||
panic!("Failed to find the unpacked library at {}.", unpacked_library_directory.display());
|
||||
}
|
||||
assert!(
|
||||
unpacked_library_directory.is_dir(),
|
||||
"Failed to find the unpacked library at {}",
|
||||
unpacked_library_directory.display()
|
||||
);
|
||||
|
||||
unpacked_library_directory
|
||||
}
|
||||
@ -50,9 +59,14 @@ fn provision_library() -> PathBuf {
|
||||
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
||||
|
||||
let expected_library_directory = out_dir.join(get_artifact_name(version, &os, &arch)).join(CIRCUIT_NAME);
|
||||
let expected_library_directory = out_dir
|
||||
.join(get_artifact_name(version, &os, &arch))
|
||||
.join(CIRCUIT_NAME);
|
||||
if expected_library_directory.exists() {
|
||||
println!("Found an existing library at {}. Reusing it.", expected_library_directory.display());
|
||||
println!(
|
||||
"Found an existing library at {}. Reusing it.",
|
||||
expected_library_directory.display()
|
||||
);
|
||||
return expected_library_directory;
|
||||
}
|
||||
|
||||
@ -66,21 +80,23 @@ fn main() {
|
||||
println!("cargo:rerun-if-changed=Cargo.toml");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
let lib_dir = std::env::var(LIB_VAR_NAME).map(
|
||||
let lib_dir = std::env::var(LIB_VAR_NAME).map_or_else(
|
||||
|_| provision_library(),
|
||||
|lib_dir| {
|
||||
println!("Using a library directory from {LIB_VAR_NAME}: {lib_dir}");
|
||||
let lib_dir_path = PathBuf::from(lib_dir);
|
||||
if !lib_dir_path.exists() {
|
||||
panic!("The library directory specified in {LIB_VAR_NAME} at {} does not exist.", lib_dir_path.display());
|
||||
|
||||
}
|
||||
assert!(
|
||||
lib_dir_path.is_dir(),
|
||||
"The library directory specified in {LIB_VAR_NAME} at {} does not exist.",
|
||||
lib_dir_path.display()
|
||||
);
|
||||
lib_dir_path
|
||||
}
|
||||
).unwrap_or_else(|_| {
|
||||
provision_library()
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let lib_dir = lib_dir.to_str().expect("Failed to convert the library directory path to a string");
|
||||
let lib_dir = lib_dir
|
||||
.to_str()
|
||||
.expect("Failed to convert the library directory path to a string");
|
||||
println!("cargo:rustc-env={LIB_VAR_NAME}={lib_dir}");
|
||||
println!("cargo:rustc-link-search=native={lib_dir}");
|
||||
println!("cargo:rustc-link-lib=static={CIRCUIT_NAME}");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use std::ffi::c_char;
|
||||
use lbc_types::ffi::{Bytes, Status, WitnessInput};
|
||||
use std::ffi::c_char;
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn pol_generate_witness(input: *const WitnessInput, output: *mut Bytes) -> Status;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
mod ffi;
|
||||
pub mod native;
|
||||
|
||||
pub use native::{generate_witness, generate_witness_from_files, PolWitnessInput};
|
||||
pub use native::{PolWitnessInput, generate_witness, generate_witness_from_files};
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
use std::path::Path;
|
||||
use lbc_types::{ffi, native::{Bytes, Error}};
|
||||
use lbc_common::string::path_as_null_terminated_string;
|
||||
use crate::ffi::{pol_generate_witness, pol_generate_witness_from_files};
|
||||
use lbc_common::string::path_as_null_terminated_string;
|
||||
use lbc_types::{
|
||||
ffi,
|
||||
native::{Bytes, Error},
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
static RAW_CIRCUIT_DAT: &[u8] = include_bytes!(concat!(env!("LBC_POL_LIB_DIR"), "/witness_generator.dat"));
|
||||
static RAW_CIRCUIT_DAT: &[u8] =
|
||||
include_bytes!(concat!(env!("LBC_POL_LIB_DIR"), "/witness_generator.dat"));
|
||||
|
||||
pub struct PolDat;
|
||||
impl<'dat> lbc_types::CircuitDat<'dat> for PolDat {
|
||||
@ -12,74 +16,67 @@ impl<'dat> lbc_types::CircuitDat<'dat> for PolDat {
|
||||
|
||||
pub type PolWitnessInput<'dat> = lbc_types::CircuitWitnessInput<'dat, PolDat>;
|
||||
|
||||
pub fn generate_witness(
|
||||
input: PolWitnessInput,
|
||||
) -> Result<Bytes, Error> {
|
||||
pub fn generate_witness(input: &PolWitnessInput) -> Result<Bytes, Error> {
|
||||
let ffi_input_guard = input.as_ffi();
|
||||
let ffi_input = ffi_input_guard.as_ref();
|
||||
|
||||
let mut ffi_output_bytes = ffi::Bytes::null();
|
||||
|
||||
let status = unsafe {
|
||||
pol_generate_witness(
|
||||
ffi_input as *const ffi::WitnessInput,
|
||||
&mut ffi_output_bytes as *mut ffi::Bytes
|
||||
)
|
||||
};
|
||||
// SAFETY: ffi_input is a valid pointer and ffi_output_bytes is a locally initialized null Bytes.
|
||||
let status =
|
||||
unsafe { pol_generate_witness(std::ptr::from_ref(ffi_input), &raw mut ffi_output_bytes) };
|
||||
|
||||
status.try_into().map(|()| { Bytes::from(ffi_output_bytes) })
|
||||
status.try_into().map(|()| Bytes::from(ffi_output_bytes))
|
||||
}
|
||||
|
||||
pub fn generate_witness_from_files(
|
||||
dat: &Path,
|
||||
inputs: &Path,
|
||||
output: &Path,
|
||||
) -> Result<(), Error> {
|
||||
pub fn generate_witness_from_files(dat: &Path, inputs: &Path, output: &Path) -> Result<(), Error> {
|
||||
let c_dat = path_as_null_terminated_string(dat)?;
|
||||
let c_inputs = path_as_null_terminated_string(inputs)?;
|
||||
let c_output = path_as_null_terminated_string(output)?;
|
||||
|
||||
unsafe {
|
||||
pol_generate_witness_from_files(
|
||||
c_dat.as_ptr(),
|
||||
c_inputs.as_ptr(),
|
||||
c_output.as_ptr(),
|
||||
)
|
||||
}.try_into()
|
||||
// SAFETY: c_dat, c_inputs, and c_output are valid null-terminated C strings for the duration of the call.
|
||||
unsafe { pol_generate_witness_from_files(c_dat.as_ptr(), c_inputs.as_ptr(), c_output.as_ptr()) }
|
||||
.try_into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{PolWitnessInput, generate_witness, generate_witness_from_files};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::LazyLock;
|
||||
use super::{generate_witness, generate_witness_from_files, PolWitnessInput};
|
||||
|
||||
static LIB_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
const ENV_VAR: &str = "LBC_POL_LIB_DIR";
|
||||
PathBuf::from(
|
||||
std::env::var(ENV_VAR)
|
||||
.expect(format!("Environment variable '{ENV_VAR}' must be available, as provided by the build script.").as_str()),
|
||||
std::env::var(ENV_VAR).unwrap_or_else(
|
||||
|_| panic!("Environment variable '{ENV_VAR}' must be available, as provided by the build script."),
|
||||
)
|
||||
)
|
||||
});
|
||||
static INPUTS: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("sample.input.json")
|
||||
});
|
||||
static INPUTS: LazyLock<PathBuf> =
|
||||
LazyLock::new(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("sample.input.json"));
|
||||
|
||||
#[test]
|
||||
fn test_generate_witness() {
|
||||
let dat = LIB_DIR.join("witness_generator");
|
||||
let witness_output_path = std::env::temp_dir().join("pol_test_witness.wtns");
|
||||
|
||||
generate_witness_from_files(&dat, &*INPUTS, &witness_output_path)
|
||||
generate_witness_from_files(&dat, &INPUTS, &witness_output_path)
|
||||
.expect("generate_witness_from_files failed.");
|
||||
|
||||
let inputs_json = std::fs::read_to_string(&*INPUTS)
|
||||
.expect(format!("Failed to read {}.", INPUTS.display()).as_str());
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}.", INPUTS.display()));
|
||||
|
||||
let input = PolWitnessInput::new(inputs_json).expect("Failed to construct the input for the witness generator.");
|
||||
let output = generate_witness(input).expect("generate_witness failed.");
|
||||
let input = PolWitnessInput::new(inputs_json)
|
||||
.expect("Failed to construct the input for the witness generator.");
|
||||
let output = generate_witness(&input).expect("generate_witness failed.");
|
||||
|
||||
let expected = std::fs::read(&witness_output_path).expect(format!("Failed to read the generated witness from {}.", witness_output_path.display()).as_str());
|
||||
let expected = std::fs::read(&witness_output_path).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Failed to read the generated witness from {}.",
|
||||
witness_output_path.display()
|
||||
)
|
||||
});
|
||||
assert_eq!(output.as_slice(), expected.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,9 @@ readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
lbc-types = { workspace = true }
|
||||
lbc-common = { workspace = true }
|
||||
|
||||
@ -5,7 +5,6 @@ use ureq::http::Response;
|
||||
static CIRCUIT_NAME: &str = "poq";
|
||||
static LIB_VAR_NAME: &str = "LBC_POQ_LIB_DIR";
|
||||
|
||||
|
||||
fn get_artifact_name(version: &str, os: &str, arch: &str) -> String {
|
||||
format!("logos-blockchain-circuits-v{version}-{os}-{arch}")
|
||||
}
|
||||
@ -29,17 +28,27 @@ fn fetch_library(version: &str, os: &str, arch: &str) -> Response<Body> {
|
||||
})
|
||||
}
|
||||
|
||||
fn unpack_library(response: Response<Body>, version: &str, os: &str, arch: &str, output_dir: &Path) -> PathBuf {
|
||||
fn unpack_library(
|
||||
response: Response<Body>,
|
||||
version: &str,
|
||||
os: &str,
|
||||
arch: &str,
|
||||
output_dir: &Path,
|
||||
) -> PathBuf {
|
||||
let gz_decoder = flate2::read::GzDecoder::new(response.into_body().into_reader());
|
||||
let mut archive = tar::Archive::new(gz_decoder);
|
||||
archive.unpack(output_dir).expect("Failed to unpack the downloaded archive.");
|
||||
archive
|
||||
.unpack(output_dir)
|
||||
.expect("Failed to unpack the downloaded archive.");
|
||||
|
||||
let unpacked_artifact_path = output_dir.join(get_artifact_name(version, os, arch));
|
||||
let unpacked_library_directory = unpacked_artifact_path.join(CIRCUIT_NAME);
|
||||
|
||||
if !unpacked_library_directory.exists() {
|
||||
panic!("Failed to find the unpacked library at {}.", unpacked_library_directory.display());
|
||||
}
|
||||
assert!(
|
||||
unpacked_library_directory.is_dir(),
|
||||
"Failed to find the unpacked library at {}",
|
||||
unpacked_library_directory.display()
|
||||
);
|
||||
|
||||
unpacked_library_directory
|
||||
}
|
||||
@ -50,9 +59,14 @@ fn provision_library() -> PathBuf {
|
||||
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
||||
|
||||
let expected_library_directory = out_dir.join(get_artifact_name(version, &os, &arch)).join(CIRCUIT_NAME);
|
||||
let expected_library_directory = out_dir
|
||||
.join(get_artifact_name(version, &os, &arch))
|
||||
.join(CIRCUIT_NAME);
|
||||
if expected_library_directory.exists() {
|
||||
println!("Found an existing library at {}. Reusing it.", expected_library_directory.display());
|
||||
println!(
|
||||
"Found an existing library at {}. Reusing it.",
|
||||
expected_library_directory.display()
|
||||
);
|
||||
return expected_library_directory;
|
||||
}
|
||||
|
||||
@ -77,21 +91,23 @@ fn main() {
|
||||
println!("cargo:rerun-if-changed=Cargo.toml");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
let lib_dir = std::env::var(LIB_VAR_NAME).map(
|
||||
let lib_dir = std::env::var(LIB_VAR_NAME).map_or_else(
|
||||
|_| provision_library(),
|
||||
|lib_dir| {
|
||||
println!("Using a library directory from {LIB_VAR_NAME}: {lib_dir}");
|
||||
let lib_dir_path = PathBuf::from(lib_dir);
|
||||
if !lib_dir_path.exists() {
|
||||
panic!("The library directory specified in {LIB_VAR_NAME} at {} does not exist.", lib_dir_path.display());
|
||||
|
||||
}
|
||||
assert!(
|
||||
lib_dir_path.is_dir(),
|
||||
"The library directory specified in {LIB_VAR_NAME} at {} does not exist.",
|
||||
lib_dir_path.display()
|
||||
);
|
||||
lib_dir_path
|
||||
}
|
||||
).unwrap_or_else(|_| {
|
||||
provision_library()
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let lib_dir = lib_dir.to_str().expect("Failed to convert the library directory path to a string");
|
||||
let lib_dir = lib_dir
|
||||
.to_str()
|
||||
.expect("Failed to convert the library directory path to a string");
|
||||
println!("cargo:rustc-env={LIB_VAR_NAME}={lib_dir}");
|
||||
println!("cargo:rustc-link-search=native={lib_dir}");
|
||||
println!("cargo:rustc-link-lib=static={CIRCUIT_NAME}");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use std::ffi::c_char;
|
||||
use lbc_types::ffi::{Bytes, Status, WitnessInput};
|
||||
use std::ffi::c_char;
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn poq_generate_witness(input: *const WitnessInput, output: *mut Bytes) -> Status;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
mod ffi;
|
||||
pub mod native;
|
||||
|
||||
pub use native::{generate_witness, generate_witness_from_files, PoqWitnessInput};
|
||||
pub use native::{PoqWitnessInput, generate_witness, generate_witness_from_files};
|
||||
|
||||
@ -1,9 +1,13 @@
|
||||
use std::path::Path;
|
||||
use lbc_types::{ffi, native::{Bytes, Error}};
|
||||
use lbc_common::string::path_as_null_terminated_string;
|
||||
use crate::ffi::{poq_generate_witness, poq_generate_witness_from_files};
|
||||
use lbc_common::string::path_as_null_terminated_string;
|
||||
use lbc_types::{
|
||||
ffi,
|
||||
native::{Bytes, Error},
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
static RAW_CIRCUIT_DAT: &[u8] = include_bytes!(concat!(env!("LBC_POQ_LIB_DIR"), "/witness_generator.dat"));
|
||||
static RAW_CIRCUIT_DAT: &[u8] =
|
||||
include_bytes!(concat!(env!("LBC_POQ_LIB_DIR"), "/witness_generator.dat"));
|
||||
|
||||
pub struct PoqDat;
|
||||
impl<'dat> lbc_types::CircuitDat<'dat> for PoqDat {
|
||||
@ -12,74 +16,67 @@ impl<'dat> lbc_types::CircuitDat<'dat> for PoqDat {
|
||||
|
||||
pub type PoqWitnessInput<'dat> = lbc_types::CircuitWitnessInput<'dat, PoqDat>;
|
||||
|
||||
pub fn generate_witness(
|
||||
input: PoqWitnessInput,
|
||||
) -> Result<Bytes, Error> {
|
||||
pub fn generate_witness(input: &PoqWitnessInput) -> Result<Bytes, Error> {
|
||||
let ffi_input_guard = input.as_ffi();
|
||||
let ffi_input = ffi_input_guard.as_ref();
|
||||
|
||||
let mut ffi_output_bytes = ffi::Bytes::null();
|
||||
|
||||
let status = unsafe {
|
||||
poq_generate_witness(
|
||||
ffi_input as *const ffi::WitnessInput,
|
||||
&mut ffi_output_bytes as *mut ffi::Bytes
|
||||
)
|
||||
};
|
||||
// SAFETY: ffi_input is a valid pointer and ffi_output_bytes is a locally initialized null Bytes.
|
||||
let status =
|
||||
unsafe { poq_generate_witness(std::ptr::from_ref(ffi_input), &raw mut ffi_output_bytes) };
|
||||
|
||||
status.try_into().map(|()| { Bytes::from(ffi_output_bytes) })
|
||||
status.try_into().map(|()| Bytes::from(ffi_output_bytes))
|
||||
}
|
||||
|
||||
pub fn generate_witness_from_files(
|
||||
dat: &Path,
|
||||
inputs: &Path,
|
||||
output: &Path,
|
||||
) -> Result<(), Error> {
|
||||
pub fn generate_witness_from_files(dat: &Path, inputs: &Path, output: &Path) -> Result<(), Error> {
|
||||
let c_dat = path_as_null_terminated_string(dat)?;
|
||||
let c_inputs = path_as_null_terminated_string(inputs)?;
|
||||
let c_output = path_as_null_terminated_string(output)?;
|
||||
|
||||
unsafe {
|
||||
poq_generate_witness_from_files (
|
||||
c_dat.as_ptr(),
|
||||
c_inputs.as_ptr(),
|
||||
c_output.as_ptr(),
|
||||
)
|
||||
}.try_into()
|
||||
// SAFETY: c_dat, c_inputs, and c_output are valid null-terminated C strings for the duration of the call.
|
||||
unsafe { poq_generate_witness_from_files(c_dat.as_ptr(), c_inputs.as_ptr(), c_output.as_ptr()) }
|
||||
.try_into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{PoqWitnessInput, generate_witness, generate_witness_from_files};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::LazyLock;
|
||||
use super::{generate_witness, generate_witness_from_files, PoqWitnessInput};
|
||||
|
||||
static LIB_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
const ENV_VAR: &str = "LBC_POQ_LIB_DIR";
|
||||
PathBuf::from(
|
||||
std::env::var(ENV_VAR)
|
||||
.expect(format!("Environment variable '{ENV_VAR}' must be available, as provided by the build script.").as_str()),
|
||||
std::env::var(ENV_VAR).unwrap_or_else(
|
||||
|_| panic!("Environment variable '{ENV_VAR}' must be available, as provided by the build script."),
|
||||
)
|
||||
)
|
||||
});
|
||||
static INPUTS: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("sample.input.json")
|
||||
});
|
||||
static INPUTS: LazyLock<PathBuf> =
|
||||
LazyLock::new(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("sample.input.json"));
|
||||
|
||||
#[test]
|
||||
fn test_generate_witness() {
|
||||
let dat = LIB_DIR.join("witness_generator");
|
||||
let witness_output_path = std::env::temp_dir().join("poq_test_witness.wtns");
|
||||
|
||||
generate_witness_from_files(&dat, &*INPUTS, &witness_output_path)
|
||||
generate_witness_from_files(&dat, &INPUTS, &witness_output_path)
|
||||
.expect("generate_witness_from_files failed.");
|
||||
|
||||
let inputs_json = std::fs::read_to_string(&*INPUTS)
|
||||
.expect(format!("Failed to read {}.", INPUTS.display()).as_str());
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}.", INPUTS.display()));
|
||||
|
||||
let input = PoqWitnessInput::new(inputs_json).expect("Failed to construct the input for the witness generator.");
|
||||
let output = generate_witness(input).expect("generate_witness failed.");
|
||||
let input = PoqWitnessInput::new(inputs_json)
|
||||
.expect("Failed to construct the input for the witness generator.");
|
||||
let output = generate_witness(&input).expect("generate_witness failed.");
|
||||
|
||||
let expected = std::fs::read(&witness_output_path).expect(format!("Failed to read the generated witness from {}.", witness_output_path.display()).as_str());
|
||||
let expected = std::fs::read(&witness_output_path).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Failed to read the generated witness from {}.",
|
||||
witness_output_path.display()
|
||||
)
|
||||
});
|
||||
assert_eq!(output.as_slice(), expected.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,6 +9,9 @@ readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
lbc-types = { workspace = true }
|
||||
lbc-common = { workspace = true }
|
||||
|
||||
@ -5,7 +5,6 @@ use ureq::http::Response;
|
||||
static CIRCUIT_NAME: &str = "signature";
|
||||
static LIB_VAR_NAME: &str = "LBC_SIGNATURE_LIB_DIR";
|
||||
|
||||
|
||||
fn get_artifact_name(version: &str, os: &str, arch: &str) -> String {
|
||||
format!("logos-blockchain-circuits-v{version}-{os}-{arch}")
|
||||
}
|
||||
@ -29,17 +28,27 @@ fn fetch_library(version: &str, os: &str, arch: &str) -> Response<Body> {
|
||||
})
|
||||
}
|
||||
|
||||
fn unpack_library(response: Response<Body>, version: &str, os: &str, arch: &str, output_dir: &Path) -> PathBuf {
|
||||
fn unpack_library(
|
||||
response: Response<Body>,
|
||||
version: &str,
|
||||
os: &str,
|
||||
arch: &str,
|
||||
output_dir: &Path,
|
||||
) -> PathBuf {
|
||||
let gz_decoder = flate2::read::GzDecoder::new(response.into_body().into_reader());
|
||||
let mut archive = tar::Archive::new(gz_decoder);
|
||||
archive.unpack(output_dir).expect("Failed to unpack the downloaded archive.");
|
||||
archive
|
||||
.unpack(output_dir)
|
||||
.expect("Failed to unpack the downloaded archive.");
|
||||
|
||||
let unpacked_artifact_path = output_dir.join(get_artifact_name(version, os, arch));
|
||||
let unpacked_library_directory = unpacked_artifact_path.join(CIRCUIT_NAME);
|
||||
|
||||
if !unpacked_library_directory.exists() {
|
||||
panic!("Failed to find the unpacked library at {}.", unpacked_library_directory.display());
|
||||
}
|
||||
assert!(
|
||||
unpacked_library_directory.is_dir(),
|
||||
"Failed to find the unpacked library at {}",
|
||||
unpacked_library_directory.display()
|
||||
);
|
||||
|
||||
unpacked_library_directory
|
||||
}
|
||||
@ -50,9 +59,14 @@ fn provision_library() -> PathBuf {
|
||||
let arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||
let out_dir = PathBuf::from(std::env::var("OUT_DIR").unwrap());
|
||||
|
||||
let expected_library_directory = out_dir.join(get_artifact_name(version, &os, &arch)).join(CIRCUIT_NAME);
|
||||
let expected_library_directory = out_dir
|
||||
.join(get_artifact_name(version, &os, &arch))
|
||||
.join(CIRCUIT_NAME);
|
||||
if expected_library_directory.exists() {
|
||||
println!("Found an existing library at {}. Reusing it.", expected_library_directory.display());
|
||||
println!(
|
||||
"Found an existing library at {}. Reusing it.",
|
||||
expected_library_directory.display()
|
||||
);
|
||||
return expected_library_directory;
|
||||
}
|
||||
|
||||
@ -66,21 +80,23 @@ fn main() {
|
||||
println!("cargo:rerun-if-changed=Cargo.toml");
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
|
||||
let lib_dir = std::env::var(LIB_VAR_NAME).map(
|
||||
let lib_dir = std::env::var(LIB_VAR_NAME).map_or_else(
|
||||
|_| provision_library(),
|
||||
|lib_dir| {
|
||||
println!("Using a library directory from {LIB_VAR_NAME}: {lib_dir}");
|
||||
let lib_dir_path = PathBuf::from(lib_dir);
|
||||
if !lib_dir_path.exists() {
|
||||
panic!("The library directory specified in {LIB_VAR_NAME} at {} does not exist.", lib_dir_path.display());
|
||||
|
||||
}
|
||||
assert!(
|
||||
lib_dir_path.is_dir(),
|
||||
"The library directory specified in {LIB_VAR_NAME} at {} does not exist.",
|
||||
lib_dir_path.display()
|
||||
);
|
||||
lib_dir_path
|
||||
}
|
||||
).unwrap_or_else(|_| {
|
||||
provision_library()
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
let lib_dir = lib_dir.to_str().expect("Failed to convert the library directory path to a string");
|
||||
let lib_dir = lib_dir
|
||||
.to_str()
|
||||
.expect("Failed to convert the library directory path to a string");
|
||||
println!("cargo:rustc-env={LIB_VAR_NAME}={lib_dir}");
|
||||
println!("cargo:rustc-link-search=native={lib_dir}");
|
||||
println!("cargo:rustc-link-lib=static={CIRCUIT_NAME}");
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use std::ffi::c_char;
|
||||
use lbc_types::ffi::{Bytes, Status, WitnessInput};
|
||||
use std::ffi::c_char;
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn signature_generate_witness(input: *const WitnessInput, output: *mut Bytes) -> Status;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
mod ffi;
|
||||
pub mod native;
|
||||
|
||||
pub use native::{generate_witness, generate_witness_from_files, SignatureWitnessInput};
|
||||
pub use native::{SignatureWitnessInput, generate_witness, generate_witness_from_files};
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
use std::path::Path;
|
||||
use lbc_types::{ffi, native::{Bytes, Error}};
|
||||
use lbc_common::string::path_as_null_terminated_string;
|
||||
use crate::ffi::{signature_generate_witness, signature_generate_witness_from_files};
|
||||
use lbc_common::string::path_as_null_terminated_string;
|
||||
use lbc_types::{
|
||||
ffi,
|
||||
native::{Bytes, Error},
|
||||
};
|
||||
use std::path::Path;
|
||||
|
||||
static RAW_CIRCUIT_DAT: &[u8] = include_bytes!(concat!(env!("LBC_SIGNATURE_LIB_DIR"), "/witness_generator.dat"));
|
||||
static RAW_CIRCUIT_DAT: &[u8] = include_bytes!(concat!(
|
||||
env!("LBC_SIGNATURE_LIB_DIR"),
|
||||
"/witness_generator.dat"
|
||||
));
|
||||
|
||||
pub struct SignatureDat;
|
||||
impl<'dat> lbc_types::CircuitDat<'dat> for SignatureDat {
|
||||
@ -12,74 +18,70 @@ impl<'dat> lbc_types::CircuitDat<'dat> for SignatureDat {
|
||||
|
||||
pub type SignatureWitnessInput<'dat> = lbc_types::CircuitWitnessInput<'dat, SignatureDat>;
|
||||
|
||||
pub fn generate_witness(
|
||||
input: SignatureWitnessInput,
|
||||
) -> Result<Bytes, Error> {
|
||||
pub fn generate_witness(input: &SignatureWitnessInput) -> Result<Bytes, Error> {
|
||||
let ffi_input_guard = input.as_ffi();
|
||||
let ffi_input = ffi_input_guard.as_ref();
|
||||
|
||||
let mut ffi_output_bytes = ffi::Bytes::null();
|
||||
|
||||
// SAFETY: ffi_input is a valid pointer and ffi_output_bytes is a locally initialized null Bytes.
|
||||
let status = unsafe {
|
||||
signature_generate_witness(
|
||||
ffi_input as *const ffi::WitnessInput,
|
||||
&mut ffi_output_bytes as *mut ffi::Bytes
|
||||
)
|
||||
signature_generate_witness(std::ptr::from_ref(ffi_input), &raw mut ffi_output_bytes)
|
||||
};
|
||||
|
||||
status.try_into().map(|()| { Bytes::from(ffi_output_bytes) })
|
||||
status.try_into().map(|()| Bytes::from(ffi_output_bytes))
|
||||
}
|
||||
|
||||
pub fn generate_witness_from_files(
|
||||
dat: &Path,
|
||||
inputs: &Path,
|
||||
output: &Path,
|
||||
) -> Result<(), Error> {
|
||||
pub fn generate_witness_from_files(dat: &Path, inputs: &Path, output: &Path) -> Result<(), Error> {
|
||||
let c_dat = path_as_null_terminated_string(dat)?;
|
||||
let c_inputs = path_as_null_terminated_string(inputs)?;
|
||||
let c_output = path_as_null_terminated_string(output)?;
|
||||
|
||||
// SAFETY: c_dat, c_inputs, and c_output are valid null-terminated C strings for the duration of the call.
|
||||
unsafe {
|
||||
signature_generate_witness_from_files(
|
||||
c_dat.as_ptr(),
|
||||
c_inputs.as_ptr(),
|
||||
c_output.as_ptr(),
|
||||
)
|
||||
}.try_into()
|
||||
signature_generate_witness_from_files(c_dat.as_ptr(), c_inputs.as_ptr(), c_output.as_ptr())
|
||||
}
|
||||
.try_into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{SignatureWitnessInput, generate_witness, generate_witness_from_files};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::LazyLock;
|
||||
use super::{generate_witness, generate_witness_from_files, SignatureWitnessInput};
|
||||
|
||||
static LIB_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
const ENV_VAR: &str = "LBC_SIGNATURE_LIB_DIR";
|
||||
PathBuf::from(
|
||||
std::env::var(ENV_VAR)
|
||||
.expect(format!("Environment variable '{ENV_VAR}' must be available, as provided by the build script.").as_str()),
|
||||
std::env::var(ENV_VAR).unwrap_or_else(
|
||||
|_| panic!("Environment variable '{ENV_VAR}' must be available, as provided by the build script."),
|
||||
)
|
||||
)
|
||||
});
|
||||
static INPUTS: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("sample.input.json")
|
||||
});
|
||||
static INPUTS: LazyLock<PathBuf> =
|
||||
LazyLock::new(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("sample.input.json"));
|
||||
|
||||
#[test]
|
||||
fn test_generate_witness() {
|
||||
let dat = LIB_DIR.join("witness_generator");
|
||||
let witness_output_path = std::env::temp_dir().join("signature_test_witness.wtns");
|
||||
|
||||
generate_witness_from_files(&dat, &*INPUTS, &witness_output_path)
|
||||
generate_witness_from_files(&dat, &INPUTS, &witness_output_path)
|
||||
.expect("generate_witness_from_files failed.");
|
||||
|
||||
let inputs_json = std::fs::read_to_string(&*INPUTS)
|
||||
.expect(format!("Failed to read {}.", INPUTS.display()).as_str());
|
||||
.unwrap_or_else(|_| panic!("Failed to read {}.", INPUTS.display()));
|
||||
|
||||
let input = SignatureWitnessInput::new(inputs_json).expect("Failed to construct the input for the witness generator.");
|
||||
let output = generate_witness(input).expect("generate_witness failed.");
|
||||
let input = SignatureWitnessInput::new(inputs_json)
|
||||
.expect("Failed to construct the input for the witness generator.");
|
||||
let output = generate_witness(&input).expect("generate_witness failed.");
|
||||
|
||||
let expected = std::fs::read(&witness_output_path).expect(format!("Failed to read the generated witness from {}.", witness_output_path.display()).as_str());
|
||||
let expected = std::fs::read(&witness_output_path).unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Failed to read the generated witness from {}.",
|
||||
witness_output_path.display()
|
||||
)
|
||||
});
|
||||
assert_eq!(output.as_slice(), expected.as_slice());
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,5 +9,8 @@ readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
libc = { workspace = true }
|
||||
|
||||
@ -9,7 +9,7 @@ mod inner {
|
||||
}
|
||||
|
||||
impl<T> inner::Buffer<*const T> {
|
||||
pub fn null() -> Self {
|
||||
pub const fn null() -> Self {
|
||||
Self {
|
||||
data: std::ptr::null(),
|
||||
size: 0,
|
||||
@ -18,7 +18,7 @@ impl<T> inner::Buffer<*const T> {
|
||||
}
|
||||
|
||||
impl<T> inner::Buffer<*mut T> {
|
||||
pub fn null() -> Self {
|
||||
pub const fn null() -> Self {
|
||||
Self {
|
||||
data: std::ptr::null_mut(),
|
||||
size: 0,
|
||||
@ -53,9 +53,11 @@ pub unsafe fn free_bytes(bytes: *mut Bytes) {
|
||||
return;
|
||||
}
|
||||
|
||||
// SAFETY: `bytes` is non-null (checked above).
|
||||
let bytes = unsafe { &mut *bytes };
|
||||
if !bytes.data.is_null() {
|
||||
unsafe { free(bytes.data as *mut libc::c_void) };
|
||||
// SAFETY: `bytes.data` is non-null (checked above).
|
||||
unsafe { free(bytes.data.cast::<libc::c_void>()) };
|
||||
}
|
||||
bytes.data = std::ptr::null_mut();
|
||||
bytes.size = 0;
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
//! These types map directly to the C header structs and are used at the FFI boundary. Prefer the
|
||||
//! wrappers in [`crate::native`] for ordinary Rust code.
|
||||
|
||||
pub mod status;
|
||||
pub mod bytes;
|
||||
pub mod status;
|
||||
pub mod witness_input;
|
||||
|
||||
pub use status::Status;
|
||||
pub use bytes::{Bytes, ConstBytes, free_bytes};
|
||||
pub use status::Status;
|
||||
pub use witness_input::WitnessInput;
|
||||
|
||||
@ -10,13 +10,13 @@ impl Code {
|
||||
pub const DYN_ERROR: Self = Self(1);
|
||||
pub const INVALID_INPUT: Self = Self(2);
|
||||
pub const OUT_OF_MEMORY: Self = Self(3);
|
||||
}
|
||||
|
||||
impl Code {
|
||||
#[must_use]
|
||||
pub fn is_ok(&self) -> bool {
|
||||
self == &Self::OK
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_error(&self) -> bool {
|
||||
!self.is_ok()
|
||||
}
|
||||
@ -30,22 +30,26 @@ pub struct Status {
|
||||
}
|
||||
|
||||
impl Status {
|
||||
pub fn ok() -> Self {
|
||||
Status {
|
||||
#[must_use]
|
||||
pub const fn ok() -> Self {
|
||||
Self {
|
||||
code: Code::OK,
|
||||
message: [0; 256],
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_ok(&self) -> bool {
|
||||
self.code.is_ok()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn is_error(&self) -> bool {
|
||||
self.code.is_error()
|
||||
}
|
||||
|
||||
pub fn has_message(&self) -> bool {
|
||||
#[must_use]
|
||||
pub const fn has_message(&self) -> bool {
|
||||
self.message[0] != 0
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use std::ffi::c_char;
|
||||
use crate::ffi::ConstBytes;
|
||||
use std::ffi::c_char;
|
||||
|
||||
/// Input to a witness generator function.
|
||||
///
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
//! [`native`] module re-exposes those through idiomatic Rust types that own their memory and
|
||||
//! convert FFI return values into [`Result`]s.
|
||||
|
||||
pub mod native;
|
||||
pub mod ffi;
|
||||
pub mod native;
|
||||
|
||||
pub use native::{CircuitDat, CircuitWitnessInput};
|
||||
|
||||
@ -41,11 +41,12 @@ impl From<ffi::Bytes> for Bytes {
|
||||
let vec = if ffi_value.size == 0 || ffi_value.data.is_null() {
|
||||
Vec::new()
|
||||
} else {
|
||||
unsafe {
|
||||
std::slice::from_raw_parts(ffi_value.data, ffi_value.size).to_vec()
|
||||
}
|
||||
// SAFETY: `ffi_value.data` is non-null and `ffi_value.size > 0` (checked above),
|
||||
// pointing to a valid C-allocated buffer of at least `size` bytes.
|
||||
unsafe { std::slice::from_raw_parts(ffi_value.data, ffi_value.size).to_vec() }
|
||||
};
|
||||
unsafe { ffi::free_bytes(&mut ffi_value) };
|
||||
// SAFETY: `ffi_value` is a local variable, so the raw pointer is valid for this call.
|
||||
unsafe { ffi::free_bytes(&raw mut ffi_value) };
|
||||
Self(vec)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use crate::native::{Error, WitnessInput};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use crate::native::{WitnessInput, Error};
|
||||
|
||||
pub trait CircuitDat<'dat> {
|
||||
const DAT: &'dat [u8];
|
||||
@ -7,13 +8,16 @@ pub trait CircuitDat<'dat> {
|
||||
|
||||
pub struct CircuitWitnessInput<'dat, Dat> {
|
||||
inner: WitnessInput<'dat>,
|
||||
_phantom: std::marker::PhantomData<Dat>
|
||||
_phantom: PhantomData<Dat>,
|
||||
}
|
||||
|
||||
impl<'dat, Dat: CircuitDat<'dat>> CircuitWitnessInput<'dat, Dat> {
|
||||
pub fn new(inputs_json: String) -> Result<Self, Error> {
|
||||
let inner = WitnessInput::new(Dat::DAT, inputs_json)?;
|
||||
Ok(Self { inner, _phantom: Default::default() })
|
||||
Ok(Self {
|
||||
inner,
|
||||
_phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
//! Use them in preference to the types in [`crate::ffi`].
|
||||
|
||||
pub mod bytes;
|
||||
pub mod circuit_witness_input;
|
||||
pub mod status;
|
||||
pub mod witness_input;
|
||||
pub mod circuit_witness_input;
|
||||
|
||||
pub use bytes::Bytes;
|
||||
pub use status::{Result, Error};
|
||||
pub use witness_input::WitnessInput;
|
||||
pub use circuit_witness_input::{CircuitDat, CircuitWitnessInput};
|
||||
pub use status::{Error, Result};
|
||||
pub use witness_input::WitnessInput;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::ffi::status::Code as FfiStatusCode;
|
||||
use std::ffi::CStr;
|
||||
use std::fmt::Display;
|
||||
use crate::ffi::status::Code as FfiStatusCode;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
@ -17,9 +17,9 @@ impl std::error::Error for Error {}
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let (kind, message) = match self {
|
||||
Error::InvalidInput(msg) => ("Invalid input", msg),
|
||||
Error::OutOfMemory(msg) => ("Out of memory", msg),
|
||||
Error::Other(msg) => ("Other error", msg),
|
||||
Self::InvalidInput(msg) => ("Invalid input", msg),
|
||||
Self::OutOfMemory(msg) => ("Out of memory", msg),
|
||||
Self::Other(msg) => ("Other error", msg),
|
||||
};
|
||||
match message {
|
||||
Some(message) => write!(f, "{kind}: {message}"),
|
||||
@ -32,21 +32,21 @@ impl TryFrom<crate::ffi::Status> for () {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(status: crate::ffi::Status) -> Result<()> {
|
||||
let message: Option<String> = if status.has_message() {
|
||||
let status_message = unsafe {
|
||||
CStr::from_ptr(status.message.as_ptr())
|
||||
};
|
||||
Some(status_message.to_string_lossy().into_owned())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let message: Option<String> = status.has_message().then(|| {
|
||||
// SAFETY: `status.message` is non-empty (checked by `has_message()`) and null-terminated as guaranteed by the C API.
|
||||
let status_message = unsafe { CStr::from_ptr(status.message.as_ptr()) };
|
||||
status_message.to_string_lossy().into_owned()
|
||||
});
|
||||
|
||||
match status.code {
|
||||
FfiStatusCode::OK => Ok(()),
|
||||
FfiStatusCode::DYN_ERROR => Err(Error::Other(message)),
|
||||
FfiStatusCode::INVALID_INPUT => Err(Error::InvalidInput(message)),
|
||||
FfiStatusCode::OUT_OF_MEMORY => Err(Error::OutOfMemory(message)),
|
||||
other => Err(Error::Other(Some(format!("Unknown status code: {}", other.0))))
|
||||
other => Err(Error::Other(Some(format!(
|
||||
"Unknown status code: {}",
|
||||
other.0
|
||||
)))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::ffi::CString;
|
||||
use crate::ffi;
|
||||
use crate::native::Error;
|
||||
use std::ffi::CString;
|
||||
|
||||
/// Input for witness generators
|
||||
pub struct WitnessInput<'dat> {
|
||||
@ -12,15 +12,16 @@ pub struct WitnessInput<'dat> {
|
||||
|
||||
impl<'dat> WitnessInput<'dat> {
|
||||
pub fn new(dat: &'dat [u8], inputs_json: String) -> Result<Self, Error> {
|
||||
let inputs_json = CString::new(inputs_json).map_err(
|
||||
|error| Error::InvalidInput(Some(
|
||||
format!("The parameter inputs_json could not be converted to CString: {}", error)
|
||||
))
|
||||
)?;
|
||||
let inputs_json = CString::new(inputs_json).map_err(|error| {
|
||||
Error::InvalidInput(Some(format!(
|
||||
"The parameter inputs_json could not be converted to C string: {error}"
|
||||
)))
|
||||
})?;
|
||||
Ok(Self { dat, inputs_json })
|
||||
}
|
||||
|
||||
/// Borrows this value as a temporary FFI-compatible view.
|
||||
#[must_use]
|
||||
pub fn as_ffi(&'_ self) -> WitnessInputFfiGuard<'_> {
|
||||
WitnessInputFfiGuard::new(self)
|
||||
}
|
||||
@ -34,7 +35,10 @@ pub struct WitnessInputFfiGuard<'dat> {
|
||||
|
||||
impl<'dat> WitnessInputFfiGuard<'dat> {
|
||||
fn new(inner: &'dat WitnessInput) -> Self {
|
||||
let dat = ffi::ConstBytes { data: inner.dat.as_ptr(), size: inner.dat.len() };
|
||||
let dat = ffi::ConstBytes {
|
||||
data: inner.dat.as_ptr(),
|
||||
size: inner.dat.len(),
|
||||
};
|
||||
let inputs_json = inner.inputs_json.as_ptr();
|
||||
let ffi = ffi::WitnessInput { dat, inputs_json };
|
||||
Self {
|
||||
@ -44,7 +48,7 @@ impl<'dat> WitnessInputFfiGuard<'dat> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'dat> AsRef<ffi::WitnessInput> for WitnessInputFfiGuard<'dat> {
|
||||
impl AsRef<ffi::WitnessInput> for WitnessInputFfiGuard<'_> {
|
||||
fn as_ref(&self) -> &ffi::WitnessInput {
|
||||
&self.ffi
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user