crypten说明2

#教程2:CrypTensors内部


注意:本教程是可选的,可以跳过,而不会丢失以下教程的连续性。

在本教程中,我们将简要介绍“CrypTensors”的内部结构。


使用“mpc”后端,“CrypTensor”是使用安全mpc协议加密的张量,称为“MPCSensor”。为了支持“MPCSensor”所需的数学运算,CrypTen实现了两种秘密共享协议:算术秘密共享和二进制秘密共享。算术秘密共享是“MPCSencer”实现的大多数数学运算的基础。类似地,二进制秘密共享允许对逻辑表达式进行求值。


在本教程中,我们将首先介绍`CrypTensor`<i>ptype</i>(即<i>私有类型</i>)的概念,并演示如何使用它来获得使用算术和二进制秘密共享的`MPCSensor`。我们还将描述如何使用这些<i>ptypes</i>中的每一个,以及如何将他们结合。

#import the libraries
import crypten
import torch

#initialize crypten
crypten.init()
#Disables OpenMP threads -- needed by @mpc.run_multiprocess which uses fork
torch.set_num_threads(1)

CrypTen定义了“MPCSensor”的“ptype”(对于<i>私有类型</i>)属性,以表示“CrypTensor”中使用的秘密共享协议的类型。“ptype”在许多方面类似于PyTorch的“dtype”。“ptype”可以有两个值:


-`ArithmeticSharedSensors的`crypten.mpc.athmeth``</li>

-`Crypton.mpc.binary`用于`BinarySharedSensor`</li>


我们可以使用“ptype”属性创建具有适当秘密共享协议的“CrypTensor”。例如

#Constructing CrypTensors with ptype attribute

#arithmetic secret-shared tensors
x_enc = crypten.cryptensor([1.0, 2.0, 3.0], ptype=crypten.mpc.arithmetic)
print("x_enc internal type:", x_enc.ptype)

#binary secret-shared tensors
y = torch.tensor([1, 2, 1], dtype=torch.int32)
y_enc = crypten.cryptensor(y, ptype=crypten.mpc.binary)
print("y_enc internal type:", y_enc.ptype)

x_enc internal type: ptype.arithmetic

y_enc internal type: ptype.binary

算术秘密共享

让我们更仔细地看一下“crypten.mpc.athmetic”<i>ptype</i>。“CrypTensors”实现的大多数数学运算都是使用算术秘密共享实现的。因此,“crypten.mpc.athmetic”是新生成的“Cryp张量”的默认<i>ptype</i>。


让我们首先使用“ptype=crypten.mpc.athmetic”创建一个新的“CrypTensor”,以强制加密是通过算术秘密共享完成的。我们可以打印每个共享的值,以确认值被正确加密。


要做到这一点,我们需要创建多个政党来持有每一份股份。我们在这里使用`@mpc.run_multiprocess`函数decorator来完成这项工作,我们开发该函数是为了从单个脚本中执行crypten代码(正如我们在Jupyter笔记本中所做的那样)。CrypTen遵循标准的MPI编程模型:它为每一方运行一个单独的进程,但每个进程运行一个相同(完整)的程序。每个进程都有一个“秩”变量来标识自己。

请注意,下面两个“_tensor”属性的总和等于输入的缩放表示。(因为MPC要求值为整数,所以我们在加密之前将输入浮点值缩放为定点编码。)

import crypten.mpc as mpc
import crypten.communicator as comm 

@mpc.run_multiprocess(world_size=2)
def examine_arithmetic_shares():
    x_enc = crypten.cryptensor([1, 2, 3], ptype=crypten.mpc.arithmetic)
    
    rank = comm.get().get_rank()
    crypten.print(f"\nRank {rank}:\n {x_enc}\n", in_order=True)
        
x = examine_arithmetic_shares()


Rank 0:
 MPCTensor(
	_tensor=tensor([ 4977840465844292698,   234311463858409737, -8644375101282040029])
	plain_text=HIDDEN
	ptype=ptype.arithmetic
)


Rank 1:
 MPCTensor(
	_tensor=tensor([-4977840465844227162,  -234311463858278665,  8644375101282236637])
	plain_text=HIDDEN
	ptype=ptype.arithmetic
)

###二进制秘密共享

CrypTen中实现的第二种秘密共享是二进制或XOR秘密共享。这种类型的秘密共享可以提高评估逻辑表达式的效率。

