Skip to main content

aigis_enc_binding/
lib.rs

1/// AIGIS-ENC Rust FFI绑定
2/// 支持参数集 1, 2, 3, 4
3/// 使用Cargo features选择: --features params-1/params-2/params-3/params-4
4
5use libc::{c_int, c_uchar};
6use std::fmt;
7
8// ==================== 参数常数 (由build.rs生成) ====================
9include!(concat!(env!("OUT_DIR"), "/constants.rs"));
10pub const CRYPTO_TKEM_TAGBYTES: usize = CRYPTO_BYTES;
11
12// ==================== 参数特化的FFI声明 ====================
13
14#[cfg(feature = "params-1")]
15extern "C" {
16    pub fn pqmagic_aigis_enc_1_std_keypair(pk: *mut c_uchar, sk: *mut c_uchar) -> c_int;
17    pub fn pqmagic_aigis_enc_1_std_keypair_internal(
18        pk: *mut c_uchar,
19        sk: *mut c_uchar,
20        coins: *const c_uchar,
21    ) -> c_int;
22    pub fn pqmagic_aigis_enc_1_std_enc(ct: *mut c_uchar, ss: *mut c_uchar, pk: *const c_uchar)
23        -> c_int;
24    pub fn pqmagic_aigis_enc_1_std_enc_internal(
25        ct: *mut c_uchar,
26        ss: *mut c_uchar,
27        pk: *const c_uchar,
28        coins: *const c_uchar,
29    ) -> c_int;
30    pub fn pqmagic_aigis_enc_1_std_dec(
31        ss: *mut c_uchar,
32        ct: *const c_uchar,
33        sk: *const c_uchar,
34    ) -> c_int;
35    pub fn pqmagic_aigis_enc_1_std_tkem_enc(
36        ct: *mut c_uchar,
37        ss: *mut c_uchar,
38        pk: *const c_uchar,
39        tag: *const c_uchar,
40    ) -> c_int;
41    pub fn pqmagic_aigis_enc_1_std_tkem_dec(
42        ss: *mut c_uchar,
43        ct: *const c_uchar,
44        sk: *const c_uchar,
45        tag: *const c_uchar,
46    ) -> c_int;
47}
48
49#[cfg(feature = "params-2")]
50extern "C" {
51    pub fn pqmagic_aigis_enc_2_std_keypair(pk: *mut c_uchar, sk: *mut c_uchar) -> c_int;
52    pub fn pqmagic_aigis_enc_2_std_keypair_internal(
53        pk: *mut c_uchar,
54        sk: *mut c_uchar,
55        coins: *const c_uchar,
56    ) -> c_int;
57    pub fn pqmagic_aigis_enc_2_std_enc(ct: *mut c_uchar, ss: *mut c_uchar, pk: *const c_uchar)
58        -> c_int;
59    pub fn pqmagic_aigis_enc_2_std_enc_internal(
60        ct: *mut c_uchar,
61        ss: *mut c_uchar,
62        pk: *const c_uchar,
63        coins: *const c_uchar,
64    ) -> c_int;
65    pub fn pqmagic_aigis_enc_2_std_dec(
66        ss: *mut c_uchar,
67        ct: *const c_uchar,
68        sk: *const c_uchar,
69    ) -> c_int;
70    pub fn pqmagic_aigis_enc_2_std_tkem_enc(
71        ct: *mut c_uchar,
72        ss: *mut c_uchar,
73        pk: *const c_uchar,
74        tag: *const c_uchar,
75    ) -> c_int;
76    pub fn pqmagic_aigis_enc_2_std_tkem_dec(
77        ss: *mut c_uchar,
78        ct: *const c_uchar,
79        sk: *const c_uchar,
80        tag: *const c_uchar,
81    ) -> c_int;
82}
83
84#[cfg(feature = "params-3")]
85extern "C" {
86    pub fn pqmagic_aigis_enc_3_std_keypair(pk: *mut c_uchar, sk: *mut c_uchar) -> c_int;
87    pub fn pqmagic_aigis_enc_3_std_keypair_internal(
88        pk: *mut c_uchar,
89        sk: *mut c_uchar,
90        coins: *const c_uchar,
91    ) -> c_int;
92    pub fn pqmagic_aigis_enc_3_std_enc(ct: *mut c_uchar, ss: *mut c_uchar, pk: *const c_uchar)
93        -> c_int;
94    pub fn pqmagic_aigis_enc_3_std_enc_internal(
95        ct: *mut c_uchar,
96        ss: *mut c_uchar,
97        pk: *const c_uchar,
98        coins: *const c_uchar,
99    ) -> c_int;
100    pub fn pqmagic_aigis_enc_3_std_dec(
101        ss: *mut c_uchar,
102        ct: *const c_uchar,
103        sk: *const c_uchar,
104    ) -> c_int;
105    pub fn pqmagic_aigis_enc_3_std_tkem_enc(
106        ct: *mut c_uchar,
107        ss: *mut c_uchar,
108        pk: *const c_uchar,
109        tag: *const c_uchar,
110    ) -> c_int;
111    pub fn pqmagic_aigis_enc_3_std_tkem_dec(
112        ss: *mut c_uchar,
113        ct: *const c_uchar,
114        sk: *const c_uchar,
115        tag: *const c_uchar,
116    ) -> c_int;
117}
118
119#[cfg(feature = "params-4")]
120extern "C" {
121    pub fn pqmagic_aigis_enc_4_std_keypair(pk: *mut c_uchar, sk: *mut c_uchar) -> c_int;
122    pub fn pqmagic_aigis_enc_4_std_keypair_internal(
123        pk: *mut c_uchar,
124        sk: *mut c_uchar,
125        coins: *const c_uchar,
126    ) -> c_int;
127    pub fn pqmagic_aigis_enc_4_std_enc(ct: *mut c_uchar, ss: *mut c_uchar, pk: *const c_uchar)
128        -> c_int;
129    pub fn pqmagic_aigis_enc_4_std_enc_internal(
130        ct: *mut c_uchar,
131        ss: *mut c_uchar,
132        pk: *const c_uchar,
133        coins: *const c_uchar,
134    ) -> c_int;
135    pub fn pqmagic_aigis_enc_4_std_dec(
136        ss: *mut c_uchar,
137        ct: *const c_uchar,
138        sk: *const c_uchar,
139    ) -> c_int;
140    pub fn pqmagic_aigis_enc_4_std_tkem_enc(
141        ct: *mut c_uchar,
142        ss: *mut c_uchar,
143        pk: *const c_uchar,
144        tag: *const c_uchar,
145    ) -> c_int;
146    pub fn pqmagic_aigis_enc_4_std_tkem_dec(
147        ss: *mut c_uchar,
148        ct: *const c_uchar,
149        sk: *const c_uchar,
150        tag: *const c_uchar,
151    ) -> c_int;
152}
153
154// ==================== 通用接口 ====================
155
156/// 生成密钥对
157pub fn aigis_enc_keypair(pk: *mut c_uchar, sk: *mut c_uchar) -> Result<(), c_int> {
158    let ret = unsafe {
159        #[cfg(feature = "params-1")]
160        {
161            pqmagic_aigis_enc_1_std_keypair(pk, sk)
162        }
163        #[cfg(feature = "params-2")]
164        {
165            pqmagic_aigis_enc_2_std_keypair(pk, sk)
166        }
167        #[cfg(feature = "params-3")]
168        {
169            pqmagic_aigis_enc_3_std_keypair(pk, sk)
170        }
171        #[cfg(feature = "params-4")]
172        {
173            pqmagic_aigis_enc_4_std_keypair(pk, sk)
174        }
175        #[cfg(not(any(
176            feature = "params-1",
177            feature = "params-2",
178            feature = "params-3",
179            feature = "params-4"
180        )))]
181        {
182            pqmagic_aigis_enc_2_std_keypair(pk, sk)
183        }
184    };
185    if ret == 0 {
186        Ok(())
187    } else {
188        Err(ret)
189    }
190}
191
192/// 加密
193pub fn aigis_enc_enc(
194    ct: *mut c_uchar,
195    ss: *mut c_uchar,
196    pk: *const c_uchar,
197) -> Result<(), c_int> {
198    let ret = unsafe {
199        #[cfg(feature = "params-1")]
200        {
201            pqmagic_aigis_enc_1_std_enc(ct, ss, pk)
202        }
203        #[cfg(feature = "params-2")]
204        {
205            pqmagic_aigis_enc_2_std_enc(ct, ss, pk)
206        }
207        #[cfg(feature = "params-3")]
208        {
209            pqmagic_aigis_enc_3_std_enc(ct, ss, pk)
210        }
211        #[cfg(feature = "params-4")]
212        {
213            pqmagic_aigis_enc_4_std_enc(ct, ss, pk)
214        }
215        #[cfg(not(any(
216            feature = "params-1",
217            feature = "params-2",
218            feature = "params-3",
219            feature = "params-4"
220        )))]
221        {
222            pqmagic_aigis_enc_2_std_enc(ct, ss, pk)
223        }
224    };
225    if ret == 0 {
226        Ok(())
227    } else {
228        Err(ret)
229    }
230}
231
232/// 解密
233pub fn aigis_enc_dec(
234    ss: *mut c_uchar,
235    ct: *const c_uchar,
236    sk: *const c_uchar,
237) -> Result<(), c_int> {
238    let ret = unsafe {
239        #[cfg(feature = "params-1")]
240        {
241            pqmagic_aigis_enc_1_std_dec(ss, ct, sk)
242        }
243        #[cfg(feature = "params-2")]
244        {
245            pqmagic_aigis_enc_2_std_dec(ss, ct, sk)
246        }
247        #[cfg(feature = "params-3")]
248        {
249            pqmagic_aigis_enc_3_std_dec(ss, ct, sk)
250        }
251        #[cfg(feature = "params-4")]
252        {
253            pqmagic_aigis_enc_4_std_dec(ss, ct, sk)
254        }
255        #[cfg(not(any(
256            feature = "params-1",
257            feature = "params-2",
258            feature = "params-3",
259            feature = "params-4"
260        )))]
261        {
262            pqmagic_aigis_enc_2_std_dec(ss, ct, sk)
263        }
264    };
265    if ret == 0 {
266        Ok(())
267    } else {
268        Err(ret)
269    }
270}
271
272/// Tagged encapsulation
273pub fn aigis_tkem_enc(
274    ct: *mut c_uchar,
275    ss: *mut c_uchar,
276    pk: *const c_uchar,
277    tag: *const c_uchar,
278) -> Result<(), c_int> {
279    let ret = unsafe {
280        #[cfg(feature = "params-1")]
281        {
282            pqmagic_aigis_enc_1_std_tkem_enc(ct, ss, pk, tag)
283        }
284        #[cfg(feature = "params-2")]
285        {
286            pqmagic_aigis_enc_2_std_tkem_enc(ct, ss, pk, tag)
287        }
288        #[cfg(feature = "params-3")]
289        {
290            pqmagic_aigis_enc_3_std_tkem_enc(ct, ss, pk, tag)
291        }
292        #[cfg(feature = "params-4")]
293        {
294            pqmagic_aigis_enc_4_std_tkem_enc(ct, ss, pk, tag)
295        }
296        #[cfg(not(any(
297            feature = "params-1",
298            feature = "params-2",
299            feature = "params-3",
300            feature = "params-4"
301        )))]
302        {
303            pqmagic_aigis_enc_2_std_tkem_enc(ct, ss, pk, tag)
304        }
305    };
306    if ret == 0 {
307        Ok(())
308    } else {
309        Err(ret)
310    }
311}
312
313/// Tagged decapsulation
314pub fn aigis_tkem_dec(
315    ss: *mut c_uchar,
316    ct: *const c_uchar,
317    sk: *const c_uchar,
318    tag: *const c_uchar,
319) -> Result<(), c_int> {
320    let ret = unsafe {
321        #[cfg(feature = "params-1")]
322        {
323            pqmagic_aigis_enc_1_std_tkem_dec(ss, ct, sk, tag)
324        }
325        #[cfg(feature = "params-2")]
326        {
327            pqmagic_aigis_enc_2_std_tkem_dec(ss, ct, sk, tag)
328        }
329        #[cfg(feature = "params-3")]
330        {
331            pqmagic_aigis_enc_3_std_tkem_dec(ss, ct, sk, tag)
332        }
333        #[cfg(feature = "params-4")]
334        {
335            pqmagic_aigis_enc_4_std_tkem_dec(ss, ct, sk, tag)
336        }
337        #[cfg(not(any(
338            feature = "params-1",
339            feature = "params-2",
340            feature = "params-3",
341            feature = "params-4"
342        )))]
343        {
344            pqmagic_aigis_enc_2_std_tkem_dec(ss, ct, sk, tag)
345        }
346    };
347    if ret == 0 {
348        Ok(())
349    } else {
350        Err(ret)
351    }
352}
353
354/// Error type for the safe Rust API.
355#[derive(Debug, Clone, Copy, PartialEq, Eq)]
356pub struct AigisEncError(pub c_int);
357
358impl fmt::Display for AigisEncError {
359    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
360        write!(f, "AIGIS-ENC returned non-zero status: {}", self.0)
361    }
362}
363
364impl std::error::Error for AigisEncError {}
365
366/// High-level, safe wrapper around the FFI functions.
367pub struct AigisEnc;
368
369impl AigisEnc {
370    /// Generate a keypair.
371    pub fn keypair() -> Result<(Vec<u8>, Vec<u8>), AigisEncError> {
372        let mut pk = vec![0u8; CRYPTO_PUBLICKEYBYTES];
373        let mut sk = vec![0u8; CRYPTO_SECRETKEYBYTES];
374        aigis_enc_keypair(pk.as_mut_ptr(), sk.as_mut_ptr())
375            .map_err(AigisEncError)?;
376        Ok((pk, sk))
377    }
378
379    /// Encapsulate to produce `(ciphertext, shared_secret)`.
380    pub fn encapsulate(pk: &[u8]) -> Result<(Vec<u8>, Vec<u8>), AigisEncError> {
381        if pk.len() != CRYPTO_PUBLICKEYBYTES {
382            return Err(AigisEncError(-1));
383        }
384        let mut ct = vec![0u8; CRYPTO_CIPHERTEXTBYTES];
385        let mut ss = vec![0u8; CRYPTO_BYTES];
386        aigis_enc_enc(ct.as_mut_ptr(), ss.as_mut_ptr(), pk.as_ptr()).map_err(AigisEncError)?;
387        Ok((ct, ss))
388    }
389
390    /// Decapsulate to recover the shared secret.
391    pub fn decapsulate(ct: &[u8], sk: &[u8]) -> Result<Vec<u8>, AigisEncError> {
392        if ct.len() != CRYPTO_CIPHERTEXTBYTES || sk.len() != CRYPTO_SECRETKEYBYTES {
393            return Err(AigisEncError(-1));
394        }
395        let mut ss = vec![0u8; CRYPTO_BYTES];
396        aigis_enc_dec(ss.as_mut_ptr(), ct.as_ptr(), sk.as_ptr()).map_err(AigisEncError)?;
397        Ok(ss)
398    }
399
400    /// Tagged encapsulate to produce `(ciphertext, shared_secret)`.
401    pub fn encapsulate_with_tag(pk: &[u8], tag: &[u8]) -> Result<(Vec<u8>, Vec<u8>), AigisEncError> {
402        if pk.len() != CRYPTO_PUBLICKEYBYTES || tag.len() != CRYPTO_TKEM_TAGBYTES {
403            return Err(AigisEncError(-1));
404        }
405        let mut ct = vec![0u8; CRYPTO_CIPHERTEXTBYTES];
406        let mut ss = vec![0u8; CRYPTO_BYTES];
407        aigis_tkem_enc(ct.as_mut_ptr(), ss.as_mut_ptr(), pk.as_ptr(), tag.as_ptr())
408            .map_err(AigisEncError)?;
409        Ok((ct, ss))
410    }
411
412    /// Tagged decapsulate to recover the shared secret.
413    pub fn decapsulate_with_tag(ct: &[u8], sk: &[u8], tag: &[u8]) -> Result<Vec<u8>, AigisEncError> {
414        if ct.len() != CRYPTO_CIPHERTEXTBYTES
415            || sk.len() != CRYPTO_SECRETKEYBYTES
416            || tag.len() != CRYPTO_TKEM_TAGBYTES
417        {
418            return Err(AigisEncError(-1));
419        }
420        let mut ss = vec![0u8; CRYPTO_BYTES];
421        aigis_tkem_dec(ss.as_mut_ptr(), ct.as_ptr(), sk.as_ptr(), tag.as_ptr())
422            .map_err(AigisEncError)?;
423        Ok(ss)
424    }
425}