1use bc_rand::RandomNumberGenerator;
2use secp256k1::{Secp256k1, SecretKey, PublicKey, Keypair, constants::{PUBLIC_KEY_SIZE, SECRET_KEY_SIZE, UNCOMPRESSED_PUBLIC_KEY_SIZE}};
3
4pub const ECDSA_PRIVATE_KEY_SIZE: usize = 32;
5pub const ECDSA_PUBLIC_KEY_SIZE: usize = 33;
6pub const ECDSA_UNCOMPRESSED_PUBLIC_KEY_SIZE: usize = 65;
7pub const ECDSA_MESSAGE_HASH_SIZE: usize = 32;
8pub const ECDSA_SIGNATURE_SIZE : usize = 64;
9pub const SCHNORR_PUBLIC_KEY_SIZE: usize = 32;
10
11use crate::hash::hkdf_hmac_sha256;
12
13pub fn ecdsa_new_private_key_using(rng: &mut impl RandomNumberGenerator) -> [u8; SECRET_KEY_SIZE] {
15 rng.random_data(ECDSA_PRIVATE_KEY_SIZE).try_into().unwrap()
16}
17
18pub fn ecdsa_public_key_from_private_key(private_key: &[u8; ECDSA_PRIVATE_KEY_SIZE]) -> [u8; PUBLIC_KEY_SIZE] {
20 let secp = Secp256k1::new();
21 let private_key = SecretKey::from_slice(private_key)
22 .expect("32 bytes, within curve order");
23 let public_key = PublicKey::from_secret_key(&secp, &private_key);
24 public_key.serialize()
25}
26
27pub fn ecdsa_decompress_public_key(compressed_public_key: &[u8; PUBLIC_KEY_SIZE]) -> [u8; UNCOMPRESSED_PUBLIC_KEY_SIZE] {
31 let public_key = PublicKey::from_slice(compressed_public_key)
32 .expect("65 bytes, serialized according to the spec");
33 public_key.serialize_uncompressed()
34}
35
36pub fn ecdsa_compress_public_key(uncompressed_public_key: &[u8; UNCOMPRESSED_PUBLIC_KEY_SIZE]) -> [u8; PUBLIC_KEY_SIZE] {
38 let public_key = PublicKey::from_slice(uncompressed_public_key.as_ref())
39 .expect("33 bytes, serialized according to the spec");
40 public_key.serialize()
41}
42
43pub fn ecdsa_derive_private_key(key_material: impl AsRef<[u8]>) -> Vec<u8> {
47 hkdf_hmac_sha256(key_material, "signing".as_bytes(), 32)
48}
49
50pub fn schnorr_public_key_from_private_key(private_key: &[u8; ECDSA_PRIVATE_KEY_SIZE]) -> [u8; SCHNORR_PUBLIC_KEY_SIZE] {
52 let secp = Secp256k1::new();
53 let kp: Keypair = Keypair::from_seckey_slice(&secp, private_key).unwrap();
54 let (x, _) = kp.x_only_public_key();
55 x.serialize()
56}
57
58#[cfg(test)]
59mod tests {
60 use crate::{ecdsa_public_key_from_private_key, ecdsa_new_private_key_using, ecdsa_decompress_public_key, ecdsa_compress_public_key, schnorr_public_key_from_private_key, ecdsa_derive_private_key};
61 use bc_rand::make_fake_random_number_generator;
62 use hex_literal::hex;
63
64 #[test]
65 fn test_ecdsa_keys() {
66 let mut rng = make_fake_random_number_generator();
67 let private_key = ecdsa_new_private_key_using(&mut rng);
68 assert_eq!(private_key, hex!("7eb559bbbf6cce2632cf9f194aeb50943de7e1cbad54dcfab27a42759f5e2fed"));
69 let public_key = ecdsa_public_key_from_private_key(&private_key);
70 assert_eq!(public_key, hex!("0271b92b6212a79b9215f1d24efb9e6294a1bedc95b6c8cf187cb94771ca02626b"));
71 let decompressed = ecdsa_decompress_public_key(&public_key);
72 assert_eq!(decompressed, hex!("0471b92b6212a79b9215f1d24efb9e6294a1bedc95b6c8cf187cb94771ca02626b72325f1f3bb69a44d3f1cb6d1fd488220dd502f49c0b1a46cb91ce3718d8334a"));
73 let compressed = ecdsa_compress_public_key(&decompressed);
74 assert_eq!(compressed, public_key);
75 let x_only_public_key = schnorr_public_key_from_private_key(&private_key);
76 assert_eq!(x_only_public_key, hex!("71b92b6212a79b9215f1d24efb9e6294a1bedc95b6c8cf187cb94771ca02626b"));
77
78 let private_key = ecdsa_derive_private_key(b"password");
79 assert_eq!(private_key, hex!("05cc550daa75058e613e606d9898fedf029e395911c43273a208b7e0e88e271b"));
80 }
81}