现充|junyu33

Rathee 三部曲:CrypTFlow2,SIRNN与SecFloat

Background

Notation: 记安全参数为 λ, 秘密共享的整数长度为 l-bit.

MPC方面,假设我们拥有以下基础知识:

在浮点数储存方面,我们使用 IEEE754 Float32(单精度标准):

IEEE 754 加法

不失一般性,设 xy,为了计算 z=x+y,其中:

x=(1)Sx(1.Mx)2Ex,y=(1)Sy(1.My)2Ey

则步骤如下:

  1. 指数对齐。若 Ex > Ey,将 y 的尾数右移: My1.My2ExEy,EEx,Mx(1.Mx).
  2. 尾数相加。考虑Sx,Sy的符号情况。若同号,则计算 M=Mx+My。若异号,则用大者减小者得到差的绝对值M=|MxMy|,并附上正确的符号S
  3. 规范化。显然 max{Mx+My,|MxMy|}<4,故M右移最多只需一次(对应指数E加1即可)。若 M=0,则直接跳到第四步。其余情况反复左移并自减E,直到M[1,2) 时停止。
  4. 写入结果。最后将 M 的首位 1 剔除,将最后的 S,E,M 重新作为新的 32 位浮点结果。
  5. My1.My2ExEyM=Mx+MyM=|MxMy|以及对M右移一位这四个步骤中,会涉及到舍入问题。

IEEE 754 乘法

乘法由于不涉及数的大小比较,因此步骤相对比较简单。

  1. 符号位异或。S=SxSy.
  2. 指数相加。E=Ex+Eybias.
  3. 尾数相乘。M=(1.Mx)(1.My),结果在 [1,4) 范围内。
  4. 规范化。如果结果 2,将 E 自增并将 M 右移一位,最后剔除 M 最高位的 1.
  5. M=(1.Mx)(1.My)M 右移一位这两步涉及到舍入操作。

舍入方法

我们令 d,g,f 分别为 M 的最低位(decision bit),被丢弃的最高位(guard bit)和被丢弃的剩余位(sticky bit)。则“四舍六入五成双”的规则可以形式化表述为如下公式:

c=g(df)

简单的解释一下,就是只有当 g=1 时才可能进位。此时如果 f=1(肯定大于0.5)或者 d=1(刚好0.5但要是偶数),则进位(c=1)。

注意舍入之后有可能需要再次规范化。

Building Blocks

下面用自底向上的方式,讲清楚整个协议是如何构建的。

FMUX

我们需要实现的理想功能是,MUX(b,x)=(b==1?x:0)。即对于布尔 secret share [c]=(c0,c1),ci{0,1} 和算术 secret share [a]=(a0,a1),aZn,输出 [ac]。步骤如下:

SETUP: P0 持有 a0,c0P1 持有 a1,c1

我们列举出四种可能的 (c0,c1) 情况:

(s0,s1)=(r0+c0a0,r0+a0(1c0))(t0,t1)=(r1+c1a1,r1+a1(1c1))

x0=tc0,x1=sc1

c0 c1 x0 x1 (r0+r1)+(x0+x1)
0 0 r1+c1a1 r0+c0a0 0
0 1 r1+c1a1 r0+a0(1c0) a
1 0 r1+a1(1c1) r0+c0a0 a
1 1 r1+a1(1c1) r0+a0(1c0) 0

结果刚好等于 [ac],因此协议正确。

通信量为两轮 IKNP-OT 的开销,也就是 2(λ+2l)=2λ+4l。但 CryptoFlow2 的 3.1.1 节可以将通信开销优化到 2λ+2l

FAND

这是显然的,直接使用 beaver triple 实现,通信量为 (λ+16)+4。(见 CryptoFlow2 的附录 A1 节)

FOR

我们有 [xy]=[xy][xy]。因此令 [xy]=(z0,z1),因此每一方直接计算 xiyizi 即可。通信量与 FAND 相同,也为 λ+20

FEQ

我们将 x,y 按照 m-bit 进行分块。考虑对某个块 xj,yj 进行比较。我们使用 1-out-of-2m OT:

我们可以通过树状结构与 FAND,计算 (eq1,j)i=(eq0,j)i(eq0,j+m)i,将 m-bit 比较拓展到 2m-bit,最后完成整个长度的比较。通信量为 lm(2λ+2m)+lm(λ+20),轮数为 logl.

