<p>After looking into the source code for the Electrum Wallet a bit further I was able to come up with a working implementation in JavaScript.</p>

<p>The problem I described in my question was that the <code>long_user_id</code> is 32 bytes while you only need 4 bytes to derive a child key. It turns out that the third xpub is actually not a child of the hard-coded signing xpub, but rather a root key derived from that signing key (i.e. it has a completely different chain code and its index is <code>0</code>).</p>

<p>Here's the function I wrote which takes the two wallet xpubs (found under <code>x1/</code> and <code>x2/</code> in the wallet / keystore file) and the hard-coded xpub from Trustedcoin and derives the third xpub.</p>

<pre><code>import HDKey from 'hdkey';
import crypto from 'crypto';
import secp256k1 from 'secp256k1';

function getCosignerXPub(xpub_x1, xpub_x2){
    const signing_xpub = "xpub661MyMwAqRbcGnMkaTx2594P9EDuiEqMq25PM2aeG6UmwzaohgA6uDmNsvSUV8ubqwA3Wpste1hg69XHgjUuCD5HLcEp2QPzyV1HMrPppsL";

    const xpubs = [xpub_x1, xpub_x2].sort().join("");
    const long_user_id = new Buffer(sha256(xpubs), 'hex');

    const hdkey = HDKey.fromExtendedKey(signing_xpub);

    const data = Buffer.concat([hdkey.publicKey, long_user_id]);

    const I = crypto.createHmac('sha512', hdkey.chainCode).update(data).digest();

    const IL = I.slice(0, 32);
    const IR = I.slice(32);

    const hd = new HDKey(hdkey.versions);

    hd.publicKey = secp256k1.publicKeyTweakAdd(hdkey.publicKey, IL, true);
    hd.chainCode = IR;

    return hd.publicExtendedKey;
}
</code></pre>

CC BY-SA 3.0
2017-12-14T17:41:48.253Z
2017-12-14T17:41:48.253Z
Tadej Gašparovič
<p>I'm working on a project which requires me to take an Electrum mnemonic, determine its type and derive the corresponding addresses for that wallet.</p>

<p>I found lots of information on how to determine the mnemonic type and covert it into the master seed, but I'm struggling to understand how addresses for the 2FA wallet are derived. To be more exact, I was able to derive both extended keypairs (<code>x1/</code> and <code>x2/</code> in the wallet file), but I can't seem to be able to derive the third xpub (<code>x3/</code> in the wallet file).</p>

<p>I've looked through the source code and it seems this key is derived by combining both xpub keys (the keys should be <strong>ORDERED</strong>) that can be derived from the master seed (<code>x1/</code> and <code>x2/</code>), hashing them using <code>SHA-256</code> and using that as the index when deriving the third xpub. A hard-coded xpub is used as the root.</p>

<p>I'm having trouble understanding / implementing this because the <code>SHA-256</code> algorithm returns 32 bytes of data and the child index has to be 4 bytes long (as per the <code>BIP32</code> specification).</p>

<p>Here's the code from Electrum that handles this.</p>

<pre><code>def get_user_id(storage):
    def make_long_id(xpub_hot, xpub_cold):
        return bitcoin.sha256(''.join(sorted([xpub_hot, xpub_cold])))
    xpub1 = storage.get('x1/')['xpub']
    xpub2 = storage.get('x2/')['xpub']
    long_id = make_long_id(xpub1, xpub2)
    short_id = hashlib.sha256(long_id).hexdigest()
    return long_id, short_id

def make_xpub(xpub, s):
    version, _, _, _, c, cK = deserialize_xpub(xpub)
    cK2, c2 = bitcoin._CKD_pub(cK, c, s)
    return bitcoin.serialize_xpub(version, c2, cK2)
</code></pre>

<p>The functions are then called like this:</p>

<pre><code>xpub1 = wizard.storage.get('x1/')['xpub']
xpub2 = wizard.storage.get('x2/')['xpub']
# Generate third key deterministically.
long_user_id, short_id = get_user_id(wizard.storage)
xpub3 = make_xpub(signing_xpub, long_user_id)
</code></pre>

<p>The <code>long_user_id</code> is 32 bytes long since it's the result of the <code>SHA-256</code> function and it's then being used to call the <code>make_xpub()</code> function which is supposed to take in 4 bytes of data as the child index.</p>

