@@ -10,10 +10,8 @@ import (
1010 "github.com/btcsuite/btcd/btcec/v2"
1111 "github.com/btcsuite/btcd/txscript"
1212 "github.com/btcsuite/btcd/wire"
13- "github.com/lightninglabs/taproot-assets/address"
1413 "github.com/lightninglabs/taproot-assets/asset"
1514 "github.com/lightninglabs/taproot-assets/commitment"
16- "github.com/lightninglabs/taproot-assets/tappsbt"
1715 "github.com/lightninglabs/taproot-assets/vm"
1816 "golang.org/x/sync/errgroup"
1917)
@@ -255,28 +253,58 @@ func (p *Proof) verifyChallengeWitness() (bool, error) {
255253 // independent of how the asset was created. The chain params are only
256254 // needed when encoding/decoding a vPkt, so it doesn't matter what
257255 // network we choose as we only need the packet to get the witness.
258- vPkt := tappsbt .OwnershipProofPacket (
259- p .Asset .Copy (), & address .MainNetTap ,
260- )
261- vIn := vPkt .Inputs [0 ]
262- vOut := vPkt .Outputs [0 ]
256+ ownedAsset := p .Asset .Copy ()
257+ prevId , proofAsset := CreateOwnershipProofAsset (ownedAsset )
263258
264259 // The 1-in-1-out packet for the challenge witness is well-defined, we
265260 // don't have to do any extra checks, just set the witness and then
266261 // validate it.
267- vOut . Asset .PrevWitnesses [0 ].TxWitness = p .ChallengeWitness
262+ proofAsset .PrevWitnesses [0 ].TxWitness = p .ChallengeWitness
268263
269264 prevAssets := commitment.InputSet {
270- vIn . PrevID : vIn . Asset () ,
265+ prevId : ownedAsset ,
271266 }
272- engine , err := vm .New (vOut . Asset , nil , prevAssets )
267+ engine , err := vm .New (proofAsset , nil , prevAssets )
273268 if err != nil {
274269 return false , err
275270 }
276271
277272 return p .Asset .HasSplitCommitmentWitness (), engine .Execute ()
278273}
279274
275+ // CreateOwnershipProofAsset creates a virtual asset that can be used to prove
276+ // ownership of an asset. The virtual asset is created by spending the full
277+ // asset into a NUMS key.
278+ func CreateOwnershipProofAsset (
279+ ownedAsset * asset.Asset ) (asset.PrevID , * asset.Asset ) {
280+
281+ // We create the ownership proof by creating a virtual input and output
282+ // that spends the full asset into a NUMS key. But in order to prevent
283+ // that witness to be used in an actual state transition by a malicious
284+ // actor, we create the signature over an empty outpoint. This means the
285+ // witness is fully valid, but a full transition proof can never be
286+ // created, as the previous outpoint would not match the one that
287+ // actually goes on chain.
288+ //
289+ // TODO(guggero): Revisit this proof once we support pocket universes.
290+ emptyOutPoint := wire.OutPoint {}
291+ prevId := asset.PrevID {
292+ ID : ownedAsset .ID (),
293+ OutPoint : emptyOutPoint ,
294+ ScriptKey : asset .ToSerialized (
295+ ownedAsset .ScriptKey .PubKey ,
296+ ),
297+ }
298+
299+ outputAsset := ownedAsset .Copy ()
300+ outputAsset .ScriptKey = asset .NUMSScriptKey
301+ outputAsset .PrevWitnesses = []asset.Witness {{
302+ PrevID : & prevId ,
303+ }}
304+
305+ return prevId , outputAsset
306+ }
307+
280308// verifyGenesisReveal checks that the genesis reveal present in the proof at
281309// minting validates against the asset ID and proof details.
282310func (p * Proof ) verifyGenesisReveal () error {
0 commit comments