iota_move_natives_latest/crypto/
groth16.rs1use std::collections::VecDeque;
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::{self, Value, VectorRef},
15};
16use smallvec::smallvec;
17
18use crate::{NativesCostTable, object_runtime::ObjectRuntime};
19
20pub const INVALID_VERIFYING_KEY: u64 = 0;
21pub const INVALID_CURVE: u64 = 1;
22pub const TOO_MANY_PUBLIC_INPUTS: u64 = 2;
23
24pub const BLS12381: u8 = 0;
26pub const BN254: u8 = 1;
27
28pub const MAX_PUBLIC_INPUTS: usize = 8;
31
32#[derive(Clone)]
33pub struct Groth16PrepareVerifyingKeyCostParams {
34 pub groth16_prepare_verifying_key_bls12381_cost_base: InternalGas,
35 pub groth16_prepare_verifying_key_bn254_cost_base: InternalGas,
36}
37pub fn prepare_verifying_key_internal(
50 context: &mut NativeContext,
51 ty_args: Vec<Type>,
52 mut args: VecDeque<Value>,
53) -> PartialVMResult<NativeResult> {
54 debug_assert!(ty_args.is_empty());
55 debug_assert!(args.len() == 2);
56
57 let (groth16_prepare_verifying_key_cost_params, crypto_invalid_arguments_cost) = {
59 let cost_table = &context.extensions().get::<NativesCostTable>();
60 (
61 cost_table.groth16_prepare_verifying_key_cost_params.clone(),
62 cost_table.crypto_invalid_arguments_cost,
63 )
64 };
65 let bytes = pop_arg!(args, VectorRef);
66 let verifying_key = bytes.as_bytes_ref();
67
68 let curve = pop_arg!(args, u8);
69
70 let base_cost = match curve {
72 BLS12381 => {
73 groth16_prepare_verifying_key_cost_params
74 .groth16_prepare_verifying_key_bls12381_cost_base
75 }
76 BN254 => {
77 groth16_prepare_verifying_key_cost_params.groth16_prepare_verifying_key_bn254_cost_base
78 }
79 _ => {
80 context.charge_gas(crypto_invalid_arguments_cost);
83 return Ok(NativeResult::err(context.gas_used(), INVALID_CURVE));
84 }
85 };
86 native_charge_gas_early_exit!(context, base_cost);
88 let cost = context.gas_used();
89
90 let result;
91 if curve == BLS12381 {
92 result = fastcrypto_zkp::bls12381::api::prepare_pvk_bytes(&verifying_key);
93 } else if curve == BN254 {
94 result = fastcrypto_zkp::bn254::api::prepare_pvk_bytes(&verifying_key);
95 } else {
96 return Ok(NativeResult::err(cost, INVALID_CURVE));
97 }
98
99 match result {
100 Ok(pvk) => Ok(NativeResult::ok(
101 cost,
102 smallvec![Value::struct_(values::Struct::pack(vec![
103 Value::vector_u8(pvk[0].to_vec()),
104 Value::vector_u8(pvk[1].to_vec()),
105 Value::vector_u8(pvk[2].to_vec()),
106 Value::vector_u8(pvk[3].to_vec())
107 ]))],
108 )),
109 Err(_) => Ok(NativeResult::err(cost, INVALID_VERIFYING_KEY)),
110 }
111}
112
113#[derive(Clone)]
114pub struct Groth16VerifyGroth16ProofInternalCostParams {
115 pub groth16_verify_groth16_proof_internal_bls12381_cost_base: InternalGas,
116 pub groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: InternalGas,
117
118 pub groth16_verify_groth16_proof_internal_bn254_cost_base: InternalGas,
119 pub groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: InternalGas,
120
121 pub groth16_verify_groth16_proof_internal_public_input_cost_per_byte: InternalGas,
122}
123pub fn verify_groth16_proof_internal(
148 context: &mut NativeContext,
149 ty_args: Vec<Type>,
150 mut args: VecDeque<Value>,
151) -> PartialVMResult<NativeResult> {
152 debug_assert!(ty_args.is_empty());
153 debug_assert!(args.len() == 7);
154
155 let (groth16_verify_groth16_proof_internal_cost_params, crypto_invalid_arguments_cost) = {
157 let cost_table = &context.extensions().get::<NativesCostTable>();
158 (
159 cost_table
160 .groth16_verify_groth16_proof_internal_cost_params
161 .clone(),
162 cost_table.crypto_invalid_arguments_cost,
163 )
164 };
165 let bytes5 = pop_arg!(args, VectorRef);
166 let proof_points = bytes5.as_bytes_ref();
167
168 let bytes4 = pop_arg!(args, VectorRef);
169 let public_proof_inputs = bytes4.as_bytes_ref();
170
171 let bytes3 = pop_arg!(args, VectorRef);
172 let delta_g2_neg_pc = bytes3.as_bytes_ref();
173
174 let bytes2 = pop_arg!(args, VectorRef);
175 let gamma_g2_neg_pc = bytes2.as_bytes_ref();
176
177 let byte1 = pop_arg!(args, VectorRef);
178 let alpha_g1_beta_g2 = byte1.as_bytes_ref();
179
180 let bytes = pop_arg!(args, VectorRef);
181 let vk_gamma_abc_g1 = bytes.as_bytes_ref();
182
183 let curve = pop_arg!(args, u8);
184
185 let (base_cost, cost_per_public_input, num_public_inputs) = match curve {
186 BLS12381 => (
187 groth16_verify_groth16_proof_internal_cost_params
188 .groth16_verify_groth16_proof_internal_bls12381_cost_base,
189 groth16_verify_groth16_proof_internal_cost_params
190 .groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input,
191 public_proof_inputs
192 .len()
193 .div_ceil(fastcrypto::groups::bls12381::SCALAR_LENGTH),
194 ),
195 BN254 => (
196 groth16_verify_groth16_proof_internal_cost_params
197 .groth16_verify_groth16_proof_internal_bn254_cost_base,
198 groth16_verify_groth16_proof_internal_cost_params
199 .groth16_verify_groth16_proof_internal_bn254_cost_per_public_input,
200 public_proof_inputs
201 .len()
202 .div_ceil(fastcrypto_zkp::bn254::api::SCALAR_SIZE),
203 ),
204 _ => {
205 context.charge_gas(crypto_invalid_arguments_cost);
208 let cost = if context
209 .extensions()
210 .get::<ObjectRuntime>()
211 .protocol_config
212 .native_charging_v2()
213 {
214 context.gas_used()
215 } else {
216 context.gas_budget()
217 };
218 return Ok(NativeResult::err(cost, INVALID_CURVE));
219 }
220 };
221 native_charge_gas_early_exit!(context, base_cost);
223 native_charge_gas_early_exit!(
225 context,
226 cost_per_public_input * (num_public_inputs as u64).into()
227 + groth16_verify_groth16_proof_internal_cost_params
228 .groth16_verify_groth16_proof_internal_public_input_cost_per_byte
229 * (public_proof_inputs.len() as u64).into()
230 );
231
232 let cost = context.gas_used();
233
234 let result;
235 if curve == BLS12381 {
236 if public_proof_inputs.len()
237 > fastcrypto::groups::bls12381::SCALAR_LENGTH * MAX_PUBLIC_INPUTS
238 {
239 return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
240 }
241 result = fastcrypto_zkp::bls12381::api::verify_groth16_in_bytes(
242 &vk_gamma_abc_g1,
243 &alpha_g1_beta_g2,
244 &gamma_g2_neg_pc,
245 &delta_g2_neg_pc,
246 &public_proof_inputs,
247 &proof_points,
248 );
249 } else if curve == BN254 {
250 if public_proof_inputs.len() > fastcrypto_zkp::bn254::api::SCALAR_SIZE * MAX_PUBLIC_INPUTS {
251 return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
252 }
253 result = fastcrypto_zkp::bn254::api::verify_groth16_in_bytes(
254 &vk_gamma_abc_g1,
255 &alpha_g1_beta_g2,
256 &gamma_g2_neg_pc,
257 &delta_g2_neg_pc,
258 &public_proof_inputs,
259 &proof_points,
260 );
261 } else {
262 return Ok(NativeResult::err(cost, INVALID_CURVE));
263 }
264
265 Ok(NativeResult::ok(
266 cost,
267 smallvec![Value::bool(result.unwrap_or(false))],
268 ))
269}