1use crate::{
6 hazmat::{DigestPrimitive, SignPrimitive},
7 Error, Result, Signature, SignatureSize,
8};
9use core::fmt::{self, Debug};
10use elliptic_curve::{
11 generic_array::ArrayLength,
12 group::ff::PrimeField,
13 ops::{Invert, Reduce},
14 subtle::{Choice, ConstantTimeEq, CtOption},
15 zeroize::{Zeroize, ZeroizeOnDrop},
16 FieldBytes, FieldSize, NonZeroScalar, PrimeCurve, ProjectiveArithmetic, Scalar, SecretKey,
17};
18use signature::{
19 digest::{core_api::BlockSizeUser, Digest, FixedOutput, FixedOutputReset},
20 hazmat::PrehashSigner,
21 rand_core::{CryptoRng, RngCore},
22 DigestSigner, RandomizedDigestSigner, RandomizedSigner, Signer,
23};
24
25#[cfg(feature = "pem")]
26use {
27 crate::elliptic_curve::pkcs8::{EncodePrivateKey, SecretDocument},
28 core::str::FromStr,
29};
30
31#[cfg(feature = "pkcs8")]
32use crate::elliptic_curve::{
33 pkcs8::{self, AssociatedOid, DecodePrivateKey},
34 sec1::{self, FromEncodedPoint, ToEncodedPoint},
35 AffinePoint,
36};
37
38#[cfg(feature = "verify")]
39use {crate::verify::VerifyingKey, elliptic_curve::PublicKey, signature::Keypair};
40
41#[derive(Clone)]
46#[cfg_attr(docsrs, doc(cfg(feature = "sign")))]
47pub struct SigningKey<C>
48where
49 C: PrimeCurve + ProjectiveArithmetic,
50 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
51 SignatureSize<C>: ArrayLength<u8>,
52{
53 secret_scalar: NonZeroScalar<C>,
55
56 #[cfg(feature = "verify")]
58 verifying_key: VerifyingKey<C>,
59}
60
61impl<C> SigningKey<C>
62where
63 C: PrimeCurve + ProjectiveArithmetic,
64 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
65 SignatureSize<C>: ArrayLength<u8>,
66{
67 pub fn random(rng: impl CryptoRng + RngCore) -> Self {
69 NonZeroScalar::<C>::random(rng).into()
70 }
71
72 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
74 SecretKey::<C>::from_be_bytes(bytes)
75 .map(|sk| sk.to_nonzero_scalar().into())
76 .map_err(|_| Error::new())
77 }
78
79 pub fn to_bytes(&self) -> FieldBytes<C> {
81 self.secret_scalar.to_repr()
82 }
83
84 pub fn as_nonzero_scalar(&self) -> &NonZeroScalar<C> {
92 &self.secret_scalar
93 }
94
95 #[cfg(feature = "verify")]
98 #[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
99 pub fn verifying_key(&self) -> VerifyingKey<C> {
100 self.verifying_key
101 }
102}
103
104#[cfg(feature = "verify")]
105#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
106impl<C> AsRef<VerifyingKey<C>> for SigningKey<C>
107where
108 C: PrimeCurve + ProjectiveArithmetic,
109 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
110 SignatureSize<C>: ArrayLength<u8>,
111{
112 fn as_ref(&self) -> &VerifyingKey<C> {
113 &self.verifying_key
114 }
115}
116
117impl<C> ConstantTimeEq for SigningKey<C>
118where
119 C: PrimeCurve + ProjectiveArithmetic,
120 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
121 SignatureSize<C>: ArrayLength<u8>,
122{
123 fn ct_eq(&self, other: &Self) -> Choice {
124 self.secret_scalar.ct_eq(&other.secret_scalar)
125 }
126}
127
128impl<C> Debug for SigningKey<C>
129where
130 C: PrimeCurve + ProjectiveArithmetic,
131 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
132 SignatureSize<C>: ArrayLength<u8>,
133{
134 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135 f.debug_struct("SigningKey").finish_non_exhaustive()
136 }
137}
138
139impl<C> Drop for SigningKey<C>
140where
141 C: PrimeCurve + ProjectiveArithmetic,
142 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
143 SignatureSize<C>: ArrayLength<u8>,
144{
145 fn drop(&mut self) {
146 self.secret_scalar.zeroize();
147 }
148}
149
150impl<C> ZeroizeOnDrop for SigningKey<C>
151where
152 C: PrimeCurve + ProjectiveArithmetic,
153 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
154 SignatureSize<C>: ArrayLength<u8>,
155{
156}
157
158impl<C> Eq for SigningKey<C>
160where
161 C: PrimeCurve + ProjectiveArithmetic,
162 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
163 SignatureSize<C>: ArrayLength<u8>,
164{
165}
166
167impl<C> PartialEq for SigningKey<C>
169where
170 C: PrimeCurve + ProjectiveArithmetic,
171 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
172 SignatureSize<C>: ArrayLength<u8>,
173{
174 fn eq(&self, other: &SigningKey<C>) -> bool {
175 self.ct_eq(other).into()
176 }
177}
178
179impl<C> From<SecretKey<C>> for SigningKey<C>
180where
181 C: PrimeCurve + ProjectiveArithmetic,
182 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
183 SignatureSize<C>: ArrayLength<u8>,
184{
185 fn from(secret_key: SecretKey<C>) -> Self {
186 Self::from(&secret_key)
187 }
188}
189
190impl<C> From<&SecretKey<C>> for SigningKey<C>
191where
192 C: PrimeCurve + ProjectiveArithmetic,
193 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
194 SignatureSize<C>: ArrayLength<u8>,
195{
196 fn from(secret_key: &SecretKey<C>) -> Self {
197 secret_key.to_nonzero_scalar().into()
198 }
199}
200
201impl<C> From<SigningKey<C>> for SecretKey<C>
202where
203 C: PrimeCurve + ProjectiveArithmetic,
204 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
205 SignatureSize<C>: ArrayLength<u8>,
206{
207 fn from(key: SigningKey<C>) -> Self {
208 key.secret_scalar.into()
209 }
210}
211
212impl<C> From<&SigningKey<C>> for SecretKey<C>
213where
214 C: PrimeCurve + ProjectiveArithmetic,
215 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
216 SignatureSize<C>: ArrayLength<u8>,
217{
218 fn from(secret_key: &SigningKey<C>) -> Self {
219 secret_key.secret_scalar.into()
220 }
221}
222
223impl<C, D> DigestSigner<D, Signature<C>> for SigningKey<C>
224where
225 C: PrimeCurve + ProjectiveArithmetic,
226 C::UInt: for<'a> From<&'a Scalar<C>>,
227 D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
228 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
229
230 SignatureSize<C>: ArrayLength<u8>,
231{
232 fn try_sign_digest(&self, msg_digest: D) -> Result<Signature<C>> {
237 Ok(self
238 .secret_scalar
239 .try_sign_digest_rfc6979::<D>(msg_digest, &[])?
240 .0)
241 }
242}
243
244#[cfg(feature = "verify")]
245#[cfg_attr(docsrs, doc(cfg(feature = "verify")))]
246impl<C> Keypair<Signature<C>> for SigningKey<C>
247where
248 C: PrimeCurve + ProjectiveArithmetic,
249 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
250 SignatureSize<C>: ArrayLength<u8>,
251{
252 type VerifyingKey = VerifyingKey<C>;
253}
254
255impl<C> PrehashSigner<Signature<C>> for SigningKey<C>
256where
257 C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
258 C::Digest: BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
259 C::UInt: for<'a> From<&'a Scalar<C>>,
260 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
261 SignatureSize<C>: ArrayLength<u8>,
262{
263 fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature<C>> {
264 let prehash = C::prehash_to_field_bytes(prehash)?;
265
266 Ok(self
267 .secret_scalar
268 .try_sign_prehashed_rfc6979::<C::Digest>(prehash, &[])?
269 .0)
270 }
271}
272
273impl<C> Signer<Signature<C>> for SigningKey<C>
274where
275 Self: DigestSigner<C::Digest, Signature<C>>,
276 C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
277 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
278 SignatureSize<C>: ArrayLength<u8>,
279{
280 fn try_sign(&self, msg: &[u8]) -> Result<Signature<C>> {
281 self.try_sign_digest(C::Digest::new_with_prefix(msg))
282 }
283}
284
285impl<C, D> RandomizedDigestSigner<D, Signature<C>> for SigningKey<C>
286where
287 C: PrimeCurve + ProjectiveArithmetic,
288 C::UInt: for<'a> From<&'a Scalar<C>>,
289 D: Digest + BlockSizeUser + FixedOutput<OutputSize = FieldSize<C>> + FixedOutputReset,
290 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
291 SignatureSize<C>: ArrayLength<u8>,
292{
293 fn try_sign_digest_with_rng(
297 &self,
298 mut rng: impl CryptoRng + RngCore,
299 msg_digest: D,
300 ) -> Result<Signature<C>> {
301 let mut ad = FieldBytes::<C>::default();
302 rng.fill_bytes(&mut ad);
303 Ok(self
304 .secret_scalar
305 .try_sign_digest_rfc6979::<D>(msg_digest, &ad)?
306 .0)
307 }
308}
309
310impl<C> RandomizedSigner<Signature<C>> for SigningKey<C>
311where
312 Self: RandomizedDigestSigner<C::Digest, Signature<C>>,
313 C: PrimeCurve + ProjectiveArithmetic + DigestPrimitive,
314 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
315 SignatureSize<C>: ArrayLength<u8>,
316{
317 fn try_sign_with_rng(&self, rng: impl CryptoRng + RngCore, msg: &[u8]) -> Result<Signature<C>> {
318 self.try_sign_digest_with_rng(rng, C::Digest::new_with_prefix(msg))
319 }
320}
321
322impl<C> From<NonZeroScalar<C>> for SigningKey<C>
323where
324 C: PrimeCurve + ProjectiveArithmetic,
325 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
326 SignatureSize<C>: ArrayLength<u8>,
327{
328 fn from(secret_scalar: NonZeroScalar<C>) -> Self {
329 #[cfg(feature = "verify")]
330 let public_key = PublicKey::from_secret_scalar(&secret_scalar);
331
332 Self {
333 secret_scalar,
334 #[cfg(feature = "verify")]
335 verifying_key: public_key.into(),
336 }
337 }
338}
339
340impl<C> TryFrom<&[u8]> for SigningKey<C>
341where
342 C: PrimeCurve + ProjectiveArithmetic,
343 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
344 SignatureSize<C>: ArrayLength<u8>,
345{
346 type Error = Error;
347
348 fn try_from(bytes: &[u8]) -> Result<Self> {
349 Self::from_bytes(bytes)
350 }
351}
352
353#[cfg(feature = "verify")]
354impl<C> From<&SigningKey<C>> for VerifyingKey<C>
355where
356 C: PrimeCurve + ProjectiveArithmetic,
357 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
358 SignatureSize<C>: ArrayLength<u8>,
359{
360 fn from(signing_key: &SigningKey<C>) -> VerifyingKey<C> {
361 signing_key.verifying_key()
362 }
363}
364
365#[cfg(feature = "pkcs8")]
366#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
367impl<C> TryFrom<pkcs8::PrivateKeyInfo<'_>> for SigningKey<C>
368where
369 C: PrimeCurve + AssociatedOid + ProjectiveArithmetic,
370 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
371 FieldSize<C>: sec1::ModulusSize,
372 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
373 SignatureSize<C>: ArrayLength<u8>,
374{
375 type Error = pkcs8::Error;
376
377 fn try_from(private_key_info: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result<Self> {
378 SecretKey::try_from(private_key_info).map(Into::into)
379 }
380}
381
382#[cfg(feature = "pem")]
383#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
384impl<C> EncodePrivateKey for SigningKey<C>
385where
386 C: AssociatedOid + PrimeCurve + ProjectiveArithmetic,
387 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
388 FieldSize<C>: sec1::ModulusSize,
389 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
390 SignatureSize<C>: ArrayLength<u8>,
391{
392 fn to_pkcs8_der(&self) -> pkcs8::Result<SecretDocument> {
393 SecretKey::from(self.secret_scalar).to_pkcs8_der()
394 }
395}
396
397#[cfg(feature = "pkcs8")]
398#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
399impl<C> DecodePrivateKey for SigningKey<C>
400where
401 C: PrimeCurve + AssociatedOid + ProjectiveArithmetic,
402 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
403 FieldSize<C>: sec1::ModulusSize,
404 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
405 SignatureSize<C>: ArrayLength<u8>,
406{
407}
408
409#[cfg(feature = "pem")]
410#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
411impl<C> FromStr for SigningKey<C>
412where
413 C: PrimeCurve + AssociatedOid + ProjectiveArithmetic,
414 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
415 FieldSize<C>: sec1::ModulusSize,
416 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + Reduce<C::UInt> + SignPrimitive<C>,
417 SignatureSize<C>: ArrayLength<u8>,
418{
419 type Err = Error;
420
421 fn from_str(s: &str) -> Result<Self> {
422 Self::from_pkcs8_pem(s).map_err(|_| Error::new())
423 }
424}