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