<p>The steps for computing a BIP350 (bech32m) address for a P2TR (pay to taproot) output spendable with a given private key depend on what you want that output to do.</p>
<p>The most straightforward way (but not recommended, see further) is the following:</p>
<ul>
<li>Compute the public key <em>P = privkey * G</em>.</li>
<li>Let <em>Pb</em> be the serialization of <em>P</em> in x-only form: that's just the 32-byte big endian encoding of its X coordinate. Equivalently, it's the compressed public key encoding with the first byte removed.</li>
<li>The address is <em>bech32m_encode(payload=Pb, version=1)</em>. See <a href="https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki" rel="nofollow noreferrer">BIP350</a> for details.</li>
</ul>
<p>Spending such outputs is then done by providing a <a href="https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki" rel="nofollow noreferrer">BIP340</a> signature on that public key, using the message hash mechanism described in <a href="https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#taproot-key-path-spending-signature-validation" rel="nofollow noreferrer">BIP341</a>.</p>
<p>However, P2TR outputs are effectively a combination of a pay-to-key and a pay-to-script: each output can be spent for either by signing the output directly, or by revealing how the output commits to a script, and then satisfying that script. Even if you don't want any scripts in there, <a href="https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs" rel="nofollow noreferrer">BIP341</a> still recommends using a &quot;dummy&quot; script. For simple single-key setups this is unlikely to matter, but it may matter for more advanced cases (see footnote 23 in BIP341), and thus the suggested standard is to always do this. In this case, the procedure would be:</p>
<ul>
<li>Compute the public key <em>P = privkey * G</em>.</li>
<li>Let <em>Pb</em> be the serialization of <em>P</em> in x-only form.</li>
<li>Compute the tweak <em>t = SHA256(SHA256(&quot;TapTweak&quot;) || SHA256(&quot;TapTweak&quot;) || Pb)</em>, interpreted as 32-byte big endian encoded integer.</li>
<li>Compute the tweaked public key <em>Q = P + (t * G)</em>.</li>
<li>Let <em>Qb</em> be the serialization of <em>Q</em> in x-only form.</li>
<li>The address is <em>bech32m_encode(payload=Qb, version=1)</em>.</li>
</ul>
<p>Signing now requires a BIP340 signature with <em>(privkey + t)</em> as private key.</p>

CC BY-SA 4.0
2022-12-15T16:51:39.787Z
Thanks. I just re-edited my question. Is the tweak step mandatory?
Simon L
CC BY-SA 4.0
2022-12-15T17:04:51.667Z
No, it is not. As I pointed out, it's the standard approach as it is beneficial in some more advanced scenarios, but it is unlikely to matter for simple single-key scenarios. I strongly recommand you use it though, as it avoids needing to understand when it might matter, and will be more interoperable with other software/wallets that do the same. See footnote 23 in BIP341 for details.
Pieter Wuille
CC BY-SA 4.0
2022-12-15T16:07:40.497Z
2022-12-15T17:06:02.150Z
2022-12-15T17:06:02.150Z
Pieter Wuille
<p>I followed that algorithm step by step and used Samourai Wallet to sweep the final address and it don't worked.</p>
<p>I checked by another script that I already have running and tested the sweep with Samourai with success and there is a difference in this step:</p>
<ul>
<li>Compute the tweaked public key Q = P + (t * G).</li>
</ul>
<p>The difference is in the P, the working script that I have running don't use the X and Y source coordinates of P, it uses only the X coordinate and a new one for Y that is calculated with:</p>
<p>math.liftX function</p>
<p>So this formula should be Q = P(xP,yliftx) + (t * G)</p>
<p>I don't know yet what liftX does, but is the only way of making it work for sweep the address with success in Samourai.</p>
<p>Can you pronounce about this?</p>
<p>It's very annoying some formula like this don't be correct or should I think that maybe Samourai Wallet use another method ?</p>

