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.

8.0 KiB

Review of the DateKeys v0.9 design: consistency, compatibility and implementability

These checks passed, so the core design holds:

  • Arithmetic. Every padding and length figure in the note recomputes exactly, and all 5 fixtures fit the length formulas. The v2 control is 103 bytes, and reforzado(L_MAX+1) is 2^53.
  • Old readers. None of the 1825 inspect_differential.json cases produces VERSION 2 (byte 4 comes out as a7, 05, e8 or 20). Go framing.go:111 and TS framing.ts:47 both reject VERSION 2 at step 2 with no network request.
  • Precedence. Every existing §69.1 example stays true, and so do the six new rows.
  • Format-1 codes. No invalid format-1 input changes its code except those with VERSION 2. A control v1 with keys 6/7 gives ERR_NON_CANONICAL_CBOR in both readers. A control v2 in format 1 gives ERR_UNSUPPORTED_VERSION in both.

Corrections, most serious first:

  1. HIGH: relabel cases that offer a .dkk fail at step 9.a, not at 12 or 14. Every writer-made .dkk has a capsule_digest, and editing byte 4 breaks it.

    • Evidence:
      • encrypt.go:232 always sets Verification{CapsuleDigest}.
      • time_and_key_portable.dkk.json has capsule_digest 2e97….
      • The existing mutation "capsule_digest of the .dkk does not match" (one byte edit) gives ERR_ACCESS_INVALID, step 9, network:false.
      • The corpus reader gets a seekable file, so the digest is checked (testdata/README.md:212-214).
    • Wrong as written:
      • §11 row "format 1 time_and_key relabeled format 2 | time_and_key_portable.dkc + .dkk → ERR_POLICY_STRUCTURE_MISMATCH 12".
      • §11 row "format 2 time_and_key relabeled format 1 | … + .dkk → ERR_UNSUPPORTED_VERSION 14".
    • Unconditional claims that need qualifying: the time_and_key rows of the §1.3 table, the §26 addition ("Antes falla en el paso 12 o en el 14"), the last paragraph of §70, and §76 case 4 ("falla en el paso 14 en los dos lectores").
    • Fix: build these cases with identities (the raw access_material), not the .dkk. In §64 write "…con una identity". Add to §26 and §70: "o en el paso 9.a, con ERR_ACCESS_INVALID, si se ofrece una .dkk con capsule_digest y se comprueba (§43, §69.1 Alcance)".
  2. MEDIUM: "En ningún caso entrega el contenido con su relleno" (§70) and "No path outputs padding as content" (§1.3) claim too much.

    • For a format-2 time_only capsule, anyone can do this after the release:
      1. Open the control with FK_TIME and read I_PAYLOAD.
      2. Set VERSION to 1.
      3. Seal a v1 control with the same I_PAYLOAD and a recomputed header_binding (§36.1).
    • Both readers then open it as format 1 and output content‖zeros.
    • Fix: limit the claim to "una cápsula de formato 2 cuyo control no se ha vuelto a sellar", and cite §36.1 and §55.1.
  3. MEDIUM: new normative rules outside D1–D7 that §12 does not list for the author's confirmation.

    • L_MAX = 2^53 − 2^46. It is a new writer MUST NOT and a new reader rejection (ERR_NON_CANONICAL_CBOR). D2 only said "up to the format limits", and today PAYLOAD_AGE has no bound.
    • The MUST to shuffle the 16 stanzas with a CSPRNG. It is needed for D1: the portable-key holder is last in encrypt.go:294 and would learn the exact count. The text should also require an unbiased shuffle.
    • "Control schema version MUST equal the format". This ties every future format to a new control version. Better as a format → version table. Also state that a new padding code needs a new format, so old readers still fail at step 2.
    • The §72 clause "salvo que su registro diga otra cosa". It adds a registry declaration that is not in §72's MUST-declare list: either add it to the list or drop the clause.
  4. MEDIUM: writer implementability — L must be known up front, and a streaming writer cannot take back what it wrote.

    • Go: Encrypt(dst, src io.Reader, …) streams a source of unknown length (encrypt.go:218), after writing PRELUDE, header and control to dst (207-211).
    • TS: the phase 3 plan (decision 2) accepts a ReadableStream, whose length is unknown.
    • Both APIs need an explicit length input, or must spool the source to a temporary file first. §61.1 and §62.1 rule 6 should say a writer MAY spool and MUST NOT guess L.
    • "abortar y descartar lo escrito" (§61 step 13, rule 9) is something a streaming writer cannot do. Rephrase as: the writer MUST report the error, and whoever receives the output MUST discard it, as with the capsule-rejected case of §56.
  5. LOW-MEDIUM: nothing says a reader must not reserve memory from L. A control may declare L up to 8.9·10^15. Add to §57 and §63 step 16: "L no es una longitud de trama: un lector no reserva memoria según L; la acota el ciphertext". The TS reader already bounds its buffer by the ciphertext length (open.ts:422); the text should keep that.

  6. LOW-MEDIUM: §69.1 paragraph L2106 (cross-object checks) is not updated. The design moves one cross-object check (control version against PRELUDE VERSION) into layer 2, but L2106 still lists every cross-object check as belonging to its own step. Add "y la versión de CONTROL_CBOR frente al formato (paso 14, capa 2)" to that list.

  7. LOW: a proposed cbor.json vector cannot test what it claims. "padding 3 and an unknown critical extension (layer 3 before layer 4)" does not work there: schema vectors never check critical extensions (testdata/README.md:115-118, 131-133). Keep it only as a mutation or a TestPrecedenceAcrossSteps case at step 14.

  8. LOW: the informative note of §62.1 is wrong. It says "Con C = 91 y k = 1 o 3, las fórmulas dan las longitudes de los cinco fixtures". But time_only_extensions has C = 127 (482 = 335 + 4 + 127 + 16), and three of the fixtures are time_only, with no k. Fix: "C = 91 (127 en time_only_extensions); k = 1 o 3 en los dos time_and_key".

  9. LOW: the floating-point log2 example is outside the valid range. 2^53 − 1 is above L_MAX. Use L = 2^49 − 1, the first failing case in range: Math.log2 gives 49 and the correct value is 48 (checked in Node).

  10. LOW: "bloque256 añade menos de 256 bytes" is false for L = 0, which adds 256. Write "como mucho 256".

  11. LOW: new §39 says "En formato 1, INNER_ACCESS_AGE MAY contener uno o más stanzas". That weakens the MUST (≥ 1) of §33 and §36. Write "contiene (MUST, §33) uno o más".

  12. LOW: §74 contradicts itself and the README.

    • The design declares the encoding of L and the 16 slots "no provisionales". §74 still lists "schema CBOR final byte-a-byte de CONTROL_CBOR" as open, and spec/README says v0.9 is "not frozen".
    • The out-of-scope list sits under "Aspectos todavía provisionales". Put it in its own "Trabajo futuro" paragraph.
  13. LOW: forward references. §29.1 cites testdata/vectors/padding.json, which does not exist. §76 cites "TODO" tests. Every existing §76 entry cites only tests that exist. Mark these "a generar con la implementación de v0.9", or keep the test list out of §76 until they exist.

  14. LOW: wording in §55.2.

    • The ".dkk lleva en claro …" line leaves out the credential itself (access_material).
    • "Credencial" in §39 means a recipient (a public key). In §63 step 9 it means an identity or .dkk the reader offers. Define the term once.
  15. INFO: effects on the TS phase 3 plan (App/docs/PLAN_fase3_escritura.md).

    • Decision 6 keeps R_ACCESS last; it must become the shuffle.
    • The test "1 024 recipients + portable" becomes a rejection above 16.
    • Decision 8 ("no vuelve a descifrar") and plan §6, which wipes I_PAYLOAD right after the real seal, conflict with the new SHOULD self-check that I_PAYLOAD opens the PAYLOAD_AGE header. Wipe it after that check.
  16. INFO: test data.

    • The cbor.json vector "unknown key 6" (control, key 6 = uint 0) has a misleading name once key 6 exists; rename it.
    • Go's Open never records a step 17 stage (open.go:246 goes to 261), so fixture stages lack step 17. The new step 17 checks make that entry worth adding for §67.

Powered by TurnKey Linux.