Skip to content

Commit bab8a59

Browse files
committed
Merge #278: Clean up hashes and related types ahead of bitcoin_hashes 1.0
fa3ea85 address: introduce constructors for (W)ScriptHash (Andrew Poelstra) b553acb re-export WPubkeyHash and PubkeyHash rather than defining our own (Andrew Poelstra) 5c22659 dynafed: use newtypes for the various merkle roots in dynafed params (Andrew Poelstra) 8153c4a issuance: also back AssetId by [u8; 32] rather than Midstate (Andrew Poelstra) b985342 issuance: move AssetId boilerplate into macro (Andrew Poelstra) da8942a issuance: use newtype rather than bare sha256::Midstate for asset entropy (Andrew Poelstra) 5f54fef hash_types: add serde regression tests for all 32-byte hashes (Andrew Poelstra) 90183f4 pset: remove a bunch of other ununused error variants (Andrew Poelstra) 7ec80fe pset: remove unused FromSliceError (Andrew Poelstra) da967f8 pset: eliminate a use of Hash::from_slice (Andrew Poelstra) 0c006d7 sighash: strongly type leaf_version field in SighashCache (Andrew Poelstra) dc701a5 taproot: use TapNodeHash for internal hashes in Taptrees (Andrew Poelstra) dbfbaf8 serde: modernize serde imports (Andrew Poelstra) Pull request description: I am going to PR soon to update to bitcoin-hashes 1.0. There are several big changes versus the old version of bitcoin-hashes that we were using: * Hash wrapper types (like `Txid`, `Blockhash`, etc) no longer have general hashing methods like `hash` that let you hash up arbitrary data; the intention of these types is that they only be constructable from byte slices or by hashing the right kind of data * We no longer directly support construction from byte slices; instead you must use arrays. stdlib has a `TryFrom<&[u8; N]> for &[u8]` impl which is just a pointer cast, so you can get the old behavior by using this `TryFrom` * The `sha256::Midstate` type now carries a length with it, so it behaves something like a deconstructed hash engine rather than being a "hash" which is computed from the sha256 compression function; you can no longer effectively wrap a midstate the way you would wrap a sha256 hash, so instead we directly wrap `[u8; 32]`s for the types that did this * Many changes to make the macros more ergonomic, standard trait impls more consistent and complete, etc This PR makes a bunch of prepatory changes to make this transition smaller. In particular, it * eliminate all the bare `sha256::Midstate` uses by introducing newtypes for each midstate (asset entropy, dynafed elided params, etc) * replace slices with arrays in many places throughout the codebase, eliminating a ton of unreachable panic paths * **makes `Address::p2wpkh` and `Address::p2shwpkh` panic if you give them uncompressed keys** rather than producing unspendable addresses; later we will clean this up further by type-separating compressed keys, but for now ISTM that a panic is better than silently creating black-hole addresses * does a whole pile of code cleanups ACKs for top commit: stringhandler: utACK fa3ea85 Tree-SHA512: c051ec3a8578072e612164d39cf07dddbbf50b14a0d9d1ce25f0a57473b9d8d54d897b5f4ecc3ee9687e4f67cb08d4b025a08271a234d7fa5e0060b41fcaa354
2 parents 0cf99a8 + fa3ea85 commit bab8a59

25 files changed

Lines changed: 353 additions & 318 deletions

Cargo.toml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ default = ["json-contract"]
1919

2020
json-contract = ["serde_json"]
2121
"serde" = [
22+
"dep:serde",
2223
"bitcoin/serde",
2324
"bitcoin/serde",
2425
"secp256k1-zkp/serde",
25-
"actual-serde",
2626
]
2727
base64 = ["bitcoin/base64"]
2828

@@ -33,10 +33,7 @@ secp256k1-zkp = { version = "0.11.0", features = ["global-context", "hashes"] }
3333

3434
# Used for ContractHash::from_json_contract.
3535
serde_json = { version = "1.0", optional = true }
36-
37-
actual-serde = { package = "serde", version = "1.0.103", features = [
38-
"derive",
39-
], optional = true }
36+
serde = { version = "1.0.103", features = [ "derive" ], optional = true }
4037
hex = { package = "hex-conservative", version = "1.1.0" }
4138

4239

src/address.rs

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use crate::schnorr::{TapTweak, TweakedPublicKey, UntweakedPublicKey};
3636
use crate::taproot::TapNodeHash;
3737

