1pub use ecdsa_core::signature::{self, Error, Result};
43
44#[cfg(feature = "ecdsa")]
45use {
46 crate::{AffinePoint, EncodedPoint, FieldBytes, NonZeroScalar, Scalar},
47 ecdsa_core::{
48 hazmat::{bits2field, sign_prehashed, SignPrimitive, VerifyPrimitive},
49 signature::{
50 hazmat::{PrehashVerifier, RandomizedPrehashSigner},
51 rand_core::CryptoRngCore,
52 RandomizedSigner, Verifier,
53 },
54 },
55 elliptic_curve::Field,
56 sha2::{Digest, Sha512},
57};
58
59#[cfg(all(feature = "ecdsa", feature = "getrandom"))]
60use {
61 ecdsa_core::signature::{hazmat::PrehashSigner, Signer},
62 rand_core::OsRng,
63};
64
65use super::NistP521;
66
67pub type Signature = ecdsa_core::Signature<NistP521>;
69
70pub type DerSignature = ecdsa_core::der::Signature<NistP521>;
72
73#[cfg(feature = "ecdsa")]
74impl SignPrimitive<NistP521> for Scalar {}
75
76#[cfg(feature = "ecdsa")]
77impl VerifyPrimitive<NistP521> for AffinePoint {}
78
79#[cfg(feature = "ecdsa")]
81#[derive(Clone)]
82pub struct SigningKey(ecdsa_core::SigningKey<NistP521>);
83
84#[cfg(feature = "ecdsa")]
85impl SigningKey {
86 pub fn random(rng: &mut impl CryptoRngCore) -> Self {
88 ecdsa_core::SigningKey::<NistP521>::random(rng).into()
89 }
90
91 pub fn from_bytes(bytes: &FieldBytes) -> Result<Self> {
93 ecdsa_core::SigningKey::<NistP521>::from_bytes(bytes).map(Into::into)
94 }
95
96 pub fn from_slice(bytes: &[u8]) -> Result<Self> {
98 ecdsa_core::SigningKey::<NistP521>::from_slice(bytes).map(Into::into)
99 }
100
101 pub fn to_bytes(&self) -> FieldBytes {
103 self.0.to_bytes()
104 }
105
106 pub fn as_nonzero_scalar(&self) -> &NonZeroScalar {
114 self.0.as_nonzero_scalar()
115 }
116
117 #[cfg(feature = "verifying")]
119 pub fn verifying_key(&self) -> VerifyingKey {
120 VerifyingKey::from(self)
121 }
122}
123
124#[cfg(feature = "ecdsa")]
125impl From<ecdsa_core::SigningKey<NistP521>> for SigningKey {
126 fn from(inner: ecdsa_core::SigningKey<NistP521>) -> SigningKey {
127 SigningKey(inner)
128 }
129}
130
131#[cfg(all(feature = "ecdsa", feature = "getrandom"))]
132impl PrehashSigner<Signature> for SigningKey {
133 fn sign_prehash(&self, prehash: &[u8]) -> Result<Signature> {
134 self.sign_prehash_with_rng(&mut OsRng, prehash)
135 }
136}
137
138#[cfg(feature = "ecdsa")]
139impl RandomizedPrehashSigner<Signature> for SigningKey {
140 fn sign_prehash_with_rng(
141 &self,
142 rng: &mut impl CryptoRngCore,
143 prehash: &[u8],
144 ) -> Result<Signature> {
145 let z = bits2field::<NistP521>(prehash)?;
146 let k = Scalar::random(rng);
147 sign_prehashed(self.0.as_nonzero_scalar().as_ref(), k, &z).map(|sig| sig.0)
148 }
149}
150
151#[cfg(feature = "ecdsa")]
152impl RandomizedSigner<Signature> for SigningKey {
153 fn try_sign_with_rng(&self, rng: &mut impl CryptoRngCore, msg: &[u8]) -> Result<Signature> {
154 self.sign_prehash_with_rng(rng, &Sha512::digest(msg))
155 }
156}
157
158#[cfg(all(feature = "ecdsa", feature = "getrandom"))]
159impl Signer<Signature> for SigningKey {
160 fn try_sign(&self, msg: &[u8]) -> Result<Signature> {
161 self.try_sign_with_rng(&mut OsRng, msg)
162 }
163}
164
165#[cfg(feature = "ecdsa")]
167#[derive(Clone)]
168pub struct VerifyingKey(ecdsa_core::VerifyingKey<NistP521>);
169
170#[cfg(feature = "ecdsa")]
171impl VerifyingKey {
172 pub fn from_sec1_bytes(bytes: &[u8]) -> Result<Self> {
174 ecdsa_core::VerifyingKey::<NistP521>::from_sec1_bytes(bytes).map(Into::into)
175 }
176
177 pub fn from_affine(affine: AffinePoint) -> Result<Self> {
182 ecdsa_core::VerifyingKey::<NistP521>::from_affine(affine).map(Into::into)
183 }
184
185 pub fn from_encoded_point(public_key: &EncodedPoint) -> Result<Self> {
187 ecdsa_core::VerifyingKey::<NistP521>::from_encoded_point(public_key).map(Into::into)
188 }
189
190 pub fn to_encoded_point(&self, compress: bool) -> EncodedPoint {
193 self.0.to_encoded_point(compress)
194 }
195
196 pub fn as_affine(&self) -> &AffinePoint {
198 self.0.as_affine()
199 }
200}
201
202#[cfg(feature = "ecdsa")]
203impl From<&SigningKey> for VerifyingKey {
204 fn from(signing_key: &SigningKey) -> VerifyingKey {
205 Self::from(*signing_key.0.verifying_key())
206 }
207}
208
209#[cfg(feature = "ecdsa")]
210impl From<ecdsa_core::VerifyingKey<NistP521>> for VerifyingKey {
211 fn from(inner: ecdsa_core::VerifyingKey<NistP521>) -> VerifyingKey {
212 VerifyingKey(inner)
213 }
214}
215
216#[cfg(feature = "ecdsa")]
217impl PrehashVerifier<Signature> for VerifyingKey {
218 fn verify_prehash(&self, prehash: &[u8], signature: &Signature) -> Result<()> {
219 self.0.verify_prehash(prehash, signature)
220 }
221}
222
223#[cfg(feature = "ecdsa")]
224impl Verifier<Signature> for VerifyingKey {
225 fn verify(&self, msg: &[u8], signature: &Signature) -> Result<()> {
226 self.verify_prehash(&Sha512::digest(msg), signature)
227 }
228}
229
230#[cfg(all(test, feature = "ecdsa", feature = "getrandom"))]
231mod tests {
232 mod sign {
235 use crate::{test_vectors::ecdsa::ECDSA_TEST_VECTORS, NistP521};
236 ecdsa_core::new_signing_test!(NistP521, ECDSA_TEST_VECTORS);
237 }
238
239 mod verify {
240 use crate::{test_vectors::ecdsa::ECDSA_TEST_VECTORS, NistP521};
241 ecdsa_core::new_verification_test!(NistP521, ECDSA_TEST_VECTORS);
242 }
243
244 mod wycheproof {
245 use crate::{
246 ecdsa::{Signature, Verifier, VerifyingKey},
247 EncodedPoint, NistP521,
248 };
249
250 #[test]
252 fn wycheproof() {
253 use blobby::Blob5Iterator;
254 use elliptic_curve::generic_array::typenum::Unsigned;
255
256 fn element_from_padded_slice<C: elliptic_curve::Curve>(
259 data: &[u8],
260 ) -> elliptic_curve::FieldBytes<C> {
261 let point_len = C::FieldBytesSize::USIZE;
262 if data.len() >= point_len {
263 let offset = data.len() - point_len;
264 for v in data.iter().take(offset) {
265 assert_eq!(*v, 0, "EcdsaVerifier: point too large");
266 }
267 elliptic_curve::FieldBytes::<C>::clone_from_slice(&data[offset..])
268 } else {
269 let iter = core::iter::repeat(0)
272 .take(point_len - data.len())
273 .chain(data.iter().cloned());
274 elliptic_curve::FieldBytes::<C>::from_exact_iter(iter).unwrap()
275 }
276 }
277
278 fn run_test(
279 wx: &[u8],
280 wy: &[u8],
281 msg: &[u8],
282 sig: &[u8],
283 pass: bool,
284 ) -> Option<&'static str> {
285 let x = element_from_padded_slice::<NistP521>(wx);
286 let y = element_from_padded_slice::<NistP521>(wy);
287 let q_encoded =
288 EncodedPoint::from_affine_coordinates(&x, &y, false);
289 let verifying_key = VerifyingKey::from_encoded_point(&q_encoded).unwrap();
290
291 let sig = match Signature::from_der(sig) {
292 Ok(s) => s,
293 Err(_) if !pass => return None,
294 Err(_) => return Some("failed to parse signature ASN.1"),
295 };
296
297 match verifying_key.verify(msg, &sig) {
298 Ok(_) if pass => None,
299 Ok(_) => Some("signature verify unexpectedly succeeded"),
300 Err(_) if !pass => None,
301 Err(_) => Some("signature verify failed"),
302 }
303 }
304
305 let data = include_bytes!(concat!("test_vectors/data/wycheproof.blb"));
306
307 for (i, row) in Blob5Iterator::new(data).unwrap().enumerate() {
308 let [wx, wy, msg, sig, status] = row.unwrap();
309 let pass = match status[0] {
310 0 => false,
311 1 => true,
312 _ => panic!("invalid value for pass flag"),
313 };
314 if let Some(desc) = run_test(wx, wy, msg, sig, pass) {
315 panic!(
316 "\n\
317 Failed test №{}: {}\n\
318 wx:\t{:?}\n\
319 wy:\t{:?}\n\
320 msg:\t{:?}\n\
321 sig:\t{:?}\n\
322 pass:\t{}\n",
323 i, desc, wx, wy, msg, sig, pass,
324 );
325 }
326 }
327 }
328 }
329}