Sample code for 30+ languages & platforms
Lua

BIP39 Compute Binary Seed from Mnemonic

See more Encryption Examples

Creates a binary seed from a mnemonic. Uses the PBKDF2 function with a mnemonic sentence (in UTF-8 NFKD) used as the password and the string "mnemonic" + passphrase (again in UTF-8 NFKD) used as the salt. The iteration count is set to 2048 and HMAC-SHA512 is used as the pseudo-random function. The length of the derived key is 512 bits (= 64 bytes).

Chilkat Lua Downloads

Lua
local chilkat = require("chilkat")

-- This example assumes the Chilkat API to have been previously unlocked.
-- See Global Unlock Sample for sample code.

local crypt = chilkat.Crypt2.new()

-- Test with the test vectors at https://github.com/trezor/python-mnemonic/blob/master/vectors.json

-- This is the 2nd test vector..
local mnemonic = "legal winner thank year wave sausage worth useful legal winner thank yellow"
local passphrase = "TREZOR"
local expectedSeed = "2e8905819b8723fe2c1d161860e5ee1830318dbf49a83bd451cfb8440c28bd6fa457fe1296106559a3c80937a1c1069be3a3a5bd381ee6260e8d9739fce1f607"
local expectedMasterKey = "xprv9s21ZrQH143K2gA81bYFHqU68xz1cX2APaSq5tt6MFSLeXnCKV1RVUJt9FWNTbrrryem4ZckN8k4Ls1H6nwdvDTvnV7zEXs2HgPezuVccsq"

-- The mnemonic sentence (in UTF-8 NFKD) used as the password.
-- The string "mnemonic" + passphrase (again in UTF-8 NFKD) used as the salt.
-- The iteration count is set to 2048 and HMAC-SHA512 is used as the pseudo-random function.
-- The length of the derived key is 512 bits (= 64 bytes).

-- We want the computed seed to be lowercase hex, therefore our salt must also be hex.
-- The seed is the keyword "mnemonic" + passphrase (in this case is "TREZOR") converted to hex.
local bdSalt = chilkat.BinData.new()
bdSalt:append_string("mnemonic", "utf-8")
bdSalt:append_string(passphrase, "utf-8")

local computedSeed = crypt:pbkdf2(mnemonic, "utf-8", "sha512", bdSalt:get_encoded("hex_lower"), 2048, 512, "hex_lower")

print("Expected: " .. expectedSeed)
print("Computed: " .. computedSeed)

-- To compute the hd_master_key, duplicate this Python code:

--     def to_hd_master_key(seed: bytes, testnet: bool = False) -> str:
--         if len(seed) != 64:
--             raise ValueError("Provided seed should have length of 64")
--
--         # Compute HMAC-SHA512 of seed
--         seed = hmac.new(b"Bitcoin seed", seed, digestmod=hashlib.sha512).digest()
--
--         # Serialization format can be found at: https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#Serialization_format
--         xprv = b"\x04\x88\xad\xe4"  # Version for private mainnet
--         if testnet:
--             xprv = b"\x04\x35\x83\x94"  # Version for private testnet
--         xprv += b"\x00" * 9  # Depth, parent fingerprint, and child number
--         xprv += seed[32:]  # Chain code
--         xprv += b"\x00" + seed[:32]  # Master key
--
--         # Double hash using SHA256
--         hashed_xprv = hashlib.sha256(xprv).digest()
--         hashed_xprv = hashlib.sha256(hashed_xprv).digest()
--
--         # Append 4 bytes of checksum
--         xprv += hashed_xprv[:4]
--
--         # Return base58
--         return b58encode(xprv)

-- First compute the HMAC-SHA512 of the computedSeed
local bdSeed = chilkat.BinData.new()
bdSeed:append_encoded(computedSeed, "hex_lower")
crypt.encoding_mode = "hex_lower"
crypt.hash_algorithm = "sha512"
crypt:set_mac_key_string("Bitcoin seed")
local hmacSha512_hex = crypt:mac_bd_enc(bdSeed)

local bdHmac = chilkat.BinData.new()
bdHmac:append_encoded(hmacSha512_hex, "hex_lower")

local bdXprv = chilkat.BinData.new()
bdXprv:append_encoded("0488ade4", "hex_lower")
bdXprv:append_encoded("000000000000000000", "hex_lower")
bdXprv:append_encoded(bdHmac:get_encoded_chunk(32, 32, "hex_lower"), "hex_lower")
bdXprv:append_byte(0)
bdXprv:append_encoded(bdHmac:get_encoded_chunk(0, 32, "hex_lower"), "hex_lower")

-- Double hash using SHA256
crypt.encoding_mode = "hex_lower"
crypt.hash_algorithm = "sha256"

local bdHash = chilkat.BinData.new()
bdHash:append_encoded(crypt:hash_bd_enc(bdXprv), "hex_lower")
local secondHash = crypt:hash_bd_enc(bdHash)
bdHash:clear()
bdHash:append_encoded(secondHash, "hex_lower")

-- Append the 1st 4 bytes of the bdHash to bdXprv.
bdXprv:append_encoded(bdHash:get_encoded_chunk(0, 4, "hex_lower"), "hex_lower")

-- Base58 encode bdXprv
local computedMasterKey = bdXprv:get_encoded("base58")

print("Expected Master Key: " .. expectedMasterKey)
print("Computed Master Key: " .. computedMasterKey)