Skip to content

Commit

Permalink
Support all functionality when PRSS disabled.
Browse files Browse the repository at this point in the history
  • Loading branch information
lschoe committed Jul 30, 2023
1 parent f0e0c87 commit 50ab220
Show file tree
Hide file tree
Showing 15 changed files with 572 additions and 241 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ dist: jammy
language: python
jobs:
- python: 3.9
env:
- MPYC_NOPRSS=1
install: pip install numpy==1.22.* gmpy2
- python: pypy3.9-7.3.9
install: pip install numpy==1.23.*
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

MPyC supports secure *m*-party computation tolerating a dishonest minority of up to *t* passively corrupt parties,
where *m ≥ 1* and *0 ≤ t < m/2*. The underlying cryptographic protocols are based on threshold secret sharing over finite
fields (using Shamir's threshold scheme as well as pseudorandom secret sharing).
fields (using Shamir's threshold scheme and optionally pseudorandom secret sharing).

The details of the secure computation protocols are mostly transparent due to the use of sophisticated operator overloading
combined with asynchronous evaluation of the associated protocols.
Expand Down
2 changes: 1 addition & 1 deletion demos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ optional arguments:

`python ridgeregression.py -i3 -a7`

`python ridgeregression.py -M3`
`python ridgeregression.py -M3 --no-prss`

`python multilateration.py -i 3 4 5`

Expand Down
19 changes: 17 additions & 2 deletions demos/bnnmnist.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ async def bsgn_0(a):

s = mpc.random_bits(Zp, 1, signed=True) # random sign
r = mpc._random(Zp)
if mpc.options.no_prss:
r = (await r)[0]
r = mpc.prod([r, r]) # random square modulo p
a, s, r = await mpc.gather(a, s, r)
b = await mpc.prod([2*a+1, s[0], r])
Expand All @@ -117,6 +119,8 @@ async def vector_bsgn_0(x):

s = mpc.random_bits(Zp, n, signed=True) # n random signs
r = mpc._randoms(Zp, n)
if mpc.options.no_prss:
r = await r
r = mpc.schur_prod(r, r) # n random squares modulo p
x, s, r = await mpc.gather(x, s, r)
y = [2*a+1 for a in x]
Expand All @@ -141,6 +145,8 @@ async def bsgn_1(a):

s = mpc.random_bits(Zp, 3, signed=True) # 3 random signs
r = mpc._randoms(Zp, 3)
if mpc.options.no_prss:
r = await r
r = mpc.schur_prod(r, r) # 3 random squares modulo p
a, s, r = await mpc.gather(a, s, r)
y = [b + 2*i for b in (2*a+1,) for i in (-1, 0, 1)]
Expand Down Expand Up @@ -168,6 +174,8 @@ async def vector_bsgn_1(x):

s = mpc.random_bits(Zp, 3*n, signed=True) # 3n random signs
r = mpc._randoms(Zp, 3*n)
if mpc.options.no_prss:
r = await r
r = mpc.schur_prod(r, r) # 3n random squares modulo p
x, s, r = await mpc.gather(x, s, r)
y = [b + 2*i for b in (2*a+1 for a in x) for i in (-1, 0, 1)]
Expand Down Expand Up @@ -200,6 +208,8 @@ async def bsgn_2(a):

s = mpc.random_bits(Zp, 6, signed=True) # 6 random signs
r = mpc._randoms(Zp, 6)
if mpc.options.no_prss:
r = await r
r = mpc.schur_prod(r, r) # 6 random squares modulo p
a, s, r = await mpc.gather(a, s, r)
y = [b + 2*i for b in (2*a+1,) for i in (-2, -1, 0, 1, 2)]
Expand All @@ -224,6 +234,8 @@ async def vector_bsgn_2(x):

s = mpc.random_bits(Zp, 6*n, signed=True) # 6n random signs
r = mpc._randoms(Zp, 6*n)
if mpc.options.no_prss:
r = await r
r = mpc.schur_prod(r, r) # 6n random squares modulo p
x, s, r = await mpc.gather(x, s, r)
y = [b + 2*i for b in (2*a+1 for a in x) for i in (-2, -1, 0, 1, 2)]
Expand Down Expand Up @@ -252,14 +264,17 @@ async def vector_sge(x):
l = stype.bit_length
k = mpc.options.sec_param

r_bits = await mpc.random_bits(Zp, (l+1) * n)
r_bits = mpc.random_bits(Zp, (l+1) * n)
r_divl = mpc._randoms(Zp, n, 1<<k)
r_bits = await r_bits
r_bits = [b.value for b in r_bits]
r_modl = [0] * n
for j in range(n):
for i in range(l-1, -1, -1):
r_modl[j] <<= 1
r_modl[j] += r_bits[l * j + i]
r_divl = mpc._randoms(Zp, n, 1<<k)
if mpc.options.no_prss:
r_divl = await r_divl
x = await mpc.gather(x)
x_r = [a + ((1<<l) + b) for a, b in zip(x, r_modl)]
c = await mpc.output([a + (b.value << l) for a, b in zip(x_r, r_divl)])
Expand Down
17 changes: 13 additions & 4 deletions demos/np_bnnmnist.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ async def bsgn_0(a):

n = a.size
s = mpc.np_random_bits(Zp, n, signed=True) # n random signs
r2 = mpc._np_randoms(Zp, n) ** 2 # n random squares modulo p
r2 = mpc._np_randoms(Zp, n)
if mpc.options.no_prss:
r2 = await r2
r2 **= 2 # n random squares modulo p
r2 = mpc._reshare(r2)
s, r2 = await mpc.gather(s, r2)
y = s * r2
Expand All @@ -87,7 +90,10 @@ async def bsgn_1(a):

n = a.size
s = mpc.np_random_bits(Zp, 3*n, signed=True) # 3n random signs
r2 = mpc._np_randoms(Zp, 3*n) ** 2 # 3n random squares modulo p
r2 = mpc._np_randoms(Zp, 3*n)
if mpc.options.no_prss:
r2 = await r2
r2 **= 2 # 3n random squares modulo p
r2 = mpc._reshare(r2)
s, r2 = await mpc.gather(s, r2)
s = s.reshape(3, n)
Expand Down Expand Up @@ -127,7 +133,10 @@ async def bsgn_2(a):

n = a.size
s = mpc.np_random_bits(Zp, 6*n, signed=True) # 6n random signs
r2 = mpc._np_randoms(Zp, 6*n) ** 2 # 6n random squares modulo p
r2 = mpc._np_randoms(Zp, 6*n)
if mpc.options.no_prss:
r2 = await r2
r2 **= 2 # 6n random squares modulo p
r2 = mpc._reshare(r2)
s, r2 = await mpc.gather(s, r2)
s = s.reshape(6, n)
Expand All @@ -144,7 +153,7 @@ async def bsgn_2(a):
y = await mpc.output(y, threshold=2*mpc.threshold)
t = np.sum(s[:5] * legendre_p(y[:5].value), axis=0)
t = await mpc.output(t * y[5])
return Zp.array(s[5] * legendre_p(t.value)).reshape(a.shape)
return (s[5] * legendre_p(t.value)).reshape(a.shape)


async def main():
Expand Down
6 changes: 4 additions & 2 deletions demos/np_lpsolver.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ async def main():
coefs = w_powers[[[(-j * k) % N for k in range(N)] for j in range(n)]]
else:
coefs = Zp.array([[w_powers[-j*k % N].value for k in range(N)] for j in range(n)])
sum_powers = np.sum(np.fromiter((np_pwlst(T[i+1][-1] / N, basis[i], N) for i in range(m)), 'O'))
sum_powers = np.sum(np.fromiter((np_pwlst(T[i+1][-1] / N, basis[i], N) for i in range(m)),
'O', count=m))
x = coefs @ sum_powers
Ax_bounded_by_b = np.all(A @ x <= b * cd)
x_nonnegative = np.all(x >= 0)
Expand All @@ -145,7 +146,8 @@ async def main():
coefs = w_powers[[[(-i * k) % N for k in range(N)] for i in range(N - m, N)]]
else:
coefs = Zp.array([[w_powers[-i*k % N].value for k in range(N)] for i in range(N - m, N)])
sum_powers = np.sum(np.fromiter((np_pwlst(T[0][j] / N, cobasis[j], N) for j in range(n)), 'O'))
sum_powers = np.sum(np.fromiter((np_pwlst(T[0][j] / N, cobasis[j], N) for j in range(n)),
'O', count=n))
y = coefs @ sum_powers
yA_bounded_by_c = np.all(y @ A >= c * cd)
y_nonnegative = np.all(y >= 0)
Expand Down
4 changes: 2 additions & 2 deletions demos/np_lpsolverfxp.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,13 +105,13 @@ async def main():

logging.info('Solution x')
x = np.sum(np.fromiter((T[i+1, -1] * mpc.np_unit_vector(basis[i], n + m)[:n] for i in range(m)),
'O'))
'O', count=m))
Ax_bounded_by_b = np.all(A @ x <= 1.01 * b + 0.0001)
x_nonnegative = np.all(x >= 0)

