sntrup-sys 0.1.1

Streamlined NTRU Prime, extracted from SUPERCOP with a deduplicated vendor tree, compiled via the cc crate
Documentation
//! Rust FFI bindings over the extracted, deduplicated SUPERCOP Streamlined
//! NTRU Prime sources in `vendor/`. Every module wraps one parameter set,
//! all sharing one compiled copy of `vendor/common/` (see
//! `vendor/NOTICE.md` for why the split between shared and per-parameter-
//! set code is drawn where it is). Each enabled parameter set gets its own
//! module (gated by the matching Cargo feature), exposing `keypair()`,
//! `encapsulate(pk)`, and `decapsulate(c, sk)`.
//!
//! # Randomness
//!
//! The vendored C code calls a single external `randombytes` C function for
//! all key generation and encapsulation randomness. This crate implements
//! it here using `getrandom` (the OS CSPRNG), satisfying the one external
//! symbol every vendored directory expects (see vendor/NOTICE.md).

/// # Safety
///
/// `buf` must be valid for writes of `buf_len` bytes and not aliased by any
/// other live reference for the duration of this call. The vendored C code
/// upholds this by construction (it always passes a real buffer of exactly
/// `buf_len` bytes) but Rust can't verify that across the FFI boundary, so
/// the contract is on the caller, hence `unsafe fn`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn randombytes(buf: *mut u8, buf_len: u64) {
    let slice = unsafe { std::slice::from_raw_parts_mut(buf, buf_len as usize) };
    getrandom::fill(slice).expect("OS randomness source failed");
}

#[cfg(feature = "sntrup653")]
pub mod sntrup653 {
    use std::os::raw::c_int;

    pub const PUBLIC_KEY_BYTES: usize = 994;
    pub const SECRET_KEY_BYTES: usize = 1518;
    pub const CIPHERTEXT_BYTES: usize = 897;
    pub const SHARED_SECRET_BYTES: usize = 32;

    unsafe extern "C" {
        fn sntrup653_ref_crypto_kem_keypair(pk: *mut u8, sk: *mut u8) -> c_int;
        fn sntrup653_ref_crypto_kem_enc(c: *mut u8, k: *mut u8, pk: *const u8) -> c_int;
        fn sntrup653_ref_crypto_kem_dec(k: *mut u8, c: *const u8, sk: *const u8) -> c_int;
    }

    /// Generate a fresh keypair. Returns `(public_key, secret_key)`.
    pub fn keypair() -> (Vec<u8>, Vec<u8>) {
        let mut pk = vec![0u8; PUBLIC_KEY_BYTES];
        let mut sk = vec![0u8; SECRET_KEY_BYTES];
        let rc = unsafe { sntrup653_ref_crypto_kem_keypair(pk.as_mut_ptr(), sk.as_mut_ptr()) };
        assert_eq!(rc, 0, "sntrup653_ref_crypto_kem_keypair failed");
        (pk, sk)
    }

    /// Encapsulate against `pk`. Returns `(ciphertext, shared_secret)`.
    pub fn encapsulate(pk: &[u8]) -> (Vec<u8>, Vec<u8>) {
        assert_eq!(pk.len(), PUBLIC_KEY_BYTES, "invalid public key length");
        let mut c = vec![0u8; CIPHERTEXT_BYTES];
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        let rc =
            unsafe { sntrup653_ref_crypto_kem_enc(c.as_mut_ptr(), ss.as_mut_ptr(), pk.as_ptr()) };
        assert_eq!(rc, 0, "sntrup653_ref_crypto_kem_enc failed");
        (c, ss)
    }

    /// Decapsulate `c` using `sk`. Returns the shared secret.
    ///
    /// Per the Streamlined NTRU Prime KEM spec this always returns *some*
    /// 32-byte value, even for an invalid/malformed ciphertext (implicit
    /// rejection) -- it does not signal failure via the return value, by
    /// design, to avoid a decryption-failure oracle.
    pub fn decapsulate(c: &[u8], sk: &[u8]) -> Vec<u8> {
        assert_eq!(c.len(), CIPHERTEXT_BYTES, "invalid ciphertext length");
        assert_eq!(sk.len(), SECRET_KEY_BYTES, "invalid secret key length");
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        unsafe { sntrup653_ref_crypto_kem_dec(ss.as_mut_ptr(), c.as_ptr(), sk.as_ptr()) };
        ss
    }
}

#[cfg(feature = "sntrup761")]
pub mod sntrup761 {
    use std::os::raw::c_int;

    pub const PUBLIC_KEY_BYTES: usize = 1158;
    pub const SECRET_KEY_BYTES: usize = 1763;
    pub const CIPHERTEXT_BYTES: usize = 1039;
    pub const SHARED_SECRET_BYTES: usize = 32;

