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 = if curve == BLS12381 {
91 fastcrypto_zkp::bls12381::api::prepare_pvk_bytes(&verifying_key)
92 } else if curve == BN254 {
93 fastcrypto_zkp::bn254::api::prepare_pvk_bytes(&verifying_key)
94 } else {
95 return Ok(NativeResult::err(cost, INVALID_CURVE));
96 };
97
98 match result {
99 Ok(pvk) => Ok(NativeResult::ok(
100 cost,
101 smallvec![Value::struct_(values::Struct::pack(vec![
102 Value::vector_u8(pvk[0].to_vec()),
103 Value::vector_u8(pvk[1].to_vec()),
104 Value::vector_u8(pvk[2].to_vec()),
105 Value::vector_u8(pvk[3].to_vec())
106 ]))],
107 )),
108 Err(_) => Ok(NativeResult::err(cost, INVALID_VERIFYING_KEY)),
109 }
110}
111
112#[derive(Clone)]
113pub struct Groth16VerifyGroth16ProofInternalCostParams {
114 pub groth16_verify_groth16_proof_internal_bls12381_cost_base: InternalGas,
115 pub groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: InternalGas,
116
117 pub groth16_verify_groth16_proof_internal_bn254_cost_base: InternalGas,
118 pub groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: InternalGas,
119
120 pub groth16_verify_groth16_proof_internal_public_input_cost_per_byte: InternalGas,
121}
122pub fn verify_groth16_proof_internal(
147 context: &mut NativeContext,
148 ty_args: Vec<Type>,
149 mut args: VecDeque<Value>,
150) -> PartialVMResult<NativeResult> {
151 debug_assert!(ty_args.is_empty());
152 debug_assert!(args.len() == 7);
153
154 let (groth16_verify_groth16_proof_internal_cost_params, crypto_invalid_arguments_cost) = {
156 let cost_table = &context.extensions().get::<NativesCostTable>()?;
157 (
158 cost_table
159 .groth16_verify_groth16_proof_internal_cost_params
160 .clone(),
161 cost_table.crypto_invalid_arguments_cost,
162 )
163 };
164 let bytes5 = pop_arg!(args, VectorRef);
165 let proof_points = bytes5.as_bytes_ref();
166
167 let bytes4 = pop_arg!(args, VectorRef);
168 let public_proof_inputs = bytes4.as_bytes_ref();
169
170 let bytes3 = pop_arg!(args, VectorRef);
171 let delta_g2_neg_pc = bytes3.as_bytes_ref();
172
173 let bytes2 = pop_arg!(args, VectorRef);
174 let gamma_g2_neg_pc = bytes2.as_bytes_ref();
175
176 let byte1 = pop_arg!(args, VectorRef);
177 let alpha_g1_beta_g2 = byte1.as_bytes_ref();
178
179 let bytes = pop_arg!(args, VectorRef);
180 let vk_gamma_abc_g1 = bytes.as_bytes_ref();
181
182 let curve = pop_arg!(args, u8);
183
184 let (base_cost, cost_per_public_input, num_public_inputs) = match curve {
185 BLS12381 => (
186 groth16_verify_groth16_proof_internal_cost_params
187 .groth16_verify_groth16_proof_internal_bls12381_cost_base,
188 groth16_verify_groth16_proof_internal_cost_params
189 .groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input,
190 public_proof_inputs
191 .len()
192 .div_ceil(fastcrypto::groups::bls12381::SCALAR_LENGTH),
193 ),
194 BN254 => (
195 groth16_verify_groth16_proof_internal_cost_params
196 .groth16_verify_groth16_proof_internal_bn254_cost_base,
197 groth16_verify_groth16_proof_internal_cost_params
198 .groth16_verify_groth16_proof_internal_bn254_cost_per_public_input,
199 public_proof_inputs
200 .len()
201 .div_ceil(fastcrypto_zkp::bn254::api::SCALAR_SIZE),
202 ),
203 _ => {
204 context.charge_gas(crypto_invalid_arguments_cost);
207 let cost = if context
208 .extensions()
209 .get::<ObjectRuntime>()?
210 .protocol_config
211 .native_charging_v2()
212 {
213 context.gas_used()
214 } else {
215 context.gas_budget()
216 };
217 return Ok(NativeResult::err(cost, INVALID_CURVE));
218 }
219 };
220 native_charge_gas_early_exit!(context, base_cost);
222 native_charge_gas_early_exit!(
224 context,
225 cost_per_public_input * (num_public_inputs as u64).into()
226 + groth16_verify_groth16_proof_internal_cost_params
227 .groth16_verify_groth16_proof_internal_public_input_cost_per_byte
228 * (public_proof_inputs.len() as u64).into()
229 );
230
231 let cost = context.gas_used();
232
233 let result = if curve == BLS12381 {
234 if public_proof_inputs.len()
235 > fastcrypto::groups::bls12381::SCALAR_LENGTH * MAX_PUBLIC_INPUTS
236 {
237 return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
238 }
239 fastcrypto_zkp::bls12381::api::verify_groth16_in_bytes(
240 &vk_gamma_abc_g1,
241 &alpha_g1_beta_g2,
242 &gamma_g2_neg_pc,
243 &delta_g2_neg_pc,
244 &public_proof_inputs,
245 &proof_points,
246 )
247 } else if curve == BN254 {
248 if public_proof_inputs.len() > fastcrypto_zkp::bn254::api::SCALAR_SIZE * MAX_PUBLIC_INPUTS {
249 return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
250 }
251 fastcrypto_zkp::bn254::api::verify_groth16_in_bytes(
252 &vk_gamma_abc_g1,
253 &alpha_g1_beta_g2,
254 &gamma_g2_neg_pc,
255 &delta_g2_neg_pc,
256 &public_proof_inputs,
257 &proof_points,
258 )
259 } else {
260 return Ok(NativeResult::err(cost, INVALID_CURVE));
261 };
262
263 Ok(NativeResult::ok(
264 cost,
265 smallvec![Value::bool(result.unwrap_or(false))],
266 ))
267}