Use `Sha256`s for tweaks in `sign` to enforce randomness
authorMatt Corallo <git@bluematt.me>
Fri, 19 Apr 2024 00:36:52 +0000 (00:36 +0000)
committerMatt Corallo <git@bluematt.me>
Mon, 22 Apr 2024 13:00:29 +0000 (13:00 +0000)
We assume that tweaks are the output of a SHA-256 hash function
(and thus that failing to create a private key from the has
negligible probability) in `add_public_key_tweak` and elsewhere.

Thus, we really shouldn't be taking byte arrays in the public API
but rather `Sha256` objects, and communicating in the docs for
`add_public_key_tweak` that we can panic if its not the output of
a hash function, both of which we do here.

lightning/src/ln/channel_keys.rs
lightning/src/sign/mod.rs

index 76dc1e42b37d72e7dca1d92c98ff7193cc817693..eaa14f27f3312aa613e449c7d8084183a3cdee4b 100644 (file)
@@ -45,11 +45,11 @@ macro_rules! basepoint_impl {
                        ///
                        /// This calculates the hash part in the tweak derivation process, which is used to
                        /// ensure that each key is unique and cannot be guessed by an external party.
-                       pub fn derive_add_tweak(&self, per_commitment_point: &PublicKey) -> [u8; 32] {
+                       pub fn derive_add_tweak(&self, per_commitment_point: &PublicKey) -> Sha256 {
                                let mut sha = Sha256::engine();
                                sha.input(&per_commitment_point.serialize());
                                sha.input(&self.to_public_key().serialize());
-                               Sha256::from_engine(sha).to_byte_array()
+                               Sha256::from_engine(sha)
                        }
                }
 
@@ -166,18 +166,20 @@ fn derive_public_key<T: secp256k1::Signing>(
        let mut sha = Sha256::engine();
        sha.input(&per_commitment_point.serialize());
        sha.input(&base_point.serialize());
-       let res = Sha256::from_engine(sha).to_byte_array();
+       let res = Sha256::from_engine(sha);
 
        add_public_key_tweak(secp_ctx, base_point, &res)
 }
 
 /// Adds a tweak to a public key to derive a new public key.
+///
+/// May panic if `tweak` is not the output of a SHA-256 hash.
 pub fn add_public_key_tweak<T: secp256k1::Signing>(
-       secp_ctx: &Secp256k1<T>, base_point: &PublicKey, tweak: &[u8; 32],
+       secp_ctx: &Secp256k1<T>, base_point: &PublicKey, tweak: &Sha256,
 ) -> PublicKey {
        let hashkey = PublicKey::from_secret_key(
                &secp_ctx,
-               &SecretKey::from_slice(tweak)
+               &SecretKey::from_slice(tweak.as_byte_array())
                        .expect("Hashes should always be valid keys unless SHA-256 is broken"),
        );
        base_point.combine(&hashkey)
index 43acc67af04b3699ef406a8dc64113908463b357..8148c88e1042758d58e6cd7f2e592be6c99ddee4 100644 (file)
@@ -401,7 +401,7 @@ impl SpendableOutputDescriptor {
                                                                        subtype: 0,
                                                                        key: "add_tweak".as_bytes().to_vec(),
                                                                },
-                                                               add_tweak.to_vec(),
+                                                               add_tweak.as_byte_array().to_vec(),
                                                        )]
                                                        .into_iter()
                                                        .collect()