Merge rust-bitcoin/rust-bitcoin#1434: Format the `rust-bitcoin` crate
913575ac91
hashes: Run the formatter (Tobin C. Harding)52c4579057
Enable formatting for hashes (Tobin C. Harding)3f16b6bf9f
util: Run the formatter (Tobin C. Harding)d210d2ac83
Enable formatting for util (Tobin C. Harding)5973dce9db
blockdata: Run the formatter (Tobin C. Harding)0dcbed3c7b
Enable formatting for blockdata (Tobin C. Harding)a52746d01c
psbt: Run the formatter (Tobin C. Harding)ef306db5e2
Enable formatting for psbt (Tobin C. Harding)296f2ed82c
Make test panic instead of using code comment (Tobin C. Harding)3ec8a12428
crypto: Run the formatter (Tobin C. Harding)c8a3c58786
Enable formatting for crypto (Tobin C. Harding)314e6786b4
crypto: Add rustfmt::skip attributes (Tobin C. Harding)450a84f6e8
consensus: Run the formatter (Tobin C. Harding)89143205f9
Enable formatting for consensus (Tobin C. Harding)ce773af20f
tests: Remove useless use of super imports (Tobin C. Harding)ef01f4d0f6
consensus: Introduce local variables (Tobin C. Harding) Pull request description: One final push crew, 16 patches, only a few are big. All non-trivial formatting is done in separate patches so the changes can be verified mechanically. With this applied the whole `rust-bitcoin` crate will be formatted. Big thanks to everyone for putting up with the ongoing formatting PRs, no-one likes doing these but hopefully this an improvement to the project - especially in helping us get more contributors to the project. ACKs for top commit: tcharding: > ACK [913575a
](913575ac91
). Went through the workflow locally. sanket1729: ACK913575ac91
. Went through the workflow locally. apoelstra: ACK913575ac91
Tree-SHA512: b30eaa2893563155de05f8fa97be4a24a7dd8bf43bb426314c5104598477ca2173af279da796da8b18cc53a0ed525908b3d4edd0504836a443465efa0773632d
This commit is contained in:
commit
24af58c5ad
|
@ -9,24 +9,20 @@
|
||||||
//! these blocks and the blockchain.
|
//! these blocks and the blockchain.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use crate::merkle_tree;
|
|
||||||
use crate::error::Error::{self, BlockBadTarget, BlockBadProofOfWork};
|
|
||||||
use crate::hashes::{Hash, HashEngine};
|
|
||||||
use crate::hash_types::{Wtxid, TxMerkleNode, WitnessMerkleNode, WitnessCommitment};
|
|
||||||
use crate::consensus::{encode, Encodable, Decodable};
|
|
||||||
use crate::blockdata::transaction::Transaction;
|
|
||||||
use crate::blockdata::script;
|
|
||||||
use crate::pow::{CompactTarget, Target, Work};
|
|
||||||
use crate::VarInt;
|
|
||||||
use crate::internal_macros::impl_consensus_encoding;
|
|
||||||
use crate::io;
|
|
||||||
use super::Weight;
|
use super::Weight;
|
||||||
|
use crate::blockdata::script;
|
||||||
|
use crate::blockdata::transaction::Transaction;
|
||||||
|
use crate::consensus::{encode, Decodable, Encodable};
|
||||||
|
use crate::error::Error::{self, BlockBadProofOfWork, BlockBadTarget};
|
||||||
pub use crate::hash_types::BlockHash;
|
pub use crate::hash_types::BlockHash;
|
||||||
|
use crate::hash_types::{TxMerkleNode, WitnessCommitment, WitnessMerkleNode, Wtxid};
|
||||||
|
use crate::hashes::{Hash, HashEngine};
|
||||||
|
use crate::internal_macros::impl_consensus_encoding;
|
||||||
|
use crate::pow::{CompactTarget, Target, Work};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::{io, merkle_tree, VarInt};
|
||||||
|
|
||||||
/// Bitcoin block header.
|
/// Bitcoin block header.
|
||||||
///
|
///
|
||||||
|
@ -67,14 +63,10 @@ impl Header {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the target (range [0, T] inclusive) that a blockhash must land in to be valid.
|
/// Computes the target (range [0, T] inclusive) that a blockhash must land in to be valid.
|
||||||
pub fn target(&self) -> Target {
|
pub fn target(&self) -> Target { self.bits.into() }
|
||||||
self.bits.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the popular "difficulty" measure for mining.
|
/// Computes the popular "difficulty" measure for mining.
|
||||||
pub fn difficulty(&self) -> u128 {
|
pub fn difficulty(&self) -> u128 { self.target().difficulty() }
|
||||||
self.target().difficulty()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the popular "difficulty" measure for mining and returns a float value of f64.
|
/// Computes the popular "difficulty" measure for mining and returns a float value of f64.
|
||||||
pub fn difficulty_float(&self) -> f64 {
|
pub fn difficulty_float(&self) -> f64 {
|
||||||
|
@ -96,9 +88,7 @@ impl Header {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the total work of the block.
|
/// Returns the total work of the block.
|
||||||
pub fn work(&self) -> Work {
|
pub fn work(&self) -> Work { self.target().to_work() }
|
||||||
self.target().to_work()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bitcoin block version number.
|
/// Bitcoin block version number.
|
||||||
|
@ -140,16 +130,12 @@ impl Version {
|
||||||
/// Creates a [`Version`] from a signed 32 bit integer value.
|
/// Creates a [`Version`] from a signed 32 bit integer value.
|
||||||
///
|
///
|
||||||
/// This is the data type used in consensus code in Bitcoin Core.
|
/// This is the data type used in consensus code in Bitcoin Core.
|
||||||
pub fn from_consensus(v: i32) -> Self {
|
pub fn from_consensus(v: i32) -> Self { Version(v) }
|
||||||
Version(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the inner `i32` value.
|
/// Returns the inner `i32` value.
|
||||||
///
|
///
|
||||||
/// This is the data type used in consensus code in Bitcoin Core.
|
/// This is the data type used in consensus code in Bitcoin Core.
|
||||||
pub fn to_consensus(self) -> i32 {
|
pub fn to_consensus(self) -> i32 { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks whether the version number is signalling a soft fork at the given bit.
|
/// Checks whether the version number is signalling a soft fork at the given bit.
|
||||||
///
|
///
|
||||||
|
@ -172,9 +158,7 @@ impl Version {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Version {
|
impl Default for Version {
|
||||||
fn default() -> Version {
|
fn default() -> Version { Self::NO_SOFT_FORK_SIGNALLING }
|
||||||
Self::NO_SOFT_FORK_SIGNALLING
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Encodable for Version {
|
impl Encodable for Version {
|
||||||
|
@ -207,16 +191,14 @@ pub struct Block {
|
||||||
/// The block header
|
/// The block header
|
||||||
pub header: Header,
|
pub header: Header,
|
||||||
/// List of transactions contained in the block
|
/// List of transactions contained in the block
|
||||||
pub txdata: Vec<Transaction>
|
pub txdata: Vec<Transaction>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_consensus_encoding!(Block, header, txdata);
|
impl_consensus_encoding!(Block, header, txdata);
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
/// Returns the block hash.
|
/// Returns the block hash.
|
||||||
pub fn block_hash(&self) -> BlockHash {
|
pub fn block_hash(&self) -> BlockHash { self.header.block_hash() }
|
||||||
self.header.block_hash()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checks if merkle root of header matches merkle root of the transaction list.
|
/// Checks if merkle root of header matches merkle root of the transaction list.
|
||||||
pub fn check_merkle_root(&self) -> bool {
|
pub fn check_merkle_root(&self) -> bool {
|
||||||
|
@ -244,15 +226,21 @@ impl Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commitment is in the last output that starts with magic bytes.
|
// Commitment is in the last output that starts with magic bytes.
|
||||||
if let Some(pos) = coinbase.output.iter()
|
if let Some(pos) = coinbase
|
||||||
.rposition(|o| o.script_pubkey.len () >= 38 && o.script_pubkey.as_bytes()[0..6] == MAGIC)
|
.output
|
||||||
|
.iter()
|
||||||
|
.rposition(|o| o.script_pubkey.len() >= 38 && o.script_pubkey.as_bytes()[0..6] == MAGIC)
|
||||||
{
|
{
|
||||||
let commitment = WitnessCommitment::from_slice(&coinbase.output[pos].script_pubkey.as_bytes()[6..38]).unwrap();
|
let commitment = WitnessCommitment::from_slice(
|
||||||
|
&coinbase.output[pos].script_pubkey.as_bytes()[6..38],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
// Witness reserved value is in coinbase input witness.
|
// Witness reserved value is in coinbase input witness.
|
||||||
let witness_vec: Vec<_> = coinbase.input[0].witness.iter().collect();
|
let witness_vec: Vec<_> = coinbase.input[0].witness.iter().collect();
|
||||||
if witness_vec.len() == 1 && witness_vec[0].len() == 32 {
|
if witness_vec.len() == 1 && witness_vec[0].len() == 32 {
|
||||||
if let Some(witness_root) = self.witness_root() {
|
if let Some(witness_root) = self.witness_root() {
|
||||||
return commitment == Self::compute_witness_commitment(&witness_root, witness_vec[0]);
|
return commitment
|
||||||
|
== Self::compute_witness_commitment(&witness_root, witness_vec[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,7 +255,10 @@ impl Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the witness commitment for the block's transaction list.
|
/// Computes the witness commitment for the block's transaction list.
|
||||||
pub fn compute_witness_commitment(witness_root: &WitnessMerkleNode, witness_reserved_value: &[u8]) -> WitnessCommitment {
|
pub fn compute_witness_commitment(
|
||||||
|
witness_root: &WitnessMerkleNode,
|
||||||
|
witness_reserved_value: &[u8],
|
||||||
|
) -> WitnessCommitment {
|
||||||
let mut encoder = WitnessCommitment::engine();
|
let mut encoder = WitnessCommitment::engine();
|
||||||
witness_root.consensus_encode(&mut encoder).expect("engines don't error");
|
witness_root.consensus_encode(&mut encoder).expect("engines don't error");
|
||||||
encoder.input(witness_reserved_value);
|
encoder.input(witness_reserved_value);
|
||||||
|
@ -288,9 +279,7 @@ impl Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// base_size == size of header + size of encoded transaction count.
|
/// base_size == size of header + size of encoded transaction count.
|
||||||
fn base_size(&self) -> usize {
|
fn base_size(&self) -> usize { 80 + VarInt(self.txdata.len() as u64).len() }
|
||||||
80 + VarInt(self.txdata.len() as u64).len()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the size of the block.
|
/// Returns the size of the block.
|
||||||
///
|
///
|
||||||
|
@ -314,9 +303,7 @@ impl Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the coinbase transaction, if one is present.
|
/// Returns the coinbase transaction, if one is present.
|
||||||
pub fn coinbase(&self) -> Option<&Transaction> {
|
pub fn coinbase(&self) -> Option<&Transaction> { self.txdata.first() }
|
||||||
self.txdata.first()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the block height, as encoded in the coinbase transaction according to BIP34.
|
/// Returns the block height, as encoded in the coinbase transaction according to BIP34.
|
||||||
pub fn bip34_block_height(&self) -> Result<u64, Bip34Error> {
|
pub fn bip34_block_height(&self) -> Result<u64, Bip34Error> {
|
||||||
|
@ -339,7 +326,8 @@ impl Block {
|
||||||
match push.map_err(|_| Bip34Error::NotPresent)? {
|
match push.map_err(|_| Bip34Error::NotPresent)? {
|
||||||
script::Instruction::PushBytes(b) => {
|
script::Instruction::PushBytes(b) => {
|
||||||
// Check that the number is encoded in the minimal way.
|
// Check that the number is encoded in the minimal way.
|
||||||
let h = script::read_scriptint(b.as_bytes()).map_err(|_e| Bip34Error::UnexpectedPush(b.as_bytes().to_vec()))?;
|
let h = script::read_scriptint(b.as_bytes())
|
||||||
|
.map_err(|_e| Bip34Error::UnexpectedPush(b.as_bytes().to_vec()))?;
|
||||||
if h < 0 {
|
if h < 0 {
|
||||||
Err(Bip34Error::NegativeHeight)
|
Err(Bip34Error::NegativeHeight)
|
||||||
} else {
|
} else {
|
||||||
|
@ -385,44 +373,32 @@ impl std::error::Error for Bip34Error {
|
||||||
use self::Bip34Error::*;
|
use self::Bip34Error::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Unsupported |
|
Unsupported | NotPresent | UnexpectedPush(_) | NegativeHeight => None,
|
||||||
NotPresent |
|
|
||||||
UnexpectedPush(_) |
|
|
||||||
NegativeHeight => None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Header> for BlockHash {
|
impl From<Header> for BlockHash {
|
||||||
fn from(header: Header) -> BlockHash {
|
fn from(header: Header) -> BlockHash { header.block_hash() }
|
||||||
header.block_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Header> for BlockHash {
|
impl From<&Header> for BlockHash {
|
||||||
fn from(header: &Header) -> BlockHash {
|
fn from(header: &Header) -> BlockHash { header.block_hash() }
|
||||||
header.block_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Block> for BlockHash {
|
impl From<Block> for BlockHash {
|
||||||
fn from(block: Block) -> BlockHash {
|
fn from(block: Block) -> BlockHash { block.block_hash() }
|
||||||
block.block_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Block> for BlockHash {
|
impl From<&Block> for BlockHash {
|
||||||
fn from(block: &Block) -> BlockHash {
|
fn from(block: &Block) -> BlockHash { block.block_hash() }
|
||||||
block.block_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::hashes::hex::FromHex;
|
|
||||||
use crate::consensus::encode::{deserialize, serialize};
|
use crate::consensus::encode::{deserialize, serialize};
|
||||||
|
use crate::hashes::hex::FromHex;
|
||||||
use crate::internal_macros::hex;
|
use crate::internal_macros::hex;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -436,7 +412,6 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(block.bip34_block_height(), Ok(100_000));
|
assert_eq!(block.bip34_block_height(), Ok(100_000));
|
||||||
|
|
||||||
|
|
||||||
// block with 9-byte bip34 push
|
// block with 9-byte bip34 push
|
||||||
const BAD_HEX: &str = "0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc56490000000038ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc055227f1001c29c1ea3b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3d09a08601112233445566000427f1001c046a510100522cfabe6d6d0000000000000000000068692066726f6d20706f6f6c7365727665726aac1eeeed88ffffffff0100f2052a010000001976a914912e2b234f941f30b18afbb4fa46171214bf66c888ac00000000";
|
const BAD_HEX: &str = "0200000035ab154183570282ce9afc0b494c9fc6a3cfea05aa8c1add2ecc56490000000038ba3d78e4500a5a7570dbe61960398add4410d278b21cd9708e6d9743f374d544fc055227f1001c29c1ea3b0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff3d09a08601112233445566000427f1001c046a510100522cfabe6d6d0000000000000000000068692066726f6d20706f6f6c7365727665726aac1eeeed88ffffffff0100f2052a010000001976a914912e2b234f941f30b18afbb4fa46171214bf66c888ac00000000";
|
||||||
let bad: Block = deserialize(&hex!(BAD_HEX)).unwrap();
|
let bad: Block = deserialize(&hex!(BAD_HEX)).unwrap();
|
||||||
|
@ -469,14 +444,20 @@ mod tests {
|
||||||
assert_eq!(real_decode.header.bits, CompactTarget::from_consensus(486604799));
|
assert_eq!(real_decode.header.bits, CompactTarget::from_consensus(486604799));
|
||||||
assert_eq!(real_decode.header.nonce, 2067413810);
|
assert_eq!(real_decode.header.nonce, 2067413810);
|
||||||
assert_eq!(real_decode.header.work(), work);
|
assert_eq!(real_decode.header.work(), work);
|
||||||
assert_eq!(real_decode.header.validate_pow(real_decode.header.target()).unwrap(), real_decode.block_hash());
|
assert_eq!(
|
||||||
|
real_decode.header.validate_pow(real_decode.header.target()).unwrap(),
|
||||||
|
real_decode.block_hash()
|
||||||
|
);
|
||||||
assert_eq!(real_decode.header.difficulty(), 1);
|
assert_eq!(real_decode.header.difficulty(), 1);
|
||||||
assert_eq!(real_decode.header.difficulty_float(), 1.0);
|
assert_eq!(real_decode.header.difficulty_float(), 1.0);
|
||||||
// [test] TODO: check the transaction data
|
// [test] TODO: check the transaction data
|
||||||
|
|
||||||
assert_eq!(real_decode.size(), some_block.len());
|
assert_eq!(real_decode.size(), some_block.len());
|
||||||
assert_eq!(real_decode.strippedsize(), some_block.len());
|
assert_eq!(real_decode.strippedsize(), some_block.len());
|
||||||
assert_eq!(real_decode.weight(), Weight::from_non_witness_data_size(some_block.len() as u64));
|
assert_eq!(
|
||||||
|
real_decode.weight(),
|
||||||
|
Weight::from_non_witness_data_size(some_block.len() as u64)
|
||||||
|
);
|
||||||
|
|
||||||
// should be also ok for a non-witness block as commitment is optional in that case
|
// should be also ok for a non-witness block as commitment is optional in that case
|
||||||
assert!(real_decode.check_witness_commitment());
|
assert!(real_decode.check_witness_commitment());
|
||||||
|
@ -505,7 +486,10 @@ mod tests {
|
||||||
assert_eq!(real_decode.header.bits, CompactTarget::from_consensus(0x1a06d450));
|
assert_eq!(real_decode.header.bits, CompactTarget::from_consensus(0x1a06d450));
|
||||||
assert_eq!(real_decode.header.nonce, 1879759182);
|
assert_eq!(real_decode.header.nonce, 1879759182);
|
||||||
assert_eq!(real_decode.header.work(), work);
|
assert_eq!(real_decode.header.work(), work);
|
||||||
assert_eq!(real_decode.header.validate_pow(real_decode.header.target()).unwrap(), real_decode.block_hash());
|
assert_eq!(
|
||||||
|
real_decode.header.validate_pow(real_decode.header.target()).unwrap(),
|
||||||
|
real_decode.block_hash()
|
||||||
|
);
|
||||||
assert_eq!(real_decode.header.difficulty(), 2456598);
|
assert_eq!(real_decode.header.difficulty(), 2456598);
|
||||||
assert_eq!(real_decode.header.difficulty_float(), 2456598.4399242126);
|
assert_eq!(real_decode.header.difficulty_float(), 2456598.4399242126);
|
||||||
// [test] TODO: check the transaction data
|
// [test] TODO: check the transaction data
|
||||||
|
@ -537,8 +521,12 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn validate_pow_test() {
|
fn validate_pow_test() {
|
||||||
let some_header = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b");
|
let some_header = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b");
|
||||||
let some_header: Header = deserialize(&some_header).expect("Can't deserialize correct block header");
|
let some_header: Header =
|
||||||
assert_eq!(some_header.validate_pow(some_header.target()).unwrap(), some_header.block_hash());
|
deserialize(&some_header).expect("Can't deserialize correct block header");
|
||||||
|
assert_eq!(
|
||||||
|
some_header.validate_pow(some_header.target()).unwrap(),
|
||||||
|
some_header.block_hash()
|
||||||
|
);
|
||||||
|
|
||||||
// test with zero target
|
// test with zero target
|
||||||
match some_header.validate_pow(Target::ZERO) {
|
match some_header.validate_pow(Target::ZERO) {
|
||||||
|
@ -559,7 +547,8 @@ mod tests {
|
||||||
fn compact_roundrtip_test() {
|
fn compact_roundrtip_test() {
|
||||||
let some_header = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b");
|
let some_header = hex!("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b");
|
||||||
|
|
||||||
let header: Header = deserialize(&some_header).expect("Can't deserialize correct block header");
|
let header: Header =
|
||||||
|
deserialize(&some_header).expect("Can't deserialize correct block header");
|
||||||
|
|
||||||
assert_eq!(header.bits, header.target().to_compact_lossy());
|
assert_eq!(header.bits, header.target().to_compact_lossy());
|
||||||
}
|
}
|
||||||
|
@ -567,7 +556,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn soft_fork_signalling() {
|
fn soft_fork_signalling() {
|
||||||
for i in 0..31 {
|
for i in 0..31 {
|
||||||
let version_int = (0x20000000u32 ^ 1<<i) as i32;
|
let version_int = (0x20000000u32 ^ 1 << i) as i32;
|
||||||
let version = Version(version_int);
|
let version = Version(version_int);
|
||||||
if i < 29 {
|
if i < 29 {
|
||||||
assert!(version.is_signalling_soft_fork(i));
|
assert!(version.is_signalling_soft_fork(i));
|
||||||
|
@ -576,7 +565,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let segwit_signal = Version(0x20000000 ^ 1<<1);
|
let segwit_signal = Version(0x20000000 ^ 1 << 1);
|
||||||
assert!(!segwit_signal.is_signalling_soft_fork(0));
|
assert!(!segwit_signal.is_signalling_soft_fork(0));
|
||||||
assert!(segwit_signal.is_signalling_soft_fork(1));
|
assert!(segwit_signal.is_signalling_soft_fork(1));
|
||||||
assert!(!segwit_signal.is_signalling_soft_fork(2));
|
assert!(!segwit_signal.is_signalling_soft_fork(2));
|
||||||
|
@ -585,11 +574,12 @@ mod tests {
|
||||||
|
|
||||||
#[cfg(bench)]
|
#[cfg(bench)]
|
||||||
mod benches {
|
mod benches {
|
||||||
use super::Block;
|
|
||||||
use crate::EmptyWrite;
|
|
||||||
use crate::consensus::{deserialize, Encodable, Decodable};
|
|
||||||
use test::{black_box, Bencher};
|
use test::{black_box, Bencher};
|
||||||
|
|
||||||
|
use super::Block;
|
||||||
|
use crate::consensus::{deserialize, Decodable, Encodable};
|
||||||
|
use crate::EmptyWrite;
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn bench_stream_reader(bh: &mut Bencher) {
|
pub fn bench_stream_reader(bh: &mut Bencher) {
|
||||||
let big_block = include_bytes!("../../tests/data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");
|
let big_block = include_bytes!("../../tests/data/mainnet_block_000000000000000000000c835b2adcaedc20fdf6ee440009c249452c726dafae.raw");
|
||||||
|
|
|
@ -13,16 +13,16 @@ use core::default::Default;
|
||||||
use bitcoin_internals::impl_array_newtype;
|
use bitcoin_internals::impl_array_newtype;
|
||||||
use hex_lit::hex;
|
use hex_lit::hex;
|
||||||
|
|
||||||
use crate::hashes::{Hash, sha256d};
|
|
||||||
use crate::blockdata::script;
|
|
||||||
use crate::blockdata::opcodes::all::*;
|
|
||||||
use crate::blockdata::locktime::absolute;
|
|
||||||
use crate::blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn, Sequence};
|
|
||||||
use crate::blockdata::block::{self, Block};
|
use crate::blockdata::block::{self, Block};
|
||||||
|
use crate::blockdata::locktime::absolute;
|
||||||
|
use crate::blockdata::opcodes::all::*;
|
||||||
|
use crate::blockdata::script;
|
||||||
|
use crate::blockdata::transaction::{OutPoint, Sequence, Transaction, TxIn, TxOut};
|
||||||
use crate::blockdata::witness::Witness;
|
use crate::blockdata::witness::Witness;
|
||||||
|
use crate::hashes::{sha256d, Hash};
|
||||||
|
use crate::internal_macros::impl_bytes_newtype;
|
||||||
use crate::network::constants::Network;
|
use crate::network::constants::Network;
|
||||||
use crate::pow::CompactTarget;
|
use crate::pow::CompactTarget;
|
||||||
use crate::internal_macros::impl_bytes_newtype;
|
|
||||||
|
|
||||||
/// How many satoshis are in "one bitcoin".
|
/// How many satoshis are in "one bitcoin".
|
||||||
pub const COIN_VALUE: u64 = 100_000_000;
|
pub const COIN_VALUE: u64 = 100_000_000;
|
||||||
|
@ -73,7 +73,8 @@ fn bitcoin_genesis_tx() -> Transaction {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inputs
|
// Inputs
|
||||||
let in_script = script::Builder::new().push_int(486604799)
|
let in_script = script::Builder::new()
|
||||||
|
.push_int(486604799)
|
||||||
.push_int_non_minimal(4)
|
.push_int_non_minimal(4)
|
||||||
.push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks")
|
.push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks")
|
||||||
.into_script();
|
.into_script();
|
||||||
|
@ -86,14 +87,9 @@ fn bitcoin_genesis_tx() -> Transaction {
|
||||||
|
|
||||||
// Outputs
|
// Outputs
|
||||||
let script_bytes = hex!("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
|
let script_bytes = hex!("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f");
|
||||||
let out_script = script::Builder::new()
|
let out_script =
|
||||||
.push_slice(script_bytes)
|
script::Builder::new().push_slice(script_bytes).push_opcode(OP_CHECKSIG).into_script();
|
||||||
.push_opcode(OP_CHECKSIG)
|
ret.output.push(TxOut { value: 50 * COIN_VALUE, script_pubkey: out_script });
|
||||||
.into_script();
|
|
||||||
ret.output.push(TxOut {
|
|
||||||
value: 50 * COIN_VALUE,
|
|
||||||
script_pubkey: out_script
|
|
||||||
});
|
|
||||||
|
|
||||||
// end
|
// end
|
||||||
ret
|
ret
|
||||||
|
@ -105,58 +101,50 @@ pub fn genesis_block(network: Network) -> Block {
|
||||||
let hash: sha256d::Hash = txdata[0].txid().into();
|
let hash: sha256d::Hash = txdata[0].txid().into();
|
||||||
let merkle_root = hash.into();
|
let merkle_root = hash.into();
|
||||||
match network {
|
match network {
|
||||||
Network::Bitcoin => {
|
Network::Bitcoin => Block {
|
||||||
Block {
|
|
||||||
header: block::Header {
|
header: block::Header {
|
||||||
version: block::Version::ONE,
|
version: block::Version::ONE,
|
||||||
prev_blockhash: Hash::all_zeros(),
|
prev_blockhash: Hash::all_zeros(),
|
||||||
merkle_root,
|
merkle_root,
|
||||||
time: 1231006505,
|
time: 1231006505,
|
||||||
bits: CompactTarget::from_consensus(0x1d00ffff),
|
bits: CompactTarget::from_consensus(0x1d00ffff),
|
||||||
nonce: 2083236893
|
nonce: 2083236893,
|
||||||
},
|
},
|
||||||
txdata,
|
txdata,
|
||||||
}
|
},
|
||||||
}
|
Network::Testnet => Block {
|
||||||
Network::Testnet => {
|
|
||||||
Block {
|
|
||||||
header: block::Header {
|
header: block::Header {
|
||||||
version: block::Version::ONE,
|
version: block::Version::ONE,
|
||||||
prev_blockhash: Hash::all_zeros(),
|
prev_blockhash: Hash::all_zeros(),
|
||||||
merkle_root,
|
merkle_root,
|
||||||
time: 1296688602,
|
time: 1296688602,
|
||||||
bits: CompactTarget::from_consensus(0x1d00ffff),
|
bits: CompactTarget::from_consensus(0x1d00ffff),
|
||||||
nonce: 414098458
|
nonce: 414098458,
|
||||||
},
|
},
|
||||||
txdata,
|
txdata,
|
||||||
}
|
},
|
||||||
}
|
Network::Signet => Block {
|
||||||
Network::Signet => {
|
|
||||||
Block {
|
|
||||||
header: block::Header {
|
header: block::Header {
|
||||||
version: block::Version::ONE,
|
version: block::Version::ONE,
|
||||||
prev_blockhash: Hash::all_zeros(),
|
prev_blockhash: Hash::all_zeros(),
|
||||||
merkle_root,
|
merkle_root,
|
||||||
time: 1598918400,
|
time: 1598918400,
|
||||||
bits: CompactTarget::from_consensus(0x1e0377ae),
|
bits: CompactTarget::from_consensus(0x1e0377ae),
|
||||||
nonce: 52613770
|
nonce: 52613770,
|
||||||
},
|
},
|
||||||
txdata,
|
txdata,
|
||||||
}
|
},
|
||||||
}
|
Network::Regtest => Block {
|
||||||
Network::Regtest => {
|
|
||||||
Block {
|
|
||||||
header: block::Header {
|
header: block::Header {
|
||||||
version: block::Version::ONE,
|
version: block::Version::ONE,
|
||||||
prev_blockhash: Hash::all_zeros(),
|
prev_blockhash: Hash::all_zeros(),
|
||||||
merkle_root,
|
merkle_root,
|
||||||
time: 1296688602,
|
time: 1296688602,
|
||||||
bits: CompactTarget::from_consensus(0x207fffff),
|
bits: CompactTarget::from_consensus(0x207fffff),
|
||||||
nonce: 2
|
nonce: 2,
|
||||||
},
|
},
|
||||||
txdata,
|
txdata,
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,13 +157,25 @@ impl_bytes_newtype!(ChainHash, 32);
|
||||||
impl ChainHash {
|
impl ChainHash {
|
||||||
// Mainnet value can be verified at https://github.com/lightning/bolts/blob/master/00-introduction.md
|
// Mainnet value can be verified at https://github.com/lightning/bolts/blob/master/00-introduction.md
|
||||||
/// `ChainHash` for mainnet bitcoin.
|
/// `ChainHash` for mainnet bitcoin.
|
||||||
pub const BITCOIN: Self = Self([111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0]);
|
pub const BITCOIN: Self = Self([
|
||||||
|
111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131,
|
||||||
|
101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0,
|
||||||
|
]);
|
||||||
/// `ChainHash` for testnet bitcoin.
|
/// `ChainHash` for testnet bitcoin.
|
||||||
pub const TESTNET: Self = Self([67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151, 32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0]);
|
pub const TESTNET: Self = Self([
|
||||||
|
67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151,
|
||||||
|
32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0,
|
||||||
|
]);
|
||||||
/// `ChainHash` for signet bitcoin.
|
/// `ChainHash` for signet bitcoin.
|
||||||
pub const SIGNET: Self = Self([246, 30, 238, 59, 99, 163, 128, 164, 119, 160, 99, 175, 50, 178, 187, 201, 124, 159, 249, 240, 31, 44, 66, 37, 233, 115, 152, 129, 8, 0, 0, 0]);
|
pub const SIGNET: Self = Self([
|
||||||
|
246, 30, 238, 59, 99, 163, 128, 164, 119, 160, 99, 175, 50, 178, 187, 201, 124, 159, 249,
|
||||||
|
240, 31, 44, 66, 37, 233, 115, 152, 129, 8, 0, 0, 0,
|
||||||
|
]);
|
||||||
/// `ChainHash` for regtest bitcoin.
|
/// `ChainHash` for regtest bitcoin.
|
||||||
pub const REGTEST: Self = Self([6, 34, 110, 70, 17, 26, 11, 89, 202, 175, 18, 96, 67, 235, 91, 191, 40, 195, 79, 58, 94, 51, 42, 31, 199, 178, 183, 60, 241, 136, 145, 15]);
|
pub const REGTEST: Self = Self([
|
||||||
|
6, 34, 110, 70, 17, 26, 11, 89, 202, 175, 18, 96, 67, 235, 91, 191, 40, 195, 79, 58, 94,
|
||||||
|
51, 42, 31, 199, 178, 183, 60, 241, 136, 145, 15,
|
||||||
|
]);
|
||||||
|
|
||||||
/// Returns the hash of the `network` genesis block for use as a chain hash.
|
/// Returns the hash of the `network` genesis block for use as a chain hash.
|
||||||
///
|
///
|
||||||
|
@ -190,10 +190,10 @@ impl ChainHash {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::network::constants::Network;
|
|
||||||
use crate::consensus::encode::serialize;
|
|
||||||
use crate::blockdata::locktime::absolute;
|
use crate::blockdata::locktime::absolute;
|
||||||
|
use crate::consensus::encode::serialize;
|
||||||
use crate::internal_macros::hex;
|
use crate::internal_macros::hex;
|
||||||
|
use crate::network::constants::Network;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bitcoin_genesis_first_transaction() {
|
fn bitcoin_genesis_first_transaction() {
|
||||||
|
@ -213,7 +213,10 @@ mod test {
|
||||||
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
|
assert_eq!(gen.output[0].value, 50 * COIN_VALUE);
|
||||||
assert_eq!(gen.lock_time, absolute::LockTime::ZERO);
|
assert_eq!(gen.lock_time, absolute::LockTime::ZERO);
|
||||||
|
|
||||||
assert_eq!(gen.wtxid().to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
|
assert_eq!(
|
||||||
|
gen.wtxid().to_string(),
|
||||||
|
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -222,12 +225,18 @@ mod test {
|
||||||
|
|
||||||
assert_eq!(gen.header.version, block::Version::ONE);
|
assert_eq!(gen.header.version, block::Version::ONE);
|
||||||
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
|
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
|
||||||
assert_eq!(gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
|
assert_eq!(
|
||||||
|
gen.header.merkle_root.to_string(),
|
||||||
|
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(gen.header.time, 1231006505);
|
assert_eq!(gen.header.time, 1231006505);
|
||||||
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff));
|
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff));
|
||||||
assert_eq!(gen.header.nonce, 2083236893);
|
assert_eq!(gen.header.nonce, 2083236893);
|
||||||
assert_eq!(gen.header.block_hash().to_string(), "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
|
assert_eq!(
|
||||||
|
gen.header.block_hash().to_string(),
|
||||||
|
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -235,11 +244,17 @@ mod test {
|
||||||
let gen = genesis_block(Network::Testnet);
|
let gen = genesis_block(Network::Testnet);
|
||||||
assert_eq!(gen.header.version, block::Version::ONE);
|
assert_eq!(gen.header.version, block::Version::ONE);
|
||||||
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
|
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
|
||||||
assert_eq!(gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
|
assert_eq!(
|
||||||
|
gen.header.merkle_root.to_string(),
|
||||||
|
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
||||||
|
);
|
||||||
assert_eq!(gen.header.time, 1296688602);
|
assert_eq!(gen.header.time, 1296688602);
|
||||||
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff));
|
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff));
|
||||||
assert_eq!(gen.header.nonce, 414098458);
|
assert_eq!(gen.header.nonce, 414098458);
|
||||||
assert_eq!(gen.header.block_hash().to_string(), "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943");
|
assert_eq!(
|
||||||
|
gen.header.block_hash().to_string(),
|
||||||
|
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -247,11 +262,17 @@ mod test {
|
||||||
let gen = genesis_block(Network::Signet);
|
let gen = genesis_block(Network::Signet);
|
||||||
assert_eq!(gen.header.version, block::Version::ONE);
|
assert_eq!(gen.header.version, block::Version::ONE);
|
||||||
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
|
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
|
||||||
assert_eq!(gen.header.merkle_root.to_string(), "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
|
assert_eq!(
|
||||||
|
gen.header.merkle_root.to_string(),
|
||||||
|
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
|
||||||
|
);
|
||||||
assert_eq!(gen.header.time, 1598918400);
|
assert_eq!(gen.header.time, 1598918400);
|
||||||
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1e0377ae));
|
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1e0377ae));
|
||||||
assert_eq!(gen.header.nonce, 52613770);
|
assert_eq!(gen.header.nonce, 52613770);
|
||||||
assert_eq!(gen.header.block_hash().to_string(), "00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6");
|
assert_eq!(
|
||||||
|
gen.header.block_hash().to_string(),
|
||||||
|
"00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The *_chain_hash tests are sanity/regression tests, they verify that the const byte array
|
// The *_chain_hash tests are sanity/regression tests, they verify that the const byte array
|
||||||
|
@ -271,12 +292,13 @@ mod test {
|
||||||
// Compare strings because the spec specifically states how the chain hash must encode to hex.
|
// Compare strings because the spec specifically states how the chain hash must encode to hex.
|
||||||
assert_eq!(got, want);
|
assert_eq!(got, want);
|
||||||
|
|
||||||
|
#[allow(unreachable_patterns)] // This is specifically trying to catch later added variants.
|
||||||
match network {
|
match network {
|
||||||
Network::Bitcoin => {},
|
Network::Bitcoin => {},
|
||||||
Network::Testnet => {},
|
Network::Testnet => {},
|
||||||
Network::Signet => {},
|
Network::Signet => {},
|
||||||
Network::Regtest => {},
|
Network::Regtest => {},
|
||||||
// Update ChainHash::using_genesis_block and chain_hash_genesis_block with new variants.
|
_ => panic!("Update ChainHash::using_genesis_block and chain_hash_genesis_block with new variants"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
//! Implements `FeeRate` and assoctiated features.
|
//! Implements `FeeRate` and assoctiated features.
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::ops::{Mul, Div};
|
use core::ops::{Div, Mul};
|
||||||
|
|
||||||
|
use super::Weight;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::Amount;
|
use crate::Amount;
|
||||||
use super::Weight;
|
|
||||||
|
|
||||||
/// Represents fee rate.
|
/// Represents fee rate.
|
||||||
///
|
///
|
||||||
|
@ -40,9 +40,7 @@ impl FeeRate {
|
||||||
pub const DUST: FeeRate = FeeRate::from_sat_per_vb_unchecked(3);
|
pub const DUST: FeeRate = FeeRate::from_sat_per_vb_unchecked(3);
|
||||||
|
|
||||||
/// Constructs `FeeRate` from satoshis per 1000 weight units.
|
/// Constructs `FeeRate` from satoshis per 1000 weight units.
|
||||||
pub const fn from_sat_per_kwu(sat_kwu: u64) -> Self {
|
pub const fn from_sat_per_kwu(sat_kwu: u64) -> Self { FeeRate(sat_kwu) }
|
||||||
FeeRate(sat_kwu)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs `FeeRate` from satoshis per virtual bytes.
|
/// Constructs `FeeRate` from satoshis per virtual bytes.
|
||||||
///
|
///
|
||||||
|
@ -57,40 +55,28 @@ impl FeeRate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs `FeeRate` from satoshis per virtual bytes without overflow check.
|
/// Constructs `FeeRate` from satoshis per virtual bytes without overflow check.
|
||||||
pub const fn from_sat_per_vb_unchecked(sat_vb: u64) -> Self {
|
pub const fn from_sat_per_vb_unchecked(sat_vb: u64) -> Self { FeeRate(sat_vb * (1000 / 4)) }
|
||||||
FeeRate(sat_vb * (1000 / 4))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns raw fee rate.
|
/// Returns raw fee rate.
|
||||||
///
|
///
|
||||||
/// Can be used instead of `into()` to avoid inference issues.
|
/// Can be used instead of `into()` to avoid inference issues.
|
||||||
pub const fn to_sat_per_kwu(self) -> u64 {
|
pub const fn to_sat_per_kwu(self) -> u64 { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts to sat/vB rounding down.
|
/// Converts to sat/vB rounding down.
|
||||||
pub const fn to_sat_per_vb_floor(self) -> u64 {
|
pub const fn to_sat_per_vb_floor(self) -> u64 { self.0 / (1000 / 4) }
|
||||||
self.0 / (1000 / 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts to sat/vB rounding up.
|
/// Converts to sat/vB rounding up.
|
||||||
pub const fn to_sat_per_vb_ceil(self) -> u64 {
|
pub const fn to_sat_per_vb_ceil(self) -> u64 { (self.0 + (1000 / 4 - 1)) / (1000 / 4) }
|
||||||
(self.0 + (1000 / 4 - 1)) / (1000 / 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checked multiplication.
|
/// Checked multiplication.
|
||||||
///
|
///
|
||||||
/// Computes `self * rhs` returning `None` if overflow occurred.
|
/// Computes `self * rhs` returning `None` if overflow occurred.
|
||||||
pub fn checked_mul(self, rhs: u64) -> Option<Self> {
|
pub fn checked_mul(self, rhs: u64) -> Option<Self> { self.0.checked_mul(rhs).map(Self) }
|
||||||
self.0.checked_mul(rhs).map(Self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checked division.
|
/// Checked division.
|
||||||
///
|
///
|
||||||
/// Computes `self / rhs` returning `None` if `rhs == 0`.
|
/// Computes `self / rhs` returning `None` if `rhs == 0`.
|
||||||
pub fn checked_div(self, rhs: u64) -> Option<Self> {
|
pub fn checked_div(self, rhs: u64) -> Option<Self> { self.0.checked_div(rhs).map(Self) }
|
||||||
self.0.checked_div(rhs).map(Self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alternative will display the unit.
|
/// Alternative will display the unit.
|
||||||
|
@ -105,9 +91,7 @@ impl fmt::Display for FeeRate {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FeeRate> for u64 {
|
impl From<FeeRate> for u64 {
|
||||||
fn from(value: FeeRate) -> Self {
|
fn from(value: FeeRate) -> Self { value.to_sat_per_kwu() }
|
||||||
value.to_sat_per_kwu()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes ceiling so that fee computation is conservative.
|
/// Computes ceiling so that fee computation is conservative.
|
||||||
|
@ -122,26 +106,23 @@ impl Mul<FeeRate> for Weight {
|
||||||
impl Mul<Weight> for FeeRate {
|
impl Mul<Weight> for FeeRate {
|
||||||
type Output = Amount;
|
type Output = Amount;
|
||||||
|
|
||||||
fn mul(self, rhs: Weight) -> Self::Output {
|
fn mul(self, rhs: Weight) -> Self::Output { rhs * self }
|
||||||
rhs * self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Div<Weight> for Amount {
|
impl Div<Weight> for Amount {
|
||||||
type Output = FeeRate;
|
type Output = FeeRate;
|
||||||
|
|
||||||
fn div(self, rhs: Weight) -> Self::Output {
|
fn div(self, rhs: Weight) -> Self::Output { FeeRate(self.to_sat() * 1000 / rhs.to_wu()) }
|
||||||
FeeRate(self.to_sat() * 1000 / rhs.to_wu())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::parse::impl_parse_str_from_int_infallible!(FeeRate, u64, from_sat_per_kwu);
|
crate::parse::impl_parse_str_from_int_infallible!(FeeRate, u64, from_sat_per_kwu);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use std::u64;
|
use std::u64;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fee_rate_const_test() {
|
fn fee_rate_const_test() {
|
||||||
assert_eq!(0, FeeRate::ZERO.to_sat_per_kwu());
|
assert_eq!(0, FeeRate::ZERO.to_sat_per_kwu());
|
||||||
|
@ -171,9 +152,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn from_sat_per_vb_unchecked_panic_test() {
|
fn from_sat_per_vb_unchecked_panic_test() { FeeRate::from_sat_per_vb_unchecked(u64::MAX); }
|
||||||
FeeRate::from_sat_per_vb_unchecked(u64::MAX);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn raw_feerate_test() {
|
fn raw_feerate_test() {
|
||||||
|
|
|
@ -7,24 +7,22 @@
|
||||||
//! whether `LockTime < LOCKTIME_THRESHOLD`.
|
//! whether `LockTime < LOCKTIME_THRESHOLD`.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::{mem, fmt};
|
use core::cmp::{Ordering, PartialOrd};
|
||||||
use core::cmp::{PartialOrd, Ordering};
|
use core::{fmt, mem};
|
||||||
|
|
||||||
use bitcoin_internals::write_err;
|
use bitcoin_internals::write_err;
|
||||||
|
|
||||||
#[cfg(all(test, mutate))]
|
#[cfg(all(test, mutate))]
|
||||||
use mutagen::mutate;
|
use mutagen::mutate;
|
||||||
|
|
||||||
|
#[cfg(doc)]
|
||||||
|
use crate::absolute;
|
||||||
use crate::consensus::encode::{self, Decodable, Encodable};
|
use crate::consensus::encode::{self, Decodable, Encodable};
|
||||||
use crate::error::ParseIntError;
|
use crate::error::ParseIntError;
|
||||||
use crate::io::{self, Read, Write};
|
use crate::io::{self, Read, Write};
|
||||||
use crate::parse::{impl_parse_str_from_int_infallible, impl_parse_str_from_int_fallible};
|
use crate::parse::{impl_parse_str_from_int_fallible, impl_parse_str_from_int_infallible};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::string::FromHexStr;
|
use crate::string::FromHexStr;
|
||||||
|
|
||||||
#[cfg(doc)]
|
|
||||||
use crate::absolute;
|
|
||||||
|
|
||||||
/// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]).
|
/// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]).
|
||||||
///
|
///
|
||||||
/// `LockTime` values _below_ the threshold are interpreted as block heights, values _above_ (or
|
/// `LockTime` values _below_ the threshold are interpreted as block heights, values _above_ (or
|
||||||
|
@ -173,9 +171,7 @@ impl LockTime {
|
||||||
|
|
||||||
/// Returns true if this lock time value is a block time (UNIX timestamp).
|
/// Returns true if this lock time value is a block time (UNIX timestamp).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_block_time(&self) -> bool {
|
pub fn is_block_time(&self) -> bool { !self.is_block_height() }
|
||||||
!self.is_block_height()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if this timelock constraint is satisfied by the respective `height`/`time`.
|
/// Returns true if this timelock constraint is satisfied by the respective `height`/`time`.
|
||||||
///
|
///
|
||||||
|
@ -278,16 +274,12 @@ impl_parse_str_from_int_infallible!(LockTime, u32, from_consensus);
|
||||||
|
|
||||||
impl From<Height> for LockTime {
|
impl From<Height> for LockTime {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(h: Height) -> Self {
|
fn from(h: Height) -> Self { LockTime::Blocks(h) }
|
||||||
LockTime::Blocks(h)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Time> for LockTime {
|
impl From<Time> for LockTime {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(t: Time) -> Self {
|
fn from(t: Time) -> Self { LockTime::Seconds(t) }
|
||||||
LockTime::Seconds(t)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for LockTime {
|
impl PartialOrd for LockTime {
|
||||||
|
@ -371,19 +363,22 @@ impl<'de> serde::Deserialize<'de> for LockTime {
|
||||||
// other visit_u*s have default implementations that forward to visit_u64.
|
// other visit_u*s have default implementations that forward to visit_u64.
|
||||||
fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<u32, E> {
|
fn visit_u64<E: serde::de::Error>(self, v: u64) -> Result<u32, E> {
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
v.try_into().map_err(|_| E::invalid_value(serde::de::Unexpected::Unsigned(v), &"a 32-bit number"))
|
v.try_into().map_err(|_| {
|
||||||
|
E::invalid_value(serde::de::Unexpected::Unsigned(v), &"a 32-bit number")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
// Also do the signed version, just for good measure.
|
// Also do the signed version, just for good measure.
|
||||||
fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<u32, E> {
|
fn visit_i64<E: serde::de::Error>(self, v: i64) -> Result<u32, E> {
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
v.try_into().map_err(|_| E::invalid_value(serde::de::Unexpected::Signed(v), &"a 32-bit number"))
|
v.try_into().map_err(|_| {
|
||||||
|
E::invalid_value(serde::de::Unexpected::Signed(v), &"a 32-bit number")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
deserializer.deserialize_u32(Visitor).map(LockTime::from_consensus)
|
deserializer.deserialize_u32(Visitor).map(LockTime::from_consensus)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// An absolute block height, guaranteed to always contain a valid height value.
|
/// An absolute block height, guaranteed to always contain a valid height value.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
@ -444,17 +439,13 @@ impl Height {
|
||||||
/// assert!(lock_time.is_block_height());
|
/// assert!(lock_time.is_block_height());
|
||||||
/// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
|
/// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_consensus_u32(self) -> u32 {
|
pub fn to_consensus_u32(self) -> u32 { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_parse_str_from_int_fallible!(Height, u32, from_consensus, Error);
|
impl_parse_str_from_int_fallible!(Height, u32, from_consensus, Error);
|
||||||
|
|
||||||
impl fmt::Display for Height {
|
impl fmt::Display for Height {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
|
||||||
fmt::Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromHexStr for Height {
|
impl FromHexStr for Height {
|
||||||
|
@ -528,17 +519,13 @@ impl Time {
|
||||||
/// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
|
/// assert_eq!(lock_time.to_consensus_u32(), n_lock_time);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_consensus_u32(self) -> u32 {
|
pub fn to_consensus_u32(self) -> u32 { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_parse_str_from_int_fallible!(Time, u32, from_consensus, Error);
|
impl_parse_str_from_int_fallible!(Time, u32, from_consensus, Error);
|
||||||
|
|
||||||
impl fmt::Display for Time {
|
impl fmt::Display for Time {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
|
||||||
fmt::Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromHexStr for Time {
|
impl FromHexStr for Time {
|
||||||
|
@ -552,14 +539,10 @@ impl FromHexStr for Time {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if `n` is a block height i.e., less than 500,000,000.
|
/// Returns true if `n` is a block height i.e., less than 500,000,000.
|
||||||
fn is_block_height(n: u32) -> bool {
|
fn is_block_height(n: u32) -> bool { n < LOCK_TIME_THRESHOLD }
|
||||||
n < LOCK_TIME_THRESHOLD
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if `n` is a UNIX timestamp i.e., greater than or equal to 500,000,000.
|
/// Returns true if `n` is a UNIX timestamp i.e., greater than or equal to 500,000,000.
|
||||||
fn is_block_time(n: u32) -> bool {
|
fn is_block_time(n: u32) -> bool { n >= LOCK_TIME_THRESHOLD }
|
||||||
n >= LOCK_TIME_THRESHOLD
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Catchall type for errors that relate to time locks.
|
/// Catchall type for errors that relate to time locks.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
@ -601,23 +584,17 @@ impl std::error::Error for Error {
|
||||||
|
|
||||||
impl From<ConversionError> for Error {
|
impl From<ConversionError> for Error {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(e: ConversionError) -> Self {
|
fn from(e: ConversionError) -> Self { Error::Conversion(e) }
|
||||||
Error::Conversion(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OperationError> for Error {
|
impl From<OperationError> for Error {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(e: OperationError) -> Self {
|
fn from(e: OperationError) -> Self { Error::Operation(e) }
|
||||||
Error::Operation(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ParseIntError> for Error {
|
impl From<ParseIntError> for Error {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(e: ParseIntError) -> Self {
|
fn from(e: ParseIntError) -> Self { Error::Parse(e) }
|
||||||
Error::Parse(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error that occurs when converting a `u32` to a lock time variant.
|
/// An error that occurs when converting a `u32` to a lock time variant.
|
||||||
|
@ -631,20 +608,10 @@ pub struct ConversionError {
|
||||||
|
|
||||||
impl ConversionError {
|
impl ConversionError {
|
||||||
/// Constructs a `ConversionError` from an invalid `n` when expecting a height value.
|
/// Constructs a `ConversionError` from an invalid `n` when expecting a height value.
|
||||||
fn invalid_height(n: u32) -> Self {
|
fn invalid_height(n: u32) -> Self { Self { unit: LockTimeUnit::Blocks, input: n } }
|
||||||
Self {
|
|
||||||
unit: LockTimeUnit::Blocks,
|
|
||||||
input: n,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs a `ConversionError` from an invalid `n` when expecting a time value.
|
/// Constructs a `ConversionError` from an invalid `n` when expecting a time value.
|
||||||
fn invalid_time(n: u32) -> Self {
|
fn invalid_time(n: u32) -> Self { Self { unit: LockTimeUnit::Seconds, input: n } }
|
||||||
Self {
|
|
||||||
unit: LockTimeUnit::Seconds,
|
|
||||||
input: n,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ConversionError {
|
impl fmt::Display for ConversionError {
|
||||||
|
@ -690,7 +657,8 @@ impl fmt::Display for OperationError {
|
||||||
use self::OperationError::*;
|
use self::OperationError::*;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
InvalidComparison => f.write_str("cannot compare different lock units (height vs time)"),
|
InvalidComparison =>
|
||||||
|
f.write_str("cannot compare different lock units (height vs time)"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,14 @@
|
||||||
//! whether bit 22 of the `u32` consensus value is set.
|
//! whether bit 22 of the `u32` consensus value is set.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::fmt;
|
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
#[cfg(all(test, mutate))]
|
#[cfg(all(test, mutate))]
|
||||||
use mutagen::mutate;
|
use mutagen::mutate;
|
||||||
|
|
||||||
use crate::parse::impl_parse_str_from_int_infallible;
|
use crate::parse::impl_parse_str_from_int_infallible;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use crate::relative;
|
use crate::relative;
|
||||||
|
|
||||||
|
@ -169,16 +168,12 @@ impl LockTime {
|
||||||
|
|
||||||
impl From<Height> for LockTime {
|
impl From<Height> for LockTime {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(h: Height) -> Self {
|
fn from(h: Height) -> Self { LockTime::Blocks(h) }
|
||||||
LockTime::Blocks(h)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Time> for LockTime {
|
impl From<Time> for LockTime {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(t: Time) -> Self {
|
fn from(t: Time) -> Self { LockTime::Time(t) }
|
||||||
LockTime::Time(t)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for LockTime {
|
impl fmt::Display for LockTime {
|
||||||
|
@ -227,24 +222,18 @@ impl Height {
|
||||||
|
|
||||||
/// Returns the inner `u16` value.
|
/// Returns the inner `u16` value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn value(self) -> u16 {
|
pub fn value(self) -> u16 { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u16> for Height {
|
impl From<u16> for Height {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(value: u16) -> Self {
|
fn from(value: u16) -> Self { Height(value) }
|
||||||
Height(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_parse_str_from_int_infallible!(Height, u16, from);
|
impl_parse_str_from_int_infallible!(Height, u16, from);
|
||||||
|
|
||||||
impl fmt::Display for Height {
|
impl fmt::Display for Height {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
|
||||||
fmt::Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A relative lock time lock-by-blocktime value.
|
/// A relative lock time lock-by-blocktime value.
|
||||||
|
@ -279,9 +268,7 @@ impl Time {
|
||||||
///
|
///
|
||||||
/// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin.
|
/// Encoding finer granularity of time for relative lock-times is not supported in Bitcoin.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn from_512_second_intervals(intervals: u16) -> Self {
|
pub fn from_512_second_intervals(intervals: u16) -> Self { Time(intervals) }
|
||||||
Time(intervals)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a [`Time`] from seconds, converting the seconds into 512 second interval with ceiling
|
/// Create a [`Time`] from seconds, converting the seconds into 512 second interval with ceiling
|
||||||
/// division.
|
/// division.
|
||||||
|
@ -300,17 +287,13 @@ impl Time {
|
||||||
|
|
||||||
/// Returns the inner `u16` value.
|
/// Returns the inner `u16` value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn value(self) -> u16 {
|
pub fn value(self) -> u16 { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_parse_str_from_int_infallible!(Time, u16, from_512_second_intervals);
|
impl_parse_str_from_int_infallible!(Time, u16, from_512_second_intervals);
|
||||||
|
|
||||||
impl fmt::Display for Time {
|
impl fmt::Display for Time {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
|
||||||
fmt::Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors related to relative lock times.
|
/// Errors related to relative lock times.
|
||||||
|
@ -328,9 +311,15 @@ pub enum Error {
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Self::IntegerOverflow(val) => write!(f, "{} seconds is too large to be encoded to a 16 bit 512 second interval", val),
|
Self::IntegerOverflow(val) => write!(
|
||||||
Self::IncompatibleHeight(lock, height) => write!(f, "tried to satisfy lock {} with height: {}", lock, height),
|
f,
|
||||||
Self::IncompatibleTime(lock, time) => write!(f, "tried to satisfy lock {} with time: {}", lock, time),
|
"{} seconds is too large to be encoded to a 16 bit 512 second interval",
|
||||||
|
val
|
||||||
|
),
|
||||||
|
Self::IncompatibleHeight(lock, height) =>
|
||||||
|
write!(f, "tried to satisfy lock {} with height: {}", lock, height),
|
||||||
|
Self::IncompatibleTime(lock, time) =>
|
||||||
|
write!(f, "tried to satisfy lock {} with time: {}", lock, time),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,15 +7,15 @@
|
||||||
//! transactions which make up the Bitcoin system.
|
//! transactions which make up the Bitcoin system.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
pub mod block;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
|
pub mod fee_rate;
|
||||||
pub mod locktime;
|
pub mod locktime;
|
||||||
pub mod opcodes;
|
pub mod opcodes;
|
||||||
pub mod script;
|
pub mod script;
|
||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
pub mod block;
|
|
||||||
pub mod witness;
|
|
||||||
pub mod weight;
|
pub mod weight;
|
||||||
pub mod fee_rate;
|
pub mod witness;
|
||||||
|
|
||||||
pub use weight::Weight;
|
|
||||||
pub use fee_rate::FeeRate;
|
pub use fee_rate::FeeRate;
|
||||||
|
pub use weight::Weight;
|
||||||
|
|
|
@ -9,12 +9,15 @@
|
||||||
|
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
|
||||||
#[cfg(feature = "serde")] use serde;
|
use core::convert::From;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
#[cfg(feature = "serde")] use crate::prelude::*;
|
|
||||||
|
|
||||||
use core::{fmt, convert::From};
|
|
||||||
use bitcoin_internals::debug_from_display;
|
use bitcoin_internals::debug_from_display;
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
use serde;
|
||||||
|
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// A script Opcode.
|
/// A script Opcode.
|
||||||
///
|
///
|
||||||
|
@ -351,6 +354,7 @@ impl All {
|
||||||
(OP_VERIF, _) | (OP_VERNOTIF, _) | (OP_INVALIDOPCODE, _) => Class::IllegalOp,
|
(OP_VERIF, _) | (OP_VERNOTIF, _) | (OP_INVALIDOPCODE, _) => Class::IllegalOp,
|
||||||
|
|
||||||
// 15 opcodes illegal in Legacy context
|
// 15 opcodes illegal in Legacy context
|
||||||
|
#[rustfmt::skip]
|
||||||
(OP_CAT, ctx) | (OP_SUBSTR, ctx)
|
(OP_CAT, ctx) | (OP_SUBSTR, ctx)
|
||||||
| (OP_LEFT, ctx) | (OP_RIGHT, ctx)
|
| (OP_LEFT, ctx) | (OP_RIGHT, ctx)
|
||||||
| (OP_INVERT, ctx)
|
| (OP_INVERT, ctx)
|
||||||
|
@ -361,13 +365,15 @@ impl All {
|
||||||
|
|
||||||
// 87 opcodes of SuccessOp class only in TapScript context
|
// 87 opcodes of SuccessOp class only in TapScript context
|
||||||
(op, ClassifyContext::TapScript)
|
(op, ClassifyContext::TapScript)
|
||||||
if op.code == 80 || op.code == 98 ||
|
if op.code == 80
|
||||||
(op.code >= 126 && op.code <= 129) ||
|
|| op.code == 98
|
||||||
(op.code >= 131 && op.code <= 134) ||
|
|| (op.code >= 126 && op.code <= 129)
|
||||||
(op.code >= 137 && op.code <= 138) ||
|
|| (op.code >= 131 && op.code <= 134)
|
||||||
(op.code >= 141 && op.code <= 142) ||
|
|| (op.code >= 137 && op.code <= 138)
|
||||||
(op.code >= 149 && op.code <= 153) ||
|
|| (op.code >= 141 && op.code <= 142)
|
||||||
(op.code >= 187 && op.code <= 254) => Class::SuccessOp,
|
|| (op.code >= 149 && op.code <= 153)
|
||||||
|
|| (op.code >= 187 && op.code <= 254) =>
|
||||||
|
Class::SuccessOp,
|
||||||
|
|
||||||
// 11 opcodes of NoOp class
|
// 11 opcodes of NoOp class
|
||||||
(OP_NOP, _) => Class::NoOp,
|
(OP_NOP, _) => Class::NoOp,
|
||||||
|
@ -377,9 +383,9 @@ impl All {
|
||||||
(OP_RETURN, _) => Class::ReturnOp,
|
(OP_RETURN, _) => Class::ReturnOp,
|
||||||
|
|
||||||
// 4 opcodes operating equally to `OP_RETURN` only in Legacy context
|
// 4 opcodes operating equally to `OP_RETURN` only in Legacy context
|
||||||
(OP_RESERVED, ctx)
|
(OP_RESERVED, ctx) | (OP_RESERVED1, ctx) | (OP_RESERVED2, ctx) | (OP_VER, ctx)
|
||||||
| (OP_RESERVED1, ctx) | (OP_RESERVED2, ctx)
|
if ctx == ClassifyContext::Legacy =>
|
||||||
| (OP_VER, ctx) if ctx == ClassifyContext::Legacy => Class::ReturnOp,
|
Class::ReturnOp,
|
||||||
|
|
||||||
// 71 opcodes operating equally to `OP_RETURN` only in Legacy context
|
// 71 opcodes operating equally to `OP_RETURN` only in Legacy context
|
||||||
(op, ClassifyContext::Legacy) if op.code >= OP_CHECKSIGADD.code => Class::ReturnOp,
|
(op, ClassifyContext::Legacy) if op.code >= OP_CHECKSIGADD.code => Class::ReturnOp,
|
||||||
|
@ -392,9 +398,8 @@ impl All {
|
||||||
(OP_PUSHNUM_NEG1, _) => Class::PushNum(-1),
|
(OP_PUSHNUM_NEG1, _) => Class::PushNum(-1),
|
||||||
|
|
||||||
// 16 opcodes of PushNum class
|
// 16 opcodes of PushNum class
|
||||||
(op, _) if op.code >= OP_PUSHNUM_1.code && op.code <= OP_PUSHNUM_16.code => {
|
(op, _) if op.code >= OP_PUSHNUM_1.code && op.code <= OP_PUSHNUM_16.code =>
|
||||||
Class::PushNum(1 + self.code as i32 - OP_PUSHNUM_1.code as i32)
|
Class::PushNum(1 + self.code as i32 - OP_PUSHNUM_1.code as i32),
|
||||||
},
|
|
||||||
|
|
||||||
// 76 opcodes of PushBytes class
|
// 76 opcodes of PushBytes class
|
||||||
(op, _) if op.code <= OP_PUSHBYTES_75.code => Class::PushBytes(self.code as u32),
|
(op, _) if op.code <= OP_PUSHBYTES_75.code => Class::PushBytes(self.code as u32),
|
||||||
|
@ -406,16 +411,12 @@ impl All {
|
||||||
|
|
||||||
/// Encodes [`All`] as a byte.
|
/// Encodes [`All`] as a byte.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn to_u8(self) -> u8 {
|
pub const fn to_u8(self) -> u8 { self.code }
|
||||||
self.code
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for All {
|
impl From<u8> for All {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(b: u8) -> All {
|
fn from(b: u8) -> All { All { code: b } }
|
||||||
All {code: b}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debug_from_display!(All);
|
debug_from_display!(All);
|
||||||
|
@ -458,7 +459,7 @@ pub enum Class {
|
||||||
/// Does nothing.
|
/// Does nothing.
|
||||||
NoOp,
|
NoOp,
|
||||||
/// Any opcode not covered above.
|
/// Any opcode not covered above.
|
||||||
Ordinary(Ordinary)
|
Ordinary(Ordinary),
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! ordinary_opcode {
|
macro_rules! ordinary_opcode {
|
||||||
|
@ -526,9 +527,7 @@ ordinary_opcode! {
|
||||||
impl Ordinary {
|
impl Ordinary {
|
||||||
/// Encodes [`All`] as a byte.
|
/// Encodes [`All`] as a byte.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_u8(self) -> u8 {
|
pub fn to_u8(self) -> u8 { self as u8 }
|
||||||
self as u8
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -546,7 +545,7 @@ mod tests {
|
||||||
assert_eq!(s1, s2);
|
assert_eq!(s1, s2);
|
||||||
assert_eq!(s1, stringify!($op));
|
assert_eq!(s1, stringify!($op));
|
||||||
assert!($unique.insert(s1));
|
assert!($unique.insert(s1));
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -559,16 +558,25 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn classify_test() {
|
fn classify_test() {
|
||||||
let op174 = OP_CHECKMULTISIG;
|
let op174 = OP_CHECKMULTISIG;
|
||||||
assert_eq!(op174.classify(ClassifyContext::Legacy), Class::Ordinary(Ordinary::OP_CHECKMULTISIG));
|
assert_eq!(
|
||||||
|
op174.classify(ClassifyContext::Legacy),
|
||||||
|
Class::Ordinary(Ordinary::OP_CHECKMULTISIG)
|
||||||
|
);
|
||||||
assert_eq!(op174.classify(ClassifyContext::TapScript), Class::ReturnOp);
|
assert_eq!(op174.classify(ClassifyContext::TapScript), Class::ReturnOp);
|
||||||
|
|
||||||
let op175 = OP_CHECKMULTISIGVERIFY;
|
let op175 = OP_CHECKMULTISIGVERIFY;
|
||||||
assert_eq!(op175.classify(ClassifyContext::Legacy), Class::Ordinary(Ordinary::OP_CHECKMULTISIGVERIFY));
|
assert_eq!(
|
||||||
|
op175.classify(ClassifyContext::Legacy),
|
||||||
|
Class::Ordinary(Ordinary::OP_CHECKMULTISIGVERIFY)
|
||||||
|
);
|
||||||
assert_eq!(op175.classify(ClassifyContext::TapScript), Class::ReturnOp);
|
assert_eq!(op175.classify(ClassifyContext::TapScript), Class::ReturnOp);
|
||||||
|
|
||||||
let op186 = OP_CHECKSIGADD;
|
let op186 = OP_CHECKSIGADD;
|
||||||
assert_eq!(op186.classify(ClassifyContext::Legacy), Class::ReturnOp);
|
assert_eq!(op186.classify(ClassifyContext::Legacy), Class::ReturnOp);
|
||||||
assert_eq!(op186.classify(ClassifyContext::TapScript), Class::Ordinary(Ordinary::OP_CHECKSIGADD));
|
assert_eq!(
|
||||||
|
op186.classify(ClassifyContext::TapScript),
|
||||||
|
Class::Ordinary(Ordinary::OP_CHECKSIGADD)
|
||||||
|
);
|
||||||
|
|
||||||
let op187 = OP_RETURN_187;
|
let op187 = OP_RETURN_187;
|
||||||
assert_eq!(op187.classify(ClassifyContext::Legacy), Class::ReturnOp);
|
assert_eq!(op187.classify(ClassifyContext::Legacy), Class::ReturnOp);
|
||||||
|
|
|
@ -5,22 +5,25 @@ use core::convert::{TryFrom, TryInto};
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
#[cfg(rust_v_1_53)]
|
#[cfg(rust_v_1_53)]
|
||||||
use core::ops::Bound;
|
use core::ops::Bound;
|
||||||
use core::ops::{Index, Range, RangeFull, RangeFrom, RangeTo, RangeInclusive, RangeToInclusive};
|
use core::ops::{Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
|
||||||
|
|
||||||
use secp256k1::{Secp256k1, Verification};
|
use secp256k1::{Secp256k1, Verification};
|
||||||
|
|
||||||
use crate::address::WitnessVersion;
|
use crate::address::WitnessVersion;
|
||||||
use crate::blockdata::opcodes::{self, all::*};
|
use crate::blockdata::opcodes::all::*;
|
||||||
use crate::blockdata::script::{bytes_to_asm_fmt, Builder, Instruction, Instructions, InstructionIndices, ScriptBuf};
|
use crate::blockdata::opcodes::{self};
|
||||||
#[cfg(feature = "bitcoinconsensus")]
|
#[cfg(feature = "bitcoinconsensus")]
|
||||||
use crate::blockdata::script::Error;
|
use crate::blockdata::script::Error;
|
||||||
|
use crate::blockdata::script::{
|
||||||
|
bytes_to_asm_fmt, Builder, Instruction, InstructionIndices, Instructions, ScriptBuf,
|
||||||
|
};
|
||||||
use crate::consensus::Encodable;
|
use crate::consensus::Encodable;
|
||||||
use crate::hash_types::{ScriptHash, WScriptHash};
|
use crate::hash_types::{ScriptHash, WScriptHash};
|
||||||
use crate::hashes::Hash;
|
use crate::hashes::Hash;
|
||||||
use crate::key::{PublicKey, UntweakedPublicKey};
|
use crate::key::{PublicKey, UntweakedPublicKey};
|
||||||
use crate::policy::DUST_RELAY_TX_FEE;
|
use crate::policy::DUST_RELAY_TX_FEE;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::taproot::{LeafVersion, TapNodeHash, TapLeafHash};
|
use crate::taproot::{LeafVersion, TapLeafHash, TapNodeHash};
|
||||||
|
|
||||||
/// Bitcoin script slice.
|
/// Bitcoin script slice.
|
||||||
///
|
///
|
||||||
|
@ -69,14 +72,12 @@ use crate::taproot::{LeafVersion, TapNodeHash, TapLeafHash};
|
||||||
///
|
///
|
||||||
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
|
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Script(pub (in crate::blockdata::script) [u8]);
|
pub struct Script(pub(in crate::blockdata::script) [u8]);
|
||||||
|
|
||||||
impl ToOwned for Script {
|
impl ToOwned for Script {
|
||||||
type Owned = ScriptBuf;
|
type Owned = ScriptBuf;
|
||||||
|
|
||||||
fn to_owned(&self) -> Self::Owned {
|
fn to_owned(&self) -> Self::Owned { ScriptBuf(self.0.to_owned()) }
|
||||||
ScriptBuf(self.0.to_owned())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Script {
|
impl Script {
|
||||||
|
@ -87,9 +88,7 @@ impl Script {
|
||||||
// The pointer was just created from a reference which is still alive.
|
// The pointer was just created from a reference which is still alive.
|
||||||
// Casting slice pointer to a transparent struct wrapping that slice is sound (same
|
// Casting slice pointer to a transparent struct wrapping that slice is sound (same
|
||||||
// layout).
|
// layout).
|
||||||
unsafe {
|
unsafe { &*(bytes as *const [u8] as *const Script) }
|
||||||
&*(bytes as *const [u8] as *const Script)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Treat mutable byte slice as `Script`
|
/// Treat mutable byte slice as `Script`
|
||||||
|
@ -101,43 +100,31 @@ impl Script {
|
||||||
// layout).
|
// layout).
|
||||||
// Function signature prevents callers from accessing `bytes` while the returned reference
|
// Function signature prevents callers from accessing `bytes` while the returned reference
|
||||||
// is alive.
|
// is alive.
|
||||||
unsafe {
|
unsafe { &mut *(bytes as *mut [u8] as *mut Script) }
|
||||||
&mut *(bytes as *mut [u8] as *mut Script)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the script data as a byte slice.
|
/// Returns the script data as a byte slice.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_bytes(&self) -> &[u8] {
|
pub fn as_bytes(&self) -> &[u8] { &self.0 }
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the script data as a mutable byte slice.
|
/// Returns the script data as a mutable byte slice.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_mut_bytes(&mut self) -> &mut [u8] {
|
pub fn as_mut_bytes(&mut self) -> &mut [u8] { &mut self.0 }
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new empty script.
|
/// Creates a new empty script.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn empty() -> &'static Script { Script::from_bytes(&[]) }
|
pub fn empty() -> &'static Script { Script::from_bytes(&[]) }
|
||||||
|
|
||||||
/// Creates a new script builder
|
/// Creates a new script builder
|
||||||
pub fn builder() -> Builder {
|
pub fn builder() -> Builder { Builder::new() }
|
||||||
Builder::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns 160-bit hash of the script.
|
/// Returns 160-bit hash of the script.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn script_hash(&self) -> ScriptHash {
|
pub fn script_hash(&self) -> ScriptHash { ScriptHash::hash(self.as_bytes()) }
|
||||||
ScriptHash::hash(self.as_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns 256-bit hash of the script for P2WSH outputs.
|
/// Returns 256-bit hash of the script for P2WSH outputs.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn wscript_hash(&self) -> WScriptHash {
|
pub fn wscript_hash(&self) -> WScriptHash { WScriptHash::hash(self.as_bytes()) }
|
||||||
WScriptHash::hash(self.as_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes leaf hash of tapscript.
|
/// Computes leaf hash of tapscript.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -159,21 +146,21 @@ impl Script {
|
||||||
|
|
||||||
/// Returns an iterator over script bytes.
|
/// Returns an iterator over script bytes.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn bytes(&self) -> Bytes<'_> {
|
pub fn bytes(&self) -> Bytes<'_> { Bytes(self.as_bytes().iter().copied()) }
|
||||||
Bytes(self.as_bytes().iter().copied())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the P2WSH output corresponding to this witnessScript (aka the "witness redeem
|
/// Computes the P2WSH output corresponding to this witnessScript (aka the "witness redeem
|
||||||
/// script").
|
/// script").
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_v0_p2wsh(&self) -> ScriptBuf {
|
pub fn to_v0_p2wsh(&self) -> ScriptBuf { ScriptBuf::new_v0_p2wsh(&self.wscript_hash()) }
|
||||||
ScriptBuf::new_v0_p2wsh(&self.wscript_hash())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes P2TR output with a given internal key and a single script spending path equal to
|
/// Computes P2TR output with a given internal key and a single script spending path equal to
|
||||||
/// the current script, assuming that the script is a Tapscript.
|
/// the current script, assuming that the script is a Tapscript.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_v1_p2tr<C: Verification>(&self, secp: &Secp256k1<C>, internal_key: UntweakedPublicKey) -> ScriptBuf {
|
pub fn to_v1_p2tr<C: Verification>(
|
||||||
|
&self,
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
internal_key: UntweakedPublicKey,
|
||||||
|
) -> ScriptBuf {
|
||||||
let leaf_hash = self.tapscript_leaf_hash();
|
let leaf_hash = self.tapscript_leaf_hash();
|
||||||
let merkle_root = TapNodeHash::from(leaf_hash);
|
let merkle_root = TapNodeHash::from(leaf_hash);
|
||||||
ScriptBuf::new_v1_p2tr(secp, internal_key, Some(merkle_root))
|
ScriptBuf::new_v1_p2tr(secp, internal_key, Some(merkle_root))
|
||||||
|
@ -210,9 +197,7 @@ impl Script {
|
||||||
/// You can obtain the public key, if its valid,
|
/// You can obtain the public key, if its valid,
|
||||||
/// by calling [`p2pk_public_key()`](Self::p2pk_public_key)
|
/// by calling [`p2pk_public_key()`](Self::p2pk_public_key)
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_p2pk(&self) -> bool {
|
pub fn is_p2pk(&self) -> bool { self.p2pk_pubkey_bytes().is_some() }
|
||||||
self.p2pk_pubkey_bytes().is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the public key if this script is P2PK with a **valid** public key.
|
/// Returns the public key if this script is P2PK with a **valid** public key.
|
||||||
///
|
///
|
||||||
|
@ -228,15 +213,11 @@ impl Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(in crate::blockdata::script) fn p2pk_pubkey_bytes(&self) -> Option<&[u8]> {
|
pub(in crate::blockdata::script) fn p2pk_pubkey_bytes(&self) -> Option<&[u8]> {
|
||||||
match self.len() {
|
match self.len() {
|
||||||
67 if self.0[0] == OP_PUSHBYTES_65.to_u8()
|
67 if self.0[0] == OP_PUSHBYTES_65.to_u8() && self.0[66] == OP_CHECKSIG.to_u8() =>
|
||||||
&& self.0[66] == OP_CHECKSIG.to_u8() => {
|
Some(&self.0[1..66]),
|
||||||
Some(&self.0[1..66])
|
35 if self.0[0] == OP_PUSHBYTES_33.to_u8() && self.0[34] == OP_CHECKSIG.to_u8() =>
|
||||||
}
|
Some(&self.0[1..34]),
|
||||||
35 if self.0[0] == OP_PUSHBYTES_33.to_u8()
|
_ => None,
|
||||||
&& self.0[34] == OP_CHECKSIG.to_u8() => {
|
|
||||||
Some(&self.0[1..34])
|
|
||||||
}
|
|
||||||
_ => None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +230,7 @@ impl Script {
|
||||||
// byte vector pushed is called the "witness program".
|
// byte vector pushed is called the "witness program".
|
||||||
let script_len = self.0.len();
|
let script_len = self.0.len();
|
||||||
if !(4..=42).contains(&script_len) {
|
if !(4..=42).contains(&script_len) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
let ver_opcode = opcodes::All::from(self.0[0]); // Version 0 or PUSHNUM_1-PUSHNUM_16
|
let ver_opcode = opcodes::All::from(self.0[0]); // Version 0 or PUSHNUM_1-PUSHNUM_16
|
||||||
let push_opbyte = self.0[1]; // Second byte push opcode 2-40 bytes
|
let push_opbyte = self.0[1]; // Second byte push opcode 2-40 bytes
|
||||||
|
@ -294,17 +275,17 @@ impl Script {
|
||||||
|
|
||||||
/// Check if this is an OP_RETURN output.
|
/// Check if this is an OP_RETURN output.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_op_return (&self) -> bool {
|
pub fn is_op_return(&self) -> bool {
|
||||||
match self.0.first() {
|
match self.0.first() {
|
||||||
Some(b) => *b == OP_RETURN.to_u8(),
|
Some(b) => *b == OP_RETURN.to_u8(),
|
||||||
None => false
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether a script can be proven to have no satisfying input.
|
/// Checks whether a script can be proven to have no satisfying input.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_provably_unspendable(&self) -> bool {
|
pub fn is_provably_unspendable(&self) -> bool {
|
||||||
use crate::blockdata::opcodes::Class::{ReturnOp, IllegalOp};
|
use crate::blockdata::opcodes::Class::{IllegalOp, ReturnOp};
|
||||||
|
|
||||||
match self.0.first() {
|
match self.0.first() {
|
||||||
Some(b) => {
|
Some(b) => {
|
||||||
|
@ -312,7 +293,7 @@ impl Script {
|
||||||
let class = first.classify(opcodes::ClassifyContext::Legacy);
|
let class = first.classify(opcodes::ClassifyContext::Legacy);
|
||||||
|
|
||||||
class == ReturnOp || class == IllegalOp
|
class == ReturnOp || class == IllegalOp
|
||||||
},
|
}
|
||||||
None => false,
|
None => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,10 +328,7 @@ impl Script {
|
||||||
/// To force minimal pushes, use [`instructions_minimal`](Self::instructions_minimal).
|
/// To force minimal pushes, use [`instructions_minimal`](Self::instructions_minimal).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn instructions(&self) -> Instructions {
|
pub fn instructions(&self) -> Instructions {
|
||||||
Instructions {
|
Instructions { data: self.0.iter(), enforce_minimal: false }
|
||||||
data: self.0.iter(),
|
|
||||||
enforce_minimal: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over the script instructions while enforcing minimal pushes.
|
/// Iterates over the script instructions while enforcing minimal pushes.
|
||||||
|
@ -359,10 +337,7 @@ impl Script {
|
||||||
/// is not minimal.
|
/// is not minimal.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn instructions_minimal(&self) -> Instructions {
|
pub fn instructions_minimal(&self) -> Instructions {
|
||||||
Instructions {
|
Instructions { data: self.0.iter(), enforce_minimal: true }
|
||||||
data: self.0.iter(),
|
|
||||||
enforce_minimal: true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterates over the script instructions and their indices.
|
/// Iterates over the script instructions and their indices.
|
||||||
|
@ -392,9 +367,14 @@ impl Script {
|
||||||
/// * `index` - The input index in spending which is spending this transaction.
|
/// * `index` - The input index in spending which is spending this transaction.
|
||||||
/// * `amount` - The amount this script guards.
|
/// * `amount` - The amount this script guards.
|
||||||
/// * `spending_tx` - The transaction that attempts to spend the output holding this script.
|
/// * `spending_tx` - The transaction that attempts to spend the output holding this script.
|
||||||
#[cfg(feature="bitcoinconsensus")]
|
#[cfg(feature = "bitcoinconsensus")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
|
||||||
pub fn verify (&self, index: usize, amount: crate::Amount, spending_tx: &[u8]) -> Result<(), Error> {
|
pub fn verify(
|
||||||
|
&self,
|
||||||
|
index: usize,
|
||||||
|
amount: crate::Amount,
|
||||||
|
spending_tx: &[u8],
|
||||||
|
) -> Result<(), Error> {
|
||||||
self.verify_with_flags(index, amount, spending_tx, bitcoinconsensus::VERIFY_ALL)
|
self.verify_with_flags(index, amount, spending_tx, bitcoinconsensus::VERIFY_ALL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,10 +385,22 @@ impl Script {
|
||||||
/// * `amount` - The amount this script guards.
|
/// * `amount` - The amount this script guards.
|
||||||
/// * `spending_tx` - The transaction that attempts to spend the output holding this script.
|
/// * `spending_tx` - The transaction that attempts to spend the output holding this script.
|
||||||
/// * `flags` - Verification flags, see [`bitcoinconsensus::VERIFY_ALL`] and similar.
|
/// * `flags` - Verification flags, see [`bitcoinconsensus::VERIFY_ALL`] and similar.
|
||||||
#[cfg(feature="bitcoinconsensus")]
|
#[cfg(feature = "bitcoinconsensus")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "bitcoinconsensus")))]
|
||||||
pub fn verify_with_flags<F: Into<u32>>(&self, index: usize, amount: crate::Amount, spending_tx: &[u8], flags: F) -> Result<(), Error> {
|
pub fn verify_with_flags<F: Into<u32>>(
|
||||||
Ok(bitcoinconsensus::verify_with_flags (&self.0[..], amount.to_sat(), spending_tx, index, flags.into())?)
|
&self,
|
||||||
|
index: usize,
|
||||||
|
amount: crate::Amount,
|
||||||
|
spending_tx: &[u8],
|
||||||
|
flags: F,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
Ok(bitcoinconsensus::verify_with_flags(
|
||||||
|
&self.0[..],
|
||||||
|
amount.to_sat(),
|
||||||
|
spending_tx,
|
||||||
|
index,
|
||||||
|
flags.into(),
|
||||||
|
)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes the assembly decoding of the script to the formatter.
|
/// Writes the assembly decoding of the script to the formatter.
|
||||||
|
@ -428,9 +420,7 @@ impl Script {
|
||||||
/// This is a more convenient and performant way to write `format!("{:x}", script)`.
|
/// This is a more convenient and performant way to write `format!("{:x}", script)`.
|
||||||
/// For better performance you should generally prefer displaying the script but if `String` is
|
/// For better performance you should generally prefer displaying the script but if `String` is
|
||||||
/// required (this is common in tests) this method is can be used.
|
/// required (this is common in tests) this method is can be used.
|
||||||
pub fn to_hex_string(&self) -> String {
|
pub fn to_hex_string(&self) -> String { self.as_bytes().to_lower_hex_string() }
|
||||||
self.as_bytes().to_lower_hex_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the first opcode of the script (if there is any).
|
/// Returns the first opcode of the script (if there is any).
|
||||||
pub fn first_opcode(&self) -> Option<opcodes::All> {
|
pub fn first_opcode(&self) -> Option<opcodes::All> {
|
||||||
|
@ -467,31 +457,21 @@ impl Iterator for Bytes<'_> {
|
||||||
type Item = u8;
|
type Item = u8;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> { self.0.next() }
|
||||||
self.0.next()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
|
||||||
self.0.size_hint()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
fn nth(&mut self, n: usize) -> Option<Self::Item> { self.0.nth(n) }
|
||||||
self.0.nth(n)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DoubleEndedIterator for Bytes<'_> {
|
impl DoubleEndedIterator for Bytes<'_> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> { self.0.next_back() }
|
||||||
self.0.next_back()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
|
fn nth_back(&mut self, n: usize) -> Option<Self::Item> { self.0.nth_back(n) }
|
||||||
self.0.nth_back(n)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExactSizeIterator for Bytes<'_> {}
|
impl ExactSizeIterator for Bytes<'_> {}
|
||||||
|
@ -513,7 +493,14 @@ macro_rules! delegate_index {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate_index!(Range<usize>, RangeFrom<usize>, RangeTo<usize>, RangeFull, RangeInclusive<usize>, RangeToInclusive<usize>);
|
delegate_index!(
|
||||||
|
Range<usize>,
|
||||||
|
RangeFrom<usize>,
|
||||||
|
RangeTo<usize>,
|
||||||
|
RangeFull,
|
||||||
|
RangeInclusive<usize>,
|
||||||
|
RangeToInclusive<usize>
|
||||||
|
);
|
||||||
#[cfg(rust_v_1_53)]
|
#[cfg(rust_v_1_53)]
|
||||||
#[cfg_attr(docsrs, doc(cfg(rust_v_1_53)))]
|
#[cfg_attr(docsrs, doc(cfg(rust_v_1_53)))]
|
||||||
delegate_index!((Bound<usize>, Bound<usize>));
|
delegate_index!((Bound<usize>, Bound<usize>));
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
// Written in 2014 by Andrew Poelstra <apoelstra@wpsoftware.net>
|
// Written in 2014 by Andrew Poelstra <apoelstra@wpsoftware.net>
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
#[cfg(feature="bitcoinconsensus")] use core::convert::From;
|
#[cfg(feature = "bitcoinconsensus")]
|
||||||
|
use core::convert::From;
|
||||||
use core::default::Default;
|
use core::default::Default;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use secp256k1::XOnlyPublicKey;
|
use secp256k1::XOnlyPublicKey;
|
||||||
|
|
||||||
use crate::blockdata::locktime::absolute;
|
use crate::blockdata::locktime::absolute;
|
||||||
use crate::blockdata::opcodes::{self, all::*};
|
use crate::blockdata::opcodes::all::*;
|
||||||
use crate::blockdata::script::{write_scriptint, opcode_to_verify, Script, ScriptBuf, PushBytes};
|
use crate::blockdata::opcodes::{self};
|
||||||
|
use crate::blockdata::script::{opcode_to_verify, write_scriptint, PushBytes, Script, ScriptBuf};
|
||||||
use crate::blockdata::transaction::Sequence;
|
use crate::blockdata::transaction::Sequence;
|
||||||
use crate::key::PublicKey;
|
use crate::key::PublicKey;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
@ -20,9 +22,7 @@ pub struct Builder(ScriptBuf, Option<opcodes::All>);
|
||||||
|
|
||||||
impl Builder {
|
impl Builder {
|
||||||
/// Creates a new empty script.
|
/// Creates a new empty script.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Builder(ScriptBuf::new(), None) }
|
||||||
Builder(ScriptBuf::new(), None)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the length in bytes of the script.
|
/// Returns the length in bytes of the script.
|
||||||
pub fn len(&self) -> usize { self.0.len() }
|
pub fn len(&self) -> usize { self.0.len() }
|
||||||
|
@ -37,9 +37,7 @@ impl Builder {
|
||||||
pub fn push_int(self, data: i64) -> Builder {
|
pub fn push_int(self, data: i64) -> Builder {
|
||||||
// We can special-case -1, 1-16
|
// We can special-case -1, 1-16
|
||||||
if data == -1 || (1..=16).contains(&data) {
|
if data == -1 || (1..=16).contains(&data) {
|
||||||
let opcode = opcodes::All::from(
|
let opcode = opcodes::All::from((data - 1 + opcodes::OP_TRUE.to_u8() as i64) as u8);
|
||||||
(data - 1 + opcodes::OP_TRUE.to_u8() as i64) as u8
|
|
||||||
);
|
|
||||||
self.push_opcode(opcode)
|
self.push_opcode(opcode)
|
||||||
}
|
}
|
||||||
// We can also special-case zero
|
// We can also special-case zero
|
||||||
|
@ -47,7 +45,9 @@ impl Builder {
|
||||||
self.push_opcode(opcodes::OP_0)
|
self.push_opcode(opcodes::OP_0)
|
||||||
}
|
}
|
||||||
// Otherwise encode it as data
|
// Otherwise encode it as data
|
||||||
else { self.push_int_non_minimal(data) }
|
else {
|
||||||
|
self.push_int_non_minimal(data)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds instructions to push an integer onto the stack without optimization.
|
/// Adds instructions to push an integer onto the stack without optimization.
|
||||||
|
@ -103,7 +103,7 @@ impl Builder {
|
||||||
Some(opcode) => {
|
Some(opcode) => {
|
||||||
(self.0).0.pop();
|
(self.0).0.pop();
|
||||||
self.push_opcode(opcode)
|
self.push_opcode(opcode)
|
||||||
},
|
}
|
||||||
None => self.push_opcode(OP_VERIFY),
|
None => self.push_opcode(OP_VERIFY),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,24 +119,16 @@ impl Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the `Builder` into `ScriptBuf`.
|
/// Converts the `Builder` into `ScriptBuf`.
|
||||||
pub fn into_script(self) -> ScriptBuf {
|
pub fn into_script(self) -> ScriptBuf { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts the `Builder` into script bytes
|
/// Converts the `Builder` into script bytes
|
||||||
pub fn into_bytes(self) -> Vec<u8> {
|
pub fn into_bytes(self) -> Vec<u8> { self.0.into() }
|
||||||
self.0.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the internal script
|
/// Returns the internal script
|
||||||
pub fn as_script(&self) -> &Script {
|
pub fn as_script(&self) -> &Script { &self.0 }
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns script bytes
|
/// Returns script bytes
|
||||||
pub fn as_bytes(&self) -> &[u8] {
|
pub fn as_bytes(&self) -> &[u8] { self.0.as_bytes() }
|
||||||
self.0.as_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Builder {
|
impl Default for Builder {
|
||||||
|
@ -153,9 +145,7 @@ impl From<Vec<u8>> for Builder {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Builder {
|
impl fmt::Display for Builder {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.0.fmt_asm(f) }
|
||||||
self.0.fmt_asm(f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bitcoin_internals::debug_from_display!(Builder);
|
bitcoin_internals::debug_from_display!(Builder);
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
|
|
||||||
use crate::blockdata::opcodes;
|
use crate::blockdata::opcodes;
|
||||||
use crate::blockdata::script::{read_uint_iter, Error, Script, ScriptBuf, UintError, PushBytes};
|
use crate::blockdata::script::{read_uint_iter, Error, PushBytes, Script, ScriptBuf, UintError};
|
||||||
|
|
||||||
/// A "parsed opcode" which allows iterating over a [`Script`] in a more sensible way.
|
/// A "parsed opcode" which allows iterating over a [`Script`] in a more sensible way.
|
||||||
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
|
||||||
|
@ -51,9 +52,7 @@ impl<'a> Instructions<'a> {
|
||||||
/// Views the remaining script as a slice.
|
/// Views the remaining script as a slice.
|
||||||
///
|
///
|
||||||
/// This is analogous to what [`core::str::Chars::as_str`] does.
|
/// This is analogous to what [`core::str::Chars::as_str`] does.
|
||||||
pub fn as_script(&self) -> &'a Script {
|
pub fn as_script(&self) -> &'a Script { Script::from_bytes(self.data.as_slice()) }
|
||||||
Script::from_bytes(self.data.as_slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the iterator to end so that it won't iterate any longer.
|
/// Sets the iterator to end so that it won't iterate any longer.
|
||||||
pub(super) fn kill(&mut self) {
|
pub(super) fn kill(&mut self) {
|
||||||
|
@ -80,7 +79,11 @@ impl<'a> Instructions<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn next_push_data_len(&mut self, len: PushDataLenLen, min_push_len: usize) -> Option<Result<Instruction<'a>, Error>> {
|
pub(super) fn next_push_data_len(
|
||||||
|
&mut self,
|
||||||
|
len: PushDataLenLen,
|
||||||
|
min_push_len: usize,
|
||||||
|
) -> Option<Result<Instruction<'a>, Error>> {
|
||||||
let n = match read_uint_iter(&mut self.data, len as usize) {
|
let n = match read_uint_iter(&mut self.data, len as usize) {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
// We do exhaustive matching to not forget to handle new variants if we extend
|
// We do exhaustive matching to not forget to handle new variants if we extend
|
||||||
|
@ -90,7 +93,7 @@ impl<'a> Instructions<'a> {
|
||||||
Err(UintError::EarlyEndOfScript) | Err(UintError::NumericOverflow) => {
|
Err(UintError::EarlyEndOfScript) | Err(UintError::NumericOverflow) => {
|
||||||
self.kill();
|
self.kill();
|
||||||
return Some(Err(Error::EarlyEndOfScript));
|
return Some(Err(Error::EarlyEndOfScript));
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
if self.enforce_minimal && n < min_push_len {
|
if self.enforce_minimal && n < min_push_len {
|
||||||
self.kill();
|
self.kill();
|
||||||
|
@ -129,33 +132,28 @@ impl<'a> Iterator for Instructions<'a> {
|
||||||
|
|
||||||
let op_byte = self.data.as_slice().first();
|
let op_byte = self.data.as_slice().first();
|
||||||
match (self.enforce_minimal, op_byte, n) {
|
match (self.enforce_minimal, op_byte, n) {
|
||||||
(true, Some(&op_byte), 1) if op_byte == 0x81 || (op_byte > 0 && op_byte <= 16) => {
|
(true, Some(&op_byte), 1)
|
||||||
|
if op_byte == 0x81 || (op_byte > 0 && op_byte <= 16) =>
|
||||||
|
{
|
||||||
self.kill();
|
self.kill();
|
||||||
Some(Err(Error::NonMinimalPush))
|
Some(Err(Error::NonMinimalPush))
|
||||||
},
|
}
|
||||||
(_, None, 0) => {
|
(_, None, 0) => {
|
||||||
// the iterator is already empty, may as well use this information to avoid
|
// the iterator is already empty, may as well use this information to avoid
|
||||||
// whole take_slice_or_kill function
|
// whole take_slice_or_kill function
|
||||||
Some(Ok(Instruction::PushBytes(PushBytes::empty())))
|
Some(Ok(Instruction::PushBytes(PushBytes::empty())))
|
||||||
},
|
}
|
||||||
_ => {
|
_ => Some(self.take_slice_or_kill(n).map(Instruction::PushBytes)),
|
||||||
Some(self.take_slice_or_kill(n).map(Instruction::PushBytes))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) =>
|
||||||
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) => {
|
self.next_push_data_len(PushDataLenLen::One, 76),
|
||||||
self.next_push_data_len(PushDataLenLen::One, 76)
|
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) =>
|
||||||
}
|
self.next_push_data_len(PushDataLenLen::Two, 0x100),
|
||||||
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) => {
|
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) =>
|
||||||
self.next_push_data_len(PushDataLenLen::Two, 0x100)
|
self.next_push_data_len(PushDataLenLen::Four, 0x10000),
|
||||||
}
|
|
||||||
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => {
|
|
||||||
self.next_push_data_len(PushDataLenLen::Four, 0x10000)
|
|
||||||
}
|
|
||||||
// Everything else we can push right through
|
// Everything else we can push right through
|
||||||
_ => {
|
_ => Some(Ok(Instruction::Op(opcodes::All::from(byte)))),
|
||||||
Some(Ok(Instruction::Op(opcodes::All::from(byte))))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,27 +186,23 @@ impl<'a> InstructionIndices<'a> {
|
||||||
///
|
///
|
||||||
/// This is analogous to what [`core::str::Chars::as_str`] does.
|
/// This is analogous to what [`core::str::Chars::as_str`] does.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn as_script(&self) -> &'a Script {
|
pub fn as_script(&self) -> &'a Script { self.instructions.as_script() }
|
||||||
self.instructions.as_script()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates `Self` setting `pos` to 0.
|
/// Creates `Self` setting `pos` to 0.
|
||||||
pub(super) fn from_instructions(instructions: Instructions<'a>) -> Self {
|
pub(super) fn from_instructions(instructions: Instructions<'a>) -> Self {
|
||||||
InstructionIndices {
|
InstructionIndices { instructions, pos: 0 }
|
||||||
instructions,
|
|
||||||
pos: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn remaining_bytes(&self) -> usize {
|
pub(super) fn remaining_bytes(&self) -> usize { self.instructions.as_script().len() }
|
||||||
self.instructions.as_script().len()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Modifies the iterator using `next_fn` returning the next item.
|
/// Modifies the iterator using `next_fn` returning the next item.
|
||||||
///
|
///
|
||||||
/// This generically computes the new position and maps the value to be returned from iterator
|
/// This generically computes the new position and maps the value to be returned from iterator
|
||||||
/// method.
|
/// method.
|
||||||
pub(super) fn next_with<F: FnOnce(&mut Self) -> Option<Result<Instruction<'a>, Error>>>(&mut self, next_fn: F) -> Option<<Self as Iterator>::Item> {
|
pub(super) fn next_with<F: FnOnce(&mut Self) -> Option<Result<Instruction<'a>, Error>>>(
|
||||||
|
&mut self,
|
||||||
|
next_fn: F,
|
||||||
|
) -> Option<<Self as Iterator>::Item> {
|
||||||
let prev_remaining = self.remaining_bytes();
|
let prev_remaining = self.remaining_bytes();
|
||||||
let prev_pos = self.pos;
|
let prev_pos = self.pos;
|
||||||
let instruction = next_fn(self)?;
|
let instruction = next_fn(self)?;
|
||||||
|
@ -224,14 +218,10 @@ impl<'a> Iterator for InstructionIndices<'a> {
|
||||||
/// The `usize` in the tuple represents index at which the returned `Instruction` is located.
|
/// The `usize` in the tuple represents index at which the returned `Instruction` is located.
|
||||||
type Item = Result<(usize, Instruction<'a>), Error>;
|
type Item = Result<(usize, Instruction<'a>), Error>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> { self.next_with(|this| this.instructions.next()) }
|
||||||
self.next_with(|this| this.instructions.next())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) { self.instructions.size_hint() }
|
||||||
self.instructions.size_hint()
|
|
||||||
}
|
|
||||||
|
|
||||||
// the override avoids computing pos multiple times
|
// the override avoids computing pos multiple times
|
||||||
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
fn nth(&mut self, n: usize) -> Option<Self::Item> {
|
||||||
|
|
|
@ -51,28 +51,28 @@
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
#[cfg(any(not(rust_v_1_60), target_has_atomic = "ptr"))]
|
#[cfg(any(not(rust_v_1_60), target_has_atomic = "ptr"))]
|
||||||
use alloc::sync::Arc;
|
use alloc::sync::Arc;
|
||||||
|
|
||||||
use core::cmp::Ordering;
|
|
||||||
use core::borrow::{Borrow, BorrowMut};
|
use core::borrow::{Borrow, BorrowMut};
|
||||||
|
use core::cmp::Ordering;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde;
|
use serde;
|
||||||
|
|
||||||
use crate::blockdata::opcodes::{self, all::*};
|
use crate::blockdata::opcodes::all::*;
|
||||||
|
use crate::blockdata::opcodes::{self};
|
||||||
use crate::consensus::{encode, Decodable, Encodable};
|
use crate::consensus::{encode, Decodable, Encodable};
|
||||||
use crate::hash_types::{ScriptHash, WScriptHash};
|
use crate::hash_types::{ScriptHash, WScriptHash};
|
||||||
use crate::{io, OutPoint};
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::{io, OutPoint};
|
||||||
|
|
||||||
mod borrowed;
|
mod borrowed;
|
||||||
mod builder;
|
mod builder;
|
||||||
mod instruction;
|
mod instruction;
|
||||||
mod owned;
|
mod owned;
|
||||||
|
mod push_bytes;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
mod push_bytes;
|
|
||||||
|
|
||||||
pub use self::borrowed::*;
|
pub use self::borrowed::*;
|
||||||
pub use self::builder::*;
|
pub use self::builder::*;
|
||||||
|
@ -90,7 +90,9 @@ pub use self::push_bytes::*;
|
||||||
/// [`CScriptNum::serialize`]: <https://github.com/bitcoin/bitcoin/blob/8ae2808a4354e8dcc697f76bacc5e2f2befe9220/src/script/script.h#L345>
|
/// [`CScriptNum::serialize`]: <https://github.com/bitcoin/bitcoin/blob/8ae2808a4354e8dcc697f76bacc5e2f2befe9220/src/script/script.h#L345>
|
||||||
pub fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize {
|
pub fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
if n == 0 { return len; }
|
if n == 0 {
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
let neg = n < 0;
|
let neg = n < 0;
|
||||||
|
|
||||||
|
@ -136,7 +138,9 @@ pub fn write_scriptint(out: &mut [u8; 8], n: i64) -> usize {
|
||||||
/// This code is based on the `CScriptNum` constructor in Bitcoin Core (see `script.h`).
|
/// This code is based on the `CScriptNum` constructor in Bitcoin Core (see `script.h`).
|
||||||
pub fn read_scriptint(v: &[u8]) -> Result<i64, Error> {
|
pub fn read_scriptint(v: &[u8]) -> Result<i64, Error> {
|
||||||
let len = v.len();
|
let len = v.len();
|
||||||
if len > 4 { return Err(Error::NumericOverflow); }
|
if len > 4 {
|
||||||
|
return Err(Error::NumericOverflow);
|
||||||
|
}
|
||||||
let last = match v.last() {
|
let last = match v.last() {
|
||||||
Some(last) => last,
|
Some(last) => last,
|
||||||
None => return Ok(0),
|
None => return Ok(0),
|
||||||
|
@ -157,8 +161,7 @@ pub fn read_scriptint(v: &[u8]) -> Result<i64, Error> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut ret, sh) = v.iter()
|
let (mut ret, sh) = v.iter().fold((0, 0), |(acc, sh), n| (acc + ((*n as i64) << sh), sh + 8));
|
||||||
.fold((0, 0), |(acc, sh), n| (acc + ((*n as i64) << sh), sh + 8));
|
|
||||||
if v[len - 1] & 0x80 != 0 {
|
if v[len - 1] & 0x80 != 0 {
|
||||||
ret &= (1 << (sh - 1)) - 1;
|
ret &= (1 << (sh - 1)) - 1;
|
||||||
ret = -ret;
|
ret = -ret;
|
||||||
|
@ -219,29 +222,23 @@ fn read_uint_iter(data: &mut core::slice::Iter<'_, u8>, size: usize) -> Result<u
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opcode_to_verify(opcode: Option<opcodes::All>) -> Option<opcodes::All> {
|
fn opcode_to_verify(opcode: Option<opcodes::All>) -> Option<opcodes::All> {
|
||||||
opcode.and_then(|opcode| {
|
opcode.and_then(|opcode| match opcode {
|
||||||
match opcode {
|
|
||||||
OP_EQUAL => Some(OP_EQUALVERIFY),
|
OP_EQUAL => Some(OP_EQUALVERIFY),
|
||||||
OP_NUMEQUAL => Some(OP_NUMEQUALVERIFY),
|
OP_NUMEQUAL => Some(OP_NUMEQUALVERIFY),
|
||||||
OP_CHECKSIG => Some(OP_CHECKSIGVERIFY),
|
OP_CHECKSIG => Some(OP_CHECKSIGVERIFY),
|
||||||
OP_CHECKMULTISIG => Some(OP_CHECKMULTISIGVERIFY),
|
OP_CHECKMULTISIG => Some(OP_CHECKMULTISIGVERIFY),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// We keep all the `Script` and `ScriptBuf` impls together since its easier to see side-by-side.
|
// We keep all the `Script` and `ScriptBuf` impls together since its easier to see side-by-side.
|
||||||
|
|
||||||
impl From<ScriptBuf> for Box<Script> {
|
impl From<ScriptBuf> for Box<Script> {
|
||||||
fn from(v: ScriptBuf) -> Self {
|
fn from(v: ScriptBuf) -> Self { v.into_boxed_script() }
|
||||||
v.into_boxed_script()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ScriptBuf> for Cow<'_, Script> {
|
impl From<ScriptBuf> for Cow<'_, Script> {
|
||||||
fn from(value: ScriptBuf) -> Self {
|
fn from(value: ScriptBuf) -> Self { Cow::Owned(value) }
|
||||||
Cow::Owned(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<Cow<'a, Script>> for ScriptBuf {
|
impl<'a> From<Cow<'a, Script>> for ScriptBuf {
|
||||||
|
@ -263,21 +260,15 @@ impl<'a> From<Cow<'a, Script>> for Box<Script> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a Script> for Box<Script> {
|
impl<'a> From<&'a Script> for Box<Script> {
|
||||||
fn from(value: &'a Script) -> Self {
|
fn from(value: &'a Script) -> Self { value.to_owned().into() }
|
||||||
value.to_owned().into()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a Script> for ScriptBuf {
|
impl<'a> From<&'a Script> for ScriptBuf {
|
||||||
fn from(value: &'a Script) -> Self {
|
fn from(value: &'a Script) -> Self { value.to_owned() }
|
||||||
value.to_owned()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a Script> for Cow<'a, Script> {
|
impl<'a> From<&'a Script> for Cow<'a, Script> {
|
||||||
fn from(value: &'a Script) -> Self {
|
fn from(value: &'a Script) -> Self { Cow::Borrowed(value) }
|
||||||
Cow::Borrowed(value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note: This will fail to compile on old Rust for targets that don't support atomics
|
/// Note: This will fail to compile on old Rust for targets that don't support atomics
|
||||||
|
@ -314,90 +305,62 @@ impl From<ScriptBuf> for Vec<u8> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ScriptBuf> for ScriptHash {
|
impl From<ScriptBuf> for ScriptHash {
|
||||||
fn from(script: ScriptBuf) -> ScriptHash {
|
fn from(script: ScriptBuf) -> ScriptHash { script.script_hash() }
|
||||||
script.script_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&ScriptBuf> for ScriptHash {
|
impl From<&ScriptBuf> for ScriptHash {
|
||||||
fn from(script: &ScriptBuf) -> ScriptHash {
|
fn from(script: &ScriptBuf) -> ScriptHash { script.script_hash() }
|
||||||
script.script_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Script> for ScriptHash {
|
impl From<&Script> for ScriptHash {
|
||||||
fn from(script: &Script) -> ScriptHash {
|
fn from(script: &Script) -> ScriptHash { script.script_hash() }
|
||||||
script.script_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ScriptBuf> for WScriptHash {
|
impl From<ScriptBuf> for WScriptHash {
|
||||||
fn from(script: ScriptBuf) -> WScriptHash {
|
fn from(script: ScriptBuf) -> WScriptHash { script.wscript_hash() }
|
||||||
script.wscript_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&ScriptBuf> for WScriptHash {
|
impl From<&ScriptBuf> for WScriptHash {
|
||||||
fn from(script: &ScriptBuf) -> WScriptHash {
|
fn from(script: &ScriptBuf) -> WScriptHash { script.wscript_hash() }
|
||||||
script.wscript_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Script> for WScriptHash {
|
impl From<&Script> for WScriptHash {
|
||||||
fn from(script: &Script) -> WScriptHash {
|
fn from(script: &Script) -> WScriptHash { script.wscript_hash() }
|
||||||
script.wscript_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<Script> for Script {
|
impl AsRef<Script> for Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_ref(&self) -> &Script {
|
fn as_ref(&self) -> &Script { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<Script> for ScriptBuf {
|
impl AsRef<Script> for ScriptBuf {
|
||||||
fn as_ref(&self) -> &Script {
|
fn as_ref(&self) -> &Script { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<[u8]> for Script {
|
impl AsRef<[u8]> for Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] { self.as_bytes() }
|
||||||
self.as_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<[u8]> for ScriptBuf {
|
impl AsRef<[u8]> for ScriptBuf {
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] { self.as_bytes() }
|
||||||
self.as_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<Script> for Script {
|
impl AsMut<Script> for Script {
|
||||||
fn as_mut(&mut self) -> &mut Script {
|
fn as_mut(&mut self) -> &mut Script { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<Script> for ScriptBuf {
|
impl AsMut<Script> for ScriptBuf {
|
||||||
fn as_mut(&mut self) -> &mut Script {
|
fn as_mut(&mut self) -> &mut Script { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<[u8]> for Script {
|
impl AsMut<[u8]> for Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_mut(&mut self) -> &mut [u8] {
|
fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
|
||||||
self.as_mut_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<[u8]> for ScriptBuf {
|
impl AsMut<[u8]> for ScriptBuf {
|
||||||
fn as_mut(&mut self) -> &mut [u8] {
|
fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
|
||||||
self.as_mut_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Script {
|
impl fmt::Debug for Script {
|
||||||
|
@ -409,23 +372,17 @@ impl fmt::Debug for Script {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ScriptBuf {
|
impl fmt::Debug for ScriptBuf {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self.as_script(), f) }
|
||||||
fmt::Debug::fmt(self.as_script(), f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Script {
|
impl fmt::Display for Script {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_asm(f) }
|
||||||
self.fmt_asm(f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ScriptBuf {
|
impl fmt::Display for ScriptBuf {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(self.as_script(), f) }
|
||||||
fmt::Display::fmt(self.as_script(), f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::LowerHex for Script {
|
impl fmt::LowerHex for Script {
|
||||||
|
@ -436,9 +393,7 @@ impl fmt::LowerHex for Script {
|
||||||
|
|
||||||
impl fmt::LowerHex for ScriptBuf {
|
impl fmt::LowerHex for ScriptBuf {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self.as_script(), f) }
|
||||||
fmt::LowerHex::fmt(self.as_script(), f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::UpperHex for Script {
|
impl fmt::UpperHex for Script {
|
||||||
|
@ -449,47 +404,33 @@ impl fmt::UpperHex for Script {
|
||||||
|
|
||||||
impl fmt::UpperHex for ScriptBuf {
|
impl fmt::UpperHex for ScriptBuf {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::UpperHex::fmt(self.as_script(), f) }
|
||||||
fmt::UpperHex::fmt(self.as_script(), f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for ScriptBuf {
|
impl Deref for ScriptBuf {
|
||||||
type Target = Script;
|
type Target = Script;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target { Script::from_bytes(&self.0) }
|
||||||
Script::from_bytes(&self.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for ScriptBuf {
|
impl DerefMut for ScriptBuf {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target { Script::from_bytes_mut(&mut self.0) }
|
||||||
Script::from_bytes_mut(&mut self.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Borrow<Script> for ScriptBuf {
|
impl Borrow<Script> for ScriptBuf {
|
||||||
fn borrow(&self) -> &Script {
|
fn borrow(&self) -> &Script { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BorrowMut<Script> for ScriptBuf {
|
impl BorrowMut<Script> for ScriptBuf {
|
||||||
fn borrow_mut(&mut self) -> &mut Script {
|
fn borrow_mut(&mut self) -> &mut Script { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<ScriptBuf> for Script {
|
impl PartialEq<ScriptBuf> for Script {
|
||||||
fn eq(&self, other: &ScriptBuf) -> bool {
|
fn eq(&self, other: &ScriptBuf) -> bool { self.eq(other.as_script()) }
|
||||||
self.eq(other.as_script())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq<Script> for ScriptBuf {
|
impl PartialEq<Script> for ScriptBuf {
|
||||||
fn eq(&self, other: &Script) -> bool {
|
fn eq(&self, other: &Script) -> bool { self.as_script().eq(other) }
|
||||||
self.as_script().eq(other)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd<Script> for ScriptBuf {
|
impl PartialOrd<Script> for ScriptBuf {
|
||||||
|
@ -531,7 +472,9 @@ impl<'de> serde::Deserialize<'de> for &'de Script {
|
||||||
if deserializer.is_human_readable() {
|
if deserializer.is_human_readable() {
|
||||||
use crate::serde::de::Error;
|
use crate::serde::de::Error;
|
||||||
|
|
||||||
return Err(D::Error::custom("deserialization of `&Script` from human-readable formats is not possible"));
|
return Err(D::Error::custom(
|
||||||
|
"deserialization of `&Script` from human-readable formats is not possible",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Visitor;
|
struct Visitor;
|
||||||
|
@ -573,10 +516,10 @@ impl<'de> serde::Deserialize<'de> for ScriptBuf {
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
use core::fmt::Formatter;
|
use core::fmt::Formatter;
|
||||||
|
|
||||||
use crate::hashes::hex::FromHex;
|
use crate::hashes::hex::FromHex;
|
||||||
|
|
||||||
if deserializer.is_human_readable() {
|
if deserializer.is_human_readable() {
|
||||||
|
|
||||||
struct Visitor;
|
struct Visitor;
|
||||||
impl<'de> serde::de::Visitor<'de> for Visitor {
|
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||||
type Value = ScriptBuf;
|
type Value = ScriptBuf;
|
||||||
|
@ -639,7 +582,9 @@ impl Encodable for ScriptBuf {
|
||||||
|
|
||||||
impl Decodable for ScriptBuf {
|
impl Decodable for ScriptBuf {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(
|
||||||
|
r: &mut R,
|
||||||
|
) -> Result<Self, encode::Error> {
|
||||||
Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?))
|
Ok(ScriptBuf(Decodable::consensus_decode_from_finite_reader(r)?))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -677,7 +622,9 @@ pub(super) fn bytes_to_asm_fmt(script: &[u8], f: &mut dyn fmt::Write) -> fmt::Re
|
||||||
while let Some(byte) = iter.next() {
|
while let Some(byte) = iter.next() {
|
||||||
let opcode = opcodes::All::from(*byte);
|
let opcode = opcodes::All::from(*byte);
|
||||||
|
|
||||||
let data_len = if let opcodes::Class::PushBytes(n) = opcode.classify(opcodes::ClassifyContext::Legacy) {
|
let data_len = if let opcodes::Class::PushBytes(n) =
|
||||||
|
opcode.classify(opcodes::ClassifyContext::Legacy)
|
||||||
|
{
|
||||||
n as usize
|
n as usize
|
||||||
} else {
|
} else {
|
||||||
match opcode {
|
match opcode {
|
||||||
|
@ -693,7 +640,7 @@ pub(super) fn bytes_to_asm_fmt(script: &[u8], f: &mut dyn fmt::Write) -> fmt::Re
|
||||||
// side effects: may write and break from the loop
|
// side effects: may write and break from the loop
|
||||||
read_push_data_len!(&mut iter, 4, f)
|
read_push_data_len!(&mut iter, 4, f)
|
||||||
}
|
}
|
||||||
_ => 0
|
_ => 0,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -744,7 +691,7 @@ pub enum Error {
|
||||||
/// Can not find the spent output.
|
/// Can not find the spent output.
|
||||||
UnknownSpentOutput(OutPoint),
|
UnknownSpentOutput(OutPoint),
|
||||||
/// Can not serialize the spending transaction.
|
/// Can not serialize the spending transaction.
|
||||||
Serialization
|
Serialization,
|
||||||
}
|
}
|
||||||
|
|
||||||
// If bitcoinonsensus-std is off but bitcoinconsensus is present we patch the error type to
|
// If bitcoinonsensus-std is off but bitcoinconsensus is present we patch the error type to
|
||||||
|
@ -757,15 +704,11 @@ mod bitcoinconsensus_hack {
|
||||||
pub(crate) struct Error(bitcoinconsensus::Error);
|
pub(crate) struct Error(bitcoinconsensus::Error);
|
||||||
|
|
||||||
impl fmt::Debug for Error {
|
impl fmt::Debug for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.0, f) }
|
||||||
fmt::Debug::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
|
||||||
fmt::Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// bitcoinconsensus::Error has no sources at this time
|
// bitcoinconsensus::Error has no sources at this time
|
||||||
|
@ -775,13 +718,15 @@ mod bitcoinconsensus_hack {
|
||||||
// Unfortunately, we cannot have the reference inside `Error` struct because of the 'static
|
// Unfortunately, we cannot have the reference inside `Error` struct because of the 'static
|
||||||
// bound on `source` return type, so we have to use unsafe to overcome the limitation.
|
// bound on `source` return type, so we have to use unsafe to overcome the limitation.
|
||||||
// SAFETY: the type is repr(transparent) and the lifetimes match
|
// SAFETY: the type is repr(transparent) and the lifetimes match
|
||||||
unsafe {
|
unsafe { &*(error as *const _ as *const Error) }
|
||||||
&*(error as *const _ as *const Error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(all(feature = "std", feature = "bitcoinconsensus", not(feature = "bitcoinconsensus-std"))))]
|
#[cfg(not(all(
|
||||||
|
feature = "std",
|
||||||
|
feature = "bitcoinconsensus",
|
||||||
|
not(feature = "bitcoinconsensus-std")
|
||||||
|
)))]
|
||||||
mod bitcoinconsensus_hack {
|
mod bitcoinconsensus_hack {
|
||||||
#[allow(unused_imports)] // conditionally used
|
#[allow(unused_imports)] // conditionally used
|
||||||
pub(crate) use core::convert::identity as wrap_error;
|
pub(crate) use core::convert::identity as wrap_error;
|
||||||
|
@ -795,11 +740,14 @@ impl fmt::Display for Error {
|
||||||
match *self {
|
match *self {
|
||||||
Error::NonMinimalPush => f.write_str("non-minimal datapush"),
|
Error::NonMinimalPush => f.write_str("non-minimal datapush"),
|
||||||
Error::EarlyEndOfScript => f.write_str("unexpected end of script"),
|
Error::EarlyEndOfScript => f.write_str("unexpected end of script"),
|
||||||
Error::NumericOverflow => f.write_str("numeric overflow (number on stack larger than 4 bytes)"),
|
Error::NumericOverflow =>
|
||||||
|
f.write_str("numeric overflow (number on stack larger than 4 bytes)"),
|
||||||
#[cfg(feature = "bitcoinconsensus")]
|
#[cfg(feature = "bitcoinconsensus")]
|
||||||
Error::BitcoinConsensus(ref e) => write_err!(f, "bitcoinconsensus verification failed"; bitcoinconsensus_hack::wrap_error(e)),
|
Error::BitcoinConsensus(ref e) =>
|
||||||
|
write_err!(f, "bitcoinconsensus verification failed"; bitcoinconsensus_hack::wrap_error(e)),
|
||||||
Error::UnknownSpentOutput(ref point) => write!(f, "unknown spent output: {}", point),
|
Error::UnknownSpentOutput(ref point) => write!(f, "unknown spent output: {}", point),
|
||||||
Error::Serialization => f.write_str("can not serialize the spending transaction in Transaction::verify()"),
|
Error::Serialization =>
|
||||||
|
f.write_str("can not serialize the spending transaction in Transaction::verify()"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -841,7 +789,5 @@ impl From<UintError> for Error {
|
||||||
#[cfg(feature = "bitcoinconsensus")]
|
#[cfg(feature = "bitcoinconsensus")]
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
impl From<bitcoinconsensus::Error> for Error {
|
impl From<bitcoinconsensus::Error> for Error {
|
||||||
fn from(err: bitcoinconsensus::Error) -> Error {
|
fn from(err: bitcoinconsensus::Error) -> Error { Error::BitcoinConsensus(err) }
|
||||||
Error::BitcoinConsensus(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,12 @@ use core::ops::Deref;
|
||||||
|
|
||||||
use secp256k1::{Secp256k1, Verification};
|
use secp256k1::{Secp256k1, Verification};
|
||||||
|
|
||||||
use crate::address::{WitnessVersion, WitnessProgram};
|
use crate::address::{WitnessProgram, WitnessVersion};
|
||||||
use crate::blockdata::opcodes::{self, all::*};
|
use crate::blockdata::opcodes::all::*;
|
||||||
use crate::blockdata::script::{opcode_to_verify, Builder, Instruction, Script, PushBytes};
|
use crate::blockdata::opcodes::{self};
|
||||||
|
use crate::blockdata::script::{opcode_to_verify, Builder, Instruction, PushBytes, Script};
|
||||||
|
use crate::hash_types::{PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash};
|
||||||
use crate::hashes::hex;
|
use crate::hashes::hex;
|
||||||
use crate::hash_types::{PubkeyHash, WPubkeyHash, ScriptHash, WScriptHash};
|
|
||||||
use crate::key::{PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey};
|
use crate::key::{PublicKey, TapTweak, TweakedPublicKey, UntweakedPublicKey};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::taproot::TapNodeHash;
|
use crate::taproot::TapNodeHash;
|
||||||
|
@ -29,14 +30,10 @@ pub struct ScriptBuf(pub(in crate::blockdata::script) Vec<u8>);
|
||||||
|
|
||||||
impl ScriptBuf {
|
impl ScriptBuf {
|
||||||
/// Creates a new empty script.
|
/// Creates a new empty script.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { ScriptBuf(Vec::new()) }
|
||||||
ScriptBuf(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new empty script with pre-allocated capacity.
|
/// Creates a new empty script with pre-allocated capacity.
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self { ScriptBuf(Vec::with_capacity(capacity)) }
|
||||||
ScriptBuf(Vec::with_capacity(capacity))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pre-allocates at least `additional_len` bytes if needed.
|
/// Pre-allocates at least `additional_len` bytes if needed.
|
||||||
///
|
///
|
||||||
|
@ -48,9 +45,7 @@ impl ScriptBuf {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the new capacity exceeds `isize::MAX bytes`.
|
/// Panics if the new capacity exceeds `isize::MAX bytes`.
|
||||||
pub fn reserve(&mut self, additional_len: usize) {
|
pub fn reserve(&mut self, additional_len: usize) { self.0.reserve(additional_len); }
|
||||||
self.0.reserve(additional_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Pre-allocates exactly `additional_len` bytes if needed.
|
/// Pre-allocates exactly `additional_len` bytes if needed.
|
||||||
///
|
///
|
||||||
|
@ -65,31 +60,20 @@ impl ScriptBuf {
|
||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the new capacity exceeds `isize::MAX bytes`.
|
/// Panics if the new capacity exceeds `isize::MAX bytes`.
|
||||||
pub fn reserve_exact(&mut self, additional_len: usize) {
|
pub fn reserve_exact(&mut self, additional_len: usize) { self.0.reserve_exact(additional_len); }
|
||||||
self.0.reserve_exact(additional_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference to unsized script.
|
/// Returns a reference to unsized script.
|
||||||
pub fn as_script(&self) -> &Script {
|
pub fn as_script(&self) -> &Script { Script::from_bytes(&self.0) }
|
||||||
Script::from_bytes(&self.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a mutable reference to unsized script.
|
/// Returns a mutable reference to unsized script.
|
||||||
pub fn as_mut_script(&mut self) -> &mut Script {
|
pub fn as_mut_script(&mut self) -> &mut Script { Script::from_bytes_mut(&mut self.0) }
|
||||||
Script::from_bytes_mut(&mut self.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new script builder
|
/// Creates a new script builder
|
||||||
pub fn builder() -> Builder {
|
pub fn builder() -> Builder { Builder::new() }
|
||||||
Builder::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generates P2PK-type of scriptPubkey.
|
/// Generates P2PK-type of scriptPubkey.
|
||||||
pub fn new_p2pk(pubkey: &PublicKey) -> Self {
|
pub fn new_p2pk(pubkey: &PublicKey) -> Self {
|
||||||
Builder::new()
|
Builder::new().push_key(pubkey).push_opcode(OP_CHECKSIG).into_script()
|
||||||
.push_key(pubkey)
|
|
||||||
.push_opcode(OP_CHECKSIG)
|
|
||||||
.into_script()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates P2PKH-type of scriptPubkey.
|
/// Generates P2PKH-type of scriptPubkey.
|
||||||
|
@ -126,7 +110,11 @@ impl ScriptBuf {
|
||||||
|
|
||||||
/// Generates P2TR for script spending path using an internal public key and some optional
|
/// Generates P2TR for script spending path using an internal public key and some optional
|
||||||
/// script tree merkle root.
|
/// script tree merkle root.
|
||||||
pub fn new_v1_p2tr<C: Verification>(secp: &Secp256k1<C>, internal_key: UntweakedPublicKey, merkle_root: Option<TapNodeHash>) -> Self {
|
pub fn new_v1_p2tr<C: Verification>(
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
internal_key: UntweakedPublicKey,
|
||||||
|
merkle_root: Option<TapNodeHash>,
|
||||||
|
) -> Self {
|
||||||
let (output_key, _) = internal_key.tap_tweak(secp, merkle_root);
|
let (output_key, _) = internal_key.tap_tweak(secp, merkle_root);
|
||||||
// output key is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv1)
|
// output key is 32 bytes long, so it's safe to use `new_witness_program_unchecked` (Segwitv1)
|
||||||
ScriptBuf::new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize())
|
ScriptBuf::new_witness_program_unchecked(WitnessVersion::V1, output_key.serialize())
|
||||||
|
@ -151,23 +139,20 @@ impl ScriptBuf {
|
||||||
///
|
///
|
||||||
/// Convenience method used by `new_v0_p2wpkh`, `new_v0_p2wsh`, `new_v1_p2tr`, and
|
/// Convenience method used by `new_v0_p2wpkh`, `new_v0_p2wsh`, `new_v1_p2tr`, and
|
||||||
/// `new_v1_p2tr_tweaked`.
|
/// `new_v1_p2tr_tweaked`.
|
||||||
fn new_witness_program_unchecked<T: AsRef<PushBytes>>(version: WitnessVersion, program: T) -> Self {
|
fn new_witness_program_unchecked<T: AsRef<PushBytes>>(
|
||||||
|
version: WitnessVersion,
|
||||||
|
program: T,
|
||||||
|
) -> Self {
|
||||||
let program = program.as_ref();
|
let program = program.as_ref();
|
||||||
debug_assert!(program.len() >= 2 && program.len() <= 40);
|
debug_assert!(program.len() >= 2 && program.len() <= 40);
|
||||||
// In segwit v0, the program must be 20 or 32 bytes long.
|
// In segwit v0, the program must be 20 or 32 bytes long.
|
||||||
debug_assert!(version != WitnessVersion::V0 || program.len() == 20 || program.len() == 32);
|
debug_assert!(version != WitnessVersion::V0 || program.len() == 20 || program.len() == 32);
|
||||||
Builder::new()
|
Builder::new().push_opcode(version.into()).push_slice(program).into_script()
|
||||||
.push_opcode(version.into())
|
|
||||||
.push_slice(program)
|
|
||||||
.into_script()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates OP_RETURN-type of scriptPubkey for the given data.
|
/// Generates OP_RETURN-type of scriptPubkey for the given data.
|
||||||
pub fn new_op_return<T: AsRef<PushBytes>>(data: &T) -> Self {
|
pub fn new_op_return<T: AsRef<PushBytes>>(data: &T) -> Self {
|
||||||
Builder::new()
|
Builder::new().push_opcode(OP_RETURN).push_slice(data).into_script()
|
||||||
.push_opcode(OP_RETURN)
|
|
||||||
.push_slice(data)
|
|
||||||
.into_script()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a [`ScriptBuf`] from a hex string.
|
/// Creates a [`ScriptBuf`] from a hex string.
|
||||||
|
@ -181,9 +166,7 @@ impl ScriptBuf {
|
||||||
/// Converts byte vector into script.
|
/// Converts byte vector into script.
|
||||||
///
|
///
|
||||||
/// This method doesn't (re)allocate.
|
/// This method doesn't (re)allocate.
|
||||||
pub fn from_bytes(bytes: Vec<u8>) -> Self {
|
pub fn from_bytes(bytes: Vec<u8>) -> Self { ScriptBuf(bytes) }
|
||||||
ScriptBuf(bytes)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts the script into a byte vector.
|
/// Converts the script into a byte vector.
|
||||||
///
|
///
|
||||||
|
@ -191,9 +174,7 @@ impl ScriptBuf {
|
||||||
pub fn into_bytes(self) -> Vec<u8> { self.0 }
|
pub fn into_bytes(self) -> Vec<u8> { self.0 }
|
||||||
|
|
||||||
/// Computes the P2SH output corresponding to this redeem script.
|
/// Computes the P2SH output corresponding to this redeem script.
|
||||||
pub fn to_p2sh(&self) -> ScriptBuf {
|
pub fn to_p2sh(&self) -> ScriptBuf { ScriptBuf::new_p2sh(&self.script_hash()) }
|
||||||
ScriptBuf::new_p2sh(&self.script_hash())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the script code used for spending a P2WPKH output if this script is a script pubkey
|
/// Returns the script code used for spending a P2WPKH output if this script is a script pubkey
|
||||||
/// for a P2WPKH output. The `scriptCode` is described in [BIP143].
|
/// for a P2WPKH output. The `scriptCode` is described in [BIP143].
|
||||||
|
@ -213,9 +194,7 @@ impl ScriptBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a single opcode to the script.
|
/// Adds a single opcode to the script.
|
||||||
pub fn push_opcode(&mut self, data: opcodes::All) {
|
pub fn push_opcode(&mut self, data: opcodes::All) { self.0.push(data.to_u8()); }
|
||||||
self.0.push(data.to_u8());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds instructions to push some arbitrary data onto the stack.
|
/// Adds instructions to push some arbitrary data onto the stack.
|
||||||
pub fn push_slice<T: AsRef<PushBytes>>(&mut self, data: T) {
|
pub fn push_slice<T: AsRef<PushBytes>>(&mut self, data: T) {
|
||||||
|
@ -228,16 +207,18 @@ impl ScriptBuf {
|
||||||
fn push_slice_no_opt(&mut self, data: &PushBytes) {
|
fn push_slice_no_opt(&mut self, data: &PushBytes) {
|
||||||
// Start with a PUSH opcode
|
// Start with a PUSH opcode
|
||||||
match data.len() as u64 {
|
match data.len() as u64 {
|
||||||
n if n < opcodes::Ordinary::OP_PUSHDATA1 as u64 => { self.0.push(n as u8); },
|
n if n < opcodes::Ordinary::OP_PUSHDATA1 as u64 => {
|
||||||
|
self.0.push(n as u8);
|
||||||
|
}
|
||||||
n if n < 0x100 => {
|
n if n < 0x100 => {
|
||||||
self.0.push(opcodes::Ordinary::OP_PUSHDATA1.to_u8());
|
self.0.push(opcodes::Ordinary::OP_PUSHDATA1.to_u8());
|
||||||
self.0.push(n as u8);
|
self.0.push(n as u8);
|
||||||
},
|
}
|
||||||
n if n < 0x10000 => {
|
n if n < 0x10000 => {
|
||||||
self.0.push(opcodes::Ordinary::OP_PUSHDATA2.to_u8());
|
self.0.push(opcodes::Ordinary::OP_PUSHDATA2.to_u8());
|
||||||
self.0.push((n % 0x100) as u8);
|
self.0.push((n % 0x100) as u8);
|
||||||
self.0.push((n / 0x100) as u8);
|
self.0.push((n / 0x100) as u8);
|
||||||
},
|
}
|
||||||
n if n < 0x100000000 => {
|
n if n < 0x100000000 => {
|
||||||
self.0.push(opcodes::Ordinary::OP_PUSHDATA4.to_u8());
|
self.0.push(opcodes::Ordinary::OP_PUSHDATA4.to_u8());
|
||||||
self.0.push((n % 0x100) as u8);
|
self.0.push((n % 0x100) as u8);
|
||||||
|
@ -245,7 +226,7 @@ impl ScriptBuf {
|
||||||
self.0.push(((n / 0x10000) % 0x100) as u8);
|
self.0.push(((n / 0x10000) % 0x100) as u8);
|
||||||
self.0.push((n / 0x1000000) as u8);
|
self.0.push((n / 0x1000000) as u8);
|
||||||
}
|
}
|
||||||
_ => panic!("tried to put a 4bn+ sized object into a script!")
|
_ => panic!("tried to put a 4bn+ sized object into a script!"),
|
||||||
}
|
}
|
||||||
// Then push the raw bytes
|
// Then push the raw bytes
|
||||||
self.0.extend_from_slice(data.as_bytes());
|
self.0.extend_from_slice(data.as_bytes());
|
||||||
|
@ -297,9 +278,7 @@ impl ScriptBuf {
|
||||||
/// This function needs to iterate over the script to find the last instruction. Prefer
|
/// This function needs to iterate over the script to find the last instruction. Prefer
|
||||||
/// `Builder` if you're creating the script from scratch or if you want to push `OP_VERIFY`
|
/// `Builder` if you're creating the script from scratch or if you want to push `OP_VERIFY`
|
||||||
/// multiple times.
|
/// multiple times.
|
||||||
pub fn scan_and_push_verify(&mut self) {
|
pub fn scan_and_push_verify(&mut self) { self.push_verify(self.last_opcode()); }
|
||||||
self.push_verify(self.last_opcode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Adds an `OP_VERIFY` to the script or changes the most-recently-added opcode to `VERIFY`
|
/// Adds an `OP_VERIFY` to the script or changes the most-recently-added opcode to `VERIFY`
|
||||||
/// alternative.
|
/// alternative.
|
||||||
|
@ -310,7 +289,7 @@ impl ScriptBuf {
|
||||||
Some(opcode) => {
|
Some(opcode) => {
|
||||||
self.0.pop();
|
self.0.pop();
|
||||||
self.push_opcode(opcode);
|
self.push_opcode(opcode);
|
||||||
},
|
}
|
||||||
None => self.push_opcode(OP_VERIFY),
|
None => self.push_opcode(OP_VERIFY),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,7 +310,10 @@ impl ScriptBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> core::iter::FromIterator<Instruction<'a>> for ScriptBuf {
|
impl<'a> core::iter::FromIterator<Instruction<'a>> for ScriptBuf {
|
||||||
fn from_iter<T>(iter: T) -> Self where T: IntoIterator<Item = Instruction<'a>> {
|
fn from_iter<T>(iter: T) -> Self
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = Instruction<'a>>,
|
||||||
|
{
|
||||||
let mut script = ScriptBuf::new();
|
let mut script = ScriptBuf::new();
|
||||||
script.extend(iter);
|
script.extend(iter);
|
||||||
script
|
script
|
||||||
|
@ -339,7 +321,10 @@ impl<'a> core::iter::FromIterator<Instruction<'a>> for ScriptBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Extend<Instruction<'a>> for ScriptBuf {
|
impl<'a> Extend<Instruction<'a>> for ScriptBuf {
|
||||||
fn extend<T>(&mut self, iter: T) where T: IntoIterator<Item = Instruction<'a>> {
|
fn extend<T>(&mut self, iter: T)
|
||||||
|
where
|
||||||
|
T: IntoIterator<Item = Instruction<'a>>,
|
||||||
|
{
|
||||||
let iter = iter.into_iter();
|
let iter = iter.into_iter();
|
||||||
// Most of Bitcoin scripts have only a few opcodes, so we can avoid reallocations in many
|
// Most of Bitcoin scripts have only a few opcodes, so we can avoid reallocations in many
|
||||||
// cases.
|
// cases.
|
||||||
|
@ -354,7 +339,11 @@ impl<'a> Extend<Instruction<'a>> for ScriptBuf {
|
||||||
*head = Some(instr);
|
*head = Some(instr);
|
||||||
}
|
}
|
||||||
// Incorrect impl of `size_hint` breaks `Iterator` contract so we're free to panic.
|
// Incorrect impl of `size_hint` breaks `Iterator` contract so we're free to panic.
|
||||||
assert!(iter.next().is_none(), "Buggy implementation of `Iterator` on {} returns invalid upper bound", core::any::type_name::<T::IntoIter>());
|
assert!(
|
||||||
|
iter.next().is_none(),
|
||||||
|
"Buggy implementation of `Iterator` on {} returns invalid upper bound",
|
||||||
|
core::any::type_name::<T::IntoIter>()
|
||||||
|
);
|
||||||
self.reserve(total_size);
|
self.reserve(total_size);
|
||||||
for instr in head.iter().cloned().flatten() {
|
for instr in head.iter().cloned().flatten() {
|
||||||
self.push_instruction_no_opt(instr);
|
self.push_instruction_no_opt(instr);
|
||||||
|
|
|
@ -1,28 +1,29 @@
|
||||||
//! Contains `PushBytes` & co
|
//! Contains `PushBytes` & co
|
||||||
|
|
||||||
use core::ops::{Deref, DerefMut};
|
|
||||||
use core::borrow::{Borrow, BorrowMut};
|
use core::borrow::{Borrow, BorrowMut};
|
||||||
#[allow(unused)]
|
use core::ops::{Deref, DerefMut};
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
pub use primitive::*;
|
pub use primitive::*;
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
|
use crate::prelude::*;
|
||||||
|
|
||||||
/// This module only contains required operations so that outside functions wouldn't accidentally
|
/// This module only contains required operations so that outside functions wouldn't accidentally
|
||||||
/// break invariants. Therefore auditing this module should be sufficient.
|
/// break invariants. Therefore auditing this module should be sufficient.
|
||||||
mod primitive {
|
mod primitive {
|
||||||
|
use core::convert::{TryFrom, TryInto};
|
||||||
|
#[cfg(feature = "rust_v_1_53")]
|
||||||
|
use core::ops::Bound;
|
||||||
|
use core::ops::{
|
||||||
|
Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::PushBytesError;
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use super::PushBytesError;
|
|
||||||
use core::convert::{TryFrom, TryInto};
|
|
||||||
use core::ops::{Index, Range, RangeFull, RangeFrom, RangeTo, RangeInclusive, RangeToInclusive};
|
|
||||||
#[cfg(feature = "rust_v_1_53")]
|
|
||||||
use core::ops::Bound;
|
|
||||||
|
|
||||||
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
|
#[cfg(any(target_pointer_width = "16", target_pointer_width = "32"))]
|
||||||
fn check_limit(len: usize) -> Result<(), PushBytesError> {
|
fn check_limit(len: usize) -> Result<(), PushBytesError> { Ok(()) }
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(any(target_pointer_width = "16", target_pointer_width = "32")))]
|
#[cfg(not(any(target_pointer_width = "16", target_pointer_width = "32")))]
|
||||||
fn check_limit(len: usize) -> Result<(), PushBytesError> {
|
fn check_limit(len: usize) -> Result<(), PushBytesError> {
|
||||||
|
@ -68,14 +69,10 @@ mod primitive {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying bytes.
|
/// Returns the underlying bytes.
|
||||||
pub fn as_bytes(&self) -> &[u8] {
|
pub fn as_bytes(&self) -> &[u8] { &self.0 }
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the underlying mutbale bytes.
|
/// Returns the underlying mutbale bytes.
|
||||||
pub fn as_mut_bytes(&mut self) -> &mut [u8] {
|
pub fn as_mut_bytes(&mut self) -> &mut [u8] { &mut self.0 }
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! delegate_index {
|
macro_rules! delegate_index {
|
||||||
|
@ -98,7 +95,14 @@ mod primitive {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate_index!(Range<usize>, RangeFrom<usize>, RangeTo<usize>, RangeFull, RangeInclusive<usize>, RangeToInclusive<usize>);
|
delegate_index!(
|
||||||
|
Range<usize>,
|
||||||
|
RangeFrom<usize>,
|
||||||
|
RangeTo<usize>,
|
||||||
|
RangeFull,
|
||||||
|
RangeInclusive<usize>,
|
||||||
|
RangeToInclusive<usize>
|
||||||
|
);
|
||||||
#[cfg(feature = "rust_v_1_53")]
|
#[cfg(feature = "rust_v_1_53")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "rust_v_1_53")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "rust_v_1_53")))]
|
||||||
delegate_index!((Bound<usize>, Bound<usize>));
|
delegate_index!((Bound<usize>, Bound<usize>));
|
||||||
|
@ -108,9 +112,7 @@ mod primitive {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[cfg_attr(rust_v_1_46, track_caller)]
|
#[cfg_attr(rust_v_1_46, track_caller)]
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
fn index(&self, index: usize) -> &Self::Output { &self.0[index] }
|
||||||
&self.0[index]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> TryFrom<&'a [u8]> for &'a PushBytes {
|
impl<'a> TryFrom<&'a [u8]> for &'a PushBytes {
|
||||||
|
@ -194,14 +196,10 @@ mod primitive {
|
||||||
|
|
||||||
impl PushBytesBuf {
|
impl PushBytesBuf {
|
||||||
/// Creates a new empty `PushBytesBuf`.
|
/// Creates a new empty `PushBytesBuf`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { PushBytesBuf(Vec::new()) }
|
||||||
PushBytesBuf(Vec::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new empty `PushBytesBuf` with reserved capacity.
|
/// Creates a new empty `PushBytesBuf` with reserved capacity.
|
||||||
pub fn with_capacity(capacity: usize) -> Self {
|
pub fn with_capacity(capacity: usize) -> Self { PushBytesBuf(Vec::with_capacity(capacity)) }
|
||||||
PushBytesBuf(Vec::with_capacity(capacity))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reserve capacity for `additional_capacity` bytes.
|
/// Reserve capacity for `additional_capacity` bytes.
|
||||||
pub fn reserve(&mut self, additional_capacity: usize) {
|
pub fn reserve(&mut self, additional_capacity: usize) {
|
||||||
|
@ -234,9 +232,7 @@ mod primitive {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove the last byte from buffer if any.
|
/// Remove the last byte from buffer if any.
|
||||||
pub fn pop(&mut self) -> Option<u8> {
|
pub fn pop(&mut self) -> Option<u8> { self.0.pop() }
|
||||||
self.0.pop()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove the byte at `index` and return it.
|
/// Remove the byte at `index` and return it.
|
||||||
///
|
///
|
||||||
|
@ -244,19 +240,13 @@ mod primitive {
|
||||||
///
|
///
|
||||||
/// This method panics if `index` is out of bounds.
|
/// This method panics if `index` is out of bounds.
|
||||||
#[cfg_attr(rust_v_1_46, track_caller)]
|
#[cfg_attr(rust_v_1_46, track_caller)]
|
||||||
pub fn remove(&mut self, index: usize) -> u8 {
|
pub fn remove(&mut self, index: usize) -> u8 { self.0.remove(index) }
|
||||||
self.0.remove(index)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove all bytes from buffer without affecting capacity.
|
/// Remove all bytes from buffer without affecting capacity.
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) { self.0.clear() }
|
||||||
self.0.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove bytes from buffer past `len`.
|
/// Remove bytes from buffer past `len`.
|
||||||
pub fn truncate(&mut self, len: usize) {
|
pub fn truncate(&mut self, len: usize) { self.0.truncate(len) }
|
||||||
self.0.truncate(len)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extracts `PushBytes` slice
|
/// Extracts `PushBytes` slice
|
||||||
pub fn as_push_bytes(&self) -> &PushBytes {
|
pub fn as_push_bytes(&self) -> &PushBytes {
|
||||||
|
@ -271,15 +261,11 @@ mod primitive {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Accesses inner `Vec` - provided for `super` to impl other methods.
|
/// Accesses inner `Vec` - provided for `super` to impl other methods.
|
||||||
pub(super) fn inner(&self) -> &Vec<u8> {
|
pub(super) fn inner(&self) -> &Vec<u8> { &self.0 }
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PushBytesBuf> for Vec<u8> {
|
impl From<PushBytesBuf> for Vec<u8> {
|
||||||
fn from(value: PushBytesBuf) -> Self {
|
fn from(value: PushBytesBuf) -> Self { value.0 }
|
||||||
value.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Vec<u8>> for PushBytesBuf {
|
impl TryFrom<Vec<u8>> for PushBytesBuf {
|
||||||
|
@ -295,101 +281,69 @@ mod primitive {
|
||||||
impl ToOwned for PushBytes {
|
impl ToOwned for PushBytes {
|
||||||
type Owned = PushBytesBuf;
|
type Owned = PushBytesBuf;
|
||||||
|
|
||||||
fn to_owned(&self) -> Self::Owned {
|
fn to_owned(&self) -> Self::Owned { PushBytesBuf(self.0.to_owned()) }
|
||||||
PushBytesBuf(self.0.to_owned())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PushBytes {
|
impl PushBytes {
|
||||||
/// Returns the number of bytes in buffer.
|
/// Returns the number of bytes in buffer.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize { self.as_bytes().len() }
|
||||||
self.as_bytes().len()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the buffer contains zero bytes.
|
/// Returns true if the buffer contains zero bytes.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool { self.as_bytes().is_empty() }
|
||||||
self.as_bytes().is_empty()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PushBytesBuf {
|
impl PushBytesBuf {
|
||||||
/// Returns the number of bytes in buffer.
|
/// Returns the number of bytes in buffer.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize { self.inner().len() }
|
||||||
self.inner().len()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of bytes the buffer can contain without reallocating.
|
/// Returns the number of bytes the buffer can contain without reallocating.
|
||||||
pub fn capacity(&self) -> usize {
|
pub fn capacity(&self) -> usize { self.inner().capacity() }
|
||||||
self.inner().capacity()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if the buffer contains zero bytes.
|
/// Returns true if the buffer contains zero bytes.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool { self.inner().is_empty() }
|
||||||
self.inner().is_empty()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<[u8]> for PushBytes {
|
impl AsRef<[u8]> for PushBytes {
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] { self.as_bytes() }
|
||||||
self.as_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<[u8]> for PushBytes {
|
impl AsMut<[u8]> for PushBytes {
|
||||||
fn as_mut(&mut self) -> &mut [u8] {
|
fn as_mut(&mut self) -> &mut [u8] { self.as_mut_bytes() }
|
||||||
self.as_mut_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for PushBytesBuf {
|
impl Deref for PushBytesBuf {
|
||||||
type Target = PushBytes;
|
type Target = PushBytes;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target { self.as_push_bytes() }
|
||||||
self.as_push_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for PushBytesBuf {
|
impl DerefMut for PushBytesBuf {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target { self.as_mut_push_bytes() }
|
||||||
self.as_mut_push_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<PushBytes> for PushBytes {
|
impl AsRef<PushBytes> for PushBytes {
|
||||||
fn as_ref(&self) -> &PushBytes {
|
fn as_ref(&self) -> &PushBytes { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<PushBytes> for PushBytes {
|
impl AsMut<PushBytes> for PushBytes {
|
||||||
fn as_mut(&mut self) -> &mut PushBytes {
|
fn as_mut(&mut self) -> &mut PushBytes { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<PushBytes> for PushBytesBuf {
|
impl AsRef<PushBytes> for PushBytesBuf {
|
||||||
fn as_ref(&self) -> &PushBytes {
|
fn as_ref(&self) -> &PushBytes { self.as_push_bytes() }
|
||||||
self.as_push_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<PushBytes> for PushBytesBuf {
|
impl AsMut<PushBytes> for PushBytesBuf {
|
||||||
fn as_mut(&mut self) -> &mut PushBytes {
|
fn as_mut(&mut self) -> &mut PushBytes { self.as_mut_push_bytes() }
|
||||||
self.as_mut_push_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Borrow<PushBytes> for PushBytesBuf {
|
impl Borrow<PushBytes> for PushBytesBuf {
|
||||||
fn borrow(&self) -> &PushBytes {
|
fn borrow(&self) -> &PushBytes { self.as_push_bytes() }
|
||||||
self.as_push_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BorrowMut<PushBytes> for PushBytesBuf {
|
impl BorrowMut<PushBytes> for PushBytesBuf {
|
||||||
fn borrow_mut(&mut self) -> &mut PushBytes {
|
fn borrow_mut(&mut self) -> &mut PushBytes { self.as_mut_push_bytes() }
|
||||||
self.as_mut_push_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reports information about failed conversion into `PushBytes`.
|
/// Reports information about failed conversion into `PushBytes`.
|
||||||
|
@ -403,9 +357,7 @@ pub trait PushBytesErrorReport {
|
||||||
|
|
||||||
impl PushBytesErrorReport for core::convert::Infallible {
|
impl PushBytesErrorReport for core::convert::Infallible {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn input_len(&self) -> usize {
|
fn input_len(&self) -> usize { match *self {} }
|
||||||
match *self {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
|
@ -423,15 +375,11 @@ mod error {
|
||||||
|
|
||||||
impl super::PushBytesErrorReport for PushBytesError {
|
impl super::PushBytesErrorReport for PushBytesError {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn input_len(&self) -> usize {
|
fn input_len(&self) -> usize { match self.never {} }
|
||||||
match self.never {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for PushBytesError {
|
impl fmt::Display for PushBytesError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.never {} }
|
||||||
match self.never {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -445,19 +393,21 @@ mod error {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PushBytesError {
|
pub struct PushBytesError {
|
||||||
/// How long the input was.
|
/// How long the input was.
|
||||||
pub(super) len: usize
|
pub(super) len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::PushBytesErrorReport for PushBytesError {
|
impl super::PushBytesErrorReport for PushBytesError {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn input_len(&self) -> usize {
|
fn input_len(&self) -> usize { self.len }
|
||||||
self.len
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for PushBytesError {
|
impl fmt::Display for PushBytesError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "attempt to prepare {} bytes to be pushed into script but the limit is 2^32-1", self.len)
|
write!(
|
||||||
|
f,
|
||||||
|
"attempt to prepare {} bytes to be pushed into script but the limit is 2^32-1",
|
||||||
|
self.len
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
use crate::hashes::Hash;
|
|
||||||
use crate::hash_types::{PubkeyHash, WPubkeyHash, ScriptHash, WScriptHash};
|
|
||||||
use crate::consensus::encode::{deserialize, serialize};
|
|
||||||
use crate::blockdata::opcodes;
|
|
||||||
use crate::crypto::key::{PublicKey, XOnlyPublicKey};
|
|
||||||
use crate::psbt::serialize::Serialize;
|
|
||||||
use hex_lit::hex;
|
use hex_lit::hex;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::blockdata::opcodes;
|
||||||
|
use crate::consensus::encode::{deserialize, serialize};
|
||||||
|
use crate::crypto::key::{PublicKey, XOnlyPublicKey};
|
||||||
|
use crate::hash_types::{PubkeyHash, ScriptHash, WPubkeyHash, WScriptHash};
|
||||||
|
use crate::hashes::Hash;
|
||||||
|
use crate::psbt::serialize::Serialize;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[rustfmt::skip]
|
||||||
fn script() {
|
fn script() {
|
||||||
let mut comp = vec![];
|
let mut comp = vec![];
|
||||||
let mut script = Builder::new();
|
let mut script = Builder::new();
|
||||||
|
@ -88,20 +89,16 @@ fn p2pk_pubkey_bytes_different_op_code_returns_none() {
|
||||||
fn p2pk_pubkey_bytes_incorrect_key_size_returns_none() {
|
fn p2pk_pubkey_bytes_incorrect_key_size_returns_none() {
|
||||||
// 63 byte key
|
// 63 byte key
|
||||||
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1";
|
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1";
|
||||||
let invalid_p2pk_script = Script::builder()
|
let invalid_p2pk_script =
|
||||||
.push_slice(malformed_key)
|
Script::builder().push_slice(malformed_key).push_opcode(OP_CHECKSIG).into_script();
|
||||||
.push_opcode(OP_CHECKSIG)
|
|
||||||
.into_script();
|
|
||||||
assert!(invalid_p2pk_script.p2pk_pubkey_bytes().is_none());
|
assert!(invalid_p2pk_script.p2pk_pubkey_bytes().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn p2pk_pubkey_bytes_invalid_key_returns_some() {
|
fn p2pk_pubkey_bytes_invalid_key_returns_some() {
|
||||||
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1ux";
|
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1ux";
|
||||||
let invalid_key_script = Script::builder()
|
let invalid_key_script =
|
||||||
.push_slice(malformed_key)
|
Script::builder().push_slice(malformed_key).push_opcode(OP_CHECKSIG).into_script();
|
||||||
.push_opcode(OP_CHECKSIG)
|
|
||||||
.into_script();
|
|
||||||
assert!(invalid_key_script.p2pk_pubkey_bytes().is_some());
|
assert!(invalid_key_script.p2pk_pubkey_bytes().is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,21 +151,16 @@ fn p2pk_public_key_different_op_code_returns_none() {
|
||||||
#[test]
|
#[test]
|
||||||
fn p2pk_public_key_incorrect_size_returns_none() {
|
fn p2pk_public_key_incorrect_size_returns_none() {
|
||||||
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1";
|
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1";
|
||||||
let malformed_key_script = Script::builder()
|
let malformed_key_script =
|
||||||
.push_slice(malformed_key)
|
Script::builder().push_slice(malformed_key).push_opcode(OP_CHECKSIG).into_script();
|
||||||
.push_opcode(OP_CHECKSIG)
|
|
||||||
.into_script();
|
|
||||||
assert!(malformed_key_script.p2pk_public_key().is_none());
|
assert!(malformed_key_script.p2pk_public_key().is_none());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn p2pk_public_key_invalid_key_returns_none() {
|
fn p2pk_public_key_invalid_key_returns_none() {
|
||||||
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1ux";
|
let malformed_key = b"21032e58afe51f9ed8ad3cc7897f634d881fdbe49816429ded8156bebd2ffd1ux";
|
||||||
let invalid_key_script = Script::builder()
|
let invalid_key_script =
|
||||||
.push_slice(malformed_key)
|
Script::builder().push_slice(malformed_key).push_opcode(OP_CHECKSIG).into_script();
|
||||||
.push_opcode(OP_CHECKSIG)
|
|
||||||
.into_script();
|
|
||||||
assert!(invalid_key_script.p2pk_public_key().is_none());
|
assert!(invalid_key_script.p2pk_public_key().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +187,8 @@ fn script_x_only_key() {
|
||||||
#[test]
|
#[test]
|
||||||
fn script_builder() {
|
fn script_builder() {
|
||||||
// from txid 3bb5e6434c11fb93f64574af5d116736510717f2c595eb45b52c28e31622dfff which was in my mempool when I wrote the test
|
// from txid 3bb5e6434c11fb93f64574af5d116736510717f2c595eb45b52c28e31622dfff which was in my mempool when I wrote the test
|
||||||
let script = Builder::new().push_opcode(OP_DUP)
|
let script = Builder::new()
|
||||||
|
.push_opcode(OP_DUP)
|
||||||
.push_opcode(OP_HASH160)
|
.push_opcode(OP_HASH160)
|
||||||
.push_slice(hex!("16e1ae70ff0fa102905d4af297f6912bda6cce19"))
|
.push_slice(hex!("16e1ae70ff0fa102905d4af297f6912bda6cce19"))
|
||||||
.push_opcode(OP_EQUALVERIFY)
|
.push_opcode(OP_EQUALVERIFY)
|
||||||
|
@ -206,7 +199,9 @@ fn script_builder() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn script_generators() {
|
fn script_generators() {
|
||||||
let pubkey = PublicKey::from_str("0234e6a79c5359c613762d537e0e19d86c77c1666d8c9ab050f23acd198e97f93e").unwrap();
|
let pubkey =
|
||||||
|
PublicKey::from_str("0234e6a79c5359c613762d537e0e19d86c77c1666d8c9ab050f23acd198e97f93e")
|
||||||
|
.unwrap();
|
||||||
assert!(ScriptBuf::new_p2pk(&pubkey).is_p2pk());
|
assert!(ScriptBuf::new_p2pk(&pubkey).is_p2pk());
|
||||||
|
|
||||||
let pubkey_hash = PubkeyHash::hash(&pubkey.inner.serialize());
|
let pubkey_hash = PubkeyHash::hash(&pubkey.inner.serialize());
|
||||||
|
@ -215,9 +210,7 @@ fn script_generators() {
|
||||||
let wpubkey_hash = WPubkeyHash::hash(&pubkey.inner.serialize());
|
let wpubkey_hash = WPubkeyHash::hash(&pubkey.inner.serialize());
|
||||||
assert!(ScriptBuf::new_v0_p2wpkh(&wpubkey_hash).is_v0_p2wpkh());
|
assert!(ScriptBuf::new_v0_p2wpkh(&wpubkey_hash).is_v0_p2wpkh());
|
||||||
|
|
||||||
let script = Builder::new().push_opcode(OP_NUMEQUAL)
|
let script = Builder::new().push_opcode(OP_NUMEQUAL).push_verify().into_script();
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
let script_hash = ScriptHash::hash(&script.serialize());
|
let script_hash = ScriptHash::hash(&script.serialize());
|
||||||
let p2sh = ScriptBuf::new_p2sh(&script_hash);
|
let p2sh = ScriptBuf::new_p2sh(&script_hash);
|
||||||
assert!(p2sh.is_p2sh());
|
assert!(p2sh.is_p2sh());
|
||||||
|
@ -233,68 +226,42 @@ fn script_generators() {
|
||||||
let data = hex!("aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a");
|
let data = hex!("aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a");
|
||||||
let op_return = ScriptBuf::new_op_return(&data);
|
let op_return = ScriptBuf::new_op_return(&data);
|
||||||
assert!(op_return.is_op_return());
|
assert!(op_return.is_op_return());
|
||||||
assert_eq!(op_return.to_hex_string(), "6a24aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a");
|
assert_eq!(
|
||||||
|
op_return.to_hex_string(),
|
||||||
|
"6a24aa21a9ed20280f53f2d21663cac89e6bd2ad19edbabb048cda08e73ed19e9268d0afea2a"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn script_builder_verify() {
|
fn script_builder_verify() {
|
||||||
let simple = Builder::new()
|
let simple = Builder::new().push_verify().into_script();
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(simple.to_hex_string(), "69");
|
assert_eq!(simple.to_hex_string(), "69");
|
||||||
let simple2 = Builder::from(vec![])
|
let simple2 = Builder::from(vec![]).push_verify().into_script();
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(simple2.to_hex_string(), "69");
|
assert_eq!(simple2.to_hex_string(), "69");
|
||||||
|
|
||||||
let nonverify = Builder::new()
|
let nonverify = Builder::new().push_verify().push_verify().into_script();
|
||||||
.push_verify()
|
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(nonverify.to_hex_string(), "6969");
|
assert_eq!(nonverify.to_hex_string(), "6969");
|
||||||
let nonverify2 = Builder::from(vec![0x69])
|
let nonverify2 = Builder::from(vec![0x69]).push_verify().into_script();
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(nonverify2.to_hex_string(), "6969");
|
assert_eq!(nonverify2.to_hex_string(), "6969");
|
||||||
|
|
||||||
let equal = Builder::new()
|
let equal = Builder::new().push_opcode(OP_EQUAL).push_verify().into_script();
|
||||||
.push_opcode(OP_EQUAL)
|
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(equal.to_hex_string(), "88");
|
assert_eq!(equal.to_hex_string(), "88");
|
||||||
let equal2 = Builder::from(vec![0x87])
|
let equal2 = Builder::from(vec![0x87]).push_verify().into_script();
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(equal2.to_hex_string(), "88");
|
assert_eq!(equal2.to_hex_string(), "88");
|
||||||
|
|
||||||
let numequal = Builder::new()
|
let numequal = Builder::new().push_opcode(OP_NUMEQUAL).push_verify().into_script();
|
||||||
.push_opcode(OP_NUMEQUAL)
|
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(numequal.to_hex_string(), "9d");
|
assert_eq!(numequal.to_hex_string(), "9d");
|
||||||
let numequal2 = Builder::from(vec![0x9c])
|
let numequal2 = Builder::from(vec![0x9c]).push_verify().into_script();
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(numequal2.to_hex_string(), "9d");
|
assert_eq!(numequal2.to_hex_string(), "9d");
|
||||||
|
|
||||||
let checksig = Builder::new()
|
let checksig = Builder::new().push_opcode(OP_CHECKSIG).push_verify().into_script();
|
||||||
.push_opcode(OP_CHECKSIG)
|
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(checksig.to_hex_string(), "ad");
|
assert_eq!(checksig.to_hex_string(), "ad");
|
||||||
let checksig2 = Builder::from(vec![0xac])
|
let checksig2 = Builder::from(vec![0xac]).push_verify().into_script();
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(checksig2.to_hex_string(), "ad");
|
assert_eq!(checksig2.to_hex_string(), "ad");
|
||||||
|
|
||||||
let checkmultisig = Builder::new()
|
let checkmultisig = Builder::new().push_opcode(OP_CHECKMULTISIG).push_verify().into_script();
|
||||||
.push_opcode(OP_CHECKMULTISIG)
|
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(checkmultisig.to_hex_string(), "af");
|
assert_eq!(checkmultisig.to_hex_string(), "af");
|
||||||
let checkmultisig2 = Builder::from(vec![0xae])
|
let checkmultisig2 = Builder::from(vec![0xae]).push_verify().into_script();
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(checkmultisig2.to_hex_string(), "af");
|
assert_eq!(checkmultisig2.to_hex_string(), "af");
|
||||||
|
|
||||||
let trick_slice = Builder::new()
|
let trick_slice = Builder::new()
|
||||||
|
@ -302,9 +269,7 @@ fn script_builder_verify() {
|
||||||
.push_verify()
|
.push_verify()
|
||||||
.into_script();
|
.into_script();
|
||||||
assert_eq!(trick_slice.to_hex_string(), "01ae69");
|
assert_eq!(trick_slice.to_hex_string(), "01ae69");
|
||||||
let trick_slice2 = Builder::from(vec![0x01, 0xae])
|
let trick_slice2 = Builder::from(vec![0x01, 0xae]).push_verify().into_script();
|
||||||
.push_verify()
|
|
||||||
.into_script();
|
|
||||||
assert_eq!(trick_slice2.to_hex_string(), "01ae69");
|
assert_eq!(trick_slice2.to_hex_string(), "01ae69");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,8 +296,18 @@ fn scriptint_round_trip() {
|
||||||
assert_eq!(build_scriptint(257), vec![1, 1]);
|
assert_eq!(build_scriptint(257), vec![1, 1]);
|
||||||
assert_eq!(build_scriptint(511), vec![255, 1]);
|
assert_eq!(build_scriptint(511), vec![255, 1]);
|
||||||
let test_vectors = [
|
let test_vectors = [
|
||||||
10, 100, 255, 256, 1000, 10000, 25000, 200000, 5000000, 1000000000,
|
10,
|
||||||
(1 << 31) - 1, -((1 << 31) - 1),
|
100,
|
||||||
|
255,
|
||||||
|
256,
|
||||||
|
1000,
|
||||||
|
10000,
|
||||||
|
25000,
|
||||||
|
200000,
|
||||||
|
5000000,
|
||||||
|
1000000000,
|
||||||
|
(1 << 31) - 1,
|
||||||
|
-((1 << 31) - 1),
|
||||||
];
|
];
|
||||||
for &i in test_vectors.iter() {
|
for &i in test_vectors.iter() {
|
||||||
assert_eq!(Ok(i), read_scriptint(&build_scriptint(i)));
|
assert_eq!(Ok(i), read_scriptint(&build_scriptint(i)));
|
||||||
|
@ -354,9 +329,15 @@ fn non_minimal_scriptints() {
|
||||||
fn script_hashes() {
|
fn script_hashes() {
|
||||||
let script = ScriptBuf::from_hex("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap();
|
let script = ScriptBuf::from_hex("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap();
|
||||||
assert_eq!(script.script_hash().to_string(), "8292bcfbef1884f73c813dfe9c82fd7e814291ea");
|
assert_eq!(script.script_hash().to_string(), "8292bcfbef1884f73c813dfe9c82fd7e814291ea");
|
||||||
assert_eq!(script.wscript_hash().to_string(), "3e1525eb183ad4f9b3c5fa3175bdca2a52e947b135bbb90383bf9f6408e2c324");
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ScriptBuf::from_hex("20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac").unwrap().tapscript_leaf_hash().to_string(),
|
script.wscript_hash().to_string(),
|
||||||
|
"3e1525eb183ad4f9b3c5fa3175bdca2a52e947b135bbb90383bf9f6408e2c324"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ScriptBuf::from_hex("20d85a959b0290bf19bb89ed43c916be835475d013da4b362117393e25a48229b8ac")
|
||||||
|
.unwrap()
|
||||||
|
.tapscript_leaf_hash()
|
||||||
|
.to_string(),
|
||||||
"5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21"
|
"5b75adecf53548f3ec6ad7d78383bf84cc57b55a3127c72b9a2481752dd88b21"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -367,14 +348,22 @@ fn provably_unspendable_test() {
|
||||||
assert!(!ScriptBuf::from_hex("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap().is_provably_unspendable());
|
assert!(!ScriptBuf::from_hex("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").unwrap().is_provably_unspendable());
|
||||||
assert!(!ScriptBuf::from_hex("4104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac").unwrap().is_provably_unspendable());
|
assert!(!ScriptBuf::from_hex("4104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac").unwrap().is_provably_unspendable());
|
||||||
// p2pkhash
|
// p2pkhash
|
||||||
assert!(!ScriptBuf::from_hex("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac").unwrap().is_provably_unspendable());
|
assert!(!ScriptBuf::from_hex("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac")
|
||||||
assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87").unwrap().is_provably_unspendable());
|
.unwrap()
|
||||||
|
.is_provably_unspendable());
|
||||||
|
assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87")
|
||||||
|
.unwrap()
|
||||||
|
.is_provably_unspendable());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn op_return_test() {
|
fn op_return_test() {
|
||||||
assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87").unwrap().is_op_return());
|
assert!(ScriptBuf::from_hex("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87")
|
||||||
assert!(!ScriptBuf::from_hex("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac").unwrap().is_op_return());
|
.unwrap()
|
||||||
|
.is_op_return());
|
||||||
|
assert!(!ScriptBuf::from_hex("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac")
|
||||||
|
.unwrap()
|
||||||
|
.is_op_return());
|
||||||
assert!(!ScriptBuf::from_hex("").unwrap().is_op_return());
|
assert!(!ScriptBuf::from_hex("").unwrap().is_op_return());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,10 +381,14 @@ fn script_json_serialize() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn script_asm() {
|
fn script_asm() {
|
||||||
assert_eq!(ScriptBuf::from_hex("6363636363686868686800").unwrap().to_asm_string(),
|
assert_eq!(
|
||||||
"OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0");
|
ScriptBuf::from_hex("6363636363686868686800").unwrap().to_asm_string(),
|
||||||
assert_eq!(ScriptBuf::from_hex("6363636363686868686800").unwrap().to_asm_string(),
|
"OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0"
|
||||||
"OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0");
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ScriptBuf::from_hex("6363636363686868686800").unwrap().to_asm_string(),
|
||||||
|
"OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0"
|
||||||
|
);
|
||||||
assert_eq!(ScriptBuf::from_hex("2102715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699ac").unwrap().to_asm_string(),
|
assert_eq!(ScriptBuf::from_hex("2102715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699ac").unwrap().to_asm_string(),
|
||||||
"OP_PUSHBYTES_33 02715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699 OP_CHECKSIG");
|
"OP_PUSHBYTES_33 02715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699 OP_CHECKSIG");
|
||||||
// Elements Alpha peg-out transaction with some signatures removed for brevity. Mainly to test PUSHDATA1
|
// Elements Alpha peg-out transaction with some signatures removed for brevity. Mainly to test PUSHDATA1
|
||||||
|
@ -403,20 +396,28 @@ fn script_asm() {
|
||||||
"OP_0 OP_PUSHBYTES_71 304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401 OP_0 OP_PUSHDATA1 552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae");
|
"OP_0 OP_PUSHBYTES_71 304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401 OP_0 OP_PUSHDATA1 552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae");
|
||||||
// Various weird scripts found in transaction 6d7ed9914625c73c0288694a6819196a27ef6c08f98e1270d975a8e65a3dc09a
|
// Various weird scripts found in transaction 6d7ed9914625c73c0288694a6819196a27ef6c08f98e1270d975a8e65a3dc09a
|
||||||
// which triggerred overflow bugs on 32-bit machines in script formatting in the past.
|
// which triggerred overflow bugs on 32-bit machines in script formatting in the past.
|
||||||
assert_eq!(ScriptBuf::from_hex("01").unwrap().to_asm_string(),
|
assert_eq!(
|
||||||
"OP_PUSHBYTES_1 <push past end>");
|
ScriptBuf::from_hex("01").unwrap().to_asm_string(),
|
||||||
assert_eq!(ScriptBuf::from_hex("0201").unwrap().to_asm_string(),
|
"OP_PUSHBYTES_1 <push past end>"
|
||||||
"OP_PUSHBYTES_2 <push past end>");
|
);
|
||||||
assert_eq!(ScriptBuf::from_hex("4c").unwrap().to_asm_string(),
|
assert_eq!(
|
||||||
"<unexpected end>");
|
ScriptBuf::from_hex("0201").unwrap().to_asm_string(),
|
||||||
assert_eq!(ScriptBuf::from_hex("4c0201").unwrap().to_asm_string(),
|
"OP_PUSHBYTES_2 <push past end>"
|
||||||
"OP_PUSHDATA1 <push past end>");
|
);
|
||||||
assert_eq!(ScriptBuf::from_hex("4d").unwrap().to_asm_string(),
|
assert_eq!(ScriptBuf::from_hex("4c").unwrap().to_asm_string(), "<unexpected end>");
|
||||||
"<unexpected end>");
|
assert_eq!(
|
||||||
assert_eq!(ScriptBuf::from_hex("4dffff01").unwrap().to_asm_string(),
|
ScriptBuf::from_hex("4c0201").unwrap().to_asm_string(),
|
||||||
"OP_PUSHDATA2 <push past end>");
|
"OP_PUSHDATA1 <push past end>"
|
||||||
assert_eq!(ScriptBuf::from_hex("4effffffff01").unwrap().to_asm_string(),
|
);
|
||||||
"OP_PUSHDATA4 <push past end>");
|
assert_eq!(ScriptBuf::from_hex("4d").unwrap().to_asm_string(), "<unexpected end>");
|
||||||
|
assert_eq!(
|
||||||
|
ScriptBuf::from_hex("4dffff01").unwrap().to_asm_string(),
|
||||||
|
"OP_PUSHDATA2 <push past end>"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
ScriptBuf::from_hex("4effffffff01").unwrap().to_asm_string(),
|
||||||
|
"OP_PUSHDATA4 <push past end>"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -429,18 +430,34 @@ fn script_buf_collect() {
|
||||||
#[test]
|
#[test]
|
||||||
fn script_p2sh_p2p2k_template() {
|
fn script_p2sh_p2p2k_template() {
|
||||||
// random outputs I picked out of the mempool
|
// random outputs I picked out of the mempool
|
||||||
assert!(ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap().is_p2pkh());
|
assert!(ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac")
|
||||||
assert!(!ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").unwrap().is_p2sh());
|
.unwrap()
|
||||||
assert!(!ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ad").unwrap().is_p2pkh());
|
.is_p2pkh());
|
||||||
|
assert!(!ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac")
|
||||||
|
.unwrap()
|
||||||
|
.is_p2sh());
|
||||||
|
assert!(!ScriptBuf::from_hex("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ad")
|
||||||
|
.unwrap()
|
||||||
|
.is_p2pkh());
|
||||||
assert!(!ScriptBuf::from_hex("").unwrap().is_p2pkh());
|
assert!(!ScriptBuf::from_hex("").unwrap().is_p2pkh());
|
||||||
assert!(ScriptBuf::from_hex("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87").unwrap().is_p2sh());
|
assert!(ScriptBuf::from_hex("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87")
|
||||||
assert!(!ScriptBuf::from_hex("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87").unwrap().is_p2pkh());
|
.unwrap()
|
||||||
assert!(!ScriptBuf::from_hex("a314acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87").unwrap().is_p2sh());
|
.is_p2sh());
|
||||||
|
assert!(!ScriptBuf::from_hex("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87")
|
||||||
|
.unwrap()
|
||||||
|
.is_p2pkh());
|
||||||
|
assert!(!ScriptBuf::from_hex("a314acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87")
|
||||||
|
.unwrap()
|
||||||
|
.is_p2sh());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn script_p2pk() {
|
fn script_p2pk() {
|
||||||
assert!(ScriptBuf::from_hex("21021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac").unwrap().is_p2pk());
|
assert!(ScriptBuf::from_hex(
|
||||||
|
"21021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
.is_p2pk());
|
||||||
assert!(ScriptBuf::from_hex("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac").unwrap().is_p2pk());
|
assert!(ScriptBuf::from_hex("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac").unwrap().is_p2pk());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -449,20 +466,26 @@ fn p2sh_p2wsh_conversion() {
|
||||||
// Test vectors taken from Core tests/data/script_tests.json
|
// Test vectors taken from Core tests/data/script_tests.json
|
||||||
// bare p2wsh
|
// bare p2wsh
|
||||||
let redeem_script = ScriptBuf::from_hex("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap();
|
let redeem_script = ScriptBuf::from_hex("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap();
|
||||||
let expected_witout = ScriptBuf::from_hex("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64").unwrap();
|
let expected_witout =
|
||||||
|
ScriptBuf::from_hex("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64")
|
||||||
|
.unwrap();
|
||||||
assert!(redeem_script.to_v0_p2wsh().is_v0_p2wsh());
|
assert!(redeem_script.to_v0_p2wsh().is_v0_p2wsh());
|
||||||
assert_eq!(redeem_script.to_v0_p2wsh(), expected_witout);
|
assert_eq!(redeem_script.to_v0_p2wsh(), expected_witout);
|
||||||
|
|
||||||
// p2sh
|
// p2sh
|
||||||
let redeem_script = ScriptBuf::from_hex("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8").unwrap();
|
let redeem_script = ScriptBuf::from_hex("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8").unwrap();
|
||||||
let expected_p2shout = ScriptBuf::from_hex("a91491b24bf9f5288532960ac687abb035127b1d28a587").unwrap();
|
let expected_p2shout =
|
||||||
|
ScriptBuf::from_hex("a91491b24bf9f5288532960ac687abb035127b1d28a587").unwrap();
|
||||||
assert!(redeem_script.to_p2sh().is_p2sh());
|
assert!(redeem_script.to_p2sh().is_p2sh());
|
||||||
assert_eq!(redeem_script.to_p2sh(), expected_p2shout);
|
assert_eq!(redeem_script.to_p2sh(), expected_p2shout);
|
||||||
|
|
||||||
// p2sh-p2wsh
|
// p2sh-p2wsh
|
||||||
let redeem_script = ScriptBuf::from_hex("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap();
|
let redeem_script = ScriptBuf::from_hex("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac").unwrap();
|
||||||
let expected_witout = ScriptBuf::from_hex("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64").unwrap();
|
let expected_witout =
|
||||||
let expected_out = ScriptBuf::from_hex("a914f386c2ba255cc56d20cfa6ea8b062f8b5994551887").unwrap();
|
ScriptBuf::from_hex("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64")
|
||||||
|
.unwrap();
|
||||||
|
let expected_out =
|
||||||
|
ScriptBuf::from_hex("a914f386c2ba255cc56d20cfa6ea8b062f8b5994551887").unwrap();
|
||||||
assert!(redeem_script.to_p2sh().is_p2sh());
|
assert!(redeem_script.to_p2sh().is_p2sh());
|
||||||
assert!(redeem_script.to_p2sh().to_v0_p2wsh().is_v0_p2wsh());
|
assert!(redeem_script.to_p2sh().to_v0_p2wsh().is_v0_p2wsh());
|
||||||
assert_eq!(redeem_script.to_v0_p2wsh(), expected_witout);
|
assert_eq!(redeem_script.to_v0_p2wsh(), expected_witout);
|
||||||
|
@ -491,12 +514,21 @@ fn test_iterator() {
|
||||||
|
|
||||||
let v_min: Result<Vec<_>, Error> = minimal.instruction_indices_minimal().collect();
|
let v_min: Result<Vec<_>, Error> = minimal.instruction_indices_minimal().collect();
|
||||||
let v_nonmin: Result<Vec<_>, Error> = nonminimal.instruction_indices_minimal().collect();
|
let v_nonmin: Result<Vec<_>, Error> = nonminimal.instruction_indices_minimal().collect();
|
||||||
let v_nonmin_alt: Result<Vec<_>, Error> = nonminimal_alt.instruction_indices_minimal().collect();
|
let v_nonmin_alt: Result<Vec<_>, Error> =
|
||||||
|
nonminimal_alt.instruction_indices_minimal().collect();
|
||||||
let slop_v_min: Result<Vec<_>, Error> = minimal.instruction_indices().collect();
|
let slop_v_min: Result<Vec<_>, Error> = minimal.instruction_indices().collect();
|
||||||
let slop_v_nonmin: Result<Vec<_>, Error> = nonminimal.instruction_indices().collect();
|
let slop_v_nonmin: Result<Vec<_>, Error> = nonminimal.instruction_indices().collect();
|
||||||
let slop_v_nonmin_alt: Result<Vec<_>, Error> = nonminimal_alt.instruction_indices().collect();
|
let slop_v_nonmin_alt: Result<Vec<_>, Error> = nonminimal_alt.instruction_indices().collect();
|
||||||
|
|
||||||
unwrap_all!(v_zero, v_zeropush, v_min, v_nonmin_alt, slop_v_min, slop_v_nonmin, slop_v_nonmin_alt);
|
unwrap_all!(
|
||||||
|
v_zero,
|
||||||
|
v_zeropush,
|
||||||
|
v_min,
|
||||||
|
v_nonmin_alt,
|
||||||
|
slop_v_min,
|
||||||
|
slop_v_nonmin,
|
||||||
|
slop_v_nonmin_alt
|
||||||
|
);
|
||||||
|
|
||||||
assert_eq!(v_zero, vec![(0, Instruction::PushBytes(PushBytes::empty()))]);
|
assert_eq!(v_zero, vec![(0, Instruction::PushBytes(PushBytes::empty()))]);
|
||||||
assert_eq!(v_zeropush, vec![(0, Instruction::PushBytes([0].as_ref()))]);
|
assert_eq!(v_zeropush, vec![(0, Instruction::PushBytes([0].as_ref()))]);
|
||||||
|
@ -510,7 +542,10 @@ fn test_iterator() {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
v_nonmin_alt,
|
v_nonmin_alt,
|
||||||
vec![(0, Instruction::PushBytes([105, 0].as_ref())), (3, Instruction::Op(opcodes::OP_NOP3))]
|
vec![
|
||||||
|
(0, Instruction::PushBytes([105, 0].as_ref())),
|
||||||
|
(3, Instruction::Op(opcodes::OP_NOP3))
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(v_min, slop_v_min);
|
assert_eq!(v_min, slop_v_min);
|
||||||
|
@ -544,7 +579,7 @@ fn script_ord() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "bitcoinconsensus")]
|
#[cfg(feature = "bitcoinconsensus")]
|
||||||
fn test_bitcoinconsensus () {
|
fn test_bitcoinconsensus() {
|
||||||
// a random segwit transaction from the blockchain using native segwit
|
// a random segwit transaction from the blockchain using native segwit
|
||||||
let spent_bytes = hex!("0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d");
|
let spent_bytes = hex!("0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d");
|
||||||
let spent = Script::from_bytes(&spent_bytes);
|
let spent = Script::from_bytes(&spent_bytes);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
||||||
//! Implements `Weight` and associated features.
|
//! Implements `Weight` and associated features.
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Div, DivAssign};
|
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
@ -30,28 +30,20 @@ impl Weight {
|
||||||
pub const MAX: Weight = Weight(u64::max_value());
|
pub const MAX: Weight = Weight(u64::max_value());
|
||||||
|
|
||||||
/// Directly constructs `Weight` from weight units.
|
/// Directly constructs `Weight` from weight units.
|
||||||
pub const fn from_wu(wu: u64) -> Self {
|
pub const fn from_wu(wu: u64) -> Self { Weight(wu) }
|
||||||
Weight(wu)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs `Weight` from virtual bytes.
|
/// Constructs `Weight` from virtual bytes.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Returns `None` on overflow.
|
/// Returns `None` on overflow.
|
||||||
pub fn from_vb(vb: u64) -> Option<Self> {
|
pub fn from_vb(vb: u64) -> Option<Self> { vb.checked_mul(4).map(Weight::from_wu) }
|
||||||
vb.checked_mul(4).map(Weight::from_wu)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs `Weight` from virtual bytes without overflow check.
|
/// Constructs `Weight` from virtual bytes without overflow check.
|
||||||
pub const fn from_vb_unchecked(vb: u64) -> Self {
|
pub const fn from_vb_unchecked(vb: u64) -> Self { Weight::from_wu(vb * 4) }
|
||||||
Weight::from_wu(vb * 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs `Weight` from witness size.
|
/// Constructs `Weight` from witness size.
|
||||||
pub const fn from_witness_data_size(witness_size: u64) -> Self {
|
pub const fn from_witness_data_size(witness_size: u64) -> Self { Weight(witness_size) }
|
||||||
Weight(witness_size)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Constructs `Weight` from non-witness size.
|
/// Constructs `Weight` from non-witness size.
|
||||||
pub const fn from_non_witness_data_size(non_witness_size: u64) -> Self {
|
pub const fn from_non_witness_data_size(non_witness_size: u64) -> Self {
|
||||||
|
@ -61,47 +53,33 @@ impl Weight {
|
||||||
/// Returns raw weight units.
|
/// Returns raw weight units.
|
||||||
///
|
///
|
||||||
/// Can be used instead of `into()` to avoid inference issues.
|
/// Can be used instead of `into()` to avoid inference issues.
|
||||||
pub const fn to_wu(self) -> u64 {
|
pub const fn to_wu(self) -> u64 { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts to vB rounding down.
|
/// Converts to vB rounding down.
|
||||||
pub const fn to_vbytes_floor(self) -> u64 {
|
pub const fn to_vbytes_floor(self) -> u64 { self.0 / 4 }
|
||||||
self.0 / 4
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts to vB rounding up.
|
/// Converts to vB rounding up.
|
||||||
pub const fn to_vbytes_ceil(self) -> u64 {
|
pub const fn to_vbytes_ceil(self) -> u64 { (self.0 + 3) / 4 }
|
||||||
(self.0 + 3) / 4
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checked addition.
|
/// Checked addition.
|
||||||
///
|
///
|
||||||
/// Computes `self + rhs` returning `None` if overflow occurred.
|
/// Computes `self + rhs` returning `None` if overflow occurred.
|
||||||
pub fn checked_add(self, rhs: Self) -> Option<Self> {
|
pub fn checked_add(self, rhs: Self) -> Option<Self> { self.0.checked_add(rhs.0).map(Self) }
|
||||||
self.0.checked_add(rhs.0).map(Self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checked subtraction.
|
/// Checked subtraction.
|
||||||
///
|
///
|
||||||
/// Computes `self - rhs` returning `None` if overflow occurred.
|
/// Computes `self - rhs` returning `None` if overflow occurred.
|
||||||
pub fn checked_sub(self, rhs: Self) -> Option<Self> {
|
pub fn checked_sub(self, rhs: Self) -> Option<Self> { self.0.checked_sub(rhs.0).map(Self) }
|
||||||
self.0.checked_sub(rhs.0).map(Self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checked multiplication.
|
/// Checked multiplication.
|
||||||
///
|
///
|
||||||
/// Computes `self * rhs` returning `None` if overflow occurred.
|
/// Computes `self * rhs` returning `None` if overflow occurred.
|
||||||
pub fn checked_mul(self, rhs: u64) -> Option<Self> {
|
pub fn checked_mul(self, rhs: u64) -> Option<Self> { self.0.checked_mul(rhs).map(Self) }
|
||||||
self.0.checked_mul(rhs).map(Self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Checked division.
|
/// Checked division.
|
||||||
///
|
///
|
||||||
/// Computes `self / rhs` returning `None` if `rhs == 0`.
|
/// Computes `self / rhs` returning `None` if `rhs == 0`.
|
||||||
pub fn checked_div(self, rhs: u64) -> Option<Self> {
|
pub fn checked_div(self, rhs: u64) -> Option<Self> { self.0.checked_div(rhs).map(Self) }
|
||||||
self.0.checked_div(rhs).map(Self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Alternative will display the unit.
|
/// Alternative will display the unit.
|
||||||
|
@ -141,9 +119,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic]
|
#[should_panic]
|
||||||
fn from_vb_unchecked_panic_test() {
|
fn from_vb_unchecked_panic_test() { Weight::from_vb_unchecked(u64::max_value()); }
|
||||||
Weight::from_vb_unchecked(u64::max_value());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_witness_data_size_test() {
|
fn from_witness_data_size_test() {
|
||||||
|
@ -206,83 +182,69 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Weight> for u64 {
|
impl From<Weight> for u64 {
|
||||||
fn from(value: Weight) -> Self {
|
fn from(value: Weight) -> Self { value.to_wu() }
|
||||||
value.to_wu()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Add for Weight {
|
impl Add for Weight {
|
||||||
type Output = Weight;
|
type Output = Weight;
|
||||||
|
|
||||||
fn add(self, rhs: Weight) -> Self::Output {
|
fn add(self, rhs: Weight) -> Self::Output { Weight(self.0 + rhs.0) }
|
||||||
Weight(self.0 + rhs.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AddAssign for Weight {
|
impl AddAssign for Weight {
|
||||||
fn add_assign(&mut self, rhs: Self) {
|
fn add_assign(&mut self, rhs: Self) { self.0 += rhs.0 }
|
||||||
self.0 += rhs.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sub for Weight {
|
impl Sub for Weight {
|
||||||
type Output = Weight;
|
type Output = Weight;
|
||||||
|
|
||||||
fn sub(self, rhs: Weight) -> Self::Output {
|
fn sub(self, rhs: Weight) -> Self::Output { Weight(self.0 - rhs.0) }
|
||||||
Weight(self.0 - rhs.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubAssign for Weight {
|
impl SubAssign for Weight {
|
||||||
fn sub_assign(&mut self, rhs: Self) {
|
fn sub_assign(&mut self, rhs: Self) { self.0 -= rhs.0 }
|
||||||
self.0 -= rhs.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mul<u64> for Weight {
|
impl Mul<u64> for Weight {
|
||||||
type Output = Weight;
|
type Output = Weight;
|
||||||
|
|
||||||
fn mul(self, rhs: u64) -> Self::Output {
|
fn mul(self, rhs: u64) -> Self::Output { Weight(self.0 * rhs) }
|
||||||
Weight(self.0 * rhs)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mul<Weight> for u64 {
|
impl Mul<Weight> for u64 {
|
||||||
type Output = Weight;
|
type Output = Weight;
|
||||||
|
|
||||||
fn mul(self, rhs: Weight) -> Self::Output {
|
fn mul(self, rhs: Weight) -> Self::Output { Weight(self * rhs.0) }
|
||||||
Weight(self * rhs.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MulAssign<u64> for Weight {
|
impl MulAssign<u64> for Weight {
|
||||||
fn mul_assign(&mut self, rhs: u64) {
|
fn mul_assign(&mut self, rhs: u64) { self.0 *= rhs }
|
||||||
self.0 *= rhs
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Div<u64> for Weight {
|
impl Div<u64> for Weight {
|
||||||
type Output = Weight;
|
type Output = Weight;
|
||||||
|
|
||||||
fn div(self, rhs: u64) -> Self::Output {
|
fn div(self, rhs: u64) -> Self::Output { Weight(self.0 / rhs) }
|
||||||
Weight(self.0 / rhs)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DivAssign<u64> for Weight {
|
impl DivAssign<u64> for Weight {
|
||||||
fn div_assign(&mut self, rhs: u64) {
|
fn div_assign(&mut self, rhs: u64) { self.0 /= rhs }
|
||||||
self.0 /= rhs
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::iter::Sum for Weight {
|
impl core::iter::Sum for Weight {
|
||||||
fn sum<I>(iter: I) -> Self where I: Iterator<Item = Self> {
|
fn sum<I>(iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: Iterator<Item = Self>,
|
||||||
|
{
|
||||||
Weight(iter.map(Weight::to_wu).sum())
|
Weight(iter.map(Weight::to_wu).sum())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> core::iter::Sum<&'a Weight> for Weight {
|
impl<'a> core::iter::Sum<&'a Weight> for Weight {
|
||||||
fn sum<I>(iter: I) -> Self where I: Iterator<Item = &'a Weight> {
|
fn sum<I>(iter: I) -> Self
|
||||||
|
where
|
||||||
|
I: Iterator<Item = &'a Weight>,
|
||||||
|
{
|
||||||
iter.cloned().sum()
|
iter.cloned().sum()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,11 @@ use secp256k1::ecdsa;
|
||||||
|
|
||||||
use crate::consensus::encode::{Error, MAX_VEC_SIZE};
|
use crate::consensus::encode::{Error, MAX_VEC_SIZE};
|
||||||
use crate::consensus::{Decodable, Encodable, WriteExt};
|
use crate::consensus::{Decodable, Encodable, WriteExt};
|
||||||
use crate::sighash::EcdsaSighashType;
|
|
||||||
use crate::io::{self, Read, Write};
|
use crate::io::{self, Read, Write};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::{Script, VarInt};
|
use crate::sighash::EcdsaSighashType;
|
||||||
use crate::taproot::TAPROOT_ANNEX_PREFIX;
|
use crate::taproot::TAPROOT_ANNEX_PREFIX;
|
||||||
|
use crate::{Script, VarInt};
|
||||||
|
|
||||||
/// The Witness is the data used to unlock bitcoin since the [segwit upgrade].
|
/// The Witness is the data used to unlock bitcoin since the [segwit upgrade].
|
||||||
///
|
///
|
||||||
|
@ -103,8 +103,9 @@ impl Decodable for Witness {
|
||||||
encode_cursor(&mut content, 0, i, cursor - witness_index_space);
|
encode_cursor(&mut content, 0, i, cursor - witness_index_space);
|
||||||
|
|
||||||
resize_if_needed(&mut content, required_len);
|
resize_if_needed(&mut content, required_len);
|
||||||
element_size_varint
|
element_size_varint.consensus_encode(
|
||||||
.consensus_encode(&mut &mut content[cursor..cursor + element_size_varint_len])?;
|
&mut &mut content[cursor..cursor + element_size_varint_len],
|
||||||
|
)?;
|
||||||
cursor += element_size_varint_len;
|
cursor += element_size_varint_len;
|
||||||
r.read_exact(&mut content[cursor..cursor + element_size])?;
|
r.read_exact(&mut content[cursor..cursor + element_size])?;
|
||||||
cursor += element_size;
|
cursor += element_size;
|
||||||
|
@ -112,22 +113,18 @@ impl Decodable for Witness {
|
||||||
content.truncate(cursor);
|
content.truncate(cursor);
|
||||||
// Index space is now at the end of the Vec
|
// Index space is now at the end of the Vec
|
||||||
content.rotate_left(witness_index_space);
|
content.rotate_left(witness_index_space);
|
||||||
Ok(Witness {
|
Ok(Witness { content, witness_elements, indices_start: cursor - witness_index_space })
|
||||||
content,
|
|
||||||
witness_elements,
|
|
||||||
indices_start: cursor - witness_index_space,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Correctness Requirements: value must always fit within u32
|
/// Correctness Requirements: value must always fit within u32
|
||||||
#[inline]
|
#[inline]
|
||||||
fn encode_cursor(bytes: &mut [u8], start_of_indices: usize, index: usize, value: usize) {
|
fn encode_cursor(bytes: &mut [u8], start_of_indices: usize, index: usize, value: usize) {
|
||||||
let start = start_of_indices + index * 4;
|
let start = start_of_indices + index * 4;
|
||||||
let end = start + 4;
|
let end = start + 4;
|
||||||
bytes[start..end].copy_from_slice(&u32::to_ne_bytes(value.try_into().expect("Larger than u32")));
|
bytes[start..end]
|
||||||
|
.copy_from_slice(&u32::to_ne_bytes(value.try_into().expect("Larger than u32")));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -165,15 +162,11 @@ impl Encodable for Witness {
|
||||||
|
|
||||||
impl Witness {
|
impl Witness {
|
||||||
/// Creates a new empty [`Witness`].
|
/// Creates a new empty [`Witness`].
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self { Witness::default() }
|
||||||
Witness::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates [`Witness`] object from an array of byte-arrays
|
/// Creates [`Witness`] object from an array of byte-arrays
|
||||||
#[deprecated(since="0.30.0", note="use `Witness::from_slice()` instead")]
|
#[deprecated(since = "0.30.0", note = "use `Witness::from_slice()` instead")]
|
||||||
pub fn from_vec(vec: Vec<Vec<u8>>) -> Self {
|
pub fn from_vec(vec: Vec<Vec<u8>>) -> Self { Witness::from_slice(&vec) }
|
||||||
Witness::from_slice(&vec)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a [`Witness`] object from a slice of bytes slices where each slice is a witness item.
|
/// Creates a [`Witness`] object from a slice of bytes slices where each slice is a witness item.
|
||||||
pub fn from_slice<T: AsRef<[u8]>>(slice: &[T]) -> Self {
|
pub fn from_slice<T: AsRef<[u8]>>(slice: &[T]) -> Self {
|
||||||
|
@ -197,42 +190,26 @@ impl Witness {
|
||||||
cursor += elem.as_ref().len();
|
cursor += elem.as_ref().len();
|
||||||
}
|
}
|
||||||
|
|
||||||
Witness {
|
Witness { witness_elements, content, indices_start: content_size }
|
||||||
witness_elements,
|
|
||||||
content,
|
|
||||||
indices_start: content_size,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method to create an array of byte-arrays from this witness.
|
/// Convenience method to create an array of byte-arrays from this witness.
|
||||||
pub fn to_vec(&self) -> Vec<Vec<u8>> {
|
pub fn to_vec(&self) -> Vec<Vec<u8>> { self.iter().map(|s| s.to_vec()).collect() }
|
||||||
self.iter().map(|s| s.to_vec()).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if the witness contains no element.
|
/// Returns `true` if the witness contains no element.
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool { self.witness_elements == 0 }
|
||||||
self.witness_elements == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a struct implementing [`Iterator`].
|
/// Returns a struct implementing [`Iterator`].
|
||||||
pub fn iter(&self) -> Iter {
|
pub fn iter(&self) -> Iter {
|
||||||
Iter {
|
Iter { inner: self.content.as_slice(), indices_start: self.indices_start, current_index: 0 }
|
||||||
inner: self.content.as_slice(),
|
|
||||||
indices_start: self.indices_start,
|
|
||||||
current_index: 0,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of elements this witness holds.
|
/// Returns the number of elements this witness holds.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize { self.witness_elements }
|
||||||
self.witness_elements
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the bytes required when this Witness is consensus encoded.
|
/// Returns the bytes required when this Witness is consensus encoded.
|
||||||
pub fn serialized_len(&self) -> usize {
|
pub fn serialized_len(&self) -> usize {
|
||||||
self.iter()
|
self.iter().map(|el| VarInt(el.len() as u64).len() + el.len()).sum::<usize>()
|
||||||
.map(|el| VarInt(el.len() as u64).len() + el.len())
|
|
||||||
.sum::<usize>()
|
|
||||||
+ VarInt(self.witness_elements as u64).len()
|
+ VarInt(self.witness_elements as u64).len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,12 +232,16 @@ impl Witness {
|
||||||
let element_len_varint = VarInt(new_element.len() as u64);
|
let element_len_varint = VarInt(new_element.len() as u64);
|
||||||
let current_content_len = self.content.len();
|
let current_content_len = self.content.len();
|
||||||
let new_item_total_len = element_len_varint.len() + new_element.len();
|
let new_item_total_len = element_len_varint.len() + new_element.len();
|
||||||
self.content
|
self.content.resize(current_content_len + new_item_total_len + 4, 0);
|
||||||
.resize(current_content_len + new_item_total_len + 4, 0);
|
|
||||||
|
|
||||||
self.content[previous_content_end..].rotate_right(new_item_total_len);
|
self.content[previous_content_end..].rotate_right(new_item_total_len);
|
||||||
self.indices_start += new_item_total_len;
|
self.indices_start += new_item_total_len;
|
||||||
encode_cursor(&mut self.content, self.indices_start, self.witness_elements - 1, previous_content_end);
|
encode_cursor(
|
||||||
|
&mut self.content,
|
||||||
|
self.indices_start,
|
||||||
|
self.witness_elements - 1,
|
||||||
|
previous_content_end,
|
||||||
|
);
|
||||||
|
|
||||||
let end_varint = previous_content_end + element_len_varint.len();
|
let end_varint = previous_content_end + element_len_varint.len();
|
||||||
element_len_varint
|
element_len_varint
|
||||||
|
@ -271,7 +252,11 @@ impl Witness {
|
||||||
|
|
||||||
/// Pushes a DER-encoded ECDSA signature with a signature hash type as a new element on the
|
/// Pushes a DER-encoded ECDSA signature with a signature hash type as a new element on the
|
||||||
/// witness, requires an allocation.
|
/// witness, requires an allocation.
|
||||||
pub fn push_bitcoin_signature(&mut self, signature: &ecdsa::SerializedSignature, hash_type: EcdsaSighashType) {
|
pub fn push_bitcoin_signature(
|
||||||
|
&mut self,
|
||||||
|
signature: &ecdsa::SerializedSignature,
|
||||||
|
hash_type: EcdsaSighashType,
|
||||||
|
) {
|
||||||
// Note that a maximal length ECDSA signature is 72 bytes, plus the sighash type makes 73
|
// Note that a maximal length ECDSA signature is 72 bytes, plus the sighash type makes 73
|
||||||
let mut sig = [0; 73];
|
let mut sig = [0; 73];
|
||||||
sig[..signature.len()].copy_from_slice(signature);
|
sig[..signature.len()].copy_from_slice(signature);
|
||||||
|
@ -279,7 +264,6 @@ impl Witness {
|
||||||
self.push(&sig[..signature.len() + 1]);
|
self.push(&sig[..signature.len() + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn element_at(&self, index: usize) -> Option<&[u8]> {
|
fn element_at(&self, index: usize) -> Option<&[u8]> {
|
||||||
let varint = VarInt::consensus_decode(&mut &self.content[index..]).ok()?;
|
let varint = VarInt::consensus_decode(&mut &self.content[index..]).ok()?;
|
||||||
let start = index + varint.len();
|
let start = index + varint.len();
|
||||||
|
@ -319,8 +303,7 @@ impl Witness {
|
||||||
/// check whether this is actually a Taproot witness.
|
/// check whether this is actually a Taproot witness.
|
||||||
pub fn tapscript(&self) -> Option<&Script> {
|
pub fn tapscript(&self) -> Option<&Script> {
|
||||||
let len = self.len();
|
let len = self.len();
|
||||||
self
|
self.last()
|
||||||
.last()
|
|
||||||
.map(|last_elem| {
|
.map(|last_elem| {
|
||||||
// From BIP341:
|
// From BIP341:
|
||||||
// If there are at least two witness elements, and the first byte of
|
// If there are at least two witness elements, and the first byte of
|
||||||
|
@ -335,9 +318,7 @@ impl Witness {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.filter(|&script_pos_from_last| len >= script_pos_from_last)
|
.filter(|&script_pos_from_last| len >= script_pos_from_last)
|
||||||
.and_then(|script_pos_from_last| {
|
.and_then(|script_pos_from_last| self.nth(len - script_pos_from_last))
|
||||||
self.nth(len - script_pos_from_last)
|
|
||||||
})
|
|
||||||
.map(Script::from_bytes)
|
.map(Script::from_bytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -345,9 +326,7 @@ impl Witness {
|
||||||
impl Index<usize> for Witness {
|
impl Index<usize> for Witness {
|
||||||
type Output = [u8];
|
type Output = [u8];
|
||||||
|
|
||||||
fn index(&self, index: usize) -> &Self::Output {
|
fn index(&self, index: usize) -> &Self::Output { self.nth(index).expect("Out of Bounds") }
|
||||||
self.nth(index).expect("Out of Bounds")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Iter<'a> {
|
impl<'a> Iterator for Iter<'a> {
|
||||||
|
@ -376,9 +355,7 @@ impl<'a> IntoIterator for &'a Witness {
|
||||||
type IntoIter = Iter<'a>;
|
type IntoIter = Iter<'a>;
|
||||||
type Item = &'a [u8];
|
type Item = &'a [u8];
|
||||||
|
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter { self.iter() }
|
||||||
self.iter()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serde keep backward compatibility with old Vec<Vec<u8>> format
|
// Serde keep backward compatibility with old Vec<Vec<u8>> format
|
||||||
|
@ -411,40 +388,45 @@ impl<'de> serde::Deserialize<'de> for Witness {
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
struct Visitor; // Human-readable visitor.
|
struct Visitor; // Human-readable visitor.
|
||||||
impl<'de> serde::de::Visitor<'de> for Visitor
|
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||||
{
|
|
||||||
type Value = Witness;
|
type Value = Witness;
|
||||||
|
|
||||||
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||||
write!(f, "a sequence of hex arrays")
|
write!(f, "a sequence of hex arrays")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_seq<A: serde::de::SeqAccess<'de>>(self, mut a: A) -> Result<Self::Value, A::Error>
|
fn visit_seq<A: serde::de::SeqAccess<'de>>(
|
||||||
{
|
self,
|
||||||
use crate::hashes::hex::FromHex;
|
mut a: A,
|
||||||
use crate::hashes::hex::Error::*;
|
) -> Result<Self::Value, A::Error> {
|
||||||
use serde::de::{self, Unexpected};
|
use serde::de::{self, Unexpected};
|
||||||
|
|
||||||
|
use crate::hashes::hex::Error::*;
|
||||||
|
use crate::hashes::hex::FromHex;
|
||||||
|
|
||||||
let mut ret = match a.size_hint() {
|
let mut ret = match a.size_hint() {
|
||||||
Some(len) => Vec::with_capacity(len),
|
Some(len) => Vec::with_capacity(len),
|
||||||
None => Vec::new(),
|
None => Vec::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
while let Some(elem) = a.next_element::<String>()? {
|
while let Some(elem) = a.next_element::<String>()? {
|
||||||
let vec = Vec::<u8>::from_hex(&elem).map_err(|e| {
|
let vec = Vec::<u8>::from_hex(&elem).map_err(|e| match e {
|
||||||
match e {
|
InvalidChar(b) => match core::char::from_u32(b.into()) {
|
||||||
InvalidChar(b) => {
|
Some(c) => de::Error::invalid_value(
|
||||||
match core::char::from_u32(b.into()) {
|
Unexpected::Char(c),
|
||||||
Some(c) => de::Error::invalid_value(Unexpected::Char(c), &"a valid hex character"),
|
&"a valid hex character",
|
||||||
None => de::Error::invalid_value(Unexpected::Unsigned(b.into()), &"a valid hex character")
|
),
|
||||||
}
|
None => de::Error::invalid_value(
|
||||||
}
|
Unexpected::Unsigned(b.into()),
|
||||||
OddLengthString(len) => de::Error::invalid_length(len, &"an even length string"),
|
&"a valid hex character",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
OddLengthString(len) =>
|
||||||
|
de::Error::invalid_length(len, &"an even length string"),
|
||||||
InvalidLength(expected, got) => {
|
InvalidLength(expected, got) => {
|
||||||
let exp = format!("expected length: {}", expected);
|
let exp = format!("expected length: {}", expected);
|
||||||
de::Error::invalid_length(got, &exp.as_str())
|
de::Error::invalid_length(got, &exp.as_str())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})?;
|
})?;
|
||||||
ret.push(vec);
|
ret.push(vec);
|
||||||
}
|
}
|
||||||
|
@ -462,37 +444,28 @@ impl<'de> serde::Deserialize<'de> for Witness {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec<Vec<u8>>> for Witness {
|
impl From<Vec<Vec<u8>>> for Witness {
|
||||||
fn from(vec: Vec<Vec<u8>>) -> Self {
|
fn from(vec: Vec<Vec<u8>>) -> Self { Witness::from_slice(&vec) }
|
||||||
Witness::from_slice(&vec)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&[&[u8]]> for Witness {
|
impl From<&[&[u8]]> for Witness {
|
||||||
fn from(slice: &[&[u8]]) -> Self {
|
fn from(slice: &[&[u8]]) -> Self { Witness::from_slice(slice) }
|
||||||
Witness::from_slice(slice)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&[Vec<u8>]> for Witness {
|
impl From<&[Vec<u8>]> for Witness {
|
||||||
fn from(slice: &[Vec<u8>]) -> Self {
|
fn from(slice: &[Vec<u8>]) -> Self { Witness::from_slice(slice) }
|
||||||
Witness::from_slice(slice)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Vec<&[u8]>> for Witness {
|
impl From<Vec<&[u8]>> for Witness {
|
||||||
fn from(vec: Vec<&[u8]>) -> Self {
|
fn from(vec: Vec<&[u8]>) -> Self { Witness::from_slice(&vec) }
|
||||||
Witness::from_slice(&vec)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use crate::consensus::{deserialize, serialize};
|
use crate::consensus::{deserialize, serialize};
|
||||||
use crate::internal_macros::hex;
|
use crate::internal_macros::hex;
|
||||||
use crate::Transaction;
|
|
||||||
use crate::secp256k1::ecdsa;
|
use crate::secp256k1::ecdsa;
|
||||||
|
use crate::Transaction;
|
||||||
|
|
||||||
fn append_u32_vec(mut v: Vec<u8>, n: &[u32]) -> Vec<u8> {
|
fn append_u32_vec(mut v: Vec<u8>, n: &[u32]) -> Vec<u8> {
|
||||||
for &num in n {
|
for &num in n {
|
||||||
|
@ -557,7 +530,6 @@ mod test {
|
||||||
assert_eq!(&witness[2], &[4u8, 5u8][..]);
|
assert_eq!(&witness[2], &[4u8, 5u8][..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_iter_len() {
|
fn test_iter_len() {
|
||||||
let mut witness = Witness::default();
|
let mut witness = Witness::default();
|
||||||
|
@ -588,8 +560,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_witness() {
|
fn test_witness() {
|
||||||
let w0 =
|
let w0 = hex!("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105");
|
||||||
hex!("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105");
|
|
||||||
let w1 = hex!("000000");
|
let w1 = hex!("000000");
|
||||||
let witness_vec = vec![w0.clone(), w1.clone()];
|
let witness_vec = vec![w0.clone(), w1.clone()];
|
||||||
let witness_serialized: Vec<u8> = serialize(&witness_vec);
|
let witness_serialized: Vec<u8> = serialize(&witness_vec);
|
||||||
|
@ -655,7 +626,10 @@ mod test {
|
||||||
assert_eq!(expected_wit[i], wit_el.to_lower_hex_string());
|
assert_eq!(expected_wit[i], wit_el.to_lower_hex_string());
|
||||||
}
|
}
|
||||||
assert_eq!(expected_wit[1], tx.input[0].witness.last().unwrap().to_lower_hex_string());
|
assert_eq!(expected_wit[1], tx.input[0].witness.last().unwrap().to_lower_hex_string());
|
||||||
assert_eq!(expected_wit[0], tx.input[0].witness.second_to_last().unwrap().to_lower_hex_string());
|
assert_eq!(
|
||||||
|
expected_wit[0],
|
||||||
|
tx.input[0].witness.second_to_last().unwrap().to_lower_hex_string()
|
||||||
|
);
|
||||||
assert_eq!(expected_wit[0], tx.input[0].witness.nth(0).unwrap().to_lower_hex_string());
|
assert_eq!(expected_wit[0], tx.input[0].witness.nth(0).unwrap().to_lower_hex_string());
|
||||||
assert_eq!(expected_wit[1], tx.input[0].witness.nth(1).unwrap().to_lower_hex_string());
|
assert_eq!(expected_wit[1], tx.input[0].witness.nth(1).unwrap().to_lower_hex_string());
|
||||||
assert_eq!(None, tx.input[0].witness.nth(2));
|
assert_eq!(None, tx.input[0].witness.nth(2));
|
||||||
|
@ -708,10 +682,10 @@ mod test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(bench)]
|
#[cfg(bench)]
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::{Bencher, black_box};
|
use test::{black_box, Bencher};
|
||||||
|
|
||||||
use super::Witness;
|
use super::Witness;
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
|
@ -733,5 +707,4 @@ mod benches {
|
||||||
black_box(witness.to_vec());
|
black_box(witness.to_vec());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,22 +16,23 @@
|
||||||
//! typically big-endian decimals, etc.)
|
//! typically big-endian decimals, etc.)
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use crate::prelude::*;
|
use core::convert::From;
|
||||||
|
use core::{fmt, mem, u32};
|
||||||
use core::{fmt, mem, u32, convert::From};
|
|
||||||
|
|
||||||
use bitcoin_internals::write_err;
|
use bitcoin_internals::write_err;
|
||||||
|
|
||||||
use crate::hashes::{sha256d, Hash, sha256};
|
use crate::bip152::{PrefilledTransaction, ShortId};
|
||||||
use crate::hash_types::{BlockHash, FilterHash, TxMerkleNode, FilterHeader};
|
use crate::blockdata::transaction::{Transaction, TxIn, TxOut};
|
||||||
|
use crate::hash_types::{BlockHash, FilterHash, FilterHeader, TxMerkleNode};
|
||||||
|
use crate::hashes::{sha256, sha256d, Hash};
|
||||||
use crate::io::{self, Cursor, Read};
|
use crate::io::{self, Cursor, Read};
|
||||||
|
|
||||||
use crate::bip152::{ShortId, PrefilledTransaction};
|
|
||||||
use crate::taproot::TapLeafHash;
|
|
||||||
|
|
||||||
use crate::blockdata::transaction::{TxOut, Transaction, TxIn};
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use crate::network::{message_blockdata::Inventory, address::{Address, AddrV2Message}};
|
use crate::network::{
|
||||||
|
address::{AddrV2Message, Address},
|
||||||
|
message_blockdata::Inventory,
|
||||||
|
};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::taproot::TapLeafHash;
|
||||||
|
|
||||||
/// Encoding error.
|
/// Encoding error.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -65,14 +66,14 @@ impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Error::Io(ref e) => write_err!(f, "IO error"; e),
|
Error::Io(ref e) => write_err!(f, "IO error"; e),
|
||||||
Error::OversizedVectorAllocation { requested: ref r, max: ref m } => write!(f,
|
Error::OversizedVectorAllocation { requested: ref r, max: ref m } =>
|
||||||
"allocation of oversized vector: requested {}, maximum {}", r, m),
|
write!(f, "allocation of oversized vector: requested {}, maximum {}", r, m),
|
||||||
Error::InvalidChecksum { expected: ref e, actual: ref a } => write!(f,
|
Error::InvalidChecksum { expected: ref e, actual: ref a } =>
|
||||||
"invalid checksum: expected {:x}, actual {:x}", e.as_hex(), a.as_hex()),
|
write!(f, "invalid checksum: expected {:x}, actual {:x}", e.as_hex(), a.as_hex()),
|
||||||
Error::NonMinimalVarInt => write!(f, "non-minimal varint"),
|
Error::NonMinimalVarInt => write!(f, "non-minimal varint"),
|
||||||
Error::ParseFailed(ref s) => write!(f, "parse failed: {}", s),
|
Error::ParseFailed(ref s) => write!(f, "parse failed: {}", s),
|
||||||
Error::UnsupportedSegwitFlag(ref swflag) => write!(f,
|
Error::UnsupportedSegwitFlag(ref swflag) =>
|
||||||
"unsupported segwit version: {}", swflag),
|
write!(f, "unsupported segwit version: {}", swflag),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,9 +97,7 @@ impl std::error::Error for Error {
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(error: io::Error) -> Self {
|
fn from(error: io::Error) -> Self { Error::Io(error) }
|
||||||
Error::Io(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encodes an object into a vector.
|
/// Encodes an object into a vector.
|
||||||
|
@ -137,9 +136,8 @@ pub fn deserialize_partial<T: Decodable>(data: &[u8]) -> Result<(T, usize), Erro
|
||||||
Ok((rv, consumed))
|
Ok((rv, consumed))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Extensions of `Write` to encode data as per Bitcoin consensus.
|
/// Extensions of `Write` to encode data as per Bitcoin consensus.
|
||||||
pub trait WriteExt : io::Write {
|
pub trait WriteExt: io::Write {
|
||||||
/// Outputs a 64-bit unsigned integer.
|
/// Outputs a 64-bit unsigned integer.
|
||||||
fn emit_u64(&mut self, v: u64) -> Result<(), io::Error>;
|
fn emit_u64(&mut self, v: u64) -> Result<(), io::Error>;
|
||||||
/// Outputs a 32-bit unsigned integer.
|
/// Outputs a 32-bit unsigned integer.
|
||||||
|
@ -166,7 +164,7 @@ pub trait WriteExt : io::Write {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extensions of `Read` to decode data as per Bitcoin consensus.
|
/// Extensions of `Read` to decode data as per Bitcoin consensus.
|
||||||
pub trait ReadExt : io::Read {
|
pub trait ReadExt: io::Read {
|
||||||
/// Reads a 64-bit unsigned integer.
|
/// Reads a 64-bit unsigned integer.
|
||||||
fn read_u64(&mut self) -> Result<u64, Error>;
|
fn read_u64(&mut self) -> Result<u64, Error>;
|
||||||
/// Reads a 32-bit unsigned integer.
|
/// Reads a 32-bit unsigned integer.
|
||||||
|
@ -198,7 +196,7 @@ macro_rules! encoder_fn {
|
||||||
fn $name(&mut self, v: $val_type) -> Result<(), io::Error> {
|
fn $name(&mut self, v: $val_type) -> Result<(), io::Error> {
|
||||||
self.write_all(&v.to_le_bytes())
|
self.write_all(&v.to_le_bytes())
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! decoder_fn {
|
macro_rules! decoder_fn {
|
||||||
|
@ -209,7 +207,7 @@ macro_rules! decoder_fn {
|
||||||
self.read_exact(&mut val[..]).map_err(Error::Io)?;
|
self.read_exact(&mut val[..]).map_err(Error::Io)?;
|
||||||
Ok(<$val_type>::from_le_bytes(val))
|
Ok(<$val_type>::from_le_bytes(val))
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: io::Write + ?Sized> WriteExt for W {
|
impl<W: io::Write + ?Sized> WriteExt for W {
|
||||||
|
@ -221,21 +219,13 @@ impl<W: io::Write + ?Sized> WriteExt for W {
|
||||||
encoder_fn!(emit_i16, i16);
|
encoder_fn!(emit_i16, i16);
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn emit_i8(&mut self, v: i8) -> Result<(), io::Error> {
|
fn emit_i8(&mut self, v: i8) -> Result<(), io::Error> { self.write_all(&[v as u8]) }
|
||||||
self.write_all(&[v as u8])
|
|
||||||
}
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn emit_u8(&mut self, v: u8) -> Result<(), io::Error> {
|
fn emit_u8(&mut self, v: u8) -> Result<(), io::Error> { self.write_all(&[v]) }
|
||||||
self.write_all(&[v])
|
|
||||||
}
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn emit_bool(&mut self, v: bool) -> Result<(), io::Error> {
|
fn emit_bool(&mut self, v: bool) -> Result<(), io::Error> { self.write_all(&[v as u8]) }
|
||||||
self.write_all(&[v as u8])
|
|
||||||
}
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn emit_slice(&mut self, v: &[u8]) -> Result<(), io::Error> {
|
fn emit_slice(&mut self, v: &[u8]) -> Result<(), io::Error> { self.write_all(v) }
|
||||||
self.write_all(v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read + ?Sized> ReadExt for R {
|
impl<R: Read + ?Sized> ReadExt for R {
|
||||||
|
@ -259,9 +249,7 @@ impl<R: Read + ?Sized> ReadExt for R {
|
||||||
Ok(slice[0] as i8)
|
Ok(slice[0] as i8)
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_bool(&mut self) -> Result<bool, Error> {
|
fn read_bool(&mut self) -> Result<bool, Error> { ReadExt::read_i8(self).map(|bit| bit != 0) }
|
||||||
ReadExt::read_i8(self).map(|bit| bit != 0)
|
|
||||||
}
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_slice(&mut self, slice: &mut [u8]) -> Result<(), Error> {
|
fn read_slice(&mut self, slice: &mut [u8]) -> Result<(), Error> {
|
||||||
self.read_exact(slice).map_err(Error::Io)
|
self.read_exact(slice).map_err(Error::Io)
|
||||||
|
@ -313,7 +301,9 @@ pub trait Decodable: Sized {
|
||||||
/// avoid creating redundant `Take` wrappers. Failure to do so might result only in a tiny
|
/// avoid creating redundant `Take` wrappers. Failure to do so might result only in a tiny
|
||||||
/// performance hit.
|
/// performance hit.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, Error> {
|
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(
|
||||||
|
reader: &mut R,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
// This method is always strictly less general than, `consensus_decode`, so it's safe and
|
// This method is always strictly less general than, `consensus_decode`, so it's safe and
|
||||||
// make sense to default to just calling it. This way most types, that don't care about
|
// make sense to default to just calling it. This way most types, that don't care about
|
||||||
// protecting against resource exhaustion due to malicious input, can just ignore it.
|
// protecting against resource exhaustion due to malicious input, can just ignore it.
|
||||||
|
@ -353,12 +343,15 @@ macro_rules! impl_int_encodable {
|
||||||
}
|
}
|
||||||
impl Encodable for $ty {
|
impl Encodable for $ty {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
fn consensus_encode<W: io::Write + ?Sized>(
|
||||||
|
&self,
|
||||||
|
w: &mut W,
|
||||||
|
) -> Result<usize, io::Error> {
|
||||||
w.$meth_enc(*self)?;
|
w.$meth_enc(*self)?;
|
||||||
Ok(mem::size_of::<$ty>())
|
Ok(mem::size_of::<$ty>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_int_encodable!(u8, read_u8, emit_u8);
|
impl_int_encodable!(u8, read_u8, emit_u8);
|
||||||
|
@ -398,22 +391,22 @@ impl Encodable for VarInt {
|
||||||
0..=0xFC => {
|
0..=0xFC => {
|
||||||
(self.0 as u8).consensus_encode(w)?;
|
(self.0 as u8).consensus_encode(w)?;
|
||||||
Ok(1)
|
Ok(1)
|
||||||
},
|
}
|
||||||
0xFD..=0xFFFF => {
|
0xFD..=0xFFFF => {
|
||||||
w.emit_u8(0xFD)?;
|
w.emit_u8(0xFD)?;
|
||||||
(self.0 as u16).consensus_encode(w)?;
|
(self.0 as u16).consensus_encode(w)?;
|
||||||
Ok(3)
|
Ok(3)
|
||||||
},
|
}
|
||||||
0x10000..=0xFFFFFFFF => {
|
0x10000..=0xFFFFFFFF => {
|
||||||
w.emit_u8(0xFE)?;
|
w.emit_u8(0xFE)?;
|
||||||
(self.0 as u32).consensus_encode(w)?;
|
(self.0 as u32).consensus_encode(w)?;
|
||||||
Ok(5)
|
Ok(5)
|
||||||
},
|
}
|
||||||
_ => {
|
_ => {
|
||||||
w.emit_u8(0xFF)?;
|
w.emit_u8(0xFF)?;
|
||||||
self.0.consensus_encode(w)?;
|
self.0.consensus_encode(w)?;
|
||||||
Ok(9)
|
Ok(9)
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -447,7 +440,7 @@ impl Decodable for VarInt {
|
||||||
Ok(VarInt(x as u64))
|
Ok(VarInt(x as u64))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
n => Ok(VarInt(n as u64))
|
n => Ok(VarInt(n as u64)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -508,7 +501,10 @@ macro_rules! impl_array {
|
||||||
( $size:literal ) => {
|
( $size:literal ) => {
|
||||||
impl Encodable for [u8; $size] {
|
impl Encodable for [u8; $size] {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode<W: WriteExt + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
fn consensus_encode<W: WriteExt + ?Sized>(
|
||||||
|
&self,
|
||||||
|
w: &mut W,
|
||||||
|
) -> Result<usize, io::Error> {
|
||||||
w.emit_slice(&self[..])?;
|
w.emit_slice(&self[..])?;
|
||||||
Ok(self.len())
|
Ok(self.len())
|
||||||
}
|
}
|
||||||
|
@ -549,7 +545,9 @@ impl Decodable for [u16; 8] {
|
||||||
impl Encodable for [u16; 8] {
|
impl Encodable for [u16; 8] {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||||
for c in self.iter() { c.consensus_encode(w)?; }
|
for c in self.iter() {
|
||||||
|
c.consensus_encode(w)?;
|
||||||
|
}
|
||||||
Ok(16)
|
Ok(16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -558,7 +556,10 @@ macro_rules! impl_vec {
|
||||||
($type: ty) => {
|
($type: ty) => {
|
||||||
impl Encodable for Vec<$type> {
|
impl Encodable for Vec<$type> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
fn consensus_encode<W: io::Write + ?Sized>(
|
||||||
|
&self,
|
||||||
|
w: &mut W,
|
||||||
|
) -> Result<usize, io::Error> {
|
||||||
let mut len = 0;
|
let mut len = 0;
|
||||||
len += VarInt(self.len() as u64).consensus_encode(w)?;
|
len += VarInt(self.len() as u64).consensus_encode(w)?;
|
||||||
for c in self.iter() {
|
for c in self.iter() {
|
||||||
|
@ -570,7 +571,9 @@ macro_rules! impl_vec {
|
||||||
|
|
||||||
impl Decodable for Vec<$type> {
|
impl Decodable for Vec<$type> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
|
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(
|
||||||
|
r: &mut R,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
let len = VarInt::consensus_decode_from_finite_reader(r)?.0;
|
let len = VarInt::consensus_decode_from_finite_reader(r)?.0;
|
||||||
// Do not allocate upfront more items than if the sequnce of type
|
// Do not allocate upfront more items than if the sequnce of type
|
||||||
// occupied roughly quarter a block. This should never be the case
|
// occupied roughly quarter a block. This should never be the case
|
||||||
|
@ -586,7 +589,7 @@ macro_rules! impl_vec {
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
impl_vec!(BlockHash);
|
impl_vec!(BlockHash);
|
||||||
impl_vec!(FilterHash);
|
impl_vec!(FilterHash);
|
||||||
|
@ -602,17 +605,22 @@ impl_vec!(VarInt);
|
||||||
impl_vec!(ShortId);
|
impl_vec!(ShortId);
|
||||||
impl_vec!(PrefilledTransaction);
|
impl_vec!(PrefilledTransaction);
|
||||||
|
|
||||||
#[cfg(feature = "std")] impl_vec!(Inventory);
|
#[cfg(feature = "std")]
|
||||||
#[cfg(feature = "std")] impl_vec!((u32, Address));
|
impl_vec!(Inventory);
|
||||||
#[cfg(feature = "std")] impl_vec!(AddrV2Message);
|
#[cfg(feature = "std")]
|
||||||
|
impl_vec!((u32, Address));
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl_vec!(AddrV2Message);
|
||||||
|
|
||||||
pub(crate) fn consensus_encode_with_size<S: io::Write>(data: &[u8], mut s: S) -> Result<usize, io::Error> {
|
pub(crate) fn consensus_encode_with_size<S: io::Write>(
|
||||||
|
data: &[u8],
|
||||||
|
mut s: S,
|
||||||
|
) -> Result<usize, io::Error> {
|
||||||
let vi_len = VarInt(data.len() as u64).consensus_encode(&mut s)?;
|
let vi_len = VarInt(data.len() as u64).consensus_encode(&mut s)?;
|
||||||
s.emit_slice(data)?;
|
s.emit_slice(data)?;
|
||||||
Ok(vi_len + data.len())
|
Ok(vi_len + data.len())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct ReadBytesFromFiniteReaderOpts {
|
struct ReadBytesFromFiniteReaderOpts {
|
||||||
len: usize,
|
len: usize,
|
||||||
chunk_size: usize,
|
chunk_size: usize,
|
||||||
|
@ -623,7 +631,10 @@ struct ReadBytesFromFiniteReaderOpts {
|
||||||
/// This function relies on reader being bound in amount of data
|
/// This function relies on reader being bound in amount of data
|
||||||
/// it returns for OOM protection. See [`Decodable::consensus_decode_from_finite_reader`].
|
/// it returns for OOM protection. See [`Decodable::consensus_decode_from_finite_reader`].
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_bytes_from_finite_reader<D: io::Read>(mut d: D, mut opts: ReadBytesFromFiniteReaderOpts) -> Result<Vec<u8>, Error> {
|
fn read_bytes_from_finite_reader<D: io::Read>(
|
||||||
|
mut d: D,
|
||||||
|
mut opts: ReadBytesFromFiniteReaderOpts,
|
||||||
|
) -> Result<Vec<u8>, Error> {
|
||||||
let mut ret = vec![];
|
let mut ret = vec![];
|
||||||
|
|
||||||
assert_ne!(opts.chunk_size, 0);
|
assert_ne!(opts.chunk_size, 0);
|
||||||
|
@ -652,7 +663,8 @@ impl Decodable for Vec<u8> {
|
||||||
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
|
fn consensus_decode_from_finite_reader<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
|
||||||
let len = VarInt::consensus_decode(r)?.0 as usize;
|
let len = VarInt::consensus_decode(r)?.0 as usize;
|
||||||
// most real-world vec of bytes data, wouldn't be larger than 128KiB
|
// most real-world vec of bytes data, wouldn't be larger than 128KiB
|
||||||
read_bytes_from_finite_reader(r, ReadBytesFromFiniteReaderOpts { len, chunk_size: 128 * 1024 })
|
let opts = ReadBytesFromFiniteReaderOpts { len, chunk_size: 128 * 1024 };
|
||||||
|
read_bytes_from_finite_reader(r, opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,7 +682,6 @@ impl Decodable for Box<[u8]> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Does a double-SHA256 on `data` and returns the first 4 bytes.
|
/// Does a double-SHA256 on `data` and returns the first 4 bytes.
|
||||||
fn sha2_checksum(data: &[u8]) -> [u8; 4] {
|
fn sha2_checksum(data: &[u8]) -> [u8; 4] {
|
||||||
let checksum = <sha256d::Hash as Hash>::hash(data);
|
let checksum = <sha256d::Hash as Hash>::hash(data);
|
||||||
|
@ -693,13 +704,11 @@ impl Decodable for CheckedData {
|
||||||
let len = u32::consensus_decode_from_finite_reader(r)? as usize;
|
let len = u32::consensus_decode_from_finite_reader(r)? as usize;
|
||||||
|
|
||||||
let checksum = <[u8; 4]>::consensus_decode_from_finite_reader(r)?;
|
let checksum = <[u8; 4]>::consensus_decode_from_finite_reader(r)?;
|
||||||
let ret = read_bytes_from_finite_reader(r, ReadBytesFromFiniteReaderOpts { len, chunk_size: MAX_VEC_SIZE })?;
|
let opts = ReadBytesFromFiniteReaderOpts { len, chunk_size: MAX_VEC_SIZE };
|
||||||
|
let ret = read_bytes_from_finite_reader(r, opts)?;
|
||||||
let expected_checksum = sha2_checksum(&ret);
|
let expected_checksum = sha2_checksum(&ret);
|
||||||
if expected_checksum != checksum {
|
if expected_checksum != checksum {
|
||||||
Err(self::Error::InvalidChecksum {
|
Err(self::Error::InvalidChecksum { expected: expected_checksum, actual: checksum })
|
||||||
expected: expected_checksum,
|
|
||||||
actual: checksum,
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Ok(CheckedData(ret))
|
Ok(CheckedData(ret))
|
||||||
}
|
}
|
||||||
|
@ -805,13 +814,13 @@ impl Decodable for TapLeafHash {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use core::fmt;
|
||||||
|
use core::mem::{self, discriminant};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use core::{mem::{self, discriminant}, fmt};
|
use crate::consensus::{deserialize_partial, Decodable, Encodable};
|
||||||
use super::{deserialize, serialize, Error, CheckedData, VarInt};
|
|
||||||
use super::{Transaction, BlockHash, FilterHash, TxMerkleNode, TxOut, TxIn};
|
|
||||||
use crate::consensus::{Encodable, deserialize_partial, Decodable};
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use crate::network::{Address, message_blockdata::Inventory};
|
use crate::network::{message_blockdata::Inventory, Address};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_int_test() {
|
fn serialize_int_test() {
|
||||||
|
@ -854,7 +863,10 @@ mod tests {
|
||||||
assert_eq!(serialize(&-256i64), vec![0u8, 255, 255, 255, 255, 255, 255, 255]);
|
assert_eq!(serialize(&-256i64), vec![0u8, 255, 255, 255, 255, 255, 255, 255]);
|
||||||
assert_eq!(serialize(&-5000i64), vec![120u8, 236, 255, 255, 255, 255, 255, 255]);
|
assert_eq!(serialize(&-5000i64), vec![120u8, 236, 255, 255, 255, 255, 255, 255]);
|
||||||
assert_eq!(serialize(&-500000i64), vec![224u8, 94, 248, 255, 255, 255, 255, 255]);
|
assert_eq!(serialize(&-500000i64), vec![224u8, 94, 248, 255, 255, 255, 255, 255]);
|
||||||
assert_eq!(serialize(&-723401728380766730i64), vec![246u8, 245, 245, 245, 245, 245, 245, 245]);
|
assert_eq!(
|
||||||
|
serialize(&-723401728380766730i64),
|
||||||
|
vec![246u8, 245, 245, 245, 245, 245, 245, 245]
|
||||||
|
);
|
||||||
assert_eq!(serialize(&1i64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]);
|
assert_eq!(serialize(&1i64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]);
|
||||||
assert_eq!(serialize(&256i64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]);
|
assert_eq!(serialize(&256i64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]);
|
||||||
assert_eq!(serialize(&5000i64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]);
|
assert_eq!(serialize(&5000i64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]);
|
||||||
|
@ -869,8 +881,14 @@ mod tests {
|
||||||
assert_eq!(serialize(&VarInt(0xFD)), vec![0xFDu8, 0xFD, 0]);
|
assert_eq!(serialize(&VarInt(0xFD)), vec![0xFDu8, 0xFD, 0]);
|
||||||
assert_eq!(serialize(&VarInt(0xFFF)), vec![0xFDu8, 0xFF, 0xF]);
|
assert_eq!(serialize(&VarInt(0xFFF)), vec![0xFDu8, 0xFF, 0xF]);
|
||||||
assert_eq!(serialize(&VarInt(0xF0F0F0F)), vec![0xFEu8, 0xF, 0xF, 0xF, 0xF]);
|
assert_eq!(serialize(&VarInt(0xF0F0F0F)), vec![0xFEu8, 0xF, 0xF, 0xF, 0xF]);
|
||||||
assert_eq!(serialize(&VarInt(0xF0F0F0F0F0E0)), vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0]);
|
assert_eq!(
|
||||||
assert_eq!(test_varint_encode(0xFF, &0x100000000_u64.to_le_bytes()).unwrap(), VarInt(0x100000000));
|
serialize(&VarInt(0xF0F0F0F0F0E0)),
|
||||||
|
vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
test_varint_encode(0xFF, &0x100000000_u64.to_le_bytes()).unwrap(),
|
||||||
|
VarInt(0x100000000)
|
||||||
|
);
|
||||||
assert_eq!(test_varint_encode(0xFE, &0x10000_u64.to_le_bytes()).unwrap(), VarInt(0x10000));
|
assert_eq!(test_varint_encode(0xFE, &0x10000_u64.to_le_bytes()).unwrap(), VarInt(0x10000));
|
||||||
assert_eq!(test_varint_encode(0xFD, &0xFD_u64.to_le_bytes()).unwrap(), VarInt(0xFD));
|
assert_eq!(test_varint_encode(0xFD, &0xFD_u64.to_le_bytes()).unwrap(), VarInt(0xFD));
|
||||||
|
|
||||||
|
@ -881,7 +899,7 @@ mod tests {
|
||||||
test_varint_len(VarInt(0xFFFF), 3);
|
test_varint_len(VarInt(0xFFFF), 3);
|
||||||
test_varint_len(VarInt(0x10000), 5);
|
test_varint_len(VarInt(0x10000), 5);
|
||||||
test_varint_len(VarInt(0xFFFFFFFF), 5);
|
test_varint_len(VarInt(0xFFFFFFFF), 5);
|
||||||
test_varint_len(VarInt(0xFFFFFFFF+1), 9);
|
test_varint_len(VarInt(0xFFFFFFFF + 1), 9);
|
||||||
test_varint_len(VarInt(u64::max_value()), 9);
|
test_varint_len(VarInt(u64::max_value()), 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -894,35 +912,62 @@ mod tests {
|
||||||
fn test_varint_encode(n: u8, x: &[u8]) -> Result<VarInt, Error> {
|
fn test_varint_encode(n: u8, x: &[u8]) -> Result<VarInt, Error> {
|
||||||
let mut input = [0u8; 9];
|
let mut input = [0u8; 9];
|
||||||
input[0] = n;
|
input[0] = n;
|
||||||
input[1..x.len()+1].copy_from_slice(x);
|
input[1..x.len() + 1].copy_from_slice(x);
|
||||||
deserialize_partial::<VarInt>(&input).map(|t|t.0)
|
deserialize_partial::<VarInt>(&input).map(|t| t.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deserialize_nonminimal_vec() {
|
fn deserialize_nonminimal_vec() {
|
||||||
// Check the edges for variant int
|
// Check the edges for variant int
|
||||||
assert_eq!(discriminant(&test_varint_encode(0xFF, &(0x100000000_u64-1).to_le_bytes()).unwrap_err()),
|
assert_eq!(
|
||||||
discriminant(&Error::NonMinimalVarInt));
|
discriminant(
|
||||||
assert_eq!(discriminant(&test_varint_encode(0xFE, &(0x10000_u64-1).to_le_bytes()).unwrap_err()),
|
&test_varint_encode(0xFF, &(0x100000000_u64 - 1).to_le_bytes()).unwrap_err()
|
||||||
discriminant(&Error::NonMinimalVarInt));
|
),
|
||||||
assert_eq!(discriminant(&test_varint_encode(0xFD, &(0xFD_u64-1).to_le_bytes()).unwrap_err()),
|
discriminant(&Error::NonMinimalVarInt)
|
||||||
discriminant(&Error::NonMinimalVarInt));
|
);
|
||||||
|
assert_eq!(
|
||||||
assert_eq!(discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0x00, 0x00]).unwrap_err()),
|
discriminant(&test_varint_encode(0xFE, &(0x10000_u64 - 1).to_le_bytes()).unwrap_err()),
|
||||||
discriminant(&Error::NonMinimalVarInt));
|
discriminant(&Error::NonMinimalVarInt)
|
||||||
assert_eq!(discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
|
);
|
||||||
discriminant(&Error::NonMinimalVarInt));
|
assert_eq!(
|
||||||
assert_eq!(discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
|
discriminant(&test_varint_encode(0xFD, &(0xFD_u64 - 1).to_le_bytes()).unwrap_err()),
|
||||||
discriminant(&Error::NonMinimalVarInt));
|
discriminant(&Error::NonMinimalVarInt)
|
||||||
assert_eq!(discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0x00, 0x00, 0x00]).unwrap_err()),
|
);
|
||||||
discriminant(&Error::NonMinimalVarInt));
|
|
||||||
assert_eq!(discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0xff, 0x00, 0x00]).unwrap_err()),
|
|
||||||
discriminant(&Error::NonMinimalVarInt));
|
|
||||||
assert_eq!(discriminant(&deserialize::<Vec<u8>>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]).unwrap_err()),
|
|
||||||
discriminant(&Error::NonMinimalVarInt));
|
|
||||||
assert_eq!(discriminant(&deserialize::<Vec<u8>>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00]).unwrap_err()),
|
|
||||||
discriminant(&Error::NonMinimalVarInt));
|
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0x00, 0x00]).unwrap_err()),
|
||||||
|
discriminant(&Error::NonMinimalVarInt)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
|
||||||
|
discriminant(&Error::NonMinimalVarInt)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
|
||||||
|
discriminant(&Error::NonMinimalVarInt)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0x00, 0x00, 0x00]).unwrap_err()),
|
||||||
|
discriminant(&Error::NonMinimalVarInt)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0xff, 0x00, 0x00]).unwrap_err()),
|
||||||
|
discriminant(&Error::NonMinimalVarInt)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
discriminant(
|
||||||
|
&deserialize::<Vec<u8>>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
|
||||||
|
.unwrap_err()
|
||||||
|
),
|
||||||
|
discriminant(&Error::NonMinimalVarInt)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
discriminant(
|
||||||
|
&deserialize::<Vec<u8>>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00])
|
||||||
|
.unwrap_err()
|
||||||
|
),
|
||||||
|
discriminant(&Error::NonMinimalVarInt)
|
||||||
|
);
|
||||||
|
|
||||||
let mut vec_256 = vec![0; 259];
|
let mut vec_256 = vec![0; 259];
|
||||||
vec_256[0] = 0xfd;
|
vec_256[0] = 0xfd;
|
||||||
|
@ -1003,21 +1048,38 @@ mod tests {
|
||||||
|
|
||||||
// u64
|
// u64
|
||||||
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABu64));
|
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABu64));
|
||||||
assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(0x99000099CDAB0DA0u64));
|
assert_eq!(
|
||||||
|
deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(),
|
||||||
|
Some(0x99000099CDAB0DA0u64)
|
||||||
|
);
|
||||||
let failure64: Result<u64, _> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
|
let failure64: Result<u64, _> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
|
||||||
assert!(failure64.is_err());
|
assert!(failure64.is_err());
|
||||||
|
|
||||||
// i64
|
// i64
|
||||||
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABi64));
|
assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABi64));
|
||||||
assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(-0x66ffff663254f260i64));
|
assert_eq!(
|
||||||
assert_eq!(deserialize(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).ok(), Some(-1_i64));
|
deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(),
|
||||||
assert_eq!(deserialize(&[0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).ok(), Some(-2_i64));
|
Some(-0x66ffff663254f260i64)
|
||||||
assert_eq!(deserialize(&[0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).ok(), Some(-255_i64));
|
);
|
||||||
assert_eq!(deserialize(&[0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).ok(), Some(-254_i64));
|
assert_eq!(
|
||||||
|
deserialize(&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).ok(),
|
||||||
|
Some(-1_i64)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
deserialize(&[0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).ok(),
|
||||||
|
Some(-2_i64)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
deserialize(&[0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).ok(),
|
||||||
|
Some(-255_i64)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
deserialize(&[0x02, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]).ok(),
|
||||||
|
Some(-254_i64)
|
||||||
|
);
|
||||||
|
|
||||||
let failurei64: Result<i64, _> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
|
let failurei64: Result<i64, _> = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]);
|
||||||
assert!(failurei64.is_err());
|
assert!(failurei64.is_err());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1025,13 +1087,18 @@ mod tests {
|
||||||
assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4]));
|
assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4]));
|
||||||
assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result<Vec<u8>, _>).is_err());
|
assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result<Vec<u8>, _>).is_err());
|
||||||
// found by cargo fuzz
|
// found by cargo fuzz
|
||||||
assert!(deserialize::<Vec<u64>>(&[0xff,0xff,0xff,0xff,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0xa,0xa,0x3a]).is_err());
|
assert!(deserialize::<Vec<u64>>(&[
|
||||||
|
0xff, 0xff, 0xff, 0xff, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b, 0x6b,
|
||||||
|
0x6b, 0x6b, 0xa, 0xa, 0x3a
|
||||||
|
])
|
||||||
|
.is_err());
|
||||||
|
|
||||||
let rand_io_err = Error::Io(io::Error::new(io::ErrorKind::Other, ""));
|
let rand_io_err = Error::Io(io::Error::new(io::ErrorKind::Other, ""));
|
||||||
|
|
||||||
// Check serialization that `if len > MAX_VEC_SIZE {return err}` isn't inclusive,
|
// Check serialization that `if len > MAX_VEC_SIZE {return err}` isn't inclusive,
|
||||||
// by making sure it fails with IO Error and not an `OversizedVectorAllocation` Error.
|
// by making sure it fails with IO Error and not an `OversizedVectorAllocation` Error.
|
||||||
let err = deserialize::<CheckedData>(&serialize(&(super::MAX_VEC_SIZE as u32))).unwrap_err();
|
let err =
|
||||||
|
deserialize::<CheckedData>(&serialize(&(super::MAX_VEC_SIZE as u32))).unwrap_err();
|
||||||
assert_eq!(discriminant(&err), discriminant(&rand_io_err));
|
assert_eq!(discriminant(&err), discriminant(&rand_io_err));
|
||||||
|
|
||||||
test_len_is_max_vec::<u8>();
|
test_len_is_max_vec::<u8>();
|
||||||
|
@ -1049,7 +1116,11 @@ mod tests {
|
||||||
test_len_is_max_vec::<Inventory>();
|
test_len_is_max_vec::<Inventory>();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_len_is_max_vec<T>() where Vec<T>: Decodable, T: fmt::Debug {
|
fn test_len_is_max_vec<T>()
|
||||||
|
where
|
||||||
|
Vec<T>: Decodable,
|
||||||
|
T: fmt::Debug,
|
||||||
|
{
|
||||||
let rand_io_err = Error::Io(io::Error::new(io::ErrorKind::Other, ""));
|
let rand_io_err = Error::Io(io::Error::new(io::ErrorKind::Other, ""));
|
||||||
let varint = VarInt((super::MAX_VEC_SIZE / mem::size_of::<T>()) as u64);
|
let varint = VarInt((super::MAX_VEC_SIZE / mem::size_of::<T>()) as u64);
|
||||||
let err = deserialize::<Vec<T>>(&serialize(&varint)).unwrap_err();
|
let err = deserialize::<Vec<T>>(&serialize(&varint)).unwrap_err();
|
||||||
|
@ -1058,7 +1129,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deserialize_strbuf_test() {
|
fn deserialize_strbuf_test() {
|
||||||
assert_eq!(deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), Some("Andrew".to_string()));
|
assert_eq!(
|
||||||
|
deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(),
|
||||||
|
Some("Andrew".to_string())
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(),
|
deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(),
|
||||||
Some(Cow::Borrowed("Andrew"))
|
Some(Cow::Borrowed("Andrew"))
|
||||||
|
@ -1067,7 +1141,8 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn deserialize_checkeddata_test() {
|
fn deserialize_checkeddata_test() {
|
||||||
let cd: Result<CheckedData, _> = deserialize(&[5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]);
|
let cd: Result<CheckedData, _> =
|
||||||
|
deserialize(&[5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]);
|
||||||
assert_eq!(cd.ok(), Some(CheckedData(vec![1u8, 2, 3, 4, 5])));
|
assert_eq!(cd.ok(), Some(CheckedData(vec![1u8, 2, 3, 4, 5])));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1105,7 +1180,7 @@ mod tests {
|
||||||
let mut data = Vec::with_capacity(256);
|
let mut data = Vec::with_capacity(256);
|
||||||
let mut data64 = Vec::with_capacity(256);
|
let mut data64 = Vec::with_capacity(256);
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
round_trip!{bool, i8, u8, i16, u16, i32, u32, i64, u64,
|
round_trip! {bool, i8, u8, i16, u16, i32, u32, i64, u64,
|
||||||
(bool, i8, u16, i32), (u64, i64, u32, i32, u16, i16), (i8, u8, i16, u16, i32, u32, i64, u64),
|
(bool, i8, u16, i32), (u64, i64, u32, i32, u16, i16), (i8, u8, i16, u16, i32, u32, i64, u64),
|
||||||
[u8; 2], [u8; 4], [u8; 8], [u8; 12], [u8; 16], [u8; 32]};
|
[u8; 2], [u8; 4], [u8; 8], [u8; 12], [u8; 16], [u8; 32]};
|
||||||
|
|
||||||
|
@ -1116,22 +1191,21 @@ mod tests {
|
||||||
data64.resize(len, 0u64);
|
data64.resize(len, 0u64);
|
||||||
let mut arr33 = [0u8; 33];
|
let mut arr33 = [0u8; 33];
|
||||||
let mut arr16 = [0u16; 8];
|
let mut arr16 = [0u16; 8];
|
||||||
round_trip_bytes!{(Vec<u8>, data), ([u8; 33], arr33), ([u16; 8], arr16), (Vec<u64>, data64)};
|
round_trip_bytes! {(Vec<u8>, data), ([u8; 33], arr33), ([u16; 8], arr16), (Vec<u64>, data64)};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_read_bytes_from_finite_reader() {
|
fn test_read_bytes_from_finite_reader() {
|
||||||
let data : Vec<u8> = (0..10).collect();
|
let data: Vec<u8> = (0..10).collect();
|
||||||
|
|
||||||
for chunk_size in 1..20 {
|
for chunk_size in 1..20 {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
read_bytes_from_finite_reader(
|
read_bytes_from_finite_reader(
|
||||||
io::Cursor::new(&data),
|
io::Cursor::new(&data),
|
||||||
ReadBytesFromFiniteReaderOpts { len: data.len(), chunk_size }
|
ReadBytesFromFiniteReaderOpts { len: data.len(), chunk_size }
|
||||||
).unwrap(),
|
)
|
||||||
|
.unwrap(),
|
||||||
data
|
data
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,9 @@
|
||||||
pub mod encode;
|
pub mod encode;
|
||||||
pub mod params;
|
pub mod params;
|
||||||
|
|
||||||
pub use self::encode::{Encodable, Decodable, WriteExt, ReadExt};
|
pub use self::encode::{
|
||||||
pub use self::encode::{serialize, deserialize, deserialize_partial};
|
deserialize, deserialize_partial, serialize, Decodable, Encodable, ReadExt, WriteExt,
|
||||||
|
};
|
||||||
pub use self::params::Params;
|
pub use self::params::Params;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
|
|
@ -9,20 +9,22 @@
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use crate::io;
|
|
||||||
use serde::{Serializer, Deserializer};
|
use serde::de::{SeqAccess, Unexpected, Visitor};
|
||||||
use serde::de::{Visitor, SeqAccess, Unexpected};
|
|
||||||
use serde::ser::SerializeSeq;
|
use serde::ser::SerializeSeq;
|
||||||
use super::{Encodable, Decodable};
|
use serde::{Deserializer, Serializer};
|
||||||
|
|
||||||
use super::encode::Error as ConsensusError;
|
use super::encode::Error as ConsensusError;
|
||||||
|
use super::{Decodable, Encodable};
|
||||||
|
use crate::io;
|
||||||
|
|
||||||
/// Hex-encoding strategy
|
/// Hex-encoding strategy
|
||||||
pub struct Hex<Case = hex::Lower>(PhantomData<Case>) where Case: hex::Case;
|
pub struct Hex<Case = hex::Lower>(PhantomData<Case>)
|
||||||
|
where
|
||||||
|
Case: hex::Case;
|
||||||
|
|
||||||
impl<C: hex::Case> Default for Hex<C> {
|
impl<C: hex::Case> Default for Hex<C> {
|
||||||
fn default() -> Self {
|
fn default() -> Self { Hex(Default::default()) }
|
||||||
Hex(Default::default())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: hex::Case> ByteEncoder for Hex<C> {
|
impl<C: hex::Case> ByteEncoder for Hex<C> {
|
||||||
|
@ -33,6 +35,7 @@ impl<C: hex::Case> ByteEncoder for Hex<C> {
|
||||||
pub mod hex {
|
pub mod hex {
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use bitcoin_internals as internals;
|
use bitcoin_internals as internals;
|
||||||
use internals::hex::BufEncoder;
|
use internals::hex::BufEncoder;
|
||||||
|
|
||||||
|
@ -131,9 +134,7 @@ pub mod hex {
|
||||||
type DecodeError = DecodeError;
|
type DecodeError = DecodeError;
|
||||||
type Decoder = Decoder<'a>;
|
type Decoder = Decoder<'a>;
|
||||||
|
|
||||||
fn from_str(s: &'a str) -> Result<Self::Decoder, Self::InitError> {
|
fn from_str(s: &'a str) -> Result<Self::Decoder, Self::InitError> { Decoder::new(s) }
|
||||||
Decoder::new(s)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl super::IntoDeError for DecodeInitError {
|
impl super::IntoDeError for DecodeInitError {
|
||||||
|
@ -141,7 +142,8 @@ pub mod hex {
|
||||||
use bitcoin_hashes::hex::Error;
|
use bitcoin_hashes::hex::Error;
|
||||||
|
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Error::OddLengthString(len) => E::invalid_length(len, &"an even number of ASCII-encoded hex digits"),
|
Error::OddLengthString(len) =>
|
||||||
|
E::invalid_length(len, &"an even number of ASCII-encoded hex digits"),
|
||||||
error => panic!("unexpected error: {:?}", error),
|
error => panic!("unexpected error: {:?}", error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,8 +157,10 @@ pub mod hex {
|
||||||
const EXPECTED_CHAR: &str = "an ASCII-encoded hex digit";
|
const EXPECTED_CHAR: &str = "an ASCII-encoded hex digit";
|
||||||
|
|
||||||
match self.0 {
|
match self.0 {
|
||||||
Error::InvalidChar(c) if c.is_ascii() => E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR),
|
Error::InvalidChar(c) if c.is_ascii() =>
|
||||||
Error::InvalidChar(c) => E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR),
|
E::invalid_value(Unexpected::Char(c as _), &EXPECTED_CHAR),
|
||||||
|
Error::InvalidChar(c) =>
|
||||||
|
E::invalid_value(Unexpected::Unsigned(c.into()), &EXPECTED_CHAR),
|
||||||
error => panic!("unexpected error: {:?}", error),
|
error => panic!("unexpected error: {:?}", error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,8 +177,15 @@ impl<'a, T: 'a + Encodable, E: ByteEncoder> fmt::Display for DisplayWrapper<'a,
|
||||||
{
|
{
|
||||||
use crate::StdError;
|
use crate::StdError;
|
||||||
|
|
||||||
if error.kind() != io::ErrorKind::Other || error.source().is_some() || !writer.writer.was_error {
|
if error.kind() != io::ErrorKind::Other
|
||||||
panic!("{} returned an unexpected error: {:?}", core::any::type_name::<T>(), error);
|
|| error.source().is_some()
|
||||||
|
|| !writer.writer.was_error
|
||||||
|
{
|
||||||
|
panic!(
|
||||||
|
"{} returned an unexpected error: {:?}",
|
||||||
|
core::any::type_name::<T>(),
|
||||||
|
error
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmt::Error
|
fmt::Error
|
||||||
|
@ -255,15 +266,10 @@ struct IoWrapper<'a, W: fmt::Write, E: EncodeBytes> {
|
||||||
|
|
||||||
impl<'a, W: fmt::Write, E: EncodeBytes> IoWrapper<'a, W, E> {
|
impl<'a, W: fmt::Write, E: EncodeBytes> IoWrapper<'a, W, E> {
|
||||||
fn new(writer: &'a mut W, encoder: E) -> Self {
|
fn new(writer: &'a mut W, encoder: E) -> Self {
|
||||||
IoWrapper {
|
IoWrapper { writer: ErrorTrackingWriter::new(writer), encoder }
|
||||||
writer: ErrorTrackingWriter::new(writer),
|
|
||||||
encoder,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn actually_flush(&mut self) -> fmt::Result {
|
fn actually_flush(&mut self) -> fmt::Result { self.encoder.flush(&mut self.writer) }
|
||||||
self.encoder.flush(&mut self.writer)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, W: fmt::Write, E: EncodeBytes> io::Write for IoWrapper<'a, W, E> {
|
impl<'a, W: fmt::Write, E: EncodeBytes> io::Write for IoWrapper<'a, W, E> {
|
||||||
|
@ -319,7 +325,7 @@ pub trait ByteDecoder<'a> {
|
||||||
type DecodeError: IntoDeError + fmt::Debug;
|
type DecodeError: IntoDeError + fmt::Debug;
|
||||||
|
|
||||||
/// The decoder state.
|
/// The decoder state.
|
||||||
type Decoder: Iterator<Item=Result<u8, Self::DecodeError>>;
|
type Decoder: Iterator<Item = Result<u8, Self::DecodeError>>;
|
||||||
|
|
||||||
/// Constructs the decoder from string.
|
/// Constructs the decoder from string.
|
||||||
fn from_str(s: &'a str) -> Result<Self::Decoder, Self::InitError>;
|
fn from_str(s: &'a str) -> Result<Self::Decoder, Self::InitError>;
|
||||||
|
@ -331,15 +337,13 @@ pub trait IntoDeError {
|
||||||
fn into_de_error<E: serde::de::Error>(self) -> E;
|
fn into_de_error<E: serde::de::Error>(self) -> E;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BinWriter<S: SerializeSeq>{
|
struct BinWriter<S: SerializeSeq> {
|
||||||
serializer: S,
|
serializer: S,
|
||||||
error: Option<S::Error>,
|
error: Option<S::Error>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: SerializeSeq> io::Write for BinWriter<S> {
|
impl<S: SerializeSeq> io::Write for BinWriter<S> {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.write_all(buf).map(|_| buf.len()) }
|
||||||
self.write_all(buf).map(|_| buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
|
||||||
for byte in buf {
|
for byte in buf {
|
||||||
|
@ -372,15 +376,29 @@ enum DecodeError<E> {
|
||||||
fn consensus_error_into_serde<E: serde::de::Error>(error: ConsensusError) -> E {
|
fn consensus_error_into_serde<E: serde::de::Error>(error: ConsensusError) -> E {
|
||||||
match error {
|
match error {
|
||||||
ConsensusError::Io(error) => panic!("unexpected IO error {:?}", error),
|
ConsensusError::Io(error) => panic!("unexpected IO error {:?}", error),
|
||||||
ConsensusError::OversizedVectorAllocation { requested, max } => E::custom(format_args!("the requested allocation of {} items exceeds maximum of {}", requested, max)),
|
ConsensusError::OversizedVectorAllocation { requested, max } => E::custom(format_args!(
|
||||||
ConsensusError::InvalidChecksum { expected, actual } => E::invalid_value(Unexpected::Bytes(&actual), &DisplayExpected(format_args!("checksum {:02x}{:02x}{:02x}{:02x}", expected[0], expected[1], expected[2], expected[3]))),
|
"the requested allocation of {} items exceeds maximum of {}",
|
||||||
ConsensusError::NonMinimalVarInt => E::custom(format_args!("compact size was not encoded minimally")),
|
requested, max
|
||||||
|
)),
|
||||||
|
ConsensusError::InvalidChecksum { expected, actual } => E::invalid_value(
|
||||||
|
Unexpected::Bytes(&actual),
|
||||||
|
&DisplayExpected(format_args!(
|
||||||
|
"checksum {:02x}{:02x}{:02x}{:02x}",
|
||||||
|
expected[0], expected[1], expected[2], expected[3]
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
ConsensusError::NonMinimalVarInt =>
|
||||||
|
E::custom(format_args!("compact size was not encoded minimally")),
|
||||||
ConsensusError::ParseFailed(msg) => E::custom(msg),
|
ConsensusError::ParseFailed(msg) => E::custom(msg),
|
||||||
ConsensusError::UnsupportedSegwitFlag(flag) => E::invalid_value(Unexpected::Unsigned(flag.into()), &"segwit version 1 flag"),
|
ConsensusError::UnsupportedSegwitFlag(flag) =>
|
||||||
|
E::invalid_value(Unexpected::Unsigned(flag.into()), &"segwit version 1 flag"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> DecodeError<E> where E: serde::de::Error {
|
impl<E> DecodeError<E>
|
||||||
|
where
|
||||||
|
E: serde::de::Error,
|
||||||
|
{
|
||||||
fn unify(self) -> E {
|
fn unify(self) -> E {
|
||||||
match self {
|
match self {
|
||||||
DecodeError::Other(error) => error,
|
DecodeError::Other(error) => error,
|
||||||
|
@ -390,7 +408,10 @@ impl<E> DecodeError<E> where E: serde::de::Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> IntoDeError for DecodeError<E> where E: IntoDeError {
|
impl<E> IntoDeError for DecodeError<E>
|
||||||
|
where
|
||||||
|
E: IntoDeError,
|
||||||
|
{
|
||||||
fn into_de_error<DE: serde::de::Error>(self) -> DE {
|
fn into_de_error<DE: serde::de::Error>(self) -> DE {
|
||||||
match self {
|
match self {
|
||||||
DecodeError::Other(error) => error.into_de_error(),
|
DecodeError::Other(error) => error.into_de_error(),
|
||||||
|
@ -400,18 +421,13 @@ impl<E> IntoDeError for DecodeError<E> where E: IntoDeError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IterReader<E: fmt::Debug, I: Iterator<Item=Result<u8, E>>> {
|
struct IterReader<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> {
|
||||||
iterator: core::iter::Fuse<I>,
|
iterator: core::iter::Fuse<I>,
|
||||||
error: Option<E>,
|
error: Option<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: fmt::Debug, I: Iterator<Item=Result<u8, E>>> IterReader<E, I> {
|
impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> IterReader<E, I> {
|
||||||
fn new(iterator: I) -> Self {
|
fn new(iterator: I) -> Self { IterReader { iterator: iterator.fuse(), error: None } }
|
||||||
IterReader {
|
|
||||||
iterator: iterator.fuse(),
|
|
||||||
error: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> {
|
fn decode<T: Decodable>(mut self) -> Result<T, DecodeError<E>> {
|
||||||
use crate::StdError;
|
use crate::StdError;
|
||||||
|
@ -431,7 +447,7 @@ impl<E: fmt::Debug, I: Iterator<Item=Result<u8, E>>> IterReader<E, I> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: fmt::Debug, I: Iterator<Item=Result<u8, E>>> io::Read for IterReader<E, I> {
|
impl<E: fmt::Debug, I: Iterator<Item = Result<u8, E>>> io::Read for IterReader<E, I> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
for (dst, src) in buf.iter_mut().zip(&mut self.iterator) {
|
for (dst, src) in buf.iter_mut().zip(&mut self.iterator) {
|
||||||
|
@ -469,30 +485,46 @@ pub struct With<E>(PhantomData<E>);
|
||||||
|
|
||||||
impl<E> With<E> {
|
impl<E> With<E> {
|
||||||
/// Serializes the value as consensus-encoded
|
/// Serializes the value as consensus-encoded
|
||||||
pub fn serialize<T: Encodable, S: Serializer>(value: &T, serializer: S) -> Result<S::Ok, S::Error> where E: ByteEncoder {
|
pub fn serialize<T: Encodable, S: Serializer>(
|
||||||
|
value: &T,
|
||||||
|
serializer: S,
|
||||||
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
E: ByteEncoder,
|
||||||
|
{
|
||||||
if serializer.is_human_readable() {
|
if serializer.is_human_readable() {
|
||||||
serializer.collect_str(&DisplayWrapper::<'_, _, E>(value, Default::default()))
|
serializer.collect_str(&DisplayWrapper::<'_, _, E>(value, Default::default()))
|
||||||
} else {
|
} else {
|
||||||
use crate::StdError;
|
use crate::StdError;
|
||||||
|
|
||||||
let serializer = serializer.serialize_seq(None)?;
|
let serializer = serializer.serialize_seq(None)?;
|
||||||
let mut writer = BinWriter {
|
let mut writer = BinWriter { serializer, error: None };
|
||||||
serializer,
|
|
||||||
error: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = value.consensus_encode(&mut writer);
|
let result = value.consensus_encode(&mut writer);
|
||||||
match (result, writer.error) {
|
match (result, writer.error) {
|
||||||
(Ok(_), None) => writer.serializer.end(),
|
(Ok(_), None) => writer.serializer.end(),
|
||||||
(Ok(_), Some(error)) => panic!("{} silently ate an IO error: {:?}", core::any::type_name::<T>(), error),
|
(Ok(_), Some(error)) =>
|
||||||
(Err(io_error), Some(ser_error)) if io_error.kind() == io::ErrorKind::Other && io_error.source().is_none() => Err(ser_error),
|
panic!("{} silently ate an IO error: {:?}", core::any::type_name::<T>(), error),
|
||||||
(Err(io_error), ser_error) => panic!("{} returned an unexpected IO error: {:?} serialization error: {:?}", core::any::type_name::<T>(), io_error, ser_error),
|
(Err(io_error), Some(ser_error))
|
||||||
|
if io_error.kind() == io::ErrorKind::Other && io_error.source().is_none() =>
|
||||||
|
Err(ser_error),
|
||||||
|
(Err(io_error), ser_error) => panic!(
|
||||||
|
"{} returned an unexpected IO error: {:?} serialization error: {:?}",
|
||||||
|
core::any::type_name::<T>(),
|
||||||
|
io_error,
|
||||||
|
ser_error
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserializes the value as consensus-encoded
|
/// Deserializes the value as consensus-encoded
|
||||||
pub fn deserialize<'d, T: Decodable, D: Deserializer<'d>>(deserializer: D) -> Result<T, D::Error> where for<'a> E: ByteDecoder<'a> {
|
pub fn deserialize<'d, T: Decodable, D: Deserializer<'d>>(
|
||||||
|
deserializer: D,
|
||||||
|
) -> Result<T, D::Error>
|
||||||
|
where
|
||||||
|
for<'a> E: ByteDecoder<'a>,
|
||||||
|
{
|
||||||
if deserializer.is_human_readable() {
|
if deserializer.is_human_readable() {
|
||||||
deserializer.deserialize_str(HRVisitor::<_, E>(Default::default()))
|
deserializer.deserialize_str(HRVisitor::<_, E>(Default::default()))
|
||||||
} else {
|
} else {
|
||||||
|
@ -535,7 +567,5 @@ struct SeqIterator<'a, S: serde::de::SeqAccess<'a>>(S, PhantomData<&'a ()>);
|
||||||
impl<'a, S: serde::de::SeqAccess<'a>> Iterator for SeqIterator<'a, S> {
|
impl<'a, S: serde::de::SeqAccess<'a>> Iterator for SeqIterator<'a, S> {
|
||||||
type Item = Result<u8, S::Error>;
|
type Item = Result<u8, S::Error>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> { self.0.next_element::<u8>().transpose() }
|
||||||
self.0.next_element::<u8>().transpose()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use core::{fmt, iter};
|
use core::{fmt, iter};
|
||||||
|
|
||||||
use bitcoin_internals::write_err;
|
|
||||||
use bitcoin_internals::hex::display::DisplayHex;
|
use bitcoin_internals::hex::display::DisplayHex;
|
||||||
|
use bitcoin_internals::write_err;
|
||||||
use secp256k1;
|
use secp256k1;
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
use crate::hashes::hex::{self, FromHex};
|
use crate::hashes::hex::{self, FromHex};
|
||||||
use crate::sighash::{EcdsaSighashType, NonStandardSighashType};
|
use crate::prelude::*;
|
||||||
use crate::script::PushBytes;
|
use crate::script::PushBytes;
|
||||||
|
use crate::sighash::{EcdsaSighashType, NonStandardSighashType};
|
||||||
|
|
||||||
const MAX_SIG_LEN: usize = 73;
|
const MAX_SIG_LEN: usize = 73;
|
||||||
|
|
||||||
|
@ -33,20 +33,15 @@ pub struct Signature {
|
||||||
impl Signature {
|
impl Signature {
|
||||||
/// Constructs an ECDSA bitcoin signature for [`EcdsaSighashType::All`].
|
/// Constructs an ECDSA bitcoin signature for [`EcdsaSighashType::All`].
|
||||||
pub fn sighash_all(sig: secp256k1::ecdsa::Signature) -> Signature {
|
pub fn sighash_all(sig: secp256k1::ecdsa::Signature) -> Signature {
|
||||||
Signature {
|
Signature { sig, hash_ty: EcdsaSighashType::All }
|
||||||
sig,
|
|
||||||
hash_ty: EcdsaSighashType::All
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Deserializes from slice following the standardness rules for [`EcdsaSighashType`].
|
/// Deserializes from slice following the standardness rules for [`EcdsaSighashType`].
|
||||||
pub fn from_slice(sl: &[u8]) -> Result<Self, Error> {
|
pub fn from_slice(sl: &[u8]) -> Result<Self, Error> {
|
||||||
let (hash_ty, sig) = sl.split_last()
|
let (hash_ty, sig) = sl.split_last().ok_or(Error::EmptySignature)?;
|
||||||
.ok_or(Error::EmptySignature)?;
|
|
||||||
let hash_ty = EcdsaSighashType::from_standard(*hash_ty as u32)
|
let hash_ty = EcdsaSighashType::from_standard(*hash_ty as u32)
|
||||||
.map_err(|_| Error::NonStandardSighashType(*hash_ty as u32))?;
|
.map_err(|_| Error::NonStandardSighashType(*hash_ty as u32))?;
|
||||||
let sig = secp256k1::ecdsa::Signature::from_der(sig)
|
let sig = secp256k1::ecdsa::Signature::from_der(sig).map_err(Error::Secp256k1)?;
|
||||||
.map_err(Error::Secp256k1)?;
|
|
||||||
Ok(Signature { sig, hash_ty })
|
Ok(Signature { sig, hash_ty })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,10 +53,7 @@ impl Signature {
|
||||||
let signature = self.sig.serialize_der();
|
let signature = self.sig.serialize_der();
|
||||||
buf[..signature.len()].copy_from_slice(&signature);
|
buf[..signature.len()].copy_from_slice(&signature);
|
||||||
buf[signature.len()] = self.hash_ty as u8;
|
buf[signature.len()] = self.hash_ty as u8;
|
||||||
SerializedSignature {
|
SerializedSignature { data: buf, len: signature.len() + 1 }
|
||||||
data: buf,
|
|
||||||
len: signature.len() + 1,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serializes an ECDSA signature (inner secp256k1 signature in DER format) into `Vec`.
|
/// Serializes an ECDSA signature (inner secp256k1 signature in DER format) into `Vec`.
|
||||||
|
@ -70,10 +62,7 @@ impl Signature {
|
||||||
/// [`serialize`](Self::serialize) method instead.
|
/// [`serialize`](Self::serialize) method instead.
|
||||||
pub fn to_vec(self) -> Vec<u8> {
|
pub fn to_vec(self) -> Vec<u8> {
|
||||||
// TODO: add support to serialize to a writer to SerializedSig
|
// TODO: add support to serialize to a writer to SerializedSig
|
||||||
self.sig.serialize_der()
|
self.sig.serialize_der().iter().copied().chain(iter::once(self.hash_ty as u8)).collect()
|
||||||
.iter().copied()
|
|
||||||
.chain(iter::once(self.hash_ty as u8))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +78,10 @@ impl FromStr for Signature {
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
let bytes = Vec::from_hex(s)?;
|
let bytes = Vec::from_hex(s)?;
|
||||||
let (sighash_byte, signature) = bytes.split_last()
|
let (sighash_byte, signature) = bytes.split_last().ok_or(Error::EmptySignature)?;
|
||||||
.ok_or(Error::EmptySignature)?;
|
|
||||||
Ok(Signature {
|
Ok(Signature {
|
||||||
sig: secp256k1::ecdsa::Signature::from_der(signature)?,
|
sig: secp256k1::ecdsa::Signature::from_der(signature)?,
|
||||||
hash_ty: EcdsaSighashType::from_standard(*sighash_byte as u32)?
|
hash_ty: EcdsaSighashType::from_standard(*sighash_byte as u32)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,60 +102,44 @@ pub struct SerializedSignature {
|
||||||
impl SerializedSignature {
|
impl SerializedSignature {
|
||||||
/// Returns an iterator over bytes of the signature.
|
/// Returns an iterator over bytes of the signature.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn iter(&self) -> core::slice::Iter<'_, u8> {
|
pub fn iter(&self) -> core::slice::Iter<'_, u8> { self.into_iter() }
|
||||||
self.into_iter()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::ops::Deref for SerializedSignature {
|
impl core::ops::Deref for SerializedSignature {
|
||||||
type Target = [u8];
|
type Target = [u8];
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target { &self.data[..self.len] }
|
||||||
&self.data[..self.len]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::ops::DerefMut for SerializedSignature {
|
impl core::ops::DerefMut for SerializedSignature {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.data[..self.len] }
|
||||||
&mut self.data[..self.len]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<[u8]> for SerializedSignature {
|
impl AsRef<[u8]> for SerializedSignature {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsMut<[u8]> for SerializedSignature {
|
impl AsMut<[u8]> for SerializedSignature {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_mut(&mut self) -> &mut [u8] {
|
fn as_mut(&mut self) -> &mut [u8] { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<PushBytes> for SerializedSignature {
|
impl AsRef<PushBytes> for SerializedSignature {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn as_ref(&self) -> &PushBytes {
|
fn as_ref(&self) -> &PushBytes { &<&PushBytes>::from(&self.data)[..self.len()] }
|
||||||
&<&PushBytes>::from(&self.data)[..self.len()]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::borrow::Borrow<[u8]> for SerializedSignature {
|
impl core::borrow::Borrow<[u8]> for SerializedSignature {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn borrow(&self) -> &[u8] {
|
fn borrow(&self) -> &[u8] { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::borrow::BorrowMut<[u8]> for SerializedSignature {
|
impl core::borrow::BorrowMut<[u8]> for SerializedSignature {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn borrow_mut(&mut self) -> &mut [u8] {
|
fn borrow_mut(&mut self) -> &mut [u8] { self }
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for SerializedSignature {
|
impl fmt::Debug for SerializedSignature {
|
||||||
|
@ -202,9 +174,7 @@ impl PartialEq for SerializedSignature {
|
||||||
impl Eq for SerializedSignature {}
|
impl Eq for SerializedSignature {}
|
||||||
|
|
||||||
impl core::hash::Hash for SerializedSignature {
|
impl core::hash::Hash for SerializedSignature {
|
||||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: core::hash::Hasher>(&self, state: &mut H) { core::hash::Hash::hash(&**self, state) }
|
||||||
core::hash::Hash::hash(&**self, state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IntoIterator for &'a SerializedSignature {
|
impl<'a> IntoIterator for &'a SerializedSignature {
|
||||||
|
@ -212,9 +182,7 @@ impl<'a> IntoIterator for &'a SerializedSignature {
|
||||||
type Item = &'a u8;
|
type Item = &'a u8;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn into_iter(self) -> Self::IntoIter {
|
fn into_iter(self) -> Self::IntoIter { (*self).iter() }
|
||||||
(*self).iter()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A key-related error.
|
/// A key-related error.
|
||||||
|
@ -231,18 +199,14 @@ pub enum Error {
|
||||||
Secp256k1(secp256k1::Error),
|
Secp256k1(secp256k1::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
Error::HexEncoding(ref e) =>
|
Error::HexEncoding(ref e) => write_err!(f, "Signature hex encoding error"; e),
|
||||||
write_err!(f, "Signature hex encoding error"; e),
|
|
||||||
Error::NonStandardSighashType(hash_ty) =>
|
Error::NonStandardSighashType(hash_ty) =>
|
||||||
write!(f, "Non standard signature hash type {}", hash_ty),
|
write!(f, "Non standard signature hash type {}", hash_ty),
|
||||||
Error::EmptySignature =>
|
Error::EmptySignature => write!(f, "Empty ECDSA signature"),
|
||||||
write!(f, "Empty ECDSA signature"),
|
Error::Secp256k1(ref e) => write_err!(f, "invalid ECDSA signature"; e),
|
||||||
Error::Secp256k1(ref e) =>
|
|
||||||
write_err!(f, "invalid ECDSA signature"; e),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -262,19 +226,13 @@ impl std::error::Error for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<secp256k1::Error> for Error {
|
impl From<secp256k1::Error> for Error {
|
||||||
fn from(e: secp256k1::Error) -> Error {
|
fn from(e: secp256k1::Error) -> Error { Error::Secp256k1(e) }
|
||||||
Error::Secp256k1(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<NonStandardSighashType> for Error {
|
impl From<NonStandardSighashType> for Error {
|
||||||
fn from(err: NonStandardSighashType) -> Self {
|
fn from(err: NonStandardSighashType) -> Self { Error::NonStandardSighashType(err.0) }
|
||||||
Error::NonStandardSighashType(err.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<hex::Error> for Error {
|
impl From<hex::Error> for Error {
|
||||||
fn from(err: hex::Error) -> Self {
|
fn from(err: hex::Error) -> Self { Error::HexEncoding(err) }
|
||||||
Error::HexEncoding(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,20 +6,20 @@
|
||||||
//! This module provides keys used in Bitcoin that can be roundtrip
|
//! This module provides keys used in Bitcoin that can be roundtrip
|
||||||
//! (de)serialized.
|
//! (de)serialized.
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
use core::{ops, str::FromStr};
|
|
||||||
use core::fmt::{self, Write};
|
use core::fmt::{self, Write};
|
||||||
|
use core::ops;
|
||||||
|
use core::str::FromStr;
|
||||||
|
|
||||||
use bitcoin_internals::write_err;
|
use bitcoin_internals::write_err;
|
||||||
|
pub use secp256k1::{self, constants, KeyPair, Parity, Secp256k1, Verification, XOnlyPublicKey};
|
||||||
|
|
||||||
pub use secp256k1::{self, constants, Secp256k1, KeyPair, XOnlyPublicKey, Verification, Parity};
|
|
||||||
|
|
||||||
use crate::{base58, io};
|
|
||||||
use crate::network::constants::Network;
|
|
||||||
use crate::hashes::{Hash, hash160, hex, hex::FromHex};
|
|
||||||
use crate::hash_types::{PubkeyHash, WPubkeyHash};
|
use crate::hash_types::{PubkeyHash, WPubkeyHash};
|
||||||
|
use crate::hashes::hex::FromHex;
|
||||||
|
use crate::hashes::{hash160, hex, Hash};
|
||||||
|
use crate::network::constants::Network;
|
||||||
|
use crate::prelude::*;
|
||||||
use crate::taproot::{TapNodeHash, TapTweakHash};
|
use crate::taproot::{TapNodeHash, TapTweakHash};
|
||||||
|
use crate::{base58, io};
|
||||||
|
|
||||||
/// A key-related error.
|
/// A key-related error.
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
@ -44,7 +44,8 @@ impl fmt::Display for Error {
|
||||||
Error::Secp256k1(ref e) => write_err!(f, "key secp256k1 error"; e),
|
Error::Secp256k1(ref e) => write_err!(f, "key secp256k1 error"; e),
|
||||||
Error::InvalidKeyPrefix(ref b) => write!(f, "key prefix invalid: {}", b),
|
Error::InvalidKeyPrefix(ref b) => write!(f, "key prefix invalid: {}", b),
|
||||||
Error::Hex(ref e) => write_err!(f, "key hex decoding error"; e),
|
Error::Hex(ref e) => write_err!(f, "key hex decoding error"; e),
|
||||||
Error::InvalidHexLength(got) => write!(f, "PublicKey hex should be 66 or 130 digits long, got: {}", got),
|
Error::InvalidHexLength(got) =>
|
||||||
|
write!(f, "PublicKey hex should be 66 or 130 digits long, got: {}", got),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,26 +67,19 @@ impl std::error::Error for Error {
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
impl From<base58::Error> for Error {
|
impl From<base58::Error> for Error {
|
||||||
fn from(e: base58::Error) -> Error {
|
fn from(e: base58::Error) -> Error { Error::Base58(e) }
|
||||||
Error::Base58(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
impl From<secp256k1::Error> for Error {
|
impl From<secp256k1::Error> for Error {
|
||||||
fn from(e: secp256k1::Error) -> Error {
|
fn from(e: secp256k1::Error) -> Error { Error::Secp256k1(e) }
|
||||||
Error::Secp256k1(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
impl From<hex::Error> for Error {
|
impl From<hex::Error> for Error {
|
||||||
fn from(e: hex::Error) -> Self {
|
fn from(e: hex::Error) -> Self { Error::Hex(e) }
|
||||||
Error::Hex(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A Bitcoin ECDSA public key
|
/// A Bitcoin ECDSA public key
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct PublicKey {
|
pub struct PublicKey {
|
||||||
|
@ -98,19 +92,13 @@ pub struct PublicKey {
|
||||||
impl PublicKey {
|
impl PublicKey {
|
||||||
/// Constructs compressed ECDSA public key from the provided generic Secp256k1 public key
|
/// Constructs compressed ECDSA public key from the provided generic Secp256k1 public key
|
||||||
pub fn new(key: impl Into<secp256k1::PublicKey>) -> PublicKey {
|
pub fn new(key: impl Into<secp256k1::PublicKey>) -> PublicKey {
|
||||||
PublicKey {
|
PublicKey { compressed: true, inner: key.into() }
|
||||||
compressed: true,
|
|
||||||
inner: key.into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs uncompressed (legacy) ECDSA public key from the provided generic Secp256k1
|
/// Constructs uncompressed (legacy) ECDSA public key from the provided generic Secp256k1
|
||||||
/// public key
|
/// public key
|
||||||
pub fn new_uncompressed(key: impl Into<secp256k1::PublicKey>) -> PublicKey {
|
pub fn new_uncompressed(key: impl Into<secp256k1::PublicKey>) -> PublicKey {
|
||||||
PublicKey {
|
PublicKey { compressed: false, inner: key.into() }
|
||||||
compressed: false,
|
|
||||||
inner: key.into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_serialized<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
fn with_serialized<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
|
||||||
|
@ -122,15 +110,13 @@ impl PublicKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns bitcoin 160-bit hash of the public key
|
/// Returns bitcoin 160-bit hash of the public key
|
||||||
pub fn pubkey_hash(&self) -> PubkeyHash {
|
pub fn pubkey_hash(&self) -> PubkeyHash { self.with_serialized(PubkeyHash::hash) }
|
||||||
self.with_serialized(PubkeyHash::hash)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns bitcoin 160-bit hash of the public key for witness program
|
/// Returns bitcoin 160-bit hash of the public key for witness program
|
||||||
pub fn wpubkey_hash(&self) -> Option<WPubkeyHash> {
|
pub fn wpubkey_hash(&self) -> Option<WPubkeyHash> {
|
||||||
if self.compressed {
|
if self.compressed {
|
||||||
Some(WPubkeyHash::from_byte_array(
|
Some(WPubkeyHash::from_byte_array(
|
||||||
hash160::Hash::hash(&self.inner.serialize()).to_byte_array()
|
hash160::Hash::hash(&self.inner.serialize()).to_byte_array(),
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
// We can't create witness pubkey hashes for an uncompressed
|
// We can't create witness pubkey hashes for an uncompressed
|
||||||
|
@ -251,24 +237,23 @@ impl PublicKey {
|
||||||
65 => false,
|
65 => false,
|
||||||
len => {
|
len => {
|
||||||
return Err(base58::Error::InvalidLength(len).into());
|
return Err(base58::Error::InvalidLength(len).into());
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if !compressed && data[0] != 0x04 {
|
if !compressed && data[0] != 0x04 {
|
||||||
return Err(Error::InvalidKeyPrefix(data[0]))
|
return Err(Error::InvalidKeyPrefix(data[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(PublicKey {
|
Ok(PublicKey { compressed, inner: secp256k1::PublicKey::from_slice(data)? })
|
||||||
compressed,
|
|
||||||
inner: secp256k1::PublicKey::from_slice(data)?,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the public key as supposed to be used with this secret
|
/// Computes the public key as supposed to be used with this secret
|
||||||
pub fn from_private_key<C: secp256k1::Signing>(secp: &Secp256k1<C>, sk: &PrivateKey) -> PublicKey {
|
pub fn from_private_key<C: secp256k1::Signing>(
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
sk: &PrivateKey,
|
||||||
|
) -> PublicKey {
|
||||||
sk.public_key(secp)
|
sk.public_key(secp)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An opaque return type for PublicKey::to_sort_key
|
/// An opaque return type for PublicKey::to_sort_key
|
||||||
|
@ -299,9 +284,7 @@ impl FromStr for PublicKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<PublicKey> for PubkeyHash {
|
impl From<PublicKey> for PubkeyHash {
|
||||||
fn from(key: PublicKey) -> PubkeyHash {
|
fn from(key: PublicKey) -> PubkeyHash { key.pubkey_hash() }
|
||||||
key.pubkey_hash()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Bitcoin ECDSA private key
|
/// A Bitcoin ECDSA private key
|
||||||
|
@ -320,35 +303,25 @@ impl PrivateKey {
|
||||||
/// Constructs compressed ECDSA private key from the provided generic Secp256k1 private key
|
/// Constructs compressed ECDSA private key from the provided generic Secp256k1 private key
|
||||||
/// and the specified network
|
/// and the specified network
|
||||||
pub fn new(key: secp256k1::SecretKey, network: Network) -> PrivateKey {
|
pub fn new(key: secp256k1::SecretKey, network: Network) -> PrivateKey {
|
||||||
PrivateKey {
|
PrivateKey { compressed: true, network, inner: key }
|
||||||
compressed: true,
|
|
||||||
network,
|
|
||||||
inner: key,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs uncompressed (legacy) ECDSA private key from the provided generic Secp256k1
|
/// Constructs uncompressed (legacy) ECDSA private key from the provided generic Secp256k1
|
||||||
/// private key and the specified network
|
/// private key and the specified network
|
||||||
pub fn new_uncompressed(key: secp256k1::SecretKey, network: Network) -> PrivateKey {
|
pub fn new_uncompressed(key: secp256k1::SecretKey, network: Network) -> PrivateKey {
|
||||||
PrivateKey {
|
PrivateKey { compressed: false, network, inner: key }
|
||||||
compressed: false,
|
|
||||||
network,
|
|
||||||
inner: key,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a public key from this private key
|
/// Creates a public key from this private key
|
||||||
pub fn public_key<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> PublicKey {
|
pub fn public_key<C: secp256k1::Signing>(&self, secp: &Secp256k1<C>) -> PublicKey {
|
||||||
PublicKey {
|
PublicKey {
|
||||||
compressed: self.compressed,
|
compressed: self.compressed,
|
||||||
inner: secp256k1::PublicKey::from_secret_key(secp, &self.inner)
|
inner: secp256k1::PublicKey::from_secret_key(secp, &self.inner),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialize the private key to bytes
|
/// Serialize the private key to bytes
|
||||||
pub fn to_bytes(self) -> Vec<u8> {
|
pub fn to_bytes(self) -> Vec<u8> { self.inner[..].to_vec() }
|
||||||
self.inner[..].to_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Deserialize a private key from a slice
|
/// Deserialize a private key from a slice
|
||||||
pub fn from_slice(data: &[u8], network: Network) -> Result<PrivateKey, Error> {
|
pub fn from_slice(data: &[u8], network: Network) -> Result<PrivateKey, Error> {
|
||||||
|
@ -409,30 +382,22 @@ impl PrivateKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for PrivateKey {
|
impl fmt::Display for PrivateKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_wif(f) }
|
||||||
self.fmt_wif(f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
impl fmt::Debug for PrivateKey {
|
impl fmt::Debug for PrivateKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[private key data]") }
|
||||||
write!(f, "[private key data]")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for PrivateKey {
|
impl FromStr for PrivateKey {
|
||||||
type Err = Error;
|
type Err = Error;
|
||||||
fn from_str(s: &str) -> Result<PrivateKey, Error> {
|
fn from_str(s: &str) -> Result<PrivateKey, Error> { PrivateKey::from_wif(s) }
|
||||||
PrivateKey::from_wif(s)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ops::Index<ops::RangeFull> for PrivateKey {
|
impl ops::Index<ops::RangeFull> for PrivateKey {
|
||||||
type Output = [u8];
|
type Output = [u8];
|
||||||
fn index(&self, _: ops::RangeFull) -> &[u8] {
|
fn index(&self, _: ops::RangeFull) -> &[u8] { &self.inner[..] }
|
||||||
&self.inner[..]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
@ -559,15 +524,11 @@ pub type UntweakedPublicKey = XOnlyPublicKey;
|
||||||
pub struct TweakedPublicKey(XOnlyPublicKey);
|
pub struct TweakedPublicKey(XOnlyPublicKey);
|
||||||
|
|
||||||
impl fmt::LowerHex for TweakedPublicKey {
|
impl fmt::LowerHex for TweakedPublicKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
|
||||||
fmt::LowerHex::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for TweakedPublicKey {
|
impl fmt::Display for TweakedPublicKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
|
||||||
fmt::Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Untweaked BIP-340 key pair
|
/// Untweaked BIP-340 key pair
|
||||||
|
@ -613,7 +574,11 @@ pub trait TapTweak {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The tweaked key and its parity.
|
/// The tweaked key and its parity.
|
||||||
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> Self::TweakedAux;
|
fn tap_tweak<C: Verification>(
|
||||||
|
self,
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
merkle_root: Option<TapNodeHash>,
|
||||||
|
) -> Self::TweakedAux;
|
||||||
|
|
||||||
/// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`]
|
/// Directly converts an [`UntweakedPublicKey`] to a [`TweakedPublicKey`]
|
||||||
///
|
///
|
||||||
|
@ -638,7 +603,11 @@ impl TapTweak for UntweakedPublicKey {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The tweaked key and its parity.
|
/// The tweaked key and its parity.
|
||||||
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> (TweakedPublicKey, Parity) {
|
fn tap_tweak<C: Verification>(
|
||||||
|
self,
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
merkle_root: Option<TapNodeHash>,
|
||||||
|
) -> (TweakedPublicKey, Parity) {
|
||||||
let tweak = TapTweakHash::from_key_and_tweak(self, merkle_root).to_scalar();
|
let tweak = TapTweakHash::from_key_and_tweak(self, merkle_root).to_scalar();
|
||||||
let (output_key, parity) = self.add_tweak(secp, &tweak).expect("Tap tweak failed");
|
let (output_key, parity) = self.add_tweak(secp, &tweak).expect("Tap tweak failed");
|
||||||
|
|
||||||
|
@ -646,9 +615,7 @@ impl TapTweak for UntweakedPublicKey {
|
||||||
(TweakedPublicKey(output_key), parity)
|
(TweakedPublicKey(output_key), parity)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dangerous_assume_tweaked(self) -> TweakedPublicKey {
|
fn dangerous_assume_tweaked(self) -> TweakedPublicKey { TweakedPublicKey(self) }
|
||||||
TweakedPublicKey(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TapTweak for UntweakedKeyPair {
|
impl TapTweak for UntweakedKeyPair {
|
||||||
|
@ -667,16 +634,18 @@ impl TapTweak for UntweakedKeyPair {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// The tweaked key and its parity.
|
/// The tweaked key and its parity.
|
||||||
fn tap_tweak<C: Verification>(self, secp: &Secp256k1<C>, merkle_root: Option<TapNodeHash>) -> TweakedKeyPair {
|
fn tap_tweak<C: Verification>(
|
||||||
|
self,
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
merkle_root: Option<TapNodeHash>,
|
||||||
|
) -> TweakedKeyPair {
|
||||||
let (pubkey, _parity) = XOnlyPublicKey::from_keypair(&self);
|
let (pubkey, _parity) = XOnlyPublicKey::from_keypair(&self);
|
||||||
let tweak = TapTweakHash::from_key_and_tweak(pubkey, merkle_root).to_scalar();
|
let tweak = TapTweakHash::from_key_and_tweak(pubkey, merkle_root).to_scalar();
|
||||||
let tweaked = self.add_xonly_tweak(secp, &tweak).expect("Tap tweak failed");
|
let tweaked = self.add_xonly_tweak(secp, &tweak).expect("Tap tweak failed");
|
||||||
TweakedKeyPair(tweaked)
|
TweakedKeyPair(tweaked)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dangerous_assume_tweaked(self) -> TweakedKeyPair {
|
fn dangerous_assume_tweaked(self) -> TweakedKeyPair { TweakedKeyPair(self) }
|
||||||
TweakedKeyPair(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TweakedPublicKey {
|
impl TweakedPublicKey {
|
||||||
|
@ -698,17 +667,13 @@ impl TweakedPublicKey {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying public key.
|
/// Returns the underlying public key.
|
||||||
pub fn to_inner(self) -> XOnlyPublicKey {
|
pub fn to_inner(self) -> XOnlyPublicKey { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serialize the key as a byte-encoded pair of values. In compressed form
|
/// Serialize the key as a byte-encoded pair of values. In compressed form
|
||||||
/// the y-coordinate is represented by only a single bit, as x determines
|
/// the y-coordinate is represented by only a single bit, as x determines
|
||||||
/// it up to one bit.
|
/// it up to one bit.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn serialize(&self) -> [u8; constants::SCHNORR_PUBLIC_KEY_SIZE] {
|
pub fn serialize(&self) -> [u8; constants::SCHNORR_PUBLIC_KEY_SIZE] { self.0.serialize() }
|
||||||
self.0.serialize()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TweakedKeyPair {
|
impl TweakedKeyPair {
|
||||||
|
@ -718,15 +683,11 @@ impl TweakedKeyPair {
|
||||||
/// This method is dangerous and can lead to loss of funds if used incorrectly.
|
/// This method is dangerous and can lead to loss of funds if used incorrectly.
|
||||||
/// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
|
/// Specifically, in multi-party protocols a peer can provide a value that allows them to steal.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn dangerous_assume_tweaked(pair: KeyPair) -> TweakedKeyPair {
|
pub fn dangerous_assume_tweaked(pair: KeyPair) -> TweakedKeyPair { TweakedKeyPair(pair) }
|
||||||
TweakedKeyPair(pair)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the underlying key pair.
|
/// Returns the underlying key pair.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_inner(self) -> KeyPair {
|
pub fn to_inner(self) -> KeyPair { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the [`TweakedPublicKey`] and its [`Parity`] for this [`TweakedKeyPair`].
|
/// Returns the [`TweakedPublicKey`] and its [`Parity`] for this [`TweakedKeyPair`].
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -738,43 +699,36 @@ impl TweakedKeyPair {
|
||||||
|
|
||||||
impl From<TweakedPublicKey> for XOnlyPublicKey {
|
impl From<TweakedPublicKey> for XOnlyPublicKey {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(pair: TweakedPublicKey) -> Self {
|
fn from(pair: TweakedPublicKey) -> Self { pair.0 }
|
||||||
pair.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TweakedKeyPair> for KeyPair {
|
impl From<TweakedKeyPair> for KeyPair {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(pair: TweakedKeyPair) -> Self {
|
fn from(pair: TweakedKeyPair) -> Self { pair.0 }
|
||||||
pair.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TweakedKeyPair> for TweakedPublicKey {
|
impl From<TweakedKeyPair> for TweakedPublicKey {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(pair: TweakedKeyPair) -> Self {
|
fn from(pair: TweakedKeyPair) -> Self { TweakedPublicKey::from_keypair(pair) }
|
||||||
TweakedPublicKey::from_keypair(pair)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use secp256k1::Secp256k1;
|
use secp256k1::Secp256k1;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
use crate::address::Address;
|
use crate::address::Address;
|
||||||
use crate::hashes::hex::FromHex;
|
use crate::hashes::hex::FromHex;
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::network::constants::Network::Testnet;
|
use crate::network::constants::Network::{Bitcoin, Testnet};
|
||||||
use crate::network::constants::Network::Bitcoin;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_derivation() {
|
fn test_key_derivation() {
|
||||||
// testnet compressed
|
// testnet compressed
|
||||||
let sk = PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap();
|
let sk =
|
||||||
|
PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap();
|
||||||
assert_eq!(sk.network, Testnet);
|
assert_eq!(sk.network, Testnet);
|
||||||
assert!(sk.compressed);
|
assert!(sk.compressed);
|
||||||
assert_eq!(&sk.to_wif(), "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy");
|
assert_eq!(&sk.to_wif(), "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy");
|
||||||
|
@ -790,7 +744,8 @@ mod tests {
|
||||||
assert_eq!(&sk.to_wif(), &sk_str.to_wif());
|
assert_eq!(&sk.to_wif(), &sk_str.to_wif());
|
||||||
|
|
||||||
// mainnet uncompressed
|
// mainnet uncompressed
|
||||||
let sk = PrivateKey::from_wif("5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3").unwrap();
|
let sk =
|
||||||
|
PrivateKey::from_wif("5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3").unwrap();
|
||||||
assert_eq!(sk.network, Bitcoin);
|
assert_eq!(sk.network, Bitcoin);
|
||||||
assert!(!sk.compressed);
|
assert!(!sk.compressed);
|
||||||
assert_eq!(&sk.to_wif(), "5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3");
|
assert_eq!(&sk.to_wif(), "5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3");
|
||||||
|
@ -803,13 +758,25 @@ mod tests {
|
||||||
let addr = Address::p2pkh(&pk, sk.network);
|
let addr = Address::p2pkh(&pk, sk.network);
|
||||||
assert_eq!(&addr.to_string(), "1GhQvF6dL8xa6wBxLnWmHcQsurx9RxiMc8");
|
assert_eq!(&addr.to_string(), "1GhQvF6dL8xa6wBxLnWmHcQsurx9RxiMc8");
|
||||||
pk.compressed = true;
|
pk.compressed = true;
|
||||||
assert_eq!(&pk.to_string(), "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af");
|
assert_eq!(
|
||||||
assert_eq!(pk, PublicKey::from_str("032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af").unwrap());
|
&pk.to_string(),
|
||||||
|
"032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
pk,
|
||||||
|
PublicKey::from_str(
|
||||||
|
"032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af"
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_pubkey_hash() {
|
fn test_pubkey_hash() {
|
||||||
let pk = PublicKey::from_str("032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af").unwrap();
|
let pk = PublicKey::from_str(
|
||||||
|
"032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let upk = PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap();
|
let upk = PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap();
|
||||||
assert_eq!(pk.pubkey_hash().to_string(), "9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4");
|
assert_eq!(pk.pubkey_hash().to_string(), "9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4");
|
||||||
assert_eq!(upk.pubkey_hash().to_string(), "ac2e7daf42d2c97418fd9f78af2de552bb9c6a7a");
|
assert_eq!(upk.pubkey_hash().to_string(), "ac2e7daf42d2c97418fd9f78af2de552bb9c6a7a");
|
||||||
|
@ -817,16 +784,22 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_wpubkey_hash() {
|
fn test_wpubkey_hash() {
|
||||||
let pk = PublicKey::from_str("032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af").unwrap();
|
let pk = PublicKey::from_str(
|
||||||
|
"032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let upk = PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap();
|
let upk = PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap();
|
||||||
assert_eq!(pk.wpubkey_hash().unwrap().to_string(), "9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4");
|
assert_eq!(
|
||||||
|
pk.wpubkey_hash().unwrap().to_string(),
|
||||||
|
"9511aa27ef39bbfa4e4f3dd15f4d66ea57f475b4"
|
||||||
|
);
|
||||||
assert_eq!(upk.wpubkey_hash(), None);
|
assert_eq!(upk.wpubkey_hash(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_serde() {
|
fn test_key_serde() {
|
||||||
use serde_test::{Configure, Token, assert_tokens};
|
use serde_test::{assert_tokens, Configure, Token};
|
||||||
|
|
||||||
static KEY_WIF: &str = "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy";
|
static KEY_WIF: &str = "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy";
|
||||||
static PK_STR: &str = "039b6347398505f5ec93826dc61c19f47c66c0283ee9be980e29ce325a0f4679ef";
|
static PK_STR: &str = "039b6347398505f5ec93826dc61c19f47c66c0283ee9be980e29ce325a0f4679ef";
|
||||||
|
@ -835,6 +808,7 @@ mod tests {
|
||||||
9b6347398505f5ec93826dc61c19f47c66c0283ee9be980e29ce325a0f4679ef\
|
9b6347398505f5ec93826dc61c19f47c66c0283ee9be980e29ce325a0f4679ef\
|
||||||
87288ed73ce47fc4f5c79d19ebfa57da7cff3aff6e819e4ee971d86b5e61875d\
|
87288ed73ce47fc4f5c79d19ebfa57da7cff3aff6e819e4ee971d86b5e61875d\
|
||||||
";
|
";
|
||||||
|
#[rustfmt::skip]
|
||||||
static PK_BYTES: [u8; 33] = [
|
static PK_BYTES: [u8; 33] = [
|
||||||
0x03,
|
0x03,
|
||||||
0x9b, 0x63, 0x47, 0x39, 0x85, 0x05, 0xf5, 0xec,
|
0x9b, 0x63, 0x47, 0x39, 0x85, 0x05, 0xf5, 0xec,
|
||||||
|
@ -842,6 +816,7 @@ mod tests {
|
||||||
0x66, 0xc0, 0x28, 0x3e, 0xe9, 0xbe, 0x98, 0x0e,
|
0x66, 0xc0, 0x28, 0x3e, 0xe9, 0xbe, 0x98, 0x0e,
|
||||||
0x29, 0xce, 0x32, 0x5a, 0x0f, 0x46, 0x79, 0xef,
|
0x29, 0xce, 0x32, 0x5a, 0x0f, 0x46, 0x79, 0xef,
|
||||||
];
|
];
|
||||||
|
#[rustfmt::skip]
|
||||||
static PK_BYTES_U: [u8; 65] = [
|
static PK_BYTES_U: [u8; 65] = [
|
||||||
0x04,
|
0x04,
|
||||||
0x9b, 0x63, 0x47, 0x39, 0x85, 0x05, 0xf5, 0xec,
|
0x9b, 0x63, 0x47, 0x39, 0x85, 0x05, 0xf5, 0xec,
|
||||||
|
@ -857,10 +832,7 @@ mod tests {
|
||||||
let s = Secp256k1::new();
|
let s = Secp256k1::new();
|
||||||
let sk = PrivateKey::from_str(KEY_WIF).unwrap();
|
let sk = PrivateKey::from_str(KEY_WIF).unwrap();
|
||||||
let pk = PublicKey::from_private_key(&s, &sk);
|
let pk = PublicKey::from_private_key(&s, &sk);
|
||||||
let pk_u = PublicKey {
|
let pk_u = PublicKey { inner: pk.inner, compressed: false };
|
||||||
inner: pk.inner,
|
|
||||||
compressed: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_tokens(&sk, &[Token::BorrowedStr(KEY_WIF)]);
|
assert_tokens(&sk, &[Token::BorrowedStr(KEY_WIF)]);
|
||||||
assert_tokens(&pk.compact(), &[Token::BorrowedBytes(&PK_BYTES[..])]);
|
assert_tokens(&pk.compact(), &[Token::BorrowedBytes(&PK_BYTES[..])]);
|
||||||
|
@ -920,26 +892,29 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn pubkey_to_sort_key() {
|
fn pubkey_to_sort_key() {
|
||||||
let key1 = PublicKey::from_str("02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8").unwrap();
|
let key1 = PublicKey::from_str(
|
||||||
let key2 = PublicKey {
|
"02ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8",
|
||||||
inner: key1.inner,
|
)
|
||||||
compressed: false,
|
.unwrap();
|
||||||
};
|
let key2 = PublicKey { inner: key1.inner, compressed: false };
|
||||||
let expected1 = SortKey(
|
let expected1 = SortKey(
|
||||||
2,
|
2,
|
||||||
<[u8; 32]>::from_hex(
|
<[u8; 32]>::from_hex(
|
||||||
"ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8",
|
"ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8",
|
||||||
).unwrap(),
|
)
|
||||||
|
.unwrap(),
|
||||||
[0_u8; 32],
|
[0_u8; 32],
|
||||||
);
|
);
|
||||||
let expected2 = SortKey(
|
let expected2 = SortKey(
|
||||||
4,
|
4,
|
||||||
<[u8; 32]>::from_hex(
|
<[u8; 32]>::from_hex(
|
||||||
"ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8",
|
"ff12471208c14bd580709cb2358d98975247d8765f92bc25eab3b2763ed605f8",
|
||||||
).unwrap(),
|
)
|
||||||
|
.unwrap(),
|
||||||
<[u8; 32]>::from_hex(
|
<[u8; 32]>::from_hex(
|
||||||
"1794e7f3d5e420641a3bc690067df5541470c966cbca8c694bf39aa16d836918",
|
"1794e7f3d5e420641a3bc690067df5541470c966cbca8c694bf39aa16d836918",
|
||||||
).unwrap(),
|
)
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
assert_eq!(key1.to_sort_key(), expected1);
|
assert_eq!(key1.to_sort_key(), expected1);
|
||||||
assert_eq!(key2.to_sort_key(), expected2);
|
assert_eq!(key2.to_sort_key(), expected2);
|
||||||
|
@ -951,9 +926,8 @@ mod tests {
|
||||||
input: Vec<PublicKey>,
|
input: Vec<PublicKey>,
|
||||||
expect: Vec<PublicKey>,
|
expect: Vec<PublicKey>,
|
||||||
}
|
}
|
||||||
let fmt = |v: Vec<_>| v.into_iter()
|
let fmt =
|
||||||
.map(|s| PublicKey::from_str(s).unwrap())
|
|v: Vec<_>| v.into_iter().map(|s| PublicKey::from_str(s).unwrap()).collect::<Vec<_>>();
|
||||||
.collect::<Vec<_>>();
|
|
||||||
let vectors = vec![
|
let vectors = vec![
|
||||||
// Start BIP67 vectors
|
// Start BIP67 vectors
|
||||||
// Vector 1
|
// Vector 1
|
||||||
|
|
|
@ -14,14 +14,14 @@
|
||||||
use core::borrow::{Borrow, BorrowMut};
|
use core::borrow::{Borrow, BorrowMut};
|
||||||
use core::{fmt, str};
|
use core::{fmt, str};
|
||||||
|
|
||||||
use crate::{io, Script, ScriptBuf, Transaction, TxIn, TxOut, Sequence};
|
|
||||||
use crate::blockdata::transaction::EncodeSigningDataResult;
|
use crate::blockdata::transaction::EncodeSigningDataResult;
|
||||||
use crate::blockdata::witness::Witness;
|
use crate::blockdata::witness::Witness;
|
||||||
use crate::consensus::{encode, Encodable};
|
use crate::consensus::{encode, Encodable};
|
||||||
use crate::error::impl_std_error;
|
use crate::error::impl_std_error;
|
||||||
use crate::hashes::{hash_newtype, sha256, sha256t_hash_newtype, sha256d, Hash};
|
use crate::hashes::{hash_newtype, sha256, sha256d, sha256t_hash_newtype, Hash};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::taproot::{LeafVersion, TapLeafHash, TAPROOT_ANNEX_PREFIX};
|
use crate::taproot::{LeafVersion, TapLeafHash, TAPROOT_ANNEX_PREFIX};
|
||||||
|
use crate::{io, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut};
|
||||||
|
|
||||||
/// Used for signature hash for invalid use of SIGHASH_SINGLE.
|
/// Used for signature hash for invalid use of SIGHASH_SINGLE.
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
|
@ -44,7 +44,7 @@ macro_rules! impl_thirty_two_byte_hash {
|
||||||
impl secp256k1::ThirtyTwoByteHash for $ty {
|
impl secp256k1::ThirtyTwoByteHash for $ty {
|
||||||
fn into_32(self) -> [u8; 32] { self.to_byte_array() }
|
fn into_32(self) -> [u8; 32] { self.to_byte_array() }
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
hash_newtype! {
|
hash_newtype! {
|
||||||
|
@ -60,10 +60,15 @@ hash_newtype! {
|
||||||
impl_thirty_two_byte_hash!(LegacySighash);
|
impl_thirty_two_byte_hash!(LegacySighash);
|
||||||
impl_thirty_two_byte_hash!(SegwitV0Sighash);
|
impl_thirty_two_byte_hash!(SegwitV0Sighash);
|
||||||
|
|
||||||
sha256t_hash_newtype!(TapSighash, TapSighashTag, MIDSTATE_TAPSIGHASH, 64,
|
sha256t_hash_newtype!(
|
||||||
doc="Taproot-tagged hash with tag \"TapSighash\".
|
TapSighash,
|
||||||
|
TapSighashTag,
|
||||||
|
MIDSTATE_TAPSIGHASH,
|
||||||
|
64,
|
||||||
|
doc = "Taproot-tagged hash with tag \"TapSighash\".
|
||||||
|
|
||||||
This hash type is used for computing taproot signature hash.", forward
|
This hash type is used for computing taproot signature hash.",
|
||||||
|
forward
|
||||||
);
|
);
|
||||||
|
|
||||||
impl_thirty_two_byte_hash!(TapSighash);
|
impl_thirty_two_byte_hash!(TapSighash);
|
||||||
|
@ -559,14 +564,10 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the reference to the cached transaction.
|
/// Returns the reference to the cached transaction.
|
||||||
pub fn transaction(&self) -> &Transaction {
|
pub fn transaction(&self) -> &Transaction { self.tx.borrow() }
|
||||||
self.tx.borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Destroys the cache and recovers the stored transaction.
|
/// Destroys the cache and recovers the stored transaction.
|
||||||
pub fn into_transaction(self) -> R {
|
pub fn into_transaction(self) -> R { self.tx }
|
||||||
self.tx
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Encodes the BIP341 signing data for any flag type into a given object implementing a
|
/// Encodes the BIP341 signing data for any flag type into a given object implementing a
|
||||||
/// [`io::Write`] trait.
|
/// [`io::Write`] trait.
|
||||||
|
@ -633,7 +634,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
// scriptPubKey (35): scriptPubKey of the previous output spent by this input, serialized as script inside CTxOut. Its size is always 35 bytes.
|
// scriptPubKey (35): scriptPubKey of the previous output spent by this input, serialized as script inside CTxOut. Its size is always 35 bytes.
|
||||||
// nSequence (4): nSequence of this input.
|
// nSequence (4): nSequence of this input.
|
||||||
if anyone_can_pay {
|
if anyone_can_pay {
|
||||||
let txin = &self.tx.borrow().input.get(input_index).ok_or(Error::IndexOutOfInputsBounds {
|
let txin =
|
||||||
|
&self.tx.borrow().input.get(input_index).ok_or(Error::IndexOutOfInputsBounds {
|
||||||
index: input_index,
|
index: input_index,
|
||||||
inputs_size: self.tx.borrow().input.len(),
|
inputs_size: self.tx.borrow().input.len(),
|
||||||
})?;
|
})?;
|
||||||
|
@ -782,7 +784,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let txin = &self.tx.borrow().input.get(input_index).ok_or(Error::IndexOutOfInputsBounds {
|
let txin =
|
||||||
|
&self.tx.borrow().input.get(input_index).ok_or(Error::IndexOutOfInputsBounds {
|
||||||
index: input_index,
|
index: input_index,
|
||||||
inputs_size: self.tx.borrow().input.len(),
|
inputs_size: self.tx.borrow().input.len(),
|
||||||
})?;
|
})?;
|
||||||
|
@ -795,7 +798,8 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
|
|
||||||
if sighash != EcdsaSighashType::Single && sighash != EcdsaSighashType::None {
|
if sighash != EcdsaSighashType::Single && sighash != EcdsaSighashType::None {
|
||||||
self.segwit_cache().outputs.consensus_encode(&mut writer)?;
|
self.segwit_cache().outputs.consensus_encode(&mut writer)?;
|
||||||
} else if sighash == EcdsaSighashType::Single && input_index < self.tx.borrow().output.len() {
|
} else if sighash == EcdsaSighashType::Single && input_index < self.tx.borrow().output.len()
|
||||||
|
{
|
||||||
let mut single_enc = LegacySighash::engine();
|
let mut single_enc = LegacySighash::engine();
|
||||||
self.tx.borrow().output[input_index].consensus_encode(&mut single_enc)?;
|
self.tx.borrow().output[input_index].consensus_encode(&mut single_enc)?;
|
||||||
let hash = LegacySighash::from_engine(single_enc);
|
let hash = LegacySighash::from_engine(single_enc);
|
||||||
|
@ -865,7 +869,11 @@ impl<R: Borrow<Transaction>> SighashCache<R> {
|
||||||
}
|
}
|
||||||
let sighash_type: u32 = sighash_type.into();
|
let sighash_type: u32 = sighash_type.into();
|
||||||
|
|
||||||
if is_invalid_use_of_sighash_single(sighash_type, input_index, self.tx.borrow().output.len()) {
|
if is_invalid_use_of_sighash_single(
|
||||||
|
sighash_type,
|
||||||
|
input_index,
|
||||||
|
self.tx.borrow().output.len(),
|
||||||
|
) {
|
||||||
// We cannot correctly handle the SIGHASH_SINGLE bug here because usage of this function
|
// We cannot correctly handle the SIGHASH_SINGLE bug here because usage of this function
|
||||||
// will result in the data written to the writer being hashed, however the correct
|
// will result in the data written to the writer being hashed, however the correct
|
||||||
// handling of the SIGHASH_SINGLE bug is to return the 'one array' - either implement
|
// handling of the SIGHASH_SINGLE bug is to return the 'one array' - either implement
|
||||||
|
@ -1197,8 +1205,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_tap_sighash_hash() {
|
fn test_tap_sighash_hash() {
|
||||||
let bytes = hex!("00011b96877db45ffa23b307e9f0ac87b80ef9a80b4c5f0db3fbe734422453e83cc5576f3d542c5d4898fb2b696c15d43332534a7c1d1255fda38993545882df92c3e353ff6d36fbfadc4d168452afd8467f02fe53d71714fcea5dfe2ea759bd00185c4cb02bc76d42620393ca358a1a713f4997f9fc222911890afb3fe56c6a19b202df7bffdcfad08003821294279043746631b00e2dc5e52a111e213bbfe6ef09a19428d418dab0d50000000000");
|
let bytes = hex!("00011b96877db45ffa23b307e9f0ac87b80ef9a80b4c5f0db3fbe734422453e83cc5576f3d542c5d4898fb2b696c15d43332534a7c1d1255fda38993545882df92c3e353ff6d36fbfadc4d168452afd8467f02fe53d71714fcea5dfe2ea759bd00185c4cb02bc76d42620393ca358a1a713f4997f9fc222911890afb3fe56c6a19b202df7bffdcfad08003821294279043746631b00e2dc5e52a111e213bbfe6ef09a19428d418dab0d50000000000");
|
||||||
let expected =
|
let expected = hex!("04e808aad07a40b3767a1442fead79af6ef7e7c9316d82dec409bb31e77699b0");
|
||||||
hex!("04e808aad07a40b3767a1442fead79af6ef7e7c9316d82dec409bb31e77699b0");
|
|
||||||
let mut enc = TapSighash::engine();
|
let mut enc = TapSighash::engine();
|
||||||
enc.input(&bytes);
|
enc.input(&bytes);
|
||||||
let hash = TapSighash::from_engine(enc);
|
let hash = TapSighash::from_engine(enc);
|
||||||
|
@ -1690,22 +1697,27 @@ mod tests {
|
||||||
let mut cache = SighashCache::new(&tx);
|
let mut cache = SighashCache::new(&tx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.segwit_signature_hash(1, &witness_script, value, EcdsaSighashType::All).unwrap(),
|
cache.segwit_signature_hash(1, &witness_script, value, EcdsaSighashType::All).unwrap(),
|
||||||
"c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670".parse::<SegwitV0Sighash>().unwrap(),
|
"c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670"
|
||||||
|
.parse::<SegwitV0Sighash>()
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let cache = cache.segwit_cache();
|
let cache = cache.segwit_cache();
|
||||||
// Parse hex into Vec because BIP143 test vector displays forwards but our sha256d::Hash displays backwards.
|
// Parse hex into Vec because BIP143 test vector displays forwards but our sha256d::Hash displays backwards.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.prevouts.as_byte_array(),
|
cache.prevouts.as_byte_array(),
|
||||||
&Vec::from_hex("96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37").unwrap()[..],
|
&Vec::from_hex("96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37")
|
||||||
|
.unwrap()[..],
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.sequences.as_byte_array(),
|
cache.sequences.as_byte_array(),
|
||||||
&Vec::from_hex("52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b").unwrap()[..],
|
&Vec::from_hex("52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b")
|
||||||
|
.unwrap()[..],
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.outputs.as_byte_array(),
|
cache.outputs.as_byte_array(),
|
||||||
&Vec::from_hex("863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5").unwrap()[..],
|
&Vec::from_hex("863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5")
|
||||||
|
.unwrap()[..],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1726,33 +1738,38 @@ mod tests {
|
||||||
let mut cache = SighashCache::new(&tx);
|
let mut cache = SighashCache::new(&tx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
|
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
|
||||||
"64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6".parse::<SegwitV0Sighash>().unwrap(),
|
"64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6"
|
||||||
|
.parse::<SegwitV0Sighash>()
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let cache = cache.segwit_cache();
|
let cache = cache.segwit_cache();
|
||||||
// Parse hex into Vec because BIP143 test vector displays forwards but our sha256d::Hash displays backwards.
|
// Parse hex into Vec because BIP143 test vector displays forwards but our sha256d::Hash displays backwards.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.prevouts.as_byte_array(),
|
cache.prevouts.as_byte_array(),
|
||||||
&Vec::from_hex("b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a").unwrap()[..],
|
&Vec::from_hex("b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a")
|
||||||
|
.unwrap()[..],
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.sequences.as_byte_array(),
|
cache.sequences.as_byte_array(),
|
||||||
&Vec::from_hex("18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198").unwrap()[..],
|
&Vec::from_hex("18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198")
|
||||||
|
.unwrap()[..],
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.outputs.as_byte_array(),
|
cache.outputs.as_byte_array(),
|
||||||
&Vec::from_hex("de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83").unwrap()[..],
|
&Vec::from_hex("de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83")
|
||||||
|
.unwrap()[..],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bip143_p2wsh_nested_in_p2sh() {
|
fn bip143_p2wsh_nested_in_p2sh() {
|
||||||
let tx = deserialize::<Transaction>(
|
let tx = deserialize::<Transaction>(&hex!(
|
||||||
&hex!(
|
|
||||||
"010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000\
|
"010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000\
|
||||||
ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f\
|
ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f\
|
||||||
05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000"),
|
05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000"
|
||||||
).unwrap();
|
))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let witness_script = ScriptBuf::from_hex(
|
let witness_script = ScriptBuf::from_hex(
|
||||||
"56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28\
|
"56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28\
|
||||||
|
@ -1760,29 +1777,35 @@ mod tests {
|
||||||
9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58\
|
9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58\
|
||||||
c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b1486\
|
c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b1486\
|
||||||
2c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b\
|
2c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b\
|
||||||
56ae"
|
56ae",
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
let value = 987654321;
|
let value = 987654321;
|
||||||
|
|
||||||
let mut cache = SighashCache::new(&tx);
|
let mut cache = SighashCache::new(&tx);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
|
cache.segwit_signature_hash(0, &witness_script, value, EcdsaSighashType::All).unwrap(),
|
||||||
"185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c".parse::<SegwitV0Sighash>().unwrap(),
|
"185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c"
|
||||||
|
.parse::<SegwitV0Sighash>()
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let cache = cache.segwit_cache();
|
let cache = cache.segwit_cache();
|
||||||
// Parse hex into Vec because BIP143 test vector displays forwards but our sha256d::Hash displays backwards.
|
// Parse hex into Vec because BIP143 test vector displays forwards but our sha256d::Hash displays backwards.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.prevouts.as_byte_array(),
|
cache.prevouts.as_byte_array(),
|
||||||
&Vec::from_hex("74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0").unwrap()[..],
|
&Vec::from_hex("74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0")
|
||||||
|
.unwrap()[..],
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.sequences.as_byte_array(),
|
cache.sequences.as_byte_array(),
|
||||||
&Vec::from_hex("3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044").unwrap()[..],
|
&Vec::from_hex("3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044")
|
||||||
|
.unwrap()[..],
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cache.outputs.as_byte_array(),
|
cache.outputs.as_byte_array(),
|
||||||
&Vec::from_hex("bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc").unwrap()[..],
|
&Vec::from_hex("bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc")
|
||||||
|
.unwrap()[..],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,11 +9,9 @@
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use bitcoin_internals::write_err;
|
use bitcoin_internals::write_err;
|
||||||
|
pub use secp256k1::{self, constants, KeyPair, Parity, Secp256k1, Verification, XOnlyPublicKey};
|
||||||
pub use secp256k1::{self, constants, Secp256k1, KeyPair, XOnlyPublicKey, Verification, Parity};
|
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::sighash::TapSighashType;
|
use crate::sighash::TapSighashType;
|
||||||
|
|
||||||
/// A BIP340-341 serialized taproot signature with the corresponding hash type.
|
/// A BIP340-341 serialized taproot signature with the corresponding hash type.
|
||||||
|
@ -33,21 +31,19 @@ impl Signature {
|
||||||
match sl.len() {
|
match sl.len() {
|
||||||
64 => {
|
64 => {
|
||||||
// default type
|
// default type
|
||||||
let sig = secp256k1::schnorr::Signature::from_slice(sl)
|
let sig =
|
||||||
.map_err(Error::Secp256k1)?;
|
secp256k1::schnorr::Signature::from_slice(sl).map_err(Error::Secp256k1)?;
|
||||||
Ok(Signature { sig, hash_ty: TapSighashType::Default })
|
Ok(Signature { sig, hash_ty: TapSighashType::Default })
|
||||||
},
|
}
|
||||||
65 => {
|
65 => {
|
||||||
let (hash_ty, sig) = sl.split_last().expect("Slice len checked == 65");
|
let (hash_ty, sig) = sl.split_last().expect("Slice len checked == 65");
|
||||||
let hash_ty = TapSighashType::from_consensus_u8(*hash_ty)
|
let hash_ty = TapSighashType::from_consensus_u8(*hash_ty)
|
||||||
.map_err(|_| Error::InvalidSighashType(*hash_ty))?;
|
.map_err(|_| Error::InvalidSighashType(*hash_ty))?;
|
||||||
let sig = secp256k1::schnorr::Signature::from_slice(sig)
|
let sig =
|
||||||
.map_err(Error::Secp256k1)?;
|
secp256k1::schnorr::Signature::from_slice(sig).map_err(Error::Secp256k1)?;
|
||||||
Ok(Signature { sig, hash_ty })
|
Ok(Signature { sig, hash_ty })
|
||||||
}
|
}
|
||||||
len => {
|
len => Err(Error::InvalidSignatureSize(len)),
|
||||||
Err(Error::InvalidSignatureSize(len))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +58,6 @@ impl Signature {
|
||||||
}
|
}
|
||||||
ser_sig
|
ser_sig
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A taproot sig related error.
|
/// A taproot sig related error.
|
||||||
|
@ -77,7 +72,6 @@ pub enum Error {
|
||||||
InvalidSignatureSize(usize),
|
InvalidSignatureSize(usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -85,8 +79,7 @@ impl fmt::Display for Error {
|
||||||
write!(f, "invalid signature hash type {}", hash_ty),
|
write!(f, "invalid signature hash type {}", hash_ty),
|
||||||
Error::Secp256k1(ref e) =>
|
Error::Secp256k1(ref e) =>
|
||||||
write_err!(f, "taproot signature has correct len but is malformed"; e),
|
write_err!(f, "taproot signature has correct len but is malformed"; e),
|
||||||
Error::InvalidSignatureSize(sz) =>
|
Error::InvalidSignatureSize(sz) => write!(f, "invalid taproot signature size: {}", sz),
|
||||||
write!(f, "invalid taproot signature size: {}", sz),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,8 +98,5 @@ impl std::error::Error for Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<secp256k1::Error> for Error {
|
impl From<secp256k1::Error> for Error {
|
||||||
|
fn from(e: secp256k1::Error) -> Error { Error::Secp256k1(e) }
|
||||||
fn from(e: secp256k1::Error) -> Error {
|
|
||||||
Error::Secp256k1(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
|
||||||
use bitcoin_internals::write_err;
|
use bitcoin_internals::write_err;
|
||||||
|
|
||||||
|
use crate::bip32::ExtendedPubKey;
|
||||||
use crate::blockdata::transaction::Transaction;
|
use crate::blockdata::transaction::Transaction;
|
||||||
use crate::consensus::encode;
|
use crate::consensus::encode;
|
||||||
|
use crate::prelude::*;
|
||||||
use crate::psbt::raw;
|
use crate::psbt::raw;
|
||||||
|
use crate::{hashes, io};
|
||||||
use crate::hashes;
|
|
||||||
use crate::io;
|
|
||||||
use crate::bip32::ExtendedPubKey;
|
|
||||||
|
|
||||||
/// Enum for marking psbt hash error.
|
/// Enum for marking psbt hash error.
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
|
@ -113,29 +110,41 @@ impl fmt::Display for Error {
|
||||||
Error::InvalidMagic => f.write_str("invalid magic"),
|
Error::InvalidMagic => f.write_str("invalid magic"),
|
||||||
Error::MissingUtxo => f.write_str("UTXO information is not present in PSBT"),
|
Error::MissingUtxo => f.write_str("UTXO information is not present in PSBT"),
|
||||||
Error::InvalidSeparator => f.write_str("invalid separator"),
|
Error::InvalidSeparator => f.write_str("invalid separator"),
|
||||||
Error::PsbtUtxoOutOfbounds => f.write_str("output index is out of bounds of non witness script output array"),
|
Error::PsbtUtxoOutOfbounds =>
|
||||||
|
f.write_str("output index is out of bounds of non witness script output array"),
|
||||||
Error::InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey),
|
Error::InvalidKey(ref rkey) => write!(f, "invalid key: {}", rkey),
|
||||||
Error::InvalidProprietaryKey => write!(f, "non-proprietary key type found when proprietary key was expected"),
|
Error::InvalidProprietaryKey =>
|
||||||
|
write!(f, "non-proprietary key type found when proprietary key was expected"),
|
||||||
Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey),
|
Error::DuplicateKey(ref rkey) => write!(f, "duplicate key: {}", rkey),
|
||||||
Error::UnsignedTxHasScriptSigs => f.write_str("the unsigned transaction has script sigs"),
|
Error::UnsignedTxHasScriptSigs =>
|
||||||
Error::UnsignedTxHasScriptWitnesses => f.write_str("the unsigned transaction has script witnesses"),
|
f.write_str("the unsigned transaction has script sigs"),
|
||||||
Error::MustHaveUnsignedTx => {
|
Error::UnsignedTxHasScriptWitnesses =>
|
||||||
f.write_str("partially signed transactions must have an unsigned transaction")
|
f.write_str("the unsigned transaction has script witnesses"),
|
||||||
}
|
Error::MustHaveUnsignedTx =>
|
||||||
|
f.write_str("partially signed transactions must have an unsigned transaction"),
|
||||||
Error::NoMorePairs => f.write_str("no more key-value pairs for this psbt map"),
|
Error::NoMorePairs => f.write_str("no more key-value pairs for this psbt map"),
|
||||||
Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(f, "different unsigned transaction: expected {}, actual {}", e.txid(), a.txid()),
|
Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(
|
||||||
Error::NonStandardSighashType(ref sht) => write!(f, "non-standard sighash type: {}", sht),
|
f,
|
||||||
|
"different unsigned transaction: expected {}, actual {}",
|
||||||
|
e.txid(),
|
||||||
|
a.txid()
|
||||||
|
),
|
||||||
|
Error::NonStandardSighashType(ref sht) =>
|
||||||
|
write!(f, "non-standard sighash type: {}", sht),
|
||||||
Error::HashParse(ref e) => write_err!(f, "hash parse error"; e),
|
Error::HashParse(ref e) => write_err!(f, "hash parse error"; e),
|
||||||
Error::InvalidPreimageHashPair{ref preimage, ref hash, ref hash_type} => {
|
Error::InvalidPreimageHashPair { ref preimage, ref hash, ref hash_type } => {
|
||||||
// directly using debug forms of psbthash enums
|
// directly using debug forms of psbthash enums
|
||||||
write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash )
|
write!(f, "Preimage {:?} does not match {:?} hash {:?}", preimage, hash_type, hash)
|
||||||
},
|
}
|
||||||
Error::CombineInconsistentKeySources(ref s) => { write!(f, "combine conflict: {}", s) },
|
Error::CombineInconsistentKeySources(ref s) => {
|
||||||
|
write!(f, "combine conflict: {}", s)
|
||||||
|
}
|
||||||
Error::ConsensusEncoding(ref e) => write_err!(f, "bitcoin consensus encoding error"; e),
|
Error::ConsensusEncoding(ref e) => write_err!(f, "bitcoin consensus encoding error"; e),
|
||||||
Error::NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"),
|
Error::NegativeFee => f.write_str("PSBT has a negative fee which is not allowed"),
|
||||||
Error::FeeOverflow => f.write_str("integer overflow in fee calculation"),
|
Error::FeeOverflow => f.write_str("integer overflow in fee calculation"),
|
||||||
Error::InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e),
|
Error::InvalidPublicKey(ref e) => write_err!(f, "invalid public key"; e),
|
||||||
Error::InvalidSecp256k1PublicKey(ref e) => write_err!(f, "invalid secp256k1 public key"; e),
|
Error::InvalidSecp256k1PublicKey(ref e) =>
|
||||||
|
write_err!(f, "invalid secp256k1 public key"; e),
|
||||||
Error::InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"),
|
Error::InvalidXOnlyPublicKey => f.write_str("invalid xonly public key"),
|
||||||
Error::InvalidEcdsaSignature(ref e) => write_err!(f, "invalid ECDSA signature"; e),
|
Error::InvalidEcdsaSignature(ref e) => write_err!(f, "invalid ECDSA signature"; e),
|
||||||
Error::InvalidTaprootSignature(ref e) => write_err!(f, "invalid taproot signature"; e),
|
Error::InvalidTaprootSignature(ref e) => write_err!(f, "invalid taproot signature"; e),
|
||||||
|
@ -145,7 +154,8 @@ impl fmt::Display for Error {
|
||||||
Error::TapTree(ref e) => write_err!(f, "taproot tree error"; e),
|
Error::TapTree(ref e) => write_err!(f, "taproot tree error"; e),
|
||||||
Error::XPubKey(s) => write!(f, "xpub key error - {}", s),
|
Error::XPubKey(s) => write!(f, "xpub key error - {}", s),
|
||||||
Error::Version(s) => write!(f, "version error {}", s),
|
Error::Version(s) => write!(f, "version error {}", s),
|
||||||
Error::PartialDataConsumption => f.write_str("data not consumed entirely when explicitly deserializing"),
|
Error::PartialDataConsumption =>
|
||||||
|
f.write_str("data not consumed entirely when explicitly deserializing"),
|
||||||
Error::Io(ref e) => write_err!(f, "I/O error"; e),
|
Error::Io(ref e) => write_err!(f, "I/O error"; e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,7 +171,7 @@ impl std::error::Error for Error {
|
||||||
HashParse(e) => Some(e),
|
HashParse(e) => Some(e),
|
||||||
ConsensusEncoding(e) => Some(e),
|
ConsensusEncoding(e) => Some(e),
|
||||||
Io(e) => Some(e),
|
Io(e) => Some(e),
|
||||||
| InvalidMagic
|
InvalidMagic
|
||||||
| MissingUtxo
|
| MissingUtxo
|
||||||
| InvalidSeparator
|
| InvalidSeparator
|
||||||
| PsbtUtxoOutOfbounds
|
| PsbtUtxoOutOfbounds
|
||||||
|
@ -174,7 +184,7 @@ impl std::error::Error for Error {
|
||||||
| NoMorePairs
|
| NoMorePairs
|
||||||
| UnexpectedUnsignedTx { .. }
|
| UnexpectedUnsignedTx { .. }
|
||||||
| NonStandardSighashType(_)
|
| NonStandardSighashType(_)
|
||||||
| InvalidPreimageHashPair{ .. }
|
| InvalidPreimageHashPair { .. }
|
||||||
| CombineInconsistentKeySources(_)
|
| CombineInconsistentKeySources(_)
|
||||||
| NegativeFee
|
| NegativeFee
|
||||||
| FeeOverflow
|
| FeeOverflow
|
||||||
|
@ -189,26 +199,20 @@ impl std::error::Error for Error {
|
||||||
| TapTree(_)
|
| TapTree(_)
|
||||||
| XPubKey(_)
|
| XPubKey(_)
|
||||||
| Version(_)
|
| Version(_)
|
||||||
| PartialDataConsumption=> None,
|
| PartialDataConsumption => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
impl From<hashes::Error> for Error {
|
impl From<hashes::Error> for Error {
|
||||||
fn from(e: hashes::Error) -> Error {
|
fn from(e: hashes::Error) -> Error { Error::HashParse(e) }
|
||||||
Error::HashParse(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<encode::Error> for Error {
|
impl From<encode::Error> for Error {
|
||||||
fn from(e: encode::Error) -> Self {
|
fn from(e: encode::Error) -> Self { Error::ConsensusEncoding(e) }
|
||||||
Error::ConsensusEncoding(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for Error {
|
impl From<io::Error> for Error {
|
||||||
fn from(e: io::Error) -> Self {
|
fn from(e: io::Error) -> Self { Error::Io(e) }
|
||||||
Error::Io(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
#[allow(unused_macros)]
|
#[allow(unused_macros)]
|
||||||
macro_rules! hex_psbt {
|
macro_rules! hex_psbt {
|
||||||
($s:expr) => { <$crate::psbt::PartiallySignedTransaction>::deserialize(&<$crate::prelude::Vec<u8> as $crate::hashes::hex::FromHex>::from_hex($s).unwrap()) };
|
($s:expr) => {
|
||||||
|
<$crate::psbt::PartiallySignedTransaction>::deserialize(
|
||||||
|
&<$crate::prelude::Vec<u8> as $crate::hashes::hex::FromHex>::from_hex($s).unwrap(),
|
||||||
|
)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! combine {
|
macro_rules! combine {
|
||||||
|
@ -33,9 +37,7 @@ macro_rules! impl_psbt_deserialize {
|
||||||
macro_rules! impl_psbt_serialize {
|
macro_rules! impl_psbt_serialize {
|
||||||
($thing:ty) => {
|
($thing:ty) => {
|
||||||
impl $crate::psbt::serialize::Serialize for $thing {
|
impl $crate::psbt::serialize::Serialize for $thing {
|
||||||
fn serialize(&self) -> $crate::prelude::Vec<u8> {
|
fn serialize(&self) -> $crate::prelude::Vec<u8> { $crate::consensus::serialize(self) }
|
||||||
$crate::consensus::serialize(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -43,9 +45,7 @@ macro_rules! impl_psbt_serialize {
|
||||||
macro_rules! impl_psbtmap_serialize {
|
macro_rules! impl_psbtmap_serialize {
|
||||||
($thing:ty) => {
|
($thing:ty) => {
|
||||||
impl $crate::psbt::serialize::Serialize for $thing {
|
impl $crate::psbt::serialize::Serialize for $thing {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> { self.serialize_map() }
|
||||||
self.serialize_map()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -157,9 +157,7 @@ macro_rules! impl_psbt_hash_deserialize {
|
||||||
($hash_type:ty) => {
|
($hash_type:ty) => {
|
||||||
impl $crate::psbt::serialize::Deserialize for $hash_type {
|
impl $crate::psbt::serialize::Deserialize for $hash_type {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, $crate::psbt::Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, $crate::psbt::Error> {
|
||||||
<$hash_type>::from_slice(&bytes[..]).map_err(|e| {
|
<$hash_type>::from_slice(&bytes[..]).map_err(|e| $crate::psbt::Error::from(e))
|
||||||
$crate::psbt::Error::from(e)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -168,9 +166,7 @@ macro_rules! impl_psbt_hash_deserialize {
|
||||||
macro_rules! impl_psbt_hash_serialize {
|
macro_rules! impl_psbt_hash_serialize {
|
||||||
($hash_type:ty) => {
|
($hash_type:ty) => {
|
||||||
impl $crate::psbt::serialize::Serialize for $hash_type {
|
impl $crate::psbt::serialize::Serialize for $hash_type {
|
||||||
fn serialize(&self) -> $crate::prelude::Vec<u8> {
|
fn serialize(&self) -> $crate::prelude::Vec<u8> { self.as_byte_array().to_vec() }
|
||||||
self.as_byte_array().to_vec()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,14 @@
|
||||||
|
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::bip32::{ChildNumber, DerivationPath, ExtendedPubKey, Fingerprint};
|
||||||
|
|
||||||
use crate::io::{self, Cursor, Read};
|
|
||||||
|
|
||||||
use crate::blockdata::transaction::Transaction;
|
use crate::blockdata::transaction::Transaction;
|
||||||
use crate::consensus::encode::MAX_VEC_SIZE;
|
use crate::consensus::encode::MAX_VEC_SIZE;
|
||||||
use crate::consensus::{encode, Decodable};
|
use crate::consensus::{encode, Decodable};
|
||||||
|
use crate::io::{self, Cursor, Read};
|
||||||
|
use crate::prelude::*;
|
||||||
use crate::psbt::map::Map;
|
use crate::psbt::map::Map;
|
||||||
use crate::psbt::{raw, Error, PartiallySignedTransaction};
|
use crate::psbt::{raw, Error, PartiallySignedTransaction};
|
||||||
use crate::bip32::{ExtendedPubKey, Fingerprint, DerivationPath, ChildNumber};
|
|
||||||
|
|
||||||
/// Type: Unsigned Transaction PSBT_GLOBAL_UNSIGNED_TX = 0x00
|
/// Type: Unsigned Transaction PSBT_GLOBAL_UNSIGNED_TX = 0x00
|
||||||
const PSBT_GLOBAL_UNSIGNED_TX: u8 = 0x00;
|
const PSBT_GLOBAL_UNSIGNED_TX: u8 = 0x00;
|
||||||
|
@ -27,10 +25,7 @@ impl Map for PartiallySignedTransaction {
|
||||||
let mut rv: Vec<raw::Pair> = Default::default();
|
let mut rv: Vec<raw::Pair> = Default::default();
|
||||||
|
|
||||||
rv.push(raw::Pair {
|
rv.push(raw::Pair {
|
||||||
key: raw::Key {
|
key: raw::Key { type_value: PSBT_GLOBAL_UNSIGNED_TX, key: vec![] },
|
||||||
type_value: PSBT_GLOBAL_UNSIGNED_TX,
|
|
||||||
key: vec![],
|
|
||||||
},
|
|
||||||
value: {
|
value: {
|
||||||
// Manually serialized to ensure 0-input txs are serialized
|
// Manually serialized to ensure 0-input txs are serialized
|
||||||
// without witnesses.
|
// without witnesses.
|
||||||
|
@ -45,42 +40,30 @@ impl Map for PartiallySignedTransaction {
|
||||||
|
|
||||||
for (xpub, (fingerprint, derivation)) in &self.xpub {
|
for (xpub, (fingerprint, derivation)) in &self.xpub {
|
||||||
rv.push(raw::Pair {
|
rv.push(raw::Pair {
|
||||||
key: raw::Key {
|
key: raw::Key { type_value: PSBT_GLOBAL_XPUB, key: xpub.encode().to_vec() },
|
||||||
type_value: PSBT_GLOBAL_XPUB,
|
|
||||||
key: xpub.encode().to_vec(),
|
|
||||||
},
|
|
||||||
value: {
|
value: {
|
||||||
let mut ret = Vec::with_capacity(4 + derivation.len() * 4);
|
let mut ret = Vec::with_capacity(4 + derivation.len() * 4);
|
||||||
ret.extend(fingerprint.as_bytes());
|
ret.extend(fingerprint.as_bytes());
|
||||||
derivation.into_iter().for_each(|n| ret.extend(&u32::from(*n).to_le_bytes()));
|
derivation.into_iter().for_each(|n| ret.extend(&u32::from(*n).to_le_bytes()));
|
||||||
ret
|
ret
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serializing version only for non-default value; otherwise test vectors fail
|
// Serializing version only for non-default value; otherwise test vectors fail
|
||||||
if self.version > 0 {
|
if self.version > 0 {
|
||||||
rv.push(raw::Pair {
|
rv.push(raw::Pair {
|
||||||
key: raw::Key {
|
key: raw::Key { type_value: PSBT_GLOBAL_VERSION, key: vec![] },
|
||||||
type_value: PSBT_GLOBAL_VERSION,
|
value: self.version.to_le_bytes().to_vec(),
|
||||||
key: vec![],
|
|
||||||
},
|
|
||||||
value: self.version.to_le_bytes().to_vec()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, value) in self.proprietary.iter() {
|
for (key, value) in self.proprietary.iter() {
|
||||||
rv.push(raw::Pair {
|
rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
|
||||||
key: key.to_key(),
|
|
||||||
value: value.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, value) in self.unknown.iter() {
|
for (key, value) in self.unknown.iter() {
|
||||||
rv.push(raw::Pair {
|
rv.push(raw::Pair { key: key.clone(), value: value.clone() });
|
||||||
key: key.clone(),
|
|
||||||
value: value.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rv
|
rv
|
||||||
|
@ -93,7 +76,8 @@ impl PartiallySignedTransaction {
|
||||||
let mut tx: Option<Transaction> = None;
|
let mut tx: Option<Transaction> = None;
|
||||||
let mut version: Option<u32> = None;
|
let mut version: Option<u32> = None;
|
||||||
let mut unknowns: BTreeMap<raw::Key, Vec<u8>> = Default::default();
|
let mut unknowns: BTreeMap<raw::Key, Vec<u8>> = Default::default();
|
||||||
let mut xpub_map: BTreeMap<ExtendedPubKey, (Fingerprint, DerivationPath)> = Default::default();
|
let mut xpub_map: BTreeMap<ExtendedPubKey, (Fingerprint, DerivationPath)> =
|
||||||
|
Default::default();
|
||||||
let mut proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>> = Default::default();
|
let mut proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>> = Default::default();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -119,13 +103,13 @@ impl PartiallySignedTransaction {
|
||||||
});
|
});
|
||||||
|
|
||||||
if decoder.position() != vlen as u64 {
|
if decoder.position() != vlen as u64 {
|
||||||
return Err(Error::PartialDataConsumption)
|
return Err(Error::PartialDataConsumption);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::DuplicateKey(pair.key))
|
return Err(Error::DuplicateKey(pair.key));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::InvalidKey(pair.key))
|
return Err(Error::InvalidKey(pair.key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_GLOBAL_XPUB => {
|
PSBT_GLOBAL_XPUB => {
|
||||||
|
@ -136,24 +120,33 @@ impl PartiallySignedTransaction {
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
if pair.value.is_empty() || pair.value.len() % 4 != 0 {
|
if pair.value.is_empty() || pair.value.len() % 4 != 0 {
|
||||||
return Err(Error::XPubKey("Incorrect length of global xpub derivation data"))
|
return Err(Error::XPubKey(
|
||||||
|
"Incorrect length of global xpub derivation data",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let child_count = pair.value.len() / 4 - 1;
|
let child_count = pair.value.len() / 4 - 1;
|
||||||
let mut decoder = Cursor::new(pair.value);
|
let mut decoder = Cursor::new(pair.value);
|
||||||
let mut fingerprint = [0u8; 4];
|
let mut fingerprint = [0u8; 4];
|
||||||
decoder.read_exact(&mut fingerprint[..]).map_err(|_| Error::XPubKey("Can't read global xpub fingerprint"))?;
|
decoder.read_exact(&mut fingerprint[..]).map_err(|_| {
|
||||||
|
Error::XPubKey("Can't read global xpub fingerprint")
|
||||||
|
})?;
|
||||||
let mut path = Vec::<ChildNumber>::with_capacity(child_count);
|
let mut path = Vec::<ChildNumber>::with_capacity(child_count);
|
||||||
while let Ok(index) = u32::consensus_decode(&mut decoder) {
|
while let Ok(index) = u32::consensus_decode(&mut decoder) {
|
||||||
path.push(ChildNumber::from(index))
|
path.push(ChildNumber::from(index))
|
||||||
}
|
}
|
||||||
let derivation = DerivationPath::from(path);
|
let derivation = DerivationPath::from(path);
|
||||||
// Keys, according to BIP-174, must be unique
|
// Keys, according to BIP-174, must be unique
|
||||||
if xpub_map.insert(xpub, (Fingerprint::from(fingerprint), derivation)).is_some() {
|
if xpub_map
|
||||||
return Err(Error::XPubKey("Repeated global xpub key"))
|
.insert(xpub, (Fingerprint::from(fingerprint), derivation))
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
return Err(Error::XPubKey("Repeated global xpub key"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::XPubKey("Xpub global key must contain serialized Xpub data"))
|
return Err(Error::XPubKey(
|
||||||
|
"Xpub global key must contain serialized Xpub data",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_GLOBAL_VERSION => {
|
PSBT_GLOBAL_VERSION => {
|
||||||
|
@ -164,33 +157,41 @@ impl PartiallySignedTransaction {
|
||||||
let vlen: usize = pair.value.len();
|
let vlen: usize = pair.value.len();
|
||||||
let mut decoder = Cursor::new(pair.value);
|
let mut decoder = Cursor::new(pair.value);
|
||||||
if vlen != 4 {
|
if vlen != 4 {
|
||||||
return Err(Error::Version("invalid global version value length (must be 4 bytes)"))
|
return Err(Error::Version(
|
||||||
|
"invalid global version value length (must be 4 bytes)",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
version = Some(Decodable::consensus_decode(&mut decoder)?);
|
version = Some(Decodable::consensus_decode(&mut decoder)?);
|
||||||
// We only understand version 0 PSBTs. According to BIP-174 we
|
// We only understand version 0 PSBTs. According to BIP-174 we
|
||||||
// should throw an error if we see anything other than version 0.
|
// should throw an error if we see anything other than version 0.
|
||||||
if version != Some(0) {
|
if version != Some(0) {
|
||||||
return Err(Error::Version("PSBT versions greater than 0 are not supported"))
|
return Err(Error::Version(
|
||||||
|
"PSBT versions greater than 0 are not supported",
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::DuplicateKey(pair.key))
|
return Err(Error::DuplicateKey(pair.key));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(Error::InvalidKey(pair.key))
|
return Err(Error::InvalidKey(pair.key));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_GLOBAL_PROPRIETARY => match proprietary.entry(raw::ProprietaryKey::try_from(pair.key.clone())?) {
|
PSBT_GLOBAL_PROPRIETARY => match proprietary
|
||||||
|
.entry(raw::ProprietaryKey::try_from(pair.key.clone())?)
|
||||||
|
{
|
||||||
btree_map::Entry::Vacant(empty_key) => {
|
btree_map::Entry::Vacant(empty_key) => {
|
||||||
empty_key.insert(pair.value);
|
empty_key.insert(pair.value);
|
||||||
},
|
|
||||||
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(pair.key)),
|
|
||||||
}
|
}
|
||||||
|
btree_map::Entry::Occupied(_) =>
|
||||||
|
return Err(Error::DuplicateKey(pair.key)),
|
||||||
|
},
|
||||||
_ => match unknowns.entry(pair.key) {
|
_ => match unknowns.entry(pair.key) {
|
||||||
btree_map::Entry::Vacant(empty_key) => {
|
btree_map::Entry::Vacant(empty_key) => {
|
||||||
empty_key.insert(pair.value);
|
empty_key.insert(pair.value);
|
||||||
},
|
|
||||||
btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone())),
|
|
||||||
}
|
}
|
||||||
|
btree_map::Entry::Occupied(k) =>
|
||||||
|
return Err(Error::DuplicateKey(k.key().clone())),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(crate::psbt::Error::NoMorePairs) => break,
|
Err(crate::psbt::Error::NoMorePairs) => break,
|
||||||
|
@ -206,7 +207,7 @@ impl PartiallySignedTransaction {
|
||||||
proprietary,
|
proprietary,
|
||||||
unknown: unknowns,
|
unknown: unknowns,
|
||||||
inputs: vec![],
|
inputs: vec![],
|
||||||
outputs: vec![]
|
outputs: vec![],
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::MustHaveUnsignedTx)
|
Err(Error::MustHaveUnsignedTx)
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
use crate::prelude::*;
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use core::convert::TryFrom;
|
|
||||||
|
|
||||||
use secp256k1::XOnlyPublicKey;
|
use secp256k1::XOnlyPublicKey;
|
||||||
|
|
||||||
use crate::blockdata::script::ScriptBuf;
|
|
||||||
use crate::blockdata::witness::Witness;
|
|
||||||
use crate::blockdata::transaction::{Transaction, TxOut};
|
|
||||||
use crate::crypto::{ecdsa, taproot};
|
|
||||||
use crate::crypto::key::PublicKey;
|
|
||||||
use crate::hashes::{self, hash160, ripemd160, sha256, sha256d};
|
|
||||||
use crate::bip32::KeySource;
|
use crate::bip32::KeySource;
|
||||||
|
use crate::blockdata::script::ScriptBuf;
|
||||||
|
use crate::blockdata::transaction::{Transaction, TxOut};
|
||||||
|
use crate::blockdata::witness::Witness;
|
||||||
|
use crate::crypto::key::PublicKey;
|
||||||
|
use crate::crypto::{ecdsa, taproot};
|
||||||
|
use crate::hashes::{self, hash160, ripemd160, sha256, sha256d};
|
||||||
|
use crate::prelude::*;
|
||||||
use crate::psbt::map::Map;
|
use crate::psbt::map::Map;
|
||||||
use crate::psbt::serialize::Deserialize;
|
use crate::psbt::serialize::Deserialize;
|
||||||
use crate::psbt::{self, error, raw, Error};
|
use crate::psbt::{self, error, raw, Error};
|
||||||
use crate::sighash::{self, NonStandardSighashType, SighashTypeParseError, EcdsaSighashType, TapSighashType};
|
use crate::sighash::{
|
||||||
|
self, EcdsaSighashType, NonStandardSighashType, SighashTypeParseError, TapSighashType,
|
||||||
|
};
|
||||||
use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash};
|
use crate::taproot::{ControlBlock, LeafVersion, TapLeafHash, TapNodeHash};
|
||||||
|
|
||||||
/// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00
|
/// Type: Non-Witness UTXO PSBT_IN_NON_WITNESS_UTXO = 0x00
|
||||||
|
@ -132,7 +133,6 @@ pub struct Input {
|
||||||
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
|
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A Signature hash type for the corresponding input. As of taproot upgrade, the signature hash
|
/// A Signature hash type for the corresponding input. As of taproot upgrade, the signature hash
|
||||||
/// type can be either [`EcdsaSighashType`] or [`TapSighashType`] but it is not possible to know
|
/// type can be either [`EcdsaSighashType`] or [`TapSighashType`] but it is not possible to know
|
||||||
/// directly which signature hash type the user is dealing with. Therefore, the user is responsible
|
/// directly which signature hash type the user is dealing with. Therefore, the user is responsible
|
||||||
|
@ -141,7 +141,7 @@ pub struct Input {
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
||||||
pub struct PsbtSighashType {
|
pub struct PsbtSighashType {
|
||||||
pub (in crate::psbt) inner: u32,
|
pub(in crate::psbt) inner: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for PsbtSighashType {
|
impl fmt::Display for PsbtSighashType {
|
||||||
|
@ -172,7 +172,7 @@ impl FromStr for PsbtSighashType {
|
||||||
return Ok(PsbtSighashType { inner });
|
return Ok(PsbtSighashType { inner });
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(SighashTypeParseError{ unrecognized: s.to_owned() })
|
Err(SighashTypeParseError { unrecognized: s.to_owned() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<EcdsaSighashType> for PsbtSighashType {
|
impl From<EcdsaSighashType> for PsbtSighashType {
|
||||||
|
@ -208,17 +208,12 @@ impl PsbtSighashType {
|
||||||
///
|
///
|
||||||
/// Allows construction of a non-standard or non-valid sighash flag
|
/// Allows construction of a non-standard or non-valid sighash flag
|
||||||
/// ([`EcdsaSighashType`], [`TapSighashType`] respectively).
|
/// ([`EcdsaSighashType`], [`TapSighashType`] respectively).
|
||||||
pub fn from_u32(n: u32) -> PsbtSighashType {
|
pub fn from_u32(n: u32) -> PsbtSighashType { PsbtSighashType { inner: n } }
|
||||||
PsbtSighashType { inner: n }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Converts [`PsbtSighashType`] to a raw `u32` sighash flag.
|
/// Converts [`PsbtSighashType`] to a raw `u32` sighash flag.
|
||||||
///
|
///
|
||||||
/// No guarantees are made as to the standardness or validity of the returned value.
|
/// No guarantees are made as to the standardness or validity of the returned value.
|
||||||
pub fn to_u32(self) -> u32 {
|
pub fn to_u32(self) -> u32 { self.inner }
|
||||||
self.inner
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
|
@ -247,10 +242,7 @@ impl Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> {
|
pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> {
|
||||||
let raw::Pair {
|
let raw::Pair { key: raw_key, value: raw_value } = pair;
|
||||||
key: raw_key,
|
|
||||||
value: raw_value,
|
|
||||||
} = pair;
|
|
||||||
|
|
||||||
match raw_key.type_value {
|
match raw_key.type_value {
|
||||||
PSBT_IN_NON_WITNESS_UTXO => {
|
PSBT_IN_NON_WITNESS_UTXO => {
|
||||||
|
@ -299,16 +291,36 @@ impl Input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PSBT_IN_RIPEMD160 => {
|
PSBT_IN_RIPEMD160 => {
|
||||||
psbt_insert_hash_pair(&mut self.ripemd160_preimages, raw_key, raw_value, error::PsbtHash::Ripemd)?;
|
psbt_insert_hash_pair(
|
||||||
|
&mut self.ripemd160_preimages,
|
||||||
|
raw_key,
|
||||||
|
raw_value,
|
||||||
|
error::PsbtHash::Ripemd,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
PSBT_IN_SHA256 => {
|
PSBT_IN_SHA256 => {
|
||||||
psbt_insert_hash_pair(&mut self.sha256_preimages, raw_key, raw_value, error::PsbtHash::Sha256)?;
|
psbt_insert_hash_pair(
|
||||||
|
&mut self.sha256_preimages,
|
||||||
|
raw_key,
|
||||||
|
raw_value,
|
||||||
|
error::PsbtHash::Sha256,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
PSBT_IN_HASH160 => {
|
PSBT_IN_HASH160 => {
|
||||||
psbt_insert_hash_pair(&mut self.hash160_preimages, raw_key, raw_value, error::PsbtHash::Hash160)?;
|
psbt_insert_hash_pair(
|
||||||
|
&mut self.hash160_preimages,
|
||||||
|
raw_key,
|
||||||
|
raw_value,
|
||||||
|
error::PsbtHash::Hash160,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
PSBT_IN_HASH256 => {
|
PSBT_IN_HASH256 => {
|
||||||
psbt_insert_hash_pair(&mut self.hash256_preimages, raw_key, raw_value, error::PsbtHash::Hash256)?;
|
psbt_insert_hash_pair(
|
||||||
|
&mut self.hash256_preimages,
|
||||||
|
raw_key,
|
||||||
|
raw_value,
|
||||||
|
error::PsbtHash::Hash256,
|
||||||
|
)?;
|
||||||
}
|
}
|
||||||
PSBT_IN_TAP_KEY_SIG => {
|
PSBT_IN_TAP_KEY_SIG => {
|
||||||
impl_psbt_insert_pair! {
|
impl_psbt_insert_pair! {
|
||||||
|
@ -345,7 +357,7 @@ impl Input {
|
||||||
match self.proprietary.entry(key) {
|
match self.proprietary.entry(key) {
|
||||||
btree_map::Entry::Vacant(empty_key) => {
|
btree_map::Entry::Vacant(empty_key) => {
|
||||||
empty_key.insert(raw_value);
|
empty_key.insert(raw_value);
|
||||||
},
|
}
|
||||||
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key)),
|
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,17 +483,11 @@ impl Map for Input {
|
||||||
rv.push(self.tap_merkle_root, PSBT_IN_TAP_MERKLE_ROOT)
|
rv.push(self.tap_merkle_root, PSBT_IN_TAP_MERKLE_ROOT)
|
||||||
}
|
}
|
||||||
for (key, value) in self.proprietary.iter() {
|
for (key, value) in self.proprietary.iter() {
|
||||||
rv.push(raw::Pair {
|
rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
|
||||||
key: key.to_key(),
|
|
||||||
value: value.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, value) in self.unknown.iter() {
|
for (key, value) in self.unknown.iter() {
|
||||||
rv.push(raw::Pair {
|
rv.push(raw::Pair { key: key.clone(), value: value.clone() });
|
||||||
key: key.clone(),
|
|
||||||
value: value.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rv
|
rv
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::psbt::raw;
|
use crate::psbt::raw;
|
||||||
|
|
||||||
mod global;
|
mod global;
|
||||||
|
@ -10,7 +9,6 @@ mod output;
|
||||||
|
|
||||||
pub use self::input::{Input, PsbtSighashType};
|
pub use self::input::{Input, PsbtSighashType};
|
||||||
pub use self::output::Output;
|
pub use self::output::Output;
|
||||||
|
|
||||||
use super::serialize::Serialize;
|
use super::serialize::Serialize;
|
||||||
|
|
||||||
/// A trait that describes a PSBT key-value map.
|
/// A trait that describes a PSBT key-value map.
|
||||||
|
|
|
@ -1,18 +1,16 @@
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
use core;
|
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
|
||||||
use crate::blockdata::script::ScriptBuf;
|
|
||||||
use secp256k1::XOnlyPublicKey;
|
use secp256k1::XOnlyPublicKey;
|
||||||
use crate::bip32::KeySource;
|
use {core, secp256k1};
|
||||||
use secp256k1;
|
|
||||||
use crate::psbt::map::Map;
|
|
||||||
use crate::psbt::raw;
|
|
||||||
use crate::psbt::Error;
|
|
||||||
|
|
||||||
use crate::taproot::{TapTree, TapLeafHash};
|
use crate::bip32::KeySource;
|
||||||
|
use crate::blockdata::script::ScriptBuf;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::psbt::map::Map;
|
||||||
|
use crate::psbt::{raw, Error};
|
||||||
|
use crate::taproot::{TapLeafHash, TapTree};
|
||||||
|
|
||||||
/// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00
|
/// Type: Redeem ScriptBuf PSBT_OUT_REDEEM_SCRIPT = 0x00
|
||||||
const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00;
|
const PSBT_OUT_REDEEM_SCRIPT: u8 = 0x00;
|
||||||
|
@ -51,25 +49,16 @@ pub struct Output {
|
||||||
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
|
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq"))]
|
||||||
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
|
pub tap_key_origins: BTreeMap<XOnlyPublicKey, (Vec<TapLeafHash>, KeySource)>,
|
||||||
/// Proprietary key-value pairs for this output.
|
/// Proprietary key-value pairs for this output.
|
||||||
#[cfg_attr(
|
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
|
||||||
feature = "serde",
|
|
||||||
serde(with = "crate::serde_utils::btreemap_as_seq_byte_values")
|
|
||||||
)]
|
|
||||||
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
|
pub proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>>,
|
||||||
/// Unknown key-value pairs for this output.
|
/// Unknown key-value pairs for this output.
|
||||||
#[cfg_attr(
|
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::btreemap_as_seq_byte_values"))]
|
||||||
feature = "serde",
|
|
||||||
serde(with = "crate::serde_utils::btreemap_as_seq_byte_values")
|
|
||||||
)]
|
|
||||||
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
|
pub unknown: BTreeMap<raw::Key, Vec<u8>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output {
|
impl Output {
|
||||||
pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> {
|
pub(super) fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), Error> {
|
||||||
let raw::Pair {
|
let raw::Pair { key: raw_key, value: raw_value } = pair;
|
||||||
key: raw_key,
|
|
||||||
value: raw_value,
|
|
||||||
} = pair;
|
|
||||||
|
|
||||||
match raw_key.type_value {
|
match raw_key.type_value {
|
||||||
PSBT_OUT_REDEEM_SCRIPT => {
|
PSBT_OUT_REDEEM_SCRIPT => {
|
||||||
|
@ -92,7 +81,7 @@ impl Output {
|
||||||
match self.proprietary.entry(key) {
|
match self.proprietary.entry(key) {
|
||||||
btree_map::Entry::Vacant(empty_key) => {
|
btree_map::Entry::Vacant(empty_key) => {
|
||||||
empty_key.insert(raw_value);
|
empty_key.insert(raw_value);
|
||||||
},
|
}
|
||||||
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key)),
|
btree_map::Entry::Occupied(_) => return Err(Error::DuplicateKey(raw_key)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +105,7 @@ impl Output {
|
||||||
empty_key.insert(raw_value);
|
empty_key.insert(raw_value);
|
||||||
}
|
}
|
||||||
btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone())),
|
btree_map::Entry::Occupied(k) => return Err(Error::DuplicateKey(k.key().clone())),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -165,17 +154,11 @@ impl Map for Output {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, value) in self.proprietary.iter() {
|
for (key, value) in self.proprietary.iter() {
|
||||||
rv.push(raw::Pair {
|
rv.push(raw::Pair { key: key.to_key(), value: value.clone() });
|
||||||
key: key.to_key(),
|
|
||||||
value: value.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (key, value) in self.unknown.iter() {
|
for (key, value) in self.unknown.iter() {
|
||||||
rv.push(raw::Pair {
|
rv.push(raw::Pair { key: key.clone(), value: value.clone() });
|
||||||
key: key.clone(),
|
|
||||||
value: value.clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rv
|
rv
|
||||||
|
|
|
@ -7,24 +7,22 @@
|
||||||
//! except we define PSBTs containing non-standard sighash types as invalid.
|
//! except we define PSBTs containing non-standard sighash types as invalid.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use core::{cmp, fmt};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use core::{fmt, cmp};
|
|
||||||
|
|
||||||
use secp256k1::{Message, Secp256k1, Signing};
|
|
||||||
use bitcoin_internals::write_err;
|
use bitcoin_internals::write_err;
|
||||||
|
use secp256k1::{Message, Secp256k1, Signing};
|
||||||
|
|
||||||
use crate::{prelude::*, Amount};
|
use crate::bip32::{self, ExtendedPrivKey, ExtendedPubKey, KeySource};
|
||||||
|
|
||||||
use crate::blockdata::script::ScriptBuf;
|
use crate::blockdata::script::ScriptBuf;
|
||||||
use crate::blockdata::transaction::{Transaction, TxOut};
|
use crate::blockdata::transaction::{Transaction, TxOut};
|
||||||
use crate::bip32::{self, ExtendedPrivKey, ExtendedPubKey, KeySource};
|
|
||||||
use crate::crypto::ecdsa;
|
use crate::crypto::ecdsa;
|
||||||
use crate::crypto::key::{PublicKey, PrivateKey};
|
use crate::crypto::key::{PrivateKey, PublicKey};
|
||||||
use crate::sighash::{self, EcdsaSighashType, SighashCache};
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub use crate::sighash::Prevouts;
|
pub use crate::sighash::Prevouts;
|
||||||
|
use crate::sighash::{self, EcdsaSighashType, SighashCache};
|
||||||
|
use crate::Amount;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
@ -86,7 +84,7 @@ impl PartiallySignedTransaction {
|
||||||
(None, Some(non_witness_utxo)) => {
|
(None, Some(non_witness_utxo)) => {
|
||||||
let vout = tx_input.previous_output.vout as usize;
|
let vout = tx_input.previous_output.vout as usize;
|
||||||
non_witness_utxo.output.get(vout).ok_or(Error::PsbtUtxoOutOfbounds)
|
non_witness_utxo.output.get(vout).ok_or(Error::PsbtUtxoOutOfbounds)
|
||||||
},
|
}
|
||||||
(None, None) => Err(Error::MissingUtxo),
|
(None, None) => Err(Error::MissingUtxo),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -161,7 +159,7 @@ impl PartiallySignedTransaction {
|
||||||
match self.xpub.entry(xpub) {
|
match self.xpub.entry(xpub) {
|
||||||
btree_map::Entry::Vacant(entry) => {
|
btree_map::Entry::Vacant(entry) => {
|
||||||
entry.insert((fingerprint1, derivation1));
|
entry.insert((fingerprint1, derivation1));
|
||||||
},
|
}
|
||||||
btree_map::Entry::Occupied(mut entry) => {
|
btree_map::Entry::Occupied(mut entry) => {
|
||||||
// Here in case of the conflict we select the version with algorithm:
|
// Here in case of the conflict we select the version with algorithm:
|
||||||
// 1) if everything is equal we do nothing
|
// 1) if everything is equal we do nothing
|
||||||
|
@ -174,15 +172,17 @@ impl PartiallySignedTransaction {
|
||||||
|
|
||||||
let (fingerprint2, derivation2) = entry.get().clone();
|
let (fingerprint2, derivation2) = entry.get().clone();
|
||||||
|
|
||||||
if (derivation1 == derivation2 && fingerprint1 == fingerprint2) ||
|
if (derivation1 == derivation2 && fingerprint1 == fingerprint2)
|
||||||
(derivation1.len() < derivation2.len() && derivation1[..] == derivation2[derivation2.len() - derivation1.len()..])
|
|| (derivation1.len() < derivation2.len()
|
||||||
|
&& derivation1[..]
|
||||||
|
== derivation2[derivation2.len() - derivation1.len()..])
|
||||||
{
|
{
|
||||||
continue
|
continue;
|
||||||
}
|
} else if derivation2[..]
|
||||||
else if derivation2[..] == derivation1[derivation1.len() - derivation2.len()..]
|
== derivation1[derivation1.len() - derivation2.len()..]
|
||||||
{
|
{
|
||||||
entry.insert((fingerprint1, derivation1));
|
entry.insert((fingerprint1, derivation1));
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
return Err(Error::CombineInconsistentKeySources(Box::new(xpub)));
|
return Err(Error::CombineInconsistentKeySources(Box::new(xpub)));
|
||||||
}
|
}
|
||||||
|
@ -237,8 +237,12 @@ impl PartiallySignedTransaction {
|
||||||
for i in 0..self.inputs.len() {
|
for i in 0..self.inputs.len() {
|
||||||
if let Ok(SigningAlgorithm::Ecdsa) = self.signing_algorithm(i) {
|
if let Ok(SigningAlgorithm::Ecdsa) = self.signing_algorithm(i) {
|
||||||
match self.bip32_sign_ecdsa(k, i, &mut cache, secp) {
|
match self.bip32_sign_ecdsa(k, i, &mut cache, secp) {
|
||||||
Ok(v) => { used.insert(i, v); },
|
Ok(v) => {
|
||||||
Err(e) => { errors.insert(i, e); },
|
used.insert(i, v);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
errors.insert(i, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -289,10 +293,8 @@ impl PartiallySignedTransaction {
|
||||||
Ok((msg, sighash_ty)) => (msg, sighash_ty),
|
Ok((msg, sighash_ty)) => (msg, sighash_ty),
|
||||||
};
|
};
|
||||||
|
|
||||||
let sig = ecdsa::Signature {
|
let sig =
|
||||||
sig: secp.sign_ecdsa(&msg, &sk.inner),
|
ecdsa::Signature { sig: secp.sign_ecdsa(&msg, &sk.inner), hash_ty: sighash_ty };
|
||||||
hash_ty: sighash_ty,
|
|
||||||
};
|
|
||||||
|
|
||||||
let pk = sk.public_key(secp);
|
let pk = sk.public_key(secp);
|
||||||
|
|
||||||
|
@ -323,35 +325,42 @@ impl PartiallySignedTransaction {
|
||||||
let utxo = self.spend_utxo(input_index)?;
|
let utxo = self.spend_utxo(input_index)?;
|
||||||
let spk = &utxo.script_pubkey; // scriptPubkey for input spend utxo.
|
let spk = &utxo.script_pubkey; // scriptPubkey for input spend utxo.
|
||||||
|
|
||||||
let hash_ty = input.ecdsa_hash_ty()
|
let hash_ty = input.ecdsa_hash_ty().map_err(|_| SignError::InvalidSighashType)?; // Only support standard sighash types.
|
||||||
.map_err(|_| SignError::InvalidSighashType)?; // Only support standard sighash types.
|
|
||||||
|
|
||||||
match self.output_type(input_index)? {
|
match self.output_type(input_index)? {
|
||||||
Bare => {
|
Bare => {
|
||||||
let sighash = cache.legacy_signature_hash(input_index, spk, hash_ty.to_u32())?;
|
let sighash = cache.legacy_signature_hash(input_index, spk, hash_ty.to_u32())?;
|
||||||
Ok((Message::from(sighash), hash_ty))
|
Ok((Message::from(sighash), hash_ty))
|
||||||
},
|
}
|
||||||
Sh => {
|
Sh => {
|
||||||
let script_code = input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?;
|
let script_code =
|
||||||
let sighash = cache.legacy_signature_hash(input_index, script_code, hash_ty.to_u32())?;
|
input.redeem_script.as_ref().ok_or(SignError::MissingRedeemScript)?;
|
||||||
|
let sighash =
|
||||||
|
cache.legacy_signature_hash(input_index, script_code, hash_ty.to_u32())?;
|
||||||
Ok((Message::from(sighash), hash_ty))
|
Ok((Message::from(sighash), hash_ty))
|
||||||
},
|
}
|
||||||
Wpkh => {
|
Wpkh => {
|
||||||
let script_code = ScriptBuf::p2wpkh_script_code(spk).ok_or(SignError::NotWpkh)?;
|
let script_code = ScriptBuf::p2wpkh_script_code(spk).ok_or(SignError::NotWpkh)?;
|
||||||
let sighash = cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)?;
|
let sighash =
|
||||||
|
cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)?;
|
||||||
Ok((Message::from(sighash), hash_ty))
|
Ok((Message::from(sighash), hash_ty))
|
||||||
},
|
}
|
||||||
ShWpkh => {
|
ShWpkh => {
|
||||||
let script_code = ScriptBuf::p2wpkh_script_code(input.redeem_script.as_ref().expect("checked above"))
|
let script_code = ScriptBuf::p2wpkh_script_code(
|
||||||
|
input.redeem_script.as_ref().expect("checked above"),
|
||||||
|
)
|
||||||
.ok_or(SignError::NotWpkh)?;
|
.ok_or(SignError::NotWpkh)?;
|
||||||
let sighash = cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)?;
|
let sighash =
|
||||||
|
cache.segwit_signature_hash(input_index, &script_code, utxo.value, hash_ty)?;
|
||||||
Ok((Message::from(sighash), hash_ty))
|
Ok((Message::from(sighash), hash_ty))
|
||||||
},
|
}
|
||||||
Wsh | ShWsh => {
|
Wsh | ShWsh => {
|
||||||
let script_code = input.witness_script.as_ref().ok_or(SignError::MissingWitnessScript)?;
|
let script_code =
|
||||||
let sighash = cache.segwit_signature_hash(input_index, script_code, utxo.value, hash_ty)?;
|
input.witness_script.as_ref().ok_or(SignError::MissingWitnessScript)?;
|
||||||
|
let sighash =
|
||||||
|
cache.segwit_signature_hash(input_index, script_code, utxo.value, hash_ty)?;
|
||||||
Ok((Message::from(sighash), hash_ty))
|
Ok((Message::from(sighash), hash_ty))
|
||||||
},
|
}
|
||||||
Tr => {
|
Tr => {
|
||||||
// This PSBT signing API is WIP, taproot to come shortly.
|
// This PSBT signing API is WIP, taproot to come shortly.
|
||||||
Err(SignError::Unsupported)
|
Err(SignError::Unsupported)
|
||||||
|
@ -481,13 +490,21 @@ pub trait GetKey {
|
||||||
/// - `Some(key)` if the key is found.
|
/// - `Some(key)` if the key is found.
|
||||||
/// - `None` if the key was not found but no error was encountered.
|
/// - `None` if the key was not found but no error was encountered.
|
||||||
/// - `Err` if an error was encountered while looking for the key.
|
/// - `Err` if an error was encountered while looking for the key.
|
||||||
fn get_key<C: Signing>(&self, key_request: KeyRequest, secp: &Secp256k1<C>) -> Result<Option<PrivateKey>, Self::Error>;
|
fn get_key<C: Signing>(
|
||||||
|
&self,
|
||||||
|
key_request: KeyRequest,
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
) -> Result<Option<PrivateKey>, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GetKey for ExtendedPrivKey {
|
impl GetKey for ExtendedPrivKey {
|
||||||
type Error = GetKeyError;
|
type Error = GetKeyError;
|
||||||
|
|
||||||
fn get_key<C: Signing>(&self, key_request: KeyRequest, secp: &Secp256k1<C>) -> Result<Option<PrivateKey>, Self::Error> {
|
fn get_key<C: Signing>(
|
||||||
|
&self,
|
||||||
|
key_request: KeyRequest,
|
||||||
|
secp: &Secp256k1<C>,
|
||||||
|
) -> Result<Option<PrivateKey>, Self::Error> {
|
||||||
match key_request {
|
match key_request {
|
||||||
KeyRequest::Pubkey(_) => Err(GetKeyError::NotSupported),
|
KeyRequest::Pubkey(_) => Err(GetKeyError::NotSupported),
|
||||||
KeyRequest::Bip32((fingerprint, path)) => {
|
KeyRequest::Bip32((fingerprint, path)) => {
|
||||||
|
@ -577,7 +594,8 @@ impl fmt::Display for GetKeyError {
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Bip32(ref e) => write_err!(f, "a bip23 error"; e),
|
Bip32(ref e) => write_err!(f, "a bip23 error"; e),
|
||||||
NotSupported => f.write_str("the GetKey operation is not supported for this key request"),
|
NotSupported =>
|
||||||
|
f.write_str("the GetKey operation is not supported for this key request"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -596,9 +614,7 @@ impl std::error::Error for GetKeyError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<bip32::Error> for GetKeyError {
|
impl From<bip32::Error> for GetKeyError {
|
||||||
fn from(e: bip32::Error) -> Self {
|
fn from(e: bip32::Error) -> Self { GetKeyError::Bip32(e) }
|
||||||
GetKeyError::Bip32(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The various output types supported by the Bitcoin network.
|
/// The various output types supported by the Bitcoin network.
|
||||||
|
@ -676,7 +692,7 @@ pub enum SignError {
|
||||||
/// Attempt to sign an input with the wrong signing algorithm.
|
/// Attempt to sign an input with the wrong signing algorithm.
|
||||||
WrongSigningAlgorithm,
|
WrongSigningAlgorithm,
|
||||||
/// Signing request currently unsupported.
|
/// Signing request currently unsupported.
|
||||||
Unsupported
|
Unsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for SignError {
|
impl fmt::Display for SignError {
|
||||||
|
@ -698,7 +714,8 @@ impl fmt::Display for SignError {
|
||||||
SighashComputation(e) => write!(f, "sighash: {}", e),
|
SighashComputation(e) => write!(f, "sighash: {}", e),
|
||||||
UnknownOutputType => write!(f, "unable to determine the output type"),
|
UnknownOutputType => write!(f, "unable to determine the output type"),
|
||||||
KeyNotFound => write!(f, "unable to find key"),
|
KeyNotFound => write!(f, "unable to find key"),
|
||||||
WrongSigningAlgorithm => write!(f, "attempt to sign an input with the wrong signing algorithm"),
|
WrongSigningAlgorithm =>
|
||||||
|
write!(f, "attempt to sign an input with the wrong signing algorithm"),
|
||||||
Unsupported => write!(f, "signing request currently unsupported"),
|
Unsupported => write!(f, "signing request currently unsupported"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -730,19 +747,19 @@ impl std::error::Error for SignError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<sighash::Error> for SignError {
|
impl From<sighash::Error> for SignError {
|
||||||
fn from(e: sighash::Error) -> Self {
|
fn from(e: sighash::Error) -> Self { SignError::SighashComputation(e) }
|
||||||
SignError::SighashComputation(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "base64")]
|
#[cfg(feature = "base64")]
|
||||||
mod display_from_str {
|
mod display_from_str {
|
||||||
use super::{PartiallySignedTransaction, Error};
|
use core::fmt::{self, Display, Formatter};
|
||||||
use core::fmt::{Display, Formatter, self};
|
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
|
|
||||||
use base64::display::Base64Display;
|
use base64::display::Base64Display;
|
||||||
use bitcoin_internals::write_err;
|
use bitcoin_internals::write_err;
|
||||||
|
|
||||||
|
use super::{Error, PartiallySignedTransaction};
|
||||||
|
|
||||||
/// Error encountered during PSBT decoding from Base64 string.
|
/// Error encountered during PSBT decoding from Base64 string.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "base64")))]
|
||||||
|
@ -751,7 +768,7 @@ mod display_from_str {
|
||||||
/// Error in internal PSBT data structure.
|
/// Error in internal PSBT data structure.
|
||||||
PsbtEncoding(Error),
|
PsbtEncoding(Error),
|
||||||
/// Error in PSBT Base64 encoding.
|
/// Error in PSBT Base64 encoding.
|
||||||
Base64Encoding(::base64::DecodeError)
|
Base64Encoding(::base64::DecodeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for PsbtParseError {
|
impl Display for PsbtParseError {
|
||||||
|
@ -801,26 +818,24 @@ pub use self::display_from_str::PsbtParseError;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::blockdata::locktime::absolute;
|
use secp256k1::{self, Secp256k1};
|
||||||
use crate::hashes::{sha256, hash160, Hash, ripemd160};
|
|
||||||
use crate::psbt::serialize::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
use secp256k1::{Secp256k1, self};
|
|
||||||
#[cfg(feature = "rand-std")]
|
#[cfg(feature = "rand-std")]
|
||||||
use secp256k1::{All, SecretKey};
|
use secp256k1::{All, SecretKey};
|
||||||
|
|
||||||
use crate::blockdata::script::ScriptBuf;
|
use super::*;
|
||||||
use crate::blockdata::transaction::{Transaction, TxIn, TxOut, OutPoint, Sequence};
|
|
||||||
use crate::network::constants::Network::Bitcoin;
|
|
||||||
use crate::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, KeySource};
|
use crate::bip32::{ChildNumber, ExtendedPrivKey, ExtendedPubKey, KeySource};
|
||||||
use crate::psbt::map::{Output, Input};
|
use crate::blockdata::locktime::absolute;
|
||||||
use crate::psbt::raw;
|
use crate::blockdata::script::ScriptBuf;
|
||||||
use crate::internal_macros::hex;
|
use crate::blockdata::transaction::{OutPoint, Sequence, Transaction, TxIn, TxOut};
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use crate::blockdata::witness::Witness;
|
use crate::blockdata::witness::Witness;
|
||||||
|
use crate::hashes::{hash160, ripemd160, sha256, Hash};
|
||||||
|
use crate::internal_macros::hex;
|
||||||
|
use crate::network::constants::Network::Bitcoin;
|
||||||
|
use crate::psbt::map::{Input, Output};
|
||||||
|
use crate::psbt::raw;
|
||||||
|
use crate::psbt::serialize::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn trivial_psbt() {
|
fn trivial_psbt() {
|
||||||
|
@ -844,7 +859,6 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn psbt_uncompressed_key() {
|
fn psbt_uncompressed_key() {
|
||||||
|
|
||||||
let psbt: PartiallySignedTransaction = hex_psbt!("70736274ff01003302000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff000000000000420204bb0d5d0cca36e7b9c80f63bc04c1240babb83bcd2803ef7ac8b6e2af594291daec281e856c98d210c5ab14dfd5828761f8ee7d5f45ca21ad3e4c4b41b747a3a047304402204f67e2afb76142d44fae58a2495d33a3419daa26cd0db8d04f3452b63289ac0f022010762a9fb67e94cc5cad9026f6dc99ff7f070f4278d30fbc7d0c869dd38c7fe70100").unwrap();
|
let psbt: PartiallySignedTransaction = hex_psbt!("70736274ff01003302000000010000000000000000000000000000000000000000000000000000000000000000ffffffff00ffffffff000000000000420204bb0d5d0cca36e7b9c80f63bc04c1240babb83bcd2803ef7ac8b6e2af594291daec281e856c98d210c5ab14dfd5828761f8ee7d5f45ca21ad3e4c4b41b747a3a047304402204f67e2afb76142d44fae58a2495d33a3419daa26cd0db8d04f3452b63289ac0f022010762a9fb67e94cc5cad9026f6dc99ff7f070f4278d30fbc7d0c869dd38c7fe70100").unwrap();
|
||||||
|
|
||||||
assert!(psbt.inputs[0].partial_sigs.len() == 1);
|
assert!(psbt.inputs[0].partial_sigs.len() == 1);
|
||||||
|
@ -881,8 +895,12 @@ mod tests {
|
||||||
hd_keypaths.insert(pk.public_key, (fprint, dpath.into()));
|
hd_keypaths.insert(pk.public_key, (fprint, dpath.into()));
|
||||||
|
|
||||||
let expected: Output = Output {
|
let expected: Output = Output {
|
||||||
redeem_script: Some(ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap()),
|
redeem_script: Some(
|
||||||
witness_script: Some(ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap()),
|
ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
|
||||||
|
),
|
||||||
|
witness_script: Some(
|
||||||
|
ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
|
||||||
|
),
|
||||||
bip32_derivation: hd_keypaths,
|
bip32_derivation: hd_keypaths,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
@ -898,25 +916,31 @@ mod tests {
|
||||||
unsigned_tx: Transaction {
|
unsigned_tx: Transaction {
|
||||||
version: 2,
|
version: 2,
|
||||||
lock_time: absolute::LockTime::from_consensus(1257139),
|
lock_time: absolute::LockTime::from_consensus(1257139),
|
||||||
input: vec![
|
input: vec![TxIn {
|
||||||
TxIn {
|
|
||||||
previous_output: OutPoint {
|
previous_output: OutPoint {
|
||||||
txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126".parse().unwrap(),
|
txid: "f61b1742ca13176464adb3cb66050c00787bb3a4eead37e985f2df1e37718126"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
vout: 0,
|
vout: 0,
|
||||||
},
|
},
|
||||||
script_sig: ScriptBuf::new(),
|
script_sig: ScriptBuf::new(),
|
||||||
sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
|
sequence: Sequence::ENABLE_LOCKTIME_NO_RBF,
|
||||||
witness: Witness::default(),
|
witness: Witness::default(),
|
||||||
}
|
}],
|
||||||
],
|
|
||||||
output: vec![
|
output: vec![
|
||||||
TxOut {
|
TxOut {
|
||||||
value: 99999699,
|
value: 99999699,
|
||||||
script_pubkey: ScriptBuf::from_hex("76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac").unwrap(),
|
script_pubkey: ScriptBuf::from_hex(
|
||||||
|
"76a914d0c59903c5bac2868760e90fd521a4665aa7652088ac",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
},
|
},
|
||||||
TxOut {
|
TxOut {
|
||||||
value: 100000000,
|
value: 100000000,
|
||||||
script_pubkey: ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap(),
|
script_pubkey: ScriptBuf::from_hex(
|
||||||
|
"a9143545e6e33b832c47050f24d3eeb93c9c03948bc787",
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -935,10 +959,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_then_deserialize_psbtkvpair() {
|
fn serialize_then_deserialize_psbtkvpair() {
|
||||||
let expected = raw::Pair {
|
let expected = raw::Pair {
|
||||||
key: raw::Key {
|
key: raw::Key { type_value: 0u8, key: vec![42u8, 69u8] },
|
||||||
type_value: 0u8,
|
|
||||||
key: vec![42u8, 69u8],
|
|
||||||
},
|
|
||||||
value: vec![69u8, 42u8, 4u8],
|
value: vec![69u8, 42u8, 4u8],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -965,33 +986,39 @@ mod tests {
|
||||||
let tx = Transaction {
|
let tx = Transaction {
|
||||||
version: 1,
|
version: 1,
|
||||||
lock_time: absolute::LockTime::ZERO,
|
lock_time: absolute::LockTime::ZERO,
|
||||||
input: vec![
|
input: vec![TxIn {
|
||||||
TxIn {
|
|
||||||
previous_output: OutPoint {
|
previous_output: OutPoint {
|
||||||
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389".parse().unwrap(),
|
txid: "e567952fb6cc33857f392efa3a46c995a28f69cca4bb1b37e0204dab1ec7a389"
|
||||||
|
.parse()
|
||||||
|
.unwrap(),
|
||||||
vout: 1,
|
vout: 1,
|
||||||
},
|
},
|
||||||
script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985").unwrap(),
|
script_sig: ScriptBuf::from_hex("160014be18d152a9b012039daf3da7de4f53349eecb985")
|
||||||
|
.unwrap(),
|
||||||
sequence: Sequence::MAX,
|
sequence: Sequence::MAX,
|
||||||
witness: Witness::from_slice(&[hex!("03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105")]),
|
witness: Witness::from_slice(&[hex!(
|
||||||
}
|
"03d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f2105"
|
||||||
],
|
)]),
|
||||||
output: vec![
|
}],
|
||||||
TxOut {
|
output: vec![TxOut {
|
||||||
value: 190303501938,
|
value: 190303501938,
|
||||||
script_pubkey: ScriptBuf::from_hex("a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587").unwrap(),
|
script_pubkey: ScriptBuf::from_hex(
|
||||||
},
|
"a914339725ba21efd62ac753a9bcd067d6c7a6a39d0587",
|
||||||
],
|
)
|
||||||
|
.unwrap(),
|
||||||
|
}],
|
||||||
};
|
};
|
||||||
let unknown: BTreeMap<raw::Key, Vec<u8>> = vec![(
|
let unknown: BTreeMap<raw::Key, Vec<u8>> =
|
||||||
raw::Key { type_value: 1, key: vec![0, 1] },
|
vec![(raw::Key { type_value: 1, key: vec![0, 1] }, vec![3, 4, 5])]
|
||||||
vec![3, 4 ,5],
|
.into_iter()
|
||||||
)].into_iter().collect();
|
.collect();
|
||||||
let key_source = ("deadbeef".parse().unwrap(), "m/0'/1".parse().unwrap());
|
let key_source = ("deadbeef".parse().unwrap(), "m/0'/1".parse().unwrap());
|
||||||
let keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = vec![(
|
let keypaths: BTreeMap<secp256k1::PublicKey, KeySource> = vec![(
|
||||||
"0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
|
"0339880dc92394b7355e3d0439fa283c31de7590812ea011c4245c0674a685e883".parse().unwrap(),
|
||||||
key_source.clone(),
|
key_source.clone(),
|
||||||
)].into_iter().collect();
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
let proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>> = vec![(
|
let proprietary: BTreeMap<raw::ProprietaryKey, Vec<u8>> = vec![(
|
||||||
raw::ProprietaryKey {
|
raw::ProprietaryKey {
|
||||||
|
@ -1000,7 +1027,9 @@ mod tests {
|
||||||
key: "test_key".as_bytes().to_vec(),
|
key: "test_key".as_bytes().to_vec(),
|
||||||
},
|
},
|
||||||
vec![5, 6, 7],
|
vec![5, 6, 7],
|
||||||
)].into_iter().collect();
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect();
|
||||||
|
|
||||||
let psbt = PartiallySignedTransaction {
|
let psbt = PartiallySignedTransaction {
|
||||||
version: 0,
|
version: 0,
|
||||||
|
@ -1059,19 +1088,18 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
mod bip_vectors {
|
mod bip_vectors {
|
||||||
use super::*;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
#[cfg(feature = "base64")]
|
#[cfg(feature = "base64")]
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use crate::blockdata::script::ScriptBuf;
|
use super::*;
|
||||||
use crate::blockdata::transaction::{Transaction, TxIn, TxOut, OutPoint, Sequence};
|
|
||||||
use crate::blockdata::locktime::absolute;
|
use crate::blockdata::locktime::absolute;
|
||||||
use crate::psbt::map::{Map, Input, Output};
|
use crate::blockdata::script::ScriptBuf;
|
||||||
use crate::psbt::{raw, PartiallySignedTransaction, Error};
|
use crate::blockdata::transaction::{OutPoint, Sequence, Transaction, TxIn, TxOut};
|
||||||
use crate::sighash::EcdsaSighashType;
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use crate::blockdata::witness::Witness;
|
use crate::blockdata::witness::Witness;
|
||||||
|
use crate::psbt::map::{Input, Map, Output};
|
||||||
|
use crate::psbt::{raw, Error, PartiallySignedTransaction};
|
||||||
|
use crate::sighash::EcdsaSighashType;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "InvalidMagic")]
|
#[should_panic(expected = "InvalidMagic")]
|
||||||
|
@ -1242,11 +1270,15 @@ mod tests {
|
||||||
assert_eq!(unserialized.serialize_hex(), base16str);
|
assert_eq!(unserialized.serialize_hex(), base16str);
|
||||||
assert_eq!(unserialized, hex_psbt!(base16str).unwrap());
|
assert_eq!(unserialized, hex_psbt!(base16str).unwrap());
|
||||||
|
|
||||||
#[cfg(feature = "base64")] {
|
#[cfg(feature = "base64")]
|
||||||
|
{
|
||||||
let base64str = "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA";
|
let base64str = "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA";
|
||||||
assert_eq!(PartiallySignedTransaction::from_str(base64str).unwrap(), unserialized);
|
assert_eq!(PartiallySignedTransaction::from_str(base64str).unwrap(), unserialized);
|
||||||
assert_eq!(base64str, unserialized.to_string());
|
assert_eq!(base64str, unserialized.to_string());
|
||||||
assert_eq!(PartiallySignedTransaction::from_str(base64str).unwrap(), hex_psbt!(base16str).unwrap());
|
assert_eq!(
|
||||||
|
PartiallySignedTransaction::from_str(base64str).unwrap(),
|
||||||
|
hex_psbt!(base16str).unwrap()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1260,7 +1292,8 @@ mod tests {
|
||||||
assert!(&psbt.inputs[0].final_script_sig.is_some());
|
assert!(&psbt.inputs[0].final_script_sig.is_some());
|
||||||
|
|
||||||
let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
|
let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
|
||||||
let expected_out = ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap();
|
let expected_out =
|
||||||
|
ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap();
|
||||||
|
|
||||||
assert!(redeem_script.is_v0_p2wpkh());
|
assert!(redeem_script.is_v0_p2wpkh());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1287,8 +1320,7 @@ mod tests {
|
||||||
assert_eq!(tx_input.previous_output.txid, psbt_non_witness_utxo.txid());
|
assert_eq!(tx_input.previous_output.txid, psbt_non_witness_utxo.txid());
|
||||||
assert!(psbt_non_witness_utxo.output[tx_input.previous_output.vout as usize]
|
assert!(psbt_non_witness_utxo.output[tx_input.previous_output.vout as usize]
|
||||||
.script_pubkey
|
.script_pubkey
|
||||||
.is_p2pkh()
|
.is_p2pkh());
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
psbt.inputs[0].sighash_type.as_ref().unwrap().ecdsa_hash_ty().unwrap(),
|
psbt.inputs[0].sighash_type.as_ref().unwrap().ecdsa_hash_ty().unwrap(),
|
||||||
EcdsaSighashType::All
|
EcdsaSighashType::All
|
||||||
|
@ -1306,7 +1338,8 @@ mod tests {
|
||||||
assert!(&psbt.inputs[1].final_script_sig.is_none());
|
assert!(&psbt.inputs[1].final_script_sig.is_none());
|
||||||
|
|
||||||
let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
|
let redeem_script = psbt.inputs[1].redeem_script.as_ref().unwrap();
|
||||||
let expected_out = ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap();
|
let expected_out =
|
||||||
|
ScriptBuf::from_hex("a9143545e6e33b832c47050f24d3eeb93c9c03948bc787").unwrap();
|
||||||
|
|
||||||
assert!(redeem_script.is_v0_p2wpkh());
|
assert!(redeem_script.is_v0_p2wpkh());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1330,7 +1363,8 @@ mod tests {
|
||||||
assert!(&psbt.inputs[0].final_script_sig.is_none());
|
assert!(&psbt.inputs[0].final_script_sig.is_none());
|
||||||
|
|
||||||
let redeem_script = psbt.inputs[0].redeem_script.as_ref().unwrap();
|
let redeem_script = psbt.inputs[0].redeem_script.as_ref().unwrap();
|
||||||
let expected_out = ScriptBuf::from_hex("a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87").unwrap();
|
let expected_out =
|
||||||
|
ScriptBuf::from_hex("a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87").unwrap();
|
||||||
|
|
||||||
assert!(redeem_script.is_v0_p2wsh());
|
assert!(redeem_script.is_v0_p2wsh());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -1355,10 +1389,7 @@ mod tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut unknown: BTreeMap<raw::Key, Vec<u8>> = BTreeMap::new();
|
let mut unknown: BTreeMap<raw::Key, Vec<u8>> = BTreeMap::new();
|
||||||
let key: raw::Key = raw::Key {
|
let key: raw::Key = raw::Key { type_value: 0x0fu8, key: hex!("010203040506070809") };
|
||||||
type_value: 0x0fu8,
|
|
||||||
key: hex!("010203040506070809"),
|
|
||||||
};
|
|
||||||
let value: Vec<u8> = hex!("0102030405060708090a0b0c0d0e0f");
|
let value: Vec<u8> = hex!("0102030405060708090a0b0c0d0e0f");
|
||||||
|
|
||||||
unknown.insert(key, value);
|
unknown.insert(key, value);
|
||||||
|
@ -1378,7 +1409,10 @@ mod tests {
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
assert_eq!(err.to_string(), "invalid taproot signature");
|
assert_eq!(err.to_string(), "invalid taproot signature");
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
assert_eq!(err.to_string(), "invalid taproot signature: invalid taproot signature size: 66");
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
"invalid taproot signature: invalid taproot signature size: 66"
|
||||||
|
);
|
||||||
let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757221602fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000000000").unwrap_err();
|
let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757221602fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000000000").unwrap_err();
|
||||||
assert_eq!(err.to_string(), "invalid xonly public key");
|
assert_eq!(err.to_string(), "invalid xonly public key");
|
||||||
let err = hex_psbt!("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000001052102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa23200").unwrap_err();
|
let err = hex_psbt!("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000001052102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa23200").unwrap_err();
|
||||||
|
@ -1394,12 +1428,18 @@ mod tests {
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
assert_eq!(err.to_string(), "invalid taproot signature");
|
assert_eq!(err.to_string(), "invalid taproot signature");
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
assert_eq!(err.to_string(), "invalid taproot signature: invalid taproot signature size: 66");
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
"invalid taproot signature: invalid taproot signature size: 66"
|
||||||
|
);
|
||||||
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b093989756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err();
|
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b093989756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err();
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
assert_eq!(err.to_string(), "invalid taproot signature");
|
assert_eq!(err.to_string(), "invalid taproot signature");
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
assert_eq!(err.to_string(), "invalid taproot signature: invalid taproot signature size: 57");
|
assert_eq!(
|
||||||
|
err.to_string(),
|
||||||
|
"invalid taproot signature: invalid taproot signature size: 57"
|
||||||
|
);
|
||||||
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926315c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f80023202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err();
|
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926315c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f80023202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err();
|
||||||
assert_eq!(err.to_string(), "invalid control block");
|
assert_eq!(err.to_string(), "invalid control block");
|
||||||
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926115c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e123202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err();
|
let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926115c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e123202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err();
|
||||||
|
@ -1575,11 +1615,10 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_and_deserialize_proprietary() {
|
fn serialize_and_deserialize_proprietary() {
|
||||||
let mut psbt: PartiallySignedTransaction = hex_psbt!("70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000").unwrap();
|
let mut psbt: PartiallySignedTransaction = hex_psbt!("70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000").unwrap();
|
||||||
psbt.proprietary.insert(raw::ProprietaryKey {
|
psbt.proprietary.insert(
|
||||||
prefix: b"test".to_vec(),
|
raw::ProprietaryKey { prefix: b"test".to_vec(), subtype: 0u8, key: b"test".to_vec() },
|
||||||
subtype: 0u8,
|
b"test".to_vec(),
|
||||||
key: b"test".to_vec(),
|
);
|
||||||
}, b"test".to_vec());
|
|
||||||
assert!(!psbt.proprietary.is_empty());
|
assert!(!psbt.proprietary.is_empty());
|
||||||
let rtt: PartiallySignedTransaction = hex_psbt!(&psbt.serialize_hex()).unwrap();
|
let rtt: PartiallySignedTransaction = hex_psbt!(&psbt.serialize_hex()).unwrap();
|
||||||
assert!(!rtt.proprietary.is_empty());
|
assert!(!rtt.proprietary.is_empty());
|
||||||
|
@ -1725,31 +1764,31 @@ mod tests {
|
||||||
let mut t2 = t.clone();
|
let mut t2 = t.clone();
|
||||||
t2.inputs[0].non_witness_utxo = None;
|
t2.inputs[0].non_witness_utxo = None;
|
||||||
match t2.fee().unwrap_err() {
|
match t2.fee().unwrap_err() {
|
||||||
Error::MissingUtxo => {},
|
Error::MissingUtxo => {}
|
||||||
e => panic!("unexpected error: {:?}", e)
|
e => panic!("unexpected error: {:?}", e),
|
||||||
}
|
}
|
||||||
// negative fee
|
// negative fee
|
||||||
let mut t3 = t.clone();
|
let mut t3 = t.clone();
|
||||||
t3.unsigned_tx.output[0].value = prev_output_val;
|
t3.unsigned_tx.output[0].value = prev_output_val;
|
||||||
match t3.fee().unwrap_err() {
|
match t3.fee().unwrap_err() {
|
||||||
Error::NegativeFee => {},
|
Error::NegativeFee => {}
|
||||||
e => panic!("unexpected error: {:?}", e)
|
e => panic!("unexpected error: {:?}", e),
|
||||||
}
|
}
|
||||||
// overflow
|
// overflow
|
||||||
t.unsigned_tx.output[0].value = u64::max_value();
|
t.unsigned_tx.output[0].value = u64::max_value();
|
||||||
t.unsigned_tx.output[1].value = u64::max_value();
|
t.unsigned_tx.output[1].value = u64::max_value();
|
||||||
match t.fee().unwrap_err() {
|
match t.fee().unwrap_err() {
|
||||||
Error::FeeOverflow => {},
|
Error::FeeOverflow => {}
|
||||||
e => panic!("unexpected error: {:?}", e)
|
e => panic!("unexpected error: {:?}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "rand-std")]
|
#[cfg(feature = "rand-std")]
|
||||||
fn sign_psbt() {
|
fn sign_psbt() {
|
||||||
use crate::WPubkeyHash;
|
|
||||||
use crate::address::WitnessProgram;
|
use crate::address::WitnessProgram;
|
||||||
use crate::bip32::{Fingerprint, DerivationPath};
|
use crate::bip32::{DerivationPath, Fingerprint};
|
||||||
|
use crate::WPubkeyHash;
|
||||||
|
|
||||||
let unsigned_tx = Transaction {
|
let unsigned_tx = Transaction {
|
||||||
version: 2,
|
version: 2,
|
||||||
|
@ -1767,7 +1806,7 @@ mod tests {
|
||||||
key_map.insert(pk, priv_key);
|
key_map.insert(pk, priv_key);
|
||||||
|
|
||||||
// First input we can spend. See comment above on key_map for why we use defaults here.
|
// First input we can spend. See comment above on key_map for why we use defaults here.
|
||||||
let txout_wpkh = TxOut{
|
let txout_wpkh = TxOut {
|
||||||
value: 10,
|
value: 10,
|
||||||
script_pubkey: ScriptBuf::new_v0_p2wpkh(&WPubkeyHash::hash(&pk.to_bytes())),
|
script_pubkey: ScriptBuf::new_v0_p2wpkh(&WPubkeyHash::hash(&pk.to_bytes())),
|
||||||
};
|
};
|
||||||
|
@ -1778,13 +1817,10 @@ mod tests {
|
||||||
psbt.inputs[0].bip32_derivation = map;
|
psbt.inputs[0].bip32_derivation = map;
|
||||||
|
|
||||||
// Second input is unspendable by us e.g., from another wallet that supports future upgrades.
|
// Second input is unspendable by us e.g., from another wallet that supports future upgrades.
|
||||||
let unknown_prog = WitnessProgram::new(
|
let unknown_prog =
|
||||||
crate::address::WitnessVersion::V4, vec![0xaa; 34]
|
WitnessProgram::new(crate::address::WitnessVersion::V4, vec![0xaa; 34]).unwrap();
|
||||||
).unwrap();
|
let txout_unknown_future =
|
||||||
let txout_unknown_future = TxOut{
|
TxOut { value: 10, script_pubkey: ScriptBuf::new_witness_program(&unknown_prog) };
|
||||||
value: 10,
|
|
||||||
script_pubkey: ScriptBuf::new_witness_program(&unknown_prog),
|
|
||||||
};
|
|
||||||
psbt.inputs[1].witness_utxo = Some(txout_unknown_future);
|
psbt.inputs[1].witness_utxo = Some(txout_unknown_future);
|
||||||
|
|
||||||
let sigs = psbt.sign(&key_map, &secp).unwrap();
|
let sigs = psbt.sign(&key_map, &secp).unwrap();
|
||||||
|
|
|
@ -6,16 +6,17 @@
|
||||||
//! <https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki>.
|
//! <https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki>.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
use core::fmt;
|
|
||||||
use core::convert::TryFrom;
|
use core::convert::TryFrom;
|
||||||
|
use core::fmt;
|
||||||
|
|
||||||
|
use super::serialize::{Deserialize, Serialize};
|
||||||
|
use crate::consensus::encode::{
|
||||||
|
self, deserialize, serialize, Decodable, Encodable, ReadExt, VarInt, WriteExt, MAX_VEC_SIZE,
|
||||||
|
};
|
||||||
use crate::io;
|
use crate::io;
|
||||||
use crate::consensus::encode::{self, ReadExt, WriteExt, Decodable, Encodable, VarInt, serialize, deserialize, MAX_VEC_SIZE};
|
use crate::prelude::*;
|
||||||
use crate::psbt::Error;
|
use crate::psbt::Error;
|
||||||
|
|
||||||
use super::serialize::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
/// A PSBT key in its raw byte form.
|
/// A PSBT key in its raw byte form.
|
||||||
#[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
|
#[derive(Debug, PartialEq, Hash, Eq, Clone, Ord, PartialOrd)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
|
@ -51,7 +52,10 @@ pub type ProprietaryType = u8;
|
||||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
|
||||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
#[cfg_attr(feature = "serde", serde(crate = "actual_serde"))]
|
||||||
pub struct ProprietaryKey<Subtype=ProprietaryType> where Subtype: Copy + From<u8> + Into<u8> {
|
pub struct ProprietaryKey<Subtype = ProprietaryType>
|
||||||
|
where
|
||||||
|
Subtype: Copy + From<u8> + Into<u8>,
|
||||||
|
{
|
||||||
/// Proprietary type prefix used for grouping together keys under some
|
/// Proprietary type prefix used for grouping together keys under some
|
||||||
/// application and avoid namespace collision
|
/// application and avoid namespace collision
|
||||||
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
|
#[cfg_attr(feature = "serde", serde(with = "crate::serde_utils::hex_bytes"))]
|
||||||
|
@ -83,7 +87,7 @@ impl Key {
|
||||||
return Err(encode::Error::OversizedVectorAllocation {
|
return Err(encode::Error::OversizedVectorAllocation {
|
||||||
requested: key_byte_size as usize,
|
requested: key_byte_size as usize,
|
||||||
max: MAX_VEC_SIZE,
|
max: MAX_VEC_SIZE,
|
||||||
})?
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let type_value: u8 = Decodable::consensus_decode(r)?;
|
let type_value: u8 = Decodable::consensus_decode(r)?;
|
||||||
|
@ -100,7 +104,9 @@ impl Key {
|
||||||
impl Serialize for Key {
|
impl Serialize for Key {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
let mut buf = Vec::new();
|
let mut buf = Vec::new();
|
||||||
VarInt((self.key.len() + 1) as u64).consensus_encode(&mut buf).expect("in-memory writers don't error");
|
VarInt((self.key.len() + 1) as u64)
|
||||||
|
.consensus_encode(&mut buf)
|
||||||
|
.expect("in-memory writers don't error");
|
||||||
|
|
||||||
self.type_value.consensus_encode(&mut buf).expect("in-memory writers don't error");
|
self.type_value.consensus_encode(&mut buf).expect("in-memory writers don't error");
|
||||||
|
|
||||||
|
@ -131,14 +137,14 @@ impl Deserialize for Pair {
|
||||||
|
|
||||||
impl Pair {
|
impl Pair {
|
||||||
pub(crate) fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
|
pub(crate) fn decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, Error> {
|
||||||
Ok(Pair {
|
Ok(Pair { key: Key::decode(r)?, value: Decodable::consensus_decode(r)? })
|
||||||
key: Key::decode(r)?,
|
|
||||||
value: Decodable::consensus_decode(r)?,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Subtype> Encodable for ProprietaryKey<Subtype> where Subtype: Copy + From<u8> + Into<u8> {
|
impl<Subtype> Encodable for ProprietaryKey<Subtype>
|
||||||
|
where
|
||||||
|
Subtype: Copy + From<u8> + Into<u8>,
|
||||||
|
{
|
||||||
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
fn consensus_encode<W: io::Write + ?Sized>(&self, w: &mut W) -> Result<usize, io::Error> {
|
||||||
let mut len = self.prefix.consensus_encode(w)? + 1;
|
let mut len = self.prefix.consensus_encode(w)? + 1;
|
||||||
w.emit_u8(self.subtype.into())?;
|
w.emit_u8(self.subtype.into())?;
|
||||||
|
@ -148,7 +154,10 @@ impl<Subtype> Encodable for ProprietaryKey<Subtype> where Subtype: Copy + From<u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Subtype> Decodable for ProprietaryKey<Subtype> where Subtype: Copy + From<u8> + Into<u8> {
|
impl<Subtype> Decodable for ProprietaryKey<Subtype>
|
||||||
|
where
|
||||||
|
Subtype: Copy + From<u8> + Into<u8>,
|
||||||
|
{
|
||||||
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
fn consensus_decode<R: io::Read + ?Sized>(r: &mut R) -> Result<Self, encode::Error> {
|
||||||
let prefix = Vec::<u8>::consensus_decode(r)?;
|
let prefix = Vec::<u8>::consensus_decode(r)?;
|
||||||
let subtype = Subtype::from(r.read_u8()?);
|
let subtype = Subtype::from(r.read_u8()?);
|
||||||
|
@ -158,19 +167,18 @@ impl<Subtype> Decodable for ProprietaryKey<Subtype> where Subtype: Copy + From<u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Subtype> ProprietaryKey<Subtype> where Subtype: Copy + From<u8> + Into<u8> {
|
impl<Subtype> ProprietaryKey<Subtype>
|
||||||
|
where
|
||||||
|
Subtype: Copy + From<u8> + Into<u8>,
|
||||||
|
{
|
||||||
/// Constructs full [Key] corresponding to this proprietary key type
|
/// Constructs full [Key] corresponding to this proprietary key type
|
||||||
pub fn to_key(&self) -> Key {
|
pub fn to_key(&self) -> Key { Key { type_value: 0xFC, key: serialize(self) } }
|
||||||
Key {
|
|
||||||
type_value: 0xFC,
|
|
||||||
key: serialize(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Subtype> TryFrom<Key> for ProprietaryKey<Subtype>
|
impl<Subtype> TryFrom<Key> for ProprietaryKey<Subtype>
|
||||||
where
|
where
|
||||||
Subtype:Copy + From<u8> + Into<u8> {
|
Subtype: Copy + From<u8> + Into<u8>,
|
||||||
|
{
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
/// Constructs a [`ProprietaryKey`] from a [`Key`].
|
/// Constructs a [`ProprietaryKey`] from a [`Key`].
|
||||||
|
@ -179,7 +187,7 @@ where
|
||||||
/// Returns [`Error::InvalidProprietaryKey`] if `key` does not start with `0xFC` byte.
|
/// Returns [`Error::InvalidProprietaryKey`] if `key` does not start with `0xFC` byte.
|
||||||
fn try_from(key: Key) -> Result<Self, Self::Error> {
|
fn try_from(key: Key) -> Result<Self, Self::Error> {
|
||||||
if key.type_value != 0xFC {
|
if key.type_value != 0xFC {
|
||||||
return Err(Error::InvalidProprietaryKey)
|
return Err(Error::InvalidProprietaryKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(deserialize(&key.key)?)
|
Ok(deserialize(&key.key)?)
|
||||||
|
@ -194,7 +202,7 @@ pub(crate) fn read_to_end<D: io::Read>(mut d: D) -> Result<Vec<u8>, io::Error> {
|
||||||
match d.read(&mut buf) {
|
match d.read(&mut buf) {
|
||||||
Ok(0) => break,
|
Ok(0) => break,
|
||||||
Ok(n) => result.extend_from_slice(&buf[0..n]),
|
Ok(n) => result.extend_from_slice(&buf[0..n]),
|
||||||
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {},
|
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,31 +6,26 @@
|
||||||
//! according to the BIP-174 specification.
|
//! according to the BIP-174 specification.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::convert::TryFrom;
|
use core::convert::{TryFrom, TryInto};
|
||||||
use core::convert::TryInto;
|
|
||||||
|
|
||||||
use crate::VarInt;
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
use crate::io;
|
|
||||||
|
|
||||||
use crate::blockdata::script::ScriptBuf;
|
|
||||||
use crate::blockdata::witness::Witness;
|
|
||||||
use crate::blockdata::transaction::{Transaction, TxOut};
|
|
||||||
use crate::consensus::encode::{self, serialize, Decodable, Encodable, deserialize_partial};
|
|
||||||
use crate::taproot::TapTree;
|
|
||||||
use secp256k1::{self, XOnlyPublicKey};
|
use secp256k1::{self, XOnlyPublicKey};
|
||||||
use crate::bip32::{ChildNumber, Fingerprint, KeySource};
|
|
||||||
use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
|
||||||
use crate::crypto::{ecdsa, taproot};
|
|
||||||
use crate::psbt::{Error, PartiallySignedTransaction};
|
|
||||||
use crate::taproot::{TapNodeHash, TapLeafHash, ControlBlock, LeafVersion};
|
|
||||||
use crate::crypto::key::PublicKey;
|
|
||||||
|
|
||||||
use super::map::{Map, Input, Output, PsbtSighashType};
|
use super::map::{Input, Map, Output, PsbtSighashType};
|
||||||
use super::Psbt;
|
use super::Psbt;
|
||||||
|
use crate::bip32::{ChildNumber, Fingerprint, KeySource};
|
||||||
use crate::taproot::TaprootBuilder;
|
use crate::blockdata::script::ScriptBuf;
|
||||||
|
use crate::blockdata::transaction::{Transaction, TxOut};
|
||||||
|
use crate::blockdata::witness::Witness;
|
||||||
|
use crate::consensus::encode::{self, deserialize_partial, serialize, Decodable, Encodable};
|
||||||
|
use crate::crypto::key::PublicKey;
|
||||||
|
use crate::crypto::{ecdsa, taproot};
|
||||||
|
use crate::hashes::{hash160, ripemd160, sha256, sha256d, Hash};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::psbt::{Error, PartiallySignedTransaction};
|
||||||
|
use crate::taproot::{
|
||||||
|
ControlBlock, LeafVersion, TapLeafHash, TapNodeHash, TapTree, TaprootBuilder,
|
||||||
|
};
|
||||||
|
use crate::{io, VarInt};
|
||||||
/// A trait for serializing a value as raw data for insertion into PSBT
|
/// A trait for serializing a value as raw data for insertion into PSBT
|
||||||
/// key-value maps.
|
/// key-value maps.
|
||||||
pub(crate) trait Serialize {
|
pub(crate) trait Serialize {
|
||||||
|
@ -46,9 +41,7 @@ pub(crate) trait Deserialize: Sized {
|
||||||
|
|
||||||
impl PartiallySignedTransaction {
|
impl PartiallySignedTransaction {
|
||||||
/// Serialize a value as bytes in hex.
|
/// Serialize a value as bytes in hex.
|
||||||
pub fn serialize_hex(&self) -> String {
|
pub fn serialize_hex(&self) -> String { self.serialize().to_lower_hex_string() }
|
||||||
self.serialize().to_lower_hex_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serialize as raw binary data
|
/// Serialize as raw binary data
|
||||||
pub fn serialize(&self) -> Vec<u8> {
|
pub fn serialize(&self) -> Vec<u8> {
|
||||||
|
@ -72,7 +65,6 @@ impl PartiallySignedTransaction {
|
||||||
buf
|
buf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Deserialize a value from raw binary data.
|
/// Deserialize a value from raw binary data.
|
||||||
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
pub fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
const MAGIC_BYTES: &[u8] = b"psbt";
|
const MAGIC_BYTES: &[u8] = b"psbt";
|
||||||
|
@ -133,15 +125,11 @@ impl_psbt_hash_de_serialize!(sha256d::Hash);
|
||||||
impl_psbt_de_serialize!(Vec<TapLeafHash>);
|
impl_psbt_de_serialize!(Vec<TapLeafHash>);
|
||||||
|
|
||||||
impl Serialize for ScriptBuf {
|
impl Serialize for ScriptBuf {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> { self.to_bytes() }
|
||||||
self.to_bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for ScriptBuf {
|
impl Deserialize for ScriptBuf {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { Ok(Self::from(bytes.to_vec())) }
|
||||||
Ok(Self::from(bytes.to_vec()))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for PublicKey {
|
impl Serialize for PublicKey {
|
||||||
|
@ -154,28 +142,22 @@ impl Serialize for PublicKey {
|
||||||
|
|
||||||
impl Deserialize for PublicKey {
|
impl Deserialize for PublicKey {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
PublicKey::from_slice(bytes)
|
PublicKey::from_slice(bytes).map_err(Error::InvalidPublicKey)
|
||||||
.map_err(Error::InvalidPublicKey)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for secp256k1::PublicKey {
|
impl Serialize for secp256k1::PublicKey {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> { self.serialize().to_vec() }
|
||||||
self.serialize().to_vec()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for secp256k1::PublicKey {
|
impl Deserialize for secp256k1::PublicKey {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
secp256k1::PublicKey::from_slice(bytes)
|
secp256k1::PublicKey::from_slice(bytes).map_err(Error::InvalidSecp256k1PublicKey)
|
||||||
.map_err(Error::InvalidSecp256k1PublicKey)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for ecdsa::Signature {
|
impl Serialize for ecdsa::Signature {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> { self.to_vec() }
|
||||||
self.to_vec()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for ecdsa::Signature {
|
impl Deserialize for ecdsa::Signature {
|
||||||
|
@ -193,17 +175,10 @@ impl Deserialize for ecdsa::Signature {
|
||||||
// also has a field sighash_u32 (See BIP141). For example, when signing with non-standard
|
// also has a field sighash_u32 (See BIP141). For example, when signing with non-standard
|
||||||
// 0x05, the sighash message would have the last field as 0x05u32 while, the verification
|
// 0x05, the sighash message would have the last field as 0x05u32 while, the verification
|
||||||
// would use check the signature assuming sighash_u32 as `0x01`.
|
// would use check the signature assuming sighash_u32 as `0x01`.
|
||||||
ecdsa::Signature::from_slice(bytes)
|
ecdsa::Signature::from_slice(bytes).map_err(|e| match e {
|
||||||
.map_err(|e| match e {
|
ecdsa::Error::EmptySignature => Error::InvalidEcdsaSignature(e),
|
||||||
ecdsa::Error::EmptySignature => {
|
ecdsa::Error::NonStandardSighashType(flag) => Error::NonStandardSighashType(flag),
|
||||||
Error::InvalidEcdsaSignature(e)
|
ecdsa::Error::Secp256k1(..) => Error::InvalidEcdsaSignature(e),
|
||||||
}
|
|
||||||
ecdsa::Error::NonStandardSighashType(flag) => {
|
|
||||||
Error::NonStandardSighashType(flag)
|
|
||||||
}
|
|
||||||
ecdsa::Error::Secp256k1(..) => {
|
|
||||||
Error::InvalidEcdsaSignature(e)
|
|
||||||
}
|
|
||||||
ecdsa::Error::HexEncoding(..) => {
|
ecdsa::Error::HexEncoding(..) => {
|
||||||
unreachable!("Decoding from slice, not hex")
|
unreachable!("Decoding from slice, not hex")
|
||||||
}
|
}
|
||||||
|
@ -228,7 +203,7 @@ impl Serialize for KeySource {
|
||||||
impl Deserialize for KeySource {
|
impl Deserialize for KeySource {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
if bytes.len() < 4 {
|
if bytes.len() < 4 {
|
||||||
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
|
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let fprint: Fingerprint = bytes[0..4].try_into().expect("4 is the fingerprint length");
|
let fprint: Fingerprint = bytes[0..4].try_into().expect("4 is the fingerprint length");
|
||||||
|
@ -248,21 +223,15 @@ impl Deserialize for KeySource {
|
||||||
|
|
||||||
// partial sigs
|
// partial sigs
|
||||||
impl Serialize for Vec<u8> {
|
impl Serialize for Vec<u8> {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> { self.clone() }
|
||||||
self.clone()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for Vec<u8> {
|
impl Deserialize for Vec<u8> {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> { Ok(bytes.to_vec()) }
|
||||||
Ok(bytes.to_vec())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for PsbtSighashType {
|
impl Serialize for PsbtSighashType {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> { serialize(&self.to_u32()) }
|
||||||
serialize(&self.to_u32())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for PsbtSighashType {
|
impl Deserialize for PsbtSighashType {
|
||||||
|
@ -274,37 +243,25 @@ impl Deserialize for PsbtSighashType {
|
||||||
|
|
||||||
// Taproot related ser/deser
|
// Taproot related ser/deser
|
||||||
impl Serialize for XOnlyPublicKey {
|
impl Serialize for XOnlyPublicKey {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> { XOnlyPublicKey::serialize(self).to_vec() }
|
||||||
XOnlyPublicKey::serialize(self).to_vec()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for XOnlyPublicKey {
|
impl Deserialize for XOnlyPublicKey {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
XOnlyPublicKey::from_slice(bytes)
|
XOnlyPublicKey::from_slice(bytes).map_err(|_| Error::InvalidXOnlyPublicKey)
|
||||||
.map_err(|_| Error::InvalidXOnlyPublicKey)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for taproot::Signature {
|
impl Serialize for taproot::Signature {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> { self.to_vec() }
|
||||||
self.to_vec()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for taproot::Signature {
|
impl Deserialize for taproot::Signature {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
taproot::Signature::from_slice(bytes)
|
taproot::Signature::from_slice(bytes).map_err(|e| match e {
|
||||||
.map_err(|e| match e {
|
taproot::Error::InvalidSighashType(flag) => Error::NonStandardSighashType(flag as u32),
|
||||||
taproot::Error::InvalidSighashType(flag) => {
|
taproot::Error::InvalidSignatureSize(_) => Error::InvalidTaprootSignature(e),
|
||||||
Error::NonStandardSighashType(flag as u32)
|
taproot::Error::Secp256k1(..) => Error::InvalidTaprootSignature(e),
|
||||||
}
|
|
||||||
taproot::Error::InvalidSignatureSize(_) => {
|
|
||||||
Error::InvalidTaprootSignature(e)
|
|
||||||
}
|
|
||||||
taproot::Error::Secp256k1(..) => {
|
|
||||||
Error::InvalidTaprootSignature(e)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,7 +279,7 @@ impl Serialize for (XOnlyPublicKey, TapLeafHash) {
|
||||||
impl Deserialize for (XOnlyPublicKey, TapLeafHash) {
|
impl Deserialize for (XOnlyPublicKey, TapLeafHash) {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
if bytes.len() < 32 {
|
if bytes.len() < 32 {
|
||||||
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
|
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into());
|
||||||
}
|
}
|
||||||
let a: XOnlyPublicKey = Deserialize::deserialize(&bytes[..32])?;
|
let a: XOnlyPublicKey = Deserialize::deserialize(&bytes[..32])?;
|
||||||
let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?;
|
let b: TapLeafHash = Deserialize::deserialize(&bytes[32..])?;
|
||||||
|
@ -331,15 +288,12 @@ impl Deserialize for (XOnlyPublicKey, TapLeafHash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for ControlBlock {
|
impl Serialize for ControlBlock {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> { ControlBlock::serialize(self) }
|
||||||
ControlBlock::serialize(self)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deserialize for ControlBlock {
|
impl Deserialize for ControlBlock {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
Self::decode(bytes)
|
Self::decode(bytes).map_err(|_| Error::InvalidControlBlock)
|
||||||
.map_err(|_| Error::InvalidControlBlock)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -356,7 +310,7 @@ impl Serialize for (ScriptBuf, LeafVersion) {
|
||||||
impl Deserialize for (ScriptBuf, LeafVersion) {
|
impl Deserialize for (ScriptBuf, LeafVersion) {
|
||||||
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
fn deserialize(bytes: &[u8]) -> Result<Self, Error> {
|
||||||
if bytes.is_empty() {
|
if bytes.is_empty() {
|
||||||
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into())
|
return Err(io::Error::from(io::ErrorKind::UnexpectedEof).into());
|
||||||
}
|
}
|
||||||
// The last byte is LeafVersion.
|
// The last byte is LeafVersion.
|
||||||
let script = ScriptBuf::deserialize(&bytes[..bytes.len() - 1])?;
|
let script = ScriptBuf::deserialize(&bytes[..bytes.len() - 1])?;
|
||||||
|
@ -366,10 +320,9 @@ impl Deserialize for (ScriptBuf, LeafVersion) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl Serialize for (Vec<TapLeafHash>, KeySource) {
|
impl Serialize for (Vec<TapLeafHash>, KeySource) {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
let mut buf = Vec::with_capacity( 32 * self.0.len() + key_source_len(&self.1));
|
let mut buf = Vec::with_capacity(32 * self.0.len() + key_source_len(&self.1));
|
||||||
self.0.consensus_encode(&mut buf).expect("Vecs don't error allocation");
|
self.0.consensus_encode(&mut buf).expect("Vecs don't error allocation");
|
||||||
// TODO: Add support for writing into a writer for key-source
|
// TODO: Add support for writing into a writer for key-source
|
||||||
buf.extend(self.1.serialize());
|
buf.extend(self.1.serialize());
|
||||||
|
@ -387,11 +340,14 @@ impl Deserialize for (Vec<TapLeafHash>, KeySource) {
|
||||||
|
|
||||||
impl Serialize for TapTree {
|
impl Serialize for TapTree {
|
||||||
fn serialize(&self) -> Vec<u8> {
|
fn serialize(&self) -> Vec<u8> {
|
||||||
let capacity = self.script_leaves().map(|l| {
|
let capacity = self
|
||||||
|
.script_leaves()
|
||||||
|
.map(|l| {
|
||||||
l.script().len() + VarInt(l.script().len() as u64).len() // script version
|
l.script().len() + VarInt(l.script().len() as u64).len() // script version
|
||||||
+ 1 // merkle branch
|
+ 1 // merkle branch
|
||||||
+ 1 // leaf version
|
+ 1 // leaf version
|
||||||
}).sum::<usize>();
|
})
|
||||||
|
.sum::<usize>();
|
||||||
let mut buf = Vec::with_capacity(capacity);
|
let mut buf = Vec::with_capacity(capacity);
|
||||||
for leaf_info in self.script_leaves() {
|
for leaf_info in self.script_leaves() {
|
||||||
// # Cast Safety:
|
// # Cast Safety:
|
||||||
|
@ -416,9 +372,10 @@ impl Deserialize for TapTree {
|
||||||
if consumed > 0 {
|
if consumed > 0 {
|
||||||
bytes_iter.nth(consumed - 1);
|
bytes_iter.nth(consumed - 1);
|
||||||
}
|
}
|
||||||
let leaf_version = LeafVersion::from_consensus(*version)
|
let leaf_version =
|
||||||
.map_err(|_| Error::InvalidLeafVersion)?;
|
LeafVersion::from_consensus(*version).map_err(|_| Error::InvalidLeafVersion)?;
|
||||||
builder = builder.add_leaf_with_ver(*depth, script, leaf_version)
|
builder = builder
|
||||||
|
.add_leaf_with_ver(*depth, script, leaf_version)
|
||||||
.map_err(|_| Error::Taproot("Tree not in DFS order"))?;
|
.map_err(|_| Error::Taproot("Tree not in DFS order"))?;
|
||||||
}
|
}
|
||||||
TapTree::try_from(builder).map_err(Error::TapTree)
|
TapTree::try_from(builder).map_err(Error::TapTree)
|
||||||
|
@ -426,9 +383,7 @@ impl Deserialize for TapTree {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to compute key source len
|
// Helper function to compute key source len
|
||||||
fn key_source_len(key_source: &KeySource) -> usize {
|
fn key_source_len(key_source: &KeySource) -> usize { 4 + 4 * (key_source.1).as_ref().len() }
|
||||||
4 + 4 * (key_source.1).as_ref().len()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
@ -439,7 +394,10 @@ mod tests {
|
||||||
// Composes tree matching a given depth map, filled with dumb script leafs,
|
// Composes tree matching a given depth map, filled with dumb script leafs,
|
||||||
// each of which consists of a single push-int op code, with int value
|
// each of which consists of a single push-int op code, with int value
|
||||||
// increased for each consecutive leaf.
|
// increased for each consecutive leaf.
|
||||||
pub fn compose_taproot_builder<'map>(opcode: u8, depth_map: impl IntoIterator<Item = &'map u8>) -> TaprootBuilder {
|
pub fn compose_taproot_builder<'map>(
|
||||||
|
opcode: u8,
|
||||||
|
depth_map: impl IntoIterator<Item = &'map u8>,
|
||||||
|
) -> TaprootBuilder {
|
||||||
let mut val = opcode;
|
let mut val = opcode;
|
||||||
let mut builder = TaprootBuilder::new();
|
let mut builder = TaprootBuilder::new();
|
||||||
for depth in depth_map {
|
for depth in depth_map {
|
||||||
|
@ -454,7 +412,13 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn taptree_hidden() {
|
fn taptree_hidden() {
|
||||||
let mut builder = compose_taproot_builder(0x51, &[2, 2, 2]);
|
let mut builder = compose_taproot_builder(0x51, &[2, 2, 2]);
|
||||||
builder = builder.add_leaf_with_ver(3, ScriptBuf::from_hex("b9").unwrap(), LeafVersion::from_consensus(0xC2).unwrap()).unwrap();
|
builder = builder
|
||||||
|
.add_leaf_with_ver(
|
||||||
|
3,
|
||||||
|
ScriptBuf::from_hex("b9").unwrap(),
|
||||||
|
LeafVersion::from_consensus(0xC2).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
builder = builder.add_hidden_node(3, TapNodeHash::all_zeros()).unwrap();
|
builder = builder.add_hidden_node(3, TapNodeHash::all_zeros()).unwrap();
|
||||||
assert!(TapTree::try_from(builder).is_err());
|
assert!(TapTree::try_from(builder).is_err());
|
||||||
}
|
}
|
||||||
|
@ -462,7 +426,13 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn taptree_roundtrip() {
|
fn taptree_roundtrip() {
|
||||||
let mut builder = compose_taproot_builder(0x51, &[2, 2, 2, 3]);
|
let mut builder = compose_taproot_builder(0x51, &[2, 2, 2, 3]);
|
||||||
builder = builder.add_leaf_with_ver(3, ScriptBuf::from_hex("b9").unwrap(), LeafVersion::from_consensus(0xC2).unwrap()).unwrap();
|
builder = builder
|
||||||
|
.add_leaf_with_ver(
|
||||||
|
3,
|
||||||
|
ScriptBuf::from_hex("b9").unwrap(),
|
||||||
|
LeafVersion::from_consensus(0xC2).unwrap(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
let tree = TapTree::try_from(builder).unwrap();
|
let tree = TapTree::try_from(builder).unwrap();
|
||||||
let tree_prime = TapTree::deserialize(&tree.serialize()).unwrap();
|
let tree_prime = TapTree::deserialize(&tree.serialize()).unwrap();
|
||||||
assert_eq!(tree, tree_prime);
|
assert_eq!(tree, tree_prime);
|
||||||
|
|
|
@ -42,12 +42,14 @@ pub mod misc {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i += match opcodes::All::from((*haystack)[i]).classify(opcodes::ClassifyContext::Legacy) {
|
i += match opcodes::All::from((*haystack)[i])
|
||||||
|
.classify(opcodes::ClassifyContext::Legacy)
|
||||||
|
{
|
||||||
opcodes::Class::PushBytes(n) => n as usize + 1,
|
opcodes::Class::PushBytes(n) => n as usize + 1,
|
||||||
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) => 2,
|
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) => 2,
|
||||||
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) => 3,
|
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) => 3,
|
||||||
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => 5,
|
opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => 5,
|
||||||
_ => 1
|
_ => 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,22 +22,30 @@ pub fn fixed_time_eq(a: &[u8], b: &[u8]) -> bool {
|
||||||
for i in 0..count {
|
for i in 0..count {
|
||||||
let mut rs = unsafe { core::ptr::read_volatile(&r) };
|
let mut rs = unsafe { core::ptr::read_volatile(&r) };
|
||||||
rs |= lhs[i] ^ rhs[i];
|
rs |= lhs[i] ^ rhs[i];
|
||||||
unsafe { core::ptr::write_volatile(&mut r, rs); }
|
unsafe {
|
||||||
|
core::ptr::write_volatile(&mut r, rs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut t = unsafe { core::ptr::read_volatile(&r) };
|
let mut t = unsafe { core::ptr::read_volatile(&r) };
|
||||||
t |= t >> 4;
|
t |= t >> 4;
|
||||||
unsafe { core::ptr::write_volatile(&mut r, t); }
|
unsafe {
|
||||||
|
core::ptr::write_volatile(&mut r, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut t = unsafe { core::ptr::read_volatile(&r) };
|
let mut t = unsafe { core::ptr::read_volatile(&r) };
|
||||||
t |= t >> 2;
|
t |= t >> 2;
|
||||||
unsafe { core::ptr::write_volatile(&mut r, t); }
|
unsafe {
|
||||||
|
core::ptr::write_volatile(&mut r, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut t = unsafe { core::ptr::read_volatile(&r) };
|
let mut t = unsafe { core::ptr::read_volatile(&r) };
|
||||||
t |= t >> 1;
|
t |= t >> 1;
|
||||||
unsafe { core::ptr::write_volatile(&mut r, t); }
|
unsafe {
|
||||||
|
core::ptr::write_volatile(&mut r, t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
unsafe { (::core::ptr::read_volatile(&r) & 1) == 0 }
|
unsafe { (::core::ptr::read_volatile(&r) & 1) == 0 }
|
||||||
}
|
}
|
||||||
|
@ -72,7 +80,7 @@ fn eq_test() {
|
||||||
assert!(!fixed_time_eq(&[0b10000000], &[0b00000000]));
|
assert!(!fixed_time_eq(&[0b10000000], &[0b00000000]));
|
||||||
assert!(!fixed_time_eq(&[0b10000000], &[0b11111111]));
|
assert!(!fixed_time_eq(&[0b10000000], &[0b11111111]));
|
||||||
|
|
||||||
assert!( fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000000, 0b00000000]));
|
assert!(fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000000, 0b00000000]));
|
||||||
assert!(!fixed_time_eq(&[0b00000001, 0b00000000], &[0b00000000, 0b00000000]));
|
assert!(!fixed_time_eq(&[0b00000001, 0b00000000], &[0b00000000, 0b00000000]));
|
||||||
assert!(!fixed_time_eq(&[0b00000000, 0b00000001], &[0b00000000, 0b00000000]));
|
assert!(!fixed_time_eq(&[0b00000000, 0b00000001], &[0b00000000, 0b00000000]));
|
||||||
assert!(!fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000001, 0b00000000]));
|
assert!(!fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000001, 0b00000000]));
|
||||||
|
@ -83,78 +91,62 @@ fn eq_test() {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{Hash, sha256, sha512};
|
|
||||||
use crate::cmp::fixed_time_eq;
|
use crate::cmp::fixed_time_eq;
|
||||||
|
use crate::{sha256, sha512, Hash};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_32b_constant_time_cmp_ne(bh: &mut Bencher) {
|
fn bench_32b_constant_time_cmp_ne(bh: &mut Bencher) {
|
||||||
let hash_a = sha256::Hash::hash(&[0; 1]);
|
let hash_a = sha256::Hash::hash(&[0; 1]);
|
||||||
let hash_b = sha256::Hash::hash(&[1; 1]);
|
let hash_b = sha256::Hash::hash(&[1; 1]);
|
||||||
bh.iter(|| {
|
bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..]))
|
||||||
fixed_time_eq(&hash_a[..], &hash_b[..])
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_32b_slice_cmp_ne(bh: &mut Bencher) {
|
fn bench_32b_slice_cmp_ne(bh: &mut Bencher) {
|
||||||
let hash_a = sha256::Hash::hash(&[0; 1]);
|
let hash_a = sha256::Hash::hash(&[0; 1]);
|
||||||
let hash_b = sha256::Hash::hash(&[1; 1]);
|
let hash_b = sha256::Hash::hash(&[1; 1]);
|
||||||
bh.iter(|| {
|
bh.iter(|| &hash_a[..] == &hash_b[..])
|
||||||
&hash_a[..] == &hash_b[..]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_32b_constant_time_cmp_eq(bh: &mut Bencher) {
|
fn bench_32b_constant_time_cmp_eq(bh: &mut Bencher) {
|
||||||
let hash_a = sha256::Hash::hash(&[0; 1]);
|
let hash_a = sha256::Hash::hash(&[0; 1]);
|
||||||
let hash_b = sha256::Hash::hash(&[0; 1]);
|
let hash_b = sha256::Hash::hash(&[0; 1]);
|
||||||
bh.iter(|| {
|
bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..]))
|
||||||
fixed_time_eq(&hash_a[..], &hash_b[..])
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_32b_slice_cmp_eq(bh: &mut Bencher) {
|
fn bench_32b_slice_cmp_eq(bh: &mut Bencher) {
|
||||||
let hash_a = sha256::Hash::hash(&[0; 1]);
|
let hash_a = sha256::Hash::hash(&[0; 1]);
|
||||||
let hash_b = sha256::Hash::hash(&[0; 1]);
|
let hash_b = sha256::Hash::hash(&[0; 1]);
|
||||||
bh.iter(|| {
|
bh.iter(|| &hash_a[..] == &hash_b[..])
|
||||||
&hash_a[..] == &hash_b[..]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_64b_constant_time_cmp_ne(bh: &mut Bencher) {
|
fn bench_64b_constant_time_cmp_ne(bh: &mut Bencher) {
|
||||||
let hash_a = sha512::Hash::hash(&[0; 1]);
|
let hash_a = sha512::Hash::hash(&[0; 1]);
|
||||||
let hash_b = sha512::Hash::hash(&[1; 1]);
|
let hash_b = sha512::Hash::hash(&[1; 1]);
|
||||||
bh.iter(|| {
|
bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..]))
|
||||||
fixed_time_eq(&hash_a[..], &hash_b[..])
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_64b_slice_cmp_ne(bh: &mut Bencher) {
|
fn bench_64b_slice_cmp_ne(bh: &mut Bencher) {
|
||||||
let hash_a = sha512::Hash::hash(&[0; 1]);
|
let hash_a = sha512::Hash::hash(&[0; 1]);
|
||||||
let hash_b = sha512::Hash::hash(&[1; 1]);
|
let hash_b = sha512::Hash::hash(&[1; 1]);
|
||||||
bh.iter(|| {
|
bh.iter(|| &hash_a[..] == &hash_b[..])
|
||||||
&hash_a[..] == &hash_b[..]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_64b_constant_time_cmp_eq(bh: &mut Bencher) {
|
fn bench_64b_constant_time_cmp_eq(bh: &mut Bencher) {
|
||||||
let hash_a = sha512::Hash::hash(&[0; 1]);
|
let hash_a = sha512::Hash::hash(&[0; 1]);
|
||||||
let hash_b = sha512::Hash::hash(&[0; 1]);
|
let hash_b = sha512::Hash::hash(&[0; 1]);
|
||||||
bh.iter(|| {
|
bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..]))
|
||||||
fixed_time_eq(&hash_a[..], &hash_b[..])
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_64b_slice_cmp_eq(bh: &mut Bencher) {
|
fn bench_64b_slice_cmp_eq(bh: &mut Bencher) {
|
||||||
let hash_a = sha512::Hash::hash(&[0; 1]);
|
let hash_a = sha512::Hash::hash(&[0; 1]);
|
||||||
let hash_b = sha512::Hash::hash(&[0; 1]);
|
let hash_b = sha512::Hash::hash(&[0; 1]);
|
||||||
bh.iter(|| {
|
bh.iter(|| &hash_a[..] == &hash_b[..])
|
||||||
&hash_a[..] == &hash_b[..]
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,8 @@ impl fmt::Display for Error {
|
||||||
use self::Error::*;
|
use self::Error::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
InvalidLength(ref ell, ref ell2) => write!(f, "invalid slice length {} (expected {})", ell2, ell),
|
InvalidLength(ref ell, ref ell2) =>
|
||||||
|
write!(f, "invalid slice length {} (expected {})", ell2, ell),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,11 @@
|
||||||
//! HASH160 (SHA256 then RIPEMD160) implementation.
|
//! HASH160 (SHA256 then RIPEMD160) implementation.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::str;
|
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::slice::SliceIndex;
|
use core::slice::SliceIndex;
|
||||||
|
use core::str;
|
||||||
|
|
||||||
use crate::{Error, ripemd160, sha256};
|
use crate::{ripemd160, sha256, Error};
|
||||||
|
|
||||||
crate::internal_macros::hash_type! {
|
crate::internal_macros::hash_type! {
|
||||||
160,
|
160,
|
||||||
|
@ -61,6 +61,7 @@ mod tests {
|
||||||
output_str: &'static str,
|
output_str: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
let tests = vec![
|
let tests = vec![
|
||||||
// Uncompressed pubkey obtained from Bitcoin key; data from validateaddress
|
// Uncompressed pubkey obtained from Bitcoin key; data from validateaddress
|
||||||
Test {
|
Test {
|
||||||
|
@ -104,9 +105,11 @@ mod tests {
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
#[test]
|
#[test]
|
||||||
fn ripemd_serde() {
|
fn ripemd_serde() {
|
||||||
use serde_test::{Configure, Token, assert_tokens};
|
use serde_test::{assert_tokens, Configure, Token};
|
||||||
|
|
||||||
use crate::{hash160, Hash};
|
use crate::{hash160, Hash};
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
static HASH_BYTES: [u8; 20] = [
|
static HASH_BYTES: [u8; 20] = [
|
||||||
0x13, 0x20, 0x72, 0xdf,
|
0x13, 0x20, 0x72, 0xdf,
|
||||||
0x69, 0x09, 0x33, 0x83,
|
0x69, 0x09, 0x33, 0x83,
|
||||||
|
@ -125,13 +128,13 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{Hash, HashEngine, hash160};
|
use crate::{hash160, Hash, HashEngine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn hash160_10(bh: &mut Bencher) {
|
pub fn hash160_10(bh: &mut Bencher) {
|
||||||
let mut engine = hash160::Hash::engine();
|
let mut engine = hash160::Hash::engine();
|
||||||
let bytes = [1u8; 10];
|
let bytes = [1u8; 10];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -141,7 +144,7 @@ mod benches {
|
||||||
pub fn hash160_1k(bh: &mut Bencher) {
|
pub fn hash160_1k(bh: &mut Bencher) {
|
||||||
let mut engine = hash160::Hash::engine();
|
let mut engine = hash160::Hash::engine();
|
||||||
let bytes = [1u8; 1024];
|
let bytes = [1u8; 1024];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -151,7 +154,7 @@ mod benches {
|
||||||
pub fn hash160_64k(bh: &mut Bencher) {
|
pub fn hash160_64k(bh: &mut Bencher) {
|
||||||
let mut engine = hash160::Hash::engine();
|
let mut engine = hash160::Hash::engine();
|
||||||
let bytes = [1u8; 65536];
|
let bytes = [1u8; 65536];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
|
|
@ -15,16 +15,15 @@
|
||||||
//! Hex encoding and decoding.
|
//! Hex encoding and decoding.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
use core::{fmt, str};
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
|
||||||
use crate::alloc::vec::Vec;
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
#[cfg(all(feature = "core2", not(feature = "std")))]
|
#[cfg(all(feature = "core2", not(feature = "std")))]
|
||||||
use core2::io;
|
use core2::io;
|
||||||
|
|
||||||
use core::{fmt, str};
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
|
use crate::alloc::vec::Vec;
|
||||||
|
|
||||||
/// Hex decoding error.
|
/// Hex decoding error.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
@ -42,7 +41,8 @@ impl fmt::Display for Error {
|
||||||
match *self {
|
match *self {
|
||||||
Error::InvalidChar(ch) => write!(f, "invalid hex character {}", ch),
|
Error::InvalidChar(ch) => write!(f, "invalid hex character {}", ch),
|
||||||
Error::OddLengthString(ell) => write!(f, "odd hex string length {}", ell),
|
Error::OddLengthString(ell) => write!(f, "odd hex string length {}", ell),
|
||||||
Error::InvalidLength(ell, ell2) => write!(f, "bad hex string length {} (expected {})", ell2, ell),
|
Error::InvalidLength(ell, ell2) =>
|
||||||
|
write!(f, "bad hex string length {} (expected {})", ell2, ell),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,9 +67,7 @@ pub trait FromHex: Sized {
|
||||||
I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator;
|
I: Iterator<Item = Result<u8, Error>> + ExactSizeIterator + DoubleEndedIterator;
|
||||||
|
|
||||||
/// Produces an object from a hex string.
|
/// Produces an object from a hex string.
|
||||||
fn from_hex(s: &str) -> Result<Self, Error> {
|
fn from_hex(s: &str) -> Result<Self, Error> { Self::from_byte_iter(HexIterator::new(s)?) }
|
||||||
Self::from_byte_iter(HexIterator::new(s)?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Iterator over a hex-encoded string slice which decodes hex and yields bytes.
|
/// Iterator over a hex-encoded string slice which decodes hex and yields bytes.
|
||||||
|
@ -95,12 +93,8 @@ impl<'a> HexIterator<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chars_to_hex(hi: u8, lo: u8) -> Result<u8, Error> {
|
fn chars_to_hex(hi: u8, lo: u8) -> Result<u8, Error> {
|
||||||
let hih = (hi as char)
|
let hih = (hi as char).to_digit(16).ok_or(Error::InvalidChar(hi))?;
|
||||||
.to_digit(16)
|
let loh = (lo as char).to_digit(16).ok_or(Error::InvalidChar(lo))?;
|
||||||
.ok_or(Error::InvalidChar(hi))?;
|
|
||||||
let loh = (lo as char)
|
|
||||||
.to_digit(16)
|
|
||||||
.ok_or(Error::InvalidChar(lo))?;
|
|
||||||
|
|
||||||
let ret = (hih << 4) + loh;
|
let ret = (hih << 4) + loh;
|
||||||
Ok(ret as u8)
|
Ok(ret as u8)
|
||||||
|
@ -131,7 +125,7 @@ impl<'a> io::Read for HexIterator<'a> {
|
||||||
Some(Ok(src)) => {
|
Some(Ok(src)) => {
|
||||||
*dst = src;
|
*dst = src;
|
||||||
bytes_read += 1;
|
bytes_read += 1;
|
||||||
},
|
}
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,7 +172,7 @@ macro_rules! impl_fromhex_array {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_fromhex_array!(2);
|
impl_fromhex_array!(2);
|
||||||
|
@ -204,9 +198,10 @@ impl_fromhex_array!(512);
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
|
||||||
use internals::hex::exts::DisplayHex;
|
use internals::hex::exts::DisplayHex;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hex_roundtrip() {
|
fn hex_roundtrip() {
|
||||||
let expected = "0123456789abcdef";
|
let expected = "0123456789abcdef";
|
||||||
|
@ -235,29 +230,11 @@ mod tests {
|
||||||
let badchar2 = "012Y456789abcdeb";
|
let badchar2 = "012Y456789abcdeb";
|
||||||
let badchar3 = "«23456789abcdef";
|
let badchar3 = "«23456789abcdef";
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(Vec::<u8>::from_hex(oddlen), Err(Error::OddLengthString(17)));
|
||||||
Vec::<u8>::from_hex(oddlen),
|
assert_eq!(<[u8; 4]>::from_hex(oddlen), Err(Error::OddLengthString(17)));
|
||||||
Err(Error::OddLengthString(17))
|
assert_eq!(<[u8; 8]>::from_hex(oddlen), Err(Error::OddLengthString(17)));
|
||||||
);
|
assert_eq!(Vec::<u8>::from_hex(badchar1), Err(Error::InvalidChar(b'Z')));
|
||||||
assert_eq!(
|
assert_eq!(Vec::<u8>::from_hex(badchar2), Err(Error::InvalidChar(b'Y')));
|
||||||
<[u8; 4]>::from_hex(oddlen),
|
assert_eq!(Vec::<u8>::from_hex(badchar3), Err(Error::InvalidChar(194)));
|
||||||
Err(Error::OddLengthString(17))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
<[u8; 8]>::from_hex(oddlen),
|
|
||||||
Err(Error::OddLengthString(17))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Vec::<u8>::from_hex(badchar1),
|
|
||||||
Err(Error::InvalidChar(b'Z'))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Vec::<u8>::from_hex(badchar2),
|
|
||||||
Err(Error::InvalidChar(b'Y'))
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Vec::<u8>::from_hex(badchar3),
|
|
||||||
Err(Error::InvalidChar(194))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,9 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::{borrow, fmt, ops, str};
|
use core::{borrow, fmt, ops, str};
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
use serde::{Serialize, Serializer, Deserialize, Deserializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
use crate::{Error, Hash, HashEngine};
|
use crate::{Error, Hash, HashEngine};
|
||||||
|
|
||||||
|
@ -35,9 +36,7 @@ pub struct Hmac<T: Hash>(T);
|
||||||
|
|
||||||
impl<T: Hash + str::FromStr> str::FromStr for Hmac<T> {
|
impl<T: Hash + str::FromStr> str::FromStr for Hmac<T> {
|
||||||
type Err = <T as str::FromStr>::Err;
|
type Err = <T as str::FromStr>::Err;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> { Ok(Hmac(str::FromStr::from_str(s)?)) }
|
||||||
Ok(Hmac(str::FromStr::from_str(s)?))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pair of underlying hash midstates which represent the current state of an `HmacEngine`.
|
/// Pair of underlying hash midstates which represent the current state of an `HmacEngine`.
|
||||||
|
@ -56,9 +55,7 @@ pub struct HmacEngine<T: Hash> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> Default for HmacEngine<T> {
|
impl<T: Hash> Default for HmacEngine<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self { HmacEngine::new(&[]) }
|
||||||
HmacEngine::new(&[])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> HmacEngine<T> {
|
impl<T: Hash> HmacEngine<T> {
|
||||||
|
@ -74,10 +71,7 @@ impl<T: Hash> HmacEngine<T> {
|
||||||
|
|
||||||
let mut ipad = [0x36u8; 128];
|
let mut ipad = [0x36u8; 128];
|
||||||
let mut opad = [0x5cu8; 128];
|
let mut opad = [0x5cu8; 128];
|
||||||
let mut ret = HmacEngine {
|
let mut ret = HmacEngine { iengine: <T as Hash>::engine(), oengine: <T as Hash>::engine() };
|
||||||
iengine: <T as Hash>::engine(),
|
|
||||||
oengine: <T as Hash>::engine(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if key.len() > T::Engine::BLOCK_SIZE {
|
if key.len() > T::Engine::BLOCK_SIZE {
|
||||||
let hash = <T as Hash>::hash(key);
|
let hash = <T as Hash>::hash(key);
|
||||||
|
@ -103,10 +97,7 @@ impl<T: Hash> HmacEngine<T> {
|
||||||
|
|
||||||
/// A special constructor giving direct access to the underlying "inner" and "outer" engines.
|
/// A special constructor giving direct access to the underlying "inner" and "outer" engines.
|
||||||
pub fn from_inner_engines(iengine: T::Engine, oengine: T::Engine) -> HmacEngine<T> {
|
pub fn from_inner_engines(iengine: T::Engine, oengine: T::Engine) -> HmacEngine<T> {
|
||||||
HmacEngine {
|
HmacEngine { iengine, oengine }
|
||||||
iengine,
|
|
||||||
oengine,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,80 +105,55 @@ impl<T: Hash> HashEngine for HmacEngine<T> {
|
||||||
type MidState = HmacMidState<T>;
|
type MidState = HmacMidState<T>;
|
||||||
|
|
||||||
fn midstate(&self) -> Self::MidState {
|
fn midstate(&self) -> Self::MidState {
|
||||||
HmacMidState {
|
HmacMidState { inner: self.iengine.midstate(), outer: self.oengine.midstate() }
|
||||||
inner: self.iengine.midstate(),
|
|
||||||
outer: self.oengine.midstate(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BLOCK_SIZE: usize = T::Engine::BLOCK_SIZE;
|
const BLOCK_SIZE: usize = T::Engine::BLOCK_SIZE;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> usize {
|
fn n_bytes_hashed(&self) -> usize { self.iengine.n_bytes_hashed() }
|
||||||
self.iengine.n_bytes_hashed()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input(&mut self, buf: &[u8]) {
|
fn input(&mut self, buf: &[u8]) { self.iengine.input(buf) }
|
||||||
self.iengine.input(buf)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> fmt::Debug for Hmac<T> {
|
impl<T: Hash> fmt::Debug for Hmac<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.0, f) }
|
||||||
fmt::Debug::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> fmt::Display for Hmac<T> {
|
impl<T: Hash> fmt::Display for Hmac<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) }
|
||||||
fmt::Display::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> fmt::LowerHex for Hmac<T> {
|
impl<T: Hash> fmt::LowerHex for Hmac<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) }
|
||||||
fmt::LowerHex::fmt(&self.0, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> ops::Index<usize> for Hmac<T> {
|
impl<T: Hash> ops::Index<usize> for Hmac<T> {
|
||||||
type Output = u8;
|
type Output = u8;
|
||||||
fn index(&self, index: usize) -> &u8 {
|
fn index(&self, index: usize) -> &u8 { &self.0[index] }
|
||||||
&self.0[index]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> ops::Index<ops::Range<usize>> for Hmac<T> {
|
impl<T: Hash> ops::Index<ops::Range<usize>> for Hmac<T> {
|
||||||
type Output = [u8];
|
type Output = [u8];
|
||||||
fn index(&self, index: ops::Range<usize>) -> &[u8] {
|
fn index(&self, index: ops::Range<usize>) -> &[u8] { &self.0[index] }
|
||||||
&self.0[index]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> ops::Index<ops::RangeFrom<usize>> for Hmac<T> {
|
impl<T: Hash> ops::Index<ops::RangeFrom<usize>> for Hmac<T> {
|
||||||
type Output = [u8];
|
type Output = [u8];
|
||||||
fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] {
|
fn index(&self, index: ops::RangeFrom<usize>) -> &[u8] { &self.0[index] }
|
||||||
&self.0[index]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> ops::Index<ops::RangeTo<usize>> for Hmac<T> {
|
impl<T: Hash> ops::Index<ops::RangeTo<usize>> for Hmac<T> {
|
||||||
type Output = [u8];
|
type Output = [u8];
|
||||||
fn index(&self, index: ops::RangeTo<usize>) -> &[u8] {
|
fn index(&self, index: ops::RangeTo<usize>) -> &[u8] { &self.0[index] }
|
||||||
&self.0[index]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> ops::Index<ops::RangeFull> for Hmac<T> {
|
impl<T: Hash> ops::Index<ops::RangeFull> for Hmac<T> {
|
||||||
type Output = [u8];
|
type Output = [u8];
|
||||||
fn index(&self, index: ops::RangeFull) -> &[u8] {
|
fn index(&self, index: ops::RangeFull) -> &[u8] { &self.0[index] }
|
||||||
&self.0[index]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> borrow::Borrow<[u8]> for Hmac<T> {
|
impl<T: Hash> borrow::Borrow<[u8]> for Hmac<T> {
|
||||||
fn borrow(&self) -> &[u8] {
|
fn borrow(&self) -> &[u8] { &self[..] }
|
||||||
&self[..]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Hash> Hash for Hmac<T> {
|
impl<T: Hash> Hash for Hmac<T> {
|
||||||
|
@ -203,21 +169,13 @@ impl<T: Hash> Hash for Hmac<T> {
|
||||||
|
|
||||||
const LEN: usize = T::LEN;
|
const LEN: usize = T::LEN;
|
||||||
|
|
||||||
fn from_slice(sl: &[u8]) -> Result<Hmac<T>, Error> {
|
fn from_slice(sl: &[u8]) -> Result<Hmac<T>, Error> { T::from_slice(sl).map(Hmac) }
|
||||||
T::from_slice(sl).map(Hmac)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_byte_array(self) -> Self::Bytes {
|
fn to_byte_array(self) -> Self::Bytes { self.0.to_byte_array() }
|
||||||
self.0.to_byte_array()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_byte_array(&self) -> &Self::Bytes {
|
fn as_byte_array(&self) -> &Self::Bytes { self.0.as_byte_array() }
|
||||||
self.0.as_byte_array()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_byte_array(bytes: T::Bytes) -> Self {
|
fn from_byte_array(bytes: T::Bytes) -> Self { Hmac(T::from_byte_array(bytes)) }
|
||||||
Hmac(T::from_byte_array(bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn all_zeros() -> Self {
|
fn all_zeros() -> Self {
|
||||||
let zeros = T::all_zeros();
|
let zeros = T::all_zeros();
|
||||||
|
@ -247,7 +205,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
fn test() {
|
fn test() {
|
||||||
use crate::{sha256, HashEngine, HmacEngine, Hash, Hmac};
|
use crate::{sha256, Hash, HashEngine, Hmac, HmacEngine};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Test {
|
struct Test {
|
||||||
|
@ -256,6 +214,7 @@ mod tests {
|
||||||
output: Vec<u8>,
|
output: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
let tests = vec![
|
let tests = vec![
|
||||||
// Test vectors copied from libsecp256k1
|
// Test vectors copied from libsecp256k1
|
||||||
// Sadly the RFC2104 test vectors all use MD5 as their underlying hash function,
|
// Sadly the RFC2104 test vectors all use MD5 as their underlying hash function,
|
||||||
|
@ -372,9 +331,11 @@ mod tests {
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
#[test]
|
#[test]
|
||||||
fn hmac_sha512_serde() {
|
fn hmac_sha512_serde() {
|
||||||
use serde_test::{Configure, Token, assert_tokens};
|
use serde_test::{assert_tokens, Configure, Token};
|
||||||
|
|
||||||
use crate::{sha512, Hash, Hmac};
|
use crate::{sha512, Hash, Hmac};
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
static HASH_BYTES: [u8; 64] = [
|
static HASH_BYTES: [u8; 64] = [
|
||||||
0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
|
0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
|
||||||
0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
|
0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
|
||||||
|
@ -392,7 +353,7 @@ mod tests {
|
||||||
&hash.readable(),
|
&hash.readable(),
|
||||||
&[Token::Str(
|
&[Token::Str(
|
||||||
"8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\
|
"8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\
|
||||||
fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c"
|
fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c",
|
||||||
)],
|
)],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -402,13 +363,13 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{Hmac, Hash, HashEngine, sha256};
|
use crate::{sha256, Hash, HashEngine, Hmac};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn hmac_sha256_10(bh: &mut Bencher) {
|
pub fn hmac_sha256_10(bh: &mut Bencher) {
|
||||||
let mut engine = Hmac::<sha256::Hash>::engine();
|
let mut engine = Hmac::<sha256::Hash>::engine();
|
||||||
let bytes = [1u8; 10];
|
let bytes = [1u8; 10];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -418,7 +379,7 @@ mod benches {
|
||||||
pub fn hmac_sha256_1k(bh: &mut Bencher) {
|
pub fn hmac_sha256_1k(bh: &mut Bencher) {
|
||||||
let mut engine = Hmac::<sha256::Hash>::engine();
|
let mut engine = Hmac::<sha256::Hash>::engine();
|
||||||
let bytes = [1u8; 1024];
|
let bytes = [1u8; 1024];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -428,10 +389,9 @@ mod benches {
|
||||||
pub fn hmac_sha256_64k(bh: &mut Bencher) {
|
pub fn hmac_sha256_64k(bh: &mut Bencher) {
|
||||||
let mut engine = Hmac::<sha256::Hash>::engine();
|
let mut engine = Hmac::<sha256::Hash>::engine();
|
||||||
let bytes = [1u8; 65536];
|
let bytes = [1u8; 65536];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@ use std::io;
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use core2::io;
|
use core2::io;
|
||||||
|
|
||||||
use crate::{HashEngine, sha1, sha256, sha512, ripemd160, siphash24, hmac};
|
use crate::{hmac, ripemd160, sha1, sha256, sha512, siphash24, HashEngine};
|
||||||
|
|
||||||
impl io::Write for sha1::HashEngine {
|
impl io::Write for sha1::HashEngine {
|
||||||
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
fn flush(&mut self) -> io::Result<()> { Ok(()) }
|
||||||
|
@ -82,8 +82,7 @@ impl<T: crate::Hash> io::Write for hmac::HmacEngine<T> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::io::Write;
|
use super::io::Write;
|
||||||
|
use crate::{hash160, hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, Hash};
|
||||||
use crate::{Hash, sha1, sha256, sha256d, sha512, ripemd160, hash160, siphash24, hmac};
|
|
||||||
|
|
||||||
macro_rules! write_test {
|
macro_rules! write_test {
|
||||||
($mod:ident, $exp_empty:expr, $exp_256:expr, $exp_64k:expr,) => {
|
($mod:ident, $exp_empty:expr, $exp_256:expr, $exp_64k:expr,) => {
|
||||||
|
@ -91,26 +90,17 @@ mod tests {
|
||||||
fn $mod() {
|
fn $mod() {
|
||||||
let mut engine = $mod::Hash::engine();
|
let mut engine = $mod::Hash::engine();
|
||||||
engine.write_all(&[]).unwrap();
|
engine.write_all(&[]).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", $mod::Hash::from_engine(engine)), $exp_empty);
|
||||||
format!("{}", $mod::Hash::from_engine(engine)),
|
|
||||||
$exp_empty
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut engine = $mod::Hash::engine();
|
let mut engine = $mod::Hash::engine();
|
||||||
engine.write_all(&[1; 256]).unwrap();
|
engine.write_all(&[1; 256]).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", $mod::Hash::from_engine(engine)), $exp_256);
|
||||||
format!("{}", $mod::Hash::from_engine(engine)),
|
|
||||||
$exp_256
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut engine = $mod::Hash::engine();
|
let mut engine = $mod::Hash::engine();
|
||||||
engine.write_all(&[99; 64000]).unwrap();
|
engine.write_all(&[99; 64000]).unwrap();
|
||||||
assert_eq!(
|
assert_eq!(format!("{}", $mod::Hash::from_engine(engine)), $exp_64k);
|
||||||
format!("{}", $mod::Hash::from_engine(engine)),
|
|
||||||
$exp_64k
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
write_test!(
|
write_test!(
|
||||||
|
@ -158,12 +148,7 @@ mod tests {
|
||||||
"a9608c952c8dbcc20c53803d2ca5ad31d64d9313",
|
"a9608c952c8dbcc20c53803d2ca5ad31d64d9313",
|
||||||
);
|
);
|
||||||
|
|
||||||
write_test!(
|
write_test!(siphash24, "d70077739d4b921e", "3a3ccefde9b5b1e3", "ce456e4e4ecbc5bf",);
|
||||||
siphash24,
|
|
||||||
"d70077739d4b921e",
|
|
||||||
"3a3ccefde9b5b1e3",
|
|
||||||
"ce456e4e4ecbc5bf",
|
|
||||||
);
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hmac() {
|
fn hmac() {
|
||||||
|
|
|
@ -186,21 +186,16 @@ macro_rules! hash_type {
|
||||||
#[cfg_attr(feature = "schemars", derive(crate::schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(crate::schemars::JsonSchema))]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Hash(
|
pub struct Hash(
|
||||||
#[cfg_attr(feature = "schemars", schemars(schema_with = $schemars))]
|
#[cfg_attr(feature = "schemars", schemars(schema_with = $schemars))] [u8; $bits / 8],
|
||||||
[u8; $bits / 8]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
impl Hash {
|
impl Hash {
|
||||||
fn internal_new(arr: [u8; $bits / 8]) -> Self {
|
fn internal_new(arr: [u8; $bits / 8]) -> Self { Hash(arr) }
|
||||||
Hash(arr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn internal_engine() -> HashEngine {
|
fn internal_engine() -> HashEngine { Default::default() }
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::internal_macros::hash_trait_impls!($bits, $reverse);
|
crate::internal_macros::hash_trait_impls!($bits, $reverse);
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
pub(crate) use hash_type;
|
pub(crate) use hash_type;
|
||||||
|
|
|
@ -79,28 +79,30 @@
|
||||||
|
|
||||||
// Coding conventions
|
// Coding conventions
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
// Experimental features we need.
|
// Experimental features we need.
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg))]
|
||||||
#![cfg_attr(bench, feature(test))]
|
#![cfg_attr(bench, feature(test))]
|
||||||
|
|
||||||
// In general, rust is absolutely horrid at supporting users doing things like,
|
// In general, rust is absolutely horrid at supporting users doing things like,
|
||||||
// for example, compiling Rust code for real environments. Disable useless lints
|
// for example, compiling Rust code for real environments. Disable useless lints
|
||||||
// that don't do anything but annoy us and cant actually ever be resolved.
|
// that don't do anything but annoy us and cant actually ever be resolved.
|
||||||
#![allow(bare_trait_objects)]
|
#![allow(bare_trait_objects)]
|
||||||
#![allow(ellipsis_inclusive_range_patterns)]
|
#![allow(ellipsis_inclusive_range_patterns)]
|
||||||
|
|
||||||
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
|
#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
|
||||||
|
|
||||||
// Instead of littering the codebase for non-fuzzing code just globally allow.
|
// Instead of littering the codebase for non-fuzzing code just globally allow.
|
||||||
#![cfg_attr(fuzzing, allow(dead_code, unused_imports))]
|
#![cfg_attr(fuzzing, allow(dead_code, unused_imports))]
|
||||||
|
|
||||||
#[cfg(bench)] extern crate test;
|
#[cfg(all(feature = "alloc", not(feature = "std")))]
|
||||||
#[cfg(any(test, feature = "std"))] extern crate core;
|
extern crate alloc;
|
||||||
#[cfg(feature = "core2")] extern crate core2;
|
#[cfg(any(test, feature = "std"))]
|
||||||
#[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc;
|
extern crate core;
|
||||||
#[cfg(feature = "serde")] pub extern crate serde;
|
#[cfg(feature = "core2")]
|
||||||
#[cfg(all(test,feature = "serde"))] extern crate serde_test;
|
extern crate core2;
|
||||||
|
#[cfg(feature = "serde")]
|
||||||
|
pub extern crate serde;
|
||||||
|
#[cfg(all(test, feature = "serde"))]
|
||||||
|
extern crate serde_test;
|
||||||
|
#[cfg(bench)]
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mod _export {
|
pub mod _export {
|
||||||
|
@ -114,27 +116,30 @@ pub mod _export {
|
||||||
extern crate actual_schemars as schemars;
|
extern crate actual_schemars as schemars;
|
||||||
|
|
||||||
mod internal_macros;
|
mod internal_macros;
|
||||||
#[macro_use] mod util;
|
#[macro_use]
|
||||||
#[macro_use] pub mod serde_macros;
|
mod util;
|
||||||
#[cfg(any(feature = "std", feature = "core2"))] mod impls;
|
#[macro_use]
|
||||||
|
pub mod serde_macros;
|
||||||
|
pub mod cmp;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod hex;
|
|
||||||
pub mod hash160;
|
pub mod hash160;
|
||||||
|
pub mod hex;
|
||||||
pub mod hmac;
|
pub mod hmac;
|
||||||
|
#[cfg(any(feature = "std", feature = "core2"))]
|
||||||
|
mod impls;
|
||||||
pub mod ripemd160;
|
pub mod ripemd160;
|
||||||
pub mod sha1;
|
pub mod sha1;
|
||||||
pub mod sha256;
|
pub mod sha256;
|
||||||
pub mod sha256d;
|
pub mod sha256d;
|
||||||
pub mod sha256t;
|
pub mod sha256t;
|
||||||
pub mod siphash24;
|
|
||||||
pub mod sha512;
|
pub mod sha512;
|
||||||
pub mod sha512_256;
|
pub mod sha512_256;
|
||||||
pub mod cmp;
|
pub mod siphash24;
|
||||||
|
|
||||||
use core::{borrow, fmt, hash, ops};
|
use core::{borrow, fmt, hash, ops};
|
||||||
|
|
||||||
pub use hmac::{Hmac, HmacEngine};
|
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
pub use hmac::{Hmac, HmacEngine};
|
||||||
|
|
||||||
/// A hashing engine which bytes can be serialized into.
|
/// A hashing engine which bytes can be serialized into.
|
||||||
pub trait HashEngine: Clone + Default {
|
pub trait HashEngine: Clone + Default {
|
||||||
|
@ -156,14 +161,23 @@ pub trait HashEngine: Clone + Default {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait which applies to hashes of all types.
|
/// Trait which applies to hashes of all types.
|
||||||
pub trait Hash: Copy + Clone + PartialEq + Eq + PartialOrd + Ord +
|
pub trait Hash:
|
||||||
hash::Hash + fmt::Debug + fmt::Display + fmt::LowerHex +
|
Copy
|
||||||
ops::Index<ops::RangeFull, Output = [u8]> +
|
+ Clone
|
||||||
ops::Index<ops::RangeFrom<usize>, Output = [u8]> +
|
+ PartialEq
|
||||||
ops::Index<ops::RangeTo<usize>, Output = [u8]> +
|
+ Eq
|
||||||
ops::Index<ops::Range<usize>, Output = [u8]> +
|
+ PartialOrd
|
||||||
ops::Index<usize, Output = u8> +
|
+ Ord
|
||||||
borrow::Borrow<[u8]>
|
+ hash::Hash
|
||||||
|
+ fmt::Debug
|
||||||
|
+ fmt::Display
|
||||||
|
+ fmt::LowerHex
|
||||||
|
+ ops::Index<ops::RangeFull, Output = [u8]>
|
||||||
|
+ ops::Index<ops::RangeFrom<usize>, Output = [u8]>
|
||||||
|
+ ops::Index<ops::RangeTo<usize>, Output = [u8]>
|
||||||
|
+ ops::Index<ops::Range<usize>, Output = [u8]>
|
||||||
|
+ ops::Index<usize, Output = u8>
|
||||||
|
+ borrow::Borrow<[u8]>
|
||||||
{
|
{
|
||||||
/// A hashing engine which bytes can be serialized into. It is expected
|
/// A hashing engine which bytes can be serialized into. It is expected
|
||||||
/// to implement the `io::Write` trait, and to never return errors under
|
/// to implement the `io::Write` trait, and to never return errors under
|
||||||
|
@ -174,9 +188,7 @@ pub trait Hash: Copy + Clone + PartialEq + Eq + PartialOrd + Ord +
|
||||||
type Bytes: hex::FromHex + Copy;
|
type Bytes: hex::FromHex + Copy;
|
||||||
|
|
||||||
/// Constructs a new engine.
|
/// Constructs a new engine.
|
||||||
fn engine() -> Self::Engine {
|
fn engine() -> Self::Engine { Self::Engine::default() }
|
||||||
Self::Engine::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Produces a hash from the current state of a given engine.
|
/// Produces a hash from the current state of a given engine.
|
||||||
fn from_engine(e: Self::Engine) -> Self;
|
fn from_engine(e: Self::Engine) -> Self;
|
||||||
|
@ -218,7 +230,7 @@ pub trait Hash: Copy + Clone + PartialEq + Eq + PartialOrd + Ord +
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{Hash, sha256d};
|
use crate::{sha256d, Hash};
|
||||||
|
|
||||||
hash_newtype! {
|
hash_newtype! {
|
||||||
/// A test newtype
|
/// A test newtype
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
//! RIPEMD160 implementation.
|
//! RIPEMD160 implementation.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::{cmp, str};
|
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::slice::SliceIndex;
|
use core::slice::SliceIndex;
|
||||||
|
use core::{cmp, str};
|
||||||
|
|
||||||
use crate::{Error, HashEngine as _};
|
use crate::{Error, HashEngine as _};
|
||||||
|
|
||||||
|
@ -102,9 +102,7 @@ impl crate::HashEngine for HashEngine {
|
||||||
|
|
||||||
const BLOCK_SIZE: usize = 64;
|
const BLOCK_SIZE: usize = 64;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> usize {
|
fn n_bytes_hashed(&self) -> usize { self.length }
|
||||||
self.length
|
|
||||||
}
|
|
||||||
|
|
||||||
engine_input_impl!();
|
engine_input_impl!();
|
||||||
}
|
}
|
||||||
|
@ -407,7 +405,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
fn test() {
|
fn test() {
|
||||||
use crate::{Hash, HashEngine, ripemd160};
|
use crate::{ripemd160, Hash, HashEngine};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct Test {
|
struct Test {
|
||||||
|
@ -416,6 +414,7 @@ mod tests {
|
||||||
output_str: &'static str,
|
output_str: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
let tests = vec![
|
let tests = vec![
|
||||||
// Test messages from FIPS 180-1
|
// Test messages from FIPS 180-1
|
||||||
Test {
|
Test {
|
||||||
|
@ -487,9 +486,11 @@ mod tests {
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
#[test]
|
#[test]
|
||||||
fn ripemd_serde() {
|
fn ripemd_serde() {
|
||||||
use serde_test::{Configure, Token, assert_tokens};
|
use serde_test::{assert_tokens, Configure, Token};
|
||||||
|
|
||||||
use crate::{ripemd160, Hash};
|
use crate::{ripemd160, Hash};
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
static HASH_BYTES: [u8; 20] = [
|
static HASH_BYTES: [u8; 20] = [
|
||||||
0x13, 0x20, 0x72, 0xdf,
|
0x13, 0x20, 0x72, 0xdf,
|
||||||
0x69, 0x09, 0x33, 0x83,
|
0x69, 0x09, 0x33, 0x83,
|
||||||
|
@ -508,13 +509,13 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{Hash, HashEngine, ripemd160};
|
use crate::{ripemd160, Hash, HashEngine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn ripemd160_10(bh: &mut Bencher) {
|
pub fn ripemd160_10(bh: &mut Bencher) {
|
||||||
let mut engine = ripemd160::Hash::engine();
|
let mut engine = ripemd160::Hash::engine();
|
||||||
let bytes = [1u8; 10];
|
let bytes = [1u8; 10];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -524,7 +525,7 @@ mod benches {
|
||||||
pub fn ripemd160_1k(bh: &mut Bencher) {
|
pub fn ripemd160_1k(bh: &mut Bencher) {
|
||||||
let mut engine = ripemd160::Hash::engine();
|
let mut engine = ripemd160::Hash::engine();
|
||||||
let bytes = [1u8; 1024];
|
let bytes = [1u8; 1024];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -534,10 +535,9 @@ mod benches {
|
||||||
pub fn ripemd160_64k(bh: &mut Bencher) {
|
pub fn ripemd160_64k(bh: &mut Bencher) {
|
||||||
let mut engine = ripemd160::Hash::engine();
|
let mut engine = ripemd160::Hash::engine();
|
||||||
let bytes = [1u8; 65536];
|
let bytes = [1u8; 65536];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,13 @@
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "serde")))]
|
||||||
pub mod serde_details {
|
pub mod serde_details {
|
||||||
use crate::Error;
|
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::{fmt, ops, str};
|
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
|
use core::{fmt, ops, str};
|
||||||
|
|
||||||
|
use crate::Error;
|
||||||
struct HexVisitor<ValueT>(PhantomData<ValueT>);
|
struct HexVisitor<ValueT>(PhantomData<ValueT>);
|
||||||
use serde::{de, Serializer, Deserializer};
|
use serde::{de, Deserializer, Serializer};
|
||||||
|
|
||||||
impl<'de, ValueT> de::Visitor<'de> for HexVisitor<ValueT>
|
impl<'de, ValueT> de::Visitor<'de> for HexVisitor<ValueT>
|
||||||
where
|
where
|
||||||
|
@ -45,10 +45,7 @@ pub mod serde_details {
|
||||||
if let Ok(hex) = str::from_utf8(v) {
|
if let Ok(hex) = str::from_utf8(v) {
|
||||||
Self::Value::from_str(hex).map_err(E::custom)
|
Self::Value::from_str(hex).map_err(E::custom)
|
||||||
} else {
|
} else {
|
||||||
return Err(E::invalid_value(
|
return Err(E::invalid_value(de::Unexpected::Bytes(v), &self));
|
||||||
de::Unexpected::Bytes(v),
|
|
||||||
&self,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,10 @@
|
||||||
//! SHA1 implementation.
|
//! SHA1 implementation.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::{cmp, str};
|
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::slice::SliceIndex;
|
use core::slice::SliceIndex;
|
||||||
|
use core::{cmp, str};
|
||||||
|
|
||||||
use crate::{Error, HashEngine as _};
|
use crate::{Error, HashEngine as _};
|
||||||
|
|
||||||
|
@ -89,9 +89,7 @@ impl crate::HashEngine for HashEngine {
|
||||||
|
|
||||||
const BLOCK_SIZE: usize = 64;
|
const BLOCK_SIZE: usize = 64;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> usize {
|
fn n_bytes_hashed(&self) -> usize { self.length }
|
||||||
self.length
|
|
||||||
}
|
|
||||||
|
|
||||||
engine_input_impl!();
|
engine_input_impl!();
|
||||||
}
|
}
|
||||||
|
@ -106,7 +104,7 @@ impl HashEngine {
|
||||||
*w_val = u32::from_be_bytes(buff_bytes.try_into().expect("4 bytes slice"))
|
*w_val = u32::from_be_bytes(buff_bytes.try_into().expect("4 bytes slice"))
|
||||||
}
|
}
|
||||||
for i in 16..80 {
|
for i in 16..80 {
|
||||||
w[i] =(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
|
w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut a = self.h[0];
|
let mut a = self.h[0];
|
||||||
|
@ -121,10 +119,11 @@ impl HashEngine {
|
||||||
20...39 => (b ^ c ^ d, 0x6ed9eba1),
|
20...39 => (b ^ c ^ d, 0x6ed9eba1),
|
||||||
40...59 => ((b & c) | (b & d) | (c & d), 0x8f1bbcdc),
|
40...59 => ((b & c) | (b & d) | (c & d), 0x8f1bbcdc),
|
||||||
60...79 => (b ^ c ^ d, 0xca62c1d6),
|
60...79 => (b ^ c ^ d, 0xca62c1d6),
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let new_a = a.rotate_left(5).wrapping_add(f).wrapping_add(e).wrapping_add(k).wrapping_add(wi);
|
let new_a =
|
||||||
|
a.rotate_left(5).wrapping_add(f).wrapping_add(e).wrapping_add(k).wrapping_add(wi);
|
||||||
e = d;
|
e = d;
|
||||||
d = c;
|
d = c;
|
||||||
c = b.rotate_left(30);
|
c = b.rotate_left(30);
|
||||||
|
@ -154,7 +153,7 @@ mod tests {
|
||||||
output_str: &'static str,
|
output_str: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
let tests = vec![
|
let tests = vec![
|
||||||
// Examples from wikipedia
|
// Examples from wikipedia
|
||||||
Test {
|
Test {
|
||||||
|
@ -213,9 +212,11 @@ mod tests {
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
#[test]
|
#[test]
|
||||||
fn sha1_serde() {
|
fn sha1_serde() {
|
||||||
use serde_test::{Configure, Token, assert_tokens};
|
use serde_test::{assert_tokens, Configure, Token};
|
||||||
|
|
||||||
use crate::{sha1, Hash};
|
use crate::{sha1, Hash};
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
static HASH_BYTES: [u8; 20] = [
|
static HASH_BYTES: [u8; 20] = [
|
||||||
0x13, 0x20, 0x72, 0xdf,
|
0x13, 0x20, 0x72, 0xdf,
|
||||||
0x69, 0x09, 0x33, 0x83,
|
0x69, 0x09, 0x33, 0x83,
|
||||||
|
@ -234,13 +235,13 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{Hash, HashEngine, sha1};
|
use crate::{sha1, Hash, HashEngine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn sha1_10(bh: &mut Bencher) {
|
pub fn sha1_10(bh: &mut Bencher) {
|
||||||
let mut engine = sha1::Hash::engine();
|
let mut engine = sha1::Hash::engine();
|
||||||
let bytes = [1u8; 10];
|
let bytes = [1u8; 10];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -250,7 +251,7 @@ mod benches {
|
||||||
pub fn sha1_1k(bh: &mut Bencher) {
|
pub fn sha1_1k(bh: &mut Bencher) {
|
||||||
let mut engine = sha1::Hash::engine();
|
let mut engine = sha1::Hash::engine();
|
||||||
let bytes = [1u8; 1024];
|
let bytes = [1u8; 1024];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -260,10 +261,9 @@ mod benches {
|
||||||
pub fn sha1_64k(bh: &mut Bencher) {
|
pub fn sha1_64k(bh: &mut Bencher) {
|
||||||
let mut engine = sha1::Hash::engine();
|
let mut engine = sha1::Hash::engine();
|
||||||
let bytes = [1u8; 65536];
|
let bytes = [1u8; 65536];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
//! SHA256 implementation.
|
//! SHA256 implementation.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::{cmp, str};
|
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::slice::SliceIndex;
|
use core::slice::SliceIndex;
|
||||||
|
use core::{cmp, str};
|
||||||
|
|
||||||
use crate::{Error, HashEngine as _, hex, sha256d};
|
use crate::{hex, sha256d, Error, HashEngine as _};
|
||||||
|
|
||||||
crate::internal_macros::hash_type! {
|
crate::internal_macros::hash_type! {
|
||||||
256,
|
256,
|
||||||
|
@ -73,7 +73,10 @@ pub struct HashEngine {
|
||||||
impl Default for HashEngine {
|
impl Default for HashEngine {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
HashEngine {
|
HashEngine {
|
||||||
h: [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19],
|
h: [
|
||||||
|
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
|
||||||
|
0x5be0cd19,
|
||||||
|
],
|
||||||
length: 0,
|
length: 0,
|
||||||
buffer: [0; BLOCK_SIZE],
|
buffer: [0; BLOCK_SIZE],
|
||||||
}
|
}
|
||||||
|
@ -101,9 +104,7 @@ impl crate::HashEngine for HashEngine {
|
||||||
|
|
||||||
const BLOCK_SIZE: usize = 64;
|
const BLOCK_SIZE: usize = 64;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> usize {
|
fn n_bytes_hashed(&self) -> usize { self.length }
|
||||||
self.length
|
|
||||||
}
|
|
||||||
|
|
||||||
engine_input_impl!();
|
engine_input_impl!();
|
||||||
}
|
}
|
||||||
|
@ -127,16 +128,12 @@ impl<I: SliceIndex<[u8]>> Index<I> for Midstate {
|
||||||
type Output = I::Output;
|
type Output = I::Output;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn index(&self, index: I) -> &Self::Output {
|
fn index(&self, index: I) -> &Self::Output { &self.0[index] }
|
||||||
&self.0[index]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl str::FromStr for Midstate {
|
impl str::FromStr for Midstate {
|
||||||
type Err = hex::Error;
|
type Err = hex::Error;
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> { hex::FromHex::from_hex(s) }
|
||||||
hex::FromHex::from_hex(s)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Midstate {
|
impl Midstate {
|
||||||
|
@ -149,9 +146,7 @@ impl Midstate {
|
||||||
const DISPLAY_BACKWARD: bool = true;
|
const DISPLAY_BACKWARD: bool = true;
|
||||||
|
|
||||||
/// Construct a new [`Midstate`] from the inner value.
|
/// Construct a new [`Midstate`] from the inner value.
|
||||||
pub fn from_byte_array(inner: [u8; 32]) -> Self {
|
pub fn from_byte_array(inner: [u8; 32]) -> Self { Midstate(inner) }
|
||||||
Midstate(inner)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Copies a byte slice into the [`Midstate`] object.
|
/// Copies a byte slice into the [`Midstate`] object.
|
||||||
pub fn from_slice(sl: &[u8]) -> Result<Midstate, Error> {
|
pub fn from_slice(sl: &[u8]) -> Result<Midstate, Error> {
|
||||||
|
@ -165,9 +160,7 @@ impl Midstate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unwraps the [`Midstate`] and returns the underlying byte array.
|
/// Unwraps the [`Midstate`] and returns the underlying byte array.
|
||||||
pub fn to_byte_array(self) -> [u8; 32] {
|
pub fn to_byte_array(self) -> [u8; 32] { self.0 }
|
||||||
self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl hex::FromHex for Midstate {
|
impl hex::FromHex for Midstate {
|
||||||
|
@ -182,7 +175,8 @@ impl hex::FromHex for Midstate {
|
||||||
|
|
||||||
macro_rules! Ch( ($x:expr, $y:expr, $z:expr) => ($z ^ ($x & ($y ^ $z))) );
|
macro_rules! Ch( ($x:expr, $y:expr, $z:expr) => ($z ^ ($x & ($y ^ $z))) );
|
||||||
macro_rules! Maj( ($x:expr, $y:expr, $z:expr) => (($x & $y) | ($z & ($x | $y))) );
|
macro_rules! Maj( ($x:expr, $y:expr, $z:expr) => (($x & $y) | ($z & ($x | $y))) );
|
||||||
macro_rules! Sigma0( ($x:expr) => ($x.rotate_left(30) ^ $x.rotate_left(19) ^ $x.rotate_left(10)) ); macro_rules! Sigma1( ($x:expr) => ( $x.rotate_left(26) ^ $x.rotate_left(21) ^ $x.rotate_left(7)) );
|
macro_rules! Sigma0( ($x:expr) => ($x.rotate_left(30) ^ $x.rotate_left(19) ^ $x.rotate_left(10)) );
|
||||||
|
macro_rules! Sigma1( ($x:expr) => ( $x.rotate_left(26) ^ $x.rotate_left(21) ^ $x.rotate_left(7)) );
|
||||||
macro_rules! sigma0( ($x:expr) => ($x.rotate_left(25) ^ $x.rotate_left(14) ^ ($x >> 3)) );
|
macro_rules! sigma0( ($x:expr) => ($x.rotate_left(25) ^ $x.rotate_left(14) ^ ($x >> 3)) );
|
||||||
macro_rules! sigma1( ($x:expr) => ($x.rotate_left(15) ^ $x.rotate_left(13) ^ ($x >> 10)) );
|
macro_rules! sigma1( ($x:expr) => ($x.rotate_left(15) ^ $x.rotate_left(13) ^ ($x >> 10)) );
|
||||||
|
|
||||||
|
@ -215,11 +209,7 @@ impl HashEngine {
|
||||||
*ret_val = u32::from_be_bytes(midstate_bytes.try_into().expect("4 byte slice"));
|
*ret_val = u32::from_be_bytes(midstate_bytes.try_into().expect("4 byte slice"));
|
||||||
}
|
}
|
||||||
|
|
||||||
HashEngine {
|
HashEngine { buffer: [0; BLOCK_SIZE], h: ret, length }
|
||||||
buffer: [0; BLOCK_SIZE],
|
|
||||||
h: ret,
|
|
||||||
length,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Algorithm copied from libsecp256k1
|
// Algorithm copied from libsecp256k1
|
||||||
|
@ -321,7 +311,7 @@ impl HashEngine {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{Hash, HashEngine, sha256};
|
use crate::{sha256, Hash, HashEngine};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
@ -333,6 +323,7 @@ mod tests {
|
||||||
output_str: &'static str,
|
output_str: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
let tests = vec![
|
let tests = vec![
|
||||||
// Examples from wikipedia
|
// Examples from wikipedia
|
||||||
Test {
|
Test {
|
||||||
|
@ -386,6 +377,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[rustfmt::skip]
|
||||||
fn midstate() {
|
fn midstate() {
|
||||||
// Test vector obtained by doing an asset issuance on Elements
|
// Test vector obtained by doing an asset issuance on Elements
|
||||||
let mut engine = sha256::Hash::engine();
|
let mut engine = sha256::Hash::engine();
|
||||||
|
@ -444,15 +436,19 @@ mod tests {
|
||||||
// Test that a specific midstate results in a specific hash. Midstate was
|
// Test that a specific midstate results in a specific hash. Midstate was
|
||||||
// obtained by applying sha256 to sha256("MuSig coefficient")||sha256("MuSig
|
// obtained by applying sha256 to sha256("MuSig coefficient")||sha256("MuSig
|
||||||
// coefficient").
|
// coefficient").
|
||||||
|
#[rustfmt::skip]
|
||||||
static MIDSTATE: [u8; 32] = [
|
static MIDSTATE: [u8; 32] = [
|
||||||
0x0f, 0xd0, 0x69, 0x0c, 0xfe, 0xfe, 0xae, 0x97, 0x99, 0x6e, 0xac, 0x7f, 0x5c, 0x30,
|
0x0f, 0xd0, 0x69, 0x0c, 0xfe, 0xfe, 0xae, 0x97,
|
||||||
0xd8, 0x64, 0x8c, 0x4a, 0x05, 0x73, 0xac, 0xa1, 0xa2, 0x2f, 0x6f, 0x43, 0xb8, 0x01,
|
0x99, 0x6e, 0xac, 0x7f, 0x5c, 0x30, 0xd8, 0x64,
|
||||||
0x85, 0xce, 0x27, 0xcd,
|
0x8c, 0x4a, 0x05, 0x73, 0xac, 0xa1, 0xa2, 0x2f,
|
||||||
|
0x6f, 0x43, 0xb8, 0x01, 0x85, 0xce, 0x27, 0xcd,
|
||||||
];
|
];
|
||||||
|
#[rustfmt::skip]
|
||||||
static HASH_EXPECTED: [u8; 32] = [
|
static HASH_EXPECTED: [u8; 32] = [
|
||||||
0x18, 0x84, 0xe4, 0x72, 0x40, 0x4e, 0xf4, 0x5a, 0xb4, 0x9c, 0x4e, 0xa4, 0x9a, 0xe6,
|
0x18, 0x84, 0xe4, 0x72, 0x40, 0x4e, 0xf4, 0x5a,
|
||||||
0x23, 0xa8, 0x88, 0x52, 0x7f, 0x7d, 0x8a, 0x06, 0x94, 0x20, 0x8f, 0xf1, 0xf7, 0xa9,
|
0xb4, 0x9c, 0x4e, 0xa4, 0x9a, 0xe6, 0x23, 0xa8,
|
||||||
0xd5, 0x69, 0x09, 0x59,
|
0x88, 0x52, 0x7f, 0x7d, 0x8a, 0x06, 0x94, 0x20,
|
||||||
|
0x8f, 0xf1, 0xf7, 0xa9, 0xd5, 0x69, 0x09, 0x59,
|
||||||
];
|
];
|
||||||
let midstate_engine =
|
let midstate_engine =
|
||||||
sha256::HashEngine::from_midstate(sha256::Midstate::from_byte_array(MIDSTATE), 64);
|
sha256::HashEngine::from_midstate(sha256::Midstate::from_byte_array(MIDSTATE), 64);
|
||||||
|
@ -463,8 +459,9 @@ mod tests {
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
#[test]
|
#[test]
|
||||||
fn sha256_serde() {
|
fn sha256_serde() {
|
||||||
use serde_test::{Configure, Token, assert_tokens};
|
use serde_test::{assert_tokens, Configure, Token};
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
static HASH_BYTES: [u8; 32] = [
|
static HASH_BYTES: [u8; 32] = [
|
||||||
0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
|
0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
|
||||||
0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
|
0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
|
||||||
|
@ -474,14 +471,17 @@ mod tests {
|
||||||
|
|
||||||
let hash = sha256::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
|
let hash = sha256::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
|
||||||
assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
|
assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
|
||||||
assert_tokens(&hash.readable(), &[Token::Str("ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c")]);
|
assert_tokens(
|
||||||
|
&hash.readable(),
|
||||||
|
&[Token::Str("ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c")],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
mod wasm_tests {
|
mod wasm_tests {
|
||||||
extern crate wasm_bindgen_test;
|
extern crate wasm_bindgen_test;
|
||||||
use super::*;
|
|
||||||
use self::wasm_bindgen_test::*;
|
use self::wasm_bindgen_test::*;
|
||||||
|
use super::*;
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn sha256_tests() {
|
fn sha256_tests() {
|
||||||
test();
|
test();
|
||||||
|
@ -495,13 +495,13 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{Hash, HashEngine, sha256};
|
use crate::{sha256, Hash, HashEngine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn sha256_10(bh: &mut Bencher) {
|
pub fn sha256_10(bh: &mut Bencher) {
|
||||||
let mut engine = sha256::Hash::engine();
|
let mut engine = sha256::Hash::engine();
|
||||||
let bytes = [1u8; 10];
|
let bytes = [1u8; 10];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -511,7 +511,7 @@ mod benches {
|
||||||
pub fn sha256_1k(bh: &mut Bencher) {
|
pub fn sha256_1k(bh: &mut Bencher) {
|
||||||
let mut engine = sha256::Hash::engine();
|
let mut engine = sha256::Hash::engine();
|
||||||
let bytes = [1u8; 1024];
|
let bytes = [1u8; 1024];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -521,10 +521,9 @@ mod benches {
|
||||||
pub fn sha256_64k(bh: &mut Bencher) {
|
pub fn sha256_64k(bh: &mut Bencher) {
|
||||||
let mut engine = sha256::Hash::engine();
|
let mut engine = sha256::Hash::engine();
|
||||||
let bytes = [1u8; 65536];
|
let bytes = [1u8; 65536];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@
|
||||||
//! SHA256d implementation (double SHA256).
|
//! SHA256d implementation (double SHA256).
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::str;
|
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::slice::SliceIndex;
|
use core::slice::SliceIndex;
|
||||||
|
use core::str;
|
||||||
|
|
||||||
use crate::{Error, sha256};
|
use crate::{sha256, Error};
|
||||||
|
|
||||||
crate::internal_macros::hash_type! {
|
crate::internal_macros::hash_type! {
|
||||||
256,
|
256,
|
||||||
|
@ -55,6 +55,7 @@ mod tests {
|
||||||
output_str: &'static str,
|
output_str: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
let tests = vec![
|
let tests = vec![
|
||||||
// Test vector copied out of rust-bitcoin
|
// Test vector copied out of rust-bitcoin
|
||||||
Test {
|
Test {
|
||||||
|
@ -96,9 +97,11 @@ mod tests {
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
#[test]
|
#[test]
|
||||||
fn sha256_serde() {
|
fn sha256_serde() {
|
||||||
use serde_test::{Configure, Token, assert_tokens};
|
use serde_test::{assert_tokens, Configure, Token};
|
||||||
|
|
||||||
use crate::{sha256d, Hash};
|
use crate::{sha256d, Hash};
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
static HASH_BYTES: [u8; 32] = [
|
static HASH_BYTES: [u8; 32] = [
|
||||||
0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
|
0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7,
|
||||||
0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
|
0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97,
|
||||||
|
@ -108,7 +111,10 @@ mod tests {
|
||||||
|
|
||||||
let hash = sha256d::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
|
let hash = sha256d::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
|
||||||
assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
|
assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
|
||||||
assert_tokens(&hash.readable(), &[Token::Str("6cfb35868c4465b7c289d7d5641563aa973db6a929655282a7bf95c8257f53ef")]);
|
assert_tokens(
|
||||||
|
&hash.readable(),
|
||||||
|
&[Token::Str("6cfb35868c4465b7c289d7d5641563aa973db6a929655282a7bf95c8257f53ef")],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,13 +122,13 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{Hash, HashEngine, sha256d};
|
use crate::{sha256d, Hash, HashEngine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn sha256d_10(bh: &mut Bencher) {
|
pub fn sha256d_10(bh: &mut Bencher) {
|
||||||
let mut engine = sha256d::Hash::engine();
|
let mut engine = sha256d::Hash::engine();
|
||||||
let bytes = [1u8; 10];
|
let bytes = [1u8; 10];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -132,7 +138,7 @@ mod benches {
|
||||||
pub fn sha256d_1k(bh: &mut Bencher) {
|
pub fn sha256d_1k(bh: &mut Bencher) {
|
||||||
let mut engine = sha256d::Hash::engine();
|
let mut engine = sha256d::Hash::engine();
|
||||||
let bytes = [1u8; 1024];
|
let bytes = [1u8; 1024];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -142,7 +148,7 @@ mod benches {
|
||||||
pub fn sha256d_64k(bh: &mut Bencher) {
|
pub fn sha256d_64k(bh: &mut Bencher) {
|
||||||
let mut engine = sha256d::Hash::engine();
|
let mut engine = sha256d::Hash::engine();
|
||||||
let bytes = [1u8; 65536];
|
let bytes = [1u8; 65536];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
|
|
@ -15,12 +15,12 @@
|
||||||
//! SHA256t implementation (tagged SHA256).
|
//! SHA256t implementation (tagged SHA256).
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::{cmp, str};
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::slice::SliceIndex;
|
use core::slice::SliceIndex;
|
||||||
|
use core::{cmp, str};
|
||||||
|
|
||||||
use crate::{Error, sha256};
|
use crate::{sha256, Error};
|
||||||
|
|
||||||
type HashEngine = sha256::HashEngine;
|
type HashEngine = sha256::HashEngine;
|
||||||
|
|
||||||
|
@ -34,38 +34,30 @@ pub trait Tag {
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Hash<T: Tag>(
|
pub struct Hash<T: Tag>(
|
||||||
#[cfg_attr(feature = "schemars", schemars(schema_with = "crate::util::json_hex_string::len_32"))]
|
#[cfg_attr(
|
||||||
|
feature = "schemars",
|
||||||
|
schemars(schema_with = "crate::util::json_hex_string::len_32")
|
||||||
|
)]
|
||||||
[u8; 32],
|
[u8; 32],
|
||||||
#[cfg_attr(feature = "schemars", schemars(skip))]
|
#[cfg_attr(feature = "schemars", schemars(skip))] PhantomData<T>,
|
||||||
PhantomData<T>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
impl<T: Tag> Hash<T> {
|
impl<T: Tag> Hash<T> {
|
||||||
fn internal_new(arr: [u8; 32]) -> Self {
|
fn internal_new(arr: [u8; 32]) -> Self { Hash(arr, Default::default()) }
|
||||||
Hash(arr, Default::default())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn internal_engine() -> HashEngine {
|
fn internal_engine() -> HashEngine { T::engine() }
|
||||||
T::engine()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Tag> Copy for Hash<T> {}
|
impl<T: Tag> Copy for Hash<T> {}
|
||||||
impl<T: Tag> Clone for Hash<T> {
|
impl<T: Tag> Clone for Hash<T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self { Hash(self.0, self.1) }
|
||||||
Hash(self.0, self.1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl<T: Tag> PartialEq for Hash<T> {
|
impl<T: Tag> PartialEq for Hash<T> {
|
||||||
fn eq(&self, other: &Hash<T>) -> bool {
|
fn eq(&self, other: &Hash<T>) -> bool { self.0 == other.0 }
|
||||||
self.0 == other.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl<T: Tag> Eq for Hash<T> {}
|
impl<T: Tag> Eq for Hash<T> {}
|
||||||
impl<T: Tag> Default for Hash<T> {
|
impl<T: Tag> Default for Hash<T> {
|
||||||
fn default() -> Self {
|
fn default() -> Self { Hash([0; 32], PhantomData) }
|
||||||
Hash([0; 32], PhantomData)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl<T: Tag> PartialOrd for Hash<T> {
|
impl<T: Tag> PartialOrd for Hash<T> {
|
||||||
fn partial_cmp(&self, other: &Hash<T>) -> Option<cmp::Ordering> {
|
fn partial_cmp(&self, other: &Hash<T>) -> Option<cmp::Ordering> {
|
||||||
|
@ -73,14 +65,10 @@ impl<T: Tag> PartialOrd for Hash<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<T: Tag> Ord for Hash<T> {
|
impl<T: Tag> Ord for Hash<T> {
|
||||||
fn cmp(&self, other: &Hash<T>) -> cmp::Ordering {
|
fn cmp(&self, other: &Hash<T>) -> cmp::Ordering { cmp::Ord::cmp(&self.0, &other.0) }
|
||||||
cmp::Ord::cmp(&self.0, &other.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
impl<T: Tag> core::hash::Hash for Hash<T> {
|
impl<T: Tag> core::hash::Hash for Hash<T> {
|
||||||
fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
|
fn hash<H: core::hash::Hasher>(&self, h: &mut H) { self.0.hash(h) }
|
||||||
self.0.hash(h)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::internal_macros::hash_trait_impls!(256, true, T: Tag);
|
crate::internal_macros::hash_trait_impls!(256, true, T: Tag);
|
||||||
|
@ -98,7 +86,15 @@ fn from_engine<T: Tag>(e: sha256::HashEngine) -> Hash<T> {
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! sha256t_hash_newtype {
|
macro_rules! sha256t_hash_newtype {
|
||||||
($newtype:ident, $tag:ident, $midstate:ident, $midstate_len:expr, $docs:meta, $direction:tt) => {
|
($newtype:ident, $tag:ident, $midstate:ident, $midstate_len:expr, $docs:meta, $direction:tt) => {
|
||||||
sha256t_hash_newtype!($newtype, $tag, $midstate, $midstate_len, $docs, $direction, stringify!($newtype));
|
sha256t_hash_newtype!(
|
||||||
|
$newtype,
|
||||||
|
$tag,
|
||||||
|
$midstate,
|
||||||
|
$midstate_len,
|
||||||
|
$docs,
|
||||||
|
$direction,
|
||||||
|
stringify!($newtype)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
($newtype:ident, $tag:ident, $midstate:ident, $midstate_len:expr, $docs:meta, $direction:tt, $sname:expr) => {
|
($newtype:ident, $tag:ident, $midstate:ident, $midstate_len:expr, $docs:meta, $direction:tt, $sname:expr) => {
|
||||||
|
@ -125,13 +121,13 @@ macro_rules! sha256t_hash_newtype {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{sha256, sha256t};
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use crate::Hash;
|
use crate::Hash;
|
||||||
|
use crate::{sha256, sha256t};
|
||||||
|
|
||||||
const TEST_MIDSTATE: [u8; 32] = [
|
const TEST_MIDSTATE: [u8; 32] = [
|
||||||
156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243,
|
156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, 147,
|
||||||
147, 108, 71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201,
|
108, 71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201,
|
||||||
];
|
];
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
|
||||||
|
@ -150,7 +146,7 @@ mod tests {
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub type TestHash = sha256t::Hash<TestHashTag>;
|
pub type TestHash = sha256t::Hash<TestHashTag>;
|
||||||
|
|
||||||
sha256t_hash_newtype!(NewTypeHash, NewTypeTag, TEST_MIDSTATE, 64, doc="test hash", backward);
|
sha256t_hash_newtype!(NewTypeHash, NewTypeTag, TEST_MIDSTATE, 64, doc = "test hash", backward);
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
//! SHA512 implementation.
|
//! SHA512 implementation.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::{cmp, hash, str};
|
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::slice::SliceIndex;
|
use core::slice::SliceIndex;
|
||||||
|
use core::{cmp, hash, str};
|
||||||
|
|
||||||
use crate::{Error, HashEngine as _};
|
use crate::{Error, HashEngine as _};
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ pub struct HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for HashEngine {
|
impl Default for HashEngine {
|
||||||
|
#[rustfmt::skip]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
HashEngine {
|
HashEngine {
|
||||||
h: [
|
h: [
|
||||||
|
@ -73,9 +74,7 @@ impl crate::HashEngine for HashEngine {
|
||||||
|
|
||||||
const BLOCK_SIZE: usize = 128;
|
const BLOCK_SIZE: usize = 128;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> usize {
|
fn n_bytes_hashed(&self) -> usize { self.length }
|
||||||
self.length
|
|
||||||
}
|
|
||||||
|
|
||||||
engine_input_impl!();
|
engine_input_impl!();
|
||||||
}
|
}
|
||||||
|
@ -84,18 +83,17 @@ impl crate::HashEngine for HashEngine {
|
||||||
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct Hash(
|
pub struct Hash(
|
||||||
#[cfg_attr(feature = "schemars", schemars(schema_with = "crate::util::json_hex_string::len_64"))]
|
#[cfg_attr(
|
||||||
[u8; 64]
|
feature = "schemars",
|
||||||
|
schemars(schema_with = "crate::util::json_hex_string::len_64")
|
||||||
|
)]
|
||||||
|
[u8; 64],
|
||||||
);
|
);
|
||||||
|
|
||||||
impl Hash {
|
impl Hash {
|
||||||
fn internal_new(arr: [u8; 64]) -> Self {
|
fn internal_new(arr: [u8; 64]) -> Self { Hash(arr) }
|
||||||
Hash(arr)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn internal_engine() -> HashEngine {
|
fn internal_engine() -> HashEngine { Default::default() }
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Copy for Hash {}
|
impl Copy for Hash {}
|
||||||
|
@ -109,35 +107,25 @@ impl Clone for Hash {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Hash {
|
impl PartialEq for Hash {
|
||||||
fn eq(&self, other: &Hash) -> bool {
|
fn eq(&self, other: &Hash) -> bool { self.0[..] == other.0[..] }
|
||||||
self.0[..] == other.0[..]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for Hash {}
|
impl Eq for Hash {}
|
||||||
|
|
||||||
impl Default for Hash {
|
impl Default for Hash {
|
||||||
fn default() -> Hash {
|
fn default() -> Hash { Hash([0; 64]) }
|
||||||
Hash([0; 64])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for Hash {
|
impl PartialOrd for Hash {
|
||||||
fn partial_cmp(&self, other: &Hash) -> Option<cmp::Ordering> {
|
fn partial_cmp(&self, other: &Hash) -> Option<cmp::Ordering> { self.0.partial_cmp(&other.0) }
|
||||||
self.0.partial_cmp(&other.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for Hash {
|
impl Ord for Hash {
|
||||||
fn cmp(&self, other: &Hash) -> cmp::Ordering {
|
fn cmp(&self, other: &Hash) -> cmp::Ordering { self.0.cmp(&other.0) }
|
||||||
self.0.cmp(&other.0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl hash::Hash for Hash {
|
impl hash::Hash for Hash {
|
||||||
fn hash<H: hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: hash::Hasher>(&self, state: &mut H) { self.0.hash(state) }
|
||||||
self.0.hash(state)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(fuzzing))]
|
#[cfg(not(fuzzing))]
|
||||||
|
@ -319,6 +307,7 @@ mod tests {
|
||||||
output_str: &'static str,
|
output_str: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
let tests = vec![
|
let tests = vec![
|
||||||
// Test vectors computed with `sha512sum`
|
// Test vectors computed with `sha512sum`
|
||||||
Test {
|
Test {
|
||||||
|
@ -386,9 +375,11 @@ mod tests {
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
#[test]
|
#[test]
|
||||||
fn sha512_serde() {
|
fn sha512_serde() {
|
||||||
use serde_test::{Configure, Token, assert_tokens};
|
use serde_test::{assert_tokens, Configure, Token};
|
||||||
|
|
||||||
use crate::{sha512, Hash};
|
use crate::{sha512, Hash};
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
static HASH_BYTES: [u8; 64] = [
|
static HASH_BYTES: [u8; 64] = [
|
||||||
0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
|
0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21,
|
||||||
0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
|
0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e,
|
||||||
|
@ -406,7 +397,7 @@ mod tests {
|
||||||
&hash.readable(),
|
&hash.readable(),
|
||||||
&[Token::Str(
|
&[Token::Str(
|
||||||
"8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\
|
"8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\
|
||||||
fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c"
|
fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c",
|
||||||
)],
|
)],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -416,13 +407,13 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{Hash, HashEngine, sha512};
|
use crate::{sha512, Hash, HashEngine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn sha512_10(bh: &mut Bencher) {
|
pub fn sha512_10(bh: &mut Bencher) {
|
||||||
let mut engine = sha512::Hash::engine();
|
let mut engine = sha512::Hash::engine();
|
||||||
let bytes = [1u8; 10];
|
let bytes = [1u8; 10];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -432,7 +423,7 @@ mod benches {
|
||||||
pub fn sha512_1k(bh: &mut Bencher) {
|
pub fn sha512_1k(bh: &mut Bencher) {
|
||||||
let mut engine = sha512::Hash::engine();
|
let mut engine = sha512::Hash::engine();
|
||||||
let bytes = [1u8; 1024];
|
let bytes = [1u8; 1024];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -442,10 +433,9 @@ mod benches {
|
||||||
pub fn sha512_64k(bh: &mut Bencher) {
|
pub fn sha512_64k(bh: &mut Bencher) {
|
||||||
let mut engine = sha512::Hash::engine();
|
let mut engine = sha512::Hash::engine();
|
||||||
let bytes = [1u8; 65536];
|
let bytes = [1u8; 65536];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,11 +24,12 @@
|
||||||
//! produces an entirely different hash compared to sha512. More information at
|
//! produces an entirely different hash compared to sha512. More information at
|
||||||
//! <https://eprint.iacr.org/2010/548.pdf>.
|
//! <https://eprint.iacr.org/2010/548.pdf>.
|
||||||
|
|
||||||
use core::str;
|
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::slice::SliceIndex;
|
use core::slice::SliceIndex;
|
||||||
|
use core::str;
|
||||||
|
|
||||||
use crate::{sha512, sha512::BLOCK_SIZE, Error};
|
use crate::sha512::BLOCK_SIZE;
|
||||||
|
use crate::{sha512, Error};
|
||||||
|
|
||||||
/// Engine to compute SHA512/256 hash function.
|
/// Engine to compute SHA512/256 hash function.
|
||||||
///
|
///
|
||||||
|
@ -40,6 +41,7 @@ use crate::{sha512, sha512::BLOCK_SIZE, Error};
|
||||||
pub struct HashEngine(sha512::HashEngine);
|
pub struct HashEngine(sha512::HashEngine);
|
||||||
|
|
||||||
impl Default for HashEngine {
|
impl Default for HashEngine {
|
||||||
|
#[rustfmt::skip]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
HashEngine(sha512::HashEngine {
|
HashEngine(sha512::HashEngine {
|
||||||
h: [
|
h: [
|
||||||
|
@ -55,19 +57,13 @@ impl Default for HashEngine {
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
type MidState = [u8; 64];
|
type MidState = [u8; 64];
|
||||||
|
|
||||||
fn midstate(&self) -> [u8; 64] {
|
fn midstate(&self) -> [u8; 64] { self.0.midstate() }
|
||||||
self.0.midstate()
|
|
||||||
}
|
|
||||||
|
|
||||||
const BLOCK_SIZE: usize = sha512::BLOCK_SIZE;
|
const BLOCK_SIZE: usize = sha512::BLOCK_SIZE;
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> usize {
|
fn n_bytes_hashed(&self) -> usize { self.0.length }
|
||||||
self.0.length
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input(&mut self, inp: &[u8]) {
|
fn input(&mut self, inp: &[u8]) { self.0.input(inp); }
|
||||||
self.0.input(inp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
crate::internal_macros::hash_type! {
|
crate::internal_macros::hash_type! {
|
||||||
|
@ -97,6 +93,7 @@ mod tests {
|
||||||
output_str: &'static str,
|
output_str: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
let tests = vec![
|
let tests = vec![
|
||||||
// Examples from go sha512/256 tests.
|
// Examples from go sha512/256 tests.
|
||||||
Test {
|
Test {
|
||||||
|
@ -174,13 +171,13 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{Hash, HashEngine, sha512_256};
|
use crate::{sha512_256, Hash, HashEngine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn sha512_256_10(bh: &mut Bencher) {
|
pub fn sha512_256_10(bh: &mut Bencher) {
|
||||||
let mut engine = sha512_256::Hash::engine();
|
let mut engine = sha512_256::Hash::engine();
|
||||||
let bytes = [1u8; 10];
|
let bytes = [1u8; 10];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -190,7 +187,7 @@ mod benches {
|
||||||
pub fn sha512_256_1k(bh: &mut Bencher) {
|
pub fn sha512_256_1k(bh: &mut Bencher) {
|
||||||
let mut engine = sha512_256::Hash::engine();
|
let mut engine = sha512_256::Hash::engine();
|
||||||
let bytes = [1u8; 1024];
|
let bytes = [1u8; 1024];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
|
@ -200,10 +197,9 @@ mod benches {
|
||||||
pub fn sha512_256_64k(bh: &mut Bencher) {
|
pub fn sha512_256_64k(bh: &mut Bencher) {
|
||||||
let mut engine = sha512_256::Hash::engine();
|
let mut engine = sha512_256::Hash::engine();
|
||||||
let bytes = [1u8; 65536];
|
let bytes = [1u8; 65536];
|
||||||
bh.iter( || {
|
bh.iter(|| {
|
||||||
engine.input(&bytes);
|
engine.input(&bytes);
|
||||||
});
|
});
|
||||||
bh.bytes = bytes.len() as u64;
|
bh.bytes = bytes.len() as u64;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@
|
||||||
//! SipHash 2-4 implementation.
|
//! SipHash 2-4 implementation.
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use core::{cmp, mem, ptr, str};
|
|
||||||
use core::ops::Index;
|
use core::ops::Index;
|
||||||
use core::slice::SliceIndex;
|
use core::slice::SliceIndex;
|
||||||
|
use core::{cmp, mem, ptr, str};
|
||||||
|
|
||||||
use crate::{Error, Hash as _, HashEngine as _};
|
use crate::{Error, Hash as _, HashEngine as _};
|
||||||
|
|
||||||
|
@ -34,9 +34,7 @@ crate::internal_macros::hash_type! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(fuzzing))]
|
#[cfg(not(fuzzing))]
|
||||||
fn from_engine(e: HashEngine) -> Hash {
|
fn from_engine(e: HashEngine) -> Hash { Hash::from_u64(Hash::from_engine_to_u64(e)) }
|
||||||
Hash::from_u64(Hash::from_engine_to_u64(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(fuzzing)]
|
#[cfg(fuzzing)]
|
||||||
fn from_engine(e: HashEngine) -> Hash {
|
fn from_engine(e: HashEngine) -> Hash {
|
||||||
|
@ -44,7 +42,6 @@ fn from_engine(e: HashEngine) -> Hash {
|
||||||
Hash::from_u64(state.v0 ^ state.v1 ^ state.v2 ^ state.v3)
|
Hash::from_u64(state.v0 ^ state.v1 ^ state.v2 ^ state.v3)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
macro_rules! compress {
|
macro_rules! compress {
|
||||||
($state:expr) => {{
|
($state:expr) => {{
|
||||||
compress!($state.v0, $state.v1, $state.v2, $state.v3)
|
compress!($state.v0, $state.v1, $state.v2, $state.v3)
|
||||||
|
@ -128,14 +125,10 @@ impl HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new SipHash24 engine.
|
/// Creates a new SipHash24 engine.
|
||||||
pub fn new() -> HashEngine {
|
pub fn new() -> HashEngine { HashEngine::with_keys(0, 0) }
|
||||||
HashEngine::with_keys(0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the keys of this engine.
|
/// Retrieves the keys of this engine.
|
||||||
pub fn keys(&self) -> (u64, u64) {
|
pub fn keys(&self) -> (u64, u64) { (self.k0, self.k1) }
|
||||||
(self.k0, self.k1)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn c_rounds(state: &mut State) {
|
fn c_rounds(state: &mut State) {
|
||||||
|
@ -153,17 +146,13 @@ impl HashEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for HashEngine {
|
impl Default for HashEngine {
|
||||||
fn default() -> Self {
|
fn default() -> Self { HashEngine::new() }
|
||||||
HashEngine::new()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::HashEngine for HashEngine {
|
impl crate::HashEngine for HashEngine {
|
||||||
type MidState = State;
|
type MidState = State;
|
||||||
|
|
||||||
fn midstate(&self) -> State {
|
fn midstate(&self) -> State { self.state.clone() }
|
||||||
self.state.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
const BLOCK_SIZE: usize = 8;
|
const BLOCK_SIZE: usize = 8;
|
||||||
|
|
||||||
|
@ -207,10 +196,7 @@ impl crate::HashEngine for HashEngine {
|
||||||
self.ntail = left;
|
self.ntail = left;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn n_bytes_hashed(&self) -> usize {
|
fn n_bytes_hashed(&self) -> usize { self.length }
|
||||||
self.length
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash {
|
impl Hash {
|
||||||
|
@ -246,14 +232,10 @@ impl Hash {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the (little endian) 64-bit integer representation of the hash value.
|
/// Returns the (little endian) 64-bit integer representation of the hash value.
|
||||||
pub fn as_u64(&self) -> u64 {
|
pub fn as_u64(&self) -> u64 { u64::from_le_bytes(self.0) }
|
||||||
u64::from_le_bytes(self.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a hash from its (little endian) 64-bit integer representation.
|
/// Creates a hash from its (little endian) 64-bit integer representation.
|
||||||
pub fn from_u64(hash: u64) -> Hash {
|
pub fn from_u64(hash: u64) -> Hash { Hash(hash.to_le_bytes()) }
|
||||||
Hash(hash.to_le_bytes())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load an u64 using up to 7 bytes of a byte slice.
|
/// Load an u64 using up to 7 bytes of a byte slice.
|
||||||
|
@ -286,6 +268,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_siphash_2_4() {
|
fn test_siphash_2_4() {
|
||||||
|
#[rustfmt::skip]
|
||||||
let vecs: [[u8; 8]; 64] = [
|
let vecs: [[u8; 8]; 64] = [
|
||||||
[0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72],
|
[0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72],
|
||||||
[0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74],
|
[0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74],
|
||||||
|
@ -375,7 +358,7 @@ mod tests {
|
||||||
mod benches {
|
mod benches {
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
||||||
use crate::{Hash, HashEngine, siphash24};
|
use crate::{siphash24, Hash, HashEngine};
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
pub fn siphash24_1ki(bh: &mut Bencher) {
|
pub fn siphash24_1ki(bh: &mut Bencher) {
|
||||||
|
|
|
@ -107,8 +107,6 @@ macro_rules! engine_input_impl(
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Creates a new newtype around a [`Hash`] type.
|
/// Creates a new newtype around a [`Hash`] type.
|
||||||
///
|
///
|
||||||
/// The syntax is similar to the usual tuple struct syntax:
|
/// The syntax is similar to the usual tuple struct syntax:
|
||||||
|
@ -403,8 +401,9 @@ macro_rules! hash_newtype_known_attrs {
|
||||||
#[cfg(feature = "schemars")]
|
#[cfg(feature = "schemars")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "schemars")))]
|
#[cfg_attr(docsrs, doc(cfg(feature = "schemars")))]
|
||||||
pub mod json_hex_string {
|
pub mod json_hex_string {
|
||||||
|
use schemars::gen::SchemaGenerator;
|
||||||
use schemars::schema::{Schema, SchemaObject};
|
use schemars::schema::{Schema, SchemaObject};
|
||||||
use schemars::{gen::SchemaGenerator, JsonSchema};
|
use schemars::JsonSchema;
|
||||||
macro_rules! define_custom_hex {
|
macro_rules! define_custom_hex {
|
||||||
($name:ident, $len:expr) => {
|
($name:ident, $len:expr) => {
|
||||||
pub fn $name(gen: &mut SchemaGenerator) -> Schema {
|
pub fn $name(gen: &mut SchemaGenerator) -> Schema {
|
||||||
|
@ -426,7 +425,7 @@ pub mod json_hex_string {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{Hash, sha256};
|
use crate::{sha256, Hash};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hash_as_ref_array() {
|
fn hash_as_ref_array() {
|
||||||
|
|
11
rustfmt.toml
11
rustfmt.toml
|
@ -1,13 +1,4 @@
|
||||||
# Eventually this shoud be: ignore = []
|
ignore = []
|
||||||
ignore = [
|
|
||||||
"bitcoin/src/blockdata",
|
|
||||||
"bitcoin/src/consensus",
|
|
||||||
"bitcoin/src/crypto",
|
|
||||||
"bitcoin/src/psbt",
|
|
||||||
"bitcoin/src/util",
|
|
||||||
"hashes",
|
|
||||||
]
|
|
||||||
|
|
||||||
hard_tabs = false
|
hard_tabs = false
|
||||||
tab_spaces = 4
|
tab_spaces = 4
|
||||||
newline_style = "Auto"
|
newline_style = "Auto"
|
||||||
|
|
Loading…
Reference in New Issue