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