sui_move_natives_latest/crypto/
groth16.rs1use crate::{NativesCostTable, get_extension, object_runtime::ObjectRuntime};
4use move_binary_format::errors::PartialVMResult;
5use move_core_types::gas_algebra::InternalGas;
6use move_vm_runtime::{native_charge_gas_early_exit, native_functions::NativeContext};
7use move_vm_types::{
8 loaded_data::runtime_types::Type,
9 natives::function::NativeResult,
10 pop_arg,
11 values::{self, Value, VectorRef},
12};
13use smallvec::smallvec;
14use std::collections::VecDeque;
15
16pub const INVALID_VERIFYING_KEY: u64 = 0;
17pub const INVALID_CURVE: u64 = 1;
18pub const TOO_MANY_PUBLIC_INPUTS: u64 = 2;
19
20pub const BLS12381: u8 = 0;
22pub const BN254: u8 = 1;
23
24pub const MAX_PUBLIC_INPUTS: usize = 8;
26
27#[derive(Clone)]
28pub struct Groth16PrepareVerifyingKeyCostParams {
29 pub groth16_prepare_verifying_key_bls12381_cost_base: InternalGas,
30 pub groth16_prepare_verifying_key_bn254_cost_base: InternalGas,
31}
32pub fn prepare_verifying_key_internal(
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() == 2);
47
48 let (groth16_prepare_verifying_key_cost_params, crypto_invalid_arguments_cost) = {
50 let cost_table: &NativesCostTable = get_extension!(context)?;
51 (
52 cost_table.groth16_prepare_verifying_key_cost_params.clone(),
53 cost_table.crypto_invalid_arguments_cost,
54 )
55 };
56 let bytes = pop_arg!(args, VectorRef);
57 let verifying_key = bytes.as_bytes_ref();
58
59 let curve = pop_arg!(args, u8);
60
61 let base_cost = match curve {
63 BLS12381 => {
64 groth16_prepare_verifying_key_cost_params
65 .groth16_prepare_verifying_key_bls12381_cost_base
66 }
67 BN254 => {
68 groth16_prepare_verifying_key_cost_params.groth16_prepare_verifying_key_bn254_cost_base
69 }
70 _ => {
71 context.charge_gas(crypto_invalid_arguments_cost);
73 return Ok(NativeResult::err(context.gas_used(), INVALID_CURVE));
74 }
75 };
76 native_charge_gas_early_exit!(context, base_cost);
78 let cost = context.gas_used();
79
80 let result;
81 if curve == BLS12381 {
82 result = fastcrypto_zkp::bls12381::api::prepare_pvk_bytes(&verifying_key);
83 } else if curve == BN254 {
84 result = fastcrypto_zkp::bn254::api::prepare_pvk_bytes(&verifying_key);
85 } else {
86 return Ok(NativeResult::err(cost, INVALID_CURVE));
87 }
88
89 match result {
90 Ok(pvk) => Ok(NativeResult::ok(
91 cost,
92 smallvec![Value::struct_(values::Struct::pack(vec![
93 Value::vector_u8(pvk[0].to_vec()),
94 Value::vector_u8(pvk[1].to_vec()),
95 Value::vector_u8(pvk[2].to_vec()),
96 Value::vector_u8(pvk[3].to_vec())
97 ]))],
98 )),
99 Err(_) => Ok(NativeResult::err(cost, INVALID_VERIFYING_KEY)),
100 }
101}
102
103#[derive(Clone)]
104pub struct Groth16VerifyGroth16ProofInternalCostParams {
105 pub groth16_verify_groth16_proof_internal_bls12381_cost_base: InternalGas,
106 pub groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: InternalGas,
107
108 pub groth16_verify_groth16_proof_internal_bn254_cost_base: InternalGas,
109 pub groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: InternalGas,
110
111 pub groth16_verify_groth16_proof_internal_public_input_cost_per_byte: InternalGas,
112}
113pub fn verify_groth16_proof_internal(
129 context: &mut NativeContext,
130 ty_args: Vec<Type>,
131 mut args: VecDeque<Value>,
132) -> PartialVMResult<NativeResult> {
133 debug_assert!(ty_args.is_empty());
134 debug_assert!(args.len() == 7);
135
136 let (groth16_verify_groth16_proof_internal_cost_params, crypto_invalid_arguments_cost) = {
138 let cost_table: &NativesCostTable = get_extension!(context)?;
139 (
140 cost_table
141 .groth16_verify_groth16_proof_internal_cost_params
142 .clone(),
143 cost_table.crypto_invalid_arguments_cost,
144 )
145 };
146 let bytes5 = pop_arg!(args, VectorRef);
147 let proof_points = bytes5.as_bytes_ref();
148
149 let bytes4 = pop_arg!(args, VectorRef);
150 let public_proof_inputs = bytes4.as_bytes_ref();
151
152 let bytes3 = pop_arg!(args, VectorRef);
153 let delta_g2_neg_pc = bytes3.as_bytes_ref();
154
155 let bytes2 = pop_arg!(args, VectorRef);
156 let gamma_g2_neg_pc = bytes2.as_bytes_ref();
157
158 let byte1 = pop_arg!(args, VectorRef);
159 let alpha_g1_beta_g2 = byte1.as_bytes_ref();
160
161 let bytes = pop_arg!(args, VectorRef);
162 let vk_gamma_abc_g1 = bytes.as_bytes_ref();
163
164 let curve = pop_arg!(args, u8);
165
166 let (base_cost, cost_per_public_input, num_public_inputs) = match curve {
167 BLS12381 => (
168 groth16_verify_groth16_proof_internal_cost_params
169 .groth16_verify_groth16_proof_internal_bls12381_cost_base,
170 groth16_verify_groth16_proof_internal_cost_params
171 .groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input,
172 public_proof_inputs
173 .len()
174 .div_ceil(fastcrypto::groups::bls12381::SCALAR_LENGTH),
175 ),
176 BN254 => (
177 groth16_verify_groth16_proof_internal_cost_params
178 .groth16_verify_groth16_proof_internal_bn254_cost_base,
179 groth16_verify_groth16_proof_internal_cost_params
180 .groth16_verify_groth16_proof_internal_bn254_cost_per_public_input,
181 public_proof_inputs
182 .len()
183 .div_ceil(fastcrypto_zkp::bn254::api::SCALAR_SIZE),
184 ),
185 _ => {
186 context.charge_gas(crypto_invalid_arguments_cost);
188 let cost = if get_extension!(context, ObjectRuntime)?
189 .protocol_config
190 .native_charging_v2()
191 {
192 context.gas_used()
193 } else {
194 context.gas_budget()
195 };
196 return Ok(NativeResult::err(cost, INVALID_CURVE));
197 }
198 };
199 native_charge_gas_early_exit!(context, base_cost);
201 native_charge_gas_early_exit!(
203 context,
204 cost_per_public_input * (num_public_inputs as u64).into()
205 + groth16_verify_groth16_proof_internal_cost_params
206 .groth16_verify_groth16_proof_internal_public_input_cost_per_byte
207 * (public_proof_inputs.len() as u64).into()
208 );
209
210 let cost = context.gas_used();
211
212 let result;
213 if curve == BLS12381 {
214 if public_proof_inputs.len()
215 > fastcrypto::groups::bls12381::SCALAR_LENGTH * MAX_PUBLIC_INPUTS
216 {
217 return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
218 }
219 result = fastcrypto_zkp::bls12381::api::verify_groth16_in_bytes(
220 &vk_gamma_abc_g1,
221 &alpha_g1_beta_g2,
222 &gamma_g2_neg_pc,
223 &delta_g2_neg_pc,
224 &public_proof_inputs,
225 &proof_points,
226 );
227 } else if curve == BN254 {
228 if public_proof_inputs.len() > fastcrypto_zkp::bn254::api::SCALAR_SIZE * MAX_PUBLIC_INPUTS {
229 return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
230 }
231 result = fastcrypto_zkp::bn254::api::verify_groth16_in_bytes(
232 &vk_gamma_abc_g1,
233 &alpha_g1_beta_g2,
234 &gamma_g2_neg_pc,
235 &delta_g2_neg_pc,
236 &public_proof_inputs,
237 &proof_points,
238 );
239 } else {
240 return Ok(NativeResult::err(cost, INVALID_CURVE));
241 }
242
243 Ok(NativeResult::ok(
244 cost,
245 smallvec![Value::bool(result.unwrap_or(false))],
246 ))
247}