Skip to content

Commit 8cbfe53

Browse files
committed
test: cover output diagnostics and independent proof restrictions
1 parent 2089a14 commit 8cbfe53

1 file changed

Lines changed: 108 additions & 0 deletions

File tree

‎src/blind.rs‎

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,4 +1629,112 @@ mod tests {
16291629
}
16301630
tx.verify_tx_amt_proofs(&secp, &utxos).unwrap();
16311631
}
1632+
1633+
#[test]
1634+
fn verify_explicit_output_fields() {
1635+
let asset = AssetId::LIQUID_BTC;
1636+
let explicit = |value, script_pubkey| TxOut { script_pubkey, ..TxOut::new_fee(value, asset) };
1637+
let op_return = Script::new_op_return(b"data");
1638+
let spk = Script::from(vec![0x51]);
1639+
let tx = Transaction {
1640+
version: 2,
1641+
lock_time: crate::LockTime::ZERO,
1642+
input: vec![TxIn::default()],
1643+
output: vec![
1644+
explicit(0, op_return.clone()),
1645+
explicit(90, spk.clone()),
1646+
TxOut::new_fee(10, asset),
1647+
],
1648+
};
1649+
let spent_utxo = [TxOut::new_fee(100, asset)];
1650+
let verify = |tx: &Transaction| tx.verify_tx_amt_proofs(SECP256K1, &spent_utxo);
1651+
let verify_with = |index: usize, out: TxOut| {
1652+
let mut tx = tx.clone();
1653+
tx.output[index] = out;
1654+
verify(&tx)
1655+
};
1656+
1657+
assert_eq!(verify(&tx), Ok(()));
1658+
let oversized = Script::from(vec![0x51; 10_001]);
1659+
assert_eq!(verify_with(0, explicit(0, oversized)), Ok(()));
1660+
assert_eq!(verify_with(0, TxOut::new_fee(0, asset)), Ok(()));
1661+
assert_eq!(
1662+
verify_with(2, TxOut::new_fee(11, asset)),
1663+
Err(VerificationError::BalanceCheckFailed)
1664+
);
1665+
1666+
assert_eq!(
1667+
verify_with(1, explicit(0, spk.clone())),
1668+
Err(VerificationError::TxOutError(1, TxOutError::NonUnspendableZeroValue))
1669+
);
1670+
assert_eq!(
1671+
verify_with(0, TxOut { asset: Asset::Null, ..explicit(0, op_return.clone()) }),
1672+
Err(VerificationError::TxOutError(0, TxOutError::UnExpectedNullAsset))
1673+
);
1674+
let asset_bf = AssetBlindingFactor::new(&mut thread_rng());
1675+
let blinded_asset = Asset::new_confidential(SECP256K1, asset, asset_bf);
1676+
assert_eq!(
1677+
verify_with(0, TxOut { asset: blinded_asset, ..explicit(0, op_return.clone()) }),
1678+
Err(VerificationError::SurjectionProofMissing(0))
1679+
);
1680+
1681+
let vbf = ValueBlindingFactor::new(&mut thread_rng());
1682+
let blinded_value =
1683+
Value::new_confidential_from_assetid(SECP256K1, 90, asset, vbf, AssetBlindingFactor::zero());
1684+
let blinded_value_out = TxOut { value: blinded_value, ..explicit(90, spk.clone()) };
1685+
assert_eq!(
1686+
verify_with(1, blinded_value_out.clone()),
1687+
Err(VerificationError::RangeProofMissing(1))
1688+
);
1689+
1690+
let gen = Generator::new_unblinded(SECP256K1, asset.into_tag());
1691+
let comm = blinded_value.commitment().unwrap();
1692+
// Unlike `blind_value_proof`, this commits to `spk`, so it is valid for `blinded_value_out`.
1693+
let rangeproof = RangeProof::new(
1694+
SECP256K1,
1695+
90,
1696+
comm,
1697+
90,
1698+
vbf.into_inner(),
1699+
&[],
1700+
spk.as_bytes(),
1701+
SecretKey::new(&mut thread_rng()),
1702+
-1,
1703+
0,
1704+
gen,
1705+
)
1706+
.unwrap();
1707+
let surjection_proof =
1708+
SurjectionProof::blind_asset_proof(&mut thread_rng(), SECP256K1, asset, asset_bf).unwrap();
1709+
let witness = |surjection_proof, rangeproof| TxOutWitness { surjection_proof, rangeproof };
1710+
// The only input's asset is the domain, so `surjection_proof` is valid for `blinded_asset`.
1711+
let zero_blinded_asset = |rangeproof| TxOut {
1712+
asset: blinded_asset,
1713+
witness: witness(surjection_proof.clone(), rangeproof),
1714+
..explicit(0, op_return.clone())
1715+
};
1716+
assert_eq!(verify_with(0, zero_blinded_asset(RangeProof::EMPTY)), Ok(()));
1717+
// Valid proofs, but for nothing an explicit value or asset commits to.
1718+
assert_eq!(
1719+
verify_with(0, zero_blinded_asset(rangeproof.clone())),
1720+
Err(VerificationError::RangeProofError(0, secp256k1_zkp::Error::InvalidRangeProof))
1721+
);
1722+
let explicit_rangeproof = TxOut {
1723+
witness: witness(SurjectionProof::EMPTY, rangeproof.clone()),
1724+
..explicit(90, spk)
1725+
};
1726+
assert_eq!(
1727+
verify_with(1, explicit_rangeproof),
1728+
Err(VerificationError::RangeProofError(1, secp256k1_zkp::Error::InvalidRangeProof))
1729+
);
1730+
let explicit_asset_surjection_proof =
1731+
TxOut { witness: witness(surjection_proof, rangeproof), ..blinded_value_out };
1732+
assert_eq!(
1733+
verify_with(1, explicit_asset_surjection_proof),
1734+
Err(VerificationError::SurjectionProofError(
1735+
1,
1736+
secp256k1_zkp::Error::InvalidSurjectionProof
1737+
))
1738+
);
1739+
}
16321740
}

0 commit comments

Comments
 (0)