#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#[cfg(feature = "serde")]
use std::convert::TryFrom;
use std::error::Error as StdError;
use std::fmt;
use std::hash::Hash;
use std::ptr;
use bitmask_enum::bitmask;
use secp256k1::{
schnorr, All, Keypair as SecpKeypair, Secp256k1, SecretKey as SecpSecretKey, XOnlyPublicKey,
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "serde")]
mod hex_bytes {
use serde::{de::Error, Deserialize, Deserializer, Serializer};
use std::vec::Vec;
pub fn serialize<S>(bytes: &Vec<u8>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&hex::encode(bytes))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
hex::decode(s).map_err(Error::custom)
}
}
pub(crate) mod bindings_include;
use bindings_include::*;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum PqcError {
BadArgument,
InsufficientData,
BadKey,
BadSignature,
NotImplemented,
AlgorithmMismatch,
Secp256k1Error(secp256k1::Error),
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::InsufficientData => write!(f, "Not enough data provided"),
PqcError::BadKey => write!(f, "Invalid key provided or invalid format"),
PqcError::BadSignature => write!(f, "Invalid signature provided or invalid format"),
PqcError::NotImplemented => write!(f, "Algorithm not implemented"),
PqcError::AlgorithmMismatch => {
write!(f, "Public key and signature algorithms mismatch")
}
PqcError::Secp256k1Error(e) => write!(f, "Secp256k1 error: {e}"),
PqcError::Other(code) => write!(f, "Unexpected error code: {code}"),
}
}
}
impl StdError for PqcError {
fn source(&self) -> Option<&(dyn StdError + 'static)> {
match self {
PqcError::Secp256k1Error(e) => Some(e),
_ => None,
}
}
}
impl From<secp256k1::Error> for PqcError {
fn from(e: secp256k1::Error) -> Self {
PqcError::Secp256k1Error(e)
}
}
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)),
}
}
}
#[bitmask(u8)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(try_from = "String", into = "String")
)]
pub enum Algorithm {
SECP256K1_SCHNORR,
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::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,
_ => panic!("Invalid algorithm"),
}
}
}
#[cfg(feature = "serde")]
impl TryFrom<String> for Algorithm {
type Error = String;
fn try_from(s: String) -> Result<Self, Self::Error> {
match s.as_str() {
"SECP256K1_SCHNORR" => Ok(Algorithm::SECP256K1_SCHNORR),
"ML_DSA_44" => Ok(Algorithm::ML_DSA_44),
"SLH_DSA_128S" => Ok(Algorithm::SLH_DSA_128S),
_ => Err(format!("Unknown algorithm string: {s}")),
}
}
}
#[cfg(feature = "serde")]
impl From<Algorithm> for String {
fn from(alg: Algorithm) -> Self {
match alg {
Algorithm::SECP256K1_SCHNORR => "SECP256K1_SCHNORR".to_string(),
Algorithm::ML_DSA_44 => "ML_DSA_44".to_string(),
Algorithm::SLH_DSA_128S => "SLH_DSA_128S".to_string(),
_ => panic!("Invalid algorithm variant"), }
}
}
impl fmt::Display for Algorithm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Algorithm::SECP256K1_SCHNORR => write!(f, "SECP256K1_SCHNORR"),
Algorithm::ML_DSA_44 => write!(f, "ML_DSA_44"),
Algorithm::SLH_DSA_128S => write!(f, "SLH_DSA_128S"),
_ => write!(f, "Unknown({:b})", self.bits),
}
}
}
impl Algorithm {
pub fn debug_name(&self) -> String {
match *self {
Algorithm::SECP256K1_SCHNORR => "SECP256K1_SCHNORR".to_string(),
Algorithm::ML_DSA_44 => "ML_DSA_44".to_string(),
Algorithm::SLH_DSA_128S => "SLH_DSA_128S".to_string(),
_ => format!("Unknown({:b})", self.bits),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct PublicKey {
#[cfg_attr(feature = "serde", serde(flatten))]
pub algorithm: Algorithm,
#[cfg_attr(feature = "serde", serde(with = "hex_bytes"))]
pub bytes: Vec<u8>,
}
impl PublicKey {
pub fn try_from_slice(algorithm: Algorithm, bytes: &[u8]) -> Result<Self, PqcError> {
let expected_len = public_key_size(algorithm);
if bytes.len() != expected_len {
return Err(PqcError::BadKey); }
if algorithm == Algorithm::SECP256K1_SCHNORR {
XOnlyPublicKey::from_slice(bytes).map_err(|_| PqcError::BadKey)?;
}
Ok(PublicKey {
algorithm,
bytes: bytes.to_vec(),
})
}
pub fn from_str(algorithm: Algorithm, s: &str) -> Result<Self, PqcError> {
let bytes = hex::decode(s).map_err(|_| PqcError::BadArgument)?;
Self::try_from_slice(algorithm, &bytes)
}
pub fn secp256k1_key(&self) -> Result<XOnlyPublicKey, PqcError> {
if self.algorithm == Algorithm::SECP256K1_SCHNORR {
XOnlyPublicKey::from_slice(&self.bytes).map_err(|_| PqcError::BadKey)
} else {
Err(PqcError::AlgorithmMismatch)
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SecretKey {
#[cfg_attr(feature = "serde", serde(flatten))]
pub algorithm: Algorithm,
#[cfg_attr(feature = "serde", serde(with = "hex_bytes"))]
pub bytes: Vec<u8>,
}
impl SecretKey {
pub fn from_str(algorithm: Algorithm, s: &str) -> Result<Self, PqcError> {
let bytes = hex::decode(s).map_err(|_| PqcError::BadArgument)?;
Self::try_from_slice(algorithm, &bytes)
}
pub fn try_from_slice(algorithm: Algorithm, bytes: &[u8]) -> Result<Self, PqcError> {
let expected_len = secret_key_size(algorithm);
if bytes.len() != expected_len {
return Err(PqcError::BadKey);
}
if algorithm == Algorithm::SECP256K1_SCHNORR {
SecpSecretKey::from_slice(bytes).map_err(|_| PqcError::BadKey)?;
}
Ok(SecretKey {
algorithm,
bytes: bytes.to_vec(),
})
}
pub fn secp256k1_key(&self) -> Result<SecpSecretKey, PqcError> {
if self.algorithm == Algorithm::SECP256K1_SCHNORR {
SecpSecretKey::from_slice(&self.bytes).map_err(|_| PqcError::BadKey)
} else {
Err(PqcError::AlgorithmMismatch)
}
}
}
impl Drop for SecretKey {
fn drop(&mut self) {
for byte in &mut self.bytes {
*byte = 0;
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Signature {
#[cfg_attr(feature = "serde", serde(flatten))]
pub algorithm: Algorithm,
#[cfg_attr(feature = "serde", serde(with = "hex_bytes"))]
pub bytes: Vec<u8>,
}
impl Signature {
pub fn try_from_slice(algorithm: Algorithm, bytes: &[u8]) -> Result<Self, PqcError> {
let expected_len = signature_size(algorithm);
if bytes.len() != expected_len {
return Err(PqcError::BadSignature);
}
if algorithm == Algorithm::SECP256K1_SCHNORR {
schnorr::Signature::from_slice(bytes).map_err(|_| PqcError::BadSignature)?;
}
Ok(Signature {
algorithm,
bytes: bytes.to_vec(),
})
}
pub fn from_str(algorithm: Algorithm, s: &str) -> Result<Self, PqcError> {
let bytes = hex::decode(s).map_err(|_| PqcError::BadArgument)?;
Self::try_from_slice(algorithm, &bytes)
}
pub fn secp256k1_signature(&self) -> Result<schnorr::Signature, PqcError> {
if self.algorithm == Algorithm::SECP256K1_SCHNORR {
schnorr::Signature::from_slice(&self.bytes).map_err(|_| PqcError::BadSignature)
} else {
Err(PqcError::AlgorithmMismatch)
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct KeyPair {
pub public_key: PublicKey,
pub secret_key: SecretKey,
}
pub fn generate_keypair(algorithm: Algorithm, random_data: &[u8]) -> Result<KeyPair, PqcError> {
if algorithm == Algorithm::SECP256K1_SCHNORR {
let required_size = secret_key_size(algorithm);
if random_data.len() < required_size {
return Err(PqcError::InsufficientData);
}
let key_data = &random_data[..required_size];
let secp = Secp256k1::<All>::new();
let sk_result = SecpSecretKey::from_slice(key_data);
let sk = sk_result.map_err(|_| PqcError::BadKey)?;
let keypair = SecpKeypair::from_secret_key(&secp, &sk);
let (pk, _parity) = XOnlyPublicKey::from_keypair(&keypair);
let public_key = PublicKey {
algorithm: Algorithm::SECP256K1_SCHNORR,
bytes: pk.serialize().to_vec(), };
let secret_key = SecretKey {
algorithm: Algorithm::SECP256K1_SCHNORR,
bytes: sk.as_ref().to_vec(), };
Ok(KeyPair {
public_key,
secret_key,
})
} else {
if random_data.len() < 128 {
return Err(PqcError::InsufficientData);
}
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 {
bitcoin_pqc_keypair_free(&mut keypair);
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);
let public_key = PublicKey {
algorithm,
bytes: pk_bytes,
};
let secret_key = SecretKey {
algorithm,
bytes: sk_bytes,
};
Ok(KeyPair {
public_key,
secret_key,
})
}
}
}
pub fn sign(secret_key: &SecretKey, message: &[u8]) -> Result<Signature, PqcError> {
match secret_key.algorithm {
Algorithm::SECP256K1_SCHNORR => {
let required_size = 32;
if message.len() < required_size {
return Err(PqcError::InsufficientData);
}
let msg_data = &message[..required_size];
let secp = Secp256k1::<All>::new();
let sk = secret_key.secp256k1_key()?;
let keypair = SecpKeypair::from_secret_key(&secp, &sk);
let schnorr_sig = secp.sign_schnorr_no_aux_rand(msg_data, &keypair);
Ok(Signature {
algorithm: Algorithm::SECP256K1_SCHNORR,
bytes: schnorr_sig.as_ref().to_vec(),
})
}
pqc_alg => {
unsafe {
let mut signature = bitcoin_pqc_signature_t {
algorithm: pqc_alg.into(),
signature: ptr::null_mut(),
signature_size: 0,
};
let result = bitcoin_pqc_sign(
pqc_alg.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: pqc_alg,
bytes: sig_bytes,
})
}
}
}
}
pub fn verify(
public_key: &PublicKey,
message: &[u8],
signature: &Signature,
) -> Result<(), PqcError> {
if public_key.algorithm != signature.algorithm {
return Err(PqcError::AlgorithmMismatch);
}
match public_key.algorithm {
Algorithm::SECP256K1_SCHNORR => {
let required_size = 32;
if message.len() < required_size {
return Err(PqcError::InsufficientData);
}
let msg_data = &message[..required_size];
let secp = Secp256k1::<secp256k1::VerifyOnly>::verification_only();
let pk = public_key.secp256k1_key()?;
let sig = signature.secp256k1_signature()?;
secp.verify_schnorr(&sig, msg_data, &pk)
.map_err(PqcError::Secp256k1Error)
}
pqc_alg => {
if public_key.bytes.len() != public_key_size(pqc_alg) {
return Err(PqcError::BadKey);
}
unsafe {
let result = bitcoin_pqc_verify(
pqc_alg.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 {
if algorithm == Algorithm::SECP256K1_SCHNORR {
32 } else {
unsafe { bitcoin_pqc_public_key_size(algorithm.into()) }
}
}
pub fn secret_key_size(algorithm: Algorithm) -> usize {
if algorithm == Algorithm::SECP256K1_SCHNORR {
32 } else {
unsafe { bitcoin_pqc_secret_key_size(algorithm.into()) }
}
}
pub fn signature_size(algorithm: Algorithm) -> usize {
if algorithm == Algorithm::SECP256K1_SCHNORR {
64 } else {
unsafe { bitcoin_pqc_signature_size(algorithm.into()) }
}
}