sui_move_natives_v1/crypto/
ed25519.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3use crate::NativesCostTable;
4use fastcrypto::{
5    ed25519::{Ed25519PublicKey, Ed25519Signature},
6    traits::{ToFromBytes, VerifyingKey},
7};
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;
18use std::collections::VecDeque;
19
20const ED25519_BLOCK_SIZE: usize = 128;
21
22#[derive(Clone)]
23pub struct Ed25519VerifyCostParams {
24    /// Base cost for invoking the `ed25519_verify` function
25    pub ed25519_ed25519_verify_cost_base: InternalGas,
26    /// Cost per byte of `msg`
27    pub ed25519_ed25519_verify_msg_cost_per_byte: InternalGas,
28    /// Cost per block of `msg`, where a block is 128 bytes
29    pub ed25519_ed25519_verify_msg_cost_per_block: InternalGas,
30}
31/***************************************************************************************************
32 * native fun ed25519_verify
33 * Implementation of the Move native function `ed25519::ed25519_verify(signature: &vector<u8>, public_key: &vector<u8>, msg: &vector<u8>): bool;`
34 *   gas cost: ed25519_ed25519_verify_cost_base                          | base cost for function call and fixed opers
35 *              + ed25519_ed25519_verify_msg_cost_per_byte * msg.len()   | cost depends on length of message
36 *              + ed25519_ed25519_verify_msg_cost_per_block * num_blocks(msg) | cost depends on number of blocks in message
37 * Note: each block is of size `ED25519_BLOCK_SIZE` bytes, and we round up.
38 *       `signature` and `public_key` are fixed size, so their costs are included in the base cost.
39 **************************************************************************************************/
40pub fn ed25519_verify(
41    context: &mut NativeContext,
42    ty_args: Vec<Type>,
43    mut args: VecDeque<Value>,
44) -> PartialVMResult<NativeResult> {
45    debug_assert!(ty_args.is_empty());
46    debug_assert!(args.len() == 3);
47
48    // Load the cost parameters from the protocol config
49    let ed25519_verify_cost_params = &context
50        .extensions()
51        .get::<NativesCostTable>()
52        .ed25519_verify_cost_params
53        .clone();
54    // Charge the base cost for this oper
55    native_charge_gas_early_exit!(
56        context,
57        ed25519_verify_cost_params.ed25519_ed25519_verify_cost_base
58    );
59
60    let msg = pop_arg!(args, VectorRef);
61    let msg_ref = msg.as_bytes_ref();
62    let public_key_bytes = pop_arg!(args, VectorRef);
63    let public_key_bytes_ref = public_key_bytes.as_bytes_ref();
64    let signature_bytes = pop_arg!(args, VectorRef);
65    let signature_bytes_ref = signature_bytes.as_bytes_ref();
66
67    // Charge the arg size dependent costs
68    native_charge_gas_early_exit!(
69        context,
70        ed25519_verify_cost_params.ed25519_ed25519_verify_msg_cost_per_byte
71            * (msg_ref.len() as u64).into()
72            + ed25519_verify_cost_params.ed25519_ed25519_verify_msg_cost_per_block
73                * (msg_ref.len().div_ceil(ED25519_BLOCK_SIZE) as u64).into()
74    );
75    let cost = context.gas_used();
76
77    let Ok(signature) = <Ed25519Signature as ToFromBytes>::from_bytes(&signature_bytes_ref) else {
78        return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)]));
79    };
80
81    let Ok(public_key) = <Ed25519PublicKey as ToFromBytes>::from_bytes(&public_key_bytes_ref)
82    else {
83        return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)]));
84    };
85
86    Ok(NativeResult::ok(
87        cost,
88        smallvec![Value::bool(public_key.verify(&msg_ref, &signature).is_ok())],
89    ))
90}