# Derivação de chaves biométricas para identidade descentralizada usando fuzzy extractors

> A pergunta é: e se a sua biometria, por exemplo o 'rosto', fosse a sua chave privada? Nada de seed phrases para perder, nada de senhas para esquecer, nada de chaves para guardar. A sua biometria gera a sua carteira, que guarda as suas credenciais verificáveis, que você prova usando ZKPs.

Por Shodipo Ayomide, publicado em 21 de out. de 2025. Versão web: https://blog.shodipoayomide.com/pt/biometric-bound-key-derivation-for-decentralized-identity-using-fuzzy-extractors

![Derivação de chaves vinculadas à biometria para DID usando fuzzy extractors](https://blog.shodipoayomide.com/banners/biometric-bound-key-derivation-for-decentralized-identity-using-fuzzy-extractors.png)

Os sistemas de identidade de hoje exigem que você confie demais nas empresas para guardar os seus dados com segurança. Vários provedores de KYC guardam os seus dados por tempo indeterminado. Cada app recebe todos os seus dados, mesmo quando só precisa saber que você tem mais de 18 anos, o que é informação demais para compartilhar e deixar espalhada por todo lado.

A Self-Sovereign Identity **SSI** resolve isso dando a você o controle das suas credenciais, você pode compartilhar só o que é necessário e provar afirmações sem revelar dados. basicamente, as verifiable credentials **VC** permitem que você prove que tem mais de 18 anos sem mostrar a sua data de nascimento exata. Mas a **SSI** tem um problema - onde você guarda as chaves privadas que controlam a sua identidade?

Existem várias soluções fundamentais para isso e uma delas é `biometric crypto identities`, que não é uma das mais populares, a pergunta é: e se a sua `biometric`, por exemplo o `face`, fosse a sua `private-key`? Nada de `seed phrases` para perder, nada de `passwords` para esquecer, nada de `keys` para guardar. A sua `biometric` gera a sua `wallet`, que guarda as suas credenciais verificáveis, que você prova usando ZKPs.

Isso é possível com `fuzzy extractors` + `zero-knowledge proofs`. Veja como funciona.

## O problema real que isso poderia resolver

Os sistemas criptográficos tradicionais foram projetados para bits reproduzíveis. Só que a biometria quebra duas regras importantes das quais esses sistemas dependem:

**As chaves precisam ser perfeitamente reproduzíveis** - Eles exigem uma reprodução da chave perfeita bit a bit. A sua chave privada para assinar transações precisa ser idêntica todas as vezes. Mas a biometria é ruidosa, com muitas variáveis a considerar. A leitura da sua digital hoje não vai bater bit a bit com a leitura de ontem por causa de variações no sensor, posição do dedo, umidade, temperatura - a lista não acaba. O mesmo vale para leituras de rosto, padrões de íris ou qualquer medição biológica.

**As chaves precisam ser uniformemente aleatórias** - A segurança criptográfica parte do princípio de que a sua chave é sorteada de forma uniformemente aleatória dentre todo o espaço de chaves. Mas os dados biométricos têm estrutura e padrões. A sua íris não é uniformemente aleatória, ela tem restrições biológicas, semelhanças no nível da população e entropia concentrada em características específicas.

Isso cria o famoso problema do ovo e da galinha: você não pode usar a biometria diretamente como chave **ela é muito ruidosa**, você não pode guardá-la com segurança **ela é PII e imutável**, e você não pode simplesmente fazer o hash dela **o ruído quebra as funções de hash**, como você sabe. Então, o que fazer?

Agora vem a parte boa!

## O que são fuzzy extractors?

Pense nos fuzzy extractors como uma criptografia com correção de erros para dados ruidosos. Eles são um par de algoritmos, `Gen` *gerar* e `Rep` *reproduzir*, que fazem algo bem empolgante:

$Gen(w) \rightarrow (R, P)$ - Recebe a sua entrada biométrica ruidosa `w` e gera uma string uniformemente aleatória `R` **a chave criptográfica de fato** e uma string auxiliar pública `P`. Aqui vai outro fato curioso: `P` pode ser publicada abertamente sem comprometer a segurança. Ela não revela absolutamente nenhuma informação relevante sobre a sua biometria.

$Rep(w', P) \rightarrow R$ - Recebe uma leitura biométrica diferente `w'` e a mesma string auxiliar pública `P`, e reproduz exatamente o mesmo `R`, desde que `w'` esteja **perto o suficiente** do `w` original. Eu sei que isso assusta, mas neste caso **perto o suficiente** é medido pela distância em algum espaço métrico **distância de Hamming para strings binárias, distância de edição para sequências, diferença de conjuntos para vetores de características**.

A garantia de segurança é da teoria da informação, mesmo com `P` em mãos, a chave extraída `R` é $\varepsilon$-próxima de uniforme desde que a sua biometria tenha min-entropy $\geq m$. Não é preciso nenhuma suposição de dificuldade computacional. Um adversário com poder computacional infinito ainda não consegue distinguir  `R` de uma chave realmente aleatória com vantagem maior que $\varepsilon$.

A matemática é linda. Para um fuzzy extractor com parâmetros $(m, \ell, t, \varepsilon)$:

- $m$ = min-entropy da sua entrada biométrica **bits de imprevisibilidade**
- $\ell$ = tamanho da chave extraída `R`
- $t$ = tolerância a erros **o quanto `w'` pode ser diferente de `w`**
- $\varepsilon$ = distância estatística em relação à distribuição uniforme **parâmetro de segurança**

## Como isso funciona na prática

A construção usa duas primitivas trabalhando juntas:

### Secure sketches $(SS, Rec)$

Um secure sketch é como um fuzzy commitment. $SS(w) \rightarrow s$ gera um sketch `s` que revela informação suficiente só para corrigir erros, mas nem de longe o suficiente para reconstruir o próprio `w`. Depois, $Rec(w', s) \rightarrow w$ recupera o `w` original a partir de um `w'` ruidoso usando o sketch.

Para strings binárias com distância de Hamming, a Syndrome Construction é ótima:

```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
```

O que está acontecendo aqui:

- `sketch()` calcula a síndrome da biometria `w` e gera `s` com `$n-k$` bits
- `recover()` corrige os erros no `w_prime` ruidoso usando o sketch `s`
- A perda de entropia é exatamente o tamanho do sketch, `$n-k$` bits
- Para o código `BCH` estendido $(128, 64, 22)$ **códigos Bose–Chaudhuri–Hocquenghem**: perde 64 bits e corrige até $t = \lfloor(22-1)/2\rfloor = 10$ erros

### Agora, do sketch ao extractor

Depois da correção de erros, você faz o hash da biometria recuperada para extrair uma chave uniforme, por exemplo:

```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)
}
```

A função `fuzzy_gen()`:

- Cria o sketch a partir da biometria
- Gera uma seed aleatória para a função de hash
- Extrai a chave usando `hash(biometric || seed)`
- Retorna `key, helper`, em que helper = `sketch, seed`

A função `fuzzy_rep()`:

- Recupera a biometria original a partir da leitura ruidosa usando o sketch
- Aplica a mesma função de hash com a mesma seed
- Produz a chave idêntica!

Para as biometrias mais comuns:

- Íris: código bruto de 2048 bits **~249 bits de entropia real**, 10-30% de erro → extrai **chaves de 40-105 bits**
- Digital: 20-80 minúcias **~50-150 bits**, muito ruído → extrai **chaves de 8-40 bits**
- Rosto: embedding de 512 dimensões **20-60 bits de entropia efetiva**

> Nota: As representações biométricas brutas têm redundância e correlações. Os códigos de íris mostram uma proporção de ~8:1 entre os bits brutos (2048) e a entropia da teoria da informação (~249 bits). A extração de chaves precisa respeitar a entropia real, e não o tamanho da representação.

## A jogada da identidade
![](https://i.ibb.co/MyZNpbG3/Screenshot-2025-10-21-at-4-02-19-PM.png)

O modelo de confiança da SSI tem três atores:

- Identity Holder - Você, com uma carteira que contém credenciais
- Issuer - A fonte de confiança (governo, universidade, provedor de KYC)
- Verifier - Quem consome a confiança (dApps, smart contracts)
- Confiança no mundo real - A ponte entre o issuer e o verifier

O fluxo completo:
**Biometria → Carteira → Credenciais → Provas ZK → Identidade verificada**

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

Vamos ver passo a passo:

### Da biometria à carteira

```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
    };
}
```

O processo:

- Pré-processar a biometria → vetor binário **código de íris, embedding de rosto, etc.**
- Rodar `fuzzy_gen()` → obter uma chave de 40-128 bits + a string auxiliar pública
- Converter para um mnemônico `BIP39` → derivar a seed da carteira HD
- Derivar endereços para BTC `P2WPKH`, ETH `EVM`, SOL `Ed25519`
- Retornar os endereços + a string auxiliar + o salt **guarde tudo publicamente!**

No caso específico da Solana, é uma **curva diferente**:

```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();
```

> Nota: A Solana usa `Ed25519`, e não `secp256k1`. Então, na sua implementação, use `ed25519-hd-key` para ter compatibilidade com `SLIP-0010` **igual a `Phantom`, `Solflare`**.

### Obtendo as suas verifiable credentials

A sua carteira agora tem um `DID`, mas para provar qualquer coisa, você precisa de uma Verifiable Credential **VC**. É aqui que começa o triângulo de confiança.
O issuer verifica os seus documentos off-chain e emite uma prova assinada criptograficamente:

```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;
}
```
O que aconteceu:

- O issuer verifica os seus documentos off-chain, por exemplo passaporte, selfie, etc.
- Emite uma `VC` assinada de forma `cryptographically` com as suas afirmações
- A `VC` inclui a assinatura do `DID` do issuer, que prova a autenticidade
- Fica guardada localmente na sua carteira, e não na blockchain
- Várias `VCs` de issuers diferentes: educação, emprego, KYC

O schema da credencial define o que vai na 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..."
  }
}
```
Agora, quando um verifier pede **prove que você tem mais de 18 anos**, você gera uma ZKP a partir dessa credencial.

