@@ -93,10 +93,10 @@ const (
9393type EncodeType uint8
9494
9595const (
96- // Encode normal is the normal encoding type for an asset.
96+ // EncodeNormal normal is the normal encoding type for an asset.
9797 EncodeNormal EncodeType = iota
9898
99- // EncodeSegwit denotes that the witness vector field is not be be
99+ // EncodeSegwit denotes that the witness vector field is not to be
100100 // encoded.
101101 EncodeSegwit
102102)
@@ -247,6 +247,124 @@ func DecodeGenesis(r io.Reader) (Genesis, error) {
247247 return gen , err
248248}
249249
250+ var (
251+ // ErrUnwrapAssetID is an error type which is returned when an asset ID
252+ // cannot be unwrapped from a specifier.
253+ ErrUnwrapAssetID = errors .New ("unable to unwrap asset ID" )
254+ )
255+
256+ // Specifier is a type that can be used to specify an asset by its ID, its asset
257+ // group public key, or both.
258+ type Specifier struct {
259+ // id is the asset ID.
260+ id fn.Option [ID ]
261+
262+ // groupKey is the asset group public key.
263+ groupKey fn.Option [btcec.PublicKey ]
264+ }
265+
266+ // NewSpecifierOptionalGroupPubKey creates a new specifier that specifies an
267+ // asset by its ID and an optional group public key.
268+ func NewSpecifierOptionalGroupPubKey (id ID ,
269+ groupPubKey * btcec.PublicKey ) Specifier {
270+
271+ s := Specifier {
272+ id : fn .Some (id ),
273+ }
274+
275+ if groupPubKey != nil {
276+ s .groupKey = fn .Some (* groupPubKey )
277+ }
278+
279+ return s
280+ }
281+
282+ // NewSpecifierOptionalGroupKey creates a new specifier that specifies an
283+ // asset by its ID and an optional group key.
284+ func NewSpecifierOptionalGroupKey (id ID , groupKey * GroupKey ) Specifier {
285+ s := Specifier {
286+ id : fn .Some (id ),
287+ }
288+
289+ if groupKey != nil {
290+ s .groupKey = fn .Some (groupKey .GroupPubKey )
291+ }
292+
293+ return s
294+ }
295+
296+ // NewSpecifierFromId creates a new specifier that specifies an asset by its ID.
297+ func NewSpecifierFromId (id ID ) Specifier {
298+ return Specifier {
299+ id : fn .Some (id ),
300+ }
301+ }
302+
303+ // NewSpecifierFromGroupKey creates a new specifier that specifies an asset by
304+ // its group public key.
305+ func NewSpecifierFromGroupKey (groupPubKey btcec.PublicKey ) Specifier {
306+ return Specifier {
307+ groupKey : fn .Some (groupPubKey ),
308+ }
309+ }
310+
311+ // AsBytes returns the asset ID and group public key as byte slices.
312+ func (s * Specifier ) AsBytes () ([]byte , []byte ) {
313+ var assetIDBytes , groupKeyBytes []byte
314+
315+ s .WhenGroupPubKey (func (groupKey btcec.PublicKey ) {
316+ groupKeyBytes = groupKey .SerializeCompressed ()
317+ })
318+
319+ s .WhenId (func (id ID ) {
320+ assetIDBytes = id [:]
321+ })
322+
323+ return assetIDBytes , groupKeyBytes
324+ }
325+
326+ // HasId returns true if the asset ID field is specified.
327+ func (s * Specifier ) HasId () bool {
328+ return s .id .IsSome ()
329+ }
330+
331+ // HasGroupPubKey returns true if the asset group public key field is specified.
332+ func (s * Specifier ) HasGroupPubKey () bool {
333+ return s .groupKey .IsSome ()
334+ }
335+
336+ // WhenId executes the given function if the ID field is specified.
337+ func (s * Specifier ) WhenId (f func (ID )) {
338+ s .id .WhenSome (f )
339+ }
340+
341+ // WhenGroupPubKey executes the given function if asset group public key field
342+ // is specified.
343+ func (s * Specifier ) WhenGroupPubKey (f func (btcec.PublicKey )) {
344+ s .groupKey .WhenSome (f )
345+ }
346+
347+ // UnwrapIdOrErr unwraps the ID field or returns an error if it is not
348+ // specified.
349+ func (s * Specifier ) UnwrapIdOrErr () (ID , error ) {
350+ id := s .id .UnwrapToPtr ()
351+ if id == nil {
352+ return ID {}, ErrUnwrapAssetID
353+ }
354+
355+ return * id , nil
356+ }
357+
358+ // UnwrapIdToPtr unwraps the ID field to a pointer.
359+ func (s * Specifier ) UnwrapIdToPtr () * ID {
360+ return s .id .UnwrapToPtr ()
361+ }
362+
363+ // UnwrapGroupKeyToPtr unwraps the asset group public key field to a pointer.
364+ func (s * Specifier ) UnwrapGroupKeyToPtr () * btcec.PublicKey {
365+ return s .groupKey .UnwrapToPtr ()
366+ }
367+
250368// Type denotes the asset types supported by the Taproot Asset protocol.
251369type Type uint8
252370
@@ -1434,23 +1552,38 @@ func New(genesis Genesis, amount, locktime, relativeLocktime uint64,
14341552}
14351553
14361554// TapCommitmentKey is the key that maps to the root commitment for a specific
1437- // asset group within a TapCommitment.
1555+ // asset within a TapCommitment.
14381556//
14391557// NOTE: This function is also used outside the asset package.
1440- func TapCommitmentKey (assetID ID , groupKey * btcec.PublicKey ) [32 ]byte {
1441- if groupKey == nil {
1442- return assetID
1558+ func TapCommitmentKey (assetSpecifier Specifier ) [32 ]byte {
1559+ var commitmentKey [32 ]byte
1560+
1561+ switch {
1562+ case assetSpecifier .HasGroupPubKey ():
1563+ assetSpecifier .WhenGroupPubKey (func (pubKey btcec.PublicKey ) {
1564+ serializedPubKey := schnorr .SerializePubKey (& pubKey )
1565+ commitmentKey = sha256 .Sum256 (serializedPubKey )
1566+ })
1567+
1568+ case assetSpecifier .HasId ():
1569+ assetSpecifier .WhenId (func (id ID ) {
1570+ commitmentKey = id
1571+ })
1572+
1573+ default :
1574+ // We should never reach this point as the asset specifier
1575+ // should always have either a group public key, an asset ID, or
1576+ // both.
1577+ panic ("invalid asset specifier" )
14431578 }
1444- return sha256 .Sum256 (schnorr .SerializePubKey (groupKey ))
1579+
1580+ return commitmentKey
14451581}
14461582
14471583// TapCommitmentKey is the key that maps to the root commitment for a specific
14481584// asset group within a TapCommitment.
14491585func (a * Asset ) TapCommitmentKey () [32 ]byte {
1450- if a .GroupKey == nil {
1451- return TapCommitmentKey (a .Genesis .ID (), nil )
1452- }
1453- return TapCommitmentKey (a .Genesis .ID (), & a .GroupKey .GroupPubKey )
1586+ return TapCommitmentKey (a .Specifier ())
14541587}
14551588
14561589// AssetCommitmentKey returns a key which can be used to locate an
@@ -1893,6 +2026,12 @@ func (a *Asset) Leaf() (*mssmt.LeafNode, error) {
18932026 return mssmt .NewLeafNode (buf .Bytes (), a .Amount ), nil
18942027}
18952028
2029+ // Specifier returns the asset's specifier.
2030+ func (a * Asset ) Specifier () Specifier {
2031+ id := a .Genesis .ID ()
2032+ return NewSpecifierOptionalGroupKey (id , a .GroupKey )
2033+ }
2034+
18962035// Validate ensures that an asset is valid.
18972036func (a * Asset ) Validate () error {
18982037 // TODO(ffranr): Add validation check for remaining fields.
0 commit comments