<p>What am I missing here? Any input is appreciated.</p>

<electrum><public-key><bip32-hd-wallets><xpub>
Electrum 2FA Wallet - Deriving the Third XPub
Tadej Gašparovič
# Electrum 2FA Wallet - Deriving the Third XPub

(Asked by: username_0 on 2017-12-13)

I'm working on a project which requires me to take an Electrum mnemonic, determine its type and derive the corresponding addresses for that wallet.

I found lots of information on how to determine the mnemonic type and covert it into the master seed, but I'm struggling to understand how addresses for the 2FA wallet are derived. To be more exact, I was able to derive both extended keypairs (`x1/` and `x2/` in the wallet file), but I can't seem to be able to derive the third xpub (`x3/` in the wallet file).

I've looked through the source code and it seems this key is derived by combining both xpub keys (the keys should be **ORDERED**) that can be derived from the master seed (`x1/` and `x2/`), hashing them using `SHA-256` and using that as the index when deriving the third xpub. A hard-coded xpub is used as the root.

I'm having trouble understanding / implementing this because the `SHA-256` algorithm returns 32 bytes of data and the child index has to be 4 bytes long (as per the `BIP32` specification).

Here's the code from Electrum that handles this.

```
def get_user_id(storage):
    def make_long_id(xpub_hot, xpub_cold):
        return bitcoin.sha256(''.join(sorted([xpub_hot, xpub_cold])))
    xpub1 = storage.get('x1/')['xpub']
    xpub2 = storage.get('x2/')['xpub']
    long_id = make_long_id(xpub1, xpub2)
    short_id = hashlib.sha256(long_id).hexdigest()
    return long_id, short_id

def make_xpub(xpub, s):
    version, _, _, _, c, cK = deserialize_xpub(xpub)
    cK2, c2 = bitcoin._CKD_pub(cK, c, s)
    return bitcoin.serialize_xpub(version, c2, cK2)

```

The functions are then called like this:

```
xpub1 = wizard.storage.get('x1/')['xpub']
xpub2 = wizard.storage.get('x2/')['xpub']
# Generate third key deterministically.
long_user_id, short_id = get_user_id(wizard.storage)
xpub3 = make_xpub(signing_xpub, long_user_id)

```

The `long_user_id` is 32 bytes long since it's the result of the `SHA-256` function and it's then being used to call the `make_xpub()` function which is supposed to take in 4 bytes of data as the child index.

What am I missing here? Any input is appreciated.

**Tags:** electrum, public-key, bip32-hd-wallets, xpub


---

## 1 answers

### Answer by username_0 on 2017-12-14. Score: 1 | Accepted answer

After looking into the source code for the Electrum Wallet a bit further I was able to come up with a working implementation in JavaScript.

The problem I described in my question was that the `long_user_id` is 32 bytes while you only need 4 bytes to derive a child key. It turns out that the third xpub is actually not a child of the hard-coded signing xpub, but rather a root key derived from that signing key (i.e. it has a completely different chain code and its index is `0`).

Here's the function I wrote which takes the two wallet xpubs (found under `x1/` and `x2/` in the wallet / keystore file) and the hard-coded xpub from Trustedcoin and derives the third xpub.

```
import HDKey from 'hdkey';
import crypto from 'crypto';
import secp256k1 from 'secp256k1';

function getCosignerXPub(xpub_x1, xpub_x2){
    const signing_xpub = "xpub661MyMwAqRbcGnMkaTx2594P9EDuiEqMq25PM2aeG6UmwzaohgA6uDmNsvSUV8ubqwA3Wpste1hg69XHgjUuCD5HLcEp2QPzyV1HMrPppsL";

    const xpubs = [xpub_x1, xpub_x2].sort().join("");
    const long_user_id = new Buffer(sha256(xpubs), 'hex');

    const hdkey = HDKey.fromExtendedKey(signing_xpub);

    const data = Buffer.concat([hdkey.publicKey, long_user_id]);

    const I = crypto.createHmac('sha512', hdkey.chainCode).update(data).digest();

    const IL = I.slice(0, 32);
    const IR = I.slice(32);

    const hd = new HDKey(hdkey.versions);

    hd.publicKey = secp256k1.publicKeyTweakAdd(hdkey.publicKey, IL, true);
    hd.chainCode = IR;

    return hd.publicExtendedKey;
}

```


---

