async def vector_bsgn_1(x): """Compute bsgn_1(a) for all elements a of x in parallel.""" stype = type(x[0]) n = len(x) await mpc.returnType(stype, n) Zp = stype.field p = Zp.modulus legendre_p = lambda a: gmpy2.legendre(a.value, p) s = mpc.random_bits(Zp, 3 * n, signed=True) # 3n random signs r = mpc._randoms(Zp, 3 * n) r = mpc.schur_prod(r, r) # 3n random squares modulo p x, s, r = await mpc.gather(x, s, r) y = [b + 2 * i for b in (2 * a + 1 for a in x) for i in (-1, 0, 1)] y.extend(s[:n]) s.extend(s[n:2 * n]) r.extend(s[-n:]) y = await mpc.schur_prod(y, s) y = await mpc.schur_prod(y, r) y = await mpc.output(y) h = [legendre_p(y[j]) for j in range(3 * n)] t = [s[j] * h[j] for j in range(3 * n)] z = [ h[3 * j] * h[3 * j + 1] * h[3 * j + 2] * y[3 * n + j] for j in range(n) ] q = (p + 1) >> 1 # q = 1/2 mod p return [ Zp((u.value + v.value + w.value - uvw.value) * q) for u, v, w, uvw in zip(*[iter(t)] * 3, z) ]
async def bsgn_1(a): """Compute binary sign of a securely. Binary sign of a (1 if a>=0 else -1) is obtained by securely computing (u+v+w - u*v*w)/2 with u=(2a-1 | p), v=(2a+1 | p), and w=(2a+3 | p). """ stype = type(a) await mpc.returnType(stype) Zp = stype.field p = Zp.modulus legendre_p = lambda a: gmpy2.legendre(a.value, p) s = mpc.random_bits(Zp, 3, signed=True) # 3 random signs r = mpc._randoms(Zp, 3) r = mpc.schur_prod(r, r) # 3 random squares modulo p a, s, r = await mpc.gather(a, s, r) y = [b + 2 * i for b in (2 * a + 1, ) for i in (-1, 0, 1)] y.append(s[0]) s.append(s[1]) r.append(s[2]) y = await mpc.schur_prod(y, s) y = await mpc.schur_prod(y, r) y = await mpc.output(y) h = [legendre_p(y[i]) for i in range(3)] u, v, w = [s[i] * h[i] for i in range(3)] uvw = h[0] * h[1] * h[2] * y[3] return (u + v + w - uvw) / 2
async def add(a, b): await asyncoro.returnType(sec, 32) res = [None] * 32 c = None atb = mpc.schur_prod(a, b) apb = mpc.vector_add(a, b) for i in range(31, -1, -1): res[i], c = add_(atb[i], apb[i], c) return res
def test_empty_input(self): secint = mpc.SecInt() self.assertEqual(mpc.run(mpc.gather([])), []) self.assertEqual(mpc.run(mpc.output([])), []) self.assertEqual(mpc._reshare([]), []) self.assertEqual(mpc.convert([], None), []) self.assertEqual(mpc.sum([]), 0) self.assertEqual(mpc.prod([]), 1) self.assertEqual(mpc.in_prod([], []), 0) self.assertEqual(mpc.vector_add([], []), []) self.assertEqual(mpc.vector_sub([], []), []) self.assertEqual(mpc.scalar_mul(secint(0), []), []) self.assertEqual(mpc.schur_prod([], []), []) self.assertEqual(mpc.from_bits([]), 0)
async def vector_bsgn_0(x): """Compute bsgn_0(a) for all elements a of x in parallel.""" stype = type(x[0]) n = len(x) await mpc.returnType(stype, n) Zp = stype.field p = Zp.modulus legendre_p = lambda a: gmpy2.legendre(a.value, p) s = mpc.random_bits(Zp, n, signed=True) # n random signs r = mpc._randoms(Zp, n) r = mpc.schur_prod(r, r) # n random squares modulo p x, s, r = await mpc.gather(x, s, r) y = [2 * a + 1 for a in x] y = await mpc.schur_prod(y, s) y = await mpc.schur_prod(y, r) y = await mpc.output(y) return [s[j] * legendre_p(y[j]) for j in range(n)]
async def vector_bsgn_2(x): """Compute bsgn_2(a) for all elements a of x in parallel.""" stype = type(x[0]) n = len(x) await mpc.returnType(stype, n) Zp = stype.field p = Zp.modulus legendre_p = lambda a: gmpy2.legendre(a.value, p) s = mpc.random_bits(Zp, 6*n, signed=True) # 6n random signs r = mpc._randoms(Zp, 6*n) r = mpc.schur_prod(r, r) # 6n random squares modulo p x, s, r = await mpc.gather(x, s, r) y = [b + 2 * i for b in (2 * a + 1 for a in x) for i in (-2, -1, 0, 1, 2)] y = await mpc.schur_prod(y, s[:-n]) y.extend(s[-n:]) y = await mpc.schur_prod(y, r) y = await mpc.output(y) t = [sum(s[5*j + i] * legendre_p(y[5*j + i]) for i in range(5)) for j in range(n)] t = await mpc.output(await mpc.schur_prod(t, y[-n:])) return [c * legendre_p(d) for c, d in zip(s[-n:], t)]
def argmin(x, arg_le): n = len(x) if n == 1: return ([1], x[0]) if n == 2: b, m = arg_le(x[0], x[1]) return ([1 - b, b], m) b2 = [None] * (n // 2) m2 = [None] * ((n + 1) // 2) for i in range(n // 2): b2[i], m2[i] = arg_le(x[2 * i], x[2 * i + 1]) if n % 2 == 1: m2[-1] = x[-1] a2, m = argmin(m2, arg_le) a = [None] * n if n % 2 == 1: a[-1] = a2.pop() b2 = mpc.schur_prod(b2, a2) for i in range(n // 2): a[2 * i] = a2[i] - b2[i] a[2 * i + 1] = b2[i] return a, m
async def main(): # initialize mpc, define secure int type LEN = 10 await mpc.start() secint = mpc.SecInt(64) # initialize inputs values = [np.random.randint(1,1000) for _ in range(LEN)] n = len(mpc.parties) inputs = mpc.input([secint(v)for v in values], senders=list(range(n))) # compute pairwise products prod = inputs[0] for inp in inputs[1:]: prod = mpc.schur_prod(prod, inp) ip = mpc.sum(prod) # output result result = await mpc.output(ip) print("result:", result) await mpc.shutdown()
async def id3(T, R) -> asyncio.Future: sizes = [mpc.in_prod(T, v) for v in S[C]] i, mx = mpc.argmax(sizes) sizeT = mpc.sum(sizes) stop = (sizeT <= int(args.epsilon * len(T))) + (mx == sizeT) if not (R and await mpc.is_zero_public(stop)): i = await mpc.output(i) logging.info(f'Leaf node label {i}') tree = i else: T_R = [[mpc.schur_prod(T, v) for v in S[A]] for A in R] gains = [GI(mpc.matrix_prod(T_A, S[C], True)) for T_A in T_R] k = await mpc.output(mpc.argmax(gains, key=SecureFraction)[0]) T_Rk = T_R[k] del T_R, gains # release memory A = list(R)[k] logging.info(f'Attribute node {A}') if args.parallel_subtrees: subtrees = await mpc.gather( [id3(Tj, R.difference([A])) for Tj in T_Rk]) else: subtrees = [await id3(Tj, R.difference([A])) for Tj in T_Rk] tree = A, subtrees return tree
async def bsgn_2(a): """Compute binary sign of a securely. Binary sign of a (1 if a>=0 else -1) is obtained by securely computing (t | p), with t = sum((2a+1+2i | p) for i=-2,-1,0,1,2). """ stype = type(a) await mpc.returnType(stype) Zp = stype.field p = Zp.modulus legendre_p = lambda a: gmpy2.legendre(a.value, p) s = mpc.random_bits(Zp, 6, signed=True) # 6 random signs r = mpc._randoms(Zp, 6) r = mpc.schur_prod(r, r) # 6 random squares modulo p a, s, r = await mpc.gather(a, s, r) y = [b + 2 * i for b in (2 * a + 1, ) for i in (-2, -1, 0, 1, 2)] y = await mpc.schur_prod(y, s[:-1]) y.append(s[-1]) y = await mpc.schur_prod(y, r) y = await mpc.output(y) t = sum(s[i] * legendre_p(y[i]) for i in range(5)) t = await mpc.output(t * y[-1]) return s[-1] * legendre_p(t)
def test_secfxp(self): secfxp = mpc.SecFxp() self.assertEqual( mpc.run(mpc.output(mpc.input(secfxp(7.75), senders=0))), 7.75) c = mpc.to_bits(secfxp(0), 0) # mpc.output() only works for nonempty lists self.assertEqual(c, []) c = mpc.run(mpc.output(mpc.to_bits(secfxp(0)))) self.assertEqual(c, [0.0] * 32) c = mpc.run(mpc.output(mpc.to_bits(secfxp(1)))) self.assertEqual(c, [0.0] * 16 + [1.0] + [0.0] * 15) c = mpc.run(mpc.output(mpc.to_bits(secfxp(0.5)))) self.assertEqual(c, [0.0] * 15 + [1.0] + [0.0] * 16) c = mpc.run(mpc.output(mpc.to_bits(secfxp(8113)))) self.assertEqual(c, [0.0] * 16 + [1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0]) c = mpc.run(mpc.output(mpc.to_bits(secfxp(2**15 - 1)))) self.assertEqual(c, [0] * 16 + [1] * 15 + [0]) c = mpc.run(mpc.output(mpc.to_bits(secfxp(-1)))) self.assertEqual(c, [0] * 16 + [1] * 16) c = mpc.run(mpc.output(mpc.to_bits(secfxp(-2**15)))) self.assertEqual(c, [0] * 31 + [1]) for f in [8, 16, 32, 64]: secfxp = mpc.SecFxp(2 * f) c = mpc.run(mpc.output(secfxp(1) + secfxp(1))) self.assertEqual(c, 2) c = mpc.run(mpc.output(secfxp(2**-f) + secfxp(1))) if f != 64: # NB: 1 + 2**-64 == 1 in Python self.assertEqual(c, 1 + 2**-f) self.assertEqual(mpc.run(mpc.output(secfxp(0.5) * secfxp(2.0))), 1) self.assertEqual(mpc.run(mpc.output(secfxp(2.0) * secfxp(0.5))), 1) c = mpc.run( mpc.output( secfxp(2**(f // 2 - 1) - 0.5) * secfxp(-2**(f // 2) + 0.5))) self.assertEqual(c, -2**(f - 1) + 1.5 * 2**(f // 2 - 1) - 0.25) s = [10.75, -3.375, 0.125, -0.125] self.assertEqual(mpc.run(mpc.output(list(map(secfxp, s)))), s) s = [10.5, -3.25, 0.125, -0.125] a, b, c, d = list(map(secfxp, s)) t = [v * v for v in s] self.assertEqual(mpc.run(mpc.output([a * a, b * b, c * c, d * d])), t) x = [a, b, c, d] self.assertEqual(mpc.run(mpc.output(mpc.schur_prod(x, x))), t) self.assertEqual(mpc.run(mpc.output(mpc.schur_prod(x, x[:]))), t) t = sum(t) self.assertEqual(mpc.run(mpc.output(mpc.in_prod(x, x))), t) self.assertEqual(mpc.run(mpc.output(mpc.in_prod(x, x[:]))), t) self.assertEqual( mpc.run(mpc.output(mpc.matrix_prod([x], [x], True)[0])), [t]) u = mpc.unit_vector(secfxp(3), 4) self.assertEqual( mpc.run(mpc.output(mpc.matrix_prod([x], [u], True)[0])), [s[3]]) self.assertEqual( mpc.run(mpc.output(mpc.matrix_prod([u], [x], True)[0])), [s[3]]) self.assertEqual( mpc.run(mpc.output(mpc.gauss([[a]], b, [a], [b])[0])), [0]) t = [_ for a, b, c, d in [s] for _ in [a + b, a * b, a - b]] self.assertEqual(mpc.run(mpc.output([a + b, a * b, a - b])), t) t = [ _ for a, b, c, d in [s] for _ in [(a + b)**2, (a + b)**2 + 3 * c] ] self.assertEqual( mpc.run(mpc.output([(a + b)**2, (a + b)**2 + 3 * c])), t) t = [_ for a, b, c, d in [s] for _ in [a < b, b < c, c < d]] self.assertEqual(mpc.run(mpc.output([a < b, b < c, c < d])), t) t = s[0] < s[1] and s[1] < s[2] self.assertEqual(mpc.run(mpc.output((a < b) & (b < c))), t) t = s[0] < s[1] or s[1] < s[2] self.assertEqual(mpc.run(mpc.output((a < b) | (b < c))), t) t = (int(s[0] < s[1]) ^ int(s[1] < s[2])) self.assertEqual(mpc.run(mpc.output((a < b) ^ (b < c))), t) t = (int(not s[0] < s[1]) ^ int(s[1] < s[2])) self.assertEqual(mpc.run(mpc.output(~(a < b) ^ b < c)), t) t = [s[0] > 1, 10 * s[1] < 5, 10 * s[0] == 5] self.assertEqual( mpc.run(mpc.output([a > 1, 10 * b < 5, 10 * a == 5])), t) s[3] = -0.120 d = secfxp(s[3]) t = s[3] / 0.25 self.assertAlmostEqual(mpc.run(mpc.output(d / 0.25)), t, delta=2**(1 - f)) t = round(s[3] / s[2] + s[0]) self.assertEqual(round(mpc.run(mpc.output(d / c + a))), t) t = ((s[0] + s[1])**2 + 3 * s[2]) / s[2] self.assertAlmostEqual(mpc.run(mpc.output( ((a + b)**2 + 3 * c) / c)), t, delta=2**(8 - f)) t = 1 / s[3] self.assertAlmostEqual(mpc.run(mpc.output(1 / d)), t, delta=2**(6 - f)) t = s[2] / s[3] self.assertAlmostEqual(mpc.run(mpc.output(c / d)), t, delta=2**(3 - f)) t = -s[3] / s[2] self.assertAlmostEqual(mpc.run(mpc.output(-d / c)), t, delta=2**(3 - f)) self.assertEqual(mpc.run(mpc.output(mpc.sgn(+a))), s[0] > 0) self.assertEqual(mpc.run(mpc.output(mpc.sgn(-a))), -(s[0] > 0)) self.assertEqual(mpc.run(mpc.output(mpc.sgn(secfxp(0)))), 0) self.assertEqual(mpc.run(mpc.output(abs(secfxp(-1.5)))), 1.5) self.assertEqual(mpc.run(mpc.output(mpc.min(a, b, c, d))), min(s)) self.assertEqual(mpc.run(mpc.output(mpc.min(a, 0))), min(s[0], 0)) self.assertEqual(mpc.run(mpc.output(mpc.min(0, b))), min(0, s[1])) self.assertEqual(mpc.run(mpc.output(mpc.max(a, b, c, d))), max(s)) self.assertEqual(mpc.run(mpc.output(mpc.max(a, 0))), max(s[0], 0)) self.assertEqual(mpc.run(mpc.output(mpc.max(0, b))), max(0, s[1])) self.assertEqual( mpc.run(mpc.output(list(mpc.min_max(a, b, c, d)))), [min(s), max(s)]) self.assertEqual(mpc.run(mpc.output(mpc.argmin([a, b, c, d])[0])), 1) self.assertEqual( mpc.run(mpc.output(mpc.argmin([a, b], key=operator.neg)[1])), max(s)) self.assertEqual(mpc.run(mpc.output(mpc.argmax([a, b, c, d])[0])), 0) self.assertEqual( mpc.run(mpc.output(mpc.argmax([a, b], key=operator.neg)[1])), min(s)) self.assertEqual(mpc.run(mpc.output(secfxp(5) % 2)), 1) self.assertEqual(mpc.run(mpc.output(secfxp(1) % 2**(1 - f))), 0) self.assertEqual(mpc.run(mpc.output(secfxp(2**-f) % 2**(1 - f))), 2**-f) self.assertEqual( mpc.run(mpc.output(secfxp(2 * 2**-f) % 2**(1 - f))), 0) self.assertEqual(mpc.run(mpc.output(secfxp(1) // 2**(1 - f))), 2**(f - 1)) self.assertEqual(mpc.run(mpc.output(secfxp(27.0) % 7.0)), 6.0) self.assertEqual(mpc.run(mpc.output(secfxp(-27.0) // 7.0)), -4.0) self.assertEqual( mpc.run(mpc.output(list(divmod(secfxp(27.0), 6.0)))), [4.0, 3.0]) self.assertEqual(mpc.run(mpc.output(secfxp(21.5) % 7.5)), 6.5) self.assertEqual(mpc.run(mpc.output(secfxp(-21.5) // 7.5)), -3.0) self.assertEqual( mpc.run(mpc.output(list(divmod(secfxp(21.5), 0.5)))), [43.0, 0.0])
def test_secfxp(self): secfxp = mpc.SecFxp() c = mpc.to_bits(secfxp(0), 0) # mpc.output() only works for nonempty lists self.assertEqual(c, []) c = mpc.run(mpc.output(mpc.to_bits(secfxp(0)))) self.assertEqual(c, [0.0] * 32) c = mpc.run(mpc.output(mpc.to_bits(secfxp(1)))) self.assertEqual(c, [0.0] * 16 + [1.0] + [0.0] * 15) c = mpc.run(mpc.output(mpc.to_bits(secfxp(0.5)))) self.assertEqual(c, [0.0] * 15 + [1.0] + [0.0] * 16) c = mpc.run(mpc.output(mpc.to_bits(secfxp(8113)))) self.assertEqual(c, [0.0] * 16 + [ float(b) for b in [1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0] ]) c = mpc.run(mpc.output(mpc.to_bits(secfxp(2**15 - 1)))) self.assertEqual(c, [float(b) for b in [0] * 16 + [1] * 15 + [0]]) c = mpc.run(mpc.output(mpc.to_bits(secfxp(-1)))) self.assertEqual(c, [float(b) for b in [0] * 16 + [1] * 16]) c = mpc.run(mpc.output(mpc.to_bits(secfxp(-2**15)))) self.assertEqual(c, [float(b) for b in [0] * 31 + [1]]) for f in [8, 16, 32, 64]: secfxp = mpc.SecFxp(2 * f) c = mpc.run(mpc.output(secfxp(1) + secfxp(1))) self.assertEqual(c.frac_length, f) self.assertEqual(c, 2) c = mpc.run(mpc.output(secfxp(2**-f) + secfxp(1))) if f != 64: # NB: 1 + 2**-64 == 1 in Python self.assertEqual(c, 1 + 2**-f) self.assertEqual(mpc.run(mpc.output(secfxp(0.5) * secfxp(2.0))), 1) self.assertEqual(mpc.run(mpc.output(secfxp(2.0) * secfxp(0.5))), 1) s = [10.7, -3.4, 0.1, -0.11] self.assertEqual(mpc.run(mpc.output(list(map(secfxp, s)))), s) s = [10.5, -3.25, 0.125, -0.125] a, b, c, d = list(map(secfxp, s)) t = [v * v for v in s] self.assertEqual(mpc.run(mpc.output([a * a, b * b, c * c, d * d])), t) x = [a, b, c, d] self.assertEqual(mpc.run(mpc.output(mpc.schur_prod(x, x))), t) self.assertEqual(mpc.run(mpc.output(mpc.schur_prod(x, x[:]))), t) t = sum(t) self.assertEqual(mpc.run(mpc.output(mpc.in_prod(x, x))), t) self.assertEqual(mpc.run(mpc.output(mpc.in_prod(x, x[:]))), t) self.assertEqual( mpc.run(mpc.output(mpc.matrix_prod([x], [x], True)[0])), [t]) t = [_ for a, b, c, d in [s] for _ in [a + b, a * b, a - b]] self.assertEqual(mpc.run(mpc.output([a + b, a * b, a - b])), t) t = [ _ for a, b, c, d in [s] for _ in [(a + b)**2, (a + b)**2 + 3 * c] ] self.assertEqual( mpc.run(mpc.output([(a + b)**2, (a + b)**2 + 3 * c])), t) t = [int(_) for a, b, c, d in [s] for _ in [a < b, b < c, c < d]] self.assertEqual(mpc.run(mpc.output([a < b, b < c, c < d])), t) t = int(s[0] < s[1] and s[1] < s[2]) self.assertEqual(mpc.run(mpc.output((a < b) & (b < c))), t) t = int(s[0] < s[1] or s[1] < s[2]) self.assertEqual(mpc.run(mpc.output((a < b) | (b < c))), t) t = (int(s[0] < s[1]) ^ int(s[1] < s[2])) self.assertEqual(mpc.run(mpc.output((a < b) ^ (b < c))), t) t = (int(not s[0] < s[1]) ^ int(s[1] < s[2])) self.assertEqual(mpc.run(mpc.output(~(a < b) ^ b < c)), t) t = [int(s[0] > 1), int(10 * s[1] < 5), int(10 * s[0] == 5)] self.assertEqual( mpc.run(mpc.output([a > 1, 10 * b < 5, 10 * a == 5])), t) s[3] = -0.120 d = secfxp(s[3]) t = s[3] / 0.25 self.assertAlmostEqual(mpc.run(mpc.output(d / 0.25)).signed(), t, delta=1) t = s[3] / s[2] + s[0] self.assertAlmostEqual(mpc.run(mpc.output(d / c + a)).signed(), t, delta=1) t = round(t * (1 << f)) self.assertAlmostEqual(mpc.run(mpc.output(d / c + a)), t, delta=1) t = ((s[0] + s[1])**2 + 3 * s[2]) / s[2] self.assertAlmostEqual(mpc.run(mpc.output( ((a + b)**2 + 3 * c) / c)).signed(), t, delta=2) t = 1 / s[3] self.assertAlmostEqual((mpc.run(mpc.output(1 / d))).signed(), t, delta=1) t = s[2] / s[3] self.assertAlmostEqual(mpc.run(mpc.output(c / d)).signed(), t, delta=1) t = -s[3] / s[2] t = round(t * (1 << f)) self.assertAlmostEqual(mpc.run(mpc.output(-d / c)), t, delta=1) t = s[2] / s[3] t = round(t * (1 << f)) self.assertAlmostEqual(mpc.run(mpc.output(d / c)), t, delta=1) self.assertEqual(mpc.run(mpc.output(mpc.sgn(+a))), int(s[0] > 0)) self.assertEqual(mpc.run(mpc.output(mpc.sgn(-a))), -int(s[0] > 0)) self.assertEqual(mpc.run(mpc.output(mpc.sgn(secfxp(0)))), 0) self.assertEqual(mpc.run(mpc.output(abs(secfxp(-1.5)))), 1.5) self.assertEqual(mpc.run(mpc.output(mpc.min(a, b, c, d))), min(s)) self.assertEqual(mpc.run(mpc.output(mpc.min(a, 0))), min(s[0], 0)) self.assertEqual(mpc.run(mpc.output(mpc.min(0, b))), min(0, s[1])) self.assertEqual(mpc.run(mpc.output(mpc.max(a, b, c, d))), max(s)) self.assertEqual(mpc.run(mpc.output(mpc.max(a, 0))), max(s[0], 0)) self.assertEqual(mpc.run(mpc.output(mpc.max(0, b))), max(0, s[1])) self.assertEqual( mpc.run(mpc.output(list(mpc.min_max(a, b, c, d)))), [min(s), max(s)]) self.assertEqual(mpc.run(mpc.output(secfxp(5) % 2)), 1) self.assertEqual(mpc.run(mpc.output(secfxp(1) % 2**(1 - f))), 0) self.assertEqual(mpc.run(mpc.output(secfxp(2**-f) % 2**(1 - f))), 2**-f) self.assertEqual( mpc.run(mpc.output(secfxp(2 * 2**-f) % 2**(1 - f))), 0) self.assertEqual(mpc.run(mpc.output(secfxp(1) // 2**(1 - f))), 2**(f - 1)) self.assertEqual(mpc.run(mpc.output(secfxp(27.0) % 7.0)), 6.0) self.assertEqual(mpc.run(mpc.output(secfxp(-27.0) // 7.0)), -4.0) self.assertEqual( mpc.run(mpc.output(list(divmod(secfxp(27.0), 6.0)))), [4.0, 3.0]) self.assertEqual(mpc.run(mpc.output(secfxp(21.5) % 7.5)), 6.5) self.assertEqual(mpc.run(mpc.output(secfxp(-21.5) // 7.5)), -3.0) self.assertEqual( mpc.run(mpc.output(list(divmod(secfxp(21.5), 0.5)))), [43.0, 0.0])
def test_secfxp(self): secfxp = mpc.SecFxp() c = mpc.to_bits(secfxp(0), 0) # mpc.output() only works for non-empty lists self.assertEqual(c, []) c = mpc.run(mpc.output(mpc.to_bits(secfxp(0)))) self.assertEqual(c, [0.0] * 32) c = mpc.run(mpc.output(mpc.to_bits(secfxp(1)))) self.assertEqual(c, [0.0] * 16 + [1.0] + [0.0] * 15) c = mpc.run(mpc.output(mpc.to_bits(secfxp(8113)))) self.assertEqual(c, [0.0] * 16 + [ float(b) for b in [1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0] ]) c = mpc.run(mpc.output(mpc.to_bits(secfxp(2**15 - 1)))) self.assertEqual(c, [float(b) for b in [0] * 16 + [1] * 15 + [0]]) c = mpc.run(mpc.output(mpc.to_bits(secfxp(-1)))) self.assertEqual(c, [float(b) for b in [0] * 16 + [1] * 16]) c = mpc.run(mpc.output(mpc.to_bits(secfxp(-2**15)))) self.assertEqual(c, [float(b) for b in [0] * 31 + [1]]) for f in [8, 16, 32, 64]: secfxp = mpc.SecFxp(2 * f) d = mpc.run(mpc.output(secfxp(1) + secfxp(1))) self.assertEqual(d.frac_length, f) self.assertEqual(d, 2) d = mpc.run(mpc.output(secfxp(2**-f) + secfxp(1))) f == 64 or self.assertEqual( d, 1 + 2**-f) # NB: 1 + 2**-64 == 1 in Python d = mpc.run(mpc.output(secfxp(0.5) * secfxp(2.0))) self.assertEqual(d, 1) d = mpc.run(mpc.output(secfxp(2.0) * secfxp(0.5))) self.assertEqual(d, 1) s = [10.7, -3.4, 0.1, -0.11] self.assertEqual(mpc.run(mpc.output(list(map(secfxp, s)))), s) s = [10.5, -3.25, 0.125, -0.125] x, y, z, w = list(map(secfxp, s)) s2 = [v * v for v in s] self.assertEqual(mpc.run(mpc.output([x * x, y * y, z * z, w * w])), s2) self.assertEqual( mpc.run(mpc.output(mpc.schur_prod([x, y, z, w], [x, y, z, w]))), s2) s2 = [_ for x, y, z, w in [s] for _ in [x + y, x * y, x - y]] self.assertEqual(mpc.run(mpc.output([x + y, x * y, x - y])), s2) s2 = [ _ for x, y, z, w in [s] for _ in [(x + y)**2, (x + y)**2 + 3 * z] ] self.assertEqual( mpc.run(mpc.output([(x + y)**2, (x + y)**2 + 3 * z])), s2) s2 = [int(_) for x, y, z, w in [s] for _ in [x < y, y < z, z < w]] self.assertEqual(mpc.run(mpc.output([x < y, y < z, z < w])), s2) s2 = int(s[0] < s[1] and s[1] < s[2]) self.assertEqual(mpc.run(mpc.output((x < y) & (y < z))), s2) s2 = int(s[0] < s[1] or s[1] < s[2]) self.assertEqual(mpc.run(mpc.output((x < y) | (y < z))), s2) s2 = (int(s[0] < s[1]) ^ int(s[1] < s[2])) self.assertEqual(mpc.run(mpc.output((x < y) ^ (y < z))), s2) s2 = (int(not s[0] < s[1]) ^ int(s[1] < s[2])) self.assertEqual(mpc.run(mpc.output(~(x < y) ^ y < z)), s2) s2 = [int(s[0] < 1), int(10 * s[1] < 5), int(10 * s[0] == 5)] self.assertEqual( mpc.run(mpc.output([x < 1, 10 * y < 5, 10 * x == 5])), s2) s[3] = -0.120 w = secfxp(s[3]) for _ in range(3): s2 = s[3] / s[2] + s[0] self.assertAlmostEqual(mpc.run(mpc.output(w / z + x)).signed(), s2, delta=1) ss2 = round(s2 * (1 << f)) self.assertAlmostEqual(mpc.run(mpc.output(w / z + x)), ss2, delta=1) s2 = ((s[0] + s[1])**2 + 3 * s[2]) / s[2] self.assertAlmostEqual(mpc.run( mpc.output(((x + y)**2 + 3 * z) / z)).signed(), s2, delta=2) s2 = 1 / s[3] self.assertAlmostEqual((mpc.run(mpc.output(1 / w))).signed(), s2, delta=1) s2 = s[2] / s[3] self.assertAlmostEqual(mpc.run(mpc.output(z / w)).signed(), s2, delta=1) s2 = -s[3] / s[2] ss2 = round(s2 * (1 << f)) self.assertAlmostEqual(mpc.run(mpc.output(-w / z)), ss2, delta=1) s2 = s[2] / s[3] ss2 = round(s2 * (1 << f)) self.assertAlmostEqual(mpc.run(mpc.output(w / z)), ss2, delta=1) self.assertEqual(mpc.run(mpc.output(mpc.sgn(x))), int(s[0] > 0)) self.assertEqual(mpc.run(mpc.output(mpc.sgn(-x))), -int(s[0] > 0)) self.assertEqual(mpc.run(mpc.output(mpc.sgn(secfxp(0)))), 0) self.assertEqual(mpc.run(mpc.output(mpc.min(x, y, w, z))), min(s)) self.assertEqual(mpc.run(mpc.output(mpc.min(x, 0))), min(s[0], 0)) self.assertEqual(mpc.run(mpc.output(mpc.min(0, y))), min(0, s[1])) self.assertEqual(mpc.run(mpc.output(mpc.max(x, y, w, z))), max(s)) self.assertEqual(mpc.run(mpc.output(mpc.max(x, 0))), max(s[0], 0)) self.assertEqual(mpc.run(mpc.output(mpc.max(0, y))), max(0, s[1])) self.assertEqual(mpc.run(mpc.output(secfxp(5) % 2)), 1 * (2**f)) self.assertEqual(mpc.run(mpc.output(secfxp(1) % 2**(1 - f))), 0 * (2**f)) self.assertEqual( mpc.run(mpc.output(secfxp(1 / 2**f) % 2**(1 - f))), 1) self.assertEqual( mpc.run(mpc.output(secfxp(2 / 2**f) % 2**(1 - f))), 0) self.assertEqual(mpc.run(mpc.output(secfxp(1) // 2**(1 - f))), 2**(f - 1)) self.assertEqual(mpc.run(mpc.output(secfxp(27.0) % 7.0)), 6.0) self.assertEqual(mpc.run(mpc.output(secfxp(-27.0) // 7.0)), -4.0) self.assertEqual( mpc.run(mpc.output(list(divmod(secfxp(27.0), 6.0)))), [4.0, 3.0]) self.assertEqual(mpc.run(mpc.output(secfxp(21.5) % 7.5)), 6.5) self.assertEqual(mpc.run(mpc.output(secfxp(-21.5) // 7.5)), -3.0) self.assertEqual( mpc.run(mpc.output(list(divmod(secfxp(21.5), 0.5)))), [43.0, 0.0])
def getitem(self, index): """get item with a secret index, returns 0 when item is not included""" length = len(self.values) unit = mpc.unit_vector(index, length) return mpc.sum(mpc.schur_prod(self.included_values_or_zero(), unit))
def included_values_or_zero(self): return mpc.schur_prod(self.values, self.included)
def getitem(self, index): """get item with a secret index""" length = len(self.values) unit = mpc.unit_vector(index, length) return mpc.sum(mpc.schur_prod(self.values, unit))
def get_attribute_value_for_sample(sample, index): unit_vector = mpc.unit_vector(index, len(sample)) return mpc.sum(mpc.schur_prod(sample, unit_vector))
def select(self, *include): selection = ObliviousArray(self.values).select(*include) included = mpc.schur_prod(self.included, selection.included) return ObliviousSelection(selection.values, included)
async def main(): await mpc.start() with open(f"icissp2020-{len(mpc.parties)}_parties-output.csv", 'w', newline='') as csvfile: print(f"running benchmarks; output will be in {csvfile.name}") print("clearing netem delay just in case ...") subprocess.run(["sudo", "tc", "qdisc","del","dev","lo","root","netem","delay", '0ms']) subprocess.run(["sudo", "tc", "qdisc","del","dev","lo","root","netem","loss", '0%']) fieldnames = ["length","delay","loss","addition","mpc.vector_add()","summation","mpc.sum()","multiplication","mpc.schur_prod()","product","mpc.prod()"] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() for d in range(0,55,5): for p in range(0,11,1): for length in [1,10,100]: print("generating random inputs ...") a = [ [ mpc.input(sec(secrets.randbits(sec.bit_length)))[0] for _ in range(length) ] for _ in range(loop) ] b = [ [ mpc.input(sec(secrets.randbits(sec.bit_length)))[0] for _ in range(length) ] for _ in range(loop) ] r1 = [None] * loop r2 = [None] * loop res = [None] * 8 for i in range(loop): await mpc.output(a[i]) await mpc.output(b[i]) time.sleep(1) print(f"comparing {loop} runs on vectors of length {length} with latency {d*2}ms and {p}% loss\n") subprocess.run(["sudo", "tc", "qdisc","add","dev","lo","root","netem","delay", f"{d}ms"]) subprocess.run(["sudo", "tc", "qdisc","add","dev","lo","root","netem","loss", f"{p}%"]) print("elementwise addition".ljust(32), end='', flush=True) t1 = time.perf_counter() for i in range(loop): r = list(map(operator.add, a[i], b[i])) r1[i] = await mpc.gather(r) t2 = time.perf_counter() print(f"{(t2 - t1):.5} seconds") res[0] = f"{(t2 - t1):f}" time.sleep(1) print("mpc.vector_add()".ljust(32), end='', flush=True) t1 = time.perf_counter() for i in range(loop): r = mpc.vector_add(a[i], b[i]) r2[i] = await mpc.gather(r) t2 = time.perf_counter() print(f"{(t2 - t1):.5} seconds") res[1] = f"{(t2 - t1):f}" time.sleep(1) print("summation".ljust(32), end='', flush=True) t1 = time.perf_counter() for i in range(loop): r = functools.reduce(operator.add, a[i]) r1[i] = await mpc.gather(r) t2 = time.perf_counter() print(f"{(t2 - t1):.5} seconds") res[2] = f"{(t2 - t1):f}" time.sleep(1) print("mpc.sum()".ljust(32), end='', flush=True) t1 = time.perf_counter() for i in range(loop): r = mpc.sum(a[i]) r2[i] = await mpc.gather(r) t2 = time.perf_counter() print(f"{(t2 - t1):.5} seconds") res[3] = f"{(t2 - t1):f}" time.sleep(1) print("elementwise multiplication".ljust(32), end='', flush=True) t1 = time.perf_counter() for i in range(loop): r = list(map(operator.mul, a[i], b[i])) r1[i] = await mpc.gather(r) t2 = time.perf_counter() print(f"{(t2 - t1):.5} seconds") res[4] = f"{(t2 - t1):f}" time.sleep(1) print("mpc.schur_prod()".ljust(32), end='', flush=True) t1 = time.perf_counter() for i in range(loop): r = mpc.schur_prod(a[i], b[i]) r2[i] = await mpc.gather(r) t2 = time.perf_counter() print(f"{(t2 - t1):.5} seconds") res[5] = f"{(t2 - t1):f}" time.sleep(1) print("product".ljust(32), end='', flush=True) t1 = time.perf_counter() for i in range(loop): r = functools.reduce(operator.mul, a[i]) r1[i] = await mpc.gather(r) t2 = time.perf_counter() print(f"{(t2 - t1):.5} seconds") res[6] = f"{(t2 - t1):f}" time.sleep(1) print("mpc.prod()".ljust(32), end='', flush=True) t1 = time.perf_counter() for i in range(loop): r = mpc.prod(a[i]) r2[i] = await mpc.gather(r) t2 = time.perf_counter() print(f"{(t2 - t1):.5} seconds") res[7] = f"{(t2 - t1):f}" time.sleep(1) subprocess.run(["sudo", "tc", "qdisc","del","dev","lo","root","netem","delay", "0ms"]) subprocess.run(["sudo", "tc", "qdisc","del","dev","lo","root","netem","loss", "0%"]) writer.writerow({ 'length': f"{length}", 'delay': f"{d*2}", 'loss': f"{p}", 'addition': res[0], 'mpc.vector_add()': res[1], 'summation': res[2], 'mpc.sum()': res[3], 'multiplication': res[4], 'mpc.schur_prod()': res[5], 'product': res[6], 'mpc.prod()': res[7] }) await mpc.shutdown()