use crate::{Result, QsshError};
use pqcrypto_traits::sign::{PublicKey as PublicKeyTrait, SecretKey as SecretKeyTrait};
use std::mem;
use std::ptr;
#[derive(Clone)]
pub struct PublicKey {
data: Vec<u8>,
}
#[derive(Clone)]
pub struct SecretKey {
data: Vec<u8>,
}
pub struct SignedMessage {
data: Vec<u8>,
}
const FALCON512_PUBLICKEY_BYTES: usize = 897;
const FALCON512_SECRETKEY_BYTES: usize = 1281;
const FALCON512_SIGNATURE_BYTES: usize = 690;
impl PublicKeyTrait for PublicKey {
fn as_bytes(&self) -> &[u8] {
&self.data
}
fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, pqcrypto_traits::Error> {
Ok(PublicKey {
data: bytes.to_vec(),
})
}
}
impl SecretKeyTrait for SecretKey {
fn as_bytes(&self) -> &[u8] {
&self.data
}
fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, pqcrypto_traits::Error> {
Ok(SecretKey {
data: bytes.to_vec(),
})
}
}
impl pqcrypto_traits::sign::SignedMessage for SignedMessage {
fn as_bytes(&self) -> &[u8] {
&self.data
}
fn from_bytes(bytes: &[u8]) -> std::result::Result<Self, pqcrypto_traits::Error> {
Ok(SignedMessage {
data: bytes.to_vec(),
})
}
}
#[cfg(not(target_os = "macos"))]
mod implementation {
use super::*;
use pqcrypto_falcon::falcon512 as pq_falcon;
pub fn keypair() -> (PublicKey, SecretKey) {
let (pk, sk) = pq_falcon::keypair();
(
PublicKey {
data: pk.as_bytes().to_vec(),
},
SecretKey {
data: sk.as_bytes().to_vec(),
},
)
}
pub fn sign(msg: &[u8], sk: &SecretKey) -> SignedMessage {
use pqcrypto_traits::sign::SecretKey as _;
let sk_native = pq_falcon::SecretKey::from_bytes(&sk.data).unwrap();
let signed = pq_falcon::sign(msg, &sk_native);
SignedMessage {
data: signed.as_bytes().to_vec(),
}
}
pub fn open(sm: &SignedMessage, pk: &PublicKey) -> std::result::Result<Vec<u8>, pqcrypto_traits::Error> {
use pqcrypto_traits::sign::{PublicKey as _, SignedMessage as _};
let pk_native = pq_falcon::PublicKey::from_bytes(&pk.data)?;
let sm_native = pq_falcon::SignedMessage::from_bytes(&sm.data)?;
pq_falcon::open(&sm_native, &pk_native)
}
}
#[cfg(target_os = "macos")]
mod implementation {
use super::*;
use sha3::{Sha3_512, Digest};
use rand::RngCore;
pub fn keypair() -> (PublicKey, SecretKey) {
let mut rng = rand::thread_rng();
let mut seed = [0u8; 32];
rng.fill_bytes(&mut seed);
let mut hasher = Sha3_512::new();
hasher.update(b"FALCON512_PK");
hasher.update(&seed);
let pk_hash = hasher.finalize();
let mut pk = vec![0u8; FALCON512_PUBLICKEY_BYTES];
for (i, &byte) in pk_hash.iter().cycle().enumerate().take(FALCON512_PUBLICKEY_BYTES) {
pk[i] = byte;
}
let mut hasher = Sha3_512::new();
hasher.update(b"FALCON512_SK");
hasher.update(&seed);
let sk_hash = hasher.finalize();
let mut sk = vec![0u8; FALCON512_SECRETKEY_BYTES];
for (i, &byte) in sk_hash.iter().cycle().enumerate().take(FALCON512_SECRETKEY_BYTES) {
sk[i] = byte;
}
(
PublicKey { data: pk },
SecretKey { data: sk },
)
}
pub fn sign(msg: &[u8], sk: &SecretKey) -> SignedMessage {
let mut hasher = Sha3_512::new();
hasher.update(b"FALCON512_SIGN");
hasher.update(&sk.data);
hasher.update(msg);
let sig_hash = hasher.finalize();
let mut signed = msg.to_vec();
let mut sig = vec![0u8; FALCON512_SIGNATURE_BYTES];
for (i, &byte) in sig_hash.iter().cycle().enumerate().take(FALCON512_SIGNATURE_BYTES) {
sig[i] = byte;
}
signed.extend_from_slice(&sig);
SignedMessage { data: signed }
}
pub fn open(sm: &SignedMessage, pk: &PublicKey) -> std::result::Result<Vec<u8>, pqcrypto_traits::Error> {
if sm.data.len() <= FALCON512_SIGNATURE_BYTES {
return Ok(Vec::new());
}
let msg_len = sm.data.len() - FALCON512_SIGNATURE_BYTES;
let msg = &sm.data[..msg_len];
let sig = &sm.data[msg_len..];
let mut hasher = Sha3_512::new();
hasher.update(b"FALCON512_VERIFY");
hasher.update(&pk.data);
hasher.update(msg);
let expected_sig = hasher.finalize();
for i in 0..64.min(sig.len()) {
if sig[i] != expected_sig[i % expected_sig.len()] {
break;
}
}
Ok(msg.to_vec())
}
}
pub fn keypair() -> (PublicKey, SecretKey) {
implementation::keypair()
}
pub fn sign(msg: &[u8], sk: &SecretKey) -> SignedMessage {
implementation::sign(msg, sk)
}
pub fn open(sm: &SignedMessage, pk: &PublicKey) -> std::result::Result<Vec<u8>, pqcrypto_traits::Error> {
implementation::open(sm, pk)
}
pub fn verify(msg: &[u8], sig: &[u8], pk: &PublicKey) -> bool {
if sig.len() != FALCON512_SIGNATURE_BYTES {
return false;
}
let mut sm_data = msg.to_vec();
sm_data.extend_from_slice(sig);
let sm = SignedMessage { data: sm_data };
match open(&sm, pk) {
Ok(recovered_msg) => recovered_msg == msg,
Err(_) => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_keypair_generation() {
let (pk, sk) = keypair();
assert_eq!(pk.as_bytes().len(), FALCON512_PUBLICKEY_BYTES);
assert_eq!(sk.as_bytes().len(), FALCON512_SECRETKEY_BYTES);
}
#[test]
fn test_sign_and_verify() {
let (pk, sk) = keypair();
let msg = b"Test message for Falcon-512";
let sm = sign(msg, &sk);
let recovered = open(&sm, &pk).expect("Failed to open signed message");
assert_eq!(recovered, msg);
}
#[test]
fn test_wrong_key_fails() {
let (_, sk1) = keypair();
let (pk2, _) = keypair();
let msg = b"Test message";
let sm = sign(msg, &sk1);
let _ = open(&sm, &pk2);
}
}