Acredite ou não, é possível realizar cálculos com dados criptografados. Em outras palavras, é possível executar um programa onde TODAS as variáveis estão criptografadas!
Neste tutorial, nós vamos falar sobre as ferramentas básicas de computação criptografada. Em particular, nós vamos focar em uma abordagem popular chamada Computação Multiparte Segura (i.e. Secure Multi-Party Computation ou SMPC). Nesta lição, você aprenderá como criar uma calculadora criptografada que pode executar cálculos com números criptografados.
Autores:
Tradução:
Referências:
SMPC é, à primeira vista, uma forma bastante estranha de "criptografia". Em vez de usar uma chave pública/privada para criptografar uma variável, cada valor é dividido em várias partes
, cada uma das quais opera como uma chave privada. Normalmente, essas partes
serão distribuídas entre 2 ou mais proprietários. Assim, para decifrar a variável, todos os proprietários devem concordar em permitir a sua descriptografia. Em essência, todos têm uma chave privada.
Então, digamos que queríamos "encriptar" uma variável x
, podíamos fazê-lo da seguinte forma.
A criptografia não utiliza números reais ou de ponto flutuante mas um espaço matemático chamado de integer quotient ring (anel quociente inteiro) que são basicamente os inteiros entre
0
eQ-1
, ondeQ
é primo e "grande o suficiente" tal que o espaço contenha todos os números que nós usamos em nossos experimentos. Na prática, dado um valorx
inteiro, fazemosx % Q
(resto da divisão inteira) para que esteja contido no "anel". (É por isso que evitamos usar o númerox
>Q
)
In [1]:
Q = 1234567891011
In [2]:
x = 25
In [3]:
import random
def encrypt(x):
share_a = random.randint(-Q,Q) # Entenda share_a como parte A de x, idem para B, e C.
share_b = random.randint(-Q,Q)
share_c = (x - share_a - share_b) % Q
return (share_a, share_b, share_c)
In [4]:
encrypt(x)
Out[4]:
In [5]:
def decrypt(*shares):
return sum(shares) % Q
In [6]:
a,b,c = encrypt(25)
In [7]:
decrypt(a, b, c)
Out[7]:
É importante notar que se tentarmos decifrar com apenas duas partes, a descriptografia não funciona!
In [8]:
decrypt(a, b)
Out[8]:
Assim, precisamos que todos os proprietários participem para decifrar o valor. É desta forma que as partes agem como chaves privadas, todas as quais devem estar presentes para decifrar um valor.
In [9]:
x = encrypt(25)
y = encrypt(5)
In [10]:
def add(x, y):
z = list()
# o primeiro worker adiciona as suas partes
z.append((x[0] + y[0]) % Q)
# o segundo worker adiciona as suas partes
z.append((x[1] + y[1]) % Q)
# o terceiro worker adiciona as suas partes
z.append((x[2] + y[2]) % Q)
return z
In [11]:
decrypt(*add(x,y))
Out[11]:
E aqui o temos! Se cada worker (separadamente) somar suas partes, então as partes resultantes serão decifradas para o valor correto (25 + 5 === 30).
Acontece que, existem protocolos SMPC que podem permitir este cálculo criptografado para as seguintes operações:
e usando estas três operações básicas, podemos fazer cálculos arbitrários!!!
Na próxima seção, vamos aprender como usar a biblioteca PySyft para realizar estas operações!
Nas seções anteriores, nós demostramos algumas intuições básicas em torno do SMPC e como o método deve funcionar. Contudo, na prática, não queremos ter de ser nós próprios a escrever à mão todas as operações primitivas ao escrever os nossos programas criptografados. Então, nesta seção vamos passar pelo básico de como fazer computação criptografada usando o PySyft. Em particular, vamos focar em como fazer as 3 operações básicas mencionados anteriormente: adição, multiplicação, e comparação.
Primeiro, precisamos criar alguns Workers Virtuais (esperamos que você já esteja familiarizado com os nossos tutoriais anteriores).
In [12]:
import torch
import syft as sy
hook = sy.TorchHook(torch)
bob = sy.VirtualWorker(hook, id="bob")
alice = sy.VirtualWorker(hook, id="alice")
bill = sy.VirtualWorker(hook, id="bill")
In [13]:
x = torch.tensor([25])
In [14]:
x
Out[14]:
In [15]:
encrypted_x = x.share(bob, alice, bill)
In [16]:
encrypted_x.get()
Out[16]:
In [17]:
bob._objects
Out[17]:
In [18]:
x = torch.tensor([25]).share(bob, alice, bill)
In [19]:
# Parte de Bob
bobs_share = list(bob._objects.values())[0]
bobs_share
Out[19]:
In [20]:
# Parte de Alice
alices_share = list(alice._objects.values())[0]
alices_share
Out[20]:
In [21]:
# Parte de Bill
bills_share = list(bill._objects.values())[0]
bills_share
Out[21]:
E se quiséssemos, poderíamos decifrar esses valores usando a mesma abordagem de que falamos anteriormente!!!
In [22]:
(bobs_share + alices_share + bills_share)
Out[22]:
As you can see, when we called .share()
it simply split the value into 3 shares and sent one share to each of the parties!
Como você pode ver, quando chamamos .share()
simplesmente dividimos o valor em 3 partes e o enviamos para cada um dos workers !
In [23]:
x = torch.tensor([25]).share(bob,alice)
y = torch.tensor([5]).share(bob,alice)
In [24]:
z = x + y
z.get()
Out[24]:
In [25]:
z = x - y
z.get()
Out[25]:
Para a multiplicação, precisamos de uma parte adicional que seja responsável pela geração consistente de números aleatórios (e que não colida com nenhuma das outras partes). Nós chamamos essa terceira parte de "provedor de criptografia". Para todos os propósitos, o provedor de criptografia é apenas um "VirtualWorker" adicional, mas é importante reconhecer que o provedor de criptografia não é um "dono/proprietário", pois ele não possui partes, mas é alguém que precisa ser confiável para não entrar em conluio com nenhuma das partes existentes.
In [26]:
crypto_provider = sy.VirtualWorker(hook, id="crypto_provider")
In [27]:
x = torch.tensor([25]).share(bob,alice, crypto_provider=crypto_provider)
y = torch.tensor([5]).share(bob,alice, crypto_provider=crypto_provider)
In [28]:
# multiplicação
z = x * y
z.get()
Out[28]:
Você também pode fazer multiplicação matricial
In [29]:
x = torch.tensor([[1, 2],[3,4]]).share(bob,alice, crypto_provider=crypto_provider)
y = torch.tensor([[2, 0],[0,2]]).share(bob,alice, crypto_provider=crypto_provider)
In [30]:
# multiplicação de matrizes
z = x.mm(y)
z.get()
Out[30]:
Também é possível fazer comparações privadas entre valores privados. Contamos aqui com o protocolo SecureNN , cujos detalhes podem ser encontrados aqui. O resultado da comparação é também um tensor privado compartilhado.
In [31]:
x = torch.tensor([25]).share(bob,alice, crypto_provider=crypto_provider)
y = torch.tensor([5]).share(bob,alice, crypto_provider=crypto_provider)
In [32]:
z = x > y
z.get()
Out[32]:
In [33]:
z = x <= y
z.get()
Out[33]:
In [34]:
z = x == y
z.get()
Out[34]:
In [35]:
z = x == y + 20
z.get()
Out[35]:
Você também pode realizar operações de maximum.
In [36]:
x = torch.tensor([2, 3, 4, 1]).share(bob,alice, crypto_provider=crypto_provider)
x.max().get()
Out[36]:
In [37]:
x = torch.tensor([[2, 3], [4, 1]]).share(bob,alice, crypto_provider=crypto_provider)
max_values, max_ids = x.max(dim=0)
max_values.get()
Out[37]:
Parabéns por concluir esta etapa do tutorial! Se você gostou e gostaria de se juntar ao movimento em direção à proteção de privacidade, propriedade descentralizada e geração, demanda em cadeia, de dados em IA, você pode fazê-lo das seguintes maneiras!
A maneira mais fácil de ajudar nossa comunidade é adicionando uma estrela nos nossos repositórios! Isso ajuda a aumentar a conscientização sobre essas ferramentas legais que estamos construindo.
A melhor maneira de manter-se atualizado sobre os últimos avanços é se juntar à nossa comunidade! Você pode fazer isso preenchendo o formulário em http://slack.openmined.org
A melhor maneira de contribuir para a nossa comunidade é se tornando um contribuidor do código! A qualquer momento, você pode acessar a página de Issues (problemas) do PySyft no GitHub e filtrar por "Projetos". Isso mostrará todas as etiquetas (tags) na parte superior, com uma visão geral de quais projetos você pode participar! Se você não deseja ingressar em um projeto, mas gostaria de codificar um pouco, também pode procurar mais mini-projetos "independentes" pesquisando problemas no GitHub marcados como "good first issue".
Se você não tem tempo para contribuir com nossa base de códigos, mas ainda deseja nos apoiar, também pode se tornar um Apoiador em nosso Open Collective. Todas as doações vão para hospedagem na web e outras despesas da comunidade, como hackathons e meetups!
In [ ]: