Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Taproot address format #361

Closed
EricDLee-sz opened this issue May 15, 2023 · 9 comments
Closed

Taproot address format #361

EricDLee-sz opened this issue May 15, 2023 · 9 comments
Labels
🤔 question Further information is requested

Comments

@EricDLee-sz
Copy link

Hey bro, Im excited about using your lib to generate Taproot address and It did work for my case.

But as I reading Vectors from bip86 https://github.com/bitcoin/bips/blob/master/bip-0086.mediawiki I found that the output address is not equal to the expected one, could you help to advice?

mnemonic = abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
rootpriv = xprv9s21ZrQH143K3GJpoapnV8SFfukcVBSfeCficPSGfubmSFDxo1kuHnLisriDvSnRRuL2Qrg5ggqHKNVpxR86QEC8w35uxmGoggxtQTPvfUu
rootpub  = xpub661MyMwAqRbcFkPHucMnrGNzDwb6teAX1RbKQmqtEF8kK3Z7LZ59qafCjB9eCRLiTVG3uxBxgKvRgbubRhqSKXnGGb1aoaqLrpMBDrVxga8

// Account 0, root = m/86'/0'/0'
xprv = xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk
xpub = xpub6BgBgsespWvERF3LHQu6CnqdvfEvtMcQjYrcRzx53QJjSxarj2afYWcLteoGVky7D3UKDP9QyrLprQ3VCECoY49yfdDEHGCtMMj92pReUsQ

// Account 0, first receiving address = m/86'/0'/0'/0/0
xprv         = xprvA449goEeU9okwCzzZaxiy475EQGQzBkc65su82nXEvcwzfSskb2hAt2WymrjyRL6kpbVTGL3cKtp9herYXSjjQ1j4stsXXiRF7kXkCacK3T
xpub         = xpub6H3W6JmYJXN49h5TfcVjLC3onS6uPeUTTJoVvRC8oG9vsTn2J8LwigLzq5tHbrwAzH9DGo6ThGUdWsqce8dGfwHVBxSbixjDADGGdzF7t2B
internal_key = cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115
output_key   = a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c
scriptPubKey = 5120a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c
address      = bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr

My output is bc1qxr25l5xagg9xuhudxcj0tu6g9jhr2rme6hc82wl4hmhectv34u7qpnecln

@csjones
Copy link
Contributor

csjones commented May 15, 2023

Hey @EricDLee-sz 👋

Would you mind sharing the code used to generate your output? I can't get a sense of what's going wrong with just test vectors.

@EricDLee-sz
Copy link
Author

Absolutely, here

let privateKeyBytes = try! "4604b4b710fe91f584fff084e1a9159fe4f8408fff380596a604948474ce4fa3".bytes
let privateKey = try! secp256k1.Signing.PrivateKey(dataRepresentation: privateKeyBytes)
let pub = privateKey.publicKey

let coder = SegwitAddrCoder(bech32m: true)
let add = coder.encode(hrp: "bc", version: 1, program: pub.dataRepresentation)

Noted that I have drag the Bech32m from another of your repo too.

Let say if we want to verify the test vectors by using this secp256k1, what can I do to generate target bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr?

BTW I have tried to use secp256k1.Schnorr.PrivateKey(dataRepresentation: privateKeyBytes) as well, by seems no available publicKey can be use from Schnorr.Privatekey

@csjones
Copy link
Contributor

csjones commented May 15, 2023

Thanks for the additional info. Maybe there is more of your implementation missing because based on my understanding, the private key should actually be 41F41D69260DF4CF277826A9B65A3717E4EEDDBEEDF637F212CA096576479361 which derives the internal_key from the test vector. What's your derivation path logic? Also, how are you handling spending conditions that do not require a script path?

let privateKeyBytes = try! "41F41D69260DF4CF277826A9B65A3717E4EEDDBEEDF637F212CA096576479361".bytes
let privateKey = try! secp256k1.Schnorr.PrivateKey(dataRepresentation: privateKeyBytes)
let pub = privateKey.xonly // cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115

@EricDLee-sz
Copy link
Author

Thank you for you guide, yes, you are right, I got the wrong private key last time and able to generate 41F41D69260DF4CF277826A9B65A3717E4EEDDBEEDF637F212CA096576479361 by input the correct path m/86'/0'/0'/0/0.

But seems I still need some steps to reach the final Bech32m encode address and I have no clues about that.

Should I use Tweak as well?

@EricDLee-sz
Copy link
Author

Here is my correction, the lengh of the output is equal to bc1p5cyxnuxmeuwuvkwfem96lqzszd02n6xdcjrs20cac6yqjjwudpxqkedrcr
what do I missed?

let privateKeyBytes = try! "41f41d69260df4cf277826a9b65a3717e4eeddbeedf637f212ca096576479361".bytes
let privateKey = try! secp256k1.Schnorr.PrivateKey(dataRepresentation: privateKeyBytes)
let internalPub = privateKey.xonly

let coder = SegwitAddrCoder(bech32m: true)
let add = coder.encode(hrp: "bc", version: 1, program: Data(internalPub.bytes))
//bc1pej9yh3jd39aam30mctm8paaghg9nsemezpk0zg3udlza0nt0cy2sqvps98

@csjones
Copy link
Contributor

csjones commented May 16, 2023

Yep! Tweaking is required for BIP86 to get the output_key and this is the key that you'll want to encode using Bech32.

Updated code:

let privateKeyBytes = try! "41F41D69260DF4CF277826A9B65A3717E4EEDDBEEDF637F212CA096576479361".bytes
let privateKey = try! secp256k1.Schnorr.PrivateKey(dataRepresentation: privateKeyBytes)
let internalKey = privateKey.xonly // cc8a4bc64d897bddc5fbc2f670f7a8ba0b386779106cf1223c6fc5d7cd6fc115

let tweakHash = try! SHA256.taggedHash(
    tag: "TapTweak".data(using: .utf8)!,
    data: Data(internalKey.bytes)
)

let outputKey = try! internalKey.add(tweakHash.bytes) // a60869f0dbcf1dc659c9cecbaf8050135ea9e8cdc487053f1dc6880949dc684c

@csjones csjones added the 🤔 question Further information is requested label May 16, 2023
@EricDLee-sz
Copy link
Author

Thank you very much for the fast update, I can finally generate taproot address and I can see you also update unit test already.

Cheer~

@EricDLee-sz
Copy link
Author

One more tiny question, is that TapTweak a static string need to be there for every single tweak action? If that so we can turn it into enum

@csjones
Copy link
Contributor

csjones commented May 19, 2023

Glad to help! No, the TapTweak string is not used for every single tweak action. Other tags exist for tapscript. BIP340 states Tagged Hashes ...are used for multiple purposes in the specification below and in Bitcoin in general.

This swift package is open to improvements. Ideally, we'd want to maintain the API flexibility that libsecp256k1 already provides. I'm not sure an enum for specific tags used in BIPs 86, 340, 341 (or others) is the best fit for this package when the enum would be better served in a concrete implementations of BIP86.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🤔 question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants