sui_move_natives_latest/crypto/
vdf.rs1use crate::object_runtime::ObjectRuntime;
4use crate::{NativesCostTable, get_extension};
5use fastcrypto_vdf::class_group::QuadraticForm;
6use fastcrypto_vdf::class_group::discriminant::DISCRIMINANT_3072;
7use fastcrypto_vdf::vdf::VDF;
8use fastcrypto_vdf::vdf::wesolowski::DefaultVDF;
9use move_binary_format::errors::PartialVMResult;
10use move_core_types::gas_algebra::InternalGas;
11use move_core_types::vm_status::StatusCode;
12use move_vm_runtime::{
13 execution::{
14 Type,
15 values::{Value, VectorRef},
16 },
17 natives::functions::{NativeResult, PartialVMError},
18 pop_arg,
19};
20use move_vm_runtime::{native_charge_gas_early_exit, natives::functions::NativeContext};
21use smallvec::smallvec;
22use std::collections::VecDeque;
23
24pub const INVALID_INPUT_ERROR: u64 = 0;
25pub const NOT_SUPPORTED_ERROR: u64 = 1;
26
27fn is_supported(context: &NativeContext) -> PartialVMResult<bool> {
28 Ok(get_extension!(context, ObjectRuntime)?
29 .protocol_config
30 .enable_vdf())
31}
32
33#[derive(Clone)]
34pub struct VDFCostParams {
35 pub vdf_verify_cost: Option<InternalGas>,
36 pub hash_to_input_cost: Option<InternalGas>,
37}
38
39pub fn vdf_verify_internal(
51 context: &mut NativeContext,
52 ty_args: Vec<Type>,
53 mut args: VecDeque<Value>,
54) -> PartialVMResult<NativeResult> {
55 let cost = context.gas_used();
56 if !is_supported(context)? {
57 return Ok(NativeResult::err(cost, NOT_SUPPORTED_ERROR));
58 }
59
60 let cost_params = get_extension!(context, NativesCostTable)?
62 .vdf_cost_params
63 .clone();
64
65 native_charge_gas_early_exit!(
67 context,
68 cost_params
69 .vdf_verify_cost
70 .ok_or_else(
71 || PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
72 .with_message("Gas cost for vdf_verify not available".to_string())
73 )?
74 );
75
76 debug_assert!(ty_args.is_empty());
77 debug_assert!(args.len() == 4);
78
79 let iterations = pop_arg!(args, u64);
81 let proof_bytes = pop_arg!(args, VectorRef);
82 let output_bytes = pop_arg!(args, VectorRef);
83 let input_bytes = pop_arg!(args, VectorRef);
84
85 let input = match bcs::from_bytes::<QuadraticForm>(&input_bytes.as_bytes_ref()?) {
86 Ok(input) => input,
87 Err(_) => return Ok(NativeResult::err(context.gas_used(), INVALID_INPUT_ERROR)),
88 };
89
90 let proof = match bcs::from_bytes::<QuadraticForm>(&proof_bytes.as_bytes_ref()?) {
91 Ok(proof) => proof,
92 Err(_) => return Ok(NativeResult::err(context.gas_used(), INVALID_INPUT_ERROR)),
93 };
94
95 let output = match bcs::from_bytes::<QuadraticForm>(&output_bytes.as_bytes_ref()?) {
96 Ok(output) => output,
97 Err(_) => return Ok(NativeResult::err(context.gas_used(), INVALID_INPUT_ERROR)),
98 };
99
100 let vdf = DefaultVDF::new(DISCRIMINANT_3072.clone(), iterations);
103 let verified = vdf.verify(&input, &output, &proof).is_ok();
104
105 Ok(NativeResult::ok(
106 context.gas_used(),
107 smallvec![Value::bool(verified)],
108 ))
109}
110
111pub fn hash_to_input_internal(
119 context: &mut NativeContext,
120 ty_args: Vec<Type>,
121 mut args: VecDeque<Value>,
122) -> PartialVMResult<NativeResult> {
123 let cost = context.gas_used();
124 if !is_supported(context)? {
125 return Ok(NativeResult::err(cost, NOT_SUPPORTED_ERROR));
126 }
127
128 let cost_params = get_extension!(context, NativesCostTable)?
130 .vdf_cost_params
131 .clone();
132
133 native_charge_gas_early_exit!(
135 context,
136 cost_params
137 .hash_to_input_cost
138 .ok_or_else(
139 || PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
140 .with_message("Gas cost for hash_to_input not available".to_string())
141 )?
142 );
143
144 debug_assert!(ty_args.is_empty());
145 debug_assert!(args.len() == 1);
146
147 let message = pop_arg!(args, VectorRef);
148
149 let output = match QuadraticForm::hash_to_group_with_default_parameters(
150 &message.as_bytes_ref()?,
151 &DISCRIMINANT_3072,
152 ) {
153 Ok(output) => output,
154 Err(_) => return Ok(NativeResult::err(context.gas_used(), INVALID_INPUT_ERROR)),
155 };
156
157 let output_bytes = match bcs::to_bytes(&output) {
158 Ok(bytes) => bytes,
159 Err(_) => return Ok(NativeResult::err(context.gas_used(), INVALID_INPUT_ERROR)),
161 };
162
163 Ok(NativeResult::ok(
164 context.gas_used(),
165 smallvec![Value::vector_u8(output_bytes)],
166 ))
167}