# Dérivation de clés biométriques pour l'identité décentralisée avec les fuzzy extractors

> Et si votre biométrie, par exemple votre « visage », était votre clé privée ? Pas de seed phrase à perdre, pas de mot de passe à oublier, pas de clé à stocker. Votre biométrie génère votre wallet, qui contient vos verifiable credentials, que vous prouvez à l'aide de ZKP.

Par Shodipo Ayomide, publié le 21 oct. 2025. Version web : https://blog.shodipoayomide.com/fr/biometric-bound-key-derivation-for-decentralized-identity-using-fuzzy-extractors

![Dérivation de clés liée à la biométrie pour la DID avec les fuzzy extractors](https://blog.shodipoayomide.com/banners/biometric-bound-key-derivation-for-decentralized-identity-using-fuzzy-extractors.png)

Les systèmes d'identité actuels nous obligent à faire énormément confiance aux entreprises pour stocker nos données de manière sécurisée. De nombreux fournisseurs de KYC conservent vos données indéfiniment. Chaque app reçoit l'intégralité de vos informations, même quand elle a seulement besoin de savoir que vous avez plus de 18 ans, ce qui fait beaucoup trop d'informations partagées et éparpillées un peu partout.

L'identité auto-souveraine (Self-Sovereign Identity) **SSI** règle ce problème en vous donnant le contrôle de vos credentials, vous pouvez partager uniquement ce qui est nécessaire et prouver des affirmations sans révéler de données. en gros, les verifiable credentials **VC** vous permettent de prouver que vous avez plus de 18 ans sans montrer votre date de naissance exacte. Mais la **SSI** a un problème - où stocker les clés privées qui contrôlent votre identité ?

Il existe beaucoup de solutions de fond à ce problème, et l'une d'elles est celle des `biometric crypto identities`, qui ne fait pas partie des plus populaires, la question est la suivante : et si votre `biometric`, par exemple votre `face`, était votre `private-key` ? Pas de `seed phrases` à perdre, pas de `passwords` à oublier, pas de `keys` à stocker. Votre `biometric` génère votre `wallet`, qui contient vos verifiable credentials, que vous prouvez à l'aide de ZKP.

C'est possible grâce aux `fuzzy extractors` + `zero-knowledge proofs`. Voici comment ça marche.

## Le vrai problème que cela pourrait résoudre

Les systèmes cryptographiques traditionnels ont été conçus pour des bits reproductibles. Mais la biométrie enfreint deux règles essentielles sur lesquelles reposent ces systèmes :

**Les clés doivent être parfaitement reproductibles** - Ces systèmes exigent une reproduction des clés exacte au bit près. Votre clé privée pour signer des transactions doit être identique à chaque fois. Mais la biométrie est bruitée, il y a beaucoup de variables à prendre en compte. Le scan de votre empreinte digitale aujourd'hui ne correspondra pas bit pour bit à celui d'hier, à cause des variations du capteur, du placement du doigt, de l'humidité, de la température - et la liste est encore longue. Même chose pour les scans du visage, les motifs de l'iris ou n'importe quelle mesure biologique.

**Les clés doivent être uniformément aléatoires** - La sécurité cryptographique suppose que votre clé est tirée uniformément au hasard dans tout l'espace des clés. Mais les données biométriques ont une structure et des motifs. Votre iris n'est pas uniformément aléatoire, il est soumis à des contraintes biologiques, présente des similarités à l'échelle de la population, et son entropie est concentrée dans certaines caractéristiques précises.

Cela crée le problème classique de l'œuf et de la poule : vous ne pouvez pas utiliser directement la biométrie comme clé **elle est très bruitée**, vous ne pouvez pas la stocker de manière sécurisée **ce sont des PII, et elles sont immuables**, et vous ne pouvez pas simplement la hacher **le bruit casse les fonctions de hachage**, comme vous le savez. Alors, que faire ?

Et c'est là que ça devient intéressant !

## Que sont les fuzzy extractors ?

Voyez les fuzzy extractors comme de la cryptographie à correction d'erreurs pour les données bruitées. Il s'agit d'une paire d'algorithmes, `Gen` *générer* et `Rep` *reproduire*, qui font quelque chose de vraiment passionnant :

$Gen(w) \rightarrow (R, P)$ - Prend votre entrée biométrique bruitée `w` et produit une chaîne uniformément aléatoire `R` **la vraie clé cryptographique** ainsi qu'une chaîne d'aide publique `P`. Et voici un autre fait amusant : `P` peut être publiée ouvertement sans compromettre la sécurité. Elle ne révèle absolument aucune information utile sur votre biométrie.

$Rep(w', P) \rightarrow R$ - Prend une autre lecture biométrique `w'` et la même chaîne d'aide publique `P`, puis reproduit exactement la même `R` tant que `w'` est **suffisamment proche** de la `w` d'origine. Je sais que ça peut faire peur, mais ici, **suffisamment proche** se mesure par une distance dans un certain espace métrique **distance de Hamming pour les chaînes binaires, distance d'édition pour les séquences, différence d'ensembles pour les vecteurs de caractéristiques**.

La garantie de sécurité relève de la théorie de l'information : même en connaissant `P`, la clé extraite `R` est $\varepsilon$-proche de l'uniforme tant que votre biométrie a une min-entropie $\geq m$. Aucune hypothèse de difficulté calculatoire n'est nécessaire. Un adversaire doté d'une puissance de calcul infinie ne peut toujours pas distinguer  `R` d'une clé réellement aléatoire avec un avantage supérieur à $\varepsilon$.

Les mathématiques sont magnifiques. Pour un fuzzy extractor de paramètres $(m, \ell, t, \varepsilon)$ :

- $m$ = min-entropie de votre entrée biométrique **bits d'imprévisibilité**
- $\ell$ = longueur de la clé extraite `R`
- $t$ = tolérance aux erreurs **à quel point `w'` peut différer de `w`**
- $\varepsilon$ = distance statistique par rapport à l'uniforme **paramètre de sécurité**

## Comment ça marche concrètement

La construction utilise deux primitives qui travaillent ensemble :

### Les secure sketches $(SS, Rec)$

Un secure sketch ressemble à un engagement flou (fuzzy commitment). $SS(w) \rightarrow s$ produit un sketch `s` qui révèle juste assez d'informations pour corriger les erreurs, mais loin d'être assez pour reconstruire `w` elle-même. Ensuite, $Rec(w', s) \rightarrow w$ retrouve la `w` d'origine à partir d'une `w'` bruitée, grâce au sketch.

Pour les chaînes binaires avec la distance de Hamming, la Syndrome Construction est optimale :

```python
class SyndromeSketch:
    def __init__(self, n, k, t):
        self.n, self.k, self.t = n, k, t
        self.syn_matrix = generate_bch_syndrome_matrix(n, k)

    def sketch(self, w):
        return np.dot(self.syn_matrix, w) % 2

    def recover(self, w_prime, s):
        s_prime = np.dot(self.syn_matrix, w_prime) % 2
        error_syn = (s_prime - s) % 2
        e = bch_decode(error_syn, self.t)
        return (w_prime - e) % 2
```

Ce qui se passe ici :

- `sketch()` calcule le syndrome de la biométrie `w` et produit `s`, soit `$n-k$` bits
- `recover()` corrige les erreurs de la `w_prime` bruitée à l'aide du sketch `s`
- La perte d'entropie est exactement égale à la longueur du sketch, soit `$n-k$` bits
- Pour le code `BCH` étendu $(128, 64, 22)$ **codes de Bose–Chaudhuri–Hocquenghem** : on perd 64 bits, et on corrige jusqu'à $t = \lfloor(22-1)/2\rfloor = 10$ erreurs

### Maintenant, du sketch à l'extracteur

Après la correction d'erreurs, on hache la biométrie retrouvée pour en extraire une clé uniforme, par exemple

```rust
pub fn fuzzy_gen(biometric: &[u8]) -> (Vec<u8>, Vec<u8>) {
    let sketch = secure_sketch(biometric);
    let seed: Vec<u8> = (0..32).map(|_| rng.gen()).collect();
    let key = extract_key(biometric, &seed);
    let helper = [sketch, seed].concat();
    (key, helper)
}

pub fn fuzzy_rep(noisy_biometric: &[u8], helper: &[u8]) -> Vec<u8> {
    let (sketch, seed) = split_helper(helper);
    let recovered = sketch_recover(noisy_biometric, sketch);
    extract_key(&recovered, &seed)
}
```

La fonction `fuzzy_gen()` :

- Crée un sketch à partir de la biométrie
- Génère une seed aléatoire pour la fonction de hachage
- Extrait la clé avec `hash(biometric || seed)`
- Renvoie `key, helper`, où helper = `sketch, seed`

La fonction `fuzzy_rep()` :

- Retrouve la biométrie d'origine à partir du scan bruité, grâce au sketch
- Applique la même fonction de hachage avec la même seed
- Produit exactement la même clé !

Pour les biométries courantes :

- Iris : code brut de 2048 bits **~249 bits d'entropie réelle**, 10-30 % d'erreurs → extraction de **clés de 40 à 105 bits**
- Empreinte digitale : 20-80 minuties **~50-150 bits**, bruit élevé → extraction de **clés de 8 à 40 bits**
- Visage : embedding de 512 dimensions **20-60 bits d'entropie effective**

> Note : Les représentations biométriques brutes contiennent de la redondance et des corrélations. Les codes d'iris présentent un ratio de ~8:1 entre les bits bruts (2048) et l'entropie au sens de la théorie de l'information (~249 bits). L'extraction de clé doit respecter l'entropie réelle, pas la taille de la représentation.

## Le volet identité
![](https://i.ibb.co/MyZNpbG3/Screenshot-2025-10-21-at-4-02-19-PM.png)

Le modèle de confiance de la SSI compte trois acteurs :

- Détenteur de l'identité - Vous, avec un wallet contenant vos credentials
- Émetteur - Source de confiance (gouvernement, université, fournisseur de KYC)
- Vérificateur - Consommateur de confiance (dApps, smart contracts)
- Confiance du monde réel - Le pont entre l'émetteur et le vérificateur

Le flux complet :
**Biométrie → Wallet → Credentials → Preuves ZK → Identité vérifiée**

![](https://i.ibb.co/WpHYM9Fq/image.png)

Voyons cela étape par étape :

### De la biométrie au wallet

```javascript
async function biometricToWallet(rawBiometric) {
    const binary = await preprocessBiometric(rawBiometric);
    const { key, helper } = await fuzzyExtractor.gen(binary);

    const expandedKey = await hkdf(
        key,
        128,
        'bip39-seed',
        await crypto.getRandomValues(new Uint8Array(32))
    );

    const mnemonic = bip39.entropyToMnemonic(expandedKey);
    const seed = await bip39.mnemonicToSeed(mnemonic);
    const master = bip32.fromSeed(seed);

    return {
        btc: deriveBitcoin(master),
        eth: deriveEthereum(master),
        sol: deriveSolana(seed),
        helper,
        salt
    };
}
```

Le processus :

- Prétraiter la biométrie → vecteur binaire **code d'iris, embedding du visage, etc.**
- Exécuter `fuzzy_gen()` → obtenir une clé de 40 à 128 bits + une chaîne d'aide publique
- Convertir en mnémonique `BIP39` → dériver la seed du wallet HD
- Dériver les adresses pour BTC `P2WPKH`, ETH `EVM`, SOL `Ed25519`
- Renvoyer les adresses + la chaîne d'aide + le salt **tout peut être stocké publiquement !**

Pour Solana en particulier, c'est une **courbe différente** :

```javascript
import { derivePath } from 'ed25519-hd-key';

const solSeed = derivePath("m/44'/501'/0'/0'", seed.toString('hex')).key;
const solKeypair = Keypair.fromSeed(solSeed);
const solAddress = solKeypair.publicKey.toBase58();
```

> Note : Solana utilise `Ed25519`, pas `secp256k1`. Dans votre implémentation, utilisez donc `ed25519-hd-key` pour être conforme à `SLIP-0010` **correspond à `Phantom`, `Solflare`**.

### Obtenir vos verifiable credentials

Votre wallet a maintenant un `DID`, mais pour prouver quoi que ce soit, il vous faut un Verifiable Credential **VC**. C'est là que commence le triangle de confiance.
L'émetteur vérifie vos documents off-chain et émet une preuve signée cryptographiquement :

```javascript
async function requestCredential(wallet, issuerEndpoint, claimData) {
    const connectionRequest = await issuerEndpoint.createConnection(wallet.did);
    
    const credentialOffer = await issuerEndpoint.offerCredential({
        type: 'KYCCredential',
        schema: 'https://schema.org/kyc-v1',
        claims: {
            country: claimData.country,
            birthYear: claimData.birthYear,
            verified: true
        }
    });
    
    const signedVC = await wallet.acceptCredential(credentialOffer);
    await wallet.storeCredential(signedVC);
    
    return signedVC;
}
```
Ce qui s'est passé :

- L'émetteur vérifie vos documents off-chain, par exemple passeport, selfie, etc.
- Il émet un `VC` signé `cryptographically` avec vos affirmations
- Le `VC` inclut la signature du `DID` de l'émetteur, qui en prouve l'authenticité
- Il est stocké localement dans votre wallet, pas sur la blockchain
- Plusieurs `VCs` provenant de différents émetteurs : formation, emploi, KYC

Le schéma du credential définit ce que contient le VC :
```json
{
  "@context": "https://www.w3.org/2018/credentials/v1",
  "type": ["VerifiableCredential", "KYCCredential"],
  "issuer": "did:polygonid:polygon:amoy:2qH7...",
  "issuanceDate": "2025-01-15T00:00:00Z",
  "credentialSubject": {
    "id": "did:polygonid:polygon:amoy:2qPz...",
    "birthYear": 1995,
    "country": "US",
    "kycVerified": true
  },
  "proof": {
    "type": "BJJSignature2021",
    "issuerData": {...},
    "signature": "0x..."
  }
}
```
Désormais, quand un vérificateur vous demande de **prouver que vous avez plus de 18 ans**, vous générez une ZKP à partir de ce credential.

### La couche de preuve à divulgation nulle de connaissance

C'est ici que vous pouvez prouver vos informations personnelles, comme **l'âge, la citoyenneté, un diplôme, l'adresse, la date de naissance, etc.**, sans révéler ces données sensibles.

```javascript
async function proveAge(wallet, minAge) {
    const credential = await wallet.getCredential('kyc');
    const inputs = {
        birthYear: credential.birthYear,
        currentYear: 2025,
        minAge: minAge,
        signature: credential.signature
    };

    const { proof, publicSignals } = await snarkjs.groth16.fullProve(
        inputs,
        "ageCheck.wasm",
        "ageCheck.zkey"
    );

    return { proof, publicSignals };
}
```

Ce qui est prouvé :

- L'utilisateur a plus de `minAge` ans
- Le credential est signé par un émetteur de confiance
- Ce qui n'est PAS révélé : l'âge réel, la date de naissance, le nom ou toute autre PII

Le circuit Circom :

```circom
template AgeCheck() {
    signal input birthYear;
    signal input currentYear;
    signal input minAge;

    signal age <== currentYear - birthYear;

    component check = GreaterEqThan(16);
    check.in[0] <== age;
    check.in[1] <== minAge;
    
    signal output isValid;
    isValid <== check.out;
}
```

Vérification on-chain - `Solidity` :

```solidity
contract IdentityGate {
    mapping(address => mapping(uint256 => bool)) public verified;

    function submitProof(
        uint256 requestId,
        uint[2] calldata pA,
        uint[2][2] calldata pB,
        uint[2] calldata pC,
        uint[3] calldata pubSignals
    ) external {
        require(zkpVerifier.verifyProof(pA, pB, pC, pubSignals), "Invalid proof");
        require(pubSignals[2] >= minAge, "Age requirement not met");

        verified[msg.sender][requestId] = true;
        _grantAccess(msg.sender);
    }
}
```

Le contrat :

- Vérifie cryptographiquement la preuve ZK
- Contrôle les signaux publics **DID de l'émetteur, seuil d'âge**
- Marque l'utilisateur comme vérifié
- Exécute la logique métier **airdrop, accès à une DAO, etc.**

À partir de ce flux, vous voyez donc comment votre biométrie est devenue :

- **Votre wallet** - Multi-chain, non-custodial, sans seed phrase
- **Votre identité** - Un identifiant décentralisé `DID` ancré à votre biométrie
- **Vos credentials** - Des verifiable credentials `VC` provenant d'émetteurs de confiance
- **Votre vie privée** - Des preuves à divulgation nulle de connaissance `ZKP` qui ne révèlent rien sur vous

Et il ne s'agit pas de plusieurs systèmes séparés - c'est UN seul flux unifié. La génération du wallet a lieu une seule fois, lors de l'enrôlement. Le flux ZKP peut être utilisé chaque fois qu'une vérification d'identité est nécessaire. Voyez-le ainsi : vous pouvez utiliser votre wallet biométrique comme n'importe quel autre wallet crypto pour vos transactions habituelles. Mais quand une dApp a besoin d'un KYC ou de n'importe quel type de vérification basée sur des `PII` **comme les cas d'usage de `Polygon ID`**, la couche ZKP entre en jeu pour prouver vos credentials sans exposer vos données.

## Quelques cas d'usage possibles

1. **Passeports agentiques :**

Chaque agent IA peut avoir un `DID` dérivé d'une biométrie. Imaginez un agent IA de trading avec son propre wallet et des credentials vérifiés :

```javascript
class TradingAgent {
    constructor(agentFingerprint) {
        this.wallet = await biometricToWallet(agentFingerprint);
        this.did = await createDID(this.wallet);
    }

    async trade(dex, params) {
        const proof = await this.proveReputation();
        return await dex.trade(params, proof);
    }
}
```

L'agent :

- Dérive son wallet de sa `biometric` **hash du réseau de neurones**
- Prouve sa réputation **plus de 1000 trades réussis** via une `ZKP`
- Opère de manière autonome avec un historique vérifié

`SingularityNET` construit exactement ça, un AI Agent Trust Registry où les agents prouvent leur authenticité, leur sûreté et leur statut d'audit à l'aide de verifiable credentials. Le flux `biometric-wallet-ZKP` permet aux agents d'opérer de manière autonome tout en restant responsables de leurs actes.

2. **Couche d'identité pour dApps :**

Un protocole DeFi a besoin du KYC mais ne veut pas stocker les données des utilisateurs **responsabilité réglementaire + pot de miel pour les hackers** :

```solidity
contract DeFiProtocol {
    modifier onlyKYCVerified() {
        require(identityGate.verified(msg.sender, KYC_ID), "KYC required");
        _;
    }

    function borrowUndercollateralized(uint256 amount) external onlyKYCVerified {
        _issueLoan(msg.sender, amount);
    }
}
```

Le protocole ne voit jamais votre passeport, votre nom ni votre adresse. Conformité assurée, vie privée préservée.

Le même schéma s'applique pour :

- Le vote dans une DAO **prouver l'appartenance, pas l'identité**
- Les airdrops **prouver qu'on est humain, empêcher les bots**
- Les restrictions d'âge **prouver qu'on a plus de 18 ans, pas l'âge exact**

3. **Connexion sans mot de passe pour le Web2**

```javascript
async function login(website) {
    const { key } = await fuzzyExtractor.rep(biometric, helper);
    const siteKey = deriveKey(key, website.domain);
    const signature = sign(challenge, siteKey);
    await website.verify(signature);
}
```

Chaque site obtient une clé dérivée unique. Aucun mot de passe envoyé, aucun identifiant à hameçonner.

4. **Paiements biométriques :**

Votre biométrie autorise la transaction :

```javascript
async function pay(merchant, amount) {
    const wallet = await biometricToWallet(scan);

    if (amount > 1000) {
        await merchant.verifyProof(generateKYCProof(wallet));
    }

    await wallet.sendTransaction({ to: merchant.address, value: amount });
}
```

[BMONI](https://bmoni.com) + `BKey` implémente actuellement ce principe : vos wallets sont entièrement dérivés de votre biométrie « **votre visage** » et provisionnés sur certaines chaînes EVM et certains tokens, le tout via votre visage !

5. **Base de données anti-arnaque :**

```solidity
contract AML {
    bytes32 public scamMerkleRoot;

    function checkClean(address wallet, bytes32[] calldata proof) public view returns (bool) {
        bytes32 hash = keccak256(abi.encodePacked(wallet));
        return !MerkleProof.verify(proof, scamMerkleRoot, hash);
    }
}
```

Les dApps l'interrogent avant d'accorder l'accès. Les arnaqueurs connus sont bloqués sur tout le réseau et ceux qui ont un historique d'activité étrange sont également signalés, tandis que les intégrateurs reçoivent une notification de l'activité suspecte passée.

## Intégrations pour les développeurs

Construire avec des identités biométriques nécessite de l'infrastructure. L'écosystème fournit trois composants principaux :

### Issuer Node

Les organisations font tourner des issuer nodes auto-hébergés pour émettre des credentials :

```bash
docker-compose up -d
make import-private-key-to-kms private_key=<eth-key>

# access the ui at localhost:8088
# access the api at localhost:3001
```

Fonctionnalités :

- Créer un `DID` d'émetteur
- Définir des `schemas` de credentials
- Émettre/révoquer des `VCs`
- Gérer les connexions des utilisateurs
- Faire transiter l'état on-chain **Polygon**

Exemple d'API :

```javascript
const issuerAPI = new IssuerNode({
    url: 'https://issuer.example.com',
    auth: { user: 'admin', password: 'secure' }
});

await issuerAPI.createIdentity({
    blockchain: 'polygon',
    network: 'amoy',
    method: 'polygonid'
});

await issuerAPI.issueCredential({
    did: 'did:polygonid:...',
    schema: 'KYCCredential',
    claims: { ageOver: 18 }
});
```

**Écosystème d'outils**

- Schema Builder : créez des schémas de VC personnalisés sur `tools.privado.id/builder`
- Query Builder : concevez des requêtes ZKP sur `tools.privado.id/query-builder`
- Schema Explorer : parcourez les `schemas` de la communauté
- Marketplace : découvrez des `issuers` de credentials

## Quelques défis techniques et leurs solutions

1 : **Variabilité biométrique**

Votre empreinte digitale varie de 10 à 15 % d'un scan à l'autre. Solution : les codes `BCH` sont optimaux pour la correction d'erreurs au niveau du bit. Pour un code d'iris de 2048 bits **qui contient ~249 bits d'entropie réelle** avec 10 % d'erreurs (~205 bits erronés) :

- Utiliser le code BCH $[2048, 1122, 341]$ sur $GF(2^{11})$ - corrige jusqu'à 170 bits erronés
- Perte d'entropie, $2048 - 1122 = 926$ bits (longueur du sketch)
- Entropie restante, $249 - (926 / 8.2) \approx 136$ bits d'entropie effective
- Extraire une clé de 128 bits **estimation prudente, qui tient compte de la perte d'entropie**

**Distinction essentielle** : les 2048 bits correspondent à la représentation BRUTE du code d'iris **sortie de l'algorithme de Daugman**. L'entropie réelle, au sens de la théorie de l'information, n'est que de ~249 bits, à cause des corrélations biologiques et de la redondance **ratio de ~8:1**.

2 : **Vieillissement du modèle biométrique**

Problème : votre visage change avec le temps **vieillissement, poids, pilosité faciale, etc.**

Solution : un ré-enrôlement périodique avec migration des clés :

```javascript
async function migrate(oldBio, newBio) {
    const oldWallet = await recover(oldBio);
    const { newWallet, newHelper } = await enroll(newBio);
    await oldWallet.transferAll(newWallet.address);
    await storage.update(newHelper);
}
```

Ré-enrôlez-vous tous les 2-3 ans pour le visage, tous les 5 ans pour l'iris, chaque année pour la voix, etc.

3 : **Détection du vivant**

Problème : un attaquant qui possède votre photo ne devrait pas pouvoir accéder à votre wallet.

Solution : des contrôles de détection du vivant lors de la capture biométrique :

```javascript
const checks = await Promise.all([
    depthSensor.measure(),
    motionDetector.verify(['blink', 'nod']),
    thermalCamera.capture(),
    videoAnalyzer.checkTemporal()
]);
```

L'Orb de WorldCoin fait cela avec des scans de l'iris : plus de 25 contrôles de détection du vivant, de l'imagerie 3D, des caméras infrarouges + RVB. Ça fonctionne incroyablement bien - taux de fausse acceptation $< 0.0001\%$.

4 : **Confidentialité de la chaîne d'aide**

Est-ce que `P`, expliquée plus haut, fait fuiter des informations biométriques ? Non. D'après le théorème **Dodis et al.**, l'attaquant apprend au plus $n-k$ bits **la longueur du sketch**, et la clé `R` reste statistiquement aléatoire. Pour notre iris : il apprend 408 bits, il reste 392 bits d'entropie.

## Est-ce prêt pour la production ?

Les briques existent déjà :

- Fuzzy extractors : la bibliothèque `CompFE` (MIT), qui tourne sur mobile
- Preuves ZK : BKey, Privado ID et d'autres sont en ligne sur le mainnet
- Matériel : le wallet D'CENT, FaceID, les capteurs d'empreintes sont partout
- Standards : W3C DIDs, VCs, WebAuthn
- Réseaux : BTC, ETH, Polygon, Solana prennent tous en charge les wallets HD **BIP32/39/44 depuis 2013**

Qu'est-ce qui manque ? Les intégrations...

## Exemple d'implémentation en production

Voici à quoi ressemble concrètement l'utilisation de ce système dans un environnement de production

```javascript
async function enrollUser() {
    const bio = await captureLive();
    const { key, helper } = await fuzzyExtractor.gen(bio);

    const salt = await crypto.getRandomValues(new Uint8Array(32));
    const expandedKey = await hkdf('sha256', key, salt, 'bip39-seed', 128/8);
    const wallet = await deriveWallet(expandedKey);

    const did = await createDID(wallet.eth);
    const kycCred = await requestKYC(did, { passport, selfie });

    await storage.save({ helper, salt, did, credentials: [kycCred] });
    return { wallet, did };
}

async function accessDApp(dappURL) {
    const bio = await captureLive();
    const { helper, salt } = await storage.getHelperData();
    const key = await fuzzyExtractor.rep(bio, helper);

    const expandedKey = await hkdf('sha256', key, salt, 'bip39-seed', 128/8);
    const wallet = await deriveWallet(expandedKey);

    const proof = await generateProof(wallet, dappURL.request);
    await submitProof(wallet, proof, dappURL.verifier);

    await dappURL.grantAccess(wallet.address);
}

async function sendPayment(recipient, amount) {
    const bio = await captureLive();
    const { helper, salt } = await storage.getHelperData();
    const key = await fuzzyExtractor.rep(bio, helper);

    const expandedKey = await hkdf('sha256', key, salt, 'bip39-seed', 128/8);
    const wallet = await deriveWallet(expandedKey);

    await wallet.send({ to: recipient, value: amount });
}
```

Le flux de wallet classique et le flux d'identité coexistent. La ZKP n'intervient que lorsqu'une vérification est nécessaire, que ce soit pour le KYC ou pour toute vérification basée sur des `PII`, comme l'âge, la citoyenneté, un diplôme, l'adresse, la date de naissance, etc. 

Votre biométrie est votre clé, votre wallet est votre identité sur toutes les chaînes prises en charge, et vous n'avez plus jamais à vous soucier de perdre votre seed phrase ou vos clés privées, tout est lié à vos attributs physiques, et dans l'implémentation de BMoni, c'est votre visage !

## Liens essentiels

- [Fuzzy Extractors Survey](https://www.cs.bu.edu/~reyzin/papers/fuzzysurvey.pdf) - Dodis, Reyzin, Smith
- [Fuzzy Extractors (SIAM)](https://epubs.siam.org/doi/10.1137/060651380)
- [Efficient Reusable Fuzzy Extractors from LWE](https://www.cs.umd.edu/~jkatz/papers/reusable-FE.pdf) - Constructions post-quantiques
- [CompFE](https://github.com/benjaminfuller/CompFE)
- [Polygon ID SDK](https://github.com/0xPolygonID) - Système d'identité basé sur les ZKP
- [La sécurité chez BMoni](https://bmoni.com/security/#22patents) - Notre architecture de sécurité
- [snarkjs](https://github.com/iden3/snarkjs) - Bibliothèque ZK-SNARK
