This repository has no description
3.6 kB
141 lines
1use k256::ecdsa::signature::{Signer as _, Verifier as _};
2use k256::ecdsa::{Signature as K256Signature, SigningKey, VerifyingKey};
3
4use crate::Entropy;
5
6pub const MAX_SCALAR_ATTEMPTS: usize = 64;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct Signature(Vec<u8>);
10
11impl Signature {
12 pub fn from_bytes(bytes: Vec<u8>) -> Self {
13 Self(bytes)
14 }
15
16 pub fn as_bytes(&self) -> &[u8] {
17 &self.0
18 }
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct PublicKeyBytes(Vec<u8>);
23
24impl PublicKeyBytes {
25 pub fn from_bytes(bytes: Vec<u8>) -> Self {
26 Self(bytes)
27 }
28
29 pub fn as_bytes(&self) -> &[u8] {
30 &self.0
31 }
32}
33
34#[derive(Debug, thiserror::Error)]
35pub enum SignerError {
36 #[error("invalid signing key bytes")]
37 InvalidKey,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub enum SignatureScheme {
42 Secp256k1,
43 P256,
44}
45
46pub trait Signer: Send + Sync + 'static {
47 fn sign(&self, message: &[u8]) -> Signature;
48 fn public_key(&self) -> PublicKeyBytes;
49 fn scheme(&self) -> SignatureScheme;
50}
51
52pub struct K256Signer {
53 key: SigningKey,
54}
55
56impl K256Signer {
57 pub fn from_slice(bytes: &[u8]) -> Result<Self, SignerError> {
58 SigningKey::from_slice(bytes)
59 .map(|key| Self { key })
60 .map_err(|_| SignerError::InvalidKey)
61 }
62
63 // peak dice rolling
64 pub fn generate(entropy: &dyn Entropy) -> Self {
65 std::iter::repeat_with(|| {
66 let mut bytes = [0u8; 32];
67 entropy.fill(&mut bytes);
68 SigningKey::from_slice(&bytes).ok()
69 })
70 .take(MAX_SCALAR_ATTEMPTS)
71 .flatten()
72 .next()
73 .map(|key| Self { key })
74 .unwrap_or_else(|| {
75 panic!(
76 "entropy failed to yield valid secp256k1 scalar in {MAX_SCALAR_ATTEMPTS} attempts"
77 )
78 })
79 }
80}
81
82impl Signer for K256Signer {
83 fn sign(&self, message: &[u8]) -> Signature {
84 let signature: K256Signature = self.key.sign(message);
85 Signature(signature.to_bytes().to_vec())
86 }
87
88 fn public_key(&self) -> PublicKeyBytes {
89 let point = self.key.verifying_key().to_encoded_point(true);
90 PublicKeyBytes(point.as_bytes().to_vec())
91 }
92
93 fn scheme(&self) -> SignatureScheme {
94 SignatureScheme::Secp256k1
95 }
96}
97
98pub fn verify(public_key: &PublicKeyBytes, message: &[u8], signature: &Signature) -> bool {
99 let Ok(verifying_key) = VerifyingKey::from_sec1_bytes(public_key.as_bytes()) else {
100 return false;
101 };
102 let Ok(parsed) = K256Signature::from_slice(signature.as_bytes()) else {
103 return false;
104 };
105 verifying_key.verify(message, &parsed).is_ok()
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::SeededEntropy;
112
113 #[test]
114 fn generate_is_deterministic_from_seed() {
115 let one = K256Signer::generate(&SeededEntropy::new(99));
116 let two = K256Signer::generate(&SeededEntropy::new(99));
117 assert_eq!(one.public_key(), two.public_key());
118 }
119
120 struct BrokenEntropy;
121
122 impl crate::Entropy for BrokenEntropy {
123 fn next_u64(&self) -> u64 {
124 0
125 }
126
127 fn fill(&self, buffer: &mut [u8]) {
128 buffer.fill(0);
129 }
130
131 fn derive(&self, _label: u64) -> Box<dyn crate::Entropy> {
132 Box::new(BrokenEntropy)
133 }
134 }
135
136 #[test]
137 #[should_panic(expected = "entropy failed to yield valid secp256k1 scalar")]
138 fn broken_entropy_fails_stop_instead_of_spinning() {
139 let _ = K256Signer::generate(&BrokenEntropy);
140 }
141}