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