예제 #1
0
파일: vm.py 프로젝트: malchev/cairo-lang
 def deduce_op1(
         self, instruction: Instruction, dst: Optional[MaybeRelocatable],
         op0: Optional[MaybeRelocatable]) -> \
         Tuple[Optional[MaybeRelocatable], Optional[MaybeRelocatable]]:
     if instruction.opcode is Instruction.Opcode.ASSERT_EQ:
         if (instruction.res is Instruction.Res.OP1) and (dst is not None):
             return dst, dst
         elif (instruction.res is Instruction.Res.ADD) and (dst is not None) and \
                 (op0 is not None):
             return (dst - op0) % self.prime, dst  # type: ignore
         elif (instruction.res is Instruction.Res.MUL) and isinstance(dst, int) and \
                 isinstance(op0, int) and op0 != 0:
             return div_mod(dst, op0, self.prime), dst
     return None, None
예제 #2
0
파일: vm.py 프로젝트: malchev/cairo-lang
 def deduce_op0(
         self, instruction: Instruction, dst: Optional[MaybeRelocatable],
         op1: Optional[MaybeRelocatable]) -> \
         Tuple[Optional[MaybeRelocatable], Optional[MaybeRelocatable]]:
     if instruction.opcode is Instruction.Opcode.CALL:
         return self.run_context.pc + instruction.size, None
     elif instruction.opcode is Instruction.Opcode.ASSERT_EQ:
         if (instruction.res is Instruction.Res.ADD) and (dst is not None) and \
                 (op1 is not None):
             return (dst - op1) % self.prime, dst  # type: ignore
         elif (instruction.res is Instruction.Res.MUL) and isinstance(dst, int) and \
                 isinstance(op1, int) and op1 != 0:
             return div_mod(dst, op1, self.prime), dst
     return None, None
예제 #3
0
def test_div_mod():
    assert div_mod(2, 3, 5) == 4
    with pytest.raises(AssertionError):
        div_mod(8, 10, 5)
예제 #4
0
파일: vm.py 프로젝트: malchev/cairo-lang
    def __init__(
            self, program: ProgramBase, run_context: RunContext,
            hint_locals: dict, static_locals: dict = {},
            builtin_runners: Dict[str, BuiltinRunner] = {}, program_base: Optional[int] = None):
        """
        hints - a dictionary from memory addresses to an executable object.
          When the pc points to the memory address, before the execution of the instruction,
          the executable object will be run.
          Executable objects are anything that can be placed inside exec.
          For example, 'a=5', or compile('a=5').
        hint_locals - dictionary holding local values for execution of hints.
          Passed as locals parameter for the exec function.
        static_locals - dictionary holding static values for execution. They are available in all
          scopes.
        program_base - The pc of the first instruction in program (default is run_context.pc).
        """
        self.prime = program.prime
        self.builtin_runners = builtin_runners
        self.exec_scopes: List[dict] = []
        self.enter_scope(dict(hint_locals))
        self.run_context = copy.copy(run_context)  # Shallow copy.
        self.hints: Dict[MaybeRelocatable, CompiledHint] = {}
        # A map from hint index to pc.
        self.hint_pcs: Dict[int, MaybeRelocatable] = {}
        self.instruction_debug_info: Dict[MaybeRelocatable, InstructionLocation] = {}
        self.debug_file_contents: Dict[str, str] = {}
        self.program = program
        self.program_base = program_base if program_base is not None else self.run_context.pc
        self.validated_memory = ValidatedMemoryDict(memory=self.run_context.memory)

        # If program is a StrippedProgram, there are no hints or debug information to load.
        if isinstance(program, Program):
            self.load_program(
                program=program,
                program_base=self.program_base,
            )

        self.trace: List[TraceEntry[MaybeRelocatable]] = []

        # auto_deduction contains a mapping from a memory segment index to a list of functions
        # (and a tuple of additional arguments) that may try to automatically deduce the value
        # of memory cells in the segment (based on other memory cells).
        self.auto_deduction: Dict[int, List[Tuple[Rule, tuple]]] = {}
        # Current step.
        self.current_step = 0

        # This flag can be set to true by hints to avoid the execution of the current step in
        # step() (so that only the hint will be performed, but nothing else will happen).
        self.skip_instruction_execution = False

        from starkware.python import math_utils
        self.static_locals = static_locals.copy()
        self.static_locals.update({
            'PRIME': self.prime,
            'fadd': lambda a, b, p=self.prime: (a + b) % p,
            'fsub': lambda a, b, p=self.prime: (a - b) % p,
            'fmul': lambda a, b, p=self.prime: (a * b) % p,
            'fdiv': lambda a, b, p=self.prime: math_utils.div_mod(a, b, p),
            'fpow': lambda a, b, p=self.prime: pow(a, b, p),
            'fis_quad_residue': lambda a, p=self.prime: math_utils.is_quad_residue(a, p),
            'fsqrt': lambda a, p=self.prime: math_utils.sqrt(a, p),
            'safe_div': math_utils.safe_div,
        })
예제 #5
0
    def visit_ExprOperator(self, expr: ExprOperator):
        a = self.visit(expr.a)
        b = self.visit(expr.b)
        op = expr.op

        if isinstance(b, ExprConst) and op == '/' and b.val == 0:
            raise SimplifierError('Division by zero.', location=b.location)

        if isinstance(a, ExprConst) and isinstance(b, ExprConst):
            val = None
            if op == '/' and self.prime is not None:
                if b.val % self.prime == 0:
                    raise SimplifierError('Division by zero.', location=b.location)
                val = div_mod(a.val, b.val, self.prime)
            if op != '/':
                val = self._to_field_element(OPERATOR_DICT[op](a.val, b.val))
            if val is not None:
                return ExprConst(val, location=expr.location)

        if isinstance(a, ExprConst) and op == '+':
            assert not isinstance(b, ExprConst)
            # Move constant expression to the right. E.g., "5 + fp" -> "fp + 5"
            a, b = b, a

        if isinstance(b, ExprConst) and op == '-':
            # Replace x - y with x + (-y) for constant y.
            op = '+'
            b = ExprConst(val=self._to_field_element(-b.val), location=b.location)

        if isinstance(b, ExprConst) and op == '/' and self.prime is not None:
            # Replace x / y with x * (1/y) for constant y.
            op = '*'
            if b.val % self.prime == 0:
                raise SimplifierError('Division by zero.', location=b.location)
            inv_val = div_mod(1, b.val, self.prime)
            b = ExprConst(val=self._to_field_element(inv_val), location=b.location)

        if isinstance(b, ExprConst) and b.val == 0 and op in ['+', '-']:
            # Replace x + 0 and x - 0 by x.
            return a

        if isinstance(b, ExprConst) and b.val == 1 and op in ['*', '/']:
            # Replace x * 1 and x / 1 by x.
            return a

        if isinstance(a, ExprConst) and a.val == 1 and op == '*':
            # Replace 1 * x by x.
            return b

        if isinstance(b, ExprConst) and isinstance(a, ExprOperator) and \
                ((op == '+' and a.op in ['+', '-']) or (op == '*' and a.op == '*')):
            # If the expression is of the form "(a + b) + c" where c is constant, change it to
            # "a + (b + c)", this allows compiling expressions of the form: "[fp + x + y]".

            # Rotate right.
            return self.visit(ExprOperator(
                a=a.a,
                op=a.op,
                b=ExprOperator(
                    a=a.b,
                    op=a.op,
                    b=b,
                    location=expr.location),
                location=expr.location))

        return ExprOperator(a=a, op=op, b=b, location=expr.location)