iota_move_natives_latest/crypto/
hash.rs

1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2024 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5use std::{collections::VecDeque, ops::Mul};
6
7use fastcrypto::hash::{Blake2b256, HashFunction, Keccak256};
8use move_binary_format::errors::PartialVMResult;
9use move_core_types::gas_algebra::InternalGas;
10use move_vm_runtime::{native_charge_gas_early_exit, native_functions::NativeContext};
11use move_vm_types::{
12    loaded_data::runtime_types::Type,
13    natives::function::NativeResult,
14    pop_arg,
15    values::{Value, VectorRef},
16};
17use smallvec::smallvec;
18
19use crate::NativesCostTable;
20
21const BLAKE_2B256_BLOCK_SIZE: u16 = 128;
22const KECCAK_256_BLOCK_SIZE: u16 = 136;
23
24fn hash<H: HashFunction<DIGEST_SIZE>, const DIGEST_SIZE: usize>(
25    context: &mut NativeContext,
26    ty_args: Vec<Type>,
27    mut args: VecDeque<Value>,
28    // The caller provides the cost per byte
29    msg_cost_per_byte: InternalGas,
30    // The caller provides the cost per block
31    msg_cost_per_block: InternalGas,
32    // The caller specifies the block size
33    block_size: u16,
34) -> PartialVMResult<NativeResult> {
35    debug_assert!(ty_args.is_empty());
36    debug_assert!(args.len() == 1);
37
38    let msg = pop_arg!(args, VectorRef);
39    let msg_ref = msg.as_bytes_ref();
40
41    let block_size = block_size as usize;
42
43    // Charge the msg dependent costs
44    native_charge_gas_early_exit!(
45        context,
46        msg_cost_per_byte.mul((msg_ref.len() as u64).into())
47            // Round up the blocks
48            + msg_cost_per_block
49                .mul((msg_ref.len().div_ceil(block_size) as u64).into())
50    );
51
52    Ok(NativeResult::ok(
53        context.gas_used(),
54        smallvec![Value::vector_u8(
55            H::digest(msg.as_bytes_ref().as_slice()).digest
56        )],
57    ))
58}
59
60#[derive(Clone)]
61pub struct HashKeccak256CostParams {
62    /// Base cost for invoking the `blake2b256` function
63    pub hash_keccak256_cost_base: InternalGas,
64    /// Cost per byte of `data`
65    pub hash_keccak256_data_cost_per_byte: InternalGas,
66    /// Cost per block of `data`, where a block is 136 bytes
67    pub hash_keccak256_data_cost_per_block: InternalGas,
68}
69
70/// ****************************************************************************
71/// ********************* native fun keccak256
72/// Implementation of the Move native function `hash::keccak256(data:
73/// &vector<u8>): vector<u8>`   gas cost: hash_keccak256_cost_base
74/// | base cost for function call and fixed opers
75///              + hash_keccak256_data_cost_per_byte * msg.len()       | cost
76///                depends on length of message
77///              + hash_keccak256_data_cost_per_block * num_blocks     | cost
78///                depends on number of blocks in message
79/// ****************************************************************************
80/// *******************
81pub fn keccak256(
82    context: &mut NativeContext,
83    ty_args: Vec<Type>,
84    args: VecDeque<Value>,
85) -> PartialVMResult<NativeResult> {
86    // Load the cost parameters from the protocol config
87    let hash_keccak256_cost_params = &context
88        .extensions()
89        .get::<NativesCostTable>()
90        .hash_keccak256_cost_params
91        .clone();
92    // Charge the base cost for this oper
93    native_charge_gas_early_exit!(context, hash_keccak256_cost_params.hash_keccak256_cost_base);
94
95    hash::<Keccak256, 32>(
96        context,
97        ty_args,
98        args,
99        hash_keccak256_cost_params.hash_keccak256_data_cost_per_byte,
100        hash_keccak256_cost_params.hash_keccak256_data_cost_per_block,
101        KECCAK_256_BLOCK_SIZE,
102    )
103}
104
105#[derive(Clone)]
106pub struct HashBlake2b256CostParams {
107    /// Base cost for invoking the `blake2b256` function
108    pub hash_blake2b256_cost_base: InternalGas,
109    /// Cost per byte of `data`
110    pub hash_blake2b256_data_cost_per_byte: InternalGas,
111    /// Cost per block of `data`, where a block is 128 bytes
112    pub hash_blake2b256_data_cost_per_block: InternalGas,
113}
114/// ****************************************************************************
115/// ********************* native fun blake2b256
116/// Implementation of the Move native function `hash::blake2b256(data:
117/// &vector<u8>): vector<u8>`   gas cost: hash_blake2b256_cost_base
118/// | base cost for function call and fixed opers
119///              + hash_blake2b256_data_cost_per_byte * msg.len()       | cost
120///                depends on length of message
121///              + hash_blake2b256_data_cost_per_block * num_blocks     | cost
122///                depends on number of blocks in message
123/// ****************************************************************************
124/// *******************
125pub fn blake2b256(
126    context: &mut NativeContext,
127    ty_args: Vec<Type>,
128    args: VecDeque<Value>,
129) -> PartialVMResult<NativeResult> {
130    // Load the cost parameters from the protocol config
131    let hash_blake2b256_cost_params = &context
132        .extensions()
133        .get::<NativesCostTable>()
134        .hash_blake2b256_cost_params
135        .clone();
136    // Charge the base cost for this oper
137    native_charge_gas_early_exit!(
138        context,
139        hash_blake2b256_cost_params.hash_blake2b256_cost_base
140    );
141
142    hash::<Blake2b256, 32>(
143        context,
144        ty_args,
145        args,
146        hash_blake2b256_cost_params.hash_blake2b256_data_cost_per_byte,
147        hash_blake2b256_cost_params.hash_blake2b256_data_cost_per_block,
148        BLAKE_2B256_BLOCK_SIZE,
149    )
150}