FGT/LT

仍然是分块的思路,首先计算块长度为 m 的结果 1{xj<yj},还是可以使用 1-out-of-2m OT 完成。P0 只需随机生成 (lt0,j)0, 并准备 2m 个消息 tj,k=(lt0,j)01{xj<k}.

然后合并的时候高位优先,1{x<y}=1{xH<yH}(1{xH=yH}1{xL<yL}).

通信成本小于 λ(4q)+2m(2q)+22q,取 m=4,q=l/4 时为 λl+13.5l ,轮数 logl.

FLUT

假设 LUT 有 2m 项,每一项有 n-bit.

SETUP: P0 随机取索引 r{0,1}m,和 LUT L 混淆后的 share T0[i]Z2n,i{0,1}m.

FWrap

如果我们要计算 1{a+b>2n1},这等同于计算 1{2n1a<b}。因此直接使用 FGT/LT 即可。

FB2A

P0,P1 分别持有布尔共享的一位 c=c0c1,c{0,1},并最后得到 d=d0+d1(mod2n)d=c

验证一下结果,d0+d1=c0+c12(y0+y1)

通信开销为一次 1-out-of-2 COTn,成本为 λ+n.

FZExt

我们有了前面的 FWrapFB2A,构造 FZExt 便是自然的事情。对于 m-bit 的加法共享,我们尝试将其零扩展到 n-bit (n>m)。首先,我们要 check 这两个 share 是否有进位(使用 FWrap),然后将得到的布尔进位 w 使用 FB2A 转为 Z2nm 的算术值。

但我们只是做零扩展操作,两个 share 相加,不能在第 m 位产生进位,因此双方要在 Z2n 减掉一个 2m 的 share,由于 m 公开,可以直接本地完成。

成本为 Comm(FWrap+FB2A)=λm+14m+λ+(nm)=λ(m+1)+13m+n.

FTR

既然我们有了从小到大的 FZExt,那自然也有反过来的 FTR。我们假设从 l-bit 截断低位的 s-bit,并输出最终的高位 ls-bit(这本质上也等同于 x >> s):

SETUP: Pb 将原来的 share xb 拆成 ub||vb,前者为 ls 位,后者为 s 位,可以证明:

TR(x,s)=u0+u1+Wrap(v0,v1,s)

开销为 Comm(FWrap+FB2A)=(λs+14s)+(λ+(ls))=λ(s+1)+13s+l.

FCrossTerm

FCrossTerm 与用 beaver triple 的安全乘法比较相近,但区别是后者 P0P1 都知道 xy 的一部分 share。而 FCrossTerm 的适用条件是 P0 独占 xP1 独占 y,最后各自获得长度 l=m+nxy 的 share.

总通信成本为 i=0m1(λ+(li))=mλ+mlm(m1)2=O(mλ+mn).

FUMult

语义是双方持有 x=x0+x1(mod2m),y=y0+y1(mod2n),目标是计算 z=xyZ2m+n.

这里还是不能直接做 beaver triple,因为它是 ring agnostic 的,可能会带来未知的 wrap 问题。当然一个办法是将 x,y 都扩展到足够大的环,做安全乘法后又截断回去。当然这里有两个问题,一是 FTR 是高位截断而不是低位截断,协议需要稍微改一改;二是这种办法运算成本较高,不如接下来介绍的专用 FUMult 协议。

我们现在要计算(x0+x1)(y0+y1)=x0y0+x1y1+x0y1+x1y0,前两者可以分别由 P0,P1 离线完成。而后两者就涉及到刚才的 FCrossTerm 了。总之,我们有了在 P0 存储的完整 x0y0P1 存储的 x1y1,以及双方都拥有的 x0y1,x1y0 的一部分。FUMult 的作用就是把这 4 项安全地拼起来,并且处理 wrap 的问题。

尝试把两个 share 加起来看看:b(xbyb+x0y1b+x1y0)=(x0+x1)(y0+y1)

b(2ngb2mhb)=2ng2mh=2n(wyx)2m(wxy)

合在一起,z=(x0+x1)(y0+y1)wy(x2n)wx(y2m)

=(x+wx2m)(y+wy2n)wy(x2n)wx(y2m)=xy,刚好抵消。

