diff --git a/Cargo.lock b/Cargo.lock index def0436bb60681..a9315f2a31e591 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -80,6 +80,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" +[[package]] +name = "array-bytes" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad284aeb45c13f2fb4f084de4a420ebf447423bdf9386c0540ce33cb3ef4b8c" + [[package]] name = "arrayref" version = "0.3.6" @@ -428,6 +434,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "bn-plus" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90037d4bc5a0f87267ee77f0b9c9035a3edbeafc6552109d765283133cf36ca" +dependencies = [ + "byteorder", + "rand 0.3.23", + "rustc-serialize", +] + [[package]] name = "borsh" version = "0.9.1" @@ -1296,6 +1313,12 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elastic-array-plus" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562cc8504a01eb20c10fb154abd7c4baeb9beba2329cf85838ee2bd48a468b18" + [[package]] name = "encode_unicode" version = "0.3.6" @@ -1406,6 +1429,37 @@ dependencies = [ "tower-service", ] +[[package]] +name = "etcommon-bigint" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8375b615f02fc1ea1aea0a323e11c1084c841bd530a6dc57b9e1da80a502abd" +dependencies = [ + "byteorder", + "etcommon-hexutil", + "etcommon-rlp", + "libc", + "rand 0.3.23", +] + +[[package]] +name = "etcommon-hexutil" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20b4d1933bf88b806ba2d9189880b1b4ef205e42df9573b65716f2a50818024c" + +[[package]] +name = "etcommon-rlp" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c978ef454cd97da44a3a15d55cc312313be04b9692e39fa4cd3c00401f39bcb" +dependencies = [ + "byteorder", + "elastic-array-plus", + "etcommon-hexutil", + "lazy_static", +] + [[package]] name = "failure" version = "0.1.8" @@ -3502,6 +3556,16 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + [[package]] name = "rand" version = "0.4.6" @@ -3951,6 +4015,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + [[package]] name = "rustc_version" version = "0.2.3" @@ -4668,6 +4738,7 @@ name = "solana-bpf-loader-program" version = "1.9.22" dependencies = [ "bincode", + "bn-plus", "byteorder", "libsecp256k1 0.6.0", "log 0.4.14", @@ -5606,11 +5677,13 @@ name = "solana-program" version = "1.9.22" dependencies = [ "anyhow", + "array-bytes", "assert_matches", "base64 0.13.0", "bincode", "bitflags", "blake3 1.2.0", + "bn-plus", "borsh", "borsh-derive", "bs58 0.4.0", @@ -5619,6 +5692,7 @@ dependencies = [ "console_error_panic_hook", "console_log", "curve25519-dalek 3.2.0", + "etcommon-bigint", "getrandom 0.1.16", "itertools 0.10.3", "js-sys", diff --git a/program-runtime/src/compute_budget.rs b/program-runtime/src/compute_budget.rs index da11b19a43eae2..85df3136045f67 100644 --- a/program-runtime/src/compute_budget.rs +++ b/program-runtime/src/compute_budget.rs @@ -62,6 +62,13 @@ pub struct ComputeBudget { pub heap_cost: u64, /// Memory operation syscall base cost pub mem_op_base_cost: u64, + /// Number of compute units consumed to call alt_bn128_addition + pub alt_bn128_addition_cost: u64, + /// Number of compute units consumed to call alt_bn128_multiplication. + pub alt_bn128_multiplication_cost: u64, + /// Number of compute units consumed to pairing one pair of input elements. + /// Total cost will be one_pair_cost * (num_elems - 1) + pub alt_bn128_pairing_one_pair_cost: u64, } impl Default for ComputeBudget { @@ -92,6 +99,9 @@ impl ComputeBudget { heap_size: None, heap_cost: 8, mem_op_base_cost: 10, + alt_bn128_addition_cost: 120, + alt_bn128_multiplication_cost: 200, + alt_bn128_pairing_one_pair_cost: 110, } } diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 148594c8330aee..c59317a474cbf4 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -80,6 +80,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" +[[package]] +name = "array-bytes" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad284aeb45c13f2fb4f084de4a420ebf447423bdf9386c0540ce33cb3ef4b8c" + [[package]] name = "arrayref" version = "0.3.6" @@ -377,6 +383,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" +[[package]] +name = "bn-plus" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90037d4bc5a0f87267ee77f0b9c9035a3edbeafc6552109d765283133cf36ca" +dependencies = [ + "byteorder 1.4.3", + "rand 0.3.23", + "rustc-serialize", +] + [[package]] name = "borsh" version = "0.9.1" @@ -1064,6 +1081,12 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "elastic-array-plus" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562cc8504a01eb20c10fb154abd7c4baeb9beba2329cf85838ee2bd48a468b18" + [[package]] name = "elf" version = "0.0.10" @@ -1170,6 +1193,37 @@ dependencies = [ "tower-service", ] +[[package]] +name = "etcommon-bigint" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8375b615f02fc1ea1aea0a323e11c1084c841bd530a6dc57b9e1da80a502abd" +dependencies = [ + "byteorder 1.4.3", + "etcommon-hexutil", + "etcommon-rlp", + "libc", + "rand 0.3.23", +] + +[[package]] +name = "etcommon-hexutil" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20b4d1933bf88b806ba2d9189880b1b4ef205e42df9573b65716f2a50818024c" + +[[package]] +name = "etcommon-rlp" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c978ef454cd97da44a3a15d55cc312313be04b9692e39fa4cd3c00401f39bcb" +dependencies = [ + "byteorder 1.4.3", + "elastic-array-plus", + "etcommon-hexutil", + "lazy_static", +] + [[package]] name = "failure" version = "0.1.8" @@ -3087,6 +3141,29 @@ dependencies = [ "proc-macro2 1.0.36", ] +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi 0.3.9", +] + [[package]] name = "rand" version = "0.6.5" @@ -3495,6 +3572,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + [[package]] name = "rustc_version" version = "0.2.3" @@ -4056,6 +4139,7 @@ name = "solana-bpf-loader-program" version = "1.9.22" dependencies = [ "bincode", + "bn-plus", "byteorder 1.4.3", "libsecp256k1", "log 0.4.14", @@ -5007,10 +5091,12 @@ dependencies = [ name = "solana-program" version = "1.9.22" dependencies = [ + "array-bytes", "base64 0.13.0", "bincode", "bitflags", "blake3", + "bn-plus", "borsh", "borsh-derive", "bs58", @@ -5019,6 +5105,7 @@ dependencies = [ "console_error_panic_hook", "console_log", "curve25519-dalek", + "etcommon-bigint", "getrandom 0.1.16", "itertools", "js-sys", @@ -5040,6 +5127,7 @@ dependencies = [ "solana-frozen-abi-macro 1.9.22", "solana-logger 1.9.22", "solana-sdk-macro 1.9.22", + "static_assertions", "thiserror", "wasm-bindgen", ] diff --git a/programs/bpf/build.rs b/programs/bpf/build.rs index 6e4e6cb1e9f9d1..a38ebfc379222e 100644 --- a/programs/bpf/build.rs +++ b/programs/bpf/build.rs @@ -60,6 +60,7 @@ fn main() { let rust_programs = [ "128bit", "alloc", + "alt_bn128", "call_depth", "caller_access", "custom_heap", diff --git a/programs/bpf_loader/Cargo.toml b/programs/bpf_loader/Cargo.toml index 43afa490e56584..504051352c70a1 100644 --- a/programs/bpf_loader/Cargo.toml +++ b/programs/bpf_loader/Cargo.toml @@ -11,6 +11,7 @@ edition = "2021" [dependencies] bincode = "1.3.3" +bn-plus = "=0.4" byteorder = "1.4.3" log = "0.4.14" libsecp256k1 = "0.6.0" diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index 2db15ca4e87040..40b3cfe576b03f 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -18,14 +18,16 @@ use { solana_sdk::{ account::{AccountSharedData, ReadableAccount, WritableAccount}, account_info::AccountInfo, + alt_bn128::prelude::*, blake3, bpf_loader, bpf_loader_deprecated, bpf_loader_upgradeable, entrypoint::{BPF_ALIGN_OF_U128, MAX_PERMITTED_DATA_INCREASE, SUCCESS}, feature_set::{ - add_get_processed_sibling_instruction_syscall, blake3_syscall_enabled, - disable_fees_sysvar, do_support_realloc, fixed_memcpy_nonoverlapping_check, - libsecp256k1_0_5_upgrade_enabled, prevent_calling_precompiles_as_programs, - return_data_syscall_enabled, secp256k1_recover_syscall_enabled, - sol_log_data_syscall_enabled, update_syscall_base_costs, + add_get_processed_sibling_instruction_syscall, alt_bn128_syscall_enabled, + blake3_syscall_enabled, disable_fees_sysvar, do_support_realloc, + fixed_memcpy_nonoverlapping_check, libsecp256k1_0_5_upgrade_enabled, + prevent_calling_precompiles_as_programs, return_data_syscall_enabled, + secp256k1_recover_syscall_enabled, sol_log_data_syscall_enabled, + update_syscall_base_costs, }, hash::{Hasher, HASH_BYTES}, instruction::{ @@ -192,6 +194,21 @@ pub fn register_syscalls( // Memory allocator syscall_registry.register_syscall_by_name(b"sol_alloc_free_", SyscallAllocFree::call)?; + // alt_bn128 + if invoke_context + .feature_set + .is_active(&alt_bn128_syscall_enabled::id()) + { + syscall_registry + .register_syscall_by_name(b"sol_alt_bn128_addition", SyscallAltBn128Addition::call)?; + syscall_registry.register_syscall_by_name( + b"sol_alt_bn128_multiplication", + SyscallAltBn128Multiplication::call, + )?; + syscall_registry + .register_syscall_by_name(b"sol_alt_bn128_pairing", SyscallAltBn128Pairing::call)?; + } + // Return data if invoke_context .feature_set @@ -257,6 +274,9 @@ pub fn bind_syscall_context_objects<'a, 'b>( let is_secp256k1_recover_syscall_active = invoke_context .feature_set .is_active(&secp256k1_recover_syscall_enabled::id()); + let is_alt_bn128_syscall_active = invoke_context + .feature_set + .is_active(&alt_bn128_syscall_enabled::id()); let is_fee_sysvar_via_syscall_active = !invoke_context .feature_set .is_active(&disable_fees_sysvar::id()); @@ -376,6 +396,33 @@ pub fn bind_syscall_context_objects<'a, 'b>( }), ); + // alt_bn128 addition + bind_feature_gated_syscall_context_object!( + vm, + is_alt_bn128_syscall_active, + Box::new(SyscallAltBn128Addition { + invoke_context: invoke_context.clone(), + }), + ); + + // alt_bn128 multiplication + bind_feature_gated_syscall_context_object!( + vm, + is_alt_bn128_syscall_active, + Box::new(SyscallAltBn128Multiplication { + invoke_context: invoke_context.clone(), + }), + ); + + // alt_bn128 pairing + bind_feature_gated_syscall_context_object!( + vm, + is_alt_bn128_syscall_active, + Box::new(SyscallAltBn128Pairing { + invoke_context: invoke_context.clone(), + }), + ); + vm.bind_syscall_context_object( Box::new(SyscallGetClockSysvar { invoke_context: invoke_context.clone(), @@ -1812,6 +1859,204 @@ impl<'a, 'b> SyscallObject for SyscallBlake3<'a, 'b> { } } +/// alt_bn128 addition +pub struct SyscallAltBn128Addition<'a, 'b> { + invoke_context: Rc>>, +} + +impl<'a, 'b> SyscallObject for SyscallAltBn128Addition<'a, 'b> { + fn call( + &mut self, + input_addr: u64, + input_size: u64, + result_addr: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let cost = invoke_context.get_compute_budget().alt_bn128_addition_cost; + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); + let input = question_mark!( + translate_slice::(memory_mapping, input_addr, input_size, &loader_id), + result + ); + let call_result = question_mark!( + translate_slice_mut::( + memory_mapping, + result_addr, + ALT_BN128_ADDITION_OUTPUT_LEN as u64, + &loader_id, + ), + result + ); + + let result_point = match alt_bn128_addition(input) { + Ok(result_point) => result_point, + Err(e) => { + *result = Ok(e.into()); + return; + } + }; + + if result_point.len() != ALT_BN128_ADDITION_OUTPUT_LEN { + *result = Ok(AltBn128Error::SliceOutOfBounds.into()); + return; + } + + call_result.copy_from_slice(&result_point); + *result = Ok(SUCCESS); + } +} + +/// alt_bn128 scalar multiplication +pub struct SyscallAltBn128Multiplication<'a, 'b> { + invoke_context: Rc>>, +} + +impl<'a, 'b> SyscallObject for SyscallAltBn128Multiplication<'a, 'b> { + fn call( + &mut self, + input_addr: u64, + input_size: u64, + result_addr: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let cost = invoke_context + .get_compute_budget() + .alt_bn128_multiplication_cost; + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); + let input = question_mark!( + translate_slice::(memory_mapping, input_addr, input_size, &loader_id), + result + ); + let call_result = question_mark!( + translate_slice_mut::( + memory_mapping, + result_addr, + ALT_BN128_MULTIPLICATION_OUTPUT_LEN as u64, + &loader_id, + ), + result + ); + + let result_point = match alt_bn128_multiplication(input) { + Ok(result_point) => result_point, + Err(e) => { + *result = Ok(e.into()); + return; + } + }; + + if result_point.len() != ALT_BN128_MULTIPLICATION_OUTPUT_LEN { + *result = Ok(AltBn128Error::SliceOutOfBounds.into()); + return; + } + + call_result.copy_from_slice(&result_point); + *result = Ok(SUCCESS); + } +} + +/// alt_bn128 pairing equation +#[allow(dead_code)] +pub struct SyscallAltBn128Pairing<'a, 'b> { + invoke_context: Rc>>, +} + +impl<'a, 'b> SyscallObject for SyscallAltBn128Pairing<'a, 'b> { + fn call( + &mut self, + input_addr: u64, + input_size: u64, + result_addr: u64, + _arg4: u64, + _arg5: u64, + memory_mapping: &MemoryMapping, + result: &mut Result>, + ) { + let invoke_context = question_mark!( + self.invoke_context + .try_borrow() + .map_err(|_| SyscallError::InvokeContextBorrowFailed), + result + ); + let ele_len = input_size / ALT_BN128_PAIRING_ELEMENT_LEN as u64; + let cost = invoke_context.get_compute_budget().mem_op_base_cost.max( + invoke_context + .get_compute_budget() + .alt_bn128_pairing_one_pair_cost + .saturating_mul(ele_len - 1), + ); + question_mark!(invoke_context.get_compute_meter().consume(cost), result); + + let loader_id = question_mark!( + invoke_context + .get_loader() + .map_err(SyscallError::InstructionError), + result + ); + let input = question_mark!( + translate_slice::(memory_mapping, input_addr, input_size, &loader_id), + result + ); + let call_result = question_mark!( + translate_slice_mut::( + memory_mapping, + result_addr, + ALT_BN128_PAIRING_OUTPUT_LEN as u64, + &loader_id, + ), + result + ); + + let result_point = match alt_bn128_pairing(input) { + Ok(result_point) => result_point, + Err(e) => { + *result = Ok(e.into()); + return; + } + }; + + if result_point.len() != ALT_BN128_PAIRING_OUTPUT_LEN { + *result = Ok(AltBn128Error::SliceOutOfBounds.into()); + return; + } + + call_result.copy_from_slice(&result_point); + *result = Ok(SUCCESS); + } +} + // Cross-program invocation syscalls struct CallerAccount<'a> { diff --git a/sdk/bpf/c/inc/sol/alt_bn128.h b/sdk/bpf/c/inc/sol/alt_bn128.h new file mode 100644 index 00000000000000..340e416f62a29e --- /dev/null +++ b/sdk/bpf/c/inc/sol/alt_bn128.h @@ -0,0 +1,58 @@ +#pragma once +/** + * @brief Solana alt_bn128 system calls + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Addition on elliptic curves alt_bn128 + * + * @param input ... + * @param input_size ... + * @param result 64 byte array to hold the result. ... + * @return 0 if executed successfully + */ +uint64_t sol_alt_bn128_addition( + const uint8_t *input, + const unit64_t input_size, + uint8_t *result +); + +/** + * Multiplication on elliptic curves alt_bn128 + * + * @param input ... + * @param input_size ... + * @param result 64 byte array to hold the result. ... + * @return 0 if executed successfully + */ +uint64_t sol_alt_bn128_multiplication( + const uint8_t *input, + const unit64_t input_size, + uint8_t *result +); + +/** + * Pairing on elliptic curves alt_bn128 + * + * @param input ... + * @param input_size ... + * @param result 64 byte array to hold the result. ... + * @return 0 if executed successfully + */ +uint64_t sol_alt_bn128_pairing( + const uint8_t *input, + const unit64_t input_size, + uint8_t *result +); + +#ifdef __cplusplus +} +#endif + +/**@}*/ diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index 829b66486c541d..bd8b3275882467 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/sdk/program/Cargo.toml b/sdk/program/Cargo.toml index 5d973157e87172..14aa39403525e0 100644 --- a/sdk/program/Cargo.toml +++ b/sdk/program/Cargo.toml @@ -33,11 +33,15 @@ solana-frozen-abi = { path = "../../frozen-abi", version = "=1.9.22" } solana-frozen-abi-macro = { path = "../../frozen-abi/macro", version = "=1.9.22" } solana-sdk-macro = { path = "../macro", version = "=1.9.22" } thiserror = "1.0" +static_assertions = "1.1.0" [target.'cfg(not(target_arch = "bpf"))'.dependencies] +array-bytes = "=1.4.1" +bn-plus = "=0.4" bitflags = "1.3.1" base64 = "0.13" curve25519-dalek = "3.0.0" +etcommon-bigint = "=0.2.10" libsecp256k1 = "0.6.0" rand = "0.7.0" solana-logger = { path = "../../logger", version = "=1.9.22" } diff --git a/sdk/program/src/alt_bn128.rs b/sdk/program/src/alt_bn128.rs new file mode 100644 index 00000000000000..091ae3a7eecd91 --- /dev/null +++ b/sdk/program/src/alt_bn128.rs @@ -0,0 +1,860 @@ +pub mod prelude { + pub use crate::alt_bn128::{ + alt_bn128_addition, alt_bn128_multiplication, alt_bn128_pairing, consts::*, AltBn128Error, + }; +} + +use { + borsh::{BorshDeserialize, BorshSchema, BorshSerialize}, + core::convert::TryFrom, + thiserror::Error, +}; + +#[cfg(not(target_arch = "bpf"))] +use { + bigint::U256, + bn::{pairing, AffineG1, AffineG2, Fq, Fq2, Fr, Group, Gt, G1, G2}, +}; + +use consts::*; + +//---- Constants + +mod consts { + /// Input length for the add operation. + pub const ALT_BN128_ADDITION_INPUT_LEN: usize = 128; + + /// Input length for the multiplication operation. + pub const ALT_BN128_MULTIPLICATION_INPUT_LEN: usize = 128; + + /// Pair element length. + pub const ALT_BN128_PAIRING_ELEMENT_LEN: usize = 192; + + /// Output length for the add operation. + pub const ALT_BN128_ADDITION_OUTPUT_LEN: usize = 64; + + /// Output length for the multiplication operation. + pub const ALT_BN128_MULTIPLICATION_OUTPUT_LEN: usize = 64; + + /// Output length for pairing operation.. + pub const ALT_BN128_PAIRING_OUTPUT_LEN: usize = 32; + + /// Size of the EC point field, in bytes. + pub const ALT_BN128_FIELD_SIZE: usize = 32; + + /// Size of the EC point. `alt_bn128` point contains + /// the consistently united x and y fields as 64 bytes. + pub const ALT_BN128_POINT_SIZE: usize = 64; + + /// Internal representation of the EC field (32 bytes). + pub type FieldBytes = [u8; ALT_BN128_FIELD_SIZE]; + + /// Internal representation of the EC point (64 bytes). + pub type PointBytes = [u8; ALT_BN128_POINT_SIZE]; +} + +//---- Custom errors + +#[derive(Debug, Error, Clone, PartialEq, Eq)] +pub enum AltBn128Error { + #[error("The input data is invalid")] + InvalidInputData, + #[error("Incorrect size of input data slice for curve field")] + InvalidFieldSliceSize, + #[error("Incorrect size of input data slice for curve point")] + InvalidPointSliceSize, + #[error("Slice data is going out of input data bounds")] + SliceOutOfBounds, + #[error("Cannot convert slice to specified array")] + TryFromSliceError, + #[error("Invalid field data")] + FieldError, + #[error("Invalid group data")] + GroupError, + #[error("Unexpected error")] + UnexpectedError, +} + +impl From for AltBn128Error { + fn from(v: u64) -> AltBn128Error { + match v { + 1 => AltBn128Error::InvalidInputData, + 2 => AltBn128Error::InvalidFieldSliceSize, + 3 => AltBn128Error::InvalidPointSliceSize, + 4 => AltBn128Error::SliceOutOfBounds, + 5 => AltBn128Error::TryFromSliceError, + 6 => AltBn128Error::FieldError, + 7 => AltBn128Error::GroupError, + _ => AltBn128Error::UnexpectedError, + } + } +} + +impl From for u64 { + fn from(v: AltBn128Error) -> u64 { + match v { + AltBn128Error::InvalidInputData => 1, + AltBn128Error::InvalidFieldSliceSize => 2, + AltBn128Error::InvalidPointSliceSize => 3, + AltBn128Error::SliceOutOfBounds => 4, + AltBn128Error::TryFromSliceError => 5, + AltBn128Error::FieldError => 6, + AltBn128Error::GroupError => 7, + AltBn128Error::UnexpectedError => 0, + } + } +} + +//---- Field & Point structs + +/// Field struct. +#[repr(transparent)] +#[derive( + BorshSerialize, + BorshDeserialize, + BorshSchema, + Clone, + Copy, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + AbiExample, +)] +pub struct AltBn128Field(FieldBytes); + +impl AltBn128Field { + pub fn to_bytes(self) -> FieldBytes { + self.0 + } +} + +impl From for AltBn128Field { + fn from(input: FieldBytes) -> Self { + Self(input) + } +} + +impl TryFrom<&[u8]> for AltBn128Field { + type Error = AltBn128Error; + fn try_from(input: &[u8]) -> Result { + FieldBytes::try_from(input) + .map_err(|_| AltBn128Error::TryFromSliceError) + .map(Self) + } +} + +impl TryFrom<(&[u8], usize)> for AltBn128Field { + type Error = AltBn128Error; + fn try_from((input, pos): (&[u8], usize)) -> Result { + if input.len() < pos.saturating_add(ALT_BN128_FIELD_SIZE) { + return Err(AltBn128Error::SliceOutOfBounds); + } + let mut buf = [0; ALT_BN128_FIELD_SIZE]; + buf.copy_from_slice(&input[pos..(pos.saturating_add(ALT_BN128_FIELD_SIZE))]); + Ok(AltBn128Field::from(buf)) + } +} + +/// Point struct. +#[repr(transparent)] +#[derive( + BorshSerialize, + BorshDeserialize, + BorshSchema, + Clone, + Copy, + Eq, + PartialEq, + Ord, + PartialOrd, + Hash, + AbiExample, +)] +pub struct AltBn128Point((AltBn128Field, AltBn128Field)); + +impl AltBn128Point { + pub fn new(x: AltBn128Field, y: AltBn128Field) -> Self { + Self((x, y)) + } + + pub fn x(self) -> AltBn128Field { + (self.0).0 + } + + pub fn y(self) -> AltBn128Field { + (self.0).1 + } + + pub fn to_bytes(self) -> Result { + PointBytes::try_from( + [self.x().to_bytes(), self.y().to_bytes()] + .concat() + .as_slice(), + ) + .map_err(|_| AltBn128Error::TryFromSliceError) + } +} + +impl TryFrom<&[u8]> for AltBn128Point { + type Error = AltBn128Error; + fn try_from(input: &[u8]) -> Result { + AltBn128Point::try_from( + &PointBytes::try_from(input).map_err(|_| AltBn128Error::TryFromSliceError)?, + ) + } +} + +impl TryFrom<&PointBytes> for AltBn128Point { + type Error = AltBn128Error; + fn try_from(point_data: &PointBytes) -> Result { + Ok(AltBn128Point::new( + AltBn128Field::try_from((point_data as &[u8], 0))?, + AltBn128Field::try_from((point_data as &[u8], ALT_BN128_FIELD_SIZE))?, + )) + } +} + +//---- + +// Field -> Fq +#[cfg(not(target_arch = "bpf"))] +impl TryFrom<&AltBn128Field> for Fq { + type Error = AltBn128Error; + fn try_from(value: &AltBn128Field) -> Result { + Fq::from_slice(&value.0).map_err(|_| AltBn128Error::FieldError) + } +} + +// Field -> Fr +#[cfg(not(target_arch = "bpf"))] +impl TryFrom<&AltBn128Field> for Fr { + type Error = AltBn128Error; + fn try_from(value: &AltBn128Field) -> Result { + Fr::from_slice(&value.0).map_err(|_| AltBn128Error::FieldError) + } +} + +// FqPair +#[cfg(not(target_arch = "bpf"))] +struct FqPair(pub Fq, pub Fq); +#[cfg(not(target_arch = "bpf"))] +impl FqPair { + pub fn new(x: Fq, y: Fq) -> Self { + Self(x, y) + } +} + +// (Fq, Fq) -> G1 +#[cfg(not(target_arch = "bpf"))] +impl TryFrom for G1 { + type Error = AltBn128Error; + fn try_from(pair: FqPair) -> Result { + Ok(if pair.0 == Fq::zero() && pair.1 == Fq::zero() { + G1::zero() + } else { + G1::from(AffineG1::new(pair.0, pair.1).map_err(|_| AltBn128Error::GroupError)?) + }) + } +} + +// (Fq, Fq) -> Fq2 +#[cfg(not(target_arch = "bpf"))] +impl From for Fq2 { + fn from(pair: FqPair) -> Self { + Fq2::new(pair.0, pair.1) + } +} + +//---- Precompiled contracts + +pub fn alt_bn128_addition(input: &[u8]) -> Result, AltBn128Error> { + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_alt_bn128_addition(input: *const u8, input_size: u64, result: *mut u8) -> u64; + } + + if input.len() > ALT_BN128_ADDITION_INPUT_LEN { + return Err(AltBn128Error::InvalidInputData); + } + let mut result_buffer = [0; ALT_BN128_ADDITION_OUTPUT_LEN]; + let result = unsafe { + sol_alt_bn128_addition( + input.as_ptr(), + input.len() as u64, + result_buffer.as_mut_ptr(), + ) + }; + + match result { + 0 => Ok(result_buffer.to_vec()), + error => Err(AltBn128Error::from(error)), + } + } + + #[cfg(not(target_arch = "bpf"))] + { + if input.len() > ALT_BN128_ADDITION_INPUT_LEN { + return Err(AltBn128Error::InvalidInputData); + } + let mut input = input.to_vec(); + input.resize(ALT_BN128_ADDITION_INPUT_LEN, 0); + + let px = &AltBn128Field::try_from((input.as_slice(), 0))?; + let py = &AltBn128Field::try_from((input.as_slice(), ALT_BN128_FIELD_SIZE))?; + let qx = + &AltBn128Field::try_from((input.as_slice(), ALT_BN128_FIELD_SIZE.saturating_mul(2)))?; + let qy = + &AltBn128Field::try_from((input.as_slice(), ALT_BN128_FIELD_SIZE.saturating_mul(3)))?; + + let p = G1::try_from(FqPair::new(Fq::try_from(px)?, Fq::try_from(py)?))?; + let q = G1::try_from(FqPair::new(Fq::try_from(qx)?, Fq::try_from(qy)?))?; + + let mut result_point_data = [0; ALT_BN128_ADDITION_OUTPUT_LEN]; + if let Some(result_point) = AffineG1::from_jacobian(p + q) { + result_point + .x() + .to_big_endian(&mut result_point_data[0..ALT_BN128_FIELD_SIZE]) + .map_err(|_| AltBn128Error::SliceOutOfBounds)?; + result_point + .y() + .to_big_endian(&mut result_point_data[ALT_BN128_FIELD_SIZE..]) + .map_err(|_| AltBn128Error::SliceOutOfBounds)?; + } + Ok(result_point_data.to_vec()) + } +} + +pub fn alt_bn128_multiplication(input: &[u8]) -> Result, AltBn128Error> { + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_alt_bn128_multiplication( + input: *const u8, + input_size: u64, + result: *mut u8, + ) -> u64; + } + + if input.len() > ALT_BN128_MULTIPLICATION_INPUT_LEN { + return Err(AltBn128Error::InvalidInputData); + } + let mut result_buffer = [0u8; ALT_BN128_POINT_SIZE]; + let result = unsafe { + sol_alt_bn128_multiplication( + input.as_ptr(), + input.len() as u64, + result_buffer.as_mut_ptr(), + ) + }; + + match result { + 0 => Ok(result_buffer.to_vec()), + error => Err(AltBn128Error::from(error)), + } + } + + #[cfg(not(target_arch = "bpf"))] + { + if input.len() > ALT_BN128_MULTIPLICATION_INPUT_LEN { + return Err(AltBn128Error::InvalidInputData); + } + let mut input = input.to_vec(); + input.resize(ALT_BN128_MULTIPLICATION_INPUT_LEN, 0); + + let px = &AltBn128Field::try_from((input.as_slice(), 0))?; + let py = &AltBn128Field::try_from((input.as_slice(), ALT_BN128_FIELD_SIZE))?; + let fr = + &AltBn128Field::try_from((input.as_slice(), ALT_BN128_FIELD_SIZE.saturating_mul(2)))?; + + let p = G1::try_from(FqPair::new(Fq::try_from(px)?, Fq::try_from(py)?))?; + let fr = Fr::try_from(fr)?; + + let mut result_point_data = [0; ALT_BN128_MULTIPLICATION_OUTPUT_LEN]; + if let Some(result_point) = AffineG1::from_jacobian(p * fr) { + result_point + .x() + .to_big_endian(&mut result_point_data[0..ALT_BN128_FIELD_SIZE]) + .map_err(|_| AltBn128Error::SliceOutOfBounds)?; + result_point + .y() + .to_big_endian(&mut result_point_data[ALT_BN128_FIELD_SIZE..]) + .map_err(|_| AltBn128Error::SliceOutOfBounds)?; + } + Ok(result_point_data.to_vec()) + } +} + +pub fn alt_bn128_pairing(input: &[u8]) -> Result, AltBn128Error> { + #[cfg(target_arch = "bpf")] + { + extern "C" { + fn sol_alt_bn128_pairing(input: *const u8, input_size: u64, result: *mut u8) -> u64; + } + + if input + .len() + .checked_rem(consts::ALT_BN128_PAIRING_ELEMENT_LEN) + .unwrap() + != 0 + { + return Err(AltBn128Error::InvalidInputData); + } + let mut result_buffer = [0u8; 32]; + let result = unsafe { + sol_alt_bn128_pairing( + input.as_ptr(), + input.len() as u64, + result_buffer.as_mut_ptr(), + ) + }; + + match result { + 0 => Ok(result_buffer.to_vec()), + error => Err(AltBn128Error::from(error)), + } + } + + #[cfg(not(target_arch = "bpf"))] + { + if input + .len() + .checked_rem(consts::ALT_BN128_PAIRING_ELEMENT_LEN) + .unwrap() + != 0 + { + return Err(AltBn128Error::InvalidInputData); + } + + fn read_one(s: &[u8]) -> Result<(G1, G2), AltBn128Error> { + let ax = Fq::try_from(&AltBn128Field::try_from((s, 0))?)?; + let ay = Fq::try_from(&AltBn128Field::try_from((s, ALT_BN128_FIELD_SIZE))?)?; + let bay = Fq::try_from(&AltBn128Field::try_from(( + s, + ALT_BN128_FIELD_SIZE.saturating_mul(2), + ))?)?; + let bax = Fq::try_from(&AltBn128Field::try_from(( + s, + ALT_BN128_FIELD_SIZE.saturating_mul(3), + ))?)?; + let bby = Fq::try_from(&AltBn128Field::try_from(( + s, + ALT_BN128_FIELD_SIZE.saturating_mul(4), + ))?)?; + let bbx = Fq::try_from(&AltBn128Field::try_from(( + s, + ALT_BN128_FIELD_SIZE.saturating_mul(5), + ))?)?; + + let ba = Fq2::new(bax, bay); + let bb = Fq2::new(bbx, bby); + + let b = if ba.is_zero() && bb.is_zero() { + G2::zero() + } else { + G2::from(AffineG2::new(ba, bb).map_err(|_| AltBn128Error::GroupError)?) + }; + let a = G1::try_from(FqPair::new(ax, ay))?; + Ok((a, b)) + } + + let ele_len = input.len().saturating_div(ALT_BN128_PAIRING_ELEMENT_LEN); + let mut acc = Gt::one(); + for i in 0..ele_len { + let (a, b) = read_one( + &input[i.saturating_mul(ALT_BN128_PAIRING_ELEMENT_LEN) + ..i.saturating_mul(ALT_BN128_PAIRING_ELEMENT_LEN) + .saturating_add(ALT_BN128_PAIRING_ELEMENT_LEN)], + )?; + acc = acc * pairing(a, b); + } + + let result = if acc == Gt::one() { + U256::from(1) + } else { + U256::zero() + }; + + let mut output = vec![0u8; ALT_BN128_PAIRING_OUTPUT_LEN]; + result.to_big_endian(&mut output); + + Ok(output) + } +} + +#[test] +#[cfg(not(target_arch = "bpf"))] +fn alt_bn128_addition_test() { + use serde::Deserialize; + + let test_data = r#"[ + { + "Input": "18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f3726607c2b7f58a84bd6145f00c9c2bc0bb1a187f20ff2c92963a88019e7c6a014eed06614e20c147e940f2d70da3f74c9a17df361706a4485c742bd6788478fa17d7", + "Expected": "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c915", + "Name": "chfast1", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "2243525c5efd4b9c3d3c45ac0ca3fe4dd85e830a4ce6b65fa1eeaee202839703301d1d33be6da8e509df21cc35964723180eed7532537db9ae5e7d48f195c91518b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9063c909c4720840cb5134cb9f59fa749755796819658d32efc0d288198f37266", + "Expected": "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb204", + "Name": "chfast2", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "cdetrio1", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "cdetrio2", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "cdetrio3", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "cdetrio4", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "cdetrio5", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Name": "cdetrio6", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Name": "cdetrio7", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Name": "cdetrio8", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Gas": 150, + "Name": "cdetrio9", + "NoBenchmark": false + },{ + "Input": "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Gas": 150, + "Name": "cdetrio10", + "NoBenchmark": false + },{ + "Input": "0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + "Expected": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + "Name": "cdetrio11", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4", + "Name": "cdetrio12", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", + "Expected": "15bf2bb17880144b5d1cd2b1f46eff9d617bffd1ca57c37fb5a49bd84e53cf66049c797f9ce0d17083deb32b5e36f2ea2a212ee036598dd7624c168993d1355f", + "Name": "cdetrio13", + "Gas": 150, + "NoBenchmark": false + },{ + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa92e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Expected": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "Name": "cdetrio14", + "Gas": 150, + "NoBenchmark": false + } + ]"#; + + #[derive(Deserialize)] + #[serde(rename_all = "PascalCase")] + struct TestCase { + input: String, + expected: String, + } + + let test_cases: Vec = serde_json::from_str(test_data).unwrap(); + + test_cases.iter().for_each(|test| { + let input = array_bytes::hex2bytes_unchecked(&test.input); + let result = alt_bn128_addition(&input); + assert!(result.is_ok()); + let result = result.unwrap(); + + let expected = array_bytes::hex2bytes_unchecked(&test.expected); + assert_eq!(result, expected); + }); +} + +#[test] +#[cfg(not(target_arch = "bpf"))] +fn alt_bn128_multiplication_test() { + use serde::Deserialize; + + let test_data = r#"[ + { + "Input": "2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb721611ce0a6af85915e2f1d70300909ce2e49dfad4a4619c8390cae66cefdb20400000000000000000000000000000000000000000000000011138ce750fa15c2", + "Expected": "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc", + "Name": "chfast1", + "Gas": 6000, + "NoBenchmark": false + },{ + "Input": "070a8d6a982153cae4be29d434e8faef8a47b274a053f5a4ee2a6c9c13c31e5c031b8ce914eba3a9ffb989f9cdd5b0f01943074bf4f0f315690ec3cec6981afc30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd46", + "Expected": "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e", + "Name": "chfast2", + "Gas": 6000, + "NoBenchmark": false + },{ + "Input": "025a6f4181d2b4ea8b724290ffb40156eb0adb514c688556eb79cdea0752c2bb2eff3f31dea215f1eb86023a133a996eb6300b44da664d64251d05381bb8a02e183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3", + "Expected": "14789d0d4a730b354403b5fac948113739e276c23e0258d8596ee72f9cd9d3230af18a63153e0ec25ff9f2951dd3fa90ed0197bfef6e2a1a62b5095b9d2b4a27", + "Name": "chfast3", + "Gas": 6000, + "NoBenchmark": false + },{ + "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "Expected": "2cde5879ba6f13c0b5aa4ef627f159a3347df9722efce88a9afbb20b763b4c411aa7e43076f6aee272755a7f9b84832e71559ba0d2e0b17d5f9f01755e5b0d11", + "Name": "cdetrio1", + "Gas": 6000, + "NoBenchmark": false + },{ + "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f630644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", + "Expected": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe3163511ddc1c3f25d396745388200081287b3fd1472d8339d5fecb2eae0830451", + "Name": "cdetrio2", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000100000000000000000000000000000000", + "Expected": "1051acb0700ec6d42a88215852d582efbaef31529b6fcbc3277b5c1b300f5cf0135b2394bb45ab04b8bd7611bd2dfe1de6a4e6e2ccea1ea1955f577cd66af85b", + "Name": "cdetrio3", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000009", + "Expected": "1dbad7d39dbc56379f78fac1bca147dc8e66de1b9d183c7b167351bfe0aeab742cd757d51289cd8dbd0acf9e673ad67d0f0a89f912af47ed1be53664f5692575", + "Name": "cdetrio4", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f60000000000000000000000000000000000000000000000000000000000000001", + "Expected": "1a87b0584ce92f4593d161480614f2989035225609f08058ccfa3d0f940febe31a2f3c951f6dadcc7ee9007dff81504b0fcd6d7cf59996efdc33d92bf7f9f8f6", + "Name": "cdetrio5", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "Expected": "29e587aadd7c06722aabba753017c093f70ba7eb1f1c0104ec0564e7e3e21f6022b1143f6a41008e7755c71c3d00b6b915d386de21783ef590486d8afa8453b1", + "Name": "cdetrio6", + "Gas": 6000, + "NoBenchmark": false + },{ + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", + "Expected": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa92e83f8d734803fc370eba25ed1f6b8768bd6d83887b87165fc2434fe11a830cb", + "Name": "cdetrio7", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000100000000000000000000000000000000", + "Expected": "221a3577763877920d0d14a91cd59b9479f83b87a653bb41f82a3f6f120cea7c2752c7f64cdd7f0e494bff7b60419f242210f2026ed2ec70f89f78a4c56a1f15", + "Name": "cdetrio8", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000000000000000000000000000000000009", + "Expected": "228e687a379ba154554040f8821f4e41ee2be287c201aa9c3bc02c9dd12f1e691e0fd6ee672d04cfd924ed8fdc7ba5f2d06c53c1edc30f65f2af5a5b97f0a76a", + "Name": "cdetrio9", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c0000000000000000000000000000000000000000000000000000000000000001", + "Expected": "17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c", + "Name": "cdetrio10", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "Expected": "00a1a234d08efaa2616607e31eca1980128b00b415c845ff25bba3afcb81dc00242077290ed33906aeb8e42fd98c41bcb9057ba03421af3f2d08cfc441186024", + "Name": "cdetrio11", + "Gas": 6000, + "NoBenchmark": false + },{ + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d9830644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000", + "Expected": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b8692929ee761a352600f54921df9bf472e66217e7bb0cee9032e00acc86b3c8bfaf", + "Name": "cdetrio12", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000100000000000000000000000000000000", + "Expected": "1071b63011e8c222c5a771dfa03c2e11aac9666dd097f2c620852c3951a4376a2f46fe2f73e1cf310a168d56baa5575a8319389d7bfa6b29ee2d908305791434", + "Name": "cdetrio13", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000009", + "Expected": "19f75b9dd68c080a688774a6213f131e3052bd353a304a189d7a2ee367e3c2582612f545fb9fc89fde80fd81c68fc7dcb27fea5fc124eeda69433cf5c46d2d7f", + "Name": "cdetrio14", + "Gas": 6000, + "NoBenchmark": true + },{ + "Input": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d980000000000000000000000000000000000000000000000000000000000000001", + "Expected": "039730ea8dff1254c0fee9c0ea777d29a9c710b7e616683f194f18c43b43b869073a5ffcc6fc7a28c30723d6e58ce577356982d65b833a5a5c15bf9024b43d98", + "Name": "cdetrio15", + "Gas": 6000, + "NoBenchmark": true + } + ]"#; + + #[derive(Deserialize)] + #[serde(rename_all = "PascalCase")] + struct TestCase { + input: String, + expected: String, + } + + let test_cases: Vec = serde_json::from_str(test_data).unwrap(); + + test_cases.iter().for_each(|test| { + let input = array_bytes::hex2bytes_unchecked(&test.input); + let result = alt_bn128_multiplication(&input); + assert!(result.is_ok()); + let result = result.unwrap(); + + let expected = array_bytes::hex2bytes_unchecked(&test.expected); + assert_eq!(result, expected); + }); +} + +#[test] +#[cfg(not(target_arch = "bpf"))] +fn alt_bn128_pairing_test() { + use serde::Deserialize; + + let test_data = r#"[ + { + "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "jeff1", + "Gas": 113000, + "NoBenchmark": false + },{ + "Input": "2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "jeff2", + "Gas": 113000, + "NoBenchmark": false + },{ + "Input": "0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "jeff3", + "Gas": 113000, + "NoBenchmark": false + },{ + "Input": "2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "jeff4", + "Gas": 147000, + "NoBenchmark": false + },{ + "Input": "20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "jeff5", + "Gas": 147000, + "NoBenchmark": false + },{ + "Input": "1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000", + "Name": "jeff6", + "Gas": 113000, + "NoBenchmark": false + },{ + "Input": "", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "empty_data", + "Gas": 45000, + "NoBenchmark": false + },{ + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000000", + "Name": "one_point", + "Gas": 79000, + "NoBenchmark": false + },{ + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "two_point_match_2", + "Gas": 113000, + "NoBenchmark": false + },{ + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "two_point_match_3", + "Gas": 113000, + "NoBenchmark": false + },{ + "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "two_point_match_4", + "Gas": 113000, + "NoBenchmark": false + },{ + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "ten_point_match_1", + "Gas": 385000, + "NoBenchmark": false + },{ + "Input": "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd31a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a83198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "ten_point_match_2", + "Gas": 385000, + "NoBenchmark": false + },{ + "Input": "105456a333e6d636854f987ea7bb713dfd0ae8371a72aea313ae0c32c0bf10160cf031d41b41557f3e7e3ba0c51bebe5da8e6ecd855ec50fc87efcdeac168bcc0476be093a6d2b4bbf907172049874af11e1b6267606e00804d3ff0037ec57fd3010c68cb50161b7d1d96bb71edfec9880171954e56871abf3d93cc94d745fa114c059d74e5b6c4ec14ae5864ebe23a71781d86c29fb8fb6cce94f70d3de7a2101b33461f39d9e887dbb100f170a2345dde3c07e256d1dfa2b657ba5cd030427000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000021a2c3013d2ea92e13c800cde68ef56a294b883f6ac35d25f587c09b1b3c635f7290158a80cd3d66530f74dc94c94adb88f5cdb481acca997b6e60071f08a115f2f997f3dbd66a7afe07fe7862ce239edba9e05c5afff7f8a1259c9733b2dfbb929d1691530ca701b4a106054688728c9972c8512e9789e9567aae23e302ccd75", + "Expected": "0000000000000000000000000000000000000000000000000000000000000001", + "Name": "ten_point_match_3", + "Gas": 113000, + "NoBenchmark": false + } + ]"#; + + #[derive(Deserialize)] + #[serde(rename_all = "PascalCase")] + struct TestCase { + input: String, + expected: String, + } + + let test_cases: Vec = serde_json::from_str(test_data).unwrap(); + + test_cases.iter().for_each(|test| { + let input = array_bytes::hex2bytes_unchecked(&test.input); + let result = alt_bn128_pairing(&input); + assert!(result.is_ok()); + let result = result.unwrap(); + + let expected = array_bytes::hex2bytes_unchecked(&test.expected); + assert_eq!(result, expected); + }); +} diff --git a/sdk/program/src/lib.rs b/sdk/program/src/lib.rs index 8ac9a961b6dd58..e1295588a445a8 100644 --- a/sdk/program/src/lib.rs +++ b/sdk/program/src/lib.rs @@ -6,6 +6,7 @@ extern crate self as solana_program; pub mod account_info; +pub mod alt_bn128; pub(crate) mod atomic_u64; pub mod blake3; pub mod borsh; diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index 3a8af16810ddaa..af4bb8fac97821 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -315,6 +315,10 @@ pub mod default_units_per_instruction { solana_sdk::declare_id!("J2QdYx8crLbTVK8nur1jeLsmc3krDbfjoxoea2V1Uy5Q"); } +pub mod alt_bn128_syscall_enabled { + solana_sdk::declare_id!("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXALTBN128"); +} + lazy_static! { /// Map of feature identifiers to user-visible description pub static ref FEATURE_NAMES: HashMap = [ @@ -388,6 +392,7 @@ lazy_static! { (fixed_memcpy_nonoverlapping_check::id(), "use correct check for nonoverlapping regions in memcpy syscall"), (drop_redundant_turbine_path::id(), "drop redundant turbine path"), (default_units_per_instruction::id(), "Default max tx-wide compute units calculated per instruction"), + (alt_bn128_syscall_enabled::id(), "add alt_bn128 syscalls"), /*************** ADD NEW FEATURES HERE ***************/ ] .iter()