def collude_and_recover(num_players, reconstruction_threshold, max_secret_length, shares_subset, num_collude): ''' Args: num_players, the number of players that were shared across reconstruction_threshold, the threshold for reconstruction max_secret_length, the maximum length of the secret that was shared shares_subset, a dictionary of a subset of players to json robust shares num_corrupt, the number of players that will collude Returns: the result of robust reconstruction ''' max_secret_length = len(secret) colluders = {player: rss._deserialize_robust_share(share) for player, share in shares_subset.items()[:num_collude]} for player, player_dict in colluders.items(): player_dict["share"] /= 2 for verifier, verifier_dict in colluders.items(): new_key, new_vector = authentication.generate_check_vector(player_dict["share"], max_secret_length) verifier_dict["keys"][player] = new_key player_dict["vectors"][verifier] = new_vector # assert that these players do in fact collude for verifier, verifier_dict in colluders.items(): for player, player_dict in colluders.items(): assert authentication.validate(verifier_dict["keys"][player], player_dict["vectors"][verifier], player_dict["share"], max_secret_length) is True shares = combine_testing_dictionaries(shares_subset, jsonify_dict(colluders)) return rss.reconstruct_authenticated_secret(num_players, reconstruction_threshold, max_secret_length, shares)
def reconstruct(shares_map, secret_length, total_shares, threshold): """ Reconstruct a secret if possible from the given shares. If the shares are corrupt or the given number of shares is less than the recreation threshold, invalid data will be returned. Args: shares_map: a map of player_id to the share assigned to that player in call to share secret_length: the length of the secret that was shared total_shares: the original number of shares created threshold: the number of shares required to reconstruct the secret. Returns: If successful (secret, honest_players, dishonest_players) secret: the original bytestring that was shared by share_authenticated_secret honest_players: a non-exhaustive list of players whose shares could be used for reconstruction of that secret dishonest_players: a non-exhaustive list of dishonest players (specifically those whose shares caused structural errors) Raises: ReconstructionError: the underlying library could not reconstruct LibraryException: an exception was thrown by the supporting sharing library """ try: return rss.reconstruct_authenticated_secret(total_shares, threshold, secret_length, shares_map) except rss.FatalReconstructionFailure: logging.exception("Exception encountered during secret share reconstruction") raise exceptions.ReconstructionError
def share_and_recover(players, reconstruction_threshold, secret, end): ''' Args: players, a list of unique player ids reconstruction_threshold, the threshold needed for secret reconstruction secret, the secret to be shared end, the number of shares to use in reconstruction Returns: the result of robust reconstruction ''' max_secret_length = len(secret) shares_subset = get_shares_subset(players, reconstruction_threshold, secret, end) return rss.reconstruct_authenticated_secret(len(players), reconstruction_threshold, max_secret_length, shares_subset)
def corrupt_share_and_recover(num_players, reconstruction_threshold, max_secret_length, shares_subset, num_corrupt): ''' Args: num_players, the number of players that were shared across reconstruction_threshold, the threshold for reconstruction max_secret_length, the maximum length of the secret that was shared shares_subset, a dictionary of a subset of players to json robust shares num_corrupt, the number of players that will corrupt their shares Returns: the result of robust reconstruction ''' corrupters = {player: rss._deserialize_robust_share(share) for player, share in shares_subset.items()[:num_corrupt]} # corrupt share data for player, share_dict in corrupters.items(): share_dict["share"] /= 4 shares = combine_testing_dictionaries(shares_subset, jsonify_dict(corrupters)) return rss.reconstruct_authenticated_secret(num_players, reconstruction_threshold, max_secret_length, shares)
def test_json_parse_make_key_dict_string(): num_players = 8 reconstruction_threshold = 4 end = num_players num_broken = reconstruction_threshold - 1 players = get_ids(num_players) shares_subset = get_shares_subset(players, reconstruction_threshold, secret, end) unjsonify_shares = {player: rss._deserialize_robust_share(share) for player, share in shares_subset.items()[:num_broken]} for player, share in unjsonify_shares.items(): share["keys"] = str(share["keys"]) shares = combine_testing_dictionaries(shares_subset, jsonify_dict(unjsonify_shares)) recovered_secret, authorized_players, invalid_players = \ rss.reconstruct_authenticated_secret(num_players, reconstruction_threshold, len(secret), shares) assert verify_results(recovered_secret, secret, authorized_players, shares_subset.keys()[num_broken:], invalid_players, shares_subset.keys()[:num_broken]) is True
def test_json_bracket_parse_error(): num_players = 8 reconstruction_threshold = 4 end = num_players num_broken = reconstruction_threshold - 1 players = get_ids(num_players) shares_subset = get_shares_subset(players, reconstruction_threshold, secret, end) broken_shares = {} for player, share in shares_subset.items()[:num_broken]: broken_shares[player] = share[1:] # remove opening JSON bracket shares = combine_testing_dictionaries(shares_subset, broken_shares) recovered_secret, authorized_players, invalid_players = \ rss.reconstruct_authenticated_secret(num_players, reconstruction_threshold, len(secret), shares) assert verify_results(recovered_secret, secret, authorized_players, shares_subset.keys()[num_broken:], invalid_players, shares_subset.keys()[:num_broken]) is True
def test_json_key_error(): num_players = 8 reconstruction_threshold = 4 end = num_players num_broken = reconstruction_threshold - 1 players = get_ids(num_players) shares_subset = get_shares_subset(players, reconstruction_threshold, secret, end) broken_shares = {} for player, share in shares_subset.items()[:num_broken]: keys_index = share.index("keys") share = share[:keys_index] + "pown" + share[keys_index + len("keys"):] broken_shares[player] = share shares = combine_testing_dictionaries(shares_subset, broken_shares) recovered_secret, authorized_players, invalid_players = \ rss.reconstruct_authenticated_secret(num_players, reconstruction_threshold, len(secret), shares) assert verify_results(recovered_secret, secret, authorized_players, shares_subset.keys()[num_broken:], invalid_players, shares_subset.keys()[:num_broken]) is True
def corrupt_keys_and_recover(num_players, reconstruction_threshold, max_secret_length, shares_subset, num_corrupt, degree_of_corruption): ''' Args: num_players, the number of players that were shared across reconstruction_threshold, the threshold for reconstruction max_secret_length, the maximum length of the secret that was shared shares_subset, a dictionary of a subset of players to json robust shares num_corrupt, the number of players that will corrupt auth keys degree_of_corruption, how many of the keys each corrupting player will corrupt Returns: the result of robust reconstruction ''' corrupters = {player: rss._deserialize_robust_share(share) for player, share in shares_subset.items()[:num_corrupt]} verifiers = [player for player in shares_subset.keys()[:degree_of_corruption]] # corrupt key data for player, share_dict in corrupters.items(): for verifier in verifiers: share_dict["keys"][verifier] /= 4 shares = combine_testing_dictionaries(shares_subset, jsonify_dict(corrupters)) return rss.reconstruct_authenticated_secret(num_players, reconstruction_threshold, max_secret_length, shares)
def test_various_parse_errors(): reconstruction_threshold = 6 num_broken = reconstruction_threshold - 1 num_players = reconstruction_threshold + num_broken end = num_players players = get_ids(num_players) shares_subset = get_shares_subset(players, reconstruction_threshold, secret, end) unjsonify_shares = {player: rss._deserialize_robust_share(share) for player, share in shares_subset.items()} remove_vectors_player = players[0] remove_vectors_share = unjsonify_shares[remove_vectors_player] unjsonify_shares[remove_vectors_player]["vectors"] = {player: vector for player, vector in remove_vectors_share["vectors"].items()[:4]} remove_keys_player = players[1] remove_keys_share = unjsonify_shares[remove_keys_player] unjsonify_shares[remove_keys_player]["keys"] = {player: key for player, key in remove_keys_share["keys"].items()[:4]} make_share_string_player = players[2] unjsonify_shares[make_share_string_player]["share"] = str(unjsonify_shares[make_share_string_player]["share"]) shares = jsonify_dict(unjsonify_shares) json_parse_player = players[3] shares[json_parse_player] = shares[json_parse_player][1:] # remove starting bracket key_error_player = players[4] key_error_share = shares[key_error_player] keys_index = key_error_share.index("keys") shares[key_error_player] = key_error_share[:keys_index] + "pown" + key_error_share[keys_index + len("keys"):] recovered_secret, authorized_players, invalid_players = \ rss.reconstruct_authenticated_secret(num_players, reconstruction_threshold, len(secret), shares) dishonest_players = [remove_vectors_player, remove_keys_player, make_share_string_player, json_parse_player, key_error_player] assert verify_results(recovered_secret, secret, authorized_players, list(set(players) - set(dishonest_players)), invalid_players, dishonest_players) is True