challenge_bypass_ristretto/
oprf.rs

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
16/// The length of a `TokenPreimage`, in bytes.
17pub const TOKEN_PREIMAGE_LENGTH: usize = 64;
18/// The length of a `Token`, in bytes.
19pub const TOKEN_LENGTH: usize = 96;
20/// The length of a `BlindedToken`, in bytes.
21pub const BLINDED_TOKEN_LENGTH: usize = 32;
22/// The length of a `PublicKey`, in bytes.
23pub const PUBLIC_KEY_LENGTH: usize = 32;
24/// The length of a `SigningKey`, in bytes.
25pub const SIGNING_KEY_LENGTH: usize = 32;
26/// The length of a `SignedToken`, in bytes.
27pub const SIGNED_TOKEN_LENGTH: usize = 32;
28/// The length of a `UnblindedToken`, in bytes.
29pub const UNBLINDED_TOKEN_LENGTH: usize = 96;
30/// The length of a `VerificationSignature`, in bytes.
31pub const VERIFICATION_SIGNATURE_LENGTH: usize = 64;
32/// The length of wide scalar input, in bytes.
33pub const SCALAR_WIDE_INPUT_LENGTH: usize = 64;
34
35/// A `TokenPreimage` is a slice of bytes which can be hashed to a `RistrettoPoint`.
36///
37/// The hash function must ensure the discrete log with respect to other points is unknown.
38/// In this construction `RistrettoPoint::from_uniform_bytes` is used as the hash function.
39#[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    /// Convert this `TokenPreimage` to a byte array.
68    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    /// Construct a `TokenPreimage` from a slice of bytes.
80    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/// A `Token` consists of a randomly chosen preimage and blinding factor.
92///
93/// Since a token includes the blinding factor it should be treated
94/// as a client secret and NEVER revealed to the server.
95#[cfg_attr(not(feature = "cbindgen"), repr(C))]
96#[derive(Debug, Clone)]
97pub struct Token {
98    /// `t` is a `TokenPreimage`
99    pub(crate) t: TokenPreimage,
100    /// `r` is a `Scalar` which is the blinding factor
101    r: Scalar,
102}
103
104/// Overwrite the token blinding factor with null when it goes out of scope.
105impl 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    /// Generates a new random `Token` using the provided random number generator.
120    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    /// Creates a new `Token`, using hashing to derive a `TokenPreimage` and the specified blind
132    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    /// Creates a new `Token`, using hashing to derive a `TokenPreimage` and a random blind
148    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    /// Blinds the `Token`, returning a `BlindedToken` to be sent to the server.
158    pub fn blind(&self) -> BlindedToken {
159        BlindedToken((self.r * self.t.T()).compress())
160    }
161
162    /// Using the blinding factor of the original `Token`, unblind a `SignedToken`
163    /// returned from the server.
164    ///
165    /// Returns a `TokenError` if the `SignedToken` point is not valid.
166    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    /// Convert this `Token` to a byte array.
178    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    /// Construct a `Token` from a slice of bytes.
194    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/// A `BlindedToken` is sent to the server for signing.
214///
215/// It is the result of the scalar multiplication of the point derived from the token
216/// preimage with the blinding factor.
217///
218/// \\(P = T^r = H_1(t)^r\\)
219#[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    /// Convert this `BlindedToken` to a byte array.
231    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    /// Construct a `BlindedToken` from a slice of bytes.
243    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/// A `PublicKey` is a committment by the server to a particular `SigningKey`.
255///
256/// \\(Y = X^k\\)
257#[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    /// Convert this `PublicKey` to a byte array.
270    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    /// Construct a `PublicKey` from a slice of bytes.
282    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/// A `SigningKey` is used to sign a `BlindedToken` and verify an `UnblindedToken`.
295///
296/// This is a server secret and should NEVER be revealed to the client.
297#[cfg_attr(not(feature = "cbindgen"), repr(C))]
298#[derive(Debug, Clone)]
299pub struct SigningKey {
300    /// A `PublicKey` showing a committment to this particular key
301    pub public_key: PublicKey,
302    /// `k` is the actual key
303    pub(crate) k: Scalar,
304}
305
306#[cfg(any(test, feature = "base64"))]
307impl_base64!(SigningKey);
308
309#[cfg(feature = "serde")]
310impl_serde!(SigningKey);
311
312/// Overwrite signing key with null when it goes out of scope.
313impl Drop for SigningKey {
314    fn drop(&mut self) {
315        self.k.zeroize();
316    }
317}
318
319#[allow(non_snake_case)]
320impl SigningKey {
321    /// Generates a new random `SigningKey` using the provided random number generator.
322    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    /// Construct a `SigningKey` from 64 random bytes.
332    ///
333    /// The random bytes MUST be cryptographically strong, uniform random bytes
334    /// such as those output from a CSPRNG or appropriately seeded KDF.
335    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    /// Signs the provided `BlindedToken`
355    ///
356    /// Returns None if the `BlindedToken` point is not valid.
357    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    /// Rederives an `UnblindedToken` via the token preimage of the provided `UnblindedToken`
368    ///
369    /// W' = T^k = H_1(t)^k
370    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    /// Convert this `SigningKey` to a byte array.
378    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    /// Construct a `SigningKey` from a slice of bytes.
390    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/// A `SignedToken` is the result of signing a `BlindedToken`.
410///
411/// \\(Q = P^k = (T^r)^k\\)
412#[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    /// Convert this `SignedToken` to a byte array.
424    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    /// Construct a `SignedToken` from a slice of bytes.
436    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/// An `UnblindedToken` is the result of unblinding a `SignedToken`.
448///
449/// While both the client and server both "know" this value,
450/// it should nevertheless not be sent between the two.
451#[cfg_attr(not(feature = "cbindgen"), repr(C))]
452#[allow(non_snake_case)]
453#[derive(Debug, Clone)]
454pub struct UnblindedToken {
455    /// `t` is the `TokenPreimage`
456    pub t: TokenPreimage,
457    /// `W` is the unblinded signed `CompressedRistretto` point
458    ///
459    /// \\(W = Q^{1/r} = P^{k(1/r)} = T^{rk(1/r)} = T^k\\)
460    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    /// Derive the `VerificationKey` for this particular `UnblindedToken`
471    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    /// Convert this `UnblindedToken` to a byte array.
489    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    /// Construct a `UnblindedToken` from a slice of bytes.
505    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/// The shared `VerificationKey` for proving / verifying the validity of an `UnblindedToken`.
522///
523/// \\(K = H_2(t, W)\\)
524#[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    /// Use the `VerificationKey` to "sign" a message, producing a `VerificationSignature`
536    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    /// Use the `VerificationKey` to check that the signature of a message matches the
547    /// provided `VerificationSignature`
548    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/// A `VerificationSignature` which can be verified given the `VerificationKey` and message
557#[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    /// Convert this `VerificationSignature` to a byte array.
581    /// We intentionally keep this private to avoid accidental non constant time comparisons
582    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    /// Construct a `VerificationSignature` from a slice of bytes.
596    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        // Generated using tools/oprf-test-gen
621        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        // Server setup
671
672        let server_key = SigningKey::random(&mut rng);
673
674        // Signing
675
676        // client prepares a random token and blinding scalar
677        let token = Token::random::<Sha512, _>(&mut rng);
678        // client blinds the token and sends it to the server
679        let blinded_token = token.blind();
680
681        // server signs the blinded token and returns it to the client
682        let signed_token = server_key.sign(&blinded_token).unwrap();
683
684        // client uses the blinding scalar to unblind the returned signed token
685        let unblinded_token = token.unblind(&signed_token).unwrap();
686
687        // Redemption
688
689        // client derives the shared key from the unblinded token
690        let client_verification_key = unblinded_token.derive_verification_key::<Sha512>();
691        // client signs a message using the shared key
692        let client_sig = client_verification_key.sign::<HmacSha512>(b"test message");
693
694        // client sends the token preimage, signature and message to the server
695
696        // server derives the unblinded token using it's key and the clients token preimage
697        let server_unblinded_token = server_key.rederive_unblinded_token(&unblinded_token.t);
698        // server derives the shared key from the unblinded token
699        let server_verification_key = server_unblinded_token.derive_verification_key::<Sha512>();
700        // server signs the same message using the shared key
701        let server_sig = server_verification_key.sign::<HmacSha512>(b"test message");
702
703        // The server compares the client signature to it's own
704        assert!(client_sig == server_sig);
705
706        // and a failing equality
707        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        // Test correctness and determinism
721        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        // Test edge cases
744        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        // Test functionality
751        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        // Test uniqueness
762        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        // Test error handling
774        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}