fedimint_wallet_common/
tweakable.rs

1use std::io::Write;
2
3use bitcoin::hashes::{Hash as BitcoinHash, Hmac, HmacEngine, sha256};
4use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey, Signing, Verification};
5
6/// An object that can be used as a Ricardian contract to tweak a key
7pub trait Contract {
8    /// Serialize the contract in a deterministic way to be used as a tweak
9    fn encode<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()>;
10}
11
12/// A key or object containing keys that may be tweaked for pay-to-contract
13/// constructions
14pub trait Tweakable {
15    /// Tweak the key with a `tweak` contract
16    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") // TODO: why could this happen?
54    }
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}