Skip to content

Commit

Permalink
Add a hash type 'BlockSigHash' for signing blocks
Browse files Browse the repository at this point in the history
  • Loading branch information
Yamaguchi committed Jun 11, 2024
1 parent dfa0955 commit d7a8f0c
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 9 deletions.
70 changes: 62 additions & 8 deletions tapyrus/src/blockdata/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ use super::Weight;
use crate::blockdata::script;
use crate::blockdata::transaction::Transaction;
use crate::consensus::encode::serialize_hex;
use crate::consensus::{encode, Decodable, Encodable};
use crate::consensus::{encode, serialize, Decodable, Encodable};
use crate::crypto::key::PublicKey;
use crate::crypto::schnorr::Signature;
pub use crate::hash_types::BlockHash;
use crate::hash_types::{TxMerkleNode, WitnessCommitment, WitnessMerkleNode, Wtxid};
use crate::hash_types::{BlockSigHash, TxMerkleNode, WitnessCommitment, WitnessMerkleNode, Wtxid};
use crate::internal_macros::impl_consensus_encoding;
use crate::prelude::*;
use crate::{crypto, io, merkle_tree, VarInt};
Expand Down Expand Up @@ -68,6 +68,22 @@ impl Header {
self.consensus_encode(&mut engine).expect("engines don't error");
BlockHash::from_engine(engine)
}

/// Return the Aggregate public key in this BlockHeader
pub fn aggregated_public_key(&self) -> Option<PublicKey> {
match self.xfield {
XField::AggregatePublicKey(pk) => Some(pk),
_ => None,
}
}

/// Computes a signature hash for this block.
/// Tapyrus signer needs to sign this hash. The signature will be added to
/// the block header as the proof field and submitted to the tapyrus node.
pub fn signature_hash(&self) -> BlockSigHash {
let block = HeaderWithoutProof::from(self);
BlockSigHash::hash(&serialize(&block))
}
}

impl_consensus_encoding!(
Expand Down Expand Up @@ -178,16 +194,38 @@ impl Decodable for Version {
}
}

impl Header {
/// Return the Aggregate public key in this BlockHeader
pub fn aggregated_public_key(&self) -> Option<PublicKey> {
match self.xfield {
XField::AggregatePublicKey(pk) => Some(pk),
_ => None,
struct HeaderWithoutProof {
version: Version,
prev_blockhash: BlockHash,
merkle_root: TxMerkleNode,
im_merkle_root: TxMerkleNode,
time: u32,
xfield: XField,
}

impl HeaderWithoutProof {
fn from(header: &Header) -> Self {
Self {
version: header.version.clone(),
prev_blockhash: header.prev_blockhash,
merkle_root: header.merkle_root,
im_merkle_root: header.im_merkle_root,
time: header.time,
xfield: header.xfield.clone(),
}
}
}

impl_consensus_encoding!(
HeaderWithoutProof,
version,
prev_blockhash,
merkle_root,
im_merkle_root,
time,
xfield
);

/// An extra field that allows the block header to hold arbitrary data.
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub enum XField {
Expand Down Expand Up @@ -608,6 +646,8 @@ mod tests {

use super::*;
use crate::consensus::encode::{deserialize, serialize};
use crate::crypto::key::PublicKey;
use crate::hash_types::BlockSigHash;

#[test]
#[ignore]
Expand Down Expand Up @@ -756,6 +796,20 @@ mod tests {
assert_eq!(serialize(&real_decode), segwit_block);
}

#[test]
fn signature_hash_test() {
let block = hex!("010000000000000000000000000000000000000000000000000000000000000000000000c1457ff3e5c527e69858108edf0ff1f49eea9c58d8d37300a164b3b4f8c8c7cef1a2e72770d547feae29f2dd40123a97c580d44fd4493de072416d53331997617b96f05d00403a4c09253c7b583e5260074380c9b99b895f938e37799d326ded984fb707e91fa4df2e0524a4ccf5fe224945b4fb94784b411a760eb730d95402d3383dd7ffdc01010000000100000000000000000000000000000000000000000000000000000000000000000000000022210366262690cbdf648132ce0c088962c6361112582364ede120f3780ab73438fc4bffffffff0100f2052a010000002776a9226d70757956774d32596a454d755a4b72687463526b614a787062715447417346484688ac00000000");
let decode: Result<Block, _> = deserialize(&block);
assert!(decode.is_ok());
assert_eq!(
decode.unwrap().header.signature_hash(),
BlockSigHash::from_str(
"3d856f50e0718f72bab6516c1ab020ce3390ebc97490b6d2bad4054dc7a40a93"
)
.unwrap()
);
}

#[test]
fn block_version_test() {
let block = hex!("ffffff7f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
Expand Down
4 changes: 3 additions & 1 deletion tapyrus/src/hash_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ mod newtypes {
pub struct Wtxid(sha256d::Hash);
/// A tapyrus block hash.
pub struct BlockHash(sha256d::Hash);
/// A hash of the block for sigining.
pub struct BlockSigHash(sha256d::Hash);

/// A hash of the Merkle tree branch or root for transactions
pub struct TxMerkleNode(sha256d::Hash);
Expand All @@ -85,7 +87,7 @@ mod newtypes {
impl_hashencode!(Txid);
impl_hashencode!(Wtxid);
impl_hashencode!(BlockHash);

impl_hashencode!(BlockSigHash);
impl_hashencode!(TxMerkleNode);
impl_hashencode!(WitnessMerkleNode);

Expand Down

0 comments on commit d7a8f0c

Please sign in to comment.