3838
use crate::{opcodes, script};
39-
use crate::{PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash};
39+
use crate::{PubkeyHash, ScriptHash, WScriptHash};
4040

4141
/// Encoding error
4242
#[derive(Debug, PartialEq)]
@@ -236,13 +236,9 @@ impl Address {
236236
blinder: Option<secp256k1_zkp::PublicKey>,
237237
params: &'static AddressParams,
238238
) -> Address {
239-
let mut hash_engine = PubkeyHash::engine();
240-
pk.write_into(&mut hash_engine)
241-
.expect("engines don't error");
242-
243239
Address {
244240
params,
245-
payload: Payload::PubkeyHash(PubkeyHash::from_engine(hash_engine)),
241+
payload: Payload::PubkeyHash(pk.pubkey_hash()),
246242
blinding_pubkey: blinder,
247243
}
248244
}
@@ -257,50 +253,51 @@ impl Address {
257253
) -> Address {
258254
Address {
259255
params,
260-
payload: Payload::ScriptHash(ScriptHash::hash(&script[..])),
256+
payload: Payload::ScriptHash(ScriptHash::hash_script(script)),
261257
blinding_pubkey: blinder,
262258
}
263259
}
264260

265261
/// Create a witness pay to public key address from a public key
266262
/// This is the native segwit address type for an output redeemable with a single signature
263+
///
264+
/// # Panics
265+
///
266+
/// Panics if the provided public key is not compressed.
267267
pub fn p2wpkh(
268268
pk: &PublicKey,
269269
blinder: Option<secp256k1_zkp::PublicKey>,
270270
params: &'static AddressParams,
271271
) -> Address {
272-
let mut hash_engine = WPubkeyHash::engine();
273-
pk.write_into(&mut hash_engine)
274-
.expect("engines don't error");
275-
276272
Address {
277273
params,
278274
payload: Payload::WitnessProgram {
279275
version: Fe32::Q,
280-
program: WPubkeyHash::from_engine(hash_engine)[..].to_vec(),
276+
program: pk.wpubkey_hash().expect("public key must be compressed").as_byte_array().to_vec(),
281277
},
282278
blinding_pubkey: blinder,
283279
}
284280
}
285281

286282
/// Create a pay to script address that embeds a witness pay to public key
287283
/// This is a segwit address type that looks familiar (as p2sh) to legacy clients
284+
///
285+
/// # Panics
286+
///
287+
/// Panics if the provided public key is not compressed.
288288
pub fn p2shwpkh(
289289
pk: &PublicKey,
290290
blinder: Option<secp256k1_zkp::PublicKey>,
291291
params: &'static AddressParams,
292292
) -> Address {
293-
let mut hash_engine = ScriptHash::engine();
294-
pk.write_into(&mut hash_engine)
295-
.expect("engines don't error");
296-
293+
let pkh = pk.wpubkey_hash().expect("public key must be compressed");
297294
let builder = script::Builder::new()
298295
.push_int(0)
299-
.push_slice(&ScriptHash::from_engine(hash_engine)[..]);
296+
.push_slice(pkh.as_ref());
300297

301298
Address {
302299
params,
303-
payload: Payload::ScriptHash(ScriptHash::hash(builder.into_script().as_bytes())),
300+
payload: Payload::ScriptHash(ScriptHash::hash_script(&builder.into_script())),
304301
blinding_pubkey: blinder,
305302
}
306303
}
@@ -315,7 +312,7 @@ impl Address {
315312
params,
316313
payload: Payload::WitnessProgram {
317314
version: Fe32::Q,
318-
program: WScriptHash::hash(&script[..])[..].to_vec(),
315+
program: WScriptHash::hash_script(script).as_byte_array().to_vec(),
319316
},
320317
blinding_pubkey: blinder,
321318
}

src/blind.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//! # Transactions Blinding
1616
//!
1717
18+
use core::convert::TryFrom;
1819
use std::{self, collections::BTreeMap, fmt};
1920