ν=max(m,n),l=m+n,论文给出了具体的开销,数量级为 O(λν+ν2)。相比于 beaver triple 做法(含生成乘法三元组)的 O(λl+l2) 数量级相同,但论文声称 FUMult 通信少 1.5×.

FSMultFUMult 原理类似,通信量完全相同,这里就略过了。

FDigDec

作用是将一个 l-bit 的 share x,按 d-bit 分块,拆分成 c=ld{zi}i=0c1,其中 x=zc1||zc2||||z0. 显然,本地进行这个操作会导致 wrap 问题。

当然解决这个问题的思路也容易想到,首先使用 Fwrap 判断 x[0,d1] 的两个 share 是否溢出,并得到溢出结果的 share c0,令 z0=x[0,d1]2dc0,并将目前双方的高位 x[d,l1] 加上 c0,最后递归执行这一过程即可。

复杂度相当于 (c1)Fwrap 的成本,也就是 (c1)(λd+14d).

FMSNZBP

检测第 id-bit 分块中最高非零位对应的全局 index,也可以理解成 log2(zi)+id,这里的具体实现方法是直接 FLUT 解决。但有一个问题是当 zi=0 时右边这个式子与左边实现的语义并不相同,作者这里选择让 zi=0 的结果未定义,交给上层协议来解决。

这一点我不是很理解,zi=0 的情况也可以在 FLUT 的情况直接解决啊,又不会增加通信成本。

总之,通信量等价于一个 1-out-of-2d OTlog2l 实现,因此通信量为 2λ+2dlog2l.

FZeros,FOneHot

前者的意思是判断一个长度为 d 的向量(或者 d-bit 数)是否为零。而后者是将一个 k[0,l1] 的 share,转化为一个长度为 l 的向量 share,满足和为 (0,0,,1,,0),其中仅有第 k 个向量为 1.

这两个分别可以用 1-out-of-2d OT 和 1-out-of-l OTl 实现,成本分别为 2λ+2d2λ+l2。虽然后者成本较高,但只在父协议 FMSNZB 的最后调用一次,因此总成本还能接受。

FMSNZB

含义是给定一个输入 xl,计算出 l 的最高零位的值 k,输出向量 share 满足和为 (0,0,,1,,0),其中仅有第 k 个向量为 1。 为了简单起见,这里我假设 FMSNZBP 是定义良好的(也就是处理了 zi=0 的情况)。令 ι=log2l:

总结

原语 依赖的原语 功能 通信开销
FMUX (21)OTl 长度l位的三目运算符 2λ+2l
FOR FAND, i.e. beaver triple 逻辑或 λ+20
FEQ (2m1)OT,FAND 长度l位的算术相等 <34λl+9l
FLT/GT (2m1)OT,FAND 长度l位的算术比较 <λl+14l
FLUT (2m1)OTn 长度m位,结果 n 位的查找表 2λ+2mn
FZExt FWrap,FB2A m 位零扩展到 n λ(m+1)+13m+n
FTR FWrap,FB2A l 位截取高 ls λ(s+1)+l+13s
FUMult,FSMult FCrossTerm,FWrap,FMUX 长度m,n位的无/有符号乘 O(λl+l2)
FMSNZB FDigDec,FMSNZBP,FOneHot 长度l位的最高非零位index λ(5l4)+l2

Primitives

我们终于构建了 secfloat 论文对应的所有基础协议,现在我们转入本篇论文构造的重要原语。

FFPcheckp,q

用来检查浮点数在浮点参数为 p,q(IEEE754 默认 p=8,q=23)的情况下是否上溢或者下溢。这是本文的一个创新点,就是可以自己选取浮点参数,不一定遵照 IEEE754 的格式。

α = (z, s, e, m)
if 1{e > 2^{p-1} - 1} then
   m = 2^q; e = 2^{p-1}
if 1{z = 1} ∨ 1{e < 2 - 2^{p-1}} then
   m = 0; e = 1 - 2^{p-1}; z = 1
Return (z, s, e, m)

这个逻辑符合论文对溢出的处理方式,这里大概描述一下协议是怎么跑的:

FTRSl,s

