rxwing 0.1.0-draft11

Minimalist pure Rust implementation of the X-Wing Key Encapsulation Mechanism (draft 11)
Documentation
#[doc(inline)]
pub use crate::xwing_internal::{
    ciphertext_from_bytes, ciphertext_to_bytes, decaps, encaps, generate_keypair,
    sharedsecret_to_bytes, xwingencapskey_from_bytes, xwingencapskey_to_bytes, SHAREDSECRET,
    XWINGCIPHERTEXT, XWINGDECAPSKEY, XWINGENCAPSKEY,
};

#[cfg(test)]
#[cfg(feature = "rfctest")]
mod tests {
    use core::fmt;
    use core::fmt::Debug;
    use hybrid_array::{
        sizes::{U1088, U1120, U1184, U1216, U32, U6, U64, U96},
        Array, ArrayN,
    };
    use serde::Deserialize;
    use x25519_dalek::{PublicKey, SharedSecret, StaticSecret};

    use super::*;
    use crate::xwing_internal::{
        encaps_derand, generate_keypair_derand, xwingdecapskey_from_bytes, xwingdecapskey_to_bytes,
        CIPHERTEXT_SIZE, DECAPSULATION_KEY_SIZE, ENCAPSULATION_KEY_SIZE,
        ENCAPSULATION_RANDOMNESS_SIZE,
    };
    use rkyber::randombytes::randombytes;

    #[derive(Deserialize)]
    struct TestVector {
        #[serde(deserialize_with = "hex::serde::deserialize")]
        seed: Vec<u8>,

        #[serde(deserialize_with = "hex::serde::deserialize")]
        eseed: Vec<u8>,

        #[serde(deserialize_with = "hex::serde::deserialize")]
        ss: [u8; 32],

        #[serde(deserialize_with = "hex::serde::deserialize")]
        sk: [u8; 32],

        #[serde(deserialize_with = "hex::serde::deserialize")]
        pk: Vec<u8>, //[u8; PUBLIC_KEY_SIZE],

        #[serde(deserialize_with = "hex::serde::deserialize")]
        ct: Vec<u8>, //[u8; 1120],
    }

    /// Test with test vectors from: <https://github.com/dconnolly/draft-connolly-cfrg-xwing-kem/blob/main/spec/test-vectors.json>
    #[test]
    #[cfg(feature = "rfctest")]
    fn rfc_test_vectors() {
        let test_vectors =
            serde_json::from_str::<Vec<TestVector>>(include_str!("test-vectors.json")).unwrap();

        for test_vector in test_vectors {
            run_test(test_vector);
        }
    }

    #[cfg(feature = "rfctest")]
    fn run_test(test_vector: TestVector) {
        let seed = ArrayN::<u8, 32>::try_from(test_vector.seed.as_slice()).unwrap();
        let mut sk: XWINGDECAPSKEY = Default::default();
        let mut pk: XWINGENCAPSKEY = Default::default();
        generate_keypair_derand(&mut pk, &mut sk, (&seed).into());

        let mut dk_bytes: [u8; DECAPSULATION_KEY_SIZE] = [42; DECAPSULATION_KEY_SIZE];
        xwingdecapskey_to_bytes(&mut dk_bytes, &sk);
        assert_eq!(dk_bytes, test_vector.sk);
        let mut ek_bytes: [u8; ENCAPSULATION_KEY_SIZE] = [42; ENCAPSULATION_KEY_SIZE];
        xwingencapskey_to_bytes((&mut ek_bytes).into(), &pk);
        assert_eq!(ek_bytes, test_vector.pk.as_slice());

        let eseed =
            ArrayN::<u8, ENCAPSULATION_RANDOMNESS_SIZE>::try_from(test_vector.eseed.as_slice())
                .unwrap();
        let mut ct: XWINGCIPHERTEXT = Default::default();
        let mut ss: SHAREDSECRET = Default::default();
        encaps_derand(&mut ss, &mut ct, &pk, &eseed);

        assert_eq!(ss.ss_hat.as_slice(), test_vector.ss);
        let mut bytes: [u8; CIPHERTEXT_SIZE] = [42; CIPHERTEXT_SIZE];
        ciphertext_to_bytes((&mut bytes).into(), &ct);
        assert_eq!(bytes, *test_vector.ct.as_slice());

        decaps(&mut ss, &ct, &sk);
        assert_eq!(ss.ss_hat.as_slice(), test_vector.ss);
    }

    #[test]
    #[cfg(feature = "rfctest")]
    fn ciphertext_serialize() {
        let mut ct_a: XWINGCIPHERTEXT = Default::default();
        let mut bytes: [u8; 32] = [42; 32];
        randombytes(&mut ct_a.ct_m, 1088);
        randombytes(&mut bytes, 32);
        ct_a.ct_x = PublicKey::from(bytes);

        let mut bytes: [u8; CIPHERTEXT_SIZE] = [42; CIPHERTEXT_SIZE];
        ciphertext_to_bytes((&mut bytes).into(), &ct_a);
        let mut ct_b: XWINGCIPHERTEXT = Default::default();
        ciphertext_from_bytes(&mut ct_b, (&bytes).into());

        assert_eq!(ct_a, ct_b);
    }

    #[test]
    #[cfg(feature = "rfctest")]
    fn key_serialize() {
        let mut sk: XWINGDECAPSKEY = Default::default();
        let mut pk: XWINGENCAPSKEY = Default::default();
        generate_keypair(&mut pk, &mut sk);

        let mut sk_bytes: [u8; DECAPSULATION_KEY_SIZE] = [42; DECAPSULATION_KEY_SIZE];
        xwingdecapskey_to_bytes(&mut sk_bytes, &sk);
        let mut pk_bytes: Array<u8, U1216> = Default::default();
        xwingencapskey_to_bytes(&mut pk_bytes, &pk);

        let mut sk_b: XWINGDECAPSKEY = Default::default();
        xwingdecapskey_from_bytes(&mut sk_b, &sk_bytes);
        let mut pk_b: XWINGENCAPSKEY = Default::default();
        xwingencapskey_from_bytes(&mut pk_b, &pk_bytes);

        assert_eq!(sk, sk_b);
        assert_eq!(pk, pk_b);
    }
}