BIP39 Proceso de prueba de unidad de vector mnemotécnico japonés

Hay un json para pruebas unitarias de caracteres japoneses que quiero validar usando Python, específicamente con esta bifurcación de pybitcointools , que tiene la funcionalidad bip39.

Las pruebas unitarias de los vectores de prueba python-mnemonic de Trezor funcionan bien (en Python 2.7 IME), sin embargo, esto es sencillo ya que no hay normalización de la dialéctica Unicode y demás, ya que todos los mnemotécnicos están en minúsculas en inglés.

Los campos japoneses son:

  1. Entropía (hexadecimal)
  2. Mnemónico (japonés)
  3. Contraseña (en japonés, parece ser la misma para todas las pruebas)
  4. Semilla (hexadecimal, 64 bytes)
  5. xprv

Entonces entropysemillas mnemonic (bip39?), entonces mnemonic| passwordhash a Seed; Seedluego actúa como la llave maestra para el bip32 xprv? (¿¡Corrígeme si estoy equivocado!?)

Entonces, suponiendo que sea tan sencillo...

  1. ¿Cómo se "normaliza" el texto Unicode japonés? (¿Es solo la normalización NKFD Unicode, que hace Electrum 2.0 ?)
  2. ¿Qué significa "normal" para los japoneses?

Respuestas (1)

Entonces, la entropía genera mnemónico (¿bip39?), luego mnemónico | hashes de contraseña para Seed; Seed entonces actúa como la llave maestra para el bip32 xprv? (¿¡Corrígeme si estoy equivocado!?)

Eso suena bien. La mayor parte del proceso está bien detallado en BIP-39 .

  1. Se toma un SHA-256 de la entropía y los primeros entropy_len_in_bits / 32bits de este hash se agregan al final de la entropía. La cadena de bits de entropía resultante es divisible en fragmentos de 11 bits (ya no es un número entero de bytes).
  2. Cada fragmento de 11 bits se convierte en una de 2 11 palabras mnemotécnicas.
  3. Las palabras van unidas por espacios. Para fines de visualización en japonés, estos deben ser ESPACIOS IDEOGRAFICOS Unicode, '\u3000'. Si no hay necesidad de mostrar el mnemotécnico al usuario, pueden ser ESPACIOS "normales" ( '\u0020').
  4. La oración mnemotécnica es Unicode normalizada en formato NFKD. Esto convierte cualquier ESPACIO IDEOGRAFICO en ESPACIO. También cambia algunos caracteres en algunas de las palabras mnemotécnicas, por lo que este paso no se puede omitir. (La pregunta ¿ Qué es la normalización de NFKD? es un tema completamente separado que probablemente se pregunte mejor en otro lugar, en mi opinión ...)
  5. La oración mnemotécnica se convierte en bytes a través de la codificación UTF-8 .
  6. La semilla binaria se calcula como PBKDF2 HMAC SHA512 (clave = "mnemónico" | frase de contraseña, datos = utf8_mnemónico, iteraciones = 2048, out_bytes_length = 64). La frase de contraseña puede ser la cadena vacía. Primero debe pasar por los mismos pasos 4 y 5 que el mnemotécnico.
  7. (Esta parte no se detalla en ninguna parte AFAIK) La clave privada extendida maestra se construye utilizando los primeros 32 bytes de la semilla binaria como clave privada y los últimos 32 bytes como código de cadena.

¿Es solo la normalización NKFD Unicode, que hace Electrum 2.0?

Electrum 2.x usa la normalización NFKD, pero también realiza pasos adicionales, como eliminar espacios entre palabras japonesas después del paso 4. También usa una cadena de clave diferente en el paso 6 y un proceso completamente diferente antes del paso 4. Ver esto respuesta para una implementación del procedimiento mnemónico-palabras-a-semilla de Electrum 2.x en Python.

