def test_generate_shares() -> None: precision = 12 base = 4 x_secret = torch.Tensor([5.0]) # test with default values x_share = ShareTensor(data=x_secret) shares_from_share_tensor = MPCTensor.generate_shares(x_share, nr_parties=2) shares_from_secret = MPCTensor.generate_shares(x_secret, nr_parties=2, config=Config()) assert sum(shares_from_share_tensor).tensor == sum( shares_from_secret).tensor x_share = ShareTensor(data=x_secret, config=Config(encoder_precision=precision, encoder_base=base)) shares_from_share_tensor = MPCTensor.generate_shares(x_share, 2) shares_from_secret = MPCTensor.generate_shares( x_secret, 2, config=Config(encoder_precision=precision, encoder_base=base)) assert sum(shares_from_share_tensor).tensor == sum( shares_from_secret).tensor
def _get_triples( op_str: str, nr_parties: int, a_shape: Tuple[int], b_shape: Tuple[int] ) -> Tuple[Tuple[ShareTensor, ShareTensor, ShareTensor]]: """ The Trusted Third Party (TTP) or Crypto Provider should provide this triples Currently, the one that orchestrates the communication provides those triples. """ a_rand = torch.empty(size=a_shape, dtype=torch.long).random_( generator=ttp_generator ) a = ShareTensor(data=a_rand, encoder_precision=0) a_shares = MPCTensor.generate_shares(a, nr_parties, torch.long) b_rand = torch.empty(size=b_shape, dtype=torch.long).random_( generator=ttp_generator ) b = ShareTensor(data=b_rand, encoder_precision=0) b_shares = MPCTensor.generate_shares(b, nr_parties, torch.long) cmd = getattr(operator, op_str) c_val = cmd(a_rand, b_rand) c = ShareTensor(data=c_val, encoder_precision=0) c_shares = MPCTensor.generate_shares(c, nr_parties, torch.long) return a_shares, b_shares, c_shares
def test_generate_shares_config(get_clients) -> None: x_secret = torch.Tensor([5.0]) x_share = ShareTensor(data=x_secret) shares_from_share_tensor = MPCTensor.generate_shares(x_share, 2) shares_from_secret = MPCTensor.generate_shares( x_secret, 2, config=Config(encoder_base=2, encoder_precision=16) ) assert sum(shares_from_share_tensor) == sum(shares_from_secret)
def test_generate_shares_session(get_clients) -> None: clients = get_clients(2) session = Session(parties=clients) SessionManager.setup_mpc(session) x_secret = torch.Tensor([5.0]) x_share = ShareTensor(data=x_secret, session=session) shares_from_share_tensor = MPCTensor.generate_shares(x_share, 2) shares_from_secret = MPCTensor.generate_shares(x_secret, 2, session=session) assert sum(shares_from_share_tensor) == sum(shares_from_secret)
def test_reconstruct(get_clients) -> None: clients = get_clients(2) session = Session(parties=clients) SessionManager.setup_mpc(session) a_rand = 3 a = ShareTensor(data=a_rand, encoder_precision=0) a_shares = MPCTensor.generate_shares(a, 2, torch.long) a_shares_copy = MPCTensor.generate_shares(a_rand, 2, torch.long) x_secret = torch.Tensor([1, -2, 3.0907, -4.870]) x = MPCTensor(secret=x_secret, session=session) x = x.reconstruct() assert torch.allclose(x_secret, x)
def count_wraps_rand( nr_parties: int, shape: Tuple[int] ) -> Tuple[List[ShareTensor], List[ShareTensor]]: """Count wraps random. The Trusted Third Party (TTP) or Crypto provider should generate: - a set of shares for a random number - a set of shares for the number of wraparounds for that number Those shares are used when doing a public division, such that the end result would be the correct one. Args: nr_parties (int): Number of parties shape (Tuple[int]): The shape for the random value Returns: List[List[List[ShareTensor, ShareTensor]]: a list of instaces with the shares for a random integer value and shares for the number of wraparounds that are done when reconstructing the random value """ rand_val = torch.empty(size=shape, dtype=torch.long).random_( generator=ttp_generator ) r_shares = MPCTensor.generate_shares( secret=rand_val, nr_parties=nr_parties, tensor_type=torch.long, encoder_precision=0, ) wraps = count_wraps([share.data for share in r_shares]) theta_r_shares = MPCTensor.generate_shares( secret=wraps, nr_parties=nr_parties, tensor_type=torch.long, encoder_precision=0 ) # We are always creating only an instance primitives_sequential = [(r_shares, theta_r_shares)] primitives = list( map(list, zip(*map(lambda x: map(list, zip(*x)), primitives_sequential))) ) return primitives
def test_reconstruct(get_clients) -> None: clients = get_clients(2) session = Session(parties=clients) SessionManager.setup_mpc(session) a_rand = 3 a = ShareTensor(data=a_rand, config=Config(encoder_precision=0)) MPCTensor.generate_shares(secret=a, nr_parties=2, tensor_type=torch.long) MPCTensor.generate_shares( secret=a_rand, nr_parties=2, config=Config(), tensor_type=torch.long ) x_secret = torch.Tensor([1, -2, 3.0907, -4.870]) x = MPCTensor(secret=x_secret, session=session) x = x.reconstruct() assert np.allclose(x_secret, x)
def test_share_distribution_number_shares(get_clients, parties): parties = get_clients(parties) protocol = Falcon("semi-honest") session = Session(protocol=protocol, parties=parties) SessionManager.setup_mpc(session) shares = MPCTensor.generate_shares(100.42, len(parties)) share_ptrs = ReplicatedSharedTensor.distribute_shares(shares, session) for RSTensor in share_ptrs: assert len(RSTensor.get_shares().get()) == (len(parties) - 1)
def test_share_tensor(get_clients) -> None: assert FSS.share_class == ShareTensor session = Session(parties=get_clients(3)) SessionManager.setup_mpc(session) secret = torch.tensor([-1, 0, 1]) shares = MPCTensor.generate_shares(secret, nr_parties=3) distributed_shares = FSS.distribute_shares(shares, session=session) assert all(ispointer(share_ptr) for share_ptr in distributed_shares)
def count_wraps_rand( nr_parties: int, shape: Tuple[int] ) -> Tuple[List[ShareTensor], List[ShareTensor]]: """ The Trusted Third Party (TTP) or Crypto Provider should generate - a set of shares for a random number - a set of shares for the number of wraparounds for that number Those shares are used when doing a public division, such that the end result would be the correct one. """ rand_val = torch.empty(size=shape, dtype=torch.long).random_( generator=ttp_generator ) r = ShareTensor(data=rand_val, encoder_precision=0) r_shares = MPCTensor.generate_shares(r, nr_parties, torch.long) wraps = count_wraps([share.data for share in r_shares]) theta_r = ShareTensor(data=wraps, encoder_precision=0) theta_r_shares = MPCTensor.generate_shares(theta_r, nr_parties, torch.long) return r_shares, theta_r_shares
def _get_triples( op_str: str, nr_parties: int, a_shape: Tuple[int], b_shape: Tuple[int], **kwargs: Dict[Any, Any] ) -> List[Tuple[Tuple[ShareTensor, ShareTensor, ShareTensor]]]: """Get triples. The Trusted Third Party (TTP) or Crypto Provider should provide this triples Currently, the one that orchestrates the communication provides those triples.". Args: op_str (str): Operator string. nr_parties (int): Number of parties a_shape (Tuple[int]): Shape of a from beaver triples protocol. b_shape (Tuple[int]): Shape of b part from beaver triples protocol. kwargs: Arbitrary keyword arguments for commands. Returns: List[List[3 x List[ShareTensor, ShareTensor, ShareTensor]]]: The generated triples a,b,c for each party. """ a_rand = torch.empty(size=a_shape, dtype=torch.long).random_( generator=ttp_generator ) a_shares = MPCTensor.generate_shares( secret=a_rand, nr_parties=nr_parties, tensor_type=torch.long, encoder_precision=0, ) b_rand = torch.empty(size=b_shape, dtype=torch.long).random_( generator=ttp_generator ) b_shares = MPCTensor.generate_shares( secret=b_rand, nr_parties=nr_parties, tensor_type=torch.long, encoder_precision=0, ) if op_str == "conv2d": cmd = torch.conv2d else: cmd = getattr(operator, op_str) c_val = cmd(a_rand, b_rand, **kwargs) c_shares = MPCTensor.generate_shares( secret=c_val, nr_parties=nr_parties, tensor_type=torch.long, encoder_precision=0 ) # We are always creating an instance triple_sequential = [(a_shares, b_shares, c_shares)] """ Example -- for n_instances=2 and n_parties=2: For Beaver Triples the "res" would look like: res = [ ([a0_sh_p0, a0_sh_p1], [b0_sh_p0, b0_sh_p1], [c0_sh_p0, c0_sh_p1]), ([a1_sh_p0, a1_sh_p1], [b1_sh_p0, b1_sh_p1], [c1_sh_p0, c1_sh_p1]) ] We want to send to each party the values they should hold: primitives = [ [[a0_sh_p0, b0_sh_p0, c0_sh_p0], [a1_sh_p0, b1_sh_p0, c1_sh_p0]], # (Row 0) [[a0_sh_p1, b0_sh_p1, c0_sh_p1], [a1_sh_p1, b1_sh_p1, c1_sh_p1]] # (Row 1) ] The first party (party 0) receives Row 0 and the second party (party 1) receives Row 1 """ triple = list(map(list, zip(*map(lambda x: map(list, zip(*x)), triple_sequential)))) return triple
def _get_triples( op_str: str, nr_parties: int, a_shape: Tuple[int], b_shape: Tuple[int], session: Session, ring_size: Optional[int] = None, config: Optional[Config] = None, **kwargs: Dict[Any, Any], ) -> List[Tuple[Tuple[ShareTensor, ShareTensor, ShareTensor]]]: """Get triples. The Trusted Third Party (TTP) or Crypto Provider should provide this triples Currently, the one that orchestrates the communication provides those triples.". Args: op_str (str): Operator string. nr_parties (int): Number of parties a_shape (Tuple[int]): Shape of a from beaver triples protocol. b_shape (Tuple[int]): Shape of b part from beaver triples protocol. session (Session) : Session to generate the triples for. ring_size (int) : Ring Size of the triples to generate. config (Config) : The configuration(base,precision) of the shares to generate. kwargs: Arbitrary keyword arguments for commands. Returns: List[List[3 x List[ShareTensor, ShareTensor, ShareTensor]]]: The generated triples a,b,c for each party. Raises: ValueError: If the triples are not consistent. ValueError: If the share class is invalid. """ from sympc.protocol import Falcon config = Config(encoder_precision=0) if op_str in ["conv2d", "conv_transpose2d"]: cmd = getattr(torch, op_str) else: cmd = getattr(operator, op_str) if session.protocol.share_class == ShareTensor: a_rand = torch.empty(size=a_shape, dtype=torch.long).random_(generator=ttp_generator) a_shares = MPCTensor.generate_shares( secret=a_rand, nr_parties=nr_parties, tensor_type=torch.long, config=config, ) b_rand = torch.empty(size=b_shape, dtype=torch.long).random_(generator=ttp_generator) b_shares = MPCTensor.generate_shares( secret=b_rand, nr_parties=nr_parties, tensor_type=torch.long, config=config, ) c_val = cmd(a_rand, b_rand, **kwargs) c_shares = MPCTensor.generate_shares(secret=c_val, nr_parties=nr_parties, tensor_type=torch.long, config=config) elif session.protocol.share_class == ReplicatedSharedTensor: if ring_size is None: ring_size = session.ring_size if config is None: config = session.config a_ptrs: List = [] b_ptrs: List = [] for session_ptr in session.session_ptrs: a_ptrs.append( session_ptr.prrs_generate_random_share(a_shape, str(ring_size))) b_ptrs.append( session_ptr.prrs_generate_random_share(b_shape, str(ring_size))) a = MPCTensor(shares=a_ptrs, session=session, shape=a_shape) b = MPCTensor(shares=b_ptrs, session=session, shape=b_shape) c = Falcon.mul_semi_honest(a, b, session, op_str, ring_size, config, reshare=True, **kwargs) a_shares = [share.get_copy() for share in a.share_ptrs] b_shares = [share.get_copy() for share in b.share_ptrs] c_shares = [share.get_copy() for share in c.share_ptrs] shares_sum = ReplicatedSharedTensor.shares_sum a_val = shares_sum([a_shares[0].shares[0]] + a_shares[1].shares, ring_size) b_val = shares_sum([b_shares[0].shares[0]] + b_shares[1].shares, ring_size) c_val = shares_sum([c_shares[0].shares[0]] + c_shares[1].shares, ring_size) op = ReplicatedSharedTensor.get_op(ring_size, op_str) if (c_val != op(a_val, b_val)).all(): raise ValueError("Computation aborted:Invalid Triples") else: raise ValueError("Invalid share class.") # We are always creating an instance triple_sequential = [(a_shares, b_shares, c_shares)] """ Example -- for n_instances=2 and n_parties=2: For Beaver Triples the "res" would look like: res = [ ([a0_sh_p0, a0_sh_p1], [b0_sh_p0, b0_sh_p1], [c0_sh_p0, c0_sh_p1]), ([a1_sh_p0, a1_sh_p1], [b1_sh_p0, b1_sh_p1], [c1_sh_p0, c1_sh_p1]) ] We want to send to each party the values they should hold: primitives = [ [[a0_sh_p0, b0_sh_p0, c0_sh_p0], [a1_sh_p0, b1_sh_p0, c1_sh_p0]], # (Row 0) [[a0_sh_p1, b0_sh_p1, c0_sh_p1], [a1_sh_p1, b1_sh_p1, c1_sh_p1]] # (Row 1) ] The first party (party 0) receives Row 0 and the second party (party 1) receives Row 1 """ triple = list( map(list, zip(*map(lambda x: map(list, zip(*x)), triple_sequential)))) return triple