sui_move_natives_v0/crypto/
hash.rs

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