1use super::SimpleSignature;
2use crate::checkpoint::EpochId;
3use crate::u256::U256;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
24#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
25pub struct ZkLoginAuthenticator {
26 pub inputs: ZkLoginInputs,
28
29 pub max_epoch: EpochId,
31
32 pub signature: SimpleSignature,
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
49pub struct ZkLoginInputs {
50 proof_points: ZkLoginProof,
51 iss_base64_details: ZkLoginClaim,
52 header_base64: String,
53
54 jwt_header: JwtHeader,
55 jwk_id: JwkId,
56 public_identifier: ZkLoginPublicIdentifier,
57}
58
59impl ZkLoginInputs {
60 #[cfg(feature = "serde")]
61 #[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
62 pub fn new(
63 proof_points: ZkLoginProof,
64 iss_base64_details: ZkLoginClaim,
65 header_base64: String,
66 address_seed: Bn254FieldElement,
67 ) -> Result<Self, InvalidZkLoginAuthenticatorError> {
68 let iss = {
69 const ISS: &str = "iss";
70
71 let iss = iss_base64_details.verify_extended_claim(ISS)?;
72
73 if iss.len() > 255 {
74 return Err(InvalidZkLoginAuthenticatorError::new(
75 "invalid iss: too long",
76 ));
77 }
78 iss
79 };
80
81 let jwt_header = JwtHeader::from_base64(&header_base64)?;
82 let jwk_id = JwkId {
83 iss: iss.clone(),
84 kid: jwt_header.kid.clone(),
85 };
86
87 let public_identifier = ZkLoginPublicIdentifier { iss, address_seed };
88
89 Ok(Self {
90 proof_points,
91 iss_base64_details,
92 header_base64,
93 jwt_header,
94 jwk_id,
95 public_identifier,
96 })
97 }
98
99 pub fn proof_points(&self) -> &ZkLoginProof {
100 &self.proof_points
101 }
102
103 pub fn iss_base64_details(&self) -> &ZkLoginClaim {
104 &self.iss_base64_details
105 }
106
107 pub fn header_base64(&self) -> &str {
108 &self.header_base64
109 }
110
111 pub fn address_seed(&self) -> &Bn254FieldElement {
112 &self.public_identifier.address_seed
113 }
114
115 pub fn jwk_id(&self) -> &JwkId {
116 &self.jwk_id
117 }
118
119 pub fn iss(&self) -> &str {
120 &self.public_identifier.iss
121 }
122
123 pub fn public_identifier(&self) -> &ZkLoginPublicIdentifier {
124 &self.public_identifier
125 }
126}
127
128#[cfg(feature = "proptest")]
129impl proptest::arbitrary::Arbitrary for ZkLoginInputs {
130 type Parameters = ();
131 type Strategy = proptest::strategy::BoxedStrategy<Self>;
132
133 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
134 use proptest::prelude::*;
135
136 (any::<ZkLoginProof>(), any::<Bn254FieldElement>())
137 .prop_map(|(proof_points, address_seed)| {
138 let iss_base64_details = ZkLoginClaim {
140 value: "wiaXNzIjoiaHR0cHM6Ly9pZC50d2l0Y2gudHYvb2F1dGgyIiw".to_owned(),
141 index_mod_4: 2,
142 };
143 let header_base64 = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEifQ".to_owned();
144 Self::new(
145 proof_points,
146 iss_base64_details,
147 header_base64,
148 address_seed,
149 )
150 .unwrap()
151 })
152 .boxed()
153 }
154}
155
156#[derive(Debug, Clone, PartialEq, Eq)]
166#[cfg_attr(
167 feature = "serde",
168 derive(serde_derive::Serialize, serde_derive::Deserialize)
169)]
170#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
171pub struct ZkLoginClaim {
172 pub value: String,
173 pub index_mod_4: u8,
174}
175
176#[derive(Debug)]
177pub struct InvalidZkLoginAuthenticatorError(String);
178
179#[cfg(feature = "serde")]
180#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
181impl InvalidZkLoginAuthenticatorError {
182 fn new<T: Into<String>>(err: T) -> Self {
183 Self(err.into())
184 }
185}
186
187impl std::fmt::Display for InvalidZkLoginAuthenticatorError {
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 write!(f, "invalid zklogin claim: {}", self.0)
190 }
191}
192
193impl std::error::Error for InvalidZkLoginAuthenticatorError {}
194
195#[cfg(feature = "serde")]
196#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
197impl ZkLoginClaim {
198 pub fn decoded_extended_claim(&self) -> Result<String, InvalidZkLoginAuthenticatorError> {
201 decode_base64_url(&self.value, &self.index_mod_4)
202 }
203
204 fn verify_extended_claim(
205 &self,
206 expected_key: &str,
207 ) -> Result<String, InvalidZkLoginAuthenticatorError> {
208 let extended_claim = self.decoded_extended_claim()?;
209
210 if !(extended_claim.ends_with('}') || extended_claim.ends_with(',')) {
212 return Err(InvalidZkLoginAuthenticatorError::new(
213 "Invalid extended claim",
214 ));
215 }
216
217 let json_str = format!("{{{}}}", &extended_claim[..extended_claim.len() - 1]);
218
219 serde_json::from_str::<serde_json::Value>(&json_str)
220 .map_err(|e| InvalidZkLoginAuthenticatorError::new(e.to_string()))?
221 .as_object_mut()
222 .and_then(|o| o.get_mut(expected_key))
223 .map(serde_json::Value::take)
224 .and_then(|v| match v {
225 serde_json::Value::String(s) => Some(s),
226 _ => None,
227 })
228 .ok_or_else(|| InvalidZkLoginAuthenticatorError::new("invalid extended claim"))
229 }
230}
231
232#[cfg(feature = "serde")]
233fn base64_to_bitarray(input: &str) -> Result<Vec<u8>, InvalidZkLoginAuthenticatorError> {
236 use itertools::Itertools;
237
238 const BASE64_URL_CHARSET: &str =
239 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
240
241 input
242 .chars()
243 .map(|c| {
244 BASE64_URL_CHARSET
245 .find(c)
246 .map(|index| index as u8)
247 .map(|index| (0..6).rev().map(move |i| (index >> i) & 1))
248 .ok_or_else(|| {
249 InvalidZkLoginAuthenticatorError::new("base64_to_bitarry invalid input")
250 })
251 })
252 .flatten_ok()
253 .collect()
254}
255
256#[cfg(feature = "serde")]
257fn bitarray_to_bytearray(bits: &[u8]) -> Result<Vec<u8>, InvalidZkLoginAuthenticatorError> {
260 #[expect(clippy::manual_is_multiple_of)]
261 if bits.len() % 8 != 0 {
262 return Err(InvalidZkLoginAuthenticatorError::new(
263 "bitarray_to_bytearray invalid input",
264 ));
265 }
266 Ok(bits
267 .chunks(8)
268 .map(|chunk| {
269 let mut byte = 0u8;
270 for (i, bit) in chunk.iter().rev().enumerate() {
271 byte |= bit << i;
272 }
273 byte
274 })
275 .collect())
276}
277
278#[cfg(feature = "serde")]
279fn decode_base64_url(
281 s: &str,
282 index_mod_4: &u8,
283) -> Result<String, InvalidZkLoginAuthenticatorError> {
284 if s.len() < 2 {
285 return Err(InvalidZkLoginAuthenticatorError::new(
286 "Base64 string smaller than 2",
287 ));
288 }
289 let mut bits = base64_to_bitarray(s)?;
290 match index_mod_4 {
291 0 => {}
292 1 => {
293 bits.drain(..2);
294 }
295 2 => {
296 bits.drain(..4);
297 }
298 _ => {
299 return Err(InvalidZkLoginAuthenticatorError::new(
300 "Invalid first_char_offset",
301 ));
302 }
303 }
304
305 let last_char_offset = (*index_mod_4 as usize + s.len() - 1) % 4;
311 match last_char_offset {
312 3 => {}
313 2 => {
314 bits.drain(bits.len() - 2..);
315 }
316 1 => {
317 bits.drain(bits.len() - 4..);
318 }
319 _ => {
320 return Err(InvalidZkLoginAuthenticatorError::new(
321 "Invalid last_char_offset",
322 ));
323 }
324 }
325
326 if bits.len() % 8 != 0 {
327 return Err(InvalidZkLoginAuthenticatorError::new("Invalid bits length"));
328 }
329
330 Ok(std::str::from_utf8(&bitarray_to_bytearray(&bits)?)
331 .map_err(|_| InvalidZkLoginAuthenticatorError::new("Invalid UTF8 string"))?
332 .to_owned())
333}
334
335#[derive(Debug, Clone, PartialEq, Eq)]
338struct JwtHeader {
339 alg: String,
340 kid: String,
341 typ: Option<String>,
342}
343
344impl JwtHeader {
345 #[cfg(feature = "serde")]
346 fn from_base64(s: &str) -> Result<Self, InvalidZkLoginAuthenticatorError> {
347 use base64ct::Base64UrlUnpadded;
348 use base64ct::Encoding;
349
350 #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
351 struct Header {
352 alg: String,
353 kid: String,
354 #[serde(skip_serializing_if = "Option::is_none")]
355 typ: Option<String>,
356 }
357
358 let header_bytes = Base64UrlUnpadded::decode_vec(s)
359 .map_err(|e| InvalidZkLoginAuthenticatorError::new(format!("invalid base64: {e}")))?;
360 let Header { alg, kid, typ } = serde_json::from_slice(&header_bytes)
361 .map_err(|e| InvalidZkLoginAuthenticatorError::new(format!("invalid json: {e}")))?;
362 if alg != "RS256" {
363 return Err(InvalidZkLoginAuthenticatorError::new(
364 "jwt alg must be RS256",
365 ));
366 }
367 Ok(Self { alg, kid, typ })
368 }
369}
370
371#[derive(Debug, Clone, PartialEq, Eq)]
381#[cfg_attr(
382 feature = "serde",
383 derive(serde_derive::Serialize, serde_derive::Deserialize)
384)]
385#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
386pub struct ZkLoginProof {
387 pub a: CircomG1,
388 pub b: CircomG2,
389 pub c: CircomG1,
390}
391
392#[derive(Clone, Debug, PartialEq, Eq)]
404#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
405pub struct CircomG1(pub [Bn254FieldElement; 3]);
406
407#[derive(Clone, Debug, PartialEq, Eq)]
420#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
421pub struct CircomG2(pub [[Bn254FieldElement; 2]; 3]);
422
423#[derive(Clone, Debug, PartialEq, Eq)]
473#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
474pub struct ZkLoginPublicIdentifier {
475 iss: String,
476 address_seed: Bn254FieldElement,
477}
478
479impl ZkLoginPublicIdentifier {
480 pub fn new(iss: String, address_seed: Bn254FieldElement) -> Option<Self> {
481 if iss.len() > 255 {
482 None
483 } else {
484 Some(Self { iss, address_seed })
485 }
486 }
487
488 pub fn iss(&self) -> &str {
489 &self.iss
490 }
491
492 pub fn address_seed(&self) -> &Bn254FieldElement {
493 &self.address_seed
494 }
495}
496
497#[derive(Clone, Debug, PartialEq, Eq, Hash)]
511#[cfg_attr(
512 feature = "serde",
513 derive(serde_derive::Serialize, serde_derive::Deserialize)
514)]
515#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
516pub struct Jwk {
517 pub kty: String,
519
520 pub e: String,
522
523 pub n: String,
525
526 pub alg: String,
528}
529
530#[derive(Clone, Debug, PartialEq, Eq, Hash)]
540#[cfg_attr(
541 feature = "serde",
542 derive(serde_derive::Serialize, serde_derive::Deserialize)
543)]
544#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
545pub struct JwkId {
546 pub iss: String,
548
549 pub kid: String,
551}
552
553#[derive(Clone, Debug, Default, PartialEq, Eq)]
567#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
568pub struct Bn254FieldElement([u8; 32]);
569
570impl Bn254FieldElement {
571 pub const fn new(bytes: [u8; 32]) -> Self {
572 Self(bytes)
573 }
574
575 pub const fn from_str_radix_10(s: &str) -> Result<Self, Bn254FieldElementParseError> {
576 let u256 = match U256::from_str_radix(s, 10) {
577 Ok(u256) => u256,
578 Err(e) => return Err(Bn254FieldElementParseError(e)),
579 };
580 let be = u256.to_be();
581 Ok(Self(*be.digits()))
582 }
583
584 pub fn unpadded(&self) -> &[u8] {
585 let mut buf = self.0.as_slice();
586
587 while !buf.is_empty() && buf[0] == 0 {
588 buf = &buf[1..];
589 }
590
591 if buf.is_empty() { &self.0[31..] } else { buf }
593 }
594
595 pub fn padded(&self) -> &[u8] {
596 &self.0
597 }
598}
599
600impl std::fmt::Display for Bn254FieldElement {
601 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
602 let u256 = U256::from_be(U256::from_digits(self.0));
603 let radix10 = u256.to_str_radix(10);
604 f.write_str(&radix10)
605 }
606}
607
608#[derive(Debug)]
609pub struct Bn254FieldElementParseError(crate::U256ParseError);
610
611impl std::fmt::Display for Bn254FieldElementParseError {
612 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
613 write!(f, "unable to parse radix10 encoded value {}", self.0)
614 }
615}
616
617impl std::error::Error for Bn254FieldElementParseError {}
618
619impl std::str::FromStr for Bn254FieldElement {
620 type Err = Bn254FieldElementParseError;
621
622 fn from_str(s: &str) -> Result<Self, Self::Err> {
623 let u256 = U256::from_str_radix(s, 10).map_err(Bn254FieldElementParseError)?;
624 let be = u256.to_be();
625 Ok(Self(*be.digits()))
626 }
627}
628
629#[cfg(test)]
630mod test {
631 use super::Bn254FieldElement;
632 use num_bigint::BigUint;
633 use proptest::prelude::*;
634 use std::str::FromStr;
635 use test_strategy::proptest;
636
637 #[cfg(target_arch = "wasm32")]
638 use wasm_bindgen_test::wasm_bindgen_test as test;
639
640 #[test]
641 fn unpadded_slice() {
642 let seed = Bn254FieldElement([0; 32]);
643 let zero: [u8; 1] = [0];
644 assert_eq!(seed.unpadded(), zero.as_slice());
645
646 let mut seed = Bn254FieldElement([1; 32]);
647 seed.0[0] = 0;
648 assert_eq!(seed.unpadded(), [1; 31].as_slice());
649 }
650
651 #[proptest]
652 fn dont_crash_on_large_inputs(
653 #[strategy(proptest::collection::vec(any::<u8>(), 33..1024))] bytes: Vec<u8>,
654 ) {
655 let big_int = BigUint::from_bytes_be(&bytes);
656 let radix10 = big_int.to_str_radix(10);
657
658 let _ = Bn254FieldElement::from_str(&radix10);
660 }
661
662 #[proptest]
663 fn valid_address_seeds(
664 #[strategy(proptest::collection::vec(any::<u8>(), 1..=32))] bytes: Vec<u8>,
665 ) {
666 let big_int = BigUint::from_bytes_be(&bytes);
667 let radix10 = big_int.to_str_radix(10);
668
669 let seed = Bn254FieldElement::from_str(&radix10).unwrap();
670 assert_eq!(radix10, seed.to_string());
671 seed.unpadded();
673 }
674
675 #[cfg(feature = "serde")]
685 #[test]
686 fn bcs_rejects_non_canonical_radix10_encoding() {
687 let canonical = bcs::to_bytes("7").unwrap();
688 let leading_zero = bcs::to_bytes("007").unwrap();
689 assert_ne!(canonical, leading_zero);
690
691 let parsed: Bn254FieldElement = bcs::from_bytes(&canonical).unwrap();
692 assert_eq!(parsed.to_string(), "7");
693
694 let err = bcs::from_bytes::<Bn254FieldElement>(&leading_zero).unwrap_err();
695 assert!(
696 err.to_string().contains("non-canonical"),
697 "unexpected error: {err}"
698 );
699 }
700
701 #[cfg(feature = "serde")]
709 #[test]
710 fn long_claim_value_does_not_panic_on_u8_overflow() {
711 use super::ZkLoginClaim;
712
713 let claim = ZkLoginClaim {
714 value: "A".repeat(256),
715 index_mod_4: 0,
716 };
717 assert!(claim.verify_extended_claim("iss").is_err());
718 }
719}
720
721#[cfg(feature = "serde")]
722#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
723mod serialization {
724 use crate::SignatureScheme;
725
726 use super::*;
727 use serde::Deserialize;
728 use serde::Deserializer;
729 use serde::Serialize;
730 use serde::Serializer;
731 use serde_with::Bytes;
732 use serde_with::DeserializeAs;
733 use serde_with::SerializeAs;
734 use std::borrow::Cow;
735
736 impl Serialize for ZkLoginPublicIdentifier {
738 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
739 where
740 S: Serializer,
741 {
742 if serializer.is_human_readable() {
743 #[derive(serde_derive::Serialize)]
744 struct Readable<'a> {
745 iss: &'a str,
746 address_seed: &'a Bn254FieldElement,
747 }
748 let readable = Readable {
749 iss: &self.iss,
750 address_seed: &self.address_seed,
751 };
752 readable.serialize(serializer)
753 } else {
754 let mut buf = Vec::new();
755 let iss_bytes = self.iss.as_bytes();
756 buf.push(iss_bytes.len() as u8);
757 buf.extend(iss_bytes);
758
759 buf.extend(&self.address_seed.0);
760
761 serializer.serialize_bytes(&buf)
762 }
763 }
764 }
765
766 impl<'de> Deserialize<'de> for ZkLoginPublicIdentifier {
767 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
768 where
769 D: Deserializer<'de>,
770 {
771 if deserializer.is_human_readable() {
772 #[derive(serde_derive::Deserialize)]
773 struct Readable {
774 iss: String,
775 address_seed: Bn254FieldElement,
776 }
777
778 let Readable { iss, address_seed } = Deserialize::deserialize(deserializer)?;
779 Self::new(iss, address_seed)
780 .ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))
781 } else {
782 let bytes: Cow<'de, [u8]> = Bytes::deserialize_as(deserializer)?;
783 let iss_len = *bytes
784 .first()
785 .ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))?;
786 let iss_bytes = bytes
787 .get(1..(1 + iss_len as usize))
788 .ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))?;
789 let iss = std::str::from_utf8(iss_bytes).map_err(serde::de::Error::custom)?;
790 let address_seed_bytes = bytes
791 .get((1 + iss_len as usize)..)
792 .ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))?;
793
794 let address_seed = <[u8; 32]>::try_from(address_seed_bytes)
795 .map_err(serde::de::Error::custom)
796 .map(Bn254FieldElement)?;
797
798 Self::new(iss.into(), address_seed)
799 .ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))
800 }
801 }
802 }
803
804 #[derive(serde_derive::Serialize)]
805 struct AuthenticatorRef<'a> {
806 inputs: &'a ZkLoginInputs,
807 max_epoch: EpochId,
808 signature: &'a SimpleSignature,
809 }
810
811 #[derive(serde_derive::Deserialize)]
812 struct Authenticator {
813 inputs: ZkLoginInputs,
814 max_epoch: EpochId,
815 signature: SimpleSignature,
816 }
817
818 impl Serialize for ZkLoginAuthenticator {
819 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
820 where
821 S: Serializer,
822 {
823 if serializer.is_human_readable() {
824 let authenticator_ref = AuthenticatorRef {
825 inputs: &self.inputs,
826 max_epoch: self.max_epoch,
827 signature: &self.signature,
828 };
829
830 authenticator_ref.serialize(serializer)
831 } else {
832 let bytes = self.to_bytes();
833 serializer.serialize_bytes(&bytes)
834 }
835 }
836 }
837
838 impl<'de> Deserialize<'de> for ZkLoginAuthenticator {
839 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
840 where
841 D: Deserializer<'de>,
842 {
843 if deserializer.is_human_readable() {
844 let Authenticator {
845 inputs,
846 max_epoch,
847 signature,
848 } = Authenticator::deserialize(deserializer)?;
849 Ok(Self {
850 inputs,
851 max_epoch,
852 signature,
853 })
854 } else {
855 let bytes: Cow<'de, [u8]> = Bytes::deserialize_as(deserializer)?;
856 Self::from_serialized_bytes(bytes)
857 }
858 }
859 }
860
861 impl ZkLoginAuthenticator {
862 pub(crate) fn to_bytes(&self) -> Vec<u8> {
863 let authenticator_ref = AuthenticatorRef {
864 inputs: &self.inputs,
865 max_epoch: self.max_epoch,
866 signature: &self.signature,
867 };
868
869 let mut buf = Vec::new();
870 buf.push(SignatureScheme::ZkLogin as u8);
871
872 bcs::serialize_into(&mut buf, &authenticator_ref).expect("serialization cannot fail");
873 buf
874 }
875
876 pub(crate) fn from_serialized_bytes<T: AsRef<[u8]>, E: serde::de::Error>(
877 bytes: T,
878 ) -> Result<Self, E> {
879 let bytes = bytes.as_ref();
880 let flag = SignatureScheme::from_byte(
881 *bytes
882 .first()
883 .ok_or_else(|| serde::de::Error::custom("missing signature scheme flag"))?,
884 )
885 .map_err(serde::de::Error::custom)?;
886 if flag != SignatureScheme::ZkLogin {
887 return Err(serde::de::Error::custom("invalid zklogin flag"));
888 }
889 let bcs_bytes = &bytes[1..];
890
891 let Authenticator {
892 inputs,
893 max_epoch,
894 signature,
895 } = bcs::from_bytes(bcs_bytes).map_err(serde::de::Error::custom)?;
896 Ok(Self {
897 inputs,
898 max_epoch,
899 signature,
900 })
901 }
902 }
903
904 impl Serialize for ZkLoginInputs {
905 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
906 where
907 S: Serializer,
908 {
909 #[derive(serde_derive::Serialize)]
910 struct Inputs<'a> {
911 proof_points: &'a ZkLoginProof,
912 iss_base64_details: &'a ZkLoginClaim,
913 header_base64: &'a str,
914 address_seed: &'a Bn254FieldElement,
915 }
916
917 Inputs {
918 proof_points: self.proof_points(),
919 iss_base64_details: self.iss_base64_details(),
920 header_base64: self.header_base64(),
921 address_seed: self.address_seed(),
922 }
923 .serialize(serializer)
924 }
925 }
926
927 impl<'de> Deserialize<'de> for ZkLoginInputs {
928 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
929 where
930 D: Deserializer<'de>,
931 {
932 #[derive(serde_derive::Deserialize)]
933 struct Inputs {
934 proof_points: ZkLoginProof,
935 iss_base64_details: ZkLoginClaim,
936 header_base64: String,
937 address_seed: Bn254FieldElement,
938 }
939
940 let Inputs {
941 proof_points,
942 iss_base64_details,
943 header_base64,
944 address_seed,
945 } = Inputs::deserialize(deserializer)?;
946 Self::new(
947 proof_points,
948 iss_base64_details,
949 header_base64,
950 address_seed,
951 )
952 .map_err(serde::de::Error::custom)
953 }
954 }
955
956 impl Serialize for Bn254FieldElement {
958 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
959 where
960 S: serde::Serializer,
961 {
962 serde_with::DisplayFromStr::serialize_as(self, serializer)
963 }
964 }
965
966 impl<'de> Deserialize<'de> for Bn254FieldElement {
967 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
968 where
969 D: Deserializer<'de>,
970 {
971 let s: std::borrow::Cow<'de, str> = Deserialize::deserialize(deserializer)?;
983 let value = s
984 .parse::<Bn254FieldElement>()
985 .map_err(serde::de::Error::custom)?;
986 if value.to_string() != *s {
987 return Err(serde::de::Error::custom(
988 "non-canonical Bn254FieldElement encoding",
989 ));
990 }
991 Ok(value)
992 }
993 }
994
995 impl Serialize for CircomG1 {
996 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
997 where
998 S: serde::Serializer,
999 {
1000 use serde::ser::SerializeSeq;
1001 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
1002 for element in &self.0 {
1003 seq.serialize_element(element)?;
1004 }
1005 seq.end()
1006 }
1007 }
1008
1009 impl<'de> Deserialize<'de> for CircomG1 {
1010 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1011 where
1012 D: Deserializer<'de>,
1013 {
1014 let inner = <Vec<_>>::deserialize(deserializer)?;
1015 Ok(Self(inner.try_into().map_err(|_| {
1016 serde::de::Error::custom("expected array of length 3")
1017 })?))
1018 }
1019 }
1020
1021 impl Serialize for CircomG2 {
1022 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1023 where
1024 S: serde::Serializer,
1025 {
1026 use serde::ser::SerializeSeq;
1027
1028 struct Inner<'a>(&'a [Bn254FieldElement; 2]);
1029
1030 impl Serialize for Inner<'_> {
1031 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1032 where
1033 S: serde::Serializer,
1034 {
1035 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
1036 for element in self.0 {
1037 seq.serialize_element(element)?;
1038 }
1039 seq.end()
1040 }
1041 }
1042
1043 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
1044 for element in &self.0 {
1045 seq.serialize_element(&Inner(element))?;
1046 }
1047 seq.end()
1048 }
1049 }
1050
1051 impl<'de> Deserialize<'de> for CircomG2 {
1052 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1053 where
1054 D: Deserializer<'de>,
1055 {
1056 let vecs = <Vec<Vec<Bn254FieldElement>>>::deserialize(deserializer)?;
1057 let mut inner: [[Bn254FieldElement; 2]; 3] = Default::default();
1058
1059 if vecs.len() != 3 {
1060 return Err(serde::de::Error::custom(
1061 "vector of three vectors each being a vector of two strings",
1062 ));
1063 }
1064
1065 for (i, v) in vecs.into_iter().enumerate() {
1066 if v.len() != 2 {
1067 return Err(serde::de::Error::custom(
1068 "vector of three vectors each being a vector of two strings",
1069 ));
1070 }
1071
1072 for (j, point) in v.into_iter().enumerate() {
1073 inner[i][j] = point;
1074 }
1075 }
1076
1077 Ok(Self(inner))
1078 }
1079 }
1080}