### A camada de zero-knowledge proof

É aqui que você consegue provar os seus dados pessoais, como **idade, cidadania, um diploma, endereço, data de nascimento, etc.**, sem revelar esses dados sensíveis.

```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 };
}
```

O que é provado:

- O usuário tem mais de `minAge` anos
- A credencial é assinada por um issuer confiável
- NÃO é revelado: a idade real, a data de nascimento, o nome ou qualquer PII

O circuito em 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;
}
```

Verificação 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);
    }
}
```

O contrato:

- Verifica a prova ZK criptograficamente
- Confere os sinais públicos **DID do issuer, limite de idade**
- Marca o usuário como verificado
- Executa a lógica de negócio **airdrop, acesso a DAO, etc.**

Então, por esse fluxo, dá para ver como a sua biometria se tornou:

- **A sua carteira** - Multi-chain, non-custodial, sem seed phrase
- **A sua identidade** - Um identificador descentralizado `DID` ancorado na sua biometria
- **As suas credenciais** - Verifiable credentials `VC` de issuers confiáveis
- **A sua privacidade** - Zero-knowledge proofs `ZKP` que não revelam nada sobre você

E isso não são vários sistemas separados - é UM fluxo unificado. A geração da carteira acontece uma vez, durante o cadastro. O fluxo de ZKP pode ser usado sempre que for preciso verificar a identidade. Pense assim: você pode usar a sua carteira biométrica como qualquer outra carteira cripto para transações normais. Mas quando um dApp precisa de KYC ou de qualquer tipo de verificação baseada em `PII` **como nos casos de uso do `Polygon ID`**, a camada de ZKP entra em ação para provar as credenciais sem expor os seus dados.

