def symbolic_moo_gen(session_label, block_label): c = Function("C", 3) p = Constant(session_label) i = Constant(block_label) a = Constant("1") pList = [ Variable(f"x{session_label}{block_label}"), Variable(f"x{session_label}{block_label}"), Variable(f"x{session_label}{block_label}") ] cList = [c(p, i, a), c(p, i, a), c(p, i, a)] return program.chaining_function(3, [0], pList, cList)
def program(): """ Webpage that walks the user through an interaction between the adversary and the oracle. """ if request.method != "POST": # If you step away from the simulation, destroy the previous session if 'uid' in session and session['uid'] in moo_sessions.keys(): del moo_sessions[session['uid']] session.pop('uid', None) return render_moo_template('program_create.html') # If a MOOProgram is already in session.... if 'uid' in session and session['uid'] in moo_sessions.keys(): uid = session['uid'] moo_session: MOOProgram = moo_sessions[uid] if 'next' in request.form: plaintext = Variable("x_" + str(moo_session.iteration)) ciphertext = moo_session.rcv_block(plaintext) response = str( ciphertext ) if ciphertext is not None else "Sent " + str(plaintext) return render_moo_template('program.html', response=response) if 'end' in request.form: ciphertext = moo_session.rcv_stop() del moo_sessions[uid] session.pop('uid', None) response = str(ciphertext) if ciphertext is not None else None if response is None: return render_moo_template('program_create.html') return render_moo_template('program.html', response=response) # If we are creating a session of a MOOProgram.... if 'chaining' in request.form and 'schedule' in request.form: # Create new session chaining_moo = request.form.get('chaining') schedule = request.form.get('schedule') moo_session = MOOProgram(chaining_moo, schedule) # Send an initial message plaintext = Variable("x_" + str(moo_session.iteration)) ciphertext = moo_session.rcv_block(plaintext) # Set up a userid and save the moo_session session['uid'] = uuid4() moo_sessions[session['uid']] = moo_session response = str( ciphertext) if ciphertext is not None else "Sent " + str(plaintext) return render_moo_template('program.html', response=response) return render_moo_template('program_create.html')
def _temporary_parser(moo_string: str) -> Term: """ A temporary parser to parse a user supplied cryptographic mode of operation. This function is limited in what it can parse. """ parser = Parser() parser.add(Function("f", 1)) parser.add(xor) parser.add(Variable("P[i]")) parser.add(Variable("C[i]")) parser.add(Variable("C[i-1]")) parser.add(Constant("r")) parser.add(Constant("P[0]")) return parser.parse(moo_string)
def test_pick_fail(): c = Function("C", 3) f = Function("f", 1) a = Constant("a") b = Constant('1') e = Constant("e") p = Constant('p') q = Constant('q') i = Constant('i') j = Constant('j') x = Variable("x") z = Zero() func = FuncTerm(f, [a]) func2 = FuncTerm(f, [e]) func_pi = FuncTerm(c, [p, i, b]) func_qj = FuncTerm(c, [q, j, b]) eq1 = Equation(func, z) eq2 = Equation(func_qj, x) eq3 = Equation(xor(func_pi, func), z) eq4 = Equation(xor(xor(func_pi, func), func2), z) topf: Set[Equation] = {eq1, eq4} print("Testing pick_fail with ", topf) new_set = pick_fail(topf, cbc_gen) print("Result: ", new_set) print() topf: Set[Equation] = {eq1, eq2, eq3} print("Testing pick_fail with ", topf) new_set = pick_fail(topf, ex4_gen) print("Result: ", new_set) print()
def test_check_xor_structure(): f = Function("f", 1) a = Constant("a") b = Constant("b") c = Constant("c") x = Variable("x") z = Zero() func = FuncTerm(f, [a]) func1 = FuncTerm(f, [b]) func2 = FuncTerm(f, [c]) func3 = FuncTerm(f, [x]) func4 = xor(func, func1) func5 = xor(func2, func3) eq1 = Equation(func, b) eq2 = Equation(func3, c) eq3 = Equation(func5, z) eq4 = Equation(xor(func2, func3), z) eq5 = Equation(xor(func4, func5), z) topf: Set[Equation] = {eq1, eq2, eq3, eq5} print("Testing pick_f with equation set: ", topf) print("Result pick_f: ", pick_f(topf)) print()
def ex4_gen(p, i): if i == 0: return Constant('r' + str(p)) else: return xor( xor(FuncTerm(f, [ex4_gen(p, i - 1)]), FuncTerm(f, [FuncTerm(f, [ex4_gen(p, i - 1)])])), Variable("x" + str(p) + str(i)))
def _satisfies_chaining(term: Term, max_history: int): """Checks to see if a preivous ciphertext is in the term.""" previous_ciphertexts = [ Variable("C[i-" + str(i + 1) + "]") for i in range(max_history) ] previous_ciphertexts_in_term = [(ci in term) for ci in previous_ciphertexts] return any(previous_ciphertexts_in_term)
def symbolic_cbc_gen(session_label, block_label): a = Constant("1") p = Constant(session_label) i = Constant(block_label) cInner = FuncTerm(c, [p, i, a]) x = Variable("xpi") return xor(FuncTerm(f, [cInner]), x)
def invert_simple(term): """ Algorithm to get the plaintext P_{i} out of a MOO. Works by moving up in the DAG from the plaintext variable Applying the reverse transformation as it moves along f -> f^{-1} xor(P, x) -> xor(P, xor(x, x)) -> P Assumptions: - Previous plaintexts aren't in the term - The plaintext is only in one position """ inverse_term = Variable("x") transforms = [] # Create a TermDAG and check to see # that the plaintext is only in one position. d = TermDAG(term) assert Counter(d.leaves())[_P] == 1 # Move up the DAG starting from the plaintext # leaf and add inverse operations to the # transforms list. current_term = deepcopy(_P) parent_term = list(d.parents(current_term)) while parent_term != []: parent_term = parent_term[0] if parent_term.function == _f: transforms.append((_finv, )) elif parent_term.function == xor: # Cancel out the xor by xoring with # the other argument again. if parent_term.arguments[0] == current_term: transforms.append((xor, parent_term.arguments[1])) else: transforms.append((xor, parent_term.arguments[0])) else: raise ValueError("A function other than f or xor detected") current_term = deepcopy(parent_term) parent_term = list(d.parents(parent_term)) # Construct inverse term for transform in reversed(transforms): if transform[0] == _finv: inverse_term = _finv(inverse_term) else: # Assume xor inverse_term = xor(inverse_term, transform[1]) return inverse_term
def test_elimf(): f = Function("f", 1) xo = Function("f", 2) z = Zero() c = Constant("c") x = Variable("x") b = Variable("b") func = FuncTerm(f, [x]) func2 = FuncTerm(f, [z]) func3 = FuncTerm(xo, [c, b]) eq1 = Equation(func, c) eq2 = Equation(xor(func, func3), z) eq3 = Equation(b, func) eq4 = Equation(func2, z) topf: Set[Equation] = {eq1, eq2, eq3, eq4} print("Testing elim_f with ", topf) new_set = elim_f(topf) print("Result ", new_set) print()
def symbolic_ex4_gen(session_label, block_label): a = Constant("1") p = Constant(session_label) i = Constant(block_label) cInner = FuncTerm(c, [p, i, a]) x = Variable("xpi") fSummandOne = FuncTerm(f, [cInner]) fSummandTwo = FuncTerm(f, [FuncTerm(f, [cInner])]) return xor(fSummandOne, fSummandTwo, x)
def test_occurs(): f = Function("f", 1) g = Function("g", 1) c = Function("C", 3) p = Constant('p') q = Constant('q') i = Constant('i') z = Variable("z") x = Variable("x") y = Variable("y") b = Variable("b") a = Variable("a") cpi = FuncTerm(c, [p, i, Constant("1")]) fcpi = FuncTerm(f, [cpi]) e1 = Equation(cpi, fcpi) e2 = Equation(x, FuncTerm(f, [g(x)])) e3 = Equation(x, FuncTerm(f, [b])) occ = {e1, e2, e3} print("Testing occurs check with ", occ) print("new set: ", occurs_check(occ)) print()
def _changeVars(overlaping_vars: List[Variable], term: Term, hypothesis: Term, conclusion: Term): """Change variable names in hypothesis & conclusion to not overlap with overlapping_vars""" hypothesis = deepcopy(hypothesis) conclusion = deepcopy(conclusion) all_vars = get_vars(term, unique=True) | \ get_vars(hypothesis, unique=True) | \ get_vars(conclusion, unique=True) new_vars: List[Variable] = [] # Go through all the variables that share the same symbol between the term and rewrite rule # and change the variables in the rewrite rule for v in overlaping_vars: new_var = v # Keep renaming variable in rewrite rule until it is not an already existing variable while new_var in all_vars: new_var = Variable(new_var.symbol + "_1", new_var.sort) new_vars.append(new_var) # Create substitution between the old and new variable names and apply them s = SubstituteTerm() for old_v, new_v in zip(overlaping_vars, new_vars): s.add(old_v, new_v) return hypothesis * s, conclusion * s
def InvertMOO(term: Term, plaintext: str, nonces: list, nonceone: Constant, knowsiv: bool): """ NOT COMPLETE Implementation of Lemma 10 from the Indocrypt paper Parameters ========== Term: The first recursive case str: The plaintext to check for bool: Is the IV known Examples ======== from symcollab.algebra import Constant, Variable from symcollab.moe.program import MOOProgram from symcollab.moe.check import moo_check from symcollab.Unification.constrained.xor_rooted_unif import XOR_rooted_security from symcollab.Unification.constrained.p_unif import p_unif result = moo_check('cipher_block_chaining', "every", p_unif, 2, True, True) print(result.invert_result) """ if nonceone in get_constants(term, unique=True): if knowsiv == False: return False #Make sure C_0 is only IV if len(nonces) == 1: plaintext = Variable(plaintext) # Make sure C_i contains p_i but only once if count_occurence(plaintext, term) == 1: return True # Passes all the criteria return False
def rcv_block(self, message: Term) -> Optional[MOOFrame]: """ The adversary gives a plaintext block to the oracle to encrypt. Depending on the schedule, the oracle might return back a MOOFrame. """ if self.stopped: raise ValueError("Session already stopped.") self.iteration += 1 self.plain_texts.append(message) # Create new cipher text variable and map it to the MOO Term new_cipher_var = Variable(f"y_{self.iteration}") encrypted_block = self.chaining_function(self.iteration, self.nonces, self.plain_texts, self.cipher_texts) self.substitutions.add(new_cipher_var, encrypted_block) self.cipher_texts.append(new_cipher_var) # If the schedule allows, return a MOO Frame if self.schedule(self.iteration): return MOOFrame(deepcopy(new_cipher_var), deepcopy(self.substitutions)) return None
def test_pick_c(): c = Function("C", 3) f = Function("f", 1) a = Constant("a") b = Constant('1') p = Constant('p') q = Constant('q') i = Constant('i') j = Constant('j') x = Variable("x") z = Zero() func = FuncTerm(f, [a]) func_pi = FuncTerm(c, [p, i, b]) func_qj = FuncTerm(c, [q, j, b]) eq1 = Equation(func, z) eq2 = Equation(func_qj, x) eq3 = Equation(xor(func_pi, func), 0) topf: Set[Equation] = {eq1, eq2, eq3} print("Testing pick_c with ", topf)
def test_elimc(): c = Function("C", 3) p = Constant('p') q = Constant('q') i = Constant('i') j = Constant('j') a = Constant('1') x = Variable("x") z = Zero() func_pi = FuncTerm(c, [p, i, a]) func_qj = FuncTerm(c, [q, j, a]) eq1 = Equation(xor(func_pi, func_qj), z) eq2 = Equation(xor(func_qj, func_pi), z) eq3 = Equation(func_pi, x) topf: Set[Equation] = {eq1, eq2, eq3} print("Testing elim_c with ", topf) new_set = elim_c(topf) print("Result: ", new_set) print() b = Constant('2') func_pi = FuncTerm(c, [p, i, a]) func_qj = FuncTerm(c, [q, j, b]) eq1 = Equation(xor(func_pi, func_qj), z) eq2 = Equation(xor(func_qj, func_pi), z) topf: Set[Equation] = {eq1, eq2} print("Testing elim_c with ", topf) new_set = elim_c(topf) print("Result: ", new_set) print()
def name_xor_terms(t, eqs): # Purify arguments # Name top-level xor-subterms # Return (renamed_term, a set of equations) if is_zero(t): return (t, eqs) elif (isinstance(t, Constant)): return (t, eqs) elif (isinstance(t, Variable)): return (t, eqs) elif (is_xor_term(t)): (term1, eqs) = purify_a_term(t.arguments[0], eqs) #eqs = eqs + equation1 (term2, eqs) = purify_a_term(t.arguments[1], eqs) #eqs = eqs + equation2 #equations = equation1 + equation2 name = look_up_a_name(xor(term1, term2), eqs) if (name != None): return (name, eqs) else: global variable_counter variable_counter += 1 new_variable = Variable("N" + str(variable_counter)) eqs.append(Equation(new_variable, xor(term1, term2))) return (new_variable, eqs) elif (isinstance(t, FuncTerm)): terms = [] for arg in t.arguments: (term, eqs) = name_xor_terms(arg, eqs) #eqs = eqs + equations terms.append(term) return (FuncTerm(t.function, terms), eqs) else: print("error") return None
#!/usr/bin/env python3 from symcollab.algebra import Function, Variable, Constant, Equation from symcollab.Unification.unif import unif # Setting up terms f = Function("f", 2) g = Function("g", 1) x = Variable("x") y = Variable("y") z = Variable("z") a = Constant("a") b = Constant("b") # applying unification #example 1: unifiable unif({Equation(f(x, y), f(a, b))}) #example 2: simple function clash unif({Equation(f(x, y), g(z))}) #example 3: function clash unif({Equation(f(x, x), f(g(y), a))}) #example 4: occurs check unif({Equation(f(x, y), f(g(x), a))}) #example 5: unifiable unif({Equation(f(z, z), f(g(f(x, y)), g(f(a, b))))})
#!/usr/bin/env python3 from symcollab.algebra import Constant, Function, Variable from symcollab.rewrite import RewriteRule a = Constant("a") b = Constant("b") c = Constant("c") x = Variable("x") y = Variable("y") f = Function("f", 2) g = Function("g", 2) r = RewriteRule(f(y, g(x, a)), g(y, a)) term = f(b, g(c, a)) print("Applying " + str(r) + " to " + str(term)) print("Result:", r.apply(term)) print("Now to show what happens when you can't apply a term...") term = f(a, b) print("Applying " + str(r) + " to " + str(term)) print("Result:", r.apply(term)) print("Applying f(x, x) -> x to f(f(x, x), f(x, x))") term = f(f(x, x), f(x, x)) r = RewriteRule(f(x, x), x) print("Result:", r.apply(term)) print("Applying f(x, x) -> x to f(f(x, x), f(x,x)) at position 2") print("Result:", r.apply(term, '2'))
def Launcher(): window = make_window() window.finalize() filename = "moo_output.txt" f_writetype = "w+" fileinfo = "" moo_session = None window_size = window.Size # event loop while True: event, values = window.read() # type: str, dict # if the window is closed leave loop immediately if event == sg.WIN_CLOSED: break #print(event, values) start, stop = 1, 6 result = [] popup = True goodInput = True function = '' '''Commenting this out because not sure if it is desired or not if event == 'Submit settings': filename = str(values[22]) + ".txt" if values[23] == 'Append': f_writetype = "a+"''' # all tool tab events if event == 'Execute!': # check all input start, stop = 1, 6 function = 'tool' for i in range(start, stop + 1): result.append(values[i]) sim_next = False # all simulation tab events if event == 'Execute!0' or event == 'Next>>': if event == 'Next>>': sim_next = True # check all input start, stop = 7, 8 function = 'simulation' for i in range(start, stop): result.append(values[i]) result.append(values[stop]) # all custom tab events if event == 'Execute!1': # check all input start, stop = 9, 14 function = 'custom' for i in range(start, stop + 1): result.append(values[i]) # all random tab events if event == 'Execute!2': #check all input start, stop = 15, 24 function = 'random' for i in range(start, stop + 1): result.append(values[i]) # check if any of the inputs are blank if all(result) is not True: sg.Popup('Input left blank, please enter a value.', title='ERROR') popup = False goodInput = False if function == 'tool' and goodInput: if valid_moo_unif_pair(result[0], result[1]) == False: goodInput = False sg.Popup( 'Invalid unfication algorithm and chaining function combination, see Help -> Tool for more information', title='ERROR') # if none of the input is blank / combinations are good #then perform tool functions and output results to window if goodInput: if function == 'tool': fileinfo += "#######################################################################################################\n" fileinfo += "Tool inputs: " + str(result) + "\n" unif = unif_dict[result[0]] chaining = cf_dict[result[1]] sched = scd_dict[result[2]] length_bound = restrict_to_range(int(result[3]), 0, 100) knows_iv = yn_tf(result[4]) invert_check = yn_tf(result[5]) # check for security and catch exceptions try: result = moo_check(chaining, sched, unif, length_bound, knows_iv, invert_check) except ValueError as v_err: message = 'ValueError: ' + str(v_err) sg.Popup(message, title='VALUE ERROR') window.close() except: print("Unexpected error:", sys.exc_info()[0]) window.close() response = get_response(result) fileinfo += "tool output:\n" + response + "\n" window['-O1-'].update(response) if function == 'simulation': fileinfo += "#######################################################################################################\n" fileinfo += "Simulation inputs: " + str(result) + "\n" chaining = cf_dict[result[0]] sched = scd_dict[result[1]] if sim_next: # continuing session if moo_session is None: window['-O2-'].update("Begin session first!") else: plaintext = Variable("x_" + str(moo_session.iteration)) ciphertext = moo_session.rcv_block(plaintext) response = str( ciphertext ) if ciphertext is not None else "Sent " + str( plaintext) fileinfo += "Next: " + response + "\n" window['-O2-'].update(response) else: # creating the session moo_session = MOOProgram(chaining, sched) plaintext = Variable("x_" + str(moo_session.iteration)) ciphertext = moo_session.rcv_block(plaintext) response = str( ciphertext ) if ciphertext is not None else "Sent " + str(plaintext) fileinfo += "Simulation begin:\n" + response + "\n" window['-O2-'].update(response) if function == 'custom': fileinfo += "#######################################################################################################\n" fileinfo += "Custom inputs: " + str(result) + "\n" chaining = CustomMOO(_temporary_parser(result[0])).name unif = unif_dict[result[1]] sched = scd_dict[result[2]] length_bound = restrict_to_range(int(result[3]), 0, 100) knows_iv = yn_tf(result[4]) invert_check = yn_tf(result[5]) try: result = moo_check(chaining, sched, unif, length_bound, knows_iv, invert_check) except ValueError as v_err: message = 'ValueError: ' + str(v_err) sg.Popup(message, title='VALUE ERROR') window.close() except: print("Unexpected error:", sys.exc_info()[0]) window.close() response = get_response(result) fileinfo += "Custom output:\n" + response + "\n" window['-O3-'].update(response) if function == 'random': fileinfo += "#######################################################################################################\n" fileinfo += "Random inputs: " + str(result) + "\n" unif = unif_dict[result[0]] sched = scd_dict[result[1]] length_bound = restrict_to_range(int(result[2]), 0, 100) f_bound = int(result[3]) moo_bound = restrict_to_range(int(result[4]), 1, 100) c_req = yn_tf(result[5]) iv_req = yn_tf(result[6]) sec_req = yn_tf(result[7]) knows_iv = yn_tf(result[8]) invert_check = yn_tf(result[9]) # generate random moos filtered_gen = FilteredMOOGenerator(1, f_bound, iv_req, c_req) moo_list = (next(filtered_gen) for i in range(moo_bound)) response = "" # Check security of the modes of operation moo_safe_list: List[Term] = list() for random_moo_term in moo_list: response += str(random_moo_term) + "\n" cm = CustomMOO(random_moo_term) moo_result = moo_check(cm.name, sched, unif, length_bound, knows_iv, invert_check) if moo_result.secure: moo_safe_list.append(random_moo_term) fileinfo += "Random output:\n" + response + "\n" window['-O4-'].update(response) # menu button events create popups # my intent with these is for this to be a place to give users more information # about how to use each part of the tool, but any of this can be removed as desired if event == 'Tool': sg.Popup('Valid unification algorithm and chaining function pairs:\n\n' 'Syntactic: Cipher Block Chaining, Propogating Cipher Block Chaining,' \ ' Hash Cipher Block Chaining, Cipher Feedback, Output Feedback\n' 'F-Rooted P-XOR: Cipher Block Chaining, Propogating Cipher Block Chaining, Hash Cipher Block Chaining\n' 'XOR-Rooted P-XOR: Cipher Feedback, Output Feedback', title='Tool usage', line_width=200) if event == 'Simulation': sg.Popup('This is a blurb about how to use the simulation page', title='Simulation usage') if event == 'Custom': sg.Popup('This is a blurb about how to use the custom page', title='Custom usage') if event == 'Random': sg.Popup('This is a blurb about how to use the random page', title='Random usage') f = open(filename, f_writetype) f.write(fileinfo) f.close() window.close()
def instantiate_a_constraint(constraint, sigma): #Instantiate a constraint using sigma #For example, if constraint is {x1: [a, b], x2: [f(x1)]}, and sigma is {x1 |-> a} #then the result is {x1: [a, b], x2: [f(a)]} new_constraints = {} for key in constraint.keys(): old_constraint = constraint[key] new_constraint = [] for o in old_constraint: new_constraint.append( ConstrainedTerm(o.term * sigma, SubstituteTerm())) new_constraints.update({key: new_constraint}) return new_constraints x1 = Variable("x1") x2 = Variable("x2") x3 = Variable("x3") x4 = Variable("x4") a = Constant("a") b = Constant("b") c = Constant("c") d = Constant("d") f = Function("f", 1) t0 = a t1 = xor(a, b) t2 = xor(b, c) t3 = f(xor(x1, c)) t4 = f(x2)
"""Definition and properties for two-arity tuple.""" from symcollab.algebra import Function, Variable from symcollab.rewrite import RewriteRule, RewriteSystem from .inductive import TheorySystem, Inductive @Inductive class Pair(TheorySystem): pair = Function("pair", 2) # Fix domain of pair to take anything Pair.pair.domain_sort = None # Variables for later rules _a = Variable("a", sort=Pair.sort) _b = Variable("b", sort=Pair.sort) fst = Function("fst", 1, domain_sort=Pair.sort) Pair.define(fst, RewriteSystem({ RewriteRule(fst(Pair.pair(_a, _b)), _a), })) lst = Function("lst", 1, domain_sort=Pair.sort) Pair.define(lst, RewriteSystem({ RewriteRule(lst(Pair.pair(_a, _b)), _b), }))
@classmethod def from_bool(cls, x: bool) -> Term: """Converts a bool to a Boolean.""" return deepcopy(Boolean.trueb if x else Boolean.falseb) @classmethod def to_bool(cls, x: Term) -> bool: """Converts a Boolean to an bool.""" if not isinstance(x, FuncTerm) or x != Boolean.trueb or x != Boolean.falseb: raise ValueError("to_bool function expects a simplified Boolean.") return x == Boolean.trueb # Variables for later rules _n = Variable("n", sort=Boolean.sort) _m = Variable("m", sort=Boolean.sort) # Negation neg = Function("neg", 1, domain_sort=Boolean.sort, range_sort=Boolean.sort) Boolean.define( neg, RewriteSystem({ RewriteRule(neg(Boolean.trueb), Boolean.falseb), RewriteRule(neg(Boolean.falseb), Boolean.trueb) }) ) # Boolean And andb = Function("andb", 2, domain_sort=Boolean.sort, range_sort=Boolean.sort) Boolean.define(
#Example of using the deducible function from symcollab.algebra import Function, Variable, Constant from symcollab.moe.invertibility import deducible x = Constant("x") f = Function("f", 2) p = Constant("p_i") deducible(f(x, p), {x}) deducible(f(x, p), {}) #example of using invertibility with MOO security check from symcollab.algebra import Constant, Variable from symcollab.moe.program import MOOProgram from symcollab.moe.check import moo_check from symcollab.Unification.constrained.xor_rooted_unif import XOR_rooted_security from symcollab.Unification.constrained.p_unif import p_unif result = moo_check('cipher_block_chaining', "every", p_unif, 2, True, True) print(result.invert_result) #example of using invertibility by itself, not how it's intended to be used #but can be done for testing from symcollab.moe.invertibility import InvertMOO from symcollab.xor import xor f = Function("f", 1) x = Variable("x") IV = Constant("IV") C1 = xor(x, IV) print("MOO Invertible?", InvertMOO(C1, "x", [IV], IV, True))
it does not simplify to a normal form of a term. Inspired by "Implementing a Propositional Logic Theorem Prover in Haskell" by Laurence Edward Day """ from symcollab.algebra import Function, Variable from symcollab.rewrite import RewriteRule, RewriteSystem from .inductive import Inductive, TheorySystem @Inductive class Prop(TheorySystem): pass A = Variable("A", sort=Prop.sort) B = Variable("B", sort=Prop.sort) C = Variable("C", sort=Prop.sort) Not = Function("not", 1, domain_sort=Prop.sort, range_sort=Prop.sort) Prop.define(Not, RewriteSystem({RewriteRule(Not(Not(A)), A)})) And = Function("and", 2, domain_sort=Prop.sort, range_sort=Prop.sort) Prop.define(And, RewriteSystem({ RewriteRule(And(A, A), A), })) Or = Function("or", 2, domain_sort=Prop.sort, range_sort=Prop.sort) Prop.define(Or, RewriteSystem({ RewriteRule(Or(A, A), A), }))
#eac_unif_ex.py from symcollab.algebra import Function, Equation, Variable from symcollab.Unification.eac_unif import eac_unif exp = Function("exp", 2) x = Variable("x") y = Variable("y") w = Variable("w") t = exp(x, y) t2 = exp(x, w) e1 = Equation(t, t2) U = set() U.add(e1) z = Variable("z") g = Function("g", 2) t3 = g(z, z) t4 = g(w, w) e2 = Equation(t3, t4) U.add(e2) eac_unif(U) u = Variable("u") v = Variable("v") t3 = exp(v, w) t4 = g(x, y) e3 = Equation(u, t3) e4 = Equation(u, t4) U = set() U.add(e3) U.add(e4) eac_unif(U)
# TODO: Capture the commutative property of addition @Inductive class Ring(TheorySystem): """ A ring is an abelian group with another binary operation that is associative, distributive over the abelian operation, and has an ientity element. """ add = Function("add", 2) mul = Function("mul", 2) negate = Function("neg", 1) zero = Constant("0") _x = Variable("x", sort=Group.sort) _y = Variable("y", sort=Group.sort) _z = Variable("z", sort=Group.sort) # TODO: Make Group.rules.rules match what the function symbols are Ring.rules = RewriteSystem(Group.rules.rules | { ## Associativity Rules # (x * y) * z → x * (y * z) RewriteRule(Ring.mul(Ring.mul(_x, _y), _z), Ring.mul(_x, Ring.mul(_y, _z))), ## Zero rules # 0 * x → 0 RewriteRule(Ring.mul(Ring.zero, _x), Ring.zero), # x * 0 → 0 RewriteRule(Ring.mul(_x, Ring.zero), Ring.zero), ## Distributivity rules # x * (y + z) → (x * y) + (x * z) RewriteRule(Ring.mul(_x, Ring.add(_y, _z)), Ring.add(Ring.mul(_x, _y), Ring.mul(_x, _z))),
#!/usr/bin/env python3 from symcollab.algebra import Function, Variable, Constant from symcollab.xor.xorhelper import * from symcollab.xor.structure import * f = Function("f", 1) x = Variable("x") y = Variable("y") z = Variable("z") x1 = Variable("x1") x2 = Variable("x2") x3 = Variable("x3") a = Constant("a") b = Constant("b") c = Constant("c") d = Constant("d") ze = Zero() t1 = xor(x, f(y), f(x1)) t2 = xor(y, f(z), f(x2)) t3 = xor(z, f(x), f(x3)) eq1 = Equation(ze, t1) eq2 = Equation(ze, t2) eq3 = Equation(ze, t3) equations = Equations([eq1, eq2, eq3]) #t1 = f(xor(x, y)) #t2 = x #eq1 = Equation(t1, t2) #equations = Equations([eq1])
#!/usr/bin/env python3 from symcollab.algebra import Constant, Function, Variable, Equation from symcollab.Unification.syntactic_ac_unification import * #Setup the variables and AC function f = Function("f", 2) x = Variable("x") y = Variable("y") z = Variable("z") a = Constant("a") b = Constant("b") x1 = Variable("x1") y1 = Variable("y1") z1 = Variable("z1") #Example 1 e = Equation(f(x, y), f(x1, y1)) U = {e} sol = synt_ac_unif(U) #For a single solution # also sol = synt_ac)unif(U, True) sol = synt_ac_unif(U, False) # For all solutions #Example 2 e = Equation(f(x, x), f(y, y)) U = {e} sol = synt_ac_unif(U) #Example 3 e2 = Equation(f(x, x), f(f(y, y), f(z, z))) U1 = {e2} sol = synt_ac_unif(U1)