Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ hashbrown = { version = "0.8", optional = true }
anyhow = { version= "1.0", optional = true}
hex = { version= "0.4", optional = true}

rs-x11-hash = "0.1"

[dev-dependencies]
serde_json = "<1.0.45"
serde_test = "1"
Expand Down
9 changes: 4 additions & 5 deletions src/blockdata/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,17 @@ use prelude::*;

use core::fmt;

use util;
use ::{util, BlockHash, VarInt};
use util::Error::{BlockBadTarget, BlockBadProofOfWork};
use util::hash::dash_merkle_root;
use hashes::{Hash, HashEngine};
use hash_types::{Wtxid, BlockHash, TxMerkleNode, WitnessMerkleNode, WitnessCommitment};
use hash_types::{Wtxid, TxMerkleNode, WitnessMerkleNode, WitnessCommitment};
use util::uint::Uint256;
use consensus::encode::Encodable;
use network::constants::Network;
use blockdata::transaction::Transaction;
use blockdata::constants::{max_target, WITNESS_SCALE_FACTOR};
use blockdata::script;
use VarInt;

/// A block header, which contains all the block's information except
/// the actual transactions
Expand Down Expand Up @@ -166,7 +165,7 @@ pub struct Block {
/// The block header
pub header: BlockHeader,
/// List of transactions contained in the block
pub txdata: Vec<Transaction>
pub txdata: Vec<Transaction>,
}

