O Balcão que Não Lembra.
Pharma global pergunta. Farmácia responde. Sem ninguém ver pacientes individuais.
O Cenário
Pharma quer saber: quantos pacientes diabéticos iniciaram metformina nos últimos 90 dias e abandonaram em 30? A farmácia tem a base; pharma envia query cifrada.
O Problema
O modelo IQVIA atual depende de "anonimização" que cada vez mais é considerada legalmente frágil. FHE oferece garantia matemática.
A Garantia
Pharma decifra apenas a contagem agregada. Nunca vê pacientes individuais. Farmácia nunca vê a query (a query também é cifrada). Tudo verificável.
Definir os parâmetros.
Antes de cifrar a base de pacientes, escolhemos os parâmetros BGV. Cada um é um trade-off entre segurança, velocidade e capacidade de cálculo.
Parâmetros · BGV
O que cada termo significa
BGV (esquema "exato") — Opera sobre números inteiros. Sem ruído de aproximação. Resultado é bit-a-bit idêntico ao plaintext. Ideal para contagens, queries SQL e lógica booleana — exatamente o que esta demo de RWE precisa.
8 192 slots — Cada ciphertext é um vetor de 8 192 valores empacotados. 1 ciphertext cabe 8 192 pacientes simultaneamente. Operação única processa todos. Em produção real, milhões via batching.
Profundidade multiplicativa 2 — Quantas multiplicações encadeadas o ciphertext suporta. A query desta demo precisa de 2 (AND triplo entre 3 flags binárias) → profundidade 2 basta.
~128 bits de segurança — Padrão da indústria. Quebrar a chave exigiria ~2128 operações.
Base RLWE — Ring Learning With Errors. O mesmo problema matemático sobre o qual NIST padronizou criptografia pós-quântica (ML-KEM, ML-DSA).
Pharma cria, farmácia recebe.
Diferente de outros casos, aqui a chave secreta pertence à PHARMA (quem faz a query). A farmácia só recebe a chave pública para poder cifrar dados sob ela. Inversão de papéis comum em RWE pull.
Quem tem o quê
Pharma — gera o par (sk, pk). Mantém sk consigo. Apenas pharma poderá decifrar a resposta final.
Farmácia — recebe pk + rlk + galois keys. Pode cifrar dados e processar queries, mas NÃO PODE decifrar nada (nem mesmo sua própria base depois de cifrada).
Por que essa inversão
Pharma define a pergunta — Em RWE pull, pharma é quem precisa da resposta. Ela escolhe a query, precisa entender o resultado, e decide o que fazer com ele. Faz sentido que ela detenha a chave.
Farmácia perde flexibilidade — Mas ganha proteção: não pode ser obrigada a decifrar a base sob ordem judicial, nem por funcionário desonesto, nem por invasor. Tecnicamente impossível.
Modelo simétrico vs assimétrico — Para cruzamento entre operadora e hospital (caso simétrico), usaríamos threshold com chaves divididas. Para query pharma → farmácia (assimétrico), o modelo "pharma detém a chave" funciona melhor.
Cifrar a base.
A farmácia cifra UMA VEZ os 3 vetores característicos (diabético, iniciou metformina, abandonou). Qualquer query futura reusa esses ciphertexts.
Base de Pacientes
Distribuição realista: ~30% diabéticos, ~12% iniciaram metformina, ~3% abandonaram em 30d.
Cifragem
A pharma pergunta.
Pharma define a pergunta de RWE como uma fórmula booleana SQL-like sobre as flags. Sob FHE, a tradução é direta: AND vira multiplicação, contagem vira InnerSum.
A query em SQL tradicional
FROM pacientes
WHERE diabetico = 1
AND iniciou_metformina = 1
AND abandonou_30d = 1
Esta é a query que pharma quer executar. Em SQL tradicional, exigiria acesso direto à base da farmácia em claro.
A mesma query sob FHE
ctAnd := evaluator.Mul(
ctDiab, ctMet,
)
ctAnd := evaluator.Mul(
ctAnd, ctAban,
)
// COUNT = InnerSum dos slots
ctCount := evaluator.InnerSum(ctAnd)
Mesma semântica, sintaxe diferente. A multiplicação de ciphertexts binários é exatamente AND lógico. A soma dos slots é exatamente COUNT.
Query roda sobre a base cifrada.
A farmácia executa a query inteira sobre os ciphertexts. Cada operação é matemática pura — sem nenhum ponto onde o dado é decifrado. Tempo total: 47 ms.
O que a operação significa
2 multiplicações cifradas — Para um AND triplo entre 3 flags binárias, precisamos encadear 2 multiplicações: ct₁·ct₂, depois (ct₁·ct₂)·ct₃. Cada multiplicação consome 1 nível de profundidade. Por isso configuramos LogQ com 2 níveis multiplicativos no Passo 01.
log₂(N) rotações Galois — Para somar todos os 1 000 slots ativos via InnerSum, são necessárias ~10 rotações em estilo árvore binária. Cada rotação é uma operação Galois cifrada usando as Galois keys do passo 2.
47 ms total — Tempo real medido. Comparado a query SQL tradicional (~ms), é 50× mais lento. Comparado ao tempo de uma reunião de comitê para autorizar acesso a dado clínico em modelo tradicional (semanas), é 10⁹ × mais rápido.
0 bytes decifrados — A farmácia não decifra nada. Não pode. Não tem chave. O resultado fica como ciphertext até chegar à pharma.
O que a farmácia possui agora
Um único ciphertext: ct_resposta. Codifica a contagem. A farmácia também não pode decifrar — só a pharma tem a chave secreta.
Pharma decifra.
A pharma recebe ct_resposta. Decifra com sua chave secreta. Descobre apenas a contagem.
Validação matemática.
BGV é esquema exato — sem ruído de aproximação como CKKS.
FHE vs Plaintext
| Métrica | FHE | Plaintext |
|---|---|---|
| Contagem | 33 | 33 |
| Diferença | EXATA — 0 erro | |
Por que é Exato
BGV opera sobre inteiros módulo um primo (65537). Para contagens dentro do domínio, o resultado FHE é bit-a-bit idêntico ao plaintext.
Pharma desonesta.
O que pharma pode tentar para inferir indivíduos da contagem agregada?
Ataques
- 1 — Inferir indivíduo da contagemUma única contagem não é injetiva. Para isolar um indivíduo, pharma precisaria fazer queries específicas — bloqueado por política de mínimos por query (ex: nunca reportar contagem < 10).
- 2 — Ler bytes cifradosPseudoaleatórios. Nada recuperável.
- 3 — Brute force2^3000 combinações de flags. Inviável.
Defesa em camadas
Privacidade diferencial pode ser adicionada à contagem (ruído gaussiano calibrado), garantindo que mesmo com queries adaptativas pharma não consegue isolar indivíduo.
O que aconteceu.
Em menos de 100 ms, pharma obteve um insight regulatório-grade sem nunca ver pacientes individuais.
O Fluxo
- Farmácia cifrou sua base de 1000 pacientes uma única vez
- Pharma definiu uma query SQL-like sobre 3 flags
- Farmácia executou a query inteira sob cifra
- Pharma decifrou apenas a contagem agregada