def test_misc(self): secint = mpc.SecInt() secfxp = mpc.SecFxp() secfld = mpc.SecFld() for secnum in (secint, secfxp, secfld): self.assertEqual(type(mpc.run(mpc.output(secnum(0), raw=True))), secnum.field) self.assertEqual(mpc.run(mpc.output(mpc._reshare([secnum(0)]))), [0]) self.assertEqual(mpc.run(mpc.output(mpc.all(secnum(1) for _ in range(5)))), True) self.assertEqual(mpc.run(mpc.output(mpc.all([secnum(1), secnum(1), secnum(0)]))), False) self.assertEqual(mpc.run(mpc.output(mpc.any(secnum(0) for _ in range(5)))), False) self.assertEqual(mpc.run(mpc.output(mpc.any([secnum(0), secnum(1), secnum(1)]))), True) self.assertEqual(mpc.run(mpc.output(mpc.sum([secnum(1)], start=1))), 2) self.assertEqual(mpc.run(mpc.output(mpc.prod([secnum(1)], start=1))), 1) self.assertEqual(mpc.run(mpc.output(mpc.sum([secnum(1)], start=secnum(1)))), 2) self.assertEqual(mpc.run(mpc.output(mpc.min(secint(i) for i in range(-1, 2, 1)))), -1) self.assertEqual(mpc.run(mpc.output(mpc.argmin(secint(i) for i in range(-1, 2, 1))[0])), 0) self.assertEqual(mpc.run(mpc.output(mpc.max(secfxp(i) for i in range(-1, 2, 1)))), 1) self.assertEqual(mpc.run(mpc.output(mpc.argmax(secfxp(i) for i in range(-1, 2, 1))[0])), 2) self.assertEqual(mpc.run(mpc.output(list(mpc.min_max(map(secfxp, range(5)))))), [0, 4]) x = (secint(i) for i in range(-3, 3)) s = [0, -1, 1, -2, 2, -3] self.assertEqual(mpc.run(mpc.output(mpc.sorted(x, key=lambda a: a*(2*a+1)))), s) x = (secfxp(i) for i in range(5)) self.assertEqual(mpc.run(mpc.output(mpc.sorted(x, reverse=True))), [4, 3, 2, 1, 0]) self.assertEqual(mpc.run(mpc.output(mpc.sum(map(secint, range(5))))), 10) self.assertEqual(mpc.run(mpc.output(mpc.sum([secfxp(2.75)], start=3.125))), 5.875) self.assertEqual(int(mpc.run(mpc.output(mpc.prod(map(secfxp, range(1, 5)))))), 24) self.assertEqual(int(mpc.run(mpc.output(mpc.prod([secfxp(1.414214)]*4)))), 4)
async def main(): # initialize mpc, define secure int type await mpc.start() secint = mpc.SecInt(64) # initialize inputs # 3 parties: random value for each party # any other number of parties: just use player 0's value 3 times. value = np.random.randint(1,10000) print("player {} input: {}".format(mpc.pid, value)) n = len(mpc.parties) if n != 3: inputs = [secint(value), secint(value), secint(value)] print("expected: {}".format(value ** 3)) else: inputs = mpc.input(secint(value), senders=[0,1,2]) # compute product prod = mpc.prod(inputs) # output result result = await mpc.output(prod) print("result:", result) await mpc.shutdown()
async def random_derangement(n, sectype): """Random permutation of [sectype(i) for i in range(n)] without fixed point.""" await mpc.returnType((sectype, True), n) p = random_permutation(n, sectype) t = mpc.prod([p[i] - i for i in range(n)]) if await mpc.is_zero_public(t): p = random_derangement(n, sectype) return p
def GI(x): """Gini impurity for contingency table x.""" y = [args.alpha * s + 1 for s in map(mpc.sum, x)] # NB: alternatively, use s + (s == 0) D = mpc.prod(y) G = mpc.in_prod(list(map(mpc.in_prod, x, x)), list(map(lambda x: 1 / x, y))) return [D * G, D] # numerator, denominator
async def random_derangement(n): # returns list of n secint elements await mpc.returnType(secint, n) # set return type of this MPyC coroutine p = random_permutation(n) t = mpc.prod([p[i] - i for i in range(n) ]) # securely multiply all differences p[i] - i if await mpc.is_zero_public(t): # publicly test whether t is equal to zero return random_derangement(n) # recurse if t is zero else: return p # done if t is nonzero
def test_misc(self): secint = mpc.SecInt() secfxp = mpc.SecFxp() secfld = mpc.SecFld() for secnum in (secint, secfxp, secfld): self.assertEqual(mpc.run(mpc.output(mpc._reshare([secnum(0)]))), [0]) self.assertEqual( mpc.run(mpc.output(mpc.all(secnum(1) for _ in range(5)))), True) self.assertEqual( mpc.run(mpc.output(mpc.all([secnum(1), secnum(1), secnum(0)]))), False) self.assertEqual( mpc.run(mpc.output(mpc.any(secnum(0) for _ in range(5)))), False) self.assertEqual( mpc.run(mpc.output(mpc.any([secnum(0), secnum(1), secnum(1)]))), True) self.assertEqual( mpc.run(mpc.output(mpc.sum([secnum(1)], start=1))), 2) self.assertEqual( mpc.run(mpc.output(mpc.prod([secnum(1)], start=1))), 1) self.assertEqual( mpc.run(mpc.output(mpc.sum([secnum(1)], start=secnum(1)))), 2) self.assertEqual( mpc.run(mpc.output(mpc.min(secint(i) for i in range(-1, 2, 1)))), -1) self.assertEqual( mpc.run(mpc.output(mpc.max(secfxp(i) for i in range(-1, 2, 1)))), 1) self.assertEqual( mpc.run(mpc.output(list(mpc.min_max(map(secfxp, range(5)))))), [0, 4]) self.assertEqual(mpc.run(mpc.output(mpc.sum(map(secint, range(5))))), 10) self.assertEqual( mpc.run(mpc.output(mpc.sum([secfxp(2.72)], start=3.14))), 5.86) self.assertEqual( int(mpc.run(mpc.output(mpc.prod(map(secfxp, range(1, 5)))))), 24) self.assertEqual( int(mpc.run(mpc.output(mpc.prod([secfxp(1.414214)] * 4)))), 4)
def random_matrix_determinant(secfld, d): d_2 = d * (d - 1) // 2 L = np.diagflat([secfld(1)] * d) L[np.tril_indices(d, -1)] = mpc._randoms(secfld, d_2) L[np.triu_indices(d, 1)] = [secfld(0)] * d_2 diag = mpc._randoms(secfld, d) U = np.diagflat(diag) U[np.tril_indices(d, -1)] = [secfld(0)] * d_2 U[np.triu_indices(d, 1)] = mpc._randoms(secfld, d_2) R = mpc.matrix_prod(L.tolist(), U.tolist()) detR = mpc.prod(diag) # detR != 0 with overwhelming probability return R, detR
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_sge(x): """Compute binary signs securely for all elements of x in parallel. Vectorized version of MPyC's built-in secure comparison. Cf. mpc.sgn() with GE=True (and EQ=False). NB: mpc.prod() and mpc.is_zero_public() are not (yet) vectorized. """ stype = type(x[0]) n = len(x) await mpc.returnType(stype, n) Zp = stype.field l = stype.bit_length k = mpc.options.sec_param r_bits = await mpc.random_bits(Zp, (l + 1) * n) r_bits = [b.value for b in r_bits] r_modl = [0] * n for j in range(n): for i in range(l - 1, -1, -1): r_modl[j] <<= 1 r_modl[j] += r_bits[l * j + i] r_divl = mpc._randoms(Zp, n, 1 << k) x = await mpc.gather(x) x_r = [a + ((1 << l) + b) for a, b in zip(x, r_modl)] c = await mpc.output([a + (b.value << l) for a, b in zip(x_r, r_divl)]) c = [c.value % (1 << l) for c in c] e = [[None] * (l + 1) for _ in range(n)] for j in range(n): s_sign = (r_bits[l * n + j] << 1) - 1 sumXors = 0 for i in range(l - 1, -1, -1): c_i = (c[j] >> i) & 1 e[j][i] = Zp(s_sign + r_bits[l * j + i] - c_i + 3 * sumXors) sumXors += 1 - r_bits[l * j + i] if c_i else r_bits[l * j + i] e[j][l] = Zp(s_sign - 1 + 3 * sumXors) e = await mpc.gather([mpc.prod(_) for _ in e]) g = await mpc.gather([mpc.is_zero_public(stype(_)) for _ in e]) UF = [1 - b if g else b for b, g in zip(r_bits[-n:], g)] z = [(a - (c + (b << l))) / (1 << l - 1) - 1 for a, b, c in zip(x_r, UF, c)] return z
async def bsgn_0(a): """Compute binary sign of a securely. Binary sign of a (1 if a>=0 else -1) is obtained by securely computing (2a+1 | p). Legendre symbols (a | p) for secret a are computed securely by evaluating (a s r^2 | p) in the clear for secret random sign s and secret random r modulo p, and outputting secret s * (a s r^2 | 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, 1, signed=True) # random sign r = mpc._random(Zp) r = mpc.prod([r, r]) # random square modulo p a, s, r = await mpc.gather(a, s, r) b = await mpc.prod([2 * a + 1, s[0], r]) b = await mpc.output(b) return s[0] * legendre_p(b)
async def schmidt_multilateration(locations, toas): """Schmidt's multilateration algorithm.""" # Transform sensor locations and ToA measurements # into linear system A w = b, using Schmidt's method: norm = [mpc.in_prod(p, p) for p in locations] A, b = [], [] for i, j, k in itertools.combinations(range(len(locations)), 3): Delta = [toas[j] - toas[k], toas[k] - toas[i], toas[i] - toas[j]] XYZN = [ locations[i] + [norm[i]], locations[j] + [norm[j]], locations[k] + [norm[k]] ] r_x, r_y, r_z, r_n = mpc.matrix_prod([Delta], XYZN)[0] A.append([2 * r_x, 2 * r_y, 2 * r_z]) b.append(mpc.prod(Delta) + r_n) # Compute least-squares solution w satisfying A^T A w = A^T b: AT, bT = list(map(list, zip(*A))), [b] # transpose of A and b ATA = mpc.matrix_prod(AT, AT, tr=True) # A^T (A^T)^T = A^T A ATb = mpc.matrix_prod(AT, bT, tr=True) # A^T (b^T)^T = A^T b w_det = linear_solve(ATA, ATb) x, y, z, det = await mpc.output(w_det) w = x / det, y / det, z / det return w
Run with m parties to compute: - m = sum_{i=0}^{m-1} 1 = sum(1 for i in range(m)) - m**2 = sum_{i=0}^{m-1} 2i+1 = sum(2*i+1 for i in range(m)) - 2**m = prod_{i=0}^{m-1} 2 = prod(2 for i in range(m)) - m! = prod_{i=0}^{m-1} i+1 = prod(i+1 for i in range(m)) Bit lengths of secure integers ensure each result fits for any m >= 1. """ from mpyc.runtime import mpc m = len(mpc.parties) l = m.bit_length() mpc.run(mpc.start()) print('m =', mpc.run(mpc.output(mpc.sum(mpc.input(mpc.SecInt(l + 1)(1)))))) print( 'm**2 =', mpc.run( mpc.output(mpc.sum(mpc.input(mpc.SecInt(2 * l + 1)(2 * mpc.pid + 1)))))) print('2**m =', mpc.run(mpc.output(mpc.prod(mpc.input(mpc.SecInt(m + 2)(2)))))) print( 'm! =', mpc.run( mpc.output( mpc.prod(mpc.input( mpc.SecInt(int(m * (l - 1.4) + 3))(mpc.pid + 1)))))) mpc.run(mpc.shutdown())
def test_misc(self): secint = mpc.SecInt() secfxp = mpc.SecFxp() secfld = mpc.SecFld() for secnum in (secint, secfxp, secfld): self.assertEqual(type(mpc.run(mpc.output(secnum(0), raw=True))), secnum.field) self.assertEqual(mpc.run(mpc.output(mpc._reshare([secnum(0)]))), [0]) self.assertEqual( mpc.run(mpc.output(mpc.all(secnum(1) for _ in range(5)))), True) self.assertEqual( mpc.run(mpc.output(mpc.all([secnum(1), secnum(1), secnum(0)]))), False) self.assertEqual( mpc.run(mpc.output(mpc.any(secnum(0) for _ in range(5)))), False) self.assertEqual( mpc.run(mpc.output(mpc.any([secnum(0), secnum(1), secnum(1)]))), True) self.assertEqual( mpc.run(mpc.output(mpc.sum([secnum(1)], start=1))), 2) self.assertEqual( mpc.run(mpc.output(mpc.prod([secnum(1)], start=1))), 1) self.assertEqual( mpc.run(mpc.output(mpc.sum([secnum(1)], start=secnum(1)))), 2) self.assertEqual( mpc.run(mpc.output(mpc.find([secnum(1)], 0, e=-1))), -1) self.assertEqual(mpc.run(mpc.output(mpc.find([secnum(1)], 1))), 0) self.assertEqual( mpc.run(mpc.output(mpc.find([secnum(1)], 1, f=lambda i: i))), 0) self.assertEqual( mpc.run(mpc.output(mpc.min(secint(i) for i in range(-1, 2, 1)))), -1) self.assertEqual( mpc.run( mpc.output(mpc.argmin(secint(i) for i in range(-1, 2, 1))[0])), 0) self.assertEqual( mpc.run(mpc.output(mpc.max(secfxp(i) for i in range(-1, 2, 1)))), 1) self.assertEqual( mpc.run( mpc.output(mpc.argmax(secfxp(i) for i in range(-1, 2, 1))[0])), 2) self.assertEqual( mpc.run(mpc.output(list(mpc.min_max(map(secfxp, range(5)))))), [0, 4]) x = (secint(i) for i in range(-3, 3)) s = [0, -1, 1, -2, 2, -3] self.assertEqual( mpc.run(mpc.output(mpc.sorted(x, key=lambda a: a * (2 * a + 1)))), s) x = (secfxp(i) for i in range(5)) self.assertEqual(mpc.run(mpc.output(mpc.sorted(x, reverse=True))), [4, 3, 2, 1, 0]) self.assertEqual(mpc.run(mpc.output(mpc.sum(map(secint, range(5))))), 10) self.assertEqual( mpc.run(mpc.output(mpc.sum([secfxp(2.75)], start=3.125))), 5.875) self.assertEqual( int(mpc.run(mpc.output(mpc.prod(map(secfxp, range(1, 5)))))), 24) self.assertEqual( int(mpc.run(mpc.output(mpc.prod([secfxp(1.414214)] * 4)))), 4) self.assertEqual(mpc.find([], 0), 0) self.assertEqual(mpc.find([], 0, e=None), (1, 0)) self.assertEqual( mpc.run(mpc.output(list(mpc.find([secfld(1)], 1, e=None)))), [0, 0]) self.assertEqual( mpc.run(mpc.output(mpc.find([secfld(2)], 2, bits=False))), 0) x = [secint(i) for i in range(5)] f = lambda i: [i**2, 3**i] self.assertEqual(mpc.run(mpc.output(mpc.find(x, 2, bits=False, f=f))), [4, 9]) cs_f = lambda b, i: [b * (2 * i + 1) + i**2, (b * 2 + 1) * 3**i] self.assertEqual( mpc.run(mpc.output(mpc.find(x, 2, bits=False, cs_f=cs_f))), [4, 9])
"""Couple of MPyC oneliners. Run with m parties to compute: - m = sum_{i=0}^{m-1} 1 = sum(1 for i in range(m)) - m**2 = sum_{i=0}^{m-1} 2i+1 = sum(2*i+1 for i in range(m)) - 2**m = prod_{i=0}^{m-1} 2 = prod(2 for i in range(m)) - m! = prod_{i=0}^{m-1} i+1 = prod(i+1 for i in range(m)) Bit lengths of secure integers ensure each result fits for any m, 1<=m<=256. """ from mpyc.runtime import mpc mpc.run(mpc.start()) print('m =', mpc.run(mpc.output(mpc.sum(mpc.input(mpc.SecInt(9)(1)))))) print('m**2 =', mpc.run(mpc.output(mpc.sum(mpc.input(mpc.SecInt(17)(2 * mpc.pid + 1)))))) print('2**m =', mpc.run(mpc.output(mpc.prod(mpc.input(mpc.SecInt(257)(2)))))) print('m! =', mpc.run(mpc.output(mpc.prod(mpc.input(mpc.SecInt(1685)(mpc.pid + 1)))))) mpc.run(mpc.shutdown())
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()