@@ -1408,15 +1408,35 @@ func (p *ChainPorter) prelimCheckAddrParcel(addrParcel AddressParcel) error {
14081408 return nil
14091409}
14101410
1411- // verifyPacketInputProofs ensures that each virtual packet's inputs reference
1412- // a valid Taproot Asset commitment before the package is broadcast .
1413- func (p * ChainPorter ) verifyPacketInputProofs (ctx context.Context ,
1411+ // verifyVPackets performs various verification checks on the given virtual
1412+ // packets .
1413+ func (p * ChainPorter ) verifyVPackets (ctx context.Context ,
14141414 packets []* tappsbt.VPacket ) error {
14151415
1416- if len (packets ) == 0 {
1417- return nil
1416+ for pktIdx := range packets {
1417+ vPkt := packets [pktIdx ]
1418+
1419+ err := p .verifyPacketInputProofs (ctx , * vPkt )
1420+ if err != nil {
1421+ return fmt .Errorf ("verify packet input proofs " +
1422+ "(vpkt_idx=%d): %w" , pktIdx , err )
1423+ }
1424+
1425+ err = verifySplitCommitmentWitnesses (* vPkt )
1426+ if err != nil {
1427+ return fmt .Errorf ("verify split commitment " +
1428+ "witnesses (vpkt_idx=%d): %w" , pktIdx , err )
1429+ }
14181430 }
14191431
1432+ return nil
1433+ }
1434+
1435+ // verifyPacketInputProofs ensures that each virtual packet's inputs reference
1436+ // a valid Taproot Asset commitment before the package is broadcast.
1437+ func (p * ChainPorter ) verifyPacketInputProofs (ctx context.Context ,
1438+ vPkt tappsbt.VPacket ) error {
1439+
14201440 headerVerifier := tapgarden .GenHeaderVerifier (ctx , p .cfg .ChainBridge )
14211441 vCtx := proof.VerifierCtx {
14221442 HeaderVerifier : headerVerifier ,
@@ -1426,21 +1446,57 @@ func (p *ChainPorter) verifyPacketInputProofs(ctx context.Context,
14261446 IgnoreChecker : p .cfg .IgnoreChecker ,
14271447 }
14281448
1429- for pktIdx := range packets {
1430- vPkt := packets [pktIdx ]
1431- for inputIdx := range vPkt .Inputs {
1432- assetProof := vPkt .Inputs [inputIdx ].Proof
1433- if assetProof == nil {
1434- return fmt .Errorf ("packet %d input %d proof " +
1435- "is nil" , pktIdx , inputIdx )
1436- }
1449+ for inputIdx := range vPkt .Inputs {
1450+ assetProof := vPkt .Inputs [inputIdx ].Proof
1451+ if assetProof == nil {
1452+ return fmt .Errorf ("packet input proof is nil " +
1453+ "(input_idx=%d)" , inputIdx )
1454+ }
14371455
1438- _ , err := assetProof .VerifyProofIntegrity (ctx , vCtx )
1439- if err != nil {
1440- return fmt .Errorf ("unable to verify " +
1441- "inclusion proof for packet %d " +
1442- "input %d: %w" , pktIdx , inputIdx , err )
1443- }
1456+ _ , err := assetProof .VerifyProofIntegrity (ctx , vCtx )
1457+ if err != nil {
1458+ return fmt .Errorf ("unable to verify " +
1459+ "inclusion proof for packet input " +
1460+ "(input_idx=%d): %w" , inputIdx , err )
1461+ }
1462+ }
1463+
1464+ return nil
1465+ }
1466+
1467+ // verifySplitCommitmentWitnesses ensures split leaf outputs embed a split root
1468+ // that actually carries a witness. Split leaves intentionally keep their own
1469+ // TxWitness empty and rely on the embedded root witness for validation.
1470+ func verifySplitCommitmentWitnesses (vPkt tappsbt.VPacket ) error {
1471+ for outIdx := range vPkt .Outputs {
1472+ vOut := vPkt .Outputs [outIdx ]
1473+
1474+ if vOut .Asset == nil ||
1475+ ! vOut .Asset .HasSplitCommitmentWitness () {
1476+
1477+ continue
1478+ }
1479+
1480+ splitCommitment := vOut .Asset .PrevWitnesses [0 ].SplitCommitment
1481+ if splitCommitment == nil {
1482+ return fmt .Errorf ("output missing split commitment " +
1483+ "(output_idx=%d)" , outIdx )
1484+ }
1485+
1486+ root := & splitCommitment .RootAsset
1487+ if len (root .PrevWitnesses ) == 0 {
1488+ return fmt .Errorf ("output split root has no prev " +
1489+ "witnesses (output_idx=%d)" , outIdx )
1490+ }
1491+
1492+ hasWitness := fn .Any (
1493+ root .PrevWitnesses , func (wit asset.Witness ) bool {
1494+ return len (wit .TxWitness ) > 0
1495+ },
1496+ )
1497+ if ! hasWitness {
1498+ return fmt .Errorf ("output split root witness empty " +
1499+ "(output_idx=%d)" , outIdx )
14441500 }
14451501 }
14461502
@@ -1697,12 +1753,11 @@ func (p *ChainPorter) stateStep(currentPkg sendPackage) (*sendPackage, error) {
16971753 allPackets = append (allPackets , currentPkg .VirtualPackets ... )
16981754 allPackets = append (allPackets , currentPkg .PassiveAssets ... )
16991755
1700- err := p .verifyPacketInputProofs (ctx , allPackets )
1756+ err := p .verifyVPackets (ctx , allPackets )
17011757 if err != nil {
17021758 p .unlockInputs (ctx , & currentPkg )
17031759
1704- return nil , fmt .Errorf ("unable to verify input " +
1705- "proofs: %w" , err )
1760+ return nil , fmt .Errorf ("verifying vPackets: %w" , err )
17061761 }
17071762
17081763 currentPkg .SendState = SendStateStorePreBroadcast
0 commit comments