From f91bd073d1b832a4b7f4530de13ec1c65159bb32 Mon Sep 17 00:00:00 2001 From: Alejandro Cabeza Romero Date: Mon, 27 Apr 2026 18:17:40 +0200 Subject: [PATCH] Various fixes and improvements. --- rust/Cargo.lock | 56 ----------------- rust/Cargo.toml | 1 - .../Cargo.toml | 2 +- .../build.rs | 15 ++++- .../src/native.rs | 32 ++++++---- .../Cargo.toml | 1 - .../src/ffi/bytes.rs | 20 +++++- .../src/ffi/status.rs | 19 +++--- .../src/native/bytes.rs | 12 ++-- .../src/native/status.rs | 62 +++++++++++-------- .../src/native/witness_input.rs | 11 +++- 11 files changed, 116 insertions(+), 115 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 22a65e3..823efcf 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -166,7 +166,6 @@ name = "logos-blockchain-circuits-types" version = "0.4.2" dependencies = [ "libc", - "thiserror", ] [[package]] @@ -197,24 +196,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -[[package]] -name = "proc-macro2" -version = "1.0.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" -dependencies = [ - "proc-macro2", -] - [[package]] name = "redox_syscall" version = "0.7.4" @@ -304,17 +285,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "syn" -version = "2.0.117" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "tar" version = "0.4.45" @@ -326,32 +296,6 @@ dependencies = [ "xattr", ] -[[package]] -name = "thiserror" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-ident" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" - [[package]] name = "untrusted" version = "0.9.0" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 11df230..a83eff5 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -24,5 +24,4 @@ lbc-types = { default-features = false, package = "logos-blockchain-circuits-typ flate2 = "1" libc = "0.2.185" tar = "0.4" -thiserror = "2.0.18" ureq = "3.3.0" diff --git a/rust/logos-blockchain-circuits-poq-sys/Cargo.toml b/rust/logos-blockchain-circuits-poq-sys/Cargo.toml index 7a54adc..cbac3bd 100644 --- a/rust/logos-blockchain-circuits-poq-sys/Cargo.toml +++ b/rust/logos-blockchain-circuits-poq-sys/Cargo.toml @@ -10,7 +10,7 @@ repository.workspace = true version.workspace = true [dependencies] -lbc-types = { workspace = true} +lbc-types = { workspace = true } [build-dependencies] flate2 = { workspace = true } diff --git a/rust/logos-blockchain-circuits-poq-sys/build.rs b/rust/logos-blockchain-circuits-poq-sys/build.rs index 93c742f..06f3eef 100644 --- a/rust/logos-blockchain-circuits-poq-sys/build.rs +++ b/rust/logos-blockchain-circuits-poq-sys/build.rs @@ -20,6 +20,7 @@ fn get_artifact_url(version: &str, os: &str, arch: &str) -> String { fn fetch_library(version: &str, os: &str, arch: &str) -> Response { let url = get_artifact_url(version, os, arch); + // TODO: Verify checksum. ureq::get(&url).call().unwrap_or_else(|error| { panic!( "Failed to download a prebuilt library for {os}-{arch} v{version}: {error}. \ @@ -35,7 +36,11 @@ fn unpack_library(response: Response, version: &str, os: &str, arch: &str, let unpacked_artifact_path = output_dir.join(get_artifact_name(version, os, arch)); let unpacked_library_directory = unpacked_artifact_path.join(CIRCUIT_NAME); - assert!(unpacked_library_directory.exists(), "Expected the unpacked library at {}.", unpacked_library_directory.display()); + + if !unpacked_library_directory.exists() { + panic!("Failed to find the unpacked library at {}.", unpacked_library_directory.display()); + } + unpacked_library_directory } @@ -57,12 +62,18 @@ fn provision_library() -> PathBuf { fn main() { println!("cargo:rerun-if-env-changed={LIB_VAR_NAME}"); + println!("cargo:rerun-if-env-changed=CARGO_PKG_VERSION"); + println!("cargo:rerun-if-changed=Cargo.toml"); + println!("cargo:rerun-if-changed=build.rs"); let lib_dir = std::env::var(LIB_VAR_NAME).map( |lib_dir| { println!("Using a library directory from {LIB_VAR_NAME}: {lib_dir}"); let lib_dir_path = PathBuf::from(lib_dir); - assert!(lib_dir_path.exists(), "The library directory at {} does not exist.", lib_dir_path.display()); + if !lib_dir_path.exists() { + panic!("The library directory specified in {LIB_VAR_NAME} at {} does not exist.", lib_dir_path.display()); + + } lib_dir_path } ).unwrap_or_else(|_| { diff --git a/rust/logos-blockchain-circuits-poq-sys/src/native.rs b/rust/logos-blockchain-circuits-poq-sys/src/native.rs index ce49465..df85c72 100644 --- a/rust/logos-blockchain-circuits-poq-sys/src/native.rs +++ b/rust/logos-blockchain-circuits-poq-sys/src/native.rs @@ -1,18 +1,28 @@ -use std::ffi::c_char; use std::path::Path; use lbc_types::{ffi, native::{Bytes, Error, WitnessInput}}; use crate::ffi::{poq_generate_witness, poq_generate_witness_from_files}; +fn into_null_terminated_string( + string: &str, +) -> Result { + std::ffi::CString::new(string) + .map_err(|error| Error::InvalidInput(Some(format!("Could not convert string to CString: {error}")))) +} + +fn path_as_null_terminated_string( + path: &Path, +) -> Result { + let path = path.to_str().ok_or(Error::InvalidInput(Some(format!("Could not convert the path to a string: {}", path.display()))))?; + into_null_terminated_string(path) +} + pub fn generate_witness( input: WitnessInput, ) -> Result { let ffi_input_guard = input.as_ffi(); let ffi_input = ffi_input_guard.as_ref(); - let mut ffi_output_bytes = ffi::Bytes { - data: std::ptr::null_mut(), - size: 0 - }; + let mut ffi_output_bytes = ffi::Bytes::null(); let status = unsafe { poq_generate_witness( @@ -29,15 +39,15 @@ pub fn generate_witness_from_files( inputs: &Path, output: &Path, ) -> Result<(), Error> { - let dat = dat.to_str().ok_or_else(|| Error::InvalidInput)?; // TODO: Message - let inputs = inputs.to_str().ok_or_else(|| Error::InvalidInput)?; - let output = output.to_str().ok_or_else(|| Error::InvalidInput)?; + 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 ( - dat.as_ptr() as *const c_char, - inputs.as_ptr() as *const c_char, - output.as_ptr() as *const c_char + c_dat.as_ptr(), + c_inputs.as_ptr(), + c_output.as_ptr(), ) }.try_into() } diff --git a/rust/logos-blockchain-circuits-types/Cargo.toml b/rust/logos-blockchain-circuits-types/Cargo.toml index defada9..898cb4f 100644 --- a/rust/logos-blockchain-circuits-types/Cargo.toml +++ b/rust/logos-blockchain-circuits-types/Cargo.toml @@ -11,4 +11,3 @@ version.workspace = true [dependencies] libc = { workspace = true } -thiserror = { workspace = true } diff --git a/rust/logos-blockchain-circuits-types/src/ffi/bytes.rs b/rust/logos-blockchain-circuits-types/src/ffi/bytes.rs index 046257d..d0e37d0 100644 --- a/rust/logos-blockchain-circuits-types/src/ffi/bytes.rs +++ b/rust/logos-blockchain-circuits-types/src/ffi/bytes.rs @@ -8,6 +8,24 @@ mod inner { } } +impl inner::Buffer<*const T> { + pub fn null() -> Self { + Self { + data: std::ptr::null(), + size: 0, + } + } +} + +impl inner::Buffer<*mut T> { + pub fn null() -> Self { + Self { + data: std::ptr::null_mut(), + size: 0, + } + } +} + /// Owned byte buffer returned by the C witness generator functions. /// /// The inner `data` pointer must be null-initialized. It's heap-allocated by the C side and must be @@ -29,7 +47,7 @@ pub type ConstBytes = inner::Buffer<*const u8>; /// /// # Safety /// -/// Dereferences raw pointers. The caller must ensure that the pointer is valid. +/// Dereferences raw pointers. pub unsafe fn free_bytes(bytes: *mut Bytes) { if bytes.is_null() { return; diff --git a/rust/logos-blockchain-circuits-types/src/ffi/status.rs b/rust/logos-blockchain-circuits-types/src/ffi/status.rs index 746dfaf..44ad026 100644 --- a/rust/logos-blockchain-circuits-types/src/ffi/status.rs +++ b/rust/logos-blockchain-circuits-types/src/ffi/status.rs @@ -1,17 +1,20 @@ use std::ffi::c_char; /// Status codes for C API functions. -#[repr(C)] -pub enum Code { - Ok = 0, - DynError = 1, - InvalidInput = 2, - OutOfMemory = 3, +#[derive(PartialEq, Eq)] // Enables comparisons with named constants. +#[repr(transparent)] +pub struct Code(pub i32); + +impl Code { + pub const OK: Self = Self(0); + pub const DYN_ERROR: Self = Self(1); + pub const INVALID_INPUT: Self = Self(2); + pub const OUT_OF_MEMORY: Self = Self(3); } impl Code { pub fn is_ok(&self) -> bool { - matches!(self, Code::Ok) + self == &Self::OK } pub fn is_error(&self) -> bool { @@ -29,7 +32,7 @@ pub struct Status { impl Status { pub fn ok() -> Self { Status { - code: Code::Ok, + code: Code::OK, message: [0; 256], } } diff --git a/rust/logos-blockchain-circuits-types/src/native/bytes.rs b/rust/logos-blockchain-circuits-types/src/native/bytes.rs index 53251d4..2f35fbb 100644 --- a/rust/logos-blockchain-circuits-types/src/native/bytes.rs +++ b/rust/logos-blockchain-circuits-types/src/native/bytes.rs @@ -26,10 +26,14 @@ impl From> for Bytes { impl From for Bytes { fn from(mut ffi_value: ffi::Bytes) -> Self { - let raw = unsafe { - std::slice::from_raw_parts(ffi_value.data, ffi_value.size).to_vec() + 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() + } }; - unsafe { ffi::free_bytes(&mut ffi_value); } - Self(raw) + unsafe { ffi::free_bytes(&mut ffi_value) }; + Self(vec) } } diff --git a/rust/logos-blockchain-circuits-types/src/native/status.rs b/rust/logos-blockchain-circuits-types/src/native/status.rs index d2dddc7..75c3c74 100644 --- a/rust/logos-blockchain-circuits-types/src/native/status.rs +++ b/rust/logos-blockchain-circuits-types/src/native/status.rs @@ -1,44 +1,52 @@ use std::ffi::CStr; -use thiserror::Error; +use std::fmt::Display; use crate::ffi::status::Code as FfiStatusCode; -pub type DynError = Box; pub type Result = std::result::Result; /// Error returned when a witness generator call does not succeed. -#[derive(Debug, Error)] +#[derive(Debug)] pub enum Error { - #[error("Invalid input")] - InvalidInput, - #[error("Out of memory")] - OutOfMemory, - #[error(transparent)] - Other(#[from] DynError), + InvalidInput(Option), + OutOfMemory(Option), + Other(Option), +} + +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), + }; + match message { + Some(message) => write!(f, "{kind}: {message}"), + None => write!(f, "{kind}"), + } + } } impl TryFrom for () { type Error = Error; fn try_from(status: crate::ffi::Status) -> Result<()> { + let message: Option = 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 + }; + match status.code { - FfiStatusCode::Ok => Ok(()), - FfiStatusCode::DynError => { - let message: Option<&CStr> = - if status.has_message() { - let status_message = unsafe { - CStr::from_ptr(status.message.as_ptr()) - }; - Some(status_message) - } else { - None - }; - let error_message = message - .map(|inner| DynError::from(inner.to_string_lossy().into_owned())) - .unwrap_or_else(|| DynError::from("Unknown error")); - Err(error_message.into()) - }, - FfiStatusCode::InvalidInput => Err(Error::InvalidInput), - FfiStatusCode::OutOfMemory => Err(Error::OutOfMemory), + 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)))) } } } diff --git a/rust/logos-blockchain-circuits-types/src/native/witness_input.rs b/rust/logos-blockchain-circuits-types/src/native/witness_input.rs index 00843db..ced2660 100644 --- a/rust/logos-blockchain-circuits-types/src/native/witness_input.rs +++ b/rust/logos-blockchain-circuits-types/src/native/witness_input.rs @@ -1,5 +1,6 @@ -use std::ffi::{CString, NulError}; +use std::ffi::CString; use crate::ffi; +use crate::native::Error; /// Input for witness generators pub struct WitnessInput { @@ -10,8 +11,12 @@ pub struct WitnessInput { } impl WitnessInput { - pub fn new(dat: Vec, inputs_json: String) -> Result { - let inputs_json = CString::new(inputs_json)?; + pub fn new(dat: Vec, inputs_json: String) -> Result { + 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) + )) + )?; Ok(Self { dat, inputs_json }) }