Derivación de claves en carteras HD utilizando la clave privada extendida frente a la derivación reforzada

Estoy leyendo el libro Mastering Bitcoin y estoy confundido acerca de las derivaciones de claves de billetera en el Capítulo 4. Claves, direcciones, billeteras .

El libro menciona primero una derivación de clave privada secundaria donde la clave privada secundaria se deriva de tres entradas: (clave pública principal derivada previamente de clave privada principal, código de cadena principal, índice).

A continuación, el libro analiza las claves extendidas y menciona dos tipos: claves privadas extendidas y claves públicas extendidas.

Las claves públicas extendidas se utilizan para derivar claves públicas secundarias de claves públicas principales para evitar exponer las claves privadas y, por lo tanto, más seguras. Este es el diagrama de bloques para la clave pública extendida .

Por otro lado, el libro menciona que la clave privada extendida se usa para derivar la clave privada de un niño usando la clave privada y el código de cadena de los padres.

Sin embargo, aunque la clave pública extendida no expone la clave privada, su uso sigue siendo arriesgado ya que expone los códigos de la cadena. Si se filtra una clave privada, se pueden usar juntas para derivar otras claves secundarias.

Finalmente, el libro sugiere usar la clave reforzada , que para mí es exactamente la misma descripción que la clave privada extendida.

Mi primera pregunta es, ¿la clave privada extendida es lo mismo que la derivación de clave reforzada?

Mi segunda pregunta es qué técnica se usa realmente al derivar la clave privada para niños, la primera que menciono en mi pregunta o la segunda usando la clave privada extendida, que para mí es exactamente lo mismo que la derivación de clave reforzada.

Respuestas (3)

Hay mucha confusión aquí, en su mayoría fragmentos de todo el esquema que es la derivación determinista jerárquica, y finalmente dos preguntas que parecen indicar que falta algún punto al respecto. La respuesta a la primera pregunta es No. La segunda pregunta es más interesante:

Empecemos por las teclas extendidas, concretamente las teclas BIP32. Al igual que las claves privadas y las claves públicas, las claves extendidas pueden ser "privadas" o "públicas". Pongo ambos entre comillas porque ambos tipos de claves extendidas contienen información privada. Al menos lo suficiente para rastrear el uso de claves. Este mecanismo es utilizado por carteras de hardware y carteras de software "watchonly" en una PC.

Una clave extendida es solo una serialización codificada en base58 de algunos datos:

[ magic ][ depth ][ parent fingerprint ][ key index ][ chain code ][ key ]

Donde keypuede ser una clave pública o una clave privada. Las claves privadas se anteponen con un solo 0x00byte, por lo que la longitud de este blob permanece igual. Una clave extendida generalmente se deriva "atravesando" algunos path, lo que significa que comenzaría su derivación en alguna clave extendida principal y derivaría consecutivamente claves secundarias con índices específicos hasta que finalmente derivara la clave extendida final en el path. Dejaré de usar "extendido" en esta respuesta. De ahora en adelante me referiré a una clave privada extendida como xprvya una clave pública extendida como xpub, ya veces solo "claves". Los no extendidos son solo "clave privada" o "clave pública".

Un xprv o xpub magicson 4 bytes para indicar la red a la que pertenece: testnet o mainnet ( to xrespectivamente), y el tipo de clave que es ( puby prvrespectivamente). El depthes un byte que indica la profundidad de un xpriv o xpout en una ruta, comenzando desde 00la profundidad de la masterclave e incrementando en uno a medida que se derivan más claves secundarias a lo largo de la ruta. Tenga en cuenta que hasta ahora, la única diferencia entre las teclas xprvy xpubque mencioné es la parte prvo puben la magia. También debe quedar claro que un xprvy xpubpuede estar en el mismo camino y en la misma profundidad. Esto significa que para tal par de xprvy xpub, el[ key ]parte del tendrá una clave privada de 32 bytes (precedida de un 00byte) en el xprv, y una clave pública de 33 bytes que es la clave pública que obtiene de la clave privada en el xprv.

La huella digital de un padre son los primeros 4 bytes de la hash160clave pública del padre. Esto significa que incluso si xprvse usara un padre para derivar un hijo xprv, tendría lo mismo parent fingerprintque si xpubse usara un padre para derivar un hijo xpub. Una relación padre-hijo entre claves significa que son adyacentes en una ruta.