CC BY-SA 4.0
2023-09-04T00:43:50.517Z
2023-09-04T00:48:43.427Z
2023-09-04T00:48:43.427Z
cfstackman
<p>It is almost the same as doing a version 0 Bech32 encoding with a couple of differences. For all bech32(m) encodings, the data that gets encoded starts with one version byte and ends with 6 checksum bytes. As far as I know, these 7 bytes are the only differences.</p>
<p>The version byte changes from 0 to 1.</p>
<p>The checksum bytes are also determined differently. A function called <code>PolyMod</code> is called to produce the checksum. The result of this function is XORed with a constant. For the version 0 (Bech32) encoding, this constant is <code>1</code>. But for the version 1 (Bech32M) encoding, the constant is <code>0x2bc830a3</code>.</p>
<p>As far as I know, every other part of the process is the same. Writing a step-by-step is somewhat difficult because it depends on various parameters. If you don't mind wading through a bunch of C++ code (it actually isn't that much and is pretty straight forward), the exact algorithm is in the files <a href="https://github.com/bitcoin/bitcoin/blob/master/src/bech32.h" rel="nofollow noreferrer">bech32.h</a> and <a href="https://github.com/bitcoin/bitcoin/blob/master/src/bech32.cpp" rel="nofollow noreferrer">bech32.cpp</a>. The process of doing either a Bech32 or a Bech32M encoding would begin on line 357 in bech32.cpp, with a call to the <code>Encode</code> function.</p>

CC BY-SA 4.0
2022-12-15T16:10:02.560Z
This answer is correct, but only focuses on the difference between bech32 and bech32m. There are many more differences in other steps between the private key and the finding the data that goes into the address; see my own answer.
Pieter Wuille
CC BY-SA 4.0
2022-12-15T13:29:10.813Z
2022-12-15T13:29:10.813Z
Zephyrus
<p>The steps to convert a private key to a SegWit (version 0, bech32) address are roughly as follows:</p>
<pre><code>1.  public_key = Generator * private_key  (use the compressed version)
2.  public_key_hash = RIPEMD160(SHA256(public_key)))
3.  bech32_encode
</code></pre>
<p>For taproot address (version 2 witness), is the tweak mandatory or optional? Are the following calculations correct? (No tweak):</p>
<p>Suppose the private key is 1</p>
<pre><code>1. The corresponding 32-byte compressed key (x-only, without oddness indicator): 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798

2. Directly encode the above 32 bytes using the new modified bech32m encoding, and witness version 1:
    bech32m_encode(hrp='bc', witness_version=1, bytes.fromhex('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'))

result: bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0
</code></pre>
<p>Also, what the point of adding a tweak step? It doesn’t seem to improve any security by adding a number to privkey. Thanks.</p>

<taproot>
What are the steps to convert a private key to a taproot address?
Simon L
# What are the steps to convert a private key to a taproot address?

(Asked by: username_0 on 2022-12-15)

The steps to convert a private key to a SegWit (version 0, bech32) address are roughly as follows:

```
1.  public_key = Generator * private_key  (use the compressed version)
2.  public_key_hash = RIPEMD160(SHA256(public_key)))
3.  bech32_encode

```

For taproot address (version 2 witness), is the tweak mandatory or optional? Are the following calculations correct? (No tweak):

Suppose the private key is 1

```
1. The corresponding 32-byte compressed key (x-only, without oddness indicator): 79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798

2. Directly encode the above 32 bytes using the new modified bech32m encoding, and witness version 1:
    bech32m_encode(hrp='bc', witness_version=1, bytes.fromhex('79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798'))

result: bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0

```

Also, what the point of adding a tweak step? It doesn’t seem to improve any security by adding a number to privkey. Thanks.

**Tags:** taproot


---

## 3 answers

### Answer by username_1 on 2022-12-15. Score: 3

The steps for computing a BIP350 (bech32m) address for a P2TR (pay to taproot) output spendable with a given private key depend on what you want that output to do.

The most straightforward way (but not recommended, see further) is the following:

* Compute the public key *P = privkey \* G*.
* Let *Pb* be the serialization of *P* in x-only form: that's just the 32-byte big endian encoding of its X coordinate. Equivalently, it's the compressed public key encoding with the first byte removed.
* The address is *bech32m\_encode(payload=Pb, version=1)*. See [BIP350](https://github.com/bitcoin/bips/blob/master/bip-0350.mediawiki) for details.

Spending such outputs is then done by providing a [BIP340](https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki) signature on that public key, using the message hash mechanism described in [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#taproot-key-path-spending-signature-validation).

However, P2TR outputs are effectively a combination of a pay-to-key and a pay-to-script: each output can be spent for either by signing the output directly, or by revealing how the output commits to a script, and then satisfying that script. Even if you don't want any scripts in there, [BIP341](https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki#constructing-and-spending-taproot-outputs) still recommends using a "dummy" script. For simple single-key setups this is unlikely to matter, but it may matter for more advanced cases (see footnote 23 in BIP341), and thus the suggested standard is to always do this. In this case, the procedure would be:

* Compute the public key *P = privkey \* G*.
* Let *Pb* be the serialization of *P* in x-only form.
* Compute the tweak *t = SHA256(SHA256("TapTweak") || SHA256("TapTweak") || Pb)*, interpreted as 32-byte big endian encoded integer.
* Compute the tweaked public key *Q = P + (t \* G)*.
* Let *Qb* be the serialization of *Q* in x-only form.
* The address is *bech32m\_encode(payload=Qb, version=1)*.

Signing now requires a BIP340 signature with *(privkey + t)* as private key.

> **Comments:**
> **username_0**: Thanks. I just re-edited my question. Is the tweak step mandatory?  
> **username_1**: No, it is not. As I pointed out, it's the standard approach as it is beneficial in some more advanced scenarios, but it is unlikely to matter for simple single-key scenarios. I strongly recommand you use it though, as it avoids needing to understand when it might matter, and will be more interoperable with other software/wallets that do the same. See footnote 23 in BIP341 for details.  

---

### Answer by username_2 on 2023-09-04. Score: 0

I followed that algorithm step by step and used Samourai Wallet to sweep the final address and it don't worked.

I checked by another script that I already have running and tested the sweep with Samourai with success and there is a difference in this step:

* Compute the tweaked public key Q = P + (t \* G).

The difference is in the P, the working script that I have running don't use the X and Y source coordinates of P, it uses only the X coordinate and a new one for Y that is calculated with:

math.liftX function

So this formula should be Q = P(xP,yliftx) + (t \* G)

I don't know yet what liftX does, but is the only way of making it work for sweep the address with success in Samourai.

Can you pronounce about this?

It's very annoying some formula like this don't be correct or should I think that maybe Samourai Wallet use another method ?


---

### Answer by username_3 on 2022-12-15. Score: 0

It is almost the same as doing a version 0 Bech32 encoding with a couple of differences. For all bech32(m) encodings, the data that gets encoded starts with one version byte and ends with 6 checksum bytes. As far as I know, these 7 bytes are the only differences.

The version byte changes from 0 to 1.

The checksum bytes are also determined differently. A function called `PolyMod` is called to produce the checksum. The result of this function is XORed with a constant. For the version 0 (Bech32) encoding, this constant is `1`. But for the version 1 (Bech32M) encoding, the constant is `0x2bc830a3`.

As far as I know, every other part of the process is the same. Writing a step-by-step is somewhat difficult because it depends on various parameters. If you don't mind wading through a bunch of C++ code (it actually isn't that much and is pretty straight forward), the exact algorithm is in the files [bech32.h](https://github.com/bitcoin/bitcoin/blob/master/src/bech32.h) and [bech32.cpp](https://github.com/bitcoin/bitcoin/blob/master/src/bech32.cpp). The process of doing either a Bech32 or a Bech32M encoding would begin on line 357 in bech32.cpp, with a call to the `Encode` function.

> **Comments:**
> **username_1**: This answer is correct, but only focuses on the difference between bech32 and bech32m. There are many more differences in other steps between the private key and the finding the data that goes into the address; see my own answer.  

---

