From d7a8f0cb3e9774fd04d2eece9352a3f69ed23d1d Mon Sep 17 00:00:00 2001 From: Yamaguchi Date: Wed, 5 Jun 2024 14:40:35 +0900 Subject: [PATCH] Add a hash type 'BlockSigHash' for signing blocks --- tapyrus/src/blockdata/block.rs | 70 ++++++++++++++++++++++++++++++---- tapyrus/src/hash_types.rs | 4 +- 2 files changed, 65 insertions(+), 9 deletions(-) diff --git a/tapyrus/src/blockdata/block.rs b/tapyrus/src/blockdata/block.rs index 318930c6..378e586f 100644 --- a/tapyrus/src/blockdata/block.rs +++ b/tapyrus/src/blockdata/block.rs @@ -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}; @@ -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 { + 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!( @@ -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 { - 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 { @@ -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] @@ -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 = 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"); diff --git a/tapyrus/src/hash_types.rs b/tapyrus/src/hash_types.rs index b86dbccf..d2f0a323 100644 --- a/tapyrus/src/hash_types.rs +++ b/tapyrus/src/hash_types.rs @@ -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); @@ -85,7 +87,7 @@ mod newtypes { impl_hashencode!(Txid); impl_hashencode!(Wtxid); impl_hashencode!(BlockHash); - + impl_hashencode!(BlockSigHash); impl_hashencode!(TxMerkleNode); impl_hashencode!(WitnessMerkleNode);