A pathes una n-tupla de índices, generalmente en base 10, separados por /. El rango de un índice puede estar entre cero y 4294967295 (o 2^32-1), donde cualquier cosa [0,2147483647]sigue una derivación no reforzada y los índices [2147483648,4294967295]siguen una derivación reforzada . Puede ver que cada mitad del rango de índices se usa para un método diferente. Podemos decir que hay dos rangos. [0,2147483647]para llaves no templadas y [0h,2147483647h]para llaves templadas. indica que el híndice (lo llamaremos i) debe tratarse como i + 2147483648. Probablemente es más probable que veas la hnotación como un símbolo de intercalación ', así que 1' == 1h, pero no creo que sea muy bonito, así que me quedaré con él hpor ahora.

Un ejemplo de cómo se ve una ruta es:

m/0h/1/2h/2/1000000000

El msignifica que la clave en este índice es a master xprvo master xpub. Un pequeño msignifica que esta clave extendida es un master xprvy grande Mun master xpub. Siguiendo las definiciones anteriores, puede decir que mes el padre de la clave en 0h, y la clave en 2hes el hijo de la clave anterior en el índice 1. Para que esto sea más fácil de seguir, anotaremos las diferentes claves en la ruta con letras {a..e}si queremos decir que estas son xprvs y {A..B}si xpubs.

m / 0h / 1 / 2h / 2 / 1000000000
m   a    b   c    d   e

Por lo general, se proporciona una ruta con índices en base 10, pero en la clave misma están codificados en hexadecimal (base 16), por lo que a [ key index ]siempre tiene 4 bytes con ceros antepuestos si es necesario. Los depthy indexde una llave maestra son ambos siempre cero, por lo que 00y 00000000, y pueden llegar a un máximo de FFy FFFFFFFFrespectivamente. Entonces my ason padre e hijo, y también lo son dy e. El depthde bes 02y su índice es 00000001, y el depthde ces 03mientras su índice es 80000002(80000000 + 2). La última clave secundaria que se deriva es e. Podemos decir que seguimos un camino que comienza en m, de ahí derivamos la clave aen index 0h, luego deaderivamos la clave ben el índice 1.. y así sucesivamente. Pero, ¿qué significa derivar una nueva clave?

Los dos elementos restantes en el formato de clave extendida, la clave principal [ chain code ]y [ key ]se utilizan junto con lo que sería la clave secundaria indexpara derivarla. Eso significa que para derivar cde b, alimentaríamos alguna función con b's chain codey key, y c's index. Un ejemplo específico de nuestro by csería:

b :

0488ADE4
02
5C1BD648
00000001
2A7857631386BA23DACAC34180DD1983734E444FDBF774041578E9B6ADB37C19
003C6CB8D0F6A264C91EA8B5030FADAA8E538B020F0A387421A12DE9319DC93368

c :

0488ADE4
03
BEF5A2F9
80000002
04466B9CC8E161E966409CA52986C584F07E9DC81F735DB683C3FF6EC7B1503F
00CBCE0D719ECF7431D88E6A89FA1483E02E35092AF60C042B1DF2FF59FA424DCA

Los campos están ordenados como en la estructura anterior. En ambos, magicdice xprv, depthse incrementa entre el padre y el hijo, el fingerprintat ces el hash160de la clave pública que obtendría de la clave privada en b, y bel de indexestá en la primera mitad no reforzada del rango mientras c' s es la segunda mitad endurecida. Finalmente se codifican los chain codeys keyde cada uno de los s.xprv

Derivar el chain codey keypara cde bse hace con un proceso llamado CKDpriv, lo que significa derivar un hijo xprvde un padre xprv. En este proceso usamos el chain codeand keyfrom by el indexfrom c. El punto importante a destacar: solo codificamos c después de derivar its chain codey keyde lo que sería its index.

Any xprvse puede usar con CKDprivpara derivar un hijo xprven any index. La forma específica CKDpriven que actuará sobre la entrada depende de si el niño se indexencuentra en el rango endurecido o en el rango no endurecido. Básicamente, una CKDprivfunción ejecuta un HMAC-SHA512en el padre chain codey en keyel hijo index. Esta función hmac toma dos valores a key*(que no debe confundirse con nuestras apariciones de key, se denominará hkey) y text. El padre chain codese usa como el hkey, mientras que el textestá compuesto por el padre keyen forma de clave privada si el índice del hijo está en el rango endurecido [0h,2147483647h], y en la clave públicaformulario si el índice está en el rango no endurecido. Luego se concatena con el del niño index.

cEl índice de está en el rango reforzado, por lo CKDprivque hmac-sha512 se ejecuta con las entradas:

HMAC-SHA512( 2A7857631386BA23DACAC34180DD1983734E444FDBF774041578E9B6ADB37C19,
             003C6CB8D0F6A264C91EA8B5030FADAA8E538B020F0A387421A12DE9319DC9336880000002 )

