sui_move_natives_latest/crypto/
bls12381.rs

1// Copyright (c) Mysten Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3use fastcrypto::{
4    bls12381::{min_pk, min_sig},
5    traits::{ToFromBytes, VerifyingKey},
6};
7use move_binary_format::errors::PartialVMResult;
8use move_core_types::gas_algebra::InternalGas;
9use move_vm_runtime::{native_charge_gas_early_exit, native_functions::NativeContext};
10use move_vm_types::{
11    loaded_data::runtime_types::Type,
12    natives::function::NativeResult,
13    pop_arg,
14    values::{Value, VectorRef},
15};
16use smallvec::smallvec;
17use std::collections::VecDeque;
18
19use crate::{NativesCostTable, get_extension};
20
21const BLS12381_BLOCK_SIZE: usize = 64;
22
23#[derive(Clone)]
24pub struct Bls12381Bls12381MinSigVerifyCostParams {
25    /// Base cost for invoking the `bls12381_min_sig_verify` function
26    pub bls12381_bls12381_min_sig_verify_cost_base: InternalGas,
27    /// Cost per byte of `msg`
28    pub bls12381_bls12381_min_sig_verify_msg_cost_per_byte: InternalGas,
29    /// Cost per block of `msg`, where a block is 64 bytes
30    pub bls12381_bls12381_min_sig_verify_msg_cost_per_block: InternalGas,
31}
32/***************************************************************************************************
33 * native fun bls12381_min_sig_verify
34 * Implementation of the Move native function `bls12381_min_sig_verify(signature: &vector<u8>, public_key: &vector<u8>, msg: &vector<u8>): bool`
35 *   gas cost: bls12381_bls12381_min_sig_verify_cost_base                    | covers various fixed costs in the oper
36 *              + bls12381_bls12381_min_sig_verify_msg_cost_per_byte    * size_of(msg)        | covers cost of operating on each byte of `msg`
37 *              + bls12381_bls12381_min_sig_verify_msg_cost_per_block   * num_blocks(msg)     | covers cost of operating on each block in `msg`
38 * Note: each block is of size `BLS12381_BLOCK_SIZE` bytes, and we round up.
39 *       `signature` and `public_key` are fixed size, so their costs are included in the base cost.
40 **************************************************************************************************/
41pub fn bls12381_min_sig_verify(
42    context: &mut NativeContext,
43    ty_args: Vec<Type>,
44    mut args: VecDeque<Value>,
45) -> PartialVMResult<NativeResult> {
46    debug_assert!(ty_args.is_empty());
47    debug_assert!(args.len() == 3);
48
49    // Load the cost parameters from the protocol config
50    let bls12381_bls12381_min_sig_verify_cost_params = get_extension!(context, NativesCostTable)?
51        .bls12381_bls12381_min_sig_verify_cost_params
52        .clone();
53    // Charge the base cost for this oper
54    native_charge_gas_early_exit!(
55        context,
56        bls12381_bls12381_min_sig_verify_cost_params.bls12381_bls12381_min_sig_verify_cost_base
57    );
58
59    let msg = pop_arg!(args, VectorRef);
60    let public_key_bytes = pop_arg!(args, VectorRef);
61    let signature_bytes = pop_arg!(args, VectorRef);
62
63    let msg_ref = msg.as_bytes_ref();
64    let public_key_bytes_ref = public_key_bytes.as_bytes_ref();
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        bls12381_bls12381_min_sig_verify_cost_params
71            .bls12381_bls12381_min_sig_verify_msg_cost_per_byte
72            * (msg_ref.len() as u64).into()
73            + bls12381_bls12381_min_sig_verify_cost_params
74                .bls12381_bls12381_min_sig_verify_msg_cost_per_block
75                * (msg_ref.len().div_ceil(BLS12381_BLOCK_SIZE) as u64).into()
76    );
77
78    let cost = context.gas_used();
79
80    let Ok(signature) =
81        <min_sig::BLS12381Signature as ToFromBytes>::from_bytes(&signature_bytes_ref)
82    else {
83        return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)]));
84    };
85
86    let public_key =
87        match <min_sig::BLS12381PublicKey as ToFromBytes>::from_bytes(&public_key_bytes_ref) {
88            Ok(public_key) => match public_key.validate() {
89                Ok(_) => public_key,
90                Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
91            },
92            Err(_) => 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}
100
101#[derive(Clone)]
102pub struct Bls12381Bls12381MinPkVerifyCostParams {
103    /// Base cost for invoking the `bls12381_min_sig_verify` function
104    pub bls12381_bls12381_min_pk_verify_cost_base: InternalGas,
105    /// Cost per byte of `msg`
106    pub bls12381_bls12381_min_pk_verify_msg_cost_per_byte: InternalGas,
107    /// Cost per block of `msg`, where a block is 64 bytes
108    pub bls12381_bls12381_min_pk_verify_msg_cost_per_block: InternalGas,
109}
110/***************************************************************************************************
111 * native fun bls12381_min_pk_verify
112 * Implementation of the Move native function `bls12381_min_pk_verify(signature: &vector<u8>, public_key: &vector<u8>, msg: &vector<u8>): bool`
113 *   gas cost: bls12381_bls12381_min_pk_verify_cost_base                    | covers various fixed costs in the oper
114 *              + bls12381_bls12381_min_pk_verify_msg_cost_per_byte    * size_of(msg)        | covers cost of operating on each byte of `msg`
115 *              + bls12381_bls12381_min_pk_verify_msg_cost_per_block   * num_blocks(msg)     | covers cost of operating on each block in `msg`
116 * Note: each block is of size `BLS12381_BLOCK_SIZE` bytes, and we round up.
117 *       `signature` and `public_key` are fixed size, so their costs are included in the base cost.
118 **************************************************************************************************/
119pub fn bls12381_min_pk_verify(
120    context: &mut NativeContext,
121    ty_args: Vec<Type>,
122    mut args: VecDeque<Value>,
123) -> PartialVMResult<NativeResult> {
124    debug_assert!(ty_args.is_empty());
125    debug_assert!(args.len() == 3);
126
127    // Load the cost parameters from the protocol config
128    let bls12381_bls12381_min_pk_verify_cost_params = get_extension!(context, NativesCostTable)?
129        .bls12381_bls12381_min_pk_verify_cost_params
130        .clone();
131
132    // Charge the base cost for this oper
133    native_charge_gas_early_exit!(
134        context,
135        bls12381_bls12381_min_pk_verify_cost_params.bls12381_bls12381_min_pk_verify_cost_base
136    );
137
138    let msg = pop_arg!(args, VectorRef);
139    let public_key_bytes = pop_arg!(args, VectorRef);
140    let signature_bytes = pop_arg!(args, VectorRef);
141
142    let msg_ref = msg.as_bytes_ref();
143    let public_key_bytes_ref = public_key_bytes.as_bytes_ref();
144    let signature_bytes_ref = signature_bytes.as_bytes_ref();
145
146    // Charge the arg size dependent costs
147    native_charge_gas_early_exit!(
148        context,
149        bls12381_bls12381_min_pk_verify_cost_params
150            .bls12381_bls12381_min_pk_verify_msg_cost_per_byte
151            * (msg_ref.len() as u64).into()
152            + bls12381_bls12381_min_pk_verify_cost_params
153                .bls12381_bls12381_min_pk_verify_msg_cost_per_block
154                * (msg_ref.len().div_ceil(BLS12381_BLOCK_SIZE) as u64).into()
155    );
156
157    let cost = context.gas_used();
158
159    let signature =
160        match <min_pk::BLS12381Signature as ToFromBytes>::from_bytes(&signature_bytes_ref) {
161            Ok(signature) => signature,
162            Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
163        };
164
165    let public_key =
166        match <min_pk::BLS12381PublicKey as ToFromBytes>::from_bytes(&public_key_bytes_ref) {
167            Ok(public_key) => match public_key.validate() {
168                Ok(_) => public_key,
169                Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
170            },
171            Err(_) => return Ok(NativeResult::ok(cost, smallvec![Value::bool(false)])),
172        };
173
174    Ok(NativeResult::ok(
175        cost,
176        smallvec![Value::bool(public_key.verify(&msg_ref, &signature).is_ok())],
177    ))
178}