fedimint_wallet_common/
tweakable.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use std::io::Write;

use bitcoin::hashes::{sha256, Hash as BitcoinHash, Hmac, HmacEngine};
use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey, Signing, Verification};

/// An object that can be used as a Ricardian contract to tweak a key
pub trait Contract {
    /// Serialize the contract in a deterministic way to be used as a tweak
    fn encode<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()>;
}

/// A key or object containing keys that may be tweaked for pay-to-contract
/// constructions
pub trait Tweakable {
    /// Tweak the key with a `tweak` contract
    fn tweak<Ctx: Verification + Signing, Ctr: Contract>(
        &self,
        tweak: &Ctr,
        secp: &Secp256k1<Ctx>,
    ) -> Self;
}

impl Tweakable for PublicKey {
    fn tweak<Ctx: Verification + Signing, Ctr: Contract>(
        &self,
        tweak: &Ctr,
        secp: &Secp256k1<Ctx>,
    ) -> Self {
        let mut hasher = HmacEngine::<sha256::Hash>::new(&self.serialize()[..]);
        tweak.encode(&mut hasher).expect("hashing is infallible");
        let tweak = Hmac::from_engine(hasher).to_byte_array();

        self.add_exp_tweak(secp, &Scalar::from_be_bytes(tweak).expect("can't fail"))
            .expect("tweak is always 32 bytes, other failure modes are negligible")
    }
}

impl Tweakable for SecretKey {
    fn tweak<Ctx: Verification + Signing, Ctr: Contract>(
        &self,
        tweak_in: &Ctr,
        secp: &Secp256k1<Ctx>,
    ) -> Self {
        let pub_key = PublicKey::from_secret_key(secp, self);

        let tweak = {
            let mut hasher = HmacEngine::<sha256::Hash>::new(&pub_key.serialize()[..]);
            tweak_in.encode(&mut hasher).expect("hashing is infallible");
            Hmac::from_engine(hasher).to_byte_array()
        };

        self.add_tweak(&Scalar::from_be_bytes(tweak).expect("can't fail"))
            .expect("Tweaking priv key failed") // TODO: why could this happen?
    }
}

impl Contract for PublicKey {
    fn encode<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
        writer.write_all(&self.serialize())
    }
}

impl Contract for Vec<u8> {
    fn encode<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
        writer.write_all(self)
    }
}

impl Contract for [u8; 33] {
    fn encode<W: Write>(&self, writer: &mut W) -> std::io::Result<()> {
        writer.write_all(self)
    }
}