def _modexp(data): base_length, exponent_length, modulus_length = _extract_lengths(data) if base_length == 0: return 0 elif modulus_length == 0: return 0 # compute start:end indexes base_end_idx = 96 + base_length exponent_end_idx = base_end_idx + exponent_length modulus_end_dx = exponent_end_idx + modulus_length # extract arguments modulus_bytes = zpad_right( data[exponent_end_idx:modulus_end_dx], to_size=modulus_length, ) modulus = big_endian_to_int(modulus_bytes) if modulus == 0: return 0 base_bytes = zpad_right(data[96:base_end_idx], to_size=base_length) base = big_endian_to_int(base_bytes) exponent_bytes = zpad_right( data[base_end_idx:exponent_end_idx], to_size=exponent_length, ) exponent = big_endian_to_int(exponent_bytes) print('base', base, 'exponent', exponent, 'modulus', modulus) result = pow(base, exponent, modulus) return result
def _compute_adjusted_exponent_length(exponent_length, first_32_exponent_bytes): exponent = big_endian_to_int(first_32_exponent_bytes) if exponent_length <= 32 and exponent == 0: return 0 elif exponent_length <= 32: return get_highest_bit_index(exponent) else: first_32_bytes_as_int = big_endian_to_int(first_32_exponent_bytes) return (8 * (exponent_length - 32) + get_highest_bit_index(first_32_bytes_as_int))
def _extract_lengths(data): # extract argument lengths base_length_bytes = pad32r(data[:32]) base_length = big_endian_to_int(base_length_bytes) exponent_length_bytes = pad32r(data[32:64]) exponent_length = big_endian_to_int(exponent_length_bytes) modulus_length_bytes = pad32r(data[64:96]) modulus_length = big_endian_to_int(modulus_length_bytes) return base_length, exponent_length, modulus_length
def check_pow(block_number: int, mining_hash: Hash32, mix_hash: Hash32, nonce: bytes, difficulty: int) -> None: validate_length(mix_hash, 32, title="Mix Hash") validate_length(mining_hash, 32, title="Mining Hash") validate_length(nonce, 8, title="POW Nonce") cache = get_cache(block_number) mining_output = hashimoto_light(block_number, cache, mining_hash, big_endian_to_int(nonce)) if mining_output[b'mix digest'] != mix_hash: raise ValidationError("mix hash mismatch; {0} != {1}".format( encode_hex(mining_output[b'mix digest']), encode_hex(mix_hash))) result = big_endian_to_int(mining_output[b'result']) validate_lte(result, 2**256 // difficulty, title="POW Difficulty")
def _ecmull(data): x_bytes = pad32r(data[:32]) y_bytes = pad32r(data[32:64]) m_bytes = pad32r(data[64:96]) x = big_endian_to_int(x_bytes) y = big_endian_to_int(y_bytes) m = big_endian_to_int(m_bytes) p = validate_point(x, y) result = bn128.normalize(bn128.multiply(p, m)) return result
def _ecadd(data): x1_bytes = pad32r(data[:32]) y1_bytes = pad32r(data[32:64]) x2_bytes = pad32r(data[64:96]) y2_bytes = pad32r(data[96:128]) x1 = big_endian_to_int(x1_bytes) y1 = big_endian_to_int(y1_bytes) x2 = big_endian_to_int(x2_bytes) y2 = big_endian_to_int(y2_bytes) p1 = validate_point(x1, y1) p2 = validate_point(x2, y2) result = bn128.normalize(bn128.add(p1, p2)) return result
def mine_pow_nonce(block_number: int, mining_hash: Hash32, difficulty: int) -> Tuple[bytes, bytes]: cache = get_cache(block_number) for nonce in range(MAX_TEST_MINE_ATTEMPTS): mining_output = hashimoto_light(block_number, cache, mining_hash, nonce) result = big_endian_to_int(mining_output[b'result']) result_cap = 2**256 // difficulty if result <= result_cap: return nonce.to_bytes(8, 'big'), mining_output[b'mix digest'] raise Exception("Too many attempts at POW mining, giving up")
def ecrecover(computation): computation.consume_gas(constants.GAS_ECRECOVER, reason="ECRecover Precompile") raw_message_hash = computation.msg.data[:32] message_hash = pad32r(raw_message_hash) v_bytes = pad32r(computation.msg.data[32:64]) v = big_endian_to_int(v_bytes) r_bytes = pad32r(computation.msg.data[64:96]) r = big_endian_to_int(r_bytes) s_bytes = pad32r(computation.msg.data[96:128]) s = big_endian_to_int(s_bytes) try: validate_lt_secpk1n(r, title="ECRecover: R") validate_lt_secpk1n(s, title="ECRecover: S") validate_lte(v, 28, title="ECRecover: V") validate_gte(v, 27, title="ECRecover: V") except ValidationError: return computation canonical_v = v - 27 try: signature = keys.Signature(vrs=(canonical_v, r, s)) public_key = signature.recover_public_key_from_msg_hash(message_hash) except BadSignature: return computation address = public_key.to_canonical_address() padded_address = pad32(address) computation.output = padded_address return computation
def _extract_point(data_slice): x1_bytes = data_slice[:32] y1_bytes = data_slice[32:64] x2_i_bytes = data_slice[64:96] x2_r_bytes = data_slice[96:128] y2_i_bytes = data_slice[128:160] y2_r_bytes = data_slice[160:192] x1 = big_endian_to_int(x1_bytes) y1 = big_endian_to_int(y1_bytes) x2_i = big_endian_to_int(x2_i_bytes) x2_r = big_endian_to_int(x2_r_bytes) y2_i = big_endian_to_int(y2_i_bytes) y2_r = big_endian_to_int(y2_r_bytes) return x1, y1, x2_i, x2_r, y2_i, y2_r
def _pop(self, num_items, type_hint): for _ in range(num_items): if type_hint == constants.UINT256: value = self.values.pop() if isinstance(value, int): yield value else: yield big_endian_to_int(value) elif type_hint == constants.BYTES: value = self.values.pop() if isinstance(value, bytes): yield value else: yield int_to_big_endian(value) elif type_hint == constants.ANY: yield self.values.pop() else: raise TypeError( "Unknown type_hint: {0}. Must be one of {1}".format( type_hint, ", ".join((constants.UINT256, constants.BYTES)), ) )