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