让我们更仔细地看一下`crypten.mpc.binary`<i>ptype</i>。“CrypTensors”实现的大多数逻辑运算都是使用算术秘密共享实现的。当我们想计算二进制运算符(如“^&|><<`等”)或逻辑运算(如比较器)时,我们通常会使用这种类型的秘密共享。

让我们首先使用“ptype=crypten.mpc.binary”创建一个新的“CrypTensor”,以强制加密是通过二进制秘密共享完成的。我们可以打印每个共享的值,以确认值被正确加密,就像我们对算术秘密共享所做的那样。

(请注意,下面两个“_tensor”属性的xor等于输入的未缩放版本。)

@mpc.run_multiprocess(world_size=2)
def examine_binary_shares():
    x_enc = crypten.cryptensor([2, 3], ptype=crypten.mpc.binary)
    
    rank = comm.get().get_rank()
    crypten.print(f"\nRank {rank}:\n {x_enc}\n", in_order=True)
        
x = examine_binary_shares()


Rank 0:
 MPCTensor(
	_tensor=tensor([-3617348383499570248,  -581960226550774565])
	plain_text=HIDDEN
	ptype=ptype.binary
)


Rank 1:
 MPCTensor(
	_tensor=tensor([-3617348383499570246,  -581960226550774568])
	plain_text=HIDDEN
	ptype=ptype.binary
)

###使用两种秘密共享协议
通常,数学函数可能需要同时使用加法和异或秘密共享来进行有效评估。需要在共享类型之间进行转换的函数包括比较器(`>,>=,<,<=,==,!=`)以及从它们派生的函数(`abs,sign,relu`等)。有关支持功能的完整列表,请参阅CrypTen文档。
CrypTen提供了允许在<i>ptypes</i>之间转换的功能。<i>ptypes</i>之间的转换可以使用带有“crypten.ptype”输入的“.to()”函数来完成,也可以通过调用“.athmetic()”和“.binary()”转换函数来完成。

from crypten.mpc import MPCTensor

@mpc.run_multiprocess(world_size=2)
def examine_conversion():
    x = torch.tensor([1, 2, 3])
    rank = comm.get().get_rank()

    # create an MPCTensor with arithmetic secret sharing
    x_enc_arithmetic = MPCTensor(x, ptype=crypten.mpc.arithmetic)
    
    # To binary
    x_enc_binary = x_enc_arithmetic.to(crypten.mpc.binary)
    x_from_binary = x_enc_binary.get_plain_text()
    
    # print only once
    crypten.print("to(crypten.binary):")
    crypten.print(f"  ptype: {x_enc_binary.ptype}\n  plaintext: {x_from_binary}\n")

        
    # To arithmetic
    x_enc_arithmetic = x_enc_arithmetic.to(crypten.mpc.arithmetic)
    x_from_arithmetic = x_enc_arithmetic.get_plain_text()
    
    # print only once
    crypten.print("to(crypten.arithmetic):")
    crypten.print(f"  ptype: {x_enc_arithmetic.ptype}\n  plaintext: {x_from_arithmetic}\n")

WARNING:root:module 'torchvision.models.mobilenet' has no attribute 'ConvBNReLU'




x_enc internal type: ptype.arithmetic
y_enc internal type: ptype.binary

Rank 0:
 MPCTensor(
	_tensor=tensor([ 4977840465844292698,   234311463858409737, -8644375101282040029])
	plain_text=HIDDEN
	ptype=ptype.arithmetic
)


Rank 1:
 MPCTensor(
	_tensor=tensor([-4977840465844227162,  -234311463858278665,  8644375101282236637])
	plain_text=HIDDEN
	ptype=ptype.arithmetic
)


Rank 0:
 MPCTensor(
	_tensor=tensor([-3617348383499570248,  -581960226550774565])
	plain_text=HIDDEN
	ptype=ptype.binary
)


Rank 1:
 MPCTensor(
	_tensor=tensor([-3617348383499570246,  -581960226550774568])
	plain_text=HIDDEN
	ptype=ptype.binary
)

to(crypten.binary):
  ptype: ptype.binary
  plaintext: tensor([1., 2., 3.])

to(crypten.arithmetic):
  ptype: ptype.arithmetic
  plaintext: tensor([1., 2., 3.])
        
z = examine_conversion()

##数据源

CrypTen遵循标准的MPI编程模型:它为每一方运行一个单独的进程,但每个进程运行一个相同(完整)的程序。每个进程都有一个“秩”变量来标识自己。


如果秩为“i”的进程是数据“x”的源,则“x”以“i”作为其源值(表示为“src”)进行加密。然而,MPI协议要求两个进程都提供与其输入大小相同的张量。加密时,CrypTen会忽略非源进程提供的所有数据。


在下一个示例中,我们将展示如何使用“rank”和“src”值来加密张量。这里,我们将使三方中的每一方生成一个值“x”,该值等于其自身的“秩”值。在循环中,创建了3个加密张量,每个张量都有不同的源。当这些张量被解密时,我们可以验证张量是使用源进程提供的张量生成的。


(请注意,如果没有提供,“crypten.cryptensor”将秩0用作默认源。)

@mpc.run_multiprocess(world_size=3)
def examine_sources():
    # Create a different tensor on each rank
    rank = comm.get().get_rank()
    x = torch.tensor(rank)
    crypten.print(f"Rank {rank}: {x}", in_order=True)
    
    # 
    world_size = comm.get().get_world_size()
    for i in range(world_size):
        x_enc = crypten.cryptensor(x, src=i)
        z = x_enc.get_plain_text()
        
        # Only print from one process to avoid duplicates
        crypten.print(f"Source {i}: {z}")
        
x = examine_sources()

Rank 0: 0
Rank 1: 1
Rank 2: 2
Source 0: 0.0
Source 1: 1.0
Source 2: 2.0

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值