def test_secfld(self): secfld = mpc.SecFld(2, char=2) a = getrandbits(secfld, 1, True) a = mpc.run(mpc.output(a)) self.assertGreaterEqual(int(a[0]), 0) self.assertLessEqual(int(a[0]), 1) secfld = mpc.SecFld(3) a = getrandbits(secfld, 1) a = mpc.run(mpc.output(a)) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 1) a = mpc.run(mpc.output(randrange(secfld, 1, 3))) self.assertGreaterEqual(int(a), 1) self.assertLessEqual(int(a), 2) secfld = mpc.SecFld(256) a = getrandbits(secfld, 8) a = mpc.run(mpc.output(a)) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 2**8 - 1) a = mpc.run(mpc.output(randrange(secfld, 256))) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 2**8 - 1) a = mpc.run(mpc.output(randint(secfld, 0, 2))) self.assertIn(a, [0, 1, 2]) x = mpc.run(mpc.output(random_unit_vector(secfld, 2))) self.assertEqual(int(sum(x)), 1) x = mpc.run(mpc.output(random_permutation(secfld, range(1, 9)))) self.assertSetEqual(set(map(int, x)), set(range(1, 9))) x = mpc.run(mpc.output(random_derangement(secfld, range(2)))) self.assertListEqual(list(map(int, x)), [1, 0]) secfld = mpc.SecFld(257) a = getrandbits(secfld, 8) a = mpc.run(mpc.output(a)) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 2**8 - 1) a = mpc.run(mpc.output(randrange(secfld, 257))) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 2**8) a = mpc.run(mpc.output(randint(secfld, -1, 1))) self.assertIn(a, [-1, 0, 1]) x = mpc.run(mpc.output(random_unit_vector(secfld, 1))) self.assertEqual(int(sum(x)), 1) x = mpc.run(mpc.output(random_permutation(secfld, range(1, 9)))) self.assertSetEqual(set(map(int, x)), set(range(1, 9))) x = mpc.run(mpc.output(random_derangement(secfld, range(2)))) self.assertListEqual(list(map(int, x)), [1, 0])
def test_secfld(self): secfld = mpc.SecFld(2, char2=True) a = getrandbits(secfld, 1) a = mpc.run(mpc.output(a)) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 1) secfld = mpc.SecFld(3) a = getrandbits(secfld, 1) a = mpc.run(mpc.output(a)) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 1) a = mpc.run(mpc.output(randrange(secfld, 1, 3))) self.assertGreaterEqual(int(a), 1) self.assertLessEqual(int(a), 2) secfld = mpc.SecFld(256) a = getrandbits(secfld, 8) a = mpc.run(mpc.output(a)) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 2**8 - 1) a = mpc.run(mpc.output(randrange(secfld, 256))) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 2**8 - 1) a = mpc.run(mpc.output(randint(secfld, 0, 2))) self.assertIn(a, [0, 1, 2]) x = mpc.run(mpc.output(random_unit_vector(secfld, 6))) self.assertEqual(int(sum(x)), 1) x = mpc.run(mpc.output(random_permutation(secfld, range(1, 9)))) self.assertSetEqual({a for a in range(1, 9)}, {int(a) for a in x}) x = mpc.run(mpc.output(random_derangement(secfld, range(2)))) self.assertListEqual([1, 0], [int(a) for a in x]) secfld = mpc.SecFld(257) a = getrandbits(secfld, 8) a = mpc.run(mpc.output(a)) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 2**8 - 1) a = mpc.run(mpc.output(randrange(secfld, 257))) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 2**8) a = mpc.run(mpc.output(randint(secfld, -1, 1))) self.assertIn(a, [-1, 0, 1]) x = mpc.run(mpc.output(random_unit_vector(secfld, 6))) self.assertEqual(int(sum(x)), 1) x = mpc.run(mpc.output(random_permutation(secfld, range(1, 9)))) self.assertSetEqual({a for a in range(1, 9)}, {int(a) for a in x}) x = mpc.run(mpc.output(random_derangement(secfld, range(2)))) self.assertListEqual([1, 0], [int(a) for a in x])
def test_secfxp(self): secfxp = mpc.SecFxp() a = getrandbits(secfxp, 10) self.assertTrue(a.integral) a = mpc.run(mpc.output(a)) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 2**10 - 1) x = mpc.run(mpc.output(random_unit_vector(secfxp, 3))) self.assertEqual(int(sum(x)), 1) x = mpc.run(mpc.output(random_permutation(secfxp, range(1, 9)))) self.assertSetEqual(set(map(int, x)), set(range(1, 9))) x = mpc.run(mpc.output(random_derangement(secfxp, [0.0, 1.0]))) self.assertListEqual(list(map(int, x)), [1, 0]) a = mpc.run(mpc.output(choice(secfxp, [0.08, 0.09, 0.1, 0.11, 0.12]))) self.assertAlmostEqual(a, 0.1, 1) a = mpc.run(mpc.output(random(secfxp))) self.assertGreaterEqual(a, 0) self.assertLessEqual(a, 1) a = mpc.run(mpc.output(uniform(secfxp, 13.13, 13.17))) self.assertGreaterEqual(a, 13.13) self.assertLessEqual(a, 13.17) a = mpc.run(mpc.output(uniform(secfxp, -13.13, -13.17))) self.assertGreaterEqual(a, -13.17) self.assertLessEqual(a, -13.13)
async def _quickselect(x, k): """Return kth order statistic, 0 <= k < n with n=len(x). If all elements of x are distinct, no information on x is leaked. If x contains duplicate elements, ties in comparisons are broken evenly, which ultimately leaks some information on the distribution of duplicate elements. Average running time (dominated by number of secure comparisons, and number of conversions of integer indices to unit vectors) is linear in n. """ stype = type(x[0]) await runtime.returnType(stype) n = len(x) if n == 1: return x[0] f = stype.field.frac_length y = runtime.random_bits(stype, n) p = runtime.in_prod(x, random.random_unit_vector(stype, n)) # random pivot z = [(x[i] - p) * 2 < y[i] * 2**-f for i in range(n)] # break ties x[i] == p uniformly at random s = int(await runtime.output(runtime.sum(z))) if k >= s: # take complement k = k - s z = [1 - a for a in z] s = n - s # 0 <= k < s w = [stype(0)] * s for i in range(n): j = runtime.sum(z[:i + 1]) # 0 <= j <= s u = runtime.unit_vector(j, s) # TODO: exploit that j <= i+1 to shorten u v = runtime.scalar_mul(z[i] * x[i], u) w = runtime.vector_add(w, v) return _quickselect(w, k)
def test_secfxp(self): secfxp = mpc.SecFxp() a = getrandbits(secfxp, 10) self.assertTrue(a.integral) a = mpc.run(mpc.output(a)) self.assertGreaterEqual(int(a), 0) self.assertLessEqual(int(a), 2**10 - 1) x = mpc.run(mpc.output(random_unit_vector(secfxp, 6))) self.assertEqual(int(sum(x)), 1) x = mpc.run(mpc.output(random_permutation(secfxp, range(1, 9)))) self.assertSetEqual({a for a in range(1, 9)}, {int(a) for a in x}) x = mpc.run(mpc.output(random_derangement(secfxp, range(2)))) self.assertListEqual([1, 0], [int(a) for a in x]) a = mpc.run(mpc.output(choice(secfxp, [0.8, 0.9, 1.0, 1.1, 1.2]))) self.assertAlmostEqual(float(a), 1.0, 0) a = mpc.run(mpc.output(choice(secfxp, [0.08, 0.09, 0.1, 0.11, 0.12]))) self.assertAlmostEqual(float(a), 0.1, 1) a = mpc.run(mpc.output(random(secfxp))) self.assertGreaterEqual(float(a), 0) self.assertLessEqual(float(a), 1) a = mpc.run(mpc.output(uniform(secfxp, 13.13, 13.17))) self.assertGreaterEqual(float(a), 13.13) self.assertLessEqual(float(a), 13.17) a = mpc.run(mpc.output(uniform(secfxp, -13.13, -13.17))) self.assertGreaterEqual(float(a), -13.17) self.assertLessEqual(float(a), -13.13)
def random(sectype, length, offset=0): n = length return secindex(random_unit_vector(sectype, n), offset=offset)
def test_secint(self): secint = mpc.SecInt() a = mpc.run(mpc.output(getrandbits(secint, 10))) self.assertGreaterEqual(a, 0) self.assertLessEqual(a, 2**10 - 1) x = mpc.run(mpc.output(random_unit_vector(secint, 4))) self.assertEqual(sum(x), 1) a = mpc.run(mpc.output(randrange(secint, 37))) # French roulette self.assertGreaterEqual(a, 0) self.assertLessEqual(a, 36) a = mpc.run(mpc.output(randrange(secint, 1, 7))) # one die self.assertGreaterEqual(a, 1) self.assertLessEqual(a, 6) a = mpc.run(mpc.output(randrange(secint, 1, 7) + randrange(secint, 1, 7))) # two dice self.assertGreaterEqual(a, 2) self.assertLessEqual(a, 12) a = mpc.run(mpc.output(randrange(secint, 1, 32, 2))) self.assertGreaterEqual(a, 1) self.assertLessEqual(a, 31) self.assertEqual(a % 2, 1) a = mpc.run(mpc.output(randint(secint, -1, 1))) self.assertIn(a, [-1, 0, 1]) x = list(range(8)) shuffle(secint, x) shuffle(secint, x) x = mpc.run(mpc.output(x)) self.assertSetEqual(set(x), set(range(8))) x = mpc.run(mpc.output(random_permutation(secint, 8))) self.assertSetEqual(set(x), set(range(8))) x = mpc.run(mpc.output(random_derangement(secint, 2))) self.assertListEqual(x, [1, 0]) x = mpc.run(mpc.output(random_derangement(secint, range(1, 9)))) self.assertSetEqual(set(x), set(range(1, 9))) x = mpc.run(mpc.output(choice(secint, [1, 2, 3, 4, 5]))) self.assertIn(x, [1, 2, 3, 4, 5]) x = mpc.run(mpc.output(choice(secint, [secint(-100), secint(200), secint(-300)]))) self.assertIn(x, [-100, 200, -300]) x = mpc.run(mpc.output(mpc.sum(choices(secint, [0, 1], k=5)))) # uniform self.assertGreaterEqual(x, 0) self.assertLessEqual(x, 5) x = mpc.run(mpc.output(mpc.sum(choices(secint, [0, 1], [25, 75])))) # Bernoulli self.assertGreaterEqual(x, 0) self.assertLessEqual(x, 1) x = mpc.run(mpc.output(mpc.sum(choices(secint, [0, 1], [25, 75], k=10)))) # binomial self.assertGreaterEqual(x, 0) self.assertLessEqual(x, 10) x = mpc.run(mpc.output(sample(secint, [2**i for i in range(16)], 8))) self.assertGreaterEqual(sum(x), 2**8 - 1) self.assertLessEqual(sum(x), 2**8 * (2**8 - 1)) x = mpc.run(mpc.output(sample(secint, range(10**8), 10))) self.assertGreaterEqual(min(x), 0) self.assertLessEqual(max(x), 10**8 - 1) x = mpc.run(mpc.output(sample(secint, range(1000000, 3000000, 1000), 10))) self.assertGreaterEqual(min(x) // 1000, 1000) self.assertLessEqual(max(x) // 1000, 3000) self.assertEqual(sum(x) % 1000, 0)
async def _quickselect(x, ks): """Return kth order statistics for k in ks, where 0 <= k < n with n=len(x). If all elements of x are distinct, no information on x is leaked. If x contains duplicate elements, ties in comparisons are broken evenly, which ultimately leaks some information on the distribution of duplicate elements. Average running time (dominated by number of secure comparisons, and number of conversions of integer indices to unit vectors) is linear in n, for fixed ks. """ # TODO: consider adding case ks is an int instead of a list # TODO: try to make implementation below competitive with straightforward "sort and pick" # approach; slowness due to expensive computation of w_left (and w_right). Also note # advantage of sorting that there is no privacy leakage. if len(ks) >= 3: y = runtime.sorted(x) return [y[k] for k in ks] if not ks: return [] n = len(x) if n == 1: return [x[0]] sectype = type(x[0]) await runtime.returnType(sectype, len(ks)) f = sectype.frac_length while True: y = runtime.random_bits(sectype, n) p = runtime.in_prod(x, random.random_unit_vector(sectype, n)) # random pivot z = [2*(x[i] - p) < y[i] * 2**-f for i in range(n)] # break ties x[i] == p evenly s = int(await runtime.output(runtime.sum(z))) if 0 < s < n: break ks_left = [k for k in ks if k < s] ks_right = [k - s for k in ks if k >= s] if not ks_left: ks_left = ks_right ks_right = [] z = [1-a for a in z] s = n - s zx = runtime.schur_prod(z, x) sectype_0 = sectype(0) w_left = [sectype_0] * s if ks_right: w_right = [sectype_0] * (n - s) for i in range(n): j = runtime.sum(z[:i+1]) # 0 <= j <= i+1 m = min(i+2, s) # i+2 to avoid wrap around when i+1 < s still u_left = runtime.unit_vector(j, m) v_left = runtime.scalar_mul(zx[i], u_left) v_left.extend([sectype_0] * (s - m)) w_left = runtime.vector_add(w_left, v_left) if ks_right: # TODO: save some work by computing w_left and w_right together j = i+1 - j m = min(i+2, n - s) # i+2 to avoid wrap around when i+1 < n - s still u_right = runtime.unit_vector(j, m) v_right = runtime.scalar_mul(x[i] - zx[i], u_right) v_right.extend([sectype_0] * (n - s - m)) w_right = runtime.vector_add(w_right, v_right) w = _quickselect(w_left, ks_left) if ks_right: w.extend(_quickselect(w_right, ks_right)) return w
def choice(self): length = len(self.samples) included = random_unit_vector(secint, length) selected = [self.samples[i] * included[i] for i in range(length)] return reduce(operator.add, selected)