1use core::cmp::Ordering;
14use core::fmt;
15use core::hash::{Hash, Hasher};
16
17use k256::ecdsa::hazmat::SignPrimitive;
18use k256::elliptic_curve::PrimeField;
19use k256::elliptic_curve::group::Group;
20use k256::elliptic_curve::ops::Reduce;
21use k256::elliptic_curve::point::AffineCoordinates;
22use k256::elliptic_curve::sec1::ToEncodedPoint;
23use k256::elliptic_curve::subtle::Choice;
24use k256::{AffinePoint, FieldBytes, NonZeroScalar, ProjectivePoint, Scalar, U256};
25use rand_core::CryptoRngCore;
26use sha2::{Digest, Sha256};
27use subtle::ConstantTimeEq;
28use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
29
30use crate::encoding::{self, EncodingError};
31
32pub const CURVE_ORDER: [u8; 32] = [
34 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xba, 0xae, 0xdc,
35 0xe6, 0xaf, 0x48, 0xa0, 0x3b, 0xbf, 0xd2, 0x5e, 0x8c, 0xd0, 0x36, 0x41, 0x41,
36];
37
38pub const CURVE_ORDER_HALF: [u8; 32] = [
40 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5d, 0x57, 0x6e,
41 0x73, 0x57, 0xa4, 0x50, 0x1d, 0xdf, 0xe9, 0x2f, 0x46, 0x68, 0x1b, 0x20, 0xa0,
42];
43
44#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
46#[non_exhaustive]
47pub enum KeyError {
48 #[error(transparent)]
50 Encoding(#[from] EncodingError),
51 #[error("invalid secp256k1 private key")]
53 InvalidPrivateKey,
54 #[error("{what} is not a valid secp256k1 public key")]
56 InvalidPublicKey {
57 what: &'static str,
59 },
60 #[error("signature {which} is out of range")]
62 SignatureOutOfRange {
63 which: &'static str,
65 },
66 #[error("signature is not strict DER")]
68 InvalidDer,
69 #[error("signing failed")]
71 SigningFailed,
72 #[error("the random number generator failed")]
74 RandomnessUnavailable,
75}
76
77pub(crate) fn scalar_from_bytes(bytes: &[u8; 32]) -> Option<Scalar> {
82 Option::from(Scalar::from_repr(FieldBytes::from(*bytes)))
83}
84
85pub(crate) fn nonzero_scalar_from_bytes(bytes: &[u8; 32]) -> Option<NonZeroScalar> {
87 let mut repr = FieldBytes::from(*bytes);
88 let scalar = Option::from(NonZeroScalar::from_repr(repr));
89 repr[..].zeroize();
90 scalar
91}
92
93pub(crate) fn reduce32(bytes: &[u8; 32]) -> Scalar {
95 <Scalar as Reduce<U256>>::reduce_bytes(&FieldBytes::from(*bytes))
96}
97
98pub(crate) fn finalize_wiped<D>(hasher: &mut D) -> sha2::digest::Output<D>
103where
104 D: Digest + sha2::digest::FixedOutputReset + sha2::digest::core_api::BlockSizeUser,
105{
106 let out = Digest::finalize_reset(hasher);
107 let zeros = [0u8; 256];
110 let fill = (<D as sha2::digest::core_api::BlockSizeUser>::block_size()).saturating_sub(1).min(zeros.len());
111 Digest::update(hasher, &zeros[..fill]);
112 out
113}
114
115pub(crate) fn scalar_to_bytes(s: &Scalar) -> [u8; 32] {
117 s.to_bytes().into()
118}
119
120pub(crate) fn x_mod_n(point: &AffinePoint) -> Scalar {
122 <Scalar as Reduce<U256>>::reduce_bytes(&point.x())
123}
124
125pub(crate) fn is_low(s: &[u8; 32]) -> bool {
127 s.as_slice() <= CURVE_ORDER_HALF.as_slice()
128}
129
130#[derive(Clone)]
135pub struct PrivateKey(k256::SecretKey);
136
137const MAX_KEY_DRAWS: usize = 8;
139
140impl PrivateKey {
141 pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R) -> Self {
144 let mut rng = rng;
145 Self(k256::SecretKey::from(NonZeroScalar::random(&mut rng)))
146 }
147
148 pub fn try_random<R: CryptoRngCore + ?Sized>(rng: &mut R) -> Result<Self, KeyError> {
151 let mut bytes = Zeroizing::new([0u8; 32]);
152 for _ in 0..MAX_KEY_DRAWS {
153 rng.try_fill_bytes(&mut *bytes).map_err(|_| KeyError::RandomnessUnavailable)?;
154 if let Ok(key) = Self::from_bytes(&bytes) {
155 return Ok(key);
156 }
157 }
158 Err(KeyError::RandomnessUnavailable)
159 }
160
161 pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, KeyError> {
163 let scalar = nonzero_scalar_from_bytes(bytes).ok_or(KeyError::InvalidPrivateKey)?;
164 Ok(Self(k256::SecretKey::from(scalar)))
165 }
166
167 pub fn from_slice(bytes: &[u8]) -> Result<Self, KeyError> {
169 let array = Zeroizing::new(encoding::to_array::<32>(bytes, "private key")?);
170 Self::from_bytes(&array)
171 }
172
173 pub fn from_hex(s: &str) -> Result<Self, KeyError> {
175 let bytes = Zeroizing::new(encoding::decode_hex(s)?);
176 Self::from_slice(&bytes)
177 }
178
179 pub fn to_bytes(&self) -> Zeroizing<[u8; 32]> {
181 let mut field = self.0.to_bytes();
182 let mut out = Zeroizing::new([0u8; 32]);
183 out.copy_from_slice(&field);
184 field[..].zeroize();
185 out
186 }
187
188 pub fn public_key(&self) -> PublicKey {
190 PublicKey::from_affine(*self.0.public_key().as_affine())
191 }
192
193 pub(crate) fn scalar(&self) -> NonZeroScalar {
194 self.0.to_nonzero_scalar()
195 }
196
197 pub fn sign_prehash(&self, digest: &[u8; 32]) -> Result<Signature, KeyError> {
201 let z = FieldBytes::from(scalar_to_bytes(&reduce32(digest)));
202 let secret = Zeroizing::new(self.scalar());
203 let (sig, _) = (**secret).try_sign_prehashed_rfc6979::<Sha256>(&z, &[]).map_err(|_| KeyError::SigningFailed)?;
204 let sig = sig.normalize_s().unwrap_or(sig);
206 let (r, s) = sig.split_bytes();
207 Signature::from_scalars(r.into(), s.into())
208 }
209}
210
211impl fmt::Debug for PrivateKey {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 f.write_str("PrivateKey(<redacted>)")
214 }
215}
216
217impl PartialEq for PrivateKey {
218 fn eq(&self, other: &Self) -> bool {
219 self.to_bytes().ct_eq(&*other.to_bytes()).into()
220 }
221}
222
223impl Eq for PrivateKey {}
224
225#[derive(Clone, Copy)]
231pub struct PublicKey {
232 bytes: [u8; 33],
233 point: AffinePoint,
234}
235
236impl PublicKey {
237 fn from_affine(point: AffinePoint) -> Self {
238 let encoded = point.to_encoded_point(true);
239 let mut bytes = [0u8; 33];
240 if let Some(slice) = encoded.as_bytes().get(..33) {
242 bytes.copy_from_slice(slice);
243 }
244 Self { bytes, point }
245 }
246
247 pub fn from_compressed(bytes: &[u8]) -> Result<Self, KeyError> {
250 Self::parse(bytes, false, "public key")
251 }
252
253 pub fn from_sec1(bytes: &[u8]) -> Result<Self, KeyError> {
256 Self::parse(bytes, true, "public key")
257 }
258
259 pub fn from_hex(s: &str) -> Result<Self, KeyError> {
261 Self::from_compressed(&encoding::decode_hex(s)?)
262 }
263
264 pub(crate) fn parse(bytes: &[u8], allow_uncompressed: bool, what: &'static str) -> Result<Self, KeyError> {
265 let well_formed = match bytes.first() {
266 Some(0x02 | 0x03) => bytes.len() == 33,
267 Some(0x04) => allow_uncompressed && bytes.len() == 65,
268 _ => false,
269 };
270 if !well_formed {
271 return Err(KeyError::InvalidPublicKey { what });
272 }
273 let key = k256::PublicKey::from_sec1_bytes(bytes).map_err(|_| KeyError::InvalidPublicKey { what })?;
274 Ok(Self::from_affine(*key.as_affine()))
275 }
276
277 pub fn is_valid_compressed(bytes: &[u8]) -> bool {
279 Self::from_compressed(bytes).is_ok()
280 }
281
282 pub const fn to_bytes(&self) -> [u8; 33] {
284 self.bytes
285 }
286
287 pub const fn as_bytes(&self) -> &[u8; 33] {
289 &self.bytes
290 }
291
292 pub fn to_uncompressed(&self) -> [u8; 65] {
294 let encoded = self.point.to_encoded_point(false);
295 let mut out = [0u8; 65];
296 if let Some(slice) = encoded.as_bytes().get(..65) {
297 out.copy_from_slice(slice);
298 }
299 out
300 }
301
302 pub fn to_hex(&self) -> String {
304 encoding::to_hex(&self.bytes)
305 }
306
307 pub fn hash160(&self) -> [u8; 20] {
309 crate::zcash::hash160(&self.bytes)
310 }
311
312 pub(crate) const fn affine(&self) -> &AffinePoint {
313 &self.point
314 }
315
316 pub(crate) fn projective(&self) -> ProjectivePoint {
317 ProjectivePoint::from(self.point)
318 }
319
320 pub(crate) fn from_projective(point: &ProjectivePoint) -> Option<Self> {
321 let affine = point.to_affine();
322 if bool::from(point.is_identity()) { None } else { Some(Self::from_affine(affine)) }
323 }
324
325 pub fn verify_prehash(&self, digest: &[u8; 32], signature: &Signature) -> bool {
327 if !signature.is_low_s() {
328 return false;
329 }
330 let Ok(sig) = k256::ecdsa::Signature::from_scalars(signature.r, signature.s) else {
331 return false;
332 };
333 let Ok(key) = k256::ecdsa::VerifyingKey::from_affine(self.point) else {
334 return false;
335 };
336 use k256::ecdsa::signature::hazmat::PrehashVerifier;
337 key.verify_prehash(digest, &sig).is_ok()
338 }
339}
340
341impl PartialEq for PublicKey {
342 fn eq(&self, other: &Self) -> bool {
343 self.bytes == other.bytes
344 }
345}
346
347impl Eq for PublicKey {}
348
349impl Hash for PublicKey {
350 fn hash<H: Hasher>(&self, state: &mut H) {
351 self.bytes.hash(state);
352 }
353}
354
355impl PartialOrd for PublicKey {
356 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
357 Some(self.cmp(other))
358 }
359}
360
361impl Ord for PublicKey {
362 fn cmp(&self, other: &Self) -> Ordering {
363 self.bytes.cmp(&other.bytes)
364 }
365}
366
367impl fmt::Debug for PublicKey {
368 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
369 write!(f, "PublicKey({})", self.to_hex())
370 }
371}
372
373impl fmt::Display for PublicKey {
374 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
375 f.write_str(&self.to_hex())
376 }
377}
378
379#[derive(Clone, PartialEq, Eq)]
386pub struct KeyPair {
387 private_key: PrivateKey,
388 public_key: PublicKey,
389}
390
391impl KeyPair {
392 pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R) -> Self {
394 Self::from_private(PrivateKey::random(rng))
395 }
396
397 pub fn try_random<R: CryptoRngCore + ?Sized>(rng: &mut R) -> Result<Self, KeyError> {
399 Ok(Self::from_private(PrivateKey::try_random(rng)?))
400 }
401
402 pub fn from_private(private_key: PrivateKey) -> Self {
404 let public_key = private_key.public_key();
405 Self { private_key, public_key }
406 }
407
408 pub fn from_private_hex(s: &str) -> Result<Self, KeyError> {
410 Ok(Self::from_private(PrivateKey::from_hex(s)?))
411 }
412
413 pub const fn private_key(&self) -> &PrivateKey {
415 &self.private_key
416 }
417
418 pub const fn public_key(&self) -> PublicKey {
420 self.public_key
421 }
422
423 pub fn into_private_key(self) -> PrivateKey {
425 self.private_key
426 }
427}
428
429impl From<PrivateKey> for KeyPair {
430 fn from(private_key: PrivateKey) -> Self {
431 Self::from_private(private_key)
432 }
433}
434
435impl fmt::Debug for KeyPair {
436 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
437 f.debug_struct("KeyPair").field("public_key", &self.public_key).finish_non_exhaustive()
438 }
439}
440
441#[derive(Clone, Copy, PartialEq, Eq, Hash)]
447pub struct Signature {
448 r: [u8; 32],
449 s: [u8; 32],
450}
451
452impl Signature {
453 pub fn from_scalars(r: [u8; 32], s: [u8; 32]) -> Result<Self, KeyError> {
455 if nonzero_scalar_from_bytes(&r).is_none() {
456 return Err(KeyError::SignatureOutOfRange { which: "r" });
457 }
458 if nonzero_scalar_from_bytes(&s).is_none() {
459 return Err(KeyError::SignatureOutOfRange { which: "s" });
460 }
461 Ok(Self { r, s })
462 }
463
464 pub fn from_compact(bytes: &[u8]) -> Result<Self, KeyError> {
466 let array: [u8; 64] = encoding::to_array(bytes, "compact signature")?;
467 let mut r = [0u8; 32];
468 let mut s = [0u8; 32];
469 r.copy_from_slice(&array[..32]);
470 s.copy_from_slice(&array[32..]);
471 Self::from_scalars(r, s)
472 }
473
474 pub fn from_der(der: &[u8]) -> Result<Self, KeyError> {
477 let (r, s) = parse_strict_der(der).ok_or(KeyError::InvalidDer)?;
478 Self::from_scalars(r, s)
479 }
480
481 pub const fn r(&self) -> [u8; 32] {
483 self.r
484 }
485
486 pub const fn s(&self) -> [u8; 32] {
488 self.s
489 }
490
491 pub fn is_low_s(&self) -> bool {
493 is_low(&self.s)
494 }
495
496 pub fn normalize_s(&self) -> Self {
498 if self.is_low_s() {
499 return *self;
500 }
501 match scalar_from_bytes(&self.s) {
502 Some(s) => Self { r: self.r, s: scalar_to_bytes(&-s) },
503 None => *self,
504 }
505 }
506
507 pub fn to_compact(&self) -> [u8; 64] {
509 let mut out = [0u8; 64];
510 out[..32].copy_from_slice(&self.r);
511 out[32..].copy_from_slice(&self.s);
512 out
513 }
514
515 pub fn to_der(&self) -> Vec<u8> {
517 let r = der_integer(&self.r);
518 let s = der_integer(&self.s);
519 let mut out = Vec::with_capacity(6 + r.len() + s.len());
520 out.push(0x30);
521 out.push((4 + r.len() + s.len()) as u8);
522 out.push(0x02);
523 out.push(r.len() as u8);
524 out.extend_from_slice(&r);
525 out.push(0x02);
526 out.push(s.len() as u8);
527 out.extend_from_slice(&s);
528 out
529 }
530
531 pub(crate) fn r_scalar(&self) -> Scalar {
532 scalar_from_bytes(&self.r).unwrap_or(Scalar::ZERO)
533 }
534
535 pub(crate) fn s_scalar(&self) -> Scalar {
536 scalar_from_bytes(&self.s).unwrap_or(Scalar::ZERO)
537 }
538}
539
540impl fmt::Debug for Signature {
541 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
542 write!(f, "Signature(r: {}, s: {})", encoding::to_hex(&self.r), encoding::to_hex(&self.s))
543 }
544}
545
546fn der_integer(value: &[u8; 32]) -> Vec<u8> {
549 let first = value.iter().position(|&b| b != 0).unwrap_or(31);
550 let digits = value.get(first..).unwrap_or(&[0]);
551 let mut out = Vec::with_capacity(33);
552 if digits.first().is_some_and(|b| b & 0x80 != 0) {
553 out.push(0);
554 }
555 out.extend_from_slice(digits);
556 out
557}
558
559fn parse_strict_der(sig: &[u8]) -> Option<([u8; 32], [u8; 32])> {
561 let len = sig.len();
562 if !(8..=72).contains(&len) {
563 return None;
564 }
565 if *sig.first()? != 0x30 || usize::from(*sig.get(1)?) != len - 2 {
566 return None;
567 }
568 let len_r = usize::from(*sig.get(3)?);
569 if 5 + len_r >= len {
570 return None;
571 }
572 let len_s = usize::from(*sig.get(5 + len_r)?);
573 if len_r + len_s + 6 != len {
574 return None;
575 }
576 let r = der_body(sig, 2, len_r)?;
577 let s = der_body(sig, 4 + len_r, len_s)?;
578 Some((r, s))
579}
580
581fn der_body(sig: &[u8], tag_at: usize, body_len: usize) -> Option<[u8; 32]> {
583 if *sig.get(tag_at)? != 0x02 || body_len == 0 {
584 return None;
585 }
586 let body = sig.get(tag_at + 2..tag_at + 2 + body_len)?;
587 let first = *body.first()?;
588 if first & 0x80 != 0 {
589 return None; }
591 if body_len > 1 && first == 0 && body.get(1).is_some_and(|b| b & 0x80 == 0) {
592 return None; }
594 let digits = if first == 0 && body_len > 1 { body.get(1..)? } else { body };
595 if digits.len() > 32 {
596 return None;
597 }
598 let mut out = [0u8; 32];
599 out.get_mut(32 - digits.len()..)?.copy_from_slice(digits);
600 Some(out)
601}
602
603#[derive(Clone, Zeroize, ZeroizeOnDrop)]
609pub struct Secret([u8; 32]);
610
611impl Secret {
612 pub fn random<R: CryptoRngCore + ?Sized>(rng: &mut R) -> Self {
614 let mut secret = Self([0u8; 32]);
615 rng.fill_bytes(&mut secret.0);
616 secret
617 }
618
619 pub fn try_random<R: CryptoRngCore + ?Sized>(rng: &mut R) -> Result<Self, KeyError> {
621 let mut secret = Self([0u8; 32]);
622 rng.try_fill_bytes(&mut secret.0).map_err(|_| KeyError::RandomnessUnavailable)?;
623 Ok(secret)
624 }
625
626 pub const fn from_bytes(bytes: [u8; 32]) -> Self {
628 Self(bytes)
629 }
630
631 pub fn from_slice(bytes: &[u8]) -> Result<Self, EncodingError> {
633 let mut secret = Self([0u8; 32]);
634 if bytes.len() != 32 {
635 return Err(EncodingError::InvalidLength { what: "secret", expected: 32, actual: bytes.len() });
636 }
637 secret.0.copy_from_slice(bytes);
638 Ok(secret)
639 }
640
641 pub fn from_hex(s: &str) -> Result<Self, EncodingError> {
643 let bytes = Zeroizing::new(encoding::decode_hex(s)?);
644 Self::from_slice(&bytes)
645 }
646
647 pub const fn expose_secret(&self) -> &[u8; 32] {
649 &self.0
650 }
651
652 pub fn to_hex(&self) -> Zeroizing<String> {
654 Zeroizing::new(encoding::to_hex(&self.0))
655 }
656
657 pub fn hashlock(&self) -> [u8; 32] {
659 let mut hasher = Sha256::new();
660 hasher.update(self.0);
661 finalize_wiped(&mut hasher).into()
662 }
663
664 pub fn matches_hashlock(&self, hashlock: &[u8; 32]) -> bool {
666 self.hashlock().ct_eq(hashlock).into()
667 }
668}
669
670impl ConstantTimeEq for Secret {
671 fn ct_eq(&self, other: &Self) -> subtle::Choice {
672 self.0.ct_eq(&other.0)
673 }
674}
675
676impl PartialEq for Secret {
677 fn eq(&self, other: &Self) -> bool {
678 self.ct_eq(other).into()
679 }
680}
681
682impl Eq for Secret {}
683
684impl fmt::Debug for Secret {
685 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
686 f.write_str("Secret(<redacted>)")
687 }
688}
689
690pub(crate) fn lift_x(x: &[u8; 32], y_odd: bool) -> Option<AffinePoint> {
692 use k256::elliptic_curve::point::DecompressPoint;
693 Option::from(AffinePoint::decompress(&FieldBytes::from(*x), Choice::from(u8::from(y_odd))))
694}
695
696#[cfg(test)]
697mod tests {
698 #![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
699 use super::*;
700
701 #[test]
702 fn public_keys_must_be_on_the_curve_and_compressed() {
703 let key = KeyPair::random(&mut crate::testutil::TestRng);
704 assert!(PublicKey::is_valid_compressed(key.public_key.as_bytes()));
705 let mut off_curve = [0u8; 33];
706 off_curve[0] = 2;
707 assert!(!PublicKey::is_valid_compressed(&off_curve));
708 assert!(!PublicKey::is_valid_compressed(&key.public_key.as_bytes()[1..]));
709 assert!(PublicKey::from_compressed(&key.public_key.to_uncompressed()).is_err());
710 assert_eq!(PublicKey::from_sec1(&key.public_key.to_uncompressed()).unwrap(), key.public_key);
711 let mut compact = key.public_key.to_bytes();
712 compact[0] = 0x05;
713 assert!(PublicKey::from_sec1(&compact).is_err());
714 assert!(PublicKey::from_sec1(&[0]).is_err());
715 }
716
717 #[test]
718 fn private_keys_are_range_checked() {
719 assert_eq!(PrivateKey::from_bytes(&[0u8; 32]), Err(KeyError::InvalidPrivateKey));
720 assert_eq!(PrivateKey::from_bytes(&CURVE_ORDER), Err(KeyError::InvalidPrivateKey));
721 let mut max = CURVE_ORDER;
722 max[31] -= 1;
723 assert!(PrivateKey::from_bytes(&max).is_ok());
724 assert!(format!("{:?}", PrivateKey::from_bytes(&max).unwrap()).contains("redacted"));
725 }
726
727 #[test]
728 fn signs_low_s_and_round_trips_der() {
729 let key = KeyPair::random(&mut crate::testutil::TestRng);
730 for i in 0..20u8 {
731 let digest: [u8; 32] = Sha256::digest([i]).into();
732 let sig = key.private_key.sign_prehash(&digest).unwrap();
733 assert!(sig.is_low_s());
734 assert!(key.public_key.verify_prehash(&digest, &sig));
735 assert_eq!(Signature::from_der(&sig.to_der()).unwrap(), sig);
736 assert_eq!(Signature::from_compact(&sig.to_compact()).unwrap(), sig);
737 let s = scalar_from_bytes(&sig.s()).unwrap();
739 let high = Signature::from_scalars(sig.r(), scalar_to_bytes(&-s)).unwrap();
740 assert!(!high.is_low_s());
741 assert!(!key.public_key.verify_prehash(&digest, &high));
742 assert_eq!(high.normalize_s(), sig);
743 }
744 }
745
746 #[test]
747 fn rejects_non_strict_der() {
748 let key = KeyPair::random(&mut crate::testutil::TestRng);
749 let sig = key.private_key.sign_prehash(&[7u8; 32]).unwrap();
750 let der = sig.to_der();
751 let mut trailing = der.clone();
752 trailing.push(0);
753 assert_eq!(Signature::from_der(&trailing), Err(KeyError::InvalidDer));
754 let r_len = usize::from(der[3]);
756 let mut padded = vec![0x30, der[1] + 1, 0x02, der[3] + 1, 0x00];
757 padded.extend_from_slice(&der[4..]);
758 assert_eq!(Signature::from_der(&padded), Err(KeyError::InvalidDer));
759 assert_eq!(r_len + 6 + usize::from(der[5 + r_len]), der.len());
760 assert_eq!(Signature::from_der(&[]), Err(KeyError::InvalidDer));
761 let negative = [0x30, 0x06, 0x02, 0x01, 0x80, 0x02, 0x01, 0x01];
763 assert_eq!(Signature::from_der(&negative), Err(KeyError::InvalidDer));
764 let zero = [0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x01];
766 assert_eq!(Signature::from_der(&zero), Err(KeyError::SignatureOutOfRange { which: "r" }));
767 }
768
769 #[test]
770 fn finalize_wiped_leaves_no_trace_of_the_message() {
771 use sha2::Sha512;
772 let secret = [0x5a; 57];
773 let mut hasher = Sha512::new();
774 hasher.update(secret);
775 let out = finalize_wiped(&mut hasher);
776 assert_eq!(out, Sha512::digest(secret));
777 assert_eq!(hasher.clone().finalize(), Sha512::digest([0u8; 127]));
780 let mut sha256 = Sha256::new();
781 sha256.update(secret);
782 assert_eq!(finalize_wiped(&mut sha256), Sha256::digest(secret));
783 assert_eq!(sha256.finalize(), Sha256::digest([0u8; 63]));
784 }
785
786 #[test]
787 fn key_pairs_derive_their_public_key() {
788 let pair = KeyPair::from_private(PrivateKey::from_bytes(&[3; 32]).unwrap());
789 assert_eq!(pair.public_key(), pair.private_key().public_key());
790 assert_eq!(KeyPair::from(PrivateKey::from_bytes(&[3; 32]).unwrap()), pair);
791 assert_eq!(pair.clone().into_private_key(), *pair.private_key());
792 let secret = Secret::from_slice(&[9; 32]).unwrap();
793 assert_eq!(secret.expose_secret(), &[9; 32]);
794 assert!(Secret::from_slice(&[9; 31]).is_err());
795 }
796
797 #[test]
798 fn secrets_are_redacted_and_hash_to_the_hashlock() {
799 let secret = Secret::from_bytes([1u8; 32]);
800 assert_eq!(format!("{secret:?}"), "Secret(<redacted>)");
801 let lock = secret.hashlock();
802 assert!(secret.matches_hashlock(&lock));
803 assert!(!Secret::from_bytes([2u8; 32]).matches_hashlock(&lock));
804 }
805}