You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dateKeys-dart/CHANGELOG.md

7.9 KiB

Changelog

Cambios notables de la librería Dart. El proyecto usa versionado semántico; mientras sea 0.x, no hay promesa de estabilidad.

Especificación 0.11, en la rama v0.11 — sin versión

Etapa 2: primitivas y age (05-10-2026)

  • Primitivas, de código propio. Son internas: lib/datekeys.dart no las exporta.
    • SHA-256 con su compresión, y HMAC-SHA256 con los estados interior y exterior de la clave calculados una vez. Sobre ellos, HKDF-SHA256 (RFC 5869) y PBKDF2-HMAC-SHA256 (RFC 8018), cuyas iteraciones son dos compresiones sobre palabras: 600 000 iteraciones tardan 1,1 s en la VM, frente a unos 3,5 s con el HMAC de package:crypto.
    • scrypt (RFC 7914) con Salsa20/8, con las comprobaciones y los textos de scrypt.Key de Go.
    • ChaCha20, Poly1305 en diez limbs de 13 bits, y ChaCha20-Poly1305 (RFC 8439), con el tag comparado en tiempo constante.
    • X25519 (RFC 7748) sobre el cuerpo de TweetNaCl en doubles, con clamping y el secreto todo a ceros rechazado con el texto de crypto/ecdh.
    • Ed25519 estricto (§29.9), port de internal/ed25519strict: verifyStrict, canonical, smallOrder y onCurve. La aritmética de los puntos es la de TweetNaCl; los escalares módulo ℓ y onCurve usan BigInt, que no es de tiempo constante, solo con datos públicos.
    • El Base64 de Go, con su modo estricto y el offset de sus errores, y el Bech32 de age, con sus textos.
    • De package:crypto solo se usa SHA-512, en Ed25519.
  • Lectura de age v1, port de filippo.io/age v1.3.2 (lib/src/age.dart):
    • la cabecera y sus límites de internal/format, con los textos de error de Go;
    • el MAC de la cabecera, sobre la cabecera escrita otra vez como la escribe age;
    • los stanzas X25519 y scrypt. La identity de scrypt rechaza por defecto un factor de trabajo por encima de 16, como authorkey de Go; el de age es 22;
    • la clave del payload y el STREAM de internal/stream, que se descifra según llega el texto cifrado, con los mismos casos de fin de fichero que el lector de Go: sin chunk final, chunk que no se autentica, último chunk vacío y datos tras el final;
    • cada fallo es una AgeException con el texto de Go y su fase, la cabecera o el payload, para que la etapa 4 dé las razones fijas de capsule.classify. La DateKeysException de una identity pasa sin cambios.
  • agewrap (lib/src/agewrap.dart): las reglas de stanzas de OUTER_TIME_AGE, PAYLOAD_AGE e INNER_ACCESS_AGE, la lectura de los stanzas sin secretos, PayloadIdentity y AccessIdentity, con los textos y los códigos de Go. checkTimeStanzas recibe la ronda, el chain hash y el id del perfil, que llegará con la etapa 4.
  • Vectores de Go en test/vectors/, que escriben tool/gen_primitive_vectors.go y tool/gen_age_vectors.go con las librerías de la caché de módulos, en el contexto del módulo de datekeys-go y sin cambiar nada en él:
    • primitives.json y su copia en Dart, primitives.g.dart: RFC 5869, 7748, 7914, 8032 (por sign.input de Go) y 8439, PBKDF2 con el vector del §38.1, los puntos de orden pequeño, Base64 y Bech32. Incluye dos mensajes con los que una suma de productos de Poly1305 pasa de 2^32: un acarreo tomado con un desplazamiento fallaría en la web, y una prueba lo detecta en Node;
    • age.json: ficheros X25519 y scrypt, sus cortes y manipulaciones, un corpus de cabeceras contra la gramática del §28.1 y el límite de 2 MiB, y las reglas e identities de agewrap, con el texto de Go en cada caso;
    • age_fixtures.json: el PAYLOAD_AGE de los 24 fixtures con su payload_identity, y el INNER_ACCESS_AGE de los 6 time_and_key, sacado de OUTER_TIME_AGE con el release del fixture.
  • Pruebas. 296 en la VM y una aplazada, 127 más que en la etapa 1; 83 en Node.js, 27 más. Las de las primitivas y las de age sin ficheros corren también compiladas a JavaScript, sin los casos largos (PBKDF2 a 600 000 iteraciones, scrypt con logN 16, X25519 iterada 1000 veces).
  • Fallos inyectados, uno a uno y revertidos: 46 en las primitivas, age y agewrap. Las pruebas detectan todos los que cambian un resultado. Cuatro no lo cambian: la máscara de una mitad de rotación de SHA-256 cuyos bits altos solo llegan a sumas enmascaradas, el redondeo de _car cuando sus entradas nunca son negativas, el de un acarreo del producto del cuerpo, que conserva el valor, y el acarreo del limb 1 de Poly1305 tomado con desplazamiento, cuya suma no pasa de 2^32.
  • tool/bench.dart mide las primitivas en la VM y compilado a JavaScript; las cifras, en el README.