2021
use secp256k1_zkp::{
@@ -26,7 +27,6 @@ use secp256k1_zkp::{Generator, RangeProof, Secp256k1, Signing, SurjectionProof};
2627

2728
use crate::{AddressParams, Script, TxIn};
2829

29-
use crate::hashes;
3030
use crate::{
3131
confidential::{Asset, AssetBlindingFactor, Nonce, Value, ValueBlindingFactor},
3232
Address, AssetId, Transaction, TxOut, TxOutWitness,
@@ -224,8 +224,7 @@ impl RangeProofMessage {
224224
/// Information about Transaction Input Asset
225225
#[cfg_attr(
226226
feature = "serde",
227-
derive(Serialize, Deserialize),
228-
serde(crate = "actual_serde")
227+
derive(serde::Serialize, serde::Deserialize),
229228
)]
230229
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
231230
pub struct TxOutSecrets {
@@ -763,7 +762,8 @@ impl TxOut {
763762
)?;
764763

765764
let (asset, asset_bf) = opening.message.as_ref().split_at(32);
766-
let asset = AssetId::from_slice(asset)?;
765+
let asset = <[u8; 32]>::try_from(asset).map_err(UnblindError::MalformedAssetId)?;
766+
let asset = AssetId::from_byte_array(asset);
767767
let asset_bf = AssetBlindingFactor::from_slice(&asset_bf[..32])?;
768768

769769
let value = opening.value;
@@ -788,7 +788,7 @@ pub enum UnblindError {
788788
/// Transaction output does not have a rangeproof.
789789
MissingRangeproof,
790790
/// Malformed asset ID.
791-
MalformedAssetId(hashes::FromSliceError),
791+
MalformedAssetId(core::array::TryFromSliceError),
792792
/// Error originated in `secp256k1_zkp`.
793793
Upstream(secp256k1_zkp::Error),
794794
}
@@ -823,12 +823,6 @@ impl From<secp256k1_zkp::Error> for UnblindError {
823823
}
824824
}
825825

826-
impl From<hashes::FromSliceError> for UnblindError {
827-
fn from(from: hashes::FromSliceError) -> Self {
828-
UnblindError::MalformedAssetId(from)
829-
}
830-
}
831-
832826
impl TxIn {
833827
/// Blind issuances for this [`TxIn`]. Asset amount and token amount must be
834828
/// set in [`AssetIssuance`](crate::AssetIssuance) field for this input
@@ -1516,7 +1510,7 @@ mod tests {
15161510

15171511
#[test]
15181512
fn blind_value_proof_test() {
1519-
let id = AssetId::from_slice(&[1u8; 32]).unwrap();
1513+
let id = AssetId::from_byte_array([1u8; 32]);
15201514
let abf = AssetBlindingFactor::new(&mut thread_rng());
15211515
let asset = confidential::Asset::new_confidential(SECP256K1, id, abf);
15221516

@@ -1542,7 +1536,7 @@ mod tests {
15421536

15431537
#[test]
15441538
fn blind_asset_proof_test() {
1545-
let id = AssetId::from_slice(&[1u8; 32]).unwrap();
1539+
let id = AssetId::from_byte_array([1u8; 32]);
15461540
let abf = AssetBlindingFactor::new(&mut thread_rng());
15471541
let asset = confidential::Asset::new_confidential(SECP256K1, id, abf);
15481542

src/block.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,16 @@ use std::io;
2121
#[cfg(feature = "serde")] use std::fmt;
2222

2323
use crate::dynafed;
24-
use crate::hashes::{Hash, sha256};
24+
use crate::hashes::Hash;
2525
use crate::Transaction;
2626
use crate::encode::{self, serialize, Decodable, Encodable, VarInt};
2727
use crate::{BlockHash, Script, TxMerkleNode};
2828

29+
impl_sha256_midstate_wrapper! {
30+
/// The Merkle root of a set of dynafed parameters.
31+
pub struct DynafedRoot([u8; 32]);
32+
}
33+
2934
/// Data related to block signatures
3035
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
3136
pub enum ExtData {
@@ -268,15 +273,15 @@ impl BlockHeader {
268273
}
269274

270275
/// Calculate the root of the dynafed params. Returns [None] when not dynafed.
271-
pub fn calculate_dynafed_params_root(&self) -> Option<sha256::Midstate> {
276+
pub fn calculate_dynafed_params_root(&self) -> Option<crate::DynafedRoot> {
272277
match self.ext {
273278
ExtData::Proof { .. } => None,
274279
ExtData::Dynafed { ref current, ref proposed, .. } => {
275280
let leaves = [
276281
current.calculate_root().to_byte_array(),
277282
proposed.calculate_root().to_byte_array(),
278283
];
279-
Some(crate::fast_merkle_root::fast_merkle_root(&leaves[..]))
284+
Some(DynafedRoot::from_midstate(crate::fast_merkle_root::fast_merkle_root(&leaves[..])))
280285
}
281286
}
282287
}

src/confidential.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,7 +1102,6 @@ impl<'de> Deserialize<'de> for ValueBlindingFactor {
11021102
#[cfg(test)]
11031103
mod tests {
11041104
use super::*;
1105-
use crate::hashes::sha256;
11061105

11071106
#[cfg(feature = "serde")]
11081107
use std::str::FromStr;
@@ -1144,7 +1143,7 @@ mod tests {
11441143

11451144
let assets = [
11461145
Asset::Null,
1147-
Asset::Explicit(AssetId::from_inner(sha256::Midstate::from_byte_array([0; 32]))),
1146+
Asset::Explicit(AssetId::from_byte_array([0; 32])),
11481147
Asset::from_commitment(&[
11491148
0x0a, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
11501149
1, 1, 1, 1, 1, 1,

src/dynafed.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,19 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
2323
use serde::ser::{SerializeSeq, SerializeStruct};
2424

2525
use crate::encode::{self, Encodable, Decodable};
26-
use crate::hashes::{Hash, sha256, sha256d};
26+
use crate::hashes::{Hash, sha256d};
2727
use crate::Script;
2828

29+
impl_sha256_midstate_wrapper! {
30+
/// The Merkle root of a set of dynafed parameters.
31+
pub struct ParamsRoot([u8; 32]);
32+
}
33+
34+
impl_sha256_midstate_wrapper! {
35+
/// A hash of elided dynafed parameter data.
36+
pub struct ElidedRoot([u8; 32]);
37+
}
38+
2939
/// ad-hoc struct to fmt in hex
3040
#[cfg(feature = "serde")]
3141
struct HexBytes<'a>(&'a [u8]);
@@ -109,7 +119,7 @@ impl FullParams {
109119
/// Return the `extra root` of this params.
110120
/// The extra root commits to the consensus parameters unrelated to
111121
/// blocksigning: `fedpeg_program`, `fedpegscript` and `extension_space`.
112-
fn extra_root(&self) -> sha256::Midstate {
122+
fn extra_root(&self) -> ElidedRoot {
113123
fn serialize_hash<E: Encodable>(obj: &E) -> sha256d::Hash {
114124
let mut engine = sha256d::Hash::engine();
115125
obj.consensus_encode(&mut engine).expect("engines don't error");
@@ -121,11 +131,11 @@ impl FullParams {
121131
serialize_hash(&self.fedpegscript).to_byte_array(),
122132
serialize_hash(&self.extension_space).to_byte_array(),
123133
];
124-
crate::fast_merkle_root::fast_merkle_root(&leaves[..])
134+
ElidedRoot::from_midstate(crate::fast_merkle_root::fast_merkle_root(&leaves[..]))
125135
}
126136

127137
/// Calculate the root of this [`FullParams`].
128-
pub fn calculate_root(&self) -> sha256::Midstate {
138+
pub fn calculate_root(&self) -> ParamsRoot {
129139
fn serialize_hash<E: Encodable>(obj: &E) -> sha256d::Hash {
130140
let mut engine = sha256d::Hash::engine();
131141
obj.consensus_encode(&mut engine).expect("engines don't error");
@@ -142,7 +152,7 @@ impl FullParams {
142152
compact_root.to_byte_array(),
143153
self.extra_root().to_byte_array(),
144154
];
145-
crate::fast_merkle_root::fast_merkle_root(&leaves[..])
155+
ParamsRoot::from_midstate(crate::fast_merkle_root::fast_merkle_root(&leaves[..]))
146156
}
147157

148158
/// Turns parameters into compact parameters.
@@ -223,7 +233,7 @@ pub enum Params {
223233
/// Maximum, in bytes, of the size of a blocksigning witness
224234
signblock_witness_limit: u32,
225235
/// Merkle root of extra data
226-
elided_root: sha256::Midstate,
236+
elided_root: ElidedRoot,
227237
},
228238
/// Full dynamic federations parameters
229239
Full(FullParams),
@@ -319,7 +329,7 @@ impl Params {
319329
}
320330

321331
/// Get the `elided_root`. Is [None] for non-[`Params::Compact`] params.
322-
pub fn elided_root(&self) -> Option<&sha256::Midstate> {
332+
pub fn elided_root(&self) -> Option<&ElidedRoot> {
323333
match *self {
324334
Params::Null => None,
325335
Params::Compact { ref elided_root, ..} => Some(elided_root),
@@ -330,24 +340,24 @@ impl Params {
330340
/// Return the `extra root` of this params.
331341
/// The extra root commits to the consensus parameters unrelated to
332342
/// blocksigning: `fedpeg_program`, `fedpegscript` and `extension_space`.
333-
fn extra_root(&self) -> sha256::Midstate {
343+
fn extra_root(&self) -> ElidedRoot {
334344
match *self {
335-
Params::Null => sha256::Midstate::from_byte_array([0u8; 32]),
345+
Params::Null => ElidedRoot::from_byte_array([0u8; 32]),
336346
Params::Compact { ref elided_root, .. } => *elided_root,
337347
Params::Full(ref f) => f.extra_root(),
338348
}
339349
}
340350

341351
/// Calculate the root of this [Params].
342-
pub fn calculate_root(&self) -> sha256::Midstate {
352+
pub fn calculate_root(&self) -> ParamsRoot {
343353
fn serialize_hash<E: Encodable>(obj: &E) -> sha256d::Hash {
344354
let mut engine = sha256d::Hash::engine();
345355
obj.consensus_encode(&mut engine).expect("engines don't error");
346356
sha256d::Hash::from_engine(engine)
347357
}
348358

349359
if self.is_null() {
350-
return sha256::Midstate::from_byte_array([0u8; 32]);
360+
return ParamsRoot::from_byte_array([0u8; 32]);
351361
}
352362

353363
let leaves = [
@@ -360,7 +370,7 @@ impl Params {
360370
compact_root.to_byte_array(),
361371
self.extra_root().to_byte_array(),
362372
];
363-
crate::fast_merkle_root::fast_merkle_root(&leaves[..])
373+
ParamsRoot::from_midstate(crate::fast_merkle_root::fast_merkle_root(&leaves[..]))
364374
}
365375

366376
/// Get the full params when this params are full.
@@ -626,7 +636,7 @@ impl Decodable for Params {
626636
1 => Ok(Params::Compact {
627637
signblockscript: Decodable::consensus_decode(&mut d)?,
628638
signblock_witness_limit: Decodable::consensus_decode(&mut d)?,
629-
elided_root: sha256::Midstate::from_byte_array(Decodable::consensus_decode(&mut d)?),
639+
elided_root: ElidedRoot::from_byte_array(Decodable::consensus_decode(&mut d)?),
630640
}),
631641
2 => Ok(Params::Full(Decodable::consensus_decode(&mut d)?)),
632642
_ => Err(encode::Error::ParseFailed(
@@ -640,7 +650,6 @@ impl Decodable for Params {
640650
mod tests {
641651
use std::fmt::{self, Write};
642652

643-
use crate::hashes::sha256;
644653
use crate::{BlockHash, TxMerkleNode};
645654

646655
use super::*;
@@ -683,7 +692,7 @@ mod tests {
683692
let compact_entry = Params::Compact {
684693
signblockscript: signblockscript.clone(),
685694
signblock_witness_limit: signblock_wl,
686-
elided_root: sha256::Midstate::from_byte_array([0; 32]),
695+
elided_root: ElidedRoot::from_byte_array([0; 32]),
687696
};
688697
assert_eq!(
689698
format!("{:x}", compact_entry.calculate_root()),
@@ -751,7 +760,7 @@ mod tests {
751760
let compact = params.into_compact().unwrap();
752761
assert_eq!(
753762
to_debug_string(&compact),
754-
"Compact { signblockscript: 0102, signblock_witness_limit: 3, elided_root: 0xc3058c822b22a13bb7c47cf50d3f3c7817e7d9075ff55a7d16c85b9673e7e553 }",
763+
"Compact { signblockscript: 0102, signblock_witness_limit: 3, elided_root: c3058c822b22a13bb7c47cf50d3f3c7817e7d9075ff55a7d16c85b9673e7e553 }",
755764
);
756765
assert_eq!(compact.calculate_root(), full.calculate_root());
757766
assert_eq!(compact.elided_root(), Some(&extra_root));

0 commit comments

Comments
 (0)