mirror of
https://github.com/logos-blockchain/logos-blockchain-circuits.git
synced 2026-05-18 15:29:26 +00:00
Implement poc, pol and signature circuits. Abstract utils into their own crate. Abstract CircuitWitnessInput.
This commit is contained in:
parent
3ae7ff2258
commit
9af51ddf7e
41
rust/Cargo.lock
generated
41
rust/Cargo.lock
generated
@ -151,12 +151,46 @@ version = "0.4.29"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
|
||||
[[package]]
|
||||
name = "logos-blockchain-circuits-poc-sys"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"logos-blockchain-circuits-types",
|
||||
"logos-blockchain-circuits-utils",
|
||||
"tar",
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "logos-blockchain-circuits-pol-sys"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"logos-blockchain-circuits-types",
|
||||
"logos-blockchain-circuits-utils",
|
||||
"tar",
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "logos-blockchain-circuits-poq-sys"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"logos-blockchain-circuits-types",
|
||||
"logos-blockchain-circuits-utils",
|
||||
"tar",
|
||||
"ureq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "logos-blockchain-circuits-signature-sys"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"logos-blockchain-circuits-types",
|
||||
"logos-blockchain-circuits-utils",
|
||||
"tar",
|
||||
"ureq",
|
||||
]
|
||||
@ -168,6 +202,13 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "logos-blockchain-circuits-utils"
|
||||
version = "0.4.2"
|
||||
dependencies = [
|
||||
"logos-blockchain-circuits-types",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.8.9"
|
||||
|
||||
@ -10,15 +10,23 @@ version = "0.4.2"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"logos-blockchain-circuits-poc-sys",
|
||||
"logos-blockchain-circuits-pol-sys",
|
||||
"logos-blockchain-circuits-poq-sys",
|
||||
"logos-blockchain-circuits-types"
|
||||
"logos-blockchain-circuits-signature-sys",
|
||||
"logos-blockchain-circuits-types",
|
||||
"logos-blockchain-circuits-utils"
|
||||
]
|
||||
resolver = "3"
|
||||
|
||||
[workspace.dependencies]
|
||||
# Internal
|
||||
lbc-poq-sys = { default-features = false, package = "logos-blockchain-circuits-poq-sys", path = "./logos-blockchain-circuits-poq-sys" }
|
||||
lbc-types = { default-features = false, package = "logos-blockchain-circuits-types", path = "./logos-blockchain-circuits-types" }
|
||||
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-utils = { default-features = false, package = "logos-blockchain-circuits-utils", path = "./logos-blockchain-circuits-utils" }
|
||||
|
||||
# External
|
||||
flate2 = "1"
|
||||
|
||||
19
rust/logos-blockchain-circuits-poc-sys/Cargo.toml
Normal file
19
rust/logos-blockchain-circuits-poc-sys/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "logos-blockchain-circuits-poc-sys"
|
||||
categories.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
lbc-types = { workspace = true }
|
||||
lbc-utils = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
flate2 = { workspace = true }
|
||||
tar = { workspace = true }
|
||||
ureq = { workspace = true }
|
||||
89
rust/logos-blockchain-circuits-poc-sys/build.rs
Normal file
89
rust/logos-blockchain-circuits-poc-sys/build.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use ureq::Body;
|
||||
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}")
|
||||
}
|
||||
|
||||
fn get_artifact_url(version: &str, os: &str, arch: &str) -> String {
|
||||
let artifact = get_artifact_name(version, os, arch);
|
||||
let artifact_tar_gz = format!("{artifact}.tar.gz");
|
||||
format!(
|
||||
"https://github.com/logos-blockchain/logos-blockchain-circuits/releases/download/v{version}/{artifact_tar_gz}"
|
||||
)
|
||||
}
|
||||
|
||||
fn fetch_library(version: &str, os: &str, arch: &str) -> Response<Body> {
|
||||
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}. \
|
||||
Set {LIB_VAR_NAME} to point to a local build instead."
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
unpacked_library_directory
|
||||
}
|
||||
|
||||
fn provision_library() -> PathBuf {
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
||||
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);
|
||||
if expected_library_directory.exists() {
|
||||
println!("Found an existing library at {}. Reusing it.", expected_library_directory.display());
|
||||
return expected_library_directory;
|
||||
}
|
||||
|
||||
let response = fetch_library(version, &os, &arch);
|
||||
unpack_library(response, version, &os, &arch, &out_dir)
|
||||
}
|
||||
|
||||
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);
|
||||
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(|_| {
|
||||
provision_library()
|
||||
});
|
||||
|
||||
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}");
|
||||
println!("cargo:rustc-link-lib=stdc++");
|
||||
println!("cargo:rustc-link-lib=gmp");
|
||||
}
|
||||
12
rust/logos-blockchain-circuits-poc-sys/src/ffi.rs
Normal file
12
rust/logos-blockchain-circuits-poc-sys/src/ffi.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use std::ffi::c_char;
|
||||
use lbc_types::ffi::{Bytes, Status, WitnessInput};
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn poc_generate_witness(input: *const WitnessInput, output: *mut Bytes) -> Status;
|
||||
|
||||
pub fn poc_generate_witness_from_files(
|
||||
dat: *const c_char,
|
||||
inputs: *const c_char,
|
||||
output: *const c_char,
|
||||
) -> Status;
|
||||
}
|
||||
4
rust/logos-blockchain-circuits-poc-sys/src/lib.rs
Normal file
4
rust/logos-blockchain-circuits-poc-sys/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod ffi;
|
||||
pub mod native;
|
||||
|
||||
pub use native::{generate_witness, generate_witness_from_files, PocWitnessInput};
|
||||
87
rust/logos-blockchain-circuits-poc-sys/src/native.rs
Normal file
87
rust/logos-blockchain-circuits-poc-sys/src/native.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use std::path::Path;
|
||||
use lbc_types::{ffi, native::{Bytes, Error}};
|
||||
use lbc_types::inputs::CircuitDat;
|
||||
use lbc_utils::string::path_as_null_terminated_string;
|
||||
use crate::ffi::{poc_generate_witness, poc_generate_witness_from_files};
|
||||
|
||||
pub(crate) const RAW_CIRCUIT_DAT: &[u8] = include_bytes!(concat!(env!("LBC_POC_LIB_DIR"), "/witness_generator.dat"));
|
||||
|
||||
pub struct PocDat;
|
||||
impl CircuitDat for PocDat {
|
||||
const DAT: &'static [u8] = RAW_CIRCUIT_DAT;
|
||||
}
|
||||
|
||||
pub type PocWitnessInput<'a> = lbc_types::inputs::CircuitWitnessInput<'a, PocDat>;
|
||||
|
||||
pub fn generate_witness(
|
||||
input: PocWitnessInput,
|
||||
) -> Result<Bytes, Error> {
|
||||
let input: lbc_types::WitnessInput = input.into();
|
||||
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
|
||||
)
|
||||
};
|
||||
|
||||
status.try_into().map(|()| { Bytes::from(ffi_output_bytes) })
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
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()),
|
||||
)
|
||||
});
|
||||
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)
|
||||
.expect("generate_witness_from_files failed.");
|
||||
|
||||
let inputs_json = std::fs::read_to_string(&*INPUTS)
|
||||
.expect(format!("Failed to read {}.", INPUTS.display()).as_str());
|
||||
|
||||
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());
|
||||
assert_eq!(output.as_slice(), expected.as_slice());
|
||||
}
|
||||
}
|
||||
19
rust/logos-blockchain-circuits-pol-sys/Cargo.toml
Normal file
19
rust/logos-blockchain-circuits-pol-sys/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "logos-blockchain-circuits-pol-sys"
|
||||
categories.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
lbc-types = { workspace = true }
|
||||
lbc-utils = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
flate2 = { workspace = true }
|
||||
tar = { workspace = true }
|
||||
ureq = { workspace = true }
|
||||
89
rust/logos-blockchain-circuits-pol-sys/build.rs
Normal file
89
rust/logos-blockchain-circuits-pol-sys/build.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use ureq::Body;
|
||||
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}")
|
||||
}
|
||||
|
||||
fn get_artifact_url(version: &str, os: &str, arch: &str) -> String {
|
||||
let artifact = get_artifact_name(version, os, arch);
|
||||
let artifact_tar_gz = format!("{artifact}.tar.gz");
|
||||
format!(
|
||||
"https://github.com/logos-blockchain/logos-blockchain-circuits/releases/download/v{version}/{artifact_tar_gz}"
|
||||
)
|
||||
}
|
||||
|
||||
fn fetch_library(version: &str, os: &str, arch: &str) -> Response<Body> {
|
||||
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}. \
|
||||
Set {LIB_VAR_NAME} to point to a local build instead."
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
unpacked_library_directory
|
||||
}
|
||||
|
||||
fn provision_library() -> PathBuf {
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
||||
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);
|
||||
if expected_library_directory.exists() {
|
||||
println!("Found an existing library at {}. Reusing it.", expected_library_directory.display());
|
||||
return expected_library_directory;
|
||||
}
|
||||
|
||||
let response = fetch_library(version, &os, &arch);
|
||||
unpack_library(response, version, &os, &arch, &out_dir)
|
||||
}
|
||||
|
||||
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);
|
||||
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(|_| {
|
||||
provision_library()
|
||||
});
|
||||
|
||||
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}");
|
||||
println!("cargo:rustc-link-lib=stdc++");
|
||||
println!("cargo:rustc-link-lib=gmp");
|
||||
}
|
||||
12
rust/logos-blockchain-circuits-pol-sys/src/ffi.rs
Normal file
12
rust/logos-blockchain-circuits-pol-sys/src/ffi.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use std::ffi::c_char;
|
||||
use lbc_types::ffi::{Bytes, Status, WitnessInput};
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn pol_generate_witness(input: *const WitnessInput, output: *mut Bytes) -> Status;
|
||||
|
||||
pub fn pol_generate_witness_from_files(
|
||||
dat: *const c_char,
|
||||
inputs: *const c_char,
|
||||
output: *const c_char,
|
||||
) -> Status;
|
||||
}
|
||||
4
rust/logos-blockchain-circuits-pol-sys/src/lib.rs
Normal file
4
rust/logos-blockchain-circuits-pol-sys/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod ffi;
|
||||
pub mod native;
|
||||
|
||||
pub use native::{generate_witness, generate_witness_from_files, PolWitnessInput};
|
||||
87
rust/logos-blockchain-circuits-pol-sys/src/native.rs
Normal file
87
rust/logos-blockchain-circuits-pol-sys/src/native.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use std::path::Path;
|
||||
use lbc_types::{ffi, native::{Bytes, Error}};
|
||||
use lbc_types::inputs::CircuitDat;
|
||||
use lbc_utils::string::path_as_null_terminated_string;
|
||||
use crate::ffi::{pol_generate_witness, pol_generate_witness_from_files};
|
||||
|
||||
pub(crate) const RAW_CIRCUIT_DAT: &[u8] = include_bytes!(concat!(env!("LBC_POL_LIB_DIR"), "/witness_generator.dat"));
|
||||
|
||||
pub struct PolDat;
|
||||
impl CircuitDat for PolDat {
|
||||
const DAT: &'static [u8] = RAW_CIRCUIT_DAT;
|
||||
}
|
||||
|
||||
pub type PolWitnessInput<'a> = lbc_types::inputs::CircuitWitnessInput<'a, PolDat>;
|
||||
|
||||
pub fn generate_witness(
|
||||
input: PolWitnessInput,
|
||||
) -> Result<Bytes, Error> {
|
||||
let input: lbc_types::WitnessInput = input.into();
|
||||
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
|
||||
)
|
||||
};
|
||||
|
||||
status.try_into().map(|()| { Bytes::from(ffi_output_bytes) })
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
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()),
|
||||
)
|
||||
});
|
||||
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)
|
||||
.expect("generate_witness_from_files failed.");
|
||||
|
||||
let inputs_json = std::fs::read_to_string(&*INPUTS)
|
||||
.expect(format!("Failed to read {}.", INPUTS.display()).as_str());
|
||||
|
||||
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());
|
||||
assert_eq!(output.as_slice(), expected.as_slice());
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,7 @@ version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
lbc-types = { workspace = true }
|
||||
lbc-utils = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
flate2 = { workspace = true }
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
mod ffi;
|
||||
pub mod native;
|
||||
|
||||
pub use native::{generate_witness, generate_witness_from_files, inputs::PoqWitnessInput};
|
||||
pub use native::{generate_witness, generate_witness_from_files, PoqWitnessInput};
|
||||
|
||||
@ -1,58 +1,20 @@
|
||||
use std::path::Path;
|
||||
use lbc_types::{ffi, native::{Bytes, Error}};
|
||||
use lbc_types::inputs::CircuitDat;
|
||||
use lbc_utils::string::path_as_null_terminated_string;
|
||||
use crate::ffi::{poq_generate_witness, poq_generate_witness_from_files};
|
||||
|
||||
mod helpers {
|
||||
use std::path::Path;
|
||||
use lbc_types::native::Error;
|
||||
pub(crate) const RAW_CIRCUIT_DAT: &[u8] = include_bytes!(concat!(env!("LBC_POQ_LIB_DIR"), "/witness_generator.dat"));
|
||||
|
||||
pub fn into_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()))))?;
|
||||
into_null_terminated_string(path)
|
||||
}
|
||||
pub struct PoqDat;
|
||||
impl CircuitDat for PoqDat {
|
||||
const DAT: &'static [u8] = RAW_CIRCUIT_DAT;
|
||||
}
|
||||
|
||||
pub mod inputs {
|
||||
use lbc_types::native::Error;
|
||||
use lbc_types::WitnessInput;
|
||||
|
||||
pub(crate) static DAT: &[u8] = include_bytes!(concat!(env!("LBC_POQ_LIB_DIR"), "/witness_generator.dat"));
|
||||
|
||||
pub struct PoqWitnessInput<'a> {
|
||||
inner: WitnessInput<'a>
|
||||
}
|
||||
|
||||
impl<'a> PoqWitnessInput<'a> {
|
||||
pub fn new(inputs_json: String) -> Result<Self, Error> {
|
||||
let inner = WitnessInput::new(DAT, inputs_json)?;
|
||||
Ok(Self { inner })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<PoqWitnessInput<'a>> for WitnessInput<'a> {
|
||||
fn from(value: PoqWitnessInput<'a>) -> Self {
|
||||
value.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<WitnessInput<'a>> for PoqWitnessInput<'a> {
|
||||
fn from(value: WitnessInput<'a>) -> Self {
|
||||
Self { inner: value }
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type PoqWitnessInput<'a> = lbc_types::inputs::CircuitWitnessInput<'a, PoqDat>;
|
||||
|
||||
pub fn generate_witness(
|
||||
input: inputs::PoqWitnessInput,
|
||||
input: PoqWitnessInput,
|
||||
) -> Result<Bytes, Error> {
|
||||
let input: lbc_types::WitnessInput = input.into();
|
||||
let ffi_input_guard = input.as_ffi();
|
||||
@ -75,9 +37,9 @@ pub fn generate_witness_from_files(
|
||||
inputs: &Path,
|
||||
output: &Path,
|
||||
) -> Result<(), Error> {
|
||||
let c_dat = helpers::path_as_null_terminated_string(dat)?;
|
||||
let c_inputs = helpers::path_as_null_terminated_string(inputs)?;
|
||||
let c_output = helpers::path_as_null_terminated_string(output)?;
|
||||
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 (
|
||||
@ -92,7 +54,7 @@ pub fn generate_witness_from_files(
|
||||
mod tests {
|
||||
use std::path::PathBuf;
|
||||
use std::sync::LazyLock;
|
||||
use super::{generate_witness, generate_witness_from_files, inputs};
|
||||
use super::{generate_witness, generate_witness_from_files, PoqWitnessInput};
|
||||
|
||||
static LIB_DIR: LazyLock<PathBuf> = LazyLock::new(|| {
|
||||
const ENV_VAR: &str = "LBC_POQ_LIB_DIR";
|
||||
@ -116,7 +78,7 @@ mod tests {
|
||||
let inputs_json = std::fs::read_to_string(&*INPUTS)
|
||||
.expect(format!("Failed to read {}.", INPUTS.display()).as_str());
|
||||
|
||||
let input = inputs::PoqWitnessInput::new(inputs_json).expect("Failed to construct the input for the witness generator.");
|
||||
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());
|
||||
|
||||
19
rust/logos-blockchain-circuits-signature-sys/Cargo.toml
Normal file
19
rust/logos-blockchain-circuits-signature-sys/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "logos-blockchain-circuits-signature-sys"
|
||||
categories.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
lbc-types = { workspace = true }
|
||||
lbc-utils = { workspace = true }
|
||||
|
||||
[build-dependencies]
|
||||
flate2 = { workspace = true }
|
||||
tar = { workspace = true }
|
||||
ureq = { workspace = true }
|
||||
89
rust/logos-blockchain-circuits-signature-sys/build.rs
Normal file
89
rust/logos-blockchain-circuits-signature-sys/build.rs
Normal file
@ -0,0 +1,89 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use ureq::Body;
|
||||
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}")
|
||||
}
|
||||
|
||||
fn get_artifact_url(version: &str, os: &str, arch: &str) -> String {
|
||||
let artifact = get_artifact_name(version, os, arch);
|
||||
let artifact_tar_gz = format!("{artifact}.tar.gz");
|
||||
format!(
|
||||
"https://github.com/logos-blockchain/logos-blockchain-circuits/releases/download/v{version}/{artifact_tar_gz}"
|
||||
)
|
||||
}
|
||||
|
||||
fn fetch_library(version: &str, os: &str, arch: &str) -> Response<Body> {
|
||||
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}. \
|
||||
Set {LIB_VAR_NAME} to point to a local build instead."
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
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.");
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
unpacked_library_directory
|
||||
}
|
||||
|
||||
fn provision_library() -> PathBuf {
|
||||
let version = env!("CARGO_PKG_VERSION");
|
||||
let os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
||||
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);
|
||||
if expected_library_directory.exists() {
|
||||
println!("Found an existing library at {}. Reusing it.", expected_library_directory.display());
|
||||
return expected_library_directory;
|
||||
}
|
||||
|
||||
let response = fetch_library(version, &os, &arch);
|
||||
unpack_library(response, version, &os, &arch, &out_dir)
|
||||
}
|
||||
|
||||
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);
|
||||
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(|_| {
|
||||
provision_library()
|
||||
});
|
||||
|
||||
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}");
|
||||
println!("cargo:rustc-link-lib=stdc++");
|
||||
println!("cargo:rustc-link-lib=gmp");
|
||||
}
|
||||
12
rust/logos-blockchain-circuits-signature-sys/src/ffi.rs
Normal file
12
rust/logos-blockchain-circuits-signature-sys/src/ffi.rs
Normal file
@ -0,0 +1,12 @@
|
||||
use std::ffi::c_char;
|
||||
use lbc_types::ffi::{Bytes, Status, WitnessInput};
|
||||
|
||||
unsafe extern "C" {
|
||||
pub fn signature_generate_witness(input: *const WitnessInput, output: *mut Bytes) -> Status;
|
||||
|
||||
pub fn signature_generate_witness_from_files(
|
||||
dat: *const c_char,
|
||||
inputs: *const c_char,
|
||||
output: *const c_char,
|
||||
) -> Status;
|
||||
}
|
||||
4
rust/logos-blockchain-circuits-signature-sys/src/lib.rs
Normal file
4
rust/logos-blockchain-circuits-signature-sys/src/lib.rs
Normal file
@ -0,0 +1,4 @@
|
||||
mod ffi;
|
||||
pub mod native;
|
||||
|
||||
pub use native::{generate_witness, generate_witness_from_files, SignatureWitnessInput};
|
||||
87
rust/logos-blockchain-circuits-signature-sys/src/native.rs
Normal file
87
rust/logos-blockchain-circuits-signature-sys/src/native.rs
Normal file
@ -0,0 +1,87 @@
|
||||
use std::path::Path;
|
||||
use lbc_types::{ffi, native::{Bytes, Error}};
|
||||
use lbc_types::inputs::CircuitDat;
|
||||
use lbc_utils::string::path_as_null_terminated_string;
|
||||
use crate::ffi::{signature_generate_witness, signature_generate_witness_from_files};
|
||||
|
||||
pub(crate) const RAW_CIRCUIT_DAT: &[u8] = include_bytes!(concat!(env!("LBC_SIGNATURE_LIB_DIR"), "/witness_generator.dat"));
|
||||
|
||||
pub struct SignatureDat;
|
||||
impl CircuitDat for SignatureDat {
|
||||
const DAT: &'static [u8] = RAW_CIRCUIT_DAT;
|
||||
}
|
||||
|
||||
pub type SignatureWitnessInput<'a> = lbc_types::inputs::CircuitWitnessInput<'a, SignatureDat>;
|
||||
|
||||
pub fn generate_witness(
|
||||
input: SignatureWitnessInput,
|
||||
) -> Result<Bytes, Error> {
|
||||
let input: lbc_types::WitnessInput = input.into();
|
||||
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 {
|
||||
signature_generate_witness(
|
||||
ffi_input as *const ffi::WitnessInput,
|
||||
&mut ffi_output_bytes as *mut ffi::Bytes
|
||||
)
|
||||
};
|
||||
|
||||
status.try_into().map(|()| { Bytes::from(ffi_output_bytes) })
|
||||
}
|
||||
|
||||
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 {
|
||||
signature_generate_witness_from_files(
|
||||
c_dat.as_ptr(),
|
||||
c_inputs.as_ptr(),
|
||||
c_output.as_ptr(),
|
||||
)
|
||||
}.try_into()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
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()),
|
||||
)
|
||||
});
|
||||
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)
|
||||
.expect("generate_witness_from_files failed.");
|
||||
|
||||
let inputs_json = std::fs::read_to_string(&*INPUTS)
|
||||
.expect(format!("Failed to read {}.", INPUTS.display()).as_str());
|
||||
|
||||
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());
|
||||
assert_eq!(output.as_slice(), expected.as_slice());
|
||||
}
|
||||
}
|
||||
@ -8,3 +8,38 @@ pub mod native;
|
||||
pub mod ffi;
|
||||
|
||||
pub use native::witness_input::WitnessInput;
|
||||
|
||||
|
||||
pub mod inputs {
|
||||
use crate::native::Error;
|
||||
use crate::WitnessInput;
|
||||
|
||||
pub trait CircuitDat {
|
||||
const DAT: &'static [u8];
|
||||
}
|
||||
|
||||
// TODO: Remove in favour on native::WitnessInput.
|
||||
pub struct CircuitWitnessInput<'input, Dat> {
|
||||
inner: WitnessInput<'input>,
|
||||
_phantom: std::marker::PhantomData<Dat>
|
||||
}
|
||||
|
||||
impl<'input, Dat: CircuitDat> CircuitWitnessInput<'input, Dat> {
|
||||
pub fn new(inputs_json: String) -> Result<Self, Error> {
|
||||
let inner = WitnessInput::new(Dat::DAT, inputs_json)?;
|
||||
Ok(Self { inner, _phantom: Default::default() })
|
||||
}
|
||||
}
|
||||
|
||||
impl<'input, Dat> From<CircuitWitnessInput<'input, Dat>> for WitnessInput<'input> {
|
||||
fn from(value: CircuitWitnessInput<'input, Dat>) -> Self {
|
||||
value.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<'input, Dat> From<WitnessInput<'input>> for CircuitWitnessInput<'input, Dat> {
|
||||
fn from(value: WitnessInput<'input>) -> Self {
|
||||
Self { inner: value, _phantom: Default::default() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
rust/logos-blockchain-circuits-utils/Cargo.toml
Normal file
13
rust/logos-blockchain-circuits-utils/Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "logos-blockchain-circuits-utils"
|
||||
categories.workspace = true
|
||||
description.workspace = true
|
||||
edition.workspace = true
|
||||
keywords.workspace = true
|
||||
license.workspace = true
|
||||
readme.workspace = true
|
||||
repository.workspace = true
|
||||
version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
lbc-types = { workspace = true}
|
||||
1
rust/logos-blockchain-circuits-utils/src/lib.rs
Normal file
1
rust/logos-blockchain-circuits-utils/src/lib.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod string;
|
||||
16
rust/logos-blockchain-circuits-utils/src/string.rs
Normal file
16
rust/logos-blockchain-circuits-utils/src/string.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use std::path::Path;
|
||||
use lbc_types::native::Error;
|
||||
|
||||
pub fn into_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()))))?;
|
||||
into_null_terminated_string(path)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user