@@ -207,10 +207,35 @@ func CreateTransitionProof(prevOut wire.OutPoint, params *TransitionParams,
207207 }
208208
209209 if proof .Asset .IsTransferRoot () && ! cfg .NoSTXOProofs {
210+ assetCommitments := params .TaprootAssetRoot .Commitments ()
211+ altCommitment , ok := assetCommitments [asset .EmptyGenesisID ]
212+ if ! ok {
213+ return nil , fmt .Errorf ("no alt leaves for transfer " +
214+ "root asset" )
215+ }
216+
217+ // If this is a transfer root, then we also expect there to be
218+ // prev witnesses.
219+ if len (proof .Asset .PrevWitnesses ) == 0 {
220+ return nil , fmt .Errorf ("no prev witnesses for " +
221+ "transfer root asset" )
222+ }
223+
224+ // We should have at least as many alt leaves as we have
225+ // prev witnesses. We may have additional alt leaves which are
226+ // not related to stxo proofs.
227+ //
228+ // nolint: lll
229+ if len (altCommitment .Assets ()) < len (proof .Asset .PrevWitnesses ) {
230+ return nil , fmt .Errorf ("not enough alt leaves for " +
231+ "transfer root asset" )
232+ }
233+
210234 stxoInclusionProofs := make (
211235 map [asset.SerializedKey ]commitment.Proof ,
212236 len (proof .Asset .PrevWitnesses ),
213237 )
238+
214239 for _ , wit := range proof .Asset .PrevWitnesses {
215240 spentAsset , err := asset .MakeSpentAsset (wit )
216241 if err != nil {
@@ -227,12 +252,36 @@ func CreateTransitionProof(prevOut wire.OutPoint, params *TransitionParams,
227252 if err != nil {
228253 return nil , err
229254 }
255+
256+ // Sanity-check the STXO proof to ensure the asset proof
257+ // is present. STXO inclusion proofs must always include
258+ // a valid asset proof.
259+ if stxoProof == nil {
260+ return nil , fmt .Errorf ("stxo inclusion proof " +
261+ "is nil" )
262+ }
263+
264+ if stxoProof .AssetProof == nil {
265+ return nil , commitment .ErrMissingAssetProof
266+ }
267+
230268 keySerialized := asset .ToSerialized (
231269 spentAsset .ScriptKey .PubKey ,
232270 )
233271 stxoInclusionProofs [keySerialized ] = * stxoProof
234272 }
235273
274+ // For assets representing a root transfer (normal assets), each
275+ // spent input corresponds to an entry in PrevWitnesses.
276+ // Therefore, the number of PrevWitnesses should match the
277+ // number of STXO inclusion proofs.
278+ if len (stxoInclusionProofs ) != len (proof .Asset .PrevWitnesses ) {
279+ return nil , fmt .Errorf ("stxo inclusion proof count " +
280+ "mismatch: expected %d, got %d" ,
281+ len (proof .Asset .PrevWitnesses ),
282+ len (stxoInclusionProofs ))
283+ }
284+
236285 if len (stxoInclusionProofs ) == 0 {
237286 return nil , fmt .Errorf ("no stxo inclusion proofs" )
238287 }
0 commit comments