Skip to content

Commit 5c22659

Browse files
committed
dynafed: use newtypes for the various merkle roots in dynafed params
There are actually 3 separate Merkle roots at play here, which are all currently typed as sha256::Midstate. Had we designed this a few years later we likely would have domain-separated all of them to prevent them from ever being collided with each other, though given the nature of the data they hash, there should be no risk of that anyway. This change was surprisingly easy. This prevents these roots from being confused with each other or with other midstates. It changes the debug output of one of the merkle roots which for some reason we were unit testing.
1 parent 8153c4a commit 5c22659

4 files changed

Lines changed: 38 additions & 26 deletions

File tree

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/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));

src/hash_types.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,9 @@ impl_hashencode!(TxMerkleNode);
7575
#[cfg(feature = "serde")]
7676
mod serde_tests {
7777
use super::*;
78-
use crate::{AssetEntropy, AssetId, ContractHash};
78+
use crate::{AssetEntropy, AssetId, ContractHash, DynafedRoot};
79+
use crate::dynafed::{ElidedRoot, ParamsRoot};
7980

80-
// Some types are currently just bare midstates. We will replace them with
81-
// newtypes in the following commits. To ensure this does not break serde,
82-
// test them here.
83-
type ElidedRoot = sha256::Midstate;
84-
8581
/// An arbitrary test vector.
8682
///
8783
/// Mainly its goal is to make sure we don't mess up and reverse stuff we don't
@@ -170,5 +166,7 @@ mod serde_tests {
170166
serde_rtt_test32!(serde_rtt_contracthash, ContractHash, REVERSED_JSON);
171167

172168
serde_rtt_test32!(serde_rtt_entropy, AssetEntropy, REVERSED_JSON);
169+
serde_rtt_test32!(serde_rtt_dynaroot, DynafedRoot, REVERSED_JSON);
173170
serde_rtt_test32!(serde_rtt_elidedroot, ElidedRoot, REVERSED_JSON);
171+
serde_rtt_test32!(serde_rtt_paramsroot, ParamsRoot, REVERSED_JSON);
174172
}

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub use crate::blind::{
8181
SurjectionInput, TxOutError, TxOutSecrets, UnblindError, VerificationError, CtLocation, CtLocationType,
8282
};
8383
pub use crate::block::ExtData as BlockExtData;
84-
pub use crate::block::{Block, BlockHeader};
84+
pub use crate::block::{Block, BlockHeader, DynafedRoot};
8585
pub use crate::ext::{ReadExt, WriteExt};
8686
pub use crate::fast_merkle_root::fast_merkle_root;
8787
pub use crate::hash_types::*;

0 commit comments

Comments
 (0)