    unsafe extern "C" {
        fn sntrup761_ref_crypto_kem_keypair(pk: *mut u8, sk: *mut u8) -> c_int;
        fn sntrup761_ref_crypto_kem_enc(c: *mut u8, k: *mut u8, pk: *const u8) -> c_int;
        fn sntrup761_ref_crypto_kem_dec(k: *mut u8, c: *const u8, sk: *const u8) -> c_int;
    }

    /// Generate a fresh keypair. Returns `(public_key, secret_key)`.
    pub fn keypair() -> (Vec<u8>, Vec<u8>) {
        let mut pk = vec![0u8; PUBLIC_KEY_BYTES];
        let mut sk = vec![0u8; SECRET_KEY_BYTES];
        let rc = unsafe { sntrup761_ref_crypto_kem_keypair(pk.as_mut_ptr(), sk.as_mut_ptr()) };
        assert_eq!(rc, 0, "sntrup761_ref_crypto_kem_keypair failed");
        (pk, sk)
    }

    /// Encapsulate against `pk`. Returns `(ciphertext, shared_secret)`.
    pub fn encapsulate(pk: &[u8]) -> (Vec<u8>, Vec<u8>) {
        assert_eq!(pk.len(), PUBLIC_KEY_BYTES, "invalid public key length");
        let mut c = vec![0u8; CIPHERTEXT_BYTES];
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        let rc =
            unsafe { sntrup761_ref_crypto_kem_enc(c.as_mut_ptr(), ss.as_mut_ptr(), pk.as_ptr()) };
        assert_eq!(rc, 0, "sntrup761_ref_crypto_kem_enc failed");
        (c, ss)
    }

    /// Decapsulate `c` using `sk`. Returns the shared secret.
    ///
    /// Per the Streamlined NTRU Prime KEM spec this always returns *some*
    /// 32-byte value, even for an invalid/malformed ciphertext (implicit
    /// rejection) -- it does not signal failure via the return value, by
    /// design, to avoid a decryption-failure oracle.
    pub fn decapsulate(c: &[u8], sk: &[u8]) -> Vec<u8> {
        assert_eq!(c.len(), CIPHERTEXT_BYTES, "invalid ciphertext length");
        assert_eq!(sk.len(), SECRET_KEY_BYTES, "invalid secret key length");
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        unsafe { sntrup761_ref_crypto_kem_dec(ss.as_mut_ptr(), c.as_ptr(), sk.as_ptr()) };
        ss
    }
}

#[cfg(feature = "sntrup857")]
pub mod sntrup857 {
    use std::os::raw::c_int;

    pub const PUBLIC_KEY_BYTES: usize = 1322;
    pub const SECRET_KEY_BYTES: usize = 1999;
    pub const CIPHERTEXT_BYTES: usize = 1184;
    pub const SHARED_SECRET_BYTES: usize = 32;

    unsafe extern "C" {
        fn sntrup857_ref_crypto_kem_keypair(pk: *mut u8, sk: *mut u8) -> c_int;
        fn sntrup857_ref_crypto_kem_enc(c: *mut u8, k: *mut u8, pk: *const u8) -> c_int;
        fn sntrup857_ref_crypto_kem_dec(k: *mut u8, c: *const u8, sk: *const u8) -> c_int;
    }

    /// Generate a fresh keypair. Returns `(public_key, secret_key)`.
    pub fn keypair() -> (Vec<u8>, Vec<u8>) {
        let mut pk = vec![0u8; PUBLIC_KEY_BYTES];
        let mut sk = vec![0u8; SECRET_KEY_BYTES];
        let rc = unsafe { sntrup857_ref_crypto_kem_keypair(pk.as_mut_ptr(), sk.as_mut_ptr()) };
        assert_eq!(rc, 0, "sntrup857_ref_crypto_kem_keypair failed");
        (pk, sk)
    }

    /// Encapsulate against `pk`. Returns `(ciphertext, shared_secret)`.
    pub fn encapsulate(pk: &[u8]) -> (Vec<u8>, Vec<u8>) {
        assert_eq!(pk.len(), PUBLIC_KEY_BYTES, "invalid public key length");
        let mut c = vec![0u8; CIPHERTEXT_BYTES];
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        let rc =
            unsafe { sntrup857_ref_crypto_kem_enc(c.as_mut_ptr(), ss.as_mut_ptr(), pk.as_ptr()) };
        assert_eq!(rc, 0, "sntrup857_ref_crypto_kem_enc failed");
        (c, ss)
    }

