|
| 1 | +//! Compression/decompression of points on the BN254 curve. |
| 2 | +
|
| 3 | +use super::{ALT_BN128_G1_SIZE, ALT_BN128_G2_SIZE}; |
| 4 | +use crate::program_error::ProgramError; |
| 5 | + |
| 6 | +#[cfg(target_os = "solana")] |
| 7 | +use crate::syscalls::sol_alt_bn128_compression; |
| 8 | + |
| 9 | +// compression sizes |
| 10 | +pub const ALT_BN128_G1_COMPRESSED_SIZE: usize = ALT_BN128_G1_SIZE / 2; // 32 |
| 11 | +pub const ALT_BN128_G2_COMPRESSED_SIZE: usize = ALT_BN128_G2_SIZE / 2; // 64 |
| 12 | + |
| 13 | +// compression operations |
| 14 | +const ALT_BN128_G1_COMPRESS: u64 = 0; |
| 15 | +const ALT_BN128_G1_DECOMPRESS: u64 = 1; |
| 16 | +const ALT_BN128_G2_COMPRESS: u64 = 2; |
| 17 | +const ALT_BN128_G2_DECOMPRESS: u64 = 3; |
| 18 | + |
| 19 | +/// Compress a G1 point on the BN254 curve. |
| 20 | +/// |
| 21 | +/// # Arguments |
| 22 | +/// |
| 23 | +/// * `input` - A G1 point in big-endian (EIP-197) encoding. |
| 24 | +/// |
| 25 | +/// # Returns |
| 26 | +/// |
| 27 | +/// A `Result` containing the compressed G1 point in big-endian (EIP-197) encoding, |
| 28 | +/// or an error if the input is not a valid G1 point. |
| 29 | +/// |
| 30 | +/// Note: This function does **not** check if the input has the correct length. |
| 31 | +/// It will return an error if the length is invalid, incurring the cost of the syscall. |
| 32 | +#[inline(always)] |
| 33 | +pub fn alt_bn128_g1_compress( |
| 34 | + input: &[u8], |
| 35 | +) -> Result<[u8; ALT_BN128_G1_COMPRESSED_SIZE], ProgramError> { |
| 36 | + alt_bn128_compression(input, ALT_BN128_G1_COMPRESS) |
| 37 | +} |
| 38 | + |
| 39 | +/// Compress a G1 point on the BN254 curve. |
| 40 | +/// |
| 41 | +/// # Arguments |
| 42 | +/// |
| 43 | +/// * `input` - A G1 point in big-endian (EIP-197) encoding. |
| 44 | +/// |
| 45 | +/// # Returns |
| 46 | +/// |
| 47 | +/// A `Result` containing the compressed G1 point in big-endian (EIP-197) encoding, |
| 48 | +/// or an error if the input is not a valid G1 point. |
| 49 | +/// |
| 50 | +/// Note: This function checks if the input has the correct length, |
| 51 | +/// returning an error without incurring the cost of the syscall. |
| 52 | +pub fn checked_alt_bn128_g1_compress( |
| 53 | + input: &[u8], |
| 54 | +) -> Result<[u8; ALT_BN128_G1_COMPRESSED_SIZE], ProgramError> { |
| 55 | + if input.len() != ALT_BN128_G1_SIZE { |
| 56 | + return Err(ProgramError::InvalidArgument); |
| 57 | + } |
| 58 | + alt_bn128_compression(input, ALT_BN128_G1_COMPRESS) |
| 59 | +} |
| 60 | + |
| 61 | +/// Decompress a G1 point on the BN254 curve. |
| 62 | +/// |
| 63 | +/// # Arguments |
| 64 | +/// |
| 65 | +/// * `input` - A compressed G1 point in big-endian (EIP-197) encoding. |
| 66 | +/// |
| 67 | +/// # Returns |
| 68 | +/// |
| 69 | +/// A `Result` containing the decompressed G1 point in big-endian (EIP-197) encoding, |
| 70 | +/// or an error if the input is not a valid compressed G1 point. |
| 71 | +/// |
| 72 | +/// Note: This function does **not** check if the input has the correct length. |
| 73 | +/// It will return an error if the length is invalid, incurring the cost of the syscall. |
| 74 | +#[inline(always)] |
| 75 | +pub fn alt_bn128_g1_decompress(input: &[u8]) -> Result<[u8; ALT_BN128_G1_SIZE], ProgramError> { |
| 76 | + alt_bn128_compression(input, ALT_BN128_G1_DECOMPRESS) |
| 77 | +} |
| 78 | + |
| 79 | +/// Decompress a G1 point on the BN254 curve. |
| 80 | +/// |
| 81 | +/// # Arguments |
| 82 | +/// |
| 83 | +/// * `input` - A compressed G1 point in big-endian (EIP-197) encoding. |
| 84 | +/// |
| 85 | +/// # Returns |
| 86 | +/// |
| 87 | +/// A `Result` containing the decompressed G1 point in big-endian (EIP-197) encoding, |
| 88 | +/// or an error if the input is not a valid compressed G1 point. |
| 89 | +/// |
| 90 | +/// Note: This function checks if the input has the correct length, |
| 91 | +/// returning an error without incurring the cost of the syscall. |
| 92 | +pub fn checked_alt_bn128_g1_decompress( |
| 93 | + input: &[u8], |
| 94 | +) -> Result<[u8; ALT_BN128_G1_SIZE], ProgramError> { |
| 95 | + if input.len() != ALT_BN128_G1_COMPRESSED_SIZE { |
| 96 | + return Err(ProgramError::InvalidArgument); |
| 97 | + } |
| 98 | + alt_bn128_compression(input, ALT_BN128_G1_DECOMPRESS) |
| 99 | +} |
| 100 | + |
| 101 | +/// Compress a G2 point on the BN254 curve. |
| 102 | +/// |
| 103 | +/// # Arguments |
| 104 | +/// |
| 105 | +/// * `input` - A G2 point in big-endian (EIP-197) encoding. |
| 106 | +/// |
| 107 | +/// # Returns |
| 108 | +/// |
| 109 | +/// A `Result` containing the compressed G2 point in big-endian (EIP-197) encoding, |
| 110 | +/// or an error if the input is not a valid G2 point. |
| 111 | +/// |
| 112 | +/// Note: This function does **not** check if the input has the correct length. |
| 113 | +/// It will return an error if the length is invalid, incurring the cost of the syscall. |
| 114 | +#[inline(always)] |
| 115 | +pub fn alt_bn128_g2_compress( |
| 116 | + input: &[u8], |
| 117 | +) -> Result<[u8; ALT_BN128_G2_COMPRESSED_SIZE], ProgramError> { |
| 118 | + alt_bn128_compression(input, ALT_BN128_G2_COMPRESS) |
| 119 | +} |
| 120 | + |
| 121 | +/// Compress a G2 point on the BN254 curve. |
| 122 | +/// |
| 123 | +/// # Arguments |
| 124 | +/// |
| 125 | +/// * `input` - A G2 point in big-endian (EIP-197) encoding. |
| 126 | +/// |
| 127 | +/// # Returns |
| 128 | +/// |
| 129 | +/// A `Result` containing the compressed G2 point in big-endian (EIP-197) encoding, |
| 130 | +/// or an error if the input is not a valid G2 point. |
| 131 | +/// |
| 132 | +/// Note: This function checks if the input has the correct length, |
| 133 | +/// returning an error without incurring the cost of the syscall. |
| 134 | +pub fn checked_alt_bn128_g2_compress( |
| 135 | + input: &[u8], |
| 136 | +) -> Result<[u8; ALT_BN128_G2_COMPRESSED_SIZE], ProgramError> { |
| 137 | + if input.len() != ALT_BN128_G2_SIZE { |
| 138 | + return Err(ProgramError::InvalidArgument); |
| 139 | + } |
| 140 | + alt_bn128_compression(input, ALT_BN128_G2_COMPRESS) |
| 141 | +} |
| 142 | + |
| 143 | +/// Decompress a G2 point on the BN254 curve. |
| 144 | +/// |
| 145 | +/// # Arguments |
| 146 | +/// |
| 147 | +/// * `input` - A compressed G2 point in big-endian (EIP-197) encoding. |
| 148 | +/// |
| 149 | +/// # Returns |
| 150 | +/// |
| 151 | +/// A `Result` containing the decompressed G2 point in big-endian (EIP-197) encoding, |
| 152 | +/// or an error if the input is not a valid compressed G2 point. |
| 153 | +/// |
| 154 | +/// Note: This function does **not** check if the input has the correct length. |
| 155 | +/// It will return an error if the length is invalid, incurring the cost of the syscall. |
| 156 | +#[inline(always)] |
| 157 | +pub fn alt_bn128_g2_decompress(input: &[u8]) -> Result<[u8; ALT_BN128_G2_SIZE], ProgramError> { |
| 158 | + alt_bn128_compression(input, ALT_BN128_G2_DECOMPRESS) |
| 159 | +} |
| 160 | + |
| 161 | +/// Decompress a G2 point on the BN254 curve. |
| 162 | +/// |
| 163 | +/// # Arguments |
| 164 | +/// |
| 165 | +/// * `input` - A compressed G2 point in big-endian (EIP-197) encoding. |
| 166 | +/// |
| 167 | +/// # Returns |
| 168 | +/// |
| 169 | +/// A `Result` containing the decompressed G2 point in big-endian (EIP-197) encoding, |
| 170 | +/// or an error if the input is not a valid compressed G2 point. |
| 171 | +/// |
| 172 | +/// Note: This function checks if the input has the correct length, |
| 173 | +/// returning an error without incurring the cost of the syscall. |
| 174 | +pub fn checked_alt_bn128_g2_decompress( |
| 175 | + input: &[u8], |
| 176 | +) -> Result<[u8; ALT_BN128_G2_SIZE], ProgramError> { |
| 177 | + if input.len() != ALT_BN128_G2_COMPRESSED_SIZE { |
| 178 | + return Err(ProgramError::InvalidArgument); |
| 179 | + } |
| 180 | + alt_bn128_compression(input, ALT_BN128_G2_DECOMPRESS) |
| 181 | +} |
| 182 | + |
| 183 | +#[inline] |
| 184 | +fn alt_bn128_compression<const OUTPUT_DATA_LEN: usize>( |
| 185 | + input: &[u8], |
| 186 | + op: u64, |
| 187 | +) -> Result<[u8; OUTPUT_DATA_LEN], ProgramError> { |
| 188 | + // Call via a system call to perform the calculation |
| 189 | + #[cfg(target_os = "solana")] |
| 190 | + { |
| 191 | + let mut bytes = core::mem::MaybeUninit::<[u8; OUTPUT_DATA_LEN]>::uninit(); |
| 192 | + |
| 193 | + let result = unsafe { |
| 194 | + sol_alt_bn128_compression( |
| 195 | + op, |
| 196 | + input as *const _ as *const u8, |
| 197 | + input.len() as u64, |
| 198 | + bytes.as_mut_ptr() as *mut u8, |
| 199 | + ) |
| 200 | + }; |
| 201 | + |
| 202 | + match result { |
| 203 | + // SAFETY: The syscall has initialized the bytes. |
| 204 | + crate::SUCCESS => Ok(unsafe { bytes.assume_init() }), |
| 205 | + _ => Err(ProgramError::InvalidArgument), |
| 206 | + } |
| 207 | + } |
| 208 | + |
| 209 | + #[cfg(not(target_os = "solana"))] |
| 210 | + { |
| 211 | + core::hint::black_box((input, op)); |
| 212 | + panic!("alt_bn128_compression is only available on target `solana`") |
| 213 | + } |
| 214 | +} |
0 commit comments