def __init__(self, name: str, first: MathExpr, last: MathExpr, size: MathExpr) -> None: first_num = first.simplified() if not isinstance(first_num, Number): raise ModelError(f'first of "{name}" contains variable') last_num = last.simplified() if not isinstance(last_num, Number): raise ModelError(f'last of "{name}" contains variable') if first_num < Number(0): raise ModelError(f'first of "{name}" negative') if first_num > last_num: raise ModelError(f'range of "{name}" negative') size_num = size.simplified() if not isinstance(size_num, Number): raise ModelError(f'size of "{name}" contains variable') if log(int(last_num) + 1) / log(2) > int(size_num): raise ModelError(f'size for "{name}" too small') super().__init__(name) self.__first = first self.__last = last self.__size = size constraints: LogExpr = TRUE if self.first.simplified() != self.base_first.simplified(): constraints = GreaterEqual(Value(self.name), self.first) if self.last.simplified() != self.base_last.simplified(): constraints = And(constraints, LessEqual(Value(self.name), self.last)) self.__constraints = constraints.simplified()
def test_prefixed_message() -> None: assert_equal( UnprovenMessage( "P.M", [ Link(INITIAL, Field("F1")), Link( Field("F1"), Field("F2"), LessEqual(Variable("F1"), Number(100)), first=First("F1"), ), Link( Field("F1"), Field("F3"), GreaterEqual(Variable("F1"), Number(200)), first=First("F1"), ), Link(Field("F2"), FINAL), Link(Field("F3"), Field("F4"), length=Variable("F3")), Link(Field("F4"), FINAL), ], { Field("F1"): deepcopy(MODULAR_INTEGER), Field("F2"): deepcopy(MODULAR_INTEGER), Field("F3"): deepcopy(RANGE_INTEGER), Field("F4"): Opaque(), }, ).prefixed("X_"), UnprovenMessage( "P.M", [ Link(INITIAL, Field("X_F1")), Link( Field("X_F1"), Field("X_F2"), LessEqual(Variable("X_F1"), Number(100)), first=First("X_F1"), ), Link( Field("X_F1"), Field("X_F3"), GreaterEqual(Variable("X_F1"), Number(200)), first=First("X_F1"), ), Link(Field("X_F2"), FINAL), Link(Field("X_F3"), Field("X_F4"), length=Variable("X_F3")), Link(Field("X_F4"), FINAL), ], { Field("X_F1"): deepcopy(MODULAR_INTEGER), Field("X_F2"): deepcopy(MODULAR_INTEGER), Field("X_F3"): deepcopy(RANGE_INTEGER), Field("X_F4"): Opaque(), }, ), )
def test_merge_message_recursive() -> None: assert_equal( deepcopy(M_DBL_REF).merged(), UnprovenMessage( "P.Dbl_Ref", [ Link(INITIAL, Field("SR_NR_F1"), length=Number(16)), Link( Field("SR_NR_F3"), Field("NR_F1"), Equal(Variable("SR_NR_F3"), Variable("P.ONE")), length=Number(16), ), Link(Field("SR_NR_F4"), Field("NR_F1"), length=Number(16)), Link(Field("NR_F3"), FINAL, Equal(Variable("NR_F3"), Variable("P.ONE"))), Link(Field("NR_F4"), FINAL), Link(Field("SR_NR_F1"), Field("SR_NR_F2")), Link( Field("SR_NR_F2"), Field("SR_NR_F3"), LessEqual(Variable("SR_NR_F2"), Number(100)), first=First("SR_NR_F2"), ), Link( Field("SR_NR_F2"), Field("SR_NR_F4"), GreaterEqual(Variable("SR_NR_F2"), Number(200)), first=First("SR_NR_F2"), ), Link(Field("NR_F1"), Field("NR_F2")), Link( Field("NR_F2"), Field("NR_F3"), LessEqual(Variable("NR_F2"), Number(100)), first=First("NR_F2"), ), Link( Field("NR_F2"), Field("NR_F4"), GreaterEqual(Variable("NR_F2"), Number(200)), first=First("NR_F2"), ), ], { Field("SR_NR_F1"): Opaque(), Field("SR_NR_F2"): deepcopy(MODULAR_INTEGER), Field("SR_NR_F3"): deepcopy(ENUMERATION), Field("SR_NR_F4"): deepcopy(RANGE_INTEGER), Field("NR_F1"): Opaque(), Field("NR_F2"): deepcopy(MODULAR_INTEGER), Field("NR_F3"): deepcopy(ENUMERATION), Field("NR_F4"): deepcopy(RANGE_INTEGER), }, ), )
def constraints(self, name: str, proof: bool = False) -> Expr: if proof: return And( GreaterEqual(Variable(name), self.first), LessEqual(Variable(name), self.last) ) c: Expr = TRUE if self.first.simplified() != self.base_first.simplified(): c = GreaterEqual(Variable(name), self.first) if self.last.simplified() != self.base_last.simplified(): c = And(c, LessEqual(Variable(name), self.last)) return c.simplified()
def __link_expression(self, link: Link) -> Expr: name = link.target.name return And( *[ Equal(First(name), self.__target_first(link)), Equal(Length(name), self.__target_length(link)), Equal(Last(name), self.__target_last(link)), GreaterEqual(First("Message"), Number(0)), GreaterEqual(Last("Message"), Last(name)), GreaterEqual(Last("Message"), First("Message")), Equal(Length("Message"), Add(Sub(Last("Message"), First("Message")), Number(1))), link.condition, ] )
def test_message_field_condition(self) -> None: self.assertEqual(ETHERNET_FRAME.field_condition(INITIAL), TRUE) self.assertEqual( ETHERNET_FRAME.field_condition(Field("TPID")), Equal(Variable("Type_Length_TPID"), Number(33024, 16)), ) self.assertEqual( ETHERNET_FRAME.field_condition(Field("Type_Length")), Or( NotEqual(Variable("Type_Length_TPID"), Number(33024, 16)), Equal(Variable("Type_Length_TPID"), Number(33024, 16)), ), ) self.assertEqual( ETHERNET_FRAME.field_condition(Field("Payload")), Or( And( Or( NotEqual(Variable("Type_Length_TPID"), Number(33024, 16)), Equal(Variable("Type_Length_TPID"), Number(33024, 16)), ), LessEqual(Variable("Type_Length"), Number(1500)), ), And( Or( NotEqual(Variable("Type_Length_TPID"), Number(33024, 16)), Equal(Variable("Type_Length_TPID"), Number(33024, 16)), ), GreaterEqual(Variable("Type_Length"), Number(1536)), ), ), )
def test_message_incoming(self) -> None: self.assertEqual(ETHERNET_FRAME.incoming(INITIAL), []) self.assertEqual( ETHERNET_FRAME.incoming(Field("Type_Length")), [ Link( Field("Type_Length_TPID"), Field("Type_Length"), NotEqual(Variable("Type_Length_TPID"), Number(0x8100, 16)), first=First("Type_Length_TPID"), ), Link(Field("TCI"), Field("Type_Length")), ], ) self.assertEqual( ETHERNET_FRAME.incoming(FINAL), [ Link( Field("Payload"), FINAL, And( GreaterEqual(Div(Length("Payload"), Number(8)), Number(46)), LessEqual(Div(Length("Payload"), Number(8)), Number(1500)), ), ) ], )
def public_context_predicate() -> Expr: return And( GreaterEqual(Call(const.TYPES_BYTE_INDEX, [Variable("First")]), Variable("Buffer_First")), LessEqual(Call(const.TYPES_BYTE_INDEX, [Variable("Last")]), Variable("Buffer_Last")), LessEqual(Variable("First"), Variable("Last")), LessEqual(Variable("Last"), Div(Last(const.TYPES_BIT_INDEX), Number(2))), )
def test_merge_message_simple_derived() -> None: assert_equal( deepcopy(M_SMPL_REF_DERI).merged(), UnprovenDerivedMessage( "P.Smpl_Ref_Deri", M_SMPL_REF, [ Link(INITIAL, Field("NR_F1"), length=Number(16)), Link(Field("NR_F3"), FINAL, Equal(Variable("NR_F3"), Variable("P.ONE"))), Link(Field("NR_F4"), FINAL), Link(Field("NR_F1"), Field("NR_F2")), Link( Field("NR_F2"), Field("NR_F3"), LessEqual(Variable("NR_F2"), Number(100)), first=First("NR_F2"), ), Link( Field("NR_F2"), Field("NR_F4"), GreaterEqual(Variable("NR_F2"), Number(200)), first=First("NR_F2"), ), ], { Field("NR_F1"): Opaque(), Field("NR_F2"): deepcopy(MODULAR_INTEGER), Field("NR_F3"): deepcopy(ENUMERATION), Field("NR_F4"): deepcopy(RANGE_INTEGER), }, ), )
def __prove_coverage(self) -> None: """ Prove that the fields of a message cover all message bits, i.e. there are no holes in the message definition. Idea: Let f be the bits covered by the message. By definition (1) f >= Message'First and f <= Message'Last holds. For every field add a conjunction of the form (2) Not(f >= Field'First and f <= Field'Last), effectively pruning the range that this field covers from the bit range of the message. For the overall expression, prove that it is false for all f, i.e. no bits are left. """ for path in [p[:-1] for p in self.__paths[FINAL] if p]: # Calculate (1) message_range = And( GreaterEqual(Variable("f"), First("Message")), LessEqual(Variable("f"), Last("Message")), ) # Calculate (2) for all fields fields = And( *[ Not( And( GreaterEqual(Variable("f"), self.__target_first(l)), LessEqual(Variable("f"), self.__target_last(l)), ) ) for l in path ] ) # Define that the end of the last field of a path is the end of the message last_field = Equal(self.__target_last(path[-1]), Last("Message")) # Constraints for links and types path_expressions = self.__with_constraints( And(*[self.__link_expression(l) for l in path]) ) # Coverage expression must be False, i.e. no bits left coverage = Not(And(*[fields, last_field, path_expressions, message_range])) result = coverage.forall() if result != ProofResult.sat: path_message = " -> ".join([l.target.name for l in path]) message = str(coverage).replace("\n\t", "") raise ModelError( f"path {path_message} does not cover whole message" f' in "{self.full_name}" ({result}: {message})' )
def __prove_field_positions(self) -> None: for f in self.__fields: for p, l in [(p, p[-1]) for p in self.__paths[f] if p]: path_expressions = And(*[self.__link_expression(l) for l in p]) length = self.__target_length(l) positive = If( [ ( And( self.__type_constraints(And(path_expressions, length)), path_expressions, ), GreaterEqual(length, Number(0)), ) ], TRUE, ) result = positive.forall() if result != ProofResult.sat: path_message = " -> ".join([l.target.name for l in p]) message = str(positive.simplified()).replace("\n\t", "") raise ModelError( f'negative length for field "{f.name}" on path {path_message}' f' in "{self.full_name}" ({result}: {message})' ) first = self.__target_first(l) start = If( [ ( And( self.__type_constraints(And(path_expressions, first)), path_expressions, ), GreaterEqual(first, First("Message")), ) ], TRUE, ) result = start.forall() if result != ProofResult.sat: path_message = " -> ".join([l.target.name for l in p]) message = str(start.simplified()).replace("\n\t", "") raise ModelError( f'start of field "{f.name}" on path {path_message} before' f' message start in "{self.full_name} ({result}: {message})' )
def bounded_composite_setter_preconditions(message: Message, field: Field) -> Sequence[Expr]: return [ Call( "Field_Condition", [ Variable("Ctx"), NamedAggregate(("Fld", Variable(field.affixed_name))) ] + ([Variable("Length")] if common.length_dependent_condition(message) else []), ), GreaterEqual( Call("Available_Space", [Variable("Ctx"), Variable(field.affixed_name)]), Variable("Length"), ), LessEqual( Add( Call("Field_First", [Variable("Ctx"), Variable(field.affixed_name)]), Variable("Length"), ), Div(Last(const.TYPES_BIT_INDEX), Number(2)), ), Or(*[ And( *[ Call("Valid", [Variable("Ctx"), Variable(field.affixed_name)]) for field in message.fields if Variable(field.name) in l.condition.variables() ], l.condition.substituted( mapping={ Variable(field.name): Call(f"Get_{field.name}", [Variable("Ctx")]) for field in message.fields if Variable(field.name) in l.condition.variables() }), ) for l in message.incoming(field) if Last("Message") in l.length ]), Equal( Mod( Call("Field_First", [Variable("Ctx"), Variable(field.affixed_name)]), Size(const.TYPES_BYTE), ), Number(1), ), Equal( Mod(Variable("Length"), Size(const.TYPES_BYTE)), Number(0), ), ]
def buffer_constraints(last: MathExpr) -> LogExpr: last = last.simplified() index_constraint = LessEqual(First('Buffer'), Div(Last('Types.Index_Type'), Number(2))) if last != Last('Buffer'): length_constraint = GreaterEqual( Length('Buffer'), Add(last, -First('Buffer'), Number(1))) return And(length_constraint, index_constraint) return index_constraint
def parse_relation(string: str, location: int, tokens: list) -> Relation: if tokens[1] == '<': return Less(tokens[0], tokens[2]) if tokens[1] == '<=': return LessEqual(tokens[0], tokens[2]) if tokens[1] == '=': return Equal(tokens[0], tokens[2]) if tokens[1] == '>=': return GreaterEqual(tokens[0], tokens[2]) if tokens[1] == '>': return Greater(tokens[0], tokens[2]) if tokens[1] == '/=': return NotEqual(tokens[0], tokens[2]) raise ParseFatalException(string, location, 'unexpected relation operator')
def create_ethernet_pdu() -> PDU: uint48 = ModularInteger('UINT48', Pow(Number(2), Number(48))) uint16 = RangeInteger('UINT16', Number(0), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16)) payload_array = Array('Payload_Array') initial = InitialNode() destination = Node('Destination', uint48) source = Node('Source', uint48) tpid = Node('TPID', uint16) tci = Node('TCI', uint16) ether_type = Node('EtherType', uint16) payload = Node('Payload', payload_array) initial.edges = [Edge(destination)] destination.edges = [Edge(source)] source.edges = [Edge(tpid)] tpid.edges = [Edge(tci, Equal(Value('TPID'), Number(0x8100))), Edge(ether_type, NotEqual(Value('TPID'), Number(0x8100)), first=First('TPID'))] tci.edges = [Edge(ether_type)] ether_type.edges = [Edge(payload, LessEqual(Value('EtherType'), Number(1500)), Mul(LengthValue('EtherType'), Number(8))), Edge(payload, GreaterEqual(Value('EtherType'), Number(1536)), Sub(Last('Message'), Last('EtherType')))] payload.edges = [Edge(FINAL, And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))))] return PDU('Ethernet.Frame', initial)
def parse_relation(string: str, location: int, tokens: ParseResults) -> Relation: if tokens[1] == "<": return Less(tokens[0], tokens[2]) if tokens[1] == "<=": return LessEqual(tokens[0], tokens[2]) if tokens[1] == "=": return Equal(tokens[0], tokens[2]) if tokens[1] == ">=": return GreaterEqual(tokens[0], tokens[2]) if tokens[1] == ">": return Greater(tokens[0], tokens[2]) if tokens[1] == "/=": return NotEqual(tokens[0], tokens[2]) raise ParseFatalException(string, location, "unexpected relation operator")
def parse_relation(string: str, location: int, tokens: ParseResults) -> Relation: def locn() -> Location: return Location(tokens[0].location.start, tokens[0].location.source, tokens[2].location.end) if tokens[1] == "<": return Less(tokens[0], tokens[2], locn()) if tokens[1] == "<=": return LessEqual(tokens[0], tokens[2], locn()) if tokens[1] == "=": return Equal(tokens[0], tokens[2], locn()) if tokens[1] == ">=": return GreaterEqual(tokens[0], tokens[2], locn()) if tokens[1] == ">": return Greater(tokens[0], tokens[2], locn()) if tokens[1] == "/=": return NotEqual(tokens[0], tokens[2], locn()) raise ParseFatalException(string, location, "unexpected relation operator")
def bounded_composite_setter_preconditions( self, message: Message, field: Field ) -> Sequence[Expr]: return [ Call( "Field_Condition", [Name("Ctx"), NamedAggregate(("Fld", Name(field.affixed_name)))] + ([Name("Length")] if length_dependent_condition(message) else []), ), GreaterEqual( Call("Available_Space", [Name("Ctx"), Name(field.affixed_name)]), Name("Length"), ), LessEqual( Add(Call("Field_First", [Name("Ctx"), Name(field.affixed_name)]), Name("Length"),), Div(Last(self.types.bit_index), Number(2)), ), Or( *[ And( *[ Call("Valid", [Name("Ctx"), Name(field.affixed_name)]) for field in message.fields if Variable(field.name) in l.condition.variables() ], l.condition.simplified( { Variable(field.name): Call(f"Get_{field.name}", [Name("Ctx")]) for field in message.fields if Variable(field.name) in l.condition.variables() } ), ) for l in message.incoming(field) if Last("Message") in l.length ] ), ]
def test_pdu_fields_ethernet(self) -> None: expected = OrderedDict([ ('Destination', Field('Destination', ModularInteger('UINT48', Pow(Number(2), Number(48))), TRUE, { '0': Variant( [], TRUE, { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47) }) })), ('Source', Field('Source', ModularInteger('UINT48', Pow(Number(2), Number(48))), TRUE, { '00': Variant( [ ('Destination', '0') ], TRUE, { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95) }) })), ('TPID', Field('TPID', RangeInteger('UINT16', Number(0), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16)), Or(NotEqual(Value('TPID'), Number(0x8100)), Equal(Value('TPID'), Number(0x8100))), { '000': Variant( [ ('Destination', '0'), ('Source', '00') ], TRUE, { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111) }) })), ('TCI', Field('TCI', RangeInteger('UINT16', Number(0), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16)), TRUE, { '0000': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000') ], Equal(Value('TPID'), Number(0x8100)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127) }) })), ('EtherType', Field('EtherType', RangeInteger('UINT16', Number(0), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16)), Or(GreaterEqual(Value('EtherType'), Number(1536)), LessEqual(Value('EtherType'), Number(1500))), { '00000': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('TCI', '0000') ], TRUE, { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127), Length('EtherType'): Number(16), First('EtherType'): Number(128), Last('EtherType'): Number(143) }), '0001': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000') ], NotEqual(Value('TPID'), Number(0x8100)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('EtherType'): Number(16), First('EtherType'): Number(96), Last('EtherType'): Number(111) }) })), ('Payload', Field('Payload', Array('Payload_Array'), And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))), { '000000': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('TCI', '0000'), ('EtherType', '00000') ], LessEqual(Value('EtherType'), Number(1500)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127), Length('EtherType'): Number(16), First('EtherType'): Number(128), Last('EtherType'): Number(143), Length('Payload'): Mul(LengthValue('EtherType'), Number(8)), First('Payload'): Number(144), Last('Payload'): Add(Mul(LengthValue('EtherType'), Number(8)), Number(143)) }), '000001': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('TCI', '0000'), ('EtherType', '00000') ], GreaterEqual(Value('EtherType'), Number(1536)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127), Length('EtherType'): Number(16), First('EtherType'): Number(128), Last('EtherType'): Number(143), Length('Payload'): Add(Last('Message'), Number(-143)), First('Payload'): Number(144), Last('Payload'): Last('Message') }), '00010': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('EtherType', '0001') ], LessEqual(Value('EtherType'), Number(1500)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('EtherType'): Number(16), First('EtherType'): Number(96), Last('EtherType'): Number(111), Length('Payload'): Mul(LengthValue('EtherType'), Number(8)), First('Payload'): Number(112), Last('Payload'): Add(Mul(LengthValue('EtherType'), Number(8)), Number(111)) }), '00011': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('EtherType', '0001') ], GreaterEqual(Value('EtherType'), Number(1536)), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('EtherType'): Number(16), First('EtherType'): Number(96), Last('EtherType'): Number(111), Length('Payload'): Add(Last('Message'), Number(-111)), First('Payload'): Number(112), Last('Payload'): Last('Message') }) })), ('FINAL', Field('FINAL', Null(), TRUE, { '0000000': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('TCI', '0000'), ('EtherType', '00000'), ('Payload', '000000') ], And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127), Length('EtherType'): Number(16), First('EtherType'): Number(128), Last('EtherType'): Number(143), Length('Payload'): Mul(LengthValue('EtherType'), Number(8)), First('Payload'): Number(144), Last('Payload'): Add(Mul(LengthValue('EtherType'), Number(8)), Number(143)) }), '0000010': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('TCI', '0000'), ('EtherType', '00000'), ('Payload', '000001') ], And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('TCI'): Number(16), First('TCI'): Number(112), Last('TCI'): Number(127), Length('EtherType'): Number(16), First('EtherType'): Number(128), Last('EtherType'): Number(143), Length('Payload'): Add(Last('Message'), Number(-143)), First('Payload'): Number(144), Last('Payload'): Last('Message') }), '000100': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('EtherType', '0001'), ('Payload', '00010') ], And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('EtherType'): Number(16), First('EtherType'): Number(96), Last('EtherType'): Number(111), Length('Payload'): Mul(LengthValue('EtherType'), Number(8)), First('Payload'): Number(112), Last('Payload'): Add(Mul(LengthValue('EtherType'), Number(8)), Number(111)) }), '000110': Variant( [ ('Destination', '0'), ('Source', '00'), ('TPID', '000'), ('EtherType', '0001'), ('Payload', '00011') ], And(GreaterEqual(Div(Length('Payload'), Number(8)), Number(46)), LessEqual(Div(Length('Payload'), Number(8)), Number(1500))), { Length('Destination'): Number(48), First('Destination'): Number(0), Last('Destination'): Number(47), Length('Source'): Number(48), First('Source'): Number(48), Last('Source'): Number(95), Length('TPID'): Number(16), First('TPID'): Number(96), Last('TPID'): Number(111), Length('EtherType'): Number(16), First('EtherType'): Number(96), Last('EtherType'): Number(111), Length('Payload'): Add(Last('Message'), Number(-111)), First('Payload'): Number(112), Last('Payload'): Last('Message') }) })) ]) self.assertEqual(ETHERNET_PDU.fields(), expected)
def sufficient_space_for_field_condition(field_name: Name) -> Expr: return GreaterEqual( Call("Available_Space", [Variable("Ctx"), field_name]), Call("Field_Length", [Variable("Ctx"), field_name]), )
def test_less_neg(self) -> None: self.assertEqual(-Less(Variable("X"), Number(1)), GreaterEqual(Variable("X"), Number(1)))
def context_predicate(message: Message, composite_fields: Sequence[Field], prefix: str) -> Expr: def valid_predecessors_invariant() -> Expr: return AndThen( *[ If( [ ( Call( "Structural_Valid", [Indexed(Variable("Cursors"), Variable(f.affixed_name))], ), Or( *[ AndThen( Call( "Structural_Valid" if l.source in composite_fields else "Valid", [ Indexed( Variable("Cursors"), Variable(l.source.affixed_name), ) ], ), Equal( Selected( Indexed( Variable("Cursors"), Variable(f.affixed_name), ), "Predecessor", ), Variable(l.source.affixed_name), ), l.condition.substituted( substitution(message, embedded=True) ), ).simplified() for l in message.incoming(f) ] ), ) ] ) for f in message.fields if f not in message.direct_successors(INITIAL) ] ) def invalid_successors_invariant() -> Expr: return AndThen( *[ If( [ ( AndThen( *[ Call( "Invalid", [Indexed(Variable("Cursors"), Variable(p.affixed_name))], ) for p in message.direct_predecessors(f) ] ), Call( "Invalid", [Indexed(Variable("Cursors"), Variable(f.affixed_name))], ), ) ] ) for f in message.fields if f not in message.direct_successors(INITIAL) ] ) return AndThen( If( [ ( NotEqual(Variable("Buffer"), Variable("null")), And( Equal(First("Buffer"), Variable("Buffer_First")), Equal(Last("Buffer"), Variable("Buffer_Last")), ), ) ] ), public_context_predicate(), ForAllIn( "F", ValueRange(First("Field"), Last("Field")), If( [ ( Call("Structural_Valid", [Indexed(Variable("Cursors"), Variable("F"))]), And( GreaterEqual( Selected(Indexed(Variable("Cursors"), Variable("F")), "First"), Variable("First"), ), LessEqual( Selected(Indexed(Variable("Cursors"), Variable("F")), "Last"), Variable("Last"), ), LessEqual( Selected(Indexed(Variable("Cursors"), Variable("F")), "First"), Add( Selected(Indexed(Variable("Cursors"), Variable("F")), "Last"), Number(1), ), ), Equal( Selected( Selected(Indexed(Variable("Cursors"), Variable("F")), "Value"), "Fld", ), Variable("F"), ), ), ) ] ), ), valid_predecessors_invariant(), invalid_successors_invariant(), message_structure_invariant(message, prefix, embedded=True), )
def context_predicate(self, message: Message, composite_fields: Sequence[Field]) -> Expr: def valid_predecessors_invariant() -> Expr: return AndThen( *[ If( [ ( Call( "Structural_Valid", [Indexed("Cursors", Name(f.affixed_name))] ), Or( *[ AndThen( Call( "Structural_Valid" if l.source in composite_fields else "Valid", [Indexed("Cursors", Name(l.source.affixed_name))], ), Equal( Selected( Indexed("Cursors", Name(f.affixed_name)), "Predecessor", ), Name(l.source.affixed_name), ), l.condition, ).simplified(self.substitution(message, False)) for l in message.incoming(f) ] ), ) ] ) for f in message.fields if f not in message.direct_successors(INITIAL) ] ) def invalid_successors_invariant() -> Expr: return AndThen( *[ If( [ ( AndThen( *[ Call("Invalid", [Indexed("Cursors", Name(p.affixed_name))]) for p in message.direct_predecessors(f) ] ), Call("Invalid", [Indexed("Cursors", Name(f.affixed_name))]), ) ] ) for f in message.fields if f not in message.direct_successors(INITIAL) ] ) return AndThen( If( [ ( NotEqual(Name(Name("Buffer")), NULL), And( Equal(First(Name("Buffer")), Name(Name("Buffer_First"))), Equal(Last(Name("Buffer")), Name(Name("Buffer_Last"))), ), ) ] ), GreaterEqual( Call(self.types.byte_index, [Name(Name("First"))]), Name(Name("Buffer_First")) ), LessEqual(Call(self.types.byte_index, [Name(Name("Last"))]), Name(Name("Buffer_Last"))), LessEqual(Name(Name("First")), Name(Name("Last"))), LessEqual(Name(Name("Last")), Div(Last(self.types.bit_index), Number(2))), ForAllIn( "F", ValueRange(First("Field"), Last("Field")), If( [ ( Call("Structural_Valid", [Indexed(Name("Cursors"), Name("F"))]), And( GreaterEqual( Selected(Indexed(Name("Cursors"), Name("F")), "First"), Name(Name("First")), ), LessEqual( Selected(Indexed(Name("Cursors"), Name("F")), "Last"), Name(Name("Last")), ), LessEqual( Selected(Indexed(Name("Cursors"), Name("F")), "First"), Add( Selected(Indexed(Name("Cursors"), Name("F")), "Last"), Number(1), ), ), Equal( Selected( Selected(Indexed(Name("Cursors"), Name("F")), "Value"), "Fld", ), Name("F"), ), ), ) ] ), ), valid_predecessors_invariant(), invalid_successors_invariant(), self.message_structure_invariant(message, prefix=False), )
Field("Type_Length"), NotEqual(Variable("Type_Length_TPID"), Number(0x8100, 16)), first=First("Type_Length_TPID"), ), Link(Field("TPID"), Field("TCI")), Link(Field("TCI"), Field("Type_Length")), Link( Field("Type_Length"), Field("Payload"), LessEqual(Variable("Type_Length"), Number(1500)), Mul(Variable("Type_Length"), Number(8)), ), Link( Field("Type_Length"), Field("Payload"), GreaterEqual(Variable("Type_Length"), Number(1536)), ), Link( Field("Payload"), FINAL, And( GreaterEqual(Div(Size("Payload"), Number(8)), Number(46)), LessEqual(Div(Size("Payload"), Number(8)), Number(1500)), ), ), ], { Field("Destination"): ETHERNET_ADDRESS, Field("Source"): ETHERNET_ADDRESS, Field("Type_Length_TPID"): ETHERNET_TYPE_LENGTH, Field("TPID"): ETHERNET_TPID,
def test_greater_equal_neg(self) -> None: self.assertEqual(-GreaterEqual(Variable("X"), Number(1)), Less(Variable("X"), Number(1)))
def create_ethernet_frame() -> Message: address_type = ModularInteger("Ethernet.Address", Pow(Number(2), Number(48))) type_length_type = RangeInteger("Ethernet.Type_Length", Number(46), Sub(Pow(Number(2), Number(16)), Number(1)), Number(16)) tpid_type = RangeInteger("Ethernet.TPID", Number(0x8100, 16), Number(0x8100, 16), Number(16)) tci_type = ModularInteger("Ethernet.TCI", Pow(Number(2), Number(16))) structure = [ Link(INITIAL, Field("Destination")), Link(Field("Destination"), Field("Source")), Link(Field("Source"), Field("Type_Length_TPID")), Link( Field("Type_Length_TPID"), Field("TPID"), Equal(Variable("Type_Length_TPID"), Number(0x8100, 16)), first=First("Type_Length_TPID"), ), Link( Field("Type_Length_TPID"), Field("Type_Length"), NotEqual(Variable("Type_Length_TPID"), Number(0x8100, 16)), first=First("Type_Length_TPID"), ), Link(Field("TPID"), Field("TCI")), Link(Field("TCI"), Field("Type_Length")), Link( Field("Type_Length"), Field("Payload"), LessEqual(Variable("Type_Length"), Number(1500)), Mul(Variable("Type_Length"), Number(8)), ), Link( Field("Type_Length"), Field("Payload"), GreaterEqual(Variable("Type_Length"), Number(1536)), Sub(Last("Message"), Last("Type_Length")), ), Link( Field("Payload"), FINAL, And( GreaterEqual(Div(Length("Payload"), Number(8)), Number(46)), LessEqual(Div(Length("Payload"), Number(8)), Number(1500)), ), ), ] types = { Field("Destination"): address_type, Field("Source"): address_type, Field("Type_Length_TPID"): type_length_type, Field("TPID"): tpid_type, Field("TCI"): tci_type, Field("Type_Length"): type_length_type, Field("Payload"): Payload(), } return Message("Ethernet.Frame", structure, types)
def create_internal_functions( self, message: Message, scalar_fields: Mapping[Field, Scalar] ) -> UnitPart: return UnitPart( [], [ SubprogramBody( ProcedureSpecification( "Set_Field_Value", [ InOutParameter(["Ctx"], "Context"), Parameter(["Val"], "Field_Dependent_Value"), OutParameter(["Fst", "Lst"], self.types.bit_index), ], ), [ *self.common.field_bit_location_declarations(Selected("Val", "Fld")), *self.common.field_byte_location_declarations(), ], [ Assignment("Fst", Name("First")), Assignment("Lst", Name("Last")), CaseStatement( Selected("Val", "Fld"), [ ( Name(f.affixed_name), [ CallStatement( "Insert", [ Selected("Val", f"{f.name}_Value"), Slice( Selected(Selected("Ctx", "Buffer"), "all"), Name("Buffer_First"), Name("Buffer_Last"), ), Name("Offset"), ], ) if f in scalar_fields else NullStatement() ], ) for f in message.all_fields ], ), ], [ Precondition( AndThen( Not(Constrained("Ctx")), Call("Has_Buffer", [Name("Ctx")]), In(Selected("Val", "Fld"), Range("Field")), Call("Valid_Next", [Name("Ctx"), Selected("Val", "Fld")]), self.common.sufficient_space_for_field_condition( Selected("Val", "Fld") ), ForAllIn( "F", Range("Field"), If( [ ( Call( "Structural_Valid", [ Indexed( Selected("Ctx", "Cursors"), Name("F"), ) ], ), LessEqual( Selected( Indexed( Selected("Ctx", "Cursors"), Name("F"), ), "Last", ), Call( "Field_Last", [Name("Ctx"), Selected("Val", "Fld")], ), ), ) ] ), ), ) ), Postcondition( And( Call("Has_Buffer", [Name("Ctx")]), Equal( Name("Fst"), Call("Field_First", [Name("Ctx"), Selected("Val", "Fld")]), ), Equal( Name("Lst"), Call("Field_Last", [Name("Ctx"), Selected("Val", "Fld")]), ), GreaterEqual(Name("Fst"), Selected("Ctx", "First")), LessEqual(Name("Fst"), Add(Name("Lst"), Number(1))), LessEqual( Call(self.types.byte_index, [Name("Lst")]), Selected("Ctx", "Buffer_Last"), ), ForAllIn( "F", Range("Field"), If( [ ( Call( "Structural_Valid", [ Indexed( Selected("Ctx", "Cursors"), Name("F"), ) ], ), LessEqual( Selected( Indexed( Selected("Ctx", "Cursors"), Name("F"), ), "Last", ), Name("Lst"), ), ) ] ), ), *[ Equal(e, Old(e)) for e in [ Selected("Ctx", "Buffer_First"), Selected("Ctx", "Buffer_Last"), Selected("Ctx", "First"), Selected("Ctx", "Cursors"), ] ], ) ), ], ) ], )
def test_greater_equal() -> None: assert GreaterEqual(Number(100), Number(1)).z3expr() == (z3.IntVal(100) >= z3.IntVal(1))
def array_functions(array: Array, package: str) -> List[Subprogram]: common_precondition = LogCall(f'Is_Contained (Buffer)') return [ Function('Valid_First', 'Boolean', [('Buffer', 'Types.Bytes')], [], [ ReturnStatement( LogCall('Valid_Next (Buffer, Offset_Type (Buffer\'First))')) ], [Precondition(common_precondition)]), Procedure('Get_First', [ ('Buffer', 'Types.Bytes'), ('Offset', 'out Offset_Type'), ('First', 'out Types.Index_Type'), ('Last', 'out Types.Index_Type') ], [], [ Assignment('Offset', Value('Offset_Type (Buffer\'First)')), CallStatement('Get_Next', ['Buffer', 'Offset', 'First', 'Last']) ], [ Precondition( And(common_precondition, LogCall('Valid_First (Buffer)'))), Postcondition( And( And(GreaterEqual(Value('First'), First('Buffer')), LessEqual(Value('Last'), Last('Buffer'))), LogCall(f'{package}.{array.element_type}.Is_Contained ' '(Buffer (First .. Last))'))) ]), Function('Valid_Next', 'Boolean', [ ('Buffer', 'Types.Bytes'), ('Offset', 'Offset_Type') ], [], [ PragmaStatement('Assume', [ (f'{package}.{array.element_type}.Is_Contained ' '(Buffer (Types.Index_Type (Offset) .. Buffer\'Last))') ]), ReturnStatement( LogCall( f'{package}.{array.element_type}.Is_Valid ' '(Buffer (Types.Index_Type (Offset) .. Buffer\'Last))')) ], [Precondition(common_precondition)]), Procedure( 'Get_Next', [('Buffer', 'Types.Bytes'), ('Offset', 'in out Offset_Type'), ('First', 'out Types.Index_Type'), ('Last', 'out Types.Index_Type')], [], [ Assignment('First', Value('Types.Index_Type (Offset)')), Assignment( 'Last', Add( Value('First'), Cast( 'Types.Length_Type', MathCall(f'{package}.{array.element_type}.' 'Message_Length (Buffer (First ' '.. Buffer\'Last))')), Number(-1))), Assignment('Offset', Value('Offset_Type (Last + 1)')), PragmaStatement( 'Assume', [(f'{package}.{array.element_type}.Is_Contained ' '(Buffer (First .. Last))')]) ], [ Precondition( And(common_precondition, LogCall('Valid_Next (Buffer, Offset)'))), Postcondition( And( And(GreaterEqual(Value('First'), First('Buffer')), LessEqual(Value('Last'), Last('Buffer'))), LogCall(f'{package}.{array.element_type}.Is_Contained ' '(Buffer (First .. Last))'))) ]) ]
def test_greater_equal_simplified(self) -> None: self.assertEqual( GreaterEqual(Value('X'), Add(Number(21), Number(21))).simplified(), GreaterEqual(Value('X'), Number(42)))