Skip to content

Commit 787486d

Browse files
committed
blind: use array splitting in TxOut::unblind (fix potential DoS?)
I don't *think* it's possible to create a rangeproof with a sidechannel smaller than 64 bytes (if you create a 0-sized "proof of exact value" then unwinding will fail entirely, and anything larger I think has at least one ring, so 128 bytes or more). Unsure. But better not to assume this by indexing recklessly into the sidechannel message.
1 parent 9274d76 commit 787486d

2 files changed

Lines changed: 27 additions & 6 deletions

File tree

src/blind.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
//! # Transactions Blinding
1616
//!
1717
18-
use core::convert::TryFrom;
18+
use internals::array::ArrayExt as _;
19+
use internals::slice::SliceExt;
1920
use std::{self, collections::BTreeMap, fmt};
2021

2122
use secp256k1_zkp::{
@@ -761,16 +762,31 @@ impl TxOut {
761762
additional_generator,
762763
)?;
763764

764-
let (asset, asset_bf) = opening.message.as_ref().split_at(32);
765-
let asset = <[u8; 32]>::try_from(asset).map_err(UnblindError::MalformedAssetId)?;
766-
let asset = AssetId::from_byte_array(asset);
767-
let asset_bf = AssetBlindingFactor::from_slice(&asset_bf[..32])?;
765+
// Use `MissingRangeproof` error because it's available so does not require
766+
// API breaks. In a later PR we should extend that enum and add #[non_exhaustive]
767+
// to it. The maybe-better `MalformedAssetId` error requires we start with a
768+
// std `FromSliceError` which we don't have.
769+
let asset_and_bf = SliceExt::split_first_chunk::<64>(opening.message.as_ref())
770+
.ok_or(UnblindError::MissingRangeproof)?
771+
.0;
772+
let (asset_id, asset_bf) = asset_and_bf.split_array();
773+
774+
let asset_id = AssetId::from_byte_array(*asset_id);
775+
let asset_bf = AssetBlindingFactor::from_byte_array(*asset_bf)?;
776+
if let Asset::Confidential(own_asset) = self.asset {
777+
let secp = Secp256k1::signing_only(); // needed to avoid API break
778+
let asset = Generator::new_blinded(&secp, asset_id.into_tag(), asset_bf.into_inner());
779+
if asset != own_asset {
780+
// See above about use of MissingRangeproof.
781+
return Err(UnblindError::MissingRangeproof);
782+
}
783+
}
768784

769785
let value = opening.value;
770786
let value_bf = ValueBlindingFactor(opening.blinding_factor);
771787

772788
Ok(TxOutSecrets {
773-
asset,
789+
asset: asset_id,
774790
asset_bf,
775791
value,
776792
value_bf,

src/confidential.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,11 @@ impl AssetBlindingFactor {
789789
s.parse()
790790
}
791791

792+
/// Create from bytes.
793+
pub fn from_byte_array(bytes: [u8; 32]) -> Result<Self, secp256k1_zkp::Error> {
794+
Ok(AssetBlindingFactor(Tweak::from_inner(bytes)?))
795+
}
796+
792797
/// Create from bytes.
793798
pub fn from_slice(bytes: &[u8]) -> Result<Self, secp256k1_zkp::Error> {
794799
Ok(AssetBlindingFactor(Tweak::from_slice(bytes)?))

0 commit comments

Comments
 (0)