#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use std::error::Error;
use std::fmt;
use std::ptr;
pub(crate) mod bindings_include;
use bindings_include::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PqcError {
BadArgument,
BadKey,
BadSignature,
NotImplemented,
Other(i32),
}
impl fmt::Display for PqcError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PqcError::BadArgument => write!(f, "Invalid arguments provided"),
PqcError::BadKey => write!(f, "Invalid key provided"),
PqcError::BadSignature => write!(f, "Invalid signature provided"),
PqcError::NotImplemented => write!(f, "Algorithm not implemented"),
PqcError::Other(code) => write!(f, "Unexpected error code: {}", code),
}
}
}
impl Error for PqcError {}
impl From<bitcoin_pqc_error_t> for Result<(), PqcError> {
fn from(error: bitcoin_pqc_error_t) -> Self {
match error {
bitcoin_pqc_error_t::BITCOIN_PQC_OK => Ok(()),
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_ARG => Err(PqcError::BadArgument),
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_KEY => Err(PqcError::BadKey),
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_SIGNATURE => Err(PqcError::BadSignature),
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_NOT_IMPLEMENTED => Err(PqcError::NotImplemented),
_ => Err(PqcError::Other(error.0)),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Algorithm {
SECP256K1_SCHNORR,
FN_DSA_512,
ML_DSA_44,
SLH_DSA_128S,
}
impl From<Algorithm> for bitcoin_pqc_algorithm_t {
fn from(alg: Algorithm) -> Self {
match alg {
Algorithm::SECP256K1_SCHNORR => bitcoin_pqc_algorithm_t::BITCOIN_PQC_SECP256K1_SCHNORR,
Algorithm::FN_DSA_512 => bitcoin_pqc_algorithm_t::BITCOIN_PQC_FN_DSA_512,
Algorithm::ML_DSA_44 => bitcoin_pqc_algorithm_t::BITCOIN_PQC_ML_DSA_44,
Algorithm::SLH_DSA_128S => bitcoin_pqc_algorithm_t::BITCOIN_PQC_SLH_DSA_SHAKE_128S,
}
}
}
#[derive(Debug)]
pub struct PublicKey {
pub algorithm: Algorithm,
pub bytes: Vec<u8>,
}
#[derive(Debug)]
pub struct SecretKey {
pub algorithm: Algorithm,
pub bytes: Vec<u8>,
}
#[derive(Debug, Clone)]
pub struct Signature {
pub algorithm: Algorithm,
pub bytes: Vec<u8>,
}
impl Drop for SecretKey {
fn drop(&mut self) {
for byte in &mut self.bytes {
*byte = 0;
}
}
}
#[derive(Debug)]
pub struct KeyPair {
pub public_key: PublicKey,
pub secret_key: SecretKey,
}
pub fn generate_keypair(algorithm: Algorithm, random_data: &[u8]) -> Result<KeyPair, PqcError> {
if random_data.len() < 128 {
return Err(PqcError::BadArgument);
}
unsafe {
let mut keypair = bitcoin_pqc_keypair_t {
algorithm: algorithm.into(),
public_key: ptr::null_mut(),
secret_key: ptr::null_mut(),
public_key_size: 0,
secret_key_size: 0,
};
let result = bitcoin_pqc_keygen(
algorithm.into(),
&mut keypair,
random_data.as_ptr(),
random_data.len(),
);
if result != bitcoin_pqc_error_t::BITCOIN_PQC_OK {
return Err(match result {
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_ARG => PqcError::BadArgument,
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_KEY => PqcError::BadKey,
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_NOT_IMPLEMENTED => PqcError::NotImplemented,
_ => PqcError::Other(result.0 as i32),
});
}
let pk_slice =
std::slice::from_raw_parts(keypair.public_key as *const u8, keypair.public_key_size);
let sk_slice =
std::slice::from_raw_parts(keypair.secret_key as *const u8, keypair.secret_key_size);
let pk_bytes = pk_slice.to_vec();
let sk_bytes = sk_slice.to_vec();
bitcoin_pqc_keypair_free(&mut keypair);
Ok(KeyPair {
public_key: PublicKey {
algorithm,
bytes: pk_bytes,
},
secret_key: SecretKey {
algorithm,
bytes: sk_bytes,
},
})
}
}
pub fn sign(secret_key: &SecretKey, message: &[u8]) -> Result<Signature, PqcError> {
unsafe {
let mut signature = bitcoin_pqc_signature_t {
algorithm: secret_key.algorithm.into(),
signature: ptr::null_mut(),
signature_size: 0,
};
let result = bitcoin_pqc_sign(
secret_key.algorithm.into(),
secret_key.bytes.as_ptr(),
secret_key.bytes.len(),
message.as_ptr(),
message.len(),
&mut signature,
);
if result != bitcoin_pqc_error_t::BITCOIN_PQC_OK {
return Err(match result {
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_ARG => PqcError::BadArgument,
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_KEY => PqcError::BadKey,
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_BAD_SIGNATURE => PqcError::BadSignature,
bitcoin_pqc_error_t::BITCOIN_PQC_ERROR_NOT_IMPLEMENTED => PqcError::NotImplemented,
_ => PqcError::Other(result.0 as i32),
});
}
let sig_slice =
std::slice::from_raw_parts(signature.signature as *const u8, signature.signature_size);
let sig_bytes = sig_slice.to_vec();
bitcoin_pqc_signature_free(&mut signature);
Ok(Signature {
algorithm: secret_key.algorithm,
bytes: sig_bytes,
})
}
}
pub fn verify(
public_key: &PublicKey,
message: &[u8],
signature: &Signature,
) -> Result<(), PqcError> {
if public_key.algorithm != signature.algorithm {
return Err(PqcError::BadArgument);
}
unsafe {
let result = bitcoin_pqc_verify(
public_key.algorithm.into(),
public_key.bytes.as_ptr(),
public_key.bytes.len(),
message.as_ptr(),
message.len(),
signature.bytes.as_ptr(),
signature.bytes.len(),
);
result.into()
}
}
pub fn public_key_size(algorithm: Algorithm) -> usize {
unsafe { bitcoin_pqc_public_key_size(algorithm.into()) }
}
pub fn secret_key_size(algorithm: Algorithm) -> usize {
unsafe { bitcoin_pqc_secret_key_size(algorithm.into()) }
}
pub fn signature_size(algorithm: Algorithm) -> usize {
unsafe { bitcoin_pqc_signature_size(algorithm.into()) }
}