FTRSFTR 的基础上,增加了对浮点数粘滞位 S 的进位判定。当被舍去的低 s 位只要有任意一位为 1,且 LSB(x)=0,则执行进位操作。其功能等同于 (x >> s) | (x & (2**s - 1) != 0)。右移还是用 FTR 搞定(或者说是结合 FWrapFB2A),但之后还要做一个 FZeros 的操作,成本较高。

由于 FZeros 也等价于判断两个 share 的和是否为 2s,或者两者都为0,因此其本质也是比较操作(或者 FWrap 操作)。因此作者选择将 FWrapFZeros 捆绑实现成 FWrap&All0s,成本仅仅相当于一个比较操作和一个 FAND 的成本(这里论文有 typo,不是两个 FAND 的成本)。

FRNTEl

FRNTE 等价于带舍入的右移 xRr。在前文中我们讲过 IEEE 的舍入逻辑如下:

c=g(df)

我们首先用 TRS(x, r-2) 确认 f 后面的位是否为 1,如果是就加回来以确保粘滞位判定逻辑正确。此时 x 的后三位就分别是d,g,f。然后用 FLUT 将这个 8-bit 的舍入逻辑硬编码到结果 c 中。最后再调用 TR(x, 2) 并加上舍入结果 c 即可。

FRoundp,q,Q

给出浮点数 α=(z,s,e,m) 中的 (e,m),将已规格化的尾数 mQ 位精度舍入到 q 位精度,并处理舍入导致的进位溢出。注意这里 m 采用了定点数形式,也就是尾数 1.M 对应定点数 m=(1.M)×2Q。因此 m 的取值范围是 [2Q,2Q+1)。协议逻辑如下所示:

if 1{m >= 2^{Q+1} − 2^{Q−q−1}} then
   Return (e+1, 2^q)
else
   Return (e, m >>R (Q−q))

以下对该代码逻辑的正确性进行说明。尾数分为两种情况:

FFPAddp,q

在前置知识一节,我们已经概括了普通浮点加法的办法。下面我们将该方法与伪代码对应:

  1. 指数对齐。若 Ex > Ey,将 x 的尾数左移: Mx(1.Mx)2ExEy,EEy.
  1. 尾数相加。考虑Sx,Sy的符号情况。若同号,则计算 M=Mx+My。若异号,则用大者减小者得到差的绝对值M=|MxMy|,并附上正确的符号S

这里考虑同号与异号的情况。同号时,β1β2 的符号位异或为 0,否则为 1。因此当 β1.sβ2.s=1 时,将 m2 变号完成相减操作。

  1. 规范化。这里我们找到加法结果 m 中最高有效位,为了保证有足够的空间舍入,协议在第一步时将精度为 qm1,m2 零扩展为 2q+2 位(但注意精度是 2q+1)。假设 MSNZB 的结果为 k,要将高位的1规范化(也就是对齐后面 Round* 协议的 2q+1 位)需要左移 2q+1k 位,对应乘 K=22q+1k

至于指数位的计算,由于先左移了 2q+1k 位,同时又因为精度变化又增加 q+1,因此 e=e(2q+1k)+(q+1)=e+kq

  1. 写入结果。最后做一轮 FRoundp,q,2q+1 的舍入,由于 |m1|>|m2|,符号位一定由 β1.s 决定。最后检查规范化的结果是否在浮点数有效范围内。

