1use hopr_crypto_random::random_bytes;
2use hopr_primitive_types::prelude::*;
3use k256::{
4 AffinePoint, Scalar, Secp256k1,
5 elliptic_curve::{
6 ProjectivePoint,
7 hash2curve::{ExpandMsgXmd, GroupDigest},
8 sec1::ToEncodedPoint,
9 },
10};
11
12use crate::{
13 errors::{CryptoError::CalculationError, Result},
14 keypairs::{ChainKeypair, Keypair},
15 types::{PublicKey, affine_point_from_bytes},
16 utils::k256_scalar_from_bytes,
17};
18
19#[allow(non_snake_case)]
24#[derive(Clone, Copy, Default)]
25#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
26pub struct VrfParameters {
27 pub V: AffinePoint,
29 pub h: Scalar,
30 pub s: Scalar,
31}
32
33impl std::fmt::Debug for VrfParameters {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 f.debug_struct("VrfParameters")
36 .field("V", &hex::encode(self.V.to_encoded_point(true)))
37 .field("h", &hex::encode(self.h.to_bytes()))
38 .field("s", &hex::encode(self.s.to_bytes()))
39 .finish()
40 }
41}
42
43impl From<VrfParameters> for [u8; VRF_PARAMETERS_SIZE] {
44 fn from(value: VrfParameters) -> Self {
45 let mut ret = [0u8; VRF_PARAMETERS_SIZE];
46 ret[0..PublicKey::SIZE_COMPRESSED].copy_from_slice(value.V.to_encoded_point(true).as_bytes());
47 ret[PublicKey::SIZE_COMPRESSED..PublicKey::SIZE_COMPRESSED + 32].copy_from_slice(value.h.to_bytes().as_ref());
48 ret[PublicKey::SIZE_COMPRESSED + 32..PublicKey::SIZE_COMPRESSED + 64]
49 .copy_from_slice(value.s.to_bytes().as_ref());
50 ret
51 }
52}
53
54impl TryFrom<&[u8]> for VrfParameters {
55 type Error = GeneralError;
56
57 fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
58 if value.len() == Self::SIZE {
59 let mut v = [0u8; PublicKey::SIZE_COMPRESSED];
60 v.copy_from_slice(&value[..PublicKey::SIZE_COMPRESSED]);
61 Ok(VrfParameters {
62 V: affine_point_from_bytes(&value[..PublicKey::SIZE_COMPRESSED])
63 .map_err(|_| GeneralError::ParseError("VrfParameters.V".into()))?,
64 h: k256_scalar_from_bytes(&value[PublicKey::SIZE_COMPRESSED..PublicKey::SIZE_COMPRESSED + 32])
65 .map_err(|_| GeneralError::ParseError("VrfParameters.h".into()))?,
66 s: k256_scalar_from_bytes(
67 &value[PublicKey::SIZE_COMPRESSED + 32..PublicKey::SIZE_COMPRESSED + 32 + 32],
68 )
69 .map_err(|_| GeneralError::ParseError("VrfParameters.s".into()))?,
70 })
71 } else {
72 Err(GeneralError::ParseError("VrfParameters.size".into()))
73 }
74 }
75}
76
77const VRF_PARAMETERS_SIZE: usize = PublicKey::SIZE_COMPRESSED + 32 + 32;
78impl BytesEncodable<VRF_PARAMETERS_SIZE> for VrfParameters {}
79
80impl VrfParameters {
81 #[allow(non_snake_case)]
84 pub fn verify<const T: usize>(&self, creator: &Address, msg: &[u8; T], dst: &[u8]) -> Result<()> {
85 let cap_B = self.get_encoded_payload(creator, msg, dst)?;
86 let v_proj = ProjectivePoint::<Secp256k1>::from(self.V);
87
88 let R_v: ProjectivePoint<Secp256k1> = cap_B * self.s - v_proj * self.h;
89
90 let h_check = Secp256k1::hash_to_scalar::<ExpandMsgXmd<sha3::Keccak256>>(
91 &[
92 creator.as_ref(),
93 &self.V.to_encoded_point(false).as_bytes()[1..],
94 &R_v.to_affine().to_encoded_point(false).as_bytes()[1..],
95 msg,
96 ],
97 &[dst],
98 )
99 .or(Err(CalculationError))?;
100
101 if h_check != self.h {
102 return Err(CalculationError);
103 }
104
105 Ok(())
106 }
107
108 pub fn get_v_encoded_point(&self) -> k256::EncodedPoint {
110 self.V.to_encoded_point(false)
111 }
112
113 pub fn get_h_v_witness(&self) -> k256::EncodedPoint {
118 (ProjectivePoint::<Secp256k1>::from(self.V) * self.h)
119 .to_affine()
120 .to_encoded_point(false)
121 }
122
123 pub fn get_s_b_witness<const T: usize>(
129 &self,
130 creator: &Address,
131 msg: &[u8; T],
132 dst: &[u8],
133 ) -> Result<k256::EncodedPoint> {
134 Ok((self.get_encoded_payload(creator, msg, dst)? * self.s)
135 .to_affine()
136 .to_encoded_point(false))
137 }
138
139 fn get_encoded_payload<const T: usize>(
146 &self,
147 creator: &Address,
148 msg: &[u8; T],
149 dst: &[u8],
150 ) -> Result<k256::ProjectivePoint> {
151 Secp256k1::hash_from_bytes::<ExpandMsgXmd<sha3::Keccak256>>(&[creator.as_ref(), msg], &[dst])
152 .or(Err(CalculationError))
153 }
154}
155
156#[cfg(feature = "rust-ecdsa")]
160#[allow(non_snake_case)]
161pub fn derive_vrf_parameters<T: AsRef<[u8]>>(
162 msg: T,
163 chain_keypair: &ChainKeypair,
164 dst: &[u8],
165) -> crate::errors::Result<VrfParameters> {
166 let chain_addr = chain_keypair.public().to_address();
167 let B = Secp256k1::hash_from_bytes::<ExpandMsgXmd<sha3::Keccak256>>(&[chain_addr.as_ref(), msg.as_ref()], &[dst])?;
168
169 let a: Scalar = chain_keypair.into();
170
171 let V = B * a;
172
173 let r = Secp256k1::hash_to_scalar::<ExpandMsgXmd<sha3::Keccak256>>(
174 &[
175 &a.to_bytes(),
176 &V.to_affine().to_encoded_point(false).as_bytes()[1..],
177 &random_bytes::<64>(),
178 ],
179 &[dst],
180 )?;
181
182 let R_v = B * r;
183
184 let h = Secp256k1::hash_to_scalar::<ExpandMsgXmd<sha3::Keccak256>>(
185 &[
186 chain_addr.as_ref(),
187 &V.to_affine().to_encoded_point(false).as_bytes()[1..],
188 &R_v.to_affine().to_encoded_point(false).as_bytes()[1..],
189 msg.as_ref(),
190 ],
191 &[dst],
192 )?;
193 let s = r + h * a;
194
195 Ok(VrfParameters { V: V.to_affine(), h, s })
196}
197
198#[cfg(not(feature = "rust-ecdsa"))]
202#[allow(non_snake_case)]
203pub fn derive_vrf_parameters<T: AsRef<[u8]>>(
204 msg: T,
205 chain_keypair: &ChainKeypair,
206 dst: &[u8],
207) -> Result<VrfParameters> {
208 let chain_addr = chain_keypair.public().to_address();
209 let B = Secp256k1::hash_from_bytes::<ExpandMsgXmd<sha3::Keccak256>>(&[chain_addr.as_ref(), msg.as_ref()], &[dst])?
210 .to_affine();
211
212 let a = secp256k1::Scalar::from_be_bytes(chain_keypair.secret().clone().into())
213 .map_err(|_| crate::errors::CryptoError::InvalidSecretScalar)?;
214
215 let B_pk = secp256k1::PublicKey::from_byte_array_uncompressed(
216 B.to_encoded_point(false)
217 .as_bytes()
218 .try_into()
219 .map_err(|_| crate::errors::CryptoError::InvalidPublicKey)?,
220 )
221 .map_err(|_| crate::errors::CryptoError::InvalidPublicKey)?;
222
223 let V = B_pk
224 .mul_tweak(secp256k1::global::SECP256K1, &a)
225 .map_err(|_| CalculationError)?;
226
227 let r = Secp256k1::hash_to_scalar::<ExpandMsgXmd<sha3::Keccak256>>(
228 &[
229 &a.to_be_bytes(),
230 &V.serialize_uncompressed()[1..],
231 &random_bytes::<64>(),
232 ],
233 &[dst],
234 )?;
235
236 let r_scalar = secp256k1::Scalar::from_be_bytes(r.to_bytes().into())
237 .map_err(|_| crate::errors::CryptoError::InvalidSecretScalar)?;
238
239 let R_v = B_pk
240 .mul_tweak(secp256k1::global::SECP256K1, &r_scalar)
241 .map_err(|_| CalculationError)?;
242
243 let h = Secp256k1::hash_to_scalar::<ExpandMsgXmd<sha3::Keccak256>>(
244 &[
245 chain_addr.as_ref(),
246 &V.serialize_uncompressed()[1..],
247 &R_v.serialize_uncompressed()[1..],
248 msg.as_ref(),
249 ],
250 &[dst],
251 )?;
252 let s = r + h * Scalar::from(chain_keypair);
253
254 let V = affine_point_from_bytes(&V.serialize_uncompressed()).map_err(|_| CalculationError)?;
255
256 Ok(VrfParameters { V, h, s })
257}
258
259#[cfg(test)]
260mod tests {
261 use hex_literal::hex;
262 use k256::elliptic_curve::ScalarPrimitive;
263 use sha3::Keccak256;
264
265 use super::*;
266 use crate::types::Hash;
267
268 lazy_static::lazy_static! {
269 static ref ALICE: ChainKeypair = ChainKeypair::from_secret(&hex!("e17fe86ce6e99f4806715b0c9412f8dad89334bf07f72d5834207a9d8f19d7f8")).expect("lazy static keypair should be valid");
270 static ref ALICE_ADDR: Address = ALICE.public().to_address();
271
272 static ref TEST_MSG: [u8; 32] = hex!("8248a966b9215e154c8f673cb154da030916be3fb31af3b1220419a1c98eeaed");
273 static ref ALICE_VRF_OUTPUT: [u8; 97] = hex!("02a4e1fa28e8a40348baf79b576a6e040b370b74893d355cd48fc382d5235ff0652ee2b835e7c475fde5adfedeb7cc31ecdd690f13ac6bb59ed046ca4c189c9996fe60abaad8c93e771c19acfe697e15c1e5ed6a182b2960bf8c7bd687e77a9975");
274
275 static ref WRONG_V_POINT_PREFIX: [u8; 97] = hex!("01a4e1fa28e8a40348baf79b576a6e040b370b74893d355cd48fc382d5235ff0652ee2b835e7c475fde5adfedeb7cc31ecdd690f13ac6bb59ed046ca4c189c9996fe60abaad8c93e771c19acfe697e15c1e5ed6a182b2960bf8c7bd687e77a9975");
276 static ref H_NOT_IN_FIELD: [u8; 97] = hex!("02a4e1fa28e8a40348baf79b576a6e040b370b74893d355cd48fc382d5235ff065fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe60abaad8c93e771c19acfe697e15c1e5ed6a182b2960bf8c7bd687e77a9975");
277 static ref S_NOT_IN_FIELD: [u8; 97] = hex!("02a4e1fa28e8a40348baf79b576a6e040b370b74893d355cd48fc382d5235ff0652ee2b835e7c475fde5adfedeb7cc31ecdd690f13ac6bb59ed046ca4c189c9996ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
278 }
279
280 #[test]
281 fn vrf_values_serialize_deserialize() -> anyhow::Result<()> {
282 let vrf_values = derive_vrf_parameters(*TEST_MSG, &ALICE, Hash::default().as_ref())?;
283
284 let deserialized = VrfParameters::try_from(ALICE_VRF_OUTPUT.as_ref())?;
285
286 assert_eq!(vrf_values.V, deserialized.V);
288 assert!(
289 deserialized
290 .verify(&ALICE_ADDR, &TEST_MSG, Hash::default().as_ref())
291 .is_ok()
292 );
293
294 let vrf: [u8; VrfParameters::SIZE] = vrf_values.clone().into();
296 let other = VrfParameters::try_from(vrf.as_ref())?;
297 assert!(vrf_values.s == other.s && vrf_values.V == other.V && vrf_values.h == other.h);
298
299 Ok(())
300 }
301
302 #[test]
303 fn vrf_values_serialize_deserialize_bad_examples() {
304 assert!(VrfParameters::try_from(WRONG_V_POINT_PREFIX.as_ref()).is_err());
305
306 assert!(VrfParameters::try_from(H_NOT_IN_FIELD.as_ref()).is_err());
307
308 assert!(VrfParameters::try_from(S_NOT_IN_FIELD.as_ref()).is_err());
309 }
310
311 #[test]
312 fn vrf_values_crypto() -> anyhow::Result<()> {
313 let vrf_values = derive_vrf_parameters(*TEST_MSG, &ALICE, Hash::default().as_ref())?;
314
315 assert!(
316 vrf_values
317 .verify(&ALICE_ADDR, &TEST_MSG, Hash::default().as_ref())
318 .is_ok()
319 );
320
321 Ok(())
322 }
323
324 #[test]
325 fn test_vrf_parameter_generation() -> anyhow::Result<()> {
326 let dst = b"some DST tag";
327 let priv_key: [u8; 32] = hex!("f13233ff60e1f618525dac5f7d117bef0bad0eb0b0afb2459f9cbc57a3a987ba"); let message = hex!("f13233ff60e1f618525dac5f7d117bef0bad0eb0b0afb2459f9cbc57a3a987ba"); let keypair = ChainKeypair::from_secret(&priv_key)?;
331 let pub_key = PublicKey::from_privkey(&priv_key)?;
333
334 let params = derive_vrf_parameters(message, &keypair, dst)?;
335
336 let cap_b =
337 Secp256k1::hash_from_bytes::<ExpandMsgXmd<Keccak256>>(&[pub_key.to_address().as_ref(), &message], &[dst])?;
338
339 assert_eq!(
340 params.get_s_b_witness(&keypair.public().to_address(), &message, dst)?,
341 (cap_b * params.s).to_encoded_point(false)
342 );
343
344 let a: Scalar = ScalarPrimitive::<Secp256k1>::from_slice(&priv_key)?.into();
345 assert_eq!(params.get_h_v_witness(), (cap_b * a * params.h).to_encoded_point(false));
346
347 let r_v: ProjectivePoint<Secp256k1> =
348 cap_b * params.s - ProjectivePoint::<Secp256k1>::from(params.V) * params.h;
349
350 let h_check = Secp256k1::hash_to_scalar::<ExpandMsgXmd<Keccak256>>(
351 &[
352 pub_key.to_address().as_ref(),
353 ¶ms.V.to_encoded_point(false).as_bytes()[1..],
354 &r_v.to_affine().to_encoded_point(false).as_bytes()[1..],
355 &message,
356 ],
357 &[dst],
358 )?;
359
360 assert_eq!(h_check, params.h);
361
362 Ok(())
363 }
364}