1mod constants;
4mod errors;
5mod proof;
6mod public;
7mod secret;
8
9pub use constants::*;
10
11pub use self::{errors::*, proof::*, public::*, secret::*};
12use crate::common::*;
13use rand::{CryptoRng, Rng};
14
15#[derive(Debug, Serialize)]
17pub struct Keypair {
18 pub secret: SecretKey,
20 pub public: PublicKey,
22}
23
24impl Keypair {
25 pub fn generate<R>(csprng: &mut R) -> Keypair
27 where
28 R: CryptoRng + Rng,
29 {
30 let sk = SecretKey::generate(csprng);
31 let pk = PublicKey::from(&sk);
32
33 Keypair {
34 public: pk,
35 secret: sk,
36 }
37 }
38
39 pub fn prove(&self, message: &[u8]) -> Proof {
41 let expanded: ExpandedSecretKey = (&self.secret).into();
42
43 expanded.prove(&self.public, message)
44 }
45}
46
47#[cfg(feature = "ffi")]
48mod expose_ffi {
49 use super::*;
50 use crate::{common::size_t, ffi_helpers::*};
51 use rand::thread_rng;
52 use std::{cmp::Ordering, sync::Arc};
53 use subtle::ConstantTimeEq;
54
55 macro_derive_from_bytes!(Arc ecvrf_proof_from_bytes, Proof);
59 macro_derive_from_bytes!(
60 Box ecvrf_public_key_from_bytes,
61 PublicKey
62 );
63 macro_derive_from_bytes_no_cursor!(
64 Box ecvrf_secret_key_from_bytes,
65 SecretKey,
66 SecretKey::from_bytes
67 );
68 macro_derive_to_bytes!(Arc ecvrf_proof_to_bytes, Proof);
69 macro_derive_to_bytes!(Box ecvrf_public_key_to_bytes, PublicKey);
70 macro_derive_to_bytes!(Box ecvrf_secret_key_to_bytes, SecretKey);
71 macro_free_ffi!(Arc ecvrf_proof_free, Proof);
73 macro_free_ffi!(Box ecvrf_public_key_free, PublicKey);
74 macro_free_ffi!(Box ecvrf_secret_key_free, SecretKey);
75
76 macro_derive_binary!(Arc ecvrf_proof_eq, Proof, Proof::eq);
78 macro_derive_binary!(Box ecvrf_public_key_eq, PublicKey, PublicKey::eq);
79 macro_derive_binary!(Box ecvrf_secret_key_eq, SecretKey, |x, y| bool::from(
81 SecretKey::ct_eq(x, y)
82 ));
83
84 #[no_mangle]
87 #[allow(clippy::not_unsafe_ptr_arg_deref)]
88 extern "C" fn ecvrf_prove(
91 public: *mut PublicKey,
92 secret: *mut SecretKey,
93 message: *const u8,
94 len: size_t,
95 ) -> *const Proof {
96 let sk = from_ptr!(secret);
97 let pk = from_ptr!(public);
98 let data: &[u8] = slice_from_c_bytes!(message, len);
99 let proof = sk.prove(pk, data);
100 Arc::into_raw(Arc::new(proof))
101 }
102
103 #[no_mangle]
104 extern "C" fn ecvrf_priv_key() -> *mut SecretKey {
107 let mut csprng = thread_rng();
108 let sk = SecretKey::generate(&mut csprng);
109 Box::into_raw(Box::new(sk))
110 }
111
112 #[no_mangle]
113 #[allow(clippy::not_unsafe_ptr_arg_deref)]
117 extern "C" fn ecvrf_pub_key(secret_key: *mut SecretKey) -> *mut PublicKey {
118 let sk = from_ptr!(secret_key);
119 let pk = PublicKey::from(sk);
120 Box::into_raw(Box::new(pk))
121 }
122
123 #[no_mangle]
124 #[allow(clippy::not_unsafe_ptr_arg_deref)]
127 extern "C" fn ecvrf_proof_to_hash(hash_ptr: *mut u8, proof_ptr: *const Proof) {
128 let hash = mut_slice_from_c_bytes!(hash_ptr, 64);
129 let proof = from_ptr!(proof_ptr);
130 hash.copy_from_slice(&proof.to_hash())
131 }
132
133 #[no_mangle]
134 #[allow(clippy::not_unsafe_ptr_arg_deref)]
135 extern "C" fn ecvrf_verify_key(key_ptr: *mut PublicKey) -> i32 {
136 let key = from_ptr!(key_ptr);
137 if key.verify_key() {
138 1
139 } else {
140 0
141 }
142 }
143
144 #[no_mangle]
145 #[allow(clippy::not_unsafe_ptr_arg_deref)]
146 extern "C" fn ecvrf_verify(
149 public_key_ptr: *mut PublicKey,
150 proof_ptr: *const Proof,
151 message_ptr: *const u8,
152 len: size_t,
153 ) -> i32 {
154 let pk = from_ptr!(public_key_ptr);
155 let proof = from_ptr!(proof_ptr);
156 let message: &[u8] = slice_from_c_bytes!(message_ptr, len);
157
158 if pk.verify(proof, message) {
159 1
160 } else {
161 0
162 }
163 }
164
165 #[no_mangle]
166 #[allow(clippy::not_unsafe_ptr_arg_deref)]
167 extern "C" fn ecvrf_proof_cmp(proof_ptr_1: *const Proof, proof_ptr_2: *const Proof) -> i32 {
169 if proof_ptr_1 == proof_ptr_2 {
171 return 0;
172 }
173
174 let p1 = from_ptr!(proof_ptr_1);
175 let p2 = from_ptr!(proof_ptr_2);
176 match p1.2.as_bytes().cmp(p2.2.as_bytes()) {
177 Ordering::Less => return -1,
178 Ordering::Greater => return 1,
179 Ordering::Equal => (),
180 }
181
182 match p1.1.as_bytes().cmp(p2.1.as_bytes()) {
185 Ordering::Less => return -1,
186 Ordering::Greater => return 1,
187 Ordering::Equal => (),
188 }
189
190 match p1.0.compress().as_bytes().cmp(p2.0.compress().as_bytes()) {
192 Ordering::Less => -1,
193 Ordering::Equal => 0,
194 Ordering::Greater => 1,
195 }
196 }
197
198 #[no_mangle]
199 #[allow(clippy::not_unsafe_ptr_arg_deref)]
200 extern "C" fn ecvrf_public_key_cmp(
202 public_key_ptr_1: *mut PublicKey,
203 public_key_ptr_2: *mut PublicKey,
204 ) -> i32 {
205 if public_key_ptr_1 == public_key_ptr_2 {
207 return 0;
208 }
209
210 let p1 = from_ptr!(public_key_ptr_1);
211 let p2 = from_ptr!(public_key_ptr_2);
212
213 match p1.0.as_bytes().cmp(p2.0.as_bytes()) {
216 Ordering::Less => -1,
217 Ordering::Equal => 0,
218 Ordering::Greater => 1,
219 }
220 }
221}
222
223#[cfg(test)]
224mod tests {
225 use super::*;
226
227 use curve25519_dalek::scalar::Scalar;
228
229 #[test]
232 fn test_vrf_proof_and_hash() {
233 fn test_example(
251 sk_bytes: [u8; 32], alpha_bytes: Vec<u8>, pk_bytes: [u8; 32], x_bytes: [u8; 32], pi_bytes: [u8; 80], beta_bytes: [u8; 64], ) {
258 let sk = SecretKey(sk_bytes);
260 let expanded_sk = ExpandedSecretKey::from(&sk);
261 let pk: PublicKey = PublicKey::from(&expanded_sk);
262 assert_eq!(pk.as_bytes(), &pk_bytes);
263
264 let x = expanded_sk.key;
266 assert_eq!(x, Scalar::from_bytes_mod_order(x_bytes));
267
268 let proof = expanded_sk.prove(&pk, &alpha_bytes);
270 let mut proof_bytes: Vec<u8> = Vec::new();
271 proof.serial(&mut proof_bytes);
272 assert!(proof_bytes.iter().eq(pi_bytes.iter()));
273
274 let p2h = proof.to_hash();
276 assert!(p2h.iter().eq(beta_bytes.iter()));
277 }
278
279 {
280 let sk_bytes: [u8; 32] = [
290 0x9d, 0x61, 0xb1, 0x9d, 0xef, 0xfd, 0x5a, 0x60, 0xba, 0x84, 0x4a, 0xf4, 0x92, 0xec,
291 0x2c, 0xc4, 0x44, 0x49, 0xc5, 0x69, 0x7b, 0x32, 0x69, 0x19, 0x70, 0x3b, 0xac, 0x03,
292 0x1c, 0xae, 0x7f, 0x60,
293 ];
294
295 let pk_bytes: [u8; 32] = [
296 0xd7, 0x5a, 0x98, 0x01, 0x82, 0xb1, 0x0a, 0xb7, 0xd5, 0x4b, 0xfe, 0xd3, 0xc9, 0x64,
297 0x07, 0x3a, 0x0e, 0xe1, 0x72, 0xf3, 0xda, 0xa6, 0x23, 0x25, 0xaf, 0x02, 0x1a, 0x68,
298 0xf7, 0x07, 0x51, 0x1a,
299 ];
300
301 let alpha_bytes: Vec<u8> = Vec::new();
302
303 let x_bytes: [u8; 32] = [
304 0x30, 0x7c, 0x83, 0x86, 0x4f, 0x28, 0x33, 0xcb, 0x42, 0x7a, 0x2e, 0xf1, 0xc0, 0x0a,
305 0x01, 0x3c, 0xfd, 0xff, 0x27, 0x68, 0xd9, 0x80, 0xc0, 0xa3, 0xa5, 0x20, 0xf0, 0x06,
306 0x90, 0x4d, 0xe9, 0x4f,
307 ];
308
309 let pi_bytes: [u8; 80] = [
311 0x86, 0x57, 0x10, 0x66, 0x90, 0xb5, 0x52, 0x62, 0x45, 0xa9, 0x2b, 0x00, 0x3b, 0xb0,
312 0x79, 0xcc, 0xd1, 0xa9, 0x21, 0x30, 0x47, 0x76, 0x71, 0xf6, 0xfc, 0x01, 0xad, 0x16,
313 0xf2, 0x6f, 0x72, 0x3f, 0x5e, 0x8b, 0xd1, 0x83, 0x9b, 0x41, 0x42, 0x19, 0xe8, 0x62,
314 0x6d, 0x39, 0x37, 0x87, 0xa1, 0x92, 0x24, 0x1f, 0xc4, 0x42, 0xe6, 0x56, 0x9e, 0x96,
315 0xc4, 0x62, 0xf6, 0x2b, 0x80, 0x79, 0xb9, 0xed, 0x83, 0xff, 0x2e, 0xe2, 0x1c, 0x90,
316 0xc7, 0xc3, 0x98, 0x80, 0x2f, 0xde, 0xeb, 0xea, 0x40, 0x01,
317 ];
318
319 let beta_bytes: [u8; 64] = [
321 0x90, 0xcf, 0x1d, 0xf3, 0xb7, 0x03, 0xcc, 0xe5, 0x9e, 0x2a, 0x35, 0xb9, 0x25, 0xd4,
322 0x11, 0x16, 0x40, 0x68, 0x26, 0x9d, 0x7b, 0x2d, 0x29, 0xf3, 0x30, 0x1c, 0x03, 0xdd,
323 0x75, 0x78, 0x76, 0xff, 0x66, 0xb7, 0x1d, 0xda, 0x49, 0xd2, 0xde, 0x59, 0xd0, 0x34,
324 0x50, 0x45, 0x1a, 0xf0, 0x26, 0x79, 0x8e, 0x8f, 0x81, 0xcd, 0x2e, 0x33, 0x3d, 0xe5,
325 0xcd, 0xf4, 0xf3, 0xe1, 0x40, 0xfd, 0xd8, 0xae,
326 ];
327
328 test_example(
329 sk_bytes,
330 alpha_bytes,
331 pk_bytes,
332 x_bytes,
333 pi_bytes,
334 beta_bytes,
335 )
336 }
337
338 {
339 let sk_bytes: [u8; 32] = [
349 0x4c, 0xcd, 0x08, 0x9b, 0x28, 0xff, 0x96, 0xda, 0x9d, 0xb6, 0xc3, 0x46, 0xec, 0x11,
350 0x4e, 0x0f, 0x5b, 0x8a, 0x31, 0x9f, 0x35, 0xab, 0xa6, 0x24, 0xda, 0x8c, 0xf6, 0xed,
351 0x4f, 0xb8, 0xa6, 0xfb,
352 ];
353
354 let pk_bytes: [u8; 32] = [
355 0x3d, 0x40, 0x17, 0xc3, 0xe8, 0x43, 0x89, 0x5a, 0x92, 0xb7, 0x0a, 0xa7, 0x4d, 0x1b,
356 0x7e, 0xbc, 0x9c, 0x98, 0x2c, 0xcf, 0x2e, 0xc4, 0x96, 0x8c, 0xc0, 0xcd, 0x55, 0xf1,
357 0x2a, 0xf4, 0x66, 0x0c,
358 ];
359
360 let alpha_bytes: Vec<u8> = vec![0x72];
361
362 let x_bytes: [u8; 32] = [
363 0x68, 0xbd, 0x9e, 0xd7, 0x58, 0x82, 0xd5, 0x28, 0x15, 0xa9, 0x75, 0x85, 0xca, 0xf4,
364 0x79, 0x0a, 0x7f, 0x6c, 0x6b, 0x3b, 0x7f, 0x82, 0x1c, 0x5e, 0x25, 0x9a, 0x24, 0xb0,
365 0x2e, 0x50, 0x2e, 0x51,
366 ];
367
368 let pi_bytes: [u8; 80] = [
370 0xf3, 0x14, 0x1c, 0xd3, 0x82, 0xdc, 0x42, 0x90, 0x9d, 0x19, 0xec, 0x51, 0x10, 0x46,
371 0x9e, 0x4f, 0xea, 0xe1, 0x83, 0x00, 0xe9, 0x4f, 0x30, 0x45, 0x90, 0xab, 0xdc, 0xed,
372 0x48, 0xae, 0xd5, 0x93, 0xf7, 0xea, 0xf3, 0xeb, 0x2f, 0x1a, 0x96, 0x8c, 0xba, 0x3f,
373 0x6e, 0x23, 0xb3, 0x86, 0xae, 0xea, 0xab, 0x7b, 0x1e, 0xa4, 0x4a, 0x25, 0x6e, 0x81,
374 0x18, 0x92, 0xe1, 0x3e, 0xea, 0xe7, 0xc9, 0xf6, 0xea, 0x89, 0x92, 0x55, 0x74, 0x53,
375 0xea, 0xc1, 0x1c, 0x4d, 0x54, 0x76, 0xb1, 0xf3, 0x5a, 0x08,
376 ];
377
378 let beta_bytes: [u8; 64] = [
380 0xeb, 0x44, 0x40, 0x66, 0x5d, 0x38, 0x91, 0xd6, 0x68, 0xe7, 0xe0, 0xfc, 0xaf, 0x58,
381 0x7f, 0x1b, 0x4b, 0xd7, 0xfb, 0xfe, 0x99, 0xd0, 0xeb, 0x22, 0x11, 0xcc, 0xec, 0x90,
382 0x49, 0x63, 0x10, 0xeb, 0x5e, 0x33, 0x82, 0x1b, 0xc6, 0x13, 0xef, 0xb9, 0x4d, 0xb5,
383 0xe5, 0xb5, 0x4c, 0x70, 0xa8, 0x48, 0xa0, 0xbe, 0xf4, 0x55, 0x3a, 0x41, 0xbe, 0xfc,
384 0x57, 0x66, 0x3b, 0x56, 0x37, 0x3a, 0x50, 0x31,
385 ];
386
387 test_example(
388 sk_bytes,
389 alpha_bytes,
390 pk_bytes,
391 x_bytes,
392 pi_bytes,
393 beta_bytes,
394 )
395 }
396
397 {
398 let sk_bytes: [u8; 32] = [
408 0xc5, 0xaa, 0x8d, 0xf4, 0x3f, 0x9f, 0x83, 0x7b, 0xed, 0xb7, 0x44, 0x2f, 0x31, 0xdc,
409 0xb7, 0xb1, 0x66, 0xd3, 0x85, 0x35, 0x07, 0x6f, 0x09, 0x4b, 0x85, 0xce, 0x3a, 0x2e,
410 0x0b, 0x44, 0x58, 0xf7,
411 ];
412
413 let pk_bytes: [u8; 32] = [
414 0xfc, 0x51, 0xcd, 0x8e, 0x62, 0x18, 0xa1, 0xa3, 0x8d, 0xa4, 0x7e, 0xd0, 0x02, 0x30,
415 0xf0, 0x58, 0x08, 0x16, 0xed, 0x13, 0xba, 0x33, 0x03, 0xac, 0x5d, 0xeb, 0x91, 0x15,
416 0x48, 0x90, 0x80, 0x25,
417 ];
418
419 let alpha_bytes: Vec<u8> = vec![0xaf, 0x82];
420
421 let x_bytes: [u8; 32] = [
422 0x90, 0x9a, 0x8b, 0x75, 0x5e, 0xd9, 0x02, 0x84, 0x90, 0x23, 0xa5, 0x5b, 0x15, 0xc2,
423 0x3d, 0x11, 0xba, 0x4d, 0x7f, 0x4e, 0xc5, 0xc2, 0xf5, 0x1b, 0x13, 0x25, 0xa1, 0x81,
424 0x99, 0x1e, 0xa9, 0x5c,
425 ];
426
427 let pi_bytes: [u8; 80] = [
429 0x9b, 0xc0, 0xf7, 0x91, 0x19, 0xcc, 0x56, 0x04, 0xbf, 0x02, 0xd2, 0x3b, 0x4c, 0xae,
430 0xde, 0x71, 0x39, 0x3c, 0xed, 0xfb, 0xb1, 0x91, 0x43, 0x4d, 0xd0, 0x16, 0xd3, 0x01,
431 0x77, 0xcc, 0xbf, 0x80, 0xe2, 0x9d, 0xc5, 0x13, 0xc0, 0x1c, 0x3a, 0x98, 0x0e, 0x0e,
432 0x54, 0x5b, 0xcd, 0x84, 0x82, 0x22, 0xd0, 0x8a, 0x6c, 0x3e, 0x36, 0x65, 0xff, 0x5a,
433 0x4c, 0xab, 0x13, 0xa6, 0x43, 0xbe, 0xf8, 0x12, 0xe2, 0x84, 0xc6, 0xb2, 0xee, 0x06,
434 0x3a, 0x2c, 0xb4, 0xf4, 0x56, 0x79, 0x47, 0x23, 0xad, 0x0a,
435 ];
436
437 let beta_bytes: [u8; 64] = [
439 0x64, 0x54, 0x27, 0xe5, 0xd0, 0x0c, 0x62, 0xa2, 0x3f, 0xb7, 0x03, 0x73, 0x2f, 0xa5,
440 0xd8, 0x92, 0x94, 0x09, 0x35, 0x94, 0x21, 0x01, 0xe4, 0x56, 0xec, 0xca, 0x7b, 0xb2,
441 0x17, 0xc6, 0x1c, 0x45, 0x21, 0x18, 0xfe, 0xc1, 0x21, 0x92, 0x02, 0xa0, 0xed, 0xcf,
442 0x03, 0x8b, 0xb6, 0x37, 0x32, 0x41, 0x57, 0x8b, 0xe7, 0x21, 0x7b, 0xa8, 0x5a, 0x26,
443 0x87, 0xf7, 0xa0, 0x31, 0x0b, 0x2d, 0xf1, 0x9f,
444 ];
445
446 test_example(
447 sk_bytes,
448 alpha_bytes,
449 pk_bytes,
450 x_bytes,
451 pi_bytes,
452 beta_bytes,
453 )
454 }
455 }
456}