HarmonyOS开发者限时福利来啦!最高10w+现金激励等你拿~ 了解详情
写点什么

隐私 AI 框架中的数据流动与工程实现

  • 2020-11-03
  • 本文字数:6809 字

    阅读完需:约 22 分钟

隐私AI框架中的数据流动与工程实现

上一篇文章中,我们介绍了,对于安全技术开发者,如何快速的基于 Rosetta 等隐私 AI 框架所提供的一系列接口,将自己的安全协议集成落地到上层的 AI 应用中来。在这一篇文章中,我们将介绍为了保护用户的隐私数据,在隐私 AI 框架的计算任务全流程中,数据是如何以密文形式流动,同时仍正确完成加法、乘法等计算步骤的。


隐私 AI 系统存在的目的就是赋能 AI,使得各种 AI 场景下对用户隐私数据的使用都是安全的。那么,这样的系统就需要提供充分的保障,从理论到工程实现的每一个阶段都应该是经得起推敲、抵抗得住各种攻击的。不能简单的认为只需要各方先在本地自己的数据上计算出一个模型,然后将模型结果交换一下计算下其模型参数的平均值,就不会泄露各方的隐私数据了。现代密码学(Cryptography)是建立在严格的数学定义、计算复杂度假设和证明基础之上的,其中 MPC (Multi-Party Computation)方向是专门研究多个参与方如何正确、安全的进行联合计算的子领域, RosettaTF Encrypted 等隐私 AI 框架都采用了 MPC 技术以提供可靠的安全性。下面我们就结合具体案例看的看下在 Rosetta 中隐私数据是如何得到安全保护的。

案例

Alice, Bob 和 Charley 三人最近需要在他们的 AI 系统中引入对数据的隐私保护能力。他们很重视安全性,所以他们想通过一个简单的例子 —— 乘法(multiply),来验证下隐私 AI 框架是否真正做到了隐私安全。


他们约定:Alice 的输入为 1.2345;Bob 的输入为 5.4321;而 Charley 拿到相乘的结果。


他们按照 Rosetta 提供的教程,快速编写了如下代码(脚本名为 rosetta-mul.py):


#!/usr/bin/env python3import latticex.rosetta as rttimport tensorflow as tf
rtt.activate("SecureNN")x = tf.Variable(rtt.private_console_input(0, shape=(1,))) # Alice's inputy = tf.Variable(rtt.private_console_input(1, shape=(1,))) # Bob's inputz = tf.multiply(x, y) # z = x * y
with tf.Session() as sess: sess.run(tf.global_variables_initializer()) res = sess.run(rtt.SecureReveal(z, receive_party=4)) # 'b0100' means Charley print('z:', res)
rtt.deactivate()
复制代码


接着,他们各自打开一个终端,分别进行如下操作:


Alice (P0) 在终端敲下如下命令行,并根据提示输入自己的私有数据:


$ python ./rosetta-mul.py --party_id=0please input the private data (float or integer): 1.2345
复制代码


Bob (P1) 执行同样的操作,输入的也是只有自己才知晓的私有数据:


$ python ./rosetta-mul.py --party_id=1please input the private data (float or integer): 5.4321
复制代码


Charley (P2) 在终端敲下如下命令行,等一会儿就可以得到所期望的计算结果:


$ python ./rosetta-mul.py --party_id=2z: [b'6.705910']
复制代码


注:

  • 对于 Charley 来说,由于没有数据,故不会提示输入。

  • Alice 和 Bob 的本地输出都会是 z: [b'0.000000'], 而不会拿到正确的结果。


可以看出,Charley 拿到的最终结果与逻辑上明文结果(6.70592745)相比,误差(0.00001745)可以忽略不计。系统的正确性得到了验证。


如果想让误差更小,可以通过配置提升精度,或使用 128-bit 的数据类型。具体操作可以参考文档


上面短短的几行代码,虽然结果是正确的,但是他们三人对于系统安全性方面仍有一些困惑:


  • Alice、Bob 的私有输入会不会被另外两方知道?

  • Charley 拿到的结果会不会被 Alice 、 Bob 知道?

  • 整个程序运行过程中,有没有其他数据的泄漏?

  • 如果前几问的回答都是否定的,那 Charley 又是如何得到明文?


在回答这些问题之前,为简化描述、突出本质,我们需要简单介绍一下 MPC 实际落地中常用的安全假设。


