iota_move_natives_latest/crypto/
bls12381.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    bls12381::{min_pk, min_sig},
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 BLS12381_BLOCK_SIZE: usize = 64;
25
26#[derive(Clone)]
27pub struct Bls12381Bls12381MinSigVerifyCostParams {
28    /// Base cost for invoking the `bls12381_min_sig_verify` function
29    pub bls12381_bls12381_min_sig_verify_cost_base: InternalGas,
30    /// Cost per byte of `msg`
31    pub bls12381_bls12381_min_sig_verify_msg_cost_per_byte: InternalGas,
32    /// Cost per block of `msg`, where a block is 64 bytes
33    pub bls12381_bls12381_min_sig_verify_msg_cost_per_block: InternalGas,
34}
35/// ****************************************************************************
36/// ********************* native fun bls12381_min_sig_verify
37/// Implementation of the Move native function
38/// `bls12381_min_sig_verify(signature: &vector<u8>, public_key: &vector<u8>,
39/// msg: &vector<u8>): bool`   gas cost:
40/// bls12381_bls12381_min_sig_verify_cost_base                    | covers
41/// various fixed costs in the oper
42///              + bls12381_bls12381_min_sig_verify_msg_cost_per_byte    *
43///                size_of(msg)        | covers cost of operating on each byte
44///                of `msg`
45///              + bls12381_bls12381_min_sig_verify_msg_cost_per_block   *
46///                num_blocks(msg)     | covers cost of operating on each block
47///                in `msg`
48/// Note: each block is of size `BLS12381_BLOCK_SIZE` bytes, and we round up.
49///       `signature` and `public_key` are fixed size, so their costs are
50/// included in the base cost. *************************************************
51/// **********************************************
52pub fn bls12381_min_sig_verify(
53    context: &mut NativeContext,
54    ty_args: Vec<Type>,
55    mut args: VecDeque<Value>,
56) -> PartialVMResult<NativeResult> {
57    debug_assert!(ty_args.is_empty());
58    debug_assert!(args.len() == 3);
59
60    // Load the cost parameters from the protocol config
61    let bls12381_bls12381_min_sig_verify_cost_params = &context
62        .extensions()
63        .get::<NativesCostTable>()
64        .bls12381_bls12381_min_sig_verify_cost_params
65        .clone();
66    // Charge the base cost for this oper
67    native_charge_gas_early_exit!(
68        context,
69        bls12381_bls12381_min_sig_verify_cost_params.bls12381_bls12381_min_sig_verify_cost_base
70    );
71
72    let msg = pop_arg!(args, VectorRef);
73    let public_key_bytes = pop_arg!(args, VectorRef);
74    let signature_bytes = pop_arg!(args, VectorRef);
75
76    let msg_ref = msg.as_bytes_ref();
77    let public_key_bytes_ref = public_key_bytes.as_bytes_ref();
78    let signature_bytes_ref = signature_bytes.as_bytes_ref();
79
80    // Charge the arg size dependent costs
81    native_charge_gas_early_exit!(
82        context,
83        bls12381_bls12381_min_sig_verify_cost_params
84            .bls12381_bls12381_min_sig_verify_msg_cost_per_byte
85            * (msg_ref.len() as u64).into()
86            + bls12381_bls12381_min_sig_verify_cost_params
87                .bls12381_bls12381_min_sig_verify_msg_cost_per_block
88                * (msg_ref.len().div_ceil(BLS12381_BLOCK_SIZE) as u64).into()
89    );
90
91    let cost = context.gas_used();
92
93    let Ok(signature) =
94        <min_sig::BLS12381Signature as ToFromBytes>::from_bytes(&signature_bytes_ref)
95    else {
96        return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)]));
97    };
98
99    let public_key =
100        match <min_sig::BLS12381PublicKey as ToFromBytes>::from_bytes(&public_key_bytes_ref) {
101            Ok(public_key) => match public_key.validate() {
102                Ok(_) => public_key,
103                Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
104            },
105            Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
106        };
107
108    Ok(NativeResult::ok(
109        cost,
110        smallvec![Value::bool(public_key.verify(&msg_ref, &signature).is_ok())],
111    ))
112}
113
114#[derive(Clone)]
115pub struct Bls12381Bls12381MinPkVerifyCostParams {
116    /// Base cost for invoking the `bls12381_min_sig_verify` function
117    pub bls12381_bls12381_min_pk_verify_cost_base: InternalGas,
118    /// Cost per byte of `msg`
119    pub bls12381_bls12381_min_pk_verify_msg_cost_per_byte: InternalGas,
120    /// Cost per block of `msg`, where a block is 64 bytes
121    pub bls12381_bls12381_min_pk_verify_msg_cost_per_block: InternalGas,
122}
123/// ****************************************************************************
124/// ********************* native fun bls12381_min_pk_verify
125/// Implementation of the Move native function
126/// `bls12381_min_pk_verify(signature: &vector<u8>, public_key: &vector<u8>,
127/// msg: &vector<u8>): bool`   gas cost:
128/// bls12381_bls12381_min_pk_verify_cost_base                    | covers
129/// various fixed costs in the oper
130///              + bls12381_bls12381_min_pk_verify_msg_cost_per_byte    *
131///                size_of(msg)        | covers cost of operating on each byte
132///                of `msg`
133///              + bls12381_bls12381_min_pk_verify_msg_cost_per_block   *
134///                num_blocks(msg)     | covers cost of operating on each block
135///                in `msg`
136/// Note: each block is of size `BLS12381_BLOCK_SIZE` bytes, and we round up.
137///       `signature` and `public_key` are fixed size, so their costs are
138/// included in the base cost. *************************************************
139/// **********************************************
140pub fn bls12381_min_pk_verify(
141    context: &mut NativeContext,
142    ty_args: Vec<Type>,
143    mut args: VecDeque<Value>,
144) -> PartialVMResult<NativeResult> {
145    debug_assert!(ty_args.is_empty());
146    debug_assert!(args.len() == 3);
147
148    // Load the cost parameters from the protocol config
149    let bls12381_bls12381_min_pk_verify_cost_params = &context
150        .extensions()
151        .get::<NativesCostTable>()
152        .bls12381_bls12381_min_pk_verify_cost_params
153        .clone();
154
155    // Charge the base cost for this oper
156    native_charge_gas_early_exit!(
157        context,
158        bls12381_bls12381_min_pk_verify_cost_params.bls12381_bls12381_min_pk_verify_cost_base
159    );
160
161    let msg = pop_arg!(args, VectorRef);
162    let public_key_bytes = pop_arg!(args, VectorRef);
163    let signature_bytes = pop_arg!(args, VectorRef);
164
165    let msg_ref = msg.as_bytes_ref();
166    let public_key_bytes_ref = public_key_bytes.as_bytes_ref();
167    let signature_bytes_ref = signature_bytes.as_bytes_ref();
168
169    // Charge the arg size dependent costs
170    native_charge_gas_early_exit!(
171        context,
172        bls12381_bls12381_min_pk_verify_cost_params
173            .bls12381_bls12381_min_pk_verify_msg_cost_per_byte
174            * (msg_ref.len() as u64).into()
175            + bls12381_bls12381_min_pk_verify_cost_params
176                .bls12381_bls12381_min_pk_verify_msg_cost_per_block
177                * (msg_ref.len().div_ceil(BLS12381_BLOCK_SIZE) as u64).into()
178    );
179
180    let cost = context.gas_used();
181
182    let signature =
183        match <min_pk::BLS12381Signature as ToFromBytes>::from_bytes(&signature_bytes_ref) {
184            Ok(signature) => signature,
185            Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
186        };
187
188    let public_key =
189        match <min_pk::BLS12381PublicKey as ToFromBytes>::from_bytes(&public_key_bytes_ref) {
190            Ok(public_key) => match public_key.validate() {
191                Ok(_) => public_key,
192                Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
193            },
194            Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
195        };
196
197    Ok(NativeResult::ok(
198        cost,
199        smallvec![Value::bool(public_key.verify(&msg_ref, &signature).is_ok())],
200    ))
201}