    /// Decapsulate `c` using `sk`. Returns the shared secret.
    ///
    /// Per the Streamlined NTRU Prime KEM spec this always returns *some*
    /// 32-byte value, even for an invalid/malformed ciphertext (implicit
    /// rejection) -- it does not signal failure via the return value, by
    /// design, to avoid a decryption-failure oracle.
    pub fn decapsulate(c: &[u8], sk: &[u8]) -> Vec<u8> {
        assert_eq!(c.len(), CIPHERTEXT_BYTES, "invalid ciphertext length");
        assert_eq!(sk.len(), SECRET_KEY_BYTES, "invalid secret key length");
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        unsafe { sntrup857_ref_crypto_kem_dec(ss.as_mut_ptr(), c.as_ptr(), sk.as_ptr()) };
        ss
    }
}

#[cfg(feature = "sntrup953")]
pub mod sntrup953 {
    use std::os::raw::c_int;

    pub const PUBLIC_KEY_BYTES: usize = 1505;
    pub const SECRET_KEY_BYTES: usize = 2254;
    pub const CIPHERTEXT_BYTES: usize = 1349;
    pub const SHARED_SECRET_BYTES: usize = 32;

    unsafe extern "C" {
        fn sntrup953_ref_crypto_kem_keypair(pk: *mut u8, sk: *mut u8) -> c_int;
        fn sntrup953_ref_crypto_kem_enc(c: *mut u8, k: *mut u8, pk: *const u8) -> c_int;
        fn sntrup953_ref_crypto_kem_dec(k: *mut u8, c: *const u8, sk: *const u8) -> c_int;
    }

    /// Generate a fresh keypair. Returns `(public_key, secret_key)`.
    pub fn keypair() -> (Vec<u8>, Vec<u8>) {
        let mut pk = vec![0u8; PUBLIC_KEY_BYTES];
        let mut sk = vec![0u8; SECRET_KEY_BYTES];
        let rc = unsafe { sntrup953_ref_crypto_kem_keypair(pk.as_mut_ptr(), sk.as_mut_ptr()) };
        assert_eq!(rc, 0, "sntrup953_ref_crypto_kem_keypair failed");
        (pk, sk)
    }

    /// Encapsulate against `pk`. Returns `(ciphertext, shared_secret)`.
    pub fn encapsulate(pk: &[u8]) -> (Vec<u8>, Vec<u8>) {
        assert_eq!(pk.len(), PUBLIC_KEY_BYTES, "invalid public key length");
        let mut c = vec![0u8; CIPHERTEXT_BYTES];
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        let rc =
            unsafe { sntrup953_ref_crypto_kem_enc(c.as_mut_ptr(), ss.as_mut_ptr(), pk.as_ptr()) };
        assert_eq!(rc, 0, "sntrup953_ref_crypto_kem_enc failed");
        (c, ss)
    }

    /// Decapsulate `c` using `sk`. Returns the shared secret.
    ///
    /// Per the Streamlined NTRU Prime KEM spec this always returns *some*
    /// 32-byte value, even for an invalid/malformed ciphertext (implicit
    /// rejection) -- it does not signal failure via the return value, by
    /// design, to avoid a decryption-failure oracle.
    pub fn decapsulate(c: &[u8], sk: &[u8]) -> Vec<u8> {
        assert_eq!(c.len(), CIPHERTEXT_BYTES, "invalid ciphertext length");
        assert_eq!(sk.len(), SECRET_KEY_BYTES, "invalid secret key length");
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        unsafe { sntrup953_ref_crypto_kem_dec(ss.as_mut_ptr(), c.as_ptr(), sk.as_ptr()) };
        ss
    }
}

#[cfg(feature = "sntrup1013")]
pub mod sntrup1013 {
    use std::os::raw::c_int;

    pub const PUBLIC_KEY_BYTES: usize = 1623;
    pub const SECRET_KEY_BYTES: usize = 2417;
    pub const CIPHERTEXT_BYTES: usize = 1455;
    pub const SHARED_SECRET_BYTES: usize = 32;

    unsafe extern "C" {
        fn sntrup1013_ref_crypto_kem_keypair(pk: *mut u8, sk: *mut u8) -> c_int;
        fn sntrup1013_ref_crypto_kem_enc(c: *mut u8, k: *mut u8, pk: *const u8) -> c_int;
        fn sntrup1013_ref_crypto_kem_dec(k: *mut u8, c: *const u8, sk: *const u8) -> c_int;
    }

    /// Generate a fresh keypair. Returns `(public_key, secret_key)`.
    pub fn keypair() -> (Vec<u8>, Vec<u8>) {
        let mut pk = vec![0u8; PUBLIC_KEY_BYTES];
        let mut sk = vec![0u8; SECRET_KEY_BYTES];
        let rc = unsafe { sntrup1013_ref_crypto_kem_keypair(pk.as_mut_ptr(), sk.as_mut_ptr()) };
        assert_eq!(rc, 0, "sntrup1013_ref_crypto_kem_keypair failed");
        (pk, sk)
    }

