sui_move_natives_v0/crypto/
hash.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0
use crate::NativesCostTable;
use fastcrypto::hash::{Blake2b256, HashFunction, Keccak256};
use move_binary_format::errors::PartialVMResult;
use move_core_types::gas_algebra::InternalGas;
use move_vm_runtime::{native_charge_gas_early_exit, native_functions::NativeContext};
use move_vm_types::{
    loaded_data::runtime_types::Type,
    natives::function::NativeResult,
    pop_arg,
    values::{Value, VectorRef},
};
use smallvec::smallvec;
use std::{collections::VecDeque, ops::Mul};

const BLAKE_2B256_BLOCK_SIZE: u16 = 128;
const KECCAK_256_BLOCK_SIZE: u16 = 136;

fn hash<H: HashFunction<DIGEST_SIZE>, const DIGEST_SIZE: usize>(
    context: &mut NativeContext,
    ty_args: Vec<Type>,
    mut args: VecDeque<Value>,
    // The caller provides the cost per byte
    msg_cost_per_byte: InternalGas,
    // The caller provides the cost per block
    msg_cost_per_block: InternalGas,
    // The caller specifies the block size
    block_size: u16,
) -> PartialVMResult<NativeResult> {
    debug_assert!(ty_args.is_empty());
    debug_assert!(args.len() == 1);

    let msg = pop_arg!(args, VectorRef);
    let msg_ref = msg.as_bytes_ref();

    let block_size = block_size as usize;

    // Charge the msg dependent costs
    native_charge_gas_early_exit!(
        context,
        msg_cost_per_byte.mul((msg_ref.len() as u64).into())
            // Round up the blocks
            + msg_cost_per_block
                .mul((msg_ref.len().div_ceil(block_size) as u64).into())
    );

    Ok(NativeResult::ok(
        context.gas_used(),
        smallvec![Value::vector_u8(
            H::digest(msg.as_bytes_ref().as_slice()).digest
        )],
    ))
}

#[derive(Clone)]
pub struct HashKeccak256CostParams {
    /// Base cost for invoking the `blake2b256` function
    pub hash_keccak256_cost_base: InternalGas,
    /// Cost per byte of `data`
    pub hash_keccak256_data_cost_per_byte: InternalGas,
    /// Cost per block of `data`, where a block is 136 bytes
    pub hash_keccak256_data_cost_per_block: InternalGas,
}

/***************************************************************************************************
 * native fun keccak256
 * Implementation of the Move native function `hash::keccak256(data: &vector<u8>): vector<u8>`
 *   gas cost: hash_keccak256_cost_base                               | base cost for function call and fixed opers
 *              + hash_keccak256_data_cost_per_byte * msg.len()       | cost depends on length of message
 *              + hash_keccak256_data_cost_per_block * num_blocks     | cost depends on number of blocks in message
 **************************************************************************************************/
pub fn keccak256(
    context: &mut NativeContext,
    ty_args: Vec<Type>,
    args: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
    // Load the cost parameters from the protocol config
    let hash_keccak256_cost_params = &context
        .extensions()
        .get::<NativesCostTable>()
        .hash_keccak256_cost_params
        .clone();
    // Charge the base cost for this oper
    native_charge_gas_early_exit!(context, hash_keccak256_cost_params.hash_keccak256_cost_base);

    hash::<Keccak256, 32>(
        context,
        ty_args,
        args,
        hash_keccak256_cost_params.hash_keccak256_data_cost_per_byte,
        hash_keccak256_cost_params.hash_keccak256_data_cost_per_block,
        KECCAK_256_BLOCK_SIZE,
    )
}

#[derive(Clone)]
pub struct HashBlake2b256CostParams {
    /// Base cost for invoking the `blake2b256` function
    pub hash_blake2b256_cost_base: InternalGas,
    /// Cost per byte of `data`
    pub hash_blake2b256_data_cost_per_byte: InternalGas,
    /// Cost per block of `data`, where a block is 128 bytes
    pub hash_blake2b256_data_cost_per_block: InternalGas,
}
/***************************************************************************************************
 * native fun blake2b256
 * Implementation of the Move native function `hash::blake2b256(data: &vector<u8>): vector<u8>`
 *   gas cost: hash_blake2b256_cost_base                               | base cost for function call and fixed opers
 *              + hash_blake2b256_data_cost_per_byte * msg.len()       | cost depends on length of message
 *              + hash_blake2b256_data_cost_per_block * num_blocks     | cost depends on number of blocks in message
 **************************************************************************************************/
pub fn blake2b256(
    context: &mut NativeContext,
    ty_args: Vec<Type>,
    args: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
    // Load the cost parameters from the protocol config
    let hash_blake2b256_cost_params = &context
        .extensions()
        .get::<NativesCostTable>()
        .hash_blake2b256_cost_params
        .clone();
    // Charge the base cost for this oper
    native_charge_gas_early_exit!(
        context,
        hash_blake2b256_cost_params.hash_blake2b256_cost_base
    );

    hash::<Blake2b256, 32>(
        context,
        ty_args,
        args,
        hash_blake2b256_cost_params.hash_blake2b256_data_cost_per_byte,
        hash_blake2b256_cost_params.hash_blake2b256_data_cost_per_block,
        BLAKE_2B256_BLOCK_SIZE,
    )
}