## Alguns casos de uso possíveis

1. **Passaportes para agentes:**

Todo agente de IA pode ter um `DID` derivado de biometria. Imagine um agente de IA de trading com a sua própria carteira e credenciais verificadas:

```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);
    }
}
```

O agente:

- Deriva a carteira a partir da sua `biometric` **hash da rede neural**
- Prova a sua reputação **1000+ trades bem-sucedidos** via `ZKP`
- Opera de forma autônoma com um histórico verificado

A `SingularityNET` está construindo exatamente isso, um AI Agent Trust Registry em que os agentes provam autenticidade, segurança e status de auditoria usando verifiable credentials. O fluxo `biometric-wallet-ZKP` permite que os agentes operem por conta própria e ainda assim prestem contas.

2. **Camada de identidade para dApps:**

Um protocolo DeFi precisa de KYC, mas não quer guardar os dados dos usuários **responsabilidade regulatória + honeypot para 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);
    }
}
```

O protocolo nunca vê o seu passaporte, nome ou endereço. Compliance garantido, privacidade preservada.

O mesmo padrão serve para:

- Votação em DAO **provar que é membro, não a identidade**
- Airdrops **provar que é humano, evitar bots**
- Restrições de idade **provar 18+, não a idade exata**

3. **Login sem senha na 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);
}
```

Cada site recebe uma chave derivada única. Nenhuma senha é enviada, nenhuma credencial para cair em phishing.

4. **Pagamentos biométricos:**

A sua biometria autoriza a transação:

```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 });
}
```

