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}