    /// Encapsulate against `pk`. Returns `(ciphertext, shared_secret)`.
    pub fn encapsulate(pk: &[u8]) -> (Vec<u8>, Vec<u8>) {
        assert_eq!(pk.len(), PUBLIC_KEY_BYTES, "invalid public key length");
        let mut c = vec![0u8; CIPHERTEXT_BYTES];
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        let rc =
            unsafe { sntrup1013_ref_crypto_kem_enc(c.as_mut_ptr(), ss.as_mut_ptr(), pk.as_ptr()) };
        assert_eq!(rc, 0, "sntrup1013_ref_crypto_kem_enc failed");
        (c, ss)
    }

    /// Decapsulate `c` using `sk`. Returns the shared secret.
    ///
    /// Per the Streamlined NTRU Prime KEM spec this always returns *some*
    /// 32-byte value, even for an invalid/malformed ciphertext (implicit
    /// rejection) -- it does not signal failure via the return value, by
    /// design, to avoid a decryption-failure oracle.
    pub fn decapsulate(c: &[u8], sk: &[u8]) -> Vec<u8> {
        assert_eq!(c.len(), CIPHERTEXT_BYTES, "invalid ciphertext length");
        assert_eq!(sk.len(), SECRET_KEY_BYTES, "invalid secret key length");
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        unsafe { sntrup1013_ref_crypto_kem_dec(ss.as_mut_ptr(), c.as_ptr(), sk.as_ptr()) };
        ss
    }
}

#[cfg(feature = "sntrup1277")]
pub mod sntrup1277 {
    use std::os::raw::c_int;

    pub const PUBLIC_KEY_BYTES: usize = 2067;
    pub const SECRET_KEY_BYTES: usize = 3059;
    pub const CIPHERTEXT_BYTES: usize = 1847;
    pub const SHARED_SECRET_BYTES: usize = 32;

    unsafe extern "C" {
        fn sntrup1277_ref_crypto_kem_keypair(pk: *mut u8, sk: *mut u8) -> c_int;
        fn sntrup1277_ref_crypto_kem_enc(c: *mut u8, k: *mut u8, pk: *const u8) -> c_int;
        fn sntrup1277_ref_crypto_kem_dec(k: *mut u8, c: *const u8, sk: *const u8) -> c_int;
    }

    /// Generate a fresh keypair. Returns `(public_key, secret_key)`.
    pub fn keypair() -> (Vec<u8>, Vec<u8>) {
        let mut pk = vec![0u8; PUBLIC_KEY_BYTES];
        let mut sk = vec![0u8; SECRET_KEY_BYTES];
        let rc = unsafe { sntrup1277_ref_crypto_kem_keypair(pk.as_mut_ptr(), sk.as_mut_ptr()) };
        assert_eq!(rc, 0, "sntrup1277_ref_crypto_kem_keypair failed");
        (pk, sk)
    }

    /// Encapsulate against `pk`. Returns `(ciphertext, shared_secret)`.
    pub fn encapsulate(pk: &[u8]) -> (Vec<u8>, Vec<u8>) {
        assert_eq!(pk.len(), PUBLIC_KEY_BYTES, "invalid public key length");
        let mut c = vec![0u8; CIPHERTEXT_BYTES];
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        let rc =
            unsafe { sntrup1277_ref_crypto_kem_enc(c.as_mut_ptr(), ss.as_mut_ptr(), pk.as_ptr()) };
        assert_eq!(rc, 0, "sntrup1277_ref_crypto_kem_enc failed");
        (c, ss)
    }

    /// Decapsulate `c` using `sk`. Returns the shared secret.
    ///
    /// Per the Streamlined NTRU Prime KEM spec this always returns *some*
    /// 32-byte value, even for an invalid/malformed ciphertext (implicit
    /// rejection) -- it does not signal failure via the return value, by
    /// design, to avoid a decryption-failure oracle.
    pub fn decapsulate(c: &[u8], sk: &[u8]) -> Vec<u8> {
        assert_eq!(c.len(), CIPHERTEXT_BYTES, "invalid ciphertext length");
        assert_eq!(sk.len(), SECRET_KEY_BYTES, "invalid secret key length");
        let mut ss = vec![0u8; SHARED_SECRET_BYTES];
        unsafe { sntrup1277_ref_crypto_kem_dec(ss.as_mut_ptr(), c.as_ptr(), sk.as_ptr()) };
        ss
    }
}