FFPMulp,q

  1. 符号位异或。S=SxSy.(第7行)
  2. 指数相加。E=Ex+Eybias.(第1行,论文这里令 bias=0
  3. 尾数相乘。M=MxMy,结果在 [22q,22q+2) 范围内。(第2行)
  4. 规范化。如果结果 22q+1,将 E 自增并将 M 右移一位,最后剔除 M 最高位的 1.

结果 22q+1 走第 6 行 else 分支,否则走第四行 if 分支。

  1. M=MxMyM 右移一位这两步涉及到舍入操作。(也就是第4、6行的 FRNTEl

Math Functions

在《学数学,就这么简单》这本书中,有这样一个桥段:

FFPsinπ8,23

基于这样的思路,我们实际上可以细化出计算机是如何计算 sinx 的。

  1. 首先利用三角函数诱导公式,将 x 的范围缩减到 [0,π/2]. (Range reduction)

这是论文的做法,但实际上舍入到 [π/4,π/4] 再利用二倍角公式,误差会小一个数量级。

  1. 使用泰勒展开进行近似,例如 sinxx16x3+1120x5. (Polynomial Evaluation)
  2. 使用秦九韶算法 x16x3+1120x5=((1120x216)x2+1)x,减少乘法次数并降低误差。

这些运算就只需要浮点加法和乘法可以搞定,至于多项式的系数由于相对固定,可以通过查表解决。

我们现在对应到具体的原语 FFPsinπ8,23 上,也就是计算 sinπx。步骤如下:

  1. 首先处理特殊情况:当 |x|>223 时,由于 q=23,超过了尾数的精度,因此 x 一定是整数。sinπx=0。另一种特殊情况是当 |x|<214 时,sinπxπx,其误差在 x 本身浮点表示的误差以内。
  1. range reduction 步骤:目的是从输入 α 算出奇偶位 a{0,1} 以及区间 δ。令 |α|=2K+a+n,若 n<0.5,则 δ=n,否则 δ=1n。故 sinπα=(1)a1{α<0}sinπδ.
m = α.m * 2^{α.e + 14}
a = TR(m, q+14); n = m mod 2^{q+14}

α 变成一个整数。由于 |α|=2α.eα.m2q,故 m=α.m2α.e+14|α|2q+14. 则 a|α| 的整数部分, n|α| 的小数部分。

f = (n > 2^{q+13} ? 2^{q+14} - n : n)
k,K = MSNZB(f); f = f * K
z = 1{f=0}; e = (z ? -2^{p-1}+1 : k - q - 14)

第一行保证 f=δ2q+14。第二行找到 f 的最高有效位,从而将 f 规范化,并在第三行设定正确的指数位 e

f=0 时,sinπα=0。将零位 z 设为 1,并按照论文约定将指数位 e 设为 2p1+1.

δ = (z, 0, e, TR(f, q+14−Q))

最后重新将定点数 fQ 位精度存储,与其他参数合并成浮点数 δ

  1. polynomial evaluation 步骤,注意论文使用了 Remez 等精度更高的逼近方法,而不是泰勒展开:
if 1{δ.e < −14} then
   µ = Float_{p,Q}(π) ⊗_{p,Q} δ

先前 |δ|214 时的特殊情况,sinπxπx.

if 1{δ.e < −5} then
   idx1 = δ.e + 14 mod 2^4
   (θ1, θ3, θ5) = GetC_{4,9,5,p,Q}(idx1, Θ1_sin, K1_sin)

考虑 214<|δ|<25 时的情况,这里 GetC 函数提供了一个查表操作,通过选取 K1_sin 这一常数类,在 Θ1_sin 这个表中,通过 index idx1(也就是 δ.e+14 的低4位)获取对应的参数 (θ1, θ3, θ5)

4 是表的 bit 数,9 是 spline(系数对)的个数,5 是拟合的多项式的次数。

idx2 = 32 · (δ.e + 5 mod 27)
idx2 = idx2 + ZXt(TR(δ.m, Q−5) mod 32, 7)
idx2 = 1{δ.e = −1} ? 127 : idx2
(θ1, θ3, θ5) = GetC_{7,34,5,p,Q}(idx2, Θ2_sin, K2_sin)

25|δ|<0.5 这个区间,用δ.e + 5的低2位和δ.m的高5位进行查表的区分(这是论文的第二个创新点:分段索引),来调用对应误差最小的 (θ1, θ3, θ5)。对 |δ|=0.5 的区间,进行特判。

  1. 使用秦九韶算法求出对应的浮点值:
Δ = δ ⊗_{p,Q} δ
µ = ((θ5 ⊗ Δ) ⊞* θ3) ⊗ Δ
µ = (µ ⊞* θ1) ⊗ δ
Return (µ.z, a ⊕ α.s, Round*(µ.e,µ.m))

Δ=δ2

μ=(θ5Δ+θ3)Δ=θ5δ4+θ3δ2

μ=(μ+θ1)δ=θ5δ5+θ3δ3+θ1δsinπδ

前文说过:sinπα=(1)a1{α<0}sinπδ,故 a ⊕ α.s 确定符号位,最后舍入即可得到最终结果。

大概总结一下,FFPsinπ8,23 先对输入做范围归约,把问题化到0到0.5的小区间并记录符号补偿;对极大或极小输入走快速分支。随后按指数和尾数位确定分段,用查表选出对应多项式系数,采用秦九韶算法计算近似值,最后做符号恢复并舍入到单精度输出。

这个方法一个潜在的缺点是,这个 GetC 函数用的表是 ad-hoc 的,与前面浮点四则运算的协议不同,如果想要任意指定p,q,或者迁移到 SecDouble,这个系数表需要进行重新计算才能使得误差小于 1ULP。论文为了追求性能与准确度,牺牲了算法的灵活性。

FFPlog28,23

α=m2N,m[1,2),N=α.e,令 a=1{N=1},则分为两种情况:

log2(α)={N+log2(1+δ)a=0,log2(1δ)a=1.

然后,分别按照 a=0a=1 构造两组近似多项式 (θ0a,θ1a,θ2a,θ3a)(θ0b,θ1b,θ2b,θ3b),还是按照分段索引法对指定范围的 δ.eδ.m 进行查表。

然后通过秦九韶算法(Horner's method)计算出 log2(1+) 的值。对于最后加 N 的计算,首先通过查表方式将 N 转化为浮点数,再调用 FFPAddp,q 协议即可。

  1. range reduction 步骤:
a = 1{N = −1}
f = a ? (2^{q+1} − α.m) : (α.m − 2^q)
k,K = MSNZB(f); f = f *_{q+1} K
e = a ? (k − q − 1) : (k − q)

N=1 时(此时 a=1),f=1m/2,否则(此时 a=0f=m1,并将 f 规范化。

z = 1{f = 0}; e = (z ? −2^{p−1}+1 : e); 
N = α.e; δ = (z,0,e, f *_{Q+1} 2^{Q−q})

通过 f 构造出浮点数 δ,并将精度从 q=23 位提高到 Q=27 位,为后文 evaluation 准备。

  1. polynomial evaluation 步骤
if 1{δ.z} then
   µ = Float_{p,Q}(0)

δ=0 时,log2(1+)=log21=0,故返回 μ=0

if 1{δ.e < −5} then
   idx1 = (δ.e + 24) mod 2^5
   (θa0,θa1,θa2,θa3) = GetC_{5,19,4,p,Q}(idx1, Θ1_log, K1_log)
   (θb0,θb1,θb2,θb3) = GetC_{5,18,4,p,Q}(idx1, Θ3_log, K3_log)

224δ<25 时,使用 δ.e + 24 的低5位作为 index,对 a=1 的情况查表 Θ1_log,对 a=0 的情况查表 Θ3_log,这里为了避免数据依赖必须两个都做。

else
   idx2 = 16 · (δ.e + 5 mod 2^7)
   idx2 = idx2 + ZXt(TR(δ.m, Q−4) mod 16, 7)
   (θa0,θa1,θa2,θa3) = GetC_{7,20,4,p,Q}(idx2, Θ2_log, K2_log)
   (θb0,θb1,θb2,θb3) = GetC_{7,32,4,p,Q}(idx2, Θ4_log, K4_log)

25δ<1 时,使用 δ.e + 5 的低3位与 δ.m 的高4位作为 index,对 a=1 的情况查表 Θ2_log,对 a=0 的情况查表 Θ4_log

(θ0,θ1,θ2,θ3) = a ? (θa0,θa1,θa2,θa3) : (θb0,θb1,θb2,θb3)

根据前文对 a 值的分类讨论,选择最终的多项式系数。

  1. 秦九韶算法(Horner)步骤及最后加N
µ = ((θ3 ⊗ δ) ⊞* θ2) ⊗ δ
µ = ((µ ⊞* θ1) ⊗ δ) ⊞* θ0

计算出三次多项式 μ=θ3δ3+θ2δ2+θ1δ+θ0=log2(1+) 的值。

β = LInt2Float(N)
β′ = (β.z,β.s,β.e, β.m *_{Q+1} 2^{Q-6})

N 使用小 LUT,将 N 转化为低精度(尾数为6位)的浮点形式 β,再转化为高精度 Q 的形式 β

γ = a ? µ : (µ ⊞* β′)
Return (γ.z, γ.s, Round*(γ.e, γ.m))

最后执行浮点加法:

最终对 γ 舍入得到协议结果。