安全聚合#
以下代码仅作为演示用,请勿直接在生产环境使用。
推荐使用 jupyter 运行教程里的代码。
安全聚合可以表述为:多个参数方在不暴露各自私有数据的前提下合作完成聚合值计算(比如求和)。
安全聚合是联邦学习中的重要概念。学术界对此已经有较多研究。隐语在水平联邦学习(梯度/权重聚合)、数据处理(比如数据探查、预处理)等方面使用了安全聚合。
下面将介绍隐语使用的安全聚合方案。
数据准备#
初始化SecretFlow。
[ ]:
import secretflow as sf
# In case you have a running SecretFlow runtime already.
sf.shutdown()
sf.init(['alice', 'bob'], address='local')
准备测试数据。
[2]:
import numpy as np
arr0, arr1 = np.random.rand(2, 3), np.random.rand(2, 3)
print('arr0:\n', arr0, '\narr1:\n', arr1)
print('Sum:\n', np.sum([arr0, arr1], axis=0))
print('Average:\n', np.average([arr0, arr1], axis=0))
print('Min:\n', np.min([arr0, arr1], axis=0))
print('Max:\n', np.max([arr0, arr1], axis=0))
arr0:
[[0.53867365 0.69040348 0.42628929]
[0.76128941 0.5444343 0.7680543 ]]
arr1:
[[0.74303296 0.7274792 0.47244091]
[0.88295957 0.80091356 0.82681861]]
Sum:
[[1.28170662 1.41788268 0.8987302 ]
[1.64424898 1.34534786 1.59487291]]
Average:
[[0.64085331 0.70894134 0.4493651 ]
[0.82212449 0.67267393 0.79743646]]
Min:
[[0.53867365 0.69040348 0.42628929]
[0.76128941 0.5444343 0.7680543 ]]
Max:
[[0.74303296 0.7274792 0.47244091]
[0.88295957 0.80091356 0.82681861]]
创建alice和bob两个参与方。
[3]:
alice, bob = sf.PYU('alice'), sf.PYU('bob')
聚合操作#
隐语提供了多种 Aggregator 供用户选择,每种 Aggregator 均提供了sum(求和)和average(求平均)方法。
基于SPU的安全聚合。#
SPU 是隐语中的一种安群设备,其基本原理是 MPC 。隐语基于SPU实现了安全聚合,下面将介绍如何使用。
[4]:
# Create an spu device.
spu = sf.SPU(sf.utils.testing.cluster_def(['alice', 'bob']))
# Create an aggregator instance using this spu.
spu_aggr = sf.security.aggregation.SPUAggregator(spu)
[5]:
# Simulate that alice and bob hold data respectively
a = alice(lambda: arr0)()
b = bob(lambda: arr1)()
[6]:
# Sum the data.
sf.reveal(spu_aggr.sum([a, b], axis=0))
[6]:
array([[1.2817066 , 1.4178827 , 0.89873016],
[1.644249 , 1.3453479 , 1.594873 ]], dtype=float32)
[7]:
# Average the data.
sf.reveal(spu_aggr.average([a, b], axis=0))
[7]:
array([[0.6408533 , 0.70894134, 0.44936508],
[0.8221245 , 0.67267394, 0.7974364 ]], dtype=float32)
Masking with One-Time Pads#
Masking with One-Time Pads 的原理描述如下:参与方两两之间分别协商掩码值,然后使用掩码值来掩藏各自的私有数据,每个参与方输出
聚合之后掩码值正好互相抵消,从而可以得到正确的结果。
\[y_1 + y_2 + y_3 = x_1 + s_{a,b} + s_{a,c} + x_2 - s_{a,b} + s_{b,c} + x_3 - s_{a,c} - s_{b,c} = x_1 + x_2 + x_3\]
Masking with One-Time Pads 基于半诚实假设且不支持掉线,更多信息可以参考 Practical Secure Aggregation for Privacy-Preserving Machine Learning
警告: SecureAggregator使用了 numpy.random.PCG64。对于PCG是否是CSPRNG有很多讨论(比如 https://crypto.stackexchange.com/questions/77101/is-the-pcg-prng-a-csprng-or-why-not),我们倾向于保守看待此类讨论,因此我们建议用户在真正工业场景中使用标准的CSPRNG。
[8]:
# Create a secure aggregator instance with alice and bob,
# where alice is responsible for performing aggregate computing operations.
secure_aggr = sf.security.aggregation.SecureAggregator(device=alice, participants=[alice, bob])
[9]:
# Sum the data.
sf.reveal(secure_aggr.sum([a, b], axis=0))
[9]:
array([[1.28170395, 1.41788101, 0.89872742],
[1.64424515, 1.34534454, 1.59486771]])
[10]:
# Average the data.
sf.reveal(secure_aggr.average([a, b], axis=0))
[10]:
array([[0.64085197, 0.70894051, 0.44936371],
[0.82212257, 0.67267227, 0.79743385]])
明文聚合(仅用作测试,请勿在生产中使用)#
PlainAggregator仅用作测试,请勿在生产中使用。
为了方便本地模拟,隐语也提供了明文聚合方式。
[12]:
# Create a plaintext aggregator instance and alice is responsible for performing aggregation.
plain_aggr = sf.security.aggregation.PlainAggregator(alice)
[13]:
# Sum the data.
sf.reveal(plain_aggr.sum([a, b], axis=0))
[13]:
array([[1.2817066 , 1.4178827 , 0.89873016],
[1.644249 , 1.3453479 , 1.594873 ]], dtype=float32)
[14]:
# Average the data.
sf.reveal(plain_aggr.average([a, b], axis=0))
[14]:
array([[0.6408533 , 0.70894134, 0.44936508],
[0.8221245 , 0.67267394, 0.7974365 ]], dtype=float32)
比较#
隐语还提供了多种 Comparator 用来进行安全比较,比如求最大最小值。举个例子,比如在水平联邦场景下,数据处理时全局的极值会通过安全比较来获得,不会暴露参与方的私有信息。
基于SPU的安全比较#
隐语基于SPU实现了安全比较,下面将展示如何使用。
[15]:
# Create an spu comparator instance.
spu_com = sf.security.compare.SPUComparator(spu)
[16]:
# Get the minimum.
sf.reveal(spu_com.min([a, b], axis=0))
[16]:
array([[0.53867364, 0.69040346, 0.4262893 ],
[0.7612894 , 0.5444343 , 0.7680543 ]], dtype=float32)
[18]:
# Get the maximum.
sf.reveal(spu_com.max([a, b], axis=0))
[18]:
array([[0.743033 , 0.7274792 , 0.4724409 ],
[0.88295954, 0.8009136 , 0.8268186 ]], dtype=float32)
明文比较(仅作为测试用,请勿在生产中使用)#
PlainComparator仅作为测试用,请勿在生产中使用。
为了方便本地模拟,隐语也提供了明文比较方式。
[19]:
# Create a plaintext comparator instance and alice is responsible for performing the comparison.
plain_com = sf.security.compare.PlainComparator(alice)
[21]:
# Get the minimum.
sf.reveal(plain_com.min([a, b], axis=0))
[21]:
array([[0.53867364, 0.69040346, 0.4262893 ],
[0.7612894 , 0.5444343 , 0.7680543 ]], dtype=float32)
[22]:
# Get the maximum.
sf.reveal(plain_com.max([a, b], axis=0))
[22]:
array([[0.743033 , 0.7274792 , 0.4724409 ],
[0.88295954, 0.8009136 , 0.8268186 ]], dtype=float32)
收尾#
[23]:
sf.shutdown()
总结#
本文讲述了隐语中的安全局和方案。隐语提供了多种安全聚合方法,用户可以根据需要自行选择合适的方案。其中明文聚合和明文比较仅作为测试目的,请勿在生产中使用。