impl_consensus_encoding!(Block, header, txdata);
Expand Down Expand Up @@ -204,7 +203,7 @@ impl Block {

// Commitment is in the last output that starts with magic bytes.
if let Some(pos) = coinbase.output.iter()
.rposition(|o| o.script_pubkey.len () >= 38 && o.script_pubkey[0..6] == MAGIC)
.rposition(|o| o.script_pubkey.len() >= 38 && o.script_pubkey[0..6] == MAGIC)
{
let commitment = WitnessCommitment::from_slice(&coinbase.output[pos].script_pubkey.as_bytes()[6..38]).unwrap();
// Witness reserved value is in coinbase input witness.
Expand Down
5 changes: 2 additions & 3 deletions src/blockdata/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use prelude::*;
use core::default::Default;

use hashes::hex::{self, HexIterator};
use hashes::sha256d;
use blockdata::opcodes;
use blockdata::script;
use blockdata::block::{Block, BlockHeader};
Expand All @@ -36,7 +35,7 @@ use blockdata::transaction::txin::TxIn;
use blockdata::transaction::txout::TxOut;
use blockdata::witness::Witness;
use network::constants::Network;
use Transaction;
use ::{hash_x11, Transaction};
use util::uint::Uint256;

/// The maximum allowable sequence number
Expand Down Expand Up @@ -125,7 +124,7 @@ fn dash_genesis_tx() -> Transaction {
/// Constructs and returns the genesis block
pub fn genesis_block(network: Network) -> Block {
let txdata = vec![dash_genesis_tx()];
let hash: sha256d::Hash = txdata[0].txid().into();
let hash: hash_x11::Hash = txdata[0].txid().into();
let merkle_root = hash.into();
match network {
Network::Dash => {
Expand Down
6 changes: 3 additions & 3 deletions src/blockdata/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use ::{io};
use core::{default::Default};
use core::convert::TryFrom;

use hashes::{Hash, sha256d};
use hashes::{Hash};

use util::{endian};
use blockdata::constants::WITNESS_SCALE_FACTOR;
Expand All @@ -53,7 +53,7 @@ use hash_types::{Sighash, Txid, Wtxid};
use ::{VarInt};
use blockdata::transaction::hash_type::EcdsaSighashType;
use blockdata::transaction::special_transaction::{TransactionPayload, TransactionType};
use InputsHash;
use ::{hash_x11, InputsHash};
#[cfg(feature="bitcoinconsensus")] use OutPoint;

#[cfg(doc)]
Expand Down Expand Up @@ -117,7 +117,7 @@ impl Transaction {
/// Computes a "normalized TXID" which does not include any signatures.
/// This gives a way to identify a transaction that is "the same" as
/// another in the sense of having same inputs and outputs.
pub fn ntxid(&self) -> sha256d::Hash {
pub fn ntxid(&self) -> hash_x11::Hash {
let cloned_tx = Transaction {
version: self.version,
lock_time: self.lock_time,
Expand Down
14 changes: 13 additions & 1 deletion src/consensus/encode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ use blockdata::transaction::{txout::TxOut, Transaction, txin::TxIn, outpoint::Ou
use blockdata::transaction::special_transaction::TransactionType;
#[cfg(feature = "std")]
use network::{message_blockdata::Inventory, address::{Address, AddrV2Message}};
use Script;
use ::{hash_x11, Script};

/// Encoding error
#[derive(Debug)]
Expand Down Expand Up @@ -792,12 +792,24 @@ impl Decodable for sha256d::Hash {
}
}

impl Decodable for hash_x11::Hash {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
Ok(Self::from_inner(<<Self as Hash>::Inner>::consensus_decode(d)?))
}
}

impl Encodable for sha256::Hash {
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, io::Error> {
self.into_inner().consensus_encode(s)
}
}

impl Encodable for hash_x11::Hash {
fn consensus_encode<S: io::Write>(&self, s: S) -> Result<usize, io::Error> {
self.into_inner().consensus_encode(s)
}
}

impl Decodable for sha256::Hash {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, Error> {
Ok(Self::from_inner(<<Self as Hash>::Inner>::consensus_decode(d)?))
Expand Down
21 changes: 11 additions & 10 deletions src/hash_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
//!

use hashes::{Hash, sha256, sha256d, hash160};
use hash_x11;

macro_rules! impl_hashencode {
($hashtype:ident) => {
Expand All @@ -42,28 +43,28 @@ macro_rules! impl_hashencode {
}
}

hash_newtype!(Txid, sha256d::Hash, 32, doc="A dash transaction hash/transaction ID.");
hash_newtype!(Wtxid, sha256d::Hash, 32, doc="A dash witness transaction ID.");
hash_newtype!(BlockHash, sha256d::Hash, 32, doc="A dash block hash.");
hash_newtype!(Txid, hash_x11::Hash, 32, doc="A dash transaction hash/transaction ID.");
hash_newtype!(Wtxid, hash_x11::Hash, 32, doc="A dash witness transaction ID.");
hash_newtype!(BlockHash, hash_x11::Hash, 32, doc="A dash block hash.");
hash_newtype!(Sighash, sha256d::Hash, 32, doc="Hash of the transaction according to the signature algorithm");

hash_newtype!(PubkeyHash, hash160::Hash, 20, doc="A hash of a public key.");
hash_newtype!(ScriptHash, hash160::Hash, 20, doc="A hash of Dash Script bytecode.");
hash_newtype!(WPubkeyHash, hash160::Hash, 20, doc="SegWit version of a public key hash.");
hash_newtype!(WScriptHash, sha256::Hash, 32, doc="SegWit version of a Bitcoin Script bytecode hash.");

hash_newtype!(TxMerkleNode, sha256d::Hash, 32, doc="A hash of the Merkle tree branch or root for transactions");
hash_newtype!(WitnessMerkleNode, sha256d::Hash, 32, doc="A hash corresponding to the Merkle tree root for witness data");
hash_newtype!(TxMerkleNode, hash_x11::Hash, 32, doc="A hash of the Merkle tree branch or root for transactions");
hash_newtype!(WitnessMerkleNode, hash_x11::Hash, 32, doc="A hash corresponding to the Merkle tree root for witness data");
hash_newtype!(WitnessCommitment, sha256d::Hash, 32, doc="A hash corresponding to the witness structure commitment in the coinbase transaction");
hash_newtype!(XpubIdentifier, hash160::Hash, 20, doc="XpubIdentifier as defined in BIP-32.");

hash_newtype!(FilterHash, sha256d::Hash, 32, doc="Filter hash, as defined in BIP-157");
hash_newtype!(FilterHeader, sha256d::Hash, 32, doc="Filter header, as defined in BIP-157");
hash_newtype!(FilterHash, hash_x11::Hash, 32, doc="Filter hash, as defined in BIP-157");
hash_newtype!(FilterHeader, hash_x11::Hash, 32, doc="Filter header, as defined in BIP-157");

hash_newtype!(MerkleRootMasternodeList, sha256d::Hash, 32, doc="The merkle root of the masternode list");
hash_newtype!(MerkleRootQuorums, sha256d::Hash, 32, doc="The merkle root of the quorums");
hash_newtype!(MerkleRootMasternodeList, hash_x11::Hash, 32, doc="The merkle root of the masternode list");
hash_newtype!(MerkleRootQuorums, hash_x11::Hash, 32, doc="The merkle root of the quorums");

hash_newtype!(SpecialTransactionPayloadHash, sha256d::Hash, 32, doc="A special transaction payload hash");
hash_newtype!(SpecialTransactionPayloadHash, hash_x11::Hash, 32, doc="A special transaction payload hash");
hash_newtype!(InputsHash, sha256d::Hash, 32, doc="A hash of all transaction inputs");

hash_newtype!(QuorumHash, sha256d::Hash, 32, doc="A hash used to identify a quorum");
Expand Down
168 changes: 168 additions & 0 deletions src/hash_x11.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// Rust Dash Library
// Originally written in 2014 by
// Andrew Poelstra <apoelstra@wpsoftware.net>
// For Bitcoin
// Updated for Dash in 2022 by
// The Dash Core Developers
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! An implementation of a hash engine to support the X1 hash,
//! which is a wrapper around the rs-x11-hash library.

use core::{str};
use std::io;
use hashes::Error;
use hashes::{Hash as HashTrait, HashEngine as EngineTrait, hex};

hex_fmt_impl!(Display, Hash);
hex_fmt_impl!(LowerHex, Hash);
index_impl!(Hash);
serde_impl!(Hash, 32);
borrow_slice_impl!(Hash);

/// Output of the X11 hash function
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash, Debug)]
#[repr(transparent)]
pub struct Hash(
[u8; 32]
);

impl str::FromStr for Hash {
type Err = hex::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
hex::FromHex::from_hex(s)
}
}

impl HashTrait for Hash {
type Engine = HashEngine;
type Inner = [u8; 32];

fn from_engine(e: Self::Engine) -> Self {
Hash(e.midstate().into_inner())
}

const LEN: usize = 32;

fn from_slice(sl: &[u8]) -> Result<Self, Error> {
if sl.len() != 32 {
Err(Error::InvalidLength(Self::LEN, sl.len()))
} else {
let mut ret = [0; 32];
ret.copy_from_slice(sl);
Ok(Hash(ret))
}
}

fn into_inner(self) -> Self::Inner {
self.0
}

fn as_inner(&self) -> &Self::Inner {
&self.0
}

fn from_inner(inner: Self::Inner) -> Self {
Hash(inner)
}
}

/// A hashing engine of X11 algorithm, which bytes can be serialized into
#[derive(Default, Clone)]
pub struct HashEngine {
buf: Vec<u8>,
length: usize,
}

impl EngineTrait for HashEngine {
type MidState = Midstate;

fn midstate(&self) -> Self::MidState {
let md: Vec<u8> = rs_x11_hash::get_x11_hash(self.buf.as_slice());
let mut h: [u8; 32] = [0; 32];
for n in 0..32 {
let v = md.get(n).unwrap();
h[32-n-1] = *v;
}
Midstate(h)
}

const BLOCK_SIZE: usize = 32;

fn input(&mut self, data: &[u8]) {
self.buf.extend_from_slice(data);
}

fn n_bytes_hashed(&self) -> usize {
self.length
}
}

/// Output of the X11 hash function
#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)]
pub struct Midstate(pub [u8; 32]);

index_impl!(Midstate);
serde_impl!(Midstate, 32);
borrow_slice_impl!(Midstate);

impl str::FromStr for Midstate {
type Err = hex::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
hex::FromHex::from_hex(s)
}
}

impl Midstate {
/// Length of the midstate, in bytes.
const LEN: usize = 32;

/// Construct a new midstate from the inner value.
pub fn from_inner(inner: [u8; 32]) -> Self {
Midstate(inner)
}

/// Copies a byte slice into the [Midstate] object.
pub fn from_slice(sl: &[u8]) -> Result<Midstate, Error> {
if sl.len() != Self::LEN {
Err(Error::InvalidLength(Self::LEN, sl.len()))
} else {
let mut ret = [0; 32];
ret.copy_from_slice(sl);
Ok(Midstate(ret))
}
}

/// Unwraps the [Midstate] and returns the underlying byte array.
pub fn into_inner(self) -> [u8; 32] {
self.0
}
}

impl hex::FromHex for Midstate {
fn from_byte_iter<I>(iter: I) -> Result<Self, hex::Error>
where I: Iterator<Item=Result<u8, hex::Error>> +
ExactSizeIterator +
DoubleEndedIterator,
{
Ok(Midstate::from_inner(hex::FromHex::from_byte_iter(iter.rev())?))
}
}

impl io::Write for HashEngine {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.input(buf);
Ok(buf.len())
}

fn flush(&mut self) -> io::Result<()> { Ok(()) }
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ pub extern crate anyhow;
#[cfg(target_pointer_width = "16")]
compile_error!("rust-bitcoin cannot be used on 16-bit architectures");

pub mod hash_x11;

#[cfg(test)]
#[macro_use]
mod test_macros;
Expand Down
2 changes: 1 addition & 1 deletion src/network/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,7 @@ mod test {
use network::constants::ServiceFlags;
use consensus::encode::{deserialize, deserialize_partial, serialize};
use hashes::hex::FromHex;
use hashes::sha256d::Hash;
use hash_x11::Hash;
use hashes::Hash as HashTrait;
use network::address::{Address, AddrV2, AddrV2Message};
use super::message_network::{Reject, RejectReason, VersionMessage};
Expand Down
Loading