假定系统中有 3 个节点,P0/P1/P2,其中 P0/P1 为数据参与方,而P2 是辅助节点,用于随机数生成。


  • 只考虑半诚实(Semi-Honest)安全模型,即三方都会遵守协议执行的流程,并且其中诚实者占多数(Honest-Majority),也就是说三个节点中只会有一个“坏人”。更为复杂的恶意(Malicious)模型等安全场景可参考其他相关论文。

  • 内部数据类型为 64 位无符号整型,即 uint64_t (这在理论上对应着在环 )。


下面我们就按照 输入–计算–输出 的顺序,详细介绍 Rosetta 中数据的表示与流动,以及所用到相关技术与算法在工程上的优化实现。

隐私数据的输入

隐私计算问题,首先要解决的是隐私数据的输入。


在上述案例中,是通过如下两行代码来完成私有数据的安全输入的:


x = tf.Variable(rtt.private_console_input(0, shape=(1,))) # Alice's inputy = tf.Variable(rtt.private_console_input(1, shape=(1,))) # Bob's input
复制代码


如代码所示,rtt.private_console_input 是 Rosetta 众多 API 之一,Rosetta 还提供了 rtt.private_inputrtt.PrivateDataset 等 API,用来处理隐私数据的输入。


这里发生了什么?x,y 的值会是什么?


在进入剖析之前,先来了解一个重要的概念 —— 秘密分享

秘密分享

什么是 秘密分享(Secret Sharing)[1]?先来看一种简单的两方 additive 的构造:


给定一个数 x,定义 share(x) = (x0, x1) = (x − r, r),其中 r 是随机数,并且与 x 独立。可以看到,x = x0 + x1 = x -r + r。原始数据 x 的秘密分享值 (x0, x1) 将会由两个数据参与方 (P0, P1) 各自保存。


在秘密分享的方案中,所有的数据,包括中间数值都会分享在两个参与方之间。直观的看,参与的两方不会得到任何的明文信息。理论上,只需要在环 上支持加法和乘法,就可以进一步通过组合来支持上层各种更复杂的函数。下文我们会看到关于乘法的详细解析,读者可以回过头来再看这段话。


那工程上是如何处理的呢?假设 P0 有一个私有数据 x,三方之间可以简单交互一下实现:


方案 1: P2 生成一个随机数 r,发送给 P0/P1。然后 P0 本地设置 x0 = x - rP1 本地设置 x1 = r。此时 share(x) = (x0, x1) = (x - r, r),与上面的定义一致。


这是方案之一,后文基于这个方案进行讲解。在本文最后,我们会提一下实际落地时的进一步优化方案。


回到主线,结合 方案 1,我们以 Alice 的输入值 x = 1.2345 为例看下具体过程。


第一步,浮点数转定点数。


对于有数据输入的一方,需要先将真实的浮点数转成定点数。


浮点数转定点数:即浮点数乘以一个固定的缩放因子(scale,一般为)使其变成定点数(取其整数部分,舍弃小数部分)。当最后需要还原真实的原始浮点数时,用定点数除以缩放因子即可。


我们先选定一个缩放因子,这里取 scale =


经过缩放后,得到 x = 1.2345 * (1<<18) = 323616.768,取整数部分即 323616,用于后续计算。


这里是有精度损失的,但在精度允许的范围内,不会影响后面的计算。


第二步,生成随机数 r 也叫掩码(Masking value),用来隐藏真实值。


P2 生成一个随机数 r,是一个 64-bit 空间的无符号整数。(如,r =​ fdad72ecbfbefeb9。这里用十六进制表示,下同)


P2r 发送给 P0,P1。此时,P0,P1 都拥有一个相同的随机数 r 了。


第三步,设置秘密分享值。


按秘密分享 方案 1 的定义,P0 本地设置 x0 = x - rP1 本地设置 x1 = r。所以有:


P0x0 = 4f020 - fdad72ecbfbefeb9 = 2528d134045f167


P1x1 = fdad72ecbfbefeb9


4f020 是 323616 的十六进制表示。

如果计算结果大于 64 bit 的空间范围,需要对结果取模(64 位空间)。下同。


至此,我们获得了关于 x 的分享值,share(x) = (x0, x1) = (x - r, r) = (2528d134045f167, fdad72ecbfbefeb9)。


感兴趣的读者朋友可以验证一下 (x0 + x1) mod


同理,我们对 Bob 的输入值进行一样的处理。


上面三步,其实就是 private_console_input 的工作机制与过程。经过处理后,各方本地都存储着如下值:


P0P1P2
X02528d134045f167X1fdad72ecbfbefeb9X20
Y0d8e19bd0a532750Y1f271e642f5c29328Y20


我们用 Xi,Yi 表示 X,YPi 的分享值。(下同)

