get_checksum_bytes
now checks input data for checksum
If `exclude_hash` is set, we split the input data, and if a checksum already existed within the original data, we check the calculated checksum against the original checksum. Additionally, the implementation of `IntoWalletDescriptor` for `&str` has been refactored for clarity.
This commit is contained in:
parent
af0b3698c6
commit
fd34956c29
@ -41,12 +41,21 @@ fn poly_mod(mut c: u64, val: u64) -> u64 {
|
|||||||
c
|
c
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the checksum bytes of a descriptor
|
/// Computes the checksum bytes of a descriptor.
|
||||||
pub fn get_checksum_bytes(desc: &str) -> Result<[u8; 8], DescriptorError> {
|
/// `exclude_hash = true` ignores all data after the first '#' (inclusive).
|
||||||
|
pub fn get_checksum_bytes(mut desc: &str, exclude_hash: bool) -> Result<[u8; 8], DescriptorError> {
|
||||||
let mut c = 1;
|
let mut c = 1;
|
||||||
let mut cls = 0;
|
let mut cls = 0;
|
||||||
let mut clscount = 0;
|
let mut clscount = 0;
|
||||||
|
|
||||||
|
let mut original_checksum = None;
|
||||||
|
if exclude_hash {
|
||||||
|
if let Some(split) = desc.split_once('#') {
|
||||||
|
desc = split.0;
|
||||||
|
original_checksum = Some(split.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for ch in desc.as_bytes() {
|
for ch in desc.as_bytes() {
|
||||||
let pos = INPUT_CHARSET
|
let pos = INPUT_CHARSET
|
||||||
.iter()
|
.iter()
|
||||||
@ -72,13 +81,20 @@ pub fn get_checksum_bytes(desc: &str) -> Result<[u8; 8], DescriptorError> {
|
|||||||
checksum[j] = CHECKSUM_CHARSET[((c >> (5 * (7 - j))) & 31) as usize];
|
checksum[j] = CHECKSUM_CHARSET[((c >> (5 * (7 - j))) & 31) as usize];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if input data already had a checksum, check calculated checksum against original checksum
|
||||||
|
if let Some(original_checksum) = original_checksum {
|
||||||
|
if original_checksum.as_bytes() != &checksum {
|
||||||
|
return Err(DescriptorError::InvalidDescriptorChecksum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(checksum)
|
Ok(checksum)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the checksum of a descriptor
|
/// Compute the checksum of a descriptor
|
||||||
pub fn get_checksum(desc: &str) -> Result<String, DescriptorError> {
|
pub fn get_checksum(desc: &str) -> Result<String, DescriptorError> {
|
||||||
// unsafe is okay here as the checksum only uses bytes in `CHECKSUM_CHARSET`
|
// unsafe is okay here as the checksum only uses bytes in `CHECKSUM_CHARSET`
|
||||||
get_checksum_bytes(desc).map(|b| unsafe { String::from_utf8_unchecked(b.to_vec()) })
|
get_checksum_bytes(desc, true).map(|b| unsafe { String::from_utf8_unchecked(b.to_vec()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -40,6 +40,7 @@ pub mod policy;
|
|||||||
pub mod template;
|
pub mod template;
|
||||||
|
|
||||||
pub use self::checksum::get_checksum;
|
pub use self::checksum::get_checksum;
|
||||||
|
use self::checksum::get_checksum_bytes;
|
||||||
pub use self::derived::{AsDerived, DerivedDescriptorKey};
|
pub use self::derived::{AsDerived, DerivedDescriptorKey};
|
||||||
pub use self::error::Error as DescriptorError;
|
pub use self::error::Error as DescriptorError;
|
||||||
pub use self::policy::Policy;
|
pub use self::policy::Policy;
|
||||||
@ -84,19 +85,15 @@ impl IntoWalletDescriptor for &str {
|
|||||||
secp: &SecpCtx,
|
secp: &SecpCtx,
|
||||||
network: Network,
|
network: Network,
|
||||||
) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
|
) -> Result<(ExtendedDescriptor, KeyMap), DescriptorError> {
|
||||||
let descriptor = if self.contains('#') {
|
let descriptor = match self.split_once('#') {
|
||||||
let parts: Vec<&str> = self.splitn(2, '#').collect();
|
Some((desc, original_checksum)) => {
|
||||||
if !get_checksum(parts[0])
|
let checksum = get_checksum_bytes(desc, false)?;
|
||||||
.ok()
|
if original_checksum.as_bytes() != &checksum {
|
||||||
.map(|computed| computed == parts[1])
|
return Err(DescriptorError::InvalidDescriptorChecksum);
|
||||||
.unwrap_or(false)
|
}
|
||||||
{
|
desc
|
||||||
return Err(DescriptorError::InvalidDescriptorChecksum);
|
|
||||||
}
|
}
|
||||||
|
None => self,
|
||||||
parts[0]
|
|
||||||
} else {
|
|
||||||
self
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ExtendedDescriptor::parse_descriptor(secp, descriptor)?
|
ExtendedDescriptor::parse_descriptor(secp, descriptor)?
|
||||||
|
@ -1943,15 +1943,10 @@ pub(crate) mod test {
|
|||||||
let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
|
let (wallet, _, _) = get_funded_wallet(get_test_wpkh());
|
||||||
let checksum = wallet.descriptor_checksum(KeychainKind::External);
|
let checksum = wallet.descriptor_checksum(KeychainKind::External);
|
||||||
assert_eq!(checksum.len(), 8);
|
assert_eq!(checksum.len(), 8);
|
||||||
|
assert_eq!(
|
||||||
let raw_descriptor = wallet
|
get_checksum(&wallet.descriptor.to_string()).unwrap(),
|
||||||
.descriptor
|
checksum
|
||||||
.to_string()
|
);
|
||||||
.split_once('#')
|
|
||||||
.unwrap()
|
|
||||||
.0
|
|
||||||
.to_string();
|
|
||||||
assert_eq!(get_checksum(&raw_descriptor).unwrap(), checksum);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user