Aller au contenu

PD-294 — Aligner le format Merkle proof sur RFC 9162 (inclusion proof)

1. Contexte

ProbatioVault produit des preuves d'inclusion Merkle dans le cadre de son enveloppe probatoire (ProofEnvelope). Le format actuel de la sous-structure merkle_proof est fonctionnel mais ne suit aucun standard reconnu. RFC 9162 (Certificate Transparency v2, section 2.1.3) definit un format d'inclusion proof largement adopte dans l'ecosysteme de transparence cryptographique.

L'objectif est d'aligner la structure de merkle_proof sur le modele RFC 9162 tout en conservant l'enveloppe ProbatioVault custom (tsa_token, hsm_signature, blockchain_anchor, event_metadata).

Positionnement : RFC 9162-inspired inclusion proof structure ; le schema de hachage reste specifique ProbatioVault (SHA3-256). Aucune revendication de conformite Certificate Transparency complete.

2. Besoin fonctionnel

En tant que verificateur de preuves ProbatioVault (auditeur, SDK client, service tiers), je veux recevoir une preuve d'inclusion Merkle dont la structure suit les conventions RFC 9162, afin de pouvoir verifier la preuve avec un algorithme standard (section 2.1.3.2 RFC 9162) et beneficier d'une interoperabilite accrue avec les outils de l'ecosysteme de transparence.

3. Format actuel (v1)

DTO MerkleProofResultAvailable

{
  status: 'available',
  eventHash: string,        // hash de l'evenement (leaf)
  merkleRoot: string,       // racine SHA hex 64 chars
  merklePath: string[],     // siblings bottom-to-top
  treeId: string,           // UUID de l'arbre
  treeSize: number,         // nombre de feuilles
  leafIndex: number,        // position 0-based
  hashAlgorithm: 'SHA-256', // ATTENTION: incohérence — le code declare SHA-256
  hashAlgorithmVersion: '1.0'
}

Export ProofArtifactDto

{
  merkle_proof: string[],   // siblings
  merkle_root: string,      // SHA hex 64 chars
  merkle_index: number      // position 0-based
}

Persistance merkle_leaves

Colonne Type Description
leaf_hash VARCHAR(64) hash hex de la feuille
leaf_index INTEGER position 0-based
inclusion_proof JSONB string[] siblings

Incohérence identifiee : le DTO declare hashAlgorithm: 'SHA-256' alors que l'ecosysteme ProbatioVault utilise SHA3-256 (journal append-only, HKDF, integrite documentaire). Cette incohérence doit etre corrigee dans PD-294.

4. Format cible (v2, RFC 9162-inspired)

Sous-structure merkle_proof dans ProofEnvelope

{
  proof_version: 2,
  leaf_index: number,           // position 0-based (RFC 9162 §2.1.3.2)
  tree_size: number,            // nombre total de feuilles (RFC 9162 §2.1.3.2)
  inclusion_path: string[],     // siblings bottom-to-top (RFC 9162 "inclusion_path")
  merkle_root: string,          // root hash hex
  hash_algorithm: 'sha3-256',   // explicite, ProbatioVault-specifique
  event_hash: string            // hash de la feuille (entree verifiee)
}

Mapping v1 -> v2

v1 v2 Transformation
merklePath inclusion_path Renommage (alignement RFC 9162)
merkleRoot merkle_root snake_case
leafIndex leaf_index snake_case
treeSize tree_size snake_case
eventHash event_hash snake_case
hashAlgorithm: 'SHA-256' hash_algorithm: 'sha3-256' Correction + renommage
proof_version: 2 Nouveau champ discriminant
treeId Supprime de la sous-structure (detail interne)
hashAlgorithmVersion Absorbe par hash_algorithm

Algorithme de verification (RFC 9162 §2.1.3.2)

Le format v2 permet la verification standard :

  1. Verifier leaf_index < tree_size
  2. Initialiser fn = leaf_index, sn = tree_size - 1, r = event_hash
  3. Pour chaque p dans inclusion_path :
  4. Si LSB(fn) est set ou fn == sn : r = HASH(0x01 || p || r)
  5. Sinon : r = HASH(0x01 || r || p)
  6. Right-shift fn et sn
  7. Verifier sn == 0 et r == merkle_root

Ou HASH = SHA3-256 (divergence assumee vs CT classique qui utilise SHA-256).

5. Strategie de migration

Principe : dual-read / single-write

  • Lecture : supporter v1 (legacy) ET v2 (nouveau format)
  • Ecriture : emettre uniquement v2
  • Pas de migration retroactive des preuves persistees (valeur probatoire)

Discriminant