P2 为何是 0 呢?在本方案中 P2 作为一个辅助节点,不参与真正的逻辑计算。


我们可以看到,在处理隐私数据输入的整个过程中,P0 无法知道 y 值,P1 无法知道 x 值,P2 无法知道 xy 值。


最后,我们总结一下这三个主要阶段:


密文上的协同计算

这是计算的核心。


上一步,我们保证了输入的安全,没有信息的泄漏,各方无法单独拿到其他节点的私有输入。


接下来,看一下计算的代码,只有一行:


z = tf.multiply(x, y) # z = x * y
复制代码


在这个计算的过程中发生了什么?下面结合乘法(Multiply) 算子原理进行实例讲解。

Multiply 算子原理

乘法相对较为复杂,我们结合经典的 Beaver Triple 方法[2]加以介绍。该方法是由密码学家 Donald Beaver 在 1991 年提出,主要思想是通过乘法。协议基本原理如下:


输入: P0 拥有 X,Y 的秘密分享值 X0,Y0P1 拥有 X,Y 的秘密分享值 X1,Y1


这里有 share(X) = (X0, X1),share(Y) = (Y0, Y1)。在此案例中,这里的输入,就对接上一节所述的"隐私输入"的输出结果。


计算步骤:


  1. P2 本地生成一组随机数 A,B,C,且满足 C = A * B


A,B,C 的生成步骤:P2 随机生成 A0,A1,B0,B1,C0,令 A = A0 + A1, B = B0 + B1,得到 C = A * B, C1 = C - C0其中 Ai,Bi,CiA,B,C 的分享值。 这些都是在 P2 本地完成的。这也就是 P2 做为辅助节点的作用(用于随机数生成)。


这里 A,B,C 一般被称为三元组(Beaver’s Triple)。


比如,某次生成的随机数如下:


A02373edde1a0e5dcdA1ad483b77e4e5db41
B0d81a4646be1c0cb8B178222aff7dcc1ae8
C062a175e20f9a1542C1483498026c6ab57e


感兴趣的读者朋友可以验证一下。如 A = A0 + A1 = 2373edde1a0e5dcd + ad483b77e4e5db41 = d0bc2955fef4390e。这个 A 是个随机数


  1. P2 将上一步生成的随机数的秘密分享值分别发送给 P0,P1


即将 A0,B0,C0 发送给 P0;将 A1,B1,C1 发送给 P1


此时,P0,P1 拥有如下值:


P0P1
A02373edde1a0e5dcdA1ad483b77e4e5db41
B0d81a4646be1c0cb8B178222aff7dcc1ae8
C062a175e20f9a1542C1483498026c6ab57e


  1. P0 计算 E0F0P1 计算 E1F1。并交换 Ei,Fi


P0 本地计算 E0 = X0 - A0, F0 = Y0 - B0


P1 本地计算 E1 = X1 - A1, F1 = Y1 - B1


此时,P0,P1 拥有如下值:


P0P1
E0dede9f352637939aE150653774dad92378
F03573d3764c371a98F17a4fbb4377f67840


交换 Ei,Fi


P0E0,F0 发送给 P1P1E1,F1 发送给 P0。此时,P0,P1 都拥有 E0,F0,E1,F1


  1. P0,P1 本地计算 得到EF


P0,P1 各自本地计算 E = E0 + E1, F = F0 + F1


P0P1
E2f43d6aa0110b712E2f43d6aa0110b712
Fafc38eb9c42d92d8Fafc38eb9c42d92d8


  1. P0 本地计算 Z0P1 本地计算 Z1


现在,P0 已经拥有 A0,B0,C0,E,FP1 已经拥有 A1,B1,C1,E,F。有了这些就可以计算出 Z = X * Y 的秘密分享值 Z0,Z1 了。 即:


P0 本地计算 Z0 = E * B0 + A0 * F + C0


P1 本地计算 Z1 = E * B1 + A1 * F + C1 + E * F


P0P1
Z01db35d14c12aZ1ffffe24ca30611b0


正确性可以通过以下恒等式加以验证:


输出: P0,P1 分别持有 Z = X * Y 的秘密分享值 Z0,Z1


我们可以看到,从输入到计算再到输出,整个过程中,没有泄漏任何隐私数据。


整个算子计算结束时, P0 单独拥有 X0,Y0,A0,B0,C0,E0,F0,E1,F1,E,F,Z0P1 单独拥有 X1,Y1,A1,B1,C1,E0,F0,E1,F1,E,F,Z1P2 单独拥有 A0,B0,C0,A1,B1,C1,三方都无法单独得到 XYZ