El gate con Node.js (05-10-2026)

  • tool/check.sh corre también dart test -p node: las pruebas que no leen ficheros, compiladas a JavaScript, comprueban en cada commit que los enteros son exactos en la web. Lo decidió el autor.

Etapa 1: errores, bytes, CBOR y DER (05-10-2026)

  • Errores normativos (§69). ErrorCode con los 19 códigos en el orden del spec y DateKeysException, con el mensaje contexto: CÓDIGO de Go. wrap y withContext hacen lo que fmt.Errorf("prefijo: %w"), y errorCode lo que datekeys.Code. Una prueba compara el catálogo con las líneas ERR_ del §69, leído de datekeys-go en el tag spec-v0.11.
  • Bytes. Hexadecimal, comparación y concatenación.
    • UTF-8 estricto: rechaza lo que rechaza utf8.Valid de Go y conserva un U+FEFF inicial. El Utf8Decoder de dart:convert lo descarta, en la VM y en la web, así que no se usa.
    • Un String con un surrogate suelto se escribe en UTF-8 generalizado (WTF-8), que no es UTF-8 válido.
    • utf8.DecodeRune y el %q de Go (strconv.Quote). La tabla de strconv.IsPrint de Go 1.26 se copia de datekeys-ts, y una prueba fija el SHA-256 del conjunto de runas.
  • CBOR (§58, §58.1). Port de codec/codec.go: CborEncoder, CborDecoder, unmarshalCbor, peekSchema, checkSchema y walkCbor, con los mismos textos de error.
    • Los enteros son exactos en la VM y en la web: un int hasta 2^53-1 y un BigInt por encima, también en las claves de los mapas y en los textos de error.
    • El Encoder de Go rechaza el UTF-8 inválido; aquí el único texto inválido es un surrogate suelto, y el error lo cita como Go citaría sus bytes en UTF-8 generalizado.
    • CborEncoder.uint exige 0..2^53-1, con un texto propio, como en datekeys-ts; uint64 escribe hasta 2^64-1.
  • DER estricto. Port de internal/der/der.go en 601e6d2, ya del borrador v0.12: check, split, content, setOfSorted y parseTime. parseTime devuelve un DerTime con los campos y los segundos Unix, exacto al nanosegundo. Es interno: lib/datekeys.dart no lo exporta.
  • Pruebas. Port de errors_test.go, codec_test.go, internal_test.go, vectors_test.go y der_test.go, de cbor.test.ts y de bytes.test.ts, con los textos de error que imprime Go.
    • Los objetivos de fuzzing de Go son propiedades con semilla, contra un codificador y un decodificador de referencia escritos aparte, como internal/cbortest.
    • testdata/vectors/cbor.json: los 36 accept y los 67 reject, con los límites de walk y los valores. Los 172 vectores de schemas se leen y se aplazan: necesitan los decodificadores de esquema de la etapa 4.
    • 169 pruebas en la VM y una aplazada. Las 56 que no leen ficheros pasan también en Node.js (dart test -p node); las que leen ficheros llevan @TestOn('vm').

Etapa 0: el paquete (05-10-2026)

  • Paquete datekeys en Dart puro, sin Flutter, para Dart 3.13 y sin publicar (publish_to: none).
  • testdata/ sincronizado con el tag spec-v0.11 de datekeys-go (ae33434): 124 ficheros. Su testdata/SOURCE.json es el mismo, byte a byte, que escribe datekeys-ts para ese commit.
  • tool/sync_testdata.dart, el equivalente de scripts/sync-testdata.mjs. test/testdata_test.dart comprueba la copia y que cada fichero nombre la versión de la especificación.
  • tool/check.sh, el gate local.
  • Dependencias: package:crypto en ejecución y package:test en desarrollo.
  • Licencia Apache-2.0.

Powered by TurnKey Linux.