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