Skip to main content

tafrah_uniffi/
lib.rs

1use rand::rngs::ThreadRng;
2use tafrah_falcon::params::{FALCON_1024, FALCON_512};
3use tafrah_falcon::types::{
4    Signature as FalconSignature, SigningKey as FalconSigningKey,
5    VerifyingKey as FalconVerifyingKey,
6};
7use tafrah_hqc::types::{
8    Ciphertext as HqcCiphertext, DecapsulationKey as HqcDecapsulationKey,
9    EncapsulationKey as HqcEncapsulationKey,
10};
11use tafrah_ml_dsa::params::ML_DSA_65;
12use tafrah_ml_dsa::types::{
13    Signature as MlDsaSignature, SigningKey as MlDsaSigningKey, VerifyingKey as MlDsaVerifyingKey,
14};
15use tafrah_ml_kem::params::ML_KEM_768;
16use tafrah_ml_kem::types::{
17    Ciphertext as MlKemCiphertext, DecapsulationKey as MlKemDecapsulationKey,
18    EncapsulationKey as MlKemEncapsulationKey,
19};
20use tafrah_slh_dsa::params::SLH_DSA_SHAKE_128F;
21use tafrah_slh_dsa::types::{
22    Signature as SlhDsaSignature, SigningKey as SlhDsaSigningKey,
23    VerifyingKey as SlhDsaVerifyingKey,
24};
25use tafrah_traits::Error;
26
27uniffi::setup_scaffolding!();
28
29#[derive(Debug, Clone, uniffi::Record)]
30pub struct KemKeypair {
31    pub encapsulation_key: Vec<u8>,
32    pub decapsulation_key: Vec<u8>,
33}
34
35#[derive(Debug, Clone, uniffi::Record)]
36pub struct SignatureKeypair {
37    pub verifying_key: Vec<u8>,
38    pub signing_key: Vec<u8>,
39}
40
41#[derive(Debug, Clone, uniffi::Record)]
42pub struct EncapsulationResult {
43    pub ciphertext: Vec<u8>,
44    pub shared_secret: Vec<u8>,
45}
46
47#[derive(Debug, Clone, Copy, uniffi::Record)]
48pub struct SchemeSizes {
49    pub public_key_bytes: u64,
50    pub secret_key_bytes: u64,
51    pub ciphertext_or_signature_bytes: u64,
52    pub shared_secret_bytes: u64,
53}
54
55#[derive(Debug, Clone, uniffi::Error)]
56#[uniffi(flat_error)]
57pub enum UniFfiError {
58    InvalidKeyLength,
59    InvalidCiphertextLength,
60    InvalidSignatureLength,
61    InvalidParameter,
62    InternalError(String),
63    NotImplemented,
64}
65
66impl core::fmt::Display for UniFfiError {
67    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
68        match self {
69            Self::InvalidKeyLength => f.write_str("invalid key length"),
70            Self::InvalidCiphertextLength => f.write_str("invalid ciphertext length"),
71            Self::InvalidSignatureLength => f.write_str("invalid signature length"),
72            Self::InvalidParameter => f.write_str("invalid parameter"),
73            Self::InternalError(message) => f.write_str(message),
74            Self::NotImplemented => f.write_str("not implemented"),
75        }
76    }
77}
78
79impl std::error::Error for UniFfiError {}
80
81impl From<Error> for UniFfiError {
82    fn from(err: Error) -> Self {
83        match err {
84            Error::InvalidKeyLength => Self::InvalidKeyLength,
85            Error::InvalidCiphertextLength => Self::InvalidCiphertextLength,
86            Error::InvalidSignatureLength => Self::InvalidSignatureLength,
87            Error::InvalidParameter => Self::InvalidParameter,
88            Error::VerificationFailed => Self::InternalError("verification failed".to_owned()),
89            Error::DecodingError => Self::InternalError("decoding error".to_owned()),
90            Error::RngError => Self::InternalError("rng error".to_owned()),
91            Error::NotImplemented => Self::NotImplemented,
92        }
93    }
94}
95
96fn ml_kem_keypair() -> KemKeypair {
97    let mut rng = rand::rng();
98    let (ek, dk) = tafrah_ml_kem::ml_kem_768::keygen(&mut rng);
99    KemKeypair {
100        encapsulation_key: ek.as_bytes().to_vec(),
101        decapsulation_key: dk.as_bytes().to_vec(),
102    }
103}
104
105fn hqc_keypair(
106    keygen: impl FnOnce(&mut ThreadRng) -> Result<(HqcEncapsulationKey, HqcDecapsulationKey), Error>,
107) -> Result<KemKeypair, UniFfiError> {
108    let mut rng = rand::rng();
109    let (ek, dk) = keygen(&mut rng)?;
110    Ok(KemKeypair {
111        encapsulation_key: ek.as_bytes().to_vec(),
112        decapsulation_key: dk.as_bytes().to_vec(),
113    })
114}
115
116fn hqc_encapsulation(
117    ek: Vec<u8>,
118    encapsulate: impl FnOnce(
119        &HqcEncapsulationKey,
120        &mut ThreadRng,
121    ) -> Result<(HqcCiphertext, tafrah_hqc::types::SharedSecret), Error>,
122) -> Result<EncapsulationResult, UniFfiError> {
123    let ek = HqcEncapsulationKey::from_bytes(ek);
124    let mut rng = rand::rng();
125    let (ct, ss) = encapsulate(&ek, &mut rng)?;
126    Ok(EncapsulationResult {
127        ciphertext: ct.as_bytes().to_vec(),
128        shared_secret: ss.as_bytes().to_vec(),
129    })
130}
131
132fn hqc_decapsulation(
133    dk: Vec<u8>,
134    ct: Vec<u8>,
135    decapsulate: impl FnOnce(
136        &HqcDecapsulationKey,
137        &HqcCiphertext,
138    ) -> Result<tafrah_hqc::types::SharedSecret, Error>,
139) -> Result<Vec<u8>, UniFfiError> {
140    let dk = HqcDecapsulationKey::from_bytes(dk);
141    let ct = HqcCiphertext::from_bytes(ct);
142    let ss = decapsulate(&dk, &ct)?;
143    Ok(ss.as_bytes().to_vec())
144}
145
146fn ml_dsa_keypair() -> SignatureKeypair {
147    let mut rng = rand::rng();
148    let (vk, sk) = tafrah_ml_dsa::ml_dsa_65::keygen(&mut rng);
149    SignatureKeypair {
150        verifying_key: vk.as_bytes().to_vec(),
151        signing_key: sk.as_bytes().to_vec(),
152    }
153}
154
155fn slh_dsa_keypair() -> SignatureKeypair {
156    let mut rng = rand::rng();
157    let (vk, sk) = tafrah_slh_dsa::keygen::slh_dsa_keygen(&mut rng, &SLH_DSA_SHAKE_128F)
158        .expect("fixed SLH-DSA parameter set must remain valid");
159    SignatureKeypair {
160        verifying_key: vk.as_bytes().to_vec(),
161        signing_key: sk.as_bytes().to_vec(),
162    }
163}
164
165fn falcon_keypair(
166    keygen: impl FnOnce(&mut ThreadRng) -> Result<(FalconVerifyingKey, FalconSigningKey), Error>,
167) -> Result<SignatureKeypair, UniFfiError> {
168    let mut rng = rand::rng();
169    let (vk, sk) = keygen(&mut rng)?;
170    Ok(SignatureKeypair {
171        verifying_key: vk.as_bytes().to_vec(),
172        signing_key: sk.as_bytes().to_vec(),
173    })
174}
175
176#[uniffi::export]
177pub fn version() -> String {
178    "tafrah-uniffi/0.1.7".to_owned()
179}
180
181#[uniffi::export]
182pub fn supported_algorithms() -> Vec<String> {
183    vec![
184        "ML-KEM-768".to_owned(),
185        "ML-DSA-65".to_owned(),
186        "SLH-DSA-SHAKE-128f".to_owned(),
187        "Falcon-512".to_owned(),
188        "Falcon-1024".to_owned(),
189        "HQC-128".to_owned(),
190        "HQC-192".to_owned(),
191        "HQC-256".to_owned(),
192    ]
193}
194
195#[uniffi::export]
196pub fn ml_kem_768_sizes() -> SchemeSizes {
197    SchemeSizes {
198        public_key_bytes: ML_KEM_768.ek_size() as u64,
199        secret_key_bytes: ML_KEM_768.dk_size() as u64,
200        ciphertext_or_signature_bytes: ML_KEM_768.ct_size() as u64,
201        shared_secret_bytes: 32,
202    }
203}
204
205#[uniffi::export]
206pub fn ml_kem_768_keygen() -> KemKeypair {
207    ml_kem_keypair()
208}
209
210#[uniffi::export]
211pub fn ml_kem_768_encapsulate(ek: Vec<u8>) -> Result<EncapsulationResult, UniFfiError> {
212    let ek = MlKemEncapsulationKey::from_bytes(ek);
213    let mut rng = rand::rng();
214    let (ct, ss) = tafrah_ml_kem::ml_kem_768::encapsulate(&ek, &mut rng)?;
215    Ok(EncapsulationResult {
216        ciphertext: ct.as_bytes().to_vec(),
217        shared_secret: ss.as_bytes().to_vec(),
218    })
219}
220
221#[uniffi::export]
222pub fn ml_kem_768_decapsulate(dk: Vec<u8>, ct: Vec<u8>) -> Result<Vec<u8>, UniFfiError> {
223    let dk = MlKemDecapsulationKey::from_bytes(dk);
224    let ct = MlKemCiphertext::from_bytes(ct);
225    let ss = tafrah_ml_kem::ml_kem_768::decapsulate(&dk, &ct)?;
226    Ok(ss.as_bytes().to_vec())
227}
228
229#[uniffi::export]
230pub fn ml_dsa_65_sizes() -> SchemeSizes {
231    SchemeSizes {
232        public_key_bytes: ML_DSA_65.vk_size() as u64,
233        secret_key_bytes: ML_DSA_65.sk_size() as u64,
234        ciphertext_or_signature_bytes: ML_DSA_65.sig_size() as u64,
235        shared_secret_bytes: 0,
236    }
237}
238
239#[uniffi::export]
240pub fn ml_dsa_65_keygen() -> SignatureKeypair {
241    ml_dsa_keypair()
242}
243
244#[uniffi::export]
245pub fn ml_dsa_65_sign(sk: Vec<u8>, message: Vec<u8>) -> Result<Vec<u8>, UniFfiError> {
246    let sk = MlDsaSigningKey::from_bytes(sk);
247    let mut rng = rand::rng();
248    let sig = tafrah_ml_dsa::ml_dsa_65::sign_with_context(&sk, &message, &[], &mut rng)?;
249    Ok(sig.as_bytes().to_vec())
250}
251
252#[uniffi::export]
253pub fn ml_dsa_65_verify(vk: Vec<u8>, message: Vec<u8>, sig: Vec<u8>) -> Result<bool, UniFfiError> {
254    let vk = MlDsaVerifyingKey::from_bytes(vk);
255    let sig = MlDsaSignature::from_bytes(sig);
256    match tafrah_ml_dsa::ml_dsa_65::verify_with_context(&vk, &message, &sig, &[]) {
257        Ok(()) => Ok(true),
258        Err(Error::VerificationFailed) => Ok(false),
259        Err(err) => Err(err.into()),
260    }
261}
262
263#[uniffi::export]
264pub fn slh_dsa_shake_128f_sizes() -> SchemeSizes {
265    SchemeSizes {
266        public_key_bytes: SLH_DSA_SHAKE_128F.pk_bytes as u64,
267        secret_key_bytes: SLH_DSA_SHAKE_128F.sk_bytes as u64,
268        ciphertext_or_signature_bytes: SLH_DSA_SHAKE_128F.sig_bytes as u64,
269        shared_secret_bytes: 0,
270    }
271}
272
273#[uniffi::export]
274pub fn slh_dsa_shake_128f_keygen() -> SignatureKeypair {
275    slh_dsa_keypair()
276}
277
278#[uniffi::export]
279pub fn slh_dsa_shake_128f_sign(sk: Vec<u8>, message: Vec<u8>) -> Result<Vec<u8>, UniFfiError> {
280    let sk = SlhDsaSigningKey::from_bytes(sk);
281    let mut rng = rand::rng();
282    let sig = tafrah_slh_dsa::sign::slh_dsa_sign(&sk, &message, &mut rng, &SLH_DSA_SHAKE_128F)?;
283    Ok(sig.as_bytes().to_vec())
284}
285
286#[uniffi::export]
287pub fn slh_dsa_shake_128f_verify(
288    vk: Vec<u8>,
289    message: Vec<u8>,
290    sig: Vec<u8>,
291) -> Result<bool, UniFfiError> {
292    let vk = SlhDsaVerifyingKey::from_bytes(vk);
293    let sig = SlhDsaSignature::from_bytes(sig);
294    match tafrah_slh_dsa::verify::slh_dsa_verify(&vk, &message, &sig, &SLH_DSA_SHAKE_128F) {
295        Ok(()) => Ok(true),
296        Err(Error::VerificationFailed) => Ok(false),
297        Err(err) => Err(err.into()),
298    }
299}
300
301#[uniffi::export]
302pub fn falcon_512_sizes() -> SchemeSizes {
303    SchemeSizes {
304        public_key_bytes: FALCON_512.pk_bytes as u64,
305        secret_key_bytes: FALCON_512.sk_bytes as u64,
306        ciphertext_or_signature_bytes: FALCON_512.sig_max_bytes as u64,
307        shared_secret_bytes: 0,
308    }
309}
310
311#[uniffi::export]
312pub fn falcon_512_keygen() -> Result<SignatureKeypair, UniFfiError> {
313    falcon_keypair(tafrah_falcon::falcon_512::keygen)
314}
315
316#[uniffi::export]
317pub fn falcon_512_sign(sk: Vec<u8>, message: Vec<u8>) -> Result<Vec<u8>, UniFfiError> {
318    let sk = FalconSigningKey::from_bytes(sk);
319    let mut rng = rand::rng();
320    let sig = tafrah_falcon::falcon_512::sign(&sk, &message, &mut rng)?;
321    Ok(sig.as_bytes().to_vec())
322}
323
324#[uniffi::export]
325pub fn falcon_512_verify(vk: Vec<u8>, message: Vec<u8>, sig: Vec<u8>) -> Result<bool, UniFfiError> {
326    let vk = FalconVerifyingKey::from_bytes(vk);
327    let sig = FalconSignature::from_bytes(sig);
328    match tafrah_falcon::falcon_512::verify(&vk, &message, &sig) {
329        Ok(()) => Ok(true),
330        Err(Error::VerificationFailed) => Ok(false),
331        Err(err) => Err(err.into()),
332    }
333}
334
335#[uniffi::export]
336pub fn falcon_1024_sizes() -> SchemeSizes {
337    SchemeSizes {
338        public_key_bytes: FALCON_1024.pk_bytes as u64,
339        secret_key_bytes: FALCON_1024.sk_bytes as u64,
340        ciphertext_or_signature_bytes: FALCON_1024.sig_max_bytes as u64,
341        shared_secret_bytes: 0,
342    }
343}
344
345#[uniffi::export]
346pub fn falcon_1024_keygen() -> Result<SignatureKeypair, UniFfiError> {
347    falcon_keypair(tafrah_falcon::falcon_1024::keygen)
348}
349
350#[uniffi::export]
351pub fn falcon_1024_sign(sk: Vec<u8>, message: Vec<u8>) -> Result<Vec<u8>, UniFfiError> {
352    let sk = FalconSigningKey::from_bytes(sk);
353    let mut rng = rand::rng();
354    let sig = tafrah_falcon::falcon_1024::sign(&sk, &message, &mut rng)?;
355    Ok(sig.as_bytes().to_vec())
356}
357
358#[uniffi::export]
359pub fn falcon_1024_verify(
360    vk: Vec<u8>,
361    message: Vec<u8>,
362    sig: Vec<u8>,
363) -> Result<bool, UniFfiError> {
364    let vk = FalconVerifyingKey::from_bytes(vk);
365    let sig = FalconSignature::from_bytes(sig);
366    match tafrah_falcon::falcon_1024::verify(&vk, &message, &sig) {
367        Ok(()) => Ok(true),
368        Err(Error::VerificationFailed) => Ok(false),
369        Err(err) => Err(err.into()),
370    }
371}
372
373#[uniffi::export]
374pub fn hqc_128_sizes() -> SchemeSizes {
375    SchemeSizes {
376        public_key_bytes: tafrah_hqc::params::HQC_128.pk_bytes as u64,
377        secret_key_bytes: tafrah_hqc::params::HQC_128.sk_bytes as u64,
378        ciphertext_or_signature_bytes: tafrah_hqc::params::HQC_128.ct_bytes as u64,
379        shared_secret_bytes: tafrah_hqc::params::HQC_128.ss_bytes as u64,
380    }
381}
382
383#[uniffi::export]
384pub fn hqc_128_keygen() -> Result<KemKeypair, UniFfiError> {
385    hqc_keypair(tafrah_hqc::hqc_128::keygen)
386}
387
388#[uniffi::export]
389pub fn hqc_128_encapsulate(ek: Vec<u8>) -> Result<EncapsulationResult, UniFfiError> {
390    hqc_encapsulation(ek, tafrah_hqc::hqc_128::encapsulate)
391}
392
393#[uniffi::export]
394pub fn hqc_128_decapsulate(dk: Vec<u8>, ct: Vec<u8>) -> Result<Vec<u8>, UniFfiError> {
395    hqc_decapsulation(dk, ct, tafrah_hqc::hqc_128::decapsulate)
396}
397
398#[uniffi::export]
399pub fn hqc_192_sizes() -> SchemeSizes {
400    SchemeSizes {
401        public_key_bytes: tafrah_hqc::params::HQC_192.pk_bytes as u64,
402        secret_key_bytes: tafrah_hqc::params::HQC_192.sk_bytes as u64,
403        ciphertext_or_signature_bytes: tafrah_hqc::params::HQC_192.ct_bytes as u64,
404        shared_secret_bytes: tafrah_hqc::params::HQC_192.ss_bytes as u64,
405    }
406}
407
408#[uniffi::export]
409pub fn hqc_192_keygen() -> Result<KemKeypair, UniFfiError> {
410    hqc_keypair(tafrah_hqc::hqc_192::keygen)
411}
412
413#[uniffi::export]
414pub fn hqc_192_encapsulate(ek: Vec<u8>) -> Result<EncapsulationResult, UniFfiError> {
415    hqc_encapsulation(ek, tafrah_hqc::hqc_192::encapsulate)
416}
417
418#[uniffi::export]
419pub fn hqc_192_decapsulate(dk: Vec<u8>, ct: Vec<u8>) -> Result<Vec<u8>, UniFfiError> {
420    hqc_decapsulation(dk, ct, tafrah_hqc::hqc_192::decapsulate)
421}
422
423#[uniffi::export]
424pub fn hqc_256_sizes() -> SchemeSizes {
425    SchemeSizes {
426        public_key_bytes: tafrah_hqc::params::HQC_256.pk_bytes as u64,
427        secret_key_bytes: tafrah_hqc::params::HQC_256.sk_bytes as u64,
428        ciphertext_or_signature_bytes: tafrah_hqc::params::HQC_256.ct_bytes as u64,
429        shared_secret_bytes: tafrah_hqc::params::HQC_256.ss_bytes as u64,
430    }
431}
432
433#[uniffi::export]
434pub fn hqc_256_keygen() -> Result<KemKeypair, UniFfiError> {
435    hqc_keypair(tafrah_hqc::hqc_256::keygen)
436}
437
438#[uniffi::export]
439pub fn hqc_256_encapsulate(ek: Vec<u8>) -> Result<EncapsulationResult, UniFfiError> {
440    hqc_encapsulation(ek, tafrah_hqc::hqc_256::encapsulate)
441}
442
443#[uniffi::export]
444pub fn hqc_256_decapsulate(dk: Vec<u8>, ct: Vec<u8>) -> Result<Vec<u8>, UniFfiError> {
445    hqc_decapsulation(dk, ct, tafrah_hqc::hqc_256::decapsulate)
446}
447
448#[cfg(test)]
449mod tests {
450    use super::*;
451
452    #[test]
453    fn test_ml_kem_uniffi_surface_roundtrip() {
454        let keypair = ml_kem_768_keygen();
455        let enc = ml_kem_768_encapsulate(keypair.encapsulation_key).expect("encaps");
456        let dec =
457            ml_kem_768_decapsulate(keypair.decapsulation_key, enc.ciphertext).expect("decaps");
458        assert_eq!(enc.shared_secret, dec);
459    }
460
461    #[test]
462    fn test_ml_dsa_uniffi_surface_sign_verify() {
463        let keypair = ml_dsa_65_keygen();
464        let message = b"uniffi ml-dsa proof".to_vec();
465        let sig = ml_dsa_65_sign(keypair.signing_key, message.clone()).expect("sign");
466        assert!(ml_dsa_65_verify(keypair.verifying_key, message, sig).expect("verify"));
467    }
468
469    #[test]
470    fn test_slh_dsa_uniffi_surface_sign_verify() {
471        let keypair = slh_dsa_shake_128f_keygen();
472        let message = b"uniffi slh-dsa proof".to_vec();
473        let sig = slh_dsa_shake_128f_sign(keypair.signing_key, message.clone()).expect("sign");
474        assert!(slh_dsa_shake_128f_verify(keypair.verifying_key, message, sig).expect("verify"));
475    }
476
477    #[test]
478    fn test_hqc_uniffi_surface_roundtrip() {
479        let keypair = hqc_128_keygen().expect("keygen");
480        let enc = hqc_128_encapsulate(keypair.encapsulation_key).expect("encaps");
481        let dec = hqc_128_decapsulate(keypair.decapsulation_key, enc.ciphertext).expect("decaps");
482        assert_eq!(enc.shared_secret, dec);
483    }
484
485    #[test]
486    fn test_falcon_uniffi_surface_sign_verify() {
487        let keypair = falcon_512_keygen().expect("keygen");
488        let message = b"uniffi falcon proof".to_vec();
489        let sig = falcon_512_sign(keypair.signing_key, message.clone()).expect("sign");
490        assert!(falcon_512_verify(keypair.verifying_key, message, sig).expect("verify"));
491    }
492}