1use std::{
2 fmt::Display,
3 str::{from_utf8, FromStr},
4};
5
6use alloy_core::sol_types::{
7 sol_data::{FixedArray, Uint},
8 SolType, SolValue,
9};
10use serde::{Deserialize, Deserializer, Serialize, Serializer};
11
12use crate::Proof;
13use semaphore_rs_utils::{bytes_from_hex, bytes_to_hex, deserialize_bytes, serialize_bytes};
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub struct PackedProof(pub [u8; 256]);
19
20impl From<Proof> for PackedProof {
21 fn from(proof: Proof) -> Self {
22 let flat_proof = [
23 proof.0 .0,
24 proof.0 .1,
25 proof.1 .0[0],
26 proof.1 .0[1],
27 proof.1 .1[0],
28 proof.1 .1[1],
29 proof.2 .0,
30 proof.2 .1,
31 ];
32
33 let bytes = flat_proof.abi_encode();
34 let mut encoded = [0u8; 256];
35 encoded.copy_from_slice(&bytes[..256]);
36 Self(encoded)
37 }
38}
39
40impl From<PackedProof> for Proof {
41 fn from(proof: PackedProof) -> Self {
42 let decoded = FixedArray::<Uint<256>, 8>::abi_decode(&proof.0).unwrap();
43
44 let a = (decoded[0], decoded[1]);
45 let b = ([decoded[2], decoded[3]], [decoded[4], decoded[5]]);
46 let c = (decoded[6], decoded[7]);
47
48 Self(a, b, c)
49 }
50}
51
52impl Display for PackedProof {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 let hex = bytes_to_hex::<256, 514>(&self.0);
55 write!(
56 f,
57 "{}",
58 from_utf8(&hex).expect("failed to convert to string")
59 )
60 }
61}
62
63impl FromStr for PackedProof {
64 type Err = hex::FromHexError;
65
66 fn from_str(s: &str) -> Result<Self, Self::Err> {
67 bytes_from_hex::<256>(s).map(Self)
68 }
69}
70
71impl Serialize for PackedProof {
72 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
73 serialize_bytes::<256, 514, S>(serializer, &self.0)
74 }
75}
76
77impl<'de> Deserialize<'de> for PackedProof {
78 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
79 let bytes = deserialize_bytes::<256, _>(deserializer)?;
80 Ok(Self(bytes))
81 }
82}
83
84#[cfg(test)]
85pub mod test {
86 use super::*;
87 use ruint::aliases::U256;
88
89 #[test]
90 fn test_serializing_proof_into_packed_proof() {
91 let proof = Proof(
92 (U256::from(1), U256::from(2)),
93 (
94 [U256::from(3), U256::from(4)],
95 [U256::from(5), U256::from(6)],
96 ),
97 (U256::from(7), U256::from(8)),
98 );
99
100 let packed_proof = PackedProof::from(proof);
101
102 assert_eq!(packed_proof.to_string(), "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008");
103
104 let proof2 = Proof::from(packed_proof);
105
106 assert_eq!(proof, proof2);
107 }
108
109 #[test]
110 fn test_parse_from_string() {
111 let packed_proof_str = "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008";
112
113 let packed_proof = PackedProof::from_str(packed_proof_str).unwrap();
114
115 let expected_proof = Proof(
116 (U256::from(1), U256::from(2)),
117 (
118 [U256::from(3), U256::from(4)],
119 [U256::from(5), U256::from(6)],
120 ),
121 (U256::from(7), U256::from(8)),
122 );
123
124 let proof: Proof = packed_proof.into();
125
126 assert_eq!(proof, expected_proof);
127 }
128
129 #[test]
130 fn test_parse_from_string_without_prefix() {
131 let packed_proof_str = "00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008";
133
134 let packed_proof = PackedProof::from_str(packed_proof_str).unwrap();
135
136 let expected_proof = Proof(
137 (U256::from(5), U256::from(6)),
138 (
139 [U256::from(3), U256::from(4)],
140 [U256::from(5), U256::from(6)],
141 ),
142 (U256::from(7), U256::from(8)),
143 );
144
145 let proof: Proof = packed_proof.into();
146
147 assert_eq!(proof, expected_proof);
148 }
149
150 #[test]
151 fn test_serialize_proof_to_json() {
152 let packed_proof_str = "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008";
153
154 let packed_proof = PackedProof::from_str(packed_proof_str).unwrap();
155 let proof: Proof = packed_proof.into();
156
157 let serialized = serde_json::to_value(proof).unwrap();
158
159 assert_eq!(
160 serialized,
161 serde_json::json!([
162 ["0x1", "0x2"],
163 [["0x3", "0x4"], ["0x5", "0x6"]],
164 ["0x7", "0x8"]
165 ])
166 );
167 }
168
169 #[test]
170 fn test_serialize_proof_to_json_real_numbers() {
171 let packed_proof_str = "0x15c1fc6907219676890dfe147ee6f10b580c7881dddacb1567b3bcbfc513a54d233afda3efff43a7631990d2e79470abcbae3ccad4b920476e64745bfe97bb0a0c8c7d7434c382d590d601d951c29c8463d555867db70f9e84f7741c81c2e1e6241d2ddf1c9e6670a24109a0e9c915cd6e07d0248a384dd38d3c91e9b0419f5f0b23c5467a06eff56cc2c246ada1e7d5705afc4dc8b43fd5a6972c679a2019c5091ed6522f7924d3674d08966a008f947f9aa016a4100bb12f911326f3e1befd0acdf5a5996e00933206cbec48f3bbdcee2a4ca75f8db911c00001e5a05474872446d6f1c1506837392a30fdc73d66fd89f4e1b1a5d14b93e2ad0c5f7b777520";
172
173 let packed_proof = PackedProof::from_str(packed_proof_str).unwrap();
174 let proof: Proof = packed_proof.into();
175
176 let serialized = serde_json::to_value(proof).unwrap();
177
178 assert_eq!(
179 serialized,
180 serde_json::json!([
181 [
182 "0x15c1fc6907219676890dfe147ee6f10b580c7881dddacb1567b3bcbfc513a54d",
183 "0x233afda3efff43a7631990d2e79470abcbae3ccad4b920476e64745bfe97bb0a"
184 ],
185 [
186 [
187 "0xc8c7d7434c382d590d601d951c29c8463d555867db70f9e84f7741c81c2e1e6",
188 "0x241d2ddf1c9e6670a24109a0e9c915cd6e07d0248a384dd38d3c91e9b0419f5f"
189 ],
190 [
191 "0xb23c5467a06eff56cc2c246ada1e7d5705afc4dc8b43fd5a6972c679a2019c5",
192 "0x91ed6522f7924d3674d08966a008f947f9aa016a4100bb12f911326f3e1befd"
193 ]
194 ],
195 [
196 "0xacdf5a5996e00933206cbec48f3bbdcee2a4ca75f8db911c00001e5a0547487",
197 "0x2446d6f1c1506837392a30fdc73d66fd89f4e1b1a5d14b93e2ad0c5f7b777520"
198 ]
199 ])
200 );
201 }
202
203 #[test]
204 fn test_deserialize_proof_from_json() {
205 let proof_str = "[
206 [
207 \"0x15c1fc6907219676890dfe147ee6f10b580c7881dddacb1567b3bcbfc513a54d\",
208 \"0x233afda3efff43a7631990d2e79470abcbae3ccad4b920476e64745bfe97bb0a\"
209 ],
210 [
211 [
212 \"0xc8c7d7434c382d590d601d951c29c8463d555867db70f9e84f7741c81c2e1e6\",
213 \"0x241d2ddf1c9e6670a24109a0e9c915cd6e07d0248a384dd38d3c91e9b0419f5f\"
214 ],
215 [
216 \"0xb23c5467a06eff56cc2c246ada1e7d5705afc4dc8b43fd5a6972c679a2019c5\",
217 \"0x91ed6522f7924d3674d08966a008f947f9aa016a4100bb12f911326f3e1befd\"
218 ]
219 ],
220 [
221 \"0xacdf5a5996e00933206cbec48f3bbdcee2a4ca75f8db911c00001e5a0547487\",
222 \"0x2446d6f1c1506837392a30fdc73d66fd89f4e1b1a5d14b93e2ad0c5f7b777520\"
223 ]
224 ]";
225
226 let proof = serde_json::from_str::<Proof>(proof_str).unwrap();
227
228 let packed_proof = PackedProof::from(proof);
229
230 let expected_proof = "0x15c1fc6907219676890dfe147ee6f10b580c7881dddacb1567b3bcbfc513a54d233afda3efff43a7631990d2e79470abcbae3ccad4b920476e64745bfe97bb0a0c8c7d7434c382d590d601d951c29c8463d555867db70f9e84f7741c81c2e1e6241d2ddf1c9e6670a24109a0e9c915cd6e07d0248a384dd38d3c91e9b0419f5f0b23c5467a06eff56cc2c246ada1e7d5705afc4dc8b43fd5a6972c679a2019c5091ed6522f7924d3674d08966a008f947f9aa016a4100bb12f911326f3e1befd0acdf5a5996e00933206cbec48f3bbdcee2a4ca75f8db911c00001e5a05474872446d6f1c1506837392a30fdc73d66fd89f4e1b1a5d14b93e2ad0c5f7b777520";
231
232 assert_eq!(packed_proof.to_string(), expected_proof);
233 }
234
235 #[test]
236 fn test_invalid_parsing() {
237 let packed_proof_str = "0x0000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000007";
239 PackedProof::from_str(packed_proof_str).expect_err("parsing should fail");
240
241 let packed_proof_str = "0000000000000000p000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008";
243 PackedProof::from_str(packed_proof_str).expect_err("parsing should fail");
244
245 let packed_proof_str = "0x0";
247 PackedProof::from_str(packed_proof_str).expect_err("parsing should fail");
248 }
249}