fedimint_wallet_common/
tweakable.rs1use std::io::Write;
2
3use bitcoin::hashes::{Hash as BitcoinHash, Hmac, HmacEngine, sha256};
4use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey, Signing, Verification};
5
6pub trait Contract {
8 fn encode<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()>;
10}
11
12pub trait Tweakable {
15 fn tweak<Ctx: Verification + Signing, Ctr: Contract>(
17 &self,
18 tweak: &Ctr,
19 secp: &Secp256k1<Ctx>,
20 ) -> Self;
21}
22
23impl Tweakable for PublicKey {
24 fn tweak<Ctx: Verification + Signing, Ctr: Contract>(
25 &self,
26 tweak: &Ctr,
27 secp: &Secp256k1<Ctx>,
28 ) -> Self {
29 let mut hasher = HmacEngine::<sha256::Hash>::new(&self.serialize()[..]);
30 tweak.encode(&mut hasher).expect("hashing is infallible");
31 let tweak = Hmac::from_engine(hasher).to_byte_array();
32
33 self.add_exp_tweak(secp, &Scalar::from_be_bytes(tweak).expect("can't fail"))
34 .expect("tweak is always 32 bytes, other failure modes are negligible")
35 }
36}
37
38impl Tweakable for SecretKey {
39 fn tweak<Ctx: Verification + Signing, Ctr: Contract>(
40 &self,
41 tweak_in: &Ctr,
42 secp: &Secp256k1<Ctx>,
43 ) -> Self {
44 let pub_key = PublicKey::from_secret_key(secp, self);
45
46 let tweak = {
47 let mut hasher = HmacEngine::<sha256::Hash>::new(&pub_key.serialize()[..]);
48 tweak_in.encode(&mut hasher).expect("hashing is infallible");
49 Hmac::from_engine(hasher).to_byte_array()
50 };
51
52 self.add_tweak(&Scalar::from_be_bytes(tweak).expect("can't fail"))
53 .expect("Tweaking priv key failed") }
55}
56
57impl Contract for PublicKey {
58 fn encode<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
59 writer.write_all(&self.serialize())
60 }
61}
62
63impl Contract for Vec<u8> {
64 fn encode<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
65 writer.write_all(self)
66 }
67}
68
69impl Contract for [u8; 33] {
70 fn encode<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
71 writer.write_all(self)
72 }
73}