sui_move_natives_v2/crypto/
hmac.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3use crate::NativesCostTable;
4use fastcrypto::{hmac, traits::ToFromBytes};
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;
16
17const HMAC_SHA3_256_BLOCK_SIZE: usize = 136;
18
19#[derive(Clone)]
20pub struct HmacHmacSha3256CostParams {
21    /// Base cost for invoking the `hmac_sha3_256` function
22    pub hmac_hmac_sha3_256_cost_base: InternalGas,
23    ///  Cost per byte of `msg` and `key`
24    pub hmac_hmac_sha3_256_input_cost_per_byte: InternalGas,
25    ///  Cost per block of `msg` and `key`, with block size = 136
26    pub hmac_hmac_sha3_256_input_cost_per_block: InternalGas,
27}
28/***************************************************************************************************
29 * native fun ed25519_verify
30 * Implementation of the Move native function `hmac_sha3_256(key: &vector<u8>, msg: &vector<u8>): vector<u8>;`
31 *   gas cost: hmac_hmac_sha3_256_cost_base                          | base cost for function call and fixed opers
32 *              + hmac_hmac_sha3_256_input_cost_per_byte * msg.len()   | cost depends on length of message
33 *              + hmac_hmac_sha3_256_input_cost_per_block * num_blocks(msg) | cost depends on number of blocks in message
34 * Note: each block is of size `HMAC_SHA3_256_BLOCK_SIZE` bytes, and we round up.
35 *       `key` is fixed size, so the cost is included in the base cost.
36 **************************************************************************************************/
37pub fn hmac_sha3_256(
38    context: &mut NativeContext,
39    ty_args: Vec<Type>,
40    mut args: VecDeque<Value>,
41) -> PartialVMResult<NativeResult> {
42    debug_assert!(ty_args.is_empty());
43    debug_assert!(args.len() == 2);
44
45    // Load the cost parameters from the protocol config
46    let hmac_hmac_sha3_256_cost_params = &context
47        .extensions()
48        .get::<NativesCostTable>()
49        .hmac_hmac_sha3_256_cost_params
50        .clone();
51
52    // Charge the base cost for this operation
53    native_charge_gas_early_exit!(
54        context,
55        hmac_hmac_sha3_256_cost_params.hmac_hmac_sha3_256_cost_base
56    );
57
58    let message = pop_arg!(args, VectorRef);
59    let key = pop_arg!(args, VectorRef);
60
61    let msg_len = message.as_bytes_ref().len();
62    let key_len = key.as_bytes_ref().len();
63    // Charge the arg size dependent costs
64    native_charge_gas_early_exit!(
65        context,
66        hmac_hmac_sha3_256_cost_params.hmac_hmac_sha3_256_input_cost_per_byte
67            // same cost for msg and key
68            * ((msg_len + key_len) as u64).into()
69            + hmac_hmac_sha3_256_cost_params.hmac_hmac_sha3_256_input_cost_per_block
70                * ((((msg_len + key_len) + (2 * HMAC_SHA3_256_BLOCK_SIZE - 2))
71                    / HMAC_SHA3_256_BLOCK_SIZE) as u64)
72                    .into()
73    );
74
75    let hmac_key = hmac::HmacKey::from_bytes(&key.as_bytes_ref())
76        .expect("HMAC key can be of any length and from_bytes should always succeed");
77    let cost = context.gas_used();
78
79    Ok(NativeResult::ok(
80        cost,
81        smallvec![Value::vector_u8(
82            hmac::hmac_sha3_256(&hmac_key, &message.as_bytes_ref()).to_vec()
83        )],
84    ))
85}