use core::alloc::Layout;
use std::alloc::{alloc, dealloc};
use std::slice;
use std::sync::atomic::{AtomicU64, Ordering};
static RANDOM_SEED_LO: AtomicU64 = AtomicU64::new(0x0123456789abcdef);
static RANDOM_SEED_HI: AtomicU64 = AtomicU64::new(0xfedcba9876543210);
#[no_mangle]
pub extern "C" fn set_random_seed(seed_ptr: *const u8) {
if seed_ptr.is_null() {
return;
}
let seed_bytes = unsafe { slice::from_raw_parts(seed_ptr, 32) };
let lo = u64::from_le_bytes(seed_bytes[0..8].try_into().unwrap());
let hi = u64::from_le_bytes(seed_bytes[8..16].try_into().unwrap());
let lo2 = u64::from_le_bytes(seed_bytes[16..24].try_into().unwrap());
let hi2 = u64::from_le_bytes(seed_bytes[24..32].try_into().unwrap());
RANDOM_SEED_LO.store(lo ^ lo2, Ordering::SeqCst);
RANDOM_SEED_HI.store(hi ^ hi2, Ordering::SeqCst);
}
use getrandom::register_custom_getrandom;
fn custom_getrandom(dest: &mut [u8]) -> Result<(), getrandom::Error> {
let mut s0 = RANDOM_SEED_LO.load(Ordering::SeqCst);
let mut s1 = RANDOM_SEED_HI.load(Ordering::SeqCst);
for chunk in dest.chunks_mut(8) {
let mut t = s0;
let s = s1;
s0 = s;
t ^= t << 23;
t ^= t >> 18;
t ^= s ^ (s >> 5);
s1 = t;
let result = s0.wrapping_add(s1);
let bytes = result.to_le_bytes();
let len = chunk.len().min(8);
chunk[..len].copy_from_slice(&bytes[..len]);
}
RANDOM_SEED_LO.store(s0, Ordering::SeqCst);
RANDOM_SEED_HI.store(s1, Ordering::SeqCst);
Ok(())
}
register_custom_getrandom!(custom_getrandom);
use crate::{
hardcoded_config_12, hardcoded_config_20, hardcoded_config_24, hardcoded_config_26,
hardcoded_config_28, hardcoded_config_30,
};
use crate::{
hardcoded_config_12_verifier, hardcoded_config_20_verifier, hardcoded_config_24_verifier,
hardcoded_config_26_verifier, hardcoded_config_28_verifier, hardcoded_config_30_verifier,
};
use crate::{prover, verifier};
use binary_fields::{BinaryElem128, BinaryElem32};
use std::marker::PhantomData;
#[no_mangle]
pub extern "C" fn wasm_alloc(size: u32) -> *mut u8 {
if size == 0 {
return core::ptr::null_mut();
}
let layout = match Layout::from_size_align(size as usize, 8) {
Ok(l) => l,
Err(_) => return core::ptr::null_mut(),
};
unsafe { alloc(layout) }
}
#[no_mangle]
pub extern "C" fn wasm_dealloc(ptr: *mut u8, size: u32) {
if ptr.is_null() || size == 0 {
return;
}
let layout = match Layout::from_size_align(size as usize, 8) {
Ok(l) => l,
Err(_) => return,
};
unsafe { dealloc(ptr, layout) }
}
#[no_mangle]
pub extern "C" fn get_polynomial_size(config_size: u8) -> u32 {
match config_size {
12 | 20 | 24 | 28 | 30 => 1u32 << config_size,
_ => 0,
}
}
#[no_mangle]
pub extern "C" fn prove_raw(poly_ptr: *const u32, poly_len: u32, config_size: u8) -> *mut u8 {
fn build_result(status: u8, data: &[u8]) -> *mut u8 {
let total_size = 1 + 4 + data.len(); let ptr = unsafe {
let layout = Layout::from_size_align(total_size, 8).unwrap();
alloc(layout)
};
if ptr.is_null() {
return ptr;
}
unsafe {
*ptr = status;
let len_bytes = (data.len() as u32).to_le_bytes();
core::ptr::copy_nonoverlapping(len_bytes.as_ptr(), ptr.add(1), 4);
core::ptr::copy_nonoverlapping(data.as_ptr(), ptr.add(5), data.len());
}
ptr
}
fn build_error(msg: &str) -> *mut u8 {
build_result(1, msg.as_bytes())
}
if poly_ptr.is_null() {
return build_error("null polynomial pointer");
}
let expected_len = get_polynomial_size(config_size);
if expected_len == 0 {
return build_error("invalid config_size (use 12, 20, 24, 28, or 30)");
}
if poly_len != expected_len {
return build_error("polynomial length mismatch");
}
let poly_slice = unsafe { slice::from_raw_parts(poly_ptr, poly_len as usize) };
let poly: Vec<BinaryElem32> = poly_slice.iter().map(|&x| BinaryElem32::from(x)).collect();
let proof_result = match config_size {
12 => {
let config =
hardcoded_config_12(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
prover::<BinaryElem32, BinaryElem128>(&config, &poly)
}
20 => {
let config =
hardcoded_config_20(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
prover::<BinaryElem32, BinaryElem128>(&config, &poly)
}
24 => {
let config =
hardcoded_config_24(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
prover::<BinaryElem32, BinaryElem128>(&config, &poly)
}
26 => {
let config =
hardcoded_config_26(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
prover::<BinaryElem32, BinaryElem128>(&config, &poly)
}
28 => {
let config =
hardcoded_config_28(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
prover::<BinaryElem32, BinaryElem128>(&config, &poly)
}
30 => {
let config =
hardcoded_config_30(PhantomData::<BinaryElem32>, PhantomData::<BinaryElem128>);
prover::<BinaryElem32, BinaryElem128>(&config, &poly)
}
_ => unreachable!(),
};
match proof_result {
Ok(proof) => {
match bincode::serialize(&proof) {
Ok(bytes) => build_result(0, &bytes),
Err(e) => build_error(&format!("serialization failed: {}", e)),
}
}
Err(e) => build_error(&format!("proving failed: {}", e)),
}
}
#[no_mangle]
pub extern "C" fn verify_raw(proof_ptr: *const u8, proof_len: u32, config_size: u8) -> u8 {
if proof_ptr.is_null() || proof_len == 0 {
return 2; }
let proof_bytes = unsafe { slice::from_raw_parts(proof_ptr, proof_len as usize) };
let proof: crate::FinalizedLigeritoProof<BinaryElem32, BinaryElem128> =
match bincode::deserialize(proof_bytes) {
Ok(p) => p,
Err(_) => return 2, };
let result = match config_size {
12 => {
let config = hardcoded_config_12_verifier();
verifier::<BinaryElem32, BinaryElem128>(&config, &proof)
}
20 => {
let config = hardcoded_config_20_verifier();
verifier::<BinaryElem32, BinaryElem128>(&config, &proof)
}
24 => {
let config = hardcoded_config_24_verifier();
verifier::<BinaryElem32, BinaryElem128>(&config, &proof)
}
26 => {
let config = hardcoded_config_26_verifier();
verifier::<BinaryElem32, BinaryElem128>(&config, &proof)
}
28 => {
let config = hardcoded_config_28_verifier();
verifier::<BinaryElem32, BinaryElem128>(&config, &proof)
}
30 => {
let config = hardcoded_config_30_verifier();
verifier::<BinaryElem32, BinaryElem128>(&config, &proof)
}
_ => return 2, };
match result {
Ok(true) => 1, Ok(false) => 0, Err(_) => 2, }
}
#[no_mangle]
pub extern "C" fn result_status(ptr: *const u8) -> u8 {
if ptr.is_null() {
return 2;
}
unsafe { *ptr }
}
#[no_mangle]
pub extern "C" fn result_len(ptr: *const u8) -> u32 {
if ptr.is_null() {
return 0;
}
unsafe {
let bytes = [*ptr.add(1), *ptr.add(2), *ptr.add(3), *ptr.add(4)];
u32::from_le_bytes(bytes)
}
}
#[no_mangle]
pub extern "C" fn result_data_ptr(ptr: *const u8) -> *const u8 {
if ptr.is_null() {
return core::ptr::null();
}
unsafe { ptr.add(5) }
}
#[no_mangle]
pub extern "C" fn result_free(ptr: *mut u8) {
if ptr.is_null() {
return;
}
let len = result_len(ptr);
let total_size = 1 + 4 + len as usize;
wasm_dealloc(ptr, total_size as u32);
}