sui_move_natives_latest/crypto/
groth16.rsuse crate::{object_runtime::ObjectRuntime, NativesCostTable};
use move_binary_format::errors::PartialVMResult;
use move_core_types::gas_algebra::InternalGas;
use move_vm_runtime::{native_charge_gas_early_exit, native_functions::NativeContext};
use move_vm_types::{
loaded_data::runtime_types::Type,
natives::function::NativeResult,
pop_arg,
values::{self, Value, VectorRef},
};
use smallvec::smallvec;
use std::collections::VecDeque;
pub const INVALID_VERIFYING_KEY: u64 = 0;
pub const INVALID_CURVE: u64 = 1;
pub const TOO_MANY_PUBLIC_INPUTS: u64 = 2;
pub const BLS12381: u8 = 0;
pub const BN254: u8 = 1;
pub const MAX_PUBLIC_INPUTS: usize = 8;
#[derive(Clone)]
pub struct Groth16PrepareVerifyingKeyCostParams {
pub groth16_prepare_verifying_key_bls12381_cost_base: InternalGas,
pub groth16_prepare_verifying_key_bn254_cost_base: InternalGas,
}
pub fn prepare_verifying_key_internal(
context: &mut NativeContext,
ty_args: Vec<Type>,
mut args: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
debug_assert!(ty_args.is_empty());
debug_assert!(args.len() == 2);
let (groth16_prepare_verifying_key_cost_params, crypto_invalid_arguments_cost) = {
let cost_table = &context.extensions().get::<NativesCostTable>()?;
(
cost_table.groth16_prepare_verifying_key_cost_params.clone(),
cost_table.crypto_invalid_arguments_cost,
)
};
let bytes = pop_arg!(args, VectorRef);
let verifying_key = bytes.as_bytes_ref();
let curve = pop_arg!(args, u8);
let base_cost = match curve {
BLS12381 => {
groth16_prepare_verifying_key_cost_params
.groth16_prepare_verifying_key_bls12381_cost_base
}
BN254 => {
groth16_prepare_verifying_key_cost_params.groth16_prepare_verifying_key_bn254_cost_base
}
_ => {
context.charge_gas(crypto_invalid_arguments_cost);
return Ok(NativeResult::err(context.gas_used(), INVALID_CURVE));
}
};
native_charge_gas_early_exit!(context, base_cost);
let cost = context.gas_used();
let result;
if curve == BLS12381 {
result = fastcrypto_zkp::bls12381::api::prepare_pvk_bytes(&verifying_key);
} else if curve == BN254 {
result = fastcrypto_zkp::bn254::api::prepare_pvk_bytes(&verifying_key);
} else {
return Ok(NativeResult::err(cost, INVALID_CURVE));
}
match result {
Ok(pvk) => Ok(NativeResult::ok(
cost,
smallvec![Value::struct_(values::Struct::pack(vec![
Value::vector_u8(pvk[0].to_vec()),
Value::vector_u8(pvk[1].to_vec()),
Value::vector_u8(pvk[2].to_vec()),
Value::vector_u8(pvk[3].to_vec())
]))],
)),
Err(_) => Ok(NativeResult::err(cost, INVALID_VERIFYING_KEY)),
}
}
#[derive(Clone)]
pub struct Groth16VerifyGroth16ProofInternalCostParams {
pub groth16_verify_groth16_proof_internal_bls12381_cost_base: InternalGas,
pub groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: InternalGas,
pub groth16_verify_groth16_proof_internal_bn254_cost_base: InternalGas,
pub groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: InternalGas,
pub groth16_verify_groth16_proof_internal_public_input_cost_per_byte: InternalGas,
}
pub fn verify_groth16_proof_internal(
context: &mut NativeContext,
ty_args: Vec<Type>,
mut args: VecDeque<Value>,
) -> PartialVMResult<NativeResult> {
debug_assert!(ty_args.is_empty());
debug_assert!(args.len() == 7);
let (groth16_verify_groth16_proof_internal_cost_params, crypto_invalid_arguments_cost) = {
let cost_table = &context.extensions().get::<NativesCostTable>()?;
(
cost_table
.groth16_verify_groth16_proof_internal_cost_params
.clone(),
cost_table.crypto_invalid_arguments_cost,
)
};
let bytes5 = pop_arg!(args, VectorRef);
let proof_points = bytes5.as_bytes_ref();
let bytes4 = pop_arg!(args, VectorRef);
let public_proof_inputs = bytes4.as_bytes_ref();
let bytes3 = pop_arg!(args, VectorRef);
let delta_g2_neg_pc = bytes3.as_bytes_ref();
let bytes2 = pop_arg!(args, VectorRef);
let gamma_g2_neg_pc = bytes2.as_bytes_ref();
let byte1 = pop_arg!(args, VectorRef);
let alpha_g1_beta_g2 = byte1.as_bytes_ref();
let bytes = pop_arg!(args, VectorRef);
let vk_gamma_abc_g1 = bytes.as_bytes_ref();
let curve = pop_arg!(args, u8);
let (base_cost, cost_per_public_input, num_public_inputs) = match curve {
BLS12381 => (
groth16_verify_groth16_proof_internal_cost_params
.groth16_verify_groth16_proof_internal_bls12381_cost_base,
groth16_verify_groth16_proof_internal_cost_params
.groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input,
public_proof_inputs
.len()
.div_ceil(fastcrypto::groups::bls12381::SCALAR_LENGTH),
),
BN254 => (
groth16_verify_groth16_proof_internal_cost_params
.groth16_verify_groth16_proof_internal_bn254_cost_base,
groth16_verify_groth16_proof_internal_cost_params
.groth16_verify_groth16_proof_internal_bn254_cost_per_public_input,
public_proof_inputs
.len()
.div_ceil(fastcrypto_zkp::bn254::api::SCALAR_SIZE),
),
_ => {
context.charge_gas(crypto_invalid_arguments_cost);
let cost = if context
.extensions()
.get::<ObjectRuntime>()?
.protocol_config
.native_charging_v2()
{
context.gas_used()
} else {
context.gas_budget()
};
return Ok(NativeResult::err(cost, INVALID_CURVE));
}
};
native_charge_gas_early_exit!(context, base_cost);
native_charge_gas_early_exit!(
context,
cost_per_public_input * (num_public_inputs as u64).into()
+ groth16_verify_groth16_proof_internal_cost_params
.groth16_verify_groth16_proof_internal_public_input_cost_per_byte
* (public_proof_inputs.len() as u64).into()
);
let cost = context.gas_used();
let result;
if curve == BLS12381 {
if public_proof_inputs.len()
> fastcrypto::groups::bls12381::SCALAR_LENGTH * MAX_PUBLIC_INPUTS
{
return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
}
result = fastcrypto_zkp::bls12381::api::verify_groth16_in_bytes(
&vk_gamma_abc_g1,
&alpha_g1_beta_g2,
&gamma_g2_neg_pc,
&delta_g2_neg_pc,
&public_proof_inputs,
&proof_points,
);
} else if curve == BN254 {
if public_proof_inputs.len() > fastcrypto_zkp::bn254::api::SCALAR_SIZE * MAX_PUBLIC_INPUTS {
return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
}
result = fastcrypto_zkp::bn254::api::verify_groth16_in_bytes(
&vk_gamma_abc_g1,
&alpha_g1_beta_g2,
&gamma_g2_neg_pc,
&delta_g2_neg_pc,
&public_proof_inputs,
&proof_points,
);
} else {
return Ok(NativeResult::err(cost, INVALID_CURVE));
}
Ok(NativeResult::ok(
cost,
smallvec![Value::bool(result.unwrap_or(false))],
))
}