async def random_unit_vector(n, sectype): """Random permutation of [sectype(1)] + [sectype(0) for i in range(n-1)].""" await mpc.returnType((sectype, True), n) if n == 1: return [sectype(1)] b = mpc.random_bit(sectype) x = random_unit_vector((n + 1) // 2, sectype) if n % 2 == 0: y = mpc.scalar_mul(b, x) return y + mpc.vector_sub(x, y) elif await mpc.eq_public(b * x[0], 1): return random_unit_vector(n, sectype) else: y = mpc.scalar_mul(b, x[1:]) return x[:1] + y + mpc.vector_sub(x[1:], y)
async def random_unit_vector(n): # returns list of n secint elements await mpc.returnType(secint, n) # set return type of this MPyC coroutine if n == 1: return [secint(1)] b = mpc.random_bit(secint) # pick one random bit if n>=2 x = random_unit_vector((n + 1) // 2) # recursive call with m=(n+1)//2 if n % 2 == 0: y = mpc.scalar_mul(b, x) # y = [0]*m or y = x return y + mpc.vector_sub(x, y) # [0]*m + x or x + [0]*m elif await mpc.eq_public(b * x[0], 1): # reject if b=1 and x[0]=1 return random_unit_vector(n) # start over else: y = mpc.scalar_mul(b, x[1:]) # y = [0]*m or y = x[1:] return x[:1] + y + mpc.vector_sub( x[1:], y) # [x[0]] + ([0]*m + x[1:] or [0]*m + x[1:])
def agg_logrank_test(secfxp, d1, d2, n1, n2, agg_d1, agg_d2, stride): candidates = [] maxT = len(d1) for start in range(0, maxT, stride): group = start // stride n_observed_events = agg_d1[group] + agg_d2[group] msn = min(stride, n_observed_events) # upper bound stop = min(start + stride, maxT) logging.info(f'Interval {group + 1} (time {start + 1} to {stop})' f' # observed events = {n_observed_events}') if msn == 0: continue oblivious_table = [[secfxp(0), secfxp(0), secfxp(1), secfxp(1)]] * msn ix = [secfxp(0)] * msn for j in range(start, stop): is_active = d1[j] + d2[j] != 0 ix = mpc.if_else(is_active, [1 - mpc.sum(ix)] + ix[:-1], ix) select = mpc.scalar_mul(is_active, ix) new = [d1[j], d2[j], n1[j], n2[j]] for i in range(msn): oblivious_table[i] = mpc.if_else(select[i], new, oblivious_table[i]) candidates.extend(oblivious_table) return logrank_test(secfxp, *zip(*candidates))
def arg_le_rat(x0, x1): (n0, d0) = x0 (n1, d1) = x1 a = mpc.in_prod([n0, d0], [d1, -n1]) >= 0 h = mpc.scalar_mul(a, [n1 - n0, d1 - d0]) m = (h[0] + n0, h[1] + d0) return a, m
def test_async(self): mpc.options.no_async = False a = mpc.SecInt()(7) b = a * a mpc.run(mpc.barrier()) self.assertEqual(mpc.run(mpc.output(b)), 49) self.assertEqual(mpc.run(mpc.output(mpc.scalar_mul(a, [-a, a]))), [-49, 49]) mpc.options.no_async = True
def si1(x, n): """Return all-0 vector of length n-1 (if x=0) and (x-1)-st unit vector of length n-1 (if 1 <= x < n).""" if n==1: return [] elif n==2: return [x] else: b = mpc.lsb(x) v = si1((x - b) / 2, (n + 1) // 2) w = mpc.scalar_mul(b, v) return [b-sum(w)] + [v[i//2]-w[i//2] if i%2==0 else w[i//2] for i in range(n-2)]
def random_permutation(n, sectype): """Random permutation of [sectype(i) for i in range(n)]. """ p = [sectype(i) for i in range(n)] for i in range(n - 1): x_r = random_unit_vector(n - i, sectype) p_r = mpc.in_prod(p[i:], x_r) d_r = mpc.scalar_mul(p[i] - p_r, x_r) p[i] = p_r for j in range(n - i): p[i + j] += d_r[j] return p
def random_permutation(n): # returns list of n secint elements p = [secint(i) for i in range(n)] # initialize p to identity permutation for i in range(n - 1): x_r = random_unit_vector( n - i) # x_r = [0]*(r-i) + [1] + [0]*(n-1-r), i <= r < n p_r = mpc.in_prod(p[i:], x_r) # p_r = p[r] d_r = mpc.scalar_mul( p[i] - p_r, x_r) # d_r = [0]*(r-i) + [p[i] - p[r]] + [0]*(n-1-r) p[i] = p_r # p[i] = p[r] for j in range(n - i): p[i + j] += d_r[j] # p[r] = p[r} + p[i] - p[r] = p[i] return p
def si1(a, n): """Return all-0 vector of length n-1 (if a=0) and (a-1)-st unit vector of length n-1 (if 1 <= a < n).""" if n == 1: return [] elif n == 2: return [a] else: b = mpc.lsb(a / 2**stype.field.frac_length) x = si1((a - b) / 2, (n + 1) // 2) y = mpc.scalar_mul(b, x) return [b - sum(y)] + [ x[i // 2] - y[i // 2] if i % 2 == 0 else y[i // 2] for i in range(n - 2) ]
def pow_list(a, x, n): if n == 1: return [a] even = pow_list(a, x**2, (n + 1) // 2) if n % 2 == 1: d = even.pop() odd = mpc.scalar_mul(x, even) xs = [None] * n for i in range(n // 2): xs[2 * i] = even[i] xs[2 * i + 1] = odd[i] if n % 2 == 1: xs[-1] = d return xs
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)
def si1(a, n): """Return (a-1)st unit vector of length n-1 (if 1 <= a < n) or all-0 vector of length n-1 (if a=0). """ if n == 1: x = [] elif n == 2: x = [a] else: a2, b = divmod(a, 2) z = si1(a2, (n + 1) // 2) y = mpc.scalar_mul(b, z) x = [b - sum(y)] + [ z[i // 2] - y[i // 2] if i % 2 == 0 else y[i // 2] for i in range(n - 2) ] return x
def pow_list(a, x, n): """Return [a,ax, ax^2, ..., ax^(n-1)]. Runs in O(log n) rounds using minimal number of n-1 secure multiplications. """ if n == 1: powers = [a] elif n == 2: powers = [a, a * x] else: even_powers = pow_list(a, x * x, (n + 1) // 2) if n % 2: d = even_powers.pop() odd_powers = mpc.scalar_mul(x, even_powers) powers = [t for _ in zip(even_powers, odd_powers) for t in _] if n % 2: powers.append(d) return powers
def pow_list(a, x, n): """Return [a,ax, ax^2, ..., ax^(n-1)]. Runs in O(log n) rounds using minimal number of n-1 secure multiplications. NB: equivalent to list(mpyc.mpctools.accumulate([x] * (n-1), f=operator.mul, iv=a)), which also runs in O(log n) rounds but using O(n log n) secure multiplications. """ if n == 1: powers = [a] elif n == 2: powers = [a, a * x] else: even_powers = pow_list(a, x * x, (n + 1) // 2) if n % 2: d = even_powers.pop() odd_powers = mpc.scalar_mul(x, even_powers) powers = [t for _ in zip(even_powers, odd_powers) for t in _] if n % 2: powers.append(d) return powers
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()
async def main(): parser = argparse.ArgumentParser() parser.add_argument('-d', '--data', help='filename for tableau') parser.add_argument('options', nargs='*') parser.set_defaults(data='default') args = parser.parse_args() if not args.options: certificate_filename = f'c{mpc.pid}.cert' logging.info('Setting certificate file to default = %s', certificate_filename) else: certificate_filename = args.options[0] T = load_tableau(args.data) l = mpc.options.bit_length m = len(T) - 1 n = len(T[0]) - 1 secint = mpc.SecInt(l, n=m + n) for i in range(m + 1): for j in range(n + 1): T[i][j] = secint(T[i][j]) Zp = secint.field N = Zp.nth w = Zp.root w_powers = [Zp(1)] for _ in range(N - 1): w_powers.append(w_powers[-1] * w) assert w_powers[-1] * w == 1 basis = [secint(w_powers[-(i + n)]) for i in range(m)] cobasis = [secint(w_powers[-j]) for j in range(n)] prev_pivot = secint(1) await mpc.start() iteration = 0 logging.info('%d Termination?...', iteration) p_col_index, minimum = argmin_int(T[-1][:-1]) while await mpc.output(minimum < 0): iteration += 1 logging.info('%d Determining pivot...', iteration) 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(m)] p_row_index, (_, pivot) = argmin_rat(constraints) logging.info('%d Updating tableau...', iteration) # T[i,j] = T[i,j]*p/p' - (C[i]/p' - p_row_index[i])*(R[j] + p * p_col_index[j]) p_row = mpc.matrix_prod([p_row_index], T)[0] delta_row = mpc.scalar_mul(prev_pivot, p_col_index) delta_row.append(secint(0)) p_row = mpc.vector_add(p_row, delta_row) prev_p_inv = 1 / prev_pivot p_col = mpc.scalar_mul(prev_p_inv, p_col) p_col = mpc.vector_sub(p_col, p_row_index + [secint(0)]) T = mpc.gauss(T, pivot * prev_p_inv, p_col, p_row) prev_pivot = pivot # swap basis entries delta = mpc.in_prod(basis, p_row_index) - mpc.in_prod( cobasis, p_col_index) p_row_index = mpc.scalar_mul(delta, p_row_index) basis = mpc.vector_sub(basis, p_row_index) p_col_index = mpc.scalar_mul(delta, p_col_index) cobasis = mpc.vector_add(cobasis, p_col_index) logging.info('%d Termination?...', iteration) p_col_index, minimum = argmin_int(T[-1][:-1]) logging.info('Termination...') mx = await mpc.output(T[-1][-1]) cd = await mpc.output(prev_pivot) print(' max(f) = %d / %d = %f' % (mx.value, cd.value, float(mx.value) / cd.value)) logging.info('Computing solution...') sum_x_powers = [secint(0) for _ in range(N)] for i in range(m): x_powers = pow_list(T[i][-1] / N, basis[i], N) sum_x_powers = mpc.vector_add(sum_x_powers, x_powers) solution = [None] * n for j in range(n): coefs = [w_powers[(j * k) % N] for k in range(N)] solution[j] = mpc.lin_comb(coefs, sum_x_powers) solution = await mpc.output(solution) logging.info('Computing dual solution...') sum_x_powers = [secint(0) for _ in range(N)] for j in range(n): x_powers = pow_list(T[-1][j] / N, cobasis[j], N) sum_x_powers = mpc.vector_add(sum_x_powers, x_powers) dual_solution = [None] * m for i in range(m): coefs = [w_powers[((n + i) * k) % N] for k in range(N)] dual_solution[i] = mpc.lin_comb(coefs, sum_x_powers) dual_solution = await mpc.output(dual_solution) await mpc.shutdown() logging.info('Writing output to %s.', certificate_filename) with open(os.path.join('data', 'lp', certificate_filename), 'w') as f: f.write('# tableau = \n' + args.data + '\n') f.write('# bit-length = \n' + str(mpc.options.bit_length) + '\n') f.write('# security parameter = \n' + str(mpc.options.sec_param) + '\n') f.write('# threshold = \n' + str(mpc.threshold) + '\n') f.write('# common denominator = \n' + str(cd.value) + '\n') f.write('# solution = \n') f.write('\t'.join(str(x.value) for x in solution) + '\n') f.write('# dual solution = \n') f.write('\t'.join(str(x.value) for x in dual_solution) + '\n')
def __mul__(self, other): multiplications = mpc.scalar_mul(other, self.inputs + [self.outcome]) multiplied_outcome = multiplications.pop() # mutates multiplications return Sample(multiplications, multiplied_outcome)
async def main(): parser = argparse.ArgumentParser() parser.add_argument('-i', '--dataset', type=int, metavar='I', help=('dataset 0=synthetic (default), 1=student, 2=wine-red, ' '3=wine-white, 4=year, 5=gas-methane, 6=gas-CO, 7=higgs')) parser.add_argument('-u', '--data-url', action='store_true', default=False, help='show URL for downloading dataset I') parser.add_argument('-l', '--lambda_', type=float, metavar='L', help='regularization L>=0.0 (default=1.0)') parser.add_argument('-a', '--accuracy', type=int, metavar='A', help='accuracy A (number of fractional bits)') parser.add_argument('-n', '--samples', type=int, metavar='N', help='number of samples in synthetic data (default=1000)') parser.add_argument('-d', '--features', type=int, metavar='D', help='number of features in synthetic data (default=10)') parser.add_argument('-e', '--targets', type=int, metavar='E', help='number of targets in synthetic data (default=1)') parser.add_argument('--ratrec', action='store_true', default=False, help='use rational reconstruction to hide determinant') parser.set_defaults(dataset=0, lambda_=1.0, accuracy=-1, samples=1000, features=10, targets=1) args = parser.parse_args() await mpc.start() if not args.dataset: range_alpha = range(4, 8) n, d, e, split = args.samples, args.features, args.targets, 0 name = 'SYNTHETIC' logging.info('Generating synthetic data') X = await synthesize_data(n, d, e) else: settings = [('student+performance', 'student-mat', 6), ('Wine+Quality', 'winequality-red', 7), ('Wine+Quality', 'winequality-white', 8), ('Yearpredictionmsd', 'YearPredictionMSD', 6), ('Gas+sensor+array+under+dynamic+gas+mixtures', 'ethylene_methane', 8), ('Gas+sensor+array+under+dynamic+gas+mixtures', 'ethylene_CO', 9), ('HIGGS', 'HIGGS', 5)] url, name, alpha = settings[args.dataset - 1] url = 'https://archive.ics.uci.edu/ml/datasets/' + url if args.data_url: print(f'URL: {url}') range_alpha = range(alpha, alpha + 1) infofile = os.path.join('data', 'regr', 'info-' + name + '.csv') logging.info(f'Loading dataset {name}') X, d, e, split = read_data(infofile) n = len(X) logging.info(f'Loaded {n} samples') print(f'dataset: {name} with {n} samples, {d} features, and {e} target(s)') print(f'regularization lambda: {args.lambda_}') # split in train set and test set if split: # fixed split X1, X2 = X[:split], X[split:] else: # random split (all parties use same rnd) rnd = await mpc.transfer(random.randrange(2**31), senders=0) X1, X2 = sklearn.model_selection.train_test_split(X, train_size=0.7, random_state=rnd) del X X1, Y1 = X1[:, :d], X1[:, d:] X2, Y2 = X2[:, :d], X2[:, d:] n1 = len(X1) d = d + 1 # add (virtual) feature column X_d = [1, ..., 1] for vertical intercept # ridge regression "in the clear" ridge = sklearn.linear_model.Ridge(alpha=args.lambda_, fit_intercept=True, copy_X=True, solver='cholesky') ridge.fit(X1, Y1) error_train_skit = rmse(Y1, ridge.predict(X1)) error_test_skit = rmse(Y2, ridge.predict(X2)) print(f'scikit train error: {error_train_skit}') print(f'scikit test error: {error_test_skit}') if args.accuracy >= 0: alpha = args.accuracy range_alpha = range(alpha, alpha + 1) for alpha in range_alpha: # accuracy parameter print('accuracy alpha:', alpha) # set parameters accordingly beta = 2**alpha lambda_ = round(args.lambda_ * beta**2) gamma = n1 * beta**2 + lambda_ secint = mpc.SecInt(gamma.bit_length() + 1) print(f'secint prime q: {secint.field.modulus.bit_length()} bits' f' (secint bit length: {secint.bit_length})') bound = round(d**(d/2)) * gamma**d if not args.ratrec: secnum = mpc.SecFld(min_order=2*bound + 1, signed=True) print(f'secfld prime p: {secnum.field.modulus.bit_length()} bits') else: secnum = mpc.SecInt(l=bound.bit_length() + 1) print(f'secint prime p: {secnum.field.modulus.bit_length()} bits' f' (secint bit length: {secnum.bit_length})') secfld = mpc.SecFld(min_order=4*bound**2) print(f"secfld prime p': {secfld.field.modulus.bit_length()} bits") f2 = float(beta) q = secint.field.modulus logging.info('Transpose, scale, and create (degree 0) shares for X and Y') # enforce full size shares (mod q numbers) by adding q to each element Xt = [[int(a * f2) + q for a in col] for col in X1.transpose()] Yt = [[int(a * f2) + q for a in col] for col in Y1.transpose()] timeStart = time.process_time() logging.info('Compute A = X^T X + lambda I and B = X^T Y') AB = [] for i in range(d-1): xi = Xt[i] for j in range(i, d-1): xj = Xt[j] s = 0 for k in range(n1): s += xi[k] * xj[k] AB.append(s) # X_i dot X_j AB.append(sum(xi) * beta) # X_i dot X_d for j in range(e): yj = Yt[j] s = 0 for k in range(n1): s += xi[k] * yj[k] AB.append(s) # X_i dot Y_j AB.append(n1 * beta**2) # X_d dot X_d for j in range(e): AB.append(beta * sum(Yt[j])) # X_d dot Y_j del Xt, Yt AB = [secint.field(a) for a in AB] AB = await mpc._reshare(AB) timeMiddle = time.process_time() logging.info('Compute w = A^-1 B') # convert secint to secnum AB = [secint(a) for a in AB] AB = mpc.convert(AB, secnum) # extract A and B from the AB array A = [[None] * d for _ in range(d)] B = [[None] * e for _ in range(d)] index = 0 for i in range(d): A[i][i] = AB[index] + lambda_ index += 1 for j in range(i+1, d): A[i][j] = A[j][i] = AB[index] index += 1 for j in range(e): B[i][j] = AB[index] index += 1 # solve A w = B w_det = linear_solve(A, B) if not args.ratrec: w_det = await mpc.output(w_det) *w, det = list(map(int, w_det)) w = np.reshape(w, (d, e)) w /= det else: *w, det = mpc.convert(w_det, secfld) w = mpc.scalar_mul(1/det, w) w = await mpc.output(w) w = [ratrec(int(a), secfld.field.modulus) for a in w] w = [a / b for a, b in w] w = np.reshape(w, (d, e)) timeEnd = time.process_time() logging.info(f'Total time {timeEnd - timeStart} = ' f'A and B in {timeMiddle - timeStart} + ' f'A^-1 B in {timeEnd - timeMiddle} seconds') error_train_mpyc = rmse(Y1, np.dot(X1, w[:-1]) + w[-1]) error_test_mpyc = rmse(Y2, np.dot(X2, w[:-1]) + w[-1]) print(f'MPyC train error: {error_train_mpyc}') print(f'MPyC test error: {error_test_mpyc}') print(f'relative train error: {(error_train_mpyc - error_train_skit) / error_train_skit}') print(f'relative test error: {(error_test_mpyc - error_test_skit) / error_test_skit}') await mpc.shutdown()
def main(): parser = argparse.ArgumentParser() parser.add_argument('-d', '--data', help='Filename for tableau.') parser.add_argument('options', nargs='*') parser.set_defaults(data='default') args = parser.parse_args(mpc.args) if not args.options: certificate_filename = "c" + str(mpc.id) + ".cert" logging.info('Setting certificate file to default = %s', certificate_filename) else: certificate_filename = args.options[0] T = load_tableau(args.data) m = len(T) - 1 n = len(T[0]) - 1 l = mpc.options.bit_length secfxp = mpc.SecFxp(l) for i in range(len(T)): for j in range(len(T[0])): T[i][j] = secfxp(T[i][j]) basis = [secfxp(i + n) for i in range(m)] cobasis = [secfxp(j) for j in range(n)] mpc.start() iteration = 0 logging.info('%d Termination?...', iteration) p_col_index, minimum = argmin_int(T[-1][:-1]) while mpc.run(mpc.output(minimum < 0)): iteration += 1 logging.info('%d Determining pivot...', iteration) p_col = index_matrix_prod(p_col_index + [secfxp(0)], T, True) constraints = [(T[i][-1] + (p_col[i] <= 0), p_col[i]) for i in range(m)] p_row_index, _ = argmin_rat(constraints) pivot = mpc.in_prod(p_row_index, p_col) pivot1 = 1 / pivot mpc.run(mpc.barrier()) logging.info('%d Updating tableau...', iteration) h = mpc.scalar_mul(pivot1, [(p_row_index[i] if i < m else 0) - p_col[i] for i in range(m + 1)]) p_row = index_matrix_prod(p_row_index, T[:-1]) v = mpc.vector_add(p_row, p_col_index + [0]) for i in range(m + 1): T[i] = mpc.vector_add(T[i], mpc.scalar_mul(h[i], v)) #swap basis entries delta = mpc.in_prod(basis, p_row_index) - mpc.in_prod( cobasis, p_col_index) p_row_index = mpc.scalar_mul(delta, p_row_index) basis = mpc.vector_sub(basis, p_row_index) p_col_index = mpc.scalar_mul(delta, p_col_index) cobasis = mpc.vector_add(cobasis, p_col_index) logging.info('%d Termination?...', iteration) p_col_index, minimum = argmin_int(T[-1][:-1]) logging.info('Termination...') mx = mpc.run(mpc.output(T[-1][-1])) print(' max(f) =', mx) logging.info('Computing solution...') solution = [secfxp(0) for _ in range(n)] for i in range(m): x = unit_vector(basis[i], m + n)[:n] y = mpc.scalar_mul(T[i][-1], x) solution = mpc.vector_add(solution, y) solution = mpc.run(mpc.output(solution)) logging.info('Computing dual solution...') dual_solution = [secfxp(0) for _ in range(m)] for j in range(n): x = unit_vector(cobasis[j], m + n)[n:] y = mpc.scalar_mul(T[-1][j], x) dual_solution = mpc.vector_add(dual_solution, y) dual_solution = mpc.run(mpc.output(dual_solution)) mpc.shutdown() logging.info('Writing output to %s.', certificate_filename) with open(os.path.join('data', 'lp', certificate_filename), 'w') as f: f.write('# tableau = \n' + args.data + '\n') f.write('# bit-length = \n' + str(mpc.options.bit_length) + '\n') f.write('# security parameter = \n' + str(mpc.options.security_parameter) + '\n') f.write('# threshold = \n' + str(mpc.threshold) + '\n') f.write('# solution = \n') f.write('\t'.join(x.__repr__() for x in solution) + '\n') f.write('# dual solution = \n') f.write('\t'.join(x.__repr__() for x in dual_solution) + '\n')
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()
async def main(): parser = argparse.ArgumentParser() parser.add_argument('-d', '--data', help='filename for tableau') parser.add_argument('options', nargs='*') parser.set_defaults(data='default') args = parser.parse_args() if not args.options: certificate_filename = f'c{mpc.pid}.cert' logging.info( f'Setting certificate file to default = {certificate_filename}') else: certificate_filename = args.options[0] T = load_tableau(args.data) m = len(T) - 1 n = len(T[0]) - 1 l = mpc.options.bit_length secfxp = mpc.SecFxp(l) for i in range(m + 1): for j in range(n + 1): T[i][j] = secfxp(T[i][j]) basis = [secfxp(i + n) for i in range(m)] cobasis = [secfxp(j) for j in range(n)] await mpc.start() iteration = 0 logging.info(f'{iteration} Termination?...') p_col_index, minimum = argmin_int(T[-1][:-1]) while await mpc.output(minimum < 0): iteration += 1 logging.info(f'{iteration} Determining pivot...') p_col = index_matrix_prod(p_col_index + [secfxp(0)], T, True) constraints = [(T[i][-1] + (p_col[i] <= 0), p_col[i]) for i in range(m)] p_row_index, _ = argmin_rat(constraints) pivot = mpc.in_prod(p_row_index, p_col) logging.info(f'{iteration} Updating tableau...') h = mpc.scalar_mul(1 / pivot, mpc.vector_sub(p_row_index + [0], p_col)) p_row = index_matrix_prod(p_row_index, T[:-1]) v = mpc.vector_add(p_row, p_col_index + [0]) for i in range(m + 1): T[i] = mpc.vector_add(T[i], mpc.scalar_mul(h[i], v)) # swap basis entries delta = mpc.in_prod(basis, p_row_index) - mpc.in_prod( cobasis, p_col_index) p_row_index = mpc.scalar_mul(delta, p_row_index) basis = mpc.vector_sub(basis, p_row_index) p_col_index = mpc.scalar_mul(delta, p_col_index) cobasis = mpc.vector_add(cobasis, p_col_index) logging.info(f'{iteration} Termination?...') p_col_index, minimum = argmin_int(T[-1][:-1]) logging.info('Termination...') mx = await mpc.output(T[-1][-1]) print(' max(f) =', mx) logging.info('Computing solution...') solution = [secfxp(0) for _ in range(n)] for i in range(m): x = mpc.unit_vector(basis[i], m + n)[:n] y = mpc.scalar_mul(T[i][-1], x) solution = mpc.vector_add(solution, y) solution = await mpc.output(solution) logging.info('Computing dual solution...') dual_solution = [secfxp(0) for _ in range(m)] for j in range(n): x = mpc.unit_vector(cobasis[j], m + n)[n:] y = mpc.scalar_mul(T[-1][j], x) dual_solution = mpc.vector_add(dual_solution, y) dual_solution = await mpc.output(dual_solution) await mpc.shutdown() logging.info(f'Writing output to {certificate_filename}') tab = '\t' with open(os.path.join('data', 'lp', certificate_filename), 'w') as f: f.write(f'# tableau =\n{args.data}\n') f.write(f'# bit-length =\n{mpc.options.bit_length}\n') f.write(f'# security parameter =\n{mpc.options.sec_param}\n') f.write(f'# threshold =\n{mpc.threshold}\n') f.write(f'# solution =\n{tab.join(x.__repr__() for x in solution)}\n') f.write( f'# dual solution =\n{tab.join(x.__repr__() for x in dual_solution)}\n' )