def sum(self, x): """Sum of all elements in x. Communication cost: none.""" yield declareReturn(self, x[0].field) x = yield x returnValue(sum(x))
def _equal(self, a, b): """Equality testing with secret shared result. This is the probabilistic method based on quadratic reciprocity described in: "Constant-Round Multiparty Computation for Interval Test, Equality Test, and Comparison" by Takashi Nishide and Kazuo Ohta, and fails with probability 1/(2**k) where k is the security parameter of the runtime. """ Zp = a.field yield declareReturn(self, Zp) d = a - b # We will check if d == 0 k = self.options.security_parameter x = [None] * k i = 0 while i < k: z = self.random_bit(Zp) r = self.random(Zp) rp = self.random(Zp) # If 1 - 2z == 1, c will always be a square modulo p if d == 0 # and with probability 1/2 otherwise (except if rp == 0). # If 1 - 2z == -1 it will be non-square. c = yield self.open(d * r + (1 - 2 * z) * rp * rp) if c == 0: continue x[i] = 1 - z if legendre(c.value, Zp.modulus) == 1 else z i += 1 e = self.prod(x) e = yield e #e = yield e returnValue(e)
def neg(self, a): """Negation of a. Communication cost: none. """ yield declareReturn(self, a.field) a = yield a returnValue(-a)
def random_derangement_3(n): yield declareReturn(tv, Zp, n) a = random_permutation(n) good_derangements = get_no_two_cycle_derangements(n) for good_derangement in good_derangements: if(yield 1-tv.sum([a[i] - good_derangement[i] for i in range(n)])): returnValue(a) returnValue(random_derangement_3(n))
def random_derangement_2(n): yield declareReturn(tv, Zp, n) a = random_permutation(n) t = tv.prod([a[i]-i if (1-a[int(str(a[0].result)[1:-1])]-i) else 0 for i in xrange(n)]) if (yield tv.equal_zero_public(t)): returnValue(random_derangement(n)) else: returnValue(a)
def bin_comb(self, x): """Binary combination: dot product of powers of 2 and shared x.""" yield declareReturn(self, x[0].field) x = yield x s = 0 for i in xrange(len(x) - 1, -1, -1): s = s * 2 + x[i] returnValue(s)
def lin_comb(self, a, x): """Linear combination: dot product of public a and shared x. Communication cost: none. Saves the construction of unnecessary shares compared to using add() and mul().""" yield declareReturn(self, x[0].field) x = yield x if isinstance(a, Share): a = yield a returnValue(sum(imap(operator.mul, a, x)))
def random_derangement(n): #basic derangement, not strictly related to an actual array -> jasper yield declareReturn(tv, Zp, n) a = random_permutation(n) #print("WASNIO", int(str(a[0].result)[1])) t = tv.prod([a[i]-i for i in xrange(n)]) # if (yield tv.equal_zero_public(t)): #if self-loop get another derangement # print"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" returnValue(random_derangement(n)) # expected value(?) else: returnValue(a)
def scalar_mul(self, a, x): """Scalar multiplication of scalar a with vector x. Communication cost: n Shamir sharings. """ yield declareReturn(self, a.field, len(x)) a, x = yield a, x for i in xrange(len(x)): x[i] = self.__share_recombine(a * x[i]) #x = yield x returnValue(x)
def lsb(self, a): """ Least Significant Bit Gate [ST06] """ Zp = a.field yield declareReturn(self, Zp) l = self.options.bit_length k = self.options.security_parameter b = self.random_bit(Zp) r = self.random_max(Zp, 2**(l + k)) a, b, r = yield a, b, r c = yield self.open(Share(self, Zp, a + b + 2 * r)) returnValue(c.bit(0) + b - 2 * c.bit(0) * b) #xor
def equal_zero_public(self, a): """Public zero test. Communication cost: 1 opening (ie. each player sends a share).""" field = a.field yield declareReturn(self, field) r = self.random(field) a, r = yield a, r field = type(a) c = yield self.open(Share(self, field, a * r), None, 2 * self.threshold) returnValue(c == 0)
def schur_prod(self, x, y): """Entrywise multiplication of vectors x and y Communication cost: n Shamir sharings. """ yield declareReturn(self, x[0].field, len(x)) x, y = yield x, y for i in xrange(len(x)): x[i] = self.__share_recombine(x[i] * y[i]) #x = yield x returnValue(x)
def invert(self, a): """Multiplicative inverse of a, assuming a!=0. Communication cost: 1 opening (ie. each player sends a share). """ field = a.field yield declareReturn(self, field) r = self.random(field) a, r = yield a, r ar = yield self.open(Share(self, field, a * r), None, 2 * self.threshold) if ar == 0: returnValue(self.invert(a)) returnValue(~ar * r)
def gauss(self, A, d, b, c): """Gaussian elimination A:= A d - b c Communication cost: m * n Shamir sharings. """ yield declareReturn(self, A[0][0].field, len(A), len(A[0])) A, d, b, c = yield A, d, b, c for i in xrange(len(A)): for j in xrange(len(A[0])): A[i][j] = self.__share_recombine(A[i][j] * d - b[i] * c[j]) #A = yield A returnValue(A)
def sub(self, a, b): """Subtraction of a and b. Communication cost: none. """ if not isinstance(a, Share): a = Share(self, b.field, a) if not isinstance(b, Share): b = Share(self, a.field, b) yield declareReturn(self, a.field) a, b = yield a, b returnValue(a - b)
def add(self, a, b): """Addition of a to b. Communication cost: none. """ yield declareReturn(self, a.field) if not isinstance(b, Share): a = yield a returnValue(a + b) a, b = yield a, b returnValue(a + b)
def prod(self, x): """Product of all elements in x. Communication cost: n Shamir sharings in log_2 n rounds.""" yield declareReturn(self, x[0].field) x = yield x while len(x) > 1: h = [] while len(x) > 1: h.append(self.__share_recombine(x.pop() * x.pop())) h = yield h h.extend(x) x = h returnValue(x[0])
def matrix_prod(self, A, B): """Computing matrix product of A with transposed B using only one round of communication.""" yield declareReturn(self, A[0][0].field, len(A), len(B)) A, B = yield A, B C = [None] * len(A) for ia in xrange(len(A)): C[ia] = [None] * len(B) for ib in xrange(len(B)): s = sum(imap(operator.mul, A[ia], B[ib])) C[ia][ib] = self.__share_recombine(s) #C = yield C returnValue(C)
def in_prod(self, x, y): """Computing dot product of x and y using only one round of communication.""" yield declareReturn(self, x[0].field) if x is y: x = yield x s = sum(imap(lambda a: a * a, x)) else: x, y = yield x, y s = sum(imap(operator.mul, x, y)) s = self.__share_recombine(s) s = yield s # s = yield s returnValue(s)
def mul(self, a, b): """Multiplication of a and b. Communication cost: 1 Shamir sharing. """ yield declareReturn(self, a.field) if not isinstance(b, Share): a = yield a returnValue(a * b) a, b = yield a, b c = self.__share_recombine(a * b) c = yield c #c = yield c returnValue(c)
def main(runtime): global tv, Zp tv = runtime k = tv.options.security_parameter l = tv.options.bit_length ln = len(tv.players).bit_length() Zp = GF(find_prime(2**(l + k + ln + 1), blum=True)) yield declareReturn(tv, Zp) shareZp = lambda x: Share(tv, Zp, Zp(x)) t = 12 for i in xrange(t): a = secret_index(shareZp(i), t) a = yield map(tv.open, a) print i, map(lambda v: int(v.value), a) tv.shutdown()
def eqz_int(rt, x, k=-1): # need int, otherwise vc_certificate and localversion also apply to subfunction yield declareReturn(rt, rt.Zp) if k==1: viff.inlinecb.returnValue(x) if k==2: viff.inlinecb.returnValue(1-(x-1)*(x-2)*(x-3)*(~x.field(-6))) if k==-1: k = rt.options.bit_length r_bits = [rt.prss_share_random(x.field, True) for _ in xrange(k)] r_divl = rt.prss_share_random_max(x.field, 2**rt.options.security_parameter) c = yield rt.open(x + sum([(2**i)*r_bits[i] for i in xrange(k)]) + (2**(k))*r_divl) c_bits = [x.field(c.bit(i)) for i in xrange(k)] d = sum([c_bits[i]+r_bits[i]-2*c_bits[i]*r_bits[i] for i in xrange(k)]) rec = yield eqz_int(rt, d, k.bit_length()) returnValue(rec)
def random_bit(self, field): """Generate shares of a uniformly random bit over the field given. Communication cost: 1 open. """ yield declareReturn(self, field) prss_key = self.prss_key() prfs = self.players[self.id].prfs(field.modulus) a = prss(len(self.players), self.id, field, prfs, prss_key) # Open the square and compute a square-root a2 = yield self.open(Share(self, field, a**2), None, 2 * self.threshold) if a2 == 0: returnValue(self.random_bit(field)) else: returnValue((a / a2.sqrt() + 1) / 2)
def id3(T, R): yield declareReturn(tv, Zp) sizes = [tv.in_prod(T, v) for v in S[C]] max, i = int_max(sizes) sizeT = tv.sum(sizes) stop = (sizeT <= int(0.05*len(T))) + (max == sizeT) if len(R) == 0 or not(yield tv.equal_zero_public(stop)): i = (yield tv.open(i)).value print "Leaf node label ", i returnValue(int(i)) else: T_R = [[tv.schur_prod(T, v) for v in S[A]] for A in R] gains = [GI(tv.matrix_prod(T_A, S[C])) for T_A in T_R] k = (yield tv.open(frac_max(gains))).value A = list(R)[k] print "Attribute node ", A trees = yield [id3(t, R.difference([A])) for t in T_R[k]] returnValue((A, trees))
def random_unit_vector(n): yield declareReturn(tv, Zp, n) if n==1: returnValue([Zp(1)]) #base step b = tv.random_bit(Zp) # 1 SHARE x = random_unit_vector((n+1)/2) ############################## if n%2==0: y = tv.scalar_mul(b, x) # scalar-vector product b_scalar, x_vector -- N SHAMIR SHARING superPrint(["######EVEN - RECURSION DEPTH",n], b, x, y, ["SUB-VALUE:", map(operator.sub, x, y)]) returnValue(y + map(operator.sub, x, y)) #with list the + symbol is concat 0 SHARMIR ############################## elif (yield tv.equal_zero_public(b * x[0] - 1)): #a==0 just if b=0 and x[0]=0 1 OPENING - if B PALAYERS B SHARINGS superPrint(["######AGAIN - RECURSION DEPTH", n], tv.equal_zero_public(b * x[0] - 1)) returnValue(random_unit_vector(n)) #rinizia da capo ############################## else: y = tv.scalar_mul(b, x[1:]) # scalar-vector product b_scalar, x_vector -- N SHAMIR SHARING superPrint(["######OTHER - RECURSION DEPTH", n], b, x, y, ["LENGTH:", len(y), len(map(operator.sub, x[1:], y)), len(x[:1]), len(y + map(operator.sub, x[1:], y) + x[:1])]) returnValue(y + map(operator.sub, x[1:], y) + x[:1]) # 0 SHAMIR
def open(self, a, receivers=None, threshold=None): """Open a secret sharing. The *receivers* are the players that will eventually obtain the opened result. The default is to let everybody know the result. Communication cost: every player sends one share to each receiving player. """ assert isinstance(a, Share) yield declareReturn(self, a.field) # all players receive result by default if receivers is None: receivers = self.players.keys() if threshold is None: threshold = self.threshold a = yield a # Send share to all receivers. for peer_id in receivers: if peer_id != self.id: self._send_share(peer_id, a) # Receive and recombine shares if this player is a receiver. if self.id in receivers: shares = [] for peer_id in self.players: field = type(a) if peer_id == self.id: s = Share(self, field, (field(peer_id), a)) else: s = self._expect_share(peer_id, field) s.addCallback(lambda s, peer_id: (field(peer_id), s), peer_id) # s.df.addCallback(lambda s, peer_id: (field(peer_id), s), peer_id) shares.append(s) shares = yield shares[:threshold + 1] #ToDo wait for t+1 shares only. returnValue(shamir.recombine(shares))
def main(runtime): print "################\n" print(dir(runtime)) print "################\n" global tv, Zp tv = runtime k = tv.options.security_parameter l = tv.options.bit_length ln = len(tv.players).bit_length() Zp = GF(find_prime(2**(l + k + ln + 1), blum=True)) print "Galois" print Zp(0) yield declareReturn(tv, Zp) for n in xrange(10,11): a = random_derangement_3(n) #a = random_unit_vector(n) print("############################## STEP", n ,"\n") #a = random_permutation(n) a = yield map(tv.open, a) #print "finito!" print map(lambda v:int(v.value), a) #time/object - this is the function that prints the values on the terminal tv.shutdown()
def sgn(self, a, EQ=False, GE=False): Zp = a.field yield declareReturn(self, Zp) l = self.options.bit_length k = self.options.security_parameter r_bits = [self.random_bit(Zp) for _ in xrange(l)] r_modl = self.bin_comb(r_bits) r_divl = self.random_max(Zp, 2**k) a_rmodl = a + 2**l + r_modl c = yield self.open(a_rmodl + 2**l * r_divl) xors = [r_bits[i] ^ c.bit(i) for i in xrange(l)] if not EQ: s_bit = self.random_bit(Zp) s_sign = 1 - 2 * s_bit # mask: uniformly random -- should be non-zero, failure prob. 1/2^(k+l) mask = self.random(Zp) #BS mask = mask * mask + 1, assuming -1 is in NQR. E = [mask] sumXors = 0 for i in xrange(l - 1, -1, -1): E.append(s_sign + r_bits[i] - c.bit(i) + 3 * sumXors) sumXors += xors[i] E.append(s_sign - 1 + 3 * sumXors) f = yield self.open(self.prod(E)) UF = (f != 0) ^ s_bit z = (a_rmodl - (c.value % 2**l + UF * 2**l)) * ~Zp(2**l) if not GE: h = self.prod([1 - b for b in xors]) if EQ: z = h else: z = (1 - h) * (2 * z - 1) z = yield z #z = yield z returnValue(z)
def main(rt): global tv, Zp, S, C tv = rt k = tv.options.security_parameter l = tv.options.bit_length ln = len(tv.players).bit_length() Zp = GF(find_prime(2**(l + k + ln + 1), blum=True)) yield declareReturn(tv, Zp) transactions = load_file(tv.options.file + ".data") attributes = load_file(tv.options.file + ".info")[0] n = len(attributes[1:]) S = [[[Share(tv, Zp, Zp(int(t[i]==j))) for t in transactions] for j in xrange(attributes[1:][i])] for i in xrange(n)] C = attributes[0] % n T = [Share(tv, Zp, Zp(1))] * len(transactions) tree = yield id3(T, frozenset(xrange(n)).difference([C])) print "Tree = ", tree height = lambda t: max(map(height, t[1]))+1 if isinstance(t,tuple) else 0 print "Tree height = ", height(tree) size = lambda t: sum(map(size, t[1]))+1 if isinstance(t,tuple) else 1 print "Tree size = ", size(tree) tv.shutdown()
def eqz_local(rt, x, k=-1): yield declareReturn(rt, rt.Zp) xval = yield x returnValue(Share(rt, x.field, x.field(0 if xval==0 else 1)))