@@ -622,7 +622,7 @@ func (k *PrivateKey) ToWif(uncompressed bool) (*string, error) {
622622//
623623// If both parameters are nil generates a random wallet
624624func CreateNewWallet (raw * big.Int , wif * string ) (* Wallet , error ) {
625- var nestedAddress , nativeAddress string
625+ var nestedAddress , nativeAddress , taprootAddress string
626626 privKey , err := NewPrivateKey (raw , wif )
627627 if err != nil {
628628 return nil , err
@@ -636,13 +636,15 @@ func CreateNewWallet(raw *big.Int, wif *string) (*Wallet, error) {
636636 if ! privKey .Uncompressed {
637637 nestedAddress = createNestedSegwit (pubKey )
638638 nativeAddress = createNativeSegwit (pubKey )
639+ taprootAddress = createTaproot (createTweakedPubKey (rawPubKey ))
639640 }
640641 return & Wallet {PrivKey : privKey ,
641642 RawPubKey : rawPubKey ,
642643 PubKey : hex .EncodeToString (pubKey ),
643644 Legacy : legacyAddress ,
644645 Nested : nestedAddress ,
645- Native : nativeAddress }, nil
646+ Native : nativeAddress ,
647+ Taproot : taprootAddress }, nil
646648}
647649
648650type Wallet struct {
@@ -652,6 +654,7 @@ type Wallet struct {
652654 Legacy string
653655 Nested string
654656 Native string
657+ Taproot string
655658}
656659
657660// String returns a formatted string representation of the Wallet.
@@ -670,7 +673,8 @@ Public Key (HEX Compressed): %s
670673Legacy Address: %s
671674Nested SegWit Address: %s
672675Native SegWit Address: %s
673- ` , w .PrivKey .Raw , * w .PrivKey .Wif , w .RawPubKey , w .PubKey , w .Legacy , w .Nested , w .Native )
676+ Taproot Address: %s
677+ ` , w .PrivKey .Raw , * w .PrivKey .Wif , w .RawPubKey , w .PubKey , w .Legacy , w .Nested , w .Native , w .Taproot )
674678}
675679
676680// NewInt converts a hexadecimal string to a big.Int pointer.
@@ -832,6 +836,32 @@ func createPubKey(rawPubKey *Point, uncompressed bool) []byte {
832836 return buf [:33 ]
833837}
834838
839+ func calculateTweak (rawPubKey * Point ) * big.Int {
840+ var tweak big.Int
841+ buf := make ([]byte , 32 )
842+ h1 := sha256 .New ()
843+ h2 := sha256 .New ()
844+ h1 .Write ([]byte ("TapTweak" ))
845+ h2 .Write (joinBytes ([][]byte {h1 .Sum (nil ), h1 .Sum (nil ), rawPubKey .X .FillBytes (buf )}... ))
846+ tweak .SetBytes (h2 .Sum (nil ))
847+ return & tweak
848+ }
849+
850+ func createTweakedPubKey (rawPubKey * Point ) []byte {
851+ var q JacobianPoint
852+ tweak := calculateTweak (rawPubKey )
853+ p := & Point {X : new (big.Int ).Set (rawPubKey .X ), Y : new (big.Int ).Set (rawPubKey .Y )}
854+ if IsOdd (p .Y ) {
855+ p .Y .Sub (Secp256k1 .PCurve , p .Y )
856+ }
857+ q .Add (p .ToJacobian (), q .Mul (tweak , nil ))
858+ qa := q .ToAffine ()
859+ if IsOdd (qa .Y ) {
860+ qa .Y .Sub (Secp256k1 .PCurve , qa .Y )
861+ }
862+ return createPubKey (qa , false )[1 :]
863+ }
864+
835865// checkSum calculates the checksum of the input byte slice using DoubleSHA256 and returns the first 4 bytes.
836866//
837867// Parameters:
@@ -893,6 +923,21 @@ func createNativeSegwit(pubKey []byte) string {
893923 return addr
894924}
895925
926+ func createTaproot (pubKey []byte ) string {
927+ converted , err := bech32 .ConvertBits (pubKey , 8 , 5 , true )
928+ if err != nil {
929+ panic (err )
930+ }
931+ combined := make ([]byte , len (converted )+ 1 )
932+ combined [0 ] = byte (1 )
933+ copy (combined [1 :], converted )
934+ addr , err := bech32 .EncodeM ("bc" , combined )
935+ if err != nil {
936+ panic (err )
937+ }
938+ return addr
939+ }
940+
896941// varInt generates a variable-length integer in bytes based on the input length.
897942//
898943// Parameters:
0 commit comments