miraland_program/alt_bn128/
compression.rs

1pub mod prelude {
2    pub use crate::alt_bn128::compression::{
3        alt_bn128_compression_size::*, consts::*, target_arch::*, AltBn128CompressionError,
4    };
5}
6
7use thiserror::Error;
8
9mod consts {
10    pub const ALT_BN128_G1_COMPRESS: u64 = 0;
11    pub const ALT_BN128_G1_DECOMPRESS: u64 = 1;
12    pub const ALT_BN128_G2_COMPRESS: u64 = 2;
13    pub const ALT_BN128_G2_DECOMPRESS: u64 = 3;
14}
15
16mod alt_bn128_compression_size {
17    pub const G1: usize = 64;
18    pub const G2: usize = 128;
19    pub const G1_COMPRESSED: usize = 32;
20    pub const G2_COMPRESSED: usize = 64;
21}
22
23#[derive(Debug, Error, Clone, PartialEq, Eq)]
24pub enum AltBn128CompressionError {
25    #[error("Unexpected error")]
26    UnexpectedError,
27    #[error("Failed to decompress g1")]
28    G1DecompressionFailed,
29    #[error("Failed to decompress g2")]
30    G2DecompressionFailed,
31    #[error("Failed to compress affine g1")]
32    G1CompressionFailed,
33    #[error("Failed to compress affine g2")]
34    G2CompressionFailed,
35    #[error("Invalid input size")]
36    InvalidInputSize,
37}
38
39impl From<u64> for AltBn128CompressionError {
40    fn from(v: u64) -> AltBn128CompressionError {
41        match v {
42            1 => AltBn128CompressionError::G1DecompressionFailed,
43            2 => AltBn128CompressionError::G2DecompressionFailed,
44            3 => AltBn128CompressionError::G1CompressionFailed,
45            4 => AltBn128CompressionError::G2CompressionFailed,
46            5 => AltBn128CompressionError::InvalidInputSize,
47            _ => AltBn128CompressionError::UnexpectedError,
48        }
49    }
50}
51
52impl From<AltBn128CompressionError> for u64 {
53    fn from(v: AltBn128CompressionError) -> u64 {
54        match v {
55            AltBn128CompressionError::G1DecompressionFailed => 1,
56            AltBn128CompressionError::G2DecompressionFailed => 2,
57            AltBn128CompressionError::G1CompressionFailed => 3,
58            AltBn128CompressionError::G2CompressionFailed => 4,
59            AltBn128CompressionError::InvalidInputSize => 5,
60            AltBn128CompressionError::UnexpectedError => 0,
61        }
62    }
63}
64
65#[cfg(not(target_os = "solana"))]
66mod target_arch {
67
68    use {
69        super::*,
70        crate::alt_bn128::compression::alt_bn128_compression_size,
71        ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate},
72    };
73
74    type G1 = ark_bn254::g1::G1Affine;
75    type G2 = ark_bn254::g2::G2Affine;
76
77    pub fn alt_bn128_g1_decompress(
78        g1_bytes: &[u8],
79    ) -> Result<[u8; alt_bn128_compression_size::G1], AltBn128CompressionError> {
80        let g1_bytes: [u8; alt_bn128_compression_size::G1_COMPRESSED] = g1_bytes
81            .try_into()
82            .map_err(|_| AltBn128CompressionError::InvalidInputSize)?;
83        if g1_bytes == [0u8; alt_bn128_compression_size::G1_COMPRESSED] {
84            return Ok([0u8; alt_bn128_compression_size::G1]);
85        }
86        let decompressed_g1 = G1::deserialize_with_mode(
87            convert_endianness::<32, 32>(&g1_bytes).as_slice(),
88            Compress::Yes,
89            Validate::No,
90        )
91        .map_err(|_| AltBn128CompressionError::G1DecompressionFailed)?;
92        let mut decompressed_g1_bytes = [0u8; alt_bn128_compression_size::G1];
93        decompressed_g1
94            .x
95            .serialize_with_mode(&mut decompressed_g1_bytes[..32], Compress::No)
96            .map_err(|_| AltBn128CompressionError::G1DecompressionFailed)?;
97        decompressed_g1
98            .y
99            .serialize_with_mode(&mut decompressed_g1_bytes[32..], Compress::No)
100            .map_err(|_| AltBn128CompressionError::G1DecompressionFailed)?;
101        Ok(convert_endianness::<32, 64>(&decompressed_g1_bytes))
102    }
103
104    pub fn alt_bn128_g1_compress(
105        g1_bytes: &[u8],
106    ) -> Result<[u8; alt_bn128_compression_size::G1_COMPRESSED], AltBn128CompressionError> {
107        let g1_bytes: [u8; alt_bn128_compression_size::G1] = g1_bytes
108            .try_into()
109            .map_err(|_| AltBn128CompressionError::InvalidInputSize)?;
110        if g1_bytes == [0u8; alt_bn128_compression_size::G1] {
111            return Ok([0u8; alt_bn128_compression_size::G1_COMPRESSED]);
112        }
113        let g1 = G1::deserialize_with_mode(
114            convert_endianness::<32, 64>(&g1_bytes).as_slice(),
115            Compress::No,
116            Validate::No,
117        )
118        .map_err(|_| AltBn128CompressionError::G1CompressionFailed)?;
119        let mut g1_bytes = [0u8; alt_bn128_compression_size::G1_COMPRESSED];
120        G1::serialize_compressed(&g1, g1_bytes.as_mut_slice())
121            .map_err(|_| AltBn128CompressionError::G2CompressionFailed)?;
122        Ok(convert_endianness::<32, 32>(&g1_bytes))
123    }
124
125    pub fn alt_bn128_g2_decompress(
126        g2_bytes: &[u8],
127    ) -> Result<[u8; alt_bn128_compression_size::G2], AltBn128CompressionError> {
128        let g2_bytes: [u8; alt_bn128_compression_size::G2_COMPRESSED] = g2_bytes
129            .try_into()
130            .map_err(|_| AltBn128CompressionError::InvalidInputSize)?;
131        if g2_bytes == [0u8; alt_bn128_compression_size::G2_COMPRESSED] {
132            return Ok([0u8; alt_bn128_compression_size::G2]);
133        }
134        let decompressed_g2 =
135            G2::deserialize_compressed(convert_endianness::<64, 64>(&g2_bytes).as_slice())
136                .map_err(|_| AltBn128CompressionError::G2DecompressionFailed)?;
137        let mut decompressed_g2_bytes = [0u8; alt_bn128_compression_size::G2];
138        decompressed_g2
139            .x
140            .serialize_with_mode(&mut decompressed_g2_bytes[..64], Compress::No)
141            .map_err(|_| AltBn128CompressionError::G2DecompressionFailed)?;
142        decompressed_g2
143            .y
144            .serialize_with_mode(&mut decompressed_g2_bytes[64..128], Compress::No)
145            .map_err(|_| AltBn128CompressionError::G2DecompressionFailed)?;
146        Ok(convert_endianness::<64, 128>(&decompressed_g2_bytes))
147    }
148
149    pub fn alt_bn128_g2_compress(
150        g2_bytes: &[u8],
151    ) -> Result<[u8; alt_bn128_compression_size::G2_COMPRESSED], AltBn128CompressionError> {
152        let g2_bytes: [u8; alt_bn128_compression_size::G2] = g2_bytes
153            .try_into()
154            .map_err(|_| AltBn128CompressionError::InvalidInputSize)?;
155        if g2_bytes == [0u8; alt_bn128_compression_size::G2] {
156            return Ok([0u8; alt_bn128_compression_size::G2_COMPRESSED]);
157        }
158        let g2 = G2::deserialize_with_mode(
159            convert_endianness::<64, 128>(&g2_bytes).as_slice(),
160            Compress::No,
161            Validate::No,
162        )
163        .map_err(|_| AltBn128CompressionError::G2DecompressionFailed)?;
164        let mut g2_bytes = [0u8; alt_bn128_compression_size::G2_COMPRESSED];
165        G2::serialize_compressed(&g2, g2_bytes.as_mut_slice())
166            .map_err(|_| AltBn128CompressionError::G2CompressionFailed)?;
167        Ok(convert_endianness::<64, 64>(&g2_bytes))
168    }
169
170    pub fn convert_endianness<const CHUNK_SIZE: usize, const ARRAY_SIZE: usize>(
171        bytes: &[u8; ARRAY_SIZE],
172    ) -> [u8; ARRAY_SIZE] {
173        let reversed: [_; ARRAY_SIZE] = bytes
174            .chunks_exact(CHUNK_SIZE)
175            .flat_map(|chunk| chunk.iter().rev().copied())
176            .enumerate()
177            .fold([0u8; ARRAY_SIZE], |mut acc, (i, v)| {
178                acc[i] = v;
179                acc
180            });
181        reversed
182    }
183}
184
185#[cfg(target_os = "solana")]
186mod target_arch {
187    use {
188        super::*,
189        alt_bn128_compression_size::{G1, G1_COMPRESSED, G2, G2_COMPRESSED},
190        prelude::*,
191    };
192
193    pub fn alt_bn128_g1_compress(
194        input: &[u8],
195    ) -> Result<[u8; G1_COMPRESSED], AltBn128CompressionError> {
196        let mut result_buffer = [0; G1_COMPRESSED];
197        let result = unsafe {
198            crate::syscalls::sol_alt_bn128_compression(
199                ALT_BN128_G1_COMPRESS,
200                input as *const _ as *const u8,
201                input.len() as u64,
202                &mut result_buffer as *mut _ as *mut u8,
203            )
204        };
205
206        match result {
207            0 => Ok(result_buffer),
208            error => Err(AltBn128CompressionError::from(error)),
209        }
210    }
211
212    pub fn alt_bn128_g1_decompress(input: &[u8]) -> Result<[u8; G1], AltBn128CompressionError> {
213        let mut result_buffer = [0; G1];
214        let result = unsafe {
215            crate::syscalls::sol_alt_bn128_compression(
216                ALT_BN128_G1_DECOMPRESS,
217                input as *const _ as *const u8,
218                input.len() as u64,
219                &mut result_buffer as *mut _ as *mut u8,
220            )
221        };
222
223        match result {
224            0 => Ok(result_buffer),
225            error => Err(AltBn128CompressionError::from(error)),
226        }
227    }
228
229    pub fn alt_bn128_g2_compress(
230        input: &[u8],
231    ) -> Result<[u8; G2_COMPRESSED], AltBn128CompressionError> {
232        let mut result_buffer = [0; G2_COMPRESSED];
233        let result = unsafe {
234            crate::syscalls::sol_alt_bn128_compression(
235                ALT_BN128_G2_COMPRESS,
236                input as *const _ as *const u8,
237                input.len() as u64,
238                &mut result_buffer as *mut _ as *mut u8,
239            )
240        };
241
242        match result {
243            0 => Ok(result_buffer),
244            error => Err(AltBn128CompressionError::from(error)),
245        }
246    }
247
248    pub fn alt_bn128_g2_decompress(
249        input: &[u8; G2_COMPRESSED],
250    ) -> Result<[u8; G2], AltBn128CompressionError> {
251        let mut result_buffer = [0; G2];
252        let result = unsafe {
253            crate::syscalls::sol_alt_bn128_compression(
254                ALT_BN128_G2_DECOMPRESS,
255                input as *const _ as *const u8,
256                input.len() as u64,
257                &mut result_buffer as *mut _ as *mut u8,
258            )
259        };
260
261        match result {
262            0 => Ok(result_buffer),
263            error => Err(AltBn128CompressionError::from(error)),
264        }
265    }
266}
267
268#[cfg(test)]
269mod tests {
270    use {
271        super::*,
272        crate::alt_bn128::compression::target_arch::convert_endianness,
273        ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate},
274        std::ops::Neg,
275        target_arch::{
276            alt_bn128_g1_compress, alt_bn128_g1_decompress, alt_bn128_g2_compress,
277            alt_bn128_g2_decompress,
278        },
279    };
280    type G1 = ark_bn254::g1::G1Affine;
281    type G2 = ark_bn254::g2::G2Affine;
282
283    #[test]
284    fn alt_bn128_g1_compression() {
285        let g1_be = [
286            45, 206, 255, 166, 152, 55, 128, 138, 79, 217, 145, 164, 25, 74, 120, 234, 234, 217,
287            68, 149, 162, 44, 133, 120, 184, 205, 12, 44, 175, 98, 168, 172, 20, 24, 216, 15, 209,
288            175, 106, 75, 147, 236, 90, 101, 123, 219, 245, 151, 209, 202, 218, 104, 148, 8, 32,
289            254, 243, 191, 218, 122, 42, 81, 193, 84,
290        ];
291        let g1_le = convert_endianness::<32, 64>(&g1_be);
292        let g1: G1 =
293            G1::deserialize_with_mode(g1_le.as_slice(), Compress::No, Validate::No).unwrap();
294
295        let g1_neg = g1.neg();
296        let mut g1_neg_be = [0u8; 64];
297        g1_neg
298            .x
299            .serialize_with_mode(&mut g1_neg_be[..32], Compress::No)
300            .unwrap();
301        g1_neg
302            .y
303            .serialize_with_mode(&mut g1_neg_be[32..64], Compress::No)
304            .unwrap();
305        let g1_neg_be: [u8; 64] = convert_endianness::<32, 64>(&g1_neg_be);
306
307        let points = [(g1, g1_be), (g1_neg, g1_neg_be)];
308
309        for (point, g1_be) in &points {
310            let mut compressed_ref = [0u8; 32];
311            G1::serialize_with_mode(point, compressed_ref.as_mut_slice(), Compress::Yes).unwrap();
312            let compressed_ref: [u8; 32] = convert_endianness::<32, 32>(&compressed_ref);
313
314            let decompressed = alt_bn128_g1_decompress(compressed_ref.as_slice()).unwrap();
315
316            assert_eq!(
317                alt_bn128_g1_compress(&decompressed).unwrap(),
318                compressed_ref
319            );
320            assert_eq!(decompressed, *g1_be);
321        }
322    }
323
324    #[test]
325    fn alt_bn128_g2_compression() {
326        let g2_be = [
327            40, 57, 233, 205, 180, 46, 35, 111, 215, 5, 23, 93, 12, 71, 118, 225, 7, 46, 247, 147,
328            47, 130, 106, 189, 184, 80, 146, 103, 141, 52, 242, 25, 0, 203, 124, 176, 110, 34, 151,
329            212, 66, 180, 238, 151, 236, 189, 133, 209, 17, 137, 205, 183, 168, 196, 92, 159, 75,
330            174, 81, 168, 18, 86, 176, 56, 16, 26, 210, 20, 18, 81, 122, 142, 104, 62, 251, 169,
331            98, 141, 21, 253, 50, 130, 182, 15, 33, 109, 228, 31, 79, 183, 88, 147, 174, 108, 4,
332            22, 14, 129, 168, 6, 80, 246, 254, 100, 218, 131, 94, 49, 247, 211, 3, 245, 22, 200,
333            177, 91, 60, 144, 147, 174, 90, 17, 19, 189, 62, 147, 152, 18,
334        ];
335        let g2_le = convert_endianness::<64, 128>(&g2_be);
336        let g2: G2 =
337            G2::deserialize_with_mode(g2_le.as_slice(), Compress::No, Validate::No).unwrap();
338
339        let g2_neg = g2.neg();
340        let mut g2_neg_be = [0u8; 128];
341        g2_neg
342            .x
343            .serialize_with_mode(&mut g2_neg_be[..64], Compress::No)
344            .unwrap();
345        g2_neg
346            .y
347            .serialize_with_mode(&mut g2_neg_be[64..128], Compress::No)
348            .unwrap();
349        let g2_neg_be: [u8; 128] = convert_endianness::<64, 128>(&g2_neg_be);
350
351        let points = [(g2, g2_be), (g2_neg, g2_neg_be)];
352
353        for (point, g2_be) in &points {
354            let mut compressed_ref = [0u8; 64];
355            G2::serialize_with_mode(point, compressed_ref.as_mut_slice(), Compress::Yes).unwrap();
356            let compressed_ref: [u8; 64] = convert_endianness::<64, 64>(&compressed_ref);
357
358            let decompressed = alt_bn128_g2_decompress(compressed_ref.as_slice()).unwrap();
359
360            assert_eq!(
361                alt_bn128_g2_compress(&decompressed).unwrap(),
362                compressed_ref
363            );
364            assert_eq!(decompressed, *g2_be);
365        }
366    }
367
368    #[test]
369    fn alt_bn128_compression_g1_point_of_infitity() {
370        let g1_bytes = vec![0u8; 64];
371        let g1_compressed = alt_bn128_g1_compress(&g1_bytes).unwrap();
372        let g1_decompressed = alt_bn128_g1_decompress(&g1_compressed).unwrap();
373        assert_eq!(g1_bytes, g1_decompressed);
374    }
375
376    #[test]
377    fn alt_bn128_compression_g2_point_of_infitity() {
378        let g1_bytes = vec![0u8; 128];
379        let g1_compressed = alt_bn128_g2_compress(&g1_bytes).unwrap();
380        let g1_decompressed = alt_bn128_g2_decompress(&g1_compressed).unwrap();
381        assert_eq!(g1_bytes, g1_decompressed);
382    }
383    #[test]
384    fn alt_bn128_compression_pairing_test_input() {
385        use serde::Deserialize;
386
387        let test_data = r#"[
388        {
389            "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
390            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
391            "Name": "jeff1",
392            "Gas": 113000,
393            "NoBenchmark": false
394        },{
395            "Input": "2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
396            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
397            "Name": "jeff2",
398            "Gas": 113000,
399            "NoBenchmark": false
400        },{
401            "Input": "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
402            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
403            "Name": "jeff3",
404            "Gas": 113000,
405            "NoBenchmark": false
406        },{
407            "Input": "2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f",
408            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
409            "Name": "jeff4",
410            "Gas": 147000,
411            "NoBenchmark": false
412        },{
413            "Input": "20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
414            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
415            "Name": "jeff5",
416            "Gas": 147000,
417            "NoBenchmark": false
418        },{
419            "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
420            "Expected": "0000000000000000000000000000000000000000000000000000000000000000",
421            "Name": "jeff6",
422            "Gas": 113000,
423            "NoBenchmark": false
424        },{
425            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
426            "Expected": "0000000000000000000000000000000000000000000000000000000000000000",
427            "Name": "one_point",
428            "Gas": 79000,
429            "NoBenchmark": false
430        },{
431            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d",
432            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
433            "Name": "two_point_match_2",
434            "Gas": 113000,
435            "NoBenchmark": false
436        },{
437            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
438            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
439            "Name": "two_point_match_3",
440            "Gas": 113000,
441            "NoBenchmark": false
442        },{
443            "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75",
444            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
445            "Name": "two_point_match_4",
446            "Gas": 113000,
447            "NoBenchmark": false
448        },{
449            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d",
450            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
451            "Name": "ten_point_match_1",
452            "Gas": 385000,
453            "NoBenchmark": false
454        },{
455            "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa",
456            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
457            "Name": "ten_point_match_2",
458            "Gas": 385000,
459            "NoBenchmark": false
460        },{
461            "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75",
462            "Expected": "0000000000000000000000000000000000000000000000000000000000000001",
463            "Name": "ten_point_match_3",
464            "Gas": 113000,
465            "NoBenchmark": false
466        }
467        ]"#;
468
469        #[derive(Deserialize)]
470        #[serde(rename_all = "PascalCase")]
471        struct TestCase {
472            input: String,
473        }
474
475        let test_cases: Vec<TestCase> = serde_json::from_str(test_data).unwrap();
476
477        test_cases.iter().for_each(|test| {
478            let input = array_bytes::hex2bytes_unchecked(&test.input);
479            let g1 = input[0..64].to_vec();
480            let g1_compressed = alt_bn128_g1_compress(&g1).unwrap();
481            assert_eq!(g1, alt_bn128_g1_decompress(&g1_compressed).unwrap());
482            let g2 = input[64..192].to_vec();
483            let g2_compressed = alt_bn128_g2_compress(&g2).unwrap();
484            assert_eq!(g2, alt_bn128_g2_decompress(&g2_compressed).unwrap());
485        });
486    }
487}