sui_move_natives_latest/crypto/
groth16.rs1use crate::{NativesCostTable, get_extension, object_runtime::ObjectRuntime};
4use move_binary_format::errors::PartialVMResult;
5use move_binary_format::partial_vm_error;
6use move_core_types::gas_algebra::InternalGas;
7use move_vm_runtime::{
8 execution::{
9 Type,
10 values::{self, Value, VectorRef},
11 },
12 natives::functions::NativeResult,
13 pop_arg,
14};
15use move_vm_runtime::{native_charge_gas_early_exit, natives::functions::NativeContext};
16use smallvec::smallvec;
17use std::collections::VecDeque;
18
19pub const INVALID_VERIFYING_KEY: u64 = 0;
20pub const INVALID_CURVE: u64 = 1;
21pub const TOO_MANY_PUBLIC_INPUTS: u64 = 2;
22
23pub const BLS12381: u8 = 0;
25pub const BN254: u8 = 1;
26
27pub const MAX_PUBLIC_INPUTS: usize = 8;
29
30#[derive(Clone)]
31pub struct Groth16PrepareVerifyingKeyCostParams {
32 pub groth16_prepare_verifying_key_bls12381_cost_base: InternalGas,
33 pub groth16_prepare_verifying_key_bn254_cost_base: InternalGas,
34}
35pub fn prepare_verifying_key_internal(
44 context: &mut NativeContext,
45 ty_args: Vec<Type>,
46 mut args: VecDeque<Value>,
47) -> PartialVMResult<NativeResult> {
48 debug_assert!(ty_args.is_empty());
49 debug_assert!(args.len() == 2);
50
51 let (groth16_prepare_verifying_key_cost_params, crypto_invalid_arguments_cost) = {
53 let cost_table: &NativesCostTable = get_extension!(context)?;
54 (
55 cost_table.groth16_prepare_verifying_key_cost_params.clone(),
56 cost_table.crypto_invalid_arguments_cost,
57 )
58 };
59 let bytes = pop_arg!(args, VectorRef);
60 let verifying_key = bytes.as_bytes_ref()?;
61
62 let curve = pop_arg!(args, u8);
63
64 let base_cost = match curve {
66 BLS12381 => {
67 groth16_prepare_verifying_key_cost_params
68 .groth16_prepare_verifying_key_bls12381_cost_base
69 }
70 BN254 => {
71 groth16_prepare_verifying_key_cost_params.groth16_prepare_verifying_key_bn254_cost_base
72 }
73 _ => {
74 context.charge_gas(crypto_invalid_arguments_cost)?;
75 return Ok(NativeResult::err(context.gas_used(), INVALID_CURVE));
76 }
77 };
78 native_charge_gas_early_exit!(context, base_cost);
80 let cost = context.gas_used();
81
82 if get_extension!(context, ObjectRuntime)?
83 .protocol_config
84 .limit_groth16_pvk_inputs()
85 {
86 let num_public_inputs = match curve {
88 BLS12381 => fastcrypto_zkp::bls12381::api::get_public_inputs_num(verifying_key.len()),
89 BN254 => fastcrypto_zkp::bn254::api::get_public_inputs_num(verifying_key.len()),
90 _ => return Err(partial_vm_error!(UNKNOWN_INVARIANT_VIOLATION_ERROR)),
91 };
92 let Ok(n) = num_public_inputs else {
93 return Ok(NativeResult::err(cost, INVALID_VERIFYING_KEY));
94 };
95 if n > MAX_PUBLIC_INPUTS {
96 return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
97 }
98 }
99
100 let result;
101 if curve == BLS12381 {
102 result = fastcrypto_zkp::bls12381::api::prepare_pvk_bytes(&verifying_key);
103 } else if curve == BN254 {
104 result = fastcrypto_zkp::bn254::api::prepare_pvk_bytes(&verifying_key);
105 } else {
106 return Ok(NativeResult::err(cost, INVALID_CURVE));
107 }
108
109 match result {
110 Ok(pvk) => Ok(NativeResult::ok(
111 cost,
112 smallvec![Value::struct_(values::Struct::pack(vec![
113 Value::vector_u8(pvk[0].to_vec()),
114 Value::vector_u8(pvk[1].to_vec()),
115 Value::vector_u8(pvk[2].to_vec()),
116 Value::vector_u8(pvk[3].to_vec())
117 ]))],
118 )),
119 Err(_) => Ok(NativeResult::err(cost, INVALID_VERIFYING_KEY)),
120 }
121}
122
123#[derive(Clone)]
124pub struct Groth16VerifyGroth16ProofInternalCostParams {
125 pub groth16_verify_groth16_proof_internal_bls12381_cost_base: InternalGas,
126 pub groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: InternalGas,
127
128 pub groth16_verify_groth16_proof_internal_bn254_cost_base: InternalGas,
129 pub groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: InternalGas,
130
131 pub groth16_verify_groth16_proof_internal_public_input_cost_per_byte: InternalGas,
132}
133pub fn verify_groth16_proof_internal(
149 context: &mut NativeContext,
150 ty_args: Vec<Type>,
151 mut args: VecDeque<Value>,
152) -> PartialVMResult<NativeResult> {
153 debug_assert!(ty_args.is_empty());
154 debug_assert!(args.len() == 7);
155
156 let (groth16_verify_groth16_proof_internal_cost_params, crypto_invalid_arguments_cost) = {
158 let cost_table: &NativesCostTable = get_extension!(context)?;
159 (
160 cost_table
161 .groth16_verify_groth16_proof_internal_cost_params
162 .clone(),
163 cost_table.crypto_invalid_arguments_cost,
164 )
165 };
166 let bytes5 = pop_arg!(args, VectorRef);
167 let proof_points = bytes5.as_bytes_ref()?;
168
169 let bytes4 = pop_arg!(args, VectorRef);
170 let public_proof_inputs = bytes4.as_bytes_ref()?;
171
172 let bytes3 = pop_arg!(args, VectorRef);
173 let delta_g2_neg_pc = bytes3.as_bytes_ref()?;
174
175 let bytes2 = pop_arg!(args, VectorRef);
176 let gamma_g2_neg_pc = bytes2.as_bytes_ref()?;
177
178 let byte1 = pop_arg!(args, VectorRef);
179 let alpha_g1_beta_g2 = byte1.as_bytes_ref()?;
180
181 let bytes = pop_arg!(args, VectorRef);
182 let vk_gamma_abc_g1 = bytes.as_bytes_ref()?;
183
184 let curve = pop_arg!(args, u8);
185
186 let (base_cost, cost_per_public_input, num_public_inputs) = match curve {
187 BLS12381 => (
188 groth16_verify_groth16_proof_internal_cost_params
189 .groth16_verify_groth16_proof_internal_bls12381_cost_base,
190 groth16_verify_groth16_proof_internal_cost_params
191 .groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input,
192 public_proof_inputs
193 .len()
194 .div_ceil(fastcrypto::groups::bls12381::SCALAR_LENGTH),
195 ),
196 BN254 => (
197 groth16_verify_groth16_proof_internal_cost_params
198 .groth16_verify_groth16_proof_internal_bn254_cost_base,
199 groth16_verify_groth16_proof_internal_cost_params
200 .groth16_verify_groth16_proof_internal_bn254_cost_per_public_input,
201 public_proof_inputs
202 .len()
203 .div_ceil(fastcrypto_zkp::bn254::api::SCALAR_SIZE),
204 ),
205 _ => {
206 context.charge_gas(crypto_invalid_arguments_cost)?;
208 let cost = if get_extension!(context, ObjectRuntime)?
209 .protocol_config
210 .native_charging_v2()
211 {
212 context.gas_used()
213 } else {
214 context.gas_budget()
215 };
216 return Ok(NativeResult::err(cost, INVALID_CURVE));
217 }
218 };
219 native_charge_gas_early_exit!(context, base_cost);
221 native_charge_gas_early_exit!(
223 context,
224 cost_per_public_input * (num_public_inputs as u64).into()
225 + groth16_verify_groth16_proof_internal_cost_params
226 .groth16_verify_groth16_proof_internal_public_input_cost_per_byte
227 * (public_proof_inputs.len() as u64).into()
228 );
229
230 let cost = context.gas_used();
231
232 let result;
233 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 result = 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 result = 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}