Now let's take a silly one
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 as_bytes(&self) -> &[u8] {
26 &self.0
27 }
28}
29
30#[derive(Debug, thiserror::Error)]
31pub enum SignerError {
32 #[error("invalid signing key bytes")]
33 InvalidKey,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum SignatureScheme {
38 Secp256k1,
39 P256,
40}
41
42pub trait Signer: Send + Sync + 'static {
43 fn sign(&self, message: &[u8]) -> Signature;
44 fn public_key(&self) -> PublicKeyBytes;
45 fn scheme(&self) -> SignatureScheme;
46}
47
48pub struct K256Signer {
49 key: SigningKey,
50}
51
52impl K256Signer {
53 pub fn from_slice(bytes: &[u8]) -> Result<Self, SignerError> {
54 SigningKey::from_slice(bytes)
55 .map(|key| Self { key })
56 .map_err(|_| SignerError::InvalidKey)
57 }
58
59 pub fn generate(entropy: &dyn Entropy) -> Self {
60 std::iter::repeat_with(|| {
61 let mut bytes = [0u8; 32];
62 entropy.fill(&mut bytes);
63 SigningKey::from_slice(&bytes).ok()
64 })
65 .take(MAX_SCALAR_ATTEMPTS)
66 .flatten()
67 .next()
68 .map(|key| Self { key })
69 .unwrap_or_else(|| {
70 panic!(
71 "entropy failed to yield valid secp256k1 scalar in {MAX_SCALAR_ATTEMPTS} attempts"
72 )
73 })
74 }
75}
76
77impl Signer for K256Signer {
78 fn sign(&self, message: &[u8]) -> Signature {
79 let signature: K256Signature = self.key.sign(message);
80 Signature(signature.to_bytes().to_vec())
81 }
82
83 fn public_key(&self) -> PublicKeyBytes {
84 let point = self.key.verifying_key().to_encoded_point(true);
85 PublicKeyBytes(point.as_bytes().to_vec())
86 }
87
88 fn scheme(&self) -> SignatureScheme {
89 SignatureScheme::Secp256k1
90 }
91}
92
93pub fn verify(public_key: &PublicKeyBytes, message: &[u8], signature: &Signature) -> bool {
94 let Ok(verifying_key) = VerifyingKey::from_sec1_bytes(public_key.as_bytes()) else {
95 return false;
96 };
97 let Ok(parsed) = K256Signature::from_slice(signature.as_bytes()) else {
98 return false;
99 };
100 verifying_key.verify(message, &parsed).is_ok()
101}
102
103#[cfg(test)]
104mod tests {
105 use super::*;
106 use crate::SeededEntropy;
107
108 #[test]
109 fn sign_then_verify_roundtrips() {
110 let signer = K256Signer::generate(&SeededEntropy::new(1));
111 let message = b"refs/heads/main update";
112 let signature = signer.sign(message);
113 assert!(verify(&signer.public_key(), message, &signature));
114 }
115
116 #[test]
117 fn verify_rejects_tampered_message() {
118 let signer = K256Signer::generate(&SeededEntropy::new(2));
119 let signature = signer.sign(b"original");
120 assert!(!verify(&signer.public_key(), b"tampered", &signature));
121 }
122
123 #[test]
124 fn generate_is_deterministic_from_seed() {
125 let one = K256Signer::generate(&SeededEntropy::new(99));
126 let two = K256Signer::generate(&SeededEntropy::new(99));
127 assert_eq!(one.public_key(), two.public_key());
128 }
129
130 struct BrokenEntropy;
131
132 impl crate::Entropy for BrokenEntropy {
133 fn next_u64(&self) -> u64 {
134 0
135 }
136
137 fn fill(&self, buffer: &mut [u8]) {
138 buffer.fill(0);
139 }
140
141 fn derive(&self, _label: u64) -> Box<dyn crate::Entropy> {
142 Box::new(BrokenEntropy)
143 }
144 }
145
146 #[test]
147 #[should_panic(expected = "entropy failed to yield valid secp256k1 scalar")]
148 fn broken_entropy_fails_stop_instead_of_spinning() {
149 let _ = K256Signer::generate(&BrokenEntropy);
150 }
151}