Aller au contenu

PD-42 — Plan d'implementation

1. Objectif

Ce document decrit comment implementer le mecanisme de recherche deterministe chiffree (Server-Side Search) tel que specifie dans PD-42-specification.md. L'implementation permet l'execution de requetes cote serveur sans acces aux keywords en clair, en respectant le principe zero-knowledge.


2. Choix techniques retenus

Decision Choix Justification
Algorithme de derivation HKDF-SHA256 Conforme a RFC 5869, derivation deterministe
Algorithme de tokenisation HMAC-SHA256 PRF standard, deterministe, collision-resistant
Encodage des tokens Base64 URL-safe (RFC 4648) sans padding, tronque a 22 chars Compatibilite URL, taille fixe
Normalisation Unicode NFC (UAX #15) Standard industriel, deterministe
Scope des cles USER Isolation cryptographique par utilisateur
Stockage serveur T_kw + metadonnees uniquement Zero-knowledge contractuel

3. Architecture ciblee

Note de delegation : Cette section decrit l'architecture globale du systeme de recherche chiffree. Les composants CLIENT (Canonicalizer, KeyDeriver, Tokenizer) sont implementes dans le cadre de PD-42. Les composants SERVEUR (MetadataValidator, SearchIndex, TokenStorage) sont specifies ici a titre de contrat d'interface, mais leur implementation est deleguee a PD-236 (Recherche backend par tokens deterministes).

┌─────────────────────────────────────────────────────────────────┐
│                     CLIENT (PD-42)                               │
├─────────────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐  │
│  │ Canonicalizer │  │ KeyDeriver   │  │ Tokenizer            │  │
│  │ (KW-CANON-01) │  │ (HKDF)       │  │ (HMAC-SHA256-B64T22) │  │
│  └──────────────┘  └──────────────┘  └──────────────────────┘  │
│           │                │                    │                │
│           └────────────────┼────────────────────┘                │
│                            ▼                                     │
│                  ┌──────────────────┐                            │
│                  │ SearchClient API │                            │
│                  └──────────────────┘                            │
└─────────────────────────────────────────────────────────────────┘
                             │ T_kw + metadonnees (jamais keyword en clair)
┌─────────────────────────────────────────────────────────────────┐
│                     SERVEUR (PD-236)                             │
├─────────────────────────────────────────────────────────────────┤
│  ┌──────────────────┐  ┌──────────────────┐                     │
│  │ MetadataValidator │  │ SearchIndex      │                     │
│  │ (ERR-04)          │  │ (egalite stricte)│                     │
│  └──────────────────┘  └──────────────────┘                     │
│                                │                                 │
│                                ▼                                 │
│                  ┌──────────────────────┐                        │
│                  │ TokenStorage         │                        │
│                  │ (T_kw, resource_id,  │                        │
│                  │  algorithm_id,       │                        │
│                  │  canonicalization_id,│                        │
│                  │  k_search_scope)     │                        │
│                  └──────────────────────┘                        │
└─────────────────────────────────────────────────────────────────┘

4. Decoupage technique

4.1 Module Canonicalizer (Client)

Responsabilite : Transformer un keyword brut en keyword canonique selon KW-CANON-01.

Interface :

interface Canonicalizer {
  canonicalize(keyword: string): Result<string, CanonicalizeError>;
}

type CanonicalizeError =
  | { code: 'ERR-01'; message: 'Keyword vide apres canonicalisation' }
  | { code: 'ERR-02'; message: 'Caractere de controle detecte' }
  | { code: 'ERR-05'; message: 'Depassement keyword_max_len_bytes' };

Algorithme : 1. Verifier UTF-8 valide → sinon ERR-02 2. Normaliser en NFC (UAX #15) 3. Trim espaces Unicode White_Space (debut/fin) 4. Remplacer sequences White_Space internes par U+0020 5. Convertir en minuscules (Unicode simple case mapping, sans locale) 6. Si resultat vide → ERR-01 7. Si caractere Cc/Cs present → ERR-02 8. Si longueur UTF-8 > 256 octets → ERR-05 9. Retourner keyword canonique

Observable : Keyword canonique identique pour toutes variantes equivalentes (TC-NOM-02)


4.2 Module KeyDeriver (Client)

Responsabilite : Deriver K_search a partir de K_master_user via HKDF-SHA256.

Interface :

interface KeyDeriver {
  deriveSearchKey(kMasterUser: Uint8Array): Result<Uint8Array, KeyError>;
}

type KeyError = { code: 'ERR-03'; message: 'K_master_user absente ou invalide' };

Algorithme : 1. Verifier K_master_user.length === 32 → sinon ERR-03 2. salt = 0x00 * 32 (32 octets de zeros) 3. info = "keyword_search" (ASCII, 14 octets) 4. K_search = HKDF-SHA256(K_master_user, salt, info, L=32) 5. Retourner K_search (32 octets)

Observable : K_search identique pour meme K_master_user (determinisme)


4.3 Module Tokenizer (Client)

Responsabilite : Produire T_kw a partir d'un keyword canonique et K_search.

Interface :

interface Tokenizer {
  tokenize(keywordCanonical: string, kSearch: Uint8Array): string;
}

Algorithme : 1. hmac = HMAC-SHA256(K_search, keywordCanonical en UTF-8) 2. b64 = Base64Encode(hmac, alphabet URL-safe, sans padding) 3. T_kw = b64.substring(0, 22) 4. Retourner T_kw

Contraintes : - Alphabet : A-Z a-z 0-9 - _ - Longueur fixe : 22 caracteres - Pas de padding '='

Observable : T_kw conforme aux vecteurs VEC-01, VEC-02, VEC-03


4.4 Module MetadataValidator (Serveur)

Delegation : Ce module est specifie ici a titre de contrat d'interface. L'implementation est realisee dans PD-236 — voir RequestValidatorService et DetHmacSha256B64T22V1Validator.

Responsabilite : Valider la conformite des metadonnees et rejeter les payloads non conformes.

Interface :

interface MetadataValidator {
  validate(request: IndexRequest | SearchRequest): Result<void, MetadataError>;
}

type MetadataError = { code: 'ERR-04'; message: string };

Regles de validation : 1. algorithm_id === "DET-HMAC-SHA256-B64T22-V1" (requis) 2. canonicalization_id === "KW-CANON-01" (requis) 3. k_search_scope === "USER" (requis) 4. Aucun champ "keyword" ou "keyword_raw" dans le payload 5. T_kw correspond au format attendu (22 chars, alphabet URL-safe)

Observable : Rejet ERR-04 trace dans les logs serveur


4.5 Module SearchIndex (Serveur)

Delegation : Ce module est specifie ici a titre de contrat d'interface. L'implementation est realisee dans PD-236 — voir TokenSearchService et TokenIndexRepository.

Responsabilite : Stocker et rechercher les associations T_kw ↔ resource_id.

Interface :

interface SearchIndex {
  index(entry: IndexEntry): Result<void, IndexError>;
  search(query: SearchQuery): SearchResult;
}

interface IndexEntry {
  token: string;           // T_kw (22 chars)
  resourceId: string;
  algorithmId: string;
  canonicalizationId: string;
  kSearchScope: string;
  userId?: string;         // Injecte par le serveur depuis le contexte auth (§9.5), jamais fourni par le client
}

interface SearchQuery {
  token: string;           // T_kw
  algorithmId: string;
  canonicalizationId: string;
  kSearchScope: string;    // Requis pour validation metadonnees (§4.4)
  userId?: string;         // Injecte par le serveur depuis le contexte auth (§9.5), jamais fourni par le client
}

interface SearchResult {
  resourceIds: string[];   // Ensemble sans doublons
}

Algorithme de recherche : 1. Extraire user_id du contexte d'authentification (§9.5) 2. Filtrer par user_id (isolation INV-04) 3. Filtrer par egalite stricte sur T_kw (byte-to-byte) 4. Verifier coherence des metadonnees (algorithm_id, canonicalization_id, k_search_scope) 5. Retourner ensemble des resource_id (deduplique)

Observable : Ensemble exact et reproductible (TC-NOM-04)


4.6 Module TokenStorage (Serveur)

Delegation : Ce module est specifie ici a titre de contrat d'interface. L'implementation est realisee dans PD-236 — voir TokenIndexRepository et schema search_token_index.

Responsabilite : Persister les donnees de l'index.

Schema de stockage :

CREATE TABLE search_tokens (
  id UUID PRIMARY KEY,
  token VARCHAR(22) NOT NULL,           -- T_kw
  resource_id UUID NOT NULL,
  algorithm_id VARCHAR(50) NOT NULL,
  canonicalization_id VARCHAR(20) NOT NULL,
  k_search_scope VARCHAR(10) NOT NULL,
  user_id UUID NOT NULL,
  created_at TIMESTAMP NOT NULL,

  CONSTRAINT chk_token_length CHECK (LENGTH(token) = 22),
  CONSTRAINT chk_token_format CHECK (token ~ '^[A-Za-z0-9_-]{22}$'),
  CONSTRAINT chk_no_plaintext CHECK (
    algorithm_id IS NOT NULL AND
    canonicalization_id IS NOT NULL
  )
);

CREATE INDEX idx_search_tokens_lookup
  ON search_tokens(token, user_id, algorithm_id, canonicalization_id);

Observable : Aucun keyword en clair dans la base (TC-NOM-06)


5. Flux detailles

5.1 Flux d'indexation

CLIENT                                          SERVEUR
  │                                                │
  │  1. keyword_raw = "  Foo\tBAR  "               │
  │  2. keyword_canon = canonicalize(keyword_raw)  │
  │     → "foo bar"                                │
  │  3. K_search = deriveSearchKey(K_master_user)  │
  │  4. T_kw = tokenize(keyword_canon, K_search)   │
  │     → "baCw880DWJd8mUmEtqgYQh"                 │
  │                                                │
  │  POST /index                                   │
  │  {                                             │
  │    "token": "baCw880DWJd8mUmEtqgYQh",         │
  │    "resource_id": "uuid-xxx",                  │
  │    "algorithm_id": "DET-HMAC-SHA256-B64T22-V1",│
  │    "canonicalization_id": "KW-CANON-01",       │
  │    "k_search_scope": "USER"                    │
  │  }                                             │
  │ ─────────────────────────────────────────────► │
  │                                                │
  │                   5. Extract user_id from auth │
  │                      context (JWT/session)     │
  │                   6. validate(request)         │
  │                   7. store(entry + user_id)    │
  │                                                │
  │ ◄───────────────────────────────────────────── │
  │  201 Created                                   │

5.2 Flux de recherche

CLIENT                                          SERVEUR
  │                                                │
  │  1. keyword_raw = "FOO   bar"                  │
  │  2. keyword_canon = canonicalize(keyword_raw)  │
  │     → "foo bar"                                │
  │  3. K_search = deriveSearchKey(K_master_user)  │
  │  4. T_kw = tokenize(keyword_canon, K_search)   │
  │     → "baCw880DWJd8mUmEtqgYQh"                 │
  │                                                │
  │  POST /search                                  │
  │  {                                             │
  │    "token": "baCw880DWJd8mUmEtqgYQh",         │
  │    "algorithm_id": "DET-HMAC-SHA256-B64T22-V1",│
  │    "canonicalization_id": "KW-CANON-01",       │
  │    "k_search_scope": "USER"                    │
  │  }                                             │
  │ ─────────────────────────────────────────────► │
  │                                                │
  │                   5. Extract user_id from auth │
  │                      context (JWT/session)     │
  │                   6. validate(request)         │
  │                   7. search(T_kw, user_id)     │
  │                      egalite stricte + filtre  │
  │                      par user_id               │
  │                                                │
  │ ◄───────────────────────────────────────────── │
  │  200 OK                                        │
  │  { "resource_ids": ["uuid-xxx", "uuid-yyy"] }  │

5bis. Diagrammes Mermaid

5bis.1 Graphe de dependances des composants

graph TD
    subgraph CLIENT_PD42["CLIENT (PD-42)"]
        CANON["Canonicalizer<br/>KW-CANON-01"]
        KDER["KeyDeriver<br/>HKDF-SHA256"]
        TOK["Tokenizer<br/>HMAC-SHA256-B64T22"]
        SCLI["SearchClient API"]
    end

    subgraph SERVEUR_PD236["SERVEUR (PD-236)"]
        MVAL["MetadataValidator<br/>ERR-04"]
        SIDX["SearchIndex<br/>egalite stricte"]
        TSTO["TokenStorage<br/>search_tokens"]
    end

    subgraph CRYPTO_EXT["Dependances cryptographiques"]
        KMASTER["K_master_user<br/>(32 octets CSPRNG)"]
        HKDF["HKDF-SHA256<br/>RFC 5869"]
        HMAC["HMAC-SHA256"]
        B64["Base64 URL-safe<br/>RFC 4648"]
    end

    subgraph AUTH["Contexte d'authentification"]
        JWT["JWT / Session"]
    end

    KMASTER --> KDER
    HKDF --> KDER
    KDER -->|K_search| TOK
    CANON -->|keyword_canon| TOK
    HMAC --> TOK
    B64 --> TOK
    TOK -->|T_kw| SCLI
    SCLI -->|"POST /index<br/>POST /search"| MVAL
    MVAL --> SIDX
    SIDX --> TSTO
    JWT -->|user_id| SIDX

    style CLIENT_PD42 fill:#e8f4f8,stroke:#2196F3
    style SERVEUR_PD236 fill:#fff3e0,stroke:#FF9800
    style CRYPTO_EXT fill:#f3e5f5,stroke:#9C27B0
    style AUTH fill:#e8f5e9,stroke:#4CAF50

5bis.2 Diagramme de sequence — Flux d'indexation (multi-service)

sequenceDiagram
    participant U as Utilisateur
    participant C as Client (PD-42)
    participant Canon as Canonicalizer
    participant KDer as KeyDeriver
    participant Tok as Tokenizer
    participant API as Serveur API (PD-236)
    participant MVal as MetadataValidator
    participant SIdx as SearchIndex
    participant DB as TokenStorage (PostgreSQL)

    U->>C: keyword_raw = "  Foo\tBAR  "
    C->>Canon: canonicalize(keyword_raw)
    Canon-->>C: "foo bar"
    C->>KDer: deriveSearchKey(K_master_user)
    KDer-->>C: K_search (32 octets)
    C->>Tok: tokenize("foo bar", K_search)
    Tok-->>C: T_kw = "baCw880DWJd8mUmEtqgYQh"

    C->>API: POST /index {token, resource_id, algorithm_id, canonicalization_id, k_search_scope}
    API->>API: Extract user_id from JWT/session
    API->>MVal: validate(request)
    alt Metadonnees non conformes
        MVal-->>API: ERR-04
        API-->>C: 400 Bad Request
    else Metadonnees conformes
        MVal-->>API: OK
        API->>SIdx: index(entry + user_id)
        SIdx->>DB: INSERT INTO search_tokens
        DB-->>SIdx: OK
        SIdx-->>API: OK
        API-->>C: 201 Created
    end

5bis.3 Diagramme de sequence — Flux de recherche (multi-service)

sequenceDiagram
    participant U as Utilisateur
    participant C as Client (PD-42)
    participant Canon as Canonicalizer
    participant KDer as KeyDeriver
    participant Tok as Tokenizer
    participant API as Serveur API (PD-236)
    participant MVal as MetadataValidator
    participant SIdx as SearchIndex
    participant DB as TokenStorage (PostgreSQL)

    U->>C: keyword_raw = "FOO   bar"
    C->>Canon: canonicalize(keyword_raw)
    Canon-->>C: "foo bar"
    C->>KDer: deriveSearchKey(K_master_user)
    KDer-->>C: K_search (32 octets)
    C->>Tok: tokenize("foo bar", K_search)
    Tok-->>C: T_kw = "baCw880DWJd8mUmEtqgYQh"

    C->>API: POST /search {token, algorithm_id, canonicalization_id, k_search_scope}
    API->>API: Extract user_id from JWT/session
    API->>MVal: validate(request)
    alt Metadonnees non conformes
        MVal-->>API: ERR-04
        API-->>C: 400 Bad Request
    else Metadonnees conformes
        MVal-->>API: OK
        API->>SIdx: search(T_kw, user_id)
        SIdx->>DB: SELECT resource_id WHERE token = T_kw AND user_id = ?
        DB-->>SIdx: [uuid-xxx, uuid-yyy]
        SIdx-->>API: {resource_ids: [uuid-xxx, uuid-yyy]}
        API-->>C: 200 OK {resource_ids: [...]}
    end

6. Mapping Invariants → Mecanismes techniques

ID Invariant Mecanisme technique Observable
INV-01 Determinisme T_kw HMAC-SHA256 est une PRF deterministe ; meme entree → meme sortie T_kw identique sur executions repetees (TC-NOM-01)
INV-02 Pas de collision fonctionnelle HMAC-SHA256 est collision-resistant dans l'espace nominal (≤256 octets) ; troncature 132 bits suffisante T_kw distincts pour keywords distincts (TC-NOM-03)
INV-03 Zero-knowledge serveur API serveur n'accepte que T_kw + metadonnees ; validation ERR-04 rejette tout payload avec keyword en clair Inspection logs + stockage ne revele aucun clair (TC-NOM-06)
INV-04 Isolation K_search HKDF derive K_search par K_master_user unique ; scope USER ; pas de partage inter-utilisateurs T_kw differents pour meme keyword, utilisateurs differents (TC-NOM-05)
INV-05 Egalite stricte Comparaison byte-to-byte sur T_kw (22 chars) ; pas de normalisation cote serveur Resultats exacts et reproductibles (TC-NOM-04)

7. Mapping Criteres d'acceptation → Tests

ID Critere Mecanisme Test(s) Observable
CA-01 Meme keyword → meme T_kw HMAC-SHA256 deterministe + canonicalisation KW-CANON-01 TC-NOM-01, TC-NR-01 Egalite stricte des T_kw
CA-02 Keywords differents → T_kw differents Resistance aux collisions HMAC-SHA256 TC-NOM-03 Inegalite des T_kw
CA-03 Aucun clair serveur Validation ERR-04 + schema DB sans champ keyword TC-NOM-06, TC-NEG-01 Inspection logs et DB
CA-04 Resultat exact et reproductible Egalite stricte + ensemble deduplique TC-NOM-04 Comparaison d'ensembles
CA-05 Absence de faux positifs INV-02 + egalite stricte TC-NOM-04 Zero ressource non attendue

8. Gestion des erreurs

Code Situation Point d'interception Reponse Log
ERR-01 Keyword vide apres canonicalisation Canonicalizer (client) 400 Bad Request { "error": "ERR-01", "message": "Keyword vide" }
ERR-02 UTF-8 invalide ou caractere Cc/Cs Canonicalizer (client) 400 Bad Request { "error": "ERR-02", "message": "Keyword non canonicalisable" }
ERR-03 K_master_user absente ou != 32 octets KeyDeriver (client) Operation impossible Log client uniquement
ERR-04 Metadonnees non conformes ou clair detecte MetadataValidator (serveur) 400 Bad Request { "error": "ERR-04", "message": "Non-conformite" } + trace audit
ERR-05 keyword_canon > 256 octets UTF-8 Canonicalizer (client) 400 Bad Request { "error": "ERR-05", "message": "Depassement longueur max" }

Observabilite : - Chaque rejet genere une trace avec code ERR-xx - Les traces serveur ne contiennent jamais de keyword en clair - Format de trace : [timestamp] [user_id] [operation] [error_code] [details]


9. Securite et contraintes cryptographiques

9.1 Isolation des cles

  • K_master_user est unique par utilisateur (32 octets aleatoires CSPRNG)
  • K_search est derivee et ne doit jamais etre partagee
  • Aucune cle ne transite vers le serveur

9.2 Zero-knowledge

  • Le serveur ne recoit que T_kw (22 chars) + metadonnees
  • Validation stricte : tout champ suspect (keyword, keyword_raw, plaintext) → rejet ERR-04
  • Logs serveur : interdiction de logger des donnees potentiellement sensibles

9.3 Rotation des cles

  • Changement de K_master_user ou k_search_context → reindexation complete obligatoire
  • Procedure :
  • Generer nouveau K_master_user
  • Marquer ancien index comme obsolete
  • Re-tokeniser tous les keywords
  • Supprimer ancien index

9.4 Validation des metadonnees

  • algorithm_id doit etre exactement "DET-HMAC-SHA256-B64T22-V1"
  • canonicalization_id doit etre exactement "KW-CANON-01"
  • Mismatch → rejet ERR-04

9.5 Contexte d'identite et isolation USER

Origine du user_id : - Le user_id est extrait du contexte d'authentification serveur (JWT, session, ou equivalent) - Le client NE transmet PAS le user_id dans le payload de la requete - Le serveur DOIT injecter le user_id verifie avant toute operation d'indexation ou de recherche

Mecanisme d'injection :

interface AuthenticatedContext {
  userId: string;      // Extrait du token/session, jamais du payload client
  verified: boolean;   // Authentification validee
}

// Middleware serveur
function injectUserContext(request: IndexRequest | SearchRequest, ctx: AuthenticatedContext): void {
  if (!ctx.verified) {
    throw new AuthenticationError();
  }
  request.userId = ctx.userId;  // Injection cote serveur uniquement
}

Contraintes : - Toute requete sans contexte d'authentification valide est rejetee (401 Unauthorized) - Le user_id utilise pour le stockage et la recherche provient UNIQUEMENT du contexte serveur - Cette isolation garantit INV-04 : un utilisateur ne peut pas acceder aux T_kw d'un autre utilisateur


10. Hypotheses techniques

10.1 Hypotheses heritees de la spec

ID Hypothese Impact si faux
H-01 K_master_user est aleatoire (CSPRNG) de 32 octets Collisions ou compromission
H-02 Client applique KW-CANON-01 avant tokenisation Resultats incoherents
H-03 algorithm_id/canonicalization_id stables par index Index corrompu

10.2 Hypotheses d'implementation

ID Hypothese Impact si faux
H-04 Bibliotheque crypto conforme (HKDF, HMAC-SHA256) Tokens incorrects
H-05 Implementation Unicode NFC disponible et conforme UAX #15 Canonicalisation incorrecte
H-06 Base64 URL-safe sans padding disponible Format T_kw incorrect
H-07 Comparaison byte-to-byte sans normalisation cote serveur Faux positifs/negatifs
H-08 Stockage supporte VARCHAR(22) ou equivalent Troncature
H-09 user_id est fourni par un contexte d'authentification valide et verifie cote serveur (ex. JWT, session) ; le client ne peut pas usurper l'identite d'un autre utilisateur Violation de l'isolation K_search (INV-04)

11. Points de vigilance

11.1 Risques

Risque Probabilite Impact Mitigation
Implementation NFC non conforme Moyenne Canonicalisation incorrecte Tests avec corpus Unicode diversifie
Troncature Base64 incorrecte Faible Tokens invalides Golden tests VEC-01/02/03
Fuite de keyword dans logs Moyenne Violation zero-knowledge Revue de code + tests TC-NOM-06
Collision sur gros volume Tres faible Faux positif 132 bits suffisants, monitoring

11.2 Tests de non-regression critiques

  • TC-NR-01 : Meme configuration → T_kw inchange (golden tests)
  • TC-NR-02 : Ajout de keywords n'altere pas T_kw existants

11.3 Tests adversariaux

  • TC-NEG-01 : Injection keyword en clair → rejet + pas de persistance
  • TC-NEG-02 : Mismatch metadonnees → rejet ERR-04

11.4 Cas limites Unicode

  • Caracteres multi-octets (emoji, CJK)
  • Espaces Unicode exotiques (U+00A0, U+2003, etc.)
  • Formes NFD vs NFC
  • Caracteres de controle (U+0000-U+001F, surrogates)

12. Hors perimetre (rappel)

Explicitement exclus de cette implementation :

  • Recherche full-text, floue, partielle, semantique
  • Requetes multi-keywords (AND/OR)
  • Scoring et classement par pertinence
  • Protection contre analyse de frequence
  • Protection contre attaques par dictionnaire
  • Mitigation de l'access pattern leakage
  • Injectivite globale hors espace nominal

13. Vecteurs de test de reference (Golden Tests)

VEC-01
K_master_user (hex) : 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
K_search (hex)      : 1195e4e89019350a6a25ffd26d63a014cab1c0b61c8cd0f0568e86090a4b5bbd
keyword_raw         : "  Foo\tBAR  "
keyword_canon       : "foo bar"
T_kw                : baCw880DWJd8mUmEtqgYQh

VEC-02
K_master_user (hex) : 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
K_search (hex)      : 1195e4e89019350a6a25ffd26d63a014cab1c0b61c8cd0f0568e86090a4b5bbd
keyword_raw         : "foo baz"
keyword_canon       : "foo baz"
T_kw                : iu5WbKakmU2t6x3k3239lJ

VEC-03
K_master_user (hex) : 202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
K_search (hex)      : 88278ecb0b55489a036dbb61f0ce749bf4c58018c8b7398cbca3bdb728ad6213
keyword_raw         : "foo bar"
keyword_canon       : "foo bar"
T_kw                : xBUVIMiGYTXK9cvuR1Wi-E

Ces vecteurs DOIVENT passer pour valider l'implementation.


14. Checklist de livraison

14.1 Composants CLIENT (PD-42)

  • Module Canonicalizer implemente et teste (TC-NOM-02, TC-ERR-01, TC-ERR-02, TC-ERR-05)
  • Module KeyDeriver implemente et teste (TC-ERR-03)
  • Module Tokenizer implemente et teste (VEC-01, VEC-02, VEC-03)
  • Tests nominaux client passes (TC-NOM-01 a TC-NOM-07)
  • Tests d'erreur client passes (TC-ERR-01 a TC-ERR-05)
  • Tests de non-regression passes (TC-NR-01, TC-NR-02)

14.2 Composants SERVEUR (delegues a PD-236)

Les items ci-dessous sont implementes dans PD-236 (Recherche backend par tokens deterministes). Voir PD-236-acceptability.md pour le verdict d'acceptabilite (✅ ACCEPTE).

  • API d'indexation implementee (flux 5.1) → PD-236
  • API de recherche implementee (flux 5.2) → PD-236
  • MetadataValidator implemente (TC-ERR-04, TC-NEG-01, TC-NEG-02) → PD-236 RequestValidatorService
  • Schema de stockage deploye → PD-236 search_token_index
  • Tests adversariaux serveur passes (TC-NEG-01, TC-NEG-02, TC-NEG-03) → PD-236
  • Revue securite : aucun keyword en clair dans logs/DB → PD-236 TC-INV-01

14.3 Documentation

  • Documentation API

References

  • Specification : PD-42-specification.md
  • Tests : PD-42-tests.md
  • Epic : PD-189 CRYPTO
  • JIRA : PD-42
  • Delegation serveur : PD-236 — Recherche backend par tokens deterministes (epic PD-186 BACKEND CORE)
  • Specification : ProbatioVault-backend/docs/epics/backend-core/PD-236-recherche-tokens/PD-236-specification.md
  • Acceptabilite : ProbatioVault-backend/docs/epics/backend-core/PD-236-recherche-tokens/PD-236-acceptability.md (✅ ACCEPTE)