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 = if curve == BLS12381 {
101 fastcrypto_zkp::bls12381::api::prepare_pvk_bytes(&verifying_key)
102 } else if curve == BN254 {
103 fastcrypto_zkp::bn254::api::prepare_pvk_bytes(&verifying_key)
104 } else {
105 return Ok(NativeResult::err(cost, INVALID_CURVE));
106 };
107
108 match result {
109 Ok(pvk) => Ok(NativeResult::ok(
110 cost,
111 smallvec![Value::struct_(values::Struct::pack(vec![
112 Value::vector_u8(pvk[0].to_vec()),
113 Value::vector_u8(pvk[1].to_vec()),
114 Value::vector_u8(pvk[2].to_vec()),
115 Value::vector_u8(pvk[3].to_vec())
116 ]))],
117 )),
118 Err(_) => Ok(NativeResult::err(cost, INVALID_VERIFYING_KEY)),
119 }
120}
121
122#[derive(Clone)]
123pub struct Groth16VerifyGroth16ProofInternalCostParams {
124 pub groth16_verify_groth16_proof_internal_bls12381_cost_base: InternalGas,
125 pub groth16_verify_groth16_proof_internal_bls12381_cost_per_public_input: InternalGas,
126
127 pub groth16_verify_groth16_proof_internal_bn254_cost_base: InternalGas,
128 pub groth16_verify_groth16_proof_internal_bn254_cost_per_public_input: InternalGas,
129
130 pub groth16_verify_groth16_proof_internal_public_input_cost_per_byte: InternalGas,
131}
132pub 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: &NativesCostTable = get_extension!(context)?;
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)?;
207 let cost = if get_extension!(context, ObjectRuntime)?
208 .protocol_config
209 .native_charging_v2()
210 {
211 context.gas_used()
212 } else {
213 context.gas_budget()
214 };
215 return Ok(NativeResult::err(cost, INVALID_CURVE));
216 }
217 };
218 native_charge_gas_early_exit!(context, base_cost);
220 native_charge_gas_early_exit!(
222 context,
223 cost_per_public_input * (num_public_inputs as u64).into()
224 + groth16_verify_groth16_proof_internal_cost_params
225 .groth16_verify_groth16_proof_internal_public_input_cost_per_byte
226 * (public_proof_inputs.len() as u64).into()
227 );
228
229 let cost = context.gas_used();
230
231 let result = if curve == BLS12381 {
232 if public_proof_inputs.len()
233 > fastcrypto::groups::bls12381::SCALAR_LENGTH * MAX_PUBLIC_INPUTS
234 {
235 return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
236 }
237 fastcrypto_zkp::bls12381::api::verify_groth16_in_bytes(
238 &vk_gamma_abc_g1,
239 &alpha_g1_beta_g2,
240 &gamma_g2_neg_pc,
241 &delta_g2_neg_pc,
242 &public_proof_inputs,
243 &proof_points,
244 )
245 } else if curve == BN254 {
246 if public_proof_inputs.len() > fastcrypto_zkp::bn254::api::SCALAR_SIZE * MAX_PUBLIC_INPUTS {
247 return Ok(NativeResult::err(cost, TOO_MANY_PUBLIC_INPUTS));
248 }
249 fastcrypto_zkp::bn254::api::verify_groth16_in_bytes(
250 &vk_gamma_abc_g1,
251 &alpha_g1_beta_g2,
252 &gamma_g2_neg_pc,
253 &delta_g2_neg_pc,
254 &public_proof_inputs,
255 &proof_points,
256 )
257 } else {
258 return Ok(NativeResult::err(cost, INVALID_CURVE));
259 };
260
261 Ok(NativeResult::ok(
262 cost,
263 smallvec![Value::bool(result.unwrap_or(false))],
264 ))
265}