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 :
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
RequestValidatorServiceetDetHmacSha256B64T22V1Validator.
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
TokenSearchServiceetTokenIndexRepository.
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
TokenIndexRepositoryet schemasearch_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)