dzham Yes, @dupe worked on the proposal as well and validated that the expected keys are generated on the Ledger: https://github.com/stellar/stellar-protocol/pull/63#issuecomment-343208163
Secret key seed from BIP39
I spent all day trying to figure this out... I am usng sjcl in JavaScript to somehow navigate this path from a bip39 seed (in hex) to derived m/44'/148' key but I am doing something wrong on the way cause that derived key output does not match test vector in sep-0005... I guess what I am confused about is how exactly you derive the path... the code in Go does not seem to align with what is described in slip-0010 and that may be due to the fact that I don't know Go Lang and/or I cannot read complicated mathematical notation describing the algorithm steps. Could someone help out and describe the intermediate steps in more details?
@zcc I get the part that I split my bip39 hex seed in two 32-byte secret key and chain code.... then my mind breaks down on what you said after that. Which one is the master key? Please help ? Thank you!
syntaxval The bitcoinjs project has some libraries you might be able to use, although I haven't used them myself so this is all going to be a guess ?
It sounds like you've got the mnemonic to seed bytes part figured out, so I'll focus on what comes next.
First, you'll need a HDNode created from those 64 bytes. bitcoinjs-lib
looks like it has a class that would work with this: https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/src/hdnode.js
However, for Stellar you'll need to use the hardcoded string "ed25519 seed" instead of "Bitcoin seed" when doing your initial sha512 hash, so you'll probably need to fork and modify their library.
They also have a bip39 library you could then use to derive the child nodes: https://github.com/bitcoinjs/bip32-utils
Hope that helps!
@zcc Thank you for trying to help me. OK so I modified bitcoinjs-lib and produced the "IL" and "IR" after the first HMAC-512 op in HDNode and the output is as follows:
IL: "5daf42e856561166e7788d292d5af4c0e3856a0e5dd815cf1f7146e64f87e775",
IR: "05294fe2430e60a3be665f5c6c44ad100d21d09ebcde853befaba92bdb788937"
which is exactly what I produce with my own code using sjcl lib. So everything up to this point should be correct.
I am following the test vectors specified in https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md
Now, (as far as I can read the Go code) I would need to feed the IR hash as chain code into another HMAC-512 with data=0x00 (representing 0 from derivation path) and again take first 32 bytes and feed it to StellarSdk.Keypair.fromRawSeed?? I already checked this scenario and the Stellar key does not match the one for m/44'/148/0'
Maybe the simplest thing would be to clarify how to get from this point (having IL/IR hashes) to producing the "m/44'/148' key: e0eec84fe165cd427cb7bc9b6cfdef0555aa1cb6f9043ff1fe986c3c8ddd22e3" (as described in https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md)
Thanks!
OK, I verified with python implementation too https://github.com/satoshilabs/slips/blob/master/slip-0010/testvectors.py and again the master private key hash for BIP39 seed (e4a5a632e70943ae7f07659df1332160937fad82587216a4c64315a0fb39497ee4a01f76ddab4cba68147977f3a147b6ad584c41808e8238a07f6cc4b582f186) is:
5daf42e856561166e7788d292d5af4c0e3856a0e5dd815cf1f7146e64f87e775
and NOT e0eec84fe165cd427cb7bc9b6cfdef0555aa1cb6f9043ff1fe986c3c8ddd22e3 (as specified in Test 1 of https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0005.md)
Again: bitcoinjs-lib, testvectors.py and my implementation return same result.
testvectors.py output:
Test vector 1 for ed25519
Seed (hex): e4a5a632e70943ae7f07659df1332160937fad82587216a4c64315a0fb39497ee4a01f76ddab4cba68147977f3a147b6ad584c41808e8238a07f6cc4b582f186
Chain m
fpr: 00000000
chain: 05294fe2430e60a3be665f5c6c44ad100d21d09ebcde853befaba92bdb788937
prv: 5daf42e856561166e7788d292d5af4c0e3856a0e5dd815cf1f7146e64f87e775
* pub: 0087c9725f4f05b37d6b054e0531a6a86f17723cd19fbbdc25687482811d855322
- Edited
I would need to feed the IR hash as chain code into another HMAC-512 with data=0x00 (representing 0 from derivation path) and again take first 32 bytes and feed it to StellarSdk.Keypair.fromRawSeed
I think this may be where things are going wrong, that first 0x00
is not related to the derivation path (I believe it's padding).
Here's some pseudo code for deriving a child node (m/44'
from the master node):
$index = 44 + 0x80000000; // all keys are hardened
// this comes from the node being used to derive `44'` (aka the master node)
$chainCodeBytes = '05294fe2430e60a3be665f5c6c44ad100d21d09ebcde853befaba92bdb788937';
// Private key of the current node
$privateKeyBytes = '5daf42e856561166e7788d292d5af4c0e3856a0e5dd815cf1f7146e64f87e775';
// index should be encoded as a 4-byte big-endian unsigned long
$indexBytes = toUint32($index);
$hmacInputBytes = 0x00;
$hmacInputBytes.append($privateKeyBytes)
$hmacInputBytes.append($indexBytes) // <--- I think this is what you're missing
$hmac = hmac_init('sha512', $chainCodeBytes);
hmac_update($hmac, $hmacInputBytes);
$hashedBytes = hmac_final($hmac);
At this point, $hashedBytes
will be a new 64-byte blob that you can create the child HDNode (m/44'
) from (first 32 bytes of it for the private key, second 32 bytes for the chain code).
To get m/44'/148'
you'll repeat the above process.
I think you're really close, you were just missing the 4 bytes of the index!
Here's a link to my PHP code if it helps: https://github.com/zulucrypto/stellar-api/blob/master/src/Derivation/HdNode.php#L64
Will post the solution once I clean it up.
Hi, could anyone point out to the Go implementation? The link provided in the SEP-0005 GitHub repo does not work
thanks @bartek .
Can you guys confirm is my understanding of the steps needed for the key derivation are correct?
- Generate the mnemonic words (i.e 12), then go from mnemonic to seed of 64 bytes --> using BIP-0039
- Split the BIP-0039 64 bytes seed into a 32-byte master key (M) and a 32-byte chain code (C).
- Use M to resolve m/44'/148' to derive the Stellar seed (SE) from BIP-0044.
- Then call StellarSdk.Keypair.fromRawSeed(SE) to get Stellar private and public keys
thanks @zcc for your feedback! @syntaxval, I will be implementing this in Javascript. From what i can read you managed to get it working :-). Have you posted the code?
Hi all, I created an npm package for SEP-0005:
https://www.npmjs.com/package/stellar-hd-wallet
https://github.com/chatch/stellar-hd-wallet
Please give it a try and let me know how it is. I've tested it in node but not in a browser as yet.
@hatch awesome! @bartek, @yulemata, my implementation is available here: https://github.com/stellar-fox/redshift/blob/master/src/lib/sep5.js but now that I saw npm package I can replace a lot of code in my tool (https://stellar-fox.github.io/redshift/)
- Edited
Hi all. I have just uploaded a python package that implements SEP-0005:
https://github.com/reverbel/seed-phrases-for-stellar
https://pypi.python.org/pypi/seed-phrases-for-stellar
In addition to deriving Stellar account keys from BIP39 seed phrases, this tool allows you to derive Stellar account keys from Electrum seed phrases. The code checks if a seed phrase is BIP39-compliant or Electrum-generated, and acts accordingly. The derivation of a master binary seed from a seed phrase either follows BIP39 or uses Electrum' s algorithm. In both cases (BIP39 phrases and Electrum phrases), the derivation of Stellar keys from the master binary seed follows SEP-0005.
Give it a spin and let me know what you think!
Hi all. Awesome work! I've learned so much from you. Thanks a lot for sharing!