8.8 KiB
17.3: Uso de BIP32 en Libwally
ℹ️ NOTA: Esta sección se ha añadido recientemente al curso y es un borrador temprano que todavía puede estar pendiente de revisión. Lectura con advertencias.
En §17.2, usted fue capaz de usar entropía para generar una semilla y su mnemónico relacionado. Como usted puede recordar de §3.5: Entendiendo el Descriptor, una semilla es la base de un Monedero Jerárquico Determinista (HD), donde esa sola semilla puede ser usada para generar muchas direcciones. Entonces, ¿cómo se pasa de la semilla a las direcciones reales? Ahí es donde entra BIP32.
Crear una raíz HD
Para crear una dirección HD se requiere comenzar con una semilla, y luego ir hacía abajo por la jerarquía hasta el punto en el que se crean las direcciones:
unsigned char entropy[16];
randombytes_buf(entropy, 16);
char *mnem = NULL;#
lw_response = bip39_mnemonic_from_bytes(NULL,entropy,16,&mnem);
unsigned char seed[BIP39_SEED_LEN_512];
size_t seed_len;
lw_response = bip39_mnemonic_to_seed(mnem,NULL,seed,BIP39_SEED_LEN_512,&seed_len);
Como puede ver, necesitará decirle qué versión de la clave devolver, en este caso BIP32_VER_TEST_PRIVATE
, una clave de testnet privada.
🔗 TESTNET vs MAINNET: En mainnet, en cambio, se pide
BIP32_VER_MAIN_PRIVATE
.
Generar xpub & xprv
Siempre que tenga una llave en la mano, puede convertirla en claves xpub o xprv para distribución con el comando bip32_key_to_base58
. Solo tiene que decirle si usted quiere una clave PRIVATE
(xprv) o PUBLIC
(xpub):
char *xprv;
lw_response = bip32_key_to_base58(key_root, BIP32_FLAG_KEY_PRIVATE, &xprv);
char *xpub;
lw_response = bip32_key_to_base58(key_root, BIP32_FLAG_KEY_PUBLIC, &xpub);
Entender la jerarquía
Antes de ir más lejos, es necesario entender cómo funciona la jerarquía de una cartera HD. Como se discute en §3.5, una ruta de derivación describe el árbol que se sigue para llegar a una clave jerárquica, por lo que [0/1/0]
es el 0º hijo del 1er hijo del 0º hijo de una clave raíz. A veces parte de esa derivación está marcada con '
s o h
s para mostrar derivaciones endurecidas, que aumentan la seguridad: [0'/1'/0']
.
Sin embargo, para las carteras HD, cada uno de esos niveles de la jerarquía se utiliza de una manera muy específica. Esto se definió originalmente en BIP44 y más tarde se actualizó para Segwit en [BIP84].
En conjunto, una ruta de derivación BIP32 se define para tener cinco niveles:
- Proósito. Normalmente se establece en
44'
o84'
, dependiendo del BIP que se esté siguiendo. - Moneda. Para bitcoins en MAINNET, esto es
0'
, para testnet es1'
. - Cuenta. Una cartera puede contener varias cuentas discretas, empezando por
0'
. - Cambio. Las direcciones externas (para distribución) se establecen en
0
, mientras que las direcciones internas (para cambio) se establecen en1
. - Índice. La enésima dirección de la jerarquía, comenzando con
0
.
Así que en testnet, la dirección cero para una dirección externa para la cuenta cero para monedas de testnet usando los estándares BIP84 es [m/84'/1'/0'/0/0]
. Esa es la dirección que usted estara creando momentáneamente.
🔗 TESTNET vs MAINNET: Para mainnet, eso sería
[m/84'/0'/0'/0'/0]
Entender la jerarquía en el núcleo de Bitcoin
Usaremos la jerarquía anterior para todas las claves de HD en Libwally, pero tenga en cuenta que este estándar no es utilizado por Bitcoin Core bitcoin-cli
, que en su lugar utiliza [m/0'/0'/0']
para la dirección externa 0º y [m/0'/1'/0']
para la dirección de cambio 0º.
Generar una dirección
Para generar una dirección, tiene que excavar a través de toda la jerarquía.
Generar una clave de cuenta
Una manera de hacer esto es usar la función bip32_key_from_parent_path_alloc
para desplegar varios niveles de una jerarquía. Incrusta los niveles en una matriz:
uint32_t path_account[] = {BIP32_INITIAL_HARDENED_CHILD+84, BIP32_INITIAL_HARDENED_CHILD+1, BIP32_INITIAL_HARDENED_CHILD};
Aquí veremos al descendiente endurecido a cero (esa es la cuenta) o al primer descendiente endurecido (eso es monedas de tesnet) del descendiente 84º endurecido (ese es el estándar BIP84): [m/84'/1'/0']
.
A continuación, puede utilizar esa ruta para generar una nueva clave a partir de su antigua clave:
struct ext_key *key_account;
lw_response = bip32_key_from_parent_path_alloc(key_root,path_account,sizeof(path_account),BIP32_FLAG_KEY_PRIVATE,&key_account);
Cada vez que tenga una nueva clave,usted puede usarla para generar nuevas claves xprv y xpub, si lo desea:
lw_response = bip32_key_to_base58(key_account, BIP32_FLAG_KEY_PRIVATE, &a_xprv);
lw_response = bip32_key_to_base58(key_account, BIP32_FLAG_KEY_PUBLIC, &a_xpub);
Generar una clave de dirección
Alternativamente, puede usar la función bip32_key_from_parent_alloc
, que simplemente baja un nivel de la jerarquía a la vez. El siguiente ejemplo se reduce al descendiente 0º de la clave de cuenta (que es la dirección externa) y luego al descendiente 0º de la anterior. Esto sería útil porque entonces usted podría seguir generando la primera dirección, la segunda dirección, y así sucesivamente a partir de esa clave externa:
struct ext_key *key_external;
lw_response = bip32_key_from_parent_alloc(key_account,0,BIP32_FLAG_KEY_PRIVATE,&key_external);
struct ext_key *key_address;
lw_response = bip32_key_from_parent_alloc(key_external,0,BIP32_FLAG_KEY_PRIVATE,&key_address);
⚠️ ADVERTENCIA: En algún momento de esta jerarquía, puede que decida generar
BIP32_FLAG_KEY_PUBLIC
en lugar deBIP32_FLAG_KEY_PRIVATE
. Obviamente esta decisión se basará en su seguridad y sus necesidades, pero recuerde que sólo necesita una clave pública para generar la dirección real.
Generar una dirección
Finalmente, usted esta listo para generar una dirección a partir de su clave final. Todo lo que hace es ejecutar wally_bip32_to_addr_segwit
usando su clave final y una descripción del tipo de dirección que es.
char *segwit;
lw_response = wally_bip32_key_to_addr_segwit(key_address,"tb",0,&segwit);
printf("[m/84'/1'/0'/0/0]: %s\n",segwit);
🔗 TESTNET vs MAINNET: El argumento
tb
define una dirección de testnet. Para mainnet usebc
.
También hay una función wally_bip32_key_to_address
que se puede utilizar para generar una dirección heredada o una dirección Segwit anidada.
Prueba de código HD
El código para este ejemplo de HD se puede encontrar, como de costumbre, en el src directory.
Puede compilarlo y probarlo:
$ cc genhd.c -lwallycore -lsodium -o genhd
$ ./genhd
Mnemonic: behind mirror pond finish borrow wood park foam guess mail regular reflect
Root xprv key: tprv8ZgxMBicQKsPdLFXmZ6VegTxcmeieNpRUq8J2ahXxSaK2aF7CGqAc14ZADLjdHJdCr8oR2Zng9YH1x1A7EBaajQLVGNtxc4YpFejdE3wyj8
Root xpub key: tpubD6NzVbkrYhZ4WoHKfCm64685BoAeoi1L48j5K6jqNiNhs4VspfeknVgRLLiQJ3RkXiA9VxguUjmEwobtmrXNbhXsPHfm9W5HJR9DKRGaGJ2
Account xprv key: tprv8yZN7h6SPvJXrhAk56z6cwHQE6qZBRreB9fqqZJ1Xd1nLci3Rw8HTmqNkpFNgf3eZx8hYzhFWafUhHSt3HgF13aHvCE6kveS7gZAyfQwMDi
Account xpub key: tpubDWFQG78gYHzCkACXxkeh2LwWo8MVLm3YkTGd85LJwtpBB6xp4KwseGTEvxjeZNhnCNPdfZqRcgcZZAka4tD3xGS2J53WKHPMRhG357VKsqT
[m/84'/1'/0'/0/0]: tb1q0knqq26ek59pfl7nukzqr28m2zl5wn2f0ldvwu
Resumen: Usando BIP32 en Libwally
Una cartera HD le permite generar un gran número de claves a partir de una sola semilla. Ahora sabe cómo se organizan esas claves bajo BIP44, BIP84 y Bitcoin Core y cómo derivarlas, empezando con una semilla o palabras mnemónicas.
🔥 Cuál es la potencia de BIP32? Las llaves son el elemento más difícil (y más peligroso) de la mayoría de las operaciones criptográficas. Si los pierde, pierde cualquier llave protegida. BIP32 se asegura de que sólo necesita conocer una clave, la semilla, en lugar de un gran número de claves diferentes para diferentes direcciones.
🔥 Cuál es la potencia del BIP32 en Libwally? Bitcoind ya crea direcciones basadas en HD para usted, lo que significa que normalmente no tiene que preocuparse de derivar direcciones de esta manera. Sin embargo, usar las funciones BIP32 de Libwally puede ser muy útil si tiene una máquina fuera de línea donde necesitas derivar direcciones, posiblemente basadas en una semilla pasada de
bitcoind
a su dispositivo fuera de línea (o viceversa).
¿Qué es lo siguiente?
Más información sobre "Programar Bitcoin con Libwally" en 17.4: Usar PSBTs en Libwally.