1use crate::prelude::*;
2use bitcoin::hashes::sha256::Hash as BitcoinSha256;
3use bitcoin::hashes::{sha256d, Hash, HashEngine, Hmac, HmacEngine};
4use bitcoin::key::XOnlyPublicKey;
5use bitcoin::secp256k1::constants::SCHNORR_SIGNATURE_SIZE;
6use bitcoin::secp256k1::{
7 self, ecdsa::Signature, schnorr, Message, PublicKey, Secp256k1, SecretKey,
8};
9use bitcoin::sighash::{EcdsaSighashType, TapSighash};
10use bitcoin::taproot::TapTweakHash;
11use bitcoin::PrivateKey;
12use lightning::ln::channel_keys::{RevocationBasepoint, RevocationKey};
13
14fn hkdf_extract_expand(salt: &[u8], secret: &[u8], info: &[u8], output: &mut [u8]) {
15 let mut hmac = HmacEngine::<BitcoinSha256>::new(salt);
16 hmac.input(secret);
17 let prk = Hmac::from_engine(hmac).to_byte_array();
18
19 let mut t = [0; 32];
20 let mut n: u8 = 0;
21
22 for chunk in output.chunks_mut(32) {
23 let mut hmac = HmacEngine::<BitcoinSha256>::new(&prk[..]);
24 n = n.checked_add(1).expect("HKDF size limit exceeded.");
25 if n != 1 {
26 hmac.input(&t);
27 }
28 hmac.input(&info);
29 hmac.input(&[n]);
30 t = Hmac::from_engine(hmac).to_byte_array();
31 chunk.copy_from_slice(&t);
32 }
33}
34
35pub fn hkdf_sha256(secret: &[u8], info: &[u8], salt: &[u8]) -> [u8; 32] {
37 let mut result = [0u8; 32];
38 hkdf_extract_expand(salt, secret, info, &mut result);
39 result
40}
41
42pub(crate) fn hkdf_sha256_keys(secret: &[u8], info: &[u8], salt: &[u8]) -> [u8; 32 * 6] {
43 let mut result = [0u8; 32 * 6];
44 hkdf_extract_expand(salt, secret, info, &mut result);
45 result
46}
47
48pub(crate) fn derive_public_key<T: secp256k1::Signing>(
49 secp_ctx: &Secp256k1<T>,
50 per_commitment_point: &PublicKey,
51 base_point: &PublicKey,
52) -> Result<PublicKey, secp256k1::Error> {
53 let mut sha = BitcoinSha256::engine();
54 sha.input(&per_commitment_point.serialize());
55 sha.input(&base_point.serialize());
56 let res = BitcoinSha256::from_engine(sha).to_byte_array();
57
58 let hashkey = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&res)?);
59 base_point.combine(&hashkey)
60}
61
62pub fn signature_to_bitcoin_vec(sig: Signature) -> Vec<u8> {
64 let mut sigvec = sig.serialize_der().to_vec();
65 sigvec.push(EcdsaSighashType::All as u8);
66 sigvec
67}
68
69pub fn schnorr_signature_to_bitcoin_vec(sig: schnorr::Signature) -> Vec<u8> {
71 let mut sigvec = Vec::with_capacity(SCHNORR_SIGNATURE_SIZE);
73 sigvec.extend_from_slice(&sig[..]);
74 sigvec
75}
76
77pub fn bitcoin_vec_to_signature(
79 sigvec: &[u8],
80 sighash_type: EcdsaSighashType,
81) -> Result<Signature, secp256k1::Error> {
82 let len = sigvec.len();
83 if len == 0 {
84 return Err(secp256k1::Error::InvalidSignature);
85 }
86 let mut sv = sigvec.to_vec();
87 let mode = sv.pop().ok_or_else(|| secp256k1::Error::InvalidSignature)?;
88 if mode != sighash_type as u8 {
89 return Err(secp256k1::Error::InvalidSignature);
90 }
91 Ok(Signature::from_der(&sv[..])?)
92}
93
94pub fn maybe_generate_seed(seed_opt: Option<[u8; 32]>) -> [u8; 32] {
96 seed_opt.unwrap_or_else(generate_seed)
97}
98
99pub fn generate_seed() -> [u8; 32] {
101 #[cfg(feature = "std")]
102 {
103 use secp256k1::rand::RngCore;
104 let mut seed = [0; 32];
105 let mut rng = secp256k1::rand::rngs::OsRng;
106 rng.fill_bytes(&mut seed);
107 seed
108 }
109 #[cfg(not(feature = "std"))]
110 unimplemented!("no RNG available in no_std environments yet");
111}
112
113pub fn sighash_from_heartbeat(ser_heartbeat: &[u8]) -> Message {
115 let mut sha = BitcoinSha256::engine();
116 sha.input("vls".as_bytes());
117 sha.input("heartbeat".as_bytes());
118 sha.input(ser_heartbeat);
119 let hash = BitcoinSha256::from_engine(sha);
120 Message::from_digest(hash.to_byte_array())
121}
122
123pub(crate) fn ecdsa_sign(
124 secp_ctx: &Secp256k1<secp256k1::All>,
125 privkey: &PrivateKey,
126 sighash: sha256d::Hash,
127) -> Signature {
128 let message = Message::from_digest(sighash.to_byte_array());
129 secp_ctx.sign_ecdsa(&message, &privkey.inner)
130}
131
132pub(crate) fn taproot_sign(
133 secp_ctx: &Secp256k1<secp256k1::All>,
134 privkey: &PrivateKey,
135 sighash: TapSighash,
136 aux_rand: &[u8; 32],
137) -> schnorr::Signature {
138 let message = Message::from(sighash);
139 let keypair = secp256k1::Keypair::from_secret_key(secp_ctx, &privkey.inner);
140 let (internal_key, _parity) = XOnlyPublicKey::from_keypair(&keypair);
141 let tweak = TapTweakHash::from_key_and_tweak(internal_key, None);
142 let tweaked_keypair = keypair.add_xonly_tweak(secp_ctx, &tweak.to_scalar()).unwrap();
143
144 secp_ctx.sign_schnorr_with_aux_rand(&message, &tweaked_keypair, aux_rand)
145}
146
147pub(crate) fn derive_public_revocation_key<T: secp256k1::Verification>(
156 secp_ctx: &Secp256k1<T>,
157 per_commitment_point: &PublicKey,
158 countersignatory_revocation_base_point: &RevocationBasepoint,
159) -> Result<RevocationKey, ()> {
160 let revocation_key = RevocationKey::from_basepoint(
161 secp_ctx,
162 &countersignatory_revocation_base_point,
163 per_commitment_point,
164 );
165 Ok(revocation_key)
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171 use bitcoin::Network;
172
173 #[test]
174 fn hkdf_tests() {
175 let secret = [1u8];
176 let info = [2u8];
177 let salt = [3u8];
178 let mut output = [0u8; 32 * 6];
179 hkdf_extract_expand(&salt, &secret, &info, &mut output);
180 assert_eq!(hex::encode(output), "13a04658302cc5173a8077f2f296662a7a3ddb2359be92770b13e0b9e63a23d0efbbb13e74af4687137801e1628d1d1876d251b31d1321383568a9387da7c0baa7dee83ba374bba3774ef01140e4c4293791a512e536764bf4405aea511be32d5fd71a0b7a7ef3638312e476eb323fbac5f3d549ccf0fe0eabb38fe7bc16ad01db2288e57de45eabecd561ede4dc89164099ed7f0b0db5250e2b377e2aa84f520838612dccbde870f7b06a1e03f3cd79d30da717c55e15442a0b4dd02aafcd86");
181 let mut output = [0u8; 32];
182 hkdf_extract_expand(&salt, &secret, &info, &mut output);
183 assert_eq!(
184 hex::encode(output),
185 "13a04658302cc5173a8077f2f296662a7a3ddb2359be92770b13e0b9e63a23d0"
186 );
187
188 let secret = [1u8];
189 let info = [2u8];
190 let salt = [3u8];
191 let result = hkdf_sha256(&secret, &info, &salt);
192 assert_eq!(
193 hex::encode(result),
194 "13a04658302cc5173a8077f2f296662a7a3ddb2359be92770b13e0b9e63a23d0"
195 );
196
197 let secret = [1u8];
198 let info = [2u8];
199 let salt = [3u8];
200 let result = hkdf_sha256_keys(&secret, &info, &salt);
201 assert_eq!(result.len(), 32 * 6);
202 let expected_prefix = "13a04658302cc5173a8077f2f296662a7a3ddb2359be92770b13e0b9e63a23d0";
203 assert_eq!(hex::encode(&result[..32]), expected_prefix);
204 }
205
206 #[test]
207 fn test_schnorr_signature_to_bitcoin_vec() {
208 let test_signature_bytes: Vec<u8> = vec![0; 64];
209 let test_signature = schnorr::Signature::from_slice(&test_signature_bytes).unwrap();
210 let result = schnorr_signature_to_bitcoin_vec(test_signature);
211 assert_eq!(test_signature_bytes, result);
212 }
213
214 #[test]
215 fn test_bitcoin_vec_to_signature() {
216 let sighash_type = EcdsaSighashType::All;
217 let sigvec: Vec<u8> = vec![];
218 let result = bitcoin_vec_to_signature(&sigvec, sighash_type);
219 assert_eq!(result, Err(secp256k1::Error::InvalidSignature));
220
221 let mut sigvec = hex::decode(
222 "304402202e1f64d831e89e2b4a0dc8565cb2d0a4d6061a89f9b48f2c26d5ac0b3b9a0bb102200c8d396f8b2e9c6c623bebc015c47f1f41e8824fabe7cb028f174a0e5df3c0a0"
223 ).unwrap();
224 sigvec.push(1 as u8);
225 let result = bitcoin_vec_to_signature(&sigvec, sighash_type).unwrap();
226 sigvec.pop();
227 let parsed_signature = Signature::from_der(&sigvec).expect("valid DER signature");
228 assert_eq!(result, parsed_signature);
229 }
230
231 #[test]
232 fn test_maybe_generate_seed() {
233 let known_seed: [u8; 32] = [1; 32];
234 let result = maybe_generate_seed(Some(known_seed));
235 assert_eq!(result, known_seed);
236
237 let result = maybe_generate_seed(None);
238 assert_eq!(result.len(), 32);
239 }
240
241 #[test]
242 fn test_taproot_sign() {
243 let secp = Secp256k1::new();
244 let privkey_bytes =
245 hex::decode("d8d3a3140ba89f14144b0dfe40e04220e02ed68736a5773e050a3c4116b1e31c")
246 .unwrap();
247 let secret_key =
248 SecretKey::from_slice(&privkey_bytes).expect("32 bytes, within curve order");
249 let privkey = PrivateKey::new(secret_key, Network::Bitcoin);
250 let sighash = TapSighash::hash(&[0]);
251 let aux_rand: [u8; 32] = [0u8; 32];
252 let signature = taproot_sign(&secp, &privkey, sighash, &aux_rand);
253 let expected_signature_hex =
254 "14262eb13409cd8928536ab60f431b95193d2d9c7cc476e9f43e8b8f98a8d5a8c38d3edc7bf43c389a12c9e5fad9485ee5d59df2d35f46c3f77ca07197ee1db2";
255 assert_eq!(expected_signature_hex, signature.to_string());
256 }
257
258 #[test]
259 fn test_derive_public_key() {
260 let secp = Secp256k1::new();
261 let per_commitment_secret = SecretKey::from_slice(&[2; 32]).unwrap();
262 let base_secret = SecretKey::from_slice(&[3; 32]).unwrap();
263 let per_commitment_point = PublicKey::from_secret_key(&secp, &per_commitment_secret);
264 let base_point = PublicKey::from_secret_key(&secp, &base_secret);
265
266 let result = derive_public_key(&secp, &per_commitment_point, &base_point).unwrap();
267 let expected = PublicKey::from_slice(
268 &hex::decode("038f363030fd6822d5b3cfaa650fe3c37ed218e3761bbd5e7585779aeb5ac191f3")
269 .unwrap(),
270 )
271 .unwrap();
272 assert_eq!(result, expected);
273 }
274
275 #[test]
276 fn test_signature_to_bitcoin_vec() {
277 let secp = Secp256k1::new();
278 let secret_key = SecretKey::from_slice(&[1; 32]).unwrap();
279 let message = Message::from_digest([2; 32]);
280 let sig = secp.sign_ecdsa(&message, &secret_key);
281 let result = signature_to_bitcoin_vec(sig);
282 let expected = vec![
283 48, 69, 2, 33, 0, 151, 239, 48, 35, 62, 173, 37, 209, 15, 123, 178, 191, 158, 175, 87,
284 26, 22, 242, 222, 179, 58, 117, 242, 8, 25, 40, 79, 12, 184, 255, 60, 193, 2, 32, 72,
285 112, 202, 5, 148, 1, 153, 193, 19, 180, 220, 119, 134, 111, 0, 23, 2, 105, 28, 222, 38,
286 159, 104, 53, 88, 30, 122, 234, 30, 173, 38, 96, 1,
287 ];
288 assert_eq!(result, expected);
289 }
290
291 #[test]
292 fn test_generate_seed() {
293 #[cfg(feature = "std")]
294 {
295 let seed = generate_seed();
296 assert_eq!(seed.len(), 32);
297 assert_ne!(seed, [0; 32]);
298 }
299 #[cfg(not(feature = "std"))]
300 {
301 let result = std::panic::catch_unwind(|| generate_seed());
302 assert!(result.is_err());
303 }
304 }
305
306 #[test]
307 fn test_sighash_from_heartbeat() {
308 let ser_heartbeat = [1, 2, 3];
309 let result = sighash_from_heartbeat(&ser_heartbeat);
310 let expected_hash = BitcoinSha256::hash(
311 &["vls".as_bytes(), "heartbeat".as_bytes(), &ser_heartbeat].concat(),
312 );
313 let expected = Message::from_digest(expected_hash.to_byte_array());
314 assert_eq!(result, expected);
315 }
316
317 #[test]
318 fn test_ecdsa_sign() {
319 let secp = Secp256k1::new();
320 let secret_key = SecretKey::from_slice(&[1; 32]).unwrap();
321 let privkey = PrivateKey::new(secret_key, Network::Bitcoin);
322 let sighash = sha256d::Hash::hash(&[2; 32]);
323 let sig = ecdsa_sign(&secp, &privkey, sighash);
324 let message = Message::from_digest(sighash.to_byte_array());
325 let pubkey = PublicKey::from_secret_key(&secp, &secret_key);
326 secp.verify_ecdsa(&message, &sig, &pubkey).unwrap();
327 }
328
329 #[test]
330 fn test_derive_public_revocation_key() {
331 let secp = Secp256k1::new();
332 let per_commitment_secret = SecretKey::from_slice(&[2; 32]).unwrap();
333 let base_secret = SecretKey::from_slice(&[3; 32]).unwrap();
334 let per_commitment_point = PublicKey::from_secret_key(&secp, &per_commitment_secret);
335 let base_point = RevocationBasepoint::from(PublicKey::from_secret_key(&secp, &base_secret));
336
337 let result =
338 derive_public_revocation_key(&secp, &per_commitment_point, &base_point).unwrap();
339 let expected = RevocationKey::from_basepoint(&secp, &base_point, &per_commitment_point);
340 assert_eq!(result, expected);
341 }
342}