def air_private_input(self, runner): return { self.name: [{ 'index': safe_div(step, self.sample_ratio), 'pc': hex(pc), 'fp': hex(fp) } for step, pc, fp in self.samples] }
def expected_stack(self, public_input): if not self.included: return [], [] addresses = public_input.memory_segments['range_check'] max_size = safe_div(public_input.n_steps, self.ratio) assert 0 <= addresses.begin_addr <= addresses.stop_ptr <= \ addresses.begin_addr + max_size < 2**64 return [addresses.begin_addr], [addresses.stop_ptr]
def expected_stack(self, public_input): if not self.included: return [], [] addresses = public_input.memory_segments['signature'] max_size = safe_div(public_input.n_steps, self.ratio) * CELLS_PER_SIGNATURE assert 0 <= addresses.begin_addr <= addresses.stop_ptr <= \ addresses.begin_addr + max_size < 2**64 return [addresses.begin_addr], [addresses.stop_ptr]
def get_used_cells_and_allocated_size(self, runner): if runner.vm.current_step < self.ratio: raise InsufficientAllocatedCells( f'Number of steps must be at least {self.ratio} for the {self.name} builtin.' ) used = self.get_used_cells(runner) size = self.cells_per_instance * safe_div(runner.vm.current_step, self.ratio) if used > size: raise InsufficientAllocatedCells( f'The {self.name} builtin used {used} cells but the capacity is {size}.' ) return used, size
def air_private_input(self, runner) -> Dict[str, Any]: res: Dict[int, Any] = {} for (addr, signature) in self.signatures.items(): addr_offset = addr - self.base idx = safe_div(addr_offset, CELLS_PER_SIGNATURE) pubkey = runner.vm_memory[addr] msg = runner.vm_memory[addr + 1] res[idx] = { 'index': idx, 'pubkey': hex(pubkey), 'msg': hex(msg), 'signature_input': self.process_signature(pubkey, msg, signature), } return {self.name: sorted(res.values(), key=lambda item: item['index'])}
def check_memory_usage(self): """ Checks that there are enough trace cells to fill the entire memory range. """ instance = LAYOUTS[self.layout] builtins_memory_units = sum( builtin_runner.get_allocated_memory_units(self) for builtin_runner in self.builtin_runners.values()) # Out of the memory units available per step, a fraction is used for public memory, and # four are used for the instruction. total_memory_units = instance.memory_units_per_step * self.vm.current_step public_memory_units = safe_div(total_memory_units, instance.public_memory_fraction) instruction_memory_units = 4 * self.vm.current_step unused_memory_units = total_memory_units - \ (public_memory_units + instruction_memory_units + builtins_memory_units) memory_address_holes = self.segments.get_memory_holes() if unused_memory_units < memory_address_holes: raise InsufficientAllocatedCells( f'There are only {unused_memory_units} cells to fill the memory address holes, but ' f'{memory_address_holes} are required.')
def check_diluted_check_usage(self): """ Checks that there are enough trace cells to fill the entire diluted checks. """ instance = LAYOUTS[self.layout] if 'bitwise' not in instance.builtins: return diluted_units_used_by_builtins = sum( builtin_runner.get_used_diluted_check_units() for builtin_runner in self.builtin_runners.values()) ratio = instance.builtins['bitwise'].ratio unused_diluted_units = instance.diluted_units_per_step * self.vm.current_step - \ diluted_units_used_by_builtins * safe_div(self.vm.current_step, ratio) diluted_usage_upper_bound = 2**instance.builtins[ 'bitwise'].diluted_n_bits if unused_diluted_units < diluted_usage_upper_bound: raise InsufficientAllocatedCells( f'There are only {unused_diluted_units} cells to fill the diluted check holes, but ' f'potentially {diluted_usage_upper_bound} are required.')
def test_safe_div(): for x in [2, 3, 5, 6, 10, 12, -2, -3, -10]: assert safe_div(60, x) * x == 60 for val in [0, 7, 120]: with pytest.raises(AssertionError): safe_div(60, val)
def get_allocated_memory_units(self, runner): return self.cells_per_instance * safe_div(runner.vm.current_step, self.ratio)
def get_used_instances(self, runner): return safe_div(self.get_used_cells(runner), self.cells_per_instance)