@@ -679,3 +679,195 @@ func TestGroupKeyDerivationInvalidAsset(t *testing.T) {
679
679
require .NoError (t , err )
680
680
require .NotNil (t , groupKey )
681
681
}
682
+
683
+ // TestAssetIsGroupAnchor tests the GroupKey.IsGroupAnchor method with various
684
+ // test cases covering both positive and negative scenarios.
685
+ func TestAssetIsGroupAnchor (t * testing.T ) {
686
+ t .Parallel ()
687
+
688
+ // Generate a sample asset ID to use as the group anchor asset ID.
689
+ firstAssetID := RandID (t )
690
+
691
+ testCases := []struct {
692
+ name string
693
+
694
+ // groupKeyVersion indicates the version of the group key
695
+ // to be tested.
696
+ groupKeyVersion GroupKeyVersion
697
+
698
+ // customTapscriptRoot is an optional custom tapscript root
699
+ // that can be used for group key derivation.
700
+ customTapscriptRoot fn.Option [chainhash.Hash ]
701
+
702
+ // groupAnchorAssetID is the asset ID that the group key is
703
+ // derived from.
704
+ groupAnchorAssetID ID
705
+
706
+ // candidateAssetID is the asset ID being checked to determine
707
+ // whether it is the group anchor asset ID.
708
+ candidateAssetID ID
709
+
710
+ // expectedIsGroupAnchorRes indicates whether we expect the
711
+ // IsGroupAnchor method to return true or false for the
712
+ // candidate asset ID.
713
+ expectedIsGroupAnchorRes bool
714
+ }{{
715
+ name : "v0 group key matching group anchor asset" ,
716
+
717
+ groupKeyVersion : GroupKeyV0 ,
718
+ customTapscriptRoot : fn .None [chainhash.Hash ](),
719
+ groupAnchorAssetID : firstAssetID ,
720
+ candidateAssetID : firstAssetID ,
721
+ expectedIsGroupAnchorRes : true ,
722
+ }, {
723
+ name : "v0 group key non-matching asset" ,
724
+
725
+ groupKeyVersion : GroupKeyV0 ,
726
+ customTapscriptRoot : fn .None [chainhash.Hash ](),
727
+ groupAnchorAssetID : RandID (t ),
728
+ candidateAssetID : RandID (t ),
729
+ expectedIsGroupAnchorRes : false ,
730
+ }, {
731
+ name : "v1 group key matching group anchor asset" ,
732
+
733
+ groupKeyVersion : GroupKeyV1 ,
734
+ customTapscriptRoot : fn .None [chainhash.Hash ](),
735
+ groupAnchorAssetID : firstAssetID ,
736
+ candidateAssetID : firstAssetID ,
737
+ expectedIsGroupAnchorRes : true ,
738
+ }, {
739
+ name : "v1 group key non-matching asset" ,
740
+ groupKeyVersion : GroupKeyV1 ,
741
+ customTapscriptRoot : fn .None [chainhash.Hash ](),
742
+ groupAnchorAssetID : RandID (t ),
743
+ candidateAssetID : RandID (t ),
744
+ expectedIsGroupAnchorRes : false ,
745
+ }, {
746
+ name : "v1 group key with custom tapscript root matching " +
747
+ "group anchor" ,
748
+
749
+ groupKeyVersion : GroupKeyV1 ,
750
+ customTapscriptRoot : fn .Some (test .RandHash ()),
751
+ groupAnchorAssetID : firstAssetID ,
752
+ candidateAssetID : firstAssetID ,
753
+ expectedIsGroupAnchorRes : true ,
754
+ }, {
755
+ name : "v1 group key with custom tapscript root non-matching" ,
756
+
757
+ groupKeyVersion : GroupKeyV1 ,
758
+ customTapscriptRoot : fn .Some (test .RandHash ()),
759
+ groupAnchorAssetID : RandID (t ),
760
+ candidateAssetID : RandID (t ),
761
+ expectedIsGroupAnchorRes : false ,
762
+ }}
763
+
764
+ for idx := range testCases {
765
+ tc := testCases [idx ]
766
+
767
+ t .Run (tc .name , func (tt * testing.T ) {
768
+ tt .Parallel ()
769
+
770
+ // Create a taproot internal key for use in constructing
771
+ // the group key.
772
+ internalKey := test .RandPubKey (tt )
773
+
774
+ // Create the group key using the group anchor asset ID
775
+ // and other parameters (we don't use the candidate
776
+ // asset ID here, as it is only used for the
777
+ // IsGroupAnchor check).
778
+ var groupKey * GroupKey
779
+ switch tc .groupKeyVersion {
780
+ case GroupKeyV0 :
781
+ // For V0, we need to derive the group key using
782
+ // the genesis asset ID.
783
+ rawKey := ToSerialized (internalKey )
784
+ tapscriptRoot := test .RandBytes (32 )
785
+ gkr := NewGroupKeyRevealV0 (
786
+ rawKey , tapscriptRoot ,
787
+ )
788
+
789
+ groupPubKey , err := gkr .GroupPubKey (
790
+ tc .groupAnchorAssetID ,
791
+ )
792
+ require .NoError (tt , err )
793
+
794
+ groupKey = & GroupKey {
795
+ Version : GroupKeyV0 ,
796
+ RawKey : keychain.KeyDescriptor {
797
+ PubKey : internalKey ,
798
+ },
799
+ GroupPubKey : * groupPubKey ,
800
+ TapscriptRoot : tapscriptRoot ,
801
+ }
802
+
803
+ case GroupKeyV1 :
804
+ // For V1, we need to derive the group key using
805
+ // the group anchor asset ID.
806
+ gkr , err := NewGroupKeyRevealV1 (
807
+ PedersenVersion , * internalKey ,
808
+ tc .groupAnchorAssetID ,
809
+ tc .customTapscriptRoot ,
810
+ )
811
+ require .NoError (tt , err )
812
+
813
+ groupPubKey , err := gkr .GroupPubKey (
814
+ tc .groupAnchorAssetID ,
815
+ )
816
+ require .NoError (tt , err )
817
+
818
+ groupKey = & GroupKey {
819
+ Version : GroupKeyV1 ,
820
+ RawKey : keychain.KeyDescriptor {
821
+ PubKey : internalKey ,
822
+ },
823
+ GroupPubKey : * groupPubKey ,
824
+ TapscriptRoot : gkr .tapscript .root [:],
825
+
826
+ // nolint: lll
827
+ CustomTapscriptRoot : tc .customTapscriptRoot ,
828
+ }
829
+
830
+ default :
831
+ t .Fatalf ("unknown group key version: %d" ,
832
+ tc .groupKeyVersion )
833
+ }
834
+
835
+ // Call IsGroupAnchor with the candidate asset ID.
836
+ result , err := groupKey .IsGroupAnchor (
837
+ tc .candidateAssetID ,
838
+ )
839
+
840
+ // Verify the result matches expectations.
841
+ require .NoError (tt , err )
842
+ require .Equal (tt , tc .expectedIsGroupAnchorRes , result )
843
+
844
+ // Additional verification: if we're testing a matching
845
+ // case, verify that the same asset ID returns true and
846
+ // a different one returns false
847
+ if tc .expectedIsGroupAnchorRes {
848
+ // Test with the actual group anchor asset ID
849
+ // (should return true).
850
+ result , err := groupKey .IsGroupAnchor (
851
+ tc .groupAnchorAssetID ,
852
+ )
853
+ require .NoError (tt , err )
854
+ require .True (tt , result )
855
+
856
+ // Test with a different asset ID (should return
857
+ // false).
858
+ differentAssetID := RandID (t )
859
+ for differentAssetID == tc .groupAnchorAssetID {
860
+ // This case should be rare, but we fail
861
+ // explicitly if it occurs.
862
+ t .Fatal ("very unexpected asset ID " +
863
+ "match" )
864
+ }
865
+ result , err = groupKey .IsGroupAnchor (
866
+ differentAssetID ,
867
+ )
868
+ require .NoError (tt , err )
869
+ require .False (tt , result )
870
+ }
871
+ })
872
+ }
873
+ }
0 commit comments