Skip to main content

jwt/
jwk.rs

1use crypto::{
2    curve25519::ed25519,
3    mldsa::{
4        MlDsa44PublicKey, MlDsa44SecretKey, MlDsa65PublicKey, MlDsa65SecretKey, MlDsa87PublicKey, MlDsa87SecretKey,
5    },
6    p256, p384, p521,
7};
8use serde::{Deserialize, Serialize};
9use small_collections::SmallString;
10use smallvec::SmallVec;
11
12use crate::{Algorithm, Error, RsaPublicKey, SecretKey};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct Jwks {
16    pub keys: SmallVec<Jwk, 5>,
17}
18
19/// a JSON Web Key
20/// https://www.rfc-editor.org/rfc/rfc7517
21/// https://www.rfc-editor.org/rfc/rfc8037
22/// https://www.ietf.org/archive/id/draft-ietf-jose-pqc-02.html
23/// Note: Jwk are not validated during deserialization
24#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct Jwk {
26    pub kid: SmallString<36>, // 36 = UUID length
27    pub r#use: KeyUse,
28    #[serde(rename = "alg")]
29    pub algorithm: Algorithm,
30
31    #[serde(flatten)]
32    pub crypto: JwkCrypto,
33}
34
35#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(rename_all = "UPPERCASE", tag = "kty")]
37pub enum JwkCrypto {
38    /// EdDSA
39    Okp {
40        #[serde(rename = "crv")]
41        curve: OkpCurve,
42        #[serde(with = "base64_url_no_padding")]
43        x: SmallVec<u8, 32>,
44        #[serde(with = "base64_url_no_padding::option", skip_serializing_if = "Option::is_none")]
45        d: Option<SmallVec<u8, 32>>,
46    },
47    /// ECDSA
48    Ec {
49        #[serde(rename = "crv")]
50        curve: EcCurve,
51        #[serde(with = "base64_url_no_padding")]
52        x: SmallVec<u8, 32>,
53        #[serde(with = "base64_url_no_padding")]
54        y: SmallVec<u8, 32>,
55        #[serde(with = "base64_url_no_padding::option", skip_serializing_if = "Option::is_none")]
56        d: Option<SmallVec<u8, 32>>,
57    },
58    /// Static keys
59    #[serde(rename = "oct")]
60    Oct {
61        #[serde(with = "base64_url_no_padding")]
62        key: SmallVec<u8, 32>,
63    },
64    /// RSA public key
65    #[serde(rename = "RSA")]
66    Rsa {
67        // Always heap-allocated. We use a `SmallVec` to avoid needing a separate implmentation for
68        // serde's `base64_url_no_padding`.
69        #[serde(with = "base64_url_no_padding")]
70        n: SmallVec<u8, 0>,
71        #[serde(with = "base64_url_no_padding")]
72        e: SmallVec<u8, 4>,
73    },
74    /// ML-DSA public key (draft "AKP" key type)
75    ///
76    /// `pub` holds the encoded public key and the optional `priv` holds the 32-byte seed the
77    /// signing key was generated from.
78    #[serde(rename = "AKP")]
79    Akp {
80        #[serde(rename = "pub", with = "base64_url_no_padding")]
81        pub_key: SmallVec<u8, 0>,
82        #[serde(
83            rename = "priv",
84            with = "base64_url_no_padding::option",
85            skip_serializing_if = "Option::is_none"
86        )]
87        private_key: Option<SmallVec<u8, 0>>,
88    },
89}
90
91#[derive(Copy, Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
92pub enum KeyUse {
93    #[serde(rename = "sig")]
94    Sign,
95    #[serde(rename = "enc")]
96    Encrypt,
97}
98
99// https://csrc.nist.gov/pubs/fips/186-5/final
100// https://csrc.nist.gov/pubs/sp/800/186/final
101// https://www.rfc-editor.org/rfc/rfc8032
102#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
103pub enum OkpCurve {
104    Ed25519,
105}
106
107impl core::str::FromStr for OkpCurve {
108    type Err = Error;
109
110    fn from_str(s: &str) -> Result<Self, Self::Err> {
111        match s {
112            "Ed25519" => Ok(OkpCurve::Ed25519),
113            _ => Err(Error::InvalidCurve),
114        }
115    }
116}
117
118impl core::fmt::Display for OkpCurve {
119    fn fmt(&self, f: &mut alloc::fmt::Formatter<'_>) -> alloc::fmt::Result {
120        write!(f, "{self:?}")
121    }
122}
123
124#[derive(Copy, Clone, Debug, Deserialize, Serialize, PartialEq, Eq)]
125pub enum EcCurve {
126    /// P-256 and SHA-256
127    #[serde(rename = "P-256")]
128    P256,
129
130    /// P-384 and SHA-384
131    #[serde(rename = "P-384")]
132    P384,
133
134    /// P-521 and SHA-512
135    #[serde(rename = "P-521")]
136    P521,
137}
138
139////////////////////////////////////////////////////////////////////////////////////////////////////
140// Secret key (BLAKE3 / HMAC)
141////////////////////////////////////////////////////////////////////////////////////////////////////
142
143impl From<&SecretKey<'_>> for Jwk {
144    #[inline]
145    fn from(key: &SecretKey<'_>) -> Self {
146        return Jwk {
147            kid: SmallString::new(),
148            r#use: KeyUse::Sign,
149            algorithm: key.algorithm,
150            crypto: JwkCrypto::Oct {
151                key: key.key.into(),
152            },
153        };
154    }
155}
156
157impl<'a> TryFrom<&'a Jwk> for SecretKey<'a> {
158    type Error = Error;
159
160    #[inline]
161    fn try_from(jwk: &'a Jwk) -> Result<Self, Self::Error> {
162        if !matches!(
163            jwk.algorithm,
164            Algorithm::BLAKE3 | Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512
165        ) {
166            return Err(Error::InvalidKey);
167        }
168
169        match &jwk.crypto {
170            JwkCrypto::Oct {
171                key,
172            } => Ok(SecretKey::new(jwk.algorithm, key.as_slice())),
173            _ => Err(Error::InvalidKey),
174        }
175    }
176}
177
178////////////////////////////////////////////////////////////////////////////////////////////////////
179// Ed25519
180////////////////////////////////////////////////////////////////////////////////////////////////////
181
182impl From<&ed25519::SecretKey> for Jwk {
183    #[inline]
184    fn from(key: &ed25519::SecretKey) -> Self {
185        return Jwk {
186            kid: SmallString::new(),
187            r#use: KeyUse::Sign,
188            algorithm: Algorithm::EdDSA,
189            crypto: JwkCrypto::Okp {
190                curve: OkpCurve::Ed25519,
191                x: key.public_key().to_bytes().into(),
192                d: Some(key.to_bytes().into()),
193            },
194        };
195    }
196}
197
198impl From<&ed25519::PublicKey> for Jwk {
199    #[inline]
200    fn from(key: &ed25519::PublicKey) -> Self {
201        return Jwk {
202            kid: SmallString::new(),
203            r#use: KeyUse::Sign,
204            algorithm: Algorithm::EdDSA,
205            crypto: JwkCrypto::Okp {
206                curve: OkpCurve::Ed25519,
207                x: key.to_bytes().into(),
208                d: None,
209            },
210        };
211    }
212}
213
214impl TryFrom<&Jwk> for ed25519::SecretKey {
215    type Error = Error;
216
217    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
218        match &jwk.crypto {
219            JwkCrypto::Okp {
220                curve: OkpCurve::Ed25519,
221                d: Some(d_bytes),
222                ..
223            } => {
224                let seed: [u8; 32] = d_bytes.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
225                Ok(ed25519::SecretKey::from_bytes(&seed))
226            }
227            _ => Err(Error::InvalidKey),
228        }
229    }
230}
231
232impl TryFrom<&Jwk> for ed25519::PublicKey {
233    type Error = Error;
234
235    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
236        match &jwk.crypto {
237            JwkCrypto::Okp {
238                curve: OkpCurve::Ed25519,
239                x,
240                ..
241            } => {
242                let public_key: [u8; 32] = x.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
243                ed25519::PublicKey::from_bytes(&public_key).map_err(|_| Error::InvalidKey)
244            }
245            _ => Err(Error::InvalidKey),
246        }
247    }
248}
249
250////////////////////////////////////////////////////////////////////////////////////////////////////
251// P-256
252////////////////////////////////////////////////////////////////////////////////////////////////////
253
254impl From<&p256::SecretKey> for Jwk {
255    #[inline]
256    fn from(key: &p256::SecretKey) -> Self {
257        let (x, y) = key.public_key().x_y();
258        return Jwk {
259            kid: SmallString::new(),
260            r#use: KeyUse::Sign,
261            algorithm: Algorithm::ES256,
262            crypto: JwkCrypto::Ec {
263                curve: EcCurve::P256,
264                x: x.into(),
265                y: y.into(),
266                d: Some(key.to_bytes().into()),
267            },
268        };
269    }
270}
271
272impl From<&p256::PublicKey> for Jwk {
273    #[inline]
274    fn from(key: &p256::PublicKey) -> Self {
275        let (x, y) = key.x_y();
276        return Jwk {
277            kid: SmallString::new(),
278            r#use: KeyUse::Sign,
279            algorithm: Algorithm::ES256,
280            crypto: JwkCrypto::Ec {
281                curve: EcCurve::P256,
282                x: x.into(),
283                y: y.into(),
284                d: None,
285            },
286        };
287    }
288}
289
290impl TryFrom<&Jwk> for p256::SecretKey {
291    type Error = Error;
292
293    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
294        match &jwk.crypto {
295            JwkCrypto::Ec {
296                curve: EcCurve::P256,
297                d: Some(d_bytes),
298                ..
299            } => {
300                let key: [u8; 32] = d_bytes.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
301                p256::SecretKey::from_bytes(&key).map_err(|_| Error::InvalidKey)
302            }
303            _ => Err(Error::InvalidKey),
304        }
305    }
306}
307
308impl TryFrom<&Jwk> for p256::PublicKey {
309    type Error = Error;
310
311    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
312        match &jwk.crypto {
313            JwkCrypto::Ec {
314                curve: EcCurve::P256,
315                x,
316                y,
317                ..
318            } => {
319                let x: [u8; 32] = x.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
320                let y: [u8; 32] = y.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
321                p256::PublicKey::from_x_y(&x, &y).map_err(|_| Error::InvalidKey)
322            }
323            _ => Err(Error::InvalidKey),
324        }
325    }
326}
327
328////////////////////////////////////////////////////////////////////////////////////////////////////
329// P-384
330////////////////////////////////////////////////////////////////////////////////////////////////////
331
332impl From<&p384::PublicKey> for Jwk {
333    #[inline]
334    fn from(key: &p384::PublicKey) -> Self {
335        let (x, y) = key.x_y();
336        return Jwk {
337            kid: SmallString::new(),
338            r#use: KeyUse::Sign,
339            algorithm: Algorithm::ES384,
340            crypto: JwkCrypto::Ec {
341                curve: EcCurve::P384,
342                x: x.into(),
343                y: y.into(),
344                d: None,
345            },
346        };
347    }
348}
349
350impl TryFrom<&Jwk> for p384::PublicKey {
351    type Error = Error;
352
353    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
354        match &jwk.crypto {
355            JwkCrypto::Ec {
356                curve: EcCurve::P384,
357                x,
358                y,
359                ..
360            } => {
361                let x: [u8; 48] = x.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
362                let y: [u8; 48] = y.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
363                p384::PublicKey::from_x_y(&x, &y).map_err(|_| Error::InvalidKey)
364            }
365            _ => Err(Error::InvalidKey),
366        }
367    }
368}
369
370////////////////////////////////////////////////////////////////////////////////////////////////////
371// P-521
372////////////////////////////////////////////////////////////////////////////////////////////////////
373
374impl From<&p521::SecretKey> for Jwk {
375    #[inline]
376    fn from(key: &p521::SecretKey) -> Self {
377        let (x, y) = key.public_key().x_y();
378        return Jwk {
379            kid: SmallString::new(),
380            r#use: KeyUse::Sign,
381            algorithm: Algorithm::ES512,
382            crypto: JwkCrypto::Ec {
383                curve: EcCurve::P521,
384                x: x.into(),
385                y: y.into(),
386                d: Some(key.to_bytes().into()),
387            },
388        };
389    }
390}
391
392impl From<&p521::PublicKey> for Jwk {
393    #[inline]
394    fn from(key: &p521::PublicKey) -> Self {
395        let (x, y) = key.x_y();
396        return Jwk {
397            kid: SmallString::new(),
398            r#use: KeyUse::Sign,
399            algorithm: Algorithm::ES512,
400            crypto: JwkCrypto::Ec {
401                curve: EcCurve::P521,
402                x: x.into(),
403                y: y.into(),
404                d: None,
405            },
406        };
407    }
408}
409
410impl TryFrom<&Jwk> for p521::SecretKey {
411    type Error = Error;
412
413    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
414        match &jwk.crypto {
415            JwkCrypto::Ec {
416                curve: EcCurve::P521,
417                d: Some(d_bytes),
418                ..
419            } => {
420                let key: [u8; 66] = d_bytes.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
421                p521::SecretKey::from_bytes(&key).map_err(|_| Error::InvalidKey)
422            }
423            _ => Err(Error::InvalidKey),
424        }
425    }
426}
427
428impl TryFrom<&Jwk> for p521::PublicKey {
429    type Error = Error;
430
431    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
432        match &jwk.crypto {
433            JwkCrypto::Ec {
434                curve: EcCurve::P521,
435                x,
436                y,
437                ..
438            } => {
439                let x: [u8; 66] = x.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
440                let y: [u8; 66] = y.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
441                p521::PublicKey::from_x_y(&x, &y).map_err(|_| Error::InvalidKey)
442            }
443            _ => Err(Error::InvalidKey),
444        }
445    }
446}
447
448////////////////////////////////////////////////////////////////////////////////////////////////////
449// RSA
450////////////////////////////////////////////////////////////////////////////////////////////////////
451
452impl From<&RsaPublicKey> for Jwk {
453    fn from(key: &RsaPublicKey) -> Self {
454        Jwk {
455            kid: SmallString::new(),
456            r#use: KeyUse::Sign,
457            algorithm: key.alg,
458            crypto: JwkCrypto::Rsa {
459                n: key.key.n_bytes().into(),
460                e: key.key.e_bytes().into(),
461            },
462        }
463    }
464}
465
466impl TryFrom<&Jwk> for RsaPublicKey {
467    type Error = Error;
468
469    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
470        match &jwk.crypto {
471            JwkCrypto::Rsa {
472                n,
473                e,
474            } => RsaPublicKey::from_n_e(jwk.algorithm, n, e),
475            _ => Err(Error::InvalidKey),
476        }
477    }
478}
479
480////////////////////////////////////////////////////////////////////////////////////////////////////
481// ML-DSA-44
482////////////////////////////////////////////////////////////////////////////////////////////////////
483
484impl From<&MlDsa44PublicKey> for Jwk {
485    fn from(key: &MlDsa44PublicKey) -> Self {
486        Jwk {
487            kid: SmallString::new(),
488            r#use: KeyUse::Sign,
489            algorithm: Algorithm::MlDsa44,
490            crypto: JwkCrypto::Akp {
491                pub_key: key.to_bytes().into(),
492                private_key: None,
493            },
494        }
495    }
496}
497
498impl From<&MlDsa44SecretKey> for Jwk {
499    fn from(key: &MlDsa44SecretKey) -> Self {
500        Jwk {
501            kid: SmallString::new(),
502            r#use: KeyUse::Sign,
503            algorithm: Algorithm::MlDsa44,
504            crypto: JwkCrypto::Akp {
505                pub_key: key.public_key().to_bytes().into(),
506                private_key: Some(key.seed().as_slice().into()),
507            },
508        }
509    }
510}
511
512impl TryFrom<&Jwk> for MlDsa44PublicKey {
513    type Error = Error;
514
515    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
516        if jwk.algorithm != Algorithm::MlDsa44 {
517            return Err(Error::InvalidKey);
518        }
519
520        match &jwk.crypto {
521            JwkCrypto::Akp {
522                pub_key, ..
523            } => MlDsa44PublicKey::try_from(pub_key.as_slice()).map_err(|_| Error::InvalidKey),
524            _ => Err(Error::InvalidKey),
525        }
526    }
527}
528
529impl TryFrom<&Jwk> for MlDsa44SecretKey {
530    type Error = Error;
531
532    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
533        if jwk.algorithm != Algorithm::MlDsa44 {
534            return Err(Error::InvalidKey);
535        }
536
537        match &jwk.crypto {
538            JwkCrypto::Akp {
539                private_key: Some(seed),
540                ..
541            } => {
542                let seed: [u8; 32] = seed.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
543                Ok(MlDsa44SecretKey::new(&seed))
544            }
545            _ => Err(Error::InvalidKey),
546        }
547    }
548}
549
550////////////////////////////////////////////////////////////////////////////////////////////////////
551// ML-DSA-65
552////////////////////////////////////////////////////////////////////////////////////////////////////
553
554impl From<&MlDsa65PublicKey> for Jwk {
555    fn from(key: &MlDsa65PublicKey) -> Self {
556        Jwk {
557            kid: SmallString::new(),
558            r#use: KeyUse::Sign,
559            algorithm: Algorithm::MlDsa65,
560            crypto: JwkCrypto::Akp {
561                pub_key: key.to_bytes().into(),
562                private_key: None,
563            },
564        }
565    }
566}
567
568impl From<&MlDsa65SecretKey> for Jwk {
569    fn from(key: &MlDsa65SecretKey) -> Self {
570        Jwk {
571            kid: SmallString::new(),
572            r#use: KeyUse::Sign,
573            algorithm: Algorithm::MlDsa65,
574            crypto: JwkCrypto::Akp {
575                pub_key: key.public_key().to_bytes().into(),
576                private_key: Some(key.seed().as_slice().into()),
577            },
578        }
579    }
580}
581
582impl TryFrom<&Jwk> for MlDsa65PublicKey {
583    type Error = Error;
584
585    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
586        if jwk.algorithm != Algorithm::MlDsa65 {
587            return Err(Error::InvalidKey);
588        }
589
590        match &jwk.crypto {
591            JwkCrypto::Akp {
592                pub_key, ..
593            } => MlDsa65PublicKey::try_from(pub_key.as_slice()).map_err(|_| Error::InvalidKey),
594            _ => Err(Error::InvalidKey),
595        }
596    }
597}
598
599impl TryFrom<&Jwk> for MlDsa65SecretKey {
600    type Error = Error;
601
602    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
603        if jwk.algorithm != Algorithm::MlDsa65 {
604            return Err(Error::InvalidKey);
605        }
606
607        match &jwk.crypto {
608            JwkCrypto::Akp {
609                private_key: Some(seed),
610                ..
611            } => {
612                let seed: [u8; 32] = seed.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
613                Ok(MlDsa65SecretKey::new(&seed))
614            }
615            _ => Err(Error::InvalidKey),
616        }
617    }
618}
619
620////////////////////////////////////////////////////////////////////////////////////////////////////
621// ML-DSA-87
622////////////////////////////////////////////////////////////////////////////////////////////////////
623
624impl From<&MlDsa87PublicKey> for Jwk {
625    fn from(key: &MlDsa87PublicKey) -> Self {
626        Jwk {
627            kid: SmallString::new(),
628            r#use: KeyUse::Sign,
629            algorithm: Algorithm::MlDsa87,
630            crypto: JwkCrypto::Akp {
631                pub_key: key.to_bytes().into(),
632                private_key: None,
633            },
634        }
635    }
636}
637
638impl From<&MlDsa87SecretKey> for Jwk {
639    fn from(key: &MlDsa87SecretKey) -> Self {
640        Jwk {
641            kid: SmallString::new(),
642            r#use: KeyUse::Sign,
643            algorithm: Algorithm::MlDsa87,
644            crypto: JwkCrypto::Akp {
645                pub_key: key.public_key().to_bytes().into(),
646                private_key: Some(key.seed().as_slice().into()),
647            },
648        }
649    }
650}
651
652impl TryFrom<&Jwk> for MlDsa87PublicKey {
653    type Error = Error;
654
655    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
656        if jwk.algorithm != Algorithm::MlDsa87 {
657            return Err(Error::InvalidKey);
658        }
659
660        match &jwk.crypto {
661            JwkCrypto::Akp {
662                pub_key, ..
663            } => MlDsa87PublicKey::try_from(pub_key.as_slice()).map_err(|_| Error::InvalidKey),
664            _ => Err(Error::InvalidKey),
665        }
666    }
667}
668
669impl TryFrom<&Jwk> for MlDsa87SecretKey {
670    type Error = Error;
671
672    fn try_from(jwk: &Jwk) -> Result<Self, Self::Error> {
673        if jwk.algorithm != Algorithm::MlDsa87 {
674            return Err(Error::InvalidKey);
675        }
676
677        match &jwk.crypto {
678            JwkCrypto::Akp {
679                private_key: Some(seed),
680                ..
681            } => {
682                let seed: [u8; 32] = seed.as_slice().try_into().map_err(|_| Error::InvalidKey)?;
683                Ok(MlDsa87SecretKey::new(&seed))
684            }
685            _ => Err(Error::InvalidKey),
686        }
687    }
688}
689
690mod base64_url_no_padding {
691    use base64::{Alphabet, decode, encode};
692    use serde::{Deserializer, Serializer};
693
694    use super::*;
695
696    pub fn serialize<S: Serializer, const N: usize>(data: &SmallVec<u8, N>, serializer: S) -> Result<S::Ok, S::Error> {
697        serializer.serialize_str(&encode(data, Alphabet::UrlNoPadding))
698    }
699
700    pub fn deserialize<'de, D: Deserializer<'de>, const N: usize>(
701        deserializer: D,
702    ) -> Result<SmallVec<u8, N>, D::Error> {
703        let s = <&str>::deserialize(deserializer)?;
704        let bytes = decode(s.as_bytes(), Alphabet::UrlNoPadding).map_err(serde::de::Error::custom)?;
705        Ok(SmallVec::from(bytes))
706    }
707
708    pub(crate) mod option {
709        use alloc::string::String;
710
711        use super::*;
712
713        pub fn serialize<S: Serializer, const N: usize>(
714            data: &Option<SmallVec<u8, N>>,
715            serializer: S,
716        ) -> Result<S::Ok, S::Error> {
717            match data {
718                Some(val) => serializer.serialize_str(&encode(val, Alphabet::UrlNoPadding)),
719                None => serializer.serialize_none(),
720            }
721        }
722
723        pub fn deserialize<'de, D: Deserializer<'de>, const N: usize>(
724            deserializer: D,
725        ) -> Result<Option<SmallVec<u8, N>>, D::Error> {
726            let opt: Option<String> = Option::deserialize(deserializer)?;
727            match opt {
728                Some(s) => {
729                    let bytes = decode(s.as_bytes(), Alphabet::UrlNoPadding).map_err(serde::de::Error::custom)?;
730                    Ok(Some(SmallVec::from(bytes)))
731                }
732                None => Ok(None),
733            }
734        }
735    }
736}