diff --git a/src/util/ecdsa.rs b/src/util/ecdsa.rs index 48af1b9ec0..e69a67a2b1 100644 --- a/src/util/ecdsa.rs +++ b/src/util/ecdsa.rs @@ -19,7 +19,7 @@ use prelude::*; -use core::{ops, str::FromStr}; +use core::{ops, str::FromStr, iter}; use core::fmt::{self, Write as _fmtWrite}; use io; @@ -451,9 +451,10 @@ impl EcdsaSig { /// Serialize EcdsaSig pub fn to_vec(&self) -> Vec { // TODO: add support to serialize to a writer to SerializedSig - let mut ser_sig = self.sig.serialize_der().to_vec(); - ser_sig.push(self.hash_ty.as_u32() as u8); - ser_sig + self.sig.serialize_der() + .iter().map(|x| *x) + .chain(iter::once(self.hash_ty as u8)) + .collect() } } diff --git a/src/util/psbt/mod.rs b/src/util/psbt/mod.rs index d851262404..814b5b5af2 100644 --- a/src/util/psbt/mod.rs +++ b/src/util/psbt/mod.rs @@ -821,7 +821,7 @@ mod tests { let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a075701172102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa232000000").unwrap_err(); assert_eq!(err.to_string(), "parse failed: Invalid xonly public key"); let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757011342173bb3d36c074afb716fec6307a069a2e450b995f3c82785945ab8df0e24260dcd703b0cbf34de399184a9481ac2b3586db6601f026a77f7e4938481bc34751701aa000000").unwrap_err(); - assert_eq!(err.to_string(), "parse failed: Invalid Schnorr signature len"); + assert_eq!(err.to_string(), "parse failed: Invalid Schnorr signature length"); let err = hex_psbt!("70736274ff010071020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02787c01000000000016001483a7e34bd99ff03a4962ef8a1a101bb295461ece606b042a010000001600147ac369df1b20e033d6116623957b0ac49f3c52e8000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757221602fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa2321900772b2da75600008001000080000000800100000000000000000000").unwrap_err(); assert_eq!(err.to_string(), "parse failed: Invalid xonly public key"); let err = hex_psbt!("70736274ff01007d020000000127744ababf3027fe0d6cf23a96eee2efb188ef52301954585883e69b6624b2420000000000ffffffff02887b0100000000001600142382871c7e8421a00093f754d91281e675874b9f606b042a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000000000001012b00f2052a010000002251205a2c2cf5b52cf31f83ad2e8da63ff03183ecd8f609c7510ae8a48e03910a0757000001052102fe349064c98d6e2a853fa3c9b12bd8b304a19c195c60efa7ee2393046d3fa23200").unwrap_err(); @@ -831,9 +831,9 @@ mod tests { let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6924214022cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b094089756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err(); assert_eq!(err.to_string(), "PSBT error: Hash Parse Error: bad slice length 33 (expected 32)"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b094289756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb01010000").unwrap_err(); - assert_eq!(err.to_string(), "parse failed: Invalid Schnorr signature len"); + assert_eq!(err.to_string(), "parse failed: Invalid Schnorr signature length"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b69241142cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2cd970e15f53fc0c82f950fd560ffa919b76172be017368a89913af074f400b093989756aa3739ccc689ec0fcf3a360be32cc0b59b16e93a1e8bb4605726b2ca7a3ff706c4176649632b2cc68e1f912b8a578e3719ce7710885c7a966f49bcd43cb0000").unwrap_err(); - assert_eq!(err.to_string(), "parse failed: Invalid Schnorr signature len"); + assert_eq!(err.to_string(), "parse failed: Invalid Schnorr signature length"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926315c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e1f80023202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err(); assert_eq!(err.to_string(), "parse failed: Invalid control block"); let err = hex_psbt!("70736274ff01005e02000000019bd48765230bf9a72e662001f972556e54f0c6f97feb56bcb5600d817f6995260100000000ffffffff0148e6052a01000000225120030da4fce4f7db28c2cb2951631e003713856597fe963882cb500e68112cca63000000000001012b00f2052a01000000225120c2247efbfd92ac47f6f40b8d42d169175a19fa9fa10e4a25d7f35eb4dd85b6926115c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac06f7d62059e9497a1a4a267569d9876da60101aff38e3529b9b939ce7f91ae970115f2e490af7cc45c4f78511f36057ce5c5a5c56325a29fb44dfc203f356e123202cb13ac68248de806aa6a3659cf3c03eb6821d09c8114a4e868febde865bb6d2acc00000").unwrap_err(); diff --git a/src/util/psbt/serialize.rs b/src/util/psbt/serialize.rs index 7194982acf..0863cf8c18 100644 --- a/src/util/psbt/serialize.rs +++ b/src/util/psbt/serialize.rs @@ -29,14 +29,14 @@ use consensus::encode::{self, serialize, Decodable, Encodable, deserialize_parti use secp256k1::{self, XOnlyPublicKey}; use util::bip32::{ChildNumber, Fingerprint, KeySource}; use hashes::{hash160, ripemd160, sha256, sha256d, Hash}; -use util::ecdsa::EcdsaSig; +use util::ecdsa::{EcdsaSig, EcdsaSigError}; use util::psbt; use util::taproot::{TapBranchHash, TapLeafHash, ControlBlock, LeafVersion}; use schnorr; + use super::map::TapTree; use util::taproot::TaprootBuilder; -use util::sighash::SchnorrSigHashType; /// A trait for serializing a value as raw data for insertion into PSBT /// key-value pairs. pub trait Serialize { @@ -90,38 +90,35 @@ impl Deserialize for secp256k1::PublicKey { impl Serialize for EcdsaSig { fn serialize(&self) -> Vec { - let mut buf = Vec::with_capacity(72); - buf.extend(self.sig.serialize_der().iter()); - buf.push(self.hash_ty as u8); - buf + self.to_vec() } } impl Deserialize for EcdsaSig { fn deserialize(bytes: &[u8]) -> Result { - let (sighash_byte, signature) = bytes.split_last() - .ok_or(encode::Error::ParseFailed("empty partial signature data"))?; - Ok(EcdsaSig { - sig: secp256k1::ecdsa::Signature::from_der(signature) - .map_err(|_| encode::Error::ParseFailed("non-DER encoded signature"))?, - // NB: Since BIP-174 says "the signature as would be pushed to the stack from - // a scriptSig or witness" we should ideally use a consensus deserialization and do - // not error on a non-standard values. However, - // - // 1) the current implementation of from_u32_consensus(`flag`) does not preserve - // the sighash byte `flag` mapping all unknown values to EcdsaSighashType::All or - // EcdsaSigHashType::AllPlusAnyOneCanPay. Therefore, break the invariant - // EcdsaSig::from_slice(&sl[..]).to_vec = sl. - // - // 2) This would cause to have invalid signatures because the sighash message - // 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 - // would use check the signature assuming sighash_u32 as `0x01`. - hash_ty: EcdsaSigHashType::from_u32_standard(*sighash_byte as u32) - .map_err(|_e| - encode::Error::from(psbt::Error::NonStandardSigHashType(*sighash_byte as u32)) - )?, - }) + // NB: Since BIP-174 says "the signature as would be pushed to the stack from + // a scriptSig or witness" we should ideally use a consensus deserialization and do + // not error on a non-standard values. However, + // + // 1) the current implementation of from_u32_consensus(`flag`) does not preserve + // the sighash byte `flag` mapping all unknown values to EcdsaSighashType::All or + // EcdsaSigHashType::AllPlusAnyOneCanPay. Therefore, break the invariant + // EcdsaSig::from_slice(&sl[..]).to_vec = sl. + // + // 2) This would cause to have invalid signatures because the sighash message + // 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 + // would use check the signature assuming sighash_u32 as `0x01`. + match EcdsaSig::from_slice(&bytes) { + Ok(sig) => Ok(sig), + Err(EcdsaSigError::EmptySignature) => + Err(encode::Error::ParseFailed("Empty partial signature data")), + Err(EcdsaSigError::NonStandardSigHashType(flag)) => + Err(encode::Error::from(psbt::Error::NonStandardSigHashType(flag))), + Err(EcdsaSigError::Secp256k1(..)) => + Err(encode::Error::ParseFailed("Invalid Ecdsa signature")), + Err(EcdsaSigError::HexEncoding(..)) => unreachable!("Decoding from slice, not hex") + } } } @@ -182,13 +179,8 @@ impl Serialize for EcdsaSigHashType { impl Deserialize for EcdsaSigHashType { fn deserialize(bytes: &[u8]) -> Result { let raw: u32 = encode::deserialize(bytes)?; - let rv: EcdsaSigHashType = EcdsaSigHashType::from_u32_consensus(raw); - - if rv.as_u32() == raw { - Ok(rv) - } else { - Err(psbt::Error::NonStandardSigHashType(raw).into()) - } + EcdsaSigHashType::from_u32_standard(raw) + .map_err(|_e| encode::Error::from(psbt::Error::NonStandardSigHashType(raw))) } } @@ -214,20 +206,15 @@ impl Serialize for schnorr::SchnorrSig { impl Deserialize for schnorr::SchnorrSig { fn deserialize(bytes: &[u8]) -> Result { - match bytes.len() { - 65 => { - let hash_ty = SchnorrSigHashType::from_u8(bytes[64]) - .map_err(|_| encode::Error::ParseFailed("Invalid Sighash type"))?; - let sig = secp256k1::schnorr::Signature::from_slice(&bytes[..64]) - .map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?; - Ok(schnorr::SchnorrSig{ sig, hash_ty }) - } - 64 => { - let sig = secp256k1::schnorr::Signature::from_slice(&bytes[..64]) - .map_err(|_| encode::Error::ParseFailed("Invalid Schnorr signature"))?; - Ok(schnorr::SchnorrSig{ sig, hash_ty: SchnorrSigHashType::Default }) + match schnorr::SchnorrSig::from_slice(&bytes) { + Ok(sig) => Ok(sig), + Err(schnorr::SchnorrSigError::InvalidSighashType(flag)) => { + Err(encode::Error::from(psbt::Error::NonStandardSigHashType(flag as u32))) } - _ => Err(encode::Error::ParseFailed("Invalid Schnorr signature len")) + Err(schnorr::SchnorrSigError::InvalidSchnorrSigSize(_)) => + Err(encode::Error::ParseFailed("Invalid Schnorr signature length")), + Err(schnorr::SchnorrSigError::Secp256k1(..)) => + Err(encode::Error::ParseFailed("Invalid Schnorr signature")), } } }