Skip to main content

bicycl_rs/
lib.rs

1//! Safe Rust bindings for the [BICYCL] cryptographic library.
2//!
3//! BICYCL implements class-group-based cryptographic schemes including:
4//! - **Paillier** homomorphic encryption
5//! - **Joye-Libert** homomorphic encryption
6//! - **CL_HSMqk / CL_HSM2k** class-group encryption with homomorphic properties
7//! - **ECDSA** signatures
8//! - **Two-party ECDSA** threshold signing (2-of-2)
9//! - **Threshold ECDSA** (t-of-n)
10//! - **CL DLog proofs**
11//!
12//! # Build
13//!
14//! Requires CMake, GMP, and OpenSSL development headers at build time.
15//!
16//! # Thread safety
17//!
18//! The underlying C library is **not** thread-safe.  All wrapper types are
19//! `!Send + !Sync` and must be used from a single thread.
20//!
21//! # License
22//!
23//! This crate is licensed under **GPL-3.0-or-later**.  Any crate or binary
24//! that depends on it inherits the GPL-3.0 copyleft obligation.
25//!
26//! # Quick start
27//!
28//! ```no_run
29//! use bicycl_rs::{Context, Error};
30//!
31//! fn main() -> Result<(), Error> {
32//!     let ctx = Context::new()?;
33//!     let mut rng = ctx.randgen_from_seed_decimal("12345")?;
34//!     let paillier = ctx.paillier(512)?;
35//!     let (sk, pk) = paillier.keygen(&ctx, &mut rng)?;
36//!     let ct = paillier.encrypt_decimal(&ctx, &pk, &mut rng, "42")?;
37//!     let plain = paillier.decrypt_decimal(&ctx, &pk, &sk, &ct)?;
38//!     assert_eq!(plain, "42");
39//!     Ok(())
40//! }
41//! ```
42//!
43//! [BICYCL]: https://gite.lirmm.fr/crypto/bicycl
44#![deny(unsafe_op_in_unsafe_fn)]
45
46mod error;
47
48use core::ffi::{c_char, c_int, c_void};
49use std::ffi::{CStr, CString};
50use std::marker::PhantomData;
51use std::ptr::NonNull;
52
53pub use error::{Error, Result};
54
55fn status_to_result(status: bicycl_rs_sys::bicycl_status_t) -> Result<()> {
56    if status == bicycl_rs_sys::bicycl_status_t::BICYCL_OK {
57        Ok(())
58    } else {
59        Err(Error::from_status(status))
60    }
61}
62
63fn ffi_string_from_len<F>(mut f: F) -> Result<String>
64where
65    F: FnMut(*mut c_char, *mut usize) -> bicycl_rs_sys::bicycl_status_t,
66{
67    let buf = ffi_bytes_from_len(|buf, len| f(buf.cast::<c_char>(), len))?;
68    let cstr = CStr::from_bytes_with_nul(&buf).map_err(|_| Error::Internal)?;
69    Ok(cstr.to_str()?.to_owned())
70}
71
72fn ffi_bytes_from_len<F>(mut f: F) -> Result<Vec<u8>>
73where
74    F: FnMut(*mut u8, *mut usize) -> bicycl_rs_sys::bicycl_status_t,
75{
76    let mut len: usize = 0;
77    let first = f(std::ptr::null_mut(), &mut len as *mut usize);
78    if first != bicycl_rs_sys::bicycl_status_t::BICYCL_ERR_BUFFER_TOO_SMALL
79        && first != bicycl_rs_sys::bicycl_status_t::BICYCL_OK
80    {
81        return Err(Error::from_status(first));
82    }
83
84    let mut buf = vec![0_u8; len];
85    if len == 0 {
86        return Ok(buf);
87    }
88
89    let second = f(buf.as_mut_ptr(), &mut len as *mut usize);
90    status_to_result(second)?;
91    buf.truncate(len);
92    Ok(buf)
93}
94
95/// Returns the ABI version of the linked `bicycl_capi` C library.
96///
97/// Compare against [`bicycl_rs_sys::BICYCL_CAPI_VERSION`] to verify
98/// the runtime library matches the headers this crate was compiled against.
99pub fn abi_version() -> u32 {
100    unsafe { bicycl_rs_sys::bicycl_get_abi_version() }
101}
102
103/// Returns the human-readable version string of the linked `bicycl_capi` library.
104///
105/// Returns an empty string if the library returns a null pointer.
106pub fn version() -> &'static str {
107    unsafe {
108        let p = bicycl_rs_sys::bicycl_get_version();
109        if p.is_null() {
110            return "";
111        }
112        CStr::from_ptr(p).to_str().unwrap_or("")
113    }
114}
115
116/// Overwrites the given byte buffer with zeros using a memory-safe barrier.
117///
118/// Unlike a plain `buf.fill(0)`, this call is guaranteed not to be optimised
119/// away by the compiler, making it suitable for clearing sensitive key material.
120pub fn zeroize(buf: &mut [u8]) {
121    unsafe {
122        bicycl_rs_sys::bicycl_zeroize(buf.as_mut_ptr().cast::<c_void>(), buf.len());
123    }
124}
125
126/// The central BICYCL library context.
127///
128/// All cryptographic objects and operations require a reference to a `Context`.
129/// The context acts as an error sink: it stores the last error message produced
130/// by the C library and is passed to every operation so the library has
131/// somewhere to record diagnostic information.
132///
133/// All derived objects (`RandGen`, scheme instances, keys, ciphertexts, etc.)
134/// own their data independently and do **not** hold pointers into the context's
135/// memory, so their drop order relative to `Context` does not affect memory
136/// safety.  `Context` is `!Send + !Sync` because the underlying C library is
137/// not thread-safe; all objects must be used from a single thread.
138#[derive(Debug)]
139pub struct Context {
140    raw: NonNull<bicycl_rs_sys::bicycl_context_t>,
141    _marker: PhantomData<*mut ()>,
142}
143
144impl Context {
145    /// Creates a new library context.
146    ///
147    /// # Errors
148    ///
149    /// Returns an error if the underlying C allocation fails.
150    pub fn new() -> Result<Self> {
151        let mut raw = std::ptr::null_mut();
152        let status = unsafe { bicycl_rs_sys::bicycl_context_new(&mut raw as *mut _) };
153        status_to_result(status)?;
154        let raw = NonNull::new(raw).expect("bicycl_context_new returned null");
155        Ok(Self {
156            raw,
157            _marker: PhantomData,
158        })
159    }
160
161    /// Returns the last error message stored by the C library, or `""` if none.
162    pub fn last_error(&self) -> &str {
163        unsafe {
164            let p = bicycl_rs_sys::bicycl_context_last_error(self.raw.as_ptr());
165            if p.is_null() {
166                return "";
167            }
168            CStr::from_ptr(p).to_str().unwrap_or("")
169        }
170    }
171
172    /// Clears the last error message stored in the context.
173    pub fn clear_error(&mut self) {
174        unsafe { bicycl_rs_sys::bicycl_context_clear_error(self.raw.as_ptr()) }
175    }
176
177    /// Creates a deterministic random number generator seeded from a decimal string.
178    ///
179    /// `seed_decimal` must be a valid decimal integer (e.g., `"12345"`).
180    /// The same seed always produces the same sequence, which is useful for
181    /// reproducible tests but **must not be used with a fixed seed in production**.
182    pub fn randgen_from_seed_decimal(&self, seed_decimal: &str) -> Result<RandGen> {
183        let seed_c = CString::new(seed_decimal)?;
184        let mut raw = std::ptr::null_mut();
185        let status = unsafe {
186            bicycl_rs_sys::bicycl_randgen_new_from_seed_decimal(
187                self.raw.as_ptr(),
188                seed_c.as_ptr(),
189                &mut raw as *mut _,
190            )
191        };
192        status_to_result(status)?;
193        let raw = NonNull::new(raw).expect("bicycl_randgen_new_from_seed_decimal returned null");
194        Ok(RandGen {
195            raw,
196            _marker: PhantomData,
197        })
198    }
199
200    /// Creates a class group from a negative fundamental discriminant given as a decimal string.
201    ///
202    /// `discriminant_decimal` must be a negative integer (e.g., `"-23"`).
203    pub fn classgroup_from_discriminant_decimal(
204        &self,
205        discriminant_decimal: &str,
206    ) -> Result<ClassGroup> {
207        let disc_c = CString::new(discriminant_decimal)?;
208        let mut raw = std::ptr::null_mut();
209        let status = unsafe {
210            bicycl_rs_sys::bicycl_classgroup_new_from_discriminant_decimal(
211                self.raw.as_ptr(),
212                disc_c.as_ptr(),
213                &mut raw as *mut _,
214            )
215        };
216        status_to_result(status)?;
217        let raw = NonNull::new(raw)
218            .expect("bicycl_classgroup_new_from_discriminant_decimal returned null");
219        Ok(ClassGroup {
220            raw,
221            _marker: PhantomData,
222        })
223    }
224
225    /// Creates a Paillier cryptosystem instance with the given RSA modulus bit length.
226    ///
227    /// Typical values for `modulus_bits`: 512 (testing), 1024, 2048.
228    pub fn paillier(&self, modulus_bits: u32) -> Result<Paillier> {
229        let mut raw = std::ptr::null_mut();
230        let status = unsafe {
231            bicycl_rs_sys::bicycl_paillier_new(self.raw.as_ptr(), modulus_bits, &mut raw as *mut _)
232        };
233        status_to_result(status)?;
234        let raw = NonNull::new(raw).expect("bicycl_paillier_new returned null");
235        Ok(Paillier {
236            raw,
237            _marker: PhantomData,
238        })
239    }
240
241    /// Creates a Joye-Libert cryptosystem instance.
242    ///
243    /// - `modulus_bits`: RSA modulus bit length (e.g., 1024, 2048).
244    /// - `k`: plaintext bit length (must be ≤ `modulus_bits / 2`).
245    pub fn joye_libert(&self, modulus_bits: u32, k: u32) -> Result<JoyeLibert> {
246        let mut raw = std::ptr::null_mut();
247        let status = unsafe {
248            bicycl_rs_sys::bicycl_joye_libert_new(
249                self.raw.as_ptr(),
250                modulus_bits,
251                k,
252                &mut raw as *mut _,
253            )
254        };
255        status_to_result(status)?;
256        let raw = NonNull::new(raw).expect("bicycl_joye_libert_new returned null");
257        Ok(JoyeLibert {
258            raw,
259            _marker: PhantomData,
260        })
261    }
262
263    /// Creates a CL_HSMqk instance.
264    ///
265    /// - `q_decimal`: the prime order `q` of the subgroup (decimal string).
266    /// - `k`: the bit-size parameter `k` (plaintext space is `Z/q^k`).
267    /// - `p_decimal`: the class-group prime `p` (decimal string).
268    pub fn cl_hsmqk(&self, q_decimal: &str, k: u32, p_decimal: &str) -> Result<ClHsmqk> {
269        let q_c = CString::new(q_decimal)?;
270        let p_c = CString::new(p_decimal)?;
271        let mut raw = std::ptr::null_mut();
272        let status = unsafe {
273            bicycl_rs_sys::bicycl_cl_hsmqk_new(
274                self.raw.as_ptr(),
275                q_c.as_ptr(),
276                k,
277                p_c.as_ptr(),
278                &mut raw as *mut _,
279            )
280        };
281        status_to_result(status)?;
282        let raw = NonNull::new(raw).expect("bicycl_cl_hsmqk_new returned null");
283        Ok(ClHsmqk {
284            raw,
285            _marker: PhantomData,
286        })
287    }
288
289    /// Creates a CL_HSM2k instance.
290    ///
291    /// - `n_decimal`: the RSA-like composite modulus `n` (decimal string).
292    /// - `k`: the bit-size parameter `k` (plaintext space is `Z/2^k`).
293    pub fn cl_hsm2k(&self, n_decimal: &str, k: u32) -> Result<ClHsm2k> {
294        let n_c = CString::new(n_decimal)?;
295        let mut raw = std::ptr::null_mut();
296        let status = unsafe {
297            bicycl_rs_sys::bicycl_cl_hsm2k_new(
298                self.raw.as_ptr(),
299                n_c.as_ptr(),
300                k,
301                &mut raw as *mut _,
302            )
303        };
304        status_to_result(status)?;
305        let raw = NonNull::new(raw).expect("bicycl_cl_hsm2k_new returned null");
306        Ok(ClHsm2k {
307            raw,
308            _marker: PhantomData,
309        })
310    }
311
312    /// Creates an ECDSA instance at the given security level.
313    ///
314    /// `seclevel_bits` selects the elliptic curve (e.g., 112 → P-224, 128 → P-256).
315    pub fn ecdsa(&self, seclevel_bits: u32) -> Result<Ecdsa> {
316        let mut raw = std::ptr::null_mut();
317        let status = unsafe {
318            bicycl_rs_sys::bicycl_ecdsa_new(self.raw.as_ptr(), seclevel_bits, &mut raw as *mut _)
319        };
320        status_to_result(status)?;
321        let raw = NonNull::new(raw).expect("bicycl_ecdsa_new returned null");
322        Ok(Ecdsa {
323            raw,
324            _marker: PhantomData,
325        })
326    }
327
328    /// Creates a new two-party ECDSA session at the given security level.
329    ///
330    /// Drive the session through the required keygen and sign rounds; see
331    /// [`TwoPartyEcdsaSession`] for method details.
332    pub fn two_party_ecdsa_session(
333        &self,
334        rng: &mut RandGen,
335        seclevel_bits: u32,
336    ) -> Result<TwoPartyEcdsaSession> {
337        let mut raw = std::ptr::null_mut();
338        let status = unsafe {
339            bicycl_rs_sys::bicycl_two_party_ecdsa_session_new(
340                self.raw.as_ptr(),
341                rng.raw.as_ptr(),
342                seclevel_bits,
343                &mut raw as *mut _,
344            )
345        };
346        status_to_result(status)?;
347        let raw = NonNull::new(raw).expect("bicycl_two_party_ecdsa_session_new returned null");
348        Ok(TwoPartyEcdsaSession {
349            raw,
350            _state: PhantomData,
351            _marker: PhantomData,
352        })
353    }
354
355    /// Creates a new CL DLog proof session at the given security level.
356    ///
357    /// Use this for non-interactive zero-knowledge proofs of discrete
358    /// logarithm in the class group.  See [`ClDlogSession`] for the
359    /// prove/verify round methods.
360    pub fn cl_dlog_session(&self, rng: &mut RandGen, seclevel_bits: u32) -> Result<ClDlogSession> {
361        let mut raw = std::ptr::null_mut();
362        let status = unsafe {
363            bicycl_rs_sys::bicycl_cl_dlog_session_new(
364                self.raw.as_ptr(),
365                rng.raw.as_ptr(),
366                seclevel_bits,
367                &mut raw as *mut _,
368            )
369        };
370        status_to_result(status)?;
371        let raw = NonNull::new(raw).expect("bicycl_cl_dlog_session_new returned null");
372        Ok(ClDlogSession {
373            raw,
374            _state: PhantomData,
375            _marker: PhantomData,
376        })
377    }
378
379    /// Creates a new threshold ECDSA session.
380    ///
381    /// - `n_players`: total number of participants.
382    /// - `threshold_t`: minimum number of participants required to sign
383    ///   (must satisfy `threshold_t < n_players`).
384    pub fn threshold_ecdsa_session(
385        &self,
386        rng: &mut RandGen,
387        seclevel_bits: u32,
388        n_players: u32,
389        threshold_t: u32,
390    ) -> Result<ThresholdEcdsaSession> {
391        let mut raw = std::ptr::null_mut();
392        let status = unsafe {
393            bicycl_rs_sys::bicycl_threshold_ecdsa_session_new(
394                self.raw.as_ptr(),
395                rng.raw.as_ptr(),
396                seclevel_bits,
397                n_players,
398                threshold_t,
399                &mut raw as *mut _,
400            )
401        };
402        status_to_result(status)?;
403        let raw = NonNull::new(raw).expect("bicycl_threshold_ecdsa_session_new returned null");
404        Ok(ThresholdEcdsaSession {
405            raw,
406            _state: PhantomData,
407            _marker: PhantomData,
408        })
409    }
410}
411
412impl Drop for Context {
413    fn drop(&mut self) {
414        unsafe { bicycl_rs_sys::bicycl_context_free(self.raw.as_ptr()) }
415    }
416}
417
418/// A deterministic pseudo-random number generator seeded from a decimal value.
419///
420/// Create via [`Context::randgen_from_seed_decimal`].
421#[derive(Debug)]
422pub struct RandGen {
423    raw: NonNull<bicycl_rs_sys::bicycl_randgen_t>,
424    _marker: PhantomData<*mut ()>,
425}
426
427impl Drop for RandGen {
428    fn drop(&mut self) {
429        unsafe { bicycl_rs_sys::bicycl_randgen_free(self.raw.as_ptr()) }
430    }
431}
432
433/// An imaginary quadratic class group defined by its discriminant.
434///
435/// Create via [`Context::classgroup_from_discriminant_decimal`].
436#[derive(Debug)]
437pub struct ClassGroup {
438    raw: NonNull<bicycl_rs_sys::bicycl_classgroup_t>,
439    _marker: PhantomData<*mut ()>,
440}
441
442impl ClassGroup {
443    /// Returns the identity element (principal form) of this class group.
444    pub fn one(&self, ctx: &Context) -> Result<Qfi> {
445        let mut raw = std::ptr::null_mut();
446        let status = unsafe {
447            bicycl_rs_sys::bicycl_classgroup_one(
448                ctx.raw.as_ptr(),
449                self.raw.as_ptr(),
450                &mut raw as *mut _,
451            )
452        };
453        status_to_result(status)?;
454        let raw = NonNull::new(raw).expect("bicycl_classgroup_one returned null");
455        Ok(Qfi {
456            raw,
457            _marker: PhantomData,
458        })
459    }
460
461    /// Computes the NUDUPL squaring of a QFI element (i.e., `input² = input ∘ input`).
462    pub fn nudupl(&self, ctx: &Context, input: &Qfi) -> Result<Qfi> {
463        let mut raw = std::ptr::null_mut();
464        let status = unsafe {
465            bicycl_rs_sys::bicycl_classgroup_nudupl(
466                ctx.raw.as_ptr(),
467                self.raw.as_ptr(),
468                input.raw.as_ptr(),
469                &mut raw as *mut _,
470            )
471        };
472        status_to_result(status)?;
473        let raw = NonNull::new(raw).expect("bicycl_classgroup_nudupl returned null");
474        Ok(Qfi {
475            raw,
476            _marker: PhantomData,
477        })
478    }
479}
480
481impl Drop for ClassGroup {
482    fn drop(&mut self) {
483        unsafe { bicycl_rs_sys::bicycl_classgroup_free(self.raw.as_ptr()) }
484    }
485}
486
487/// A Quadratic Form element in a class group.
488///
489/// Obtained from [`ClassGroup::one`] or [`ClassGroup::nudupl`].
490#[derive(Debug)]
491pub struct Qfi {
492    raw: NonNull<bicycl_rs_sys::bicycl_qfi_t>,
493    _marker: PhantomData<*mut ()>,
494}
495
496impl Qfi {
497    /// Returns `true` if this element is the identity element of the class group.
498    pub fn is_one(&self, ctx: &Context) -> Result<bool> {
499        let mut out: c_int = 0;
500        let status = unsafe {
501            bicycl_rs_sys::bicycl_qfi_is_one(
502                ctx.raw.as_ptr(),
503                self.raw.as_ptr(),
504                &mut out as *mut _,
505            )
506        };
507        status_to_result(status)?;
508        Ok(out != 0)
509    }
510
511    /// Returns the discriminant of the class group this element belongs to, as a decimal string.
512    pub fn discriminant_decimal(&self, ctx: &Context) -> Result<String> {
513        ffi_string_from_len(|buf, len| unsafe {
514            bicycl_rs_sys::bicycl_qfi_discriminant_decimal(
515                ctx.raw.as_ptr(),
516                self.raw.as_ptr(),
517                buf,
518                len,
519            )
520        })
521    }
522}
523
524impl Drop for Qfi {
525    fn drop(&mut self) {
526        unsafe { bicycl_rs_sys::bicycl_qfi_free(self.raw.as_ptr()) }
527    }
528}
529
530/// A Paillier homomorphic encryption scheme instance.
531///
532/// Create via [`Context::paillier`].
533#[derive(Debug)]
534pub struct Paillier {
535    raw: NonNull<bicycl_rs_sys::bicycl_paillier_t>,
536    _marker: PhantomData<*mut ()>,
537}
538
539/// A Paillier secret key.  Keep this private.
540#[derive(Debug)]
541pub struct PaillierSecretKey {
542    raw: NonNull<bicycl_rs_sys::bicycl_paillier_sk_t>,
543    _marker: PhantomData<*mut ()>,
544}
545
546/// A Paillier public key.  Safe to share.
547#[derive(Debug)]
548pub struct PaillierPublicKey {
549    raw: NonNull<bicycl_rs_sys::bicycl_paillier_pk_t>,
550    _marker: PhantomData<*mut ()>,
551}
552
553/// A Paillier ciphertext.
554#[derive(Debug)]
555pub struct PaillierCiphertext {
556    raw: NonNull<bicycl_rs_sys::bicycl_paillier_ct_t>,
557    _marker: PhantomData<*mut ()>,
558}
559
560impl Paillier {
561    /// Generates a fresh Paillier key pair.
562    ///
563    /// Returns `(secret_key, public_key)`.
564    pub fn keygen(
565        &self,
566        ctx: &Context,
567        rng: &mut RandGen,
568    ) -> Result<(PaillierSecretKey, PaillierPublicKey)> {
569        let mut sk_raw = std::ptr::null_mut();
570        let mut pk_raw = std::ptr::null_mut();
571        let status = unsafe {
572            bicycl_rs_sys::bicycl_paillier_keygen(
573                ctx.raw.as_ptr(),
574                self.raw.as_ptr(),
575                rng.raw.as_ptr(),
576                &mut sk_raw as *mut _,
577                &mut pk_raw as *mut _,
578            )
579        };
580        status_to_result(status)?;
581
582        let sk = PaillierSecretKey {
583            raw: NonNull::new(sk_raw).expect("bicycl_paillier_keygen/sk returned null"),
584            _marker: PhantomData,
585        };
586        let pk = PaillierPublicKey {
587            raw: NonNull::new(pk_raw).expect("bicycl_paillier_keygen/pk returned null"),
588            _marker: PhantomData,
589        };
590        Ok((sk, pk))
591    }
592
593    /// Encrypts a plaintext given as a decimal string.
594    ///
595    /// The plaintext must lie in `[0, N)` where `N` is the Paillier modulus.
596    pub fn encrypt_decimal(
597        &self,
598        ctx: &Context,
599        pk: &PaillierPublicKey,
600        rng: &mut RandGen,
601        message_decimal: &str,
602    ) -> Result<PaillierCiphertext> {
603        let message_c = CString::new(message_decimal)?;
604        let mut ct_raw = std::ptr::null_mut();
605        let status = unsafe {
606            bicycl_rs_sys::bicycl_paillier_encrypt_decimal(
607                ctx.raw.as_ptr(),
608                self.raw.as_ptr(),
609                pk.raw.as_ptr(),
610                rng.raw.as_ptr(),
611                message_c.as_ptr(),
612                &mut ct_raw as *mut _,
613            )
614        };
615        status_to_result(status)?;
616        let raw = NonNull::new(ct_raw).expect("bicycl_paillier_encrypt_decimal returned null");
617        Ok(PaillierCiphertext {
618            raw,
619            _marker: PhantomData,
620        })
621    }
622
623    /// Decrypts a ciphertext, returning the plaintext as a decimal string.
624    ///
625    /// Unlike the Joye-Libert and CL variants, Paillier decryption requires both
626    /// `pk` and `sk` because the underlying C API uses the public key's modulus
627    /// during the decryption computation.
628    pub fn decrypt_decimal(
629        &self,
630        ctx: &Context,
631        pk: &PaillierPublicKey,
632        sk: &PaillierSecretKey,
633        ct: &PaillierCiphertext,
634    ) -> Result<String> {
635        ffi_string_from_len(|buf, len| unsafe {
636            bicycl_rs_sys::bicycl_paillier_decrypt_decimal(
637                ctx.raw.as_ptr(),
638                self.raw.as_ptr(),
639                pk.raw.as_ptr(),
640                sk.raw.as_ptr(),
641                ct.raw.as_ptr(),
642                buf,
643                len,
644            )
645        })
646    }
647}
648
649impl Drop for Paillier {
650    fn drop(&mut self) {
651        unsafe { bicycl_rs_sys::bicycl_paillier_free(self.raw.as_ptr()) }
652    }
653}
654
655impl Drop for PaillierSecretKey {
656    fn drop(&mut self) {
657        unsafe { bicycl_rs_sys::bicycl_paillier_sk_free(self.raw.as_ptr()) }
658    }
659}
660
661impl Drop for PaillierPublicKey {
662    fn drop(&mut self) {
663        unsafe { bicycl_rs_sys::bicycl_paillier_pk_free(self.raw.as_ptr()) }
664    }
665}
666
667impl Drop for PaillierCiphertext {
668    fn drop(&mut self) {
669        unsafe { bicycl_rs_sys::bicycl_paillier_ct_free(self.raw.as_ptr()) }
670    }
671}
672
673/// A Joye-Libert homomorphic encryption scheme instance.
674///
675/// Create via [`Context::joye_libert`].
676#[derive(Debug)]
677pub struct JoyeLibert {
678    raw: NonNull<bicycl_rs_sys::bicycl_joye_libert_t>,
679    _marker: PhantomData<*mut ()>,
680}
681
682/// A Joye-Libert secret key.  Keep this private.
683#[derive(Debug)]
684pub struct JoyeLibertSecretKey {
685    raw: NonNull<bicycl_rs_sys::bicycl_joye_libert_sk_t>,
686    _marker: PhantomData<*mut ()>,
687}
688
689/// A Joye-Libert public key.  Safe to share.
690#[derive(Debug)]
691pub struct JoyeLibertPublicKey {
692    raw: NonNull<bicycl_rs_sys::bicycl_joye_libert_pk_t>,
693    _marker: PhantomData<*mut ()>,
694}
695
696/// A Joye-Libert ciphertext.
697#[derive(Debug)]
698pub struct JoyeLibertCiphertext {
699    raw: NonNull<bicycl_rs_sys::bicycl_joye_libert_ct_t>,
700    _marker: PhantomData<*mut ()>,
701}
702
703impl JoyeLibert {
704    /// Generates a fresh Joye-Libert key pair.  Returns `(secret_key, public_key)`.
705    pub fn keygen(
706        &self,
707        ctx: &Context,
708        rng: &mut RandGen,
709    ) -> Result<(JoyeLibertSecretKey, JoyeLibertPublicKey)> {
710        let mut sk_raw = std::ptr::null_mut();
711        let mut pk_raw = std::ptr::null_mut();
712        let status = unsafe {
713            bicycl_rs_sys::bicycl_joye_libert_keygen(
714                ctx.raw.as_ptr(),
715                self.raw.as_ptr(),
716                rng.raw.as_ptr(),
717                &mut sk_raw as *mut _,
718                &mut pk_raw as *mut _,
719            )
720        };
721        status_to_result(status)?;
722
723        let sk = JoyeLibertSecretKey {
724            raw: NonNull::new(sk_raw).expect("bicycl_joye_libert_keygen/sk returned null"),
725            _marker: PhantomData,
726        };
727        let pk = JoyeLibertPublicKey {
728            raw: NonNull::new(pk_raw).expect("bicycl_joye_libert_keygen/pk returned null"),
729            _marker: PhantomData,
730        };
731        Ok((sk, pk))
732    }
733
734    /// Encrypts a plaintext given as a decimal string.
735    ///
736    /// The plaintext must be a non-negative integer less than `2^k`.
737    pub fn encrypt_decimal(
738        &self,
739        ctx: &Context,
740        pk: &JoyeLibertPublicKey,
741        rng: &mut RandGen,
742        message_decimal: &str,
743    ) -> Result<JoyeLibertCiphertext> {
744        let message_c = CString::new(message_decimal)?;
745        let mut ct_raw = std::ptr::null_mut();
746        let status = unsafe {
747            bicycl_rs_sys::bicycl_joye_libert_encrypt_decimal(
748                ctx.raw.as_ptr(),
749                self.raw.as_ptr(),
750                pk.raw.as_ptr(),
751                rng.raw.as_ptr(),
752                message_c.as_ptr(),
753                &mut ct_raw as *mut _,
754            )
755        };
756        status_to_result(status)?;
757        let raw = NonNull::new(ct_raw).expect("bicycl_joye_libert_encrypt_decimal returned null");
758        Ok(JoyeLibertCiphertext {
759            raw,
760            _marker: PhantomData,
761        })
762    }
763
764    /// Decrypts a ciphertext, returning the plaintext as a decimal string.
765    pub fn decrypt_decimal(
766        &self,
767        ctx: &Context,
768        sk: &JoyeLibertSecretKey,
769        ct: &JoyeLibertCiphertext,
770    ) -> Result<String> {
771        ffi_string_from_len(|buf, len| unsafe {
772            bicycl_rs_sys::bicycl_joye_libert_decrypt_decimal(
773                ctx.raw.as_ptr(),
774                self.raw.as_ptr(),
775                sk.raw.as_ptr(),
776                ct.raw.as_ptr(),
777                buf,
778                len,
779            )
780        })
781    }
782}
783
784impl Drop for JoyeLibert {
785    fn drop(&mut self) {
786        unsafe { bicycl_rs_sys::bicycl_joye_libert_free(self.raw.as_ptr()) }
787    }
788}
789
790impl Drop for JoyeLibertSecretKey {
791    fn drop(&mut self) {
792        unsafe { bicycl_rs_sys::bicycl_joye_libert_sk_free(self.raw.as_ptr()) }
793    }
794}
795
796impl Drop for JoyeLibertPublicKey {
797    fn drop(&mut self) {
798        unsafe { bicycl_rs_sys::bicycl_joye_libert_pk_free(self.raw.as_ptr()) }
799    }
800}
801
802impl Drop for JoyeLibertCiphertext {
803    fn drop(&mut self) {
804        unsafe { bicycl_rs_sys::bicycl_joye_libert_ct_free(self.raw.as_ptr()) }
805    }
806}
807
808/// A CL_HSMqk class-group encryption scheme with additive homomorphism over `Z/q^k`.
809///
810/// Create via [`Context::cl_hsmqk`].
811#[derive(Debug)]
812pub struct ClHsmqk {
813    raw: NonNull<bicycl_rs_sys::bicycl_cl_hsmqk_t>,
814    _marker: PhantomData<*mut ()>,
815}
816
817/// A CL_HSMqk secret key.  Keep this private.
818#[derive(Debug)]
819pub struct ClHsmqkSecretKey {
820    raw: NonNull<bicycl_rs_sys::bicycl_cl_hsmqk_sk_t>,
821    _marker: PhantomData<*mut ()>,
822}
823
824/// A CL_HSMqk public key.  Safe to share.
825#[derive(Debug)]
826pub struct ClHsmqkPublicKey {
827    raw: NonNull<bicycl_rs_sys::bicycl_cl_hsmqk_pk_t>,
828    _marker: PhantomData<*mut ()>,
829}
830
831/// A CL_HSMqk ciphertext.
832#[derive(Debug)]
833pub struct ClHsmqkCiphertext {
834    raw: NonNull<bicycl_rs_sys::bicycl_cl_hsmqk_ct_t>,
835    _marker: PhantomData<*mut ()>,
836}
837
838impl ClHsmqk {
839    /// Generates a fresh CL_HSMqk key pair.  Returns `(secret_key, public_key)`.
840    pub fn keygen(
841        &self,
842        ctx: &Context,
843        rng: &mut RandGen,
844    ) -> Result<(ClHsmqkSecretKey, ClHsmqkPublicKey)> {
845        let mut sk_raw = std::ptr::null_mut();
846        let mut pk_raw = std::ptr::null_mut();
847        let status = unsafe {
848            bicycl_rs_sys::bicycl_cl_hsmqk_keygen(
849                ctx.raw.as_ptr(),
850                self.raw.as_ptr(),
851                rng.raw.as_ptr(),
852                &mut sk_raw as *mut _,
853                &mut pk_raw as *mut _,
854            )
855        };
856        status_to_result(status)?;
857
858        let sk = ClHsmqkSecretKey {
859            raw: NonNull::new(sk_raw).expect("bicycl_cl_hsmqk_keygen/sk returned null"),
860            _marker: PhantomData,
861        };
862        let pk = ClHsmqkPublicKey {
863            raw: NonNull::new(pk_raw).expect("bicycl_cl_hsmqk_keygen/pk returned null"),
864            _marker: PhantomData,
865        };
866        Ok((sk, pk))
867    }
868
869    /// Encrypts a plaintext in `Z/q^k` given as a decimal string.
870    pub fn encrypt_decimal(
871        &self,
872        ctx: &Context,
873        pk: &ClHsmqkPublicKey,
874        rng: &mut RandGen,
875        message_decimal: &str,
876    ) -> Result<ClHsmqkCiphertext> {
877        let message_c = CString::new(message_decimal)?;
878        let mut ct_raw = std::ptr::null_mut();
879        let status = unsafe {
880            bicycl_rs_sys::bicycl_cl_hsmqk_encrypt_decimal(
881                ctx.raw.as_ptr(),
882                self.raw.as_ptr(),
883                pk.raw.as_ptr(),
884                rng.raw.as_ptr(),
885                message_c.as_ptr(),
886                &mut ct_raw as *mut _,
887            )
888        };
889        status_to_result(status)?;
890        let raw = NonNull::new(ct_raw).expect("bicycl_cl_hsmqk_encrypt_decimal returned null");
891        Ok(ClHsmqkCiphertext {
892            raw,
893            _marker: PhantomData,
894        })
895    }
896
897    /// Decrypts a CL_HSMqk ciphertext, returning the plaintext as a decimal string.
898    pub fn decrypt_decimal(
899        &self,
900        ctx: &Context,
901        sk: &ClHsmqkSecretKey,
902        ct: &ClHsmqkCiphertext,
903    ) -> Result<String> {
904        ffi_string_from_len(|buf, len| unsafe {
905            bicycl_rs_sys::bicycl_cl_hsmqk_decrypt_decimal(
906                ctx.raw.as_ptr(),
907                self.raw.as_ptr(),
908                sk.raw.as_ptr(),
909                ct.raw.as_ptr(),
910                buf,
911                len,
912            )
913        })
914    }
915
916    /// Homomorphically adds two ciphertexts: `Enc(a) ⊕ Enc(b) = Enc(a+b mod q^k)`.
917    pub fn add_ciphertexts(
918        &self,
919        ctx: &Context,
920        pk: &ClHsmqkPublicKey,
921        rng: &mut RandGen,
922        ca: &ClHsmqkCiphertext,
923        cb: &ClHsmqkCiphertext,
924    ) -> Result<ClHsmqkCiphertext> {
925        let mut ct_raw = std::ptr::null_mut();
926        let status = unsafe {
927            bicycl_rs_sys::bicycl_cl_hsmqk_add_ciphertexts(
928                ctx.raw.as_ptr(),
929                self.raw.as_ptr(),
930                pk.raw.as_ptr(),
931                rng.raw.as_ptr(),
932                ca.raw.as_ptr(),
933                cb.raw.as_ptr(),
934                &mut ct_raw as *mut _,
935            )
936        };
937        status_to_result(status)?;
938        let raw = NonNull::new(ct_raw).expect("bicycl_cl_hsmqk_add_ciphertexts returned null");
939        Ok(ClHsmqkCiphertext {
940            raw,
941            _marker: PhantomData,
942        })
943    }
944
945    /// Homomorphically multiplies a ciphertext by a scalar: `Enc(m) * s = Enc(m*s mod q^k)`.
946    ///
947    /// `scalar_decimal` is the scalar as a decimal string.
948    pub fn scal_ciphertext_decimal(
949        &self,
950        ctx: &Context,
951        pk: &ClHsmqkPublicKey,
952        rng: &mut RandGen,
953        ct: &ClHsmqkCiphertext,
954        scalar_decimal: &str,
955    ) -> Result<ClHsmqkCiphertext> {
956        let scalar_c = CString::new(scalar_decimal)?;
957        let mut out_raw = std::ptr::null_mut();
958        let status = unsafe {
959            bicycl_rs_sys::bicycl_cl_hsmqk_scal_ciphertext_decimal(
960                ctx.raw.as_ptr(),
961                self.raw.as_ptr(),
962                pk.raw.as_ptr(),
963                rng.raw.as_ptr(),
964                ct.raw.as_ptr(),
965                scalar_c.as_ptr(),
966                &mut out_raw as *mut _,
967            )
968        };
969        status_to_result(status)?;
970        let raw =
971            NonNull::new(out_raw).expect("bicycl_cl_hsmqk_scal_ciphertext_decimal returned null");
972        Ok(ClHsmqkCiphertext {
973            raw,
974            _marker: PhantomData,
975        })
976    }
977
978    /// Computes `Enc(a + b*s mod q^k)`: adds ciphertext `ca` to a scalar multiple of `cb`.
979    ///
980    /// Specifically, multiplies `cb` by `scalar_decimal` and adds the result to `ca`,
981    /// equivalent to `scal_ciphertext_decimal(cb, s)` then `add_ciphertexts(ca, scaled_cb)`
982    /// but in a single C call.  `scalar_decimal` is the scalar as a decimal string.
983    pub fn addscal_ciphertexts_decimal(
984        &self,
985        ctx: &Context,
986        pk: &ClHsmqkPublicKey,
987        rng: &mut RandGen,
988        ca: &ClHsmqkCiphertext,
989        cb: &ClHsmqkCiphertext,
990        scalar_decimal: &str,
991    ) -> Result<ClHsmqkCiphertext> {
992        let scalar_c = CString::new(scalar_decimal)?;
993        let mut out_raw = std::ptr::null_mut();
994        let status = unsafe {
995            bicycl_rs_sys::bicycl_cl_hsmqk_addscal_ciphertexts_decimal(
996                ctx.raw.as_ptr(),
997                self.raw.as_ptr(),
998                pk.raw.as_ptr(),
999                rng.raw.as_ptr(),
1000                ca.raw.as_ptr(),
1001                cb.raw.as_ptr(),
1002                scalar_c.as_ptr(),
1003                &mut out_raw as *mut _,
1004            )
1005        };
1006        status_to_result(status)?;
1007        let raw = NonNull::new(out_raw)
1008            .expect("bicycl_cl_hsmqk_addscal_ciphertexts_decimal returned null");
1009        Ok(ClHsmqkCiphertext {
1010            raw,
1011            _marker: PhantomData,
1012        })
1013    }
1014}
1015
1016impl Drop for ClHsmqk {
1017    fn drop(&mut self) {
1018        unsafe { bicycl_rs_sys::bicycl_cl_hsmqk_free(self.raw.as_ptr()) }
1019    }
1020}
1021
1022impl Drop for ClHsmqkSecretKey {
1023    fn drop(&mut self) {
1024        unsafe { bicycl_rs_sys::bicycl_cl_hsmqk_sk_free(self.raw.as_ptr()) }
1025    }
1026}
1027
1028impl Drop for ClHsmqkPublicKey {
1029    fn drop(&mut self) {
1030        unsafe { bicycl_rs_sys::bicycl_cl_hsmqk_pk_free(self.raw.as_ptr()) }
1031    }
1032}
1033
1034impl Drop for ClHsmqkCiphertext {
1035    fn drop(&mut self) {
1036        unsafe { bicycl_rs_sys::bicycl_cl_hsmqk_ct_free(self.raw.as_ptr()) }
1037    }
1038}
1039
1040/// A CL_HSM2k class-group encryption scheme with additive homomorphism over `Z/2^k`.
1041///
1042/// Create via [`Context::cl_hsm2k`].
1043#[derive(Debug)]
1044pub struct ClHsm2k {
1045    raw: NonNull<bicycl_rs_sys::bicycl_cl_hsm2k_t>,
1046    _marker: PhantomData<*mut ()>,
1047}
1048
1049/// A CL_HSM2k secret key.  Keep this private.
1050#[derive(Debug)]
1051pub struct ClHsm2kSecretKey {
1052    raw: NonNull<bicycl_rs_sys::bicycl_cl_hsm2k_sk_t>,
1053    _marker: PhantomData<*mut ()>,
1054}
1055
1056/// A CL_HSM2k public key.  Safe to share.
1057#[derive(Debug)]
1058pub struct ClHsm2kPublicKey {
1059    raw: NonNull<bicycl_rs_sys::bicycl_cl_hsm2k_pk_t>,
1060    _marker: PhantomData<*mut ()>,
1061}
1062
1063/// A CL_HSM2k ciphertext.
1064#[derive(Debug)]
1065pub struct ClHsm2kCiphertext {
1066    raw: NonNull<bicycl_rs_sys::bicycl_cl_hsm2k_ct_t>,
1067    _marker: PhantomData<*mut ()>,
1068}
1069
1070impl ClHsm2k {
1071    /// Generates a fresh CL_HSM2k key pair.  Returns `(secret_key, public_key)`.
1072    pub fn keygen(
1073        &self,
1074        ctx: &Context,
1075        rng: &mut RandGen,
1076    ) -> Result<(ClHsm2kSecretKey, ClHsm2kPublicKey)> {
1077        let mut sk_raw = std::ptr::null_mut();
1078        let mut pk_raw = std::ptr::null_mut();
1079        let status = unsafe {
1080            bicycl_rs_sys::bicycl_cl_hsm2k_keygen(
1081                ctx.raw.as_ptr(),
1082                self.raw.as_ptr(),
1083                rng.raw.as_ptr(),
1084                &mut sk_raw as *mut _,
1085                &mut pk_raw as *mut _,
1086            )
1087        };
1088        status_to_result(status)?;
1089
1090        let sk = ClHsm2kSecretKey {
1091            raw: NonNull::new(sk_raw).expect("bicycl_cl_hsm2k_keygen/sk returned null"),
1092            _marker: PhantomData,
1093        };
1094        let pk = ClHsm2kPublicKey {
1095            raw: NonNull::new(pk_raw).expect("bicycl_cl_hsm2k_keygen/pk returned null"),
1096            _marker: PhantomData,
1097        };
1098        Ok((sk, pk))
1099    }
1100
1101    /// Encrypts a plaintext in `Z/2^k` given as a decimal string.
1102    pub fn encrypt_decimal(
1103        &self,
1104        ctx: &Context,
1105        pk: &ClHsm2kPublicKey,
1106        rng: &mut RandGen,
1107        message_decimal: &str,
1108    ) -> Result<ClHsm2kCiphertext> {
1109        let message_c = CString::new(message_decimal)?;
1110        let mut ct_raw = std::ptr::null_mut();
1111        let status = unsafe {
1112            bicycl_rs_sys::bicycl_cl_hsm2k_encrypt_decimal(
1113                ctx.raw.as_ptr(),
1114                self.raw.as_ptr(),
1115                pk.raw.as_ptr(),
1116                rng.raw.as_ptr(),
1117                message_c.as_ptr(),
1118                &mut ct_raw as *mut _,
1119            )
1120        };
1121        status_to_result(status)?;
1122        let raw = NonNull::new(ct_raw).expect("bicycl_cl_hsm2k_encrypt_decimal returned null");
1123        Ok(ClHsm2kCiphertext {
1124            raw,
1125            _marker: PhantomData,
1126        })
1127    }
1128
1129    /// Decrypts a CL_HSM2k ciphertext, returning the plaintext as a decimal string.
1130    pub fn decrypt_decimal(
1131        &self,
1132        ctx: &Context,
1133        sk: &ClHsm2kSecretKey,
1134        ct: &ClHsm2kCiphertext,
1135    ) -> Result<String> {
1136        ffi_string_from_len(|buf, len| unsafe {
1137            bicycl_rs_sys::bicycl_cl_hsm2k_decrypt_decimal(
1138                ctx.raw.as_ptr(),
1139                self.raw.as_ptr(),
1140                sk.raw.as_ptr(),
1141                ct.raw.as_ptr(),
1142                buf,
1143                len,
1144            )
1145        })
1146    }
1147
1148    /// Homomorphically adds two ciphertexts: `Enc(a) ⊕ Enc(b) = Enc(a+b mod 2^k)`.
1149    pub fn add_ciphertexts(
1150        &self,
1151        ctx: &Context,
1152        pk: &ClHsm2kPublicKey,
1153        rng: &mut RandGen,
1154        ca: &ClHsm2kCiphertext,
1155        cb: &ClHsm2kCiphertext,
1156    ) -> Result<ClHsm2kCiphertext> {
1157        let mut ct_raw = std::ptr::null_mut();
1158        let status = unsafe {
1159            bicycl_rs_sys::bicycl_cl_hsm2k_add_ciphertexts(
1160                ctx.raw.as_ptr(),
1161                self.raw.as_ptr(),
1162                pk.raw.as_ptr(),
1163                rng.raw.as_ptr(),
1164                ca.raw.as_ptr(),
1165                cb.raw.as_ptr(),
1166                &mut ct_raw as *mut _,
1167            )
1168        };
1169        status_to_result(status)?;
1170        let raw = NonNull::new(ct_raw).expect("bicycl_cl_hsm2k_add_ciphertexts returned null");
1171        Ok(ClHsm2kCiphertext {
1172            raw,
1173            _marker: PhantomData,
1174        })
1175    }
1176
1177    /// Homomorphically multiplies a ciphertext by a scalar: `Enc(m) * s = Enc(m*s mod 2^k)`.
1178    pub fn scal_ciphertext_decimal(
1179        &self,
1180        ctx: &Context,
1181        pk: &ClHsm2kPublicKey,
1182        rng: &mut RandGen,
1183        ct: &ClHsm2kCiphertext,
1184        scalar_decimal: &str,
1185    ) -> Result<ClHsm2kCiphertext> {
1186        let scalar_c = CString::new(scalar_decimal)?;
1187        let mut out_raw = std::ptr::null_mut();
1188        let status = unsafe {
1189            bicycl_rs_sys::bicycl_cl_hsm2k_scal_ciphertext_decimal(
1190                ctx.raw.as_ptr(),
1191                self.raw.as_ptr(),
1192                pk.raw.as_ptr(),
1193                rng.raw.as_ptr(),
1194                ct.raw.as_ptr(),
1195                scalar_c.as_ptr(),
1196                &mut out_raw as *mut _,
1197            )
1198        };
1199        status_to_result(status)?;
1200        let raw =
1201            NonNull::new(out_raw).expect("bicycl_cl_hsm2k_scal_ciphertext_decimal returned null");
1202        Ok(ClHsm2kCiphertext {
1203            raw,
1204            _marker: PhantomData,
1205        })
1206    }
1207
1208    /// Computes `Enc(a + b*s mod 2^k)`: adds ciphertext `ca` to a scalar multiple of `cb`.
1209    ///
1210    /// Specifically, multiplies `cb` by `scalar_decimal` and adds the result to `ca`,
1211    /// equivalent to `scal_ciphertext_decimal(cb, s)` then `add_ciphertexts(ca, scaled_cb)`
1212    /// but in a single C call.  `scalar_decimal` is the scalar as a decimal string.
1213    pub fn addscal_ciphertexts_decimal(
1214        &self,
1215        ctx: &Context,
1216        pk: &ClHsm2kPublicKey,
1217        rng: &mut RandGen,
1218        ca: &ClHsm2kCiphertext,
1219        cb: &ClHsm2kCiphertext,
1220        scalar_decimal: &str,
1221    ) -> Result<ClHsm2kCiphertext> {
1222        let scalar_c = CString::new(scalar_decimal)?;
1223        let mut out_raw = std::ptr::null_mut();
1224        let status = unsafe {
1225            bicycl_rs_sys::bicycl_cl_hsm2k_addscal_ciphertexts_decimal(
1226                ctx.raw.as_ptr(),
1227                self.raw.as_ptr(),
1228                pk.raw.as_ptr(),
1229                rng.raw.as_ptr(),
1230                ca.raw.as_ptr(),
1231                cb.raw.as_ptr(),
1232                scalar_c.as_ptr(),
1233                &mut out_raw as *mut _,
1234            )
1235        };
1236        status_to_result(status)?;
1237        let raw = NonNull::new(out_raw)
1238            .expect("bicycl_cl_hsm2k_addscal_ciphertexts_decimal returned null");
1239        Ok(ClHsm2kCiphertext {
1240            raw,
1241            _marker: PhantomData,
1242        })
1243    }
1244}
1245
1246impl Drop for ClHsm2k {
1247    fn drop(&mut self) {
1248        unsafe { bicycl_rs_sys::bicycl_cl_hsm2k_free(self.raw.as_ptr()) }
1249    }
1250}
1251
1252impl Drop for ClHsm2kSecretKey {
1253    fn drop(&mut self) {
1254        unsafe { bicycl_rs_sys::bicycl_cl_hsm2k_sk_free(self.raw.as_ptr()) }
1255    }
1256}
1257
1258impl Drop for ClHsm2kPublicKey {
1259    fn drop(&mut self) {
1260        unsafe { bicycl_rs_sys::bicycl_cl_hsm2k_pk_free(self.raw.as_ptr()) }
1261    }
1262}
1263
1264impl Drop for ClHsm2kCiphertext {
1265    fn drop(&mut self) {
1266        unsafe { bicycl_rs_sys::bicycl_cl_hsm2k_ct_free(self.raw.as_ptr()) }
1267    }
1268}
1269
1270/// An ECDSA signature scheme instance.
1271///
1272/// Create via [`Context::ecdsa`].
1273#[derive(Debug)]
1274pub struct Ecdsa {
1275    raw: NonNull<bicycl_rs_sys::bicycl_ecdsa_t>,
1276    _marker: PhantomData<*mut ()>,
1277}
1278
1279/// An ECDSA secret (signing) key.  Keep this private.
1280#[derive(Debug)]
1281pub struct EcdsaSecretKey {
1282    raw: NonNull<bicycl_rs_sys::bicycl_ecdsa_sk_t>,
1283    _marker: PhantomData<*mut ()>,
1284}
1285
1286/// An ECDSA public (verification) key.  Safe to share.
1287#[derive(Debug)]
1288pub struct EcdsaPublicKey {
1289    raw: NonNull<bicycl_rs_sys::bicycl_ecdsa_pk_t>,
1290    _marker: PhantomData<*mut ()>,
1291}
1292
1293/// An ECDSA signature `(r, s)`.
1294#[derive(Debug)]
1295pub struct EcdsaSignature {
1296    raw: NonNull<bicycl_rs_sys::bicycl_ecdsa_sig_t>,
1297    _marker: PhantomData<*mut ()>,
1298}
1299
1300impl Ecdsa {
1301    /// Generates a fresh ECDSA key pair.  Returns `(secret_key, public_key)`.
1302    pub fn keygen(
1303        &self,
1304        ctx: &Context,
1305        rng: &mut RandGen,
1306    ) -> Result<(EcdsaSecretKey, EcdsaPublicKey)> {
1307        let mut sk_raw = std::ptr::null_mut();
1308        let mut pk_raw = std::ptr::null_mut();
1309        let status = unsafe {
1310            bicycl_rs_sys::bicycl_ecdsa_keygen(
1311                ctx.raw.as_ptr(),
1312                self.raw.as_ptr(),
1313                rng.raw.as_ptr(),
1314                &mut sk_raw as *mut _,
1315                &mut pk_raw as *mut _,
1316            )
1317        };
1318        status_to_result(status)?;
1319        let sk = EcdsaSecretKey {
1320            raw: NonNull::new(sk_raw).expect("bicycl_ecdsa_keygen/sk returned null"),
1321            _marker: PhantomData,
1322        };
1323        let pk = EcdsaPublicKey {
1324            raw: NonNull::new(pk_raw).expect("bicycl_ecdsa_keygen/pk returned null"),
1325            _marker: PhantomData,
1326        };
1327        Ok((sk, pk))
1328    }
1329
1330    /// Signs a message with the given secret key.
1331    ///
1332    /// `msg` is the raw message bytes (not a hash).  The C library hashes it internally.
1333    pub fn sign_message(
1334        &self,
1335        ctx: &Context,
1336        rng: &mut RandGen,
1337        sk: &EcdsaSecretKey,
1338        msg: &[u8],
1339    ) -> Result<EcdsaSignature> {
1340        let mut sig_raw = std::ptr::null_mut();
1341        let status = unsafe {
1342            bicycl_rs_sys::bicycl_ecdsa_sign_message(
1343                ctx.raw.as_ptr(),
1344                self.raw.as_ptr(),
1345                rng.raw.as_ptr(),
1346                sk.raw.as_ptr(),
1347                msg.as_ptr(),
1348                msg.len(),
1349                &mut sig_raw as *mut _,
1350            )
1351        };
1352        status_to_result(status)?;
1353        let raw = NonNull::new(sig_raw).expect("bicycl_ecdsa_sign_message returned null");
1354        Ok(EcdsaSignature {
1355            raw,
1356            _marker: PhantomData,
1357        })
1358    }
1359
1360    /// Verifies a signature against a message and public key.
1361    ///
1362    /// Returns `true` if the signature is valid, `false` otherwise.
1363    /// Does **not** return an error on invalid signatures — errors indicate
1364    /// an internal failure (e.g., allocation), not a cryptographic mismatch.
1365    pub fn verify_message(
1366        &self,
1367        ctx: &Context,
1368        pk: &EcdsaPublicKey,
1369        msg: &[u8],
1370        sig: &EcdsaSignature,
1371    ) -> Result<bool> {
1372        let mut out_valid: c_int = 0;
1373        let status = unsafe {
1374            bicycl_rs_sys::bicycl_ecdsa_verify_message(
1375                ctx.raw.as_ptr(),
1376                self.raw.as_ptr(),
1377                pk.raw.as_ptr(),
1378                msg.as_ptr(),
1379                msg.len(),
1380                sig.raw.as_ptr(),
1381                &mut out_valid as *mut _,
1382            )
1383        };
1384        status_to_result(status)?;
1385        Ok(out_valid != 0)
1386    }
1387}
1388
1389impl EcdsaSignature {
1390    /// Returns the `r` component of the signature as a decimal string.
1391    pub fn r_decimal(&self, ctx: &Context) -> Result<String> {
1392        ffi_string_from_len(|buf, len| unsafe {
1393            bicycl_rs_sys::bicycl_ecdsa_sig_r_decimal(ctx.raw.as_ptr(), self.raw.as_ptr(), buf, len)
1394        })
1395    }
1396
1397    /// Returns the `s` component of the signature as a decimal string.
1398    pub fn s_decimal(&self, ctx: &Context) -> Result<String> {
1399        ffi_string_from_len(|buf, len| unsafe {
1400            bicycl_rs_sys::bicycl_ecdsa_sig_s_decimal(ctx.raw.as_ptr(), self.raw.as_ptr(), buf, len)
1401        })
1402    }
1403}
1404
1405// ── Two-party ECDSA session with typestate ──
1406
1407/// State markers for [`TwoPartyEcdsaSession`].
1408pub mod two_party {
1409    pub struct New;
1410    pub struct Keygen1;
1411    pub struct Keygen2;
1412    pub struct Keygen3;
1413    pub struct KeygenDone;
1414    pub struct Sign1;
1415    pub struct Sign2;
1416    pub struct Sign3;
1417    pub struct Sign4;
1418    pub struct SignDone;
1419}
1420
1421/// A stateful session for the interactive two-party (2-of-2) ECDSA signing protocol.
1422///
1423/// Create via [`Context::two_party_ecdsa_session`].  Each round method consumes
1424/// the session and returns the next state on success.  On error, the session is
1425/// dropped (the protocol is broken and must be restarted from scratch).
1426///
1427/// ```text
1428/// New → keygen_round1 → Keygen1 → keygen_round2 → Keygen2
1429///     → keygen_round3 → Keygen3 → keygen_round4 → KeygenDone
1430///     → sign_round1 → Sign1 → sign_round2 → Sign2
1431///     → sign_round3 → Sign3 → sign_round4 → Sign4
1432///     → sign_finalize → SignDone
1433/// ```
1434///
1435/// Calling a method from the wrong state is a compile-time error:
1436///
1437/// ```compile_fail
1438/// # fn main() -> Result<(), bicycl_rs::Error> {
1439/// let ctx = bicycl_rs::Context::new()?;
1440/// let mut rng = ctx.randgen_from_seed_decimal("1")?;
1441/// let session = ctx.two_party_ecdsa_session(&mut rng, 112)?;
1442/// // ERROR: New state has no sign_round1
1443/// session.sign_round1(&ctx, &mut rng, b"msg")?;
1444/// # Ok(()) }
1445/// ```
1446pub struct TwoPartyEcdsaSession<S = two_party::New> {
1447    raw: NonNull<bicycl_rs_sys::bicycl_two_party_ecdsa_session_t>,
1448    _state: PhantomData<S>,
1449    _marker: PhantomData<*mut ()>,
1450}
1451
1452impl<S> std::fmt::Debug for TwoPartyEcdsaSession<S> {
1453    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1454        f.debug_struct("TwoPartyEcdsaSession")
1455            .field("raw", &self.raw)
1456            .finish()
1457    }
1458}
1459
1460impl<S> TwoPartyEcdsaSession<S> {
1461    fn transition<T>(self) -> TwoPartyEcdsaSession<T> {
1462        let raw = self.raw;
1463        std::mem::forget(self);
1464        TwoPartyEcdsaSession {
1465            raw,
1466            _state: PhantomData,
1467            _marker: PhantomData,
1468        }
1469    }
1470}
1471
1472impl<S> Drop for TwoPartyEcdsaSession<S> {
1473    fn drop(&mut self) {
1474        unsafe { bicycl_rs_sys::bicycl_two_party_ecdsa_session_free(self.raw.as_ptr()) }
1475    }
1476}
1477
1478impl TwoPartyEcdsaSession<two_party::New> {
1479    pub fn keygen_round1(
1480        self,
1481        ctx: &Context,
1482        rng: &mut RandGen,
1483    ) -> Result<TwoPartyEcdsaSession<two_party::Keygen1>> {
1484        let status = unsafe {
1485            bicycl_rs_sys::bicycl_two_party_ecdsa_keygen_round1(
1486                ctx.raw.as_ptr(),
1487                self.raw.as_ptr(),
1488                rng.raw.as_ptr(),
1489            )
1490        };
1491        status_to_result(status)?;
1492        Ok(self.transition())
1493    }
1494}
1495
1496impl TwoPartyEcdsaSession<two_party::Keygen1> {
1497    pub fn keygen_round2(
1498        self,
1499        ctx: &Context,
1500        rng: &mut RandGen,
1501    ) -> Result<TwoPartyEcdsaSession<two_party::Keygen2>> {
1502        let status = unsafe {
1503            bicycl_rs_sys::bicycl_two_party_ecdsa_keygen_round2(
1504                ctx.raw.as_ptr(),
1505                self.raw.as_ptr(),
1506                rng.raw.as_ptr(),
1507            )
1508        };
1509        status_to_result(status)?;
1510        Ok(self.transition())
1511    }
1512}
1513
1514impl TwoPartyEcdsaSession<two_party::Keygen2> {
1515    pub fn keygen_round3(
1516        self,
1517        ctx: &Context,
1518        rng: &mut RandGen,
1519    ) -> Result<TwoPartyEcdsaSession<two_party::Keygen3>> {
1520        let status = unsafe {
1521            bicycl_rs_sys::bicycl_two_party_ecdsa_keygen_round3(
1522                ctx.raw.as_ptr(),
1523                self.raw.as_ptr(),
1524                rng.raw.as_ptr(),
1525            )
1526        };
1527        status_to_result(status)?;
1528        Ok(self.transition())
1529    }
1530}
1531
1532impl TwoPartyEcdsaSession<two_party::Keygen3> {
1533    pub fn keygen_round4(
1534        self,
1535        ctx: &Context,
1536    ) -> Result<TwoPartyEcdsaSession<two_party::KeygenDone>> {
1537        let status = unsafe {
1538            bicycl_rs_sys::bicycl_two_party_ecdsa_keygen_round4(ctx.raw.as_ptr(), self.raw.as_ptr())
1539        };
1540        status_to_result(status)?;
1541        Ok(self.transition())
1542    }
1543}
1544
1545impl TwoPartyEcdsaSession<two_party::KeygenDone> {
1546    pub fn sign_round1(
1547        self,
1548        ctx: &Context,
1549        rng: &mut RandGen,
1550        msg: &[u8],
1551    ) -> Result<TwoPartyEcdsaSession<two_party::Sign1>> {
1552        let status = unsafe {
1553            bicycl_rs_sys::bicycl_two_party_ecdsa_sign_round1(
1554                ctx.raw.as_ptr(),
1555                self.raw.as_ptr(),
1556                rng.raw.as_ptr(),
1557                msg.as_ptr(),
1558                msg.len(),
1559            )
1560        };
1561        status_to_result(status)?;
1562        Ok(self.transition())
1563    }
1564}
1565
1566impl TwoPartyEcdsaSession<two_party::Sign1> {
1567    pub fn sign_round2(
1568        self,
1569        ctx: &Context,
1570        rng: &mut RandGen,
1571    ) -> Result<TwoPartyEcdsaSession<two_party::Sign2>> {
1572        let status = unsafe {
1573            bicycl_rs_sys::bicycl_two_party_ecdsa_sign_round2(
1574                ctx.raw.as_ptr(),
1575                self.raw.as_ptr(),
1576                rng.raw.as_ptr(),
1577            )
1578        };
1579        status_to_result(status)?;
1580        Ok(self.transition())
1581    }
1582}
1583
1584impl TwoPartyEcdsaSession<two_party::Sign2> {
1585    pub fn sign_round3(self, ctx: &Context) -> Result<TwoPartyEcdsaSession<two_party::Sign3>> {
1586        let status = unsafe {
1587            bicycl_rs_sys::bicycl_two_party_ecdsa_sign_round3(ctx.raw.as_ptr(), self.raw.as_ptr())
1588        };
1589        status_to_result(status)?;
1590        Ok(self.transition())
1591    }
1592}
1593
1594impl TwoPartyEcdsaSession<two_party::Sign3> {
1595    pub fn sign_round4(
1596        self,
1597        ctx: &Context,
1598        rng: &mut RandGen,
1599    ) -> Result<TwoPartyEcdsaSession<two_party::Sign4>> {
1600        let status = unsafe {
1601            bicycl_rs_sys::bicycl_two_party_ecdsa_sign_round4(
1602                ctx.raw.as_ptr(),
1603                self.raw.as_ptr(),
1604                rng.raw.as_ptr(),
1605            )
1606        };
1607        status_to_result(status)?;
1608        Ok(self.transition())
1609    }
1610}
1611
1612impl TwoPartyEcdsaSession<two_party::Sign4> {
1613    /// Returns `true` if the produced signature is valid.
1614    pub fn sign_finalize(
1615        self,
1616        ctx: &Context,
1617    ) -> Result<(TwoPartyEcdsaSession<two_party::SignDone>, bool)> {
1618        let mut out_valid: c_int = 0;
1619        let status = unsafe {
1620            bicycl_rs_sys::bicycl_two_party_ecdsa_sign_finalize(
1621                ctx.raw.as_ptr(),
1622                self.raw.as_ptr(),
1623                &mut out_valid as *mut _,
1624            )
1625        };
1626        status_to_result(status)?;
1627        Ok((self.transition(), out_valid != 0))
1628    }
1629}
1630
1631// ── CL DLog session with typestate ──
1632
1633/// State markers for [`ClDlogSession`].
1634pub mod cl_dlog {
1635    pub struct New;
1636    pub struct Prepared;
1637    pub struct Proved;
1638    pub struct StatementImported;
1639    pub struct Ready;
1640}
1641
1642/// A session for the interactive CL DLog (discrete logarithm) proof protocol.
1643///
1644/// Create via [`Context::cl_dlog_session`].
1645///
1646/// **Prover path:**
1647/// ```text
1648/// New → prepare_statement → Prepared → prove_round → Proved
1649/// ```
1650/// In the `Proved` state: `export_statement`, `export_proof`, `verify_round`.
1651///
1652/// **Verifier path:**
1653/// ```text
1654/// New → import_statement → StatementImported → import_proof → Ready
1655/// ```
1656/// In the `Ready` state: `verify_round`.
1657///
1658/// Calling a method from the wrong state is a compile-time error:
1659///
1660/// ```compile_fail
1661/// # fn main() -> Result<(), bicycl_rs::Error> {
1662/// let ctx = bicycl_rs::Context::new()?;
1663/// let mut rng = ctx.randgen_from_seed_decimal("1")?;
1664/// let session = ctx.cl_dlog_session(&mut rng, 112)?;
1665/// // ERROR: New state has no prove_round
1666/// session.prove_round(&ctx, &mut rng)?;
1667/// # Ok(()) }
1668/// ```
1669pub struct ClDlogSession<S = cl_dlog::New> {
1670    raw: NonNull<bicycl_rs_sys::bicycl_cl_dlog_session_t>,
1671    _state: PhantomData<S>,
1672    _marker: PhantomData<*mut ()>,
1673}
1674
1675impl<S> std::fmt::Debug for ClDlogSession<S> {
1676    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1677        f.debug_struct("ClDlogSession")
1678            .field("raw", &self.raw)
1679            .finish()
1680    }
1681}
1682
1683impl<S> ClDlogSession<S> {
1684    fn transition<T>(self) -> ClDlogSession<T> {
1685        let raw = self.raw;
1686        std::mem::forget(self);
1687        ClDlogSession {
1688            raw,
1689            _state: PhantomData,
1690            _marker: PhantomData,
1691        }
1692    }
1693}
1694
1695impl<S> Drop for ClDlogSession<S> {
1696    fn drop(&mut self) {
1697        unsafe { bicycl_rs_sys::bicycl_cl_dlog_session_free(self.raw.as_ptr()) }
1698    }
1699}
1700
1701/// A serializable message container used to exchange statements and proofs
1702/// between prover and verifier in the CL DLog protocol.
1703///
1704/// Create with [`ClDlogMessage::new`] and serialise/deserialise with
1705/// [`to_bytes`][Self::to_bytes] / [`load_bytes`][Self::load_bytes].
1706#[derive(Debug)]
1707pub struct ClDlogMessage {
1708    raw: NonNull<bicycl_rs_sys::bicycl_cl_dlog_message_t>,
1709    _marker: PhantomData<*mut ()>,
1710}
1711
1712impl ClDlogSession<cl_dlog::New> {
1713    /// Prepares the statement (prover path).
1714    pub fn prepare_statement(
1715        self,
1716        ctx: &Context,
1717        rng: &mut RandGen,
1718    ) -> Result<ClDlogSession<cl_dlog::Prepared>> {
1719        let status = unsafe {
1720            bicycl_rs_sys::bicycl_cl_dlog_session_prepare_statement(
1721                ctx.raw.as_ptr(),
1722                self.raw.as_ptr(),
1723                rng.raw.as_ptr(),
1724            )
1725        };
1726        status_to_result(status)?;
1727        Ok(self.transition())
1728    }
1729
1730    /// Imports the prover's statement (verifier path).
1731    pub fn import_statement(
1732        self,
1733        ctx: &Context,
1734        msg: &ClDlogMessage,
1735    ) -> Result<ClDlogSession<cl_dlog::StatementImported>> {
1736        let status = unsafe {
1737            bicycl_rs_sys::bicycl_cl_dlog_session_import_statement(
1738                ctx.raw.as_ptr(),
1739                self.raw.as_ptr(),
1740                msg.raw.as_ptr(),
1741            )
1742        };
1743        status_to_result(status)?;
1744        Ok(self.transition())
1745    }
1746}
1747
1748impl ClDlogSession<cl_dlog::Prepared> {
1749    /// Executes the prover's round (generates the DLog proof).
1750    pub fn prove_round(
1751        self,
1752        ctx: &Context,
1753        rng: &mut RandGen,
1754    ) -> Result<ClDlogSession<cl_dlog::Proved>> {
1755        let status = unsafe {
1756            bicycl_rs_sys::bicycl_cl_dlog_session_prove_round(
1757                ctx.raw.as_ptr(),
1758                self.raw.as_ptr(),
1759                rng.raw.as_ptr(),
1760            )
1761        };
1762        status_to_result(status)?;
1763        Ok(self.transition())
1764    }
1765}
1766
1767impl ClDlogSession<cl_dlog::Proved> {
1768    /// Exports the statement into `out_msg` so it can be sent to the verifier.
1769    pub fn export_statement(&self, ctx: &Context, out_msg: &mut ClDlogMessage) -> Result<()> {
1770        let status = unsafe {
1771            bicycl_rs_sys::bicycl_cl_dlog_session_export_statement(
1772                ctx.raw.as_ptr(),
1773                self.raw.as_ptr(),
1774                out_msg.raw.as_ptr(),
1775            )
1776        };
1777        status_to_result(status)
1778    }
1779
1780    /// Exports the proof into `out_msg` so it can be sent to the verifier.
1781    pub fn export_proof(&self, ctx: &Context, out_msg: &mut ClDlogMessage) -> Result<()> {
1782        let status = unsafe {
1783            bicycl_rs_sys::bicycl_cl_dlog_session_export_proof(
1784                ctx.raw.as_ptr(),
1785                self.raw.as_ptr(),
1786                out_msg.raw.as_ptr(),
1787            )
1788        };
1789        status_to_result(status)
1790    }
1791
1792    /// Verifies the proof (self-check).  Returns `true` if valid.
1793    pub fn verify_round(&self, ctx: &Context) -> Result<bool> {
1794        let mut out_valid: c_int = 0;
1795        let status = unsafe {
1796            bicycl_rs_sys::bicycl_cl_dlog_session_verify_round(
1797                ctx.raw.as_ptr(),
1798                self.raw.as_ptr(),
1799                &mut out_valid as *mut _,
1800            )
1801        };
1802        status_to_result(status)?;
1803        Ok(out_valid != 0)
1804    }
1805}
1806
1807impl ClDlogSession<cl_dlog::StatementImported> {
1808    /// Imports the proof (on the verifier side).
1809    pub fn import_proof(
1810        self,
1811        ctx: &Context,
1812        msg: &ClDlogMessage,
1813    ) -> Result<ClDlogSession<cl_dlog::Ready>> {
1814        let status = unsafe {
1815            bicycl_rs_sys::bicycl_cl_dlog_session_import_proof(
1816                ctx.raw.as_ptr(),
1817                self.raw.as_ptr(),
1818                msg.raw.as_ptr(),
1819            )
1820        };
1821        status_to_result(status)?;
1822        Ok(self.transition())
1823    }
1824}
1825
1826impl ClDlogSession<cl_dlog::Ready> {
1827    /// Executes the verifier's round.  Returns `true` if the proof is valid.
1828    pub fn verify_round(&self, ctx: &Context) -> Result<bool> {
1829        let mut out_valid: c_int = 0;
1830        let status = unsafe {
1831            bicycl_rs_sys::bicycl_cl_dlog_session_verify_round(
1832                ctx.raw.as_ptr(),
1833                self.raw.as_ptr(),
1834                &mut out_valid as *mut _,
1835            )
1836        };
1837        status_to_result(status)?;
1838        Ok(out_valid != 0)
1839    }
1840}
1841
1842impl ClDlogMessage {
1843    /// Creates an empty message container.
1844    pub fn new() -> Result<Self> {
1845        let mut raw = std::ptr::null_mut();
1846        let status = unsafe { bicycl_rs_sys::bicycl_cl_dlog_message_new(&mut raw as *mut _) };
1847        status_to_result(status)?;
1848        let raw = NonNull::new(raw).expect("bicycl_cl_dlog_message_new returned null");
1849        Ok(Self {
1850            raw,
1851            _marker: PhantomData,
1852        })
1853    }
1854
1855    /// Serializes the message to bytes for transmission.
1856    pub fn to_bytes(&self, ctx: &Context) -> Result<Vec<u8>> {
1857        ffi_bytes_from_len(|buf, len| unsafe {
1858            bicycl_rs_sys::bicycl_cl_dlog_message_export_bytes(
1859                ctx.raw.as_ptr(),
1860                self.raw.as_ptr(),
1861                buf,
1862                len,
1863            )
1864        })
1865    }
1866
1867    /// Deserializes bytes into this message container (overwrites any previous content).
1868    pub fn load_bytes(&mut self, ctx: &Context, bytes: &[u8]) -> Result<()> {
1869        let status = unsafe {
1870            bicycl_rs_sys::bicycl_cl_dlog_message_import_bytes(
1871                ctx.raw.as_ptr(),
1872                self.raw.as_ptr(),
1873                bytes.as_ptr(),
1874                bytes.len(),
1875            )
1876        };
1877        status_to_result(status)
1878    }
1879}
1880
1881impl Drop for ClDlogMessage {
1882    fn drop(&mut self) {
1883        unsafe { bicycl_rs_sys::bicycl_cl_dlog_message_free(self.raw.as_ptr()) }
1884    }
1885}
1886
1887// ── Threshold ECDSA session with typestate ──
1888
1889/// State markers for [`ThresholdEcdsaSession`].
1890pub mod threshold {
1891    pub struct New;
1892    pub struct Keygen1;
1893    pub struct Keygen2;
1894    pub struct KeygenDone;
1895    pub struct Sign1;
1896    pub struct Sign2;
1897    pub struct Sign3;
1898    pub struct Sign4;
1899    pub struct Sign5;
1900    pub struct Sign6;
1901    pub struct Sign7;
1902    pub struct Sign8;
1903    pub struct SignDone;
1904}
1905
1906/// A stateful session for the threshold (t-of-n) ECDSA signing protocol.
1907///
1908/// Create via [`Context::threshold_ecdsa_session`].
1909///
1910/// ```text
1911/// New → keygen_round1 → Keygen1 → keygen_round2 → Keygen2
1912///     → keygen_finalize → KeygenDone
1913///     → sign_round1 → Sign1 → ... → Sign8
1914///     → sign_finalize → SignDone (signature_valid)
1915/// ```
1916///
1917/// Calling a method from the wrong state is a compile-time error:
1918///
1919/// ```compile_fail
1920/// # fn main() -> Result<(), bicycl_rs::Error> {
1921/// let ctx = bicycl_rs::Context::new()?;
1922/// let mut rng = ctx.randgen_from_seed_decimal("1")?;
1923/// let session = ctx.threshold_ecdsa_session(&mut rng, 112, 2, 1)?;
1924/// // ERROR: New state has no sign_round1
1925/// session.sign_round1(&ctx, &mut rng, b"msg")?;
1926/// # Ok(()) }
1927/// ```
1928pub struct ThresholdEcdsaSession<S = threshold::New> {
1929    raw: NonNull<bicycl_rs_sys::bicycl_threshold_ecdsa_session_t>,
1930    _state: PhantomData<S>,
1931    _marker: PhantomData<*mut ()>,
1932}
1933
1934impl<S> std::fmt::Debug for ThresholdEcdsaSession<S> {
1935    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1936        f.debug_struct("ThresholdEcdsaSession")
1937            .field("raw", &self.raw)
1938            .finish()
1939    }
1940}
1941
1942impl<S> ThresholdEcdsaSession<S> {
1943    fn transition<T>(self) -> ThresholdEcdsaSession<T> {
1944        let raw = self.raw;
1945        std::mem::forget(self);
1946        ThresholdEcdsaSession {
1947            raw,
1948            _state: PhantomData,
1949            _marker: PhantomData,
1950        }
1951    }
1952}
1953
1954impl<S> Drop for ThresholdEcdsaSession<S> {
1955    fn drop(&mut self) {
1956        unsafe { bicycl_rs_sys::bicycl_threshold_ecdsa_session_free(self.raw.as_ptr()) }
1957    }
1958}
1959
1960impl ThresholdEcdsaSession<threshold::New> {
1961    pub fn keygen_round1(
1962        self,
1963        ctx: &Context,
1964        rng: &mut RandGen,
1965    ) -> Result<ThresholdEcdsaSession<threshold::Keygen1>> {
1966        let status = unsafe {
1967            bicycl_rs_sys::bicycl_threshold_ecdsa_keygen_round1(
1968                ctx.raw.as_ptr(),
1969                self.raw.as_ptr(),
1970                rng.raw.as_ptr(),
1971            )
1972        };
1973        status_to_result(status)?;
1974        Ok(self.transition())
1975    }
1976}
1977
1978impl ThresholdEcdsaSession<threshold::Keygen1> {
1979    pub fn keygen_round2(
1980        self,
1981        ctx: &Context,
1982        rng: &mut RandGen,
1983    ) -> Result<ThresholdEcdsaSession<threshold::Keygen2>> {
1984        let status = unsafe {
1985            bicycl_rs_sys::bicycl_threshold_ecdsa_keygen_round2(
1986                ctx.raw.as_ptr(),
1987                self.raw.as_ptr(),
1988                rng.raw.as_ptr(),
1989            )
1990        };
1991        status_to_result(status)?;
1992        Ok(self.transition())
1993    }
1994}
1995
1996impl ThresholdEcdsaSession<threshold::Keygen2> {
1997    pub fn keygen_finalize(
1998        self,
1999        ctx: &Context,
2000    ) -> Result<ThresholdEcdsaSession<threshold::KeygenDone>> {
2001        let status = unsafe {
2002            bicycl_rs_sys::bicycl_threshold_ecdsa_keygen_finalize(
2003                ctx.raw.as_ptr(),
2004                self.raw.as_ptr(),
2005            )
2006        };
2007        status_to_result(status)?;
2008        Ok(self.transition())
2009    }
2010}
2011
2012impl ThresholdEcdsaSession<threshold::KeygenDone> {
2013    pub fn sign_round1(
2014        self,
2015        ctx: &Context,
2016        rng: &mut RandGen,
2017        msg: &[u8],
2018    ) -> Result<ThresholdEcdsaSession<threshold::Sign1>> {
2019        let status = unsafe {
2020            bicycl_rs_sys::bicycl_threshold_ecdsa_sign_round1(
2021                ctx.raw.as_ptr(),
2022                self.raw.as_ptr(),
2023                rng.raw.as_ptr(),
2024                msg.as_ptr(),
2025                msg.len(),
2026            )
2027        };
2028        status_to_result(status)?;
2029        Ok(self.transition())
2030    }
2031}
2032
2033impl ThresholdEcdsaSession<threshold::Sign1> {
2034    pub fn sign_round2(
2035        self,
2036        ctx: &Context,
2037        rng: &mut RandGen,
2038    ) -> Result<ThresholdEcdsaSession<threshold::Sign2>> {
2039        let status = unsafe {
2040            bicycl_rs_sys::bicycl_threshold_ecdsa_sign_round2(
2041                ctx.raw.as_ptr(),
2042                self.raw.as_ptr(),
2043                rng.raw.as_ptr(),
2044            )
2045        };
2046        status_to_result(status)?;
2047        Ok(self.transition())
2048    }
2049}
2050
2051impl ThresholdEcdsaSession<threshold::Sign2> {
2052    pub fn sign_round3(self, ctx: &Context) -> Result<ThresholdEcdsaSession<threshold::Sign3>> {
2053        let status = unsafe {
2054            bicycl_rs_sys::bicycl_threshold_ecdsa_sign_round3(ctx.raw.as_ptr(), self.raw.as_ptr())
2055        };
2056        status_to_result(status)?;
2057        Ok(self.transition())
2058    }
2059}
2060
2061impl ThresholdEcdsaSession<threshold::Sign3> {
2062    pub fn sign_round4(self, ctx: &Context) -> Result<ThresholdEcdsaSession<threshold::Sign4>> {
2063        let status = unsafe {
2064            bicycl_rs_sys::bicycl_threshold_ecdsa_sign_round4(ctx.raw.as_ptr(), self.raw.as_ptr())
2065        };
2066        status_to_result(status)?;
2067        Ok(self.transition())
2068    }
2069}
2070
2071impl ThresholdEcdsaSession<threshold::Sign4> {
2072    pub fn sign_round5(
2073        self,
2074        ctx: &Context,
2075        rng: &mut RandGen,
2076    ) -> Result<ThresholdEcdsaSession<threshold::Sign5>> {
2077        let status = unsafe {
2078            bicycl_rs_sys::bicycl_threshold_ecdsa_sign_round5(
2079                ctx.raw.as_ptr(),
2080                self.raw.as_ptr(),
2081                rng.raw.as_ptr(),
2082            )
2083        };
2084        status_to_result(status)?;
2085        Ok(self.transition())
2086    }
2087}
2088
2089impl ThresholdEcdsaSession<threshold::Sign5> {
2090    pub fn sign_round6(
2091        self,
2092        ctx: &Context,
2093        rng: &mut RandGen,
2094    ) -> Result<ThresholdEcdsaSession<threshold::Sign6>> {
2095        let status = unsafe {
2096            bicycl_rs_sys::bicycl_threshold_ecdsa_sign_round6(
2097                ctx.raw.as_ptr(),
2098                self.raw.as_ptr(),
2099                rng.raw.as_ptr(),
2100            )
2101        };
2102        status_to_result(status)?;
2103        Ok(self.transition())
2104    }
2105}
2106
2107impl ThresholdEcdsaSession<threshold::Sign6> {
2108    pub fn sign_round7(
2109        self,
2110        ctx: &Context,
2111        rng: &mut RandGen,
2112    ) -> Result<ThresholdEcdsaSession<threshold::Sign7>> {
2113        let status = unsafe {
2114            bicycl_rs_sys::bicycl_threshold_ecdsa_sign_round7(
2115                ctx.raw.as_ptr(),
2116                self.raw.as_ptr(),
2117                rng.raw.as_ptr(),
2118            )
2119        };
2120        status_to_result(status)?;
2121        Ok(self.transition())
2122    }
2123}
2124
2125impl ThresholdEcdsaSession<threshold::Sign7> {
2126    pub fn sign_round8(self, ctx: &Context) -> Result<ThresholdEcdsaSession<threshold::Sign8>> {
2127        let status = unsafe {
2128            bicycl_rs_sys::bicycl_threshold_ecdsa_sign_round8(ctx.raw.as_ptr(), self.raw.as_ptr())
2129        };
2130        status_to_result(status)?;
2131        Ok(self.transition())
2132    }
2133}
2134
2135impl ThresholdEcdsaSession<threshold::Sign8> {
2136    pub fn sign_finalize(
2137        self,
2138        ctx: &Context,
2139    ) -> Result<ThresholdEcdsaSession<threshold::SignDone>> {
2140        let status = unsafe {
2141            bicycl_rs_sys::bicycl_threshold_ecdsa_sign_finalize(ctx.raw.as_ptr(), self.raw.as_ptr())
2142        };
2143        status_to_result(status)?;
2144        Ok(self.transition())
2145    }
2146}
2147
2148impl ThresholdEcdsaSession<threshold::SignDone> {
2149    /// Returns `true` if the threshold signature produced by this session is valid.
2150    pub fn signature_valid(&self, ctx: &Context) -> Result<bool> {
2151        let mut out_valid: c_int = 0;
2152        let status = unsafe {
2153            bicycl_rs_sys::bicycl_threshold_ecdsa_signature_valid(
2154                ctx.raw.as_ptr(),
2155                self.raw.as_ptr(),
2156                &mut out_valid as *mut _,
2157            )
2158        };
2159        status_to_result(status)?;
2160        Ok(out_valid != 0)
2161    }
2162}
2163
2164impl Drop for Ecdsa {
2165    fn drop(&mut self) {
2166        unsafe { bicycl_rs_sys::bicycl_ecdsa_free(self.raw.as_ptr()) }
2167    }
2168}
2169
2170impl Drop for EcdsaSecretKey {
2171    fn drop(&mut self) {
2172        unsafe { bicycl_rs_sys::bicycl_ecdsa_sk_free(self.raw.as_ptr()) }
2173    }
2174}
2175
2176impl Drop for EcdsaPublicKey {
2177    fn drop(&mut self) {
2178        unsafe { bicycl_rs_sys::bicycl_ecdsa_pk_free(self.raw.as_ptr()) }
2179    }
2180}
2181
2182impl Drop for EcdsaSignature {
2183    fn drop(&mut self) {
2184        unsafe { bicycl_rs_sys::bicycl_ecdsa_sig_free(self.raw.as_ptr()) }
2185    }
2186}