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)
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 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.sum([], start=1), 1) self.assertEqual(mpc.run(mpc.output(mpc.sum([], start=secint(1)))), 1) self.assertEqual(mpc.prod([]), 1) self.assertEqual(mpc.all([]), 1) self.assertEqual(mpc.any([]), 0) 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 main(): parser = argparse.ArgumentParser() parser.add_argument( '-i', '--dataset', type=int, metavar='I', help=('dataset 0=uvlp (default), 1=wiki, 2=tb2x2, 3=woody, ' '4=LPExample_R20, 5=sc50b, 6=kb2, 7=LPExample')) parser.add_argument('-l', '--bit-length', type=int, metavar='L', help='override preset bit length for dataset') parser.set_defaults(dataset=0, bit_length=0) args = parser.parse_args() settings = [('uvlp', 24, 37 / 3), ('wiki', 24, 20), ('tb2x2', 18, 10.5), ('woody', 36, 540), ('LPExample_R20', 52, 3.441176), ('sc50b', 52, 70), ('kb2', 96, 1749.9204734889486), ('LPExample', 96, 1188806595)] name, bit_length, exact_max = settings[args.dataset] if args.bit_length: bit_length = args.bit_length with open(os.path.join('data', 'lp', name + '.csv')) as file: T = list(csv.reader(file)) m = len(T) - 1 n = len(T[0]) - 1 secfxp = mpc.SecFxp(bit_length) print( f'Using secure {bit_length}-bit fixed-point numbers: {secfxp.__name__}' ) print(f'dataset: {name} with {m} constraints and {n} variables') T[0][-1] = '0' # initialize optimal value for i in range(m + 1): for j in range(n + 1): T[i][j] = secfxp(float(T[i][j]), integral=False) c = T[0][:-1] # maximize c.x subject to A.x <= b, x >= 0 A = [T[i + 1][:-1] for i in range(m)] b = [T[i + 1][-1] for i in range(m)] await mpc.start() cobasis = [secfxp(j) for j in range(n)] basis = [secfxp(n + i) for i in range(m)] iteration = 0 while True: # find index of pivot column p_col_index, minimum = argmin_int(T[0][:-1]) if await mpc.output(minimum >= 0): break # maximum reached # find index of pivot row p_col = mpc.matrix_prod([p_col_index], T, True)[0] constraints = [[T[i][-1], p_col[i], p_col[i] > 0.0001] for i in range(1, m + 1)] p_row_index, (_, pivot, _) = argmin_rat(constraints) # reveal progress a bit iteration += 1 mx = await mpc.output(T[0][-1]) p = await mpc.output(pivot) logging.info(f'Iteration {iteration}: {mx} pivot={p}') # swap basis entries delta = mpc.in_prod(basis, p_row_index) - mpc.in_prod( cobasis, p_col_index) cobasis = mpc.vector_add(cobasis, mpc.scalar_mul(delta, p_col_index)) basis = mpc.vector_sub(basis, mpc.scalar_mul(delta, p_row_index)) # update tableau Tij = Tij - (Til - bool(i==k))/Tkl * (Tkj + bool(j==l)) p_col_index.append(secfxp(0)) p_row_index.insert(0, secfxp(0)) p_col = mpc.vector_sub(p_col, p_row_index) p_col = mpc.scalar_mul(1 / pivot, p_col) p_row = mpc.matrix_prod([p_row_index], T)[0] p_row = mpc.vector_add(p_row, p_col_index) T = mpc.gauss(T, secfxp(1), p_col, p_row) mx = await mpc.output(T[0][-1]) rel_error = (mx - exact_max) / exact_max print(f'max = {mx} (error {rel_error:.3%}) in {iteration} iterations') logging.info('Solution x') x = [secfxp(0) for _ in range(n)] for i in range(m): u = mpc.unit_vector(basis[i], m + n)[:n] v = mpc.scalar_mul(T[i + 1][-1], u) x = mpc.vector_add(x, v) cx = mpc.in_prod(c, x) Ax = mpc.matrix_prod([x], A, True)[0] approx = lambda a: 1.01 * a + 0.0001 Ax_bounded_by_b = mpc.all(Ax[i] <= approx(b[i]) for i in range(m)) x_nonnegative = mpc.all(x[j] >= 0 for j in range(n)) logging.info('Dual solution y') y = [secfxp(0) for _ in range(m)] for j in range(n): u = mpc.unit_vector(cobasis[j], m + n)[n:] v = mpc.scalar_mul(T[0][j], u) y = mpc.vector_sub(y, v) yb = mpc.in_prod(y, b) yA = mpc.matrix_prod([y], A)[0] approx = lambda a: mpc.if_else(a < 0, 1 / 1.01, 1.01) * a + 0.0001 yA_bounded_by_c = mpc.all(yA[j] <= approx(c[j]) for j in range(n)) y_nonpositive = mpc.all(y[i] <= 0 for i in range(m)) cx_eq_yb = abs(cx - yb) <= 0.01 * abs(cx) check = mpc.all([ cx_eq_yb, Ax_bounded_by_b, x_nonnegative, yA_bounded_by_c, y_nonpositive ]) check = bool(await mpc.output(check)) print( f'verification c.x == y.b, A.x <= b, x >= 0, y.A <= c, y <= 0: {check}' ) x = await mpc.output(x) print(f'solution = {x}') await 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])
async def main(): parser = argparse.ArgumentParser() parser.add_argument( '-i', '--dataset', type=int, metavar='I', help=('dataset 0=uvlp (default), 1=wiki, 2=tb2x2, 3=woody, ' '4=LPExample_R20, 5=sc50b, 6=kb2, 7=LPExample')) parser.add_argument('-l', '--bit-length', type=int, metavar='L', help='override preset bit length for dataset') parser.set_defaults(dataset=0, bit_length=0) args = parser.parse_args() settings = [('uvlp', 8, 1, 2), ('wiki', 6, 1, 2), ('tb2x2', 6, 1, 2), ('woody', 8, 1, 3), ('LPExample_R20', 70, 1, 5), ('sc50b', 104, 10, 55), ('kb2', 536, 100000, 106), ('LPExample', 110, 1, 178)] name, bit_length, scale, n_iter = settings[args.dataset] if args.bit_length: bit_length = args.bit_length with open(os.path.join('data', 'lp', name + '.csv')) as file: T = list(csv.reader(file)) m = len(T) - 1 n = len(T[0]) - 1 secint = mpc.SecInt(bit_length, n=m + n) # force existence of Nth root of unity, N>=m+n print(f'Using secure {bit_length}-bit integers: {secint.__name__}') print( f'dataset: {name} with {m} constraints and {n} variables (scale factor {scale})' ) T[0][-1] = '0' # initialize optimal value for i in range(m + 1): g = 0 for j in range(n + 1): T[i][j] = int(scale * float(T[i][j])) # scale to integer g = math.gcd(g, T[i][j]) g = max(g, 1) if i else 1 # skip cost row for j in range(n + 1): T[i][j] = secint(T[i][j] // g) c = T[0][:-1] # maximize c.x subject to A.x <= b, x >= 0 A = [T[i + 1][:-1] for i in range(m)] b = [T[i + 1][-1] for i in range(m)] Zp = secint.field N = Zp.nth w = Zp.root # w is an Nth root of unity in Zp, where N >= m + n w_powers = [Zp(1)] for _ in range(N - 1): w_powers.append(w_powers[-1] * w) assert w_powers[-1] * w == 1 await mpc.start() cobasis = [secint(w_powers[-j]) for j in range(n)] basis = [secint(w_powers[-(i + n)]) for i in range(m)] previous_pivot = secint(1) iteration = 0 while True: # find index of pivot column p_col_index, minimum = argmin_int(T[0][:-1]) if await mpc.output(minimum >= 0): break # maximum reached # find index of pivot row p_col = mpc.matrix_prod([p_col_index], T, True)[0] constraints = [[T[i][-1] + (p_col[i] <= 0), p_col[i]] for i in range(1, m + 1)] p_row_index, (_, pivot) = argmin_rat(constraints) # reveal progress a bit iteration += 1 mx = await mpc.output(T[0][-1]) cd = await mpc.output(previous_pivot) p = await mpc.output(pivot) # NB: no await in f-strings in Python 3.6 logging.info( f'Iteration {iteration}/{n_iter}: {mx / cd} pivot={p / cd}') # swap basis entries delta = mpc.in_prod(basis, p_row_index) - mpc.in_prod( cobasis, p_col_index) cobasis = mpc.vector_add(cobasis, mpc.scalar_mul(delta, p_col_index)) basis = mpc.vector_sub(basis, mpc.scalar_mul(delta, p_row_index)) # update tableau Tij = Tij*Tkl/Tkl' - (Til/Tkl' - bool(i==k)) * (Tkj + bool(j==l)*Tkl') p_col_index.append(secint(0)) p_row_index.insert(0, secint(0)) pp_inv = 1 / previous_pivot p_col = mpc.scalar_mul(pp_inv, p_col) p_col = mpc.vector_sub(p_col, p_row_index) p_row = mpc.matrix_prod([p_row_index], T)[0] p_row = mpc.vector_add(p_row, mpc.scalar_mul(previous_pivot, p_col_index)) T = mpc.gauss(T, pivot * pp_inv, p_col, p_row) previous_pivot = pivot mx = await mpc.output(T[0][-1]) cd = await mpc.output(previous_pivot ) # common denominator for all entries of T print( f'max = {mx} / {cd} / {scale} = {mx / cd / scale} in {iteration} iterations' ) logging.info('Solution x') sum_x_powers = [secint(0) for _ in range(N)] for i in range(m): x_powers = pow_list(T[i + 1][-1] / N, basis[i], N) sum_x_powers = mpc.vector_add(sum_x_powers, x_powers) x = [None] * n for j in range(n): coefs = [w_powers[(j * k) % N] for k in range(N)] x[j] = mpc.in_prod(coefs, sum_x_powers) cx = mpc.in_prod(c, x) Ax = mpc.matrix_prod([x], A, True)[0] Ax_bounded_by_b = mpc.all(Ax[i] <= b[i] * cd for i in range(m)) x_nonnegative = mpc.all(x[j] >= 0 for j in range(n)) logging.info('Dual solution y') sum_x_powers = [secint(0) for _ in range(N)] for j in range(n): x_powers = pow_list(T[0][j] / N, cobasis[j], N) sum_x_powers = mpc.vector_add(sum_x_powers, x_powers) y = [None] * m for i in range(m): coefs = [w_powers[((n + i) * k) % N] for k in range(N)] y[i] = mpc.in_prod(coefs, sum_x_powers) y[i] = -y[i] yb = mpc.in_prod(y, b) yA = mpc.matrix_prod([y], A)[0] yA_bounded_by_c = mpc.all(yA[j] <= c[j] * cd for j in range(n)) y_nonpositive = mpc.all(y[i] <= 0 for i in range(m)) cx_eq_yb = cx == yb check = mpc.all([ cx_eq_yb, Ax_bounded_by_b, x_nonnegative, yA_bounded_by_c, y_nonpositive ]) check = bool(await mpc.output(check)) print( f'verification c.x == y.b, A.x <= b, x >= 0, y.A <= c, y <= 0: {check}' ) x = await mpc.output(x) print(f'solution = {[a / cd for a in x]}') await mpc.shutdown()
m = len(mpc.parties) if m % 2 == 0: print('Odd number of parties required.') sys.exit() t = m // 2 voters = list(range(t + 1)) # parties P[0],...,P[t] if mpc.pid in voters: vote = int(sys.argv[1]) if sys.argv[1:] else 1 # default "yes" else: vote = None # no input secbit = mpc.SecFld(2) # secure bits over GF(2) mpc.run(mpc.start()) votes = mpc.input(secbit(vote), senders=voters) result = mpc.run(mpc.output(mpc.all(votes), receivers=voters)) mpc.run(mpc.shutdown()) if result is None: # no output print('Thanks for serving as oblivious matchmaker;)') elif result: print( f'Match: unanimous agreement between {t+1} part{"ies" if t else "y"}!') else: print( f'No match: someone disagrees among {t+1} part{"ies" if t else "y"}?')