最后,我们总结一下(1~5 对应着上面的步骤):


获取明文结果

输入到计算再到输出,各节点只能看到本地所单独拥有的秘密分享值(一些毫无规律的 64 位随机数),从上文也可以看到,节点是无法独自得到任何隐私数据的。那么,当计算结束后,如果想得到结果的明文,怎么获取呢?


Rosetta 提供了一个恢复明文的接口,使用很简单。


res = sess.run(rtt.SecureReveal(z, receive_party=4)) # 'b0100' means Charleyprint('z:', res)
复制代码


那这个 rtt.SecureReveal 是如何工作的呢?


其实非常简单:如果本方想要知道明文,只需要对方把他的秘密分享值发给我,然后本地相加即可。


比如,上一节结尾处,我们知道了各方 (P0/P1/P2) 的分享值如下:


P0P1P2
Z01db35d14c12aZ1ffffe24ca30611b0Z20


结合实例,Charley (P2) 想要获取结果明文,那么,P0,P1 将各自的分享值 Z0,Z1 发给 P2,然后 P2 本地相加即可。即: 1db35d14c12a + ffffe24ca30611b0 = 1ad2da (1757914)。我们将此值进一步再转换为浮点数,就可以得到我们想要的用户态的明文值了: 1757914 / (1 << 18)= 6.7059097

效率优化

上面介绍的 秘密分享multiply 算子 都是基于最基本的算法原理,在时间上和通信上的开销还是比较大的,在实际工程实现中,还可以进一步进行优化以提升性能。在介绍优化方案之前,先了解一下 什么是 PRF


PRF[3],Pseudo-Random Function。 简单来说,即给定一个随机种子 key,一个计数器 counter,执行 PRF(key, counter) ,会得到一个相同的随机数


补充说明一下。例如,P0,P1 执行 PRF(key01, counter01),会产生一个相同的随机数。这里的 key01counter01 对于 P0,P1 来说是一致的。程序会维护这两个值,对使用者来说是透明的。

关于秘密分享

来看看优化版本(假设: P0 有一个私有数据 x)。


  • 方案 2(优化版): P0,P1 使用 PRF(key01, counter) 本地同时生成一个相同的随机数 r。然后 P0 本地设置 x0 = x - rP1 本地设置 x1 = r。此时 share(x) = (x0, x1) = (x - r, r),与定义一致。此版本无需 P2 的参与。没有通信开销。


目前 Rosetta 开源版本中使用的正是此方案。


  • 方案 3(优化版): P0 设置 x0 = xP1 设置 x1 = 0 即可。此时 share(x) = (x, 0)此版本无需 P2 的参与。没有通信开销,也没有计算开销。


上述各个版本(包括方案 1),都是可行且安全的。可以看到P1/P2 并不知道 P0 的原始输入值。

关于 Multiply 算子

Multiply 算子中输入,输出部分没有变化,主要是计算步骤中的第 1 步与第 2 步有些许变化,以减少通信量。这里也只描述这两步,其余与前文相同。


在上文的描述中,我们知道 P2 生成三元组后,需要将其分享值发送给 P0,P1。当我们有了 PRF 后,可以这么做:


  1. P0,P2 使用 PRF(key02, counter02) 同时生成 A0,B0,C0P0,P1 使用 PRF(key12, counter12) 同时生成 A1,B1

  2. 然后,P2A = A0 + A1, B = B0 + B1,得到 C = A * B, C1 = C - C0P2C1 发送给 P1P2 的任务完成。

  3. 目前 Rosetta 开源版本中使用的是此方案。


相比于原始版本,优化版本只需要发送 C1,不用再发送 A0,A1,B0,B1,C0


在 Rosetta 中,我们还针对具体的各个不同的算子进行了一系列的算法、工程优化,欢迎感兴趣的读者来进一步了解。

小结

安全性是隐私 AI 框架的根本,在本篇文章中,我们结合隐私数据输入的处理和密文上乘法的实现,介绍了“随机数” 形式的密文是如何在多方之间流动,同时“神奇”的仍能保证计算逻辑的正确性的。我们这里对于安全性的说明是直观上的描述,而实际上,这些算法的安全性都是有严格数学证明的。感兴趣的读者可以进一步去探索相关的论文。


Rosetta 将持续集成安全可靠的密码学算法协议作为“隐私计算引擎”到框架后端中,也欢迎广大开发者参与到隐私 AI 的生态建设中来。

参考文献

[1] 秘密共享,https://en.wikipedia.org/wiki/Secret_sharing


