Beispiel #1
0
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)
Beispiel #2
0
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:])
Beispiel #3
0
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))
Beispiel #4
0
 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
Beispiel #5
0
 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
Beispiel #6
0
 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)]
Beispiel #7
0
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
Beispiel #8
0
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
Beispiel #9
0
 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)
         ]
Beispiel #10
0
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
Beispiel #11
0
 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)
Beispiel #12
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
Beispiel #13
0
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
Beispiel #14
0
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
Beispiel #15
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', 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()
Beispiel #16
0
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')
Beispiel #17
0
 def __mul__(self, other):
     multiplications = mpc.scalar_mul(other, self.inputs + [self.outcome])
     multiplied_outcome = multiplications.pop()  # mutates multiplications
     return Sample(multiplications, multiplied_outcome)
Beispiel #18
0
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()
Beispiel #19
0
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')
Beispiel #20
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()
Beispiel #21
0
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'
        )