1pub use signature::Signer;
2
3use generic_array::GenericArray;
4
5use super::{ParameterSet, SignatureLen, SigningKeyLen, VerifyingKey, VerifyingKeyLen};
6
7use super::utils;
8use utils::transcoding;
9use utils::typenum::Unsigned;
10
11use crate::ffi::{SUCCESS, c_int};
12use crate::{FFIError, prepare_domain_separation_prefix};
13
14#[derive(Debug, PartialEq)]
16#[repr(transparent)]
17pub struct SigningKey<P: ParameterSet> {
18 sk: GenericArray<u8, <P as SigningKeyLen>::LEN>,
19}
20
21pub type MlDsaSeed = GenericArray<u8, generic_array::typenum::U32>;
27
28pub type SecretKey<P> = SigningKey<P>;
29
30#[cfg(feature = "rand")]
31pub fn keygen<P: ParameterSet>() -> Result<(SigningKey<P>, VerifyingKey<P>), FFIError> {
33 let mut pk: GenericArray<u8, <P as VerifyingKeyLen>::LEN> = GenericArray::default();
34 let mut sk: GenericArray<u8, <P as SigningKeyLen>::LEN> = GenericArray::default();
35 let seed: MlDsaSeed = utils::rand::random_generic_byte_array();
36 match unsafe { P::KEYGEN_FROM_SEED_FN(pk.as_mut_ptr(), sk.as_mut_ptr(), seed.as_ptr()) } {
37 SUCCESS => Ok((SigningKey { sk }, VerifyingKey { pk })),
38 error_code => Err(FFIError { code: error_code }),
39 }
40}
41
42pub fn keygen_from_seed<P: ParameterSet>(
44 seed: &MlDsaSeed,
45) -> Result<(SigningKey<P>, VerifyingKey<P>), FFIError> {
46 let mut pk: GenericArray<u8, <P as VerifyingKeyLen>::LEN> = GenericArray::default();
47 let mut sk: GenericArray<u8, <P as SigningKeyLen>::LEN> = GenericArray::default();
48 match unsafe { P::KEYGEN_FROM_SEED_FN(pk.as_mut_ptr(), sk.as_mut_ptr(), seed.as_ptr()) } {
49 SUCCESS => Ok((SigningKey { sk }, VerifyingKey { pk })),
50 error_code => Err(FFIError { code: error_code }),
51 }
52}
53
54pub(super) fn pk_from_sk<P: ParameterSet>(sk: &SigningKey<P>) -> Result<VerifyingKey<P>, FFIError> {
55 let mut pk: GenericArray<u8, <P as VerifyingKeyLen>::LEN> = GenericArray::default();
56 match unsafe { P::PK_FROM_SK_FN(pk.as_mut_ptr(), sk.sk.as_ptr()) } {
57 SUCCESS => Ok(VerifyingKey { pk }),
58 error_code => Err(FFIError { code: error_code }),
59 }
60}
61
62impl<P: ParameterSet> SigningKey<P> {
63 #[cfg(feature = "rand")]
64 pub fn new() -> Result<Self, FFIError> {
66 let (sk, _) = keygen::<P>()?;
67 Ok(sk)
68 }
69
70 pub fn new_from_seed(seed: &MlDsaSeed) -> Result<Self, FFIError> {
72 let (sk, _) = keygen_from_seed::<P>(seed)?;
73 Ok(sk)
74 }
75
76 pub fn try_sign_with_ctx_seeded(
89 &self,
90 message: &[u8],
91 context: &[u8],
92 seed: &MlDsaSeed,
93 ) -> Result<super::Signature<P>, signature::Error> {
94 type Siglen<P> = <P as SignatureLen>::LEN;
95 let mut sig: GenericArray<u8, Siglen<P>> = GenericArray::default();
96
97 let mut siglen: usize = 0;
98 let ret: c_int = {
99 let sk = self.sk.as_ptr();
100 let prefix = prepare_domain_separation_prefix::<P>(context)?;
101
102 unsafe {
103 P::SIGN_WITH_SEED_FN(
104 sig.as_mut_ptr(),
105 &mut siglen as *mut usize,
106 message.as_ptr(),
107 message.len(),
108 prefix.as_ptr(),
109 prefix.len(),
110 seed.as_ptr(),
111 sk,
112 0, )
114 }
115 };
116 if ret != SUCCESS || siglen != <Siglen<P>>::USIZE {
117 return Err(signature::Error::new());
118 }
119
120 let s = super::Signature::<P> { sig };
123
124 Ok(s)
125 }
126}
127
128pub(super) const EMPTY_CTX: &[u8; 0] = &[];
129
130#[cfg(feature = "rand")]
131impl<P: ParameterSet> signature::Signer<super::Signature<P>> for SigningKey<P> {
132 fn try_sign(&self, msg: &[u8]) -> Result<super::Signature<P>, signature::Error> {
133 let seed = utils::rand::random_generic_byte_array();
134 self.try_sign_with_ctx_seeded(msg, EMPTY_CTX, &seed)
135 }
136}
137
138#[cfg(feature = "rand")]
139impl<P: ParameterSet> ContextSigner<super::Signature<P>> for SigningKey<P> {
140 fn try_sign_with_ctx(
141 &self,
142 msg: &[u8],
143 ctx: &[u8],
144 ) -> Result<super::Signature<P>, signature::Error> {
145 let seed = utils::rand::random_generic_byte_array();
146 self.try_sign_with_ctx_seeded(msg, ctx, &seed)
147 }
148}
149
150impl<P: ParameterSet> SeededContextSigner<super::Signature<P>> for SigningKey<P> {
151 fn try_sign_with_ctx_and_seed(
152 &self,
153 seed: &[u8],
154 msg: &[u8],
155 ctx: &[u8],
156 ) -> Result<super::Signature<P>, signature::Error> {
157 let seed = GenericArray::try_from_slice(seed).map_err(|_| signature::Error::new())?;
158 self.try_sign_with_ctx_seeded(msg, ctx, seed)
159 }
160}
161
162impl<P: ParameterSet> SeededSigner<super::Signature<P>> for SigningKey<P> {
163 fn try_sign_with_seed(
164 &self,
165 seed: &[u8],
166 msg: &[u8],
167 ) -> Result<super::Signature<P>, signature::Error> {
168 let seed = GenericArray::try_from_slice(seed).map_err(|_| signature::Error::new())?;
169 self.try_sign_with_ctx_seeded(msg, EMPTY_CTX, seed)
170 }
171}
172
173impl<P: ParameterSet> From<SigningKey<P>> for GenericArray<u8, <P as crate::SigningKeyLen>::LEN> {
174 fn from(sk: SigningKey<P>) -> Self {
175 sk.sk
176 }
177}
178
179impl<P: ParameterSet> TryFrom<&[u8]> for SigningKey<P> {
180 type Error = transcoding::TranscodingError;
181
182 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
183 let arr = GenericArray::try_from_slice(bytes)?;
186
187 let provisional_sk = Self { sk: arr.clone() };
192 let _ = pk_from_sk(&provisional_sk)?;
193
194 Ok(provisional_sk)
195 }
196}
197
198impl<P: ParameterSet> AsRef<[u8]> for SigningKey<P> {
199 fn as_ref(&self) -> &[u8] {
200 self.sk.as_ref()
201 }
202}
203
204pub trait SeededSigner<S> {
206 fn sign_with_seed(&self, seed: &[u8], msg: &[u8]) -> S {
208 self.try_sign_with_seed(seed, msg)
209 .expect("signature operation failed")
210 }
211
212 fn try_sign_with_seed(&self, seed: &[u8], msg: &[u8]) -> Result<S, signature::Error>;
218}
219
220pub trait ContextSigner<S> {
222 fn sign_with_context(&self, msg: &[u8], ctx: &[u8]) -> S {
224 self.try_sign_with_ctx(msg, ctx)
225 .expect("signature operation failed")
226 }
227
228 fn try_sign_with_ctx(&self, msg: &[u8], ctx: &[u8]) -> Result<S, signature::Error>;
234}
235
236pub trait SeededContextSigner<S> {
239 fn sign_with_context_and_seed(&self, seed: &[u8], msg: &[u8], ctx: &[u8]) -> S {
241 self.try_sign_with_ctx_and_seed(seed, msg, ctx)
242 .expect("signature operation failed")
243 }
244
245 fn try_sign_with_ctx_and_seed(
251 &self,
252 seed: &[u8],
253 msg: &[u8],
254 ctx: &[u8],
255 ) -> Result<S, signature::Error>;
256}