[2] Beaver, Donald. “Efficient multiparty protocols using circuit randomization.” Annual International Cryptology Conference. Springer, Berlin, Heidelberg, 1991.


[3] PRF 的一个简单介绍,https://crypto.stanford.edu/pbc/notes/crypto/prf.html


作者介绍:


Rosetta 技术团队,一群专注于技术、玩转算法、追求高效的工程师。Rosetta 是一款基于主流深度学习框架 TensorFlow 的隐私 AI 框架,作为矩阵元公司大规模商业落地的重要引擎,它承载和结合了隐私计算、区块链和 AI 三种典型技术。目前 Rosetta 已经在 Github 开源(https://github.com/LatticeX-Foundation/Rosetta) ,欢迎关注并参与到 Rosetta 社区中来。


系列文章:


隐私 AI 工程技术实践指南:整体介绍


面向隐私AI的TensorFlow深度定制化实践


隐私AI框架中MPC协议的快速集成


2020-11-03 10:302355

评论

发布
暂无评论
发现更多内容

斯图飞腾数据分析平台Stratifyd获评“2021大数据产业创新服务产品”

InfoQ_967a83c6d0d7

万字详解 Spark 数据倾斜及解决方案

五分钟学大数据

spark 1月月更

openGauss 助力邮储银行分布式新核心迈向智能运维时代

openGauss

关于dart中的late关键字,你了解多少?

坚果

flutter dart 1月月更

巧用Amazon PrivateLink——轻松访问私有终端节点Amazon S3

亚马逊云科技 (Amazon Web Services)

网络

【量化】量化交易入门系列6:量化交易学习书籍推荐(二)

恒生LIGHT云社区

量化策略 量化投资 量化交易 量化

skywalking核心概念

淡泊明志、宁静致远

3个重点,20个函数分析,浅析FFmpeg转码过程

奔着腾讯去

音视频 WebRTC ffmpeg RTMP RTSP

霸屏综艺,牵手明星,扩列神器皮皮APP的出圈始末

联营汇聚

【网络安全】你必须知道的几个网络安全概念

行云管家

运维 网络安全 防火墙 IT

linux系统管理与自动化运维工具用哪款好?

行云管家

Linux 运维 IT运维 自动化运维

Linux云计算好学吗?Linux云计算运维学习资料 vim编辑器和恢复ext4下误删文件

学神来啦

从四种时序数据库选型中脱颖而出,TDengine在工控领域边缘侧的应用

TDengine

数据库 大数据 tdengine 物联网

workflow 之 Prefect 基本用法(qbit)

qbit

工作流 pipeline workflow 数据流

面试官惊叹,好小子!你这多线程基础可以啊!

XiaoLin_Java

1月月更

中山市政务服务数据管理局党组书记叶永忠:积极构筑智慧联接新底座,打造中型智慧城市标杆

InfoQ_967a83c6d0d7

使用 Simple Replay 实用程序简化 Amazon Redshift RA3 迁移评估

亚马逊云科技 (Amazon Web Services)

mad

在Spark Scala/Java应用中调用Python脚本,会么?

华为云开发者联盟

Python spark python脚本 Spark Scala Java应用

Karpenter : 新一代 Kubernetes auto scaling 工具

亚马逊云科技 (Amazon Web Services)

网络

前端开发之动态管理Nginx集群的方法

@零度

nginx 前端开发

低代码实现探索(十五)安全检查报告提高低代码数据安全性

零道云-混合式低代码平台

为什么零售业需要借助CRM系统蓬勃发展

低代码小观

企业管理 CRM 企业管理系统 CRM系统 企业管理软件

基于实例数据详解准确率和召回率

华为云开发者联盟

数据集 AUC 信息检索 准确率 召回率

效果提升28个点!基于领域预训练和对比学习SimCSE的语义检索

百度大脑

人工智能

开源demo| 智慧协同demo升级——协同更直观方便

anyRTC开发者

音视频 白板 智慧协同 开源demo 远程协助

工具 | 如何对 MySQL 进行 TPC-C 测试?

RadonDB

MySQL RadonDB

风口上的“低代码”,是时候来系统学一学了!

博文视点Broadview

MySQL高级特性篇教程

编程江湖

MySQL

助力产教融合,夯实数据库产业人才基座!openGauss社区分委会正式成立

openGauss

您有一份Microsoft Office 365技能宝典等待签收

淋雨

Office 365 office办公软件

低代码实现探索(十四)工程化思想提高项目质量与可维护性

零道云-混合式低代码平台

隐私AI框架中的数据流动与工程实现_AI&大模型_Rosetta技术团队_InfoQ精选文章