1use alloc::vec::Vec;
6
7use core::ptr::{null, NonNull};
8use core::str::FromStr;
9
10#[cfg(not(feature = "std"))]
11use cstr_core::CStr;
12#[cfg(feature = "std")]
13use std::ffi::CStr;
14
15use crate::ffi::sig as ffi;
16use crate::newtype_buffer;
17use crate::*;
18
19#[cfg(feature = "serde")]
20use serde::{Deserialize, Serialize};
21
22newtype_buffer!(PublicKey, PublicKeyRef);
23newtype_buffer!(SecretKey, SecretKeyRef);
24newtype_buffer!(Signature, SignatureRef);
25
26pub type Message = [u8];
28pub type CtxStr = [u8];
30
31macro_rules! implement_sigs {
32 { $(($feat: literal) $sig: ident: $oqs_id: ident),* $(,)? } => (
33 #[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
39 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
40 #[allow(missing_docs)]
41 pub enum Algorithm {
42 $(
43 $sig,
44 )*
45 }
46
47 fn algorithm_to_id(algorithm: Algorithm) -> *const libc::c_char {
48 let id: &[u8] = match algorithm {
49 $(
50 Algorithm::$sig => &ffi::$oqs_id[..],
51 )*
52 };
53 id as *const _ as *const libc::c_char
54 }
55
56 impl FromStr for Algorithm {
57 type Err = crate::Error;
58
59 fn from_str(s: &str) -> Result<Self> {
60 $(
61 if s == Algorithm::$sig.name() {
62 return Ok(Algorithm::$sig);
63 }
64 )*
65 Err(crate::Error::AlgorithmParsingError)
66 }
67 }
68
69 $(
70 #[cfg(test)]
71 #[allow(non_snake_case)]
72 mod $sig {
73 use super::*;
74
75 #[test]
76 #[cfg(feature = $feat)]
77 fn test_signing() -> Result<()> {
78 crate::init();
79 let message = [0u8; 100];
80 let sig = Sig::new(Algorithm::$sig)?;
81 let (pk, sk) = sig.keypair()?;
82 let signature = sig.sign(&message, &sk)?;
83 sig.verify(&message, &signature, &pk)
84 }
85
86 #[test]
87 #[cfg(feature = $feat)]
88 fn test_signing_with_empty_context_string() -> Result<()> {
89 crate::init();
90 let message = [0u8; 100];
91 let ctx_str: [u8; 0] = [];
92 let sig = Sig::new(Algorithm::$sig)?;
93 let (pk, sk) = sig.keypair()?;
94 let signature = sig.sign_with_ctx_str(&message, &ctx_str, &sk)?;
95 sig.verify_with_ctx_str(&message, &signature, &ctx_str, &pk)
96 }
97
98 #[test]
99 #[cfg(feature = $feat)]
100 fn test_signing_with_nonempty_context_string() -> Result<()> {
101 crate::init();
102 let message = [0u8; 100];
103 let ctx_str = [0u8; 100];
104 let sig = Sig::new(Algorithm::$sig)?;
105 let (pk, sk) = sig.keypair()?;
106 if sig.has_ctx_str_support() {
107 let signature = sig.sign_with_ctx_str(&message, &ctx_str, &sk)?;
108 sig.verify_with_ctx_str(&message, &signature, &ctx_str, &pk)
109 } else {
110 let sig_result = sig.sign_with_ctx_str(&message, &ctx_str, &sk);
111 let sig_result: Result<()> = match sig_result {
113 Err(Error::Error) => Ok(()),
114 Ok(_) => Err(Error::Error),
115 Err(e) => Err(e)
116 };
117 if sig_result.is_ok() {
118 let signature = sig.sign(&message, &sk)?;
120 match sig.verify_with_ctx_str(&message, &signature, &ctx_str, &pk) {
122 Err(Error::Error) => Ok(()),
123 Ok(_) => Err(Error::Error),
124 Err(e) => Err(e)
125
126 }
127 } else {
128 sig_result
129 }
130 }
131 }
132
133 #[test]
134 fn test_enabled() {
135 crate::init();
136 if cfg!(feature = $feat) {
137 assert!(Algorithm::$sig.is_enabled());
138 } else {
139 assert!(!Algorithm::$sig.is_enabled())
140 }
141 }
142
143 #[test]
144 fn test_name() {
145 let algo = Algorithm::$sig;
146 let name = algo.name();
148
149 #[cfg(feature = "std")]
150 assert_eq!(name, algo.to_string());
151
152 assert!(!name.is_empty());
154 }
155
156 #[test]
157 fn test_get_algorithm_back() {
158 let algorithm = Algorithm::$sig;
159 if algorithm.is_enabled() {
160 let sig = Sig::new(algorithm).unwrap();
161 assert_eq!(algorithm, sig.algorithm());
162 }
163 }
164
165 #[test]
166 fn test_version() {
167 if let Ok(sig) = Sig::new(Algorithm::$sig) {
168 let version = sig.version();
170 assert!(!version.is_empty());
172 }
173 }
174
175 #[test]
176 fn test_from_str() {
177 let algorithm = Algorithm::$sig;
178 let name = algorithm.name();
179 let parsed = Algorithm::from_str(name).unwrap();
180 assert_eq!(algorithm, parsed);}
181 }
182 )*
183 )
184}
185
186implement_sigs! {
187 ("cross") CrossRsdp128Balanced: OQS_SIG_alg_cross_rsdp_128_balanced,
188 ("cross") CrossRsdp128Fast: OQS_SIG_alg_cross_rsdp_128_fast,
189 ("cross") CrossRsdp128Small: OQS_SIG_alg_cross_rsdp_128_small,
190 ("cross") CrossRsdp192Balanced: OQS_SIG_alg_cross_rsdp_192_balanced,
191 ("cross") CrossRsdp192Fast: OQS_SIG_alg_cross_rsdp_192_fast,
192 ("cross") CrossRsdp192Small: OQS_SIG_alg_cross_rsdp_192_small,
193 ("cross") CrossRsdp256Balanced: OQS_SIG_alg_cross_rsdp_256_balanced,
194 ("cross") CrossRsdp256Fast: OQS_SIG_alg_cross_rsdp_256_fast,
195 ("cross") CrossRsdp256Small: OQS_SIG_alg_cross_rsdp_256_small,
196 ("cross") CrossRsdpg128Balanced: OQS_SIG_alg_cross_rsdpg_128_balanced,
197 ("cross") CrossRsdpg128Fast: OQS_SIG_alg_cross_rsdpg_128_fast,
198 ("cross") CrossRsdpg128Small: OQS_SIG_alg_cross_rsdpg_128_small,
199 ("cross") CrossRsdpg192Balanced: OQS_SIG_alg_cross_rsdpg_192_balanced,
200 ("cross") CrossRsdpg192Fast: OQS_SIG_alg_cross_rsdpg_192_fast,
201 ("cross") CrossRsdpg192Small: OQS_SIG_alg_cross_rsdpg_192_small,
202 ("cross") CrossRsdpg256Balanced: OQS_SIG_alg_cross_rsdpg_256_balanced,
203 ("cross") CrossRsdpg256Fast: OQS_SIG_alg_cross_rsdpg_256_fast,
204 ("cross") CrossRsdpg256Small: OQS_SIG_alg_cross_rsdpg_256_small,
205 ("dilithium") Dilithium2: OQS_SIG_alg_dilithium_2,
206 ("dilithium") Dilithium3: OQS_SIG_alg_dilithium_3,
207 ("dilithium") Dilithium5: OQS_SIG_alg_dilithium_5,
208 ("falcon") Falcon512: OQS_SIG_alg_falcon_512,
209 ("falcon") Falcon1024: OQS_SIG_alg_falcon_1024,
210 ("mayo") Mayo1: OQS_SIG_alg_mayo_1,
211 ("mayo") Mayo2: OQS_SIG_alg_mayo_2,
212 ("mayo") Mayo3: OQS_SIG_alg_mayo_3,
213 ("mayo") Mayo5: OQS_SIG_alg_mayo_5,
214 ("ml_dsa") MlDsa44: OQS_SIG_alg_ml_dsa_44,
215 ("ml_dsa") MlDsa65: OQS_SIG_alg_ml_dsa_65,
216 ("ml_dsa") MlDsa87: OQS_SIG_alg_ml_dsa_87,
217 ("sphincs") SphincsSha2128fSimple: OQS_SIG_alg_sphincs_sha2_128f_simple,
218 ("sphincs") SphincsSha2128sSimple: OQS_SIG_alg_sphincs_sha2_128s_simple,
219 ("sphincs") SphincsSha2192fSimple: OQS_SIG_alg_sphincs_sha2_192f_simple,
220 ("sphincs") SphincsSha2192sSimple: OQS_SIG_alg_sphincs_sha2_192s_simple,
221 ("sphincs") SphincsSha2256fSimple: OQS_SIG_alg_sphincs_sha2_256f_simple,
222 ("sphincs") SphincsSha2256sSimple: OQS_SIG_alg_sphincs_sha2_256s_simple,
223 ("sphincs") SphincsShake128fSimple: OQS_SIG_alg_sphincs_shake_128f_simple,
224 ("sphincs") SphincsShake128sSimple: OQS_SIG_alg_sphincs_shake_128s_simple,
225 ("sphincs") SphincsShake192fSimple: OQS_SIG_alg_sphincs_shake_192f_simple,
226 ("sphincs") SphincsShake192sSimple: OQS_SIG_alg_sphincs_shake_192s_simple,
227 ("sphincs") SphincsShake256fSimple: OQS_SIG_alg_sphincs_shake_256f_simple,
228 ("sphincs") SphincsShake256sSimple: OQS_SIG_alg_sphincs_shake_256s_simple,
229 ("uov") UovOvIs: OQS_SIG_alg_uov_ov_Is,
230 ("uov") UovOvIp: OQS_SIG_alg_uov_ov_Ip,
231 ("uov") UovOvIII: OQS_SIG_alg_uov_ov_III,
232 ("uov") UovOvV: OQS_SIG_alg_uov_ov_V,
233 ("uov") UovOvIsPkc: OQS_SIG_alg_uov_ov_Is_pkc,
234 ("uov") UovOvIpPkc: OQS_SIG_alg_uov_ov_Ip_pkc,
235 ("uov") UovOvIIIPkc: OQS_SIG_alg_uov_ov_III_pkc,
236 ("uov") UovOvVPkc: OQS_SIG_alg_uov_ov_V_pkc,
237 ("uov") UovOvIsPkcSkc: OQS_SIG_alg_uov_ov_Is_pkc_skc,
238 ("uov") UovOvIpPkcSkc: OQS_SIG_alg_uov_ov_Ip_pkc_skc,
239 ("uov") UovOvIIIPkcSkc: OQS_SIG_alg_uov_ov_III_pkc_skc,
240 ("uov") UovOvVPkcSkc: OQS_SIG_alg_uov_ov_V_pkc_skc,
241}
242
243impl Algorithm {
244 pub fn is_enabled(self) -> bool {
247 unsafe { ffi::OQS_SIG_alg_is_enabled(algorithm_to_id(self)) == 1 }
248 }
249
250 pub fn to_id(self) -> *const libc::c_char {
254 algorithm_to_id(self)
255 }
256
257 pub fn name(&self) -> &'static str {
261 let id = unsafe { CStr::from_ptr(self.to_id()) };
263 id.to_str().expect("OQS algorithm names must be UTF-8")
264 }
265}
266
267pub struct Sig {
281 algorithm: Algorithm,
282 sig: NonNull<ffi::OQS_SIG>,
283}
284
285unsafe impl Sync for Sig {}
286unsafe impl Send for Sig {}
287
288impl Drop for Sig {
289 fn drop(&mut self) {
290 unsafe { ffi::OQS_SIG_free(self.sig.as_ptr()) };
291 }
292}
293
294#[cfg(feature = "std")]
295impl std::fmt::Display for Algorithm {
296 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
297 self.name().fmt(f)
298 }
299}
300
301impl core::convert::TryFrom<Algorithm> for Sig {
302 type Error = crate::Error;
303 fn try_from(alg: Algorithm) -> Result<Sig> {
304 Sig::new(alg)
305 }
306}
307
308impl Sig {
309 pub fn new(algorithm: Algorithm) -> Result<Self> {
313 let sig = unsafe { ffi::OQS_SIG_new(algorithm_to_id(algorithm)) };
314 NonNull::new(sig).map_or_else(
315 || Err(Error::AlgorithmDisabled),
316 |sig| Ok(Self { algorithm, sig }),
317 )
318 }
319
320 pub fn algorithm(&self) -> Algorithm {
322 self.algorithm
323 }
324
325 pub fn version(&self) -> &'static str {
327 let sig = unsafe { self.sig.as_ref() };
328 let cstr = unsafe { CStr::from_ptr(sig.alg_version) };
330 cstr.to_str()
331 .expect("Algorithm version strings must be UTF-8")
332 }
333
334 pub fn claimed_nist_level(&self) -> u8 {
336 let sig = unsafe { self.sig.as_ref() };
337 sig.claimed_nist_level
338 }
339
340 pub fn is_euf_cma(&self) -> bool {
342 let sig = unsafe { self.sig.as_ref() };
343 sig.euf_cma
344 }
345
346 pub fn has_ctx_str_support(&self) -> bool {
348 let sig = unsafe { self.sig.as_ref() };
349 sig.sig_with_ctx_support
350 }
351
352 pub fn length_public_key(&self) -> usize {
354 let sig = unsafe { self.sig.as_ref() };
355 sig.length_public_key
356 }
357
358 pub fn length_secret_key(&self) -> usize {
360 let sig = unsafe { self.sig.as_ref() };
361 sig.length_secret_key
362 }
363
364 pub fn length_signature(&self) -> usize {
366 let sig = unsafe { self.sig.as_ref() };
367 sig.length_signature
368 }
369
370 pub fn secret_key_from_bytes<'a>(&self, buf: &'a [u8]) -> Option<SecretKeyRef<'a>> {
372 if buf.len() != self.length_secret_key() {
373 None
374 } else {
375 Some(SecretKeyRef::new(buf))
376 }
377 }
378
379 pub fn public_key_from_bytes<'a>(&self, buf: &'a [u8]) -> Option<PublicKeyRef<'a>> {
381 if buf.len() != self.length_public_key() {
382 None
383 } else {
384 Some(PublicKeyRef::new(buf))
385 }
386 }
387
388 pub fn signature_from_bytes<'a>(&self, buf: &'a [u8]) -> Option<SignatureRef<'a>> {
390 if buf.len() > self.length_signature() {
391 None
392 } else {
393 Some(SignatureRef::new(buf))
394 }
395 }
396
397 pub fn keypair(&self) -> Result<(PublicKey, SecretKey)> {
399 let sig = unsafe { self.sig.as_ref() };
400 let func = sig.keypair.unwrap();
401 let mut pk = PublicKey {
402 bytes: Vec::with_capacity(sig.length_public_key),
403 };
404 let mut sk = SecretKey {
405 bytes: Vec::with_capacity(sig.length_secret_key),
406 };
407 let status = unsafe { func(pk.bytes.as_mut_ptr(), sk.bytes.as_mut_ptr()) };
408 unsafe {
410 pk.bytes.set_len(sig.length_public_key);
411 sk.bytes.set_len(sig.length_secret_key);
412 }
413 status_to_result(status)?;
414 Ok((pk, sk))
415 }
416
417 pub fn sign<'a, S: Into<SecretKeyRef<'a>>>(
419 &self,
420 message: &Message,
421 sk: S,
422 ) -> Result<Signature> {
423 let sk = sk.into();
424 let sig = unsafe { self.sig.as_ref() };
425 let func = sig.sign.unwrap();
426 let mut sig = Signature {
427 bytes: Vec::with_capacity(sig.length_signature),
428 };
429 let mut sig_len = 0;
430 let status = unsafe {
431 func(
432 sig.bytes.as_mut_ptr(),
433 &mut sig_len,
434 message.as_ptr(),
435 message.len(),
436 sk.bytes.as_ptr(),
437 )
438 };
439 status_to_result(status)?;
440 unsafe {
442 sig.bytes.set_len(sig_len);
443 }
444 Ok(sig)
445 }
446
447 pub fn sign_with_ctx_str<'a, S: Into<SecretKeyRef<'a>>>(
449 &self,
450 message: &Message,
451 ctx_str: &CtxStr,
452 sk: S,
453 ) -> Result<Signature> {
454 let sk = sk.into();
455 let sig = unsafe { self.sig.as_ref() };
456 let func = sig.sign_with_ctx_str.unwrap();
457 let mut sig = Signature {
458 bytes: Vec::with_capacity(sig.length_signature),
459 };
460 let mut sig_len = 0;
461 let ctx_str_ptr = if !ctx_str.is_empty() {
465 ctx_str.as_ptr()
466 } else {
467 null()
468 };
469 let status = unsafe {
470 func(
471 sig.bytes.as_mut_ptr(),
472 &mut sig_len,
473 message.as_ptr(),
474 message.len(),
475 ctx_str_ptr,
476 ctx_str.len(),
477 sk.bytes.as_ptr(),
478 )
479 };
480 status_to_result(status)?;
481 unsafe {
483 sig.bytes.set_len(sig_len);
484 }
485 Ok(sig)
486 }
487
488 pub fn verify<'a, 'b>(
490 &self,
491 message: &Message,
492 signature: impl Into<SignatureRef<'a>>,
493 pk: impl Into<PublicKeyRef<'b>>,
494 ) -> Result<()> {
495 let signature = signature.into();
496 let pk = pk.into();
497 if signature.bytes.len() > self.length_signature()
498 || pk.bytes.len() != self.length_public_key()
499 {
500 return Err(Error::InvalidLength);
501 }
502 let sig = unsafe { self.sig.as_ref() };
503 let func = sig.verify.unwrap();
504 let status = unsafe {
505 func(
506 message.as_ptr(),
507 message.len(),
508 signature.bytes.as_ptr(),
509 signature.len(),
510 pk.bytes.as_ptr(),
511 )
512 };
513 status_to_result(status)
514 }
515
516 pub fn verify_with_ctx_str<'a, 'b>(
518 &self,
519 message: &Message,
520 signature: impl Into<SignatureRef<'a>>,
521 ctx_str: &CtxStr,
522 pk: impl Into<PublicKeyRef<'b>>,
523 ) -> Result<()> {
524 let signature = signature.into();
525 let pk = pk.into();
526 if signature.bytes.len() > self.length_signature()
527 || pk.bytes.len() != self.length_public_key()
528 {
529 return Err(Error::InvalidLength);
530 }
531 let sig = unsafe { self.sig.as_ref() };
532 let func = sig.verify_with_ctx_str.unwrap();
533 let ctx_str_ptr = if !ctx_str.is_empty() {
537 ctx_str.as_ptr()
538 } else {
539 null()
540 };
541 let status = unsafe {
542 func(
543 message.as_ptr(),
544 message.len(),
545 signature.bytes.as_ptr(),
546 signature.len(),
547 ctx_str_ptr,
548 ctx_str.len(),
549 pk.bytes.as_ptr(),
550 )
551 };
552 status_to_result(status)
553 }
554}