1use core::fmt::Debug;
2
3use curve25519_dalek::constants;
4use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
5use curve25519_dalek::scalar::Scalar;
6use digest::generic_array::typenum::U64;
7use digest::{Digest, KeyInit};
8use hmac::digest::generic_array::GenericArray;
9use hmac::Mac;
10use rand::{CryptoRng, Rng};
11use subtle::{Choice, ConstantTimeEq};
12use zeroize::Zeroize;
13
14use crate::errors::{InternalError, TokenError};
15
16pub const TOKEN_PREIMAGE_LENGTH: usize = 64;
18pub const TOKEN_LENGTH: usize = 96;
20pub const BLINDED_TOKEN_LENGTH: usize = 32;
22pub const PUBLIC_KEY_LENGTH: usize = 32;
24pub const SIGNING_KEY_LENGTH: usize = 32;
26pub const SIGNED_TOKEN_LENGTH: usize = 32;
28pub const UNBLINDED_TOKEN_LENGTH: usize = 96;
30pub const VERIFICATION_SIGNATURE_LENGTH: usize = 64;
32pub const SCALAR_WIDE_INPUT_LENGTH: usize = 64;
34
35#[cfg_attr(not(feature = "cbindgen"), repr(C))]
40#[derive(Copy, Clone)]
41pub struct TokenPreimage([u8; TOKEN_PREIMAGE_LENGTH]);
42
43impl PartialEq for TokenPreimage {
44 fn eq(&self, other: &TokenPreimage) -> bool {
45 self.0[..] == other.0[..]
46 }
47}
48
49#[cfg(any(test, feature = "base64"))]
50impl_base64!(TokenPreimage);
51
52#[cfg(feature = "serde")]
53impl_serde!(TokenPreimage);
54
55impl Debug for TokenPreimage {
56 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
57 write!(f, "TokenPreimage: {:?}", &self.0[..])
58 }
59}
60
61#[allow(non_snake_case)]
62impl TokenPreimage {
63 pub(crate) fn T(&self) -> RistrettoPoint {
64 RistrettoPoint::from_uniform_bytes(&self.0)
65 }
66
67 pub fn to_bytes(&self) -> [u8; TOKEN_PREIMAGE_LENGTH] {
69 self.0
70 }
71
72 fn bytes_length_error() -> TokenError {
73 TokenError(InternalError::BytesLengthError {
74 name: "TokenPreimage",
75 length: TOKEN_PREIMAGE_LENGTH,
76 })
77 }
78
79 pub fn from_bytes(bytes: &[u8]) -> Result<TokenPreimage, TokenError> {
81 if bytes.len() != TOKEN_PREIMAGE_LENGTH {
82 return Err(TokenPreimage::bytes_length_error());
83 }
84
85 let mut bits: [u8; TOKEN_PREIMAGE_LENGTH] = [0u8; TOKEN_PREIMAGE_LENGTH];
86 bits.copy_from_slice(bytes);
87 Ok(TokenPreimage(bits))
88 }
89}
90
91#[cfg_attr(not(feature = "cbindgen"), repr(C))]
96#[derive(Debug, Clone)]
97pub struct Token {
98 pub(crate) t: TokenPreimage,
100 r: Scalar,
102}
103
104impl Drop for Token {
106 fn drop(&mut self) {
107 self.r.zeroize();
108 }
109}
110
111#[cfg(any(test, feature = "base64"))]
112impl_base64!(Token);
113
114#[cfg(feature = "serde")]
115impl_serde!(Token);
116
117#[allow(non_snake_case)]
118impl Token {
119 pub fn random<D, T>(rng: &mut T) -> Self
121 where
122 D: Digest<OutputSize = U64> + Default,
123 T: Rng + CryptoRng,
124 {
125 let mut seed = [0u8; 64];
126 rng.fill(&mut seed);
127 let blinding_scalar = Scalar::random(rng);
128 Self::hash_from_bytes_with_blind::<D>(&seed, blinding_scalar)
129 }
130
131 pub(crate) fn hash_from_bytes_with_blind<D>(bytes: &[u8], blinding_scalar: Scalar) -> Self
133 where
134 D: Digest<OutputSize = U64> + Default,
135 {
136 let mut hash = D::default();
137 let mut seed = [0u8; 64];
138 hash.update(bytes);
139 seed.copy_from_slice(hash.finalize().as_slice());
140
141 Token {
142 t: TokenPreimage(seed),
143 r: blinding_scalar,
144 }
145 }
146
147 pub fn hash_from_bytes<D, T>(rng: &mut T, bytes: &[u8]) -> Self
149 where
150 D: Digest<OutputSize = U64> + Default,
151 T: Rng + CryptoRng,
152 {
153 let blinding_scalar = Scalar::random(rng);
154 Self::hash_from_bytes_with_blind::<D>(bytes, blinding_scalar)
155 }
156
157 pub fn blind(&self) -> BlindedToken {
159 BlindedToken((self.r * self.t.T()).compress())
160 }
161
162 pub(crate) fn unblind(&self, Q: &SignedToken) -> Result<UnblindedToken, TokenError> {
167 Ok(UnblindedToken {
168 t: self.t,
169 W: (self.r.invert()
170 * Q.0
171 .decompress()
172 .ok_or(TokenError(InternalError::PointDecompressionError))?)
173 .compress(),
174 })
175 }
176
177 pub fn to_bytes(&self) -> [u8; TOKEN_LENGTH] {
179 let mut token_bytes: [u8; TOKEN_LENGTH] = [0u8; TOKEN_LENGTH];
180
181 token_bytes[..TOKEN_PREIMAGE_LENGTH].copy_from_slice(&self.t.to_bytes());
182 token_bytes[TOKEN_PREIMAGE_LENGTH..].copy_from_slice(&self.r.to_bytes());
183 token_bytes
184 }
185
186 fn bytes_length_error() -> TokenError {
187 TokenError(InternalError::BytesLengthError {
188 name: "Token",
189 length: TOKEN_LENGTH,
190 })
191 }
192
193 pub fn from_bytes(bytes: &[u8]) -> Result<Token, TokenError> {
195 if bytes.len() != TOKEN_LENGTH {
196 return Err(Token::bytes_length_error());
197 }
198
199 let preimage = TokenPreimage::from_bytes(&bytes[..TOKEN_PREIMAGE_LENGTH])?;
200
201 let mut blinding_factor_bits: [u8; 32] = [0u8; 32];
202 blinding_factor_bits.copy_from_slice(&bytes[TOKEN_PREIMAGE_LENGTH..]);
203 let blinding_factor = Option::from(Scalar::from_canonical_bytes(blinding_factor_bits))
204 .ok_or(TokenError(InternalError::ScalarFormatError))?;
205
206 Ok(Token {
207 t: preimage,
208 r: blinding_factor,
209 })
210 }
211}
212
213#[cfg_attr(not(feature = "cbindgen"), repr(C))]
220#[derive(Copy, Clone, Debug)]
221pub struct BlindedToken(pub(crate) CompressedRistretto);
222
223#[cfg(any(test, feature = "base64"))]
224impl_base64!(BlindedToken);
225
226#[cfg(feature = "serde")]
227impl_serde!(BlindedToken);
228
229impl BlindedToken {
230 pub fn to_bytes(&self) -> [u8; BLINDED_TOKEN_LENGTH] {
232 self.0.to_bytes()
233 }
234
235 fn bytes_length_error() -> TokenError {
236 TokenError(InternalError::BytesLengthError {
237 name: "BlindedToken",
238 length: BLINDED_TOKEN_LENGTH,
239 })
240 }
241
242 pub fn from_bytes(bytes: &[u8]) -> Result<BlindedToken, TokenError> {
244 if bytes.len() != BLINDED_TOKEN_LENGTH {
245 return Err(BlindedToken::bytes_length_error());
246 }
247
248 let mut bits: [u8; 32] = [0u8; 32];
249 bits.copy_from_slice(&bytes[..32]);
250 Ok(BlindedToken(CompressedRistretto(bits)))
251 }
252}
253
254#[cfg_attr(not(feature = "cbindgen"), repr(C))]
258#[derive(Copy, Clone, Debug)]
259#[allow(non_snake_case)]
260pub struct PublicKey(pub(crate) CompressedRistretto);
261
262#[cfg(any(test, feature = "base64"))]
263impl_base64!(PublicKey);
264
265#[cfg(feature = "serde")]
266impl_serde!(PublicKey);
267
268impl PublicKey {
269 pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] {
271 self.0.to_bytes()
272 }
273
274 fn bytes_length_error() -> TokenError {
275 TokenError(InternalError::BytesLengthError {
276 name: "PublicKey",
277 length: PUBLIC_KEY_LENGTH,
278 })
279 }
280
281 pub fn from_bytes(bytes: &[u8]) -> Result<PublicKey, TokenError> {
283 if bytes.len() != PUBLIC_KEY_LENGTH {
284 return Err(PublicKey::bytes_length_error());
285 }
286
287 let mut bits: [u8; 32] = [0u8; 32];
288 bits.copy_from_slice(&bytes[..32]);
289
290 Ok(PublicKey(CompressedRistretto(bits)))
291 }
292}
293
294#[cfg_attr(not(feature = "cbindgen"), repr(C))]
298#[derive(Debug, Clone)]
299pub struct SigningKey {
300 pub public_key: PublicKey,
302 pub(crate) k: Scalar,
304}
305
306#[cfg(any(test, feature = "base64"))]
307impl_base64!(SigningKey);
308
309#[cfg(feature = "serde")]
310impl_serde!(SigningKey);
311
312impl Drop for SigningKey {
314 fn drop(&mut self) {
315 self.k.zeroize();
316 }
317}
318
319#[allow(non_snake_case)]
320impl SigningKey {
321 pub fn random<T: Rng + CryptoRng>(rng: &mut T) -> Self {
323 let k = Scalar::random(rng);
324 let Y = k * constants::RISTRETTO_BASEPOINT_POINT;
325 SigningKey {
326 k,
327 public_key: PublicKey(Y.compress()),
328 }
329 }
330
331 pub fn from_random_bytes(bytes: &[u8]) -> Result<SigningKey, TokenError> {
336 if bytes.len() != SCALAR_WIDE_INPUT_LENGTH {
337 return Err(TokenError(InternalError::BytesLengthError {
338 name: "SigningKey random bytes",
339 length: SCALAR_WIDE_INPUT_LENGTH,
340 }));
341 }
342
343 let mut bytes_array = [0u8; SCALAR_WIDE_INPUT_LENGTH];
344 bytes_array.copy_from_slice(bytes);
345
346 let k = Scalar::from_bytes_mod_order_wide(&bytes_array);
347 let Y = k * constants::RISTRETTO_BASEPOINT_POINT;
348 Ok(SigningKey {
349 k,
350 public_key: PublicKey(Y.compress()),
351 })
352 }
353
354 pub fn sign(&self, P: &BlindedToken) -> Result<SignedToken, TokenError> {
358 Ok(SignedToken(
359 (self.k
360 * P.0
361 .decompress()
362 .ok_or(TokenError(InternalError::PointDecompressionError))?)
363 .compress(),
364 ))
365 }
366
367 pub fn rederive_unblinded_token(&self, t: &TokenPreimage) -> UnblindedToken {
371 UnblindedToken {
372 t: *t,
373 W: (self.k * t.T()).compress(),
374 }
375 }
376
377 pub fn to_bytes(&self) -> [u8; SIGNING_KEY_LENGTH] {
379 self.k.to_bytes()
380 }
381
382 fn bytes_length_error() -> TokenError {
383 TokenError(InternalError::BytesLengthError {
384 name: "SigningKey",
385 length: SIGNING_KEY_LENGTH,
386 })
387 }
388
389 pub fn from_bytes(bytes: &[u8]) -> Result<SigningKey, TokenError> {
391 if bytes.len() != SIGNING_KEY_LENGTH {
392 return Err(SigningKey::bytes_length_error());
393 }
394
395 let mut bits: [u8; 32] = [0u8; 32];
396 bits.copy_from_slice(&bytes[..32]);
397 let k = Option::from(Scalar::from_canonical_bytes(bits))
398 .ok_or(TokenError(InternalError::ScalarFormatError))?;
399
400 let Y: RistrettoPoint = k * constants::RISTRETTO_BASEPOINT_POINT;
401
402 Ok(SigningKey {
403 public_key: PublicKey(Y.compress()),
404 k,
405 })
406 }
407}
408
409#[cfg_attr(not(feature = "cbindgen"), repr(C))]
413#[derive(Copy, Clone, Debug)]
414pub struct SignedToken(pub(crate) CompressedRistretto);
415
416#[cfg(any(test, feature = "base64"))]
417impl_base64!(SignedToken);
418
419#[cfg(feature = "serde")]
420impl_serde!(SignedToken);
421
422impl SignedToken {
423 pub fn to_bytes(&self) -> [u8; SIGNED_TOKEN_LENGTH] {
425 self.0.to_bytes()
426 }
427
428 fn bytes_length_error() -> TokenError {
429 TokenError(InternalError::BytesLengthError {
430 name: "SignedToken",
431 length: SIGNED_TOKEN_LENGTH,
432 })
433 }
434
435 pub fn from_bytes(bytes: &[u8]) -> Result<SignedToken, TokenError> {
437 if bytes.len() != SIGNED_TOKEN_LENGTH {
438 return Err(SignedToken::bytes_length_error());
439 }
440
441 let mut bits: [u8; 32] = [0u8; 32];
442 bits.copy_from_slice(&bytes[..32]);
443 Ok(SignedToken(CompressedRistretto(bits)))
444 }
445}
446
447#[cfg_attr(not(feature = "cbindgen"), repr(C))]
452#[allow(non_snake_case)]
453#[derive(Debug, Clone)]
454pub struct UnblindedToken {
455 pub t: TokenPreimage,
457 W: CompressedRistretto,
461}
462
463#[cfg(any(test, feature = "base64"))]
464impl_base64!(UnblindedToken);
465
466#[cfg(feature = "serde")]
467impl_serde!(UnblindedToken);
468
469impl UnblindedToken {
470 pub fn derive_verification_key<D>(&self) -> VerificationKey
472 where
473 D: Digest<OutputSize = U64> + Default,
474 {
475 let mut hash = D::default();
476 hash.update(b"hash_derive_key");
477
478 hash.update(self.t.0.as_ref());
479 hash.update(self.W.as_bytes());
480
481 let output = hash.finalize();
482 let mut output_bytes = [0u8; 64];
483 output_bytes.copy_from_slice(output.as_slice());
484
485 VerificationKey(output_bytes)
486 }
487
488 pub fn to_bytes(&self) -> [u8; UNBLINDED_TOKEN_LENGTH] {
490 let mut unblinded_token_bytes: [u8; UNBLINDED_TOKEN_LENGTH] = [0u8; UNBLINDED_TOKEN_LENGTH];
491
492 unblinded_token_bytes[..TOKEN_PREIMAGE_LENGTH].copy_from_slice(&self.t.to_bytes());
493 unblinded_token_bytes[TOKEN_PREIMAGE_LENGTH..].copy_from_slice(&self.W.to_bytes());
494 unblinded_token_bytes
495 }
496
497 fn bytes_length_error() -> TokenError {
498 TokenError(InternalError::BytesLengthError {
499 name: "UnblindedToken",
500 length: UNBLINDED_TOKEN_LENGTH,
501 })
502 }
503
504 pub fn from_bytes(bytes: &[u8]) -> Result<UnblindedToken, TokenError> {
506 if bytes.len() != UNBLINDED_TOKEN_LENGTH {
507 return Err(UnblindedToken::bytes_length_error());
508 }
509
510 let preimage = TokenPreimage::from_bytes(&bytes[..TOKEN_PREIMAGE_LENGTH])?;
511
512 let mut w_bits: [u8; 32] = [0u8; 32];
513 w_bits.copy_from_slice(&bytes[TOKEN_PREIMAGE_LENGTH..]);
514 Ok(UnblindedToken {
515 t: preimage,
516 W: CompressedRistretto(w_bits),
517 })
518 }
519}
520
521#[cfg_attr(not(feature = "cbindgen"), repr(C))]
525#[derive(Clone)]
526pub struct VerificationKey([u8; 64]);
527
528impl Debug for VerificationKey {
529 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
530 write!(f, "VerificationKey: {:?}", &self.0[..])
531 }
532}
533
534impl VerificationKey {
535 pub fn sign<D>(&self, message: &[u8]) -> VerificationSignature
537 where
538 D: Mac<OutputSize = U64> + KeyInit,
539 {
540 let mut mac = <D as Mac>::new_from_slice(self.0.as_ref()).unwrap();
541 mac.update(message);
542
543 VerificationSignature(mac.finalize().into_bytes())
544 }
545
546 pub fn verify<D>(&self, sig: &VerificationSignature, message: &[u8]) -> bool
549 where
550 D: Mac<OutputSize = U64> + KeyInit,
551 {
552 &self.sign::<D>(message) == sig
553 }
554}
555
556#[cfg_attr(not(feature = "cbindgen"), repr(C))]
558#[derive(Clone)]
559pub struct VerificationSignature(GenericArray<u8, U64>);
560
561#[cfg(any(test, feature = "base64"))]
562impl_base64!(VerificationSignature);
563
564#[cfg(feature = "serde")]
565impl_serde!(VerificationSignature);
566
567impl ConstantTimeEq for VerificationSignature {
568 fn ct_eq(&self, other: &VerificationSignature) -> Choice {
569 self.0.ct_eq(&other.0)
570 }
571}
572impl PartialEq for VerificationSignature {
573 fn eq(&self, other: &VerificationSignature) -> bool {
574 self.ct_eq(other).unwrap_u8() == 1
575 }
576}
577
578#[cfg(any(test, feature = "serde", feature = "base64"))]
579impl VerificationSignature {
580 fn to_bytes(&self) -> [u8; VERIFICATION_SIGNATURE_LENGTH] {
583 let mut bytes: [u8; VERIFICATION_SIGNATURE_LENGTH] = [0u8; VERIFICATION_SIGNATURE_LENGTH];
584 bytes.copy_from_slice(self.0.as_slice());
585 bytes
586 }
587
588 fn bytes_length_error() -> TokenError {
589 TokenError(InternalError::BytesLengthError {
590 name: "VerificationSignature",
591 length: VERIFICATION_SIGNATURE_LENGTH,
592 })
593 }
594
595 fn from_bytes(bytes: &[u8]) -> Result<VerificationSignature, TokenError> {
597 if bytes.len() != VERIFICATION_SIGNATURE_LENGTH {
598 return Err(VerificationSignature::bytes_length_error());
599 }
600
601 let arr: &GenericArray<u8, U64> = GenericArray::from_slice(bytes);
602 Ok(VerificationSignature(*arr))
603 }
604}
605
606#[cfg(test)]
607mod tests {
608 use base64::{engine::Engine as _, prelude::BASE64_STANDARD};
609 use hmac::Hmac;
610 use rand::rngs::OsRng;
611 use sha2::Sha512;
612 use std::vec::Vec;
613
614 use super::*;
615 type HmacSha512 = Hmac<Sha512>;
616
617 #[allow(non_snake_case)]
618 #[test]
619 fn vector_tests() {
620 let vectors = [
622 ("SlPD+7xZlw7l+Fr4E4dd/8E6kEouU65+ZfoN6m5iyQE=", "nGajOcg0T5IvwyBstdroFKWUwBd90yNcJU2cQJpluAg=", "nwfnvlVROHqYupd8cy0IDcsPKaBI42VpEsZTPjLueu0ptyF2nOZOQ9VxM7B02DnVMe0fKFEK+0Ws4QofS3lNbw==", "rBKvQjzCywrH+WAHjvVpB4P59cy1A0CCcYjeUioWdA0=", "iKt8hXS7Zyqy5/xbbknh/CuCmQM+Cti6uOibdKZBlEM=", "OFccZ1mrx9SSrRSoj95nEVmkbMAdggfpj6haKO0BrQQ=", "JFJyI4tUdjjtud9a4qZalp5i9QY4I0x/VhChVu4P714="),
623 ("7oD3U1ZwWQN/2eZhiXfHtnwmhR+yl3P7Gta+T123awI=", "vtiIh6vgqE9kaR/gvfo9rxps1pehPweuB1iJEM45ySc=", "5aaIdCtHxa37WdTfdv0dseUe4Dscqfgqyhc+24tyk0dOvpgPkE0QyRZEK0eDoOmEhgy2yVeznDjtj1HP+qaKTQ==", "yhpWSFSxFQRlZH9QtcmCrL1p27dYMEKs+sub7hfVbA8=", "qDUfb1GhqEsJg2MEo0jI5fUDsKitwSSkV6kaF3wWHBU=", "goTV+GGlPyIodeEfRu62nWVJFpj3lXMjZY6w4ABaolc=", "sgJfuuExkd+VoIXOr9gv+M7VlRnjnUtveVzWcOY6YzM="),
624 ("tviSLm/W8oFds67y9lMs990fjh08hQNV17/4V2bmOQY=", "5ufRlCvVKvXp1yuxxS7Jvw9LSwQUl6Q/MlT6HY2l1Hc=", "7aq3TaFBD8BV6gaMmekmCsvjN89dPgDlsyMP/tsLmQeH0McOC/5BmOpnWN1aYftf7C35gfMb7+FT+B0XFheE2w==", "Ge3prZ2jJSoh1A3ZvrSfaSA1kDziGW2I+Gmh6jniaAs=", "pOTANELrS8oor67hIYyCvrbmlMrn6Fr+04nBmFgrvxU=", "JjbfZ+UifRtHLdxcvVdI6C2SXYls9aWS0UyS6vyfCAY=", "Ki8Vb+Fm7qqeeL63/Oco95UaMOO62bRGq2fMTz5xPU8="),
625 ("2srhyAUoqF+s2y+NfSXluDXVxC7JBgiD2ttOSXBYPww=", "HhdUX1s812RxwznoreV7i/BHvj2Xy9tJo24GxNDmtF8=", "bQqtuvgVfQYqyyQYwXakdVEbNcP2IYpWaOpbxvVLh4L4s0DwCsG+ul5izWMqfOeAnHJWCKyl7798QfI3ZD8GwA==", "gfes2hjQSpt6QOBJnz4t/N/utBkdDS+W4GRQIYjb/wQ=", "ZnaqI3kpS5nh9B3jw6uOeUld//Q2+olaAlimWRFvcDE=", "0pISjRRLsiYWLzqiukHe1xkIEuDmibUcg9m/5zcPwSo=", "2lSAwKDv4mdzZuMSEEngBXSQBJRJoprzqKMtX9Bi/zs="),
626 ("pfwD6XL8PnQfJPuzg/LKKVf3QRLc4ZclvC+6GBBETgo=", "Vv9rfOewgYx7jHMyfAZfBFEBt5IuwIKwz2NbDpra+UM=", "FtP6gVFikwP+l0FWLtBl2068AFDvVYNkroESSij1wBMTIy+8SW39iiVoZXtobXIUOCoaAJAwF92paYeEQrpa/w==", "xrF8ZzEtEsGbRfJGjULVkNisgpaAO69AHZKYhyQmng4=", "rHUztBaoMDDVwOTnOxFQgEOEeG6lKBL7Tb+fluztCxo=", "dhQv3WoCFW+EcV1dpCARarugjhU/enn0UlamXDPoFxc=", "GgWeq8r+ZRsPJa50bP7y3kVAq7yBSSN8eM0oOn/U2CM="),
627 ("xNWxYjBW6Sty2Yy33S38IPkX6v4zAwK10Ge/WPxVVwU=", "GrqZp9KBIAi1mExq2VUhG8lIuNO/J9Ap4xATdJ5TfmM=", "xP/wuGwC7WYtLSUiZHofCaey+e6lbn4gsfBszdnOw347LSCBLfNpl4Y2wiZGYDZ1gEEEdF0pl+KN9dgkKq0ZyA==", "RclUsYJkWG7Uw0tM/rn+nyvDey/Ibwl7WkmmvkIPWwc=", "fiD5jlU2Bhu+chVrhWKvZTaVJnbmBTpDcfEAH9Kcjg4=", "mCFMTFdnxZ/gvTnVNGMmZkXWqlnnZH3JnwDKhTBT3x0=", "krmSP8LTAA0O35g7uk+o7MMYTl2qACiWu+CDZXtQJSo="),
628 ("lE2Tu2LzhNgU77KnsEFbqVYOc5wsbMYYzBQOcpi32Ag=", "EuJk2I4y6ZrbIn04deR+lzJS1xrBIpN+RthbPknv+gA=", "DPw4xN363pkKIT0gj794mDNPTe7X5YMP0mZ1ExVDWuGbuU9NPckmUvJD3R+W81latHPSNW2PqPbWTMT2SxLKmQ==", "Dbpt5WypybRRaQiInYndWLf/O2ewT3IEYOOdxKywNg8=", "QJH62wtVRKX0Eq1GTWVyAVuML0mpEl18VvxFn3TvTDI=", "TMRELsL1kWbyRNLQhWuIyU2j7M2FJk0trp+uR1w4hHw=", "nDiCPlbQ6HfR3MX9jRqY3id4DWo3GaZ1FvUfkmAjWyg="),
629 ("Tmfvkm6Kvi/BWAvqNsGsdQzJTI9tkGa4Sr0dNPTMCwc=", "iPXJcLCmT9SYYVYVfNx6br3VG1rHHF2hIrD2cVx8YGE=", "BdOrSDfezktj/f1d0HordqjIJWbfGiFn2uXhJbaqDna52ZyoRmT1Du6lTkSfDlhwORN/V1Q9iSBUgxQckzFmtg==", "0web3hpMwnqhIhu9mjAKNLfmFdJUfY3pu4clcs0G8AQ=", "Qll/1fI1hlcc3Dm6xtfo3LlJwu6fgoffCZ3VzzQvCAs=", "KNbnK4jL8SThHByYWWrzdpZHxvrTVid7aBYHnZD2BW0=", "Lti4tRDBQzwNIiTbGpPVVViHMvCEfC7ov2Ne3LrQdRg="),
630 ("N8oRiMuSrYdp9TMKp++AP8ridXqdX6BoPOucx2eRCQE=", "mnikks9ySHzZGMgoPZ0SRA8/JJkMh5aA+m3eqeMfqTE=", "9sNH3G618rH0vy3TKBMNRQDKOb66LUKBo9jOtMsezeN4sgAp+2pMVDMS5BATkVxXAW5dpoGUTMJ3+cfnX0plSg==", "f44zH9r/YnCyaHZnKtEc/68diotEo1GjQ5MWepNEXAk=", "EEH0FTbmxN5XoXnAHmIH0y4VjcixJ5U9T8WqXgP2IAg=", "Km0KASMeIqj0s5vswz+WEYptTx2Y0fOb9cVjb+UKexw=", "lNDdKND+R/JmDrM08Q7w7ePoXT7/hgzGU6xVBU5RFig="),
631 ("Nye8fMOQJv1HjCY6qxG0Br661wjd8OwNI1O0ZbkmGAc=", "5szoRS3/9jdVTmhswiS9yyaLeC2I0CfBAUzfe0zGjz8=", "OkOqxU+boJmNIhmzusoRGUDVJLfPlGd9bFV3UPpNueEHfu21um4zwQSuJUQ8hr8VgzU63fb93Rmk/0kRiOPUhw==", "ZBztTnJvQKmPkxfgzGzufhRa6o4oUPublpOIhODHKA4=", "lD1eLLmRw7ebLOd51OQSps51cZGTIg2DM+GL38bQQww=", "qA27hu9S60UX0jfnWJQgUBllQvfOPu+jQVkphi6Sv24=", "HhPZFQiNAYzG+niNmUiWut2g/YMhox86h1XyZypQfVk="),
632 ];
633 for (k, Y, seed, r, P, Q, W) in vectors {
634 let server_key = SigningKey::decode_base64(k).unwrap();
635 let seed = BASE64_STANDARD.decode(seed).unwrap();
636
637 assert!(server_key.public_key.encode_base64() == Y);
638
639 let r_bytes = BASE64_STANDARD.decode(r).unwrap();
640 let mut r_bits: [u8; 32] = [0u8; 32];
641 r_bits.copy_from_slice(&r_bytes);
642 let r = Scalar::from_canonical_bytes(r_bits).unwrap();
643
644 let token = Token::hash_from_bytes_with_blind::<Sha512>(&seed, r);
645
646 let blinded_token = token.blind();
647
648 assert!(blinded_token.encode_base64() == P);
649
650 let signed_token = server_key.sign(&blinded_token).unwrap();
651
652 assert!(signed_token.encode_base64() == Q);
653
654 let unblinded_token = token.unblind(&signed_token).unwrap();
655
656 let W_bytes = BASE64_STANDARD.decode(W).unwrap();
657 let mut W_bits: [u8; 32] = [0u8; 32];
658 W_bits.copy_from_slice(&W_bytes[..32]);
659 let W = CompressedRistretto(W_bits);
660
661 let unblinded_token_expected = UnblindedToken { W, t: token.t };
662 assert!(unblinded_token.encode_base64() == unblinded_token_expected.encode_base64());
663 }
664 }
665
666 #[test]
667 fn works() {
668 let mut rng = OsRng;
669
670 let server_key = SigningKey::random(&mut rng);
673
674 let token = Token::random::<Sha512, _>(&mut rng);
678 let blinded_token = token.blind();
680
681 let signed_token = server_key.sign(&blinded_token).unwrap();
683
684 let unblinded_token = token.unblind(&signed_token).unwrap();
686
687 let client_verification_key = unblinded_token.derive_verification_key::<Sha512>();
691 let client_sig = client_verification_key.sign::<HmacSha512>(b"test message");
693
694 let server_unblinded_token = server_key.rederive_unblinded_token(&unblinded_token.t);
698 let server_verification_key = server_unblinded_token.derive_verification_key::<Sha512>();
700 let server_sig = server_verification_key.sign::<HmacSha512>(b"test message");
702
703 assert!(client_sig == server_sig);
705
706 let server_sig_fail = server_verification_key.sign::<HmacSha512>(b"failing test message");
708 assert!(!(client_sig == server_sig_fail));
709 }
710
711 #[test]
712 fn from_random_bytes_test() {
713 let seeds = [
714 "nwfnvlVROHqYupd8cy0IDcsPKaBI42VpEsZTPjLueu0ptyF2nOZOQ9VxM7B02DnVMe0fKFEK+0Ws4QofS3lNbw==",
715 "5aaIdCtHxa37WdTfdv0dseUe4Dscqfgqyhc+24tyk0dOvpgPkE0QyRZEK0eDoOmEhgy2yVeznDjtj1HP+qaKTQ==",
716 ];
717
718 let mut keys = Vec::new();
719
720 for seed in seeds.iter() {
722 let seed_bytes = BASE64_STANDARD.decode(seed).unwrap();
723 assert_eq!(seed_bytes.len(), SCALAR_WIDE_INPUT_LENGTH);
724
725 let key = SigningKey::from_random_bytes(&seed_bytes).unwrap();
726
727 let mut bytes_array = [0u8; SCALAR_WIDE_INPUT_LENGTH];
728 bytes_array.copy_from_slice(&seed_bytes);
729 let scalar = Scalar::from_bytes_mod_order_wide(&bytes_array);
730 let scalar_bytes = scalar.to_bytes();
731 let key_manual = SigningKey::from_bytes(&scalar_bytes).unwrap();
732
733 assert!(key.to_bytes() == key_manual.to_bytes());
734 assert!(key.public_key.encode_base64() == key_manual.public_key.encode_base64());
735
736 let key2 = SigningKey::from_random_bytes(&seed_bytes).unwrap();
737 assert!(key.to_bytes() == key2.to_bytes());
738 assert!(key.public_key.encode_base64() == key2.public_key.encode_base64());
739
740 keys.push(key);
741 }
742
743 let all_zeros = [0u8; SCALAR_WIDE_INPUT_LENGTH];
745 let all_ones = [0xFFu8; SCALAR_WIDE_INPUT_LENGTH];
746
747 let key_zeros = SigningKey::from_random_bytes(&all_zeros).unwrap();
748 let key_ones = SigningKey::from_random_bytes(&all_ones).unwrap();
749
750 let mut rng = OsRng;
752 let token = Token::random::<Sha512, _>(&mut rng);
753 let blinded_token = token.blind();
754
755 for key in keys.iter().chain([&key_zeros, &key_ones]) {
756 assert_eq!(key.to_bytes().len(), SIGNING_KEY_LENGTH);
757 assert_eq!(key.public_key.encode_base64().len(), 44);
758 assert!(key.sign(&blinded_token).is_ok());
759 }
760
761 let all_keys: Vec<&SigningKey> = keys.iter().chain([&key_zeros, &key_ones]).collect();
763 for i in 0..all_keys.len() {
764 for j in (i + 1)..all_keys.len() {
765 assert!(!(all_keys[i].to_bytes() == all_keys[j].to_bytes()));
766 assert!(
767 !(all_keys[i].public_key.encode_base64()
768 == all_keys[j].public_key.encode_base64())
769 );
770 }
771 }
772
773 assert!(SigningKey::from_random_bytes(&[0u8; 32]).is_err());
775 assert!(SigningKey::from_random_bytes(&[0u8; 63]).is_err());
776 assert!(SigningKey::from_random_bytes(&[0u8; 65]).is_err());
777 assert!(SigningKey::from_random_bytes(&[]).is_err());
778 assert!(SigningKey::from_random_bytes(&[0u8; 128]).is_err());
779 }
780}