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