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 fn verify_extended_claim(
199 &self,
200 expected_key: &str,
201 ) -> Result<String, InvalidZkLoginAuthenticatorError> {
202 fn base64_to_bitarray(input: &str) -> Result<Vec<u8>, InvalidZkLoginAuthenticatorError> {
205 use itertools::Itertools;
206
207 const BASE64_URL_CHARSET: &str =
208 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
209
210 input
211 .chars()
212 .map(|c| {
213 BASE64_URL_CHARSET
214 .find(c)
215 .map(|index| index as u8)
216 .map(|index| (0..6).rev().map(move |i| (index >> i) & 1))
217 .ok_or_else(|| {
218 InvalidZkLoginAuthenticatorError::new("base64_to_bitarry invalid input")
219 })
220 })
221 .flatten_ok()
222 .collect()
223 }
224
225 fn bitarray_to_bytearray(bits: &[u8]) -> Result<Vec<u8>, InvalidZkLoginAuthenticatorError> {
228 #[expect(clippy::manual_is_multiple_of)]
229 if bits.len() % 8 != 0 {
230 return Err(InvalidZkLoginAuthenticatorError::new(
231 "bitarray_to_bytearray invalid input",
232 ));
233 }
234 Ok(bits
235 .chunks(8)
236 .map(|chunk| {
237 let mut byte = 0u8;
238 for (i, bit) in chunk.iter().rev().enumerate() {
239 byte |= bit << i;
240 }
241 byte
242 })
243 .collect())
244 }
245
246 fn decode_base64_url(
248 s: &str,
249 index_mod_4: &u8,
250 ) -> Result<String, InvalidZkLoginAuthenticatorError> {
251 if s.len() < 2 {
252 return Err(InvalidZkLoginAuthenticatorError::new(
253 "Base64 string smaller than 2",
254 ));
255 }
256 let mut bits = base64_to_bitarray(s)?;
257 match index_mod_4 {
258 0 => {}
259 1 => {
260 bits.drain(..2);
261 }
262 2 => {
263 bits.drain(..4);
264 }
265 _ => {
266 return Err(InvalidZkLoginAuthenticatorError::new(
267 "Invalid first_char_offset",
268 ));
269 }
270 }
271
272 let last_char_offset = (index_mod_4 + s.len() as u8 - 1) % 4;
273 match last_char_offset {
274 3 => {}
275 2 => {
276 bits.drain(bits.len() - 2..);
277 }
278 1 => {
279 bits.drain(bits.len() - 4..);
280 }
281 _ => {
282 return Err(InvalidZkLoginAuthenticatorError::new(
283 "Invalid last_char_offset",
284 ));
285 }
286 }
287
288 if bits.len() % 8 != 0 {
289 return Err(InvalidZkLoginAuthenticatorError::new("Invalid bits length"));
290 }
291
292 Ok(std::str::from_utf8(&bitarray_to_bytearray(&bits)?)
293 .map_err(|_| InvalidZkLoginAuthenticatorError::new("Invalid UTF8 string"))?
294 .to_owned())
295 }
296
297 let extended_claim = decode_base64_url(&self.value, &self.index_mod_4)?;
298
299 if !(extended_claim.ends_with('}') || extended_claim.ends_with(',')) {
301 return Err(InvalidZkLoginAuthenticatorError::new(
302 "Invalid extended claim",
303 ));
304 }
305
306 let json_str = format!("{{{}}}", &extended_claim[..extended_claim.len() - 1]);
307
308 serde_json::from_str::<serde_json::Value>(&json_str)
309 .map_err(|e| InvalidZkLoginAuthenticatorError::new(e.to_string()))?
310 .as_object_mut()
311 .and_then(|o| o.get_mut(expected_key))
312 .map(serde_json::Value::take)
313 .and_then(|v| match v {
314 serde_json::Value::String(s) => Some(s),
315 _ => None,
316 })
317 .ok_or_else(|| InvalidZkLoginAuthenticatorError::new("invalid extended claim"))
318 }
319}
320
321#[derive(Debug, Clone, PartialEq, Eq)]
324struct JwtHeader {
325 alg: String,
326 kid: String,
327 typ: Option<String>,
328}
329
330impl JwtHeader {
331 #[cfg(feature = "serde")]
332 fn from_base64(s: &str) -> Result<Self, InvalidZkLoginAuthenticatorError> {
333 use base64ct::Base64UrlUnpadded;
334 use base64ct::Encoding;
335
336 #[derive(serde_derive::Serialize, serde_derive::Deserialize)]
337 struct Header {
338 alg: String,
339 kid: String,
340 #[serde(skip_serializing_if = "Option::is_none")]
341 typ: Option<String>,
342 }
343
344 let header_bytes = Base64UrlUnpadded::decode_vec(s)
345 .map_err(|e| InvalidZkLoginAuthenticatorError::new(format!("invalid base64: {e}")))?;
346 let Header { alg, kid, typ } = serde_json::from_slice(&header_bytes)
347 .map_err(|e| InvalidZkLoginAuthenticatorError::new(format!("invalid json: {e}")))?;
348 if alg != "RS256" {
349 return Err(InvalidZkLoginAuthenticatorError::new(
350 "jwt alg must be RS256",
351 ));
352 }
353 Ok(Self { alg, kid, typ })
354 }
355}
356
357#[derive(Debug, Clone, PartialEq, Eq)]
367#[cfg_attr(
368 feature = "serde",
369 derive(serde_derive::Serialize, serde_derive::Deserialize)
370)]
371#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
372pub struct ZkLoginProof {
373 pub a: CircomG1,
374 pub b: CircomG2,
375 pub c: CircomG1,
376}
377
378#[derive(Clone, Debug, PartialEq, Eq)]
390#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
391pub struct CircomG1(pub [Bn254FieldElement; 3]);
392
393#[derive(Clone, Debug, PartialEq, Eq)]
406#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
407pub struct CircomG2(pub [[Bn254FieldElement; 2]; 3]);
408
409#[derive(Clone, Debug, PartialEq, Eq)]
459#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
460pub struct ZkLoginPublicIdentifier {
461 iss: String,
462 address_seed: Bn254FieldElement,
463}
464
465impl ZkLoginPublicIdentifier {
466 pub fn new(iss: String, address_seed: Bn254FieldElement) -> Option<Self> {
467 if iss.len() > 255 {
468 None
469 } else {
470 Some(Self { iss, address_seed })
471 }
472 }
473
474 pub fn iss(&self) -> &str {
475 &self.iss
476 }
477
478 pub fn address_seed(&self) -> &Bn254FieldElement {
479 &self.address_seed
480 }
481}
482
483#[derive(Clone, Debug, PartialEq, Eq, Hash)]
497#[cfg_attr(
498 feature = "serde",
499 derive(serde_derive::Serialize, serde_derive::Deserialize)
500)]
501#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
502pub struct Jwk {
503 pub kty: String,
505
506 pub e: String,
508
509 pub n: String,
511
512 pub alg: String,
514}
515
516#[derive(Clone, Debug, PartialEq, Eq, Hash)]
526#[cfg_attr(
527 feature = "serde",
528 derive(serde_derive::Serialize, serde_derive::Deserialize)
529)]
530#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
531pub struct JwkId {
532 pub iss: String,
534
535 pub kid: String,
537}
538
539#[derive(Clone, Debug, Default, PartialEq, Eq)]
553#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
554pub struct Bn254FieldElement([u8; 32]);
555
556impl Bn254FieldElement {
557 pub const fn new(bytes: [u8; 32]) -> Self {
558 Self(bytes)
559 }
560
561 pub const fn from_str_radix_10(s: &str) -> Result<Self, Bn254FieldElementParseError> {
562 let u256 = match U256::from_str_radix(s, 10) {
563 Ok(u256) => u256,
564 Err(e) => return Err(Bn254FieldElementParseError(e)),
565 };
566 let be = u256.to_be();
567 Ok(Self(*be.digits()))
568 }
569
570 pub fn unpadded(&self) -> &[u8] {
571 let mut buf = self.0.as_slice();
572
573 while !buf.is_empty() && buf[0] == 0 {
574 buf = &buf[1..];
575 }
576
577 if buf.is_empty() {
579 &self.0[31..]
580 } else {
581 buf
582 }
583 }
584
585 pub fn padded(&self) -> &[u8] {
586 &self.0
587 }
588}
589
590impl std::fmt::Display for Bn254FieldElement {
591 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
592 let u256 = U256::from_be(U256::from_digits(self.0));
593 let radix10 = u256.to_str_radix(10);
594 f.write_str(&radix10)
595 }
596}
597
598#[derive(Debug)]
599pub struct Bn254FieldElementParseError(bnum::errors::ParseIntError);
600
601impl std::fmt::Display for Bn254FieldElementParseError {
602 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
603 write!(f, "unable to parse radix10 encoded value {}", self.0)
604 }
605}
606
607impl std::error::Error for Bn254FieldElementParseError {}
608
609impl std::str::FromStr for Bn254FieldElement {
610 type Err = Bn254FieldElementParseError;
611
612 fn from_str(s: &str) -> Result<Self, Self::Err> {
613 let u256 = U256::from_str_radix(s, 10).map_err(Bn254FieldElementParseError)?;
614 let be = u256.to_be();
615 Ok(Self(*be.digits()))
616 }
617}
618
619#[cfg(test)]
620mod test {
621 use super::Bn254FieldElement;
622 use num_bigint::BigUint;
623 use proptest::prelude::*;
624 use std::str::FromStr;
625 use test_strategy::proptest;
626
627 #[cfg(target_arch = "wasm32")]
628 use wasm_bindgen_test::wasm_bindgen_test as test;
629
630 #[test]
631 fn unpadded_slice() {
632 let seed = Bn254FieldElement([0; 32]);
633 let zero: [u8; 1] = [0];
634 assert_eq!(seed.unpadded(), zero.as_slice());
635
636 let mut seed = Bn254FieldElement([1; 32]);
637 seed.0[0] = 0;
638 assert_eq!(seed.unpadded(), [1; 31].as_slice());
639 }
640
641 #[proptest]
642 fn dont_crash_on_large_inputs(
643 #[strategy(proptest::collection::vec(any::<u8>(), 33..1024))] bytes: Vec<u8>,
644 ) {
645 let big_int = BigUint::from_bytes_be(&bytes);
646 let radix10 = big_int.to_str_radix(10);
647
648 let _ = Bn254FieldElement::from_str(&radix10);
650 }
651
652 #[proptest]
653 fn valid_address_seeds(
654 #[strategy(proptest::collection::vec(any::<u8>(), 1..=32))] bytes: Vec<u8>,
655 ) {
656 let big_int = BigUint::from_bytes_be(&bytes);
657 let radix10 = big_int.to_str_radix(10);
658
659 let seed = Bn254FieldElement::from_str(&radix10).unwrap();
660 assert_eq!(radix10, seed.to_string());
661 seed.unpadded();
663 }
664}
665
666#[cfg(feature = "serde")]
667#[cfg_attr(doc_cfg, doc(cfg(feature = "serde")))]
668mod serialization {
669 use crate::SignatureScheme;
670
671 use super::*;
672 use serde::Deserialize;
673 use serde::Deserializer;
674 use serde::Serialize;
675 use serde::Serializer;
676 use serde_with::Bytes;
677 use serde_with::DeserializeAs;
678 use serde_with::SerializeAs;
679 use std::borrow::Cow;
680
681 impl Serialize for ZkLoginPublicIdentifier {
683 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
684 where
685 S: Serializer,
686 {
687 if serializer.is_human_readable() {
688 #[derive(serde_derive::Serialize)]
689 struct Readable<'a> {
690 iss: &'a str,
691 address_seed: &'a Bn254FieldElement,
692 }
693 let readable = Readable {
694 iss: &self.iss,
695 address_seed: &self.address_seed,
696 };
697 readable.serialize(serializer)
698 } else {
699 let mut buf = Vec::new();
700 let iss_bytes = self.iss.as_bytes();
701 buf.push(iss_bytes.len() as u8);
702 buf.extend(iss_bytes);
703
704 buf.extend(&self.address_seed.0);
705
706 serializer.serialize_bytes(&buf)
707 }
708 }
709 }
710
711 impl<'de> Deserialize<'de> for ZkLoginPublicIdentifier {
712 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
713 where
714 D: Deserializer<'de>,
715 {
716 if deserializer.is_human_readable() {
717 #[derive(serde_derive::Deserialize)]
718 struct Readable {
719 iss: String,
720 address_seed: Bn254FieldElement,
721 }
722
723 let Readable { iss, address_seed } = Deserialize::deserialize(deserializer)?;
724 Self::new(iss, address_seed)
725 .ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))
726 } else {
727 let bytes: Cow<'de, [u8]> = Bytes::deserialize_as(deserializer)?;
728 let iss_len = *bytes
729 .first()
730 .ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))?;
731 let iss_bytes = bytes
732 .get(1..(1 + iss_len as usize))
733 .ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))?;
734 let iss = std::str::from_utf8(iss_bytes).map_err(serde::de::Error::custom)?;
735 let address_seed_bytes = bytes
736 .get((1 + iss_len as usize)..)
737 .ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))?;
738
739 let address_seed = <[u8; 32]>::try_from(address_seed_bytes)
740 .map_err(serde::de::Error::custom)
741 .map(Bn254FieldElement)?;
742
743 Self::new(iss.into(), address_seed)
744 .ok_or_else(|| serde::de::Error::custom("invalid zklogin public identifier"))
745 }
746 }
747 }
748
749 #[derive(serde_derive::Serialize)]
750 struct AuthenticatorRef<'a> {
751 inputs: &'a ZkLoginInputs,
752 max_epoch: EpochId,
753 signature: &'a SimpleSignature,
754 }
755
756 #[derive(serde_derive::Deserialize)]
757 struct Authenticator {
758 inputs: ZkLoginInputs,
759 max_epoch: EpochId,
760 signature: SimpleSignature,
761 }
762
763 impl Serialize for ZkLoginAuthenticator {
764 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
765 where
766 S: Serializer,
767 {
768 if serializer.is_human_readable() {
769 let authenticator_ref = AuthenticatorRef {
770 inputs: &self.inputs,
771 max_epoch: self.max_epoch,
772 signature: &self.signature,
773 };
774
775 authenticator_ref.serialize(serializer)
776 } else {
777 let bytes = self.to_bytes();
778 serializer.serialize_bytes(&bytes)
779 }
780 }
781 }
782
783 impl<'de> Deserialize<'de> for ZkLoginAuthenticator {
784 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
785 where
786 D: Deserializer<'de>,
787 {
788 if deserializer.is_human_readable() {
789 let Authenticator {
790 inputs,
791 max_epoch,
792 signature,
793 } = Authenticator::deserialize(deserializer)?;
794 Ok(Self {
795 inputs,
796 max_epoch,
797 signature,
798 })
799 } else {
800 let bytes: Cow<'de, [u8]> = Bytes::deserialize_as(deserializer)?;
801 Self::from_serialized_bytes(bytes)
802 }
803 }
804 }
805
806 impl ZkLoginAuthenticator {
807 pub(crate) fn to_bytes(&self) -> Vec<u8> {
808 let authenticator_ref = AuthenticatorRef {
809 inputs: &self.inputs,
810 max_epoch: self.max_epoch,
811 signature: &self.signature,
812 };
813
814 let mut buf = Vec::new();
815 buf.push(SignatureScheme::ZkLogin as u8);
816
817 bcs::serialize_into(&mut buf, &authenticator_ref).expect("serialization cannot fail");
818 buf
819 }
820
821 pub(crate) fn from_serialized_bytes<T: AsRef<[u8]>, E: serde::de::Error>(
822 bytes: T,
823 ) -> Result<Self, E> {
824 let bytes = bytes.as_ref();
825 let flag = SignatureScheme::from_byte(
826 *bytes
827 .first()
828 .ok_or_else(|| serde::de::Error::custom("missing signature scheme flag"))?,
829 )
830 .map_err(serde::de::Error::custom)?;
831 if flag != SignatureScheme::ZkLogin {
832 return Err(serde::de::Error::custom("invalid zklogin flag"));
833 }
834 let bcs_bytes = &bytes[1..];
835
836 let Authenticator {
837 inputs,
838 max_epoch,
839 signature,
840 } = bcs::from_bytes(bcs_bytes).map_err(serde::de::Error::custom)?;
841 Ok(Self {
842 inputs,
843 max_epoch,
844 signature,
845 })
846 }
847 }
848
849 impl Serialize for ZkLoginInputs {
850 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
851 where
852 S: Serializer,
853 {
854 #[derive(serde_derive::Serialize)]
855 struct Inputs<'a> {
856 proof_points: &'a ZkLoginProof,
857 iss_base64_details: &'a ZkLoginClaim,
858 header_base64: &'a str,
859 address_seed: &'a Bn254FieldElement,
860 }
861
862 Inputs {
863 proof_points: self.proof_points(),
864 iss_base64_details: self.iss_base64_details(),
865 header_base64: self.header_base64(),
866 address_seed: self.address_seed(),
867 }
868 .serialize(serializer)
869 }
870 }
871
872 impl<'de> Deserialize<'de> for ZkLoginInputs {
873 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
874 where
875 D: Deserializer<'de>,
876 {
877 #[derive(serde_derive::Deserialize)]
878 struct Inputs {
879 proof_points: ZkLoginProof,
880 iss_base64_details: ZkLoginClaim,
881 header_base64: String,
882 address_seed: Bn254FieldElement,
883 }
884
885 let Inputs {
886 proof_points,
887 iss_base64_details,
888 header_base64,
889 address_seed,
890 } = Inputs::deserialize(deserializer)?;
891 Self::new(
892 proof_points,
893 iss_base64_details,
894 header_base64,
895 address_seed,
896 )
897 .map_err(serde::de::Error::custom)
898 }
899 }
900
901 impl Serialize for Bn254FieldElement {
903 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
904 where
905 S: serde::Serializer,
906 {
907 serde_with::DisplayFromStr::serialize_as(self, serializer)
908 }
909 }
910
911 impl<'de> Deserialize<'de> for Bn254FieldElement {
912 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
913 where
914 D: Deserializer<'de>,
915 {
916 serde_with::DisplayFromStr::deserialize_as(deserializer)
917 }
918 }
919
920 impl Serialize for CircomG1 {
921 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
922 where
923 S: serde::Serializer,
924 {
925 use serde::ser::SerializeSeq;
926 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
927 for element in &self.0 {
928 seq.serialize_element(element)?;
929 }
930 seq.end()
931 }
932 }
933
934 impl<'de> Deserialize<'de> for CircomG1 {
935 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
936 where
937 D: Deserializer<'de>,
938 {
939 let inner = <Vec<_>>::deserialize(deserializer)?;
940 Ok(Self(inner.try_into().map_err(|_| {
941 serde::de::Error::custom("expected array of length 3")
942 })?))
943 }
944 }
945
946 impl Serialize for CircomG2 {
947 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
948 where
949 S: serde::Serializer,
950 {
951 use serde::ser::SerializeSeq;
952
953 struct Inner<'a>(&'a [Bn254FieldElement; 2]);
954
955 impl Serialize for Inner<'_> {
956 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
957 where
958 S: serde::Serializer,
959 {
960 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
961 for element in self.0 {
962 seq.serialize_element(element)?;
963 }
964 seq.end()
965 }
966 }
967
968 let mut seq = serializer.serialize_seq(Some(self.0.len()))?;
969 for element in &self.0 {
970 seq.serialize_element(&Inner(element))?;
971 }
972 seq.end()
973 }
974 }
975
976 impl<'de> Deserialize<'de> for CircomG2 {
977 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
978 where
979 D: Deserializer<'de>,
980 {
981 let vecs = <Vec<Vec<Bn254FieldElement>>>::deserialize(deserializer)?;
982 let mut inner: [[Bn254FieldElement; 2]; 3] = Default::default();
983
984 if vecs.len() != 3 {
985 return Err(serde::de::Error::custom(
986 "vector of three vectors each being a vector of two strings",
987 ));
988 }
989
990 for (i, v) in vecs.into_iter().enumerate() {
991 if v.len() != 2 {
992 return Err(serde::de::Error::custom(
993 "vector of three vectors each being a vector of two strings",
994 ));
995 }
996
997 for (j, point) in v.into_iter().enumerate() {
998 inner[i][j] = point;
999 }
1000 }
1001
1002 Ok(Self(inner))
1003 }
1004 }
1005}