Gracias por la respuesta. Tengo lagunas en cómo encaja UTF-8, aunque entiendo bastante bien lo que hace NKFD. ¿Por qué no simplemente codificar Unicode directamente? Además, entiendo el espacio ideográfico, creo (\u3000 es el "equivalente" japonés de \u0020). En realidad, fue la implementación de Electrum 2.0 de la preparación de semillas lo que me estaba confundiendo. Eso sí que es extraño Electrum desviado en lugares tan oscuros
Rasca eso. No puede codificar puntos de código Unicode de 4 bytes tan bien como UTF8, ¿verdad?
@WizardOfOzzie Las cadenas Unicode son simplemente secuencias de números enteros en el rango [0,0x10FFFF]. Antes de que pueda codificarlo, debe convertirlo en una secuencia de bytes. Una forma simple es tomar cada int de 4 bytes y usar esos bytes tal cual (codificación UTF-32LE), pero esto es ineficiente desde el punto de vista del espacio (considerando que el inglés solo necesita 1 byte por carácter). UTF-8 es más complicado, pero más eficiente en el espacio la mayor parte del tiempo.
@WizardOfOzzie estuvo de acuerdo en que la normalización de Electrum 2.x es mucho más compleja, pero es útil para minimizar la posibilidad de pérdida por mnemónicos mal escritos dada la falta de listas de palabras específicas. (Y el requisito de BIP-39 para listas de palabras específicas era algo con lo que el desarrollador de Electrum 2.x realmente no estaba de acuerdo).
¿Esto se ve bien?norm = lambda d: (' '.join(unicodedata.('NFKD', unicode(d)).split('\u3000'))).encode('utf-8')
¿Suponiendo que des una oración mnemotécnica de cadena de tipo Python2 o un unicode? Pensaría algo como esto para la mayoría de los idiomas (diferente para el chino, que podría no tener espacios d): norm = lambda d: (u' '.join(unicodedata.normalize('NFKD', unicode(d)).split())).encode('utf-8')(agregué el "normalizar" que faltaba y cambié dividir para dividir en todos los espacios en blanco). Tenga en cuenta que si está aceptando la entrada de un usuario, BIP-39 requiere que verifique la suma de verificación.
Gracias, lo intentaré ahora. Hmmm, asumiendo py 2/3, digamos tanto Unicode como str. Sí, estoy bastante versado con bip39, por lo que mi función mn2hex afirma check_bip39
He conseguido que todas las pruebas unitarias funcionen * excepto la comparación de bip39_hex_to_mncon VECTOR['mnemonic'], ya que la función devuelve un espacio estándar (es decir \u0020), mientras que los vectores de prueba usan \u3000. Electrum (2.x) resuelve el problema del espacio ideográfico ( \u3000) concatenando todas las palabras CJK sin espacios. Consulte github.com/simcity4242/pybitcointools/blob/master/… (Solo tengo que trabajar con u' '.join(v['mnemonic'].split()), mientras que debería serv['mnemonic']
Relacionado tangencialmente, ¿por qué las listas de palabras para inglés y japonés tienen el formato correcto (cada palabra es un objeto Unicode que consta de caracteres Unicode), mientras que el español, chino y francés ( github.com/simcity4242/pybitcointools/blob/master/bitcoin /… y siguientes) las listas de palabras tienen este formato: '\xe7\x9a\x84'?
@WizardOfOzzie Según mi lectura del estándar, bip39_hex_to_mn() debería devolver mnemónicos con espacios ideográficos para japonés, de modo que el resultado pueda usarse tanto para fines de visualización como para calcular la semilla binaria. Tal como está escrito actualmente, el valor devuelto solo es adecuado para el último propósito. Dado este cambio, podrías eliminar el "hackeo" que le hiciste a TestBIP39JAP.
@WizardOfOzzie Con respecto a sus listas de palabras, estoy de acuerdo con usted en que preferiría que todas fueran objetos Unicode por coherencia. ¿De dónde sacaste tus listas de palabras? Tal vez debería descargar los archivos de texto de la lista de palabras oficial BIP-39 directamente desde el repositorio y cargarlos con algo como with io.open(language+'.txt', encoding='utf_8_sig') as words_file: words[language] = tuple(word.strip() for word in words_file).
Los cargué usando iPython, luego escribí la variable en un archivo con la extensión %store var >> file.py. Actualizaré ambas recomendaciones, ¡gracias!