bc_components/
private_key_base.rs1use bc_rand::{ rng_random_data, RandomNumberGenerator, SecureRandomNumberGenerator };
2use bc_ur::prelude::*;
3use anyhow::{ bail, Result };
4use ssh_key::private::{
5 DsaKeypair,
6 EcdsaKeypair,
7 Ed25519Keypair,
8 KeypairData,
9 PrivateKey as SSHPrivateKey,
10 RsaKeypair,
11};
12use ssh_key::Algorithm as SSHAlgorithm;
13use zeroize::ZeroizeOnDrop;
14
15use crate::{
16 tags, Decrypter, ECKey, ECPrivateKey, Ed25519PrivateKey, EncapsulationPrivateKey, EncapsulationPublicKey, HKDFRng, PrivateKeyDataProvider, PrivateKeys, PrivateKeysProvider, PublicKeys, PublicKeysProvider, Signature, Signer, SigningOptions, SigningPrivateKey, Verifier, X25519PrivateKey
17};
18
19#[derive(Clone, Eq, PartialEq, ZeroizeOnDrop)]
62pub struct PrivateKeyBase(Vec<u8>);
63
64impl Signer for PrivateKeyBase {
65 fn sign_with_options(
66 &self,
67 message: &dyn AsRef<[u8]>,
68 options: Option<SigningOptions>
69 ) -> Result<Signature> {
70 let schnorr_key = self.schnorr_signing_private_key();
71 schnorr_key.sign_with_options(message, options)
72 }
73}
74
75impl Verifier for PrivateKeyBase {
76 fn verify(&self, signature: &Signature, message: &dyn AsRef<[u8]>) -> bool {
77 let schnorr_key = self.schnorr_signing_private_key().to_schnorr().unwrap().public_key();
78 match signature.to_schnorr() {
79 Some(schnorr_signature) => schnorr_key.verify(schnorr_signature, message),
80 None => false,
81 }
82 }
83}
84
85impl Decrypter for PrivateKeyBase {
86 fn encapsulation_private_key(&self) -> EncapsulationPrivateKey {
87 EncapsulationPrivateKey::X25519(self.x25519_private_key())
88 }
89}
90
91impl PrivateKeyBase {
92 pub fn new() -> Self {
94 let mut rng = SecureRandomNumberGenerator;
95 Self::new_using(&mut rng)
96 }
97
98 pub fn from_data(data: impl Into<Vec<u8>>) -> Self {
100 Self(data.into())
101 }
102
103 pub fn from_optional_data(data: Option<impl Into<Vec<u8>>>) -> Self {
107 match data {
108 Some(data) => Self::from_data(data),
109 None => Self::new(),
110 }
111 }
112
113 pub fn new_using(rng: &mut impl RandomNumberGenerator) -> Self {
115 Self::from_data(rng_random_data(rng, 32))
116 }
117
118 pub fn new_with_provider(provider: impl PrivateKeyDataProvider) -> Self {
120 Self::from_data(provider.private_key_data())
121 }
122
123 pub fn ecdsa_signing_private_key(&self) -> SigningPrivateKey {
125 SigningPrivateKey::new_ecdsa(ECPrivateKey::derive_from_key_material(&self.0))
126 }
127
128 pub fn schnorr_signing_private_key(&self) -> SigningPrivateKey {
130 SigningPrivateKey::new_schnorr(ECPrivateKey::derive_from_key_material(&self.0))
131 }
132
133 pub fn ed25519_signing_private_key(&self) -> SigningPrivateKey {
135 SigningPrivateKey::new_ed25519(Ed25519PrivateKey::derive_from_key_material(&self.0))
136 }
137
138 pub fn ssh_signing_private_key(
140 &self,
141 algorithm: SSHAlgorithm,
142 comment: impl Into<String>
143 ) -> Result<SigningPrivateKey> {
144 let mut rng = HKDFRng::new(&self.0, algorithm.as_str());
145 let keypair = match algorithm {
146 SSHAlgorithm::Dsa => { KeypairData::Dsa(DsaKeypair::random(&mut rng)?) }
147 SSHAlgorithm::Ecdsa { curve } => {
148 KeypairData::Ecdsa(EcdsaKeypair::random(&mut rng, curve)?)
149 }
150 SSHAlgorithm::Ed25519 => { KeypairData::Ed25519(Ed25519Keypair::random(&mut rng)) }
151 SSHAlgorithm::Rsa { hash: _ } => {
152 KeypairData::Rsa(RsaKeypair::random(&mut rng, 2048)?)
153 }
154 _ => bail!("Unsupported SSH algorithm: {:?}", algorithm.as_str()),
155 };
156 let private_key = SSHPrivateKey::new(keypair, comment)?;
157 Ok(SigningPrivateKey::new_ssh(private_key))
158 }
159
160 pub fn x25519_private_key(&self) -> X25519PrivateKey {
164 X25519PrivateKey::derive_from_key_material(&self.0)
165 }
166
167 pub fn schnorr_private_keys(&self) -> PrivateKeys {
172 PrivateKeys::with_keys(
173 self.schnorr_signing_private_key(),
174 EncapsulationPrivateKey::X25519(self.x25519_private_key())
175 )
176 }
177
178 pub fn schnorr_public_keys(&self) -> PublicKeys {
183 PublicKeys::new(
184 self.schnorr_signing_private_key().public_key().unwrap(),
185 EncapsulationPublicKey::X25519(self.x25519_private_key().public_key())
186 )
187 }
188
189 pub fn ecdsa_private_keys(&self) -> PrivateKeys {
194 PrivateKeys::with_keys(
195 self.ecdsa_signing_private_key(),
196 EncapsulationPrivateKey::X25519(self.x25519_private_key())
197 )
198 }
199
200 pub fn ecdsa_public_keys(&self) -> PublicKeys {
205 PublicKeys::new(
206 self.ecdsa_signing_private_key().public_key().unwrap(),
207 EncapsulationPublicKey::X25519(self.x25519_private_key().public_key())
208 )
209 }
210
211 pub fn ssh_private_keys(
216 &self,
217 algorithm: SSHAlgorithm,
218 comment: impl Into<String>
219 ) -> Result<PrivateKeys> {
220 let private_key = self.ssh_signing_private_key(algorithm, comment)?;
221 Ok(
222 PrivateKeys::with_keys(
223 private_key,
224 EncapsulationPrivateKey::X25519(self.x25519_private_key())
225 )
226 )
227 }
228
229 pub fn ssh_public_keys(
234 &self,
235 algorithm: SSHAlgorithm,
236 comment: impl Into<String>
237 ) -> Result<PublicKeys> {
238 let private_key = self.ssh_signing_private_key(algorithm, comment)?;
239 Ok(
240 PublicKeys::new(
241 private_key.public_key().unwrap(),
242 EncapsulationPublicKey::X25519(self.x25519_private_key().public_key())
243 )
244 )
245 }
246
247 pub fn data(&self) -> &[u8] {
249 self.into()
250 }
251}
252
253impl PrivateKeysProvider for PrivateKeyBase {
254 fn private_keys(&self) -> PrivateKeys {
255 PrivateKeys::with_keys(
256 self.schnorr_signing_private_key(),
257 EncapsulationPrivateKey::X25519(self.x25519_private_key())
258 )
259 }
260}
261
262impl PublicKeysProvider for PrivateKeyBase {
263 fn public_keys(&self) -> PublicKeys {
264 self.schnorr_public_keys()
265 }
266}
267
268impl Default for PrivateKeyBase {
269 fn default() -> Self {
270 Self::new()
271 }
272}
273
274impl std::fmt::Debug for PrivateKeyBase {
275 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
276 write!(f, "PrivateKeyBase")
277 }
278}
279
280impl<'a> From<&'a PrivateKeyBase> for &'a [u8] {
281 fn from(value: &'a PrivateKeyBase) -> Self {
282 &value.0
283 }
284}
285
286impl AsRef<PrivateKeyBase> for PrivateKeyBase {
287 fn as_ref(&self) -> &PrivateKeyBase {
288 self
289 }
290}
291
292impl AsRef<[u8]> for PrivateKeyBase {
293 fn as_ref(&self) -> &[u8] {
294 self.into()
295 }
296}
297
298impl CBORTagged for PrivateKeyBase {
299 fn cbor_tags() -> Vec<Tag> {
300 tags_for_values(&[tags::TAG_PRIVATE_KEY_BASE])
301 }
302}
303
304impl From<PrivateKeyBase> for CBOR {
305 fn from(value: PrivateKeyBase) -> Self {
306 value.tagged_cbor()
307 }
308}
309
310impl CBORTaggedEncodable for PrivateKeyBase {
311 fn untagged_cbor(&self) -> CBOR {
312 CBOR::to_byte_string(&self.0)
313 }
314}
315
316impl TryFrom<CBOR> for PrivateKeyBase {
317 type Error = dcbor::Error;
318
319 fn try_from(cbor: CBOR) -> Result<Self, Self::Error> {
320 Self::from_tagged_cbor(cbor)
321 }
322}
323
324impl CBORTaggedDecodable for PrivateKeyBase {
325 fn from_untagged_cbor(untagged_cbor: CBOR) -> dcbor::Result<Self> {
326 let data = CBOR::try_into_byte_string(untagged_cbor)?;
327 let instance = Self::from_data(data);
328 Ok(instance)
329 }
330}
331
332#[cfg(test)]
333mod tests {
334 use bc_ur::{ UREncodable, URDecodable };
335 use hex_literal::hex;
336
337 use crate::PrivateKeyBase;
338
339 const SEED: [u8; 16] = hex!("59f2293a5bce7d4de59e71b4207ac5d2");
340
341 #[test]
342 fn test_private_key_base() {
343 crate::register_tags();
344 let private_key_base = PrivateKeyBase::from_data(SEED);
345 assert_eq!(
346 private_key_base.ecdsa_signing_private_key().to_ecdsa().unwrap().data(),
347 &hex!("9505a44aaf385ce633cf0e2bc49e65cc88794213bdfbf8caf04150b9c4905f5a")
348 );
349 assert_eq!(
350 private_key_base
351 .schnorr_signing_private_key()
352 .public_key()
353 .unwrap()
354 .to_schnorr()
355 .unwrap()
356 .data(),
357 &hex!("fd4d22f9e8493da52d730aa402ac9e661deca099ef4db5503f519a73c3493e18")
358 );
359 assert_eq!(
360 private_key_base.x25519_private_key().data(),
361 &hex!("77ff838285a0403d3618aa8c30491f99f55221be0b944f50bfb371f43b897485")
362 );
363 assert_eq!(
364 private_key_base.x25519_private_key().public_key().data(),
365 &hex!("863cf3facee3ba45dc54e5eedecb21d791d64adfb0a1c63bfb6fea366c1ee62b")
366 );
367
368 let ur = private_key_base.ur_string();
369 assert_eq!(ur, "ur:crypto-prvkey-base/gdhkwzdtfthptokigtvwnnjsqzcxknsktdsfecsbbk");
370 assert_eq!(PrivateKeyBase::from_ur_string(&ur).unwrap(), private_key_base);
371 }
372}