O [BMONI](https://bmoni.com) + `BKey` já implementa isso hoje, as suas carteiras são todas derivadas totalmente da sua biometria "**O seu rosto**" e provisionadas em chains EVM e tokens específicos, tudo pelo seu rosto!

5. **Banco de dados de prevenção de golpes:**

```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);
    }
}
```

Os dApps fazem a consulta antes de liberar o acesso. Golpistas conhecidos são bloqueados em toda a rede e alguns com histórico de atividade estranha também são sinalizados, enquanto os integradores recebem uma notificação de atividades suspeitas anteriores.

## Integrações para devs

Construir com identidades biométricas exige infraestrutura. O ecossistema oferece três componentes principais:

### Issuer Node

As organizações rodam issuer nodes self-hosted para emitir credenciais:

```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
```

Funcionalidades:

- Criar o `DID` do issuer
- Definir `schemas` de credenciais
- Emitir/revogar `VCs`
- Gerenciar as conexões dos usuários
- Transitar o estado on-chain **Polygon**

Exemplo de 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 }
});
```

**Ecossistema de ferramentas**

- Schema Builder: Crie schemas de VC customizados em `tools.privado.id/builder`
- Query Builder: Monte queries de ZKP em `tools.privado.id/query-builder`
- Schema Explorer: Navegue pelos `schemas` da comunidade
- Marketplace: Descubra `issuers` de credenciais

## Alguns desafios técnicos e soluções

1: **Variabilidade biométrica**

A sua digital varia 10-15% entre uma leitura e outra. Solução: os códigos `BCH` são ótimos para correção de erros no nível de bits. Para um código de íris de 2048 bits **que contém ~249 bits de entropia real** com 10% de erros (~205 bits com erro):

- Use o código BCH $[2048, 1122, 341]$ sobre $GF(2^{11})$ - corrige até 170 bits com erro
- Perda de entropia, $2048 - 1122 = 926$ bits (tamanho do sketch)
- Entropia restante, $249 - (926 / 8.2) \approx 136$ bits de entropia efetiva
- Extraia uma chave de 128 bits **conservador, já considera a perda de entropia**

**Distinção crítica**: Os 2048 bits são a representação BRUTA do código de íris **a saída do algoritmo de Daugman**. A entropia real, do ponto de vista da teoria da informação, é de só ~249 bits por causa das correlações biológicas e da redundância **proporção de ~8:1**.

2: **Envelhecimento do template**

Problema: O seu rosto muda com o tempo **envelhecimento, peso, barba, etc.**

Solução: Recadastro periódico com migração de chave:

```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);
}
```

Refaça o cadastro a cada 2-3 anos para rosto, a cada 5 anos para íris, todo ano para voz etc.

3: **Detecção de vivacidade**

Problema: Atacantes com uma foto sua não deveriam conseguir acessar a sua carteira.

Solução: Checagens de vivacidade durante a captura biométrica:

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

O Orb da WorldCoin faz isso com leituras de íris: mais de 25 checagens de vivacidade, imagens 3D, câmeras infravermelho + RGB. Funciona incrivelmente bem - taxa de falsa aceitação $< 0.0001\%$.

4: **Privacidade da string auxiliar**

O `P` que expliquei antes vaza informação biométrica? Não. Pelo teorema **Dodis et al.**, o atacante aprende no máximo $n-k$ bits **o tamanho do sketch**, e a chave `R` continua estatisticamente aleatória. Para a nossa íris: ele aprende 408 bits, e restam 392 bits de entropia.

## Isso está pronto para produção?

As peças já existem:

- Fuzzy extractors: a biblioteca `CompFE` (MIT), que roda em mobile
- Provas ZK: BKey, Privado ID e outros já estão na mainnet
- Hardware: carteira D'CENT, FaceID, sensores de digital estão em todo lugar
- Padrões: W3C DIDs, VCs, WebAuthn
- Redes: BTC, ETH, Polygon, Solana, todas suportam carteiras HD **BIP32/39/44 desde 2013**

O que está faltando? Integrações...

## Exemplo de implementação em produção

Veja como fica usar esse sistema de verdade em um ambiente de produção

```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 });
}
```

O fluxo normal da carteira e o fluxo de identidade coexistem. A ZKP só entra em cena quando é preciso verificar algo, seja para KYC ou para qualquer verificação baseada em `PII`, como idade, cidadania, um diploma, endereço, data de nascimento, etc.

A sua biometria é a sua chave, a sua carteira é a sua identidade em todas as chains suportadas e você nunca precisa se preocupar em perder a sua seed phrase ou as suas chaves privadas, tudo está ligado aos seus atributos físicos, e na implementação da BMoni é o seu rosto!

## Links essenciais

- [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) - Construções pós-quânticas
- [CompFE](https://github.com/benjaminfuller/CompFE)
- [Polygon ID SDK](https://github.com/0xPolygonID) - Sistema de identidade com ZKP
- [Segurança da BMoni](https://bmoni.com/security/#22patents) - A nossa arquitetura de segurança
- [snarkjs](https://github.com/iden3/snarkjs) - Biblioteca de ZK-SNARK