Lo que devuelve un hash de 64 bytes:

8F6154A0A82D0F68B9E5B586EA66D951DAAA071BEBD390097CC516285C791A6204466B9CC8E161E966409CA52986C584F07E9DC81F735DB683C3FF6EC7B1503F

Los 32 bytes en la mitad derecha de este hash, 04466B9C...C7B1503Fse convierten en el hijo ( caquí) chain code, y los 32 bytes en la izquierda se usan para "modificar", lo que significa simplemente "añadir mod n" a la clave del padre, en este ejemplo:

  8F6154A0A82D0F68B9E5B586EA66D951DAAA071BEBD390097CC516285C791A62
+
  3C6CB8D0F6A264C91EA8B5030FADAA8E538B020F0A387421A12DE9319DC93368
=
  CBCE0D719ECF7431D88E6A89FA1483E02E35092AF60C042B1DF2FF59FA424DCA   mod n
  • No escribí los 00bytes antepuestos en las claves aquí porque esto es solo agregar números, pero esos bytes cero son muy importantes para la función hash, así que los incluí allí a propósito.

Ahora que tenemos c's chain codey key(en forma de clave privada), nos gustaría codificar cpara que sea utilizable xprv. Para obtener el fingerprintfrom b, necesitamos saber la clave pública del keyfrom b. Como está en forma de clave privada, tendremos que hacer la multiplicación:

CBCE0D719ECF7431D88E6A89FA1483E02E35092AF60C042B1DF2FF59FA424DCA * G
= 03501E454BF00751F24B1B489AA925215D66AF2234E3891C3B21A52BEDB3CD711C

Tome el valor hash160de esta clave pública y el hash devuelto es BEF5A2F9A56A94AAB12459F72AD9CF8CF19C7BBE. Los primeros cuatro bytes son bla huella dactilar de : BEF5A2F9. Codificar el resto ces fácil. Comience con la magia xprvya que derivamos un niño xprv, incremente la profundidad ben uno, luego el fingerprint. El siguiente cestá indexcodificado. Derivamos index 2h, por lo que esto sería 80000002, y luego new chain codey keythat we get from CKDpriv.

Esto es básicamente lo que es la derivación endurecida . La clave privada y el código de cadena del padre se utilizan para derivar la clave secundaria en algún índice reforzado. ¿Qué pasa si queremos derivar d? Está en index 2, por lo que es un índice no endurecido. Este es el segundo caso de CKDpriv.

La diferencia está en lo que se usa para el textparámetro de la HMAC-SHA512función. En lugar de usar la forma de clave privada de los padres key, usamos la forma de clave pública, por lo que para derivar den el índice 2de c, primero encontramos la clave pública de c:

CBCE0D719ECF7431D88E6A89FA1483E02E35092AF60C042B1DF2FF59FA424DCA * G
= 0357BFE1E341D01C69FE5654309956CBEA516822FBA8A601743A012A7896EE8DC2

Luego continúa siguiendo los mismos pasos que los anteriores:

HMAC-SHA512( 04466B9CC8E161E966409CA52986C584F07E9DC81F735DB683C3FF6EC7B1503F,
             0357BFE1E341D01C69FE5654309956CBEA516822FBA8A601743A012A7896EE8DC200000002 )

                            tweak                                                            chain code
437984D45C4A2F5840C65B3DC6D7274E2859AD25D092DB032C49AA4D006A426B|CFB71883F01676F587D023CC53A35BC7F88F724B1F8C2892AC1275AC822A3EDD

* tenga en cuenta que 00no se antepone a text, ya que se trata de una clave pública.

  437984D45C4A2F5840C65B3DC6D7274E2859AD25D092DB032C49AA4D006A426B
+
  CBCE0D719ECF7431D88E6A89FA1483E02E35092AF60C042B1DF2FF59FA424DCA
=
  0F479245FB19A38A1954C5C7C0EBAB2F9BDFD96A17563EF28A6A4B1A2A764EF4   mod n

hash160( 0357BFE1E341D01C69FE5654309956CBEA516822FBA8A601743A012A7896EE8DC2 )

finger
   print
EE7AB90C|DE56A8C0E2BB086AC49748B8DB9DCE72

El resto es fácil, y podemos codificar:

d :

0488ADE4
04
EE7AB90C
00000002
CFB71883F01676F587D023CC53A35BC7F88F724B1F8C2892AC1275AC822A3EDD
000F479245FB19A38A1954C5C7C0EBAB2F9BDFD96A17563EF28A6A4B1A2A764EF4