Le champ proof_version (absent en v1, valeur 2 en v2) permet au code de lecture de determiner le format et d'appliquer l'adaptateur adequat.

Adaptateur de lecture

Pour les preuves legacy (v1), l'API peut normaliser a la volee en v2 sans reecriture en base :

v1.merklePath    -> v2.inclusion_path
v1.merkleRoot    -> v2.merkle_root
v1.leafIndex     -> v2.leaf_index
v1.treeSize      -> v2.tree_size
v1.eventHash     -> v2.event_hash
proof_version    -> 1 (infere)
hash_algorithm   -> 'sha3-256' (corrige)

6. Perimetre et exclusions

Dans le scope PD-294

  • Definition du format cible v2 (sous-structure merkle_proof)
  • Regles de mapping v1 -> v2
  • Strategie de migration dual-read / single-write
  • Correction de l'incohérence hashAlgorithm: 'SHA-256' -> hash_algorithm: 'sha3-256'
  • Criteres d'acceptation transverses de compatibilite
  • Ajout de proof_version comme discriminant

Hors scope

  • Implementation de getMerkleProof() et verifyMerkleProof() : PD-56
  • Consistency proofs (RFC 9162 §2.1.4) : story separee si besoin futur
  • Migration retroactive des preuves existantes : exclue par arbitrage PO
  • Modification du schema de hachage : SHA3-256 conserve (pas de migration vers SHA-256)
  • Enveloppe ProofEnvelope : reste custom ProbatioVault, non impactee structurellement

7. Stories impactees

Story Module Impact PD-294
PD-54 (Done) Construction arbre Merkle Aucun (produit le root, pas le proof format)
PD-55 (Done) Worker ancrage blockchain Aucun (consomme le root hash)
PD-56 (en cours) Generation Merkle proof DIRECTgetMerkleProof() doit suivre v2
PD-237 (Done) Persistance Merkle Verifier compatibilite merkle_leaves avec v2
PD-245 (Done) Format preuve multi-chain Compatible (blockchain_anchor reste dans l'enveloppe PV)
PD-282 (Done) ProofEnvelope HSM/eIDAS merkle_proof devient sous-objet v2 standardise

8. Invariants

ID Invariant Justification
INV-294-01 Le format v2 DOIT contenir leaf_index, tree_size, inclusion_path, merkle_root, hash_algorithm, event_hash, proof_version Alignement RFC 9162 §2.1.3
INV-294-02 hash_algorithm DOIT valoir 'sha3-256' (pas 'SHA-256') Correction incohérence + alignement ecosysteme PV
INV-294-03 Les preuves v1 existantes NE DOIVENT PAS etre reecrites en base Valeur probatoire des preuves persistees
INV-294-04 L'API DOIT normaliser les preuves v1 en format v2 a la volee en lecture Compatibilite backward transparente
INV-294-05 proof_version absent = v1 implicite ; proof_version: 2 = v2 explicite Discriminant non-breaking
INV-294-06 L'algorithme de verification §2.1.3.2 DOIT etre applicable sur le format v2 Interoperabilite avec outils standard (modulo hash)
INV-294-07 treeId NE DOIT PAS apparaitre dans la sous-structure v2 exposee Detail d'implementation interne, pas dans le proof
INV-294-08 Toute preuve v2 emise DOIT etre verifiable par l'algorithme RFC 9162 §2.1.3.2 adapte SHA3-256 Non-regression fonctionnelle

9. Risques et arbitrages

Risque Mitigation
Incohérence SHA-256 vs SHA3-256 dans le code existant PD-294 corrige le DTO ; verifier que le hash reel est bien SHA3-256 dans la construction d'arbre (PD-54)
Breaking change API pour consommateurs existants Versionning via proof_version ; v1 reste lisible ; transition progressive
PD-56 en cours — risque de conflit PD-294 definit le contrat avant que PD-56 implemente ; coordination explicite
Preuves v1 non-migrees cohabitent indefiniment Acceptable : le discriminant proof_version assure la cohabitation ; pas de date d'obsolescence imposee

10. References

  • RFC 9162 — Certificate Transparency v2 (sections 2.1.3, 2.1.3.1, 2.1.3.2, 4.12)
  • PD-54 — Construction arbre Merkle
  • PD-55 — Worker ancrage blockchain
  • PD-56 — Generation Merkle proof (IMPACT DIRECT)
  • PD-237 — Persistance Merkle
  • PD-282 — ProofEnvelope HSM/eIDAS
  • Learning PD-55 : "Gate 3 blockchain/crypto necessite 3 iterations si formalisme RFC manquant dans les specs initiales"
  • Learning PD-264 : "Atomicite multi-composant — clarifier synchrone vs asynchrone des la spec"