logging.info('Dual solution y')
y = np.sum(np.fromiter((T[0, j] * mpc.np_unit_vector(cobasis[j], n + m)[n:] for j in range(n)),
'O'))
'O', count=n))
yA_bounded_by_c = np.all(y @ A >= np.where(c > 0, 1/1.01, 1.01) * c - 0.0001)
y_nonnegative = np.all(y >= 0)

Expand Down
4 changes: 2 additions & 2 deletions mpyc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
The MPC protocols are based on Shamir's threshold secret sharing scheme
and withstand passive adversaries controlling less than half of the parties.
Secure integer and fixed-point arithmetic is supported for parameterized
Secure integer and fixed-point arithmetic are supported for parameterized
number ranges, also including support for comparison and bitwise operations.
Secure finite field arithmetic is supported for fields of arbitrary order.
Secure NumPy arrays over these basic types are available as well.
Expand All @@ -29,7 +29,7 @@
and statistics (securely mimicking Python’s statistics module).
"""

__version__ = '0.9.3'
__version__ = '0.9.4'
__license__ = 'MIT License'

import os
Expand Down
2 changes: 1 addition & 1 deletion mpyc/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""Support for natively asynchronous REPL with MPyC preloaded.
To launch a natively asynch REPL with MPyC preloaded, run:
To launch a natively async REPL with MPyC preloaded, run:
python -m mpyc
Expand Down
2 changes: 1 addition & 1 deletion mpyc/finfields.py
Original file line number Diff line number Diff line change
Expand Up @@ -793,7 +793,7 @@ def __array_function__(self, func, types, args, kwargs):
if isinstance(a, np.ndarray):
if func.__name__ in ('roll', 'diagonal', 'diag_flat'):
a = cls(a, check=False)
else:
elif func.__name__ != 'flatnonzero':
a = cls(a)
elif isinstance(a, list):
# for func like vsplit returning list of arrays
Expand Down
2 changes: 1 addition & 1 deletion mpyc/numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
def _matmul_shape(shapeA, shapeB):
"""Return shape of A @ B for given shapes of A and B.
None is returned for the shape if A and B are both 1-D arrays,
None is returned for the shape if A and B are both 1D arrays,
as A @ B is a scalar in this case, which has no shape.
Note that A @ B does not allow A and/or B to be 0-D arrays.
Expand Down
Loading

0 comments on commit 50ab220

Please sign in to comment.