def create_leakage_automaton(automaton, observer=0, secret=0): """Gets the leakage automaton with respect to a certain observer and secret. Parameters ---------- automaton : dict The automaton to use for creating the leakage automaton observer : int The index of the agent which is observing another agent secret : int The index of the agent's secret we want to consider Returns ------- dict The leakage automaton """ det = determinize(automaton, observer) # We don't want to worry about this agent's marked states; only every other # agent's marked states. marked = det["states"]["marked"] for i in [x for x in range(len(marked)) if x != secret]: marked[i] = [] # We're only considering a specific secret! acc = get_coaccessible(det) return union([automaton, acc])
def check_modular_opacity(automata, heuristic = no_heuristic): """Verifies current state opacity for the modular system composed of the input automata. Assumes that the shared alphabet of the automata is a subset of the attacker's alphabet, and the attacker's alphabet is defined by the second (i.e., index 1, when zero indexed) observable alphabet. Only one set of secrets (i.e., marked states) will be checked (the 0th set). Parameters ---------- automata : list The automata for which to check for opacity Returns ------- bool Whether the set of modules is opaque """ automata = [determinize(x, 1) for x in automata] verified = [] unverified = automata.copy() for a in automata: if a in unverified: unverified.remove(a) # Keep a list of all automata we can use to append to current one automata_to_add = heuristic(a, unverified, verified) verified.append(a) # Keep track of the large automaton we're building curr = a # Keep going until it's opaque while check_opacity_already_determinized(curr)[0] == False: if len(automata_to_add) == 0: return False next = automata_to_add.pop(0) if next in unverified: verified.append(next) unverified.remove(next) curr = union([curr, next]) return True
def test_determinize(self): """ This ensures that all pre-built test cases work. """ for i in range(len(self.automata)): # Get the answer ans = None with open(self.filenames[i][:-2] + "out") as f: ans = json.load(f) # Get the determinization of the appropriate automaton result = determinize(self.automata[i]) # Print # helper.pretty_print(result) # helper.pretty_print(ans) # Check answer, making sure it's OK if elements not in order self.assertEqual(converter.convert_to_sets(result), converter.convert_to_sets(ans))
def check_opacity(automaton, observer=0): """Verifies current state opacity for the given automaton with respect to a certain agent's observability. That is, if every word leading to a bad state has another word with the same projection leading to a good state, the automaton is opaque. Parameters ---------- automaton : dict The automaton for which to check for opacity observer : int The index of the observer which is examining the system Returns ------- list of bool Whether or not the automaton is opaque with respect to each set of secrets. If true, indicates that opacity holds with respect to those secrets """ det = determinize(automaton, observer) return [len(m) == 0 for m in det["states"]["marked"]]
def construct_arena(automaton): """Constructs an arena from an automaton, as specified in (Ricker, Marchand, & Keroglou, 2019). The arena has the same form as a regular automaton, except with a few extra features. The "states" section has two extra lists: "v1" and "v2", which correspond to the two distinct types of states. The "transitions" section has two extra lists as well: "v1" and "v2", which are the two transition lists that exit out of the two sets of states, respectively. Note ---- Any data on bad states or transitions will be not be included in the resulting automaton. Also, the automaton must have three entries in marked, observable, and controllable. The first is the controller's perspective, the second is the first agent's perspective, and the third is the second agent's perspective. Note that the two agents' events should be subsets of the controller's event set. TODO: add a verifier to ensure correct input. Parameters ---------- automaton : dict The automaton for which to create an arena Returns ------- dict The resulting arena Examples -------- >>> arena = construct_arena(automaton) >>> print(arena) { # Dictionary for the arena with the added features specified above } """ # Get the three observers all_events = automaton["events"]["all"] obs_events = automaton["events"]["observable"] all_automata = [ determinize(automaton, i) for i in range(len(obs_events)) ] all_automata.insert(0, automaton) bad_states = [] # Get initial state. Since we determinized, each will only have one element. initial = [a["states"]["initial"][0] for a in all_automata] initial_str = format_state(initial) new_events = set() v1_trans = {} v2_trans = {} # Add initial state to a visited set and a queue v1_queue = [initial] v1_visited = {initial_str} v2_visited = set() # Keep track of secrets secrets = {} # Keep going through our queue of controller states until done while len(v1_queue) > 0: curr = v1_queue.pop(0) curr_str = format_state(curr) # Check if we have a bad state marked_obs = check_marked_agents(all_automata, curr) if len(marked_obs) != 0: bad_states.append(curr_str) secrets[curr_str] = format_all_observed_secrets(marked_obs) # Identify what events are accessible from here events = get_valid_control_actions(all_automata[0], curr[0], all_events) for event in events: # Add this event to the system event_str = format_state_set(event) new_events.add(event_str) # Add the transition from v1 to the state in v2 trans = format_transition(curr_str, event_str) curr_v2_str = format_state([curr_str, event_str]) v1_trans[trans] = [curr_v2_str] # If we haven't already visited this v2 state, start working on it! if curr_v2_str not in v2_visited: v2_visited.add(curr_v2_str) add_v2_transitions(all_automata, curr, event, v2_trans, v2_visited, v1_visited, v1_queue) # The language includes both the new event types we added and the events # already visible to the controller all_events = list(new_events.union(set(automaton["events"]["all"]))) obs_events = list(new_events.union(set(obs_events[0]))) return { "events": { "all": all_events, # The events start off identical "controllable": [list(new_events)], # In arena, control just new "observable": [obs_events] }, "states": { "all": list(v1_visited.union(v2_visited)), "v1": list(v1_visited), "v2": list(v2_visited), "initial": [initial_str], "marked": [bad_states], "bad": bad_states, "secrets": secrets # Indicates which agent sees what in composition }, "transitions": { "all": {**v1_trans, **v2_trans}, "v1": v1_trans, "v2": v2_trans, "bad": {} } }
def ops_menu(automata, temp_dir): """Opens a menu with options for different operations that can be performed. Parameters ---------- automata : list The list of automata currently open in the program temp_dir : str The temporary directory for the session Returns ------- None """ display_menu(menu_msg) inpt = input().lower() # Choose which operation to perform if inpt in ["d", "determinization"]: selected = select_automaton_menu(automata, "Determinization") if selected is not None: observer = select_observer_menu(selected) if observer is not None: result = determinize(selected, observer) __save(automata, result, temp_dir) elif inpt in ["o", "opacity"]: selected = select_automaton_menu(automata, "Checking Opacity") if selected is not None: observer = select_observer_menu(selected) if observer is not None: result = check_opacity(selected, observer) print("With respect to the observer " + str(observer) + ", the system is opaque") print("for the following secrets:") print([i for i, x in enumerate(result) if x is True]) print("The system is not opaque for the following secrets:") print([i for i, x in enumerate(result) if x is False]) elif inpt in ["u", "union", "parallel composition"]: selected = select_automata_menu(automata, 2, "Parallel Composition") if selected is not None: result = union(selected) __save(automata, result, temp_dir) elif inpt in ["p", "product", "intersection"]: selected = select_automata_menu(automata, 2, "Intersection") if selected is not None: result = product(selected) __save(automata, result, temp_dir) elif inpt in ["a", "accessible"]: selected = select_automaton_menu(automata, "Accessibility Operation") if selected is not None: result = get_accessible(selected) __save(automata, result, temp_dir) elif inpt in ["c", "controllable"]: selected = select_automaton_menu(automata, "Controllability Operation") if selected is not None: result = get_controllable(selected) __save(automata, result, temp_dir) elif inpt in ["ca", "coaccessible"]: selected = select_automaton_menu(automata, "Coaccessibility Operation") if selected is not None: result = get_coaccessible(selected) __save(automata, result, temp_dir) elif inpt in ["l", "leakage"]: selected = select_automaton_menu(automata, "Get Leakage Automaton") if selected is not None: observer = select_observer_menu(selected) if observer is not None: secret = select_secret_menu(selected) if secret is not None: result = create_leakage_automaton(selected, observer, secret) __save(automata, result, temp_dir) elif inpt in ["ba"]: selected = select_automaton_menu(automata, "Constructing Arena") if selected is not None: result = construct_arena(selected) __save(automata, result, temp_dir) show_notification("Bad states:\n" + str(result["states"]["bad"])) elif inpt in ["bt"]: selected = select_automaton_menu(automata, "Constructing Attractor") if selected is not None: result = construct_attractor(selected) __save(automata, result, temp_dir) show_notification("Bad states:\n" + str(result["states"]["bad"])) elif inpt in ["bp"]: selected = select_automaton_menu(automata, "Pruning Arena") if selected is not None: result = get_controllable(construct_attractor(selected)) __save(automata, result, temp_dir) elif inpt in ["om"]: show_notification( "With this operation, we assume the\nattacker can see all items in the\nshared alphabet,as per Enforcing\nOpacity in Modular Systems (2020)" ) selected = select_automata_menu( automata, 1, "Checking Opacity for Modular Systems") if selected is not None: heuristic = select_heuristic() result = check_modular_opacity(selected, heuristic=heuristic) show_notification("The modular system is " + ("opaque" if result else "not opaque")) elif inpt in ["bca"]: selected = select_automaton_menu(automata, "Constructing Communication Arena") if selected is not None: result = construct_communication_arena(selected) __save(automata, result, temp_dir) elif inpt in ["e", "exit"]: pass else: show_error("Command not recognized")