1use bc_rand::RandomNumberGenerator;
2use secp256k1::{
3 Keypair, PublicKey, Secp256k1, SecretKey,
4 constants::{
5 PUBLIC_KEY_SIZE, SECRET_KEY_SIZE, UNCOMPRESSED_PUBLIC_KEY_SIZE,
6 },
7};
8
9pub const ECDSA_PRIVATE_KEY_SIZE: usize = 32;
10pub const ECDSA_PUBLIC_KEY_SIZE: usize = 33;
11pub const ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE: usize = 65;
12pub const ECDSA_MESSAGE_HASH_SIZE: usize = 32;
13pub const ECDSA_SIGNATURE_SIZE: usize = 64;
14pub const SCHNORR_PUBLIC_KEY_SIZE: usize = 32;
15
16use crate::hash::hkdf_hmac_sha256;
17
18pub fn ecdsa_new_private_key_using(
20 rng: &mut impl RandomNumberGenerator,
21) -> [u8; SECRET_KEY_SIZE] {
22 rng.random_data(ECDSA_PRIVATE_KEY_SIZE).try_into().unwrap()
23}
24
25pub fn ecdsa_public_key_from_private_key(
27 private_key: &[u8; ECDSA_PRIVATE_KEY_SIZE],
28) -> [u8; PUBLIC_KEY_SIZE] {
29 let secp = Secp256k1::new();
30 let private_key = SecretKey::from_byte_array(*private_key)
31 .expect("32 bytes, within curve order");
32 let public_key = PublicKey::from_secret_key(&secp, &private_key);
33 public_key.serialize()
34}
35
36pub fn ecdsa_decompress_public_key(
40 compressed_public_key: &[u8; PUBLIC_KEY_SIZE],
41) -> [u8; UNCOMPRESSED_PUBLIC_KEY_SIZE] {
42 let public_key = PublicKey::from_slice(compressed_public_key)
43 .expect("65 bytes, serialized according to the spec");
44 public_key.serialize_uncompressed()
45}
46
47pub fn ecdsa_compress_public_key(
49 uncompressed_public_key: &[u8; UNCOMPRESSED_PUBLIC_KEY_SIZE],
50) -> [u8; PUBLIC_KEY_SIZE] {
51 let public_key = PublicKey::from_slice(uncompressed_public_key.as_ref())
52 .expect("33 bytes, serialized according to the spec");
53 public_key.serialize()
54}
55
56pub fn ecdsa_derive_private_key(key_material: impl AsRef<[u8]>) -> Vec<u8> {
61 hkdf_hmac_sha256(key_material, "signing".as_bytes(), 32)
62}
63
64pub fn schnorr_public_key_from_private_key(
66 private_key: &[u8; ECDSA_PRIVATE_KEY_SIZE],
67) -> [u8; SCHNORR_PUBLIC_KEY_SIZE] {
68 let secp = Secp256k1::new();
69 let kp: Keypair =
70 Keypair::from_seckey_byte_array(&secp, *private_key).unwrap();
71 let (x, _) = kp.x_only_public_key();
72 x.serialize()
73}
74
75#[cfg(test)]
76mod tests {
77 use bc_rand::make_fake_random_number_generator;
78 use hex_literal::hex;
79
80 use crate::{
81 ecdsa_compress_public_key, ecdsa_decompress_public_key,
82 ecdsa_derive_private_key, ecdsa_new_private_key_using,
83 ecdsa_public_key_from_private_key, schnorr_public_key_from_private_key,
84 };
85
86 #[test]
87 fn test_ecdsa_keys() {
88 let mut rng = make_fake_random_number_generator();
89 let private_key = ecdsa_new_private_key_using(&mut rng);
90 assert_eq!(
91 private_key,
92 hex!(
93 "7eb559bbbf6cce2632cf9f194aeb50943de7e1cbad54dcfab27a42759f5e2fed"
94 )
95 );
96 let public_key = ecdsa_public_key_from_private_key(&private_key);
97 assert_eq!(
98 public_key,
99 hex!(
100 "0271b92b6212a79b9215f1d24efb9e6294a1bedc95b6c8cf187cb94771ca02626b"
101 )
102 );
103 let decompressed = ecdsa_decompress_public_key(&public_key);
104 assert_eq!(
105 decompressed,
106 hex!(
107 "0471b92b6212a79b9215f1d24efb9e6294a1bedc95b6c8cf187cb94771ca02626b72325f1f3bb69a44d3f1cb6d1fd488220dd502f49c0b1a46cb91ce3718d8334a"
108 )
109 );
110 let compressed = ecdsa_compress_public_key(&decompressed);
111 assert_eq!(compressed, public_key);
112 let x_only_public_key =
113 schnorr_public_key_from_private_key(&private_key);
114 assert_eq!(
115 x_only_public_key,
116 hex!(
117 "71b92b6212a79b9215f1d24efb9e6294a1bedc95b6c8cf187cb94771ca02626b"
118 )
119 );
120
121 let private_key = ecdsa_derive_private_key(b"password");
122 assert_eq!(
123 private_key,
124 hex!(
125 "05cc550daa75058e613e606d9898fedf029e395911c43273a208b7e0e88e271b"
126 )
127 );
128 }
129}