Hierarchical Deterministic Wallets in SafeNet ProtectToolkit

Bitcoin Improvement Protocol 0032 (BIP32) introduced Hierarchical Deterministic Wallets, which use elliptic curve mathematics to calculate multiple key pair chains from a single root. This eliminates the need for backups after each Bitcoin transaction, by allowing you to create a new public address for each transaction or group of transactions without knowing the private key.

For a full description of BIP32 HD wallets, see https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki.

BIP32 Implementation in SafeNet ProtectToolkit

SafeNet ProtectToolkit introduced support for BIP32 in release 5.4. SafeNet ProtectToolkit generates HD wallets as PKCS#11 keypairs within the ProtectServer HSM, using the custom algorithms CKM_BIP32_MASTER_DERIVE and CKM_BIP32_CHILD_DERIVE. While public keys can be exported in plaintext, the SafeNet ProtectServer security architecture prevents the plaintext base58 value of private keys from existing outside of the HSM.

This information is encoded in the key's custom attributes as described below.

Validating BIP32 Test Vectors With ProtectServer

For testing purposes, you can use the procedure below to confirm that BIP32 key generation is functioning properly. The BIP32 test vectors are located at https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#test-vectors.

Descriptions of the attributes described below can be found at https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki#serialization-format.

To validate BIP32 test vectors with ProtectServer

1.Generate a BIP32 master keypair, specifying the seed provided in one of the test vectors (example: Test Vector 1). If you want to confirm the private key, you must set CKA_SENSITIVE=0 during key creation.

Example seed (hexadecimal): 000102030405060708090a0b0c0d0e0f

2.Examine the following key attribute fields (you can also use C_GetAttribute to obtain these values):

a.BIP32_VERSION_BYTES=<4_bytes>

This attribute will have one of four values. It is provided in integer form. Convert it to hexadecimal as follows:

Key Type Decimal Hexadecimal
Mainnet Public Key 76067358 0488B21E
Mainnet Private Key 76066276 0488ADE4
Testnet Public Key 70617039 043587CF
Testnet Private Key 70615956 04358394

b.BIP32_CHILD_DEPTH=<1_byte>

Represents the depth of derivations from the master key (00 on the master node).

c.BIP32_PARENT_FINGERPRINT=<4_bytes>

If this is the master key, the field appears empty. The correct value is 00000000.

d.BIP32_CHILD_INDEX=<4_bytes>

If necessary, append zeroes to include the full 4 bytes. In this example, the correct value is 00000000.

e.BIP32_CHAIN_CODE=<32_bytes>

f.VALUE=<32_bytes>

The key value in hexadecimal form. This attribute field is only visible if SENSITIVE=0.

3.Concatenate these values, in the above order, into a string.

0488B21E000000000000000000873DFF81C02F525623FD1FE5167EAC3A55A049DE3D314BB42EE227FFED37D5080339A36013301597DAEF41FBE593A02CC513D0B55527EC2DF1050E2E8FF49C85C2

4.Hash the string twice with SHA-256 to obtain the checksum.

AB473B21

5.Append the checksum to the end of the original string.

0488B21E000000000000000000873DFF81C02F525623FD1FE5167EAC3A55A049DE3D314BB42EE227FFED37D5080339A36013301597DAEF41FBE593A02CC513D0B55527EC2DF1050E2E8FF49C85C2AB473B21

6.Convert the entire string from hexadecimal to base58.

xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8

7.Compare the base58 value to the expected value from the BIP32 test vector.