mldsa_native_rs/wrapper/signature_encoding.rs
1pub use signature::SignatureEncoding;
2
3use generic_array::GenericArray;
4
5use super::ParameterSet;
6use super::utils::typenum::Unsigned;
7
8/// Represents a signature using the specified parameter set.
9///
10/// # Usage
11///
12/// ```rust
13/// # use mldsa_native_rs::*;
14/// # let sk = SigningKey::<P>::new().expect("Keygen failed");
15/// use parameter_sets::ML_DSA_44 as P;
16///
17/// let msg: &[u8] = b"Hello, world!";
18///
19/// let signature = sk.sign(msg);
20///
21/// // There are different ways to obtain a byte representation of the
22/// // signature.
23/// let signature_encoding = signature.to_bytes();
24/// let encoded_signature_via_SignatureEncoding: &[u8] = &signature_encoding;
25/// let encoded_signature_via_AsBytes = signature.as_bytes();
26/// assert_eq!(encoded_signature_via_SignatureEncoding, encoded_signature_via_AsBytes);
27///
28/// let encoded_signature = encoded_signature_via_AsBytes;
29///
30/// let recv_sig: Signature<P> = encoded_signature.try_into()
31/// .expect("Failed to parse the received signature");
32/// assert_eq!(recv_sig, signature);
33///
34/// // Equivalently, using the FromBytes trait
35/// let decoded_signature = Signature::<P>::from_bytes(encoded_signature)
36/// .expect("Failed to decode the received signature");
37/// assert_eq!(decoded_signature, signature);
38/// ```
39///
40/// If the crate is built without the `rand` feature, then the `sign` method
41/// (which takes only the `msg` as an argument) will not be available. In that
42/// case, you must generate your own random bytes and use the signing methods
43/// provided by the [`SeededSigner`](`super::signing_key::SeededSigner`) trait.
44#[derive(Clone, Debug, PartialEq, Eq)]
45pub struct Signature<P: ParameterSet> {
46 pub(super) sig: GenericArray<u8, <P as crate::SignatureLen>::LEN>,
47}
48
49impl<P: ParameterSet> signature::SignatureEncoding for Signature<P> {
50 type Repr = GenericArray<u8, <P as crate::SignatureLen>::LEN>;
51}
52
53// Implement TryFrom<&[u8]> for Signature<P>
54impl<P: ParameterSet> TryFrom<&[u8]> for Signature<P> {
55 type Error = signature::Error;
56
57 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
58 if bytes.len() != <<P as crate::SignatureLen>::LEN>::USIZE {
59 return Err(signature::Error::default());
60 }
61 let arr = GenericArray::from_slice(bytes).clone();
62 Ok(Signature { sig: arr })
63 }
64}
65
66// Implement From<Signature<P>> for GenericArray<u8, <P as crate::SignatureLen>::LEN>
67impl<P: ParameterSet> From<Signature<P>> for GenericArray<u8, <P as crate::SignatureLen>::LEN> {
68 fn from(sig: Signature<P>) -> Self {
69 sig.sig
70 }
71}
72
73impl<P: ParameterSet> AsRef<[u8]> for Signature<P> {
74 fn as_ref(&self) -> &[u8] {
75 self.sig.as_ref()
76 }
77}
78
79/// Prepare the domain separation prefix for pure ML-DSA signing with the
80/// context string `context`.
81pub(crate) fn prepare_domain_separation_prefix<P: ParameterSet>(
82 context: &[u8],
83) -> Result<Vec<u8>, signature::Error> {
84 use crate::ffi;
85 let mut prefix = [0u8; ffi::MLD_DOMAIN_SEPARATION_MAX_BYTES as usize];
86 let ret = unsafe {
87 P::PREPARE_DOMAIN_SEPARATION_PREFIX_FN(
88 prefix.as_mut_ptr(),
89 // the ph and phlen arguments are only used for pre-hashed ML-DSA
90 std::ptr::null(),
91 0,
92 context.as_ptr(),
93 context.len(),
94 ffi::MLD_PREHASH_NONE as ffi::c_int,
95 )
96 };
97 match ret {
98 0 => Err(signature::Error::default()),
99 len => Ok(Vec::from(&prefix[0..len])),
100 }
101}