La diferencia entre estos dos métodos para derivar child xprvs es sutil pero importante. Habilita CKDpub, que es una función para derivar child xpubs de un padre xpub . CKDpubfunciona casi igual que CKDprivla derivación no endurecida de , pero hace la derivación mediante la adición de puntos, por lo que en lugar de sumar números enteros para crear claves privadas secundarias, estamos sumando puntos para crear claves públicas secundarias. Observe cómo en la derivación no endurecida usamos el punto público principal para el HMAC-SHA512, usamos tweakcomo el valor agregado a la clave privada principal para derivar la clave privada secundaria, específicamente, derivamos la clave dprivada de .

Para entender CKDpub, es útil conocer primero otra función BIP32 llamada Neuter. Su propósito es convertir un xprva un xpub. Vamos a "ejecutar" Neuteren nuestro xprv d. Llamaremos a la resultante xpub D. Neuterhace dos cosas a un xprv: 1. Reemplaza el magicde 0488ADE4a 0488B21E(reemplaza xprvcon xpub) 2. Reemplaza la clave privada en el keycampo` con el punto público de la misma clave privada

para nuestro xprv d, el punto público es:

0F479245FB19A38A1954C5C7C0EBAB2F9BDFD96A17563EF28A6A4B1A2A764EF4 * G
= 02E8445082A72F29B75CA48748A914DF60622A609CACFCE8ED0E35804560741D29

(este es solo el proceso normal de clave privada -> clave pública)

entonces el resultado es:

D:

0488B21E
04
EE7AB90C
00000002
CFB71883F01676F587D023CC53A35BC7F88F724B1F8C2892AC1275AC822A3EDD
02E8445082A72F29B75CA48748A914DF60622A609CACFCE8ED0E35804560741D29

Ahora destá "castrado", Dtiene la clave pública codificada, pero vea cómo el chain code, depthy fingerprintpersistieron index. El xpub Destá en la misma posición en la ruta que el xprv d. Usaremos chain codey key(clave pública) para CKDpub, igual que CKDprivcon la derivación no reforzada, pero en cuanto a CKDpriv, derivamos la clave privada secundaria usando:

tweak + (parent private key) = child private key

porque CKDpubestaremos usando:

tweak*G + (parent public key) = child public key

Esto funciona porque parent public keyes realmente justo (parent private key)*G, y child public keyes justo (child private key)*G. Es decir, si tomamos la CKDprivecuación de ajuste y multiplicamos todos los elementos por G, obtenemos exactamente la CKDpubecuación de ajuste. CKDpubsolo puede derivar xpubclaves secundarias en el rango de índice no endurecido. Esto se debe a que la información presente en el padre xpub, específicamente la clave pública en el [ key ], solo se aplica al rango no reforzado. Donde CKDprivpodríamos usar la clave privada para conocer la clave pública, no podemos ir al otro lado. la HMAC-SHA512ronda que usa claves públicas se CKDprivaplica al rango de índice no endurecido.

Ahora que hemos neutralizado dpara crear el xpub D, el siguiente en la ruta es e's con el índice 1000000000 (o ), que está en el rango no endurecido, por 3B9ACA00lo que deberíamos poder derivar Eel elemento secundario xpubusando . Comenzamos con hmac-sha512 del padre como y padre (clave pública) concatenado con el índice del hijo:DCKDpubchain codehkeykeyE

HMAC-SHA512( CFB71883F01676F587D023CC53A35BC7F88F724B1F8C2892AC1275AC822A3EDD,
             02E8445082A72F29B75CA48748A914DF60622A609CACFCE8ED0E35804560741D293B9ACA00 )

                            tweak                                                            chain code
37D3E49D8ECB854CC518BBA096F46795A9707860BF0FC95E5B19278C997098D4|C783E67B921D2BEB8F6B389CC646D7263B4145701DADD2161548A8B078E65E9E

Multiplique el ajuste por el generador Gpara que podamos ajustar la clave pública de los padres mediante la suma de puntos:

37D3E49D8ECB854CC518BBA096F46795A9707860BF0FC95E5B19278C997098D4 * G
= 0327E992F68217BC3E88CFFC3FEAB475880145413CBE008DB22B496DF4E1C3F864  <- tweak*G

Agregue el movimiento al punto principal. El resultado es la clave pública del niño:

  0327E992F68217BC3E88CFFC3FEAB475880145413CBE008DB22B496DF4E1C3F864
+
  02E8445082A72F29B75CA48748A914DF60622A609CACFCE8ED0E35804560741D29
=
  022A471424DA5E657499D1FF51CB43C47481A03B1E77F951FE64CEC9F5A48F7011

Obtener la huella dactilar de los padres:

hash160(02E8445082A72F29B75CA48748A914DF60622A609CACFCE8ED0E35804560741D29) = D880D7D8....

Finalmente podemos codificar E:

0488B21E
05
D880D7D8
3B9ACA00
C783E67B921D2BEB8F6B389CC646D7263B4145701DADD2161548A8B078E65E9E
022A471424DA5E657499D1FF51CB43C47481A03B1E77F951FE64CEC9F5A48F7011

Neutralizando dpara Dluego derivar E, podemos decir que nuestro camino ahora se ve así:

m / 0h / 1 / 2h / 2 / 1000000000
m / a  / b / c  / D / E

O podemos usar la N()notación (para Neutro) para mostrar dónde CKDpubse usó, pero creo que es menos bonito.m / a / b / c / N(d / e)

Entonces, para resumir su pregunta, hay 3 métodos de derivación diferentes, dos que usan claves privadas y uno que usa claves públicas:

  1. CKDprivpara derivar un niño xprven un índice endurecido
  2. CKDprivpara derivar un hijo xprven un índice no endurecido
  3. CKDpubpara derivar un niño xpuben un índice no endurecido
fabulosa respuesta! gracias +1 millón
¿Pensé que la clave extendida era solo el (clave + código de cadena)?
Creo que quemé 5 Kcal siguiendo esta respuesta. Bromas aparte, sinceramente espero que esté planeando escribir un libro de O'Reilly sobre monederos criptográficos.
Es probable que el cálculo de la clave pública secp256k esté desactivado: 1% % echo CBCE0D719ECF7431D88E6A89FA1483E02E35092AF60C042B1DF2FF59FA424DCA | bx ec-to-public 0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2o 2% bx ec-multiply 0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798 CBCE0D719ECF7431D88E6A89FA1483E02E35092AF60C049FA4DF2DC5A0357bfe1e341d01c69fe5654309956cbea516822fba8a601743a012a7896ee8dc2
¿Hay un comando bx para sumar entre (tweak * g) y la clave pública? ec-add no funciona

También estoy teniendo dificultades para tratar de entender las cosas allí. Esto es lo que entiendo:

Una idea simple es que para la derivación de clave privada extendida y la derivación de clave pública extendida, todos tienen la misma entrada (una clave pública principal y un nodo de cadena principal). Como resultado, tendrán los mismos 256 bits izquierdos y 256 bits derechos.

La diferencia es que,

para la derivación de clave privada extendida, los 256 bits de la izquierda se agregan a la clave privada principal para producir la clave privada secundaria.

Y para la derivación de clave pública extendida, los 256 bits de la izquierda se agregan a la clave pública principal para producir la clave pública secundaria.

Ambas derivaciones de clave extendida utilizan su salida derecha de 256 bits como nodo de cadena, por lo que el nodo de cadena es el mismo para ambas derivaciones.

Para la derivación de clave reforzada, la entrada es diferente de la derivación de clave extendida anterior.

En lugar de usar la clave pública principal, usa la clave privada principal con el nodo de cadena como entrada , lo que producirá una salida diferente de 512 bits. Entonces, la salida derecha de 256 bits que se usa como nodo de cadena es diferente del mecanismo anterior.

Dado que el nodo de la cadena es diferente, los piratas informáticos no pueden deducir la clave privada utilizando el nodo de la cadena del mecanismo de derivación extendido.

Las claves reforzadas esencialmente generan nuevas claves por completo.

Todo el beneficio de usar claves jerárquicas es que puede generar muchas claves públicas sin acceso a las claves privadas. Más adelante, puede usar el mismo método que usó para generar las claves públicas en las claves privadas y poder gastar los fondos.

Esto es útil, por ejemplo, si desea que un sitio web reciba fondos pero no los pierda si es pirateado. El sitio web puede generar una nueva clave pública para cada cliente sin tener que tocar las claves privadas, manteniendo así los fondos más seguros.

Las llaves reforzadas rompen este enlace. Una operación de clave reforzada puede modificar una clave privada para crear una nueva pero NO modificar una clave pública.

No son realmente críticos, ya que podría generar una nueva clave y obtener el mismo resultado, pero es más conveniente. Puede ignorar más o menos las teclas endurecidas y seguir disfrutando de la vida =).

No estoy de acuerdo con eso. La derivación no reforzada es vulnerable a situaciones en las que se puede compartir una clave privada y se puede conocer la clave pública extendida. La derivación reforzada debe ser la predeterminada, a menos que haya una buena razón por la que necesite poder generar claves públicas sin acceso a la clave privada.