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