diff --git a/examples/c++/multi-gpu-poseidon/example.cu b/examples/c++/multi-gpu-poseidon/example.cu index 32f0c920c..054c7868c 100644 --- a/examples/c++/multi-gpu-poseidon/example.cu +++ b/examples/c++/multi-gpu-poseidon/example.cu @@ -6,6 +6,9 @@ #include "api/bn254.h" #include "gpu-utils/error_handler.cuh" +#include "poseidon/poseidon.cuh" +#include "hash/hash.cuh" + using namespace poseidon; using namespace bn254; @@ -20,31 +23,20 @@ void checkCudaError(cudaError_t error) // these global constants go into template calls const int size_col = 11; -// this function executes the Poseidon thread void threadPoseidon( device_context::DeviceContext ctx, unsigned size_partition, scalar_t* layers, scalar_t* column_hashes, - PoseidonConstants* constants) + Poseidon * poseidon) { cudaError_t err_result = CHK_STICKY(cudaSetDevice(ctx.device_id)); if (err_result != cudaSuccess) { std::cerr << "CUDA error: " << cudaGetErrorString(err_result) << std::endl; return; } - // CHK_IF_RETURN(); I can't use it in a standard thread function - PoseidonConfig column_config = { - ctx, // ctx - false, // are_inputes_on_device - false, // are_outputs_on_device - false, // input_is_a_state - false, // aligned - false, // loop_state - false, // is_async - }; - cudaError_t err = - bn254_poseidon_hash_cuda(layers, column_hashes, (size_t)size_partition, size_col, *constants, column_config); + SpongeConfig column_config = default_sponge_config(ctx); + cudaError_t err = poseidon->hash_many(layers, column_hashes, (size_t) size_partition, size_col, 1, column_config); checkCudaError(err); } @@ -59,6 +51,11 @@ using FpMilliseconds = std::chrono::duration(malloc(size_partition * sizeof(scalar_t))); CHECK_ALLOC(column_hash1); - PoseidonConstants column_constants0, column_constants1; - bn254_init_optimized_poseidon_constants_cuda(size_col, ctx0, &column_constants0); - cudaError_t err_result = CHK_STICKY(cudaSetDevice(ctx1.device_id)); - if (err_result != cudaSuccess) { - std::cerr << "CUDA error: " << cudaGetErrorString(err_result) << std::endl; - return; - } - bn254_init_optimized_poseidon_constants_cuda(size_col, ctx1, &column_constants1); + Poseidon column_poseidon0(size_col, ctx0); + cudaError_t err_result = CHK_STICKY(cudaSetDevice(ctx1.device_id)); + if (err_result != cudaSuccess) { + std::cerr << "CUDA error: " << cudaGetErrorString(err_result) << std::endl; + return; + } + Poseidon column_poseidon1(size_col, ctx1); std::cout << "Parallel execution of Poseidon threads" << std::endl; START_TIMER(parallel); - std::thread thread0(threadPoseidon, ctx0, size_partition, layers0, column_hash0, &column_constants0); - std::thread thread1(threadPoseidon, ctx1, size_partition, layers1, column_hash1, &column_constants1); + std::thread thread0(threadPoseidon, ctx0, size_partition, layers0, column_hash0, &column_poseidon0); + std::thread thread1(threadPoseidon, ctx1, size_partition, layers1, column_hash1, &column_poseidon1); // Wait for the threads to finish thread0.join(); @@ -141,9 +137,9 @@ int main() std::cout << "Sequential execution of Poseidon threads" << std::endl; START_TIMER(sequential); - std::thread thread2(threadPoseidon, ctx0, size_partition, layers0, column_hash0, &column_constants0); + std::thread thread2(threadPoseidon, ctx0, size_partition, layers0, column_hash0, &column_poseidon0); thread2.join(); - std::thread thread3(threadPoseidon, ctx0, size_partition, layers1, column_hash1, &column_constants0); + std::thread thread3(threadPoseidon, ctx0, size_partition, layers1, column_hash1, &column_poseidon0); thread3.join(); END_TIMER(sequential, "1 GPU"); std::cout << "Output Data from Thread 2: "; diff --git a/examples/c++/polynomial-api/example.cu b/examples/c++/polynomial-api/example.cu index d19178b2c..762298346 100644 --- a/examples/c++/polynomial-api/example.cu +++ b/examples/c++/polynomial-api/example.cu @@ -3,13 +3,11 @@ #include "polynomials/polynomials.h" #include "polynomials/cuda_backend/polynomial_cuda_backend.cuh" #include "ntt/ntt.cuh" -#include "poseidon/tree/merkle.cuh" + #include "api/bn254.h" #include -// using namespace field_config; using namespace polynomials; -using namespace merkle; using namespace bn254; // define the polynomial type diff --git a/examples/c++/poseidon/example.cu b/examples/c++/poseidon/example.cu index 171196213..c75e30217 100644 --- a/examples/c++/poseidon/example.cu +++ b/examples/c++/poseidon/example.cu @@ -4,6 +4,8 @@ #include "api/bn254.h" #include "curves/params/bn254.cuh" +#include "poseidon/poseidon.cuh" +#include "hash/hash.cuh" using namespace poseidon; using namespace bn254; @@ -14,13 +16,12 @@ inline uint32_t tree_index(uint32_t level, uint32_t offset) { return (1 << level // We assume the tree has leaves already set, compute all other levels void build_tree( - const uint32_t tree_height, scalar_t* tree, PoseidonConstants* constants, PoseidonConfig config) + const uint32_t tree_height, scalar_t* tree, Poseidon &poseidon, SpongeConfig &config) { for (uint32_t level = tree_height - 1; level > 0; level--) { const uint32_t next_level = level - 1; const uint32_t next_level_width = 1 << next_level; - bn254_poseidon_hash_cuda( - &tree[tree_index(level, 0)], &tree[tree_index(next_level, 0)], next_level_width, 2, *constants, config); + poseidon.hash_many(&tree[tree_index(level, 0)], &tree[tree_index(next_level, 0)], next_level_width, 2, 1, config); } } @@ -65,8 +66,8 @@ uint32_t validate_proof( const uint32_t tree_height, const uint32_t* proof_lr, const scalar_t* proof_hash, - PoseidonConstants* constants, - PoseidonConfig config) + Poseidon &poseidon, + SpongeConfig &config) { scalar_t hashes_in[2], hash_out[1], level_hash; level_hash = hash; @@ -79,7 +80,7 @@ uint32_t validate_proof( hashes_in[1] = level_hash; } // next level hash - bn254_poseidon_hash_cuda(hashes_in, hash_out, 1, 2, *constants, config); + poseidon.hash_many(hashes_in, hash_out, 1, 2, 1, config); level_hash = hash_out[0]; } return proof_hash[0] == level_hash; @@ -109,16 +110,15 @@ int main(int argc, char* argv[]) d = d + scalar_t::one(); } std::cout << "Hashing blocks into tree leaves..." << std::endl; - PoseidonConstants constants; - bn254_init_optimized_poseidon_constants_cuda(data_arity, ctx, &constants); - PoseidonConfig config = default_poseidon_config(data_arity + 1); - bn254_poseidon_hash_cuda(data, &tree[tree_index(leaf_level, 0)], tree_width, 4, constants, config); + + Poseidon poseidon(data_arity, ctx); + SpongeConfig config = default_sponge_config(ctx); + poseidon.hash_many(data, &tree[tree_index(leaf_level, 0)], tree_width, data_arity, 1, config); std::cout << "3. Building Merkle tree" << std::endl; - PoseidonConstants tree_constants; - bn254_init_optimized_poseidon_constants_cuda(tree_arity, ctx, &tree_constants); - PoseidonConfig tree_config = default_poseidon_config(tree_arity + 1); - build_tree(tree_height, tree, &tree_constants, tree_config); + Poseidon tree_poseidon(tree_arity, ctx); + SpongeConfig tree_config = default_sponge_config(ctx); + build_tree(tree_height, tree, tree_poseidon, tree_config); std::cout << "4. Generate membership proof" << std::endl; uint32_t position = tree_width - 1; @@ -133,13 +133,13 @@ int main(int argc, char* argv[]) std::cout << "5. Validate the hash membership" << std::endl; uint32_t validated; const scalar_t hash = tree[tree_index(leaf_level, query_position)]; - validated = validate_proof(hash, tree_height, proof_lr, proof_hash, &tree_constants, tree_config); + validated = validate_proof(hash, tree_height, proof_lr, proof_hash, tree_poseidon, tree_config); std::cout << "Validated: " << validated << std::endl; std::cout << "6. Tamper the hash" << std::endl; const scalar_t tampered_hash = hash + scalar_t::one(); - validated = validate_proof(tampered_hash, tree_height, proof_lr, proof_hash, &tree_constants, tree_config); - + validated = validate_proof(tampered_hash, tree_height, proof_lr, proof_hash, tree_poseidon, tree_config); + std::cout << "7. Invalidate tamper hash membership" << std::endl; std::cout << "Validated: " << validated << std::endl; return 0; diff --git a/examples/rust/poseidon/src/main.rs b/examples/rust/poseidon/src/main.rs index fdad0f297..f767bc95f 100644 --- a/examples/rust/poseidon/src/main.rs +++ b/examples/rust/poseidon/src/main.rs @@ -2,7 +2,8 @@ use icicle_bls12_381::curve::ScalarField as F; use icicle_cuda_runtime::device_context::DeviceContext; -use icicle_core::poseidon::{load_optimized_poseidon_constants, poseidon_hash_many, PoseidonConfig}; +use icicle_core::hash::{SpongeHash, SpongeConfig}; +use icicle_core::poseidon::Poseidon; use icicle_core::traits::FieldImpl; use icicle_cuda_runtime::memory::HostSlice; @@ -24,14 +25,14 @@ fn main() { let test_size = 1 << size; println!("Running Icicle Examples: Rust Poseidon Hash"); - let arity = 2u32; + let arity = 2; println!( "---------------------- Loading optimized Poseidon constants for arity={} ------------------------", arity ); let ctx = DeviceContext::default(); - let constants = load_optimized_poseidon_constants::(arity, &ctx).unwrap(); - let config = PoseidonConfig::default(); + let poseidon = Poseidon::load(arity, &ctx).unwrap(); + let config = SpongeConfig::default(); println!( "---------------------- Input size 2^{}={} ------------------------", @@ -45,12 +46,12 @@ fn main() { println!("Executing BLS12-381 Poseidon Hash on device..."); #[cfg(feature = "profile")] let start = Instant::now(); - poseidon_hash_many::( + poseidon.hash_many( input_slice, output_slice, - test_size as u32, - arity as u32, - &constants, + test_size, + arity, + 1, &config, ) .unwrap(); diff --git a/icicle/include/api/babybear.h b/icicle/include/api/babybear.h index e152e4c5f..deaa464ad 100644 --- a/icicle/include/api/babybear.h +++ b/icicle/include/api/babybear.h @@ -9,16 +9,98 @@ #include #include "gpu-utils/device_context.cuh" +#include "merkle-tree/merkle.cuh" +#include "matrix/matrix.cuh" #include "fields/stark_fields/babybear.cuh" #include "ntt/ntt.cuh" #include "vec_ops/vec_ops.cuh" -#include "poseidon/poseidon.cuh" -#include "poseidon/tree/merkle.cuh" #include "poseidon2/poseidon2.cuh" extern "C" cudaError_t babybear_extension_ntt_cuda( const babybear::extension_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, babybear::extension_t* output); +extern "C" cudaError_t babybear_poseidon2_create_cuda( + poseidon2::Poseidon2** poseidon, + unsigned int width, + unsigned int rate, + unsigned int alpha, + unsigned int internal_rounds, + unsigned int external_rounds, + const babybear::scalar_t* round_constants, + const babybear::scalar_t* internal_matrix_diag, + poseidon2::MdsType mds_type, + poseidon2::DiffusionStrategy diffusion, + device_context::DeviceContext& ctx +); + +extern "C" cudaError_t babybear_poseidon2_load_cuda( + poseidon2::Poseidon2** poseidon, + unsigned int width, + unsigned int rate, + poseidon2::MdsType mds_type, + poseidon2::DiffusionStrategy diffusion, + device_context::DeviceContext& ctx +); + +extern "C" cudaError_t babybear_poseidon2_hash_many_cuda( + const poseidon2::Poseidon2* poseidon, + const babybear::scalar_t* inputs, + babybear::scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + hash::SpongeConfig& cfg); + +extern "C" cudaError_t + babybear_poseidon2_delete_cuda(poseidon2::Poseidon2* poseidon, device_context::DeviceContext& ctx); + +extern "C" cudaError_t babybear_build_merkle_tree( + const babybear::scalar_t* leaves, + babybear::scalar_t* digests, + unsigned int height, + unsigned int input_block_len, + const hash::SpongeHasher* compression, + const hash::SpongeHasher* bottom_layer, + const merkle_tree::TreeBuilderConfig& tree_config); + + extern "C" cudaError_t babybear_mmcs_commit_cuda( + const matrix::Matrix* leaves, + unsigned int number_of_inputs, + babybear::scalar_t* digests, + const hash::SpongeHasher* hasher, + const hash::SpongeHasher* compression, + const merkle_tree::TreeBuilderConfig& tree_config); + +extern "C" cudaError_t babybear_mul_cuda( + babybear::scalar_t* vec_a, babybear::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, babybear::scalar_t* result); + +extern "C" cudaError_t babybear_add_cuda( + babybear::scalar_t* vec_a, babybear::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, babybear::scalar_t* result); + +extern "C" cudaError_t babybear_accumulate_cuda( + babybear::scalar_t* vec_a, babybear::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config); + +extern "C" cudaError_t babybear_sub_cuda( + babybear::scalar_t* vec_a, babybear::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, babybear::scalar_t* result); + +extern "C" cudaError_t babybear_transpose_matrix_cuda( + const babybear::scalar_t* input, + uint32_t row_size, + uint32_t column_size, + babybear::scalar_t* output, + device_context::DeviceContext& ctx, + bool on_device, + bool is_async); + +extern "C" cudaError_t babybear_bit_reverse_cuda( + const babybear::scalar_t* input, uint64_t n, vec_ops::BitReverseConfig& config, babybear::scalar_t* output); + + +extern "C" void babybear_generate_scalars(babybear::scalar_t* scalars, int size); + +extern "C" cudaError_t babybear_scalar_convert_montgomery( + babybear::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + extern "C" cudaError_t babybear_initialize_domain( babybear::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); @@ -27,10 +109,10 @@ extern "C" cudaError_t babybear_ntt_cuda( extern "C" cudaError_t babybear_release_domain(device_context::DeviceContext& ctx); -extern "C" void babybear_generate_scalars(babybear::scalar_t* scalars, int size); +extern "C" void babybear_extension_generate_scalars(babybear::extension_t* scalars, int size); -extern "C" cudaError_t babybear_scalar_convert_montgomery( - babybear::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); +extern "C" cudaError_t babybear_extension_scalar_convert_montgomery( + babybear::extension_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); extern "C" cudaError_t babybear_extension_mul_cuda( babybear::extension_t* vec_a, babybear::extension_t* vec_b, int n, vec_ops::VecOpsConfig& config, babybear::extension_t* result); @@ -57,65 +139,4 @@ extern "C" cudaError_t babybear_extension_bit_reverse_cuda( const babybear::extension_t* input, uint64_t n, vec_ops::BitReverseConfig& config, babybear::extension_t* output); -extern "C" void babybear_extension_generate_scalars(babybear::extension_t* scalars, int size); - -extern "C" cudaError_t babybear_extension_scalar_convert_montgomery( - babybear::extension_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); - -extern "C" cudaError_t babybear_mul_cuda( - babybear::scalar_t* vec_a, babybear::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, babybear::scalar_t* result); - -extern "C" cudaError_t babybear_add_cuda( - babybear::scalar_t* vec_a, babybear::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, babybear::scalar_t* result); - -extern "C" cudaError_t babybear_accumulate_cuda( - babybear::scalar_t* vec_a, babybear::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config); - -extern "C" cudaError_t babybear_sub_cuda( - babybear::scalar_t* vec_a, babybear::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, babybear::scalar_t* result); - -extern "C" cudaError_t babybear_transpose_matrix_cuda( - const babybear::scalar_t* input, - uint32_t row_size, - uint32_t column_size, - babybear::scalar_t* output, - device_context::DeviceContext& ctx, - bool on_device, - bool is_async); - -extern "C" cudaError_t babybear_bit_reverse_cuda( - const babybear::scalar_t* input, uint64_t n, vec_ops::BitReverseConfig& config, babybear::scalar_t* output); - - -extern "C" cudaError_t babybear_create_poseidon2_constants_cuda( - int width, - int alpha, - int internal_rounds, - int external_rounds, - const babybear::scalar_t* round_constants, - const babybear::scalar_t* internal_matrix_diag, - poseidon2::MdsType mds_type, - poseidon2::DiffusionStrategy diffusion, - device_context::DeviceContext& ctx, - poseidon2::Poseidon2Constants* poseidon_constants); - -extern "C" cudaError_t babybear_init_poseidon2_constants_cuda( - int width, - poseidon2::MdsType mds_type, - poseidon2::DiffusionStrategy diffusion, - device_context::DeviceContext& ctx, - poseidon2::Poseidon2Constants* poseidon_constants); - -extern "C" cudaError_t babybear_poseidon2_hash_cuda( - const babybear::scalar_t* input, - babybear::scalar_t* output, - int number_of_states, - int width, - const poseidon2::Poseidon2Constants& constants, - poseidon2::Poseidon2Config& config); - -extern "C" cudaError_t babybear_release_poseidon2_constants_cuda( - poseidon2::Poseidon2Constants* constants, - device_context::DeviceContext& ctx); - #endif \ No newline at end of file diff --git a/icicle/include/api/bls12_377.h b/icicle/include/api/bls12_377.h index f6c2a7c39..adde436f9 100644 --- a/icicle/include/api/bls12_377.h +++ b/icicle/include/api/bls12_377.h @@ -9,26 +9,13 @@ #include #include "gpu-utils/device_context.cuh" +#include "merkle-tree/merkle.cuh" +#include "matrix/matrix.cuh" #include "curves/params/bls12_377.cuh" #include "ntt/ntt.cuh" #include "msm/msm.cuh" #include "vec_ops/vec_ops.cuh" #include "poseidon/poseidon.cuh" -#include "poseidon/tree/merkle.cuh" - -extern "C" bool bls12_377_g2_eq(bls12_377::g2_projective_t* point1, bls12_377::g2_projective_t* point2); - -extern "C" void bls12_377_g2_to_affine(bls12_377::g2_projective_t* point, bls12_377::g2_affine_t* point_out); - -extern "C" void bls12_377_g2_generate_projective_points(bls12_377::g2_projective_t* points, int size); - -extern "C" void bls12_377_g2_generate_affine_points(bls12_377::g2_affine_t* points, int size); - -extern "C" cudaError_t bls12_377_g2_affine_convert_montgomery( - bls12_377::g2_affine_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); - -extern "C" cudaError_t bls12_377_g2_projective_convert_montgomery( - bls12_377::g2_projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); extern "C" cudaError_t bls12_377_g2_precompute_msm_bases_cuda( bls12_377::g2_affine_t* bases, @@ -48,6 +35,20 @@ extern "C" cudaError_t bls12_377_precompute_msm_bases_cuda( extern "C" cudaError_t bls12_377_msm_cuda( const bls12_377::scalar_t* scalars, const bls12_377::affine_t* points, int msm_size, msm::MSMConfig& config, bls12_377::projective_t* out); +extern "C" bool bls12_377_g2_eq(bls12_377::g2_projective_t* point1, bls12_377::g2_projective_t* point2); + +extern "C" void bls12_377_g2_to_affine(bls12_377::g2_projective_t* point, bls12_377::g2_affine_t* point_out); + +extern "C" void bls12_377_g2_generate_projective_points(bls12_377::g2_projective_t* points, int size); + +extern "C" void bls12_377_g2_generate_affine_points(bls12_377::g2_affine_t* points, int size); + +extern "C" cudaError_t bls12_377_g2_affine_convert_montgomery( + bls12_377::g2_affine_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + +extern "C" cudaError_t bls12_377_g2_projective_convert_montgomery( + bls12_377::g2_projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + extern "C" cudaError_t bls12_377_ecntt_cuda( const bls12_377::projective_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bls12_377::projective_t* output); @@ -65,18 +66,52 @@ extern "C" cudaError_t bls12_377_affine_convert_montgomery( extern "C" cudaError_t bls12_377_projective_convert_montgomery( bls12_377::projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); -extern "C" cudaError_t bls12_377_initialize_domain( - bls12_377::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); - -extern "C" cudaError_t bls12_377_ntt_cuda( - const bls12_377::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bls12_377::scalar_t* output); - -extern "C" cudaError_t bls12_377_release_domain(device_context::DeviceContext& ctx); - -extern "C" void bls12_377_generate_scalars(bls12_377::scalar_t* scalars, int size); +extern "C" cudaError_t bls12_377_build_merkle_tree( + const bls12_377::scalar_t* leaves, + bls12_377::scalar_t* digests, + unsigned int height, + unsigned int input_block_len, + const hash::SpongeHasher* compression, + const hash::SpongeHasher* bottom_layer, + const merkle_tree::TreeBuilderConfig& tree_config); + + extern "C" cudaError_t bls12_377_mmcs_commit_cuda( + const matrix::Matrix* leaves, + unsigned int number_of_inputs, + bls12_377::scalar_t* digests, + const hash::SpongeHasher* hasher, + const hash::SpongeHasher* compression, + const merkle_tree::TreeBuilderConfig& tree_config); + +extern "C" cudaError_t bls12_377_poseidon_create_cuda( + poseidon::Poseidon** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const bls12_377::scalar_t* round_constants, + const bls12_377::scalar_t* mds_matrix, + const bls12_377::scalar_t* non_sparse_matrix, + const bls12_377::scalar_t* sparse_matrices, + const bls12_377::scalar_t domain_tag, + device_context::DeviceContext& ctx); + +extern "C" cudaError_t bls12_377_poseidon_load_cuda( + poseidon::Poseidon** poseidon, + unsigned int arity, + device_context::DeviceContext& ctx); + +extern "C" cudaError_t bls12_377_poseidon_hash_many_cuda( + const poseidon::Poseidon* poseidon, + const bls12_377::scalar_t* inputs, + bls12_377::scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + hash::SpongeConfig& cfg); -extern "C" cudaError_t bls12_377_scalar_convert_montgomery( - bls12_377::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); +extern "C" cudaError_t + bls12_377_poseidon_delete_cuda(poseidon::Poseidon* poseidon); extern "C" cudaError_t bls12_377_mul_cuda( bls12_377::scalar_t* vec_a, bls12_377::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, bls12_377::scalar_t* result); @@ -103,31 +138,17 @@ extern "C" cudaError_t bls12_377_bit_reverse_cuda( const bls12_377::scalar_t* input, uint64_t n, vec_ops::BitReverseConfig& config, bls12_377::scalar_t* output); -extern "C" cudaError_t bls12_377_create_optimized_poseidon_constants_cuda( - int arity, - int full_rounds_half, - int partial_rounds, - const bls12_377::scalar_t* constants, - device_context::DeviceContext& ctx, - poseidon::PoseidonConstants* poseidon_constants); +extern "C" void bls12_377_generate_scalars(bls12_377::scalar_t* scalars, int size); -extern "C" cudaError_t bls12_377_init_optimized_poseidon_constants_cuda( - int arity, device_context::DeviceContext& ctx, poseidon::PoseidonConstants* constants); +extern "C" cudaError_t bls12_377_scalar_convert_montgomery( + bls12_377::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); -extern "C" cudaError_t bls12_377_poseidon_hash_cuda( - bls12_377::scalar_t* input, - bls12_377::scalar_t* output, - int number_of_states, - int arity, - const poseidon::PoseidonConstants& constants, - poseidon::PoseidonConfig& config); +extern "C" cudaError_t bls12_377_initialize_domain( + bls12_377::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); -extern "C" cudaError_t bls12_377_build_poseidon_merkle_tree( - const bls12_377::scalar_t* leaves, - bls12_377::scalar_t* digests, - uint32_t height, - int arity, - poseidon::PoseidonConstants& constants, - merkle::TreeBuilderConfig& config); +extern "C" cudaError_t bls12_377_ntt_cuda( + const bls12_377::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bls12_377::scalar_t* output); + +extern "C" cudaError_t bls12_377_release_domain(device_context::DeviceContext& ctx); #endif \ No newline at end of file diff --git a/icicle/include/api/bls12_381.h b/icicle/include/api/bls12_381.h index 0a3e2904d..35b615c3a 100644 --- a/icicle/include/api/bls12_381.h +++ b/icicle/include/api/bls12_381.h @@ -9,26 +9,13 @@ #include #include "gpu-utils/device_context.cuh" +#include "merkle-tree/merkle.cuh" +#include "matrix/matrix.cuh" #include "curves/params/bls12_381.cuh" #include "ntt/ntt.cuh" #include "msm/msm.cuh" #include "vec_ops/vec_ops.cuh" #include "poseidon/poseidon.cuh" -#include "poseidon/tree/merkle.cuh" - -extern "C" bool bls12_381_g2_eq(bls12_381::g2_projective_t* point1, bls12_381::g2_projective_t* point2); - -extern "C" void bls12_381_g2_to_affine(bls12_381::g2_projective_t* point, bls12_381::g2_affine_t* point_out); - -extern "C" void bls12_381_g2_generate_projective_points(bls12_381::g2_projective_t* points, int size); - -extern "C" void bls12_381_g2_generate_affine_points(bls12_381::g2_affine_t* points, int size); - -extern "C" cudaError_t bls12_381_g2_affine_convert_montgomery( - bls12_381::g2_affine_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); - -extern "C" cudaError_t bls12_381_g2_projective_convert_montgomery( - bls12_381::g2_projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); extern "C" cudaError_t bls12_381_g2_precompute_msm_bases_cuda( bls12_381::g2_affine_t* bases, @@ -48,6 +35,20 @@ extern "C" cudaError_t bls12_381_precompute_msm_bases_cuda( extern "C" cudaError_t bls12_381_msm_cuda( const bls12_381::scalar_t* scalars, const bls12_381::affine_t* points, int msm_size, msm::MSMConfig& config, bls12_381::projective_t* out); +extern "C" bool bls12_381_g2_eq(bls12_381::g2_projective_t* point1, bls12_381::g2_projective_t* point2); + +extern "C" void bls12_381_g2_to_affine(bls12_381::g2_projective_t* point, bls12_381::g2_affine_t* point_out); + +extern "C" void bls12_381_g2_generate_projective_points(bls12_381::g2_projective_t* points, int size); + +extern "C" void bls12_381_g2_generate_affine_points(bls12_381::g2_affine_t* points, int size); + +extern "C" cudaError_t bls12_381_g2_affine_convert_montgomery( + bls12_381::g2_affine_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + +extern "C" cudaError_t bls12_381_g2_projective_convert_montgomery( + bls12_381::g2_projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + extern "C" cudaError_t bls12_381_ecntt_cuda( const bls12_381::projective_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bls12_381::projective_t* output); @@ -65,18 +66,52 @@ extern "C" cudaError_t bls12_381_affine_convert_montgomery( extern "C" cudaError_t bls12_381_projective_convert_montgomery( bls12_381::projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); -extern "C" cudaError_t bls12_381_initialize_domain( - bls12_381::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); - -extern "C" cudaError_t bls12_381_ntt_cuda( - const bls12_381::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bls12_381::scalar_t* output); - -extern "C" cudaError_t bls12_381_release_domain(device_context::DeviceContext& ctx); - -extern "C" void bls12_381_generate_scalars(bls12_381::scalar_t* scalars, int size); +extern "C" cudaError_t bls12_381_build_merkle_tree( + const bls12_381::scalar_t* leaves, + bls12_381::scalar_t* digests, + unsigned int height, + unsigned int input_block_len, + const hash::SpongeHasher* compression, + const hash::SpongeHasher* bottom_layer, + const merkle_tree::TreeBuilderConfig& tree_config); + + extern "C" cudaError_t bls12_381_mmcs_commit_cuda( + const matrix::Matrix* leaves, + unsigned int number_of_inputs, + bls12_381::scalar_t* digests, + const hash::SpongeHasher* hasher, + const hash::SpongeHasher* compression, + const merkle_tree::TreeBuilderConfig& tree_config); + +extern "C" cudaError_t bls12_381_poseidon_create_cuda( + poseidon::Poseidon** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const bls12_381::scalar_t* round_constants, + const bls12_381::scalar_t* mds_matrix, + const bls12_381::scalar_t* non_sparse_matrix, + const bls12_381::scalar_t* sparse_matrices, + const bls12_381::scalar_t domain_tag, + device_context::DeviceContext& ctx); + +extern "C" cudaError_t bls12_381_poseidon_load_cuda( + poseidon::Poseidon** poseidon, + unsigned int arity, + device_context::DeviceContext& ctx); + +extern "C" cudaError_t bls12_381_poseidon_hash_many_cuda( + const poseidon::Poseidon* poseidon, + const bls12_381::scalar_t* inputs, + bls12_381::scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + hash::SpongeConfig& cfg); -extern "C" cudaError_t bls12_381_scalar_convert_montgomery( - bls12_381::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); +extern "C" cudaError_t + bls12_381_poseidon_delete_cuda(poseidon::Poseidon* poseidon); extern "C" cudaError_t bls12_381_mul_cuda( bls12_381::scalar_t* vec_a, bls12_381::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, bls12_381::scalar_t* result); @@ -103,31 +138,17 @@ extern "C" cudaError_t bls12_381_bit_reverse_cuda( const bls12_381::scalar_t* input, uint64_t n, vec_ops::BitReverseConfig& config, bls12_381::scalar_t* output); -extern "C" cudaError_t bls12_381_create_optimized_poseidon_constants_cuda( - int arity, - int full_rounds_half, - int partial_rounds, - const bls12_381::scalar_t* constants, - device_context::DeviceContext& ctx, - poseidon::PoseidonConstants* poseidon_constants); +extern "C" void bls12_381_generate_scalars(bls12_381::scalar_t* scalars, int size); -extern "C" cudaError_t bls12_381_init_optimized_poseidon_constants_cuda( - int arity, device_context::DeviceContext& ctx, poseidon::PoseidonConstants* constants); +extern "C" cudaError_t bls12_381_scalar_convert_montgomery( + bls12_381::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); -extern "C" cudaError_t bls12_381_poseidon_hash_cuda( - bls12_381::scalar_t* input, - bls12_381::scalar_t* output, - int number_of_states, - int arity, - const poseidon::PoseidonConstants& constants, - poseidon::PoseidonConfig& config); +extern "C" cudaError_t bls12_381_initialize_domain( + bls12_381::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); -extern "C" cudaError_t bls12_381_build_poseidon_merkle_tree( - const bls12_381::scalar_t* leaves, - bls12_381::scalar_t* digests, - uint32_t height, - int arity, - poseidon::PoseidonConstants& constants, - merkle::TreeBuilderConfig& config); +extern "C" cudaError_t bls12_381_ntt_cuda( + const bls12_381::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bls12_381::scalar_t* output); + +extern "C" cudaError_t bls12_381_release_domain(device_context::DeviceContext& ctx); #endif \ No newline at end of file diff --git a/icicle/include/api/bn254.h b/icicle/include/api/bn254.h index c11b8a30c..f3a9cb7ca 100644 --- a/icicle/include/api/bn254.h +++ b/icicle/include/api/bn254.h @@ -9,28 +9,15 @@ #include #include "gpu-utils/device_context.cuh" +#include "merkle-tree/merkle.cuh" +#include "matrix/matrix.cuh" #include "curves/params/bn254.cuh" #include "ntt/ntt.cuh" #include "msm/msm.cuh" #include "vec_ops/vec_ops.cuh" #include "poseidon/poseidon.cuh" -#include "poseidon/tree/merkle.cuh" #include "poseidon2/poseidon2.cuh" -extern "C" bool bn254_g2_eq(bn254::g2_projective_t* point1, bn254::g2_projective_t* point2); - -extern "C" void bn254_g2_to_affine(bn254::g2_projective_t* point, bn254::g2_affine_t* point_out); - -extern "C" void bn254_g2_generate_projective_points(bn254::g2_projective_t* points, int size); - -extern "C" void bn254_g2_generate_affine_points(bn254::g2_affine_t* points, int size); - -extern "C" cudaError_t bn254_g2_affine_convert_montgomery( - bn254::g2_affine_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); - -extern "C" cudaError_t bn254_g2_projective_convert_montgomery( - bn254::g2_projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); - extern "C" cudaError_t bn254_g2_precompute_msm_bases_cuda( bn254::g2_affine_t* bases, int msm_size, @@ -49,6 +36,20 @@ extern "C" cudaError_t bn254_precompute_msm_bases_cuda( extern "C" cudaError_t bn254_msm_cuda( const bn254::scalar_t* scalars, const bn254::affine_t* points, int msm_size, msm::MSMConfig& config, bn254::projective_t* out); +extern "C" bool bn254_g2_eq(bn254::g2_projective_t* point1, bn254::g2_projective_t* point2); + +extern "C" void bn254_g2_to_affine(bn254::g2_projective_t* point, bn254::g2_affine_t* point_out); + +extern "C" void bn254_g2_generate_projective_points(bn254::g2_projective_t* points, int size); + +extern "C" void bn254_g2_generate_affine_points(bn254::g2_affine_t* points, int size); + +extern "C" cudaError_t bn254_g2_affine_convert_montgomery( + bn254::g2_affine_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + +extern "C" cudaError_t bn254_g2_projective_convert_montgomery( + bn254::g2_projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + extern "C" cudaError_t bn254_ecntt_cuda( const bn254::projective_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bn254::projective_t* output); @@ -66,18 +67,87 @@ extern "C" cudaError_t bn254_affine_convert_montgomery( extern "C" cudaError_t bn254_projective_convert_montgomery( bn254::projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); -extern "C" cudaError_t bn254_initialize_domain( - bn254::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); +extern "C" cudaError_t bn254_poseidon2_create_cuda( + poseidon2::Poseidon2** poseidon, + unsigned int width, + unsigned int rate, + unsigned int alpha, + unsigned int internal_rounds, + unsigned int external_rounds, + const bn254::scalar_t* round_constants, + const bn254::scalar_t* internal_matrix_diag, + poseidon2::MdsType mds_type, + poseidon2::DiffusionStrategy diffusion, + device_context::DeviceContext& ctx +); -extern "C" cudaError_t bn254_ntt_cuda( - const bn254::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bn254::scalar_t* output); +extern "C" cudaError_t bn254_poseidon2_load_cuda( + poseidon2::Poseidon2** poseidon, + unsigned int width, + unsigned int rate, + poseidon2::MdsType mds_type, + poseidon2::DiffusionStrategy diffusion, + device_context::DeviceContext& ctx +); -extern "C" cudaError_t bn254_release_domain(device_context::DeviceContext& ctx); +extern "C" cudaError_t bn254_poseidon2_hash_many_cuda( + const poseidon2::Poseidon2* poseidon, + const bn254::scalar_t* inputs, + bn254::scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + hash::SpongeConfig& cfg); -extern "C" void bn254_generate_scalars(bn254::scalar_t* scalars, int size); +extern "C" cudaError_t + bn254_poseidon2_delete_cuda(poseidon2::Poseidon2* poseidon, device_context::DeviceContext& ctx); -extern "C" cudaError_t bn254_scalar_convert_montgomery( - bn254::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); +extern "C" cudaError_t bn254_build_merkle_tree( + const bn254::scalar_t* leaves, + bn254::scalar_t* digests, + unsigned int height, + unsigned int input_block_len, + const hash::SpongeHasher* compression, + const hash::SpongeHasher* bottom_layer, + const merkle_tree::TreeBuilderConfig& tree_config); + + extern "C" cudaError_t bn254_mmcs_commit_cuda( + const matrix::Matrix* leaves, + unsigned int number_of_inputs, + bn254::scalar_t* digests, + const hash::SpongeHasher* hasher, + const hash::SpongeHasher* compression, + const merkle_tree::TreeBuilderConfig& tree_config); + +extern "C" cudaError_t bn254_poseidon_create_cuda( + poseidon::Poseidon** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const bn254::scalar_t* round_constants, + const bn254::scalar_t* mds_matrix, + const bn254::scalar_t* non_sparse_matrix, + const bn254::scalar_t* sparse_matrices, + const bn254::scalar_t domain_tag, + device_context::DeviceContext& ctx); + +extern "C" cudaError_t bn254_poseidon_load_cuda( + poseidon::Poseidon** poseidon, + unsigned int arity, + device_context::DeviceContext& ctx); + +extern "C" cudaError_t bn254_poseidon_hash_many_cuda( + const poseidon::Poseidon* poseidon, + const bn254::scalar_t* inputs, + bn254::scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + hash::SpongeConfig& cfg); + +extern "C" cudaError_t + bn254_poseidon_delete_cuda(poseidon::Poseidon* poseidon); extern "C" cudaError_t bn254_mul_cuda( bn254::scalar_t* vec_a, bn254::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, bn254::scalar_t* result); @@ -104,62 +174,17 @@ extern "C" cudaError_t bn254_bit_reverse_cuda( const bn254::scalar_t* input, uint64_t n, vec_ops::BitReverseConfig& config, bn254::scalar_t* output); -extern "C" cudaError_t bn254_create_poseidon2_constants_cuda( - int width, - int alpha, - int internal_rounds, - int external_rounds, - const bn254::scalar_t* round_constants, - const bn254::scalar_t* internal_matrix_diag, - poseidon2::MdsType mds_type, - poseidon2::DiffusionStrategy diffusion, - device_context::DeviceContext& ctx, - poseidon2::Poseidon2Constants* poseidon_constants); - -extern "C" cudaError_t bn254_init_poseidon2_constants_cuda( - int width, - poseidon2::MdsType mds_type, - poseidon2::DiffusionStrategy diffusion, - device_context::DeviceContext& ctx, - poseidon2::Poseidon2Constants* poseidon_constants); - -extern "C" cudaError_t bn254_poseidon2_hash_cuda( - const bn254::scalar_t* input, - bn254::scalar_t* output, - int number_of_states, - int width, - const poseidon2::Poseidon2Constants& constants, - poseidon2::Poseidon2Config& config); - -extern "C" cudaError_t bn254_release_poseidon2_constants_cuda( - poseidon2::Poseidon2Constants* constants, - device_context::DeviceContext& ctx); +extern "C" void bn254_generate_scalars(bn254::scalar_t* scalars, int size); -extern "C" cudaError_t bn254_create_optimized_poseidon_constants_cuda( - int arity, - int full_rounds_half, - int partial_rounds, - const bn254::scalar_t* constants, - device_context::DeviceContext& ctx, - poseidon::PoseidonConstants* poseidon_constants); +extern "C" cudaError_t bn254_scalar_convert_montgomery( + bn254::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); -extern "C" cudaError_t bn254_init_optimized_poseidon_constants_cuda( - int arity, device_context::DeviceContext& ctx, poseidon::PoseidonConstants* constants); +extern "C" cudaError_t bn254_initialize_domain( + bn254::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); -extern "C" cudaError_t bn254_poseidon_hash_cuda( - bn254::scalar_t* input, - bn254::scalar_t* output, - int number_of_states, - int arity, - const poseidon::PoseidonConstants& constants, - poseidon::PoseidonConfig& config); +extern "C" cudaError_t bn254_ntt_cuda( + const bn254::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bn254::scalar_t* output); -extern "C" cudaError_t bn254_build_poseidon_merkle_tree( - const bn254::scalar_t* leaves, - bn254::scalar_t* digests, - uint32_t height, - int arity, - poseidon::PoseidonConstants& constants, - merkle::TreeBuilderConfig& config); +extern "C" cudaError_t bn254_release_domain(device_context::DeviceContext& ctx); #endif \ No newline at end of file diff --git a/icicle/include/api/bw6_761.h b/icicle/include/api/bw6_761.h index 931d2d6c2..8d290189d 100644 --- a/icicle/include/api/bw6_761.h +++ b/icicle/include/api/bw6_761.h @@ -9,26 +9,13 @@ #include #include "gpu-utils/device_context.cuh" +#include "merkle-tree/merkle.cuh" +#include "matrix/matrix.cuh" #include "curves/params/bw6_761.cuh" #include "ntt/ntt.cuh" #include "msm/msm.cuh" #include "vec_ops/vec_ops.cuh" #include "poseidon/poseidon.cuh" -#include "poseidon/tree/merkle.cuh" - -extern "C" bool bw6_761_g2_eq(bw6_761::g2_projective_t* point1, bw6_761::g2_projective_t* point2); - -extern "C" void bw6_761_g2_to_affine(bw6_761::g2_projective_t* point, bw6_761::g2_affine_t* point_out); - -extern "C" void bw6_761_g2_generate_projective_points(bw6_761::g2_projective_t* points, int size); - -extern "C" void bw6_761_g2_generate_affine_points(bw6_761::g2_affine_t* points, int size); - -extern "C" cudaError_t bw6_761_g2_affine_convert_montgomery( - bw6_761::g2_affine_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); - -extern "C" cudaError_t bw6_761_g2_projective_convert_montgomery( - bw6_761::g2_projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); extern "C" cudaError_t bw6_761_g2_precompute_msm_bases_cuda( bw6_761::g2_affine_t* bases, @@ -48,6 +35,20 @@ extern "C" cudaError_t bw6_761_precompute_msm_bases_cuda( extern "C" cudaError_t bw6_761_msm_cuda( const bw6_761::scalar_t* scalars, const bw6_761::affine_t* points, int msm_size, msm::MSMConfig& config, bw6_761::projective_t* out); +extern "C" bool bw6_761_g2_eq(bw6_761::g2_projective_t* point1, bw6_761::g2_projective_t* point2); + +extern "C" void bw6_761_g2_to_affine(bw6_761::g2_projective_t* point, bw6_761::g2_affine_t* point_out); + +extern "C" void bw6_761_g2_generate_projective_points(bw6_761::g2_projective_t* points, int size); + +extern "C" void bw6_761_g2_generate_affine_points(bw6_761::g2_affine_t* points, int size); + +extern "C" cudaError_t bw6_761_g2_affine_convert_montgomery( + bw6_761::g2_affine_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + +extern "C" cudaError_t bw6_761_g2_projective_convert_montgomery( + bw6_761::g2_projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + extern "C" cudaError_t bw6_761_ecntt_cuda( const bw6_761::projective_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bw6_761::projective_t* output); @@ -65,18 +66,52 @@ extern "C" cudaError_t bw6_761_affine_convert_montgomery( extern "C" cudaError_t bw6_761_projective_convert_montgomery( bw6_761::projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); -extern "C" cudaError_t bw6_761_initialize_domain( - bw6_761::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); - -extern "C" cudaError_t bw6_761_ntt_cuda( - const bw6_761::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bw6_761::scalar_t* output); - -extern "C" cudaError_t bw6_761_release_domain(device_context::DeviceContext& ctx); - -extern "C" void bw6_761_generate_scalars(bw6_761::scalar_t* scalars, int size); +extern "C" cudaError_t bw6_761_build_merkle_tree( + const bw6_761::scalar_t* leaves, + bw6_761::scalar_t* digests, + unsigned int height, + unsigned int input_block_len, + const hash::SpongeHasher* compression, + const hash::SpongeHasher* bottom_layer, + const merkle_tree::TreeBuilderConfig& tree_config); + + extern "C" cudaError_t bw6_761_mmcs_commit_cuda( + const matrix::Matrix* leaves, + unsigned int number_of_inputs, + bw6_761::scalar_t* digests, + const hash::SpongeHasher* hasher, + const hash::SpongeHasher* compression, + const merkle_tree::TreeBuilderConfig& tree_config); + +extern "C" cudaError_t bw6_761_poseidon_create_cuda( + poseidon::Poseidon** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const bw6_761::scalar_t* round_constants, + const bw6_761::scalar_t* mds_matrix, + const bw6_761::scalar_t* non_sparse_matrix, + const bw6_761::scalar_t* sparse_matrices, + const bw6_761::scalar_t domain_tag, + device_context::DeviceContext& ctx); + +extern "C" cudaError_t bw6_761_poseidon_load_cuda( + poseidon::Poseidon** poseidon, + unsigned int arity, + device_context::DeviceContext& ctx); + +extern "C" cudaError_t bw6_761_poseidon_hash_many_cuda( + const poseidon::Poseidon* poseidon, + const bw6_761::scalar_t* inputs, + bw6_761::scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + hash::SpongeConfig& cfg); -extern "C" cudaError_t bw6_761_scalar_convert_montgomery( - bw6_761::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); +extern "C" cudaError_t + bw6_761_poseidon_delete_cuda(poseidon::Poseidon* poseidon); extern "C" cudaError_t bw6_761_mul_cuda( bw6_761::scalar_t* vec_a, bw6_761::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, bw6_761::scalar_t* result); @@ -103,31 +138,17 @@ extern "C" cudaError_t bw6_761_bit_reverse_cuda( const bw6_761::scalar_t* input, uint64_t n, vec_ops::BitReverseConfig& config, bw6_761::scalar_t* output); -extern "C" cudaError_t bw6_761_create_optimized_poseidon_constants_cuda( - int arity, - int full_rounds_half, - int partial_rounds, - const bw6_761::scalar_t* constants, - device_context::DeviceContext& ctx, - poseidon::PoseidonConstants* poseidon_constants); +extern "C" void bw6_761_generate_scalars(bw6_761::scalar_t* scalars, int size); -extern "C" cudaError_t bw6_761_init_optimized_poseidon_constants_cuda( - int arity, device_context::DeviceContext& ctx, poseidon::PoseidonConstants* constants); +extern "C" cudaError_t bw6_761_scalar_convert_montgomery( + bw6_761::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); -extern "C" cudaError_t bw6_761_poseidon_hash_cuda( - bw6_761::scalar_t* input, - bw6_761::scalar_t* output, - int number_of_states, - int arity, - const poseidon::PoseidonConstants& constants, - poseidon::PoseidonConfig& config); +extern "C" cudaError_t bw6_761_initialize_domain( + bw6_761::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); -extern "C" cudaError_t bw6_761_build_poseidon_merkle_tree( - const bw6_761::scalar_t* leaves, - bw6_761::scalar_t* digests, - uint32_t height, - int arity, - poseidon::PoseidonConstants& constants, - merkle::TreeBuilderConfig& config); +extern "C" cudaError_t bw6_761_ntt_cuda( + const bw6_761::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, bw6_761::scalar_t* output); + +extern "C" cudaError_t bw6_761_release_domain(device_context::DeviceContext& ctx); #endif \ No newline at end of file diff --git a/icicle/include/api/grumpkin.h b/icicle/include/api/grumpkin.h index 5690100cd..d40a08827 100644 --- a/icicle/include/api/grumpkin.h +++ b/icicle/include/api/grumpkin.h @@ -9,11 +9,12 @@ #include #include "gpu-utils/device_context.cuh" +#include "merkle-tree/merkle.cuh" +#include "matrix/matrix.cuh" #include "curves/params/grumpkin.cuh" #include "msm/msm.cuh" #include "vec_ops/vec_ops.cuh" #include "poseidon/poseidon.cuh" -#include "poseidon/tree/merkle.cuh" extern "C" cudaError_t grumpkin_precompute_msm_bases_cuda( grumpkin::affine_t* bases, @@ -38,10 +39,52 @@ extern "C" cudaError_t grumpkin_affine_convert_montgomery( extern "C" cudaError_t grumpkin_projective_convert_montgomery( grumpkin::projective_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); -extern "C" void grumpkin_generate_scalars(grumpkin::scalar_t* scalars, int size); +extern "C" cudaError_t grumpkin_build_merkle_tree( + const grumpkin::scalar_t* leaves, + grumpkin::scalar_t* digests, + unsigned int height, + unsigned int input_block_len, + const hash::SpongeHasher* compression, + const hash::SpongeHasher* bottom_layer, + const merkle_tree::TreeBuilderConfig& tree_config); + + extern "C" cudaError_t grumpkin_mmcs_commit_cuda( + const matrix::Matrix* leaves, + unsigned int number_of_inputs, + grumpkin::scalar_t* digests, + const hash::SpongeHasher* hasher, + const hash::SpongeHasher* compression, + const merkle_tree::TreeBuilderConfig& tree_config); + +extern "C" cudaError_t grumpkin_poseidon_create_cuda( + poseidon::Poseidon** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const grumpkin::scalar_t* round_constants, + const grumpkin::scalar_t* mds_matrix, + const grumpkin::scalar_t* non_sparse_matrix, + const grumpkin::scalar_t* sparse_matrices, + const grumpkin::scalar_t domain_tag, + device_context::DeviceContext& ctx); + +extern "C" cudaError_t grumpkin_poseidon_load_cuda( + poseidon::Poseidon** poseidon, + unsigned int arity, + device_context::DeviceContext& ctx); + +extern "C" cudaError_t grumpkin_poseidon_hash_many_cuda( + const poseidon::Poseidon* poseidon, + const grumpkin::scalar_t* inputs, + grumpkin::scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + hash::SpongeConfig& cfg); -extern "C" cudaError_t grumpkin_scalar_convert_montgomery( - grumpkin::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); +extern "C" cudaError_t + grumpkin_poseidon_delete_cuda(poseidon::Poseidon* poseidon); extern "C" cudaError_t grumpkin_mul_cuda( grumpkin::scalar_t* vec_a, grumpkin::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, grumpkin::scalar_t* result); @@ -68,31 +111,9 @@ extern "C" cudaError_t grumpkin_bit_reverse_cuda( const grumpkin::scalar_t* input, uint64_t n, vec_ops::BitReverseConfig& config, grumpkin::scalar_t* output); -extern "C" cudaError_t grumpkin_create_optimized_poseidon_constants_cuda( - int arity, - int full_rounds_half, - int partial_rounds, - const grumpkin::scalar_t* constants, - device_context::DeviceContext& ctx, - poseidon::PoseidonConstants* poseidon_constants); - -extern "C" cudaError_t grumpkin_init_optimized_poseidon_constants_cuda( - int arity, device_context::DeviceContext& ctx, poseidon::PoseidonConstants* constants); - -extern "C" cudaError_t grumpkin_poseidon_hash_cuda( - grumpkin::scalar_t* input, - grumpkin::scalar_t* output, - int number_of_states, - int arity, - const poseidon::PoseidonConstants& constants, - poseidon::PoseidonConfig& config); +extern "C" void grumpkin_generate_scalars(grumpkin::scalar_t* scalars, int size); -extern "C" cudaError_t grumpkin_build_poseidon_merkle_tree( - const grumpkin::scalar_t* leaves, - grumpkin::scalar_t* digests, - uint32_t height, - int arity, - poseidon::PoseidonConstants& constants, - merkle::TreeBuilderConfig& config); +extern "C" cudaError_t grumpkin_scalar_convert_montgomery( + grumpkin::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); #endif \ No newline at end of file diff --git a/icicle/include/api/m31.h b/icicle/include/api/m31.h index 9105cf9e7..a0e38be6e 100644 --- a/icicle/include/api/m31.h +++ b/icicle/include/api/m31.h @@ -9,67 +9,86 @@ #include #include "gpu-utils/device_context.cuh" +#include "merkle-tree/merkle.cuh" +#include "matrix/matrix.cuh" #include "fields/stark_fields/m31.cuh" #include "vec_ops/vec_ops.cuh" -extern "C" void m31_generate_scalars(m31::scalar_t* scalars, int size); - -extern "C" cudaError_t m31_scalar_convert_montgomery( - m31::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); +extern "C" cudaError_t m31_build_merkle_tree( + const m31::scalar_t* leaves, + m31::scalar_t* digests, + unsigned int height, + unsigned int input_block_len, + const hash::SpongeHasher* compression, + const hash::SpongeHasher* bottom_layer, + const merkle_tree::TreeBuilderConfig& tree_config); + + extern "C" cudaError_t m31_mmcs_commit_cuda( + const matrix::Matrix* leaves, + unsigned int number_of_inputs, + m31::scalar_t* digests, + const hash::SpongeHasher* hasher, + const hash::SpongeHasher* compression, + const merkle_tree::TreeBuilderConfig& tree_config); -extern "C" cudaError_t m31_extension_mul_cuda( - m31::extension_t* vec_a, m31::extension_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::extension_t* result); +extern "C" cudaError_t m31_mul_cuda( + m31::scalar_t* vec_a, m31::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::scalar_t* result); -extern "C" cudaError_t m31_extension_add_cuda( - m31::extension_t* vec_a, m31::extension_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::extension_t* result); +extern "C" cudaError_t m31_add_cuda( + m31::scalar_t* vec_a, m31::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::scalar_t* result); -extern "C" cudaError_t m31_extension_accumulate_cuda( - m31::extension_t* vec_a, m31::extension_t* vec_b, int n, vec_ops::VecOpsConfig& config); +extern "C" cudaError_t m31_accumulate_cuda( + m31::scalar_t* vec_a, m31::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config); -extern "C" cudaError_t m31_extension_sub_cuda( - m31::extension_t* vec_a, m31::extension_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::extension_t* result); +extern "C" cudaError_t m31_sub_cuda( + m31::scalar_t* vec_a, m31::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::scalar_t* result); -extern "C" cudaError_t m31_extension_transpose_matrix_cuda( - const m31::extension_t* input, +extern "C" cudaError_t m31_transpose_matrix_cuda( + const m31::scalar_t* input, uint32_t row_size, uint32_t column_size, - m31::extension_t* output, + m31::scalar_t* output, device_context::DeviceContext& ctx, bool on_device, bool is_async); -extern "C" cudaError_t m31_extension_bit_reverse_cuda( - const m31::extension_t* input, uint64_t n, vec_ops::BitReverseConfig& config, m31::extension_t* output); +extern "C" cudaError_t m31_bit_reverse_cuda( + const m31::scalar_t* input, uint64_t n, vec_ops::BitReverseConfig& config, m31::scalar_t* output); +extern "C" void m31_generate_scalars(m31::scalar_t* scalars, int size); + +extern "C" cudaError_t m31_scalar_convert_montgomery( + m31::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + extern "C" void m31_extension_generate_scalars(m31::extension_t* scalars, int size); extern "C" cudaError_t m31_extension_scalar_convert_montgomery( m31::extension_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); -extern "C" cudaError_t m31_mul_cuda( - m31::scalar_t* vec_a, m31::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::scalar_t* result); +extern "C" cudaError_t m31_extension_mul_cuda( + m31::extension_t* vec_a, m31::extension_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::extension_t* result); -extern "C" cudaError_t m31_add_cuda( - m31::scalar_t* vec_a, m31::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::scalar_t* result); +extern "C" cudaError_t m31_extension_add_cuda( + m31::extension_t* vec_a, m31::extension_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::extension_t* result); -extern "C" cudaError_t m31_accumulate_cuda( - m31::scalar_t* vec_a, m31::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config); +extern "C" cudaError_t m31_extension_accumulate_cuda( + m31::extension_t* vec_a, m31::extension_t* vec_b, int n, vec_ops::VecOpsConfig& config); -extern "C" cudaError_t m31_sub_cuda( - m31::scalar_t* vec_a, m31::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::scalar_t* result); +extern "C" cudaError_t m31_extension_sub_cuda( + m31::extension_t* vec_a, m31::extension_t* vec_b, int n, vec_ops::VecOpsConfig& config, m31::extension_t* result); -extern "C" cudaError_t m31_transpose_matrix_cuda( - const m31::scalar_t* input, +extern "C" cudaError_t m31_extension_transpose_matrix_cuda( + const m31::extension_t* input, uint32_t row_size, uint32_t column_size, - m31::scalar_t* output, + m31::extension_t* output, device_context::DeviceContext& ctx, bool on_device, bool is_async); -extern "C" cudaError_t m31_bit_reverse_cuda( - const m31::scalar_t* input, uint64_t n, vec_ops::BitReverseConfig& config, m31::scalar_t* output); +extern "C" cudaError_t m31_extension_bit_reverse_cuda( + const m31::extension_t* input, uint64_t n, vec_ops::BitReverseConfig& config, m31::extension_t* output); #endif \ No newline at end of file diff --git a/icicle/include/api/stark252.h b/icicle/include/api/stark252.h index b8bef75bb..5271b0b25 100644 --- a/icicle/include/api/stark252.h +++ b/icicle/include/api/stark252.h @@ -9,22 +9,28 @@ #include #include "gpu-utils/device_context.cuh" +#include "merkle-tree/merkle.cuh" +#include "matrix/matrix.cuh" #include "fields/stark_fields/stark252.cuh" #include "ntt/ntt.cuh" #include "vec_ops/vec_ops.cuh" -extern "C" cudaError_t stark252_initialize_domain( - stark252::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); - -extern "C" cudaError_t stark252_ntt_cuda( - const stark252::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, stark252::scalar_t* output); - -extern "C" cudaError_t stark252_release_domain(device_context::DeviceContext& ctx); - -extern "C" void stark252_generate_scalars(stark252::scalar_t* scalars, int size); +extern "C" cudaError_t stark252_build_merkle_tree( + const stark252::scalar_t* leaves, + stark252::scalar_t* digests, + unsigned int height, + unsigned int input_block_len, + const hash::SpongeHasher* compression, + const hash::SpongeHasher* bottom_layer, + const merkle_tree::TreeBuilderConfig& tree_config); -extern "C" cudaError_t stark252_scalar_convert_montgomery( - stark252::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + extern "C" cudaError_t stark252_mmcs_commit_cuda( + const matrix::Matrix* leaves, + unsigned int number_of_inputs, + stark252::scalar_t* digests, + const hash::SpongeHasher* hasher, + const hash::SpongeHasher* compression, + const merkle_tree::TreeBuilderConfig& tree_config); extern "C" cudaError_t stark252_mul_cuda( stark252::scalar_t* vec_a, stark252::scalar_t* vec_b, int n, vec_ops::VecOpsConfig& config, stark252::scalar_t* result); @@ -51,4 +57,17 @@ extern "C" cudaError_t stark252_bit_reverse_cuda( const stark252::scalar_t* input, uint64_t n, vec_ops::BitReverseConfig& config, stark252::scalar_t* output); +extern "C" void stark252_generate_scalars(stark252::scalar_t* scalars, int size); + +extern "C" cudaError_t stark252_scalar_convert_montgomery( + stark252::scalar_t* d_inout, size_t n, bool is_into, device_context::DeviceContext& ctx); + +extern "C" cudaError_t stark252_initialize_domain( + stark252::scalar_t* primitive_root, device_context::DeviceContext& ctx, bool fast_twiddles_mode); + +extern "C" cudaError_t stark252_ntt_cuda( + const stark252::scalar_t* input, int size, ntt::NTTDir dir, ntt::NTTConfig& config, stark252::scalar_t* output); + +extern "C" cudaError_t stark252_release_domain(device_context::DeviceContext& ctx); + #endif \ No newline at end of file diff --git a/icicle/include/api/templates/fields/poseidon.h b/icicle/include/api/templates/fields/poseidon.h index 29ed62915..faa2f5a16 100644 --- a/icicle/include/api/templates/fields/poseidon.h +++ b/icicle/include/api/templates/fields/poseidon.h @@ -1,26 +1,29 @@ -extern "C" cudaError_t ${FIELD}_create_optimized_poseidon_constants_cuda( - int arity, - int full_rounds_half, - int partial_rounds, - const ${FIELD}::scalar_t* constants, - device_context::DeviceContext& ctx, - poseidon::PoseidonConstants<${FIELD}::scalar_t>* poseidon_constants); +extern "C" cudaError_t ${FIELD}_poseidon_create_cuda( + poseidon::Poseidon<${FIELD}::scalar_t>** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const ${FIELD}::scalar_t* round_constants, + const ${FIELD}::scalar_t* mds_matrix, + const ${FIELD}::scalar_t* non_sparse_matrix, + const ${FIELD}::scalar_t* sparse_matrices, + const ${FIELD}::scalar_t domain_tag, + device_context::DeviceContext& ctx); -extern "C" cudaError_t ${FIELD}_init_optimized_poseidon_constants_cuda( - int arity, device_context::DeviceContext& ctx, poseidon::PoseidonConstants<${FIELD}::scalar_t>* constants); +extern "C" cudaError_t ${FIELD}_poseidon_load_cuda( + poseidon::Poseidon<${FIELD}::scalar_t>** poseidon, + unsigned int arity, + device_context::DeviceContext& ctx); -extern "C" cudaError_t ${FIELD}_poseidon_hash_cuda( - ${FIELD}::scalar_t* input, +extern "C" cudaError_t ${FIELD}_poseidon_hash_many_cuda( + const poseidon::Poseidon<${FIELD}::scalar_t>* poseidon, + const ${FIELD}::scalar_t* inputs, ${FIELD}::scalar_t* output, - int number_of_states, - int arity, - const poseidon::PoseidonConstants<${FIELD}::scalar_t>& constants, - poseidon::PoseidonConfig& config); + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + hash::SpongeConfig& cfg); -extern "C" cudaError_t ${FIELD}_build_poseidon_merkle_tree( - const ${FIELD}::scalar_t* leaves, - ${FIELD}::scalar_t* digests, - uint32_t height, - int arity, - poseidon::PoseidonConstants<${FIELD}::scalar_t>& constants, - merkle::TreeBuilderConfig& config); \ No newline at end of file +extern "C" cudaError_t + ${FIELD}_poseidon_delete_cuda(poseidon::Poseidon<${FIELD}::scalar_t>* poseidon); \ No newline at end of file diff --git a/icicle/include/api/templates/fields/poseidon2.h b/icicle/include/api/templates/fields/poseidon2.h index 922a7ef37..30e4cf9b6 100644 --- a/icicle/include/api/templates/fields/poseidon2.h +++ b/icicle/include/api/templates/fields/poseidon2.h @@ -1,30 +1,34 @@ -extern "C" cudaError_t ${FIELD}_create_poseidon2_constants_cuda( - int width, - int alpha, - int internal_rounds, - int external_rounds, +extern "C" cudaError_t ${FIELD}_poseidon2_create_cuda( + poseidon2::Poseidon2<${FIELD}::scalar_t>** poseidon, + unsigned int width, + unsigned int rate, + unsigned int alpha, + unsigned int internal_rounds, + unsigned int external_rounds, const ${FIELD}::scalar_t* round_constants, const ${FIELD}::scalar_t* internal_matrix_diag, poseidon2::MdsType mds_type, poseidon2::DiffusionStrategy diffusion, - device_context::DeviceContext& ctx, - poseidon2::Poseidon2Constants<${FIELD}::scalar_t>* poseidon_constants); + device_context::DeviceContext& ctx +); -extern "C" cudaError_t ${FIELD}_init_poseidon2_constants_cuda( - int width, +extern "C" cudaError_t ${FIELD}_poseidon2_load_cuda( + poseidon2::Poseidon2<${FIELD}::scalar_t>** poseidon, + unsigned int width, + unsigned int rate, poseidon2::MdsType mds_type, poseidon2::DiffusionStrategy diffusion, - device_context::DeviceContext& ctx, - poseidon2::Poseidon2Constants<${FIELD}::scalar_t>* poseidon_constants); + device_context::DeviceContext& ctx +); -extern "C" cudaError_t ${FIELD}_poseidon2_hash_cuda( - const ${FIELD}::scalar_t* input, +extern "C" cudaError_t ${FIELD}_poseidon2_hash_many_cuda( + const poseidon2::Poseidon2<${FIELD}::scalar_t>* poseidon, + const ${FIELD}::scalar_t* inputs, ${FIELD}::scalar_t* output, - int number_of_states, - int width, - const poseidon2::Poseidon2Constants<${FIELD}::scalar_t>& constants, - poseidon2::Poseidon2Config& config); + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + hash::SpongeConfig& cfg); -extern "C" cudaError_t ${FIELD}_release_poseidon2_constants_cuda( - poseidon2::Poseidon2Constants<${FIELD}::scalar_t>* constants, - device_context::DeviceContext& ctx); \ No newline at end of file +extern "C" cudaError_t + ${FIELD}_poseidon2_delete_cuda(poseidon2::Poseidon2<${FIELD}::scalar_t>* poseidon, device_context::DeviceContext& ctx); \ No newline at end of file diff --git a/icicle/include/api/templates/fields/tree.h b/icicle/include/api/templates/fields/tree.h new file mode 100644 index 000000000..c3ca20f83 --- /dev/null +++ b/icicle/include/api/templates/fields/tree.h @@ -0,0 +1,16 @@ +extern "C" cudaError_t ${FIELD}_build_merkle_tree( + const ${FIELD}::scalar_t* leaves, + ${FIELD}::scalar_t* digests, + unsigned int height, + unsigned int input_block_len, + const hash::SpongeHasher<${FIELD}::scalar_t, ${FIELD}::scalar_t>* compression, + const hash::SpongeHasher<${FIELD}::scalar_t, ${FIELD}::scalar_t>* bottom_layer, + const merkle_tree::TreeBuilderConfig& tree_config); + + extern "C" cudaError_t ${FIELD}_mmcs_commit_cuda( + const matrix::Matrix<${FIELD}::scalar_t>* leaves, + unsigned int number_of_inputs, + ${FIELD}::scalar_t* digests, + const hash::SpongeHasher<${FIELD}::scalar_t, ${FIELD}::scalar_t>* hasher, + const hash::SpongeHasher<${FIELD}::scalar_t, ${FIELD}::scalar_t>* compression, + const merkle_tree::TreeBuilderConfig& tree_config); \ No newline at end of file diff --git a/icicle/include/fields/field.cuh b/icicle/include/fields/field.cuh index fef0a28e6..6fe3e069a 100644 --- a/icicle/include/fields/field.cuh +++ b/icicle/include/fields/field.cuh @@ -796,6 +796,14 @@ public: return r; } + HOST_DEVICE_INLINE Field& operator=(Field const& other) + { + for (int i = 0; i < TLC; i++) { + this->limbs_storage.limbs[i] = other.limbs_storage.limbs[i]; + } + return *this; + } + friend HOST_DEVICE_INLINE Field operator*(const Field& xs, const Field& ys) { Wide xy = mul_wide(xs, ys); // full mult diff --git a/icicle/include/fields/stark_fields/m31.cuh b/icicle/include/fields/stark_fields/m31.cuh index 03f74fd93..b45592cec 100644 --- a/icicle/include/fields/stark_fields/m31.cuh +++ b/icicle/include/fields/stark_fields/m31.cuh @@ -14,7 +14,7 @@ namespace m31 { HOST_DEVICE_INLINE MersenneField(storage x) : Field{x} {} HOST_DEVICE_INLINE MersenneField(const Field& other) : Field(other) {} - static constexpr HOST_DEVICE_INLINE MersenneField zero() { return MersenneField(CONFIG::zero.limbs[0]); } + static constexpr HOST_DEVICE_INLINE MersenneField zero() { return MersenneField(CONFIG::zero); } static constexpr HOST_DEVICE_INLINE MersenneField one() { return MersenneField(CONFIG::one.limbs[0]); } diff --git a/icicle/include/gpu-utils/device_context.cuh b/icicle/include/gpu-utils/device_context.cuh index 9dfd83f21..b1448a5ac 100644 --- a/icicle/include/gpu-utils/device_context.cuh +++ b/icicle/include/gpu-utils/device_context.cuh @@ -3,6 +3,7 @@ #define DEVICE_CONTEXT_H #include +#include "gpu-utils/error_handler.cuh" namespace device_context { @@ -30,6 +31,28 @@ namespace device_context { }; } -} // namespace device_context + // checking whether a pointer is on host or device and asserts device matches provided device + static bool is_host_ptr(const void* p, int device_id = 0) + { + cudaPointerAttributes attributes; + CHK_STICKY(cudaPointerGetAttributes(&attributes, p)); + const bool is_on_host = attributes.type == cudaMemoryTypeHost || + attributes.type == cudaMemoryTypeUnregistered; // unregistered is host memory + const bool is_on_cur_device = !is_on_host && attributes.device == device_id; + const bool is_valid_ptr = is_on_host || is_on_cur_device; + if (!is_valid_ptr) { THROW_ICICLE_ERR(IcicleError_t::InvalidArgument, "Invalid ptr"); } + + return is_on_host; + } + static int get_cuda_device(const void* p) + { + cudaPointerAttributes attributes; + CHK_STICKY(cudaPointerGetAttributes(&attributes, p)); + const bool is_on_host = attributes.type == cudaMemoryTypeHost || + attributes.type == cudaMemoryTypeUnregistered; // unregistered is host memory + return is_on_host ? -1 : attributes.device; + } + +} // namespace device_context #endif \ No newline at end of file diff --git a/icicle/include/hash/hash.cuh b/icicle/include/hash/hash.cuh new file mode 100644 index 000000000..3c8324141 --- /dev/null +++ b/icicle/include/hash/hash.cuh @@ -0,0 +1,176 @@ +#pragma once +#ifndef HASH_H +#define HASH_H + +#include "gpu-utils/device_context.cuh" +#include "gpu-utils/error_handler.cuh" +#include "matrix/matrix.cuh" +#include + +using matrix::Matrix; + +/** + * @namespace hash + * Includes classes and methods for describing hash functions. + */ +namespace hash { + + /** + * @struct SpongeConfig + * Encodes sponge hash operations parameters. + */ + struct SpongeConfig { + device_context::DeviceContext ctx; /**< Details related to the device such as its id and stream id. */ + bool are_inputs_on_device; /**< True if inputs are on device and false if they're on host. Default value: false. */ + bool + are_outputs_on_device; /**< True if outputs are on device and false if they're on host. Default value: false. */ + bool is_async; /**< Whether to run the hash operations asynchronously. If set to `true`, the functions will be + * non-blocking and you'd need to synchronize it explicitly by running + * `cudaStreamSynchronize` or `cudaDeviceSynchronize`. If set to false, + * functions will block the current CPU thread. */ + }; + + /** + * A function that returns the default value of [SpongeConfig](@ref SpongeConfig) for the [SpongeHasher](@ref + * SpongeHasher) class. + * @return Default value of [SpongeConfig](@ref SpongeConfig). + */ + static SpongeConfig + default_sponge_config(const device_context::DeviceContext& ctx = device_context::get_default_device_context()) + { + SpongeConfig config = { + ctx, // ctx + false, // are_inputs_on_device + false, // are_outputs_on_device + false, // is_async + }; + return config; + } + + /** + * @class SpongeHasher + * + * Can be inherited by a cryptographic permutation function to create a + * [sponge](https://en.wikipedia.org/wiki/Sponge_function) construction out of it. + * + * @tparam PreImage type of inputs elements + * @tparam Image type of state elements. Also used to describe the type of hash output + */ + template + class SpongeHasher + { + public: + /// @brief the width of permutation state + const unsigned int width; + + /// @brief how many elements a state can fit per 1 permutation. Used with domain separation. + const unsigned int preimage_max_length; + + /// @brief portion of the state to absorb input into, or squeeze output from + const unsigned int rate; + + /// @brief start squeezing from this offset. Used with domain separation. + const unsigned int offset; + + SpongeHasher(unsigned int width, unsigned int preimage_max_length, unsigned int rate, unsigned int offset) + : width(width), preimage_max_length(preimage_max_length), rate(rate), offset(offset) + { + assert( + rate * sizeof(PreImage) <= preimage_max_length * sizeof(Image) && + "Input rate can not be bigger than preimage max length"); + } + + virtual cudaError_t hash_2d( + const Matrix* inputs, + Image* states, + unsigned int number_of_inputs, + unsigned int output_len, + uint64_t number_of_rows, + const device_context::DeviceContext& ctx) const + { + THROW_ICICLE_ERR(IcicleError_t::InvalidArgument, "Absorb 2d is not implemented for this hash"); + return cudaError_t::cudaSuccess; + }; + + virtual cudaError_t compress_and_inject( + const Matrix* matrices_to_inject, + unsigned int number_of_inputs, + uint64_t number_of_rows, + const Image* prev_layer, + Image* next_layer, + unsigned int digest_elements, + const device_context::DeviceContext& ctx) const + { + THROW_ICICLE_ERR(IcicleError_t::InvalidArgument, "Compress and inject is not implemented for this hash"); + return cudaError_t::cudaSuccess; + } + + /// @brief Permute aligned input and do squeeze + /// @param input pointer to input allocated on-device + /// @param out pointer to output allocated on-device + cudaError_t compress_many( + const Image* input, + Image* out, + unsigned int number_of_states, + unsigned int output_len, + const SpongeConfig& cfg) const + { + return hash_many((const PreImage*)input, out, number_of_states, width, output_len, cfg); + } + + virtual cudaError_t run_hash_many_kernel( + const PreImage* input, + Image* output, + unsigned int number_of_states, + unsigned int input_len, + unsigned int output_len, + const device_context::DeviceContext& ctx) const + { + THROW_ICICLE_ERR(IcicleError_t::InvalidArgument, "Hash many kernel is not implemented for this hash"); + return cudaError_t::cudaSuccess; + }; + + cudaError_t hash_many( + const PreImage* input, + Image* output, + unsigned int number_of_states, + unsigned int input_len, + unsigned int output_len, + const SpongeConfig& cfg) const + { + const PreImage* d_input; + PreImage* d_alloc_input; + Image* d_output; + if (!cfg.are_inputs_on_device) { + CHK_IF_RETURN(cudaMallocAsync(&d_alloc_input, number_of_states * input_len * sizeof(PreImage), cfg.ctx.stream)); + CHK_IF_RETURN(cudaMemcpyAsync( + d_alloc_input, input, number_of_states * input_len * sizeof(PreImage), cudaMemcpyHostToDevice, + cfg.ctx.stream)); + d_input = d_alloc_input; + } else { + d_input = input; + } + + if (!cfg.are_outputs_on_device) { + CHK_IF_RETURN(cudaMallocAsync(&d_output, number_of_states * output_len * sizeof(Image), cfg.ctx.stream)); + } else { + d_output = output; + } + + CHK_IF_RETURN(run_hash_many_kernel(d_input, d_output, number_of_states, input_len, output_len, cfg.ctx)); + + if (!cfg.are_inputs_on_device) { CHK_IF_RETURN(cudaFreeAsync(d_alloc_input, cfg.ctx.stream)); } + if (!cfg.are_outputs_on_device) { + CHK_IF_RETURN(cudaMemcpyAsync( + output, d_output, number_of_states * output_len * sizeof(Image), cudaMemcpyDeviceToHost, cfg.ctx.stream)); + CHK_IF_RETURN(cudaFreeAsync(d_output, cfg.ctx.stream)); + } + + if (!cfg.is_async) CHK_IF_RETURN(cudaStreamSynchronize(cfg.ctx.stream)); + + return CHK_LAST(); + }; + }; +} // namespace hash + +#endif \ No newline at end of file diff --git a/icicle/include/hash/keccak/keccak.cuh b/icicle/include/hash/keccak/keccak.cuh index 251ace3b3..f05d3736e 100644 --- a/icicle/include/hash/keccak/keccak.cuh +++ b/icicle/include/hash/keccak/keccak.cuh @@ -6,6 +6,10 @@ #include "gpu-utils/device_context.cuh" #include "gpu-utils/error_handler.cuh" +#include "hash/hash.cuh" + +using namespace hash; + namespace keccak { /** * @struct KeccakConfig @@ -32,25 +36,6 @@ namespace keccak { }; return config; } - - /** - * Compute the keccak hash over a sequence of preimages. - * Takes {number_of_blocks * input_block_size} u64s of input and computes {number_of_blocks} outputs, each of size {D - * / 64} u64 - * @tparam C - number of bits of capacity (c = b - r = 1600 - r). Only multiples of 64 are supported. - * @tparam D - number of bits of output. Only multiples of 64 are supported. - * @param input a pointer to the input data. May be allocated on device or on host, regulated - * by the config. Must be of size [input_block_size](@ref input_block_size) * [number_of_blocks](@ref - * number_of_blocks)}. - * @param input_block_size - size of each input block in bytes. Should be divisible by 8. - * @param number_of_blocks number of input and output blocks. One GPU thread processes one block - * @param output a pointer to the output data. May be allocated on device or on host, regulated - * by the config. Must be of size [output_block_size](@ref output_block_size) * [number_of_blocks](@ref - * number_of_blocks)} - */ - template - cudaError_t - keccak_hash(uint8_t* input, int input_block_size, int number_of_blocks, uint8_t* output, KeccakConfig& config); } // namespace keccak #endif \ No newline at end of file diff --git a/icicle/include/matrix/matrix.cuh b/icicle/include/matrix/matrix.cuh new file mode 100644 index 000000000..e6e58fc1f --- /dev/null +++ b/icicle/include/matrix/matrix.cuh @@ -0,0 +1,14 @@ +#pragma once +#ifndef MATRIX_H +#define MATRIX_H + +namespace matrix { + template + struct Matrix { + T* values; + size_t width; + size_t height; + }; +} // namespace matrix + +#endif \ No newline at end of file diff --git a/icicle/include/merkle-tree/merkle.cuh b/icicle/include/merkle-tree/merkle.cuh new file mode 100644 index 000000000..68e729ce1 --- /dev/null +++ b/icicle/include/merkle-tree/merkle.cuh @@ -0,0 +1,128 @@ +#pragma once +#ifndef MERKLE_H +#define MERKLE_H + +#include "gpu-utils/device_context.cuh" +#include "gpu-utils/error_handler.cuh" +#include "utils/utils.h" +#include "hash/hash.cuh" +#include "matrix/matrix.cuh" + +#include +#include +#include +#include + +using namespace hash; +using matrix::Matrix; + +/** + * @namespace merkle_tree + * Implementation of the [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree) builder, + * parallelized for the use on GPU + */ +namespace merkle_tree { + static constexpr size_t GIGA = 1024 * 1024 * 1024; + + /// Bytes per stream + static constexpr uint64_t STREAM_CHUNK_SIZE = GIGA; + + /// Flattens the tree digests and sum them up to get + /// the memory needed to contain all the digests + static size_t get_digests_len(uint32_t height, uint32_t arity, uint32_t digest_elements) + { + size_t digests_len = 0; + size_t row_length = digest_elements; + for (int i = 0; i <= height; i++) { + digests_len += row_length; + row_length *= arity; + } + + return digests_len; + } + + template + void swap(T** r, T** s) + { + T* t = *r; + *r = *s; + *s = t; + } + + static unsigned int get_height(uint64_t number_of_elements) + { + unsigned int height = 0; + while (number_of_elements >>= 1) + ++height; + return height; + } + + /** + * @struct TreeBuilderConfig + * Struct that encodes various Tree builder parameters. + */ + struct TreeBuilderConfig { + device_context::DeviceContext ctx; /**< Details related to the device such as its id and stream id. */ + unsigned int arity; + unsigned int + keep_rows; /**< How many rows of the Merkle tree rows should be written to output. '0' means all of them */ + unsigned int + digest_elements; /** @param digest_elements the size of output for each bottom layer hash and compression. + * Will also be equal to the size of the root of the tree. Default value 1 */ + bool are_inputs_on_device; /**< True if inputs are on device and false if they're on host. Default value: false. */ + bool + are_outputs_on_device; /**< True if outputs are on device and false if they're on host. Default value: false. */ + bool is_async; /**< Whether to run the tree builder asynchronously. If set to `true`, the build_merkle_tree + * function will be non-blocking and you'd need to synchronize it explicitly by running + * `cudaStreamSynchronize` or `cudaDeviceSynchronize`. If set to false, the + * function will block the current CPU thread. */ + }; + + static TreeBuilderConfig + default_merkle_config(const device_context::DeviceContext& ctx = device_context::get_default_device_context()) + { + TreeBuilderConfig config = { + ctx, // ctx + 2, // arity + 0, // keep_rows + 1, // digest_elements + false, // are_inputes_on_device + false, // are_outputs_on_device + false, // is_async + }; + return config; + } + + /** + * Builds the Merkle tree + * + * @param leaves a pointer to the leaves layer. May be allocated on device or on host, regulated by the config + * Expected to have arity ^ (height) * input_block_len elements + * @param digests a pointer to the digests storage. May only be allocated on the host + * Expected to have `sum(digests_len * (arity ^ (i))) for i in [0..keep_rows]` + * @param height the height of the merkle tree + * @param input_block_len the size of input vectors at the bottom layer of the tree + * # Algorithm + * The function will split large tree into many subtrees of size that will fit `STREAM_CHUNK_SIZE`. + * Each subtree is build in it's own stream (there is a maximum number of streams) + * After all subtrees are constructed - the function will combine the resulting sub-digests into the final top-tree + */ + template + cudaError_t build_merkle_tree( + const Leaf* inputs, + Digest* digests, + const SpongeHasher& compression, + const SpongeHasher& bottom_layer, + const TreeBuilderConfig& config); + + template + cudaError_t mmcs_commit( + const Matrix* inputs, + const unsigned int number_of_inputs, + Digest* digests, + const SpongeHasher& hasher, + const SpongeHasher& compression, + const TreeBuilderConfig& tree_config); +} // namespace merkle_tree + +#endif \ No newline at end of file diff --git a/icicle/include/poseidon/constants.cuh b/icicle/include/poseidon/constants.cuh new file mode 100644 index 000000000..cbdc6e2ab --- /dev/null +++ b/icicle/include/poseidon/constants.cuh @@ -0,0 +1,114 @@ +#pragma once +#ifndef POSEIDON_CONSTANTS_H +#define POSEIDON_CONSTANTS_H + +#include + +namespace poseidon { +#define FIRST_FULL_ROUNDS true +#define SECOND_FULL_ROUNDS false + + /** + * For most of the Poseidon configurations this is the case + * TODO: Add support for different full rounds numbers + */ + const int FULL_ROUNDS_DEFAULT = 4; + + /** + * @struct PoseidonConstants + * This constants are enough to define a Poseidon instantce + * @param round_constants A pointer to round constants allocated on the device + * @param mds_matrix A pointer to an mds matrix allocated on the device + * @param non_sparse_matrix A pointer to non sparse matrix allocated on the device + * @param sparse_matrices A pointer to sparse matrices allocated on the device + */ + template + struct PoseidonConstants { + unsigned int arity; + unsigned int alpha; + unsigned int partial_rounds; + unsigned int full_rounds_half; + S* round_constants = nullptr; + S* mds_matrix = nullptr; + S* non_sparse_matrix = nullptr; + S* sparse_matrices = nullptr; + S domain_tag = S::zero(); + + PoseidonConstants() = default; + PoseidonConstants(const PoseidonConstants& other) = default; + + PoseidonConstants& operator=(PoseidonConstants const& other) + { + this->arity = other.arity; + this->alpha = other.alpha; + this->partial_rounds = other.partial_rounds; + this->full_rounds_half = other.full_rounds_half; + this->round_constants = other.round_constants; + this->mds_matrix = other.mds_matrix; + this->non_sparse_matrix = other.non_sparse_matrix; + this->sparse_matrices = other.sparse_matrices; + this->domain_tag = other.domain_tag; + + return *this; + } + }; + + /** + * @class PoseidonKernelsConfiguration + * Describes the logic of deriving CUDA kernels parameters + * such as the number of threads and the number of blocks + */ + class PoseidonKernelsConfiguration + { + public: + // The logic behind this is that 1 thread only works on 1 element + // We have {width} elements in each state, and {number_of_states} states total + static int number_of_threads(unsigned int width) { return 256 / width * width; } + + // The partial rounds operates on the whole state, so we define + // the parallelism params for processing a single hash preimage per thread + static const int singlehash_block_size = 128; + + static int hashes_per_block(unsigned int width) { return number_of_threads(width) / width; } + + static int number_of_full_blocks(unsigned int width, size_t number_of_states) + { + int total_number_of_threads = number_of_states * width; + return total_number_of_threads / number_of_threads(width) + + static_cast(total_number_of_threads % number_of_threads(width)); + } + + static int number_of_singlehash_blocks(size_t number_of_states) + { + return number_of_states / singlehash_block_size + static_cast(number_of_states % singlehash_block_size); + } + }; + + using PKC = PoseidonKernelsConfiguration; + + template + cudaError_t create_optimized_poseidon_constants( + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const S* round_constants, + const S* mds_matrix, + const S* non_sparse_matrix, + const S* sparse_matrices, + const S domain_tag, + PoseidonConstants* poseidon_constants, + device_context::DeviceContext& ctx); + + /** + * Loads pre-calculated optimized constants, moves them to the device + */ + template + cudaError_t + init_optimized_poseidon_constants(int arity, device_context::DeviceContext& ctx, PoseidonConstants* constants); + + template + cudaError_t release_optimized_poseidon_constants(PoseidonConstants* constants, device_context::DeviceContext& ctx); +} // namespace poseidon + +#endif \ No newline at end of file diff --git a/icicle/include/poseidon/constants/generate_parameters.py b/icicle/include/poseidon/constants/generate_parameters.py index 915f307d8..1e9e75bd4 100755 --- a/icicle/include/poseidon/constants/generate_parameters.py +++ b/icicle/include/poseidon/constants/generate_parameters.py @@ -8,17 +8,18 @@ from poseidon import round_constants as rc, round_numbers as rn # Modify these -arity = 11 -p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 # grumpkin +arity = 2 +p = 2 ** 31 - 1 # grumpkin +# p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 # grumpkin # p = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001 # bls12-381 # p = 0x12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001 # bls12-377 # p = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 # bn254 # p = 0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001 # bw6-761 -prime_bit_len = 255 -field_bytes = 32 +prime_bit_len = 31 +field_bytes = 4 # leave set to -1 if not sure -full_round = -1 +full_round = 8 half_full_round = full_round // 2 # leave set to -1 if not sure partial_round = -1 @@ -31,12 +32,12 @@ # F = GF(p) # F.primitive_element() # -# primitive_element = None +primitive_element = None # primitive_element = 7 # bls12-381 # primitive_element = 22 # bls12-377 # primitive_element = 5 # bn254 # primitive_element = 15 # bw6-761 -primitive_element = 3 # grumpkin +# primitive_element = 3 # grumpkin # currently we only support alpha 5, if you need alpha other than 5 - feal free to reach out alpha = 5 diff --git a/icicle/include/poseidon/constants/m31_poseidon.h b/icicle/include/poseidon/constants/m31_poseidon.h new file mode 100644 index 000000000..07bedfa54 --- /dev/null +++ b/icicle/include/poseidon/constants/m31_poseidon.h @@ -0,0 +1,508 @@ +#pragma once +#ifndef M31_POSEIDON_H +#define M31_POSEIDON_H + +namespace poseidon_constants_m31 { + /** + * This inner namespace contains optimized constants for running Poseidon. + * These constants were generated using an algorithm defined at + * https://spec.filecoin.io/algorithms/crypto/poseidon/ + * The number in the name corresponds to the arity of hash function + * Each array contains: + * RoundConstants | MDSMatrix | Non-sparse matrix | Sparse matrices + */ + + int partial_rounds_2 = 7; + + int partial_rounds_4 = 11; + + int partial_rounds_8 = 12; + + int partial_rounds_11 = 12; + + unsigned char poseidon_constants_2[] = { + 0x33, 0x8b, 0x6d, 0x47, 0xbb, 0x97, 0x11, 0x67, 0x92, 0x9d, 0x55, 0x2d, + 0xee, 0x1e, 0x2e, 0x45, 0xfe, 0x35, 0x0e, 0x25, 0x7e, 0xc3, 0x4f, 0x70, + 0x4d, 0x0a, 0x8c, 0x18, 0xd9, 0x43, 0xa4, 0x61, 0xfb, 0x14, 0xd9, 0x14, + 0x99, 0x13, 0xb9, 0x30, 0xec, 0x3b, 0x8c, 0x16, 0xcc, 0xb2, 0x0b, 0x2e, + 0x9e, 0x18, 0xbf, 0x26, 0xb6, 0xb7, 0x2a, 0x44, 0x61, 0x29, 0xdb, 0x21, + 0x18, 0x84, 0x03, 0x4e, 0xef, 0x95, 0xf9, 0x45, 0xe3, 0xd8, 0xf2, 0x46, + 0x82, 0xb4, 0xc9, 0x5e, 0x5f, 0xf3, 0xb2, 0x4f, 0x61, 0x80, 0x50, 0x0f, + 0x0d, 0x7f, 0xe3, 0x1b, 0x23, 0xbd, 0x05, 0x2f, 0x0f, 0xb1, 0x60, 0x67, + 0xd8, 0x85, 0xdf, 0x57, 0x0c, 0x8c, 0xdf, 0x50, 0x9e, 0x65, 0x3c, 0x58, + 0x07, 0xbd, 0x29, 0x7e, 0xc5, 0xe5, 0xa7, 0x5a, 0x5a, 0x4b, 0x0c, 0x29, + 0x89, 0x9d, 0x14, 0x11, 0x8c, 0x20, 0xcb, 0x76, 0x4d, 0x56, 0x2d, 0x4a, + 0x10, 0xda, 0xaf, 0x0a, 0x65, 0x9d, 0x98, 0x3e, 0xa1, 0xac, 0x57, 0x46, + 0xcb, 0xe8, 0xfc, 0x5b, 0xd4, 0x43, 0x4b, 0x63, 0x1b, 0x13, 0x4b, 0x1f, + 0xed, 0xac, 0xbf, 0x30, 0x27, 0x15, 0xac, 0x53, 0x4b, 0x27, 0x61, 0x3e, + 0x37, 0xc3, 0x65, 0x74, 0x55, 0x55, 0x55, 0x55, 0x00, 0x00, 0x00, 0x20, + 0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x20, 0x33, 0x33, 0x33, 0x33, + 0xaa, 0xaa, 0xaa, 0x6a, 0x33, 0x33, 0x33, 0x33, 0xaa, 0xaa, 0xaa, 0x6a, + 0x6d, 0xdb, 0xb6, 0x6d, 0x55, 0x55, 0x55, 0x55, 0xc0, 0x72, 0x8d, 0x36, + 0x2c, 0xe5, 0xc0, 0x51, 0x00, 0x00, 0x00, 0x20, 0x0b, 0xd5, 0x67, 0x6c, + 0x6c, 0x67, 0x2c, 0x13, 0x33, 0x33, 0x33, 0x33, 0x6c, 0x67, 0x2c, 0x13, + 0xe6, 0xb8, 0x2c, 0x62, 0x55, 0x55, 0x55, 0x55, 0x15, 0x1f, 0xaf, 0x6a, + 0xd9, 0xa8, 0x14, 0x44, 0xae, 0xb0, 0x38, 0x4b, 0x17, 0x76, 0xd9, 0x39, + 0x55, 0x55, 0x55, 0x55, 0x28, 0xef, 0x9d, 0x4f, 0xc7, 0x3b, 0xa6, 0x24, + 0x84, 0x5b, 0x79, 0x6f, 0xde, 0x4f, 0x8f, 0x3d, 0x55, 0x55, 0x55, 0x55, + 0x54, 0xc2, 0xb2, 0x00, 0x5a, 0xed, 0x68, 0x0c, 0xeb, 0xd4, 0xc4, 0x61, + 0x02, 0x8c, 0x85, 0x27, 0x55, 0x55, 0x55, 0x55, 0xe4, 0xc5, 0xbd, 0x0a, + 0xf6, 0xec, 0x75, 0x26, 0xe0, 0xdb, 0xd8, 0x52, 0xdf, 0x28, 0xff, 0x33, + 0x55, 0x55, 0x55, 0x55, 0xac, 0x68, 0x06, 0x00, 0xc9, 0xff, 0x91, 0x19, + 0xb1, 0x12, 0x2b, 0x19, 0xa2, 0xdd, 0x47, 0x39, 0x55, 0x55, 0x55, 0x55, + 0xd5, 0x03, 0x00, 0x00, 0x45, 0xc8, 0xcc, 0x4c, 0x55, 0x55, 0x55, 0x35, + 0x8d, 0xd6, 0x68, 0x3d, 0x55, 0x55, 0x55, 0x55, 0x03, 0x00, 0x00, 0x00, + 0x64, 0x66, 0x66, 0x26, 0x00, 0x00, 0x00, 0x20, 0x33, 0x33, 0x33, 0x33 +}; + + unsigned char poseidon_constants_4[] = { + 0xdb, 0x64, 0xa5, 0x32, 0xd6, 0x3d, 0x12, 0x6e, 0x65, 0x66, 0x46, 0x59, + 0x2a, 0x64, 0x51, 0x3b, 0xaf, 0xbe, 0x72, 0x0b, 0x66, 0x5f, 0x5c, 0x6c, + 0x66, 0x11, 0x8c, 0x61, 0x99, 0x24, 0x99, 0x14, 0x1d, 0x5f, 0x67, 0x0a, + 0x4d, 0xab, 0xc4, 0x1e, 0x43, 0xb2, 0x09, 0x58, 0xc0, 0x27, 0x4c, 0x5b, + 0xf0, 0x0c, 0xf5, 0x12, 0xc9, 0x2f, 0x88, 0x4f, 0x59, 0x52, 0x5b, 0x6a, + 0x73, 0x90, 0x55, 0x5b, 0xaf, 0x47, 0x55, 0x0d, 0xa7, 0xc2, 0x0c, 0x6e, + 0xe6, 0xd6, 0x4e, 0x30, 0x9e, 0x75, 0x47, 0x12, 0xca, 0x93, 0xd1, 0x5b, + 0x64, 0x27, 0xfc, 0x60, 0x6c, 0x16, 0x52, 0x20, 0xf5, 0xe0, 0x01, 0x15, + 0x27, 0xf9, 0x96, 0x7f, 0xa0, 0x38, 0xad, 0x3c, 0x95, 0xd3, 0xe4, 0x32, + 0x57, 0x95, 0x5a, 0x6b, 0x12, 0xcc, 0xdc, 0x18, 0x2b, 0xdd, 0xa4, 0x66, + 0xbf, 0xe7, 0x96, 0x15, 0x85, 0x87, 0x6a, 0x1f, 0x15, 0x19, 0x9c, 0x65, + 0xef, 0x24, 0xaa, 0x2c, 0x3f, 0x6b, 0xbc, 0x6b, 0x54, 0x24, 0x2c, 0x17, + 0xf1, 0x7a, 0x8d, 0x57, 0x90, 0xa4, 0xd4, 0x4a, 0x12, 0x06, 0x77, 0x6a, + 0xe8, 0x6b, 0xd9, 0x51, 0x80, 0x72, 0xa1, 0x31, 0xce, 0xa8, 0x59, 0x10, + 0x0c, 0x90, 0xd4, 0x10, 0x8e, 0x60, 0x54, 0x1c, 0xe7, 0xfd, 0x42, 0x3a, + 0x73, 0xc1, 0xcc, 0x4f, 0x58, 0xbb, 0x99, 0x7c, 0xd2, 0x51, 0xda, 0x43, + 0xea, 0x6e, 0xe8, 0x16, 0xb2, 0x51, 0x53, 0x61, 0x7e, 0x68, 0x44, 0x3c, + 0x33, 0x33, 0x33, 0x33, 0xaa, 0xaa, 0xaa, 0x6a, 0x6d, 0xdb, 0xb6, 0x6d, + 0x00, 0x00, 0x00, 0x10, 0x71, 0x1c, 0xc7, 0x71, 0xaa, 0xaa, 0xaa, 0x6a, + 0x6d, 0xdb, 0xb6, 0x6d, 0x00, 0x00, 0x00, 0x10, 0x71, 0x1c, 0xc7, 0x71, + 0x99, 0x99, 0x99, 0x59, 0x6d, 0xdb, 0xb6, 0x6d, 0x00, 0x00, 0x00, 0x10, + 0x71, 0x1c, 0xc7, 0x71, 0x99, 0x99, 0x99, 0x59, 0x45, 0x17, 0x5d, 0x74, + 0x00, 0x00, 0x00, 0x10, 0x71, 0x1c, 0xc7, 0x71, 0x99, 0x99, 0x99, 0x59, + 0x45, 0x17, 0x5d, 0x74, 0x55, 0x55, 0x55, 0x35, 0x71, 0x1c, 0xc7, 0x71, + 0x99, 0x99, 0x99, 0x59, 0x45, 0x17, 0x5d, 0x74, 0x55, 0x55, 0x55, 0x35, + 0xd8, 0x89, 0x9d, 0x58, 0x33, 0x33, 0x33, 0x33, 0xae, 0x9d, 0xba, 0x61, + 0x09, 0xf2, 0xee, 0x53, 0x5e, 0x5c, 0xe8, 0x61, 0x8e, 0x1a, 0x60, 0x6c, + 0xaa, 0xaa, 0xaa, 0x6a, 0xff, 0x1a, 0xb7, 0x09, 0x1d, 0x84, 0x75, 0x5e, + 0x88, 0x5e, 0x36, 0x25, 0x6b, 0xd4, 0xdd, 0x65, 0x6d, 0xdb, 0xb6, 0x6d, + 0x1d, 0x84, 0x75, 0x5e, 0x10, 0x9d, 0x2d, 0x63, 0xa7, 0x62, 0xfc, 0x1f, + 0xe2, 0x43, 0x63, 0x14, 0x00, 0x00, 0x00, 0x10, 0x88, 0x5e, 0x36, 0x25, + 0xa7, 0x62, 0xfc, 0x1f, 0x47, 0xa0, 0x19, 0x6f, 0x48, 0x1f, 0x4e, 0x22, + 0x71, 0x1c, 0xc7, 0x71, 0x6b, 0xd4, 0xdd, 0x65, 0xe2, 0x43, 0x63, 0x14, + 0x48, 0x1f, 0x4e, 0x22, 0xb7, 0x4e, 0x73, 0x01, 0x33, 0x33, 0x33, 0x33, + 0x84, 0xdd, 0xf7, 0x08, 0x6f, 0xc5, 0x14, 0x63, 0xb6, 0x22, 0x01, 0x3d, + 0xcd, 0xab, 0x7d, 0x62, 0xac, 0x7e, 0x61, 0x57, 0x40, 0x6b, 0xc5, 0x45, + 0x77, 0xbc, 0x02, 0x18, 0x8c, 0x66, 0xda, 0x74, 0x33, 0x33, 0x33, 0x33, + 0x01, 0x9d, 0x33, 0x55, 0xed, 0x7d, 0x75, 0x63, 0x41, 0x92, 0x33, 0x76, + 0x6b, 0xd5, 0x10, 0x23, 0x1a, 0xc4, 0x49, 0x5b, 0x0c, 0x86, 0x5a, 0x60, + 0x23, 0xe5, 0xd8, 0x1c, 0x43, 0xe9, 0xe2, 0x0d, 0x33, 0x33, 0x33, 0x33, + 0x1b, 0x68, 0xec, 0x17, 0x0e, 0x3f, 0x34, 0x1a, 0xb0, 0x28, 0xe9, 0x6c, + 0xc0, 0xf7, 0x3e, 0x79, 0xdc, 0x08, 0x9e, 0x32, 0x45, 0xde, 0xea, 0x73, + 0x7a, 0xc4, 0xb4, 0x0d, 0x65, 0xb6, 0x61, 0x04, 0x33, 0x33, 0x33, 0x33, + 0x41, 0x01, 0x02, 0x6b, 0xd8, 0x62, 0x6b, 0x47, 0x47, 0xd9, 0x7e, 0x72, + 0x4f, 0x80, 0x31, 0x54, 0x8b, 0x5e, 0x3e, 0x26, 0x64, 0x16, 0xe2, 0x51, + 0xf4, 0xa6, 0xed, 0x35, 0xc3, 0xe9, 0xc5, 0x41, 0x33, 0x33, 0x33, 0x33, + 0xd5, 0x3f, 0xed, 0x11, 0xf5, 0x0f, 0x56, 0x41, 0xf6, 0x0d, 0xf3, 0x78, + 0xb0, 0x78, 0xa1, 0x7d, 0x5d, 0x33, 0xc4, 0x5e, 0xa6, 0xd9, 0x47, 0x4c, + 0x07, 0xc3, 0x30, 0x5a, 0x91, 0x10, 0x31, 0x20, 0x33, 0x33, 0x33, 0x33, + 0xa5, 0xec, 0xe5, 0x25, 0xe6, 0xa7, 0x4e, 0x01, 0xee, 0x3a, 0xe7, 0x62, + 0x02, 0xfd, 0xf9, 0x08, 0xdd, 0x91, 0x3f, 0x2d, 0xca, 0xbc, 0xb5, 0x2c, + 0x54, 0x9e, 0xd4, 0x78, 0x6b, 0x18, 0x94, 0x21, 0x33, 0x33, 0x33, 0x33, + 0xe6, 0xb3, 0xd2, 0x2e, 0x49, 0xdb, 0xa8, 0x52, 0x5f, 0x6a, 0x75, 0x59, + 0xd5, 0x45, 0x5c, 0x73, 0x40, 0xe4, 0xd8, 0x2a, 0x8c, 0xe6, 0xda, 0x50, + 0x5f, 0x4f, 0x18, 0x5d, 0xf4, 0xa4, 0xf4, 0x46, 0x33, 0x33, 0x33, 0x33, + 0x3e, 0x90, 0x5b, 0x3a, 0x55, 0x96, 0x22, 0x7c, 0xd9, 0x64, 0x36, 0x4e, + 0x0b, 0xec, 0x66, 0x65, 0xac, 0x55, 0xa9, 0x19, 0x50, 0x87, 0x49, 0x1a, + 0x1f, 0x78, 0x89, 0x36, 0x25, 0x2a, 0x06, 0x55, 0x33, 0x33, 0x33, 0x33, + 0x6b, 0xf1, 0x61, 0x67, 0x67, 0x00, 0xc5, 0x24, 0x9e, 0xd1, 0x94, 0x6f, + 0xbf, 0x8b, 0xaf, 0x2d, 0x69, 0x9c, 0xb7, 0x62, 0xf8, 0x0a, 0x43, 0x13, + 0x3c, 0xc0, 0x48, 0x3e, 0x9f, 0x3f, 0xa8, 0x2c, 0x33, 0x33, 0x33, 0x33, + 0x9d, 0x5b, 0xb2, 0x2b, 0x62, 0x05, 0x39, 0x20, 0x52, 0x1f, 0xe8, 0x05, + 0x1b, 0x24, 0xc0, 0x13, 0x11, 0x11, 0x11, 0x11, 0x9c, 0x6a, 0x35, 0x45, + 0xf6, 0x7f, 0x5c, 0x4c, 0x9f, 0xc4, 0x8f, 0x1f, 0x33, 0x33, 0x33, 0x33, + 0xb1, 0xaa, 0xaa, 0x2a, 0xcb, 0xb6, 0x6d, 0x5b, 0x34, 0x49, 0x92, 0x24, + 0x90, 0x65, 0x59, 0x56, 0xaa, 0xaa, 0xaa, 0x6a, 0x6d, 0xdb, 0xb6, 0x6d, + 0x00, 0x00, 0x00, 0x10, 0x71, 0x1c, 0xc7, 0x71 + }; + + unsigned char poseidon_constants_8[] = { +0x90, 0xaf, 0x71, 0x3e, 0xa3, 0xbe, 0x5a, 0x30, 0xd4, 0x1b, 0x6f, 0x5d, + 0xeb, 0x36, 0x6b, 0x53, 0x14, 0xc0, 0x30, 0x13, 0xd5, 0xf8, 0x0b, 0x1c, + 0xa8, 0x66, 0xf1, 0x3c, 0xbd, 0x64, 0xa3, 0x6c, 0x06, 0x5e, 0x95, 0x7c, + 0xee, 0xc4, 0x0a, 0x0f, 0x37, 0x03, 0xba, 0x6d, 0x20, 0x85, 0xf1, 0x2c, + 0xee, 0x59, 0x21, 0x11, 0x42, 0xae, 0xb7, 0x3c, 0x73, 0xb4, 0xd6, 0x71, + 0x6a, 0x29, 0x40, 0x03, 0x86, 0xd8, 0x32, 0x68, 0x61, 0x62, 0x62, 0x32, + 0x44, 0x5d, 0xcc, 0x38, 0x76, 0x0f, 0xbc, 0x1f, 0xc9, 0x6e, 0x67, 0x1d, + 0x95, 0x35, 0x10, 0x79, 0x45, 0xaa, 0x0f, 0x7c, 0x73, 0xfa, 0x5d, 0x3f, + 0x53, 0xf2, 0xdc, 0x21, 0x37, 0xfa, 0x15, 0x04, 0xfd, 0x31, 0x3d, 0x5d, + 0x5d, 0xe6, 0x1d, 0x4a, 0xb3, 0x2b, 0xa2, 0x07, 0x2d, 0x48, 0x07, 0x2b, + 0x92, 0x1c, 0x31, 0x52, 0x6c, 0xd3, 0x32, 0x2f, 0x0f, 0xdd, 0x82, 0x7d, + 0x41, 0x0e, 0x81, 0x7e, 0x60, 0xfb, 0x49, 0x7b, 0xe5, 0x39, 0x3d, 0x75, + 0x6d, 0xcf, 0x02, 0x77, 0x0d, 0xf6, 0xf8, 0x0c, 0x43, 0xae, 0x62, 0x5e, + 0x26, 0x36, 0x9e, 0x3a, 0x10, 0xe3, 0x59, 0x4b, 0x3a, 0x59, 0x49, 0x73, + 0x31, 0x20, 0xb9, 0x40, 0x39, 0xed, 0xaf, 0x37, 0x6d, 0x5c, 0x4c, 0x6a, + 0xce, 0xca, 0xc4, 0x33, 0x53, 0x96, 0x92, 0x1d, 0xb2, 0xa1, 0xac, 0x65, + 0xbb, 0x43, 0xc4, 0x16, 0xf9, 0x38, 0x10, 0x67, 0x3d, 0xbb, 0x28, 0x7a, + 0x2b, 0x1e, 0x65, 0x36, 0x07, 0x14, 0x36, 0x3c, 0xcb, 0xdf, 0x03, 0x6b, + 0x03, 0x7b, 0xe6, 0x67, 0x79, 0x2a, 0x08, 0x47, 0xb7, 0x8f, 0x9c, 0x7e, + 0x54, 0xde, 0x08, 0x0a, 0xf8, 0x99, 0x24, 0x6f, 0x64, 0x78, 0x80, 0x5f, + 0x43, 0x76, 0x77, 0x40, 0x12, 0x62, 0x71, 0x10, 0x35, 0xf5, 0xdd, 0x0a, + 0x06, 0xff, 0x9b, 0x7b, 0xd8, 0x1a, 0xf3, 0x50, 0x1d, 0xc3, 0x8c, 0x60, + 0xe0, 0x61, 0xf5, 0x3d, 0xf9, 0xbf, 0xe4, 0x38, 0x78, 0xbf, 0x59, 0x0e, + 0xed, 0xc9, 0x4d, 0x0b, 0xb1, 0x7a, 0x10, 0x2b, 0x84, 0x27, 0x07, 0x70, + 0x5d, 0xc0, 0xa4, 0x7e, 0x9c, 0xf0, 0xf6, 0x69, 0x89, 0x6c, 0xc5, 0x39, + 0x4a, 0x7d, 0x5e, 0x26, 0x2f, 0x08, 0x9d, 0x05, 0xdc, 0x71, 0xec, 0x08, + 0x2b, 0xca, 0x68, 0x14, 0x42, 0xf6, 0xe6, 0x0a, 0x2f, 0xa5, 0x34, 0x6d, + 0x95, 0xaa, 0x80, 0x55, 0x23, 0x0f, 0x5f, 0x20, 0xbe, 0x4d, 0x0b, 0x20, + 0x71, 0x1c, 0xc7, 0x71, 0x99, 0x99, 0x99, 0x59, 0x45, 0x17, 0x5d, 0x74, + 0x55, 0x55, 0x55, 0x35, 0xd8, 0x89, 0x9d, 0x58, 0xb6, 0x6d, 0xdb, 0x76, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, + 0x99, 0x99, 0x99, 0x59, 0x45, 0x17, 0x5d, 0x74, 0x55, 0x55, 0x55, 0x35, + 0xd8, 0x89, 0x9d, 0x58, 0xb6, 0x6d, 0xdb, 0x76, 0x11, 0x11, 0x11, 0x11, + 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x38, 0x8e, 0xe3, 0x78, + 0x45, 0x17, 0x5d, 0x74, 0x55, 0x55, 0x55, 0x35, 0xd8, 0x89, 0x9d, 0x58, + 0xb6, 0x6d, 0xdb, 0x76, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, + 0x0f, 0x0f, 0x0f, 0x0f, 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, + 0x55, 0x55, 0x55, 0x35, 0xd8, 0x89, 0x9d, 0x58, 0xb6, 0x6d, 0xdb, 0x76, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, + 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, + 0xd8, 0x89, 0x9d, 0x58, 0xb6, 0x6d, 0xdb, 0x76, 0x11, 0x11, 0x11, 0x11, + 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x38, 0x8e, 0xe3, 0x78, + 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, 0x79, 0x9e, 0xe7, 0x79, + 0xb6, 0x6d, 0xdb, 0x76, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, + 0x0f, 0x0f, 0x0f, 0x0f, 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, + 0xcc, 0xcc, 0xcc, 0x6c, 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, + 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, + 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32, + 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x38, 0x8e, 0xe3, 0x78, + 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, 0x79, 0x9e, 0xe7, 0x79, + 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32, 0xaa, 0xaa, 0xaa, 0x5a, + 0x0f, 0x0f, 0x0f, 0x0f, 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, + 0xcc, 0xcc, 0xcc, 0x6c, 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, + 0xc8, 0x42, 0x16, 0x32, 0xaa, 0xaa, 0xaa, 0x5a, 0x70, 0x3d, 0x0a, 0x57, + 0x71, 0x1c, 0xc7, 0x71, 0x50, 0x05, 0xd7, 0x30, 0x09, 0x94, 0x4f, 0x13, + 0x11, 0x86, 0x4b, 0x61, 0x74, 0x8b, 0x94, 0x0e, 0x7e, 0x5d, 0x93, 0x27, + 0xeb, 0xb6, 0x4b, 0x61, 0x90, 0x3f, 0x9b, 0x7d, 0x10, 0xe9, 0x16, 0x06, + 0x99, 0x99, 0x99, 0x59, 0x4f, 0xf6, 0x15, 0x6b, 0x84, 0x8c, 0xe0, 0x5f, + 0x88, 0x9e, 0xb2, 0x08, 0x32, 0x36, 0xe3, 0x25, 0x64, 0x0a, 0xf5, 0x6f, + 0x80, 0xff, 0x8e, 0x6f, 0xcd, 0xb5, 0x72, 0x12, 0x90, 0xa2, 0x7a, 0x09, + 0x45, 0x17, 0x5d, 0x74, 0x84, 0x8c, 0xe0, 0x5f, 0xf5, 0x67, 0x02, 0x2d, + 0x71, 0x83, 0xf0, 0x55, 0x81, 0xa2, 0x81, 0x4b, 0xec, 0xff, 0xb0, 0x6b, + 0x17, 0x41, 0xd6, 0x36, 0xf3, 0x16, 0x58, 0x23, 0x49, 0x90, 0xa2, 0x17, + 0x55, 0x55, 0x55, 0x35, 0x88, 0x9e, 0xb2, 0x08, 0x71, 0x83, 0xf0, 0x55, + 0x27, 0x2a, 0xb0, 0x29, 0x0b, 0xe4, 0x53, 0x70, 0x7f, 0xeb, 0x60, 0x74, + 0xb9, 0x92, 0xa9, 0x4b, 0x51, 0x41, 0x0e, 0x56, 0x1b, 0xe4, 0x67, 0x43, + 0xd8, 0x89, 0x9d, 0x58, 0x32, 0x36, 0xe3, 0x25, 0x81, 0xa2, 0x81, 0x4b, + 0x0b, 0xe4, 0x53, 0x70, 0x73, 0x99, 0xf0, 0x02, 0x1a, 0xf7, 0xe1, 0x40, + 0x18, 0xc4, 0x58, 0x3a, 0xcc, 0xf5, 0x0b, 0x18, 0xf0, 0x39, 0xab, 0x7a, + 0xb6, 0x6d, 0xdb, 0x76, 0x64, 0x0a, 0xf5, 0x6f, 0xec, 0xff, 0xb0, 0x6b, + 0x7f, 0xeb, 0x60, 0x74, 0x1a, 0xf7, 0xe1, 0x40, 0xf7, 0xfc, 0xbe, 0x7f, + 0xbf, 0x63, 0xc5, 0x05, 0x15, 0x3c, 0x9f, 0x2b, 0x9b, 0x77, 0xb0, 0x44, + 0x11, 0x11, 0x11, 0x11, 0x80, 0xff, 0x8e, 0x6f, 0x17, 0x41, 0xd6, 0x36, + 0xb9, 0x92, 0xa9, 0x4b, 0x18, 0xc4, 0x58, 0x3a, 0xbf, 0x63, 0xc5, 0x05, + 0x2f, 0x5c, 0x3c, 0x09, 0x25, 0xaf, 0xdf, 0x11, 0x21, 0x7d, 0x95, 0x58, + 0x00, 0x00, 0x00, 0x08, 0xcd, 0xb5, 0x72, 0x12, 0xf3, 0x16, 0x58, 0x23, + 0x51, 0x41, 0x0e, 0x56, 0xcc, 0xf5, 0x0b, 0x18, 0x15, 0x3c, 0x9f, 0x2b, + 0x25, 0xaf, 0xdf, 0x11, 0x38, 0x50, 0xe9, 0x16, 0x12, 0xb8, 0xc8, 0x17, + 0x0f, 0x0f, 0x0f, 0x0f, 0x90, 0xa2, 0x7a, 0x09, 0x49, 0x90, 0xa2, 0x17, + 0x1b, 0xe4, 0x67, 0x43, 0xf0, 0x39, 0xab, 0x7a, 0x9b, 0x77, 0xb0, 0x44, + 0x21, 0x7d, 0x95, 0x58, 0x12, 0xb8, 0xc8, 0x17, 0x5a, 0xfc, 0xf7, 0x5c, + 0x71, 0x1c, 0xc7, 0x71, 0xdb, 0x50, 0x89, 0x38, 0x5f, 0x88, 0xe3, 0x32, + 0x8b, 0xb4, 0x3b, 0x6c, 0x95, 0x0a, 0xf1, 0x41, 0xe6, 0x0a, 0x52, 0x7d, + 0xd1, 0x0d, 0xb1, 0x57, 0x9b, 0xd2, 0xf4, 0x1d, 0x80, 0x17, 0xb2, 0x42, + 0x9c, 0x40, 0x6e, 0x2f, 0x63, 0xa7, 0x42, 0x77, 0xf9, 0x37, 0xd1, 0x43, + 0x98, 0xd1, 0xec, 0x50, 0x91, 0x26, 0xfa, 0x4e, 0x0c, 0x9e, 0xcc, 0x31, + 0x52, 0xf4, 0x20, 0x5d, 0x2a, 0x20, 0xeb, 0x1b, 0x71, 0x1c, 0xc7, 0x71, + 0x54, 0x29, 0xf4, 0x4a, 0xde, 0x91, 0xf6, 0x54, 0x8b, 0xed, 0x18, 0x26, + 0x71, 0x24, 0x22, 0x34, 0xb7, 0xaf, 0x61, 0x27, 0x7a, 0x0a, 0x21, 0x7f, + 0x9f, 0xfe, 0xa1, 0x53, 0x26, 0x97, 0x6b, 0x5b, 0xf4, 0xea, 0xef, 0x4a, + 0x4b, 0x03, 0xa0, 0x7c, 0xe6, 0x64, 0x69, 0x47, 0x76, 0xf7, 0x2d, 0x0b, + 0x6f, 0xd5, 0x2c, 0x45, 0x52, 0xc1, 0x5c, 0x46, 0x25, 0x38, 0xab, 0x79, + 0x64, 0xed, 0xe7, 0x57, 0x71, 0x1c, 0xc7, 0x71, 0x94, 0xc2, 0xb7, 0x7f, + 0xaf, 0x0d, 0x61, 0x4c, 0xa3, 0x86, 0x8e, 0x45, 0xdc, 0x73, 0xe3, 0x77, + 0x71, 0xed, 0x21, 0x7d, 0x4b, 0x8e, 0xc7, 0x52, 0x39, 0x5d, 0x49, 0x1d, + 0x75, 0x35, 0xed, 0x09, 0xc6, 0x02, 0x3b, 0x22, 0xb8, 0x91, 0x07, 0x13, + 0x7f, 0xbf, 0x15, 0x7f, 0xb5, 0xbe, 0x0a, 0x5c, 0xbc, 0x75, 0x54, 0x61, + 0x6c, 0x2f, 0x28, 0x5f, 0xff, 0xf0, 0x7b, 0x67, 0x11, 0x8e, 0x70, 0x29, + 0x71, 0x1c, 0xc7, 0x71, 0xe6, 0xfc, 0x29, 0x07, 0xbd, 0x0c, 0x4d, 0x5f, + 0x57, 0xb7, 0x87, 0x41, 0xec, 0x48, 0xda, 0x18, 0x78, 0x41, 0xb8, 0x6d, + 0xde, 0x7e, 0x47, 0x5a, 0x13, 0x03, 0xc5, 0x52, 0x2e, 0xee, 0xf3, 0x3f, + 0x06, 0xd0, 0xcd, 0x48, 0x77, 0x2a, 0xcd, 0x7e, 0x35, 0xee, 0x74, 0x63, + 0x3e, 0x26, 0x65, 0x64, 0x37, 0xa1, 0xfb, 0x7a, 0x03, 0x44, 0xa8, 0x70, + 0x2f, 0x03, 0x27, 0x1e, 0xb3, 0x02, 0x3e, 0x4a, 0x71, 0x1c, 0xc7, 0x71, + 0xfd, 0xe1, 0xfe, 0x3c, 0x88, 0x1c, 0x36, 0x53, 0x36, 0x31, 0x5a, 0x32, + 0x88, 0x7b, 0xa6, 0x17, 0x40, 0x31, 0xe4, 0x0a, 0xb3, 0x70, 0x8f, 0x4f, + 0xc3, 0xa2, 0xd7, 0x06, 0x34, 0x9d, 0x4a, 0x71, 0x5b, 0xfa, 0x79, 0x25, + 0xe8, 0x6f, 0x05, 0x65, 0xc1, 0x4a, 0xee, 0x5c, 0x9a, 0xb2, 0x83, 0x05, + 0xb0, 0x89, 0x77, 0x2e, 0xc1, 0x56, 0x34, 0x08, 0x50, 0xf5, 0xde, 0x12, + 0xae, 0x68, 0xc2, 0x1b, 0x71, 0x1c, 0xc7, 0x71, 0xb3, 0x84, 0x6e, 0x4f, + 0xae, 0x74, 0x57, 0x4f, 0x56, 0xf3, 0xfc, 0x48, 0xfa, 0x73, 0xd7, 0x0e, + 0x8a, 0xc5, 0x35, 0x4d, 0xf6, 0x26, 0x15, 0x2a, 0xcf, 0xb5, 0x2d, 0x64, + 0xd1, 0x2a, 0x84, 0x43, 0xab, 0xc0, 0xec, 0x60, 0xa9, 0xbc, 0x09, 0x11, + 0xfd, 0x06, 0xea, 0x1e, 0xba, 0x29, 0x77, 0x6c, 0xb1, 0x37, 0xa5, 0x42, + 0x1c, 0x9b, 0x58, 0x37, 0xa8, 0xb7, 0xae, 0x3e, 0x6a, 0xf8, 0x63, 0x25, + 0x71, 0x1c, 0xc7, 0x71, 0x22, 0xa0, 0x75, 0x4e, 0x17, 0x33, 0x99, 0x7c, + 0x97, 0x97, 0x30, 0x04, 0xbc, 0x22, 0x6d, 0x7c, 0xb3, 0xd7, 0xd9, 0x56, + 0x4e, 0xef, 0x40, 0x5e, 0x02, 0x05, 0x51, 0x1e, 0x0c, 0x32, 0xb7, 0x06, + 0x41, 0x16, 0x80, 0x33, 0xc2, 0xdd, 0x8f, 0x18, 0x65, 0xa3, 0xe1, 0x4a, + 0xdb, 0xb4, 0x5d, 0x78, 0xf3, 0x99, 0x48, 0x3e, 0x04, 0x5b, 0xb9, 0x09, + 0xd2, 0x3d, 0x14, 0x05, 0x69, 0x50, 0xe9, 0x57, 0x71, 0x1c, 0xc7, 0x71, + 0x0d, 0x72, 0x37, 0x6c, 0xe3, 0xd1, 0x57, 0x2f, 0x9e, 0xb7, 0xe1, 0x30, + 0x22, 0xce, 0xe5, 0x66, 0x45, 0x7b, 0x06, 0x0e, 0x06, 0x66, 0xdd, 0x11, + 0xef, 0xdf, 0x61, 0x52, 0x7d, 0xb9, 0xcf, 0x1e, 0x97, 0xbe, 0x55, 0x00, + 0x94, 0xcb, 0x50, 0x7c, 0xa0, 0x83, 0x1c, 0x57, 0xf3, 0x72, 0x8c, 0x40, + 0x07, 0x32, 0x39, 0x54, 0xe8, 0x5a, 0x10, 0x7b, 0x09, 0xc2, 0x02, 0x58, + 0xb0, 0xeb, 0x23, 0x51, 0x71, 0x1c, 0xc7, 0x71, 0xf0, 0xfd, 0x78, 0x2c, + 0xe7, 0xa8, 0x53, 0x7c, 0xdd, 0xf6, 0xa3, 0x2b, 0xa9, 0x51, 0xf4, 0x33, + 0x1d, 0x4d, 0x13, 0x0e, 0x53, 0x6b, 0xde, 0x6b, 0x48, 0x46, 0xa0, 0x01, + 0xbf, 0x74, 0xf2, 0x14, 0xe5, 0x99, 0x3d, 0x72, 0x37, 0x8e, 0xa9, 0x44, + 0x61, 0xed, 0xdd, 0x3b, 0x7c, 0x11, 0x28, 0x12, 0xd5, 0xd6, 0x27, 0x78, + 0x4e, 0xf8, 0xe4, 0x3d, 0xdc, 0x5c, 0x92, 0x0c, 0xea, 0x5b, 0xe2, 0x44, + 0x71, 0x1c, 0xc7, 0x71, 0x64, 0x55, 0xb2, 0x0d, 0x54, 0x7f, 0x64, 0x72, + 0x8e, 0xe1, 0x7b, 0x52, 0xf5, 0xe4, 0x20, 0x13, 0xd1, 0xd4, 0x5d, 0x4c, + 0x33, 0x3d, 0xb6, 0x55, 0x26, 0xed, 0xb0, 0x75, 0xa0, 0xf2, 0x72, 0x51, + 0x6b, 0xc5, 0x37, 0x23, 0x0d, 0x1d, 0xf5, 0x6f, 0xa6, 0x83, 0x5f, 0x3e, + 0x1e, 0xb5, 0x18, 0x23, 0xc8, 0x40, 0xae, 0x63, 0x68, 0x79, 0x8e, 0x56, + 0xb0, 0x33, 0x43, 0x08, 0x5b, 0xac, 0x52, 0x39, 0x71, 0x1c, 0xc7, 0x71, + 0x9d, 0xf2, 0x00, 0x73, 0xf8, 0x96, 0xbb, 0x43, 0x5b, 0x59, 0xce, 0x07, + 0xbb, 0x11, 0xc8, 0x43, 0xde, 0xea, 0xb7, 0x34, 0x51, 0xbf, 0xa7, 0x2d, + 0x33, 0x35, 0xc2, 0x40, 0x1c, 0x81, 0x60, 0x63, 0x60, 0x0b, 0xb6, 0x60, + 0xbf, 0xb9, 0x38, 0x0c, 0x02, 0x54, 0x53, 0x20, 0xd9, 0xf9, 0xeb, 0x2f, + 0x7e, 0x5b, 0xdf, 0x58, 0x4b, 0x99, 0x8e, 0x04, 0x27, 0xb4, 0x18, 0x78, + 0xd6, 0x37, 0x16, 0x60, 0x71, 0x1c, 0xc7, 0x71, 0x74, 0x66, 0x66, 0x66, + 0xb2, 0xf1, 0x94, 0x20, 0xad, 0x2f, 0xba, 0x68, 0x6a, 0x33, 0xfe, 0x6e, + 0xa5, 0x51, 0xec, 0x44, 0xab, 0x05, 0x7e, 0x60, 0x48, 0x6b, 0xa5, 0x56, + 0x38, 0x3d, 0xc7, 0x24, 0x99, 0x99, 0x99, 0x59, 0x45, 0x17, 0x5d, 0x74, + 0x55, 0x55, 0x55, 0x35, 0xd8, 0x89, 0x9d, 0x58, 0xb6, 0x6d, 0xdb, 0x76, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f + }; + + unsigned char poseidon_constants_11[] = { + 0xb0, 0xf1, 0x1f, 0x2e, 0xf8, 0x8b, 0xb5, 0x07, 0x8d, 0xc4, 0xe1, 0x46, + 0x99, 0x23, 0x9f, 0x06, 0xcc, 0x64, 0x13, 0x45, 0x9e, 0xb1, 0xdf, 0x5f, + 0xfa, 0x8e, 0x0f, 0x6f, 0x33, 0xd8, 0xfe, 0x19, 0x0a, 0x25, 0x8b, 0x20, + 0xe1, 0x2c, 0xcc, 0x36, 0x17, 0x3f, 0x03, 0x05, 0xe1, 0x13, 0xce, 0x35, + 0xd4, 0xc9, 0xe7, 0x65, 0x1f, 0x7f, 0x2c, 0x7a, 0x93, 0x9f, 0x34, 0x19, + 0x4d, 0x22, 0xf2, 0x7f, 0x8e, 0xa8, 0xb0, 0x51, 0x22, 0x8c, 0x91, 0x30, + 0xa5, 0x9c, 0xff, 0x31, 0x0e, 0x04, 0xc9, 0x19, 0x69, 0x60, 0xee, 0x0f, + 0xc5, 0xa5, 0xeb, 0x6b, 0xb0, 0xa4, 0xaa, 0x5d, 0x1c, 0x4e, 0xeb, 0x73, + 0xec, 0x94, 0xb7, 0x15, 0xce, 0x64, 0x1c, 0x60, 0x3e, 0xa3, 0x6b, 0x4a, + 0x87, 0x7a, 0x25, 0x2f, 0xfc, 0xc3, 0x17, 0x20, 0x06, 0xb6, 0x22, 0x7d, + 0xca, 0xea, 0x8b, 0x3b, 0xf9, 0xca, 0xa4, 0x32, 0xd2, 0xb7, 0x2e, 0x01, + 0x4f, 0x31, 0xc9, 0x2f, 0x10, 0xbf, 0x41, 0x4c, 0xe6, 0xfe, 0xba, 0x49, + 0xe5, 0x89, 0xbb, 0x77, 0x7e, 0xe8, 0x83, 0x1c, 0x72, 0xe7, 0x26, 0x58, + 0x24, 0x90, 0x9d, 0x1e, 0xb3, 0x20, 0xc8, 0x64, 0x84, 0xa3, 0x21, 0x5d, + 0x06, 0x64, 0x30, 0x4b, 0x19, 0x35, 0x96, 0x1e, 0xd1, 0x86, 0x57, 0x4a, + 0xb3, 0x8e, 0xd6, 0x7d, 0xaf, 0xd1, 0xde, 0x3f, 0xa2, 0x2c, 0x32, 0x0a, + 0xbb, 0xea, 0x4a, 0x46, 0x64, 0x1b, 0x72, 0x14, 0x75, 0x85, 0x1b, 0x4d, + 0x11, 0x02, 0x5f, 0x6f, 0x06, 0xdd, 0xd3, 0x6f, 0xbc, 0xcc, 0x77, 0x2e, + 0xb7, 0x43, 0xf4, 0x19, 0x9d, 0x2c, 0x4b, 0x2b, 0x0c, 0x41, 0xb9, 0x02, + 0xdc, 0x14, 0x5a, 0x67, 0xd4, 0x56, 0xca, 0x45, 0x65, 0xd2, 0x7d, 0x17, + 0xcd, 0x91, 0xdd, 0x45, 0xd8, 0xa8, 0xd8, 0x4b, 0xc9, 0x2b, 0xf2, 0x35, + 0xc1, 0x81, 0x6c, 0x33, 0xbc, 0xf4, 0x4d, 0x04, 0xfd, 0xb0, 0x91, 0x2b, + 0xcf, 0xad, 0x39, 0x45, 0x35, 0xb2, 0xac, 0x2e, 0x2f, 0x13, 0xe3, 0x0b, + 0x40, 0x59, 0x33, 0x07, 0xe3, 0xa5, 0xa1, 0x4d, 0x0e, 0x79, 0x05, 0x4c, + 0x36, 0x9b, 0xf1, 0x7f, 0x90, 0x50, 0x46, 0x25, 0x87, 0x10, 0x24, 0x3f, + 0x52, 0x5d, 0xff, 0x18, 0xad, 0xed, 0x78, 0x52, 0x00, 0x9c, 0xfe, 0x66, + 0x22, 0x24, 0xe0, 0x62, 0x13, 0xe2, 0x6f, 0x67, 0xd9, 0xe3, 0x6c, 0x64, + 0x6b, 0xa6, 0xea, 0x53, 0x61, 0x56, 0x8a, 0x33, 0x81, 0x35, 0xe5, 0x0f, + 0x35, 0xc9, 0xf3, 0x59, 0xc2, 0xa8, 0x92, 0x73, 0x69, 0x66, 0x05, 0x70, + 0xa1, 0x5f, 0xec, 0x4e, 0x3d, 0x6b, 0xc0, 0x78, 0xa4, 0xcb, 0xfc, 0x7e, + 0x44, 0x8c, 0xc4, 0x1b, 0x25, 0x70, 0x8f, 0x27, 0x87, 0x76, 0x2d, 0x4f, + 0x70, 0xb0, 0xea, 0x7a, 0x92, 0x43, 0x8c, 0x00, 0xed, 0xfd, 0x3b, 0x23, + 0x69, 0x71, 0x8e, 0x49, 0x83, 0xc3, 0x4e, 0x37, 0xab, 0x18, 0xd9, 0x30, + 0x4d, 0x48, 0x5e, 0x7e, 0xbc, 0x5a, 0x1a, 0x24, 0x34, 0xed, 0x19, 0x57, + 0xf4, 0xf4, 0x0d, 0x02, 0x0c, 0x57, 0xde, 0x6d, 0x40, 0x39, 0x1f, 0x71, + 0x9c, 0xa1, 0xb0, 0x28, 0x2d, 0x05, 0xb9, 0x6b, 0x85, 0x7a, 0x4c, 0x47, + 0x55, 0x55, 0x55, 0x35, 0xd8, 0x89, 0x9d, 0x58, 0xb6, 0x6d, 0xdb, 0x76, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, + 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, + 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32, + 0xd8, 0x89, 0x9d, 0x58, 0xb6, 0x6d, 0xdb, 0x76, 0x11, 0x11, 0x11, 0x11, + 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x38, 0x8e, 0xe3, 0x78, + 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, 0x79, 0x9e, 0xe7, 0x79, + 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32, 0xaa, 0xaa, 0xaa, 0x5a, + 0xb6, 0x6d, 0xdb, 0x76, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, + 0x0f, 0x0f, 0x0f, 0x0f, 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, + 0xcc, 0xcc, 0xcc, 0x6c, 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, + 0xc8, 0x42, 0x16, 0x32, 0xaa, 0xaa, 0xaa, 0x5a, 0x70, 0x3d, 0x0a, 0x57, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, + 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, + 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32, + 0xaa, 0xaa, 0xaa, 0x5a, 0x70, 0x3d, 0x0a, 0x57, 0xec, 0xc4, 0x4e, 0x2c, + 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, 0x38, 0x8e, 0xe3, 0x78, + 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, 0x79, 0x9e, 0xe7, 0x79, + 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32, 0xaa, 0xaa, 0xaa, 0x5a, + 0x70, 0x3d, 0x0a, 0x57, 0xec, 0xc4, 0x4e, 0x2c, 0x7b, 0x09, 0xed, 0x25, + 0x0f, 0x0f, 0x0f, 0x0f, 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, + 0xcc, 0xcc, 0xcc, 0x6c, 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, + 0xc8, 0x42, 0x16, 0x32, 0xaa, 0xaa, 0xaa, 0x5a, 0x70, 0x3d, 0x0a, 0x57, + 0xec, 0xc4, 0x4e, 0x2c, 0x7b, 0x09, 0xed, 0x25, 0xdb, 0xb6, 0x6d, 0x3b, + 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, + 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32, + 0xaa, 0xaa, 0xaa, 0x5a, 0x70, 0x3d, 0x0a, 0x57, 0xec, 0xc4, 0x4e, 0x2c, + 0x7b, 0x09, 0xed, 0x25, 0xdb, 0xb6, 0x6d, 0x3b, 0x61, 0xb9, 0xa7, 0x11, + 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, 0x79, 0x9e, 0xe7, 0x79, + 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32, 0xaa, 0xaa, 0xaa, 0x5a, + 0x70, 0x3d, 0x0a, 0x57, 0xec, 0xc4, 0x4e, 0x2c, 0x7b, 0x09, 0xed, 0x25, + 0xdb, 0xb6, 0x6d, 0x3b, 0x61, 0xb9, 0xa7, 0x11, 0x88, 0x88, 0x88, 0x48, + 0xcc, 0xcc, 0xcc, 0x6c, 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, + 0xc8, 0x42, 0x16, 0x32, 0xaa, 0xaa, 0xaa, 0x5a, 0x70, 0x3d, 0x0a, 0x57, + 0xec, 0xc4, 0x4e, 0x2c, 0x7b, 0x09, 0xed, 0x25, 0xdb, 0xb6, 0x6d, 0x3b, + 0x61, 0xb9, 0xa7, 0x11, 0x88, 0x88, 0x88, 0x48, 0xbd, 0xf7, 0xde, 0x7b, + 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32, + 0xaa, 0xaa, 0xaa, 0x5a, 0x70, 0x3d, 0x0a, 0x57, 0xec, 0xc4, 0x4e, 0x2c, + 0x7b, 0x09, 0xed, 0x25, 0xdb, 0xb6, 0x6d, 0x3b, 0x61, 0xb9, 0xa7, 0x11, + 0x88, 0x88, 0x88, 0x48, 0xbd, 0xf7, 0xde, 0x7b, 0x00, 0x00, 0x00, 0x04, + 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32, 0xaa, 0xaa, 0xaa, 0x5a, + 0x70, 0x3d, 0x0a, 0x57, 0xec, 0xc4, 0x4e, 0x2c, 0x7b, 0x09, 0xed, 0x25, + 0xdb, 0xb6, 0x6d, 0x3b, 0x61, 0xb9, 0xa7, 0x11, 0x88, 0x88, 0x88, 0x48, + 0xbd, 0xf7, 0xde, 0x7b, 0x00, 0x00, 0x00, 0x04, 0xc1, 0x07, 0x1f, 0x7c, + 0xc8, 0x42, 0x16, 0x32, 0xaa, 0xaa, 0xaa, 0x5a, 0x70, 0x3d, 0x0a, 0x57, + 0xec, 0xc4, 0x4e, 0x2c, 0x7b, 0x09, 0xed, 0x25, 0xdb, 0xb6, 0x6d, 0x3b, + 0x61, 0xb9, 0xa7, 0x11, 0x88, 0x88, 0x88, 0x48, 0xbd, 0xf7, 0xde, 0x7b, + 0x00, 0x00, 0x00, 0x04, 0xc1, 0x07, 0x1f, 0x7c, 0x87, 0x87, 0x87, 0x47, + 0x55, 0x55, 0x55, 0x35, 0x7c, 0xec, 0xe8, 0x54, 0x5f, 0xc4, 0x1c, 0x7e, + 0x02, 0x38, 0x4e, 0x55, 0x86, 0x80, 0x6d, 0x71, 0xc3, 0xa8, 0x98, 0x4a, + 0x2b, 0xaa, 0x86, 0x63, 0x60, 0xd7, 0x4f, 0x2e, 0xb4, 0xac, 0xce, 0x78, + 0xbd, 0x1c, 0x4f, 0x55, 0x6b, 0x2c, 0x33, 0x64, 0x8c, 0x56, 0x30, 0x43, + 0xd8, 0x89, 0x9d, 0x58, 0xdd, 0x29, 0xc3, 0x15, 0x02, 0x15, 0x5b, 0x4f, + 0xdc, 0xb9, 0x0c, 0x03, 0x9a, 0x8d, 0x4d, 0x53, 0x6e, 0xf2, 0x33, 0x15, + 0xed, 0x3f, 0x16, 0x06, 0x43, 0xab, 0x59, 0x54, 0x1a, 0x62, 0xcd, 0x3a, + 0xda, 0x77, 0xa8, 0x51, 0x42, 0x58, 0x05, 0x55, 0x39, 0xeb, 0xd1, 0x45, + 0xb6, 0x6d, 0xdb, 0x76, 0x02, 0x15, 0x5b, 0x4f, 0xb9, 0x5a, 0x8c, 0x36, + 0x9a, 0x63, 0x3e, 0x3c, 0xe6, 0x28, 0x72, 0x36, 0x51, 0x89, 0xdb, 0x3b, + 0xfa, 0xe0, 0x07, 0x07, 0x30, 0xb3, 0x56, 0x39, 0x91, 0x42, 0x86, 0x38, + 0xda, 0xd2, 0x8f, 0x67, 0x75, 0xca, 0x3e, 0x69, 0xe9, 0xd8, 0x07, 0x6f, + 0x11, 0x11, 0x11, 0x11, 0xdc, 0xb9, 0x0c, 0x03, 0x9a, 0x63, 0x3e, 0x3c, + 0x54, 0xdc, 0x52, 0x1f, 0xf3, 0xc8, 0xb6, 0x6b, 0x96, 0x31, 0xf8, 0x1b, + 0x20, 0xee, 0x0b, 0x07, 0x4c, 0x37, 0x80, 0x4b, 0x31, 0x99, 0xd0, 0x09, + 0xb8, 0xa5, 0x62, 0x5f, 0xa2, 0x72, 0xfb, 0x33, 0x11, 0xd8, 0x0e, 0x65, + 0x00, 0x00, 0x00, 0x08, 0x9a, 0x8d, 0x4d, 0x53, 0xe6, 0x28, 0x72, 0x36, + 0xf3, 0xc8, 0xb6, 0x6b, 0xef, 0x80, 0xab, 0x77, 0x4d, 0x49, 0x25, 0x2b, + 0x7e, 0x10, 0x08, 0x1b, 0x70, 0x22, 0x72, 0x66, 0x8b, 0xe6, 0x06, 0x3a, + 0x58, 0xb9, 0x7e, 0x02, 0x97, 0xf4, 0xc2, 0x4f, 0x6b, 0x9a, 0x68, 0x53, + 0x0f, 0x0f, 0x0f, 0x0f, 0x6e, 0xf2, 0x33, 0x15, 0x51, 0x89, 0xdb, 0x3b, + 0x96, 0x31, 0xf8, 0x1b, 0x4d, 0x49, 0x25, 0x2b, 0xe2, 0xe0, 0x5c, 0x64, + 0xb6, 0x1d, 0x73, 0x13, 0x38, 0x1b, 0xfd, 0x49, 0xe1, 0x2c, 0xce, 0x5d, + 0x2a, 0x6b, 0xb4, 0x17, 0x7e, 0xa9, 0x6e, 0x72, 0x2f, 0x77, 0x47, 0x79, + 0x38, 0x8e, 0xe3, 0x78, 0xed, 0x3f, 0x16, 0x06, 0xfa, 0xe0, 0x07, 0x07, + 0x20, 0xee, 0x0b, 0x07, 0x7e, 0x10, 0x08, 0x1b, 0xb6, 0x1d, 0x73, 0x13, + 0xca, 0x4a, 0x44, 0x68, 0x1c, 0x93, 0xbc, 0x37, 0xfa, 0x14, 0x8b, 0x55, + 0xae, 0xe0, 0xac, 0x31, 0xcb, 0x04, 0x09, 0x46, 0x27, 0x8f, 0x96, 0x07, + 0x28, 0xaf, 0xa1, 0x3c, 0x43, 0xab, 0x59, 0x54, 0x30, 0xb3, 0x56, 0x39, + 0x4c, 0x37, 0x80, 0x4b, 0x70, 0x22, 0x72, 0x66, 0x38, 0x1b, 0xfd, 0x49, + 0x1c, 0x93, 0xbc, 0x37, 0xfb, 0xdd, 0xff, 0x41, 0x73, 0x22, 0xa8, 0x31, + 0xd4, 0xc3, 0x26, 0x2b, 0xe7, 0x8c, 0xce, 0x35, 0x03, 0x29, 0x9c, 0x43, + 0xcc, 0xcc, 0xcc, 0x6c, 0x1a, 0x62, 0xcd, 0x3a, 0x91, 0x42, 0x86, 0x38, + 0x31, 0x99, 0xd0, 0x09, 0x8b, 0xe6, 0x06, 0x3a, 0xe1, 0x2c, 0xce, 0x5d, + 0xfa, 0x14, 0x8b, 0x55, 0x73, 0x22, 0xa8, 0x31, 0xaf, 0x9f, 0x0d, 0x2d, + 0xd8, 0xf1, 0xd2, 0x43, 0x41, 0x60, 0x7a, 0x48, 0xca, 0xa1, 0x4c, 0x7c, + 0x79, 0x9e, 0xe7, 0x79, 0xda, 0x77, 0xa8, 0x51, 0xda, 0xd2, 0x8f, 0x67, + 0xb8, 0xa5, 0x62, 0x5f, 0x58, 0xb9, 0x7e, 0x02, 0x2a, 0x6b, 0xb4, 0x17, + 0xae, 0xe0, 0xac, 0x31, 0xd4, 0xc3, 0x26, 0x2b, 0xd8, 0xf1, 0xd2, 0x43, + 0x38, 0xc4, 0xc5, 0x55, 0x39, 0x3d, 0x1f, 0x4c, 0x81, 0xa8, 0x99, 0x14, + 0xa2, 0x8b, 0x2e, 0x7a, 0x42, 0x58, 0x05, 0x55, 0x75, 0xca, 0x3e, 0x69, + 0xa2, 0x72, 0xfb, 0x33, 0x97, 0xf4, 0xc2, 0x4f, 0x7e, 0xa9, 0x6e, 0x72, + 0xcb, 0x04, 0x09, 0x46, 0xe7, 0x8c, 0xce, 0x35, 0x41, 0x60, 0x7a, 0x48, + 0x39, 0x3d, 0x1f, 0x4c, 0xc3, 0x27, 0xbb, 0x1a, 0x86, 0xb4, 0x97, 0x00, + 0xc8, 0x42, 0x16, 0x32, 0x39, 0xeb, 0xd1, 0x45, 0xe9, 0xd8, 0x07, 0x6f, + 0x11, 0xd8, 0x0e, 0x65, 0x6b, 0x9a, 0x68, 0x53, 0x2f, 0x77, 0x47, 0x79, + 0x27, 0x8f, 0x96, 0x07, 0x03, 0x29, 0x9c, 0x43, 0xca, 0xa1, 0x4c, 0x7c, + 0x81, 0xa8, 0x99, 0x14, 0x86, 0xb4, 0x97, 0x00, 0x0c, 0xd8, 0x29, 0x37, + 0x55, 0x55, 0x55, 0x35, 0xcc, 0xab, 0xe7, 0x58, 0x82, 0xaa, 0xb7, 0x06, + 0x3c, 0x2a, 0x3d, 0x61, 0x45, 0xbd, 0xcc, 0x4b, 0xa9, 0x83, 0x44, 0x56, + 0x16, 0xe6, 0x58, 0x6e, 0x70, 0x4b, 0x3a, 0x44, 0xe2, 0x3b, 0x37, 0x60, + 0xf0, 0x3b, 0x41, 0x1e, 0x44, 0x40, 0x84, 0x5a, 0x63, 0x5d, 0x4d, 0x78, + 0x22, 0x80, 0xb3, 0x0f, 0xe0, 0x85, 0xec, 0x77, 0xe5, 0x3d, 0xda, 0x27, + 0x55, 0xf9, 0xfd, 0x44, 0x38, 0xa7, 0x0f, 0x0a, 0x2f, 0xec, 0xda, 0x34, + 0x24, 0xef, 0x00, 0x40, 0x54, 0x9a, 0x0b, 0x27, 0xf9, 0x85, 0xf4, 0x16, + 0x14, 0x1f, 0x17, 0x30, 0x1d, 0xb0, 0xdf, 0x31, 0x55, 0x55, 0x55, 0x35, + 0x98, 0x36, 0x7e, 0x31, 0xd0, 0xda, 0x0a, 0x16, 0xae, 0xb0, 0x6a, 0x00, + 0x0e, 0x7a, 0x7e, 0x6d, 0x93, 0x81, 0x4d, 0x21, 0x45, 0x5a, 0x4d, 0x20, + 0x42, 0x5d, 0xfd, 0x49, 0x28, 0xc5, 0xe2, 0x75, 0x45, 0x85, 0x03, 0x2c, + 0xfc, 0x78, 0x72, 0x15, 0x98, 0x9c, 0x88, 0x0b, 0xed, 0x8f, 0x6f, 0x2b, + 0x55, 0x75, 0x17, 0x5f, 0xe5, 0xed, 0x21, 0x52, 0x5a, 0x34, 0x10, 0x7d, + 0x42, 0x25, 0x57, 0x6a, 0xa4, 0xb2, 0xe6, 0x2e, 0x05, 0xa8, 0xc4, 0x17, + 0xff, 0x9c, 0x7f, 0x6f, 0x23, 0x64, 0x17, 0x44, 0x85, 0xa9, 0x6b, 0x46, + 0x66, 0x58, 0x1b, 0x3b, 0x55, 0x55, 0x55, 0x35, 0x55, 0xf6, 0xca, 0x06, + 0x68, 0x75, 0xa9, 0x55, 0x54, 0x44, 0x4f, 0x61, 0x65, 0x3b, 0x96, 0x37, + 0xa9, 0x89, 0xb6, 0x47, 0x70, 0x8a, 0x8d, 0x74, 0x09, 0x53, 0x9e, 0x5e, + 0x92, 0x56, 0x2b, 0x34, 0x3e, 0x9d, 0x12, 0x0a, 0x54, 0x98, 0xf8, 0x29, + 0xde, 0xa0, 0xdd, 0x11, 0x46, 0x3e, 0x0f, 0x70, 0xff, 0xee, 0x0d, 0x7c, + 0x48, 0xe0, 0xe1, 0x6d, 0xb6, 0x5a, 0x2f, 0x7c, 0xb1, 0xb2, 0xf7, 0x2f, + 0xda, 0x64, 0x33, 0x7e, 0x87, 0x48, 0x48, 0x7e, 0x95, 0x6c, 0xd5, 0x5c, + 0x26, 0x8f, 0xc9, 0x3e, 0xf9, 0x5e, 0x99, 0x38, 0xf5, 0x32, 0xc2, 0x66, + 0x55, 0x55, 0x55, 0x35, 0x7f, 0xb1, 0x0f, 0x47, 0xac, 0x5d, 0xec, 0x76, + 0xba, 0x59, 0xc4, 0x7f, 0xfb, 0xdc, 0x32, 0x46, 0xe8, 0x83, 0xe0, 0x0a, + 0xf4, 0xb8, 0x56, 0x36, 0x07, 0x4f, 0x7f, 0x29, 0x31, 0xb8, 0xf4, 0x2c, + 0x7e, 0x42, 0xbd, 0x3e, 0xf1, 0x9d, 0x40, 0x73, 0x51, 0xf1, 0xce, 0x31, + 0x35, 0x7b, 0x0e, 0x48, 0x9e, 0xb9, 0x6e, 0x3b, 0x37, 0x00, 0x57, 0x0c, + 0x15, 0x25, 0x74, 0x64, 0xdd, 0x39, 0x64, 0x5c, 0x0a, 0x5d, 0x08, 0x2b, + 0xf5, 0xe6, 0x0c, 0x3f, 0xe6, 0xce, 0x30, 0x2d, 0x27, 0xc4, 0x07, 0x19, + 0x82, 0xfb, 0x44, 0x08, 0x7b, 0x94, 0x23, 0x69, 0x55, 0x55, 0x55, 0x35, + 0xc7, 0xbe, 0xaf, 0x49, 0xa6, 0x9a, 0x26, 0x30, 0x7c, 0xb2, 0x66, 0x35, + 0xe4, 0x83, 0x46, 0x62, 0xe3, 0x1c, 0x23, 0x07, 0x36, 0x2e, 0xd3, 0x00, + 0xe2, 0x65, 0xc8, 0x51, 0x0c, 0x09, 0x5c, 0x74, 0x13, 0x94, 0xf9, 0x67, + 0x4e, 0x07, 0x26, 0x03, 0xba, 0xb4, 0x3a, 0x7f, 0x38, 0xb4, 0x7c, 0x6a, + 0x44, 0x7a, 0x1c, 0x7b, 0xeb, 0xf9, 0x8b, 0x0b, 0x16, 0xf8, 0x23, 0x36, + 0x7b, 0x89, 0x79, 0x44, 0x80, 0xfe, 0x33, 0x2a, 0x7d, 0x59, 0xe2, 0x1b, + 0x7b, 0xe1, 0xb0, 0x15, 0x21, 0xcb, 0x47, 0x77, 0x23, 0x1a, 0xc0, 0x14, + 0x5b, 0x86, 0x06, 0x2d, 0x55, 0x55, 0x55, 0x35, 0x04, 0xb5, 0x47, 0x27, + 0x1d, 0xb7, 0x22, 0x44, 0xcc, 0x9e, 0xce, 0x7d, 0xf2, 0x75, 0x78, 0x78, + 0x7b, 0x98, 0x99, 0x12, 0xbd, 0x34, 0xe4, 0x43, 0xf0, 0x0a, 0x96, 0x43, + 0xf1, 0x50, 0x1d, 0x0b, 0x86, 0x78, 0xc9, 0x59, 0xc7, 0x78, 0xec, 0x16, + 0x71, 0xaa, 0x0c, 0x56, 0xbf, 0x92, 0xe2, 0x3a, 0xb5, 0x6e, 0x2d, 0x18, + 0xe2, 0xc7, 0x31, 0x67, 0x10, 0xab, 0x9f, 0x27, 0x27, 0x1e, 0xf3, 0x69, + 0xaf, 0x57, 0x42, 0x4c, 0x4f, 0xb4, 0x30, 0x35, 0x00, 0x54, 0xb0, 0x4a, + 0xa2, 0x00, 0x2a, 0x4a, 0x3d, 0x49, 0x58, 0x73, 0xf9, 0x16, 0xb0, 0x01, + 0x55, 0x55, 0x55, 0x35, 0xe4, 0xd5, 0x3f, 0x2e, 0xee, 0x84, 0x47, 0x51, + 0x3f, 0x84, 0xb9, 0x6b, 0x49, 0xb9, 0xae, 0x57, 0x32, 0x5a, 0x04, 0x02, + 0xe1, 0x6a, 0xf1, 0x4b, 0x30, 0x53, 0xf1, 0x05, 0x29, 0x74, 0x75, 0x76, + 0x4a, 0x15, 0x5b, 0x5d, 0xe1, 0xaa, 0x15, 0x1b, 0x62, 0xf5, 0xe8, 0x76, + 0x03, 0xc1, 0xaa, 0x06, 0x13, 0x59, 0xc8, 0x40, 0x84, 0x49, 0xc8, 0x1f, + 0x85, 0x98, 0x55, 0x6b, 0xed, 0x38, 0x45, 0x17, 0xb8, 0xc7, 0xf7, 0x69, + 0xc3, 0x87, 0xd0, 0x17, 0x0a, 0x93, 0xb7, 0x35, 0xc2, 0x45, 0x75, 0x34, + 0x7a, 0x78, 0xff, 0x51, 0x26, 0xd2, 0x59, 0x13, 0x55, 0x55, 0x55, 0x35, + 0x48, 0x38, 0xf7, 0x6e, 0x4f, 0x7d, 0xc7, 0x70, 0x32, 0x5d, 0x5b, 0x7a, + 0x85, 0x35, 0x9c, 0x07, 0x40, 0x08, 0x30, 0x5c, 0x64, 0x69, 0x27, 0x7a, + 0x07, 0x34, 0x90, 0x6c, 0x6e, 0xa6, 0x8e, 0x70, 0xd4, 0xf2, 0xf7, 0x59, + 0x0f, 0x13, 0x17, 0x5d, 0xa8, 0xa9, 0x01, 0x29, 0xad, 0xfd, 0x9a, 0x77, + 0x3c, 0x77, 0xc7, 0x67, 0xd0, 0x43, 0xb1, 0x3f, 0x97, 0x76, 0xe4, 0x72, + 0xd4, 0x82, 0x9a, 0x25, 0xec, 0xef, 0xc3, 0x03, 0xdc, 0xf9, 0x94, 0x3f, + 0xa4, 0x76, 0x88, 0x5a, 0xb8, 0x0f, 0x03, 0x76, 0x58, 0x87, 0x42, 0x11, + 0x28, 0xb7, 0xb0, 0x1d, 0x55, 0x55, 0x55, 0x35, 0x2f, 0xe6, 0x44, 0x75, + 0xf3, 0x0b, 0xe8, 0x68, 0x59, 0x72, 0x1f, 0x16, 0x8c, 0xd0, 0xe3, 0x3c, + 0xcc, 0xfc, 0x77, 0x05, 0xd6, 0x4b, 0x48, 0x78, 0x51, 0x88, 0x4c, 0x5f, + 0x30, 0x43, 0x9c, 0x2f, 0x49, 0x72, 0xba, 0x01, 0xba, 0xae, 0xfe, 0x0b, + 0x94, 0x3f, 0xe7, 0x71, 0x9d, 0xfa, 0x37, 0x06, 0xfc, 0xa2, 0x99, 0x6f, + 0xe2, 0x0d, 0xcf, 0x4b, 0x63, 0x76, 0xec, 0x49, 0xa8, 0xb5, 0x84, 0x0b, + 0x84, 0xa3, 0x75, 0x4f, 0x5e, 0x56, 0xdd, 0x37, 0x1a, 0x7d, 0x6e, 0x34, + 0x95, 0x39, 0x80, 0x1e, 0x58, 0x2e, 0x22, 0x50, 0xd3, 0x46, 0x93, 0x1e, + 0x55, 0x55, 0x55, 0x35, 0xf5, 0x96, 0x5a, 0x5f, 0x9b, 0xc8, 0x58, 0x50, + 0x3e, 0x03, 0xab, 0x16, 0xd5, 0xc6, 0x4c, 0x7f, 0x3f, 0x82, 0xf6, 0x34, + 0x1c, 0x29, 0x22, 0x16, 0x40, 0xdb, 0xe7, 0x71, 0x8b, 0x8a, 0x4b, 0x55, + 0x45, 0xbf, 0xd1, 0x68, 0x4c, 0xbb, 0xe3, 0x43, 0x1b, 0x96, 0x28, 0x3d, + 0x36, 0x4f, 0xdb, 0x58, 0xa8, 0x39, 0xac, 0x38, 0xd3, 0xeb, 0x90, 0x18, + 0x2f, 0xb7, 0x06, 0x1a, 0x5a, 0x82, 0x53, 0x13, 0x77, 0xaf, 0xe0, 0x4d, + 0x9e, 0xe9, 0x39, 0x79, 0xb7, 0xf6, 0xa2, 0x3c, 0x41, 0x9d, 0x14, 0x59, + 0x01, 0x33, 0x36, 0x20, 0x15, 0xe0, 0xe4, 0x15, 0x55, 0x55, 0x55, 0x35, + 0x58, 0x48, 0x07, 0x36, 0x3f, 0x43, 0x1e, 0x05, 0x33, 0x9e, 0x14, 0x45, + 0x69, 0xc8, 0x16, 0x63, 0x5f, 0xab, 0x77, 0x26, 0xf4, 0x08, 0xb0, 0x2e, + 0xf8, 0x31, 0x79, 0x29, 0x37, 0xc9, 0x37, 0x28, 0x55, 0x62, 0xcc, 0x43, + 0xeb, 0x6b, 0xe4, 0x03, 0xfe, 0x82, 0x50, 0x20, 0x2d, 0xdf, 0xf2, 0x7d, + 0xba, 0x07, 0xe2, 0x0e, 0x88, 0x1e, 0x82, 0x2b, 0x87, 0x54, 0x26, 0x39, + 0xdd, 0xee, 0x3e, 0x0b, 0xdc, 0xbf, 0x93, 0x1a, 0x8a, 0xce, 0xa6, 0x39, + 0x5b, 0xaf, 0x8f, 0x00, 0x7a, 0xad, 0x27, 0x71, 0x1e, 0x76, 0xd8, 0x58, + 0x96, 0x36, 0xa3, 0x14, 0x55, 0x55, 0x55, 0x35, 0x76, 0x27, 0x76, 0x62, + 0xa4, 0x9f, 0x05, 0x5a, 0x41, 0x28, 0x49, 0x12, 0x24, 0x18, 0x49, 0x12, + 0x4f, 0xc2, 0xa5, 0x25, 0x0e, 0x0e, 0x3c, 0x3c, 0x01, 0xa7, 0x65, 0x00, + 0x92, 0x9e, 0x17, 0x36, 0xa1, 0x7a, 0x92, 0x27, 0xcf, 0x74, 0xba, 0x4d, + 0xcb, 0x6f, 0x66, 0x68, 0xd8, 0x89, 0x9d, 0x58, 0xb6, 0x6d, 0xdb, 0x76, + 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x08, 0x0f, 0x0f, 0x0f, 0x0f, + 0x38, 0x8e, 0xe3, 0x78, 0x28, 0xaf, 0xa1, 0x3c, 0xcc, 0xcc, 0xcc, 0x6c, + 0x79, 0x9e, 0xe7, 0x79, 0xa2, 0x8b, 0x2e, 0x7a, 0xc8, 0x42, 0x16, 0x32 + }; +} // namespace poseidon_constants +#endif \ No newline at end of file diff --git a/icicle/src/poseidon/kernels.cu b/icicle/include/poseidon/kernels.cuh similarity index 62% rename from icicle/src/poseidon/kernels.cu rename to icicle/include/poseidon/kernels.cuh index 853592924..4afa9878b 100644 --- a/icicle/src/poseidon/kernels.cu +++ b/icicle/include/poseidon/kernels.cuh @@ -1,9 +1,13 @@ -#include "poseidon/poseidon.cuh" +#pragma once +#ifndef POSEIDON_KERNELS_H +#define POSEIDON_KERNELS_H + #include "gpu-utils/modifiers.cuh" +#include "poseidon/constants.cuh" namespace poseidon { template - __global__ void prepare_poseidon_states(S* states, size_t number_of_states, S domain_tag, bool aligned) + __global__ void prepare_poseidon_states(const S* input, S* states, unsigned int number_of_states, const S domain_tag) { int idx = blockIdx.x * blockDim.x + threadIdx.x; int state_number = idx / T; @@ -16,27 +20,27 @@ namespace poseidon { if (element_number == 0) { prepared_element = domain_tag; } else { - if (aligned) { - prepared_element = states[idx]; - } else { - prepared_element = states[idx - 1]; - } + prepared_element = input[idx - state_number - 1]; } - // We need __syncthreads here if the state is not aligned - // because then we need to shift the vector [A, B, 0] -> [D, A, B] - if (!aligned) { __syncthreads(); } - // Store element in state states[idx] = prepared_element; } template - DEVICE_INLINE S sbox_alpha_five(S element) + DEVICE_INLINE S sbox_el(S element, const int alpha) { - S result = S::sqr(element); - result = S::sqr(result); - return result * element; + S result2 = S::sqr(element); + switch (alpha) { + case 3: + return result2 * element; + case 5: + return S::sqr(result2) * element; + case 7: + return S::sqr(result2) * result2 * element; + case 11: + return S::sqr(S::sqr(result2)) * result2 * element; + } } template @@ -71,7 +75,7 @@ namespace poseidon { element = element + constants.round_constants[rc_offset + element_number]; rc_offset += T; } - element = sbox_alpha_five(element); + element = sbox_el(element, constants.alpha); if (!skip_rc) { element = element + constants.round_constants[rc_offset + element_number]; } // Multiply all the states by mds matrix @@ -111,7 +115,7 @@ namespace poseidon { __device__ S partial_round(S state[T], size_t rc_offset, int round_number, const PoseidonConstants& constants) { S element = state[0]; - element = sbox_alpha_five(element); + element = sbox_el(element, constants.alpha); element = element + constants.round_constants[rc_offset]; S* sparse_matrix = &constants.sparse_matrices[(T * 2 - 1) * round_number]; @@ -155,22 +159,58 @@ namespace poseidon { } } - // These function is just doing copy from the states to the output template - __global__ void get_hash_results(S* states, size_t number_of_states, S* out) + __global__ void + squeeze_states_kernel(const S* states, unsigned int number_of_states, unsigned int rate, unsigned int offset, S* out) { int idx = (blockIdx.x * blockDim.x) + threadIdx.x; if (idx >= number_of_states) { return; } - out[idx] = states[idx * T + 1]; + for (int i = 0; i < rate; i++) { + out[idx * rate + i] = states[idx * T + offset + i]; + } } template - __global__ void copy_recursive(S* state, size_t number_of_states, S* out) + cudaError_t poseidon_permutation_kernel( + const S* input, + S* out, + unsigned int number_of_states, + unsigned int input_len, + unsigned int output_len, + const PoseidonConstants& constants, + cudaStream_t& stream) { - int idx = (blockIdx.x * blockDim.x) + threadIdx.x; - if (idx >= number_of_states) { return; } - - state[(idx / (T - 1) * T) + (idx % (T - 1)) + 1] = out[idx]; + S* states; + CHK_IF_RETURN(cudaMallocAsync(&states, number_of_states * T * sizeof(S), stream)); + + prepare_poseidon_states + <<>>( + input, states, number_of_states, constants.domain_tag); + + size_t rc_offset = 0; + full_rounds<<< + PKC::number_of_full_blocks(T, number_of_states), PKC::number_of_threads(T), + sizeof(S) * PKC::hashes_per_block(T) * T, stream>>>( + states, number_of_states, rc_offset, FIRST_FULL_ROUNDS, constants); + rc_offset += T * (constants.full_rounds_half + 1); + + partial_rounds<<>>( + states, number_of_states, rc_offset, constants); + rc_offset += constants.partial_rounds; + + full_rounds<<< + PKC::number_of_full_blocks(T, number_of_states), PKC::number_of_threads(T), + sizeof(S) * PKC::hashes_per_block(T) * T, stream>>>( + states, number_of_states, rc_offset, SECOND_FULL_ROUNDS, constants); + + squeeze_states_kernel + <<>>( + states, number_of_states, output_len, 1, out); + + CHK_IF_RETURN(cudaFreeAsync(states, stream)); + return CHK_LAST(); } -} // namespace poseidon \ No newline at end of file +} // namespace poseidon + +#endif \ No newline at end of file diff --git a/icicle/include/poseidon/poseidon.cuh b/icicle/include/poseidon/poseidon.cuh index 9dd3beea0..8025057d0 100644 --- a/icicle/include/poseidon/poseidon.cuh +++ b/icicle/include/poseidon/poseidon.cuh @@ -8,132 +8,87 @@ #include "gpu-utils/error_handler.cuh" #include "utils/utils.h" +#include "poseidon/kernels.cuh" +#include "poseidon/constants.cuh" +#include "hash/hash.cuh" +using namespace hash; + /** * @namespace poseidon * Implementation of the [Poseidon hash function](https://eprint.iacr.org/2019/458.pdf) * Specifically, the optimized [Filecoin version](https://spec.filecoin.io/algorithms/crypto/poseidon/) */ namespace poseidon { -#define FIRST_FULL_ROUNDS true -#define SECOND_FULL_ROUNDS false - - /** - * For most of the Poseidon configurations this is the case - * TODO: Add support for different full rounds numbers - */ - const int FULL_ROUNDS_DEFAULT = 4; - - /** - * @struct PoseidonConstants - * This constants are enough to define a Poseidon instantce - * @param round_constants A pointer to round constants allocated on the device - * @param mds_matrix A pointer to an mds matrix allocated on the device - * @param non_sparse_matrix A pointer to non sparse matrix allocated on the device - * @param sparse_matrices A pointer to sparse matrices allocated on the device - */ template - struct PoseidonConstants { - int arity; - int partial_rounds; - int full_rounds_half; - S* round_constants = nullptr; - S* mds_matrix = nullptr; - S* non_sparse_matrix = nullptr; - S* sparse_matrices = nullptr; - S domain_tag; - }; - - /** - * @class PoseidonKernelsConfiguration - * Describes the logic of deriving CUDA kernels parameters - * such as the number of threads and the number of blocks - */ - template - class PoseidonKernelsConfiguration + class Poseidon : public SpongeHasher { public: - // The logic behind this is that 1 thread only works on 1 element - // We have {T} elements in each state, and {number_of_states} states total - static const int number_of_threads = 256 / T * T; + const std::size_t device_id; + PoseidonConstants constants; - // The partial rounds operates on the whole state, so we define - // the parallelism params for processing a single hash preimage per thread - static const int singlehash_block_size = 128; + cudaError_t run_hash_many_kernel( + const S* input, + S* output, + unsigned int number_of_states, + unsigned int input_len, + unsigned int output_len, + const device_context::DeviceContext& ctx) const override + { + cudaError_t permutation_error; +#define P_PERM_T(width) \ + case width: \ + permutation_error = poseidon_permutation_kernel( \ + input, output, number_of_states, input_len, output_len, this->constants, ctx.stream); \ + break; - static const int hashes_per_block = number_of_threads / T; + switch (this->width) { + P_PERM_T(3) + P_PERM_T(5) + P_PERM_T(9) + P_PERM_T(12) + default: + THROW_ICICLE_ERR(IcicleError_t::InvalidArgument, "PoseidonPermutation: #width must be one of [3, 5, 9, 12]"); + } - static int number_of_full_blocks(size_t number_of_states) - { - int total_number_of_threads = number_of_states * T; - return total_number_of_threads / number_of_threads + - static_cast(total_number_of_threads % number_of_threads); + CHK_IF_RETURN(permutation_error); + return CHK_LAST(); } - static int number_of_singlehash_blocks(size_t number_of_states) + Poseidon( + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const S* round_constants, + const S* mds_matrix, + const S* non_sparse_matrix, + const S* sparse_matrices, + const S domain_tag, + device_context::DeviceContext& ctx) + : SpongeHasher(arity + 1, arity, arity, 1), device_id(ctx.device_id) { - return number_of_states / singlehash_block_size + static_cast(number_of_states % singlehash_block_size); + PoseidonConstants constants; + CHK_STICKY(create_optimized_poseidon_constants( + arity, alpha, partial_rounds, full_rounds_half, round_constants, mds_matrix, non_sparse_matrix, sparse_matrices, + domain_tag, &constants, ctx)); + this->constants = constants; } - }; - template - using PKC = PoseidonKernelsConfiguration; + Poseidon(int arity, device_context::DeviceContext& ctx) + : SpongeHasher(arity + 1, arity, arity, 1), device_id(ctx.device_id) + { + PoseidonConstants constants{}; + CHK_STICKY(init_optimized_poseidon_constants(arity, ctx, &constants)); + this->constants = constants; + } - /** - * @struct PoseidonConfig - * Struct that encodes various Poseidon parameters. - */ - struct PoseidonConfig { - device_context::DeviceContext ctx; /**< Details related to the device such as its id and stream id. */ - bool are_inputs_on_device; /**< True if inputs are on device and false if they're on host. Default value: false. */ - bool are_outputs_on_device; /**< If true, output is preserved on device, otherwise on host. Default value: false. */ - bool input_is_a_state; /**< If true, input is considered to be a states vector, holding the preimages - * in aligned or not aligned format. Memory under the input pointer will be used for states - * If false, fresh states memory will be allocated and input will be copied into it */ - bool aligned; /**< If true - input should be already aligned for poseidon permutation. - * Aligned format: [0, A, B, 0, C, D, ...] (as you might get by using loop_state) - * not aligned format: [A, B, 0, C, D, 0, ...] (as you might get from cudaMemcpy2D) */ - bool loop_state; /**< If true, hash results will also be copied in the input pointer in aligned format */ - bool is_async; /**< Whether to run the Poseidon asynchronously. If set to `true`, the poseidon_hash function will be - * non-blocking and you'd need to synchronize it explicitly by running - * `cudaStreamSynchronize` or `cudaDeviceSynchronize`. If set to false, the poseidon_hash - * function will block the current CPU thread. */ + ~Poseidon() + { + auto ctx = device_context::get_default_device_context(); + ctx.device_id = this->device_id; + CHK_STICKY(release_optimized_poseidon_constants(&this->constants, ctx)); + } }; - - static PoseidonConfig default_poseidon_config( - int t, const device_context::DeviceContext& ctx = device_context::get_default_device_context()) - { - PoseidonConfig config = { - ctx, // ctx - false, // are_inputes_on_device - false, // are_outputs_on_device - false, // input_is_a_state - false, // aligned - false, // loop_state - false, // is_async - }; - return config; - } - - /** - * Loads pre-calculated optimized constants, moves them to the device - */ - template - cudaError_t - init_optimized_poseidon_constants(int arity, device_context::DeviceContext& ctx, PoseidonConstants* constants); - - /** - * Compute the poseidon hash over a sequence of preimages. - * Takes {number_of_states * (T-1)} elements of input and computes {number_of_states} hash images - * @param T size of the poseidon state, should be equal to {arity + 1} - * @param input a pointer to the input data. May be allocated on device or on host, regulated - * by the config. May point to a string of preimages or a string of states filled with preimages. - * @param output a pointer to the output data. May be allocated on device or on host, regulated - * by the config. Must be at least of size [number_of_states](@ref number_of_states) - * @param number_of_states number of input blocks of size T-1 (arity) - */ - template - cudaError_t poseidon_hash( - S* input, S* output, size_t number_of_states, const PoseidonConstants& constants, const PoseidonConfig& config); } // namespace poseidon #endif \ No newline at end of file diff --git a/icicle/include/poseidon/tree/merkle.cuh b/icicle/include/poseidon/tree/merkle.cuh deleted file mode 100644 index 73405d364..000000000 --- a/icicle/include/poseidon/tree/merkle.cuh +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once -#ifndef MERKLE_H -#define MERKLE_H - -#include "gpu-utils/device_context.cuh" -#include "gpu-utils/error_handler.cuh" -#include "utils/utils.h" -#include "poseidon/poseidon.cuh" - -#include -#include - -using namespace poseidon; - -/** - * @namespace merkle - * Implementation of the [Poseidon](@ref poseidon) [Merkle tree](https://en.wikipedia.org/wiki/Merkle_tree) builder, - * parallelized for the use on GPU - */ -namespace merkle { - static constexpr size_t GIGA = 1024 * 1024 * 1024; - - /// Bytes per stream - static constexpr size_t STREAM_CHUNK_SIZE = 1024 * 1024 * 1024; - - /** - * @struct TreeBuilderConfig - * Struct that encodes various Tree builder parameters. - */ - struct TreeBuilderConfig { - device_context::DeviceContext ctx; /**< Details related to the device such as its id and stream id. */ - int keep_rows; /**< How many rows of the Merkle tree rows should be written to output. '0' means all of them */ - bool are_inputs_on_device; /**< True if inputs are on device and false if they're on host. Default value: false. */ - bool is_async; /**< Whether to run the tree builder asynchronously. If set to `true`, the build_merkle_tree - * function will be non-blocking and you'd need to synchronize it explicitly by running - * `cudaStreamSynchronize` or `cudaDeviceSynchronize`. If set to false, the - * function will block the current CPU thread. */ - }; - - static TreeBuilderConfig - default_merkle_config(const device_context::DeviceContext& ctx = device_context::get_default_device_context()) - { - TreeBuilderConfig config = { - ctx, // ctx - 0, // keep_rows - false, // are_inputes_on_device - false, // is_async - }; - return config; - } - - /** - * Builds the Poseidon Merkle tree - * - * @param leaves a pointer to the leaves layer. May be allocated on device or on host, regulated by the config - * Expected to have arity ^ (height - 1) elements - * @param digests a pointer to the digests storage. May only be allocated on the host - * Expected to have `sum(arity ^ (i)) for i in [0..height-1]` - * @param height the height of the merkle tree - * # Algorithm - * The function will split large tree into many subtrees of size that will fit `STREAM_CHUNK_SIZE`. - * Each subtree is build in it's own stream (there is a maximum number of streams) - * After all subtrees are constructed - the function will combine the resulting sub-digests into the final top-tree - */ - template - cudaError_t build_merkle_tree( - const S* leaves, - S* digests, - uint32_t height, - const PoseidonConstants& poseidon, - const TreeBuilderConfig& config); -} // namespace merkle - -#endif \ No newline at end of file diff --git a/icicle/include/poseidon2/constants.cuh b/icicle/include/poseidon2/constants.cuh new file mode 100644 index 000000000..35bc2ebf3 --- /dev/null +++ b/icicle/include/poseidon2/constants.cuh @@ -0,0 +1,65 @@ +#pragma once +#ifndef POSEIDON2_CONSTANTS_H +#define POSEIDON2_CONSTANTS_H + +#include "gpu-utils/device_context.cuh" + +namespace poseidon2 { + /** + * For most of the Poseidon2 configurations this is the case + */ + const int EXTERNAL_ROUNDS_DEFAULT = 8; + + enum DiffusionStrategy { + DEFAULT_DIFFUSION, + MONTGOMERY, + }; + + enum MdsType { DEFAULT_MDS, PLONKY }; + + /** + * @struct Poseidon2Constants + * This constants are enough to define a Poseidon2 instantce + * @param round_constants A pointer to round constants allocated on the device + * @param mds_matrix A pointer to an mds matrix allocated on the device + * @param non_sparse_matrix A pointer to non sparse matrix allocated on the device + * @param sparse_matrices A pointer to sparse matrices allocated on the device + */ + template + struct Poseidon2Constants { + int width; + int alpha; + int internal_rounds; + int external_rounds; + S* round_constants = nullptr; + S* internal_matrix_diag = nullptr; + MdsType mds_type; + DiffusionStrategy diffusion; + }; + + template + cudaError_t create_poseidon2_constants( + int width, + int alpha, + int internal_rounds, + int external_rounds, + const S* round_constants, + const S* internal_matrix_diag, + MdsType mds_type, + DiffusionStrategy diffusion, + device_context::DeviceContext& ctx, + Poseidon2Constants* poseidon_constants); + + template + cudaError_t init_poseidon2_constants( + int width, + MdsType mds_type, + DiffusionStrategy diffusion, + device_context::DeviceContext& ctx, + Poseidon2Constants* poseidon2_constants); + + template + cudaError_t release_poseidon2_constants(Poseidon2Constants* constants, device_context::DeviceContext& ctx); +} // namespace poseidon2 + +#endif \ No newline at end of file diff --git a/icicle/include/poseidon2/constants/m31_poseidon2.h b/icicle/include/poseidon2/constants/m31_poseidon2.h new file mode 100644 index 000000000..c1712ea34 --- /dev/null +++ b/icicle/include/poseidon2/constants/m31_poseidon2.h @@ -0,0 +1,1077 @@ +#pragma once +#ifndef M31_POSEIDON2_H +#define M31_POSEIDON2_H + +namespace poseidon2_constants_m31 { + + namespace t2 { + int internal_rounds = 25; + + int alpha = 5; + + unsigned char mat_diag_m_1[] = { + 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + }; + + unsigned char round_constants[] = { + 0xb4, 0x5a, 0x7e, 0x4c, + 0x13, 0xa1, 0x81, 0x59, + 0x0f, 0xae, 0x6a, 0x77, + 0x47, 0xb6, 0xf3, 0x23, + 0xa3, 0x99, 0x3f, 0x33, + 0x09, 0xb9, 0xe2, 0x78, + 0xd4, 0x7f, 0x45, 0x72, + 0x8a, 0xe1, 0xfe, 0x67, + 0x5d, 0x1e, 0x9c, 0x74, + 0xa5, 0x3d, 0x15, 0x20, + 0x9c, 0x36, 0x8a, 0x28, + 0x1a, 0x48, 0xbb, 0x39, + 0x33, 0x90, 0x4d, 0x58, + 0x89, 0x86, 0xb3, 0x4f, + 0xc8, 0xda, 0x69, 0x27, + 0xc0, 0xc5, 0x50, 0x13, + 0x89, 0xe6, 0xbd, 0x31, + 0x82, 0x9c, 0x39, 0x4d, + 0xba, 0xe4, 0x51, 0x31, + 0x21, 0x7c, 0xc6, 0x56, + 0x36, 0xae, 0xae, 0x12, + 0x90, 0x08, 0x7b, 0x7e, + 0x2c, 0x52, 0xfc, 0x28, + 0x76, 0x6e, 0x76, 0x74, + 0x30, 0x83, 0xd5, 0x57, + 0x35, 0xea, 0x14, 0x34, + 0x41, 0xc4, 0xe5, 0x38, + 0x12, 0x97, 0x36, 0x1e, + 0xf3, 0xd9, 0xb6, 0x15, + 0x0a, 0x49, 0x08, 0x48, + 0x06, 0xf3, 0xd3, 0x0a, + 0x9e, 0x4d, 0xdd, 0x70, + 0x0f, 0xa8, 0xf5, 0x47, + 0x7d, 0x0a, 0x0f, 0x67, + 0xf5, 0x15, 0x95, 0x06, + 0x6b, 0xc7, 0xe1, 0x33, + 0xeb, 0xa4, 0x88, 0x13, + 0xb2, 0x2d, 0x4f, 0x37, + 0x9a, 0xf7, 0x48, 0x06, + 0x69, 0xc1, 0x18, 0x34, + 0x81, 0x51, 0x73, 0x60, + 0x19, 0x5d, 0x03, 0x71, + 0xaf, 0x79, 0x18, 0x56, + 0x93, 0x61, 0x9d, 0x64, + 0xa3, 0xb0, 0xfd, 0x26, + 0x1d, 0x81, 0x50, 0x0a, + 0x13, 0xc9, 0x91, 0x1e, + 0xd9, 0xcd, 0x3b, 0x29, + 0x10, 0xdb, 0xdc, 0x01, + }; + } + + + namespace t3 { + int internal_rounds = 19; + + int alpha = 5; + + unsigned char mat_diag_m_1[] = { + 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + }; + + unsigned char round_constants[] = { + 0x0a, 0x42, 0x30, 0x66, + 0xb5, 0xb6, 0x77, 0x6e, + 0xf3, 0xad, 0x5b, 0x08, + 0x3c, 0x7b, 0xd1, 0x06, + 0xbb, 0xa8, 0x2c, 0x2d, + 0x13, 0x5d, 0x58, 0x3e, + 0x9c, 0xd2, 0x96, 0x7f, + 0x89, 0x0c, 0xc6, 0x02, + 0x5d, 0xc7, 0x73, 0x3d, + 0x92, 0x53, 0x68, 0x44, + 0xb7, 0xb9, 0x45, 0x75, + 0xe4, 0xb4, 0xab, 0x14, + 0x37, 0x85, 0xbc, 0x18, + 0xc1, 0x93, 0x4f, 0x20, + 0x64, 0xb3, 0x81, 0x40, + 0x9b, 0x9f, 0xbe, 0x5c, + 0xa1, 0x90, 0x9f, 0x7f, + 0xc2, 0x7b, 0xbf, 0x3c, + 0xab, 0x6e, 0x8a, 0x26, + 0x11, 0x34, 0x24, 0x6f, + 0xf8, 0x54, 0x75, 0x2c, + 0x61, 0x2c, 0xab, 0x5f, + 0xae, 0x76, 0x13, 0x11, + 0xbe, 0x0e, 0xfe, 0x2c, + 0x29, 0xe7, 0xb2, 0x36, + 0xd3, 0x9a, 0x90, 0x29, + 0xd6, 0x20, 0xb8, 0x28, + 0x5d, 0x3e, 0x32, 0x54, + 0x2e, 0x4d, 0x6e, 0x78, + 0xd3, 0x30, 0x4f, 0x32, + 0x17, 0x3d, 0xf9, 0x65, + 0xb2, 0x73, 0x8c, 0x4f, + 0x34, 0xfe, 0xd9, 0x23, + 0xd1, 0x9b, 0x90, 0x17, + 0x54, 0x4a, 0x86, 0x74, + 0x84, 0xda, 0x20, 0x71, + 0x76, 0x83, 0x23, 0x4c, + 0x1e, 0x79, 0xd0, 0x28, + 0xb1, 0x4a, 0x4f, 0x15, + 0x7e, 0x49, 0xcd, 0x27, + 0x16, 0x8f, 0xd4, 0x32, + 0xb6, 0x68, 0x5e, 0x00, + 0x9b, 0x83, 0x6a, 0x68, + 0xfb, 0xc8, 0x24, 0x3c, + 0xd5, 0x22, 0x07, 0x53, + 0x9a, 0x79, 0xfe, 0x23, + 0x5f, 0xc0, 0x5d, 0x23, + 0x00, 0xa5, 0x12, 0x19, + 0xb0, 0xc2, 0xb5, 0x5b, + 0xd7, 0xd7, 0x42, 0x57, + 0x06, 0x76, 0x47, 0x37, + 0x71, 0x04, 0x60, 0x1d, + 0x2c, 0x8b, 0x7a, 0x42, + 0xcd, 0xec, 0x89, 0x7d, + 0x19, 0x10, 0x8e, 0x37, + }; + } + + + namespace t4 { + int internal_rounds = 22; + + int alpha = 5; + + unsigned char mat_diag_m_1[] = { + 0x7c, 0x10, 0x15, 0x0f, + 0x64, 0xfa, 0x28, 0x46, + 0xb8, 0x12, 0x41, 0x25, + 0xcb, 0x04, 0xa0, 0x08, + }; + + unsigned char round_constants[] = { + 0x22, 0x2c, 0xaf, 0x16, + 0x6b, 0xcd, 0x04, 0x78, + 0x4a, 0x23, 0x6e, 0x24, + 0x12, 0xcd, 0xd3, 0x5d, + 0x5c, 0xfb, 0x1b, 0x32, + 0x8b, 0x35, 0x50, 0x59, + 0x46, 0xa4, 0x64, 0x72, + 0x5e, 0x32, 0xa0, 0x78, + 0xc1, 0x02, 0xc5, 0x56, + 0xdf, 0x26, 0x9d, 0x45, + 0xe9, 0x80, 0xa8, 0x73, + 0xfe, 0x4b, 0xec, 0x41, + 0x2f, 0x74, 0x43, 0x55, + 0x75, 0x82, 0xf6, 0x72, + 0xb1, 0x08, 0xed, 0x19, + 0x79, 0xda, 0x7c, 0x14, + 0xca, 0xe4, 0x7e, 0x63, + 0xb6, 0x81, 0xd1, 0x0a, + 0xe5, 0xa3, 0xcb, 0x06, + 0x1a, 0x58, 0x19, 0x6d, + 0x18, 0xe5, 0x0c, 0x6e, + 0xba, 0xfc, 0xec, 0x67, + 0x3a, 0x16, 0x38, 0x13, + 0xed, 0x88, 0x73, 0x1b, + 0x46, 0x5b, 0x96, 0x33, + 0x53, 0xa5, 0x8f, 0x4e, + 0xf4, 0x11, 0x54, 0x30, + 0xe7, 0x4c, 0x75, 0x58, + 0x3d, 0x54, 0x80, 0x43, + 0xec, 0x78, 0x3f, 0x4f, + 0xa9, 0xaf, 0x2b, 0x7e, + 0x27, 0x6f, 0xe9, 0x60, + 0x74, 0x8e, 0x15, 0x30, + 0xc0, 0xac, 0xdb, 0x64, + 0xdd, 0xee, 0x16, 0x35, + 0xcc, 0x43, 0x06, 0x20, + 0x35, 0x34, 0x4c, 0x71, + 0x39, 0xae, 0xa7, 0x35, + 0x80, 0xd3, 0xa8, 0x22, + 0xb5, 0xc7, 0xb1, 0x17, + 0x89, 0x85, 0x58, 0x14, + 0x1f, 0x32, 0x25, 0x63, + 0x4f, 0x2d, 0xa1, 0x18, + 0x68, 0x2c, 0xd6, 0x1c, + 0xfc, 0xba, 0xf5, 0x1e, + 0x12, 0x30, 0x3f, 0x08, + 0xc0, 0x4d, 0x33, 0x6e, + 0x4d, 0x57, 0x0d, 0x59, + 0x07, 0x3a, 0x21, 0x14, + 0xc4, 0xe1, 0xc3, 0x74, + 0xbd, 0xc4, 0x7f, 0x4b, + 0x3d, 0x25, 0x29, 0x3a, + 0x30, 0x82, 0x4b, 0x01, + 0x33, 0x80, 0x22, 0x13, + }; + } + + + namespace t8 { + int internal_rounds = 13; + + int alpha = 5; + + unsigned char mat_diag_m_1[] = { + 0x56, 0x8b, 0x12, 0x03, + 0xfe, 0x3a, 0x7d, 0x4d, + 0xaa, 0x42, 0x09, 0x35, + 0xed, 0xc3, 0xa8, 0x2e, + 0x48, 0x0b, 0xe8, 0x5c, + 0x80, 0xfd, 0x5a, 0x76, + 0xfb, 0x06, 0x8f, 0x19, + 0x16, 0x2a, 0x1b, 0x7c, + }; + + unsigned char round_constants[] = { + 0x54, 0x07, 0x91, 0x12, + 0xbe, 0x49, 0xed, 0x36, + 0x97, 0x74, 0xc9, 0x07, + 0xed, 0x1f, 0xd7, 0x40, + 0x3c, 0x31, 0xee, 0x2d, + 0x70, 0x44, 0xde, 0x26, + 0xe2, 0x5a, 0x7a, 0x5d, + 0xff, 0x33, 0x1e, 0x1f, + 0x61, 0x0c, 0xc0, 0x13, + 0xf6, 0xe3, 0xc4, 0x0c, + 0xa0, 0x2b, 0xc3, 0x54, + 0x4a, 0xe5, 0x77, 0x4c, + 0x04, 0xcd, 0x51, 0x79, + 0xa2, 0xfa, 0x05, 0x4c, + 0xa0, 0x9d, 0x47, 0x6e, + 0x30, 0x77, 0x11, 0x38, + 0xce, 0xc4, 0x74, 0x73, + 0xea, 0x1a, 0x28, 0x50, + 0x55, 0x2e, 0x23, 0x48, + 0x1e, 0x9d, 0x53, 0x36, + 0xc1, 0x4a, 0x5a, 0x5e, + 0x08, 0x44, 0xea, 0x77, + 0x67, 0xa0, 0xef, 0x1c, + 0xef, 0x05, 0xce, 0x09, + 0x81, 0x4c, 0xd2, 0x26, + 0x15, 0x3b, 0x87, 0x4c, + 0x65, 0xea, 0xd2, 0x77, + 0xb3, 0x8b, 0xb2, 0x56, + 0x8c, 0x9f, 0x2b, 0x2b, + 0xf9, 0xe3, 0x57, 0x4a, + 0xa7, 0x45, 0xc4, 0x32, + 0xc7, 0x41, 0x2f, 0x78, + 0x91, 0x58, 0x20, 0x6c, + 0x5e, 0x3f, 0x50, 0x67, + 0x3f, 0x59, 0x6c, 0x75, + 0x9a, 0x47, 0x62, 0x04, + 0xca, 0xc9, 0x71, 0x42, + 0xce, 0xf3, 0x1a, 0x4d, + 0x99, 0x99, 0x0e, 0x18, + 0xdb, 0x28, 0x53, 0x02, + 0x99, 0x8c, 0x8b, 0x39, + 0x5c, 0x75, 0xf4, 0x03, + 0x5f, 0x4b, 0xc7, 0x68, + 0x81, 0x8c, 0x54, 0x5f, + 0x7f, 0x62, 0x7a, 0x73, + 0x3d, 0xee, 0x77, 0x61, + 0xc7, 0x67, 0x75, 0x48, + 0xf4, 0x94, 0x7f, 0x06, + 0x7d, 0x08, 0xd1, 0x2c, + 0x54, 0x90, 0x4d, 0x30, + 0xab, 0x2b, 0x0e, 0x49, + 0x18, 0x9e, 0x65, 0x5c, + 0xe3, 0xcc, 0x47, 0x7c, + 0xb5, 0x87, 0xa3, 0x61, + 0xf0, 0xde, 0x57, 0x38, + 0x7f, 0x46, 0x24, 0x26, + 0xc8, 0x3c, 0xf5, 0x7e, + 0x58, 0xd3, 0x2a, 0x1d, + 0xf2, 0xaf, 0x6c, 0x79, + 0xfd, 0xc4, 0xea, 0x10, + 0xa5, 0x54, 0x4b, 0x7f, + 0x00, 0x6d, 0x08, 0x35, + 0x5f, 0x00, 0xb5, 0x41, + 0x3e, 0x9f, 0xab, 0x49, + 0xfe, 0xf6, 0x0c, 0x7d, + 0x39, 0x48, 0x90, 0x13, + 0xcd, 0x28, 0xdc, 0x67, + 0x3b, 0x2a, 0x32, 0x28, + 0x95, 0x6b, 0x1d, 0x29, + 0x04, 0x63, 0x5e, 0x4b, + 0x3f, 0x79, 0x4b, 0x5e, + 0xd4, 0xe5, 0x3d, 0x1c, + 0x0e, 0x15, 0xcd, 0x52, + 0x5b, 0x05, 0x52, 0x78, + 0x2b, 0x12, 0x71, 0x3f, + 0x08, 0xa0, 0x8b, 0x40, + 0xd9, 0xde, 0xd7, 0x76, + }; + } + + + namespace t12 { + int internal_rounds = 12; + + int alpha = 5; + + unsigned char mat_diag_m_1[] = { + 0x66, 0x0d, 0xa2, 0x4a, + 0x8c, 0x08, 0x67, 0x37, + 0x8a, 0xbd, 0x82, 0x5e, + 0x8e, 0x01, 0x33, 0x28, + 0x0f, 0x30, 0x42, 0x59, + 0x6c, 0x8a, 0x1b, 0x46, + 0x85, 0x3b, 0x64, 0x3c, + 0x5c, 0xc0, 0x08, 0x4c, + 0xce, 0x76, 0x9f, 0x56, + 0xb1, 0xdb, 0x28, 0x47, + 0xeb, 0x80, 0x8d, 0x75, + 0x3c, 0x82, 0xfa, 0x33, + }; + + unsigned char round_constants[] = { + 0xe0, 0xc0, 0xb6, 0x68, + 0xb5, 0x57, 0xc2, 0x4e, + 0x48, 0xf3, 0xd9, 0x50, + 0x53, 0xcb, 0x34, 0x22, + 0xee, 0xb9, 0xe4, 0x04, + 0xfe, 0x81, 0x59, 0x30, + 0xf9, 0xae, 0x52, 0x33, + 0xa2, 0x33, 0x3c, 0x1c, + 0x8a, 0xf5, 0xac, 0x7a, + 0x97, 0xa8, 0xcb, 0x06, + 0xc0, 0x6f, 0xf4, 0x7a, + 0x08, 0xeb, 0xe5, 0x51, + 0x20, 0x6e, 0x4c, 0x09, + 0x39, 0x0e, 0x46, 0x61, + 0xb7, 0x11, 0x32, 0x69, + 0xe2, 0xb2, 0xca, 0x18, + 0x0e, 0x3d, 0xab, 0x05, + 0x78, 0xb7, 0xc0, 0x61, + 0x71, 0x8d, 0xf6, 0x7f, + 0x5c, 0xb3, 0xed, 0x7e, + 0xc6, 0xa0, 0x1b, 0x06, + 0x70, 0x47, 0x63, 0x26, + 0xa4, 0x02, 0x01, 0x3f, + 0x98, 0xe2, 0xae, 0x4a, + 0xe8, 0xa9, 0xe7, 0x38, + 0x0f, 0x8c, 0xf9, 0x06, + 0xc1, 0x6e, 0x51, 0x75, + 0xc5, 0x57, 0x28, 0x69, + 0x5c, 0x2c, 0x91, 0x1d, + 0xff, 0x84, 0x6d, 0x05, + 0x61, 0x70, 0x2d, 0x2f, + 0xcf, 0x6a, 0xa1, 0x2d, + 0xf8, 0xa6, 0x2a, 0x09, + 0x6c, 0x57, 0xe7, 0x1a, + 0xb1, 0x68, 0xa8, 0x3b, + 0x1b, 0x9a, 0x19, 0x17, + 0x76, 0x0e, 0xad, 0x3c, + 0xe3, 0x37, 0xf2, 0x42, + 0xbc, 0x53, 0x04, 0x7d, + 0xca, 0xc5, 0x8d, 0x08, + 0xf9, 0x8c, 0x28, 0x07, + 0x28, 0x18, 0x1b, 0x5f, + 0xf1, 0xbe, 0x28, 0x44, + 0x7d, 0xdc, 0xce, 0x29, + 0x41, 0x63, 0xe6, 0x49, + 0xd1, 0xa1, 0x72, 0x20, + 0x3e, 0x95, 0x03, 0x68, + 0xd3, 0x35, 0xbc, 0x53, + 0xbd, 0xd9, 0x3d, 0x2b, + 0xe6, 0x95, 0xef, 0x7a, + 0xd0, 0x46, 0x5b, 0x0e, + 0x91, 0x2e, 0x82, 0x7d, + 0xcd, 0xff, 0xa3, 0x74, + 0xe1, 0x40, 0x13, 0x2d, + 0x9a, 0x27, 0x9f, 0x05, + 0x93, 0x7d, 0x90, 0x54, + 0xce, 0xdb, 0x46, 0x3b, + 0x54, 0xf5, 0xaa, 0x77, + 0x09, 0xea, 0xf5, 0x6c, + 0xd7, 0xee, 0x1d, 0x5f, + 0xe5, 0x2a, 0x46, 0x3c, + 0x1f, 0xbb, 0xbd, 0x14, + 0x18, 0xd8, 0x9d, 0x36, + 0xa6, 0xf8, 0x82, 0x0d, + 0xe0, 0x0d, 0xff, 0x1b, + 0x4a, 0xe9, 0xe6, 0x5d, + 0x5a, 0xd6, 0x48, 0x3d, + 0x84, 0x6d, 0xcf, 0x06, + 0x6a, 0xcc, 0x48, 0x7b, + 0xd3, 0x57, 0x7b, 0x44, + 0xc5, 0x78, 0xd5, 0x76, + 0xf7, 0xb1, 0xe6, 0x5b, + 0xa4, 0x1f, 0x9e, 0x53, + 0xc3, 0x78, 0xd2, 0x3b, + 0x1c, 0x1c, 0xbc, 0x09, + 0x20, 0x95, 0xb0, 0x54, + 0xfb, 0x78, 0xd5, 0x6d, + 0xa1, 0xc3, 0x17, 0x78, + 0xef, 0x90, 0x19, 0x12, + 0xa9, 0x0f, 0x46, 0x48, + 0x89, 0xa4, 0xf7, 0x10, + 0x30, 0xeb, 0xc1, 0x2d, + 0x5f, 0xd4, 0xae, 0x6b, + 0xeb, 0xac, 0x88, 0x1f, + 0xf5, 0x49, 0x67, 0x77, + 0xa0, 0xe0, 0xf0, 0x29, + 0x0f, 0x07, 0xaf, 0x39, + 0xa6, 0xad, 0xa0, 0x3b, + 0x7c, 0x03, 0x9d, 0x1c, + 0x8e, 0x53, 0xec, 0x67, + 0x42, 0x95, 0x26, 0x47, + 0x18, 0x37, 0x90, 0x31, + 0x7c, 0x99, 0x7c, 0x3f, + 0xdc, 0xee, 0xda, 0x1e, + 0xc8, 0x88, 0x65, 0x6e, + 0x0e, 0x16, 0xdc, 0x13, + 0xb3, 0x89, 0x65, 0x7a, + 0xe7, 0x2a, 0xa4, 0x0b, + 0x85, 0x73, 0x5c, 0x40, + 0x7f, 0x2e, 0xa5, 0x3f, + 0xd1, 0x72, 0xcb, 0x20, + 0xca, 0x5c, 0x93, 0x65, + 0xa0, 0xce, 0xb5, 0x6c, + 0x04, 0xdd, 0xfc, 0x37, + 0x1d, 0x83, 0xbb, 0x56, + 0x1f, 0xdd, 0xe6, 0x17, + 0x29, 0x87, 0x94, 0x2a, + 0x61, 0x5b, 0xae, 0x68, + }; + } + + + namespace t16 { + int internal_rounds = 14; + + int alpha = 5; + + unsigned char mat_diag_m_1[] = { + 0xc4, 0x0a, 0xb8, 0x07, + 0x33, 0xcb, 0xd9, 0x6b, + 0x9f, 0x3f, 0xee, 0x48, + 0x19, 0xdd, 0x63, 0x4f, + 0xb3, 0x46, 0xc5, 0x18, + 0x8b, 0x9e, 0xf8, 0x5a, + 0xe8, 0x3d, 0xf2, 0x4f, + 0xf6, 0xaa, 0x78, 0x4f, + 0xd4, 0xc6, 0xbd, 0x53, + 0x3e, 0x82, 0x59, 0x5c, + 0x72, 0x1c, 0x47, 0x2a, + 0x79, 0x5e, 0x97, 0x4c, + 0xd4, 0x64, 0xdc, 0x58, + 0x5d, 0x31, 0xe9, 0x06, + 0x86, 0x22, 0xf3, 0x2c, + 0x5d, 0x75, 0xb6, 0x2f, + }; + + unsigned char round_constants[] = { + 0x52, 0xab, 0x8b, 0x76, + 0x7d, 0xab, 0xe0, 0x70, + 0x8a, 0x6c, 0x26, 0x3d, + 0x45, 0x20, 0xa4, 0x6d, + 0x22, 0xef, 0x0f, 0x60, + 0x6b, 0xce, 0xda, 0x41, + 0xd4, 0xbd, 0xf9, 0x64, + 0xfe, 0xd4, 0x42, 0x5d, + 0x6d, 0x51, 0xb1, 0x76, + 0x17, 0xa7, 0xc9, 0x6f, + 0xb6, 0x4f, 0xac, 0x70, + 0xf6, 0x4e, 0x19, 0x00, + 0xe2, 0x44, 0xb6, 0x22, + 0xd5, 0x16, 0x79, 0x1f, + 0xe2, 0x1b, 0x58, 0x47, + 0x23, 0xa1, 0x10, 0x27, + 0x67, 0xe8, 0x84, 0x62, + 0xfe, 0x3a, 0x8d, 0x01, + 0xf3, 0x9e, 0xf9, 0x5d, + 0x7b, 0x46, 0x1e, 0x4c, + 0xbc, 0x6a, 0x6f, 0x56, + 0x27, 0xe4, 0x94, 0x29, + 0x42, 0x6d, 0x8a, 0x53, + 0xcf, 0xf2, 0x7b, 0x5d, + 0xab, 0x2d, 0xda, 0x7f, + 0xc4, 0x54, 0xd8, 0x0f, + 0xca, 0x2f, 0x92, 0x46, + 0xa1, 0x63, 0x77, 0x3d, + 0xca, 0x05, 0xfd, 0x19, + 0x43, 0xbb, 0x4b, 0x0a, + 0x51, 0x58, 0x07, 0x15, + 0x76, 0x3d, 0x90, 0x3d, + 0xf7, 0x0f, 0x29, 0x2d, + 0xa0, 0x9f, 0x80, 0x40, + 0xec, 0xc6, 0xda, 0x59, + 0xa2, 0x27, 0x79, 0x12, + 0xa0, 0x0e, 0xbf, 0x6b, + 0x0f, 0x14, 0x94, 0x02, + 0x76, 0x29, 0x74, 0x24, + 0x81, 0xc0, 0x84, 0x6e, + 0x4a, 0x4f, 0x48, 0x22, + 0x59, 0xae, 0x4c, 0x35, + 0xe1, 0xff, 0x53, 0x04, + 0xcc, 0xa3, 0x47, 0x3f, + 0x4e, 0x20, 0x88, 0x00, + 0x09, 0xe1, 0x66, 0x60, + 0x80, 0x4b, 0x7c, 0x3b, + 0x5d, 0x66, 0x55, 0x6b, + 0x97, 0xb8, 0xc4, 0x3b, + 0x78, 0xf3, 0x5b, 0x73, + 0x42, 0xaf, 0x8d, 0x50, + 0x2b, 0xfc, 0x84, 0x18, + 0x4c, 0xf2, 0x14, 0x72, + 0x0a, 0xbe, 0x98, 0x74, + 0x40, 0xe6, 0x60, 0x1a, + 0x28, 0xf9, 0x03, 0x33, + 0x76, 0x63, 0xb4, 0x29, + 0x68, 0xbb, 0x96, 0x5c, + 0xa5, 0x97, 0xd0, 0x65, + 0x9f, 0x8e, 0x35, 0x1d, + 0x17, 0x90, 0x9a, 0x4a, + 0x76, 0xcf, 0x24, 0x47, + 0x0f, 0xf7, 0x7a, 0x34, + 0x9a, 0xe5, 0x77, 0x1e, + 0xbf, 0xc4, 0x7e, 0x7f, + 0x6f, 0x92, 0x21, 0x04, + 0x69, 0xe6, 0x98, 0x51, + 0x48, 0x31, 0xdb, 0x34, + 0xfd, 0xba, 0x68, 0x43, + 0x7f, 0x5c, 0x68, 0x66, + 0x9a, 0x24, 0xd3, 0x78, + 0x81, 0x78, 0x18, 0x60, + 0x7a, 0xd6, 0xda, 0x76, + 0x37, 0xb4, 0x90, 0x06, + 0x11, 0x53, 0xa9, 0x1e, + 0x9a, 0x36, 0xe5, 0x40, + 0xfc, 0x03, 0xf1, 0x38, + 0x21, 0x6a, 0x22, 0x1d, + 0x13, 0x06, 0x09, 0x57, + 0x08, 0x21, 0xa4, 0x1f, + 0x50, 0xef, 0xbb, 0x17, + 0x1c, 0xe1, 0xf7, 0x1f, + 0xca, 0x24, 0x7b, 0x04, + 0x75, 0x02, 0x14, 0x4e, + 0xf5, 0x86, 0xa0, 0x4f, + 0x9c, 0x30, 0x9b, 0x07, + 0x47, 0xbd, 0x59, 0x11, + 0xe5, 0xe4, 0x37, 0x6d, + 0xce, 0x8d, 0x5d, 0x07, + 0xa0, 0x1c, 0x12, 0x12, + 0x40, 0x7c, 0x6a, 0x7f, + 0xba, 0x82, 0xe1, 0x68, + 0x1b, 0x20, 0x93, 0x54, + 0x0e, 0xa8, 0x44, 0x04, + 0xc6, 0xf4, 0x64, 0x00, + 0xe6, 0xab, 0x67, 0x64, + 0x62, 0x57, 0x97, 0x66, + 0x9b, 0x8f, 0xf6, 0x2a, + 0xbe, 0x33, 0x5b, 0x34, + 0x7f, 0xd4, 0x70, 0x1b, + 0x17, 0xb7, 0x3d, 0x05, + 0xcb, 0x89, 0x11, 0x38, + 0xf8, 0x15, 0xb9, 0x43, + 0x94, 0x36, 0xdf, 0x20, + 0x26, 0x9d, 0x45, 0x0f, + 0x7b, 0xe9, 0xa0, 0x77, + 0x39, 0xe7, 0x73, 0x2f, + 0xf9, 0xc2, 0x76, 0x18, + 0x9a, 0xe2, 0xa0, 0x65, + 0xbe, 0xef, 0xab, 0x4c, + 0x68, 0x12, 0xbd, 0x5a, + 0x60, 0xa7, 0x34, 0x4d, + 0x99, 0x17, 0x77, 0x12, + 0xac, 0xc9, 0xa0, 0x69, + 0x55, 0x1e, 0x09, 0x39, + 0xd0, 0x1c, 0x61, 0x7f, + 0xda, 0x55, 0xf0, 0x3a, + 0xdf, 0xbb, 0xc0, 0x7a, + 0x24, 0x3a, 0x0f, 0x6e, + 0xf7, 0xb6, 0xe3, 0x41, + 0x6d, 0x75, 0xb3, 0x49, + 0x38, 0xc5, 0x8b, 0x56, + 0xd8, 0x79, 0xc0, 0x20, + 0x2c, 0xc7, 0x01, 0x17, + 0x6c, 0xdc, 0x70, 0x76, + 0x35, 0x90, 0x43, 0x5a, + 0x0e, 0xe0, 0x93, 0x7c, + 0x4d, 0xbb, 0x1f, 0x56, + 0x7b, 0x90, 0x78, 0x11, + 0x06, 0x74, 0x73, 0x02, + 0xf1, 0x24, 0xfb, 0x32, + 0x0a, 0xb6, 0x23, 0x63, + 0x18, 0x24, 0xb1, 0x6a, + 0xea, 0x9c, 0xc9, 0x42, + 0x97, 0x0b, 0x5a, 0x15, + 0xaa, 0xc6, 0xd1, 0x53, + 0x47, 0x03, 0xd2, 0x2b, + 0x73, 0x3d, 0x9b, 0x27, + 0x70, 0x3c, 0x5f, 0x4f, + 0x6c, 0xaf, 0x45, 0x02, + 0xd3, 0x59, 0x83, 0x23, + 0x59, 0x6a, 0x96, 0x49, + }; + } + + + namespace t20 { + int internal_rounds = 18; + + int alpha = 5; + + unsigned char mat_diag_m_1[] = { + 0xff, 0xe7, 0xda, 0x01, + 0x2a, 0xf8, 0xf6, 0x7f, + 0xac, 0x31, 0xa9, 0x34, + 0x4b, 0x36, 0x15, 0x56, + 0x42, 0xd1, 0x21, 0x7a, + 0x6c, 0x89, 0x54, 0x5c, + 0x48, 0x68, 0x0b, 0x2d, + 0xb3, 0xad, 0xbc, 0x03, + 0x80, 0xa4, 0x99, 0x4a, + 0x6f, 0x96, 0x1d, 0x3d, + 0xcf, 0x2f, 0x31, 0x1f, + 0x25, 0xa4, 0xd5, 0x2f, + 0x6e, 0x53, 0x77, 0x50, + 0xbe, 0x34, 0x65, 0x6e, + 0x87, 0x13, 0x1e, 0x28, + 0x42, 0xb0, 0xd4, 0x23, + 0xb7, 0x6f, 0x19, 0x17, + 0xcd, 0xea, 0x92, 0x5e, + 0x08, 0x3c, 0xa2, 0x28, + 0x8c, 0x99, 0x8a, 0x2e, + }; + + unsigned char round_constants[] = { + 0x97, 0x44, 0xcd, 0x30, + 0x92, 0x7d, 0xcf, 0x67, + 0x86, 0xa7, 0x3c, 0x11, + 0xf7, 0x11, 0xf5, 0x28, + 0x11, 0x03, 0x85, 0x4c, + 0xe8, 0x7b, 0xc0, 0x3d, + 0xb9, 0x14, 0x82, 0x0c, + 0x97, 0x0d, 0x09, 0x18, + 0xfb, 0x35, 0x4f, 0x68, + 0x8e, 0x47, 0x4e, 0x7f, + 0x68, 0xba, 0xee, 0x11, + 0xa7, 0x0c, 0x7d, 0x56, + 0xbc, 0xbe, 0x3f, 0x6d, + 0x60, 0x84, 0x02, 0x47, + 0x33, 0xd4, 0xa8, 0x09, + 0x5c, 0x5d, 0xbc, 0x46, + 0xb2, 0x05, 0x08, 0x11, + 0x82, 0xdc, 0xdd, 0x50, + 0xfa, 0xe4, 0x1e, 0x00, + 0x19, 0x47, 0xed, 0x55, + 0xce, 0xbd, 0x08, 0x47, + 0x2b, 0x0b, 0x53, 0x1a, + 0x00, 0x24, 0x37, 0x6d, + 0x42, 0x1d, 0x10, 0x32, + 0xd0, 0xd7, 0xb0, 0x02, + 0x12, 0xf5, 0x64, 0x30, + 0x64, 0x3c, 0x0f, 0x67, + 0x31, 0x5e, 0x73, 0x35, + 0x44, 0x61, 0x2b, 0x5a, + 0xa6, 0x6b, 0x0d, 0x21, + 0x6a, 0xe6, 0x74, 0x12, + 0x09, 0x3e, 0x2e, 0x21, + 0xf0, 0x2f, 0xe6, 0x57, + 0x74, 0x18, 0x63, 0x6b, + 0x1b, 0x7a, 0x57, 0x6b, + 0xaa, 0xfd, 0x17, 0x0d, + 0x1b, 0xe8, 0xeb, 0x24, + 0xfe, 0xc9, 0xf6, 0x34, + 0x55, 0x5a, 0x1d, 0x59, + 0x42, 0xa9, 0x45, 0x5f, + 0x3f, 0x4f, 0x45, 0x5e, + 0x33, 0x56, 0xb7, 0x23, + 0x70, 0x61, 0x07, 0x55, + 0x82, 0x94, 0xaa, 0x3c, + 0x00, 0xbf, 0x2c, 0x6a, + 0x1b, 0x80, 0x24, 0x72, + 0x64, 0x2d, 0xbb, 0x74, + 0x90, 0x09, 0x6d, 0x2e, + 0xf5, 0x7b, 0x31, 0x78, + 0x21, 0xb9, 0xea, 0x23, + 0xa8, 0x03, 0x36, 0x66, + 0x7f, 0xe9, 0xe8, 0x03, + 0x3d, 0x5d, 0xdb, 0x04, + 0x27, 0xe8, 0xc1, 0x64, + 0xfe, 0x78, 0xc4, 0x37, + 0x05, 0xc8, 0xef, 0x35, + 0xf9, 0xae, 0x5a, 0x55, + 0x0c, 0xad, 0x63, 0x65, + 0xac, 0xae, 0xc9, 0x14, + 0x72, 0xe1, 0xd6, 0x16, + 0xe9, 0xcb, 0x4f, 0x42, + 0x55, 0x08, 0x38, 0x30, + 0xbf, 0xe5, 0xd4, 0x74, + 0x83, 0xba, 0x75, 0x12, + 0x2d, 0x2a, 0xf3, 0x56, + 0x89, 0x7f, 0xf9, 0x3c, + 0x11, 0x57, 0x0c, 0x44, + 0x8a, 0x7e, 0x68, 0x48, + 0xf8, 0x00, 0x66, 0x49, + 0x9f, 0x42, 0x0e, 0x0b, + 0x26, 0x1e, 0x4b, 0x15, + 0xce, 0xb8, 0x9b, 0x37, + 0xe5, 0x83, 0x76, 0x27, + 0x94, 0xe0, 0x03, 0x44, + 0x40, 0x32, 0x03, 0x12, + 0xd7, 0x06, 0xd0, 0x3b, + 0x1b, 0xee, 0xe6, 0x4e, + 0x4c, 0x76, 0xc6, 0x62, + 0x2f, 0x55, 0x30, 0x72, + 0xe7, 0x1d, 0x34, 0x4f, + 0x49, 0x8c, 0x8f, 0x3c, + 0xe2, 0xbe, 0xc6, 0x6f, + 0x4d, 0xf7, 0x3e, 0x0a, + 0x07, 0x01, 0x71, 0x23, + 0x82, 0x0c, 0x65, 0x24, + 0xd4, 0xeb, 0xba, 0x12, + 0xce, 0xf3, 0xc2, 0x46, + 0xd9, 0x6f, 0x81, 0x57, + 0x1c, 0xe5, 0x3f, 0x44, + 0xab, 0x05, 0x78, 0x2a, + 0xf1, 0x8e, 0x50, 0x3f, + 0x6c, 0x83, 0x0b, 0x15, + 0xfa, 0x4f, 0x01, 0x1c, + 0xbe, 0x86, 0x07, 0x1c, + 0x90, 0x51, 0x64, 0x10, + 0x0a, 0x9c, 0x7b, 0x60, + 0x05, 0x15, 0x96, 0x48, + 0xbb, 0xb7, 0x20, 0x6f, + 0x23, 0xea, 0x5a, 0x5b, + 0x5c, 0x35, 0xe5, 0x1f, + 0xaa, 0x98, 0xef, 0x27, + 0x0b, 0x12, 0x3e, 0x04, + 0xcd, 0x5c, 0x7d, 0x64, + 0xb2, 0x81, 0x5c, 0x45, + 0x3f, 0x7d, 0xc2, 0x6a, + 0x26, 0x61, 0x9f, 0x27, + 0x58, 0x57, 0xa1, 0x76, + 0xa6, 0xb0, 0xc1, 0x58, + 0x01, 0x39, 0xf8, 0x4a, + 0x4f, 0x1d, 0x64, 0x45, + 0x33, 0x8c, 0xfe, 0x1d, + 0x88, 0x0c, 0x72, 0x03, + 0x0d, 0xd4, 0x82, 0x34, + 0x60, 0x89, 0x0d, 0x77, + 0x30, 0xb7, 0x08, 0x61, + 0x84, 0xc0, 0x3f, 0x06, + 0x34, 0x2a, 0x6e, 0x09, + 0xa0, 0x14, 0x05, 0x13, + 0xff, 0x3e, 0xbc, 0x42, + 0x48, 0x58, 0x77, 0x43, + 0xe4, 0x60, 0x29, 0x70, + 0x79, 0x9c, 0xf1, 0x6c, + 0xdd, 0x30, 0x30, 0x4c, + 0x32, 0x79, 0xd2, 0x6d, + 0xe9, 0x0d, 0x35, 0x64, + 0x11, 0x83, 0x0e, 0x48, + 0x2c, 0x63, 0x22, 0x6a, + 0xf6, 0xbc, 0x14, 0x28, + 0xe3, 0x97, 0x71, 0x11, + 0x19, 0xd4, 0x44, 0x48, + 0xa6, 0x81, 0xe1, 0x76, + 0xb4, 0xd7, 0x55, 0x61, + 0x26, 0xed, 0xdb, 0x42, + 0x7c, 0xdb, 0xc7, 0x78, + 0x7b, 0xc2, 0xe9, 0x62, + 0x11, 0x4f, 0x5b, 0x10, + 0x58, 0x58, 0xd4, 0x51, + 0x98, 0x02, 0xfa, 0x33, + 0x28, 0x82, 0xa0, 0x26, + 0x1f, 0x58, 0x14, 0x5f, + 0x37, 0x97, 0xd8, 0x3b, + 0x8f, 0x96, 0x25, 0x23, + 0xba, 0x12, 0x85, 0x41, + 0x20, 0x69, 0x41, 0x7e, + 0x2f, 0x44, 0x47, 0x2f, + 0xf5, 0x0a, 0x68, 0x0e, + 0xba, 0x4c, 0x42, 0x0c, + 0xae, 0x85, 0x38, 0x6d, + 0xbe, 0x8c, 0x9c, 0x0a, + 0xa9, 0xf2, 0x85, 0x24, + 0x7f, 0x35, 0x99, 0x1f, + 0x31, 0xd5, 0x58, 0x0f, + 0xb1, 0xf6, 0xd6, 0x32, + 0x6d, 0x87, 0x26, 0x2c, + 0x8e, 0xd3, 0xe3, 0x2d, + 0xc9, 0x6c, 0x7b, 0x5a, + 0xf0, 0xc7, 0xae, 0x1c, + 0x75, 0xf5, 0xa1, 0x4a, + 0xcd, 0x0c, 0xaf, 0x77, + 0x5c, 0xbe, 0xd3, 0x19, + 0xd8, 0x19, 0xa6, 0x0a, + 0x78, 0xea, 0xcf, 0x04, + 0x76, 0xab, 0xb3, 0x0d, + 0xa3, 0xfa, 0xdf, 0x2d, + 0x67, 0x67, 0x24, 0x52, + 0xf8, 0x2d, 0x63, 0x78, + 0x41, 0x46, 0xd5, 0x7b, + 0x18, 0xf0, 0xd7, 0x50, + 0x9f, 0xeb, 0x8c, 0x31, + 0x06, 0xa5, 0x69, 0x2e, + 0xfa, 0xd1, 0xd9, 0x4b, + 0x9a, 0x57, 0x0b, 0x2a, + 0xc2, 0x38, 0x12, 0x56, + 0x9a, 0xbb, 0x77, 0x28, + 0x79, 0x2c, 0xed, 0x06, + 0xba, 0x98, 0x99, 0x22, + 0x85, 0x01, 0x7f, 0x73, + 0x31, 0xad, 0x9a, 0x60, + }; + } + + + namespace t24 { + int internal_rounds = 22; + + int alpha = 5; + + unsigned char mat_diag_m_1[] = { + 0xea, 0xec, 0xd7, 0x0c, + 0x1e, 0x07, 0x4a, 0x07, + 0xfe, 0xae, 0xaa, 0x66, + 0x65, 0x4b, 0x33, 0x1c, + 0xb0, 0x4c, 0x09, 0x4d, + 0xa9, 0x79, 0x85, 0x2f, + 0x19, 0x47, 0x09, 0x27, + 0xcd, 0x93, 0x00, 0x71, + 0xac, 0x35, 0xd4, 0x53, + 0x0f, 0xa1, 0x06, 0x73, + 0x05, 0x89, 0x56, 0x57, + 0xdf, 0xd8, 0x67, 0x49, + 0x7e, 0x62, 0x74, 0x7f, + 0x59, 0x14, 0x82, 0x06, + 0x24, 0x75, 0x8d, 0x47, + 0x28, 0xc2, 0xac, 0x1e, + 0x40, 0x11, 0x1f, 0x65, + 0xef, 0x97, 0xf3, 0x42, + 0xd6, 0x9a, 0xe4, 0x24, + 0xff, 0x56, 0xa3, 0x5c, + 0xe9, 0x00, 0xf3, 0x42, + 0x84, 0x10, 0xd0, 0x2f, + 0x83, 0x64, 0xa8, 0x28, + 0xb4, 0x02, 0x44, 0x10, + }; + + unsigned char round_constants[] = { + 0x61, 0xba, 0xea, 0x1f, + 0x54, 0x44, 0x22, 0x53, + 0xe2, 0xb9, 0xce, 0x6b, + 0xb4, 0xf9, 0x19, 0x50, + 0x92, 0x65, 0x72, 0x48, + 0xa8, 0xd0, 0x22, 0x2b, + 0xf9, 0xbb, 0x51, 0x61, + 0x21, 0x4b, 0x47, 0x2f, + 0x37, 0xf3, 0xb5, 0x2e, + 0x87, 0x5d, 0x64, 0x3b, + 0xf0, 0xce, 0x42, 0x09, + 0x52, 0x8c, 0x22, 0x65, + 0x0f, 0xb3, 0xff, 0x78, + 0xc8, 0x37, 0x28, 0x4d, + 0x4f, 0xac, 0x17, 0x0e, + 0x86, 0x66, 0x54, 0x05, + 0xcc, 0x06, 0x6c, 0x04, + 0xb6, 0xc3, 0x51, 0x0b, + 0x63, 0xb7, 0x8d, 0x56, + 0xe4, 0x34, 0xb3, 0x38, + 0xf0, 0xac, 0xf5, 0x57, + 0x11, 0x26, 0xd3, 0x19, + 0x4b, 0x2f, 0xd0, 0x77, + 0xb8, 0xe9, 0x82, 0x6c, + 0xb6, 0xc1, 0x48, 0x71, + 0x75, 0x7c, 0x06, 0x08, + 0xc9, 0xe8, 0xd1, 0x46, + 0x07, 0x3b, 0x97, 0x30, + 0x3b, 0x4f, 0x61, 0x20, + 0x51, 0xf8, 0x3f, 0x5c, + 0x29, 0x33, 0x50, 0x30, + 0xcc, 0xe7, 0x72, 0x49, + 0xbc, 0xd8, 0xd1, 0x02, + 0xa6, 0xbf, 0xd5, 0x09, + 0xc0, 0x04, 0x71, 0x09, + 0x34, 0x9a, 0xa4, 0x7b, + 0xfc, 0xc2, 0x07, 0x4a, + 0x69, 0xee, 0xc1, 0x24, + 0x41, 0xab, 0xa6, 0x28, + 0xa0, 0x08, 0x91, 0x5d, + 0xc7, 0x51, 0x78, 0x3a, + 0xf9, 0x95, 0xd4, 0x1d, + 0xf4, 0x9f, 0xb4, 0x12, + 0x60, 0x57, 0xad, 0x7b, + 0xc2, 0x64, 0xed, 0x5f, + 0x6c, 0xc9, 0xf5, 0x66, + 0x02, 0xbd, 0xaf, 0x7e, + 0x3b, 0x59, 0xb3, 0x39, + 0x49, 0x3b, 0x65, 0x4a, + 0xc1, 0x1d, 0x09, 0x75, + 0xe0, 0x88, 0xe4, 0x56, + 0x55, 0xa3, 0x04, 0x17, + 0xf3, 0x4f, 0x5e, 0x74, + 0x6e, 0xf1, 0x2e, 0x39, + 0xdf, 0x3f, 0xe3, 0x31, + 0x66, 0x8c, 0xc2, 0x02, + 0x3a, 0x08, 0xc3, 0x36, + 0xfa, 0xd1, 0x04, 0x31, + 0xa3, 0xcd, 0x03, 0x5b, + 0xaf, 0xe1, 0x41, 0x66, + 0x56, 0x4b, 0x75, 0x37, + 0xf9, 0x5a, 0x6f, 0x39, + 0x1a, 0x46, 0x1a, 0x1a, + 0xf2, 0x26, 0x8e, 0x68, + 0x84, 0x97, 0x82, 0x6f, + 0x69, 0x1d, 0xb9, 0x1b, + 0x16, 0x80, 0x78, 0x5b, + 0xc5, 0xa5, 0x4a, 0x70, + 0x9c, 0x86, 0x81, 0x01, + 0x56, 0x1e, 0x21, 0x41, + 0xa0, 0x03, 0xe8, 0x0c, + 0xa0, 0xf3, 0xbf, 0x23, + 0x64, 0x70, 0xfb, 0x17, + 0x20, 0x72, 0x31, 0x47, + 0x53, 0x4b, 0x91, 0x76, + 0x05, 0x19, 0x9c, 0x21, + 0x28, 0x55, 0x65, 0x16, + 0x44, 0x55, 0xf3, 0x4d, + 0x65, 0x84, 0x80, 0x60, + 0x33, 0xf8, 0x50, 0x33, + 0xc7, 0xcd, 0xbc, 0x03, + 0x0a, 0x18, 0x87, 0x0a, + 0xf5, 0x99, 0x7a, 0x01, + 0x26, 0x57, 0x94, 0x6e, + 0x04, 0x55, 0x44, 0x15, + 0xb1, 0x33, 0x05, 0x78, + 0x38, 0xbf, 0x91, 0x3b, + 0xb1, 0x7e, 0xc7, 0x3f, + 0x0e, 0x96, 0x4d, 0x4b, + 0x2e, 0x3d, 0xd9, 0x3c, + 0x76, 0xe9, 0xa4, 0x0e, + 0xcc, 0x06, 0x53, 0x1d, + 0x84, 0xc2, 0x7a, 0x3a, + 0x34, 0x29, 0xc2, 0x0e, + 0x13, 0x97, 0x97, 0x4d, + 0x65, 0x1c, 0xa4, 0x51, + 0x11, 0x6a, 0x77, 0x22, + 0x68, 0x42, 0xa3, 0x5f, + 0x8d, 0x52, 0x15, 0x14, + 0x14, 0xbd, 0x3f, 0x56, + 0x44, 0x52, 0xf4, 0x34, + 0xb6, 0xa1, 0x0e, 0x12, + 0xa5, 0x68, 0x13, 0x26, + 0xc1, 0x5e, 0x66, 0x27, + 0x05, 0x28, 0xbe, 0x36, + 0x84, 0x47, 0x5c, 0x34, + 0xc1, 0xdc, 0xef, 0x17, + 0x30, 0x65, 0x3e, 0x39, + 0xb8, 0xb4, 0xa0, 0x6d, + 0xd3, 0xde, 0xe5, 0x31, + 0xac, 0x27, 0x5b, 0x67, + 0x30, 0x8c, 0xe8, 0x0a, + 0xcc, 0x41, 0x78, 0x57, + 0xec, 0x6d, 0xe0, 0x5f, + 0x1a, 0x69, 0xb0, 0x56, + 0x1f, 0xde, 0x42, 0x72, + 0x29, 0x75, 0x37, 0x3c, + 0x23, 0x75, 0x9b, 0x33, + 0x99, 0x22, 0x66, 0x1c, + 0x5a, 0x95, 0x7c, 0x05, + 0xf2, 0xc0, 0xb6, 0x7a, + 0x0a, 0xad, 0xa6, 0x25, + 0x58, 0x0b, 0x85, 0x75, + 0x93, 0x37, 0xfd, 0x48, + 0xb1, 0x66, 0x43, 0x0b, + 0x49, 0x0d, 0xdd, 0x0f, + 0xf9, 0x19, 0xb4, 0x7d, + 0x0f, 0xcc, 0xb9, 0x49, + 0x16, 0x97, 0x94, 0x48, + 0x90, 0x58, 0xc3, 0x29, + 0x85, 0x54, 0x44, 0x76, + 0x0c, 0xd3, 0x27, 0x1c, + 0x3b, 0x7a, 0xaa, 0x10, + 0xb6, 0x4f, 0xf3, 0x30, + 0x35, 0x64, 0xe0, 0x6f, + 0xcd, 0x5e, 0x13, 0x02, + 0x96, 0xba, 0xaa, 0x6c, + 0xd0, 0x90, 0xb2, 0x3e, + 0x3b, 0x8d, 0xfd, 0x22, + 0x25, 0x15, 0x8b, 0x76, + 0x14, 0x58, 0xe9, 0x5b, + 0xe9, 0x7f, 0x3d, 0x52, + 0xec, 0x4c, 0xe9, 0x55, + 0x1f, 0x2e, 0xc4, 0x47, + 0x5e, 0x3b, 0xa5, 0x1a, + 0x7e, 0xfe, 0xd1, 0x2f, + 0x91, 0x0e, 0x23, 0x59, + 0x66, 0xda, 0x72, 0x74, + 0xdf, 0xf2, 0x43, 0x64, + 0x9d, 0xe1, 0x9d, 0x2d, + 0x84, 0x6a, 0x7f, 0x6f, + 0x30, 0x04, 0x80, 0x77, + 0xc8, 0x4b, 0x01, 0x0f, + 0x95, 0xd0, 0xf3, 0x7b, + 0x18, 0xd3, 0xaf, 0x26, + 0xf7, 0x61, 0x25, 0x58, + 0x8c, 0x19, 0xe3, 0x5e, + 0x00, 0x00, 0xcc, 0x6a, + 0x26, 0x5e, 0x31, 0x2f, + 0x40, 0xc0, 0xca, 0x27, + 0x1e, 0x08, 0x95, 0x25, + 0xda, 0xb7, 0x63, 0x59, + 0x65, 0x35, 0x07, 0x7e, + 0xf1, 0xf5, 0xf3, 0x6c, + 0xa4, 0xa3, 0xf8, 0x09, + 0xfe, 0xcc, 0xa8, 0x0d, + 0x65, 0x23, 0xbe, 0x60, + 0xf5, 0x42, 0xd7, 0x7e, + 0x31, 0x80, 0x8b, 0x66, + 0x94, 0x34, 0xb0, 0x4b, + 0x33, 0x93, 0x01, 0x59, + 0x78, 0x28, 0x0e, 0x70, + 0x56, 0x58, 0xc4, 0x1c, + 0xf7, 0x17, 0x16, 0x1d, + 0xa6, 0x8d, 0x98, 0x7b, + 0x6c, 0x93, 0xb4, 0x4e, + 0x7e, 0xf8, 0xc9, 0x78, + 0x94, 0x3e, 0xce, 0x63, + 0x1b, 0x34, 0x78, 0x71, + 0x86, 0x2f, 0xbc, 0x45, + 0xbc, 0x75, 0xb7, 0x05, + 0x44, 0x02, 0x4b, 0x70, + 0x78, 0xd2, 0xee, 0x29, + 0x32, 0x30, 0xf4, 0x47, + 0xe5, 0xb2, 0x27, 0x21, + 0x3f, 0x90, 0x97, 0x19, + 0x03, 0xce, 0xb3, 0x24, + 0x8c, 0x29, 0x32, 0x0c, + 0x3a, 0x6f, 0x2b, 0x7d, + 0x81, 0xaa, 0xfc, 0x17, + 0xef, 0x7f, 0xf3, 0x72, + 0xa9, 0xe7, 0x28, 0x30, + 0x96, 0x4d, 0xdd, 0x5e, + 0x3b, 0x58, 0x96, 0x1f, + 0x8a, 0x91, 0xd6, 0x4c, + 0x0e, 0x0f, 0x88, 0x14, + 0x59, 0x03, 0x17, 0x69, + 0x33, 0xbd, 0x3c, 0x17, + 0xf4, 0xe7, 0x69, 0x09, + 0xab, 0x23, 0x7f, 0x6e, + 0x87, 0xea, 0x82, 0x61, + 0x5c, 0x1f, 0xcb, 0x4d, + 0x13, 0xa1, 0x5f, 0x58, + 0xb6, 0xb3, 0x9c, 0x72, + 0x7a, 0xa2, 0xb3, 0x01, + 0xe7, 0x73, 0xa1, 0x1b, + 0xea, 0xbc, 0x33, 0x4b, + 0xbb, 0x3b, 0xd9, 0x63, + 0x99, 0xbf, 0x3f, 0x6b, + 0xd1, 0xe9, 0x17, 0x6f, + 0xba, 0xd8, 0x3d, 0x0c, + 0xa8, 0xf9, 0xc1, 0x0b, + 0x70, 0xf3, 0xd3, 0x64, + 0x18, 0x6a, 0x5a, 0x46, + }; + } + +} +#endif diff --git a/icicle/include/poseidon2/constants/poseidon2_rust_params.sage b/icicle/include/poseidon2/constants/poseidon2_rust_params.sage index e14ae010d..1a8618616 100644 --- a/icicle/include/poseidon2/constants/poseidon2_rust_params.sage +++ b/icicle/include/poseidon2/constants/poseidon2_rust_params.sage @@ -3,13 +3,14 @@ from sage.rings.polynomial.polynomial_gf2x import GF2X_BuildIrred_list from math import * import itertools -CURVE_NAME = "bn254" +CURVE_NAME = "m31" ########################################################################### # p = 18446744069414584321 # GoldiLocks # p = 2013265921 # BabyBear +p = 2**31 - 1 # M31 # p = 52435875175126190479447740508185965837690552500527637822603658699938581184513 # BLS12-381 -p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 # BN254/BN256 +# p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 # BN254/BN256 # p = 28948022309329048855892746252171976963363056481941560715954676764349967630337 # Pasta (Pallas) # p = 28948022309329048855892746252171976963363056481941647379679742748393362948097 # Pasta (Vesta) @@ -617,6 +618,8 @@ print(f"namespace poseidon2_constants_{CURVE_NAME} {{") for t in TS: NUM_CELLS = t R_F_FIXED, R_P_FIXED, _, _ = poseidon_calc_final_numbers_fixed(p, t, alpha, 128, True) + if t == 16: + R_P_FIXED = 14 INIT_SEQUENCE = [] diff --git a/icicle/src/poseidon2/kernels.cu b/icicle/include/poseidon2/kernels.cuh similarity index 56% rename from icicle/src/poseidon2/kernels.cu rename to icicle/include/poseidon2/kernels.cuh index bf836b430..5f34be922 100644 --- a/icicle/src/poseidon2/kernels.cu +++ b/icicle/include/poseidon2/kernels.cuh @@ -1,7 +1,28 @@ -#include "poseidon/poseidon.cuh" +#pragma once +#ifndef POSEIDON2_KERNELS_H +#define POSEIDON2_KERNELS_H + +#include "utils/utils.h" +#include "hash/hash.cuh" +#include "matrix/matrix.cuh" +#include "poseidon2/constants.cuh" #include "gpu-utils/modifiers.cuh" +using matrix::Matrix; + namespace poseidon2 { + static DEVICE_INLINE unsigned int d_next_pow_of_two(unsigned int v) + { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; + } + template DEVICE_INLINE S sbox_el(S element, const int alpha) { @@ -19,7 +40,7 @@ namespace poseidon2 { } template - DEVICE_INLINE S sbox(S state[T], const int alpha) + DEVICE_INLINE void sbox(S state[T], const int alpha) { for (int i = 0; i < T; i++) { state[i] = sbox_el(state[i], alpha); @@ -27,7 +48,7 @@ namespace poseidon2 { } template - DEVICE_INLINE S add_rc(S state[T], size_t rc_offset, const S* rc) + DEVICE_INLINE void add_rc(S state[T], size_t rc_offset, const S* rc) { for (int i = 0; i < T; i++) { state[i] = state[i] + rc[rc_offset + i]; @@ -35,7 +56,7 @@ namespace poseidon2 { } template - __device__ S mds_light_4x4(S s[4]) + __device__ void mds_light_4x4(S s[4]) { S t0 = s[0] + s[1]; S t1 = s[2] + s[3]; @@ -56,7 +77,7 @@ namespace poseidon2 { // [ 3 1 1 2 ]. // https://github.com/Plonky3/Plonky3/blob/main/poseidon2/src/matrix.rs#L36 template - __device__ S mds_light_plonky_4x4(S s[4]) + __device__ void mds_light_plonky_4x4(S s[4]) { S t01 = s[0] + s[1]; S t23 = s[2] + s[3]; @@ -70,7 +91,7 @@ namespace poseidon2 { } template - __device__ S mds_light(S state[T], MdsType mds) + __device__ void mds_light(S state[T], MdsType mds) { S sum; switch (T) { @@ -123,7 +144,7 @@ namespace poseidon2 { } template - __device__ S internal_round(S state[T], size_t rc_offset, const Poseidon2Constants& constants) + __device__ void internal_round(S state[T], size_t rc_offset, const Poseidon2Constants& constants) { S element = state[0]; element = element + constants.round_constants[rc_offset]; @@ -176,17 +197,8 @@ namespace poseidon2 { } template - __global__ void poseidon2_permutation_kernel( - const S* states, S* states_out, size_t number_of_states, const Poseidon2Constants constants) + __device__ void permute_state(S state[T], const Poseidon2Constants& constants) { - int idx = (blockIdx.x * blockDim.x) + threadIdx.x; - if (idx >= number_of_states) { return; } - - S state[T]; - UNROLL - for (int i = 0; i < T; i++) { - state[i] = states[idx * T + i]; - } unsigned int rn; mds_light(state, constants.mds_type); @@ -213,6 +225,22 @@ namespace poseidon2 { mds_light(state, constants.mds_type); rc_offset += T; } + } + + template + __global__ void permutation_kernel( + const S* states, S* states_out, unsigned int number_of_states, const Poseidon2Constants constants) + { + int idx = (blockIdx.x * blockDim.x) + threadIdx.x; + if (idx >= number_of_states) { return; } + + S state[T]; + UNROLL + for (int i = 0; i < T; i++) { + state[i] = states[idx * T + i]; + } + + permute_state(state, constants); UNROLL for (int i = 0; i < T; i++) { @@ -220,13 +248,120 @@ namespace poseidon2 { } } - // These function is just doing copy from the states to the output template - __global__ void get_hash_results(const S* states, size_t number_of_states, int index, S* out) + __global__ void hash_many_kernel( + const S* input, + S* output, + uint64_t number_of_states, + unsigned int input_len, + unsigned int output_len, + const Poseidon2Constants constants) { - int idx = (blockIdx.x * blockDim.x) + threadIdx.x; + uint64_t idx = (blockIdx.x * blockDim.x) + threadIdx.x; if (idx >= number_of_states) { return; } - out[idx] = states[idx * T + index]; + S state[T] = {0}; + UNROLL + for (int i = 0; i < input_len; i++) { + state[i] = input[idx * input_len + i]; + } + + permute_state(state, constants); + + UNROLL + for (int i = 0; i < output_len; i++) { + output[idx * output_len + i] = state[i]; + } + } + + template + __device__ void absorb_2d_state( + const Matrix* inputs, + S state[T], + unsigned int number_of_inputs, + unsigned int rate, + uint64_t row_idx, + const Poseidon2Constants& constants) + { + unsigned int index = 0; + for (int i = 0; i < number_of_inputs; i++) { + const Matrix* input = inputs + i; + for (int j = 0; j < input->width; j++) { + state[index] = input->values[row_idx * input->width + j]; + index++; + if (index == rate) { + permute_state(state, constants); + index = 0; + } + } + } + + if (index) { permute_state(state, constants); } + } + + template + __global__ void hash_2d_kernel( + const Matrix* inputs, + S* output, + unsigned int number_of_inputs, + unsigned int rate, + unsigned int output_len, + const Poseidon2Constants constants) + { + uint64_t idx = (blockIdx.x * blockDim.x) + threadIdx.x; + if (idx >= inputs[0].height) { return; } + + S state[T] = {0}; + + absorb_2d_state(inputs, state, number_of_inputs, rate, idx, constants); + + UNROLL + for (int i = 0; i < output_len; i++) { + output[idx * output_len + i] = state[i]; + } } -} // namespace poseidon2 \ No newline at end of file + + template + __global__ void compress_and_inject_kernel( + const Matrix* matrices_to_inject, + unsigned int number_of_inputs, + const S* prev_layer, + S* next_layer, + unsigned int rate, + unsigned int digest_elements, + const Poseidon2Constants constants) + { + int idx = (blockIdx.x * blockDim.x) + threadIdx.x; + uint64_t number_of_rows = d_next_pow_of_two(matrices_to_inject[0].height); + if (idx >= number_of_rows) { return; } + + size_t next_layer_len = matrices_to_inject[0].height; + S state_to_compress[T] = {S::zero()}; + + for (int i = 0; i < digest_elements * 2; i++) { + state_to_compress[i] = prev_layer[idx * 2 * digest_elements + i]; + } + permute_state(state_to_compress, constants); + + S injected_state[T] = {S::zero()}; + if (idx < next_layer_len) { + absorb_2d_state(matrices_to_inject, injected_state, number_of_inputs, rate, idx, constants); + + for (int i = 0; i < digest_elements; i++) { + injected_state[digest_elements + i] = injected_state[i]; + injected_state[i] = state_to_compress[i]; + } + } else { + for (int i = 0; i < digest_elements; i++) { + injected_state[i] = state_to_compress[i]; + } + } + permute_state(injected_state, constants); + + for (int i = 0; i < digest_elements; i++) { + next_layer[idx * digest_elements + i] = injected_state[i]; + } + } +} // namespace poseidon2 + +#endif \ No newline at end of file diff --git a/icicle/include/poseidon2/poseidon2.cuh b/icicle/include/poseidon2/poseidon2.cuh index 9a98a5d9d..e81d88b4c 100644 --- a/icicle/include/poseidon2/poseidon2.cuh +++ b/icicle/include/poseidon2/poseidon2.cuh @@ -8,124 +8,172 @@ #include "gpu-utils/error_handler.cuh" #include "utils/utils.h" +#include "hash/hash.cuh" +#include "matrix/matrix.cuh" + +#include "poseidon2/constants.cuh" +#include "poseidon2/kernels.cuh" + +using matrix::Matrix; + /** * @namespace poseidon2 * Implementation of the [Poseidon2 hash function](https://eprint.iacr.org/2019/458.pdf) * Specifically, the optimized [Filecoin version](https://spec.filecoin.io/algorithms/crypto/poseidon/) */ namespace poseidon2 { - /** - * For most of the Poseidon2 configurations this is the case - */ - const int EXTERNAL_ROUNDS_DEFAULT = 8; - - enum DiffusionStrategy { - DEFAULT_DIFFUSION, - MONTGOMERY, - }; + template + class Poseidon2 : public hash::SpongeHasher + { + static const int POSEIDON_BLOCK_SIZE = 32; - enum MdsType { DEFAULT_MDS, PLONKY }; + static inline int poseidon_number_of_blocks(size_t number_of_states) + { + return number_of_states / POSEIDON_BLOCK_SIZE + static_cast(number_of_states % POSEIDON_BLOCK_SIZE); + } - enum PoseidonMode { - COMPRESSION, - PERMUTATION, - }; + public: + const std::size_t device_id; + Poseidon2Constants constants; - /** - * @struct Poseidon2Constants - * This constants are enough to define a Poseidon2 instantce - * @param round_constants A pointer to round constants allocated on the device - * @param mds_matrix A pointer to an mds matrix allocated on the device - * @param non_sparse_matrix A pointer to non sparse matrix allocated on the device - * @param sparse_matrices A pointer to sparse matrices allocated on the device - */ - template - struct Poseidon2Constants { - int width; - int alpha; - int internal_rounds; - int external_rounds; - S* round_constants = nullptr; - S* internal_matrix_diag = nullptr; - MdsType mds_type; - DiffusionStrategy diffusion; - }; + cudaError_t hash_2d( + const Matrix* inputs, + S* output, + unsigned int number_of_inputs, + unsigned int output_len, + uint64_t number_of_rows, + const device_context::DeviceContext& ctx) const override + { +#define P2_HASH_2D_T(width) \ + case width: \ + hash_2d_kernel<<>>( \ + inputs, output, number_of_inputs, this->rate, output_len, this->constants); \ + break; - /** - * @struct Poseidon2Config - * Struct that encodes various Poseidon2 parameters. - */ - struct Poseidon2Config { - device_context::DeviceContext ctx; /**< Details related to the device such as its id and stream id. */ - bool are_states_on_device; /**< True if inputs are on device and false if they're on host. Default value: false. */ - bool are_outputs_on_device; /**< If true, output is preserved on device, otherwise on host. Default value: false. */ - PoseidonMode mode; - int output_index; - bool - is_async; /**< Whether to run the Poseidon2 asynchronously. If set to `true`, the poseidon_hash function will be - * non-blocking and you'd need to synchronize it explicitly by running - * `cudaStreamSynchronize` or `cudaDeviceSynchronize`. If set to false, the poseidon_hash - * function will block the current CPU thread. */ - }; + switch (this->width) { + P2_HASH_2D_T(2) + P2_HASH_2D_T(3) + P2_HASH_2D_T(4) + P2_HASH_2D_T(8) + P2_HASH_2D_T(12) + P2_HASH_2D_T(16) + P2_HASH_2D_T(20) + P2_HASH_2D_T(24) + default: + THROW_ICICLE_ERR( + IcicleError_t::InvalidArgument, "PoseidonAbsorb2d: #width must be one of [2, 3, 4, 8, 12, 16, 20, 24]"); + } - static Poseidon2Config default_poseidon2_config( - int t, const device_context::DeviceContext& ctx = device_context::get_default_device_context()) - { - Poseidon2Config config = { - ctx, // ctx - false, // are_states_on_device - false, // are_outputs_on_device - PoseidonMode::COMPRESSION, - 1, // output_index - false, // is_async - }; - return config; - } + CHK_IF_RETURN(cudaPeekAtLastError()); + return CHK_LAST(); + } - template - cudaError_t create_poseidon2_constants( - int width, - int alpha, - int internal_rounds, - int external_rounds, - const S* round_constants, - const S* internal_matrix_diag, - MdsType mds_type, - DiffusionStrategy diffusion, - device_context::DeviceContext& ctx, - Poseidon2Constants* poseidon_constants); - - /** - * Loads pre-calculated optimized constants, moves them to the device - */ - template - cudaError_t init_poseidon2_constants( - int width, - MdsType mds_type, - DiffusionStrategy diffusion, - device_context::DeviceContext& ctx, - Poseidon2Constants* constants); + cudaError_t run_hash_many_kernel( + const S* input, + S* output, + unsigned int number_of_states, + unsigned int input_len, + unsigned int output_len, + const device_context::DeviceContext& ctx) const override + { +#define P2_HASH_MANY_T(width) \ + case width: \ + hash_many_kernel<<>>( \ + input, output, number_of_states, input_len, output_len, this->constants); \ + break; + + switch (this->width) { + P2_HASH_MANY_T(2) + P2_HASH_MANY_T(3) + P2_HASH_MANY_T(4) + P2_HASH_MANY_T(8) + P2_HASH_MANY_T(12) + P2_HASH_MANY_T(16) + P2_HASH_MANY_T(20) + P2_HASH_MANY_T(24) + default: + THROW_ICICLE_ERR( + IcicleError_t::InvalidArgument, "PoseidonPermutation: #width must be one of [2, 3, 4, 8, 12, 16, 20, 24]"); + } + CHK_IF_RETURN(cudaPeekAtLastError()); + return CHK_LAST(); + } + + cudaError_t compress_and_inject( + const Matrix* matrices_to_inject, + unsigned int number_of_inputs, + uint64_t number_of_rows, + const S* prev_layer, + S* next_layer, + unsigned int digest_elements, + const device_context::DeviceContext& ctx) const override + { +#define P2_COMPRESS_AND_INJECT_T(width) \ + case width: \ + compress_and_inject_kernel \ + <<>>( \ + matrices_to_inject, number_of_inputs, prev_layer, next_layer, this->rate, digest_elements, this->constants); \ + break; + + switch (this->width) { + P2_COMPRESS_AND_INJECT_T(2) + P2_COMPRESS_AND_INJECT_T(3) + P2_COMPRESS_AND_INJECT_T(4) + P2_COMPRESS_AND_INJECT_T(8) + P2_COMPRESS_AND_INJECT_T(12) + P2_COMPRESS_AND_INJECT_T(16) + P2_COMPRESS_AND_INJECT_T(20) + P2_COMPRESS_AND_INJECT_T(24) + default: + THROW_ICICLE_ERR( + IcicleError_t::InvalidArgument, "PoseidonPermutation: #width must be one of [2, 3, 4, 8, 12, 16, 20, 24]"); + } + + CHK_IF_RETURN(cudaPeekAtLastError()); + return CHK_LAST(); + } + + Poseidon2( + unsigned int width, + unsigned int rate, + unsigned int alpha, + unsigned int internal_rounds, + unsigned int external_rounds, + const S* round_constants, + const S* internal_matrix_diag, + MdsType mds_type, + DiffusionStrategy diffusion, + device_context::DeviceContext& ctx) + : hash::SpongeHasher(width, width, rate, 0), device_id(ctx.device_id) + { + Poseidon2Constants constants; + CHK_STICKY(create_poseidon2_constants( + width, alpha, internal_rounds, external_rounds, round_constants, internal_matrix_diag, mds_type, diffusion, ctx, + &constants)); + this->constants = constants; + } + + Poseidon2( + unsigned int width, + unsigned int rate, + MdsType mds_type, + DiffusionStrategy diffusion, + device_context::DeviceContext& ctx) + : hash::SpongeHasher(width, width, rate, 0), device_id(ctx.device_id) + { + Poseidon2Constants constants; + CHK_STICKY(init_poseidon2_constants(width, mds_type, diffusion, ctx, &constants)); + this->constants = constants; + } + + ~Poseidon2() + { + auto ctx = device_context::get_default_device_context(); + ctx.device_id = this->device_id; + CHK_STICKY(release_poseidon2_constants(&this->constants, ctx)); + } + }; - template - cudaError_t release_poseidon2_constants(Poseidon2Constants* constants, device_context::DeviceContext& ctx); - - /** - * Compute the poseidon hash over a sequence of preimages. - * Takes {number_of_states * (T-1)} elements of input and computes {number_of_states} hash images - * @param T size of the poseidon state, should be equal to {arity + 1} - * @param states a pointer to the input data. May be allocated on device or on host, regulated - * by the config. May point to a string of preimages or a string of states filled with preimages. - * @param output a pointer to the output data. May be allocated on device or on host, regulated - * by the config. Must be at least of size [number_of_states](@ref number_of_states) - * @param number_of_states number of input blocks of size T-1 (arity) - */ - template - cudaError_t poseidon2_hash( - const S* states, - S* output, - size_t number_of_states, - const Poseidon2Constants& constants, - const Poseidon2Config& config); } // namespace poseidon2 #endif \ No newline at end of file diff --git a/icicle/include/utils/utils.h b/icicle/include/utils/utils.h index a4cb46556..566492f60 100644 --- a/icicle/include/utils/utils.h +++ b/icicle/include/utils/utils.h @@ -5,4 +5,15 @@ #define CONCAT_DIRECT(a, b) a##_##b #define CONCAT_EXPAND(a, b) CONCAT_DIRECT(a, b) // expand a,b before concatenation +static unsigned int next_pow_of_two(unsigned int v) { + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + #endif // ICICLE_UTILS_H \ No newline at end of file diff --git a/icicle/include/vec_ops/vec_ops.cuh b/icicle/include/vec_ops/vec_ops.cuh index 909c6886b..ee624a07f 100644 --- a/icicle/include/vec_ops/vec_ops.cuh +++ b/icicle/include/vec_ops/vec_ops.cuh @@ -105,12 +105,12 @@ namespace vec_ops { * @return `cudaSuccess` if the execution was successful and an error code otherwise. */ template - cudaError_t transpose_batch( + cudaError_t transpose_matrix( const E* mat_in, E* mat_out, uint32_t row_size, uint32_t column_size, - device_context::DeviceContext& ctx, + const device_context::DeviceContext& ctx, bool on_device, bool is_async); diff --git a/icicle/src/fields/CMakeLists.txt b/icicle/src/fields/CMakeLists.txt index 82b5e15f8..1853e319f 100644 --- a/icicle/src/fields/CMakeLists.txt +++ b/icicle/src/fields/CMakeLists.txt @@ -11,6 +11,9 @@ set(SRC ${CMAKE_SOURCE_DIR}/src) set(FIELD_SOURCE ${SRC}/fields/extern.cu) list(APPEND FIELD_SOURCE ${SRC}/vec_ops/extern.cu) +list(APPEND FIELD_SOURCE ${SRC}/merkle-tree/extern.cu) +list(APPEND FIELD_SOURCE ${SRC}/merkle-tree/extern_mmcs.cu) + if(EXT_FIELD) list(APPEND FIELD_SOURCE ${SRC}/fields/extern_extension.cu) if (NOT FIELD IN_LIST SUPPORTED_FIELDS_WITHOUT_NTT) @@ -27,8 +30,6 @@ set(POLYNOMIAL_SOURCE_FILES # TODO: impl poseidon for small fields. note that it needs to be defined over the extension field! if (DEFINED CURVE) list(APPEND FIELD_SOURCE ${SRC}/poseidon/extern.cu) - list(APPEND FIELD_SOURCE ${SRC}/poseidon/poseidon.cu) - list(APPEND FIELD_SOURCE ${SRC}/poseidon/tree/merkle.cu) endif() if (NOT FIELD IN_LIST SUPPORTED_FIELDS_WITHOUT_POSEIDON2) diff --git a/icicle/src/hash/CMakeLists.txt b/icicle/src/hash/CMakeLists.txt index 0b70083b9..3f0d532c7 100644 --- a/icicle/src/hash/CMakeLists.txt +++ b/icicle/src/hash/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET icicle_hash) -add_library(${TARGET} STATIC keccak/keccak.cu) +add_library(${TARGET} STATIC keccak/extern.cu) target_include_directories(${TARGET} PUBLIC ${CMAKE_SOURCE_DIR}/include/) set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME "ingo_hash") \ No newline at end of file diff --git a/icicle/src/hash/keccak/.gitignore b/icicle/src/hash/keccak/.gitignore new file mode 100644 index 000000000..bdbfc9de6 --- /dev/null +++ b/icicle/src/hash/keccak/.gitignore @@ -0,0 +1 @@ +test_keccak \ No newline at end of file diff --git a/icicle/src/hash/keccak/Makefile b/icicle/src/hash/keccak/Makefile index c8a97c939..347efd98b 100644 --- a/icicle/src/hash/keccak/Makefile +++ b/icicle/src/hash/keccak/Makefile @@ -1,2 +1,6 @@ test_keccak: test.cu keccak.cu - nvcc -o test_keccak -I. -I../.. test.cu \ No newline at end of file + nvcc -o test_keccak -I../../../include test.cu + ./test_keccak + +clear: + rm test_keccak \ No newline at end of file diff --git a/icicle/src/hash/keccak/extern.cu b/icicle/src/hash/keccak/extern.cu new file mode 100644 index 000000000..40339d218 --- /dev/null +++ b/icicle/src/hash/keccak/extern.cu @@ -0,0 +1,20 @@ +#include "utils/utils.h" +#include "gpu-utils/error_handler.cuh" + +#include "hash/hash.cuh" +#include "hash/keccak/keccak.cuh" +#include "keccak.cu" + +namespace keccak { + extern "C" cudaError_t + keccak256_cuda(uint8_t* input, int input_block_size, int number_of_blocks, uint8_t* output, KeccakConfig& config) + { + return keccak_hash<512, 256>(input, input_block_size, number_of_blocks, output, config); + } + + extern "C" cudaError_t + keccak512_cuda(uint8_t* input, int input_block_size, int number_of_blocks, uint8_t* output, KeccakConfig& config) + { + return keccak_hash<1024, 512>(input, input_block_size, number_of_blocks, output, config); + } +} // namespace keccak \ No newline at end of file diff --git a/icicle/src/hash/keccak/keccak.cu b/icicle/src/hash/keccak/keccak.cu index 8655eed59..074940122 100644 --- a/icicle/src/hash/keccak/keccak.cu +++ b/icicle/src/hash/keccak/keccak.cu @@ -1,227 +1,14 @@ -#include "hash/keccak/keccak.cuh" - -namespace keccak { -#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) - -#define TH_ELT(t, c0, c1, c2, c3, c4, d0, d1, d2, d3, d4) \ - { \ - t = ROTL64((d0 ^ d1 ^ d2 ^ d3 ^ d4), 1) ^ (c0 ^ c1 ^ c2 ^ c3 ^ c4); \ - } - -#define THETA( \ - s00, s01, s02, s03, s04, s10, s11, s12, s13, s14, s20, s21, s22, s23, s24, s30, s31, s32, s33, s34, s40, s41, s42, \ - s43, s44) \ - { \ - TH_ELT(t0, s40, s41, s42, s43, s44, s10, s11, s12, s13, s14); \ - TH_ELT(t1, s00, s01, s02, s03, s04, s20, s21, s22, s23, s24); \ - TH_ELT(t2, s10, s11, s12, s13, s14, s30, s31, s32, s33, s34); \ - TH_ELT(t3, s20, s21, s22, s23, s24, s40, s41, s42, s43, s44); \ - TH_ELT(t4, s30, s31, s32, s33, s34, s00, s01, s02, s03, s04); \ - s00 ^= t0; \ - s01 ^= t0; \ - s02 ^= t0; \ - s03 ^= t0; \ - s04 ^= t0; \ - \ - s10 ^= t1; \ - s11 ^= t1; \ - s12 ^= t1; \ - s13 ^= t1; \ - s14 ^= t1; \ - \ - s20 ^= t2; \ - s21 ^= t2; \ - s22 ^= t2; \ - s23 ^= t2; \ - s24 ^= t2; \ - \ - s30 ^= t3; \ - s31 ^= t3; \ - s32 ^= t3; \ - s33 ^= t3; \ - s34 ^= t3; \ - \ - s40 ^= t4; \ - s41 ^= t4; \ - s42 ^= t4; \ - s43 ^= t4; \ - s44 ^= t4; \ - } - -#define RHOPI( \ - s00, s01, s02, s03, s04, s10, s11, s12, s13, s14, s20, s21, s22, s23, s24, s30, s31, s32, s33, s34, s40, s41, s42, \ - s43, s44) \ - { \ - t0 = ROTL64(s10, (uint64_t)1); \ - s10 = ROTL64(s11, (uint64_t)44); \ - s11 = ROTL64(s41, (uint64_t)20); \ - s41 = ROTL64(s24, (uint64_t)61); \ - s24 = ROTL64(s42, (uint64_t)39); \ - s42 = ROTL64(s04, (uint64_t)18); \ - s04 = ROTL64(s20, (uint64_t)62); \ - s20 = ROTL64(s22, (uint64_t)43); \ - s22 = ROTL64(s32, (uint64_t)25); \ - s32 = ROTL64(s43, (uint64_t)8); \ - s43 = ROTL64(s34, (uint64_t)56); \ - s34 = ROTL64(s03, (uint64_t)41); \ - s03 = ROTL64(s40, (uint64_t)27); \ - s40 = ROTL64(s44, (uint64_t)14); \ - s44 = ROTL64(s14, (uint64_t)2); \ - s14 = ROTL64(s31, (uint64_t)55); \ - s31 = ROTL64(s13, (uint64_t)45); \ - s13 = ROTL64(s01, (uint64_t)36); \ - s01 = ROTL64(s30, (uint64_t)28); \ - s30 = ROTL64(s33, (uint64_t)21); \ - s33 = ROTL64(s23, (uint64_t)15); \ - s23 = ROTL64(s12, (uint64_t)10); \ - s12 = ROTL64(s21, (uint64_t)6); \ - s21 = ROTL64(s02, (uint64_t)3); \ - s02 = t0; \ - } - -#define KHI( \ - s00, s01, s02, s03, s04, s10, s11, s12, s13, s14, s20, s21, s22, s23, s24, s30, s31, s32, s33, s34, s40, s41, s42, \ - s43, s44) \ - { \ - t0 = s00 ^ (~s10 & s20); \ - t1 = s10 ^ (~s20 & s30); \ - t2 = s20 ^ (~s30 & s40); \ - t3 = s30 ^ (~s40 & s00); \ - t4 = s40 ^ (~s00 & s10); \ - s00 = t0; \ - s10 = t1; \ - s20 = t2; \ - s30 = t3; \ - s40 = t4; \ - \ - t0 = s01 ^ (~s11 & s21); \ - t1 = s11 ^ (~s21 & s31); \ - t2 = s21 ^ (~s31 & s41); \ - t3 = s31 ^ (~s41 & s01); \ - t4 = s41 ^ (~s01 & s11); \ - s01 = t0; \ - s11 = t1; \ - s21 = t2; \ - s31 = t3; \ - s41 = t4; \ - \ - t0 = s02 ^ (~s12 & s22); \ - t1 = s12 ^ (~s22 & s32); \ - t2 = s22 ^ (~s32 & s42); \ - t3 = s32 ^ (~s42 & s02); \ - t4 = s42 ^ (~s02 & s12); \ - s02 = t0; \ - s12 = t1; \ - s22 = t2; \ - s32 = t3; \ - s42 = t4; \ - \ - t0 = s03 ^ (~s13 & s23); \ - t1 = s13 ^ (~s23 & s33); \ - t2 = s23 ^ (~s33 & s43); \ - t3 = s33 ^ (~s43 & s03); \ - t4 = s43 ^ (~s03 & s13); \ - s03 = t0; \ - s13 = t1; \ - s23 = t2; \ - s33 = t3; \ - s43 = t4; \ - \ - t0 = s04 ^ (~s14 & s24); \ - t1 = s14 ^ (~s24 & s34); \ - t2 = s24 ^ (~s34 & s44); \ - t3 = s34 ^ (~s44 & s04); \ - t4 = s44 ^ (~s04 & s14); \ - s04 = t0; \ - s14 = t1; \ - s24 = t2; \ - s34 = t3; \ - s44 = t4; \ - } - -#define IOTA(element, rc) \ - { \ - element ^= rc; \ - } - - __device__ const uint64_t RC[24] = {0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, - 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, - 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, - 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, - 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, - 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008}; - - __device__ void keccakf(uint64_t s[25]) - { - uint64_t t0, t1, t2, t3, t4; - - for (int i = 0; i < 24; i++) { - THETA( - s[0], s[5], s[10], s[15], s[20], s[1], s[6], s[11], s[16], s[21], s[2], s[7], s[12], s[17], s[22], s[3], s[8], - s[13], s[18], s[23], s[4], s[9], s[14], s[19], s[24]); - RHOPI( - s[0], s[5], s[10], s[15], s[20], s[1], s[6], s[11], s[16], s[21], s[2], s[7], s[12], s[17], s[22], s[3], s[8], - s[13], s[18], s[23], s[4], s[9], s[14], s[19], s[24]); - KHI( - s[0], s[5], s[10], s[15], s[20], s[1], s[6], s[11], s[16], s[21], s[2], s[7], s[12], s[17], s[22], s[3], s[8], - s[13], s[18], s[23], s[4], s[9], s[14], s[19], s[24]); - IOTA(s[0], RC[i]); - } - } - - template - __global__ void keccak_hash_blocks(uint8_t* input, int input_block_size, int number_of_blocks, uint8_t* output) - { - int bid = (blockIdx.x * blockDim.x) + threadIdx.x; - if (bid >= number_of_blocks) { return; } - - const int r_bits = 1600 - C; - const int r_bytes = r_bits / 8; - const int d_bytes = D / 8; - - uint8_t* b_input = input + bid * input_block_size; - uint8_t* b_output = output + bid * d_bytes; - uint64_t state[25] = {}; // Initialize with zeroes - - int input_len = input_block_size; - - // absorb - while (input_len >= r_bytes) { - // #pragma unroll - for (int i = 0; i < r_bytes; i += 8) { - state[i / 8] ^= *(uint64_t*)(b_input + i); - } - keccakf(state); - b_input += r_bytes; - input_len -= r_bytes; - } +#include +#include "gpu-utils/device_context.cuh" +#include "gpu-utils/error_handler.cuh" - // last block (if any) - uint8_t last_block[r_bytes]; - for (int i = 0; i < input_len; i++) { - last_block[i] = b_input[i]; - } - - // pad 10*1 - last_block[input_len] = 1; - for (int i = 0; i < r_bytes - input_len - 1; i++) { - last_block[input_len + i + 1] = 0; - } - // last bit - last_block[r_bytes - 1] |= 0x80; - - // #pragma unroll - for (int i = 0; i < r_bytes; i += 8) { - state[i / 8] ^= *(uint64_t*)(last_block + i); - } - keccakf(state); +#include "hash/hash.cuh" +#include "hash/keccak/keccak.cuh" +#include "kernels.cu" -#pragma unroll - for (int i = 0; i < d_bytes; i += 8) { - *(uint64_t*)(b_output + i) = state[i / 8]; - } - } +using namespace hash; +namespace keccak { template cudaError_t keccak_hash(uint8_t* input, int input_block_size, int number_of_blocks, uint8_t* output, KeccakConfig& config) @@ -260,16 +47,4 @@ namespace keccak { if (!config.is_async) return CHK_STICKY(cudaStreamSynchronize(stream)); return CHK_LAST(); } - - extern "C" cudaError_t - keccak256_cuda(uint8_t* input, int input_block_size, int number_of_blocks, uint8_t* output, KeccakConfig& config) - { - return keccak_hash<512, 256>(input, input_block_size, number_of_blocks, output, config); - } - - extern "C" cudaError_t - keccak512_cuda(uint8_t* input, int input_block_size, int number_of_blocks, uint8_t* output, KeccakConfig& config) - { - return keccak_hash<1024, 512>(input, input_block_size, number_of_blocks, output, config); - } } // namespace keccak \ No newline at end of file diff --git a/icicle/src/hash/keccak/kernels.cu b/icicle/src/hash/keccak/kernels.cu new file mode 100644 index 000000000..5d3e4864e --- /dev/null +++ b/icicle/src/hash/keccak/kernels.cu @@ -0,0 +1,233 @@ +#pragma once +#ifndef KECCAK_KERNELS_H +#define KECCAK_KERNELS_H + +#include +#include "gpu-utils/modifiers.cuh" + +namespace keccak { + using u64 = uint64_t; + +#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) + +#define TH_ELT(t, c0, c1, c2, c3, c4, d0, d1, d2, d3, d4) \ + { \ + t = ROTL64((d0 ^ d1 ^ d2 ^ d3 ^ d4), 1) ^ (c0 ^ c1 ^ c2 ^ c3 ^ c4); \ + } + +#define THETA( \ + s00, s01, s02, s03, s04, s10, s11, s12, s13, s14, s20, s21, s22, s23, s24, s30, s31, s32, s33, s34, s40, s41, s42, \ + s43, s44) \ + { \ + TH_ELT(t0, s40, s41, s42, s43, s44, s10, s11, s12, s13, s14); \ + TH_ELT(t1, s00, s01, s02, s03, s04, s20, s21, s22, s23, s24); \ + TH_ELT(t2, s10, s11, s12, s13, s14, s30, s31, s32, s33, s34); \ + TH_ELT(t3, s20, s21, s22, s23, s24, s40, s41, s42, s43, s44); \ + TH_ELT(t4, s30, s31, s32, s33, s34, s00, s01, s02, s03, s04); \ + s00 ^= t0; \ + s01 ^= t0; \ + s02 ^= t0; \ + s03 ^= t0; \ + s04 ^= t0; \ + \ + s10 ^= t1; \ + s11 ^= t1; \ + s12 ^= t1; \ + s13 ^= t1; \ + s14 ^= t1; \ + \ + s20 ^= t2; \ + s21 ^= t2; \ + s22 ^= t2; \ + s23 ^= t2; \ + s24 ^= t2; \ + \ + s30 ^= t3; \ + s31 ^= t3; \ + s32 ^= t3; \ + s33 ^= t3; \ + s34 ^= t3; \ + \ + s40 ^= t4; \ + s41 ^= t4; \ + s42 ^= t4; \ + s43 ^= t4; \ + s44 ^= t4; \ + } + +#define RHOPI( \ + s00, s01, s02, s03, s04, s10, s11, s12, s13, s14, s20, s21, s22, s23, s24, s30, s31, s32, s33, s34, s40, s41, s42, \ + s43, s44) \ + { \ + t0 = ROTL64(s10, (uint64_t)1); \ + s10 = ROTL64(s11, (uint64_t)44); \ + s11 = ROTL64(s41, (uint64_t)20); \ + s41 = ROTL64(s24, (uint64_t)61); \ + s24 = ROTL64(s42, (uint64_t)39); \ + s42 = ROTL64(s04, (uint64_t)18); \ + s04 = ROTL64(s20, (uint64_t)62); \ + s20 = ROTL64(s22, (uint64_t)43); \ + s22 = ROTL64(s32, (uint64_t)25); \ + s32 = ROTL64(s43, (uint64_t)8); \ + s43 = ROTL64(s34, (uint64_t)56); \ + s34 = ROTL64(s03, (uint64_t)41); \ + s03 = ROTL64(s40, (uint64_t)27); \ + s40 = ROTL64(s44, (uint64_t)14); \ + s44 = ROTL64(s14, (uint64_t)2); \ + s14 = ROTL64(s31, (uint64_t)55); \ + s31 = ROTL64(s13, (uint64_t)45); \ + s13 = ROTL64(s01, (uint64_t)36); \ + s01 = ROTL64(s30, (uint64_t)28); \ + s30 = ROTL64(s33, (uint64_t)21); \ + s33 = ROTL64(s23, (uint64_t)15); \ + s23 = ROTL64(s12, (uint64_t)10); \ + s12 = ROTL64(s21, (uint64_t)6); \ + s21 = ROTL64(s02, (uint64_t)3); \ + s02 = t0; \ + } + +#define KHI( \ + s00, s01, s02, s03, s04, s10, s11, s12, s13, s14, s20, s21, s22, s23, s24, s30, s31, s32, s33, s34, s40, s41, s42, \ + s43, s44) \ + { \ + t0 = s00 ^ (~s10 & s20); \ + t1 = s10 ^ (~s20 & s30); \ + t2 = s20 ^ (~s30 & s40); \ + t3 = s30 ^ (~s40 & s00); \ + t4 = s40 ^ (~s00 & s10); \ + s00 = t0; \ + s10 = t1; \ + s20 = t2; \ + s30 = t3; \ + s40 = t4; \ + \ + t0 = s01 ^ (~s11 & s21); \ + t1 = s11 ^ (~s21 & s31); \ + t2 = s21 ^ (~s31 & s41); \ + t3 = s31 ^ (~s41 & s01); \ + t4 = s41 ^ (~s01 & s11); \ + s01 = t0; \ + s11 = t1; \ + s21 = t2; \ + s31 = t3; \ + s41 = t4; \ + \ + t0 = s02 ^ (~s12 & s22); \ + t1 = s12 ^ (~s22 & s32); \ + t2 = s22 ^ (~s32 & s42); \ + t3 = s32 ^ (~s42 & s02); \ + t4 = s42 ^ (~s02 & s12); \ + s02 = t0; \ + s12 = t1; \ + s22 = t2; \ + s32 = t3; \ + s42 = t4; \ + \ + t0 = s03 ^ (~s13 & s23); \ + t1 = s13 ^ (~s23 & s33); \ + t2 = s23 ^ (~s33 & s43); \ + t3 = s33 ^ (~s43 & s03); \ + t4 = s43 ^ (~s03 & s13); \ + s03 = t0; \ + s13 = t1; \ + s23 = t2; \ + s33 = t3; \ + s43 = t4; \ + \ + t0 = s04 ^ (~s14 & s24); \ + t1 = s14 ^ (~s24 & s34); \ + t2 = s24 ^ (~s34 & s44); \ + t3 = s34 ^ (~s44 & s04); \ + t4 = s44 ^ (~s04 & s14); \ + s04 = t0; \ + s14 = t1; \ + s24 = t2; \ + s34 = t3; \ + s44 = t4; \ + } + +#define IOTA(element, rc) \ + { \ + element ^= rc; \ + } + + __device__ const u64 RC[24] = {0x0000000000000001, 0x0000000000008082, 0x800000000000808a, 0x8000000080008000, + 0x000000000000808b, 0x0000000080000001, 0x8000000080008081, 0x8000000000008009, + 0x000000000000008a, 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, 0x8000000000008003, + 0x8000000000008002, 0x8000000000000080, 0x000000000000800a, 0x800000008000000a, + 0x8000000080008081, 0x8000000000008080, 0x0000000080000001, 0x8000000080008008}; + + __device__ void keccakf(u64 s[25]) + { + u64 t0, t1, t2, t3, t4; + + for (int i = 0; i < 24; i++) { + THETA( + s[0], s[5], s[10], s[15], s[20], s[1], s[6], s[11], s[16], s[21], s[2], s[7], s[12], s[17], s[22], s[3], s[8], + s[13], s[18], s[23], s[4], s[9], s[14], s[19], s[24]); + RHOPI( + s[0], s[5], s[10], s[15], s[20], s[1], s[6], s[11], s[16], s[21], s[2], s[7], s[12], s[17], s[22], s[3], s[8], + s[13], s[18], s[23], s[4], s[9], s[14], s[19], s[24]); + KHI( + s[0], s[5], s[10], s[15], s[20], s[1], s[6], s[11], s[16], s[21], s[2], s[7], s[12], s[17], s[22], s[3], s[8], + s[13], s[18], s[23], s[4], s[9], s[14], s[19], s[24]); + IOTA(s[0], RC[i]); + } + } + + template + __global__ void keccak_hash_blocks(uint8_t* input, int input_block_size, int number_of_blocks, uint8_t* output) + { + int bid = (blockIdx.x * blockDim.x) + threadIdx.x; + if (bid >= number_of_blocks) { return; } + + const int r_bits = 1600 - C; + const int r_bytes = r_bits / 8; + const int d_bytes = D / 8; + + uint8_t* b_input = input + bid * input_block_size; + uint8_t* b_output = output + bid * d_bytes; + uint64_t state[25] = {}; // Initialize with zeroes + + int input_len = input_block_size; + + // absorb + while (input_len >= r_bytes) { + // #pragma unroll + for (int i = 0; i < r_bytes; i += 8) { + state[i / 8] ^= *(uint64_t*)(b_input + i); + } + keccakf(state); + b_input += r_bytes; + input_len -= r_bytes; + } + + // last block (if any) + uint8_t last_block[r_bytes]; + for (int i = 0; i < input_len; i++) { + last_block[i] = b_input[i]; + } + + // pad 10*1 + last_block[input_len] = 1; + for (int i = 0; i < r_bytes - input_len - 1; i++) { + last_block[input_len + i + 1] = 0; + } + // last bit + last_block[r_bytes - 1] |= 0x80; + + // #pragma unroll + for (int i = 0; i < r_bytes; i += 8) { + state[i / 8] ^= *(uint64_t*)(last_block + i); + } + keccakf(state); + +#pragma unroll + for (int i = 0; i < d_bytes; i += 8) { + *(uint64_t*)(b_output + i) = state[i / 8]; + } + } +} // namespace keccak + +#endif \ No newline at end of file diff --git a/icicle/src/hash/keccak/test.cu b/icicle/src/hash/keccak/test.cu index 8149dc03e..2268820d1 100644 --- a/icicle/src/hash/keccak/test.cu +++ b/icicle/src/hash/keccak/test.cu @@ -1,5 +1,5 @@ #include "gpu-utils/device_context.cuh" -#include "keccak.cu" +#include "extern.cu" // #define DEBUG diff --git a/icicle/src/hash/keccak/test_keccak b/icicle/src/hash/keccak/test_keccak deleted file mode 100755 index a2c4b13e3..000000000 Binary files a/icicle/src/hash/keccak/test_keccak and /dev/null differ diff --git a/icicle/src/poseidon/tree/.gitignore b/icicle/src/merkle-tree/.gitignore similarity index 100% rename from icicle/src/poseidon/tree/.gitignore rename to icicle/src/merkle-tree/.gitignore diff --git a/icicle/src/merkle-tree/extern.cu b/icicle/src/merkle-tree/extern.cu new file mode 100644 index 000000000..a3d082c81 --- /dev/null +++ b/icicle/src/merkle-tree/extern.cu @@ -0,0 +1,25 @@ +#include "utils/utils.h" + +#include "gpu-utils/error_handler.cuh" +#include "merkle-tree/merkle.cuh" +#include "merkle.cu" + +#include "hash/hash.cuh" + +#include "fields/field_config.cuh" +using namespace field_config; + +namespace merkle_tree { + extern "C" cudaError_t CONCAT_EXPAND(FIELD, build_merkle_tree)( + const scalar_t* leaves_digests, + scalar_t* digests, + unsigned int height, + unsigned int input_block_len, + const hash::SpongeHasher* compression, + const hash::SpongeHasher* bottom_layer, + const TreeBuilderConfig& tree_config) + { + return build_merkle_tree( + leaves_digests, digests, height, input_block_len, *compression, *bottom_layer, tree_config); + } +} // namespace merkle_tree \ No newline at end of file diff --git a/icicle/src/merkle-tree/extern_mmcs.cu b/icicle/src/merkle-tree/extern_mmcs.cu new file mode 100644 index 000000000..299c1942b --- /dev/null +++ b/icicle/src/merkle-tree/extern_mmcs.cu @@ -0,0 +1,26 @@ +#include "utils/utils.h" + +#include "gpu-utils/error_handler.cuh" +#include "merkle-tree/merkle.cuh" +#include "matrix/matrix.cuh" +#include "mmcs.cu" + +#include "hash/hash.cuh" + +#include "fields/field_config.cuh" +using namespace field_config; + +using matrix::Matrix; + +namespace merkle_tree { + extern "C" cudaError_t CONCAT_EXPAND(FIELD, mmcs_commit_cuda)( + const Matrix* leaves, + unsigned int number_of_inputs, + scalar_t* digests, + const hash::SpongeHasher* hasher, + const hash::SpongeHasher* compression, + const TreeBuilderConfig& tree_config) + { + return mmcs_commit(leaves, number_of_inputs, digests, *hasher, *compression, tree_config); + } +} // namespace merkle_tree \ No newline at end of file diff --git a/icicle/src/merkle-tree/merkle.cu b/icicle/src/merkle-tree/merkle.cu new file mode 100644 index 000000000..07da4b528 --- /dev/null +++ b/icicle/src/merkle-tree/merkle.cu @@ -0,0 +1,336 @@ +#include "hash/hash.cuh" +#include "merkle-tree/merkle.cuh" + +namespace merkle_tree { + /// Constructs merkle subtree without parallelization + /// The digests are aligned sequentially per row + /// Example: + /// + /// Big tree: + /// + /// 1 <- Root + /// / \ <- Arity = 2 + /// 2 3 <- Digests + /// / \ / \ <- Height = 2 (as the number of edges) + /// 4 5 6 7 <- height^arity leaves + /// | | | | <- Bottom layer hash 1 to 1 + /// a b c d <- Input vector 1x4 + /// + /// Subtree 1 Subtree 2 + /// 2 3 + /// / \ / \ + /// 4 5 6 7 + /// + /// Digests array for subtree 1: + /// [4 5 . . 2 . .] + /// | | | + /// ----- V + /// | Segment (offset = 4, subtree_idx = 0) + /// v + /// Segment (offset = 0, subtree_idx = 0) + /// + /// Digests array for subtree 2: + /// [. . 6 7 . 3 .] + /// | | + /// ----- + /// | + /// v + /// Segment (offset = 0, subtree_idx = 1) + /// + /// Total digests array: + /// [4 5 6 7 2 3 .] + /// + /// Example for custom config: + /// + /// arity = 2 + /// input_block_len = 2 + /// digest_elements = 2 + /// bottom_layer hash width = 4 + /// compression width = 4 + /// height = 2 + /// + /// [a, b] <- Root of the tree + /// | | + /// [a, b, c, d] + /// / \ / \ + /// [i, j, m, n] + /// ┌──┬──────┴──┴──┴──┴──────┬──┐ + /// | | | | + /// [i, j, k, l] [m, n, o, p] <- compression states + /// / \ / \ / \ / \ <- Running permutation + /// [1, 2, 5, 6] [9, 1, 4, 5] <- compression states + /// ┌──┬───┴──┴──┼──┤ ┌──┬───┴──┴──┼──┤ + /// | | | | | | | | <- digest_element * height^arity leaves + /// [1, 2, 3, 4] [5, 6, 7, 8] [9, 1, 2, 3] [4, 5, 6, 7] <- Permuted states + /// / \ / \ / \ / \ / \ / \ / \ / \ <- Running permutation + /// [a, b, 0, 0] [c, d, 0, 0] [e, f, 0, 0] [g, h, 0, 0] <- States of the bottom layer hash + /// | | | | | | | | <- Bottom layer hash 2 to 2 + /// a b c d e f g h <- Input vector 2x4 + /// + /// Input matrix: + /// ┌ ┐ + /// | a b | + /// | c d | + /// | e f | + /// | g h | + /// └ ┘ + + template + cudaError_t build_merkle_subtree( + const L* leaves, + D* states, + D* digests, + size_t subtree_idx, + size_t subtree_height, + L* big_tree_digests, + size_t start_segment_size, + size_t start_segment_offset, + uint64_t keep_rows, + uint64_t input_block_len, + const SpongeHasher& bottom_layer, + const SpongeHasher& compression, + const TreeBuilderConfig& tree_config, + device_context::DeviceContext& ctx) + { + uint64_t arity = tree_config.arity; + + SpongeConfig sponge_config = default_sponge_config(ctx); + sponge_config.are_inputs_on_device = true; + sponge_config.are_outputs_on_device = true; + sponge_config.is_async = true; + + size_t bottom_layer_states = pow(arity, subtree_height); + + if (!tree_config.are_inputs_on_device) { + CHK_IF_RETURN(cudaMemcpyAsync( + states, leaves, bottom_layer_states * input_block_len * sizeof(L), cudaMemcpyHostToDevice, ctx.stream)); + } + + bottom_layer.hash_many( + tree_config.are_inputs_on_device ? leaves : states, digests, bottom_layer_states, input_block_len, + tree_config.digest_elements, sponge_config); + + uint64_t number_of_states = bottom_layer_states / arity; + size_t segment_size = start_segment_size; + size_t segment_offset = start_segment_offset; + + if (!keep_rows || subtree_height < keep_rows) { + D* digests_with_offset = big_tree_digests + segment_offset + subtree_idx * bottom_layer_states; + CHK_IF_RETURN(cudaMemcpyAsync( + digests_with_offset, digests, bottom_layer_states * tree_config.digest_elements * sizeof(D), + cudaMemcpyDeviceToHost, ctx.stream)); + segment_offset += segment_size; + } + segment_size /= arity; + subtree_height--; + swap(&digests, &states); + + while (number_of_states > 0) { + CHK_IF_RETURN( + compression.compress_many(states, digests, number_of_states, tree_config.digest_elements, sponge_config)); + + if (!keep_rows || subtree_height < keep_rows) { + D* digests_with_offset = + big_tree_digests + segment_offset + subtree_idx * number_of_states * tree_config.digest_elements; + CHK_IF_RETURN(cudaMemcpyAsync( + digests_with_offset, digests, number_of_states * tree_config.digest_elements * sizeof(D), + cudaMemcpyDeviceToHost, ctx.stream)); + segment_offset += segment_size; + } + if (number_of_states > 1) { swap(&digests, &states); } + segment_size /= arity; + subtree_height--; + number_of_states /= arity; + } + + return CHK_LAST(); + } + + template + cudaError_t build_merkle_tree( + const L* leaves, + D* digests, + unsigned int height, + unsigned int input_block_len, + const SpongeHasher& compression, + const SpongeHasher& bottom_layer, + const TreeBuilderConfig& tree_config) + { + CHK_INIT_IF_RETURN(); + cudaStream_t& stream = tree_config.ctx.stream; + + if (input_block_len * sizeof(L) > bottom_layer.rate * sizeof(D)) + THROW_ICICLE_ERR( + IcicleError_t::InvalidArgument, + "Sponge construction at the bottom of the tree doesn't support inputs bigger than hash rate"); + if (compression.preimage_max_length < tree_config.arity * tree_config.digest_elements) + THROW_ICICLE_ERR( + IcicleError_t::InvalidArgument, + "Hash max preimage length does not match merkle tree arity multiplied by digest elements"); + + uint64_t number_of_bottom_layer_states = pow(tree_config.arity, height); + + // This will determine how much splitting do we need to do + // `number_of_streams` subtrees should fit in the device + // This means each subtree should fit in `STREAM_CHUNK_SIZE` memory + uint64_t number_of_subtrees = 1; + uint64_t subtree_height = height; + uint64_t subtree_bottom_layer_states = number_of_bottom_layer_states; + uint64_t subtree_states_size = subtree_bottom_layer_states * bottom_layer.width; + + uint64_t subtree_digests_size; + if (compression.width != compression.preimage_max_length) { + // In that case, the states on layer 1 will require extending the states by (width / preimage_max_len) factor + subtree_digests_size = + subtree_states_size * bottom_layer.preimage_max_length / bottom_layer.width * tree_config.digest_elements; + } else { + subtree_digests_size = subtree_states_size / bottom_layer.width * tree_config.digest_elements; + } + size_t subtree_memory_required = sizeof(D) * (subtree_states_size + subtree_digests_size); + while (subtree_memory_required > STREAM_CHUNK_SIZE) { + number_of_subtrees *= tree_config.arity; + subtree_height--; + subtree_bottom_layer_states /= tree_config.arity; + subtree_states_size /= tree_config.arity; + subtree_digests_size /= tree_config.arity; + subtree_memory_required = sizeof(D) * (subtree_states_size + subtree_digests_size); + } + int cap_height = height - subtree_height; + size_t caps_len = pow(tree_config.arity, cap_height) * tree_config.digest_elements; + + size_t available_memory, _total_memory; + CHK_IF_RETURN(cudaMemGetInfo(&available_memory, &_total_memory)); + available_memory -= GIGA / 8; // Leave 128 MB just in case + + // We can effectively parallelize memory copy with streams + // as long as they don't operate on more than `STREAM_CHUNK_SIZE` bytes + const size_t number_of_streams = std::min((uint64_t)(available_memory / STREAM_CHUNK_SIZE), number_of_subtrees); + cudaStream_t* streams = static_cast(malloc(sizeof(cudaStream_t) * number_of_streams)); + for (size_t i = 0; i < number_of_streams; i++) { + CHK_IF_RETURN(cudaStreamCreate(&streams[i])); + } + + bool caps_mode = tree_config.keep_rows && tree_config.keep_rows <= cap_height; + D* caps; + if (caps_mode) { caps = static_cast(malloc(caps_len * sizeof(D))); } + +#ifdef MERKLE_DEBUG + std::cout << "Available memory = " << available_memory / 1024 / 1024 << " MB" << std::endl; + std::cout << "Number of streams = " << number_of_streams << std::endl; + std::cout << "Number of subtrees = " << number_of_subtrees << std::endl; + std::cout << "Height of a subtree = " << subtree_height << std::endl; + std::cout << "Cutoff height = " << height - subtree_height << std::endl; + std::cout << "Number of leaves in a subtree = " << subtree_bottom_layer_states << std::endl; + std::cout << "State of a subtree = " << subtree_states_size << std::endl; + std::cout << "Digest elements for a subtree = " << subtree_digests_size << std::endl; + std::cout << "Size of 1 subtree states = " << subtree_states_size * sizeof(D) / 1024 / 1024 << " MB" << std::endl; + std::cout << "Size of 1 subtree digests = " << subtree_digests_size * sizeof(D) / 1024 / 1024 << " MB" << std::endl; + std::cout << "Cap height = " << cap_height << std::endl; + std::cout << "Enabling caps mode? " << caps_mode << std::endl; +#endif + + // Allocate memory for the leaves and digests + // These are shared by streams in a pool + D *states_ptr, *digests_ptr; + CHK_IF_RETURN(cudaMallocAsync(&states_ptr, subtree_states_size * number_of_streams * sizeof(D), stream)); + CHK_IF_RETURN(cudaMemsetAsync(states_ptr, 0, subtree_states_size * number_of_streams * sizeof(D), stream)); + CHK_IF_RETURN(cudaMallocAsync(&digests_ptr, subtree_digests_size * number_of_streams * sizeof(D), stream)); + // Wait for these allocations to finish + CHK_IF_RETURN(cudaStreamSynchronize(stream)); + + // Build subtrees in parallel. This for loop invokes kernels that can run in a pool of size `number_of_streams` + for (size_t subtree_idx = 0; subtree_idx < number_of_subtrees; subtree_idx++) { + size_t stream_idx = subtree_idx % number_of_streams; + cudaStream_t subtree_stream = streams[stream_idx]; + + const L* subtree_leaves = leaves + subtree_idx * subtree_bottom_layer_states * input_block_len; + D* subtree_state = states_ptr + stream_idx * subtree_states_size; + D* subtree_digests = digests_ptr + stream_idx * subtree_digests_size; + + int subtree_keep_rows = 0; + if (tree_config.keep_rows) { + int diff = tree_config.keep_rows - cap_height; + subtree_keep_rows = std::max(1, diff); + } + device_context::DeviceContext subtree_context{subtree_stream, tree_config.ctx.device_id, tree_config.ctx.mempool}; + + uint64_t start_segment_size = number_of_bottom_layer_states * tree_config.digest_elements; + cudaError_t subtree_result = build_merkle_subtree( + subtree_leaves, // leaves + subtree_state, // state + subtree_digests, // digests + subtree_idx, // subtree_idx + subtree_height, // subtree_height + caps_mode ? caps : digests, // big_tree_digests + start_segment_size, // start_segment_size + 0, // start_segment_offset + subtree_keep_rows, // keep_rows + input_block_len, // input_block_len + bottom_layer, // bottom_layer + compression, // compression + tree_config, // tree_config + subtree_context // subtree_context + ); + CHK_IF_RETURN(subtree_result); + } + + for (size_t i = 0; i < number_of_streams; i++) { + CHK_IF_RETURN(cudaStreamSynchronize(streams[i])); + } + + SpongeConfig sponge_config = default_sponge_config(tree_config.ctx); + sponge_config.are_inputs_on_device = tree_config.are_inputs_on_device; + sponge_config.are_outputs_on_device = true; + sponge_config.is_async = true; + // Finish the top-level tree if any + if (cap_height > 0) { + size_t start_segment_size = caps_len / tree_config.arity; + size_t start_segment_offset = 0; + if (!caps_mode) { // Calculate offset + size_t keep_rows = tree_config.keep_rows ? tree_config.keep_rows : height + 1; + size_t layer_size = pow(tree_config.arity, keep_rows - 1) * tree_config.digest_elements; + for (int i = 0; i < keep_rows - cap_height; i++) { + start_segment_offset += layer_size; + layer_size /= tree_config.arity; + } + } + CHK_IF_RETURN(cudaMemcpyAsync( + states_ptr, caps_mode ? caps : (digests + start_segment_offset - caps_len), caps_len * sizeof(D), + (caps_mode || !tree_config.are_outputs_on_device) ? cudaMemcpyHostToDevice : cudaMemcpyDeviceToDevice, stream)); + + uint64_t number_of_states = caps_len / tree_config.arity / tree_config.digest_elements; + + size_t segment_size = start_segment_size; + size_t segment_offset = start_segment_offset; + while (number_of_states > 0) { + CHK_IF_RETURN(compression.compress_many( + states_ptr, digests_ptr, number_of_states, tree_config.digest_elements, sponge_config)); + if (!tree_config.keep_rows || cap_height < tree_config.keep_rows + (int)caps_mode) { + D* digests_with_offset = digests + segment_offset; + CHK_IF_RETURN(cudaMemcpyAsync( + digests_with_offset, digests_ptr, number_of_states * tree_config.digest_elements * sizeof(D), + cudaMemcpyDeviceToHost, stream)); + segment_offset += segment_size; + } + + if (number_of_states > 1) { swap(&digests_ptr, &states_ptr); } + + segment_size /= tree_config.arity; + cap_height--; + number_of_states /= tree_config.arity; + } + if (caps_mode) { free(caps); } + } + + CHK_IF_RETURN(cudaFreeAsync(states_ptr, stream)); + CHK_IF_RETURN(cudaFreeAsync(digests_ptr, stream)); + if (!tree_config.is_async) return CHK_STICKY(cudaStreamSynchronize(stream)); + for (size_t i = 0; i < number_of_streams; i++) { + CHK_IF_RETURN(cudaStreamSynchronize(streams[i])); + CHK_IF_RETURN(cudaStreamDestroy(streams[i])); + } + free(streams); + return CHK_LAST(); + } + +} // namespace merkle_tree \ No newline at end of file diff --git a/icicle/src/merkle-tree/mmcs.cu b/icicle/src/merkle-tree/mmcs.cu new file mode 100644 index 000000000..5121a9a20 --- /dev/null +++ b/icicle/src/merkle-tree/mmcs.cu @@ -0,0 +1,456 @@ +#include "hash/hash.cuh" +#include "merkle-tree/merkle.cuh" +#include "matrix/matrix.cuh" +#include "vec_ops/vec_ops.cuh" + +#include + +using matrix::Matrix; + +namespace merkle_tree { + + template + cudaError_t hash_leaves( + const Matrix* leaves, + unsigned int number_of_inputs, + uint64_t number_of_rows, + D* digests, + unsigned int digest_elements, + const SpongeHasher& hasher, + const device_context::DeviceContext& ctx) + { + SpongeConfig sponge_config = default_sponge_config(ctx); + sponge_config.are_inputs_on_device = true; + sponge_config.are_outputs_on_device = true; + sponge_config.is_async = true; + + uint64_t number_of_rows_padded = next_pow_of_two(number_of_rows); + + CHK_IF_RETURN(hasher.hash_2d(leaves, digests, number_of_inputs, digest_elements, number_of_rows, ctx)); + + if (number_of_rows_padded - number_of_rows) { + // Pad with default digests + cudaMemsetAsync( + (void*)(digests + number_of_rows), 0, (number_of_rows_padded - number_of_rows) * digest_elements * sizeof(D), + ctx.stream); + } + + return CHK_LAST(); + } + + template + struct SubtreeParams { + unsigned int number_of_inputs; // Number of input matrices + unsigned int arity; // Arity of the tree + unsigned int digest_elements; // Number of output elements per hash + size_t number_of_rows; // Current number of input rows to operate on + size_t number_of_rows_padded; // next power of arity for number_of_rows + size_t subtree_idx; // The subtree id + size_t number_of_subtrees; // Total number of subtrees + uint64_t subtree_height; // Height of one subtree + + /// One segment corresponds to one layer of output digests + size_t segment_size; // The size of current segment. + size_t segment_offset; // An offset for the current segment + unsigned int leaves_offset; // An offset in the sorted list of input matrices + unsigned int number_of_leaves_to_inject; // Number of leaves to inject in current level + unsigned int keep_rows; // Number of rows to keep + bool are_inputs_on_device; + bool caps_mode; + const SpongeHasher* hasher = nullptr; + const SpongeHasher* compression = nullptr; + const device_context::DeviceContext* ctx = nullptr; + }; + + template + cudaError_t slice_and_copy_leaves( + const std::vector>& leaves, L* d_leaves, Matrix* d_leaves_info, SubtreeParams& params) + { + uint64_t target_height = params.number_of_rows_padded * params.number_of_subtrees; + params.number_of_leaves_to_inject = 0; + while (params.leaves_offset < params.number_of_inputs && + next_pow_of_two(leaves[params.leaves_offset].height) >= target_height) { + if (next_pow_of_two(leaves[params.leaves_offset].height) == target_height) params.number_of_leaves_to_inject++; + params.leaves_offset++; + } + + if (params.number_of_leaves_to_inject) { + size_t rows_offset = params.subtree_idx * params.number_of_rows_padded; + size_t actual_layer_rows = leaves[params.leaves_offset - params.number_of_leaves_to_inject].height; + params.number_of_rows = std::min(actual_layer_rows - rows_offset, params.number_of_rows_padded); + + Matrix* leaves_info = static_cast*>(malloc(params.number_of_leaves_to_inject * sizeof(Matrix))); + L* d_leaves_ptr = d_leaves; + for (auto i = 0; i < params.number_of_leaves_to_inject; i++) { + Matrix leaf = leaves[params.leaves_offset - params.number_of_leaves_to_inject + i]; + if (!params.are_inputs_on_device) { + CHK_IF_RETURN(cudaMemcpyAsync( + d_leaves_ptr, leaf.values + rows_offset * leaf.width, params.number_of_rows * leaf.width * sizeof(L), + cudaMemcpyHostToDevice, params.ctx->stream)); + } else { + d_leaves_ptr = leaf.values + rows_offset * leaf.width; + } + + leaves_info[i] = {d_leaves_ptr, leaf.width, params.number_of_rows}; + d_leaves_ptr += params.number_of_rows * leaf.width; + } + CHK_IF_RETURN(cudaMemcpyAsync( + d_leaves_info, leaves_info, params.number_of_leaves_to_inject * sizeof(Matrix), cudaMemcpyHostToDevice, + params.ctx->stream)); + free(leaves_info); + } + + return CHK_LAST(); + } + + /// Checks if the current row needs to be copied out to the resulting digests array + /// Computes the needed offsets using segments model + template + cudaError_t maybe_copy_digests(D* digests, L* big_tree_digests, SubtreeParams& params) + { + if (!params.keep_rows || params.subtree_height < params.keep_rows + (int)params.caps_mode) { + D* digests_with_offset = big_tree_digests + params.segment_offset + + params.subtree_idx * params.number_of_rows_padded * params.digest_elements; + CHK_IF_RETURN(cudaMemcpyAsync( + digests_with_offset, digests, params.number_of_rows_padded * params.digest_elements * sizeof(D), + cudaMemcpyDeviceToHost, params.ctx->stream)); + params.segment_offset += params.segment_size; + } + return CHK_LAST(); + } + + template + cudaError_t fold_layer( + const std::vector>& leaves, + D* prev_layer, + D* next_layer, + L* aux_leaves_mem, + Matrix* d_leaves_info, + SubtreeParams& params) + { + CHK_IF_RETURN(slice_and_copy_leaves(leaves, aux_leaves_mem, d_leaves_info, params)); + + if (params.number_of_leaves_to_inject) { + CHK_IF_RETURN(params.compression->compress_and_inject( + d_leaves_info, params.number_of_leaves_to_inject, params.number_of_rows, prev_layer, next_layer, + params.digest_elements, *params.ctx)); + } else { + CHK_IF_RETURN(params.compression->run_hash_many_kernel( + prev_layer, next_layer, params.number_of_rows_padded, params.compression->width, params.digest_elements, + *params.ctx)); + } + + return CHK_LAST(); + } + + template + cudaError_t build_mmcs_subtree( + const std::vector>& leaves, + L* d_leaves, + D* states, + L* aux_leaves_mem, + L* big_tree_digests, + SubtreeParams& params) + { + // Leaves info + Matrix* d_leaves_info; + CHK_IF_RETURN(cudaMallocAsync(&d_leaves_info, params.number_of_inputs * sizeof(Matrix), params.ctx->stream)); + + CHK_IF_RETURN(slice_and_copy_leaves(leaves, d_leaves, d_leaves_info, params)); + + // Reuse leaves memory + D* digests = (D*)d_leaves; + + CHK_IF_RETURN(hash_leaves( + d_leaves_info, params.number_of_leaves_to_inject, params.number_of_rows, states, params.digest_elements, + *params.hasher, *params.ctx)); + + CHK_IF_RETURN(maybe_copy_digests(digests, big_tree_digests, params)); + + params.number_of_rows_padded /= params.arity; + params.segment_size /= params.arity; + params.subtree_height--; + + D* prev_layer = states; + D* next_layer = digests; + while (params.number_of_rows_padded > 0) { + CHK_IF_RETURN(fold_layer(leaves, prev_layer, next_layer, aux_leaves_mem, d_leaves_info, params)); + CHK_IF_RETURN(maybe_copy_digests(next_layer, big_tree_digests, params)); + swap(&prev_layer, &next_layer); + params.segment_size /= params.arity; + params.subtree_height--; + params.number_of_rows_padded /= params.arity; + } + return CHK_LAST(); + } + + template + cudaError_t mmcs_commit( + const Matrix* inputs, + const unsigned int number_of_inputs, + D* digests, + const SpongeHasher& hasher, + const SpongeHasher& compression, + const TreeBuilderConfig& tree_config) + { + CHK_INIT_IF_RETURN(); + cudaStream_t& stream = tree_config.ctx.stream; + + if (number_of_inputs == 0) THROW_ICICLE_ERR(IcicleError_t::InvalidArgument, "No matrices provided"); + + if (compression.preimage_max_length < tree_config.arity * tree_config.digest_elements) + THROW_ICICLE_ERR( + IcicleError_t::InvalidArgument, + "Hash max preimage length does not match merkle tree arity multiplied by digest elements"); + + std::vector> sorted_inputs(number_of_inputs); + std::partial_sort_copy( + inputs, inputs + number_of_inputs, sorted_inputs.begin(), sorted_inputs.end(), + [](const Matrix& left, const Matrix& right) { return left.height > right.height; }); + + // Check that the height of any two given matrices either rounds up + // to the same next power of two or otherwise equal + for (unsigned int i = 0; i < number_of_inputs - 1; i++) { + unsigned int left = sorted_inputs[i].height; + unsigned int right = sorted_inputs[i + 1].height; + + if (next_pow_of_two(left) == next_pow_of_two(right) && left != right) + THROW_ICICLE_ERR( + IcicleError_t::InvalidArgument, "Matrix heights that round up to the same power of two must be equal"); + } + + uint64_t max_height = sorted_inputs[0].height; + + // Calculate maximum additional memory needed for injected matrices + uint64_t max_aux_total_elements = 0; + uint64_t current_aux_total_elements = 0; + uint64_t current_height = 0; + uint64_t bottom_layer_leaves_elements = 0; + if (!tree_config.are_inputs_on_device) { + for (auto it = sorted_inputs.begin(); it < sorted_inputs.end(); it++) { + if (it->height == max_height) { + bottom_layer_leaves_elements += it->height * it->width; + continue; + } + + if (it->height != current_height) { + current_height = it->height; + current_aux_total_elements = 0; + } + + current_aux_total_elements += it->width * it->height; + if (current_aux_total_elements > max_aux_total_elements) { + max_aux_total_elements = current_aux_total_elements; + } + } + } + + uint64_t number_of_bottom_layer_rows = next_pow_of_two(max_height); + size_t leaves_info_memory = number_of_inputs * sizeof(Matrix); + + unsigned int tree_height = get_height(number_of_bottom_layer_rows); + + // This will determine how much splitting do we need to do + // `number_of_streams` subtrees should fit in the device + // This means each subtree should fit in `STREAM_CHUNK_SIZE` memory + uint64_t number_of_subtrees = 1; + uint64_t subtree_height = tree_height; + uint64_t subtree_bottom_layer_rows = number_of_bottom_layer_rows; + uint64_t subtree_states_size = subtree_bottom_layer_rows * hasher.width; + uint64_t subtree_digests_size = subtree_bottom_layer_rows * tree_config.digest_elements; + uint64_t subtree_leaves_elements = 0; + for (int i = 0; i < number_of_inputs && sorted_inputs[i].height == max_height; i++) { + subtree_leaves_elements += sorted_inputs[i].width * sorted_inputs[i].height; + } + uint64_t subtree_aux_elements = max_aux_total_elements; + + size_t subtree_leaves_memory = std::max(subtree_leaves_elements * sizeof(L), subtree_digests_size * sizeof(D)); + size_t subtree_memory_required = + sizeof(D) * subtree_states_size + subtree_leaves_memory + subtree_aux_elements * sizeof(L) + leaves_info_memory; + while (subtree_memory_required > STREAM_CHUNK_SIZE) { + number_of_subtrees *= tree_config.arity; + subtree_height--; + subtree_bottom_layer_rows /= tree_config.arity; + subtree_states_size /= tree_config.arity; + subtree_digests_size /= tree_config.arity; + subtree_leaves_elements /= tree_config.arity; + subtree_aux_elements /= tree_config.arity; + subtree_leaves_memory = std::max(subtree_leaves_elements * sizeof(L), subtree_digests_size * sizeof(D)); + subtree_memory_required = + sizeof(D) * subtree_states_size + subtree_leaves_memory + subtree_aux_elements * sizeof(L) + leaves_info_memory; + } + unsigned int cap_height = tree_height - subtree_height; + size_t caps_len = pow(tree_config.arity, cap_height) * tree_config.digest_elements; + + size_t available_memory, _total_memory; + CHK_IF_RETURN(cudaMemGetInfo(&available_memory, &_total_memory)); + if (available_memory < (GIGA / 8 + STREAM_CHUNK_SIZE)) { + THROW_ICICLE_ERR( + IcicleError_t::InvalidArgument, + "Not enough GPU memory to build a tree. At least 1.125 GB of GPU memory required"); + } + available_memory -= GIGA / 8; // Leave 128 MB just in case + + // We can effectively parallelize memory copy with streams + // as long as they don't operate on more than `STREAM_CHUNK_SIZE` bytes + const size_t number_of_streams = std::min((uint64_t)(available_memory / STREAM_CHUNK_SIZE), number_of_subtrees); + std::vector streams(number_of_streams); + for (size_t i = 0; i < number_of_streams; i++) { + CHK_IF_RETURN(cudaStreamCreate(&streams[i])); + } + + // If keep_rows is smaller then the remaining top-tree height + // we need to allocate additional memory to store the roots + // of subtrees, in order to proceed from there + bool caps_mode = tree_config.keep_rows && tree_config.keep_rows <= cap_height; + D* caps; + if (caps_mode) { caps = static_cast(malloc(caps_len * sizeof(D))); } + +#ifdef MERKLE_DEBUG + std::cout << "MMCS DEBUG" << std::endl; + std::cout << "====================================" << std::endl; + std::cout << "Available memory = " << available_memory / 1024 / 1024 << " MB" << std::endl; + std::cout << "Number of streams = " << number_of_streams << std::endl; + std::cout << "Number of subtrees = " << number_of_subtrees << std::endl; + std::cout << "Height of a subtree = " << subtree_height << std::endl; + std::cout << "Cutoff height = " << tree_height - subtree_height << std::endl; + std::cout << "Number of leaves in a subtree = " << subtree_bottom_layer_rows << std::endl; + std::cout << "State of a subtree = " << subtree_states_size << std::endl; + std::cout << "Digest elements for a subtree = " << subtree_digests_size << std::endl; + std::cout << "Size of 1 subtree states = " << subtree_states_size * sizeof(D) / 1024 / 1024 << " MB" << std::endl; + std::cout << "Size of 1 subtree digests = " << subtree_digests_size * sizeof(D) / 1024 / 1024 << " MB" << std::endl; + std::cout << "Cap height = " << cap_height << std::endl; + std::cout << "Enabling caps mode? " << caps_mode << std::endl; + + std::cout << "Allocating " << subtree_states_size * number_of_streams << " elements for states" << std::endl; + std::cout << "Allocating " << subtree_leaves_memory * number_of_streams << " bytes for leaves" << std::endl; + std::cout << "Allocating " << subtree_aux_elements * number_of_streams << " elements for aux leaves" << std::endl; + std::cout << std::endl; +#endif + + // Allocate memory for the states, injected leaves (aux) and digests + // These are shared by streams in a pool + D* states_ptr; + L *aux_ptr, *leaves_ptr; + CHK_IF_RETURN(cudaMallocAsync(&states_ptr, subtree_states_size * number_of_streams * sizeof(D), stream)); + CHK_IF_RETURN(cudaMemsetAsync(states_ptr, 0, subtree_states_size * number_of_streams * sizeof(D), stream)); + CHK_IF_RETURN(cudaMallocAsync(&leaves_ptr, subtree_leaves_memory * number_of_streams, stream)); + CHK_IF_RETURN(cudaMallocAsync(&aux_ptr, subtree_aux_elements * number_of_streams * sizeof(L), stream)); + // Wait for these allocations to finish + CHK_IF_RETURN(cudaStreamSynchronize(stream)); + + // Build subtrees in parallel. This for loop invokes kernels that can run in a pool of size `number_of_streams` + for (size_t subtree_idx = 0; subtree_idx < number_of_subtrees; subtree_idx++) { + size_t stream_idx = subtree_idx % number_of_streams; + cudaStream_t subtree_stream = streams[stream_idx]; + + D* subtree_state = states_ptr + stream_idx * subtree_states_size; + L* subtree_leaves = (L*)((unsigned char*)leaves_ptr + stream_idx * subtree_leaves_memory); + L* subtree_aux = aux_ptr + stream_idx * subtree_aux_elements; + + unsigned int subtree_keep_rows = 0; + if (tree_config.keep_rows) { + int diff = tree_config.keep_rows - cap_height; + subtree_keep_rows = std::max(1, diff); + } + device_context::DeviceContext subtree_context{subtree_stream, tree_config.ctx.device_id, tree_config.ctx.mempool}; + + SubtreeParams params = {}; + + params.number_of_inputs = number_of_inputs; + params.arity = tree_config.arity; + params.digest_elements = tree_config.digest_elements; + params.number_of_rows = subtree_bottom_layer_rows; + params.number_of_rows_padded = subtree_bottom_layer_rows; + + params.subtree_idx = subtree_idx; + params.subtree_height = subtree_height; + params.number_of_subtrees = number_of_subtrees; + + params.segment_size = number_of_bottom_layer_rows * tree_config.digest_elements; + params.keep_rows = subtree_keep_rows; + params.are_inputs_on_device = tree_config.are_inputs_on_device; + params.hasher = &hasher; + params.compression = &compression; + params.ctx = &subtree_context; + + cudaError_t subtree_result = build_mmcs_subtree( + sorted_inputs, + subtree_leaves, // d_leaves + subtree_state, // states + subtree_aux, // aux_leaves_mem + caps_mode ? caps : digests, // big_tree_digests + params // params + ); + CHK_IF_RETURN(subtree_result); + } + + for (size_t i = 0; i < number_of_streams; i++) { + CHK_IF_RETURN(cudaStreamSynchronize(streams[i])); + } + + // Finish the top-level tree if any + if (cap_height > 0) { + D* digests_ptr = (D*)leaves_ptr; + size_t start_segment_size = caps_len / tree_config.arity; + size_t start_segment_offset = 0; + if (!caps_mode) { // Calculate offset + size_t keep_rows = tree_config.keep_rows ? tree_config.keep_rows : tree_height + 1; + size_t layer_size = pow(tree_config.arity, keep_rows - 1) * tree_config.digest_elements; + for (int i = 0; i < keep_rows - cap_height; i++) { + start_segment_offset += layer_size; + layer_size /= tree_config.arity; + } + } + + CHK_IF_RETURN(cudaMemcpyAsync( + states_ptr, caps_mode ? caps : (digests + start_segment_offset - caps_len), caps_len * sizeof(D), + (caps_mode || !tree_config.are_outputs_on_device) ? cudaMemcpyHostToDevice : cudaMemcpyDeviceToDevice, stream)); + + uint64_t number_of_states = caps_len / tree_config.arity / tree_config.digest_elements; + Matrix* d_leaves_info; + CHK_IF_RETURN(cudaMallocAsync(&d_leaves_info, number_of_inputs * sizeof(Matrix), tree_config.ctx.stream)); + + SubtreeParams top_params = {}; + + top_params.number_of_inputs = number_of_inputs; + top_params.arity = tree_config.arity; + top_params.digest_elements = tree_config.digest_elements; + top_params.number_of_rows = number_of_states; + top_params.number_of_rows_padded = number_of_states; + + top_params.subtree_height = cap_height; + top_params.number_of_subtrees = 1; + + top_params.segment_offset = start_segment_offset; + top_params.segment_size = start_segment_size; + top_params.keep_rows = tree_config.keep_rows; + top_params.are_inputs_on_device = tree_config.are_inputs_on_device; + top_params.caps_mode = caps_mode; + top_params.hasher = &hasher; + top_params.compression = &compression; + top_params.ctx = &tree_config.ctx; + + D* prev_layer = states_ptr; + D* next_layer = digests_ptr; + while (top_params.number_of_rows_padded > 0) { + CHK_IF_RETURN(fold_layer(sorted_inputs, prev_layer, next_layer, aux_ptr, d_leaves_info, top_params)); + CHK_IF_RETURN(maybe_copy_digests(next_layer, digests, top_params)); + swap(&prev_layer, &next_layer); + top_params.segment_size /= top_params.arity; + top_params.subtree_height--; + top_params.number_of_rows_padded /= top_params.arity; + } + } + + if (caps_mode) { free(caps); } + CHK_IF_RETURN(cudaFreeAsync(states_ptr, stream)); + CHK_IF_RETURN(cudaFreeAsync(leaves_ptr, stream)); + for (size_t i = 0; i < number_of_streams; i++) { + CHK_IF_RETURN(cudaStreamDestroy(streams[i])); + } + if (!tree_config.is_async) return CHK_STICKY(cudaStreamSynchronize(stream)); + return CHK_LAST(); + } + +} // namespace merkle_tree diff --git a/icicle/src/merkle-tree/tests/merkle/.gitignore b/icicle/src/merkle-tree/tests/merkle/.gitignore new file mode 100644 index 000000000..b3a0cf9c9 --- /dev/null +++ b/icicle/src/merkle-tree/tests/merkle/.gitignore @@ -0,0 +1,7 @@ +merkle.o +poseidon2.o +test_merkle_poseidon2 +merkle_bls.o +poseidon.o +test_merkle_poseidon +test_merkle \ No newline at end of file diff --git a/icicle/src/merkle-tree/tests/merkle/Makefile b/icicle/src/merkle-tree/tests/merkle/Makefile new file mode 100644 index 000000000..b3e3cfbc6 --- /dev/null +++ b/icicle/src/merkle-tree/tests/merkle/Makefile @@ -0,0 +1,23 @@ +test_merkle_poseidon: poseidon.o merkle_bls.o + nvcc -o test_merkle_poseidon -I../../../../include -DFIELD=bls12_381 -DFIELD_ID=2 -DCURVE=bls12_381 -DMERKLE_DEBUG poseidon.o merkle_bls.o test.cu + ./test_merkle_poseidon + +merkle_bls.o: ../../extern.cu ../../merkle.cu + nvcc -o merkle_bls.o -I../../../../include -DFIELD=bls12_381 -DFIELD_ID=2 -DCURVE=bls12_381 -DMERKLE_DEBUG -c ../../extern.cu + +poseidon.o: ../../../poseidon/extern.cu + nvcc -o poseidon.o -I../../../../include -DFIELD=bls12_381 -DFIELD_ID=2 -DCURVE=bls12_381 -c ../../../poseidon/extern.cu + + +test_merkle: poseidon2.o merkle.o + nvcc -o test_merkle -I../../../../include -DFIELD=babybear -DFIELD_ID=1001 -DMERKLE_DEBUG poseidon2.o merkle.o test_poseidon2.cu + ./test_merkle + +merkle.o: ../../extern.cu ../../merkle.cu + nvcc -o merkle.o -I../../../../include -DFIELD=babybear -DFIELD_ID=1001 -DMERKLE_DEBUG -c ../../extern.cu + +poseidon2.o: ../../../poseidon2/extern.cu + nvcc -o poseidon2.o -I../../../../include -DFIELD=babybear -DFIELD_ID=1001 -c ../../../poseidon2/extern.cu + +clear: + rm -f poseidon2.o merkle.o test_merkle merkle_bls.o poseidon.o test_merkle \ No newline at end of file diff --git a/icicle/src/poseidon/tree/test.cu b/icicle/src/merkle-tree/tests/merkle/test.cu similarity index 93% rename from icicle/src/poseidon/tree/test.cu rename to icicle/src/merkle-tree/tests/merkle/test.cu index e487d56b3..544e23c4d 100644 --- a/icicle/src/poseidon/tree/test.cu +++ b/icicle/src/merkle-tree/tests/merkle/test.cu @@ -1,10 +1,3 @@ -// #define DEBUG -#define MERKLE_DEBUG - -#include "curves/curve_config.cuh" -#include "../poseidon.cu" -#include "merkle.cu" - #ifndef __CUDA_ARCH__ #include #include @@ -12,15 +5,18 @@ #include #include -using namespace poseidon; -using namespace merkle; -using namespace curve_config; -using FpMilliseconds = std::chrono::duration; +#include "merkle-tree/merkle.cuh" + +#include "poseidon/poseidon.cuh" + +#include "api/bls12_381.h" +using namespace bls12_381; // Arity #define A 2 #define T (A + 1) +using FpMilliseconds = std::chrono::duration; #define START_TIMER(timer) auto timer##_start = std::chrono::high_resolution_clock::now(); #define END_TIMER(timer, msg) \ printf("%s: %.0f ms\n", msg, FpMilliseconds(std::chrono::high_resolution_clock::now() - timer##_start).count()); @@ -30,24 +26,24 @@ int main(int argc, char* argv[]) // Load poseidon constants START_TIMER(timer_const); device_context::DeviceContext ctx = device_context::get_default_device_context(); - PoseidonConstants constants; - init_optimized_poseidon_constants(A, ctx, &constants); + poseidon::Poseidon poseidon(A, ctx); END_TIMER(timer_const, "Load poseidon constants"); /// Tree of height N and arity A contains \sum{A^i} for i in 0..N-1 elements - uint32_t tree_height = argc > 1 ? atoi(argv[1]) : 28; - uint32_t number_of_leaves = pow(A, (tree_height - 1)); + uint32_t tree_height = argc > 1 ? atoi(argv[1]) : 26; + uint32_t number_of_leaves = pow(A, tree_height); + uint32_t total_number_of_leaves = number_of_leaves * A; /// Use keep_rows to specify how many rows do you want to store int keep_rows = argc > 2 ? atoi(argv[2]) : 7; - size_t digests_len = get_digests_len(keep_rows + 1, A); + size_t digests_len = merkle_tree::get_digests_len(keep_rows - 1, A, 1); - /// Fill leaves with scalars [0, 1, ... 2^{tree_height - 1} - 1] + /// Fill leaves with scalars [0, 1, ... 2^tree_height - 1] START_TIMER(timer_allocation); scalar_t input = scalar_t::zero(); - size_t leaves_mem = number_of_leaves * sizeof(scalar_t); + size_t leaves_mem = total_number_of_leaves * sizeof(scalar_t); scalar_t* leaves = static_cast(malloc(leaves_mem)); - for (uint32_t i = 0; i < number_of_leaves; i++) { + for (uint32_t i = 0; i < total_number_of_leaves; i++) { leaves[i] = input; input = input + scalar_t::one(); } @@ -62,6 +58,7 @@ int main(int argc, char* argv[]) std::cout << "Memory for leaves = " << leaves_mem / 1024 / 1024 << " MB; " << leaves_mem / 1024 / 1024 / 1024 << " GB" << std::endl; std::cout << "Number of leaves = " << number_of_leaves << std::endl; + std::cout << "Total Number of leaves = " << total_number_of_leaves << std::endl; std::cout << "Memory for digests = " << digests_mem / 1024 / 1024 << " MB; " << digests_mem / 1024 / 1024 / 1024 << " GB" << std::endl; std::cout << "Number of digest elements = " << digests_len << std::endl; @@ -69,12 +66,17 @@ int main(int argc, char* argv[]) std::cout << "Total RAM consumption = " << (digests_mem + leaves_mem) / 1024 / 1024 << " MB; " << (digests_mem + leaves_mem) / 1024 / 1024 / 1024 << " GB" << std::endl; - TreeBuilderConfig config = default_merkle_config(); - config.keep_rows = keep_rows; + merkle_tree::TreeBuilderConfig tree_config = merkle_tree::default_merkle_config(); + tree_config.arity = 2; + tree_config.keep_rows = keep_rows; START_TIMER(timer_merkle); - build_merkle_tree(leaves, digests, tree_height, constants, config); + bls12_381_build_merkle_tree(leaves, digests, tree_height, A, &poseidon, &poseidon, tree_config); END_TIMER(timer_merkle, "Merkle tree built: ") + for (int i = 0; i < digests_len; i++) { + std::cout << digests[i] << std::endl; + } + // Use this to generate test vectors // for (int i = 0; i < digests_len; i++) { // std::cout << "{"; diff --git a/icicle/src/merkle-tree/tests/merkle/test_poseidon2.cu b/icicle/src/merkle-tree/tests/merkle/test_poseidon2.cu new file mode 100644 index 000000000..7bcb444ce --- /dev/null +++ b/icicle/src/merkle-tree/tests/merkle/test_poseidon2.cu @@ -0,0 +1,108 @@ +#ifndef __CUDA_ARCH__ +#include +#include +#include +#include +#include + +#include "merkle-tree/merkle.cuh" + +#include "poseidon2/poseidon2.cuh" + +#include "api/babybear.h" +using namespace babybear; + +using FpMilliseconds = std::chrono::duration; +#define START_TIMER(timer) auto timer##_start = std::chrono::high_resolution_clock::now(); +#define END_TIMER(timer, msg) \ + printf("%s: %.0f ms\n", msg, FpMilliseconds(std::chrono::high_resolution_clock::now() - timer##_start).count()); + +int main(int argc, char* argv[]) +{ + /// Tree of height N and arity A contains \sum{A^i} for i in 0..N elements + uint32_t tree_arity = 2; + uint32_t width = 16; + uint32_t input_block_len = 8; + uint32_t digest_elements = 8; + uint64_t tree_height = argc > 1 ? atoi(argv[1]) : 23; + uint64_t number_of_leaves = pow(tree_arity, tree_height); + uint64_t total_number_of_leaves = number_of_leaves * input_block_len; + + // Load poseidon constants + START_TIMER(timer_const); + device_context::DeviceContext ctx = device_context::get_default_device_context(); + poseidon2::Poseidon2 poseidon( + width, input_block_len, poseidon2::MdsType::DEFAULT_MDS, poseidon2::DiffusionStrategy::DEFAULT_DIFFUSION, ctx); + END_TIMER(timer_const, "Load poseidon constants"); + + /// Use keep_rows to specify how many rows do you want to store + int keep_rows = argc > 2 ? atoi(argv[2]) : 3; + size_t digests_len = merkle_tree::get_digests_len(keep_rows - 1, tree_arity, digest_elements); + + /// Fill leaves with scalars [0, 1, ... 2^tree_height - 1] + START_TIMER(timer_allocation); + scalar_t input = scalar_t::zero(); + size_t leaves_mem = total_number_of_leaves * sizeof(scalar_t); + scalar_t* leaves = static_cast(malloc(leaves_mem)); + for (uint64_t i = 0; i < total_number_of_leaves; i++) { + leaves[i] = input; + input = input + scalar_t::one(); + } + END_TIMER(timer_allocation, "Allocated memory for leaves: "); + + /// Allocate memory for digests of {keep_rows} rows of a tree + START_TIMER(timer_digests); + size_t digests_mem = digests_len * sizeof(scalar_t); + scalar_t* digests = static_cast(malloc(digests_mem)); + END_TIMER(timer_digests, "Allocated memory for digests"); + + std::cout << "Memory for leaves = " << leaves_mem / 1024 / 1024 << " MB; " << leaves_mem / 1024 / 1024 / 1024 << " GB" + << std::endl; + std::cout << "Number of leaves = " << number_of_leaves << std::endl; + std::cout << "Total Number of leaves = " << total_number_of_leaves << std::endl; + std::cout << "Memory for digests = " << digests_mem / 1024 / 1024 << " MB; " << digests_mem / 1024 / 1024 / 1024 + << " GB" << std::endl; + std::cout << "Number of digest elements = " << digests_len << std::endl; + + std::cout << "Total RAM consumption = " << (digests_mem + leaves_mem) / 1024 / 1024 << " MB; " + << (digests_mem + leaves_mem) / 1024 / 1024 / 1024 << " GB" << std::endl; + + merkle_tree::TreeBuilderConfig tree_config = merkle_tree::default_merkle_config(); + tree_config.arity = tree_arity; + tree_config.keep_rows = keep_rows; + tree_config.digest_elements = digest_elements; + START_TIMER(timer_merkle); + babybear_build_merkle_tree(leaves, digests, tree_height, input_block_len, &poseidon, &poseidon, tree_config); + END_TIMER(timer_merkle, "Merkle tree built: ") + + for (int i = 0; i < digests_len; i++) { + // std::cout << digests[i] << std::endl; + } + + // Use this to generate test vectors + // for (int i = 0; i < digests_len; i++) { + // std::cout << "{"; + // for (int j = 0; j < 1; j++) { + // std::cout << ((uint32_t*)&digests[i].limbs_storage)[j]; + // } + // std::cout << "}," << std::endl; + // } + + scalar_t expected[64] = { + {1198029810}, {1114813365}, {241588005}, {735332587}, {201392606}, {623383436}, {60086186}, {1225304654}, + {1501472115}, {891216097}, {184481194}, {855632748}, {1503541944}, {1483537725}, {1023563730}, {698957505}, + {1322038939}, {1132881200}, {104782797}, {68847168}, {420051722}, {126069919}, {1350263697}, {1711085395}, + {1322038939}, {1132881200}, {104782797}, {68847168}, {420051722}, {126069919}, {1350263697}, {1711085395}, + {1019525203}, {127215304}, {1199733491}, {1473997036}, {548538385}, {364347137}, {570748364}, {426431873}, + {926562920}, {6278762}, {1894248581}, {1304248433}, {1635020421}, {719342960}, {1373719279}, {700539301}, + {708916911}, {925660920}, {994927540}, {1925434995}, {208534303}, {69614512}, {1701199215}, {1825115630}}; + + for (int i = 0; i < digests_len; i++) { + scalar_t root = digests[i]; + assert(root == expected[i]); + } + free(digests); + free(leaves); +} + +#endif \ No newline at end of file diff --git a/icicle/src/merkle-tree/tests/mmcs/.gitignore b/icicle/src/merkle-tree/tests/mmcs/.gitignore new file mode 100644 index 000000000..ae6419c96 --- /dev/null +++ b/icicle/src/merkle-tree/tests/mmcs/.gitignore @@ -0,0 +1,4 @@ +mmcs.o +poseidon2.o +test_mmcs_poseidon2 +vec_ops.o \ No newline at end of file diff --git a/icicle/src/merkle-tree/tests/mmcs/Makefile b/icicle/src/merkle-tree/tests/mmcs/Makefile new file mode 100644 index 000000000..42db32337 --- /dev/null +++ b/icicle/src/merkle-tree/tests/mmcs/Makefile @@ -0,0 +1,15 @@ +test_merkle: poseidon2.o mmcs.o vec_ops.o + nvcc -o test_mmcs_poseidon2 -lineinfo -I../../../../include -DFIELD=babybear -DFIELD_ID=1001 -DMERKLE_DEBUG poseidon2.o vec_ops.o mmcs.o test_poseidon2.cu + ./test_mmcs_poseidon2 + +mmcs.o: ../../extern_mmcs.cu ../../mmcs.cu + nvcc -o mmcs.o -I../../../../include -lineinfo -DFIELD=babybear -DFIELD_ID=1001 -DMERKLE_DEBUG -c ../../extern_mmcs.cu + +poseidon2.o: ../../../poseidon2/extern.cu + nvcc -o poseidon2.o -I../../../../include -lineinfo -DFIELD=babybear -DFIELD_ID=1001 -c ../../../poseidon2/extern.cu + +vec_ops.o: + nvcc -o vec_ops.o -I../../../../include -lineinfo -DFIELD=babybear -DFIELD_ID=1001 -c ../../../vec_ops/extern.cu + +clear: + rm -f poseidon2.o mmcs.o vec_ops.o test_mmcs_poseidon2 diff --git a/icicle/src/merkle-tree/tests/mmcs/test_poseidon2.cu b/icicle/src/merkle-tree/tests/mmcs/test_poseidon2.cu new file mode 100644 index 000000000..9de240dbc --- /dev/null +++ b/icicle/src/merkle-tree/tests/mmcs/test_poseidon2.cu @@ -0,0 +1,139 @@ +#ifndef __CUDA_ARCH__ +#include +#include +#include +#include +#include + +#include "merkle-tree/merkle.cuh" + +#include "poseidon2/poseidon2.cuh" + +#include "api/babybear.h" +using namespace babybear; + +using FpMilliseconds = std::chrono::duration; +#define START_TIMER(timer) auto timer##_start = std::chrono::high_resolution_clock::now(); +#define END_TIMER(timer, msg) \ + printf("%s: %.0f ms\n", msg, FpMilliseconds(std::chrono::high_resolution_clock::now() - timer##_start).count()); + +int main(int argc, char* argv[]) +{ + /// Tree of height N and arity A contains \sum{A^i} for i in 0..N elements + uint32_t tree_arity = 2; + uint32_t width = 16; + uint32_t input_block_len = 600; + uint32_t rate = 8; + uint32_t digest_elements = 8; + uint32_t copied_matrices = 1; + uint64_t tree_height = argc > 1 ? atoi(argv[1]) : 3; + uint64_t number_of_leaves = pow(tree_arity, tree_height); + uint64_t total_number_of_leaves = number_of_leaves * input_block_len; + + bool are_inputs_on_device = true; + + // Load poseidon constants + START_TIMER(timer_const); + device_context::DeviceContext ctx = device_context::get_default_device_context(); + poseidon2::Poseidon2 poseidon( + width, rate, poseidon2::MdsType::PLONKY, poseidon2::DiffusionStrategy::MONTGOMERY, ctx); + END_TIMER(timer_const, "Load poseidon constants"); + + /// Use keep_rows to specify how many rows do you want to store + int keep_rows = argc > 2 ? atoi(argv[2]) : 3; + size_t digests_len = merkle_tree::get_digests_len(keep_rows - 1, tree_arity, digest_elements); + + /// Fill leaves with scalars [0, 1, ... 2^tree_height - 1] + START_TIMER(timer_allocation); + scalar_t input = scalar_t::zero(); + + // unsigned int number_of_inputs = tree_height * copied_matrices; + unsigned int number_of_inputs = 1; + Matrix* leaves = static_cast*>(malloc(number_of_inputs * sizeof(Matrix))); + uint64_t current_matrix_rows = number_of_leaves; + for (int i = 0; i < number_of_inputs; i++) { + uint64_t current_matrix_size = current_matrix_rows * input_block_len; + for (int j = 0; j < copied_matrices; j++) { + scalar_t* matrix = static_cast(malloc(current_matrix_size * sizeof(scalar_t))); + + for (uint64_t k = 0; k < current_matrix_size; k++) { + matrix[k] = input; + input = input + scalar_t::one(); + } + + scalar_t* d_matrix; + if (are_inputs_on_device) { + cudaMalloc(&d_matrix, current_matrix_size * sizeof(scalar_t)); + cudaMemcpy(d_matrix, matrix, current_matrix_size * sizeof(scalar_t), cudaMemcpyHostToDevice); + } + + leaves[i * copied_matrices + j] = { + are_inputs_on_device ? d_matrix : matrix, + input_block_len, + current_matrix_rows, + }; + } + + current_matrix_rows /= tree_arity; + } + + END_TIMER(timer_allocation, "Allocated memory for leaves: "); + + /// Allocate memory for digests of {keep_rows} rows of a tree + START_TIMER(timer_digests); + size_t digests_mem = digests_len * sizeof(scalar_t); + scalar_t* digests = static_cast(malloc(digests_mem)); + END_TIMER(timer_digests, "Allocated memory for digests"); + + // std::cout << "Memory for leaves = " << total_number_of_leaves * sizeof(scalar_t) / 1024 / 1024 << " MB; " << + // leaves_mem / 1024 / 1024 / 1024 << " GB" + // << std::endl; + std::cout << "Number of leaves = " << number_of_leaves << std::endl; + std::cout << "Total Number of leaves = " << total_number_of_leaves << std::endl; + std::cout << "Memory for digests = " << digests_mem / 1024 / 1024 << " MB; " << digests_mem / 1024 / 1024 / 1024 + << " GB" << std::endl; + std::cout << "Number of digest elements = " << digests_len << std::endl; + std::cout << std::endl; + + // std::cout << "Total RAM consumption = " << (digests_mem + leaves_mem) / 1024 / 1024 << " MB; " + // << (digests_mem + leaves_mem) / 1024 / 1024 / 1024 << " GB" << std::endl; + + merkle_tree::TreeBuilderConfig tree_config = merkle_tree::default_merkle_config(); + tree_config.are_inputs_on_device = are_inputs_on_device; + tree_config.arity = tree_arity; + tree_config.keep_rows = keep_rows; + tree_config.digest_elements = digest_elements; + START_TIMER(timer_merkle); + babybear_mmcs_commit_cuda(leaves, number_of_inputs, digests, &poseidon, &poseidon, tree_config); + END_TIMER(timer_merkle, "Merkle tree built: ") + + for (int i = 0; i < 10; i++) { + std::cout << digests[digests_len - i - 1] << std::endl; + } + + // Use this to generate test vectors + // for (int i = 0; i < digests_len; i++) { + // std::cout << "{"; + // for (int j = 0; j < 8; j++) { + // std::cout << ((uint64_t*)&digests[i].limbs_storage)[j]; + // if (j != 7) { std::cout << ", "; } + // } + // std::cout << "}," << std::endl; + // } + + /// These scalars are digests of top-7 rows of a Merkle tree. + /// Arity = 2, Tree height = 28, keep_rows = 7 + /// They are aligned in the following format: + /// L-7 L-6 L-5 L-4 L-3 L-2 L-1 + /// [0..63, 64..95, 96..111, 112..119, 120..123, 124..125, 126] + scalar_t expected[0] = {}; + + for (int i = 0; i < digests_len; i++) { + scalar_t root = digests[i]; + // assert(root == expected[i]); + } + free(digests); + free(leaves); +} + +#endif \ No newline at end of file diff --git a/icicle/src/poseidon/Makefile b/icicle/src/poseidon/Makefile index 22fd2a96a..11400b418 100644 --- a/icicle/src/poseidon/Makefile +++ b/icicle/src/poseidon/Makefile @@ -1,2 +1,5 @@ -test_poseidon : test.cu poseidon.cu kernels.cu constants.cu nvcc - o test_poseidon - I../../ include - DFIELD_ID = - 2 - DCURVE_ID = 2 test.cu./ test_poseidon +test_poseidon: test.cu + nvcc -o test_poseidon -I../../include -DFIELD=bls12_381 -DFIELD_ID=2 -DCURVE_ID=2 -DDEVMODE -DDEBUG extern.cu test.cu + +test_poseidon_m31: test_m31.cu + nvcc -o test_poseidon -I../../include -DFIELD=m31 -DFIELD_ID=1003 -DDEVMODE -DDEBUG extern.cu test_m31.cu diff --git a/icicle/src/poseidon/constants.cu b/icicle/src/poseidon/constants.cu index 97d67490f..bed5a9be0 100644 --- a/icicle/src/poseidon/constants.cu +++ b/icicle/src/poseidon/constants.cu @@ -1,4 +1,5 @@ -#include "poseidon/poseidon.cuh" +#include "poseidon/constants.cuh" +#include "gpu-utils/device_context.cuh" /// These are pre-calculated constants for different curves #include "fields/id.h" @@ -17,17 +18,25 @@ using namespace poseidon_constants_bw6_761; #elif FIELD_ID == GRUMPKIN #include "poseidon/constants/grumpkin_poseidon.h" using namespace poseidon_constants_grumpkin; +#elif FIELD_ID == M31 +#include "poseidon/constants/m31_poseidon.h" +using namespace poseidon_constants_m31; #endif namespace poseidon { template cudaError_t create_optimized_poseidon_constants( - int arity, - int full_rounds_half, - int partial_rounds, - const S* constants, - device_context::DeviceContext& ctx, - PoseidonConstants* poseidon_constants) + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const S* round_constants, + const S* mds_matrix, + const S* non_sparse_matrix, + const S* sparse_matrices, + const S domain_tag, + PoseidonConstants* poseidon_constants, + device_context::DeviceContext& ctx) { CHK_INIT_IF_RETURN(); cudaStream_t& stream = ctx.stream; @@ -41,24 +50,33 @@ namespace poseidon { S* d_constants; CHK_IF_RETURN(cudaMallocAsync(&d_constants, sizeof(S) * constants_len, stream)); - // Copy constants - CHK_IF_RETURN(cudaMemcpyAsync(d_constants, constants, sizeof(S) * constants_len, cudaMemcpyHostToDevice, stream)); - - S* round_constants = d_constants; - S* mds_matrix = round_constants + round_constants_len; - S* non_sparse_matrix = mds_matrix + mds_matrix_len; - S* sparse_matrices = non_sparse_matrix + mds_matrix_len; + S* d_round_constants = d_constants; + S* d_mds_matrix = d_round_constants + round_constants_len; + S* d_non_sparse_matrix = d_mds_matrix + mds_matrix_len; + S* d_sparse_matrices = d_non_sparse_matrix + mds_matrix_len; - // Pick the domain_tag accordinaly - // For now, we only support Merkle tree mode - uint32_t tree_domain_tag_value = 1; - tree_domain_tag_value = (tree_domain_tag_value << (width - 1)) - tree_domain_tag_value; - S domain_tag = S::from(tree_domain_tag_value); + // Copy constants + CHK_IF_RETURN(cudaMemcpyAsync( + d_round_constants, round_constants, sizeof(S) * round_constants_len, cudaMemcpyHostToDevice, stream)); + CHK_IF_RETURN( + cudaMemcpyAsync(d_mds_matrix, mds_matrix, sizeof(S) * mds_matrix_len, cudaMemcpyHostToDevice, stream)); + CHK_IF_RETURN(cudaMemcpyAsync( + d_non_sparse_matrix, non_sparse_matrix, sizeof(S) * mds_matrix_len, cudaMemcpyHostToDevice, stream)); + CHK_IF_RETURN(cudaMemcpyAsync( + d_sparse_matrices, sparse_matrices, sizeof(S) * sparse_matrices_len, cudaMemcpyHostToDevice, stream)); // Make sure all the constants have been copied CHK_IF_RETURN(cudaStreamSynchronize(stream)); - *poseidon_constants = {arity, partial_rounds, full_rounds_half, round_constants, - mds_matrix, non_sparse_matrix, sparse_matrices, domain_tag}; + *poseidon_constants = { + arity, + alpha, + partial_rounds, + full_rounds_half, + d_round_constants, + d_mds_matrix, + d_non_sparse_matrix, + d_sparse_matrices, + domain_tag}; return CHK_LAST(); } @@ -68,8 +86,8 @@ namespace poseidon { int arity, device_context::DeviceContext& ctx, PoseidonConstants* poseidon_constants) { CHK_INIT_IF_RETURN(); - int full_rounds_half = FULL_ROUNDS_DEFAULT; - int partial_rounds; + unsigned int full_rounds_half = FULL_ROUNDS_DEFAULT; + unsigned int partial_rounds; unsigned char* constants; switch (arity) { case 2: @@ -94,8 +112,41 @@ namespace poseidon { } S* h_constants = reinterpret_cast(constants); - create_optimized_poseidon_constants(arity, full_rounds_half, partial_rounds, h_constants, ctx, poseidon_constants); + unsigned int width = arity + 1; + unsigned int round_constants_len = width * full_rounds_half * 2 + partial_rounds; + unsigned int mds_matrix_len = width * width; + + S* round_constants = h_constants; + S* mds_matrix = round_constants + round_constants_len; + S* non_sparse_matrix = mds_matrix + mds_matrix_len; + S* sparse_matrices = non_sparse_matrix + mds_matrix_len; + + // Pick the domain_tag accordinaly + // For now, we only support Merkle tree mode + uint32_t tree_domain_tag_value = 1; + tree_domain_tag_value = (tree_domain_tag_value << (width - 1)) - tree_domain_tag_value; + S domain_tag = S::from(tree_domain_tag_value); + + create_optimized_poseidon_constants( + arity, 5, partial_rounds, full_rounds_half, round_constants, mds_matrix, non_sparse_matrix, sparse_matrices, + domain_tag, poseidon_constants, ctx); + + return CHK_LAST(); + } + + template + cudaError_t release_optimized_poseidon_constants(PoseidonConstants* constants, device_context::DeviceContext& ctx) + { + CHK_INIT_IF_RETURN(); + CHK_IF_RETURN(cudaFreeAsync(constants->round_constants, ctx.stream)); + constants->arity = 0; + constants->partial_rounds = 0; + constants->full_rounds_half = 0; + constants->round_constants = nullptr; + constants->mds_matrix = nullptr; + constants->non_sparse_matrix = nullptr; + constants->sparse_matrices = nullptr; return CHK_LAST(); } } // namespace poseidon \ No newline at end of file diff --git a/icicle/src/poseidon/extern.cu b/icicle/src/poseidon/extern.cu index 66eac378d..d9c8211ae 100644 --- a/icicle/src/poseidon/extern.cu +++ b/icicle/src/poseidon/extern.cu @@ -2,58 +2,68 @@ using namespace field_config; -#include "poseidon.cu" +#include "poseidon/poseidon.cuh" #include "constants.cu" #include "gpu-utils/device_context.cuh" #include "utils/utils.h" namespace poseidon { - /** - * Extern "C" version of [poseidon_hash_cuda] function with the following - * value of template parameter (where the field is given by `-DFIELD` env variable during build): - * - `S` is the [field](@ref scalar_t) - either a scalar field of the elliptic curve or a - * stand-alone "STARK field"; - * @return `cudaSuccess` if the execution was successful and an error code otherwise. - */ - extern "C" cudaError_t CONCAT_EXPAND(FIELD, poseidon_hash_cuda)( - scalar_t* input, - scalar_t* output, - int number_of_states, - int arity, - const PoseidonConstants& constants, - PoseidonConfig& config) + typedef class Poseidon PoseidonInst; + + extern "C" cudaError_t CONCAT_EXPAND(FIELD, poseidon_create_cuda)( + PoseidonInst** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const scalar_t* round_constants, + const scalar_t* mds_matrix, + const scalar_t* non_sparse_matrix, + const scalar_t* sparse_matrices, + const scalar_t& domain_tag, + device_context::DeviceContext& ctx) + { + try { + *poseidon = new PoseidonInst( + arity, alpha, partial_rounds, full_rounds_half, round_constants, mds_matrix, non_sparse_matrix, sparse_matrices, + domain_tag, ctx); + return cudaError_t::cudaSuccess; + } catch (const IcicleError& _error) { + return cudaError_t::cudaErrorUnknown; + } + } + + extern "C" cudaError_t CONCAT_EXPAND(FIELD, poseidon_load_cuda)( + PoseidonInst** poseidon, unsigned int arity, device_context::DeviceContext& ctx) { - switch (arity) { - case 2: - return poseidon_hash(input, output, number_of_states, constants, config); - case 4: - return poseidon_hash(input, output, number_of_states, constants, config); - case 8: - return poseidon_hash(input, output, number_of_states, constants, config); - case 11: - return poseidon_hash(input, output, number_of_states, constants, config); - default: - THROW_ICICLE_ERR(IcicleError_t::InvalidArgument, "PoseidonHash: #arity must be one of [2, 4, 8, 11]"); + try { + *poseidon = new PoseidonInst(arity, ctx); + return cudaError_t::cudaSuccess; + } catch (const IcicleError& _error) { + return cudaError_t::cudaErrorUnknown; } - return CHK_LAST(); } - extern "C" cudaError_t CONCAT_EXPAND(FIELD, create_optimized_poseidon_constants_cuda)( - int arity, - int full_rounds_half, - int partial_rounds, - const scalar_t* constants, - device_context::DeviceContext& ctx, - PoseidonConstants* poseidon_constants) + extern "C" cudaError_t CONCAT_EXPAND(FIELD, poseidon_hash_many_cuda)( + const PoseidonInst* poseidon, + const scalar_t* inputs, + scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + const SpongeConfig& cfg) { - return create_optimized_poseidon_constants( - arity, full_rounds_half, partial_rounds, constants, ctx, poseidon_constants); + return poseidon->hash_many(inputs, output, number_of_states, input_block_len, output_len, cfg); } - extern "C" cudaError_t CONCAT_EXPAND(FIELD, init_optimized_poseidon_constants_cuda)( - int arity, device_context::DeviceContext& ctx, PoseidonConstants* constants) + extern "C" cudaError_t CONCAT_EXPAND(FIELD, poseidon_delete_cuda)(PoseidonInst* poseidon) { - return init_optimized_poseidon_constants(arity, ctx, constants); + try { + poseidon->~Poseidon(); + return cudaError_t::cudaSuccess; + } catch (const IcicleError& _error) { + return cudaError_t::cudaErrorUnknown; + } } } // namespace poseidon \ No newline at end of file diff --git a/icicle/src/poseidon/poseidon.cu b/icicle/src/poseidon/poseidon.cu deleted file mode 100644 index 835f9124e..000000000 --- a/icicle/src/poseidon/poseidon.cu +++ /dev/null @@ -1,90 +0,0 @@ -#include "fields/field_config.cuh" - -using namespace field_config; - -#include "poseidon/poseidon.cuh" -#include "kernels.cu" - -namespace poseidon { - template - cudaError_t - permute_many(S* states, size_t number_of_states, const PoseidonConstants& constants, cudaStream_t& stream) - { - size_t rc_offset = 0; - - full_rounds<<< - PKC::number_of_full_blocks(number_of_states), PKC::number_of_threads, - sizeof(S) * PKC::hashes_per_block * T, stream>>>( - states, number_of_states, rc_offset, FIRST_FULL_ROUNDS, constants); - rc_offset += T * (constants.full_rounds_half + 1); - - partial_rounds - <<::number_of_singlehash_blocks(number_of_states), PKC::singlehash_block_size, 0, stream>>>( - states, number_of_states, rc_offset, constants); - rc_offset += constants.partial_rounds; - - full_rounds<<< - PKC::number_of_full_blocks(number_of_states), PKC::number_of_threads, - sizeof(S) * PKC::hashes_per_block * T, stream>>>( - states, number_of_states, rc_offset, SECOND_FULL_ROUNDS, constants); - return CHK_LAST(); - } - - template - cudaError_t poseidon_hash( - S* input, S* output, size_t number_of_states, const PoseidonConstants& constants, const PoseidonConfig& config) - { - CHK_INIT_IF_RETURN(); - cudaStream_t& stream = config.ctx.stream; - S* states; - if (config.input_is_a_state) { - states = input; - } else { - // allocate memory for {number_of_states} states of {t} scalars each - CHK_IF_RETURN(cudaMallocAsync(&states, number_of_states * T * sizeof(S), stream)) - - // This is where the input matrix of size Arity x NumberOfBlocks is - // padded and copied to device in a T x NumberOfBlocks matrix - CHK_IF_RETURN(cudaMemcpy2DAsync( - states, T * sizeof(S), // Device pointer and device pitch - input, (T - 1) * sizeof(S), // Host pointer and pitch - (T - 1) * sizeof(S), number_of_states, // Size of the source matrix (Arity x NumberOfBlocks) - cudaMemcpyHostToDevice, stream)); - } - - S* output_device; - if (config.are_outputs_on_device) { - output_device = output; - } else { - CHK_IF_RETURN(cudaMallocAsync(&output_device, number_of_states * sizeof(S), stream)) - } - - prepare_poseidon_states - <<::number_of_full_blocks(number_of_states), PKC::number_of_threads, 0, stream>>>( - states, number_of_states, constants.domain_tag, config.aligned); - - cudaError_t hash_error = permute_many(states, number_of_states, constants, stream); - CHK_IF_RETURN(hash_error); - - get_hash_results - <<::number_of_singlehash_blocks(number_of_states), PKC::singlehash_block_size, 0, stream>>>( - states, number_of_states, output_device); - - if (config.loop_state) { - copy_recursive - <<::number_of_singlehash_blocks(number_of_states), PKC::singlehash_block_size, 0, stream>>>( - states, number_of_states, output_device); - } - - if (!config.input_is_a_state) CHK_IF_RETURN(cudaFreeAsync(states, stream)); - - if (!config.are_outputs_on_device) { - CHK_IF_RETURN( - cudaMemcpyAsync(output, output_device, number_of_states * sizeof(S), cudaMemcpyDeviceToHost, stream)); - CHK_IF_RETURN(cudaFreeAsync(output_device, stream)); - } - - if (!config.is_async) return CHK_STICKY(cudaStreamSynchronize(stream)); - return CHK_LAST(); - } -} // namespace poseidon \ No newline at end of file diff --git a/icicle/src/poseidon/test.cu b/icicle/src/poseidon/test.cu index 529984159..8617b7e48 100644 --- a/icicle/src/poseidon/test.cu +++ b/icicle/src/poseidon/test.cu @@ -4,7 +4,6 @@ using namespace curve_config; #include "gpu-utils/device_context.cuh" -#include "poseidon.cu" #ifndef __CUDA_ARCH__ #include @@ -12,6 +11,10 @@ using namespace curve_config; #include #include +#include "api/bls12_381.h" +using namespace bls12_381; + +#include "poseidon/poseidon.cuh" using namespace poseidon; #define A 2 @@ -29,8 +32,7 @@ int main(int argc, char* argv[]) // Load poseidon constants START_TIMER(timer_const); device_context::DeviceContext ctx = device_context::get_default_device_context(); - PoseidonConstants constants; - init_optimized_poseidon_constants(A, ctx, &constants); + Poseidon poseidon(A, ctx); END_TIMER(timer_const, "Load poseidon constants"); START_TIMER(allocation_timer); @@ -46,9 +48,10 @@ int main(int argc, char* argv[]) scalar_t* out_ptr = static_cast(malloc(number_of_blocks * sizeof(scalar_t))); + SpongeConfig cfg = default_sponge_config(); + START_TIMER(poseidon_timer); - PoseidonConfig config = default_poseidon_config(T); - poseidon_hash(in_ptr, out_ptr, number_of_blocks, constants, config); + poseidon.hash_many(in_ptr, out_ptr, number_of_blocks, A, 1, cfg); END_TIMER(poseidon_timer, "Poseidon") scalar_t expected[1024] = { @@ -1080,7 +1083,7 @@ int main(int argc, char* argv[]) if (number_of_blocks == 1024) { for (int i = 0; i < number_of_blocks; i++) { #ifdef DEBUG - std::cout << out_ptr[i] << std::endl; + // std::cout << out_ptr[i] << std::endl; #endif assert((out_ptr[i] == expected[i])); } diff --git a/icicle/src/poseidon/test_m31.cu b/icicle/src/poseidon/test_m31.cu new file mode 100644 index 000000000..7f6bd7ce4 --- /dev/null +++ b/icicle/src/poseidon/test_m31.cu @@ -0,0 +1,70 @@ +// #define DEBUG + +#include "fields/field_config.cuh" +using namespace field_config; + +#include "gpu-utils/device_context.cuh" +#include "poseidon/poseidon.cuh" + +#ifndef __CUDA_ARCH__ +#include +#include +#include +#include + +using namespace poseidon; + +#define A 11 +#define T (A + 1) + +#define START_TIMER(timer) auto timer##_start = std::chrono::high_resolution_clock::now(); +#define END_TIMER(timer, msg) \ + printf("%s: %.0f ms\n", msg, FpMilliseconds(std::chrono::high_resolution_clock::now() - timer##_start).count()); + +int main(int argc, char* argv[]) +{ + using FpMilliseconds = std::chrono::duration; + using FpMicroseconds = std::chrono::duration; + + // Load poseidon constants + START_TIMER(timer_const); + device_context::DeviceContext ctx = device_context::get_default_device_context(); + PoseidonConstants constants; + init_optimized_poseidon_constants(A, ctx, &constants); + END_TIMER(timer_const, "Load poseidon constants"); + + START_TIMER(allocation_timer); + // Prepare input data of [0, 1, 2 ... (number_of_blocks * arity) - 1] + int number_of_blocks = argc > 1 ? 1 << atoi(argv[1]) : 1024; + scalar_t input = scalar_t::zero(); + scalar_t* in_ptr = static_cast(malloc(number_of_blocks * A * sizeof(scalar_t))); + for (uint32_t i = 0; i < number_of_blocks * A; i++) { + in_ptr[i] = input; + input = input + scalar_t::one(); + } + END_TIMER(allocation_timer, "Allocate mem and fill input"); + + scalar_t* out_ptr = static_cast(malloc(number_of_blocks * sizeof(scalar_t))); + + START_TIMER(poseidon_timer); + PoseidonConfig config = default_poseidon_config(T); + poseidon_hash(in_ptr, out_ptr, number_of_blocks, constants, config); + END_TIMER(poseidon_timer, "Poseidon") + + // scalar_t expected[0] = {} + + if (number_of_blocks == 1024) { + for (int i = 0; i < number_of_blocks; i++) { +#ifdef DEBUG + // std::cout << out_ptr[i] << std::endl; +#endif + // assert((out_ptr[i] == expected[i])); + } + printf("Expected output matches\n"); + } + + free(in_ptr); + free(out_ptr); +} + +#endif \ No newline at end of file diff --git a/icicle/src/poseidon/tree/Makefile b/icicle/src/poseidon/tree/Makefile deleted file mode 100644 index 9b1ebd5bb..000000000 --- a/icicle/src/poseidon/tree/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -test_merkle: - nvcc -o test_merkle -I../../../include -DFIELD_ID=2 -DCURVE_ID=2 test.cu - ./test_merkle \ No newline at end of file diff --git a/icicle/src/poseidon/tree/merkle.cu b/icicle/src/poseidon/tree/merkle.cu deleted file mode 100644 index 076da24e9..000000000 --- a/icicle/src/poseidon/tree/merkle.cu +++ /dev/null @@ -1,284 +0,0 @@ -#include "fields/field_config.cuh" - -using namespace field_config; - -#include "poseidon/tree/merkle.cuh" - -namespace merkle { - /// Flattens the tree digests and sum them up to get - /// the memory needed to contain all the digests - template - size_t get_digests_len(uint32_t height, uint32_t arity) - { - size_t digests_len = 0; - size_t row_length = 1; - for (int i = 1; i < height; i++) { - digests_len += row_length; - row_length *= arity; - } - - return digests_len; - } - - /// Constructs merkle subtree without parallelization - /// The digests are aligned sequentially per row - /// Example: - /// - /// Big tree: - /// - /// 1 - /// / \ - /// 2 3 - /// / \ / \ - /// 4 5 6 7 - /// - /// Subtree 1 Subtree 2 - /// 2 3 - /// / \ / \ - /// 4 5 6 7 - /// - /// Digests array for subtree 1: - /// [4 5 . . 2 . .] - /// | | | - /// ----- V - /// | Segment (offset = 4, subtree_idx = 0) - /// v - /// Segment (offset = 0, subtree_idx = 0) - /// - /// Digests array for subtree 2: - /// [. . 6 7 . 3 .] - /// | | - /// ----- - /// | - /// v - /// Segment (offset = 0, subtree_idx = 1) - /// - /// Total digests array: - /// [4 5 6 7 2 3 .] - template - cudaError_t build_merkle_subtree( - S* state, - S* digests, - size_t subtree_idx, - size_t subtree_height, - S* big_tree_digests, - size_t start_segment_size, - size_t start_segment_offset, - int keep_rows, - const PoseidonConstants& poseidon, - cudaStream_t& stream) - { - int arity = T - 1; - - PoseidonConfig config = default_poseidon_config(T); - config.are_inputs_on_device = true; - config.are_outputs_on_device = true; - config.input_is_a_state = true; - config.loop_state = true; - config.ctx.stream = stream; - - size_t leaves_size = pow(arity, subtree_height - 1); - uint32_t number_of_blocks = leaves_size / arity; - size_t segment_size = start_segment_size; - size_t segment_offset = start_segment_offset; - - while (number_of_blocks > 0) { - cudaError_t poseidon_res = poseidon_hash(state, digests, number_of_blocks, poseidon, config); - CHK_IF_RETURN(poseidon_res); - - if (!keep_rows || subtree_height <= keep_rows + 1) { - S* digests_with_offset = big_tree_digests + segment_offset + subtree_idx * number_of_blocks; - CHK_IF_RETURN( - cudaMemcpyAsync(digests_with_offset, digests, number_of_blocks * sizeof(S), cudaMemcpyDeviceToHost, stream)); - segment_offset += segment_size; - } - - segment_size /= arity; - subtree_height--; - number_of_blocks /= arity; - config.aligned = true; - } - - return CHK_LAST(); - } - - template - cudaError_t build_merkle_tree( - const S* leaves, - S* digests, - uint32_t height, - const poseidon::PoseidonConstants& poseidon, - const TreeBuilderConfig& config) - { - CHK_INIT_IF_RETURN(); - cudaStream_t& stream = config.ctx.stream; - - int arity = T - 1; - uint32_t number_of_leaves = pow(arity, (height - 1)); - - // This will determine how much splitting do we need to do - // `number_of_streams` subtrees should fit in the device - // This means each subtree should fit in `STREAM_CHUNK_SIZE` memory - uint32_t number_of_subtrees = 1; - uint32_t subtree_height = height; - uint32_t subtree_leaves_size = pow(arity, height - 1); - uint32_t subtree_state_size = subtree_leaves_size / arity * T; - uint32_t subtree_digests_size = get_digests_len(subtree_height, arity); - size_t subtree_memory_required = sizeof(S) * (subtree_state_size + subtree_digests_size); - while (subtree_memory_required > STREAM_CHUNK_SIZE) { - number_of_subtrees *= arity; - subtree_height--; - subtree_leaves_size /= arity; - subtree_state_size = subtree_leaves_size / arity * T; - subtree_digests_size = subtree_state_size / arity; - subtree_memory_required = sizeof(S) * (subtree_state_size + subtree_digests_size); - } - int cap_height = height - subtree_height + 1; - size_t caps_len = pow(arity, cap_height - 1); - - size_t available_memory, _total_memory; - CHK_IF_RETURN(cudaMemGetInfo(&available_memory, &_total_memory)); - available_memory -= GIGA / 8; // Leave 128 MB - - // We can effectively parallelize memory copy with streams - // as long as they don't operate on more than `STREAM_CHUNK_SIZE` bytes - const size_t number_of_streams = std::min((uint32_t)(available_memory / STREAM_CHUNK_SIZE), number_of_subtrees); - cudaStream_t* streams = static_cast(malloc(sizeof(cudaStream_t) * number_of_streams)); - for (size_t i = 0; i < number_of_streams; i++) { - CHK_IF_RETURN(cudaStreamCreate(&streams[i])); - } - -#if !defined(__CUDA_ARCH__) && defined(MERKLE_DEBUG) - std::cout << "Available memory = " << available_memory / 1024 / 1024 << " MB" << std::endl; - std::cout << "Number of streams = " << number_of_streams << std::endl; - std::cout << "Number of subtrees = " << number_of_subtrees << std::endl; - std::cout << "Height of a subtree = " << subtree_height << std::endl; - std::cout << "Cutoff height = " << height - subtree_height + 1 << std::endl; - std::cout << "Number of leaves in a subtree = " << subtree_leaves_size << std::endl; - std::cout << "State of a subtree = " << subtree_state_size << std::endl; - std::cout << "Digest elements for a subtree = " << get_digests_len(subtree_height, arity) << std::endl; - std::cout << "Size of 1 subtree states = " << subtree_state_size * sizeof(S) / 1024 / 1024 << " MB" << std::endl; - std::cout << "Size of 1 subtree digests = " << subtree_digests_size * sizeof(S) / 1024 / 1024 << " MB" << std::endl; -#endif - - // Allocate memory for the leaves and digests - // These are shared by streams in a pool - S *states_ptr, *digests_ptr; - CHK_IF_RETURN(cudaMallocAsync(&states_ptr, subtree_state_size * number_of_streams * sizeof(S), stream)) - CHK_IF_RETURN(cudaMallocAsync(&digests_ptr, subtree_digests_size * number_of_streams * sizeof(S), stream)) - // Wait for these allocations to finish - CHK_IF_RETURN(cudaStreamSynchronize(stream)); - - bool caps_mode = config.keep_rows && config.keep_rows < cap_height; - S* caps; - if (caps_mode) { caps = static_cast(malloc(caps_len * sizeof(S))); } - - for (size_t subtree_idx = 0; subtree_idx < number_of_subtrees; subtree_idx++) { - size_t stream_idx = subtree_idx % number_of_streams; - cudaStream_t subtree_stream = streams[stream_idx]; - - const S* subtree_leaves = leaves + subtree_idx * subtree_leaves_size; - S* subtree_state = states_ptr + stream_idx * subtree_state_size; - S* subtree_digests = digests_ptr + stream_idx * subtree_digests_size; - - // Copy the first level from RAM / device to device - // The pitch property of cudaMemcpy2D resolves shape differences - CHK_IF_RETURN(cudaMemcpy2DAsync( - subtree_state, T * sizeof(S), // Device pointer and device pitch - subtree_leaves, arity * sizeof(S), // Host pointer and pitch - arity * sizeof(S), // Size of the source matrix (Arity) - subtree_leaves_size / arity, // Size of the source matrix (Number of blocks) - config.are_inputs_on_device ? cudaMemcpyDeviceToDevice : cudaMemcpyHostToDevice, subtree_stream)); - - int subtree_keep_rows = 0; - if (config.keep_rows) { - int diff = config.keep_rows - cap_height + 1; - subtree_keep_rows = diff <= 0 ? 1 : diff; - } - size_t start_segment_size = number_of_leaves / arity; - cudaError_t subtree_result = build_merkle_subtree( - subtree_state, // state - subtree_digests, // digests - subtree_idx, // subtree_idx - subtree_height, // subtree_height - caps_mode ? caps : digests, // big_tree_digests - start_segment_size, // start_segment_size - 0, // start_segment_offset - subtree_keep_rows, // keep_rows - poseidon, // hash - subtree_stream // stream - ); - CHK_IF_RETURN(subtree_result); - } - - for (size_t i = 0; i < number_of_streams; i++) { - CHK_IF_RETURN(cudaStreamSynchronize(streams[i])); - } - - // Finish the top-level tree if any - if (cap_height > 1) { - size_t start_segment_size = caps_len / arity; - size_t start_segment_offset = 0; - if (!caps_mode) { - size_t layer_size = pow(arity, config.keep_rows - 1); - for (int i = 0; i < config.keep_rows - cap_height + 1; i++) { - start_segment_offset += layer_size; - layer_size /= arity; - } - } - CHK_IF_RETURN(cudaMemcpy2DAsync( - states_ptr, T * sizeof(S), caps_mode ? caps : (digests + start_segment_offset - caps_len), arity * sizeof(S), - arity * sizeof(S), - caps_len / arity, // Size of the source - cudaMemcpyHostToDevice, stream)); // Direction and stream - - cudaError_t top_tree_result = build_merkle_subtree( - states_ptr, // state - digests_ptr, // digests - 0, // subtree_idx - cap_height, // subtree_height - digests, // big_tree_digests - start_segment_size, // start_segment_size - start_segment_offset, // start_segment_offset - config.keep_rows, // keep_rows - poseidon, // hash - stream // stream - ); - CHK_IF_RETURN(top_tree_result); - if (caps_mode) { free(caps); } - } - - CHK_IF_RETURN(cudaFreeAsync(states_ptr, stream)); - CHK_IF_RETURN(cudaFreeAsync(digests_ptr, stream)); - if (!config.is_async) return CHK_STICKY(cudaStreamSynchronize(stream)); - for (size_t i = 0; i < number_of_streams; i++) { - CHK_IF_RETURN(cudaStreamSynchronize(streams[i])); - CHK_IF_RETURN(cudaStreamDestroy(streams[i])); - } - free(streams); - return CHK_LAST(); - } - - extern "C" cudaError_t CONCAT_EXPAND(FIELD, build_poseidon_merkle_tree)( - const scalar_t* leaves, - scalar_t* digests, - uint32_t height, - int arity, - PoseidonConstants& constants, - TreeBuilderConfig& config) - { - switch (arity) { - case 2: - return build_merkle_tree(leaves, digests, height, constants, config); - case 4: - return build_merkle_tree(leaves, digests, height, constants, config); - case 8: - return build_merkle_tree(leaves, digests, height, constants, config); - case 11: - return build_merkle_tree(leaves, digests, height, constants, config); - default: - THROW_ICICLE_ERR(IcicleError_t::InvalidArgument, "BuildPoseidonMerkleTree: #arity must be one of [2, 4, 8, 11]"); - } - return CHK_LAST(); - } -} // namespace merkle \ No newline at end of file diff --git a/icicle/src/poseidon2/Makefile b/icicle/src/poseidon2/Makefile index 4fce6e872..705bba499 100644 --- a/icicle/src/poseidon2/Makefile +++ b/icicle/src/poseidon2/Makefile @@ -1,7 +1,5 @@ -test_poseidon: test.cu poseidon.cu kernels.cu constants.cu - nvcc -o test_poseidon -I../../include -DFIELD=bn254 -DFIELD_ID=1 -DCURVE_ID=1 -DDEVMODE -DDEBUG extern.cu test.cu - ./test_poseidon +test_poseidon: test.cu + nvcc -o test_poseidon -I../../include -DFIELD=bn254 -DFIELD_ID=1 -DCURVE_ID=1 extern.cu test.cu -test_poseidon_release: test.cu poseidon.cu kernels.cu constants.cu - nvcc -o test_poseidon_release -I../../include -DFIELD=bn254 -DFIELD_ID=1 -DCURVE_ID=1 extern.cu test.cu - ./test_poseidon_release \ No newline at end of file +test_poseidon_m31: test_m31.cu + nvcc -o test_poseidon_m31 -I../../include -DFIELD=m31 -DFIELD_ID=1003 extern.cu test_m31.cu \ No newline at end of file diff --git a/icicle/src/poseidon2/constants.cu b/icicle/src/poseidon2/constants.cu index 7cbe26325..3fa157d2a 100644 --- a/icicle/src/poseidon2/constants.cu +++ b/icicle/src/poseidon2/constants.cu @@ -1,4 +1,5 @@ -#include "poseidon2/poseidon2.cuh" +#include "poseidon2/constants.cuh" +#include "gpu-utils/device_context.cuh" /// These are pre-calculated constants for different curves #include "fields/id.h" @@ -20,6 +21,9 @@ using namespace poseidon2_constants_grumpkin; #elif FIELD_ID == BABY_BEAR #include "poseidon2/constants/babybear_poseidon2.h" using namespace poseidon2_constants_babybear; +#elif FIELD_ID == M31 +#include "poseidon2/constants/m31_poseidon2.h" +using namespace poseidon2_constants_m31; #endif namespace poseidon2 { @@ -36,7 +40,6 @@ namespace poseidon2 { device_context::DeviceContext& ctx, Poseidon2Constants* poseidon_constants) { - cudaFree(nullptr); // Temporary solution if (!(alpha == 3 || alpha == 5 || alpha == 7 || alpha == 11)) { THROW_ICICLE_ERR(IcicleError_t::InvalidArgument, "Invalid alpha value"); } @@ -78,7 +81,6 @@ namespace poseidon2 { device_context::DeviceContext& ctx, Poseidon2Constants* poseidon2_constants) { - cudaFree(nullptr); // Temporary solution CHK_INIT_IF_RETURN(); #define P2_CONSTANTS_DEF(width) \ @@ -121,7 +123,6 @@ namespace poseidon2 { cudaError_t release_poseidon2_constants(Poseidon2Constants* constants, device_context::DeviceContext& ctx) { CHK_INIT_IF_RETURN(); - CHK_IF_RETURN(cudaFreeAsync(constants->round_constants, ctx.stream)); CHK_IF_RETURN(cudaFreeAsync(constants->internal_matrix_diag, ctx.stream)); constants->alpha = 0; diff --git a/icicle/src/poseidon2/extern.cu b/icicle/src/poseidon2/extern.cu index d9eceeb17..d5ff39328 100644 --- a/icicle/src/poseidon2/extern.cu +++ b/icicle/src/poseidon2/extern.cu @@ -3,67 +3,71 @@ #include "fields/field_config.cuh" using namespace field_config; -#include "poseidon.cu" +#include "gpu-utils/error_handler.cuh" +#include "poseidon2/poseidon2.cuh" +#include "./constants.cu" namespace poseidon2 { - extern "C" cudaError_t CONCAT_EXPAND(FIELD, create_poseidon2_constants_cuda)( - int width, - int alpha, - int internal_rounds, - int external_rounds, + template class Poseidon2; + + extern "C" cudaError_t CONCAT_EXPAND(FIELD, poseidon2_create_cuda)( + Poseidon2** poseidon, + unsigned int width, + unsigned int rate, + unsigned int alpha, + unsigned int internal_rounds, + unsigned int external_rounds, const scalar_t* round_constants, const scalar_t* internal_matrix_diag, MdsType mds_type, DiffusionStrategy diffusion, - device_context::DeviceContext& ctx, - Poseidon2Constants* poseidon_constants) + device_context::DeviceContext& ctx) { - return create_poseidon2_constants( - width, alpha, internal_rounds, external_rounds, round_constants, internal_matrix_diag, mds_type, diffusion, ctx, - poseidon_constants); + try { + *poseidon = new Poseidon2( + width, rate, alpha, internal_rounds, external_rounds, round_constants, internal_matrix_diag, mds_type, + diffusion, ctx); + return cudaError_t::cudaSuccess; + } catch (const IcicleError& _error) { + return cudaError_t::cudaErrorUnknown; + } } - extern "C" cudaError_t CONCAT_EXPAND(FIELD, init_poseidon2_constants_cuda)( - int width, + extern "C" cudaError_t CONCAT_EXPAND(FIELD, poseidon2_load_cuda)( + Poseidon2** poseidon, + unsigned int width, + unsigned int rate, MdsType mds_type, DiffusionStrategy diffusion, - device_context::DeviceContext& ctx, - Poseidon2Constants* constants) + device_context::DeviceContext& ctx) { - return init_poseidon2_constants(width, mds_type, diffusion, ctx, constants); + try { + *poseidon = new Poseidon2(width, rate, mds_type, diffusion, ctx); + return cudaError_t::cudaSuccess; + } catch (const IcicleError& _error) { + return cudaError_t::cudaErrorUnknown; + } } - extern "C" cudaError_t CONCAT_EXPAND(FIELD, poseidon2_hash_cuda)( - const scalar_t* input, + extern "C" cudaError_t CONCAT_EXPAND(FIELD, poseidon2_hash_many_cuda)( + const Poseidon2* poseidon, + const scalar_t* inputs, scalar_t* output, - int number_of_states, - int width, - const Poseidon2Constants* constants, - Poseidon2Config* config) + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + hash::SpongeConfig& cfg) { -#define P2_HASH_T(width) \ - case width: \ - return poseidon2_hash(input, output, number_of_states, *constants, *config); - - switch (width) { - P2_HASH_T(2) - P2_HASH_T(3) - P2_HASH_T(4) - P2_HASH_T(8) - P2_HASH_T(12) - P2_HASH_T(16) - P2_HASH_T(20) - P2_HASH_T(24) - default: - THROW_ICICLE_ERR( - IcicleError_t::InvalidArgument, "PoseidonHash: #arity must be one of [2, 3, 4, 8, 12, 16, 20, 24]"); - } - return CHK_LAST(); + return poseidon->hash_many(inputs, output, number_of_states, input_block_len, output_len, cfg); } - extern "C" cudaError_t CONCAT_EXPAND(FIELD, release_poseidon2_constants_cuda)( - Poseidon2Constants* constants, device_context::DeviceContext& ctx) + extern "C" cudaError_t CONCAT_EXPAND(FIELD, poseidon2_delete_cuda)(Poseidon2* poseidon) { - return release_poseidon2_constants(constants, ctx); + try { + poseidon->~Poseidon2(); + return cudaError_t::cudaSuccess; + } catch (const IcicleError& _error) { + return cudaError_t::cudaErrorUnknown; + } } } // namespace poseidon2 \ No newline at end of file diff --git a/icicle/src/poseidon2/poseidon.cu b/icicle/src/poseidon2/poseidon.cu deleted file mode 100644 index 2ae0512f6..000000000 --- a/icicle/src/poseidon2/poseidon.cu +++ /dev/null @@ -1,80 +0,0 @@ -#include "poseidon2/poseidon2.cuh" -#include "constants.cu" -#include "kernels.cu" - -namespace poseidon2 { - static int poseidon_block_size = 128; - - template - int poseidon_number_of_blocks(size_t number_of_states) - { - return number_of_states / poseidon_block_size + static_cast(number_of_states % poseidon_block_size); - } - - template - cudaError_t permute_many( - const S* states, - S* states_out, - size_t number_of_states, - const Poseidon2Constants& constants, - cudaStream_t& stream) - { - poseidon2_permutation_kernel - <<(number_of_states), poseidon_block_size, 0, stream>>>( - states, states_out, number_of_states, constants); - CHK_IF_RETURN(cudaPeekAtLastError()); - return CHK_LAST(); - } - - template - cudaError_t poseidon2_hash( - const S* states, - S* output, - size_t number_of_states, - const Poseidon2Constants& constants, - const Poseidon2Config& config) - { - CHK_INIT_IF_RETURN(); - cudaStream_t& stream = config.ctx.stream; - S* d_states; - if (config.are_states_on_device) { - d_states = const_cast(states); - } else { - // allocate memory for {number_of_states} states of {t} scalars each - CHK_IF_RETURN(cudaMallocAsync(&d_states, number_of_states * T * sizeof(S), stream)) - CHK_IF_RETURN(cudaMemcpyAsync(d_states, states, number_of_states * T * sizeof(S), cudaMemcpyHostToDevice, stream)) - } - - cudaError_t hash_error = permute_many(d_states, d_states, number_of_states, constants, stream); - CHK_IF_RETURN(hash_error); - - if (config.mode == PoseidonMode::COMPRESSION) { - S* output_device; - if (config.are_outputs_on_device) { - output_device = output; - } else { - CHK_IF_RETURN(cudaMallocAsync(&output_device, number_of_states * sizeof(S), stream)) - } - - get_hash_results<<(number_of_states), poseidon_block_size, 0, stream>>>( - d_states, number_of_states, config.output_index, output_device); - CHK_IF_RETURN(cudaPeekAtLastError()); - - if (!config.are_outputs_on_device) { - CHK_IF_RETURN( - cudaMemcpyAsync(output, output_device, number_of_states * sizeof(S), cudaMemcpyDeviceToHost, stream)); - CHK_IF_RETURN(cudaFreeAsync(output_device, stream)); - } - } else { - if (!config.are_states_on_device || !config.are_outputs_on_device) { - CHK_IF_RETURN( - cudaMemcpyAsync(output, d_states, number_of_states * T * sizeof(S), cudaMemcpyDeviceToHost, stream)); - } - } - - if (!config.are_states_on_device) CHK_IF_RETURN(cudaFreeAsync(d_states, stream)); - - if (!config.is_async) return CHK_STICKY(cudaStreamSynchronize(stream)); - return CHK_LAST(); - } -} // namespace poseidon2 \ No newline at end of file diff --git a/icicle/src/poseidon2/test.cu b/icicle/src/poseidon2/test.cu index 1fc7923b0..5e78dee4b 100644 --- a/icicle/src/poseidon2/test.cu +++ b/icicle/src/poseidon2/test.cu @@ -1,6 +1,3 @@ -#include "curves/curve_config.cuh" -using namespace curve_config; - #include "gpu-utils/device_context.cuh" #ifndef __CUDA_ARCH__ @@ -12,6 +9,9 @@ using namespace curve_config; #include "poseidon2/poseidon2.cuh" using namespace poseidon2; +#include "api/bn254.h" +using namespace bn254; + #define T 3 #define START_TIMER(timer) auto timer##_start = std::chrono::high_resolution_clock::now(); @@ -23,11 +23,10 @@ int main(int argc, char* argv[]) using FpMilliseconds = std::chrono::duration; using FpMicroseconds = std::chrono::duration; - // Load poseidon constants + // Load poseidon START_TIMER(timer_const); device_context::DeviceContext ctx = device_context::get_default_device_context(); - Poseidon2Constants constants; - init_poseidon2_constants(T, MdsType::DEFAULT_MDS, DiffusionStrategy::DEFAULT_DIFFUSION, ctx, &constants); + Poseidon2 poseidon(T, T, MdsType::DEFAULT_MDS, DiffusionStrategy::DEFAULT_DIFFUSION, ctx); END_TIMER(timer_const, "Load poseidon constants"); START_TIMER(allocation_timer); @@ -43,9 +42,10 @@ int main(int argc, char* argv[]) scalar_t* out_ptr = static_cast(malloc(number_of_blocks * sizeof(scalar_t))); + SpongeConfig cfg = default_sponge_config(); + START_TIMER(poseidon_timer); - Poseidon2Config config = default_poseidon2_config(T); - poseidon2_hash(in_ptr, out_ptr, number_of_blocks, constants, config); + poseidon.hash_many(in_ptr, out_ptr, number_of_blocks, T, 1, cfg); END_TIMER(poseidon_timer, "Poseidon") // for (int i = 0; i < number_of_blocks; i++) { @@ -58,1030 +58,1030 @@ int main(int argc, char* argv[]) // } scalar_t expected[1024] = { - {2337248161, 922903866, 3071222352, 4081058267, 202960435, 3624769622, 2795065713, 587773401}, - {2877573013, 1770378927, 3640761212, 3701454630, 1398036492, 3791634046, 1398650802, 573220813}, - {2323651800, 1670011638, 4011449678, 2015366333, 2439637416, 1996298558, 2682390530, 775056766}, - {4231740498, 1547037434, 1091263111, 3069783085, 903800825, 3053320007, 759698752, 270534075}, - {929530500, 2908315047, 2379289075, 1180108740, 2567510294, 2137292693, 3238765095, 214830700}, - {1519055477, 2668743693, 856401502, 3805283196, 3483702320, 1862951136, 2910012574, 653382231}, - {3033225700, 2215712291, 3353723823, 761477891, 20561034, 3461601764, 2732180603, 498135517}, - {2970792382, 2824369266, 2283566237, 1642127343, 3714899790, 377977812, 3339933868, 21500926}, - {1465969779, 892925676, 14133348, 3282637834, 504612845, 1834263838, 1972077882, 73379048}, - {392142775, 2719578242, 3153739944, 3329248015, 2670782102, 419502418, 835741300, 663054425}, - {1635526549, 2749619586, 2649038437, 2132466526, 2715069976, 648084377, 2862160083, 106626013}, - {1106245030, 1225520809, 29309126, 3374355381, 3562744306, 3123213928, 2087330420, 59621160}, - {1593802085, 2793759314, 652946587, 3203437766, 3247487137, 1396924142, 1580303725, 174801908}, - {4025587200, 4082015564, 1173681216, 3127480166, 1034016147, 991403334, 4014149380, 420181217}, - {3592592465, 1056606453, 2680520399, 2988309624, 2669029486, 1907874230, 1196552328, 105525214}, - {2572072743, 1395302269, 544207797, 646679795, 3162693242, 2262511348, 1062107072, 188033893}, - {1064949600, 3269989712, 3654517826, 2763325899, 3393966953, 2768875167, 4010413525, 148162566}, - {3763002391, 3234888905, 1177601991, 2167351813, 686626897, 3406602152, 3582610309, 43783215}, - {4163262779, 446727167, 2960256289, 1847210772, 1055583550, 1776802596, 2385384364, 700431403}, - {2414577902, 3663803456, 2298192142, 2722412277, 1298869039, 3935592600, 386243021, 387997461}, - {3292923249, 6199936, 1675635087, 1851936447, 880093023, 2469813719, 2201651493, 451618348}, - {1980156396, 1560700264, 1928805412, 3990903692, 3008315225, 1754644267, 2616623521, 439117542}, - {602960800, 654171190, 1489674898, 700677973, 3081155653, 1750294232, 1853105141, 230811756}, - {2397946673, 287730133, 2350922701, 1485409365, 545118895, 727639541, 3536534489, 536834981}, - {3314734530, 2068838415, 1229815801, 3531994100, 3388434334, 2210601578, 2953771348, 222891795}, - {1715594389, 1797429717, 3493073480, 602222025, 3938839362, 3625143475, 1640971423, 529566839}, - {534040292, 3459841971, 355924662, 2118998096, 98842679, 3007195048, 3058773244, 758720916}, - {1412715074, 4073890062, 2685340189, 2941563092, 3879168524, 3731087948, 2592950099, 376504183}, - {3616063581, 4019848072, 3127005016, 1101094426, 3119232326, 3063443937, 3580083715, 167287947}, - {3773265618, 1058528699, 2552064976, 3988743847, 3838835032, 1602322011, 868102294, 726205922}, - {3490364313, 1682734101, 1328698766, 3056465906, 2844029492, 1755394671, 2896206636, 743353777}, - {2017541599, 4194661938, 1044380563, 628198274, 1965676232, 4205238257, 3319329476, 447655400}, - {686254453, 1107365132, 1957201750, 2471025119, 4195549802, 4211474962, 1267912361, 797556761}, - {3493885589, 3072107104, 1877405802, 2746345178, 4117435152, 474382917, 1599874355, 405332007}, - {4211697613, 1015744671, 793250876, 2404808756, 552076098, 1374578302, 1312715992, 209799213}, - {26772588, 2569569615, 871622801, 2535039090, 2459203671, 3987528618, 2100717927, 63239838}, - {675511, 3893982734, 3359119182, 3659195290, 981419420, 2380406517, 1354552512, 558799732}, - {1802645212, 4276123891, 3716652701, 3087596775, 2940891120, 4060568546, 2460386504, 218195610}, - {1402377956, 2926687580, 1141488894, 1833661823, 4068058122, 2422026810, 1861053137, 55564050}, - {2561439004, 3589302498, 4278354771, 2760506911, 2485485381, 1212999425, 780814677, 738186132}, - {976044468, 2320501313, 3059711748, 4153768708, 269258707, 1399039295, 665202609, 322804660}, - {3265409871, 4094622547, 344367927, 491389972, 1158439644, 1296279667, 3924848117, 385619225}, - {693790876, 2934193533, 1561285527, 3105502301, 4180977287, 3033478445, 4279292752, 787722893}, - {4224401439, 3175227993, 617513239, 457027841, 4030698653, 1816450574, 746124986, 657539150}, - {3121650910, 2846396407, 3822443248, 1434213221, 2078598085, 1249940458, 951819284, 239252510}, - {221914756, 813519342, 1645104741, 2415654059, 2377050516, 2650764508, 2290454486, 252003767}, - {715502223, 634531822, 3978989673, 2962630305, 1295833879, 737519409, 2250658309, 485425423}, - {3345543558, 147667313, 1444930241, 3786340393, 3112576191, 2552686221, 371511617, 33741038}, - {3819498177, 3700690306, 1057368050, 2881311417, 3538098244, 2033064374, 3002754755, 729720316}, - {2359190671, 2843646197, 511926196, 645077792, 4279973399, 2782058836, 2884283441, 672131918}, - {623583635, 931567025, 3778883078, 682313268, 28485661, 4187010247, 1553458367, 782335725}, - {236910976, 928710544, 2525950542, 1098657414, 2941819388, 1127873833, 894020196, 430322922}, - {2463827968, 616390667, 2991004569, 1592601209, 996946700, 654018048, 2348195968, 502148005}, - {31109809, 64608389, 2893203549, 1107331534, 1551391460, 3948579942, 3291211019, 44882792}, - {952164157, 3292091952, 3978650001, 2945840712, 65538748, 3106842066, 905817620, 297110806}, - {2452617628, 4034014421, 4050189010, 2750632063, 4214561776, 4033346207, 965362618, 516194619}, - {1064095749, 14886879, 2034241024, 1371896806, 2780050824, 255263072, 299675143, 665206809}, - {810623257, 1864314046, 1157534395, 1405695129, 432469242, 2733725966, 789887055, 639020524}, - {1311081811, 4025150778, 1617621518, 1406411645, 2004599739, 1948936917, 3561005711, 759938151}, - {1452171496, 2421345973, 1422103289, 66316978, 1372589087, 1014498432, 4071784861, 150213468}, - {438021311, 1456432206, 2489358783, 2545708400, 2614083501, 2102103258, 2493133380, 363251049}, - {2711022086, 2879364378, 2868735020, 1514200304, 2944304220, 1268251087, 2631614712, 10014848}, - {2231531226, 916866170, 231772764, 744940185, 3443137589, 2931639304, 2879299299, 134928447}, - {266316211, 3604155406, 3352126798, 2517227827, 3927711173, 2802786075, 981882905, 428761012}, - {786179076, 1769923701, 516353315, 3180962694, 3271820608, 30406303, 3594500813, 747929716}, - {777105115, 1899183900, 667914372, 1457129238, 3328815325, 2590359622, 2488009536, 517430037}, - {3832435548, 198596644, 3332590007, 2502610763, 723334805, 1672151984, 600362221, 553727923}, - {2286087921, 438921094, 3421468657, 3914864890, 1716870811, 1387006600, 3248947837, 680567759}, - {4142330258, 3499945506, 2281970739, 11194171, 3270321406, 3609870892, 4257049292, 411894761}, - {1345126191, 1556123727, 331697864, 4199702143, 688959955, 3176161250, 727774207, 82464625}, - {2982752070, 256117297, 1487434654, 2105033632, 3800193431, 223351374, 2780925329, 629929150}, - {1960693257, 3020833779, 1046945157, 278878346, 4188766876, 2190603088, 3947972175, 364021479}, - {4057471109, 1811863522, 1843814640, 26888260, 355417404, 3774309695, 2982373013, 757330582}, - {1012177191, 2117122888, 2417433228, 2457676308, 977927847, 1745646806, 1350043325, 472903411}, - {1509979540, 4058925795, 2229705044, 722297618, 3440702353, 989124324, 3645232002, 506244150}, - {1115651459, 732293533, 3908377613, 3825269308, 102874015, 3645719126, 1880878610, 631567228}, - {332458125, 1142700757, 3902658227, 3050335305, 2584701896, 1869835579, 1082891037, 421567409}, - {2177796381, 2957315610, 3015065024, 1873025975, 3320446940, 3303779089, 1777104286, 514593425}, - {1673926707, 838161885, 1433413100, 2393245630, 2506397732, 1319605316, 1860264855, 772459050}, - {4198116871, 732940994, 3224405840, 3565921851, 1976632750, 318845768, 2554362637, 658386493}, - {1907983310, 563710702, 1847409728, 3184351047, 2326648195, 2732066511, 2863999758, 584680395}, - {2328423411, 2730138029, 2256758981, 513858278, 2162374031, 1442026724, 2720844975, 163757041}, - {933431433, 467463603, 3756884596, 2036347316, 676045447, 100774793, 3892497389, 212647263}, - {1802402268, 1070122965, 3788376259, 3741405268, 2398347042, 1855474537, 4213042962, 383149432}, - {985070476, 3101590694, 4070232829, 3576361824, 4228424024, 1264264778, 1030485830, 675691507}, - {3185822983, 3852620957, 422052649, 1307616387, 2245157452, 3038538032, 1126109056, 212511993}, - {2679166157, 802770668, 3785219068, 3431528473, 3754136453, 1240746286, 1818522550, 592233792}, - {4277150444, 1897075938, 1331452663, 2734179863, 723890483, 55573385, 2430242200, 697338757}, - {3805263434, 1450622041, 2877552533, 1128170458, 1467243891, 3396501095, 2322397252, 84623518}, - {2196278955, 192795010, 3122787073, 2921536084, 1606757112, 3839882519, 1330546264, 518799652}, - {3248226120, 1063074110, 1325273013, 1142138594, 559043690, 744419205, 937016519, 653945724}, - {1061365120, 2511128479, 2997581980, 3133486588, 3289180994, 1920318911, 1217265032, 777851333}, - {3062331782, 1779682915, 410820795, 283812685, 4294334387, 1860452101, 2780847797, 669737746}, - {1613664239, 2271108972, 1384796276, 2289183071, 3947924579, 1149329073, 1729334587, 255329109}, - {319157060, 660735995, 3871551908, 79824831, 3862646454, 2963999647, 3560360119, 358954029}, - {2625628386, 784437329, 2905973074, 1253723858, 3360459480, 3150660330, 258506118, 664183821}, - {967441947, 1913932697, 1307512939, 1429802179, 1379615950, 794970123, 1047411669, 62803338}, - {3872350731, 415459577, 782522402, 2840257467, 3377651876, 661816146, 1632629114, 57757215}, - {3764597657, 1544843700, 525464775, 3426510382, 4126476969, 3100877925, 1211194497, 112467126}, - {4253300537, 3819059389, 1368750633, 468328748, 830081911, 1468706969, 2647404109, 487990329}, - {1813016791, 1483408797, 1534415114, 3860752788, 1524004946, 3931109338, 2582351132, 460034375}, - {1837409148, 2432513268, 3784665013, 1306098658, 3352097701, 3021886102, 677017832, 439460224}, - {236005754, 1749712099, 4178129330, 1775753003, 1178392109, 1053709817, 2647801508, 796970027}, - {3538288938, 459378793, 3002574359, 1544528395, 1609506868, 2587694889, 418937391, 666739726}, - {4178569812, 2440979473, 681076903, 3477783834, 1477521743, 3796988972, 3153413867, 17115417}, - {1439149648, 1644937769, 2884567031, 3500916308, 649643566, 2225785515, 1190131584, 181005474}, - {2536499159, 1815315390, 2691129401, 3950742, 1639747307, 114758579, 1979205400, 115929335}, - {282436162, 2997875702, 961785682, 253049464, 1436328644, 3463903079, 3148272643, 487809948}, - {1966215171, 3214604963, 3605283051, 1287206709, 3005384933, 2516623340, 2373653924, 93694081}, - {2958686706, 2732216336, 2974007729, 1653190516, 3689504705, 4108778136, 1902219089, 539809719}, - {245432450, 436579080, 861657613, 3421585074, 3562790929, 914658663, 2208032631, 693064174}, - {3295683669, 1153855205, 1000385430, 2463831470, 599983072, 3613919261, 2233267749, 88051012}, - {3323430448, 236707973, 539492632, 953033477, 3912802462, 65317092, 1591823728, 475375896}, - {2713501890, 2913267705, 705254141, 3480134322, 1754798627, 1944264126, 966994381, 445008580}, - {3934831783, 3117747375, 1294561247, 1924283368, 2761082764, 1775822982, 941642826, 733587779}, - {3674748798, 2609686518, 3310278728, 2206265719, 3054544578, 2507865364, 751011232, 778875116}, - {645417052, 3082516417, 3805895654, 2347335949, 3517118805, 3093519202, 2197930036, 57384361}, - {3604296372, 3884125706, 3098021264, 2157200333, 2730384954, 2498242803, 3643251890, 580530190}, - {4220515012, 2002525823, 487781201, 1534948768, 1787295898, 3422876605, 2091267246, 752979218}, - {3158406316, 1519824532, 3918750951, 3857420157, 1878759478, 4197781309, 1592992533, 449322726}, - {1339236063, 2982560389, 2935538018, 3878334679, 1226035659, 3396478571, 2874764482, 478125457}, - {1301985241, 3664972929, 3101843292, 3325000508, 48448890, 762417043, 1554042805, 247877307}, - {2727151629, 2579523385, 1581627359, 4124763388, 3919823608, 2615461716, 1378903827, 719056375}, - {2339124086, 2596678071, 3808098454, 4105231856, 1165206154, 3657717411, 2703578127, 672777294}, - {851401176, 891692485, 4114550078, 1064792097, 2964649173, 1624501005, 1242871086, 805159488}, - {1683650386, 292434381, 3990255596, 2743741958, 636452115, 1844938714, 3813910697, 371497676}, - {1661732372, 3537901241, 3793196095, 3492323549, 574051093, 3767852841, 2364415107, 799081786}, - {175299307, 1004192173, 4245010557, 1257380800, 1674789804, 1791990747, 158538392, 218131642}, - {2285156910, 2691954264, 2990530673, 57306082, 2511677134, 802726130, 3377419180, 400888987}, - {4233287629, 996832508, 3745182262, 530952862, 2461120472, 1274708697, 1374121784, 90685524}, - {1574136180, 2623502883, 2778113375, 1627422825, 391202864, 1759267347, 2091307810, 413636480}, - {114074142, 1779294925, 237814541, 2080865111, 4204502515, 3214858637, 19999136, 645031156}, - {3391760373, 71627995, 1697979332, 3777343521, 2802671700, 4254162849, 2042693547, 392319779}, - {3810150833, 651280532, 2475296915, 109172022, 2712324376, 1715732874, 458776052, 686453587}, - {3326164420, 1969828054, 3709531971, 3126721689, 3263142834, 3666565705, 1073293476, 23172453}, - {3986076018, 2167818884, 3220611007, 16522232, 830708824, 1850887640, 2249141627, 281625009}, - {2827056398, 2375585111, 1267214257, 4256169155, 962201898, 1977197812, 1235362612, 181464461}, - {233222763, 3134826472, 1220295653, 3463579454, 123685174, 3384874761, 1842931939, 367147323}, - {4027675605, 1897745071, 3574244036, 4132901103, 2992924023, 1017151477, 3553680041, 456651345}, - {976045846, 360246489, 2345505770, 1197193506, 3691385704, 481103099, 1408647058, 601514059}, - {1352536780, 1165947173, 2338111708, 2140113822, 3388966976, 4242622409, 2566726989, 800175220}, - {622406413, 2191399343, 20909085, 2104722296, 3921418727, 3006211145, 1098118919, 772819332}, - {3752282992, 4153396093, 1093940071, 3231647803, 2061204976, 4237986825, 3125456229, 360666073}, - {1902203594, 2166431520, 3048448267, 4211633469, 422655533, 362541296, 2833196022, 30540078}, - {3459070135, 1154925361, 2146451569, 439634125, 112215718, 1555750314, 2075602375, 268382398}, - {4170827129, 598651121, 4112051400, 354042198, 117519605, 2044834039, 3795286321, 672532677}, - {4293660292, 2559363878, 4004914935, 1954243110, 33908540, 527427480, 395512379, 666638774}, - {818922970, 3367963153, 2607019618, 996712250, 577400586, 1995154870, 275719667, 486179025}, - {303584541, 465768517, 2502083621, 1721434987, 2784685421, 2550119625, 1539026912, 768510999}, - {104843407, 456529531, 112272682, 4187763063, 2481116118, 389558599, 1211000147, 333081795}, - {3237053209, 639935465, 3269068147, 4274778399, 2996399176, 4203397644, 3808926858, 310319738}, - {543623432, 1078382120, 3788202836, 3096883067, 2006014732, 4001349400, 1785575421, 38712823}, - {3741321815, 59773016, 1650480602, 2790931744, 3436991714, 406874256, 835224126, 441554910}, - {1010116927, 3471287112, 1812466377, 1496568199, 3859844609, 3734770730, 1369915818, 1265657}, - {1080084107, 318001873, 2468738387, 4030010816, 73637460, 2688831557, 2318454267, 19914279}, - {2601959709, 3291684887, 1066143751, 215908331, 3524433531, 3669491488, 2602907859, 347340664}, - {3244669970, 870805674, 560008717, 550804583, 3448806922, 1331183860, 132817773, 374002581}, - {2893433304, 2589969971, 4199235823, 3607803569, 1972424004, 323972558, 152703836, 382520726}, - {888344433, 986947428, 1060685036, 3674232248, 2339077780, 1639123173, 4091389545, 67106784}, - {1333287312, 853197348, 249162074, 3161806107, 304522208, 1217603918, 1261890695, 773554804}, - {2388409933, 2501771242, 4284412482, 2014078276, 3755441530, 2016971399, 1936770745, 774848229}, - {509351475, 3457999243, 529792978, 2898392932, 1562217615, 3053563299, 574758, 517854749}, - {3998584973, 1878529287, 2715177727, 1224861009, 3089556237, 1474966339, 2869292964, 138958148}, - {3898301781, 3121745376, 2037278272, 1781436223, 306997564, 195781830, 2604338968, 287203504}, - {2829280039, 2058343536, 1977136684, 2904169253, 402644809, 1269671536, 1516044912, 49302678}, - {2352051521, 2680721609, 2727172665, 457099007, 1714528736, 4175463365, 2814167478, 656271669}, - {2834143746, 4001397284, 2293706075, 4007020827, 516962725, 2366209892, 2893036507, 696268803}, - {2116307717, 2041508147, 3306032831, 3380323936, 1092765598, 3151903391, 2003009443, 670127158}, - {2833968050, 945399766, 407055707, 851683248, 3408848763, 149279622, 1250062652, 294921286}, - {4026617399, 695954513, 3005400715, 260079381, 3135449838, 529626207, 21167673, 754190034}, - {19474035, 2899143989, 910198842, 2460343492, 1293439826, 3252727240, 3066595482, 806138106}, - {1466433759, 3510730148, 1387699631, 3604433846, 154722009, 323640705, 1547420357, 567790081}, - {2642538324, 879830785, 2584661233, 992548227, 3246121605, 1296199364, 264170527, 675930166}, - {2052868032, 1635031521, 3429119673, 2889866729, 2145250315, 3922438947, 2188623204, 521140894}, - {1738418046, 2409370135, 1294310241, 716789092, 2926307783, 1153688666, 1566764867, 486250524}, - {883592693, 1072520719, 870212207, 4157736859, 1200625497, 672712276, 1547325327, 219171536}, - {1941707668, 3211688457, 3230982467, 2536976061, 1459132304, 3724450953, 2535995053, 573388396}, - {2130886017, 1656793801, 988581291, 2058822212, 3397227003, 1890819646, 3580844968, 431061421}, - {2282216265, 36210372, 4057221378, 2824471251, 4100601922, 2613564575, 2911778022, 685195463}, - {889613783, 2209885933, 1131300794, 4125497290, 1433496892, 3196926123, 4027358647, 115683322}, - {1370581586, 2448227851, 567913656, 703270061, 3567129725, 3110423012, 1948162531, 319872974}, - {1384964423, 3334379336, 2375366035, 3683663757, 2510927998, 3971904043, 2829263912, 35061189}, - {461203792, 2299166222, 3109432937, 2004704915, 1523931881, 679452364, 3078778768, 560798853}, - {2636733587, 2141120890, 4009861382, 1212306808, 3611601613, 1866495696, 2663117565, 12755265}, - {1094754769, 400861220, 3204264895, 1523157390, 1385367345, 3640772357, 1805894043, 691803154}, - {3006790355, 1227864345, 473501853, 1050840399, 1148728769, 3858381821, 2719804355, 790572343}, - {2334077262, 3868453146, 4065996821, 1243336349, 1769912796, 1370255972, 1723978255, 797728569}, - {3832083753, 2783287439, 1555099498, 1382315713, 2435136441, 420044856, 1165601970, 736795505}, - {3977777209, 2104378342, 1171628315, 2881610120, 3767263625, 3623842061, 1160101635, 563129469}, - {115144535, 4243993188, 288742061, 3859409724, 899401117, 1161121382, 1582540025, 270277378}, - {3514122052, 51520497, 319622437, 2821340513, 3888417404, 2679250485, 1867915990, 284764406}, - {1837893561, 2102372510, 4276665919, 1136629789, 3967345275, 1997964639, 1099524168, 699747376}, - {980323285, 1354929829, 2058495579, 3514979641, 870109111, 906425432, 243658862, 682679331}, - {3360454496, 832134167, 2880283143, 2696134789, 2263416279, 3693002382, 1490275583, 233396907}, - {3833251520, 3097188018, 816068685, 2851931731, 2556425150, 1596903221, 2940496387, 606133325}, - {1731364937, 2999584069, 4179085212, 4102383977, 1753518417, 3146995693, 3912418491, 32102811}, - {3912599309, 733494215, 1170503393, 772727521, 3629980979, 1299362222, 2009186869, 607796444}, - {749269678, 2378271393, 306599333, 1999023827, 2383366716, 3368714950, 3318093133, 632048291}, - {2434117695, 151271185, 4193064776, 372099043, 2132436806, 4102837785, 1008730273, 200864214}, - {2206402204, 1699779656, 2670943607, 2401396857, 2524389958, 2128490726, 3887754715, 182259659}, - {2841849681, 2926017867, 2296019195, 3133153959, 2410088948, 189547912, 4141956055, 765293207}, - {3536304972, 240839497, 1206495475, 3876705763, 1238911663, 900468522, 995333840, 119330672}, - {2621459861, 3797954893, 585219282, 199743896, 698864978, 1282375985, 596194810, 355958196}, - {3021175397, 211592522, 1673782478, 58726989, 2973989794, 2544771074, 2318381320, 574486674}, - {3054492940, 1485289700, 2433164809, 1813389576, 883508782, 2661416453, 3079814721, 23213100}, - {1559703678, 742668686, 3466459550, 737840845, 2979768746, 1914567423, 3814618388, 145684224}, - {707970329, 3120067913, 4264117350, 67458286, 1060088854, 380395119, 1239761565, 737262170}, - {1550893834, 2356920896, 1315248231, 252031369, 1690232905, 2827759945, 2972790684, 369674619}, - {2626172210, 756071568, 3341309729, 2270773371, 2045609388, 3095247123, 603926665, 725656732}, - {2166628560, 2918375503, 1737039560, 420198087, 934432294, 244050916, 3209372147, 200036909}, - {420274586, 3464988436, 321318123, 2677663986, 523362419, 2399430305, 3049346663, 166461846}, - {4103841840, 2163392666, 3210173394, 3749861468, 3657755402, 1609967297, 1301177400, 143523407}, - {3304090438, 534986140, 1267368642, 3439098827, 1154894860, 1294657457, 1954429717, 118409727}, - {476665396, 1177868885, 3373809122, 2520901478, 2649330363, 2379435637, 1466619822, 661059867}, - {1924466466, 2994731347, 3692893525, 1689946896, 3546445097, 4226542711, 3015114478, 16782163}, - {1120145626, 1130121865, 1969822828, 3978589285, 612726215, 3803487244, 1926023546, 631984993}, - {1979975518, 4136512185, 2969261772, 2434196265, 365522018, 1802675085, 404441904, 32174025}, - {3080660647, 3973780412, 214381860, 90351777, 2679178747, 1780061434, 2714185994, 566493335}, - {1641729785, 3702126599, 351556288, 4166940606, 2119460071, 2162842889, 4251073808, 448396048}, - {3386871666, 3056414401, 3679209819, 674424324, 1658307487, 2983070011, 595610203, 535126756}, - {4194950213, 4109758267, 196359121, 832209294, 1229256721, 3625724099, 1758491134, 267824475}, - {1773187562, 2559664520, 2827005447, 3594999416, 857993535, 1427766684, 3595558773, 647123390}, - {769207763, 1294251016, 3858659266, 1905754251, 1804771774, 1429481580, 1848420240, 690860124}, - {236654488, 3780245311, 3300008852, 770451787, 1339549026, 396102962, 960096798, 505951319}, - {1437297671, 484459077, 895064827, 1043115759, 963418274, 4124029137, 1827681315, 810703393}, - {3993803408, 3639688973, 2712042357, 1641359170, 3526658629, 1894081400, 3566855191, 572422285}, - {1351900586, 1647101707, 2714163579, 70058369, 1491147834, 2218384726, 392877203, 91527786}, - {3908739591, 3547073020, 3506103676, 9255169, 367687146, 3277730283, 332851626, 658112961}, - {3992173089, 3336442561, 1308396561, 649897492, 498165515, 3791375902, 2476925986, 166550078}, - {459056695, 623862782, 2614682674, 252535114, 3957019296, 1669629417, 984578888, 559340348}, - {2109892813, 451411526, 629769236, 2073144596, 2706225876, 2442347888, 1930125614, 380876630}, - {449505088, 3925975612, 1781015135, 4019613773, 1244709664, 127258707, 2288182483, 261056249}, - {3198234408, 1445083148, 3203128507, 1896655444, 1800546621, 2549859473, 2674270289, 649156473}, - {3295645402, 2355403471, 1325138283, 3282236760, 186596910, 2986676413, 3091222690, 94039058}, - {392637966, 3835592021, 3395063270, 2338880248, 1307091009, 1413969228, 338356697, 110506024}, - {3927456635, 958780881, 1467123914, 800350251, 227030894, 3222995683, 637808892, 417233380}, - {222651616, 918333206, 3341359148, 3888995981, 2112943295, 3132575683, 3136568383, 747036429}, - {164100597, 2717470589, 3005641886, 2298299462, 755839109, 2812607434, 587384279, 171494897}, - {1517929317, 1746459810, 2292290049, 2118474457, 1444780887, 3288565786, 1138377533, 658116309}, - {2262800921, 2989467931, 2550042218, 2759452136, 3245301798, 1334600974, 2692828723, 515277997}, - {78686128, 85661778, 794295383, 2445409530, 1241207645, 1006634767, 2353102965, 424947616}, - {656251673, 1874858842, 3408697434, 4156867126, 4201355402, 307527125, 2984164150, 448562967}, - {3363516191, 836987291, 4041445533, 1038612888, 2378587132, 2004574365, 3034242698, 286317830}, - {2805641958, 750951597, 3379512708, 3048328768, 1158225610, 3137201145, 1413602757, 134922947}, - {1988814965, 2229475393, 2846407915, 334194828, 3607660995, 1081466899, 330489579, 99696095}, - {887137534, 610389082, 2015240627, 217466600, 3032578167, 4036110357, 2733875635, 8559943}, - {1953585854, 2737811591, 1248580326, 2914961395, 1140662723, 1554042825, 2875695471, 39247110}, - {794694455, 3919208665, 1559681874, 3272467149, 3245086200, 823169114, 818446518, 204009539}, - {2413464253, 820347123, 3595161951, 1222162452, 3008804785, 475163524, 2801010307, 55259462}, - {3783141420, 2480101165, 1582568892, 4210315390, 4104626394, 4170508678, 3521839065, 466290234}, - {4155507898, 1768692973, 2294318387, 4251134624, 3860023484, 2962944097, 825358892, 409963745}, - {2353340423, 2928779692, 2350920335, 1125003106, 2546264946, 2037086586, 3608413239, 349680431}, - {407691513, 3087008438, 3650107171, 4228010293, 228766680, 1006018908, 3899374162, 279155770}, - {219192789, 3767885343, 2001122128, 2993521540, 2040536466, 1510197515, 1949552358, 767891567}, - {4230985990, 445223622, 804925595, 32198490, 1699132452, 142946580, 3433820756, 151985030}, - {703663283, 4189294278, 391930560, 3073123820, 3810720461, 3728991122, 703072198, 705452638}, - {423838023, 3175580039, 3391238926, 2182607534, 1029096987, 2098442190, 2029684938, 506228035}, - {3486373622, 844799641, 2737997276, 101229479, 1633921456, 981779705, 3382045385, 471489862}, - {111345089, 141258419, 3035810727, 781599895, 3818721457, 2727854618, 836710756, 724712374}, - {753103137, 1612061402, 3135427825, 2024323365, 2683080252, 2322551836, 1358841983, 574105519}, - {3726776850, 264764526, 1269886327, 1646952963, 20275953, 1382351286, 3784024275, 417874095}, - {2179226830, 3961776262, 2865979297, 92406850, 1687861619, 1374033033, 1340829681, 330485254}, - {2198938516, 1594227217, 2374846273, 716624411, 315917975, 338168015, 260297398, 803884775}, - {3841490074, 1338963403, 2129573580, 296104270, 4005429983, 4152105754, 528035615, 534412746}, - {1109555456, 3630041677, 3747570039, 3733596972, 3092097551, 4101759470, 2766565742, 241058909}, - {3048972783, 1694224088, 295738413, 1621033207, 2752354468, 1577257363, 659188436, 262502991}, - {3598137172, 4026580695, 963308414, 3715504869, 162412690, 554465723, 4084782609, 326385603}, - {3149839252, 3897546728, 1721301002, 907560668, 3628415729, 4213042357, 3551649340, 750530208}, - {967736301, 1541097463, 3323544789, 589126928, 1066106088, 3926824621, 1489210414, 656688557}, - {2859895609, 4108112351, 318398405, 1050973942, 1960040445, 3272778186, 4242917146, 53520559}, - {2463115043, 3682974011, 1675118986, 2407604338, 1604446710, 3678649599, 4139129827, 432224355}, - {2892117449, 763150191, 1646592920, 674361446, 1626273500, 1714244725, 628655514, 119634681}, - {1753810191, 3668520057, 268978019, 3915204722, 1748217241, 4220898233, 2960053943, 290063457}, - {1581814618, 1288345474, 2487733488, 3752277535, 3629701936, 3651800341, 191495295, 65841960}, - {1021785467, 3001485381, 2914813443, 2687082178, 316220049, 3350235890, 1792759262, 639331636}, - {1999155496, 2861574098, 3565835920, 3383637044, 2640679988, 1701009788, 3978738595, 629881500}, - {3576887499, 2858985401, 3057276430, 3943970005, 1442941420, 3113039531, 4138906732, 195995980}, - {3553265057, 3765310733, 3625003704, 2029635544, 3957195639, 4273692513, 2555373447, 796104110}, - {1218374465, 1004886271, 3612460042, 1254301878, 1436363718, 3857000326, 3288797569, 544729442}, - {3147490267, 1127153850, 2811855210, 4184757225, 307947421, 640573867, 1031370664, 422267483}, - {3123014141, 3637820530, 868506880, 398291333, 2206404996, 1717792389, 1186050625, 714964984}, - {475021199, 3980389072, 2273101817, 3483182088, 407824675, 3203202198, 2995341796, 603013862}, - {3255501208, 4180335838, 4130718870, 1868225028, 996835541, 4293145478, 1711409294, 513725770}, - {494651647, 3242190711, 1566878708, 3966128491, 3854568623, 1290688946, 3252305120, 766060991}, - {2536171991, 2410993866, 1048336183, 1251794303, 1536371174, 3008064187, 2762500481, 465960191}, - {2023422795, 195932611, 2923732356, 4226053825, 843557238, 1906300230, 3773618072, 438839912}, - {1879468987, 2389910308, 3036200284, 2542474822, 838533435, 3151626838, 4063954647, 686742006}, - {3126296014, 760885103, 321088415, 4160052874, 2210614465, 424252582, 1846101238, 277787666}, - {2723352910, 1206886279, 2856949077, 1055442701, 1705415512, 2663334378, 2695861183, 270252188}, - {79462021, 1260747989, 1821575231, 557163641, 3711242421, 2285626455, 2027826796, 199232937}, - {2378785532, 719805778, 1449270953, 1267259818, 3577856225, 449427969, 3434205615, 361615766}, - {4270694082, 1396705645, 3242670818, 3967403042, 2393807008, 3544337696, 211661933, 661481207}, - {2751940218, 3746316717, 2750860763, 1749573481, 2758461806, 218506675, 2762407050, 362041363}, - {3114948274, 4169048040, 1267564544, 1804914662, 449251388, 1100660447, 947407107, 107737151}, - {4287071083, 4172871887, 1949821221, 2794860551, 2481492500, 4152523160, 3416060035, 292894334}, - {3792891403, 3128831891, 4226581646, 1173894036, 4193131188, 246395420, 1468347249, 725784617}, - {2103815370, 3734213562, 4210740217, 2794613289, 52312269, 1274016216, 791570238, 348997715}, - {45656427, 1785646781, 1395583357, 1871653982, 2367617401, 2452974550, 2561791707, 498225694}, - {890459953, 1559001044, 2884613559, 3187617117, 1830058456, 328948286, 123255004, 777260221}, - {2293299492, 2384872896, 3805581997, 1613762895, 1528007693, 1510116072, 2584686863, 212597834}, - {10610884, 2532378322, 466693455, 3124320697, 2287161132, 1908747670, 3586807404, 587369743}, - {4090571063, 1527205810, 3666893615, 2008281617, 2640856647, 2010916748, 2303375037, 625765724}, - {2753045775, 3864253808, 3128753931, 1614406511, 3969887838, 2496700599, 2069064881, 793687198}, - {2533187349, 765580433, 2649767742, 595306028, 424170037, 1051747750, 3051117874, 323599420}, - {263590036, 3450290652, 132744796, 2652509660, 2169093466, 2640595640, 3634039328, 572331598}, - {2881996366, 1959192279, 3620818013, 3192088936, 2578127064, 1071702746, 4145183464, 657861858}, - {2383040855, 2392156988, 482563713, 104461745, 1774946801, 2019055646, 424368308, 590508495}, - {3607742222, 2661424510, 3524715224, 2394303856, 434824238, 122064149, 1032876259, 402791940}, - {3634688335, 2901570247, 3095127443, 1083227470, 3257931247, 312689965, 2206127489, 219145063}, - {1584905775, 3107849202, 394680275, 3209823947, 1044671308, 3927839469, 2591006949, 169905389}, - {1607449497, 3496661495, 2817252186, 1495090892, 1329713306, 1526076562, 1689590997, 495710039}, - {3760997799, 1058506459, 2022981311, 1093838852, 1586441854, 3959171519, 4281405964, 532192867}, - {779208410, 2928661102, 3699846110, 2846407318, 1158998832, 3404731551, 3670637705, 457816567}, - {2961740982, 3536420115, 37732267, 3902579597, 3509195979, 198374051, 2748549079, 520181950}, - {1953048490, 1209808987, 3280351672, 2033623184, 2993866757, 1964073286, 1122682577, 500997153}, - {2688605206, 1835350361, 3723411303, 3278251141, 3056835100, 1686393268, 1160230683, 781759021}, - {1737869720, 2312844529, 3244919968, 2147043098, 293840071, 2858800424, 2064917810, 520821093}, - {4177032805, 1971150452, 1637674286, 2688247018, 2389603250, 1139831252, 1024731682, 377205546}, - {4170621378, 243912988, 901863927, 1236460471, 2248986006, 4099401238, 134149372, 676976966}, - {1641131275, 2170678768, 1955360090, 1838444204, 1029371479, 3646171117, 2275769588, 328337224}, - {726431465, 1267442720, 3977190876, 3207520462, 2410698818, 1433254284, 2543978553, 473372354}, - {1515027088, 2896930843, 2777722780, 4066994467, 590158871, 4027595267, 2499658573, 74885790}, - {4285553417, 3803221737, 912847556, 378453142, 3444240000, 1495289727, 3089766347, 229494726}, - {1488313164, 3699472100, 3829462965, 3323033477, 2859096767, 2384302314, 3801165529, 709542059}, - {1333507551, 2810133351, 2961825840, 1945584490, 2841118144, 3987938199, 1723814010, 614470248}, - {1483867499, 1953347284, 4231203002, 1767459807, 1785844729, 3126894815, 2521271277, 211406145}, - {1750640192, 3781311437, 2011709804, 3652525210, 215547163, 1184592567, 1410906485, 317588124}, - {3937880254, 340593151, 292753764, 1635734566, 2558768140, 49836033, 3539551588, 258755506}, - {2922310811, 2947117884, 2353044107, 3433276212, 1100984239, 3129723382, 3015812788, 466684063}, - {1010187419, 3625972836, 706819070, 3354902000, 101712681, 458190047, 3162242991, 578573356}, - {4187914026, 1992063546, 320280935, 4143572431, 452688662, 2570405289, 3121885633, 754593945}, - {4155080905, 190234870, 2176195649, 1064166934, 1607874844, 3059603520, 2492697053, 646393760}, - {3276410682, 2649765828, 4153961468, 1785336012, 262615884, 3105410592, 2023472520, 454606370}, - {838949062, 269010620, 866021794, 3733688614, 895197311, 2904159008, 1016730395, 753016278}, - {3374324695, 2723374257, 1847468830, 3969029342, 3566588774, 4171913911, 3107658241, 204579258}, - {654737474, 1502636344, 3529693390, 361301430, 2038830967, 3713816515, 1088048145, 266675138}, - {596902847, 2873743237, 1840854534, 1929783728, 1719866073, 3758894980, 558055233, 639051647}, - {2687616012, 2133798799, 1129311550, 1422858850, 100429944, 1216469588, 3006114955, 259849252}, - {1944227698, 304271038, 2443562904, 559480102, 4226708480, 331698087, 3526679844, 443950694}, - {3881062627, 2461274610, 440532830, 2353972927, 2114056858, 488443974, 87294917, 563538301}, - {2933562738, 2045853088, 4239934930, 3377060492, 4229089218, 575917746, 2992431740, 529027484}, - {3712706901, 159515225, 3945317584, 3766345869, 2865365948, 1543385385, 1496229209, 541913543}, - {2833556792, 2239174190, 3112295800, 3613740607, 2224869719, 3151053274, 3038879903, 765936810}, - {3188050821, 3223157776, 1652131325, 1398980979, 4012267902, 678088332, 1040247410, 284297465}, - {2813297565, 2753962057, 4255847231, 885145294, 1068483949, 2535613267, 1036733152, 769989808}, - {1472053183, 1059507492, 2121563900, 645113184, 425229974, 3813934159, 3698631681, 393393416}, - {2231823614, 4288619823, 4183888766, 2143048475, 2033398203, 4137216846, 474980981, 158973077}, - {388874235, 1603655297, 960722053, 733053333, 983646706, 3129077198, 3063061810, 532436421}, - {1052022473, 1432865711, 3606925682, 347187403, 2262685796, 1747850860, 1704181840, 292585337}, - {3019146848, 2898917751, 2308083045, 2274766448, 3853700662, 3333095553, 42468480, 793128383}, - {2344953220, 1970726924, 3364353190, 1566113672, 1198734447, 3921342124, 584763991, 764644815}, - {1156650814, 2514049934, 2194307957, 3194338911, 614363927, 2469800193, 3045830033, 307765066}, - {3583204479, 3765518215, 1193918342, 1846304647, 455458735, 518402975, 3783955837, 517534122}, - {2515124134, 573098382, 302165857, 2065117337, 2830449813, 2961866049, 3257157670, 287381190}, - {4062962045, 1593332989, 612011135, 1651818477, 393601840, 1679844539, 1258865608, 747051370}, - {2633578676, 458064705, 3232298455, 2762373638, 3378590501, 4223033509, 2002706206, 18854498}, - {704432927, 162855354, 2474601351, 2118097717, 2887845451, 1768648528, 2454817652, 745337502}, - {2131802434, 3236476564, 3948679620, 1264997775, 324824050, 2329235106, 2229282883, 395563985}, - {3576318966, 2702347439, 1548569274, 3911503746, 1594754997, 428037284, 1885280498, 221206771}, - {4175279474, 884560925, 1788293510, 4071390431, 1329278600, 75537910, 3986062653, 611587817}, - {4064165595, 3898951831, 463754301, 3876512408, 4273866525, 3656102064, 2864263282, 426873454}, - {2879487725, 4148772898, 3525294332, 902076201, 3821691807, 1187586141, 3380537603, 188586101}, - {2821300855, 3309535260, 77666608, 1553427423, 1430614226, 3789461706, 3238318651, 567891539}, - {505131892, 1765279724, 1023233775, 2717054149, 988157757, 3930370357, 3951410328, 641401394}, - {615300106, 2469938500, 2962393877, 870763254, 3939063940, 3551397902, 3066339408, 166771864}, - {1998102849, 3578856002, 3062802516, 2352178580, 2586633144, 4216494320, 1057061446, 583850163}, - {3157186817, 3462841447, 1453316416, 2878583454, 1850321470, 823183120, 831594853, 443179355}, - {3889695290, 3514048590, 3678345405, 3142461864, 3918330486, 1555565297, 1554186501, 460835257}, - {1976857203, 2270745386, 1040432684, 1719737178, 382840304, 975485366, 1339329266, 665715259}, - {1775719548, 3865921570, 1767511131, 284475597, 759000998, 2144381137, 405980571, 316308704}, - {333279683, 4154982400, 2725563020, 1624645192, 944537969, 4101796849, 1029516221, 188337419}, - {2333139764, 3370196244, 563990470, 1820343606, 1090570134, 3740057214, 2975044526, 48364264}, - {3893895884, 3415761288, 3602051122, 4222236815, 1818231542, 941030641, 1278954250, 479811509}, - {2231534561, 3001246003, 1735061971, 2367944438, 3339590515, 1525437574, 1772871571, 55664520}, - {3240991257, 1720977498, 2854283005, 618745748, 2769124500, 3453837600, 544147878, 185774213}, - {785912344, 4084408394, 4019935678, 2296140680, 1079312541, 2995946870, 337417386, 569117688}, - {1328461810, 4191446592, 664848689, 1835179220, 3844355132, 3927458525, 4291487626, 752901006}, - {1277986734, 3322459265, 2495791135, 13850161, 3322535780, 4255664143, 793736052, 590577308}, - {3943148876, 2051656845, 2378297305, 4210853378, 3025210259, 3347745040, 1829002822, 783552257}, - {390419450, 3182827290, 2074360823, 2212996980, 23849683, 4056760166, 1169573170, 808114955}, - {3116733479, 1954047770, 1307518808, 3579783916, 3833903932, 2558661739, 1641988891, 337001632}, - {1749964295, 3295770248, 1427336572, 1858592335, 1547305083, 3381883637, 3866929566, 400178036}, - {2916624080, 1249061717, 3993119010, 1762822762, 113203435, 4094737116, 3823783515, 466509000}, - {2326969558, 1953546445, 3634818439, 3363541076, 1716388780, 1654036887, 1310528587, 252006596}, - {2289710152, 3021754479, 1730561176, 2846608204, 2798838665, 4160992944, 1922020958, 334918675}, - {724068395, 2465547105, 2372702828, 2089797142, 1859306007, 2258006400, 3820751022, 8701719}, - {3680022841, 2936101336, 2805403885, 1230409280, 1298919872, 3980936177, 3165818717, 632281219}, - {1108813842, 1529004848, 1435981486, 2383497343, 1683386444, 3404737480, 27217618, 389214686}, - {1246270380, 1081021534, 3993167693, 2321702841, 3206139467, 1077029745, 3689164032, 306354043}, - {2972739279, 1430941099, 1949027652, 3632963640, 3096599524, 3940218869, 2005778595, 152490874}, - {642313713, 1588205479, 2202447625, 3555420126, 1332047067, 397194468, 3101444271, 63198304}, - {2712591838, 463230492, 1736923331, 2262259706, 4079194129, 519762708, 2389448711, 191869879}, - {1010112216, 4074559936, 437507855, 2817966447, 309413913, 1056451302, 1544301510, 423694381}, - {2447684647, 353285705, 1630251037, 2247712057, 188089176, 3081771499, 3093769200, 111203951}, - {1845044945, 2751831662, 2127410111, 1676568744, 2444385139, 2533268077, 3071493561, 364304881}, - {768848928, 4047482701, 2313239223, 4088071841, 1554969192, 1338493465, 3813724622, 346200299}, - {762098228, 1802140065, 1935378433, 1046154865, 1015776313, 1540601332, 3200690817, 82575765}, - {2223434198, 810391443, 106467804, 199497911, 4023827662, 2434945129, 874060001, 43411220}, - {3326223251, 2453943490, 1072352610, 134899467, 3228520702, 2886014882, 3533451751, 635142122}, - {148067278, 3849793796, 1600918789, 2781381503, 2067614842, 2161297898, 3642845673, 19748983}, - {352137065, 2535681309, 2338842367, 2397038445, 3179990199, 910260913, 365118543, 461936801}, - {3497302643, 2522412225, 2607217554, 1687795322, 799990799, 3041497219, 2743180658, 526588174}, - {2813321992, 4143580317, 3893942349, 2911544102, 58629387, 3093601204, 2055075336, 767828076}, - {4105354486, 2702336913, 1788403540, 69655812, 62188473, 2429577760, 1233762464, 441346868}, - {844784562, 195609859, 1449041835, 1486003536, 167369675, 1315214301, 1441535468, 695614857}, - {2932736788, 3222416485, 2368387989, 4195082025, 362530313, 1573932379, 3672582354, 173832319}, - {3972966602, 595744667, 117760213, 2429534433, 3155285528, 4051804671, 2647605051, 623156566}, - {3980114729, 1805359466, 2830352545, 909015755, 3880539667, 3047597358, 1833768029, 339607866}, - {765854896, 2846519464, 1416701728, 2205369739, 3088593881, 3906615622, 740942203, 358698089}, - {3330723199, 1083917670, 3884187274, 1533435129, 4076093059, 2400081539, 2913221579, 142782587}, - {3825153612, 195340656, 3582781097, 3622898193, 4164350212, 3700559870, 2046768656, 176872487}, - {2519218607, 662520611, 2152613548, 3458649612, 2331323669, 1044841133, 2182768561, 645399889}, - {1588635225, 3146516964, 1998150457, 3622609531, 734079935, 1145307997, 528855551, 311164367}, - {1219649753, 1306224645, 3600785293, 1467385037, 2546088316, 927995014, 1340442086, 606143243}, - {982948500, 2659135970, 3999371596, 4062615605, 1808692872, 1763199750, 822930879, 692394653}, - {3020663099, 892531167, 1917753725, 2473653846, 3141217202, 1355444419, 183309836, 167173443}, - {876955032, 1899560163, 916169092, 2564924460, 2456650772, 2906616833, 34191021, 751061730}, - {3215882789, 2209949203, 2568828409, 2122601557, 404690685, 3324595595, 4277444064, 620873853}, - {1823661598, 1948505978, 4167209663, 3198966470, 2052432795, 25764451, 3324616385, 601538950}, - {91879216, 693331263, 283833914, 4087429345, 857511747, 146178823, 1229666258, 148314651}, - {1231906121, 2534780445, 281267165, 2829574385, 2932887470, 1665154883, 1943828643, 93832301}, - {1795207740, 2484474985, 2555113195, 2410987365, 3152437313, 3463795128, 1643135544, 430084260}, - {1000638969, 275446079, 816547152, 3545120568, 745240703, 3328071895, 3278487094, 598245579}, - {3795381280, 3659445935, 2352658713, 3282320010, 891376391, 3823419244, 2438249575, 180619469}, - {3350423418, 3915825200, 3127532303, 2038598857, 3052982888, 254895303, 2101185106, 390417763}, - {2593711612, 3760863893, 2262449873, 34562974, 4181851627, 408742875, 1596013043, 338595203}, - {2214400173, 4173431011, 2697170411, 1442670119, 851454954, 3163156328, 1751010233, 666380006}, - {27426638, 158821495, 4040909608, 493366781, 1117650062, 110237812, 2187833462, 260596623}, - {2122183801, 3470598792, 3121137638, 2281503425, 3004134074, 1980442314, 2746696308, 390804011}, - {1815677887, 1805667831, 2854727323, 668053916, 1143546838, 3013547170, 1428439137, 358518894}, - {2762776387, 2642103464, 2388119724, 1021872172, 2676323334, 2786757971, 1610084234, 805085323}, - {1939394218, 2739516890, 3726162430, 4286380341, 691907891, 3258066542, 1869349768, 651460778}, - {2129339517, 3421404801, 2170569256, 496479682, 3295360930, 2096621499, 3196359792, 595224982}, - {408603686, 1914123975, 2315309220, 560986977, 622118575, 1609432092, 2420457834, 256655258}, - {1525377031, 1209591458, 1650373335, 2080307290, 1466154468, 1125339681, 3296056682, 409430405}, - {3654969858, 1012412278, 1445124567, 4125627636, 926955742, 2096457081, 2273625443, 763436073}, - {4107055918, 2998888823, 460616544, 1523822014, 287346716, 1434916581, 1018382561, 414045192}, - {762313289, 2169874898, 1630894373, 622513950, 2513112409, 1200502605, 2120695031, 687355755}, - {3687346739, 2483669419, 1910041964, 1530527235, 1698445064, 1672006103, 1567479759, 457898868}, - {3674990876, 1387891729, 2094110737, 1653293314, 1722359595, 1825385363, 2771435134, 99508405}, - {2375753360, 1615546475, 1450207413, 4028990178, 2334152157, 1848763345, 3988086625, 276159532}, - {3615711813, 3582897771, 2751168740, 2176690038, 393735109, 1835175588, 335722320, 508340591}, - {2933667941, 685875276, 4128342640, 4147721127, 183524776, 2897972606, 3933011419, 361388627}, - {2223646821, 2632618848, 952054450, 2289264974, 1873496575, 340023068, 2139652596, 100318811}, - {3841871258, 2712627286, 888008982, 3923715442, 1823901620, 2426353568, 59854549, 134804365}, - {2351747471, 1080955633, 3630462633, 2158383788, 3958858976, 2524745094, 1174992730, 226039580}, - {3147816339, 1376397807, 1975521910, 617295921, 628438421, 392474432, 554265804, 480216718}, - {1602933360, 798435382, 126245387, 3235439600, 1593136150, 1070789923, 2469792541, 520432409}, - {2096352911, 963047994, 598381083, 2645156623, 887631634, 1065597728, 3980103626, 76516514}, - {1245623231, 4114587043, 4146509475, 2910011911, 2106716323, 3969633114, 3995749352, 450298069}, - {2463387154, 547535455, 972158403, 2783830066, 3055535168, 71074883, 2227829042, 770134309}, - {1986365786, 711103606, 3841582810, 4160976452, 2520963531, 1095307938, 2574945891, 205914308}, - {3001395093, 1516157696, 3987467551, 2620365632, 3838779844, 4109106862, 4086696397, 374901940}, - {4253406492, 1733688219, 1515665408, 2121371189, 3365533133, 1781446599, 360467223, 245956572}, - {2291431391, 550667025, 3403176245, 534033278, 3725526045, 3415667475, 1291403546, 658826260}, - {482794582, 736992764, 534747520, 1907532214, 1102314720, 1146667182, 453673914, 756838263}, - {2628108090, 4178253792, 769543836, 3135530791, 3315302203, 1565299543, 1631728268, 357558234}, - {1319791894, 1088656022, 1696728404, 724771399, 2511827104, 1983046649, 1187119228, 754097971}, - {4244506077, 1936247188, 1728812353, 3747187341, 456116042, 823487992, 3489000951, 553197684}, - {1259901662, 2392750366, 2376329231, 2803867873, 3300102819, 3788675617, 2571951242, 473884580}, - {3595594100, 1693613144, 3809898002, 4041894447, 1003892451, 4087139826, 291692751, 430775641}, - {3039485509, 48649699, 3192632656, 1810075758, 3913815233, 2536746700, 2772499620, 748622812}, - {2097176515, 1600047731, 317231818, 1078694535, 186476825, 2582629845, 464849037, 753217692}, - {927265984, 542403298, 1813466127, 3624110577, 3581551878, 4243136194, 3689667615, 497417150}, - {4159444850, 3692720200, 3930065323, 3019236101, 3272741885, 4225050653, 107160360, 412265852}, - {3027812264, 3301020196, 2267856552, 120051571, 3502699381, 442037919, 200005028, 558677478}, - {3796402332, 1848284535, 1088023792, 483893883, 3380663750, 3808112315, 3839839251, 568662618}, - {1619085595, 797146432, 4270154023, 3684489458, 1480295685, 8181270, 260315033, 754977540}, - {3853431051, 3281545926, 2567402419, 3829117175, 2468212054, 3299532044, 3179771465, 473543909}, - {3123145449, 741384629, 3413383571, 1375858110, 1517778203, 2877795872, 980705543, 360229357}, - {4140966826, 117117945, 229693735, 3562162687, 1454428809, 1648245131, 1639526492, 411128134}, - {1702758715, 2956143160, 1943123539, 10078756, 1632185358, 524776506, 148224933, 487781418}, - {2135475610, 1370189320, 2373353807, 1673073312, 51392528, 491246778, 3561743330, 480978264}, - {3902950314, 109072763, 1184405627, 3585155709, 3211749467, 3368709661, 3173062106, 707833340}, - {2081821684, 107591607, 2044541119, 921298206, 500632873, 662298076, 427554499, 590098993}, - {2003658226, 2854721423, 3748246697, 2566821946, 1367413216, 330287826, 3589677766, 664655364}, - {1667498915, 3919129274, 2930993245, 1116139698, 2766896734, 3535258851, 207680994, 25230788}, - {2882770293, 1551332256, 3373355515, 507385680, 2084405163, 2653438534, 264557580, 347124519}, - {159275733, 1092034353, 2051758290, 3953839101, 4121375166, 1876026027, 2275637935, 761645256}, - {2142022646, 3661432812, 2844483949, 2692970251, 1920336615, 1814024819, 659434498, 460396417}, - {743483741, 3760303493, 4060942469, 1116057819, 1158329921, 3907404871, 816498186, 769520586}, - {1806884381, 594845828, 3801316959, 757170004, 1206862680, 2303562781, 1667079485, 743258220}, - {592861249, 912604456, 3164585141, 4138902645, 3920272879, 433653019, 2178222303, 504231169}, - {458529080, 1391142778, 1596404404, 2008325501, 2570018920, 2763907296, 2512664545, 288382504}, - {1501549678, 3114479021, 763976681, 1778271404, 2543716861, 2825460992, 144941930, 793168014}, - {3698674969, 1589621261, 2150078671, 2607524735, 3721661636, 539126131, 2503029268, 404608172}, - {3151204849, 238154583, 2587297725, 2172093458, 362946568, 722646997, 1457402779, 642599065}, - {4189244689, 3043236006, 3978893677, 846387998, 1549261405, 3615379155, 3381003940, 735830451}, - {4173593601, 1306430061, 509481556, 1365656574, 291183291, 3975165988, 1830296414, 261389791}, - {2039257548, 471240504, 335505839, 4195521316, 2918764681, 3359206013, 1277829366, 128930960}, - {2033601052, 3886456559, 1574092007, 1589610167, 3968102682, 839718695, 189984951, 197166493}, - {2004295889, 755590217, 3661839271, 2963775605, 2570267717, 4166415929, 618640813, 752253652}, - {1622700201, 3878947695, 194107185, 1308345541, 4277548422, 3237875298, 3643652409, 633844266}, - {118906827, 1487477794, 2885059769, 2201633589, 2661189547, 1640145103, 3368309926, 17705265}, - {1479339821, 3098375413, 3171083955, 2484317884, 4224256364, 3114688811, 3536563250, 210600111}, - {3958729924, 953329843, 1814792220, 889046166, 2827911351, 3089000796, 1271730277, 496281796}, - {4253742693, 1689830009, 2448767264, 637869068, 1523850713, 1828725237, 39740071, 570656665}, - {3995642699, 1762094093, 517752102, 1377520282, 687747665, 460913006, 3770252761, 505022474}, - {2110661337, 1524048191, 4270040417, 1626517836, 315132775, 659413083, 2883337788, 22340411}, - {2864289370, 164727338, 2129159655, 1562124971, 2595212214, 681690116, 3594630427, 498319930}, - {1555120363, 975603897, 2233619438, 1648310185, 377260481, 477793986, 2121183180, 433493853}, - {2798298466, 3951850593, 2564189210, 836750816, 1185308179, 2445526414, 1931511728, 117468321}, - {886360513, 4255383698, 2915952779, 4123344352, 694306712, 3365011565, 513452990, 606687510}, - {940062984, 3537763153, 960283135, 1261726476, 151433705, 3493277781, 3514543094, 163006137}, - {2920648348, 757726186, 2284970078, 2728926166, 4140531830, 260414717, 2871544046, 74206872}, - {1277905781, 751985249, 1311517516, 3239964396, 557501821, 1870521032, 4144589522, 269256496}, - {1335710171, 1615529209, 3322868836, 2110158597, 3140985499, 588928964, 2455133581, 396574610}, - {3169210269, 2765833386, 3725030179, 823924933, 71833560, 4037691083, 2908197759, 544215678}, - {3420958804, 2273179325, 2928220005, 3196647933, 128545802, 1895871453, 2685038216, 264007242}, - {1475846808, 1972706476, 3580201654, 1557025784, 769896006, 1559675218, 794925772, 41398640}, - {1010163619, 2332382593, 1059570947, 4141687112, 470748687, 2618360758, 2674310840, 56233629}, - {37523269, 853112597, 2457441771, 215668381, 2962771072, 223111345, 3852543240, 44776185}, - {457390239, 3877793556, 4216342586, 3288881383, 1335812400, 1256078055, 1363274875, 638186462}, - {4139333449, 1395301774, 665526337, 756010440, 880137858, 2062949882, 3542284409, 292515214}, - {1020746158, 1651468362, 1432913881, 319415897, 3286210217, 663862003, 4025954899, 177147873}, - {1138584193, 1574082522, 1215714038, 516749003, 3612217524, 4294087141, 1747817330, 790356041}, - {1639704238, 1341140638, 1896871953, 1623346378, 216932928, 2270191050, 2711104464, 325802540}, - {1555786819, 3440406788, 269789564, 1020605533, 393842357, 3153886038, 3611543905, 52523827}, - {2352355869, 1690853892, 1302485678, 2573403223, 3071601692, 3813694842, 1497428278, 232649963}, - {837496298, 1300273886, 3356088308, 254666478, 2801356650, 1919154841, 3094443949, 657495810}, - {1327560541, 4279649711, 1384909698, 2859670821, 1834623523, 4103117427, 131762376, 695706587}, - {477869586, 935519228, 3444402252, 3759415348, 418912688, 3308278533, 1366606885, 135090460}, - {1086202311, 764891443, 2044307831, 1728682312, 3212305602, 369614650, 1737731266, 414718711}, - {1670739801, 3416544102, 1894270404, 2535000772, 2490231217, 1827732401, 3379495505, 216298113}, - {1048096874, 1406433208, 29044865, 4142450089, 1815470090, 3016084950, 721960765, 686213022}, - {3408268869, 1418957668, 2895969374, 688906609, 4157431796, 1978546772, 1235030174, 581179304}, - {11962282, 308268003, 1466833373, 3658859344, 2287401432, 1961797335, 2559932301, 257174234}, - {1707147357, 1179838639, 3422662043, 3124705702, 3135444250, 2257788937, 4201633950, 144284097}, - {2059002417, 193261179, 469037246, 3385483097, 1053139927, 461228658, 2837771742, 580584969}, - {2746514720, 440600260, 2280710498, 438751424, 188549939, 1600947829, 1442716983, 697502987}, - {1095501080, 4005797142, 2760368110, 1548257026, 1141439411, 2712911688, 1312590098, 336551066}, - {1075489128, 2921779430, 2534147741, 3879561770, 1988905048, 1078201940, 1028480383, 73409544}, - {1329020949, 3706394743, 2165062480, 1531380912, 1933060539, 3244401757, 1753508732, 431983151}, - {969217548, 1600536317, 3790467519, 215935474, 4030239732, 1545598857, 3658632060, 580303320}, - {831932327, 2294490829, 1470018534, 3774700798, 2832312326, 2044380806, 2507109428, 402894655}, - {3333550990, 1760034668, 3991899965, 982300861, 2152930067, 2203315056, 3216576928, 932288}, - {3713367992, 694879479, 2712821630, 682899053, 73797012, 1740076558, 3947265852, 354962475}, - {1949466552, 3829197751, 2259714496, 4283278908, 4243716872, 2357682461, 1763717138, 357645310}, - {2826517417, 1352133939, 1120674599, 206592582, 161722305, 1601665653, 344151673, 167553893}, - {231630064, 3598150320, 430609839, 2832362699, 358420436, 1809822578, 2933948453, 657535763}, - {380967920, 3649711677, 788811940, 1759463194, 2612833823, 2682070304, 2011898279, 47431963}, - {3742961912, 1419886222, 2929867022, 1788639034, 2935121767, 1472361113, 4220571855, 526107287}, - {3989185536, 3359624070, 4159328644, 1069141973, 2665801493, 3926213538, 2558723650, 681516185}, - {2097862398, 491762523, 2131546987, 3408692986, 1980771082, 4198357985, 1604823949, 39246375}, - {1225456695, 3124945683, 3086603614, 1562965888, 1778940012, 75017098, 249399603, 398087011}, - {3756070237, 4013482346, 1612730152, 1419955052, 3616627088, 1854417985, 1793763173, 222492429}, - {455503183, 1335894639, 1333097431, 1116619951, 452202448, 3788061619, 1477333081, 216136877}, - {2204737014, 1040385056, 3781368674, 172963822, 1385527586, 2865056529, 4110799932, 679011937}, - {1889167259, 1400782940, 1245500673, 1191773551, 2198412706, 2143395478, 239419940, 230945512}, - {2249414749, 4154894696, 115216939, 3817998671, 4294476324, 3366511146, 3752610129, 737640645}, - {597413068, 3802725621, 3043977083, 524783786, 3192083907, 3442786264, 2391108590, 682732584}, - {3964481442, 3825114496, 751029473, 3176864200, 3710716210, 2236304516, 101531052, 75034873}, - {2987470683, 3362717087, 2940503455, 4021656684, 4189152210, 209914602, 1155086016, 285235272}, - {3994302569, 156577474, 2521939025, 2889549125, 1248122066, 2637185938, 848637158, 632657169}, - {4223276098, 1281694833, 2340313126, 3924756493, 3318112059, 347892924, 680156807, 21217740}, - {623800807, 3091698762, 2441833896, 2862898152, 1790759442, 194378638, 3358513113, 240504063}, - {2230574841, 2637722577, 193176944, 2335513946, 2609853572, 1825789588, 1261762137, 794150258}, - {1118486296, 802648799, 4236434180, 4217230218, 4087611636, 3576549535, 2798929478, 106349145}, - {1255582920, 4109239122, 2947195831, 2600925626, 2064695150, 4180574583, 3628871974, 583411016}, - {2354130490, 2323089117, 2416872201, 2552440860, 424731102, 3917508371, 2088137098, 497989354}, - {2734214130, 4057463627, 3962432450, 1773452797, 2384365848, 1725524093, 345863017, 309727929}, - {2074153466, 1934953871, 1588598849, 2709361697, 1468315688, 3786521799, 1478020244, 365804755}, - {1830600880, 57950069, 1008426221, 420152148, 4193163805, 1841447477, 619653388, 508516067}, - {3052249797, 2637105250, 129151645, 519986487, 402149478, 1656168402, 2789899894, 388835169}, - {5870670, 2233241256, 3871296155, 1185724976, 2260830859, 1444397458, 1315205248, 231708829}, - {2665163159, 1120860914, 4227563978, 610697661, 367363669, 2806124318, 494937908, 145609662}, - {2704672287, 1943609404, 1734640809, 814007514, 2733316220, 923225571, 2494687516, 124525037}, - {1667807130, 3247864501, 1769292846, 812756797, 669093949, 4106479031, 2702387969, 584116900}, - {863923100, 1048931029, 2934331603, 3941757586, 3710760979, 4041053090, 1004809219, 65720318}, - {2981281919, 2818160800, 66825153, 4184425320, 1260692449, 234563605, 127024627, 327021324}, - {850711580, 2423332806, 520992478, 2200331391, 3908615274, 2970509124, 1887302234, 369373806}, - {2504822468, 380067992, 3276057552, 2006858059, 4134377169, 3200158853, 306954331, 429469975}, - {974432242, 2299885110, 1559870647, 173865357, 3476472835, 425561145, 2723010032, 309737242}, - {91550700, 1867751434, 2192216480, 4098409813, 1434033708, 175054738, 3477875147, 666491057}, - {1690878334, 126999756, 3535552681, 1380018847, 899282797, 2835718186, 1867784176, 259741632}, - {3551521539, 2771041063, 850571440, 974418310, 1439183076, 285751486, 278451904, 396634168}, - {3343011545, 3513757902, 4052418923, 942286822, 3237733663, 756025499, 1670875885, 67072888}, - {61898155, 946895506, 97039203, 169338582, 1608856169, 2093410328, 3480011227, 572205727}, - {3612206137, 2535242174, 2541767943, 1261071458, 4104781143, 2332385587, 3493206447, 583826972}, - {3647547566, 402594886, 2714367208, 1839189694, 3057956370, 3236572339, 2676767, 762077883}, - {916053109, 320773765, 2782121270, 2500719926, 1713806984, 3860095271, 40452574, 184107579}, - {226902877, 628543012, 191739273, 2152021215, 1708034533, 1442320069, 3664113374, 770184456}, - {685624290, 2831749267, 3559018802, 1267229583, 1323729209, 3704187871, 4237325773, 368907507}, - {499938886, 302930751, 2811855265, 2515481343, 3121549889, 2754275214, 2571031363, 433478363}, - {2956898865, 188856865, 3938491636, 556963925, 548581071, 1053234116, 1230720629, 581137282}, - {3069693339, 1635912027, 2687616313, 1120802116, 3031181541, 4125308397, 998826563, 179496966}, - {1370812706, 186629271, 1287028456, 2738539764, 200403920, 1118279937, 184937642, 521720034}, - {339989448, 1409342827, 1490435786, 797629222, 1601798954, 907515724, 519324700, 188969184}, - {938796607, 4189158765, 3531840434, 4275507615, 2808195457, 693588064, 3497063679, 531152483}, - {2185063475, 2194091799, 567413826, 2355269608, 2876497886, 1716035624, 1703546891, 305247043}, - {1732299833, 2873808350, 3382090356, 118788623, 3893448862, 1039821681, 1364219473, 644222038}, - {3708182423, 1718535118, 3918128168, 605042175, 3355178597, 2427581647, 4012360821, 414740898}, - {3576210642, 2706059038, 1667684704, 924723342, 2559058223, 3172470381, 3818579100, 367253453}, - {3912841626, 206794611, 3844646971, 2820335254, 1598374533, 2110333696, 258180212, 133378665}, - {1414331781, 4199799689, 25382432, 1020573760, 1113733457, 3040133099, 3583353451, 72710959}, - {896333992, 3654622384, 3200493242, 3395651377, 708786681, 2352689312, 3996027849, 798888944}, - {1243544733, 3157709606, 451138863, 4098629930, 3600282106, 3840738094, 2469572690, 164296962}, - {4040472189, 3390663695, 241834885, 3219814886, 3115160062, 3985652515, 1570118729, 256442707}, - {2883524463, 1826017465, 1174234975, 3158863222, 1167440490, 2096974564, 3137164044, 370133368}, - {2294660742, 610444994, 3748112434, 1251638656, 3492744117, 4111109371, 3759169689, 345611315}, - {4287494374, 626397318, 1133692615, 2527847835, 429973732, 616253571, 3920240579, 125944113}, - {2637582790, 3949671770, 1980800702, 1685270455, 1642151413, 1914975991, 354374000, 555959841}, - {2025258528, 186031714, 2814463985, 3894262944, 1988497922, 759085353, 3942205402, 205709993}, - {1770138732, 4128122935, 3045324160, 2879053056, 993367167, 97973206, 1826419939, 525952233}, - {205327500, 4174603399, 1197390231, 2454884584, 3331663359, 630713632, 2637973505, 682433370}, - {3186021172, 867123661, 219948772, 1383455199, 489072600, 3952739564, 3169476193, 5957968}, - {3539563679, 2245063764, 3499857631, 122531485, 1239629091, 827751079, 547734502, 321381258}, - {2157910809, 499989486, 2961110134, 314593585, 1808702719, 2634028235, 410055372, 256605784}, - {573833592, 1465801997, 1025058176, 1085637019, 4215713018, 1402229883, 2528136886, 26293199}, - {1763588454, 3094073752, 3837735194, 3761971857, 3489905439, 242573751, 369717785, 413760023}, - {2600786792, 1714465740, 2786427637, 3872140438, 3441207075, 2563606858, 1607137066, 171089764}, - {4294049802, 828494579, 2208166442, 649493076, 1509152788, 1431789339, 2746196852, 2587522}, - {2429092364, 1913850259, 1074651797, 1854610820, 530715232, 1348839299, 57067192, 16733736}, - {2007160975, 2888625461, 667929665, 4153798929, 2889126284, 4249727396, 1317020355, 232437361}, - {3567080566, 1586472906, 3906666320, 2241661012, 2881661989, 3384353102, 1036289113, 741393770}, - {2701219046, 1867536914, 4286020861, 3709640791, 3521953587, 1352056662, 3145769045, 62436649}, - {178734766, 1598172982, 478038845, 3803684212, 668807637, 3439937191, 3768071832, 777119035}, - {2879305142, 2574930395, 3964047600, 2129281896, 3433331933, 2187559119, 2178455359, 637001349}, - {408540159, 2013794289, 3785486269, 2888473789, 418327381, 4005110456, 160294449, 734504787}, - {439668954, 3178031816, 3957591695, 1097322608, 3071550386, 2572813256, 1804491477, 342720362}, - {1038226291, 2695284337, 4142766023, 1851784457, 2246547560, 979577513, 3304838349, 390471784}, - {2484839434, 3720418484, 1382135483, 4084703581, 1927308432, 3155884285, 2200602810, 429544132}, - {875259887, 3036060744, 1497694425, 2561824592, 4010329825, 2336409099, 3723521021, 635647821}, - {268053901, 383282395, 168181065, 1323482739, 4115032899, 2486526422, 3369124190, 295676865}, - {1665352711, 2593236026, 2186171309, 3707841504, 4197606660, 1225856495, 778918195, 727808578}, - {1159269538, 501178644, 3057612673, 191172150, 1484080681, 2408293559, 778495817, 648123297}, - {2783103085, 1588050261, 263273091, 626149906, 2883068020, 2972472, 1647669446, 202616461}, - {3646040594, 918005994, 217626764, 2277275651, 3736869261, 3310263980, 2745913623, 775640061}, - {3220402089, 2690226051, 3965589287, 3379764708, 2985309188, 1932358238, 1447068751, 602216913}, - {3950849632, 2287143618, 4148376020, 3251178699, 620128138, 3728056620, 2714066056, 367259602}, - {4074895135, 2710165430, 3381762521, 4012332035, 1135558730, 3386370568, 1186397511, 777427644}, - {2035294496, 171082812, 4283266382, 797223392, 3844732122, 1695769067, 3044051310, 2440326}, - {2576149877, 2913880443, 3286806565, 1001093210, 3777032211, 3200849627, 3019554169, 220083824}, - {1782697548, 2167501671, 3083196414, 604409522, 4032404916, 3599243042, 1437655795, 643698712}, - {116821309, 1585404607, 3511509295, 2905401004, 2594908286, 1529380052, 1924068586, 656799723}, - {2365275331, 798598759, 70894990, 3883640510, 1721691890, 4110199530, 801171715, 642172582}, - {3298433150, 919172932, 2668920130, 3332205791, 3493556286, 3977202573, 3443938408, 58966574}, - {3570659222, 2422571649, 2884329285, 3661921132, 4129205484, 3732985535, 3303807478, 743634276}, - {2167819015, 3945814081, 1625979381, 842521238, 167438343, 1219013531, 3637651642, 260360158}, - {1905604226, 4190444554, 3226197787, 2687022799, 2605538091, 1258950329, 3013104045, 568577859}, - {362508123, 4177383312, 183202785, 3096130563, 2920933815, 2897307450, 3672016334, 719149408}, - {3406224442, 1307936504, 3442911218, 2325511879, 8761413, 410608403, 2526553412, 442514072}, - {2963927089, 83539992, 617534318, 3044403283, 527760169, 620897130, 598860435, 18945850}, - {1367311631, 755488260, 337267618, 2322363769, 1455433943, 3172615231, 122834954, 716589905}, - {3914091614, 3840690276, 2334511482, 2289764718, 1217731743, 4139206951, 1154438916, 31004609}, - {2676788855, 2036106896, 428886592, 2588556713, 1962529691, 1660602720, 2530745248, 76659793}, - {3505713118, 3234530812, 1948028752, 3675133359, 2780201885, 16882088, 3596521033, 443371435}, - {3364677174, 1551238127, 1884421849, 241170534, 3421092501, 1509797916, 3638938310, 357764516}, - {3850210208, 1560891982, 258999148, 2251313571, 1239287293, 232571288, 2074084038, 262686647}, - {203804955, 4210568811, 2449086045, 584938219, 1806088762, 2734893269, 199368946, 662838671}, - {1344807382, 2840406593, 2552892894, 3185782701, 2442695444, 3971395472, 3719422055, 148172480}, - {2606638707, 3841564467, 2193890992, 593256357, 1520551591, 3609713059, 3968306691, 789094452}, - {3110852112, 3960408917, 369075147, 1132474150, 1331307983, 2088305908, 2663176168, 693390552}, - {1753383331, 2987898123, 1710150827, 414237279, 3145109729, 2825789347, 2720244530, 391259207}, - {1104255462, 3215836962, 671249455, 1082452424, 1552470654, 2751246750, 1055169963, 563886433}, - {2142760191, 918605274, 1864177784, 832698115, 1336395007, 2865686285, 921081023, 202821048}, - {2684252428, 3643122526, 4057058961, 998952640, 3505232479, 4089642023, 2580106162, 745589183}, - {671607874, 1226308110, 1673653318, 1258254230, 3762331891, 1664137111, 3387759119, 31099888}, - {3924889894, 1833020092, 126811051, 251868386, 2850253760, 1539133471, 198801281, 245893636}, - {3104603738, 440625585, 2922346235, 2814865952, 3916010841, 3553013724, 2493734064, 98882497}, - {1244970574, 2027017921, 1992105263, 629137947, 78649161, 243371636, 2966330086, 547978714}, - {3413041381, 1499176521, 3529825144, 3012360062, 2946515458, 3925906441, 2999188144, 475078969}, - {1777548503, 2062137373, 3924046298, 4151690942, 2312659916, 1441023236, 3272039823, 445069543}, - {3473095268, 2254888485, 1556374038, 2906385979, 9156496, 88876348, 1116820461, 329469891}, - {2362209454, 1073014282, 3609627441, 750736910, 1772936850, 30545527, 3666832656, 237537540}, - {2348418523, 3923588791, 3269390941, 536298111, 1988877139, 2522756275, 980545248, 354756639}, - {847594321, 1991593231, 1703962863, 2655377944, 1440727144, 1081797533, 2614160840, 55193055}, - {3242110721, 1707213041, 952700414, 4189521871, 381246073, 2537207778, 3265944582, 518280393}, - {4082466210, 2511104980, 1849503376, 2666046618, 1235332334, 115025922, 3168237690, 98606010}, - {1882709758, 3428349685, 759776817, 1342583215, 3294816391, 588399977, 1809396749, 329635718}, - {1569717963, 3578500219, 4244264935, 2093092057, 4039765771, 1370455628, 2833524063, 579246317}, - {2341263495, 2903953794, 378838300, 3600148648, 3593610985, 1120565820, 2040949341, 165828620}, - {3078804837, 2124043929, 3228674754, 602413148, 537445008, 1290245481, 2004114679, 213564061}, - {3873994681, 1586014770, 2382599460, 2434060579, 3820107537, 2510436662, 1420922203, 241864590}, - {2951165399, 1774722701, 4126787531, 3719248761, 2387085946, 4168602496, 596486488, 50363649}, - {1902710788, 1690215231, 1181623476, 2324650021, 2696062558, 2657791067, 2600347935, 306852801}, - {3121562399, 1595075054, 3732002542, 410116598, 433002235, 2526175026, 3364184427, 575123535}, - {3341611328, 3590974172, 64422899, 1159622976, 2370617293, 2221793015, 1097133189, 674706082}, - {11467013, 3814736210, 749374953, 379813525, 3854808749, 2395585305, 1091681207, 463429483}, - {143130515, 2571221431, 2558035757, 1278578935, 1664187064, 982479863, 2524539920, 532903505}, - {1701848235, 1302954257, 682052141, 532990597, 1138801349, 3811156417, 1205393144, 810549984}, - {663299149, 149306511, 4289285029, 1305202218, 4138727503, 236266269, 3146683103, 226067059}, - {814539573, 1405486432, 2638979413, 1264317689, 2259188859, 2056626927, 547786521, 783729773}, - {2600548593, 3432259863, 2640775467, 561238614, 2820622034, 3545257992, 1671950244, 35803768}, - {1997206657, 1641431343, 1340334979, 1907803899, 325507737, 2311839763, 3535036916, 330482868}, - {2232015762, 2416565676, 3708409210, 2016012396, 1051447478, 3356420001, 1747008241, 514145327}, - {2721046225, 2283964573, 2543533828, 3569157170, 3505986448, 79767233, 501239358, 104653966}, - {1122413713, 1027535081, 2570661284, 602552004, 228714042, 2866639423, 3420797358, 197402093}, - {2126779417, 2697803604, 1188974778, 3783136096, 960543587, 424956067, 2317198612, 303572630}, - {1915244206, 1357945612, 166296080, 321021420, 935929016, 3501067569, 851067173, 262532228}, - {907549971, 1507569610, 3376808644, 327316072, 2428683340, 4148579514, 317045792, 409856538}, - {2131857056, 420779501, 2405174017, 1455807119, 3998648966, 3995325918, 2858428372, 311047961}, - {3882066747, 1035971306, 2102346956, 1952698807, 2017698746, 2548973924, 1189075176, 639121364}, - {4204883648, 3441769589, 1331461019, 291846887, 287798124, 354999789, 3239213632, 135762831}, - {3530123870, 1006103855, 4113103043, 4267800764, 2643527790, 3180236244, 3318564492, 333651535}, - {3508218426, 2901775611, 2199468425, 588707874, 73215051, 182685955, 2028805922, 549399184}, - {3319134494, 356400184, 838502295, 2441316632, 3016573838, 1394552432, 3398656862, 729797408}, - {2450496909, 2382262171, 2182546035, 3084526738, 4003394236, 1283945009, 4029018312, 791893508}, - {1161394017, 3493667747, 1408807542, 2278171454, 3991597147, 3644070443, 2813006060, 226447605}, - {2192034884, 1557777353, 1703880380, 2061970108, 648437808, 1516370265, 2948224759, 723908358}, - {50476625, 551680024, 2140743452, 4069842368, 2888434865, 3473078684, 3533676736, 568380188}, - {1256879467, 3753087035, 675501172, 2988114592, 3362434477, 970044609, 1651230922, 129797294}, - {2053100198, 2822218975, 1123837363, 364754976, 3757129289, 4031219746, 4252140211, 619822422}, - {1116146065, 851959614, 1260659002, 4160867865, 500055508, 472259408, 2578796235, 226020589}, - {489046325, 427922281, 657524539, 409235899, 436882198, 1529965744, 742172302, 518181919}, - {1135502487, 693536584, 4185990238, 3004860410, 2961899447, 1246502742, 3235155521, 176653879}, - {1875147331, 829499157, 610771497, 3331385920, 3115137341, 839936985, 1927102858, 684852538}, - {316510214, 1907387060, 4144269136, 1258806564, 59390707, 2964582474, 2577722811, 149526947}, - {3744483390, 2412548446, 157515279, 2859469689, 1520272630, 1822203012, 4179599519, 84528112}, - {1696492708, 1740087966, 3681679540, 557598999, 169262602, 1419876450, 1313210371, 276025251}, - {1794834281, 910895367, 2335464457, 73306478, 771912615, 2469710332, 1003616208, 780989862}, - {217225955, 1817050618, 2879323494, 149136244, 356930292, 901983577, 234161403, 541221662}, - {810193315, 841044840, 2002636299, 2107756897, 1224670597, 231575387, 2982178518, 8355881}, - {3741181145, 21400574, 1047420418, 1542923794, 3523273848, 186591362, 3438528504, 350101566}, - {3343238802, 3872571290, 2745807340, 854373139, 257161344, 2006097483, 2320249327, 341166473}, - {1662272484, 2096724268, 1746946342, 3146817319, 1690968571, 1126374124, 3153579357, 481463099}, - {3771602466, 3189481733, 1605144068, 2687605603, 128926460, 2470984938, 115718307, 373215456}, - {3304459657, 1580057057, 3720155548, 176817404, 4080043607, 2635952735, 3549789994, 302918929}, - {4242291020, 2384923175, 1847207835, 1245940914, 1668817402, 4033041422, 4096143658, 801084454}, - {3473281868, 1764786434, 2006023926, 2650677786, 3326482787, 2576875998, 4122429518, 37010334}, - {3661631265, 1782666263, 1607266809, 1334714216, 3274287922, 115666027, 1216452557, 77906794}, - {3258704295, 2856807374, 2131450535, 2608557829, 554555820, 3238366575, 1636425620, 514337985}, - {2516365495, 468770476, 2071126195, 3310878882, 2891483331, 4152617050, 4040956625, 264505422}, - {3331023109, 4139619777, 340037464, 291958598, 2841737355, 1463214967, 2840853952, 249138296}, - {374594180, 2382956525, 2896044887, 2129660450, 4136306013, 1399410547, 2501163896, 489918844}, - {2898464135, 4262653866, 1187346687, 3498436491, 3322760265, 1523632797, 1358022123, 334284675}, - {1882435620, 3660206846, 3192947579, 3950986228, 560888828, 1918731057, 4118336299, 167739984}, - {3923955762, 672139230, 857587919, 2983106292, 828435617, 1156550404, 1003071044, 226334439}, - {3329323200, 2954772638, 1048653344, 837823629, 418651653, 3665924761, 3274125160, 15392861}, - {4155831616, 4153388414, 1623183389, 2343235113, 1154523631, 2570694562, 1265208898, 730681823}, - {1706394367, 1521317380, 3997428928, 2520960272, 1162727801, 4135587198, 948103777, 124476755}, - {723186144, 3730600597, 1535912235, 3569137551, 1358400507, 732441475, 236189248, 630495580}, - {1091564579, 1879159631, 1939045371, 3400779793, 2564820469, 3478171198, 3026659117, 257012726}, - {3991440324, 1479955493, 2383632522, 3723674018, 2484248681, 2865110605, 3491285573, 593454173}, - {3063778604, 46442482, 822333087, 2540072244, 274142269, 3616795839, 3106271994, 245534750}, - {819412485, 1871164296, 3126212097, 3067134867, 3471634976, 4247303822, 4198675164, 616231674}, - {4137164129, 3074389938, 299265466, 2225269997, 1939807863, 3429318625, 122608245, 544846722}, - {2143656077, 3237031048, 2637578649, 2916329195, 109710344, 3842394137, 3620548991, 629779390}, - {238873347, 427862993, 249055815, 2810306019, 457086797, 2950565536, 2753806688, 802797169}, - {2893017500, 192458400, 412323229, 4107164755, 588508688, 3310196298, 3237898800, 197281290}, - {2657431029, 3108130688, 1113852619, 671968489, 922603604, 4258638865, 4154328264, 740244610}, - {221664061, 1557009127, 3966568348, 1972886612, 1991377028, 227958268, 636345176, 22735883}, - {1263400502, 2054967108, 3943856251, 2924524141, 2171339089, 1591232240, 2710541619, 763421498}, - {790761754, 4249253958, 3131995521, 1721120693, 3668845786, 3068014228, 704352366, 484672985}, - {198365840, 727445714, 445925625, 1416080885, 3689301030, 1528766010, 3725236276, 531675839}, - {930958873, 723329652, 3375891648, 1811607360, 107286670, 2269083562, 593486598, 547381172}, - {803229375, 2217591796, 4165646532, 3852179382, 424600146, 2459684997, 2916609492, 605815747}, - {3999041708, 2219369636, 3293160918, 3561263576, 807218253, 4117571833, 1180998444, 95709429}, - {3109057875, 1032835401, 3369398772, 1006248291, 3249087171, 3737349460, 3586808185, 406742305}, - {52543930, 2165949023, 1672486052, 1260897492, 3296737513, 3609655258, 1481021780, 60477637}, - {3062348960, 1137080966, 2512914600, 930178799, 3904977491, 2622769866, 1684723807, 643434804}, - {1144988152, 523535608, 137321465, 2464709351, 1708198424, 3475618975, 2522100058, 683304809}, - {367413557, 4168036928, 3790394027, 800834917, 3700134012, 3851950275, 330944924, 703215367}, - {1232500860, 1497767371, 1155545083, 2539659388, 3074909780, 3748047173, 677660066, 576366073}, - {3708754784, 3266952090, 4064490668, 3087221222, 1435414915, 2898844001, 3321414082, 243717798}, - {3386728783, 1449617944, 800073058, 2250091991, 673669272, 2314149220, 3595320767, 460084605}, - {3514918247, 2094668613, 3996155786, 1479217872, 3102843657, 3144394484, 4155697818, 499255864}, - {707014534, 1035567206, 2692687081, 2294902771, 618284441, 97989529, 260087336, 711349468}, - {1434985479, 652119017, 4214811585, 2298786036, 4036955355, 2324853641, 3674895622, 142803998}, - {1625926258, 1118668646, 2098009616, 1010009518, 2700282348, 1154006727, 3438767664, 550147640}, - {98686250, 4084982616, 1477648833, 3145856456, 384755982, 2483351805, 1394648928, 318295949}, - {4062754491, 4009324913, 1586667277, 2438284613, 301145277, 777648926, 260028140, 277822207}, - {4200063191, 2960271741, 2586899339, 4228576549, 3350126306, 1460579407, 1605725583, 774178058}, - {3559193021, 3278180418, 973510710, 2511219207, 2897058934, 2620105646, 165908134, 221551840}, - {1866811455, 3716732897, 2126110310, 3758955961, 3106323120, 1737944444, 3700270909, 432460719}, - {2090557257, 832173753, 2020372382, 4259108141, 489865895, 3837998217, 1529686905, 701244983}, - {1698869841, 1589814974, 849562634, 2389732391, 1867348794, 203208310, 3315452230, 3479565}, - {2568771528, 966164313, 1092550045, 1780408710, 1486725272, 615323188, 3852071633, 370517143}, - {1603758091, 4284319746, 3382131789, 772141828, 3994573395, 3094497933, 732909581, 349383300}, - {979566390, 2247324230, 3586615435, 2046688077, 2553504282, 1327773199, 3810292197, 80739763}, - {3990705240, 2308647198, 767280223, 1902313485, 3600170594, 2039734041, 4213121129, 476097370}, - {1996184363, 3098627390, 354161715, 2106214999, 4088121200, 3557993622, 1644375339, 569755620}, - {4002017679, 532395703, 777366780, 1810235269, 4121679529, 4157778940, 1935721291, 709508769}, - {4128830648, 1936459963, 1230686092, 2252935894, 1346758810, 4291313085, 2229288489, 672513682}, - {518306880, 3986274106, 1599822350, 3717413674, 2060348403, 294468191, 2953016987, 251846279}, - {2880062500, 2016035579, 3173642623, 343994625, 3691036796, 3323517077, 2387603384, 693176909}, - {1092253742, 1048802669, 265911120, 2316120235, 496222114, 2053343860, 3238467749, 476823968}, - {491143520, 4121074871, 2350468019, 2223098660, 3037704865, 1361957405, 2052829220, 597695235}, - {216226685, 1904382487, 2320394717, 627224055, 3989150905, 2149587859, 2953636942, 716559486}, - {2964211244, 3550501255, 1876972681, 1559924849, 3254127465, 600627167, 147042128, 63702487}, - {542549660, 2956023461, 546781230, 2418455258, 666242426, 3249705379, 1941948536, 770157946}, - {336157905, 2258786192, 3917868435, 1162625513, 2854776328, 1043631879, 262474032, 89625908}, - {2808034867, 927475470, 735160116, 3359081521, 1590596137, 1326967205, 2489654986, 111171194}, - {3212393027, 4052903003, 3566635582, 3427080012, 4180895840, 666198105, 2498593337, 151228223}, - {1781726916, 854357081, 2384198397, 2043213275, 1987032415, 2374095174, 1275188509, 705583535}, - {150374488, 517210786, 2988974653, 3465276826, 604242721, 1731705157, 3736432497, 407585459}, - {3209294775, 1332923375, 242879374, 3788617545, 3422855132, 3990684703, 559285607, 626230060}, - {2997074056, 641825407, 536550514, 533743881, 1987274117, 349045707, 1810814164, 282505771}, - {36390569, 912405219, 96626688, 3210108964, 2770627757, 1427480310, 4268560029, 503267648}, - {403564056, 1284728308, 2588602249, 2733996137, 59104759, 979992320, 2410813586, 525817156}, - {2770923150, 2201608967, 2498885128, 29817743, 3115329688, 3034631302, 258818847, 340214489}, - {3555787705, 2843539444, 484577041, 2547427165, 4199817259, 664342527, 2134913940, 409924101}, - {3721789925, 700616225, 1139106369, 3683758036, 3970610403, 2664780418, 2206609047, 243603418}, - {40457903, 1525438908, 3940301144, 4294595784, 866365263, 1756768688, 1181338245, 219776365}, - {1589117972, 289692211, 547881592, 2883699515, 3796257536, 4200563911, 1914913794, 479716175}, - {3209993834, 1950084935, 587708318, 3116731362, 870515718, 953615233, 752271198, 723227706}, - {3608586423, 370005668, 1550926847, 4287719786, 2780823201, 631200800, 629654402, 691164210}, - {4012908231, 3160845730, 919456325, 1146932170, 2105592149, 3235570906, 1660435383, 510266142}, - {3989973019, 1783832386, 3470800819, 4120638573, 443421054, 1686061175, 3486675570, 468718055}, - {4147485594, 3969982390, 3701019676, 170430108, 4109419329, 1960348736, 3279141214, 705156011}, - {373494381, 2252943999, 2126706376, 3701550125, 1487774356, 1631940488, 2012551323, 36646593}, - {4256882822, 458752030, 1142003419, 2684100202, 3401952993, 1456593259, 991577247, 40852113}, - {3784906861, 2587660734, 1167155817, 2030748427, 3405254521, 3130355218, 459230718, 557491007}, - {2039001162, 2277401393, 1616779875, 304537017, 1598458406, 1421478182, 616714576, 682418243}, - {4284653748, 1826399528, 3252133074, 2625823645, 2323810913, 1384409861, 3286216667, 605452785}, - {1852478968, 4164794286, 2156535131, 2774013500, 988695951, 139163172, 2887275670, 678600740}, - {61831769, 1159417149, 3385649611, 2879517528, 1913295802, 3484861509, 1755924370, 763220538}, - {3703778430, 2899660152, 3715625927, 2826422176, 3040835269, 361614726, 1949303662, 476477367}, - {355371851, 3104585212, 3736091820, 3938429433, 2150130164, 2660225889, 4029254505, 51667044}, - {3924293415, 988309056, 1566402267, 2917746463, 4229248229, 1320667965, 634539372, 249338663}, - {2755985605, 565520397, 2854362369, 618988993, 835917106, 4092209537, 3100188167, 428030139}, - {4155724613, 1351780774, 938853985, 4158254676, 2159913615, 3512202184, 573558345, 395052127}, - {2291712861, 1214888738, 1771383601, 867649606, 3281519000, 1963274236, 3367593580, 527325812}, - {828385037, 467005696, 2678029473, 1228892845, 3099103463, 2969095367, 3385383426, 605676626}, - {1954730785, 2539402302, 335542769, 3909767431, 4110606072, 3480071651, 1553077508, 384973001}, - {3468890133, 2183427650, 738140602, 2016908871, 180250525, 1418670112, 3688571482, 335249932}, - {2461986035, 3517939313, 2383461246, 3697612020, 3321356699, 2471358312, 1961010746, 704466568}, - {420787520, 2888103946, 2657795836, 418050475, 728483987, 1061294157, 729710317, 11860817}, - {3353267919, 1646858797, 306509290, 2319530550, 1079913834, 2498599641, 2566392851, 399932034}, - {4113069886, 1463625943, 2992404804, 651058958, 2189818903, 1950745534, 2933992270, 117140756}, - {1710340288, 378624391, 3877861898, 3358951788, 2879315730, 4188209817, 1852543782, 792130251}, - {1067036319, 953490631, 2238027459, 3810061217, 3471370906, 1918881001, 3994155171, 663266529}, - {1964305139, 3993296702, 1442651480, 2468200907, 1246982223, 3156989725, 1150047633, 99060746}, - {2205516974, 1494795341, 700035521, 3044504929, 2811619826, 1822685669, 684159761, 46829120}, - {509495611, 1410224929, 2215073561, 4031893811, 2672144200, 508942503, 1929538738, 264452611}, - {1408212584, 915538834, 635908151, 3884472249, 3123808397, 1479572172, 3755707413, 442480753}, - {1248816856, 3153284924, 3884893510, 3187077201, 1564930355, 89654852, 539574263, 657854691}, - {1889360117, 3220937473, 2952953524, 1792655700, 4260404741, 1990078488, 3399112832, 764246060}, - {2124127824, 3059226654, 3628194885, 3700932865, 644139102, 2202789407, 4085840725, 442199620}, - {2539599255, 10191795, 352865209, 4097461661, 359368503, 2290268893, 2718331647, 515532484}, - {3766315182, 1442322477, 990779650, 3084469334, 959497287, 1277847483, 1483795101, 487515569}, - {1706652271, 3173942204, 2194375971, 4282818903, 2953198, 3996873692, 1793245417, 662931093}, - {1437447817, 1777308524, 3573113749, 1782154480, 4203876438, 2164773950, 1329080999, 633073037}, - {965241858, 4029375758, 2171776340, 690942207, 2180549425, 712463730, 1848190139, 502527284}, - {2179202572, 1472441329, 1187451958, 475387088, 1208311234, 3139515059, 1880469612, 354374917}, - {1601343222, 3873238544, 2474626340, 3376281757, 1677310972, 219923857, 223373027, 504769030}, - {846480696, 3995120012, 209324490, 2347849411, 3120936482, 1251627788, 402248528, 631271249}, - {2533996298, 1992592611, 852073547, 1292227437, 2239484929, 2817998983, 1267025356, 676542083}, - {2516584678, 2555233430, 2158271744, 89577699, 3184733807, 1129844631, 549019606, 223682023}, - {1136687085, 1580563924, 2916324895, 602470653, 1193076748, 1809660961, 2864819260, 421605619}, - {4075830210, 3041467274, 3019230149, 3995832409, 1772082614, 115290157, 900325848, 577829541}, - {224380908, 369534528, 617906435, 3491631729, 4027138368, 583432863, 113312956, 184048741}, - {175358861, 823063274, 457994156, 2399277845, 4019154996, 2301142385, 3845627579, 117971563}, - {76370008, 1579315175, 2488079899, 2562820368, 1604801782, 2407085699, 2532307139, 70745198}, - {644314565, 1305485017, 1798518838, 3537219235, 1453053729, 1586580153, 1272290526, 204208570}, - {3258085405, 2197055553, 4231387493, 1796452054, 3330689090, 2380254209, 3690621389, 465877457}, - {552700463, 2904644716, 3382808133, 2658221391, 2747916975, 64560718, 2973732151, 31189514}, - {685496094, 2889466144, 2043782277, 2230512106, 1163392839, 2349841404, 4220629133, 38961293}, - {1311784161, 1456361316, 3616882681, 1198724727, 409732010, 1549115395, 3560188090, 722526447}, - {429566568, 4162426466, 1842316881, 3391443078, 810340022, 2990668967, 1749446760, 317341044}, - {652256748, 656821699, 2766266173, 3435505110, 1593997594, 2009065219, 4061719246, 767053263}, - {475239708, 3552530477, 2947857214, 2208636109, 1337923410, 2519580529, 1709021662, 529891184}, - {3194560856, 1498762431, 1616429368, 1036819157, 1262555488, 194221814, 1453654521, 221576601}, - {1490020210, 3346004257, 3549505628, 4184018624, 1130241908, 219028722, 2418487614, 562875911}, - {3752258902, 1238787736, 1927135666, 4029277110, 3087250245, 2783801834, 3284738174, 634789597}, - {3853464506, 212040743, 3094337825, 1510835080, 117392722, 1533678505, 3705443692, 776370202}, - {2903145482, 1709222665, 18354261, 927512221, 1495230853, 4005193974, 40724139, 317783047}, - {3856504882, 3698045971, 3358625460, 3981721980, 975700325, 428706748, 2980252944, 603247038}, - {3400022101, 1759041649, 490676943, 1469538795, 3830328360, 3765491799, 626387785, 803522356}, - {2732577350, 2573640830, 1012357954, 3806261879, 3020068749, 1276649184, 2629098625, 668557564}, - {4200038696, 1217782598, 3128163049, 2096661285, 3949976154, 3026090421, 3377264790, 793533907}, - {630972047, 4280311285, 3434635222, 3772346410, 3549849219, 3159981951, 2453973328, 50176526}, - {2445515745, 1214398782, 561237392, 3999087796, 192488841, 1845383626, 2542180138, 668984087}, - {1471261939, 3267356932, 1306250726, 4198336852, 58646793, 3779768781, 1447509702, 556284634}, - {127165838, 637848500, 547193145, 401825856, 141189184, 3175425628, 1753104934, 131511002}, - {564657575, 599712608, 479272614, 1239129151, 2461636009, 2471123613, 3640331281, 645484420}, - {1509998528, 2529298245, 227825877, 2417693463, 851815992, 236388863, 120904994, 603430254}, - {2279988621, 1471110044, 2091122439, 195884591, 3302166925, 204001814, 1881314241, 100921937}, - {655236490, 2234916031, 3371055863, 3141397166, 2024331170, 675289766, 3736560403, 773425906}, - {1881452936, 976769952, 1209168843, 3766223572, 818207738, 2402636297, 1858019172, 131105969}, - {339528405, 2923731488, 1065927063, 959457019, 3364111365, 603328845, 1471101441, 605594091}, - {3928761054, 3585962096, 581446865, 2762888938, 489572626, 265963609, 1553838821, 396580008}, - {4215050105, 1601446162, 2286799234, 1851545795, 3936452700, 4289102077, 3571499578, 432671095}, - {898026239, 378494969, 980998706, 256464757, 4194287688, 593612164, 1567500100, 327141550}, - {330582178, 2544006448, 4147538802, 156057783, 473612603, 2407192710, 929703927, 347005622}, - {299685710, 4184678332, 584163401, 2182754437, 3514265810, 2369541742, 2739775088, 290624746}, - {1467216812, 3876339904, 249267202, 3463320822, 66636192, 955133338, 1459761846, 325081500}, - {1934692786, 3761657895, 275753112, 2349914269, 2291894046, 1324826803, 2346489062, 288061082}, - {2072686050, 633481855, 753414580, 3845402292, 3474579369, 1328164019, 4268207391, 591086888}, - {156206339, 887343971, 47415238, 812969189, 819228412, 3052502825, 4038445006, 279407712}, - {3619975036, 322896317, 3382558397, 4266124956, 3896670116, 1599103643, 1384097395, 221157112}, - {969274818, 3227962518, 2522634178, 1615981241, 3210789221, 2122724434, 1082009090, 4154026}, - {357920728, 1563790903, 4267281373, 185540925, 2368115006, 3512357949, 3974044146, 9324877}, - {841720008, 443324756, 1199732519, 1177633868, 2337635901, 4202903311, 1775474521, 236087517}, - {3427868401, 3605360368, 1156775012, 874275174, 667720787, 2821001992, 3027569291, 731006984}, - {314055569, 156164249, 1507241466, 3009621203, 1956772362, 104461584, 341535724, 70676258}, - {2389852741, 2906313538, 583353154, 637461572, 2112052561, 1913441439, 3745584353, 772219737}, - {1803888082, 191800732, 1902575332, 3038758491, 1989735038, 2508765541, 4164370620, 757119884}, - {4106487790, 2824283355, 3756709729, 2105860656, 3504208062, 469467573, 2519155544, 387923015}, - {3766758202, 3558442699, 954664930, 1823340292, 1768258692, 260193904, 3838230933, 339482114}, - {1221640476, 2538966236, 3198812577, 1086423216, 1949542781, 3143874614, 4114327894, 562021069}, - {2483530296, 2142712418, 3120212372, 737075689, 2322209689, 31314919, 3980230116, 668134702}, - {3046225125, 1014109265, 848864156, 1261722385, 3580701127, 855328150, 497006894, 88035620}, - {2768154050, 916964007, 3257798718, 4081009259, 69701083, 2284125212, 466432066, 730811148}, - {1809826387, 2673607963, 2617474521, 1812880067, 115897584, 1742652388, 68790449, 550995207}, - {2895519998, 1476306435, 3248798745, 1771996108, 770876689, 3753154760, 3333694469, 811139117}, - {1121581122, 2266074962, 4209154978, 338448801, 3117187075, 2293896022, 27884241, 503884838}, - {3624689558, 47223951, 1814129011, 1003058375, 1449119675, 3730568696, 3536494429, 551989931}, - {398456932, 357590477, 2188813151, 3186889853, 149144222, 1451890631, 228056017, 360435734}, - {2148849180, 3784228538, 4085078296, 3171515257, 456622716, 4030761564, 4064542437, 405176932}, - {1547999950, 522351269, 47968381, 1293617220, 3894413802, 2631021100, 2385996741, 115075135}, - {1493553565, 2957118628, 1908959545, 1110413222, 2025843514, 314094594, 233158751, 723928830}, - {1754376520, 2872974039, 75490779, 2243905601, 2805704642, 1538798320, 368558274, 626452303}, - {3886577573, 2699804568, 2168710790, 752456812, 1002854416, 3618496664, 2944051582, 591750251}, - {953978090, 2126725740, 3286894472, 3644587634, 3048895556, 2441653671, 595623370, 458724369}, - {4108165432, 1042721255, 384831783, 2743362485, 2286450578, 928412328, 1628963225, 2376079}, - {3422357401, 3110272672, 2299385570, 1751987437, 503939183, 3190293239, 884908900, 619279216}, - {3017334797, 2470573979, 1038260492, 2763092663, 2637696720, 4049596182, 3133144874, 37337579}, - {3655637138, 3055073633, 1653390975, 1621082732, 1511169867, 1833694650, 1681902885, 544632744}, - {1045461831, 1603552931, 1226766777, 2368123702, 4289186346, 2239214339, 1008724961, 486288308}, - {2435986619, 389143552, 835680875, 911651736, 1093289566, 4194601912, 1653473918, 233566206}, - {2241113346, 4155113300, 46023730, 626921182, 2079932403, 2196959168, 2021902665, 791654192}, - {120194877, 1667064278, 3128459138, 3871495076, 2515877259, 1192181109, 2768309460, 145169074}, - {3688865205, 4198219604, 3647330128, 886177725, 2804168075, 997009595, 3793855061, 766742548}, - {1299864862, 2583664502, 45335596, 4190644134, 3876717168, 590818232, 3173406638, 589076537}, - {3698225400, 3731001659, 55385232, 1636435428, 2706965510, 2798922640, 943430884, 746785700}, - {3839030995, 3640538130, 2706339838, 500182078, 4273503265, 3943563494, 2284638216, 405523523}, - {3819494445, 1366741021, 591486648, 3284221547, 1589535710, 3279848996, 2883637377, 294654102}, - {3729644479, 62173967, 1436298415, 296986345, 1204640776, 2182879715, 686623957, 110488376}, - {2003382538, 2372485237, 2673000997, 3644578925, 2134270505, 2678203411, 2604966736, 399901840}, - {3016360620, 771238042, 3179635286, 3470724789, 1883658385, 3848559149, 3141105689, 582068634}, - {4059107788, 3734855281, 636847329, 1523016729, 1954293767, 173080446, 1573186274, 314891456}, - {2155810088, 3682738653, 3999557056, 3295651473, 3471646751, 3475110033, 2637720676, 646390475}, - {2643861001, 2481864519, 2783799210, 1462351238, 3744852584, 108997253, 2486227997, 528066334}, - {1896212197, 654879670, 4118649165, 4107378342, 3589166786, 2055186111, 2183293465, 477185171}, - {3159043030, 2031895345, 210726707, 904546222, 921886691, 2808336963, 92296964, 204092039}, - {3984274190, 338162196, 1965612074, 4200839294, 1702013313, 3547371997, 2326501314, 359175236}, - {3873939981, 918160748, 719999352, 325235812, 3736727568, 1540746949, 3061905218, 260940289}, - {1949865256, 3849121552, 2774283187, 2286285074, 1534883782, 2858705086, 941195353, 161698721}, - {566442188, 2230198406, 4043201412, 2157870427, 537899638, 2938947582, 3864710310, 664540977}, - {779042658, 4024848178, 2189819141, 1830482362, 903032102, 1205420775, 3664839102, 247558449}, - {2055604392, 584480369, 936048530, 2841061087, 3986476140, 3422457654, 319176904, 544566411}, - {3328241826, 3521004246, 3856166581, 1128827716, 1908073908, 681234780, 3804003456, 246742141}, - {3562033598, 408562682, 932114476, 1779512386, 1557246061, 3232070548, 143850872, 508031205}, - {3068893894, 1699945375, 95072326, 380162655, 4163619045, 2878555869, 2758126912, 48661630}, - {3288954973, 460923481, 4211759489, 3789812366, 754503646, 2861110257, 2746959273, 399135241}, - {1312695895, 2134864527, 4011622401, 593513488, 3115641816, 4250640419, 1154272147, 506516945}, - {2725408285, 2378362001, 2515566640, 2343214864, 2840644294, 1838430765, 2667561529, 719201936}, - {2338819695, 2652707461, 1866210749, 4041796404, 2097783059, 3540808294, 4207202316, 142196627}, - {2425934380, 3132549394, 2938346576, 1653611510, 3058773220, 2215264988, 1454808225, 713876665}, - {2154659724, 574465326, 3724811677, 3971629061, 3537917855, 504672427, 3000701836, 718520371}, - {2878971177, 1694249194, 2958641398, 4272085746, 3255016160, 2251019493, 4125079418, 426606271}, - {2174308947, 361550695, 1648557687, 3938069798, 2640598076, 4153395941, 4007562753, 547943387}, - {3765986238, 742361021, 3291104456, 3862255196, 2744864310, 3162901149, 4057811428, 62919153}, - {2648627008, 871771880, 2513512325, 476737119, 2139393580, 1274573502, 720105572, 499386544}, - {2102633499, 2724505735, 8315785, 3887975051, 903840253, 1880757888, 1375970494, 617020086}, - {2825877243, 114411527, 2587199526, 429504238, 2895455343, 1651209214, 3767398660, 427621101}, - {4053898422, 2517408032, 227584195, 3115835701, 1092678644, 3035506316, 271706561, 764483171}, - {123298172, 974371973, 115391342, 371605524, 3249509274, 959400518, 1183797521, 61027048}, - {2334313695, 2440863540, 1623345496, 2145938907, 2124167763, 2656785243, 2741062215, 787902873}, - {299210667, 2999704195, 3597933086, 1478342148, 139835572, 3477868771, 1534822061, 181508822}, - {1968236708, 1343966666, 3812968813, 43543201, 1772422278, 2787623394, 1654602274, 776752108}, - {1340419520, 337893080, 3669365346, 2983128228, 2793542927, 1828433537, 1448539106, 2063974}, - {2901860526, 3045541455, 3832449033, 3787425530, 2512667701, 3436438067, 2344391803, 373349620}, - {2467664356, 3140250175, 3846651450, 2802957584, 2079968058, 3230710970, 944995356, 629690269}, - {2168837184, 1685859611, 674855659, 2758026530, 376784106, 3984629646, 3509458712, 749039474}, - {137066443, 703657165, 2965395209, 2898312763, 2719300053, 3802883986, 3798825571, 542056121}, - {1212150667, 632887654, 892076253, 1858136194, 2640420270, 3638681911, 3781702696, 290645292}, - {1164725967, 2000822852, 3064707803, 1922407331, 4200262130, 4027489754, 1146274704, 710082705}, - {575601260, 3924609676, 1738545252, 3393796198, 2925205037, 977361721, 2443437419, 281320515}, - {2637129137, 1598284963, 822958391, 2516932546, 2661240029, 4122880721, 115573470, 473149543}, - {3937296396, 327154214, 570581226, 4277837132, 570623704, 2237583022, 3580530368, 776858125}, - {272163749, 3159190602, 3989632589, 3679304778, 1712452504, 2291307718, 3858773464, 6080126}, - {3728960685, 2528545790, 1450735158, 3994162057, 3192627643, 1189497620, 4088700445, 764871895}, - {488661351, 3349186973, 3568927615, 878899955, 1675473565, 2574603860, 3310397114, 652003274}, - {3282064541, 1110207726, 2323623339, 2412346205, 2004453776, 780068018, 1092378330, 698268181}, - {2081702688, 2378009917, 1207599696, 1187620815, 2782253692, 3694845144, 3296027736, 8248056}, - {3448644472, 3541610635, 4161883412, 902128778, 1070704453, 1329825368, 2744806391, 493092959}, - {2338786821, 950433588, 352509907, 2362228480, 742980155, 2754293856, 1462912185, 509358725}, - {2124257514, 2072351377, 3636933989, 107955755, 3245302764, 1106793144, 1141174865, 108842064}, - {3924959551, 2548878828, 1273937440, 1092120862, 4077110635, 2704265836, 4121645682, 293099906}, - {4083357445, 2483798295, 339869049, 3930963976, 4077461703, 4206357577, 2235436495, 475371872}, - {1409997637, 1019605867, 910600654, 818163324, 2331964467, 2975276179, 1408951801, 529250859}, - {2649389877, 171095272, 1846213223, 4218584093, 1730796868, 3393573382, 387438671, 132708538}, - {4167791645, 4093687969, 679331171, 2007151957, 4255500724, 551111197, 3778154110, 199490944}, - {1478439363, 3074852108, 1031218341, 3759351524, 3109576215, 2128901070, 4191100607, 21015303}, - {2012838243, 3442832362, 2338178451, 1584280351, 2877542223, 3084694501, 4226797601, 635093626}, - {2994829204, 2103649692, 3742283604, 1370660152, 827727920, 3187977030, 3200533592, 560909511}, - {195082300, 4279600851, 742417698, 2704641315, 635348433, 1140395235, 595299507, 734255112}, - {1500143258, 122407698, 540089290, 2873694132, 1074584392, 3759440530, 1728988876, 437454860}, - {2591073364, 2395517442, 2307098416, 391220324, 3205891353, 3972711241, 1671220732, 52209818}, - {3507002746, 2267622199, 2726635114, 608404605, 2757046855, 3433233405, 2381785554, 671283540}, - {397952786, 1640941657, 1490858523, 4232129674, 2559588433, 3911950936, 23268775, 737915368}, - {3305972515, 4021298069, 1866733159, 2431363183, 2012880693, 113794215, 3399236312, 456599976}, - {1531311680, 2883060700, 4159283203, 2024176822, 1478044871, 349309568, 32933276, 595785539}, - {3525632835, 4149782763, 1437863145, 2022063596, 1090440364, 3376387974, 4270214611, 378063113}, - {1382718473, 2444845994, 2509738699, 1772705019, 3198024579, 3961444780, 326778322, 504226175}, - {949643722, 1740903997, 3054951525, 2064442597, 498018081, 799819209, 731526912, 130900632}, - {3852092554, 1797952292, 4214615662, 4116490146, 3841711657, 3194526082, 856575726, 417375987}, - {1983810039, 1339673319, 3881108023, 2527862150, 3066527514, 1307432750, 3113304185, 762722646}, - {802916785, 905490236, 1403326435, 4282875544, 2011151857, 1545961089, 1969342895, 241617266}, - {2878406046, 845163802, 4193158306, 2425421676, 2690409718, 3823938474, 1928553469, 735101495}, - {2067366171, 3926970854, 2399223722, 822549143, 3170845593, 1587230119, 1023017065, 320107511}, - {740637098, 1926564339, 725185090, 2698693274, 3813802008, 405763459, 1945965061, 269622414}, - {1285295219, 2909658108, 1244685838, 3787083814, 3942635565, 3751918901, 446211910, 242117621}, - {2301362579, 3475411391, 2790374393, 1929731246, 1893330106, 2181110046, 2830785545, 312515590}, - {914782000, 4127953204, 102315094, 1013395951, 1303690415, 646606119, 2078941260, 364224220}, - {3338735837, 2781778263, 3211131981, 846193003, 712968076, 1844318704, 1066926082, 516306317}, - {2733183244, 562543819, 2001076972, 3825465585, 2175211557, 4184744051, 2968140681, 610818895}, - {167105798, 2655547678, 636122995, 3232066241, 3791797598, 797796963, 2521200954, 46324327}, - {3207319311, 2037242548, 3655207130, 1390017981, 4178311115, 1445899239, 3668672210, 456152376}, - {2597741236, 3388296694, 3578242003, 3327242923, 1519877084, 2717830190, 4170815274, 662864829}, - {2548507947, 3599600074, 1763811751, 2194267512, 2783830901, 2977894111, 4189763554, 611228145}, - {1638796406, 2163342869, 701054890, 101818028, 1729197517, 2335614605, 1409612971, 625196520}, - {163691126, 148535504, 2470178440, 518829363, 459671689, 2241251144, 1295564083, 198257532}, - {3060089510, 3767525153, 1524537602, 493464086, 1472043510, 3020385367, 2373960485, 641738582}, - {2326580689, 675933614, 884790534, 1441212202, 62854709, 1586622145, 337933918, 106534431}, - {3507869150, 3602860791, 1458797176, 88195554, 717702406, 2258039207, 3110978212, 133681376}, - {712473541, 756874562, 3416163791, 3208511936, 3644626579, 2547902695, 3325507275, 502757995}, - {1399531059, 567606245, 2667525622, 2479231013, 2706338488, 1850625964, 1730422473, 756781990}, - {1690972462, 3319884643, 2662147254, 1338138163, 3001219639, 2880788337, 54659940, 451149226}, - {3703205063, 1746349340, 621341009, 670007788, 1446599915, 430938520, 1642990285, 578286421}, - {1714814633, 3940910729, 1826052679, 3479857199, 1470726107, 3882030171, 1050453602, 290318682}, - {1305680512, 2741545869, 3360323819, 3241661327, 3880682192, 3614120258, 698369802, 482896054}, - {3784416176, 3055328299, 599310350, 865953882, 531714558, 3245189532, 3694970420, 571581830}, - {674779390, 3051875043, 2243721812, 1970583415, 1332759222, 814816987, 3283900599, 99861440}, - {702694070, 1327443076, 1691951475, 1148430054, 1070842505, 2867159869, 1555778465, 3218353}, - {2390139095, 1705718610, 3639557823, 189154351, 1464350507, 2214503432, 3358953892, 698766753}, - {2219136925, 3940498260, 3249438609, 769465176, 983865597, 4258208269, 3033494813, 638685103}, - {1920347909, 3357418334, 4043129735, 4026029976, 2839949, 24881067, 394486129, 478866805}, - {4072794518, 4100371636, 1665066205, 4122816256, 1741252354, 2457476932, 2045411878, 219611787}, - {1908156039, 3623833604, 2533384152, 1682900079, 3851122178, 1141275795, 465452611, 419398832}, - {3305018847, 2351897039, 2081765783, 2280495775, 1414969592, 3263551610, 54853103, 101173981}, - {1029902547, 361327663, 373918337, 640324612, 4198729026, 3516470706, 875102320, 451679868}}; + {1330262067, 1207394309, 2844697848, 2167681869, 2187661106, 3165754010, 3670693358, 196484388}, + {2236392765, 600060750, 920367053, 4125622762, 428886165, 3752903772, 92553574, 608728004}, + {53079953, 2044994699, 1612837193, 3764112501, 921018970, 215015938, 4218629082, 313892139}, + {240632961, 2431092835, 2770597124, 2848675875, 19279134, 2161114546, 3258041613, 195237450}, + {1144444226, 1816524584, 1400436280, 1310534496, 3335237601, 672832907, 2619262577, 517424659}, + {4001299929, 24782803, 2915500963, 503076019, 1587499556, 1016033679, 4048754075, 703614866}, + {3870416371, 3500958645, 3196065382, 1787860069, 2653283160, 3975435483, 811024008, 619872398}, + {3257385449, 10709933, 3512509755, 1525391636, 393333600, 2625894693, 1001942429, 566742296}, + {2212264614, 2485795935, 2871857667, 4085934335, 3896342670, 67629647, 3021072388, 717653957}, + {1459682963, 2203507019, 783146303, 240296772, 3678756997, 534595114, 1364856586, 236470007}, + {159320223, 3066923011, 3905929927, 813751638, 1272105506, 2054561423, 558073897, 491148798}, + {354125696, 870160205, 2498994790, 2533361477, 2594002109, 2471904983, 3904457723, 247186446}, + {154016665, 347050547, 4150214044, 775724788, 808085303, 1489183822, 1909870203, 27059986}, + {972853074, 1813315419, 1218883667, 3914855854, 4270798551, 2493057338, 2578375822, 439202350}, + {376195724, 2511373605, 1225987496, 267171352, 1188726291, 2225914597, 3934663048, 763202568}, + {516164134, 4219992554, 748812227, 2633513342, 4219133415, 1671232764, 2259242475, 110959844}, + {1920450427, 1085278665, 4064798364, 3930912353, 3005811270, 1369983266, 4090712151, 390171389}, + {3188088228, 2633073243, 1132503960, 1491856560, 1530847088, 115748594, 248454518, 804888656}, + {764457179, 2602251903, 2106284557, 2531999946, 3447126725, 3070990175, 1649968581, 554065178}, + {1645305436, 2517441714, 80447348, 1055149976, 3222032642, 4049107922, 515266657, 686284948}, + {3108525115, 1952169072, 2988179707, 1092867311, 3539146673, 1227133614, 1396060956, 566905942}, + {1898939116, 361181927, 3337680016, 3050453578, 657871993, 3839721684, 2488117256, 770463329}, + {1030661856, 3250959640, 4098817638, 1328508594, 3911280090, 2003468409, 3112136565, 189270617}, + {302332641, 1486583472, 3601938499, 682617123, 4102868379, 3108200778, 4174515428, 441007099}, + {1429776541, 2322278664, 1963150721, 2926568443, 2731188573, 709744840, 1119993632, 770041417}, + {1617401597, 2258449853, 3538375956, 2852084751, 3021082981, 3801835429, 494811601, 134759927}, + {2371193840, 3523588452, 285262742, 707943575, 1335467882, 1823758325, 2514037136, 314698820}, + {4042844027, 1516042613, 1569764209, 3494627160, 1500404905, 1740680576, 1153051103, 357511930}, + {3547546351, 755259386, 3710266810, 167683086, 1589791606, 2013271621, 93754638, 25455560}, + {1735887853, 2031684974, 2757257258, 2005044953, 1824078570, 1584413084, 252861025, 533479878}, + {1440181371, 3402955917, 203588234, 4163770690, 545720855, 4170893597, 1073246220, 15778079}, + {2070200352, 3689652800, 1818973571, 2757568210, 655600433, 3731355331, 2142658411, 69626968}, + {259320585, 1029575889, 3428555912, 1840850479, 2240920968, 1307550458, 4109509704, 281799105}, + {3782106986, 3685894266, 4114719647, 89348843, 1542895027, 3733705869, 3692528823, 23538209}, + {801026714, 1610445083, 1972544505, 3067387081, 3031268174, 2419944180, 3558632564, 530767436}, + {2369575494, 3398002242, 3235964161, 3678244557, 3296910014, 3451423645, 3788417501, 370412107}, + {1578941607, 632422277, 1626410362, 746283811, 1457067576, 2498872370, 2474369124, 436432360}, + {2660336025, 129614971, 3128569213, 355957430, 4111558851, 2534982597, 4057856642, 648328734}, + {888901348, 3555078824, 746766713, 24541328, 4035866800, 1037620242, 90800467, 284850855}, + {2221491636, 3528804395, 3161215674, 2706304467, 3908039646, 2179579913, 3686643738, 311637562}, + {1867797487, 2390104913, 3947097245, 720127936, 3906743062, 3694596253, 680248757, 709035685}, + {944902977, 785134558, 2731605584, 1277565960, 3911439092, 2595800391, 820009005, 216709515}, + {3922104899, 2694011057, 3845262823, 2014754633, 2481027977, 3672224411, 345853385, 14027699}, + {318282882, 3005990165, 3318368609, 1405064701, 888227771, 1633057223, 3795555193, 110001398}, + {1252030505, 1510730744, 4262164225, 872221794, 2823867413, 1090799591, 865846185, 86876422}, + {3419732116, 143466471, 3846374892, 1466869364, 1142359350, 1629016503, 3037319135, 187456818}, + {2424300209, 2652881349, 855063117, 729564982, 3477904713, 2438727071, 3386878946, 384319861}, + {346392377, 3037166087, 3971769069, 1309527314, 23335737, 1184515570, 25131896, 662780359}, + {740417200, 1977795293, 1327849709, 762039685, 1202558175, 4224025570, 2986249505, 310285851}, + {3733533423, 353831281, 3249939540, 3506197874, 448208918, 3078472744, 804829244, 286032252}, + {739919545, 3664337679, 3835663909, 2286078749, 3774674816, 2856492400, 1775855762, 453250427}, + {3486338536, 2639357945, 2545898989, 4005908631, 2092803172, 2576973083, 4135351675, 791626014}, + {4151271088, 3901149876, 3936019577, 2488370525, 1942895942, 3337315606, 934590515, 713140378}, + {2805044120, 261048936, 1041641539, 2075596896, 3984919901, 1294021373, 1657626134, 170203795}, + {2684724033, 307299828, 3739463933, 2459954236, 670978081, 1082744070, 3456647196, 109587474}, + {1474701256, 2924412102, 2875054509, 4145340141, 1798353896, 2932260442, 940685862, 234727314}, + {971875683, 2590911298, 1469165255, 3819523328, 2232525082, 2345748391, 757801873, 207608628}, + {2938172150, 921509004, 1991408720, 1660920415, 3875783009, 3104339729, 1448942190, 27348821}, + {185962586, 4105692341, 1472112852, 4098195842, 2001439162, 1063691209, 2442116042, 226143900}, + {3306000283, 883749023, 2670799983, 2777520226, 1837751396, 1856942575, 3497661033, 170100509}, + {3866716700, 2142594000, 1940403183, 3439717096, 1073068309, 3339941021, 2760049735, 625293661}, + {2915080529, 4121382646, 3028302365, 2036697084, 393231289, 1230446883, 3748992904, 777504476}, + {140800889, 223502574, 3854300724, 1499250194, 2634166602, 1858999910, 2198861963, 790108400}, + {1789336627, 117895160, 1048063453, 2074825413, 2265113230, 3879124072, 728325453, 70637459}, + {4180169324, 3101307653, 3413665448, 3868382944, 658211966, 1088134741, 4123322806, 396523527}, + {379432149, 2328664365, 914632872, 930657939, 2664026988, 968143760, 1011536700, 150740396}, + {4268541977, 395004233, 3901436952, 3195235118, 560033136, 324442250, 4042968724, 792767957}, + {4004656386, 781098846, 2205305163, 1896393417, 2890138150, 2948465434, 4176958849, 13154496}, + {4180051580, 4038466158, 1488241507, 842061845, 3049161244, 1450353066, 1031332932, 721893459}, + {1338337258, 4128724225, 3131385798, 2694851331, 3960563323, 1567344004, 2716378165, 209995913}, + {1977586748, 1369217488, 3993922476, 1654039010, 1365048306, 531190693, 1700206681, 523429568}, + {3902579180, 4211229041, 1537618794, 326440714, 3364025195, 2655708210, 1684827156, 504120104}, + {4147550620, 3900026905, 2769028012, 3480874313, 3137012469, 2489117402, 3312732199, 703133481}, + {965932430, 3128188484, 1953219338, 2569919972, 2584584078, 1251338152, 277710855, 723174290}, + {3662708486, 3034676012, 2622857619, 960603012, 3400381362, 1361056719, 1360090013, 371512642}, + {2746906091, 1787379388, 644757631, 965650528, 3941573626, 4074847753, 2787115514, 24830907}, + {2520122033, 3188949118, 2119123548, 4036391145, 938169934, 1908438801, 3183726538, 422040098}, + {3203285805, 2089177748, 1144477911, 3620315382, 3282078902, 1438065600, 1405801350, 551420478}, + {2603088710, 576958186, 2056196588, 136802801, 3419733766, 3827548802, 1201569385, 140054794}, + {564491297, 1584640653, 968754236, 906979133, 1089597987, 2946573851, 35445107, 60108779}, + {3313604055, 3387700136, 1971945961, 2632433136, 219768805, 1593315812, 3654669834, 122052669}, + {623789567, 3836895393, 1955781388, 4291477883, 758807826, 2656627995, 1852710988, 296150998}, + {3333309712, 895974491, 1389041341, 1098083085, 849625960, 3009669299, 805824342, 491747099}, + {875941243, 2511444264, 1333673009, 238060557, 3486570256, 1045190315, 515344987, 236019924}, + {3643619504, 2641292512, 214149033, 1341365870, 1093028952, 1404618391, 298203407, 797717040}, + {523029266, 3391100520, 851724507, 1440696181, 184627942, 707164924, 2575628332, 540351717}, + {3179703921, 862273365, 56858079, 1690092364, 3278694368, 252793818, 4106403922, 44476669}, + {1212569959, 3818568155, 484560970, 1510853316, 294260483, 1502007204, 3320093261, 666452108}, + {934062377, 2407003997, 1214066170, 501806021, 3182407720, 3235809024, 2510266228, 56521921}, + {2083784377, 77878658, 4136395901, 2489917051, 3624581680, 1733942175, 1551661674, 321690486}, + {786966688, 2697456846, 3379331505, 1807542412, 3858723323, 3828666076, 3474596227, 218365795}, + {119533502, 1088695972, 222122133, 1550678528, 1768300836, 2059219593, 2784521270, 230517209}, + {2697852283, 440128251, 3276871261, 2100506592, 2999770993, 273966875, 4244671887, 702596255}, + {2005908548, 3148366366, 84399879, 3418487451, 1768348423, 17224085, 1119138655, 655057214}, + {3164772611, 925732270, 1130829410, 1088878014, 400645026, 3160089487, 619150531, 264468503}, + {1150112239, 3495716392, 1301896261, 2250404584, 2708940386, 3833336355, 3351948298, 203193309}, + {753070873, 3035264139, 1804078603, 106847361, 2976175793, 3519137472, 2581440294, 495516644}, + {1074853302, 998954174, 3330080271, 3777083835, 1835530787, 2720801436, 3012397029, 297905393}, + {1886891144, 2424931612, 2551113092, 3303144698, 2942507875, 1908701482, 1425160780, 624487016}, + {1289627605, 4250309010, 2506793608, 211178228, 3362564747, 3065104348, 2803894598, 488586134}, + {3879181343, 2834005232, 132016662, 1333093964, 3523637782, 2895951165, 1252191248, 146883521}, + {3724720605, 3192846523, 518546700, 3389476320, 3146530121, 1302946216, 855574855, 310687701}, + {4007267181, 1424328682, 2077312669, 3913839902, 2237388684, 3346948774, 1420848914, 696861578}, + {1267136763, 2148978483, 1231752222, 2311819084, 3669480908, 471870847, 2391468968, 183152219}, + {2463109525, 3598355614, 4071843556, 578903964, 351059323, 1943352876, 3257486299, 4725844}, + {1921664859, 3793506919, 3947266066, 1215083185, 2724347230, 471819002, 3136941013, 281957823}, + {1463492753, 2066557266, 2979063114, 3421110894, 152915634, 2864470612, 4138627762, 562591346}, + {2805736963, 4184074337, 4090997024, 3175282783, 3205779689, 2461074705, 3949780078, 208674984}, + {2083622720, 3107549669, 1199553748, 3604769017, 2297035340, 2527073324, 4117286202, 83220498}, + {3988312818, 3668370141, 438178640, 249469429, 2168370965, 725322364, 693129472, 228304554}, + {596762951, 2268436688, 1695516855, 4101869954, 3325908636, 1083714944, 2133818510, 365382086}, + {2675002495, 2674608476, 880912295, 107803139, 1864541509, 2992464116, 1087763300, 45921074}, + {2434415545, 2433901123, 3595496809, 1569035236, 2793780781, 2513113263, 3504311318, 497145121}, + {735114691, 2069874646, 2716907026, 1596662587, 2307687803, 299963400, 250979365, 409002032}, + {2233859655, 1396444301, 2649392204, 1475895247, 5658348, 2438889220, 2742581223, 316888158}, + {344463616, 823021251, 3838323174, 3987836226, 2005957815, 2410558011, 1564864351, 73717447}, + {2085665835, 1327199901, 370902248, 1413066762, 4107579345, 405586777, 4033339553, 484063036}, + {2761141565, 1948480554, 1727578466, 1563334827, 2293943059, 4180364835, 1072123632, 353834111}, + {2141791875, 4128529696, 1497439698, 3008198623, 3518891901, 3315474205, 22965393, 523857645}, + {749389192, 1676656516, 2765179388, 4036019798, 28885493, 4181021362, 3254909637, 97221854}, + {1760984869, 1105179710, 2316017149, 125148063, 1865024055, 1270464494, 2109898001, 604572077}, + {2374922074, 717320342, 3033464457, 2793014509, 3185262628, 2437508150, 2377897732, 595689119}, + {3292619500, 3197421045, 1457587766, 1546683143, 2189857192, 3222046471, 1804794081, 208832831}, + {3525730487, 3853655412, 4153892471, 814877585, 1880437341, 659671587, 4089464156, 779230234}, + {780926, 1787445940, 399202445, 3904397447, 3530363980, 2484471520, 1387039016, 41389004}, + {3316070948, 2666015506, 1753241389, 1248106609, 2595410087, 3923044587, 3935502059, 161610473}, + {128337305, 1204362932, 1699144368, 3268536820, 448659947, 3002057824, 4098854530, 774013210}, + {3268489612, 1069969477, 2359779864, 522411728, 274525547, 207893542, 988240959, 126392874}, + {2726959297, 200679582, 4235639908, 3161358667, 1606108279, 3054483102, 4222042180, 218716087}, + {4178653205, 2863756274, 2543593986, 320112393, 1086146668, 2709526773, 207889362, 126320009}, + {1025901945, 1101882040, 3707218906, 3301669537, 3776605729, 3690071372, 1109720624, 545962543}, + {1174965022, 4012996672, 3185909048, 4094141660, 16180519, 2588645966, 2619567723, 495919204}, + {609527160, 775355464, 293807170, 1559721580, 826233259, 3777696456, 4178390116, 804322433}, + {4292776515, 3156270919, 3553375520, 4261893484, 4056131527, 2777750474, 4034120010, 347595242}, + {3819420131, 2364908359, 59183402, 1547428694, 310830735, 2046970846, 2654514846, 533904512}, + {295825520, 3388314649, 928336257, 2552985387, 3871500862, 996238672, 2258450807, 474531371}, + {1391171714, 3383713466, 1170722798, 1357165169, 2927152308, 3415062151, 2169293048, 743064476}, + {499196558, 4202942761, 1397272647, 1890354869, 3765532154, 2029014415, 1019134619, 298198360}, + {1948231225, 2044968606, 2445039953, 3855963460, 3045839048, 1074631595, 1511921026, 173477793}, + {3517044664, 3487930379, 2696814161, 2826851323, 495198648, 2911822566, 296426785, 726014678}, + {3944868604, 381069237, 2065494055, 983667803, 3585671813, 2600384445, 2532627636, 653346753}, + {638209103, 1990859745, 2510770250, 2877360435, 3930879604, 3571109570, 1079712045, 532964931}, + {169690164, 4228736802, 2628502721, 1263948838, 2851375698, 821518475, 4048160451, 479215775}, + {2504556352, 1638069193, 1640477594, 1070310698, 3608341261, 2367945167, 3540594774, 674109433}, + {71639129, 3314081255, 783244373, 4197555510, 797929110, 2668561179, 1471257939, 247129730}, + {3213971006, 2106498753, 4157449884, 550245530, 1847074011, 1468737606, 667785441, 720680018}, + {3356891880, 1468005459, 3938072224, 3687687966, 1361649507, 1788691405, 375466333, 707008835}, + {3066970206, 1044525202, 587594118, 123187887, 3189494582, 150311547, 594901349, 790543409}, + {947531444, 1365222080, 885795481, 1284718379, 656141567, 120705438, 690320618, 527923192}, + {3960058750, 1803033875, 3067648250, 2502579101, 3294380864, 1183716779, 1647651941, 736686268}, + {1438593711, 2790895589, 4086771482, 3826122150, 320864388, 707113930, 2451419527, 201881924}, + {2527236867, 3332489089, 3409309658, 3470543839, 959886777, 821322772, 1676260679, 459302439}, + {773135051, 2814302716, 1084266266, 2428838044, 1928074383, 3154854494, 387486246, 129438169}, + {3696422303, 3967060489, 3645380362, 1870474368, 3510864436, 3083405535, 2972396041, 224873366}, + {701278291, 938379886, 4032315092, 785482753, 1646177130, 2772382317, 1756516848, 150035716}, + {195035168, 1403894473, 3728744180, 361963740, 1119105019, 868239668, 2075588564, 683426810}, + {3682410514, 3573981901, 2215419210, 120153020, 2705012345, 159735245, 3392443488, 459630702}, + {3005764733, 3941922384, 4278438048, 2671956769, 685954767, 1471293993, 1222063564, 248915177}, + {1394883434, 166802390, 2600085747, 646744597, 1278053420, 152923645, 2128260101, 147095204}, + {1244858570, 2574217615, 3327298125, 517653498, 1833562164, 161504267, 878006508, 792639947}, + {4188698458, 2383178841, 3547514963, 1523731901, 2607226173, 1743226027, 3121170880, 163447149}, + {1769681985, 3619550060, 2456707246, 1418970995, 2757768359, 3654676753, 99765615, 523611085}, + {2868145336, 358918023, 3775355654, 2868794424, 1892250037, 902651822, 3500965518, 404449367}, + {12916612, 595383684, 8285817, 2052220267, 630315572, 1985600745, 807539771, 551199101}, + {3453598067, 2803876529, 1256300247, 3689004550, 1309472264, 985296315, 841715124, 195717844}, + {3651778299, 809461699, 35344836, 1012348889, 3675154850, 1466693486, 3010660135, 615782600}, + {2064706005, 127214486, 1839402597, 1724852266, 4035514217, 2532194722, 3607899320, 312563920}, + {2985711730, 2712215337, 819735858, 3518062094, 2105724406, 2344299165, 203705310, 396980555}, + {2246709035, 1561281801, 2404218953, 4259888554, 1093419450, 2680435207, 1937122549, 679101521}, + {52222189, 1421731802, 1529476162, 2588577173, 2284656329, 3302663317, 3382879434, 247664581}, + {3664403591, 36845171, 1836746053, 1172185825, 1338006442, 3851936954, 109555781, 275367136}, + {2428240976, 2500958260, 1827406214, 93167565, 173267254, 2121417082, 1619196174, 635532219}, + {422106082, 1513754343, 2745045170, 3562586902, 433574946, 3356472951, 4019638088, 730312999}, + {1248140720, 2578998509, 1084503277, 3818423891, 3414438503, 3589460739, 309742182, 532875539}, + {2999797384, 3745697523, 188354240, 3862336931, 1192836167, 804727634, 2527858486, 179863772}, + {3961064144, 1065007485, 109092851, 1386590839, 3327018795, 1784229062, 229358365, 210030160}, + {851228459, 97452671, 2204676978, 3918632772, 1540568081, 385531132, 3332848215, 327880853}, + {2433236175, 2587444316, 3383370911, 2393608435, 2458468718, 2503099253, 3350629988, 214294931}, + {2864806677, 1072625978, 2754398980, 923106325, 3398265406, 2423199110, 4052241450, 559971953}, + {3123303170, 2688785774, 2754277761, 894184024, 3123683156, 567327956, 3840465899, 503939631}, + {3445886452, 1215169415, 3539536669, 997311819, 3673349136, 987570051, 2896647780, 109821452}, + {2969759053, 4196242930, 3702697286, 1697242491, 2795372346, 325082306, 74925710, 312237993}, + {2887796510, 1046738189, 97048710, 4219229480, 4104091389, 39953935, 1235245601, 157153225}, + {4154199630, 2072357306, 1821505650, 2097824746, 2246188972, 1756886344, 3193172617, 96594153}, + {252504825, 1019470811, 1107162546, 1380171615, 1775355240, 2218722312, 541942013, 98718894}, + {1825737476, 2196649146, 3248485689, 3739941946, 3970534668, 3121499224, 3418380770, 717748750}, + {1345435680, 132034669, 1250012100, 1755068730, 1072560949, 266722014, 4129394289, 686880977}, + {1819828131, 4002024008, 3120031751, 1387007228, 1738167771, 3103462109, 3346666620, 7414190}, + {3678790762, 2063351082, 553741994, 2217879304, 4282489303, 2209361138, 4085558525, 389228726}, + {4048918526, 3660811667, 3647489415, 1049395720, 3613410809, 3866636489, 2151570430, 306461823}, + {1736027767, 1770610244, 1091794100, 3946873944, 1835406227, 2845259869, 2323863104, 165869671}, + {2685147204, 4029708910, 734403558, 3327102243, 263981695, 1947750987, 3260712944, 144010666}, + {349806105, 3245397220, 4031231848, 3022873019, 3502076395, 767094306, 3560337978, 545082045}, + {1969798000, 1174706992, 1613401596, 2689110985, 1603206701, 2011924982, 229896492, 83798084}, + {1066018465, 1358344860, 518313548, 3267877569, 2056295838, 387871708, 1555329877, 699909433}, + {690348365, 678396614, 173392177, 453841936, 4266388499, 4088320545, 3837498970, 669961092}, + {2900969050, 3292150420, 3125045879, 214150500, 3328730655, 3254906935, 2089548925, 588882977}, + {1146081592, 382425218, 3055658941, 2978971454, 1288237848, 2306448720, 782612008, 339895633}, + {1347834790, 4044478904, 3161979484, 796493877, 1490619042, 1247707954, 3543083298, 87325576}, + {3434376553, 226332313, 994104242, 3285182218, 3654343216, 3074496659, 437337880, 788545636}, + {1840939955, 1792486838, 1847503925, 3044505873, 3398576332, 945294699, 606053308, 525908772}, + {3259770241, 2710185061, 10370018, 2008729145, 2642455026, 4002159914, 302696357, 725166554}, + {679557440, 2371585851, 4141929894, 3808864960, 478815240, 2865727974, 1000551884, 574490416}, + {3206872583, 2072986445, 2417630473, 860338029, 177702764, 2084401278, 4004005153, 31755171}, + {779734608, 834435491, 2017015323, 1832390217, 3726560354, 4159290163, 623592332, 22670100}, + {2266741859, 1309400559, 4226856976, 706277466, 315517231, 313688210, 3198826260, 451749749}, + {3354384445, 3897770680, 1515798829, 317547768, 2796143401, 2313136145, 3769172357, 564130810}, + {605006677, 1065920430, 1408703548, 3477793029, 425410526, 2812660783, 3033821520, 413407275}, + {2927042478, 233065097, 452264414, 3275476129, 724476460, 2554849457, 4154123658, 601739935}, + {2757872145, 4234735934, 455710199, 297023508, 2993632016, 2345667946, 2685392122, 660691928}, + {298594378, 3994713336, 1916420426, 1012851528, 698109232, 409055410, 2916903805, 200539688}, + {2430226552, 1380580136, 4002727762, 4217514151, 3131010614, 4183336321, 4110071926, 656052727}, + {2952655982, 3245755907, 3408227125, 3981758216, 2763821408, 902837996, 219350638, 522886003}, + {2019666269, 2276520520, 171025980, 4076582752, 2611573509, 1282346395, 3272565533, 397684220}, + {1511356803, 4277136418, 1742364247, 2426696604, 3862679872, 386467672, 2219964539, 478733691}, + {2963886746, 2364179459, 3119636926, 3651177967, 1182467154, 2796450883, 2584119235, 745691981}, + {509796486, 2886642325, 2150176961, 530223854, 1904248236, 2955313886, 1593427883, 387383679}, + {951200897, 644897517, 2580746726, 1505354663, 1276240800, 1558084171, 1429631784, 96033348}, + {3357743999, 1737171053, 4205835225, 658649686, 749011160, 3497151767, 2685716724, 496471095}, + {815399739, 733420343, 78091716, 2683097652, 2684185790, 3630302721, 26013558, 348392348}, + {133538700, 3443228316, 1197882151, 2766588475, 1339390662, 2338646431, 1611834636, 194726466}, + {1049274448, 1245944733, 2409540296, 1311874419, 1955798338, 2519636184, 2847383697, 285163237}, + {2231145527, 3057555561, 116249431, 1242006620, 3707365912, 1141261543, 1542563613, 376965355}, + {1474102938, 2967635536, 1963371145, 795815215, 3624624448, 251469631, 720732888, 101405368}, + {2850601775, 2616882280, 1905076033, 3950595071, 3092664935, 2643463128, 4218089642, 160939444}, + {2025032388, 2527130544, 618699295, 1744749688, 860983855, 3823562891, 1511255679, 289608898}, + {1643047128, 2224892637, 4140832335, 3416912096, 2383606649, 1869070411, 3094498703, 424015949}, + {167326075, 4167555927, 3283468511, 3106176896, 1382468148, 2524414677, 4024932804, 804611832}, + {1159515013, 4117616105, 2855841271, 700143165, 4209115036, 1548998411, 255269876, 269810464}, + {962466024, 770832886, 3246898225, 2992663505, 4162800315, 2821351486, 2739010882, 2308767}, + {779002297, 1183851856, 1010244634, 3148747988, 591195060, 1746844179, 3574483178, 63686446}, + {2818888960, 1343346109, 3397353126, 1965272892, 3946460734, 2060324851, 4003352299, 274597255}, + {2804012112, 1996488251, 986037138, 3299717369, 3771914502, 4038849606, 1186556961, 515254261}, + {3988169004, 3655286517, 4245684939, 3063104788, 33375810, 589779954, 3513506748, 619675110}, + {457161970, 3459273758, 4133244498, 395058067, 4034839019, 1633896374, 2561812333, 688421139}, + {3601110064, 4232946992, 3365885742, 1063183053, 1176403615, 2905558238, 1983786201, 756615346}, + {4021707523, 3301182374, 1909078934, 4173397936, 779920034, 3236174706, 2824517652, 172250826}, + {1113622473, 3156652079, 224492663, 1757769826, 4224941458, 4210113284, 2034555133, 653140252}, + {2717875771, 2134054202, 1722282363, 2083929310, 2637749641, 2423312198, 409106378, 540689545}, + {4111607423, 3968911619, 3383950365, 4189530661, 482054863, 1827861125, 1066603546, 317135549}, + {3643818482, 207329273, 1687396548, 1054395678, 3995838012, 2404825822, 2046160735, 532213738}, + {355629106, 1125175967, 2938603440, 2485220510, 2914923563, 1291225321, 2460049864, 230139490}, + {725507140, 3264718945, 888743583, 4171947266, 1767224523, 3697606153, 744675508, 339582444}, + {2225939408, 1233168727, 3598556150, 1968915204, 3084044638, 2568268314, 2767841367, 397981279}, + {3365212038, 23407550, 2831301576, 1097653640, 2632276740, 979348979, 1934527905, 429946218}, + {4221420821, 2137370197, 2467208121, 3057556570, 3232538971, 3445866312, 1105664064, 371595716}, + {2140985003, 3022698679, 1340339089, 2188407834, 1263953566, 3842625350, 3988466860, 73215067}, + {1964184184, 3004772271, 2744896389, 3810349731, 3911382186, 3897741947, 449077276, 569433979}, + {3195478929, 3690467905, 2670728513, 2765256168, 1048462495, 521961078, 1938722570, 161318399}, + {3380092185, 5395669, 752219373, 421162318, 724736851, 1885031107, 4203632901, 379312268}, + {3768066592, 500463803, 375905124, 58464289, 2251491040, 3706412950, 3430500981, 575571290}, + {3052208442, 836748385, 193247366, 4012727222, 1084911882, 4193352389, 1041033992, 450967865}, + {1954353264, 1892287262, 965890192, 4120510293, 3017254402, 2912968196, 1556889527, 390505751}, + {3713782630, 751252084, 4188578719, 3624826242, 1423521869, 4066446244, 3665873090, 382867166}, + {132930797, 2154106237, 1753176483, 2423050930, 1778842928, 3973568246, 2982016544, 11130617}, + {1593608995, 3268032315, 1976079095, 3241184855, 1142802690, 3593893828, 987581120, 265072884}, + {3003890903, 2276754493, 951066056, 1283969998, 3874590853, 2555561591, 741414504, 423695380}, + {714971473, 1367633076, 35902302, 2181462834, 4001592706, 2246674230, 293516994, 646239055}, + {2284226056, 2499985274, 1872280939, 332933152, 4227282115, 4029795618, 1013172300, 236077993}, + {872488968, 624941315, 334013825, 676424166, 3486349078, 639377454, 2265708837, 155233122}, + {1172077431, 1355579152, 1931656454, 586225747, 3900442234, 3049153356, 2855863433, 728229643}, + {510197454, 1892994262, 1292758945, 647563109, 1866786991, 3951561112, 1251102683, 807684689}, + {2681926855, 506530422, 228718767, 2168359360, 3254233996, 2330664767, 2324390383, 211407932}, + {3676223189, 2713369853, 1362060300, 218965545, 3865544417, 3552858513, 1658475908, 565216213}, + {675743212, 593330518, 372539933, 1649498799, 1628134551, 4103662413, 1538909583, 421748862}, + {1410932492, 4293559954, 350155918, 4215117434, 489981393, 3822178983, 4033278100, 92294599}, + {2585916343, 1557854816, 3791874688, 1081958831, 1055418553, 374233687, 3926054884, 717553561}, + {2310639036, 3605058079, 643461529, 1490569198, 3279578582, 2061783791, 3281600767, 105951649}, + {1723587698, 449842012, 736698169, 2562165485, 2451050908, 1014525201, 1944872671, 312727246}, + {1778438825, 3591263034, 1933359147, 2712656031, 474766075, 1753256309, 2956210560, 266859485}, + {2394662223, 1966286998, 880830705, 4002371297, 114190614, 3518855043, 2759009812, 50827975}, + {810185173, 3626967324, 85770978, 403507819, 2356281767, 2666885194, 2722703605, 580213764}, + {4062664323, 61685585, 1736587719, 351716866, 2656638990, 641836884, 4001483418, 45007516}, + {2456744997, 4189943500, 4214883274, 3691644522, 1390181836, 327020425, 2590163230, 63784911}, + {1287772193, 1341991261, 2824192963, 910743282, 4145938605, 3815902104, 1771153197, 600929104}, + {3691453272, 3457041411, 1375897923, 4185819929, 3164614873, 4284255723, 2548220529, 544791914}, + {4161394301, 533530570, 1034031398, 3985064819, 1687680383, 2466823896, 2735126626, 187021819}, + {1571753132, 1726221600, 1657076767, 3948592976, 2577610095, 464935736, 4012150682, 290996128}, + {804870194, 648954819, 2968468060, 386642337, 1057715462, 3051238094, 2135546666, 181705880}, + {1192401836, 872163552, 69506954, 413622746, 119793233, 2549762860, 2098636152, 386641493}, + {3610674308, 4157466786, 1709818061, 1004321014, 2173483597, 58947844, 1589175259, 315087414}, + {1276718605, 1443596321, 3996552418, 720579619, 3156399317, 3038813559, 831976413, 487160715}, + {4215033339, 3129456676, 3948884923, 2722267607, 4249832930, 820296611, 3962766631, 266299584}, + {2790366916, 3706270050, 880085956, 1819462370, 3350338899, 1604323458, 1307278582, 84307103}, + {3682240495, 3863452946, 1269380345, 1003807717, 2786048481, 787149355, 4204610885, 136178492}, + {2527962326, 3326875340, 2419307186, 1966160476, 134324786, 3787850393, 3470441507, 200461135}, + {1900223398, 2958602883, 2809645681, 2057576588, 2704931960, 2479448755, 3977199129, 513627299}, + {3115260245, 3354093366, 629840826, 3078278066, 578543096, 510615478, 1818265600, 484382958}, + {1248533524, 1061553272, 1599659758, 3754696920, 4011076518, 1295241470, 1348924452, 741312025}, + {2989490590, 2886671686, 547646883, 2206240563, 2509608152, 3205191733, 3320578170, 529124755}, + {1129096308, 3102604442, 550260408, 3546408617, 3543652781, 3836933085, 3510402490, 313690302}, + {1939908362, 1036365100, 1653386560, 1136796576, 3347359464, 4143674226, 1976615652, 483912970}, + {2237244677, 1183446919, 4139773740, 1632160798, 317797814, 782299691, 53691510, 657918814}, + {2403708246, 2662665151, 4018132778, 2209483570, 2162195451, 4172438400, 1161346828, 799675123}, + {1750655346, 3497712890, 1112049640, 762253305, 277178884, 2071509061, 100749983, 736813486}, + {1812055860, 1675617842, 4180644893, 2432142884, 1034383680, 850425811, 1943567607, 480775121}, + {4275171627, 2361217690, 1270913769, 273763680, 1447514595, 3801713639, 3759789909, 594644758}, + {331600042, 73063957, 1942309435, 505255189, 3646885546, 952500636, 3837312797, 310731158}, + {3716493733, 1521596418, 1078166906, 993736884, 390386406, 831816420, 2185183722, 751280681}, + {518339000, 919957869, 2724724401, 3504438143, 2849095407, 3058186957, 1119795731, 668536683}, + {1170139575, 817794443, 3929635143, 3600779060, 2810351180, 3202518018, 2732102805, 620257815}, + {1121017473, 400118136, 3172482892, 892381065, 4198290974, 2082354122, 3134534518, 217909859}, + {3372466964, 3467017834, 1346651557, 4183681104, 774677594, 1175277379, 1319239393, 811089645}, + {1605322745, 2679666229, 3841961975, 2844382092, 2237432255, 2935047203, 1001546451, 64145355}, + {3148894061, 215438335, 4034314872, 32238219, 3061717187, 4062382703, 1486433218, 693843247}, + {3488016943, 3492787924, 2725456882, 4098088363, 386495863, 1313509568, 3954529668, 674365692}, + {3138649581, 1875106549, 1765249181, 2043325079, 1203915360, 2995858917, 616298625, 636928007}, + {2737142369, 750780467, 964776702, 2310154466, 3056419225, 1418915156, 3713042034, 589704267}, + {3986630172, 2309817482, 1287681278, 898355267, 168551053, 1949785585, 3201478163, 801328333}, + {2885793198, 2278968119, 1301180560, 3464691799, 2868584744, 3807209921, 1694893769, 739430305}, + {1832776994, 4104911102, 977383285, 2535074223, 1441615821, 1370582355, 1237984088, 518629740}, + {3323545082, 4138048802, 4041224476, 3380822835, 3699978107, 2375624563, 2388741221, 704299699}, + {69128115, 803645360, 2489774673, 2434490723, 317629302, 3166666162, 1414789122, 98090834}, + {3946636122, 3036542976, 3302209290, 347851614, 3048928811, 3299227404, 3104369174, 270173448}, + {1768214892, 3888077437, 3712029887, 4227403317, 3650534800, 220922111, 950439183, 350793561}, + {3644746425, 2200003089, 218570492, 3947405808, 542822097, 4139331575, 2440941095, 587312899}, + {3478735086, 1597550086, 2515934575, 447995949, 3987803196, 3023330449, 82564944, 557024975}, + {2450770955, 792954409, 2757841985, 4239549994, 4186078392, 2896867494, 3576079166, 725131054}, + {1470260439, 2609810289, 999886265, 1887783355, 2992947493, 1302183302, 344770932, 377552425}, + {2187994006, 2220751541, 4258505651, 3559529845, 1575830161, 2786652545, 3484209424, 14060743}, + {3505581419, 4080875179, 706905611, 1386387089, 1827414353, 2603676171, 3676950120, 89544108}, + {3888559813, 3241691713, 2773466404, 42318244, 857776865, 1385703397, 2010331446, 314753410}, + {1667125776, 2081470638, 1259654721, 567125151, 3314955806, 2429050892, 4228521613, 513406385}, + {3073905813, 2473666072, 3333347485, 2361385077, 4238763952, 3243692137, 1961796422, 267163398}, + {2314898768, 1901787205, 829125693, 1189547500, 4271214712, 455213014, 1603194468, 293140184}, + {4067824989, 1571617390, 1684055161, 2582713996, 3519633251, 2196346570, 2846271164, 559644633}, + {741606131, 1928019484, 3824078151, 1558499084, 1306258575, 1034665058, 787464085, 180211688}, + {3807096105, 928948041, 3944653980, 2607316894, 3055630141, 416285422, 1943750845, 544204096}, + {2425787067, 80440213, 463069512, 2954374324, 549604458, 3549535221, 3739529852, 146601344}, + {3691448885, 3826252058, 2005854246, 3182565549, 1759149175, 394926512, 2506026070, 60668733}, + {3216736757, 901707627, 1974077181, 3788998913, 1145831891, 18348452, 4022608911, 612676761}, + {3474371110, 2948307670, 373730209, 3030531967, 2497168141, 973357639, 3262075997, 100785675}, + {1384076787, 3770729714, 820095105, 1331363815, 2483402000, 3671940900, 3796649111, 755347757}, + {3749707224, 3280484823, 1993421256, 3387705604, 353978768, 815151894, 4139985137, 204324104}, + {3816219516, 96922150, 785310900, 846671977, 3399462516, 1636565448, 700656150, 328814335}, + {4086290675, 3733678787, 1742268131, 2082290702, 1264584521, 4030781879, 3998510331, 539389279}, + {3689405638, 3212260918, 1888370681, 3804379787, 712491701, 2676352869, 955344580, 734223092}, + {3696149374, 2190395762, 3144916762, 3239032866, 1744389540, 4020131838, 665297182, 222772635}, + {2169372292, 2292188349, 1037234022, 2643384714, 816199653, 2412593885, 1244764036, 176523182}, + {507587802, 2820124265, 1119990414, 3265317696, 3405993345, 2059722418, 430015989, 114073575}, + {1094230950, 4157729821, 2904569963, 1482359426, 3198679981, 1470443078, 4209652801, 157441872}, + {3772238076, 1147079907, 744826116, 4136570393, 478859352, 104426603, 4147857107, 660475856}, + {4243578283, 1605371363, 1039440365, 2114203010, 3488975910, 4053502433, 3172314836, 289659254}, + {1508511032, 977940460, 1650212273, 1636120605, 546697770, 2383035770, 1795867773, 260074588}, + {3169929275, 501605714, 1472110329, 751367535, 1823709191, 3895451095, 164910237, 663512978}, + {651230880, 2931052873, 4194373884, 1534404620, 86425363, 1097784862, 976282847, 34459579}, + {3954962656, 3706448192, 545578702, 346303497, 3996775507, 831617768, 3333969375, 394857317}, + {2213505532, 3629128277, 231124057, 991471210, 2754501912, 2633246233, 467157282, 669315169}, + {2633272819, 3914036813, 3873986418, 1160213734, 2609963064, 2670131233, 150768436, 555089904}, + {1525651196, 1781758622, 519778254, 3993050391, 3109201010, 638652415, 2977953139, 679458768}, + {1997649816, 2292918445, 1301538791, 2887025496, 971710371, 2671502692, 2735687302, 66929772}, + {1620667409, 3433869219, 2487493046, 1131443924, 3456230220, 1373786806, 2550435831, 478500070}, + {4250444598, 1446723407, 1785465338, 2091298378, 2409679592, 1088450226, 1614474, 529794415}, + {2272314769, 2266813597, 2359163678, 4094218215, 131645830, 869457345, 3232563163, 666106658}, + {894190519, 2684676255, 1416932906, 1190749326, 288270855, 2520389876, 349167282, 412759125}, + {248073384, 3315950827, 17935891, 1066417855, 2125003088, 674711347, 3209266074, 461188859}, + {4035495892, 231180803, 3343362979, 3142547617, 476647791, 211084348, 67276399, 159861623}, + {1149536807, 2293352275, 2371561359, 3363800157, 803712569, 2388656937, 2184601571, 258499723}, + {958563539, 340752544, 2833302361, 787978783, 2372763317, 1078533202, 4166875024, 643248593}, + {3311224958, 2104808919, 2110122541, 2052242762, 636921250, 3725990088, 2843800811, 193141382}, + {2143960517, 2487062453, 2510786670, 3075909241, 260568442, 2416858819, 3201271850, 461176201}, + {92207185, 3532115770, 2021356893, 844678439, 3652574528, 2758489489, 1642700280, 267384837}, + {2654884501, 3455136742, 702355926, 60890658, 1884585317, 3656096166, 2471747592, 190987902}, + {89322456, 560420568, 2422830881, 1569753026, 2921474166, 1628559677, 3508680013, 39018919}, + {3115255519, 144450629, 604428070, 1015791094, 3142513407, 1487669409, 1709839352, 651576059}, + {194255373, 1085781321, 3153903415, 3676302268, 1419076165, 2968790835, 2604387151, 231311237}, + {1177701258, 179013792, 1659627232, 152081700, 2601054637, 4145478048, 3721124439, 798065976}, + {1416027218, 416602981, 2650246612, 346986280, 2716448134, 2720665603, 3463395423, 261497993}, + {2616817337, 578908755, 2249858224, 3684008765, 3693723516, 2940606058, 3433020571, 736618684}, + {2071998103, 2128754790, 320841164, 2432521489, 319434478, 194268736, 630290264, 702614386}, + {1565307401, 997038380, 1295664681, 3735147853, 2285182874, 131952452, 3142623174, 585442901}, + {4142153362, 1183552429, 3344041768, 239333212, 3244266632, 1096379016, 621482871, 529539844}, + {275166408, 1042937707, 446544065, 2236399738, 3959134158, 208001923, 4024393225, 355965466}, + {307542586, 561233673, 587983390, 3985237480, 1662574573, 2743431028, 2996951157, 43993447}, + {116827723, 409109840, 1426647335, 1448033120, 3779462594, 2210314188, 859028893, 535141816}, + {926060521, 1551170931, 2289235231, 1972418854, 4239529451, 1153932000, 2208000610, 517534755}, + {1579637732, 1577159760, 2336920794, 2638869537, 1316284715, 183121741, 1689616035, 585985598}, + {4022470346, 2879656272, 4171550044, 676829527, 3143096, 3399753089, 1460728513, 575063608}, + {985117820, 2241851389, 3577568725, 944168127, 471310508, 2165049269, 1746310322, 396033423}, + {9960129, 610450187, 2646513356, 2997856639, 4836019, 1753032075, 233988536, 99967401}, + {1652621128, 4091654986, 1389144413, 1454941712, 462562743, 1447802876, 1244836172, 348634434}, + {4170784370, 3444520145, 686127044, 3870362917, 1141630870, 2893352754, 443632340, 783781260}, + {1633864189, 1211469352, 3104081006, 48582396, 3195946054, 596549108, 1643594050, 687353540}, + {2697698040, 3479863243, 2917953816, 3662345504, 1466775360, 371707515, 2722091740, 668197629}, + {2356201866, 222010597, 1360513161, 3437534657, 62803326, 1654835645, 2431652721, 669762646}, + {3544259652, 700814791, 1939993548, 926671646, 4025998850, 2700902903, 2043552972, 140088536}, + {3566836136, 2583292447, 3484294042, 4250157858, 424726046, 1005555754, 2762540252, 206036974}, + {3886949344, 3838751379, 673715856, 248100748, 1902886059, 3876807314, 522553156, 518703453}, + {3542970197, 520739798, 3997859094, 2349638040, 3435088756, 1347471640, 4221236308, 229339138}, + {2724596761, 2549292978, 1162216813, 1466745878, 1438280148, 100574226, 479252506, 731213597}, + {2861906120, 2540557332, 2550741961, 1181220352, 1033229670, 93133363, 3244443139, 117265934}, + {2320174544, 4216715978, 1724524546, 2346997821, 2929077982, 1561896092, 1714823733, 411347142}, + {2185412226, 3432278492, 4083422170, 3577085242, 3823662147, 3537971599, 2423614826, 668013764}, + {656187204, 3640289486, 1796420575, 1167286596, 4145228032, 2195839137, 4274144347, 430697672}, + {2161960828, 3664079303, 4272053314, 3502004706, 723047422, 2999989644, 1670411424, 153206104}, + {4112707427, 5560382, 990524805, 3375028135, 1304844289, 2387294208, 3273515688, 594227631}, + {311056107, 1105657091, 3183014616, 977043937, 960490263, 2260386039, 4200123855, 624400764}, + {277633862, 2329991215, 3548798743, 1137201717, 2470062221, 1493702912, 922261071, 103553029}, + {1939385053, 4109637736, 2633917528, 3325675626, 158415035, 349044679, 2517064767, 476824856}, + {2522003134, 4084646891, 4041119142, 1046264701, 1412087751, 1382291, 1310874988, 81423054}, + {898096198, 2663736544, 515246455, 2001838593, 2766916104, 3666320304, 3129087876, 359436882}, + {2568717151, 235493253, 2756330994, 3652539481, 2310243907, 1253176022, 109948087, 724782483}, + {885302032, 4187801304, 3441979317, 302507076, 242377188, 3682426690, 763161657, 762226953}, + {1374721229, 3065641777, 3981949233, 3969350043, 515841856, 1289798961, 3109538070, 198478350}, + {615887801, 2087709618, 891080510, 1442393823, 3308233714, 1207717909, 2100270836, 97013161}, + {733399971, 1086174531, 1708349098, 3286045324, 243165511, 3487391580, 527485107, 357897247}, + {4274757937, 2004459618, 2207640791, 2034702757, 2281448004, 1337413693, 1723418461, 567026300}, + {3760397945, 1805119069, 2935826602, 2873766270, 1465431552, 2280134567, 3017401994, 749348439}, + {845294654, 1919639349, 273971500, 562719309, 3407536851, 3603898173, 864808476, 129250057}, + {2427688850, 2086826480, 2188016106, 1919858649, 3196819956, 2676664096, 2412852163, 68375082}, + {3282114902, 2675619606, 4256410794, 2742243794, 2363536671, 873156091, 2828721875, 640642305}, + {3552539788, 4203785215, 3734386830, 799475980, 81819022, 2025547610, 4007895353, 550186160}, + {2339606426, 1912309251, 689636574, 3217946686, 852056651, 3126913241, 1600748603, 449894712}, + {881667538, 400844323, 151379282, 1053679732, 1808612401, 1346310114, 1505629000, 302793792}, + {532601299, 2631783040, 4213230072, 1461361965, 1296114499, 4139052660, 2300811467, 505757433}, + {3079745223, 1894258048, 3502181918, 2469999561, 336158991, 2610479246, 2439976791, 260324930}, + {2685248269, 2065247282, 3893658343, 404488947, 879913018, 2769589789, 3203576221, 728797071}, + {1114898555, 489525251, 2282461132, 763551989, 4111632688, 1560237037, 2677510533, 744112106}, + {3351325731, 2873517271, 1449794532, 1393997294, 3335079391, 3985012282, 119374276, 250763578}, + {1276646444, 3866405550, 2507513705, 3245282417, 2388712727, 3089888217, 3153658815, 408207724}, + {1112608327, 3821391782, 3795169194, 1828742135, 3633850657, 4110829380, 234596865, 741166368}, + {3360935571, 4107509814, 1650826452, 1299220335, 2190651648, 1005254712, 3465089782, 779887086}, + {3812023910, 312041235, 2350859061, 239325723, 2953051835, 3261402462, 2782545329, 802427606}, + {1126201548, 829826423, 3224204870, 371676578, 2651861742, 2316301718, 455452123, 352463212}, + {1778923303, 1829169405, 2559589269, 3016469133, 2981957161, 1431085288, 2680965465, 571864354}, + {2153974693, 3461482280, 258080814, 2138529357, 1979921555, 665497545, 2943692560, 556387289}, + {84583323, 3976071021, 3448631281, 3856136049, 4051641614, 2483054893, 2252526777, 31701584}, + {3581605069, 2708030465, 3662123183, 3786156422, 1613687543, 3758823741, 2487052118, 635999440}, + {4166713529, 616491546, 2355625476, 1879118502, 1111297523, 156579181, 1636579830, 345894682}, + {2555339489, 1773400316, 575624083, 778391108, 1094338133, 3336392532, 1408389922, 442583081}, + {3609679708, 3979606358, 2634772699, 3985025776, 532162603, 1421210395, 3437426208, 28864984}, + {4127123042, 3806827026, 3598581784, 896385894, 1916458458, 98031265, 2756740464, 164428156}, + {1577271216, 539090815, 3659052407, 2771632165, 1407032503, 491592204, 2009327826, 701656462}, + {3821300661, 246953290, 3453170403, 3211265529, 1660993220, 139084352, 1565936144, 758210986}, + {2025656907, 3336743490, 824049510, 1789034001, 1386660594, 551596089, 493210020, 581173895}, + {4087906274, 3763115060, 1801039417, 984575072, 2396049500, 1285478602, 4289381865, 575745658}, + {2776279723, 2155293082, 3387282347, 867450718, 3238359235, 2240841015, 2603818669, 156904659}, + {2137307005, 2134067008, 4140546049, 1503079005, 56775257, 3309341409, 1908470794, 332956117}, + {4183639806, 1136375369, 3323066512, 3700639388, 3015314583, 1688653406, 2966185402, 143554130}, + {1915001446, 898315125, 2122191569, 3506067640, 2117606597, 1399769880, 1086592032, 110499400}, + {3033385322, 205776104, 1440968529, 2846314038, 2593008680, 2518135092, 821956848, 343027884}, + {1330750473, 395197693, 2325809239, 1798581894, 2317842346, 1942788945, 2096836062, 254224318}, + {4127334572, 2423652509, 2692011235, 1937701750, 4263073062, 1780782636, 1007946074, 647245253}, + {195815482, 1361670382, 3530408805, 2794501391, 1471310294, 3244449008, 1049765291, 768385569}, + {324422373, 3135196537, 2589429535, 1484623234, 3974146233, 2114095773, 3634906156, 666058382}, + {760090452, 2840536639, 3011013913, 2460758771, 2042385615, 1469332620, 2018004538, 575440979}, + {2327570671, 2979198184, 3882181790, 2205792496, 2253448087, 3264095082, 314398660, 41291634}, + {1747703126, 958281433, 3243573183, 3537797551, 2070489385, 1623411891, 1927973215, 167298620}, + {656409128, 2742109338, 3233037711, 3777322804, 3133864117, 2941082770, 3138885075, 717974464}, + {429392227, 3887280359, 3246335816, 568825366, 1069663448, 1624635910, 2766027437, 102788406}, + {1687484087, 3591964010, 164633699, 4172306694, 2984539738, 113252901, 3123695641, 709708882}, + {775066284, 3555074125, 3672709342, 2379321398, 493785861, 3005226950, 2750077896, 376834946}, + {385408610, 2171422476, 1991283302, 2911723824, 1629926076, 1311090149, 4284183675, 308868757}, + {874025231, 4038370925, 3374518472, 3861357383, 3997204032, 805917401, 351882908, 679796827}, + {278761538, 2843984688, 4066153872, 942383760, 3739112655, 187654793, 3569152839, 492505805}, + {871177155, 282432483, 2678200678, 2281956281, 171214179, 2272190898, 1317678958, 303746193}, + {3368276837, 3248421532, 921441902, 1959688532, 4048084074, 1708425820, 3063758528, 364044494}, + {4013570096, 362150249, 294034787, 252511367, 3527439986, 2402231895, 3720342931, 504460098}, + {78214709, 3618862961, 1940508678, 758866751, 2535303999, 993153571, 2265331908, 757259764}, + {13186235, 3716178427, 997222573, 2361415571, 2185852701, 1138431711, 4253836696, 372571330}, + {1210881594, 3550108450, 3273631320, 4115754484, 1260229344, 2125676691, 1660016793, 736000118}, + {3703267094, 966671435, 3767769475, 1749930422, 851889483, 1162259122, 2600013392, 49965082}, + {204965223, 1205321086, 3501702655, 2674309569, 1128234257, 2210211673, 814905723, 603557667}, + {4116795789, 1263121618, 35206747, 2643737091, 3631189448, 2522726033, 1618475315, 271108188}, + {3725616922, 3916144795, 2102374220, 1589495815, 2033610587, 2118847258, 4241947822, 255634864}, + {601259917, 2936740526, 451103116, 205264142, 2420574336, 1608193939, 2357941778, 527177578}, + {3336161976, 1129214769, 2836104630, 3677956054, 736457168, 3694253178, 365535440, 23270442}, + {1581129024, 2045312647, 4057577449, 553169274, 82780950, 158900772, 3396715882, 280410655}, + {313165698, 1697175152, 3468455948, 1363031373, 660554249, 1753296245, 4050401147, 178406164}, + {3035487732, 465749091, 3559276843, 3212344518, 3449701688, 1238944587, 1114286490, 110047779}, + {1997139884, 498938945, 1362257914, 2855238312, 3723773064, 90440409, 3549934085, 387586393}, + {445142895, 1088339601, 4209186751, 473673684, 2279992221, 2463799276, 3314345148, 430614134}, + {4248467798, 1489867784, 1965727342, 2862922152, 84931137, 1074946672, 3743436199, 164359740}, + {3685461009, 3449685895, 1769465781, 2014393022, 2798836757, 205163864, 4157356532, 39894875}, + {1798742197, 3693902068, 2082913271, 1901635749, 2668674174, 2832493555, 4108433058, 105317831}, + {2427606883, 2587928788, 2164428858, 1051751481, 2852524954, 809660872, 4264971241, 545255433}, + {3168202072, 3813349032, 1649333944, 3268078354, 3158849906, 3222505651, 3044654169, 369628406}, + {2787895213, 1696055532, 2889225041, 95594431, 1463384643, 3757600343, 384995890, 763920495}, + {1169861558, 3762044300, 3826560455, 2182866262, 3921206107, 2949650513, 2012148372, 518570787}, + {4109306864, 647502730, 3946581369, 3074864639, 3963688321, 1898396593, 675442952, 506036843}, + {4279003776, 2950157204, 3145826104, 2620320724, 814551323, 457802341, 4109955377, 552150909}, + {162955572, 4002559367, 3580317170, 2084102035, 3347426977, 3552278901, 4064734813, 340643620}, + {1812759048, 1319700056, 2882676157, 3395867304, 3445522112, 1968041395, 3188169000, 606009874}, + {1270089613, 4276572412, 1817927736, 265720226, 247424563, 1591282536, 516694970, 273590067}, + {2018552281, 2580379225, 3595495704, 333621885, 246019899, 2806896448, 2206681231, 493261282}, + {2334124211, 226626457, 745895009, 266955925, 2780428600, 367332120, 2194158854, 426933972}, + {2581447320, 708405147, 1316310560, 2656507644, 461335602, 2443559010, 2165765051, 106292264}, + {828698101, 396587234, 2547112696, 3033103660, 369346556, 2875708204, 3992366671, 433071229}, + {974286627, 1698788584, 2105525928, 2779831737, 4020858871, 347833376, 530124756, 379246647}, + {3886112973, 2666436835, 2948746053, 1685230333, 3617699335, 1230561571, 2443108684, 438607203}, + {3763234566, 2725149249, 1113567889, 3879778476, 2751059715, 2414966394, 3635356376, 774977564}, + {3626715201, 3006856655, 3158746080, 1708650104, 875701331, 824986228, 2048793056, 5394001}, + {693459225, 1540892142, 2436148947, 2731682591, 3877023980, 3079542142, 178335729, 56704808}, + {2302355390, 4085831701, 1222277508, 1592428257, 3775348833, 3189506425, 3931761448, 341497402}, + {508066495, 3685410466, 326489180, 3521038034, 4171878980, 3389934487, 1033291248, 602432060}, + {799900668, 2070513283, 803709668, 864755181, 1573015671, 435448468, 3837429565, 545968589}, + {3047694565, 3426302689, 34512000, 2816478275, 1975785337, 90826622, 3845854614, 537823478}, + {424539897, 1775703610, 2013866481, 3565121371, 1619206396, 3177394702, 1438169486, 405713988}, + {2491441137, 3779406653, 1974090771, 3735662257, 1729680976, 752843224, 4585998, 250194618}, + {3809201108, 1111496635, 920755055, 1027253619, 1849135936, 744540703, 2096763431, 663016089}, + {1607968962, 704062074, 1581129890, 272386385, 3501983830, 2698905738, 4130025312, 233076338}, + {1825976965, 3536704463, 3025986331, 3961576547, 2686224577, 2335383839, 447512210, 559531891}, + {1107295997, 2846545959, 4063919601, 309602014, 1035285005, 3839570946, 275262418, 10279447}, + {681611296, 4010543388, 512792588, 1240476998, 2766253860, 2052165422, 2997264067, 172381951}, + {203330309, 1683010863, 3813227535, 365393831, 813084488, 1112789536, 820217509, 718695109}, + {119134312, 61738119, 1812190527, 1857564674, 1449056247, 385360603, 1068000165, 441454560}, + {2926474969, 1186288231, 277409315, 2491060801, 2364111862, 2500678757, 386594822, 32296030}, + {611343149, 826974031, 3637802891, 4052369716, 1542615659, 2875171305, 2319092738, 381404116}, + {731150389, 795779127, 2699462289, 1264036757, 868083424, 274496097, 1504298712, 95609898}, + {2603965696, 3141162794, 1691290222, 3075806243, 3876937718, 837997671, 2578922525, 648717171}, + {3959116008, 582553693, 192055460, 427460001, 3039675266, 1515045673, 169737361, 129722943}, + {3476596291, 3611798177, 1157647641, 1468442504, 907946330, 1035322479, 3685199321, 571051150}, + {2258759912, 2400303621, 3904734730, 2648813095, 751662485, 1398528952, 481926753, 522852190}, + {2079627616, 1372595899, 802383695, 2954983093, 1676013714, 2574811163, 2418946613, 493885514}, + {3052376563, 2976367287, 637359989, 286938342, 3409195553, 1983135602, 1750865263, 227433269}, + {1522091442, 1820479890, 1566892445, 986869248, 729321487, 315731997, 1867892644, 23792377}, + {649127087, 2548047390, 2555226628, 2155706922, 3836110859, 885816708, 2534817418, 52934958}, + {3379419208, 1132819251, 1470288217, 810099582, 1001465618, 1723122153, 81075427, 39038119}, + {4164438879, 2413492695, 3780067260, 519055459, 3955110830, 3083666637, 391534204, 696322855}, + {3651118953, 252790678, 1493000083, 2023900121, 3204471394, 2845275328, 925152584, 388210575}, + {3605425591, 1055685848, 3129228151, 1175762359, 3181523894, 444870392, 1048053365, 413327808}, + {1014695068, 1705615360, 3822565661, 1404552176, 962781197, 3327985676, 664351722, 408140017}, + {2063084639, 1508331293, 1396858808, 776206050, 3450130356, 4271884006, 1810842652, 640424123}, + {1438411124, 740833875, 1693215831, 3161427002, 1122705730, 2638522624, 3561773506, 198679801}, + {296130865, 2978607706, 138147386, 2559341105, 1263769395, 2302264666, 2508633176, 184620450}, + {1890131728, 1168886537, 1816838571, 1735311653, 387578650, 1772520323, 501310350, 483828978}, + {3569508746, 2537178669, 2984037821, 3671076112, 2997796227, 3318328286, 3216619150, 5211888}, + {4072541812, 3661716168, 2789312853, 2418586792, 1408856195, 1801733487, 2443185670, 55052251}, + {3486805571, 811459273, 2980532443, 3956585641, 3837098762, 3307538874, 2022039959, 785591199}, + {1984282435, 3796275586, 3402719192, 1106115384, 3066630638, 3333723383, 638470602, 680580995}, + {2849080487, 2906628608, 155067543, 2570089426, 3578296942, 1571939168, 593729942, 453671587}, + {239851662, 2461545664, 1296764477, 2883887988, 1495072670, 2168437346, 2898982058, 56687910}, + {214787773, 1255078312, 2500351671, 371894427, 3649681450, 462856665, 1606932396, 651931468}, + {3148730503, 654704247, 1383074816, 1938281512, 2516030254, 3440087847, 2558559988, 444197695}, + {586629258, 1009693748, 1267844613, 2491726027, 3727317303, 3450807892, 753509074, 228037171}, + {1854954782, 4155633724, 692863961, 4265004431, 3107571065, 3406678105, 356201799, 428522696}, + {1897260625, 1505096433, 300345784, 3718725735, 3184350282, 3953302202, 4103757207, 228406442}, + {240923956, 4187900405, 1176227451, 655313853, 1298034605, 294812393, 4084347356, 27114979}, + {174051420, 2366123608, 51201874, 513275878, 3514388253, 1498434102, 2699371474, 746195531}, + {1407738452, 2759241071, 4035452537, 3264625899, 300855897, 998180870, 3577396762, 27718365}, + {4285288569, 2967992801, 3186698758, 1834124219, 861199049, 3411923209, 2779943597, 331383489}, + {4106908222, 2791186196, 1426224957, 2013837652, 1008299895, 4237507183, 698748362, 745819617}, + {3243043387, 2495143236, 4285291196, 2853924090, 2493636635, 2934867018, 3782857836, 351403497}, + {3724007137, 2012330090, 2770818311, 2723809261, 1407056135, 2165808813, 2097588677, 677801250}, + {2593859512, 1545147480, 3533248026, 39255927, 2706140140, 3208721120, 1750031007, 583305867}, + {2732611333, 4220993215, 2853046337, 1832934582, 1398860418, 1839920281, 3994118, 195260961}, + {239847163, 2290541590, 3808045542, 4159765461, 1805310439, 2381869306, 1801399258, 231957164}, + {3908211466, 1402167907, 2100791329, 2316054718, 2920919702, 3159901407, 1701201362, 283497683}, + {4117394593, 397525899, 1117865941, 1197755858, 3701704451, 2157746058, 1510748273, 132140861}, + {726320899, 153214306, 753877621, 3159966414, 2874290737, 380034546, 260632863, 591101584}, + {3230072220, 2887271082, 9327771, 4241307648, 1870457156, 4178348016, 243925350, 413385008}, + {2267597627, 3976552012, 2112619937, 289645549, 1338394049, 747457585, 4217258042, 362236761}, + {344640680, 2752209194, 3663916509, 3550971574, 820450960, 2446671866, 2486490957, 638002681}, + {1850265674, 1982056912, 2760954398, 1629524270, 1010757151, 2693021850, 3877582607, 653727482}, + {2396692470, 4072522129, 1873387645, 4003433968, 3544620364, 2446521182, 743585580, 177498605}, + {442047926, 2113819132, 801944022, 4233258096, 4253481230, 580072769, 3147004310, 223433191}, + {2707515330, 2553355918, 2732410772, 3754210284, 2416732807, 1562658424, 106973911, 736628995}, + {495995655, 944361715, 1305762751, 349531501, 2325921800, 4267986139, 142757481, 69720249}, + {1844613571, 2977145149, 3856424867, 3161544640, 821038763, 1617093306, 182159125, 268341320}, + {779032386, 3037691568, 4171706326, 2017563144, 4137532968, 1907725980, 2247112602, 157001980}, + {2043929867, 521706872, 3179115968, 3174598567, 3446342843, 2002410455, 3411072237, 103005206}, + {754395401, 1420295336, 2658319484, 3448962882, 260520504, 806508665, 3687649235, 82405303}, + {26811967, 1676882284, 2916989486, 1667338479, 4040580493, 518019521, 2764112139, 271405907}, + {2011329339, 1823760269, 3879497266, 3632583552, 2351380779, 57086518, 193331315, 612411688}, + {683593038, 388087616, 4036998339, 2918353598, 934730732, 1670768487, 2748634629, 702848434}, + {2284921281, 2343640912, 633300928, 3962122771, 1314926589, 2908517123, 1393547351, 647773584}, + {342563455, 3005851558, 4167071105, 3265882202, 2098769995, 144761583, 3192815201, 436108511}, + {129098898, 1772494027, 3799029988, 3171809526, 1208640006, 3609005564, 2203551014, 753966375}, + {1047058773, 1345664134, 2616680954, 1432799547, 3105376203, 259161000, 2765187428, 327927919}, + {907851107, 2262598123, 780653553, 1784451530, 1745112413, 3641053555, 1689968199, 311445893}, + {1375447093, 4056343568, 214920454, 1417586484, 108583808, 3435080226, 2992676718, 660232279}, + {1927249, 2285590176, 3612414302, 3088659238, 418104416, 362174941, 722399206, 220303556}, + {3378640192, 1114609246, 3855290153, 1589176472, 2304652289, 4258601637, 417509247, 271170050}, + {4055406167, 863155046, 1460069472, 1092444471, 2617536048, 2235047663, 3552685287, 594505756}, + {881189926, 3908719568, 1754574502, 3567254311, 2904613025, 1474730689, 1387698817, 347562855}, + {2838831722, 1135177279, 2253294560, 2151230854, 3078399568, 1754226307, 2305199845, 762228828}, + {782091872, 1380166783, 3834910866, 2418371975, 1736384054, 585767862, 3415144201, 71103219}, + {45234869, 1284886344, 753636431, 282884478, 4034222042, 774321461, 534303432, 537565597}, + {3814578908, 2315507132, 1736201130, 1309618237, 3005196785, 2430557231, 111540609, 186822532}, + {3329076533, 2495286881, 2543073320, 212456651, 1618488075, 25836816, 2889533895, 132346250}, + {2025943471, 2642396572, 1296820176, 695564326, 3033409999, 3255128846, 1454668700, 377915797}, + {298746178, 1728904108, 4273631972, 3244354105, 3840672813, 1752664879, 4245721903, 397488252}, + {1592958574, 3993387310, 3492412781, 1191508850, 1867764147, 1184519931, 3256523274, 673151995}, + {959987054, 134660401, 4203280615, 2094425517, 3133782513, 2886052852, 714191912, 234847975}, + {3897175008, 4103578412, 1402314335, 3264235326, 967777882, 663127220, 3435133148, 67500769}, + {2319142588, 3401488539, 1013074401, 3018834969, 3890829703, 2681126154, 2703527371, 7602724}, + {390749369, 381129300, 1017634038, 1667038542, 1820919479, 236146972, 2678267597, 783118656}, + {250742823, 3129224547, 4142723395, 1366481077, 3507070579, 2579196636, 1678692740, 472386247}, + {3765884410, 3818196530, 4166930588, 4050738583, 3989060798, 302995480, 1817563181, 689319615}, + {2712509169, 3237027891, 1380933035, 264093301, 1717379375, 3519071075, 1767616967, 101073943}, + {3239677603, 2883057819, 1804424036, 2966729987, 2145333238, 545635539, 2302589215, 637378602}, + {1570912655, 3428584936, 2299576427, 4233057722, 810299821, 268867857, 812079528, 604925597}, + {2568837327, 3927870736, 3305159616, 215308271, 4033213121, 233216209, 4118012290, 282493844}, + {1377384383, 3694162642, 793753049, 3898668984, 475388736, 3002014091, 1502508238, 87213997}, + {2055587211, 2781185414, 4216646294, 860201335, 1411852197, 2930543278, 584827303, 322916839}, + {3366184755, 2746887855, 2553656732, 1392977696, 541144601, 136717118, 3970310557, 677795820}, + {933030785, 1229674238, 1134894799, 21205000, 968880261, 95535323, 2568117953, 569236660}, + {1243723987, 3935863319, 3012568419, 786272006, 2041393944, 34612570, 2424072316, 344459269}, + {1948864118, 2794615149, 3256439820, 2912436057, 3446673991, 3503313320, 3906340144, 555402482}, + {3072724303, 1959578276, 1095988690, 420694576, 1300193212, 3516052654, 2361533065, 585868252}, + {769209108, 3752071469, 2904726287, 2441772773, 1687195010, 2685644332, 2150564568, 159888588}, + {180948865, 3350895114, 1299521655, 1155971634, 2363787926, 3273808277, 587527888, 239343504}, + {736130025, 1738465784, 2445946022, 2108071309, 3834694515, 3455953793, 2440316446, 428678174}, + {3724090613, 1740243554, 1158730904, 2845030102, 550157154, 1869454367, 3052353330, 590333708}, + {3247338063, 2964024649, 3940500283, 657152032, 682513169, 2667910608, 3630660614, 168766257}, + {405526592, 3702408827, 1551625696, 4174795005, 1220321955, 1655647240, 412802057, 239499684}, + {3744687414, 2660078178, 1638400891, 4293473098, 4252114394, 3325187064, 398030592, 377679403}, + {294892373, 429220089, 1436496746, 250775576, 2340266497, 858838987, 3707390526, 745965453}, + {336787952, 839217346, 211627964, 1913488777, 901103012, 755136621, 1079455557, 367099313}, + {1052974684, 3843398262, 1451683963, 3398251624, 794015551, 3620285780, 2744082328, 69716148}, + {1392316307, 3448072006, 3769540998, 3854106905, 227687939, 3937674665, 3056915556, 81379954}, + {940884806, 595555515, 715877422, 1812462716, 3924766635, 3713126503, 1185693109, 132614538}, + {1564750467, 547574783, 89919506, 1934009746, 3138491149, 86298986, 994295175, 91682116}, + {274600132, 1617361718, 2913828453, 2505029813, 2421559646, 3812934731, 380923775, 565604819}, + {1296054944, 2587136727, 597382550, 1768825081, 2152288621, 2209055789, 2313406003, 90688769}, + {1088521906, 3058528374, 3636735629, 931135533, 3864802068, 3254321736, 3310788936, 731858522}, + {3090443405, 2305352182, 3403631429, 543912576, 3621310890, 3928836266, 1945081590, 596229920}, + {1154899110, 493126078, 313078979, 456616361, 2860388056, 1153165333, 4161866942, 271361894}, + {419821426, 1227181083, 1507152581, 96293363, 2970819811, 2446171015, 3051155065, 337629012}, + {2834789033, 3927840643, 1242435635, 2268341773, 2677673249, 2100643328, 1392052561, 368924491}, + {2912514897, 3316560006, 628216554, 2437588087, 1759699678, 3669161493, 2612238471, 499708502}, + {3328269792, 1150559351, 2872044375, 4040978872, 885368760, 3127695312, 158192761, 398363137}, + {3225556884, 418544287, 4064988259, 3701830727, 752157855, 2278111951, 419418672, 272425537}, + {315127304, 826622068, 689511825, 287813308, 1645480811, 3210485129, 1429614313, 384330936}, + {4207418039, 1263157056, 3602143375, 4064393213, 3869535358, 3917028239, 3317351110, 158477363}, + {3817534357, 900240134, 600036034, 2135837159, 3471301812, 2376562092, 581284366, 503412840}, + {2129963472, 218914102, 4057368807, 3310085716, 992376303, 992838221, 2452989566, 701326997}, + {3613254905, 2210695659, 1591638097, 1400588169, 1886673498, 2027457618, 3136164231, 504237635}, + {3354087789, 3691962723, 2129719271, 1600573041, 3532819155, 324320379, 1828472349, 478634384}, + {2068038630, 903105246, 1016664432, 1993979958, 826243379, 1298252396, 1457510354, 436771249}, + {3641953144, 3667998474, 4012526573, 2962780117, 1432379905, 2847049423, 1451470322, 565325726}, + {1461105074, 2297922808, 4070099827, 2652954537, 1599141290, 2493384389, 1081654934, 355049709}, + {4257320239, 2773077657, 4072919451, 4256582506, 1877920774, 3814938219, 70593517, 767924639}, + {3132305437, 1240893428, 3006769959, 2533434438, 775782470, 2797135339, 3370346922, 578259180}, + {1853877891, 37936802, 2617205804, 3854026353, 1464731060, 3073936084, 1704485655, 694108449}, + {880994875, 2744262882, 3002916124, 3647304262, 774932988, 3167159083, 3898650540, 741803004}, + {1513173595, 600654756, 1069548821, 173335061, 673755375, 1031065258, 29162718, 360952888}, + {2258333257, 416149108, 1964261047, 216655101, 2756910247, 2307151787, 4107029048, 695931378}, + {2648920181, 1102039322, 1053613204, 1059126329, 1199526976, 3030919941, 3727038726, 248906275}, + {1735549184, 1259026379, 1571525696, 1111699279, 287424413, 1473672836, 917086779, 20355305}, + {1991331788, 2798027316, 49673419, 1480357371, 3909721780, 2317820989, 2770575190, 619124647}, + {2613124927, 3232158687, 2541388015, 4264045874, 3462381548, 1879751443, 3217304605, 495297764}, + {3025943977, 2022349740, 901126348, 2192766926, 1619020242, 2793473223, 1990094260, 785911877}, + {2305692778, 689225923, 1594841826, 3169552569, 1571598335, 4232031289, 575872669, 754529861}, + {3530741745, 2941745193, 4239198956, 3080696891, 2443508013, 3123905783, 3808493358, 211082759}, + {1661866116, 1592052867, 2921690866, 3944580224, 1800527715, 2915217219, 399122718, 66157190}, + {2632961464, 645511587, 453455086, 2232430376, 2430226725, 2818327245, 4193801069, 705877159}, + {4047678938, 3765722689, 3054540112, 1549947186, 2768701404, 1532093773, 2193643184, 296620558}, + {947709091, 2843832698, 3533189522, 1049272994, 4156940529, 754995738, 1736804818, 180368753}, + {1899820878, 3429511613, 482494925, 2079971707, 3739531217, 3717910085, 3196978500, 240404771}, + {3558857577, 2842357455, 2618459130, 2898924734, 355664290, 348184063, 2819293414, 442801647}, + {1252901373, 1175353217, 2783262814, 902580190, 3246162711, 1466415665, 2141220550, 514463484}, + {4057102853, 180526108, 2930691199, 4251282340, 3865654890, 2310854075, 3224443560, 226323888}, + {1329502429, 447414329, 3285285982, 2661326230, 1186881835, 3506220992, 3898816178, 310227413}, + {2405600872, 745655251, 4045421903, 1997822644, 3445428010, 3432721842, 2798399400, 213520696}, + {3308486831, 915754997, 3429919489, 886892877, 3943778259, 2622222450, 46581861, 316464663}, + {1549861602, 2961484209, 860441020, 2978980178, 2853506095, 2169829058, 463763284, 123249641}, + {3490106211, 1152051007, 3871481293, 3610864759, 3201201079, 323516229, 2515712804, 592984798}, + {3175501730, 4172747683, 696734400, 2016209346, 2679581613, 1283386815, 119769961, 153162117}, + {4221400996, 1173536196, 2493643213, 3411524223, 448554863, 1770945109, 3772306227, 356641747}, + {2863881699, 2263468048, 2988015477, 3373076644, 779577530, 786820475, 1457142657, 15234319}, + {3493893011, 1650948875, 1950315015, 1720619540, 2346824358, 2765045186, 197437717, 737356027}, + {3912596926, 4205283321, 3479575881, 473084530, 2375416259, 2533386141, 1764662176, 627673995}, + {76158432, 1873165497, 1789403737, 2859990777, 70662025, 832553386, 142321365, 663806946}, + {1997748691, 479853365, 400972934, 719150376, 1295299599, 4239056267, 3021904274, 659968788}, + {1299740311, 1828402111, 717415926, 125214022, 4249218043, 3543774534, 3892018027, 632179902}, + {790843942, 714156516, 2075146925, 4173819066, 64647861, 2081375473, 29406698, 640466019}, + {81633883, 4189448534, 3984774124, 3286521685, 3012982052, 3316801760, 380696363, 5941711}, + {2507879346, 2867937141, 3393836166, 1159434792, 2741543930, 2718829099, 3662572583, 105020811}, + {3548900562, 129223459, 253886885, 2668800177, 2408369280, 380932340, 2868059382, 561561452}, + {1569645159, 519676872, 1670791309, 493309854, 3976538394, 1776121839, 2090052221, 429792945}, + {2565594159, 3820738097, 2576060869, 56104509, 1294895952, 295843056, 1251578516, 716185908}, + {4033202314, 3856035468, 4292258936, 1043914791, 2685166570, 1557466194, 2550962292, 537714142}, + {1265264179, 3431566981, 2879888728, 1209937746, 1256912094, 3450258324, 2062485283, 681741562}, + {453307838, 1046733960, 3029969908, 1854479895, 3347541797, 2602833262, 1604343937, 601209107}, + {5134728, 1897623177, 1171553227, 3686231196, 960551315, 957091398, 1584677159, 549809462}, + {645956574, 4170680366, 1519609469, 3328256465, 3785127172, 3472273900, 3324374467, 484017849}, + {3876380305, 3089869061, 1388317931, 4237411804, 851507227, 1492827591, 4213810431, 358819852}, + {3564044784, 833583939, 183599388, 4198562020, 564285005, 2750298274, 3509446650, 111880061}, + {1434433862, 455495396, 2241754289, 3440963047, 3130084619, 3747429468, 2790752444, 411536293}, + {2705702824, 1795366009, 1323100181, 1127565197, 3481721703, 2406171005, 1934934244, 462777740}, + {1830989865, 2816315052, 1807561950, 2929717206, 1687250265, 4060793923, 194397091, 787474252}, + {3043591823, 2360649179, 3643107304, 3355173723, 3772616670, 1727295825, 3968738084, 311680900}, + {1204029854, 3587275675, 2780664488, 257770146, 2871235374, 697352323, 1211344593, 211975966}, + {2701435509, 44083301, 1261997910, 3244005518, 3349300524, 2986544455, 677430368, 332363242}, + {1355275471, 3830148716, 1581801559, 917392687, 2350313816, 3915283178, 2881065734, 491815416}, + {2664110793, 742410964, 402541217, 3395414027, 2525129317, 1998954126, 1508176370, 396788988}, + {2540271643, 64529556, 1721597590, 2815893504, 1853001550, 3219439656, 2280313439, 174083413}, + {788247122, 2781310537, 3991699125, 1887128349, 3244143637, 3177799563, 497805333, 298453950}, + {4131915348, 3432281802, 398672555, 3287470851, 896510322, 1713517041, 2988448391, 451287461}, + {2827997615, 1705376012, 2085850696, 3687556228, 2841210441, 4079669364, 3281875773, 20482323}, + {3862836509, 3691323032, 2265915456, 43925825, 213345059, 2167943339, 3759698735, 241101365}, + {77982388, 203382329, 2391572935, 4096670029, 1747089504, 481839222, 3646192509, 408105100}, + {1957560336, 3636544844, 798362588, 2673281653, 1784677006, 442449111, 4240693725, 567929252}, + {770244866, 3564193795, 873828310, 1694477739, 2887241630, 2943566737, 2353643375, 455146858}, + {321964238, 2129495363, 4097758781, 3153063620, 1774044033, 1887872880, 3177409739, 229520030}, + {3892639871, 1841124267, 2835684780, 3363392962, 4272351308, 1167543473, 3081913378, 222854790}, + {421526506, 1611950406, 1135534801, 1031774188, 4115419395, 2730526033, 846455287, 202921362}, + {2856468379, 3914916464, 4041629368, 2073438480, 3108923511, 3481057275, 3029921867, 694809544}, + {2176232313, 3779660806, 4087660328, 73063295, 468142511, 2883952860, 3484827794, 708368149}, + {541030524, 641904671, 2496807899, 3777458443, 2544093657, 1691619485, 1358190795, 569516898}, + {3797485512, 2460225115, 655445897, 1221712520, 3064005672, 1335360321, 3769755888, 345272082}, + {2778340664, 4174802490, 3625554806, 2798853328, 4034373724, 1450606290, 677104980, 722400340}, + {1450173214, 904096650, 127323784, 1823278628, 1445567435, 3835749310, 589447953, 343943205}, + {3008290576, 2809877396, 1494789575, 2487718145, 244384822, 2475987620, 1630215198, 714125521}, + {2751297472, 1248176499, 1588008518, 1095623097, 150460000, 630389506, 1897196365, 186823235}, + {2402861340, 68894281, 49393503, 2365983224, 3169497347, 282767949, 3878856997, 105130501}, + {553498932, 1409145846, 1259390548, 659710738, 2272624984, 159587703, 4269980407, 326671135}, + {2336970059, 3428019743, 2141724414, 727320346, 2719683577, 1923623025, 963112148, 117224600}, + {1660953237, 1010460689, 3722805542, 1338962068, 2183826947, 3112567970, 3338403244, 288639124}, + {2067603575, 2867746123, 183225820, 3982731343, 3562208925, 3564555262, 2456656324, 600887054}, + {315784550, 1135565559, 3358161759, 3139302586, 1751515414, 4039819644, 866452945, 300226468}, + {363862078, 2695201341, 15857786, 231506566, 4066406528, 3758700868, 72439981, 237698955}, + {3748193072, 1745271950, 711477103, 2987483248, 1811909716, 2366110659, 3826647523, 464500049}, + {403554210, 4069498550, 1329930899, 2544847367, 1437485048, 32131127, 3398771219, 727175236}, + {2865543205, 590367396, 3876098927, 782785429, 3471366121, 2142726484, 3019620247, 689306695}, + {1784321462, 3426089356, 48341649, 1536638699, 3587281370, 399913232, 1173128343, 596005517}, + {1904884003, 35333078, 559982452, 1131960751, 831082963, 1140060166, 271993994, 276046253}, + {1004193195, 3464088804, 1596167141, 434163446, 1302290833, 3105180922, 1144068019, 604630409}, + {123982522, 2794385732, 2143485798, 2716005782, 2632254308, 2492085245, 2682008526, 617851001}, + {2993137816, 3557754821, 3374621558, 1342913614, 747004409, 4085482694, 2068441540, 180397289}, + {3214317014, 2103662482, 215319037, 248081529, 992688696, 3830307686, 64787198, 503775437}, + {775971188, 3437944405, 3331306177, 1971201190, 3164984365, 2656543832, 739034945, 376604045}, + {1797789187, 3679933643, 2881756501, 49921913, 2146689851, 4149109494, 593659249, 238384748}, + {497459077, 2612248300, 4237326659, 3710762301, 2622090094, 3369864197, 3796773360, 434462534}, + {3362851339, 4149889704, 2532670779, 4291135939, 527698998, 3592835995, 3572884939, 251975345}, + {2469328668, 4159545180, 4283957133, 3584245103, 274682786, 1425843146, 2801460678, 169456121}, + {2796904305, 4183946945, 1582452955, 922261186, 3234218031, 3047022691, 4095574428, 480061565}, + {2808302591, 1235420709, 3869404972, 3739645157, 2658154198, 2495959048, 540918332, 768518409}, + {2133266358, 2272541429, 934148458, 1148588086, 141793992, 825790900, 1629616173, 767319822}, + {3064553625, 3273550748, 3832084128, 486331033, 2115408287, 2577872672, 454257535, 610157196}, + {2374745634, 3746177347, 2513253862, 1005984528, 384386891, 2070940889, 2136025237, 451436705}, + {614832939, 495759957, 648167449, 1217442285, 3438421509, 3036347264, 1078884407, 81153276}, + {246603794, 3927931817, 3421115062, 3615135408, 3359058815, 2321640173, 449196633, 125667592}, + {3986932341, 3112368538, 3760256890, 1167571128, 4005167939, 3298158127, 2555831970, 229409324}, + {2712326769, 149403274, 3198176801, 2528411766, 2127916431, 835424608, 1822766692, 473039207}, + {638277013, 2942661804, 1653842725, 4230191949, 1601390781, 3767268794, 288153423, 751308210}, + {501300337, 755933204, 3081479001, 3199030874, 3648930933, 3134901930, 3975230604, 173545367}, + {3319647807, 2165572466, 2846539899, 1541161257, 353931585, 911012977, 1644186349, 184168920}, + {3944915644, 3246017156, 887253479, 3656485237, 4063535553, 557133179, 1079439812, 443042114}, + {3063992937, 1974690027, 2459863230, 2282842773, 2742732874, 4293860817, 3958029505, 649765794}, + {1425281954, 1536847139, 722971183, 1384523187, 349010195, 2665813924, 2582379133, 414182963}, + {2367320344, 390008162, 3666359935, 2898367819, 1127931997, 2697338838, 4287391050, 352300978}, + {1745040068, 3688858979, 2306482964, 1522768256, 2541393271, 3771712565, 1278722006, 271347347}, + {3897813555, 735200113, 1728182029, 4213177831, 3644972837, 4097996714, 3019023627, 100358037}, + {1392450522, 3032152238, 893809446, 578218221, 2742466204, 1101847968, 2147510285, 188532766}, + {3779311572, 2813787851, 1958148021, 3979138494, 307758872, 645177125, 2464936584, 621113476}, + {2152745848, 1936376324, 2636490230, 3352450221, 2710113758, 13666932, 3134490230, 763249366}, + {613940689, 3871041795, 2774242947, 3102196864, 220896144, 477160470, 3095490800, 698606308}, + {735379703, 3661355756, 102924175, 1172143219, 2225268217, 1368301283, 2576218122, 715297514}, + {724209457, 3251415987, 3491736743, 2630022067, 1704388517, 3184456870, 234552976, 527573842}, + {1019412378, 4235585298, 668733571, 139401874, 2283825927, 3026837265, 2955515055, 358014908}, + {1643085783, 2064767362, 649920881, 1813286291, 2284585087, 876894711, 1570997885, 144748353}, + {3545116916, 3812893427, 1186922270, 4117713763, 1228399423, 4289269302, 3133204195, 233367747}, + {1828208342, 1626903382, 2591037326, 2468531382, 2514790792, 2126741313, 699788180, 687000822}, + {2590910915, 3234222155, 998892430, 1260741454, 3275936571, 3638669485, 3560980624, 200642384}, + {2077606643, 1233020713, 1355308236, 1619858291, 1298901564, 3370632394, 2916267115, 721070317}, + {4086951750, 1682672775, 519886830, 3386613899, 1884433685, 3754502927, 3119184254, 399685140}, + {4283033957, 2497099997, 1440964180, 4231550451, 3212997967, 1194481414, 1407710707, 507554997}, + {2171988846, 3658905581, 573574519, 1058221000, 605744963, 1288411479, 952205099, 205913313}, + {787515365, 2685659153, 130673468, 2618854192, 3756641760, 2828085991, 3284313593, 360600994}, + {1884051967, 4027090027, 4273023166, 2280716024, 3012439066, 175113380, 3353944594, 712026326}, + {329019486, 4193706800, 2013277386, 3579021130, 2585777855, 283880957, 941285900, 50168956}, + {3246081921, 3845393438, 4074227765, 2277939316, 3203568742, 3432437081, 1142099870, 278637075}, + {892354367, 712256106, 3443806372, 3649542277, 521427139, 3104184092, 3176338508, 229926515}, + {3969516349, 3165640514, 3925441289, 2482005235, 622833875, 3911086579, 2977813039, 354002030}, + {765184800, 897849507, 3757213205, 2532813233, 2412926865, 2090182027, 2375252476, 477355439}, + {43747844, 895319320, 3176653097, 3830655760, 576797894, 1886464173, 2883387818, 118338082}, + {1941890815, 683076997, 912966623, 1695937522, 1333034202, 1093472880, 381429614, 218491441}, + {2946711517, 3039832677, 503492983, 2919524407, 1311784558, 4123253290, 451922031, 754728241}, + {1265918352, 1852828249, 51700440, 538791598, 31468574, 3662356296, 1418117386, 583293210}, + {3062475345, 1940132642, 4016298129, 578125704, 256272197, 1670839922, 2932426536, 496284813}, + {2422387329, 2005806195, 1441246133, 3411882910, 1477358745, 4133172900, 838539638, 390363939}, + {1664207317, 1907873194, 969995301, 2928408970, 3426138700, 1211425327, 892617553, 645335430}, + {3250401063, 3818269941, 1072247791, 1062167101, 1000702518, 1283908556, 3126111628, 775569916}, + {910594854, 2576802333, 2595625096, 3440763963, 3640267243, 2144283915, 2130479945, 725068303}, + {2978412940, 1266046701, 1509415973, 1559317597, 3445616703, 1367783392, 834322112, 145157108}, + {2236732390, 839014339, 3579206266, 3005720938, 3994117378, 369011681, 2017934536, 511202856}, + {1115064523, 2527309910, 4149306379, 480140652, 1069701838, 371284567, 4058409682, 528962797}, + {1897860531, 2047244399, 4230926918, 740377594, 2575804008, 837699794, 2533326786, 568517473}, + {4184333871, 3510440164, 2655005214, 2646579149, 2774744905, 2614448898, 2211340341, 178789764}, + {3607310315, 1869432503, 1133626001, 3934435087, 1927399982, 2529179439, 1869365112, 422155032}, + {1487985852, 4103257882, 2265878524, 1023958334, 4229045860, 1237918780, 1790033992, 195184436}, + {1064702179, 2141453013, 1392718007, 3549837752, 1865905997, 1362357736, 490410268, 447067493}, + {1798490673, 3527711718, 3833993885, 3175280771, 1549541013, 1324112837, 3864951511, 750256137}, + {1459871228, 2427684304, 2416996953, 843717827, 3236174240, 1005599397, 1682432251, 422444852}, + {1301933063, 2711766165, 1007886473, 3074523049, 1985534072, 118956493, 3855090460, 357638871}, + {3275012819, 2303323374, 2819551357, 3218639683, 2943788879, 1610928680, 350306590, 355981244}, + {1100160531, 2327840812, 3594797617, 617003074, 3353212936, 1374379726, 1694098536, 328671784}, + {1453151744, 4291082951, 305080686, 1607113515, 1020107973, 1884965423, 2791816858, 677303300}, + {258476260, 2123700355, 2496544104, 195885356, 1828867786, 1032470872, 3424250454, 553180335}, + {739121492, 3590619915, 3660444685, 1529647809, 2157307352, 3336350188, 1065579494, 86870993}, + {2430047633, 3488439891, 3185867320, 2463565111, 3355687238, 836564664, 778519943, 140443941}, + {3810434629, 910145219, 2438122767, 1324302729, 1659203146, 1201847980, 274542119, 81443981}, + {1224135538, 1638275508, 3029303248, 3037120940, 2923150632, 1447228758, 4293176500, 514950176}, + {3178469827, 1756988359, 1252938830, 2074533759, 3777245391, 3872914980, 4119880253, 791595306}, + {3148818666, 1820175066, 2666512094, 1792688114, 3675412752, 913997504, 3535705756, 746323047}, + {2937717660, 2172400902, 1761188187, 2565979264, 942116521, 2483141094, 3442907669, 794786731}, + {175341793, 2571452480, 2108738118, 2377506578, 3861053361, 3075998485, 739885242, 103746488}, + {81542165, 3951009944, 1520708664, 1484680832, 3687936991, 4222863847, 59980275, 497162498}, + {199029807, 299202620, 407838, 3257691091, 1196222521, 3220357743, 1988389575, 545124584}, + {1768381121, 3537825303, 2261166121, 1078737958, 1874766645, 2405239030, 3686829522, 18610843}, + {3458466743, 3078315637, 4061237626, 1501612158, 1158363591, 1310983479, 2642130740, 685317413}, + {1462454858, 4187423762, 389355509, 876076633, 1033290202, 1088791524, 2948577799, 456724684}, + {2576899236, 2382995665, 1986269485, 3764233564, 3019088940, 2277962645, 359878984, 81083110}, + {2806026317, 933975641, 3775558502, 1498585158, 378774460, 791772423, 2775033698, 475780210}, + {1801789115, 2907971012, 1426930661, 385460219, 2916162980, 1884772949, 1574275143, 209659349}, + {3630109185, 3791106436, 3829854882, 2624085395, 407670946, 1212243857, 2252157123, 266526032}, + {3573570867, 3166762962, 3969358721, 797177807, 977859272, 3965494733, 2025638641, 391710997}, + {3668375461, 4250595983, 2078966688, 3098322539, 2575819346, 239280274, 2268099129, 360877046}, + {1364492416, 3388901092, 1585052473, 3240021931, 1262986918, 239951066, 499528294, 719162222}, + {3700810022, 3355292378, 1725010022, 2050763579, 1422572956, 1562688117, 3621995030, 5863314}, + {2916384554, 867370581, 410986643, 3571373590, 3968451337, 914754511, 3687204704, 707492868}, + {2038452634, 1281384605, 2670976650, 486961176, 2098589955, 1271658868, 1476854712, 55804338}, + {3567894903, 3124496877, 387812786, 3650877613, 4113072104, 2194373540, 941280208, 208817520}, + {4125595573, 3106421105, 2149604073, 138205097, 169469014, 502074703, 1486172229, 574560107}, + {4256875046, 1164911178, 1648256051, 3987048209, 535235605, 3589693077, 1859145475, 705994086}, + {1366873312, 536073442, 1291766470, 3496787933, 911005464, 1646375203, 2161578815, 75498668}, + {3090478733, 4267265485, 2756838720, 943735705, 3729248066, 3886138279, 468227547, 396758447}, + {3437101105, 3588144265, 1748504961, 926941233, 4147129610, 2145744464, 3981655017, 559109962}, + {3025298283, 3845072355, 121553549, 1953787473, 1456245241, 495352613, 2188996470, 371573111}, + {232100374, 2046696238, 3496261104, 3329093659, 1439315799, 2659433917, 3330314212, 242795391}, + {1987143514, 1571980522, 608802573, 2019475782, 2725560945, 3880331404, 1432591838, 761075868}, + {2930364230, 1288612342, 3626816786, 469817881, 1970734419, 445388486, 3031104425, 243755791}, + {2328830752, 3739149031, 2309672808, 2900344525, 3941115500, 3541618858, 2529113660, 510508845}, + {2041361123, 1129135032, 4066134822, 2824692389, 3169441982, 1948576450, 3850915539, 162465316}, + {3925370634, 3056933941, 1831596225, 2577730203, 1216422870, 4239976726, 3653186773, 707939544}, + {2204735677, 2398529145, 3326803417, 90980355, 2276561735, 1155908780, 4084398169, 284138459}, + {875116666, 1937599083, 2935343225, 1970248723, 276907855, 1094276309, 1654274504, 588492319}, + {2946207514, 4057267793, 2158878946, 3935268922, 361478693, 2137840815, 1618005720, 323531841}, + {3494775068, 2017883289, 1375519872, 1657966431, 2561178132, 3372353507, 577634281, 329828625}, + {564132954, 287119299, 3340884660, 1747495471, 2489873314, 3936720615, 2185028138, 532976192}, + {4257651017, 3171883165, 1051708844, 2231111769, 2576564162, 1240387653, 3241567889, 469738595}, + {181806742, 2424246740, 469069755, 2066881364, 2021845956, 3840934251, 1670028957, 304374111}, + {2532098551, 375352588, 3910763157, 3033961211, 3546788483, 1964729331, 1425247282, 566857166}, + {3504499869, 2371558472, 3559007468, 160581895, 4142848371, 1057140580, 791460656, 601527515}, + {1481708568, 1433297130, 224354873, 4220389699, 2482831916, 2965012544, 482621252, 110572712}, + {3813536030, 2331161078, 1268776873, 3785325467, 1890686316, 541066324, 3035282357, 204797898}, + {1736001860, 3696828141, 2956953274, 751612446, 1873514337, 2620894207, 3359983432, 298771594}, + {3789710518, 3224637010, 3321308579, 2789973501, 2261859908, 262582140, 657849978, 751299167}, + {4165053348, 2640150063, 3339157318, 820706498, 3863676202, 2872555547, 3446017957, 565173782}, + {244502221, 1215842208, 3984105241, 3675531057, 2190313096, 354881607, 2415903687, 133048179}, + {1781747316, 2572912168, 1843446011, 4133954964, 1692708864, 1882917095, 3246431691, 732386649}, + {4259584428, 1041966204, 1172904123, 1649020224, 2909943702, 588410082, 362361035, 281298838}, + {1402776770, 3517067060, 1773466711, 1045436007, 2376771475, 4154963043, 902800225, 67850807}, + {3258194998, 1505901218, 3918400414, 50791346, 158120944, 3454336004, 2614571004, 734263924}, + {377240175, 3556542129, 2053698467, 1013571697, 3850800179, 487489866, 760419290, 428468227}, + {2781787399, 2294380199, 1839512208, 412518761, 1850183505, 672787798, 873135543, 661931285}, + {2157091613, 990355177, 141517022, 3203301823, 2941341468, 1511893699, 410723353, 17813782}, + {3668811448, 903531136, 1215597611, 4229067606, 3427022261, 2268595150, 1787169905, 621083996}, + {3583235201, 1537688940, 4272394104, 585575168, 2499041710, 2265696288, 1819758752, 582095837}, + {205988348, 367718018, 2982589580, 1280716624, 919128866, 1565755903, 344503733, 754625188}, + {3138381237, 255624897, 3500192886, 3738966075, 2341345602, 911051462, 1534382075, 758318435}, + {2913385280, 3914670790, 851775932, 4050411685, 1081749428, 924344136, 535377711, 686950776}, + {2024477527, 3097901272, 3610754706, 2483189320, 3845232257, 4093177003, 436577769, 376380356}, + {2336358548, 1691535606, 3790313171, 3806572388, 3552150459, 841023432, 3555680901, 708680155}, + {1621198211, 1019225663, 48101412, 2531455890, 4172994311, 3615536740, 2802805921, 9453250}, + {3874584406, 655287837, 2859373008, 3466163924, 887371939, 888068072, 671207486, 643027137}, + {644055780, 1303795411, 4152391770, 3215452348, 577394477, 1789410502, 957720903, 303989833}, + {3749045437, 10898952, 1249828162, 1233564818, 1726398562, 1391176900, 3088568261, 253768872}, + {3961024048, 33030999, 1378712700, 2213942328, 3514380392, 3417119890, 3211268371, 366764534}, + {47546571, 1907671991, 2185952227, 3151414801, 756816748, 2393321327, 1228950589, 85976968}, + {529974760, 1130236568, 1839371720, 1900189413, 1796576229, 3144651522, 14832389, 435071650}, + {4132855470, 1183130621, 3020937196, 869678530, 2674333858, 1708899310, 2668147284, 369703805}, + {148564132, 3593827463, 1744083380, 2582524445, 1165070396, 1984836090, 4109822031, 636731350}, + {690571428, 2628102033, 2650943371, 3170962324, 4035620376, 1378590732, 2925868362, 738302473}, + {1138004325, 3487551921, 508005929, 3504864296, 4233459474, 364926137, 4052039465, 701130944}, + {953078111, 3121946013, 3136065423, 1466219636, 500983323, 2472433405, 1111360848, 617949497}, + {2572597060, 453866300, 511785568, 3043268577, 2639652239, 2456954581, 2830758446, 585749680}, + {1771926849, 3863735372, 329230504, 422847805, 4017014954, 1251338230, 1899618548, 754398243}, + {1586704528, 3696226510, 3148246288, 2114534967, 3134328782, 1838405928, 820838114, 740095894}, + {2583773830, 1308206689, 3483826841, 1413093167, 3855875986, 3813412202, 3077148679, 270515165}, + {1489687704, 2121110506, 1141230631, 495613189, 1521902189, 1901073368, 2336269710, 6551269}, + {3817541169, 2540103499, 2985104664, 3953037545, 1072298019, 3326499171, 3367080759, 223824009}, + {3716626578, 4079086799, 4185343403, 1832409029, 20371401, 3023930884, 3947089857, 664085246}, + {2046798373, 2257778070, 1651758879, 1801178291, 3701890629, 1773590409, 4011133234, 578747854}, + {2160758329, 1760078880, 1131706860, 2201328005, 1989040001, 2533579253, 2066933570, 123108830}, + {4216833434, 1137776042, 1751525805, 2519237371, 963514142, 2731293836, 4026452482, 664230341}, + {1711998893, 1217182415, 2455456183, 2242258900, 1469776009, 1034935760, 3002334249, 64941050}, + {1000479447, 3808461525, 3437119785, 3813341415, 531674575, 3858118140, 2627095041, 43217524}, + {122527056, 3262659924, 3600482678, 2757441361, 843927190, 369020798, 2646249824, 116497113}, + {691520637, 2752436181, 1769061357, 1989474815, 1645749343, 289512161, 3062640830, 514816816}, + {2526067709, 2305512447, 873369687, 436741739, 1308117781, 2181162012, 1688030272, 202374240}, + {688609943, 1153567033, 291886141, 3066338190, 1565245387, 3045049922, 1519725131, 344350782}, + {1672786644, 2635373875, 2728276817, 4139586449, 2238636850, 361854074, 4064828986, 103004278}, + {421667633, 2608002385, 1067288631, 439031938, 2068490913, 33037798, 4195667595, 107496842}, + {2472641826, 4028480052, 3649614899, 3731521645, 3364970559, 1508813412, 89259060, 626722884}, + {366917435, 2970445225, 2516775629, 3011698205, 4228401168, 3054522752, 3042537621, 719995396}, + {4210580038, 1641719616, 12771882, 2981493366, 3363643757, 877292786, 1413798087, 113131294}, + {4149524203, 2262628160, 2007340322, 4199767794, 3952406057, 517124548, 2393563736, 678093509}, + {2911444565, 2468397822, 1368691032, 2043473657, 672782941, 698739082, 2458782337, 797838770}, + {3212753432, 3317999049, 3917281776, 2456750191, 3252792214, 2098050318, 2387128743, 786275816}, + {4132817964, 1379541694, 317662098, 3623540614, 2108788066, 875075611, 299342251, 271819127}, + {2553482598, 2073229268, 3034544230, 3467320700, 1804285943, 4004999146, 3491542460, 661367730}, + {1355273583, 2271548901, 4200777769, 87636593, 655658116, 2554424613, 2733678925, 777993016}, + {2521956795, 2817344585, 226130102, 1944151634, 871235276, 917741632, 928076013, 808840490}, + {1933652215, 533153785, 3421131250, 21340638, 569068910, 4255731344, 503617093, 211137209}, + {271505447, 593764543, 1186186577, 3830545905, 4146357964, 1923879069, 1454624889, 182934041}, + {2581466669, 973743394, 2292340872, 1999803862, 3407676504, 28509029, 3170786752, 704772061}, + {1157096891, 922612825, 613092896, 1253117406, 2623752559, 807835478, 550831440, 96306488}, + {3033290386, 1606683058, 4060774265, 1480313049, 3671312244, 4024321027, 911462807, 579454325}, + {1268832030, 362584811, 3283646179, 487201634, 526778732, 899056559, 2246979477, 215799402}, + {3623376158, 2894508943, 2213999902, 1833719349, 1394310970, 2111605289, 3156366688, 150746981}, + {2093694398, 2104957477, 3326550874, 3535687167, 3867937176, 2303505108, 4020683788, 677570229}, + {4149451364, 3827742964, 528176696, 2682072023, 3847809039, 3281841147, 2652239710, 67678629}, + {1982200198, 2842880079, 3557548385, 2911232948, 3822639638, 1490800412, 1347825500, 175861705}, + {4152413078, 3514098013, 1755949056, 2001678311, 2580474878, 385605760, 1489976585, 359125232}, + {4233059198, 579229479, 1835360342, 307607280, 687988400, 3066213350, 2055875794, 798039625}, + {1232462572, 3925366029, 1620195014, 2176015195, 3671133063, 961899376, 3283082995, 743145459}, + {1633466493, 2911030745, 434932836, 1924464147, 77482293, 1967795548, 3207178228, 618932054}, + {950241025, 3574262399, 435432093, 526659509, 3250183080, 1260253174, 1477756748, 620983376}, + {4238985455, 1384933065, 892565384, 723069558, 1163976795, 2332851490, 16720515, 377489343}, + {1127954644, 430102548, 1054909103, 431933726, 512606820, 2796912401, 2578195581, 683242373}, + {126232515, 345787926, 3099825661, 1397626975, 1359423794, 2242710743, 2519784721, 598310868}, + {3286231821, 2552134507, 3926012105, 3449543132, 516340069, 1696331557, 3395647040, 14662475}, + {3583997398, 3154835740, 1531480969, 3218157607, 1024959329, 504925345, 296093308, 622919519}, + {90387846, 1962605752, 1297084570, 2646084378, 2851628683, 3623064872, 62876684, 129134053}, + {849670635, 2724305507, 1870825422, 1485266504, 3749999121, 2412061966, 1105149646, 157337735}, + {1690160275, 3004160882, 2831076819, 1458075569, 1895797107, 1815996912, 389338389, 112841149}, + {1790036055, 3066064043, 3852636574, 2238604851, 2766243845, 2860146747, 2692637452, 792413130}, + {2354466869, 4031992191, 1900718541, 803909901, 2903784399, 2537682872, 412828396, 348934400}, + {4102008895, 4200758220, 1150659400, 3628831575, 2282858902, 1503270465, 3257155533, 181651}, + {148466280, 1265813663, 3055132053, 3113527335, 2889870200, 4042384978, 1372968313, 683879423}, + {3440894595, 1267980000, 2541939584, 1406401192, 2407248816, 117215441, 1526391143, 447819192}, + {2016538990, 742622597, 587120073, 1092879742, 1607843230, 3740608060, 3198154398, 734043316}, + {413557720, 1159442550, 608033172, 3718337865, 2133938846, 4230175852, 3007337826, 481845581}, + {3890645519, 3268228878, 3026246075, 3910429341, 1943891906, 3677516362, 2326243821, 225724877}, + {2906136459, 2325215648, 4230379379, 3953865363, 764816148, 1265762673, 2521807941, 609645114}, + {341062853, 592796321, 1267657783, 3533983371, 3351377890, 3925341017, 1598907786, 155929746}, + {193608668, 366442142, 644566226, 3376743304, 3131282910, 831336357, 810519160, 253001673}, + {2990404032, 2182836834, 1882939565, 3052983386, 1854047328, 1929954471, 48453717, 545681139}, + {112343877, 303561534, 490407395, 1389247083, 2791557057, 3945263852, 3975702749, 65833126}, + {166902713, 2502565692, 4055846153, 2592789208, 1709824549, 1208955811, 303039787, 501801730}, + {3667494971, 3865079819, 3397448847, 3254036894, 993243122, 4127655040, 1996682197, 803771260}, + {2920402082, 3337938646, 3600317578, 1973479702, 1872812464, 626218597, 472484540, 646785932}, + {2944530693, 3402358508, 3400322873, 4007481151, 1912170685, 343665393, 1207900060, 470880172}, + {3904825056, 342520476, 679347678, 1419045382, 171124908, 3392096710, 3673855527, 764184016}, + {3723475624, 967853357, 2570370771, 2195330426, 2591005588, 2658800601, 3482467154, 663955874}, + {428420377, 726783822, 2532640900, 697660075, 2830677525, 674411635, 1979018298, 494272489}, + {790773936, 3993297031, 3574764469, 2049845020, 2101980083, 692167187, 1574901968, 87833161}, + {3435671919, 691849461, 1730308230, 1972321576, 1547442371, 351226501, 478312380, 743650793}, + {3927541388, 107940804, 3669006231, 2971286337, 3583662418, 1050154279, 313838035, 362506787}, + {869829679, 2991959091, 2733545576, 3790384846, 1755167571, 346603833, 4065575026, 70283510}, + {140901557, 3291755308, 4217269853, 3457114917, 1224795744, 4144407790, 4272782931, 602663324}, + {3204691557, 1413054483, 1054137601, 2224742162, 3900331010, 2890196061, 3774643465, 555287697}, + {3242247914, 4137152377, 352764944, 3516126278, 2888399494, 2104488465, 50829475, 11084405}, + {3727387817, 1103752055, 1176035018, 1106940063, 632525989, 61700520, 787510626, 414719538}, + {2896549420, 2687679084, 3876043705, 2907383945, 155239316, 4230669938, 786426408, 193626759}, + {3229292556, 1948898001, 3977112906, 3705780144, 1511750498, 2771641704, 3498458217, 620516902}, + {1983331189, 3771260439, 3642411055, 3428750567, 3963294075, 1351655689, 1701794602, 713871147}, + {3998587823, 1494410106, 3289866028, 4173813545, 1871011384, 3126780570, 2628154919, 172374072}, + {3630076437, 3310402563, 1238131417, 1137229095, 368850056, 2485423066, 2384480330, 781979957}, + {95370402, 3604795187, 813355608, 3721148732, 3533315820, 2151252703, 1134684478, 519478076}, + {3160259816, 1430786622, 2748959176, 2893345977, 2335739852, 4008600600, 2207010974, 529146020}, + {1118386403, 3218720507, 591329952, 3920142337, 2289728667, 807969840, 3108865696, 644948472}, + {2018113974, 2711009152, 3388378334, 3894598107, 3087532721, 3849152008, 3542143777, 465929458}, + {3098999726, 646331671, 3340745663, 2336474733, 935901468, 232443367, 3305529224, 801860501}, + {2860816286, 1694879920, 4214894449, 3204838409, 967861396, 2708098088, 3551573450, 775559776}, + {3265751916, 2637655219, 1965253416, 2476578112, 1158942322, 1686082792, 4157422090, 5944209}, + {248726570, 3314040641, 2780373685, 4085613287, 1566267858, 2356345117, 3553161252, 40449089}, + {3583774847, 3536967210, 815635651, 3347350978, 3071104725, 4276941798, 2900471045, 303440878}, + {3768306825, 1817107868, 2823843606, 1294625429, 559366649, 948961260, 1687357915, 87440431}, + {1894838187, 2866656897, 530645990, 85389038, 3478150543, 784469641, 3240773910, 555447445}, + {341482721, 571381706, 1599176396, 1162936347, 3616266718, 2837374881, 232337492, 518112063}, + {3166330866, 237377212, 905865462, 3939046562, 484346774, 967588829, 3342090356, 59401240}, + {3983682677, 642044711, 3759638031, 681377064, 2472386698, 1553832606, 3581277332, 194294771}, + {2162939242, 1860607224, 2958369703, 2072078456, 545505355, 2196037111, 2958458732, 475313081}, + {2841365461, 3770031804, 2083404626, 3635080046, 891146518, 1987166284, 932833748, 653719772}, + {2097041198, 3759028329, 580159266, 1287205049, 2730705069, 2310421203, 893633844, 382463752}, + {3666045296, 336619703, 2575941405, 1735446521, 2879319180, 3970974456, 2547595262, 780445743}, + {2042262097, 4193737845, 3859908855, 2825809444, 1120419825, 3844527139, 1114233100, 222903076}, + {2829946496, 2731061105, 2050161490, 2598380173, 853099058, 2934697169, 3502768007, 196447356}, + {2194030329, 1801248022, 3804438426, 66769600, 3504997917, 1159866474, 392871535, 343699206}, + {2459573386, 270860229, 2700768833, 1932814782, 2575310566, 853646166, 2873944063, 224492002}, + {3347788549, 2747101372, 508413896, 2765894404, 1919468638, 392251688, 1655375042, 367083231}, + {837683533, 1343161893, 2451426024, 2398071277, 3409406836, 4136384222, 3688872847, 359920704}, + {3297466838, 2859731841, 1770323182, 1296891056, 1393203138, 1600099820, 2338122918, 579295360}, + {254287923, 4115992345, 2550646051, 1282130342, 3197728193, 849271125, 906424971, 151813805}, + {117711287, 3268411790, 832641754, 3902730642, 125348988, 3797858166, 4017832923, 376755159}, + {3970449811, 1163197420, 3120025030, 3076442808, 4113340215, 1889474076, 3776132343, 139925953}, + {3388192759, 2364545401, 2861646318, 309459237, 1816767610, 1898992437, 2065266171, 759457387}, + {133039888, 3303681702, 3550989621, 3249412640, 2338593784, 1771265630, 57679814, 58424504}, + {915615866, 407750001, 1107710834, 3582615713, 3862889066, 1415288520, 3628236631, 168349523}, + {2111350289, 2943100942, 3392877341, 1921535090, 4166367410, 2599594553, 4185903226, 715377768}, + {2137913573, 1965320711, 1754791757, 2751319501, 2380735402, 4276995111, 698162415, 718679331}, + {1509598695, 2031797739, 4130415094, 2381967072, 3015081441, 3697011228, 2697538602, 48460231}, + {3603150538, 743034925, 3354687934, 1272577746, 1384952119, 1812465974, 2118924997, 662956621}, + {4072765093, 1966215951, 1578770679, 1762823766, 58175066, 2441689522, 2526369891, 165461959}, + {531665370, 3271631152, 2225586494, 2841730381, 3727639790, 4253915311, 528910984, 702471190}, + {3386979571, 4184997495, 1180866588, 3527441271, 4087196376, 2096016789, 2252488948, 392779089}, + {740698018, 3333626702, 2877130743, 1391243029, 3024462089, 100685480, 4197580281, 526275378}, + {2872401457, 2958610551, 2859578622, 556105564, 971083653, 1612005937, 2298572468, 469157852}, + {3681109803, 3541565356, 2618369383, 2642103620, 3924213757, 33559559, 1188328000, 58691787}, + {2992468691, 809647415, 3842146259, 1900856179, 487934145, 1782399274, 3566449727, 141200541}, + {333973969, 4251697854, 3725353197, 3153001822, 4031891849, 4214437106, 3395587720, 105042497}, + {1080718137, 505479843, 3897617877, 276079320, 3298431528, 967746687, 1134910301, 582028159}, + {3746007169, 287981736, 1619957469, 719877767, 1615487305, 2351918246, 746013752, 307736525}, + {3724814561, 711406, 1507910029, 3226582437, 2938513989, 3112241950, 601917810, 101396241}, + {330186988, 1484876677, 3689314519, 3050148098, 1146547227, 4063570155, 1524042033, 671208980}, + {84414193, 1736706693, 1462110590, 474823034, 2006586010, 4239641743, 552005968, 166605351}, + {2682607204, 3108324386, 1196961907, 3881302235, 1550711018, 4085512727, 2221028896, 430499088}, + {2382717787, 1762656943, 3032714891, 2543214961, 2003353136, 3342413010, 360914170, 71471545}, + {2991685069, 370072676, 1801343335, 3939927366, 533556254, 3460099817, 3626811103, 189847548}, + {544158540, 692544768, 2104902938, 194437846, 1545517236, 1345650773, 368870194, 604814212}, + {2267831451, 2342689297, 3029497490, 635796422, 313370717, 2208819618, 1936830542, 545179923}, + {1204069312, 162118119, 2304540202, 948141484, 2551583145, 3597458519, 2513742141, 125208380}, + {1595152083, 3892638617, 549840816, 2252399889, 3317891650, 3875364058, 414620482, 568479178}, + {1241085481, 2656387059, 2963923266, 4150774343, 3770411267, 4282380932, 232450342, 76966187}, + {4203385604, 2527564380, 3014770544, 2659456612, 1815799659, 1500650462, 4137106698, 332110358}, + {4203245377, 1407158826, 2210962765, 2404084829, 4234549103, 3485418953, 3373672533, 721825057}, + {1276600703, 466365582, 2373467282, 501424221, 1996770026, 3214722369, 29036755, 486982842}, + {4007331428, 933499895, 1826629588, 486263852, 1992359682, 1178560907, 2803259956, 181205313}, + {2735501369, 3047089899, 159554757, 1887661319, 4267060487, 1198704753, 1682117104, 46317092}, + {73802200, 1631385950, 1566817196, 2761880429, 894847607, 340186117, 1282432912, 548197887}, + {3021792345, 1565885488, 874346872, 962096747, 364734492, 2714350700, 1049014517, 440398419}, + {2057812450, 3715714502, 2624601698, 4287236073, 3119141580, 2906811182, 1123527827, 537888208}, + {2415538370, 872414306, 4156873540, 368838140, 3555846514, 211542189, 3617648261, 749725581}, + {143927639, 2402297145, 1874443352, 3195074622, 4102023538, 853380081, 1087880124, 233898744}, + {1740523175, 3242505699, 521460015, 3685268115, 2327276635, 3073883883, 2330877978, 795580498}, + {1760155380, 4024143843, 3039243352, 711680256, 1583541273, 3122177871, 3909200820, 607025917}, + {2582239983, 1794725826, 955371102, 2413673143, 393768164, 2607567850, 3090792987, 120882992}, + {1517867461, 3259044536, 2417828878, 1688019206, 4067667274, 2130202910, 3714714984, 691303128}, + {2456608441, 3288745736, 2107712096, 1046208946, 2361580709, 1049741184, 4220380399, 693587988}, + {3155328558, 3316681447, 1474793783, 2186205891, 1398183598, 1739357018, 2456255887, 594778236}}; if (number_of_blocks == 1024) { for (int i = 0; i < number_of_blocks; i++) { diff --git a/icicle/src/poseidon2/test_m31.cu b/icicle/src/poseidon2/test_m31.cu new file mode 100644 index 000000000..8d39e943c --- /dev/null +++ b/icicle/src/poseidon2/test_m31.cu @@ -0,0 +1,88 @@ +#include "gpu-utils/device_context.cuh" + +#ifndef __CUDA_ARCH__ +#include +#include +#include +#include + +#include "poseidon2/poseidon2.cuh" +using namespace poseidon2; + +#include "fields/field_config.cuh" +using namespace field_config; + +#include "hash/hash.cuh" + +#define T 16 + +#define START_TIMER(timer) auto timer##_start = std::chrono::high_resolution_clock::now(); +#define END_TIMER(timer, msg) \ + printf("%s: %.0f ms\n", msg, FpMilliseconds(std::chrono::high_resolution_clock::now() - timer##_start).count()); + +int main(int argc, char* argv[]) +{ + using FpMilliseconds = std::chrono::duration; + using FpMicroseconds = std::chrono::duration; + + // Load poseidon + START_TIMER(timer_const); + device_context::DeviceContext ctx = device_context::get_default_device_context(); + Poseidon2 poseidon(T, T, MdsType::DEFAULT_MDS, DiffusionStrategy::DEFAULT_DIFFUSION, ctx); + END_TIMER(timer_const, "Load poseidon constants"); + + int number_of_blocks = argc > 1 ? 1 << atoi(argv[1]) : 1024; + scalar_t* in_ptr = static_cast(malloc(number_of_blocks * T * sizeof(scalar_t))); + scalar_t* out_ptr = static_cast(malloc(number_of_blocks * sizeof(scalar_t))); + scalar_t input = scalar_t::zero(); + + hash::SpongeConfig cfg = hash::default_sponge_config(); + + size_t number_of_repetitions = argc > 2 ? 1 << atoi(argv[2]) : 32; + + // Prepare input data of [0, 1, 2 ... (number_of_blocks * arity) - 1] + for (uint32_t i = 0; i < number_of_blocks * T; i++) { + in_ptr[i] = input; + input = input + scalar_t::one(); + } + + // Warm up + poseidon.hash_many(in_ptr, out_ptr, number_of_blocks, T, 1, cfg); + + auto total_time_start = std::chrono::high_resolution_clock::now(); + size_t avg_time = 0; + for (int i = 0; i < number_of_repetitions; i++) { + auto poseidon_start = std::chrono::high_resolution_clock::now(); + poseidon.hash_many(in_ptr, out_ptr, number_of_blocks, T, 1, cfg); + avg_time += FpMilliseconds(std::chrono::high_resolution_clock::now() - poseidon_start).count(); + } + auto total_time = FpMilliseconds(std::chrono::high_resolution_clock::now() - total_time_start).count(); + + std::cout << "Block size: " << number_of_blocks << std::endl; + std::cout << "Total time: " << total_time << " ms" << std::endl; + std::cout << "Avg time: " << avg_time / number_of_repetitions << " ms" << std::endl; + + // for (int i = 0; i < number_of_blocks; i++) { + // std::cout << "{"; + // for (int j = 0; j < 8; j++) { + // std::cout << ((uint32_t*)&out_ptr[i].limbs_storage)[j]; + // if (j != 7) { std::cout << ", "; } + // } + // std::cout << "}," << std::endl; + // } + + if (number_of_blocks == 1024) { + for (int i = 0; i < number_of_blocks; i++) { +#ifdef DEBUG + // std::cout << out_ptr[i] << std::endl; +#endif + // assert((out_ptr[i] == expected[i])); + } + printf("Expected output matches\n"); + } + + free(in_ptr); + free(out_ptr); +} + +#endif \ No newline at end of file diff --git a/icicle/src/poseidon2/test_poseidon_m31 b/icicle/src/poseidon2/test_poseidon_m31 new file mode 100755 index 000000000..3358ecbcb Binary files /dev/null and b/icicle/src/poseidon2/test_poseidon_m31 differ diff --git a/icicle/src/vec_ops/vec_ops.cu b/icicle/src/vec_ops/vec_ops.cu index fef581ec0..9cfa85e60 100644 --- a/icicle/src/vec_ops/vec_ops.cu +++ b/icicle/src/vec_ops/vec_ops.cu @@ -165,7 +165,7 @@ namespace vec_ops { E* mat_out, uint32_t row_size, uint32_t column_size, - device_context::DeviceContext& ctx, + const device_context::DeviceContext& ctx, bool on_device, bool is_async) { diff --git a/scripts/gen_c_api.py b/scripts/gen_c_api.py index 26817a440..4e7fae795 100755 --- a/scripts/gen_c_api.py +++ b/scripts/gen_c_api.py @@ -77,6 +77,8 @@ COMMON_INCLUDES = [ '#include ', '#include "gpu-utils/device_context.cuh"', + '#include "merkle-tree/merkle.cuh"', + '#include "matrix/matrix.cuh"' ] WARN_TEXT = """\ @@ -114,10 +116,9 @@ includes.append('#include "msm/msm.cuh"') if any(header.name.startswith("vec_ops") for header in headers): includes.append('#include "vec_ops/vec_ops.cuh"') - if any(header.name.startswith("poseidon") for header in headers): + if any(header.name.startswith("poseidon.h") for header in headers): includes.append('#include "poseidon/poseidon.cuh"') - includes.append('#include "poseidon/tree/merkle.cuh"') - if any(header.name.startswith("poseidon2") for header in headers): + if any(header.name.startswith("poseidon2.h") for header in headers): includes.append('#include "poseidon2/poseidon2.cuh"') contents = WARN_TEXT + INCLUDE_ONCE.format(curve.upper()) + "\n".join(includes) + "\n\n" @@ -148,10 +149,9 @@ includes.append('#include "ntt/ntt.cuh"') if any(header.name.startswith("vec_ops") for header in headers): includes.append('#include "vec_ops/vec_ops.cuh"') - if any(header.name.startswith("poseidon") for header in headers): + if any(header.name.startswith("poseidon.h") for header in headers): includes.append('#include "poseidon/poseidon.cuh"') - includes.append('#include "poseidon/tree/merkle.cuh"') - if any(header.name.startswith("poseidon2") for header in headers): + if any(header.name.startswith("poseidon2.h") for header in headers): includes.append('#include "poseidon2/poseidon2.cuh"') contents = WARN_TEXT + INCLUDE_ONCE.format(field.upper()) + "\n".join(includes) + "\n\n" diff --git a/wrappers/golang/core/poseidon.go b/wrappers/golang/core/poseidon.go deleted file mode 100644 index bc62ef178..000000000 --- a/wrappers/golang/core/poseidon.go +++ /dev/null @@ -1,94 +0,0 @@ -package core - -import ( - "fmt" - "unsafe" - - cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" -) - -type PoseidonConfig struct { - /// Details related to the device such as its id and stream id. See [DeviceContext](@ref device_context::DeviceContext). - Ctx cr.DeviceContext - areInputsOnDevice bool - areOutputsOnDevice bool - ///If true, input is considered to be a states vector, holding the preimages in aligned or not aligned format. - ///Memory under the input pointer will be used for states. If false, fresh states memory will be allocated and input will be copied into it */ - InputIsAState bool - /// If true - input should be already aligned for poseidon permutation. - ///* Aligned format: [0, A, B, 0, C, D, ...] (as you might get by using loop_state) - ///* not aligned format: [A, B, 0, C, D, 0, ...] (as you might get from cudaMemcpy2D) */ - Aligned bool - ///If true, hash results will also be copied in the input pointer in aligned format - LoopState bool - ///Whether to run the Poseidon asynchronously. If set to `true`, the poseidon_hash function will be - ///non-blocking and you'd need to synchronize it explicitly by running `cudaStreamSynchronize` or `cudaDeviceSynchronize`. - ///If set to false, the poseidon_hash function will block the current CPU thread. */ - IsAsync bool -} - -type PoseidonConstants[T any] struct { - Arity int32 - PartialRounds int32 - FullRoundsHalf int32 - RoundConstants unsafe.Pointer - MdsMatrix unsafe.Pointer - NonSparseMatrix unsafe.Pointer - SparseMatrices unsafe.Pointer - DomainTag T -} - -func GetDefaultPoseidonConfig() PoseidonConfig { - ctx, _ := cr.GetDefaultDeviceContext() - return PoseidonConfig{ - ctx, // Ctx - false, // areInputsOnDevice - false, // areOutputsOnDevice - false, // inputIsAState - false, // aligned - false, // loopState - false, // IsAsync - } -} - -func PoseidonCheck[T any](input, output HostOrDeviceSlice, cfg *PoseidonConfig, constants *PoseidonConstants[T], numberOfStates int) (unsafe.Pointer, unsafe.Pointer, unsafe.Pointer) { - inputLen, outputLen := input.Len(), output.Len() - arity := int(constants.Arity) - expectedInputLen := arity * numberOfStates - if cfg.InputIsAState { - expectedInputLen += numberOfStates - } - - if inputLen != expectedInputLen { - errorString := fmt.Sprintf( - "input is not the right length for the given parameters: %d, should be: %d", - inputLen, - arity*numberOfStates, - ) - panic(errorString) - } - - if outputLen != numberOfStates { - errorString := fmt.Sprintf( - "output is not the right length for the given parameters: %d, should be: %d", - outputLen, - numberOfStates, - ) - panic(errorString) - } - cfg.areInputsOnDevice = input.IsOnDevice() - cfg.areOutputsOnDevice = output.IsOnDevice() - - if input.IsOnDevice() { - input.(DeviceSlice).CheckDevice() - - } - - if output.IsOnDevice() { - output.(DeviceSlice).CheckDevice() - } - - cfgPointer := unsafe.Pointer(cfg) - - return input.AsUnsafePointer(), output.AsUnsafePointer(), cfgPointer -} diff --git a/wrappers/golang/core/sponge.go b/wrappers/golang/core/sponge.go new file mode 100644 index 000000000..aec2c674b --- /dev/null +++ b/wrappers/golang/core/sponge.go @@ -0,0 +1,105 @@ +package core + +import ( + "fmt" + + cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" +) + +type SpongeConfig struct { + /// Details related to the device such as its id and stream. + Ctx cr.DeviceContext + + areInputsOnDevice bool + areResultsOnDevice bool + + InputRate uint32 + OutputRate uint32 + Offset uint32 + + /// If true - input should be already aligned for poseidon permutation. + /// Aligned format: [0, A, B, 0, C, D, ...] (as you might get by using loop_state) + /// not aligned format: [A, B, 0, C, D, 0, ...] (as you might get from cudaMemcpy2D) + RecursiveSqueeze bool + + /// If true, hash results will also be copied in the input pointer in aligned format + Aligned bool + + /// Whether to run the SpongeHash asynchronously. If set to `true`, the SpongeHash function will be non-blocking + /// and you'd need to synchronize it explicitly by running `cudaStreamSynchronize` or `cudaDeviceSynchronize`. + /// If set to `false`, the SpongeHash function will block the current CPU thread. + IsAsync bool +} + +func GetDefaultSpongeConfig() SpongeConfig { + ctx, _ := cr.GetDefaultDeviceContext() + return SpongeConfig{ + ctx, + false, + false, + 0, + 0, + 0, + false, + false, + false, + } +} + +func SpongeInputCheck(inputs HostOrDeviceSlice, numberOfStates, inputBlockLength, inputRate uint32, ctx *cr.DeviceContext) { + if inputBlockLength > inputRate { + errorString := fmt.Sprintf( + "Input block (%d) can't be greater than input rate (%d)", + inputBlockLength, + inputRate, + ) + panic(errorString) + } + inputsSizeExpected := inputBlockLength * numberOfStates + if inputs.Len() < int(inputsSizeExpected) { + errorString := fmt.Sprintf( + "inputs len is %d; but needs to be at least %d", + inputs.Len(), + inputsSizeExpected, + ) + panic(errorString) + } + if inputs.IsOnDevice() { + inputs.(DeviceSlice).CheckDevice() + } +} + +func SpongeStatesCheck(states DeviceSlice, numberOfStates, width uint32, ctx *cr.DeviceContext) { + + statesSizeExpected := width * numberOfStates + if states.Len() < int(statesSizeExpected) { + errorString := fmt.Sprintf( + "inputs len is %d; but needs to be at least %d", + states.Len(), + statesSizeExpected, + ) + panic(errorString) + } + states.CheckDevice() +} + +func SpongeOutputsCheck(outputs HostOrDeviceSlice, numberOfStates, outputLen, width uint32, recursive bool, ctx *cr.DeviceContext) { + var outputsSizeExpected uint32 + if recursive { + outputsSizeExpected = width * numberOfStates + } else { + outputsSizeExpected = outputLen * numberOfStates + } + + if outputs.Len() < int(outputsSizeExpected) { + errorString := fmt.Sprintf( + "outputs len is %d; but needs to be at least %d", + outputs.Len(), + outputsSizeExpected, + ) + panic(errorString) + } + if outputs.IsOnDevice() { + outputs.(DeviceSlice).CheckDevice() + } +} diff --git a/wrappers/golang/curves/bls12377/poseidon/include/poseidon.h b/wrappers/golang/curves/bls12377/poseidon/include/poseidon.h index 625f4f189..eb31b50d5 100644 --- a/wrappers/golang/curves/bls12377/poseidon/include/poseidon.h +++ b/wrappers/golang/curves/bls12377/poseidon/include/poseidon.h @@ -9,14 +9,40 @@ extern "C" { #endif typedef struct scalar_t scalar_t; -typedef struct PoseidonConfig PoseidonConfig; typedef struct DeviceContext DeviceContext; -typedef struct PoseidonConstants PoseidonConstants; +typedef struct TreeBuilderConfig TreeBuilderConfig; +typedef struct PoseidonInst PoseidonInst; +typedef struct SpongeConfig SpongeConfig; -cudaError_t bls12_377_poseidon_hash_cuda(const scalar_t* input, scalar_t* output, int number_of_states, int arity, PoseidonConstants* constants, PoseidonConfig* config); -cudaError_t bls12_377_create_optimized_poseidon_constants_cuda(int arity, int full_rounds_halfs, int partial_rounds, const scalar_t* constants, DeviceContext* ctx, PoseidonConstants* poseidon_constants); -cudaError_t bls12_377_init_optimized_poseidon_constants_cuda(int arity, DeviceContext* ctx, PoseidonConstants* constants); +cudaError_t bls12_377_poseidon_create_cuda( + PoseidonInst** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const scalar_t* round_constants, + const scalar_t* mds_matrix, + const scalar_t* non_sparse_matrix, + const scalar_t* sparse_matrices, + const scalar_t* domain_tag, + DeviceContext* ctx); + +cudaError_t bls12_377_poseidon_load_cuda( + PoseidonInst** poseidon, + unsigned int arity, + DeviceContext* ctx); + +cudaError_t bls12_377_poseidon_hash_many_cuda( + const PoseidonInst* poseidon, + const scalar_t* inputs, + scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + SpongeConfig* cfg); + +cudaError_t bls12_377_poseidon_delete_cuda(PoseidonInst* poseidon); #ifdef __cplusplus } diff --git a/wrappers/golang/curves/bls12377/poseidon/poseidon.go b/wrappers/golang/curves/bls12377/poseidon/poseidon.go index 5b452827b..da57bbdec 100644 --- a/wrappers/golang/curves/bls12377/poseidon/poseidon.go +++ b/wrappers/golang/curves/bls12377/poseidon/poseidon.go @@ -3,55 +3,85 @@ package poseidon // #cgo CFLAGS: -I./include/ // #include "poseidon.h" import "C" - import ( + "runtime" "unsafe" "github.com/ingonyama-zk/icicle/v2/wrappers/golang/core" cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" + bls12_377 "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bls12377" ) -func GetDefaultPoseidonConfig() core.PoseidonConfig { - return core.GetDefaultPoseidonConfig() +type PoseidonHandler = C.struct_PoseidonInst +type Poseidon struct { + width uint32 + handle *PoseidonHandler } -func PoseidonHash[T any](scalars, results core.HostOrDeviceSlice, numberOfStates int, cfg *core.PoseidonConfig, constants *core.PoseidonConstants[T]) core.IcicleError { - scalarsPointer, resultsPointer, cfgPointer := core.PoseidonCheck(scalars, results, cfg, constants, numberOfStates) +func Create(arity uint32, alpha uint32, fullRoundsHalf uint32, partialRounds uint32, scalars core.HostOrDeviceSlice, mdsMatrix core.HostOrDeviceSlice, nonSparseMatrix core.HostOrDeviceSlice, sparseMatrices core.HostOrDeviceSlice, domainTag bls12_377.ScalarField, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cAlpha := (C.uint)(alpha) + cFullRoundsHalf := (C.uint)(fullRoundsHalf) + cPartialRounds := (C.uint)(partialRounds) + cScalars := (*C.scalar_t)(scalars.AsUnsafePointer()) + cMdsMatrix := (*C.scalar_t)(mdsMatrix.AsUnsafePointer()) + cNonSparseMatrix := (*C.scalar_t)(nonSparseMatrix.AsUnsafePointer()) + cSparseMatrices := (*C.scalar_t)(sparseMatrices.AsUnsafePointer()) + cDomainTag := (*C.scalar_t)(unsafe.Pointer(&domainTag)) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.bls12_377_poseidon_create_cuda(&poseidon, cArity, cAlpha, cFullRoundsHalf, cPartialRounds, cScalars, cMdsMatrix, cNonSparseMatrix, cSparseMatrices, cDomainTag, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - cScalars := (*C.scalar_t)(scalarsPointer) - cResults := (*C.scalar_t)(resultsPointer) - cNumberOfStates := (C.int)(numberOfStates) - cArity := (C.int)(constants.Arity) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - cCfg := (*C.PoseidonConfig)(cfgPointer) +func Load(arity uint32, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.bls12_377_poseidon_load_cuda(&poseidon, cArity, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - __ret := C.bls12_377_poseidon_hash_cuda(cScalars, cResults, cNumberOfStates, cArity, cConstants, cCfg) +func (poseidon *Poseidon) HashMany(inputs core.HostOrDeviceSlice, output core.HostOrDeviceSlice, numberOfStates uint32, inputBlockLen uint32, outputLen uint32, cfg *core.SpongeConfig) core.IcicleError { + core.SpongeInputCheck(inputs, numberOfStates, inputBlockLen, cfg.InputRate, &cfg.Ctx) + core.SpongeOutputsCheck(output, numberOfStates, outputLen, poseidon.width, false, &cfg.Ctx) + cInputs := (*C.scalar_t)(inputs.AsUnsafePointer()) + cOutput := (*C.scalar_t)(output.AsUnsafePointer()) + cNumberOfStates := (C.uint)(numberOfStates) + cInputBlockLen := (C.uint)(inputBlockLen) + cOutputLen := (C.uint)(outputLen) + cCfg := (*C.SpongeConfig)(unsafe.Pointer(cfg)) + __ret := C.bls12_377_poseidon_hash_many_cuda(poseidon.handle, cInputs, cOutput, cNumberOfStates, cInputBlockLen, cOutputLen, cCfg) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func CreateOptimizedPoseidonConstants[T any](arity, fullRoundsHalfs, partialRounds int, constants core.HostOrDeviceSlice, ctx cr.DeviceContext, poseidonConstants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cFullRoundsHalfs := (C.int)(fullRoundsHalfs) - cPartialRounds := (C.int)(partialRounds) - cConstants := (*C.scalar_t)(constants.AsUnsafePointer()) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cPoseidonConstants := (*C.PoseidonConstants)(unsafe.Pointer(poseidonConstants)) - - __ret := C.bls12_377_create_optimized_poseidon_constants_cuda(cArity, cFullRoundsHalfs, cPartialRounds, cConstants, cCtx, cPoseidonConstants) +func (poseidon *Poseidon) Delete() core.IcicleError { + __ret := C.bls12_377_poseidon_delete_cuda(poseidon.handle) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func InitOptimizedPoseidonConstantsCuda[T any](arity int, ctx cr.DeviceContext, constants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - - __ret := C.bls12_377_init_optimized_poseidon_constants_cuda(cArity, cCtx, cConstants) - err := (cr.CudaError)(__ret) - return core.FromCudaError(err) +func (poseidon *Poseidon) GetDefaultSpongeConfig() core.SpongeConfig { + cfg := core.GetDefaultSpongeConfig() + cfg.InputRate = poseidon.width - 1 + cfg.OutputRate = poseidon.width + return cfg } diff --git a/wrappers/golang/curves/bls12377/tests/poseidon_test.go b/wrappers/golang/curves/bls12377/tests/poseidon_test.go index b768fa291..773fe868d 100644 --- a/wrappers/golang/curves/bls12377/tests/poseidon_test.go +++ b/wrappers/golang/curves/bls12377/tests/poseidon_test.go @@ -7,6 +7,7 @@ import ( cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" bls12_377 "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bls12377" poseidon "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bls12377/poseidon" + "github.com/stretchr/testify/assert" ) func TestPoseidon(t *testing.T) { @@ -14,14 +15,11 @@ func TestPoseidon(t *testing.T) { arity := 2 numberOfStates := 1 - cfg := poseidon.GetDefaultPoseidonConfig() - cfg.IsAsync = true - stream, _ := cr.CreateStream() - cfg.Ctx.Stream = &stream + ctx, _ := cr.GetDefaultDeviceContext() + p, err := poseidon.Load(uint32(arity), &ctx) + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) - var constants core.PoseidonConstants[bls12_377.ScalarField] - - poseidon.InitOptimizedPoseidonConstantsCuda(arity, cfg.Ctx, &constants) //generate constants + cfg := p.GetDefaultSpongeConfig() scalars := bls12_377.GenerateScalars(numberOfStates * arity) scalars[0] = scalars[0].Zero() @@ -30,13 +28,13 @@ func TestPoseidon(t *testing.T) { scalarsCopy := core.HostSliceFromElements(scalars[:numberOfStates*arity]) var deviceInput core.DeviceSlice - scalarsCopy.CopyToDeviceAsync(&deviceInput, stream, true) + scalarsCopy.CopyToDevice(&deviceInput, true) var deviceOutput core.DeviceSlice - deviceOutput.MallocAsync(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement(), stream) + deviceOutput.Malloc(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement()) - poseidon.PoseidonHash(deviceInput, deviceOutput, numberOfStates, &cfg, &constants) //run Hash function + err = p.HashMany(deviceInput, deviceOutput, uint32(numberOfStates), 1, 1, &cfg) //run Hash function + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) output := make(core.HostSlice[bls12_377.ScalarField], numberOfStates) - output.CopyFromDeviceAsync(&deviceOutput, stream) - + output.CopyFromDevice(&deviceOutput) } diff --git a/wrappers/golang/curves/bls12381/poseidon/include/poseidon.h b/wrappers/golang/curves/bls12381/poseidon/include/poseidon.h index 1372013ef..2bc41ddae 100644 --- a/wrappers/golang/curves/bls12381/poseidon/include/poseidon.h +++ b/wrappers/golang/curves/bls12381/poseidon/include/poseidon.h @@ -9,14 +9,40 @@ extern "C" { #endif typedef struct scalar_t scalar_t; -typedef struct PoseidonConfig PoseidonConfig; typedef struct DeviceContext DeviceContext; -typedef struct PoseidonConstants PoseidonConstants; +typedef struct TreeBuilderConfig TreeBuilderConfig; +typedef struct PoseidonInst PoseidonInst; +typedef struct SpongeConfig SpongeConfig; -cudaError_t bls12_381_poseidon_hash_cuda(const scalar_t* input, scalar_t* output, int number_of_states, int arity, PoseidonConstants* constants, PoseidonConfig* config); -cudaError_t bls12_381_create_optimized_poseidon_constants_cuda(int arity, int full_rounds_halfs, int partial_rounds, const scalar_t* constants, DeviceContext* ctx, PoseidonConstants* poseidon_constants); -cudaError_t bls12_381_init_optimized_poseidon_constants_cuda(int arity, DeviceContext* ctx, PoseidonConstants* constants); +cudaError_t bls12_381_poseidon_create_cuda( + PoseidonInst** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const scalar_t* round_constants, + const scalar_t* mds_matrix, + const scalar_t* non_sparse_matrix, + const scalar_t* sparse_matrices, + const scalar_t* domain_tag, + DeviceContext* ctx); + +cudaError_t bls12_381_poseidon_load_cuda( + PoseidonInst** poseidon, + unsigned int arity, + DeviceContext* ctx); + +cudaError_t bls12_381_poseidon_hash_many_cuda( + const PoseidonInst* poseidon, + const scalar_t* inputs, + scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + SpongeConfig* cfg); + +cudaError_t bls12_381_poseidon_delete_cuda(PoseidonInst* poseidon); #ifdef __cplusplus } diff --git a/wrappers/golang/curves/bls12381/poseidon/poseidon.go b/wrappers/golang/curves/bls12381/poseidon/poseidon.go index 1f99b2b51..615898f25 100644 --- a/wrappers/golang/curves/bls12381/poseidon/poseidon.go +++ b/wrappers/golang/curves/bls12381/poseidon/poseidon.go @@ -3,55 +3,85 @@ package poseidon // #cgo CFLAGS: -I./include/ // #include "poseidon.h" import "C" - import ( + "runtime" "unsafe" "github.com/ingonyama-zk/icicle/v2/wrappers/golang/core" cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" + bls12_381 "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bls12381" ) -func GetDefaultPoseidonConfig() core.PoseidonConfig { - return core.GetDefaultPoseidonConfig() +type PoseidonHandler = C.struct_PoseidonInst +type Poseidon struct { + width uint32 + handle *PoseidonHandler } -func PoseidonHash[T any](scalars, results core.HostOrDeviceSlice, numberOfStates int, cfg *core.PoseidonConfig, constants *core.PoseidonConstants[T]) core.IcicleError { - scalarsPointer, resultsPointer, cfgPointer := core.PoseidonCheck(scalars, results, cfg, constants, numberOfStates) +func Create(arity uint32, alpha uint32, fullRoundsHalf uint32, partialRounds uint32, scalars core.HostOrDeviceSlice, mdsMatrix core.HostOrDeviceSlice, nonSparseMatrix core.HostOrDeviceSlice, sparseMatrices core.HostOrDeviceSlice, domainTag bls12_381.ScalarField, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cAlpha := (C.uint)(alpha) + cFullRoundsHalf := (C.uint)(fullRoundsHalf) + cPartialRounds := (C.uint)(partialRounds) + cScalars := (*C.scalar_t)(scalars.AsUnsafePointer()) + cMdsMatrix := (*C.scalar_t)(mdsMatrix.AsUnsafePointer()) + cNonSparseMatrix := (*C.scalar_t)(nonSparseMatrix.AsUnsafePointer()) + cSparseMatrices := (*C.scalar_t)(sparseMatrices.AsUnsafePointer()) + cDomainTag := (*C.scalar_t)(unsafe.Pointer(&domainTag)) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.bls12_381_poseidon_create_cuda(&poseidon, cArity, cAlpha, cFullRoundsHalf, cPartialRounds, cScalars, cMdsMatrix, cNonSparseMatrix, cSparseMatrices, cDomainTag, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - cScalars := (*C.scalar_t)(scalarsPointer) - cResults := (*C.scalar_t)(resultsPointer) - cNumberOfStates := (C.int)(numberOfStates) - cArity := (C.int)(constants.Arity) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - cCfg := (*C.PoseidonConfig)(cfgPointer) +func Load(arity uint32, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.bls12_381_poseidon_load_cuda(&poseidon, cArity, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - __ret := C.bls12_381_poseidon_hash_cuda(cScalars, cResults, cNumberOfStates, cArity, cConstants, cCfg) +func (poseidon *Poseidon) HashMany(inputs core.HostOrDeviceSlice, output core.HostOrDeviceSlice, numberOfStates uint32, inputBlockLen uint32, outputLen uint32, cfg *core.SpongeConfig) core.IcicleError { + core.SpongeInputCheck(inputs, numberOfStates, inputBlockLen, cfg.InputRate, &cfg.Ctx) + core.SpongeOutputsCheck(output, numberOfStates, outputLen, poseidon.width, false, &cfg.Ctx) + cInputs := (*C.scalar_t)(inputs.AsUnsafePointer()) + cOutput := (*C.scalar_t)(output.AsUnsafePointer()) + cNumberOfStates := (C.uint)(numberOfStates) + cInputBlockLen := (C.uint)(inputBlockLen) + cOutputLen := (C.uint)(outputLen) + cCfg := (*C.SpongeConfig)(unsafe.Pointer(cfg)) + __ret := C.bls12_381_poseidon_hash_many_cuda(poseidon.handle, cInputs, cOutput, cNumberOfStates, cInputBlockLen, cOutputLen, cCfg) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func CreateOptimizedPoseidonConstants[T any](arity, fullRoundsHalfs, partialRounds int, constants core.HostOrDeviceSlice, ctx cr.DeviceContext, poseidonConstants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cFullRoundsHalfs := (C.int)(fullRoundsHalfs) - cPartialRounds := (C.int)(partialRounds) - cConstants := (*C.scalar_t)(constants.AsUnsafePointer()) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cPoseidonConstants := (*C.PoseidonConstants)(unsafe.Pointer(poseidonConstants)) - - __ret := C.bls12_381_create_optimized_poseidon_constants_cuda(cArity, cFullRoundsHalfs, cPartialRounds, cConstants, cCtx, cPoseidonConstants) +func (poseidon *Poseidon) Delete() core.IcicleError { + __ret := C.bls12_381_poseidon_delete_cuda(poseidon.handle) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func InitOptimizedPoseidonConstantsCuda[T any](arity int, ctx cr.DeviceContext, constants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - - __ret := C.bls12_381_init_optimized_poseidon_constants_cuda(cArity, cCtx, cConstants) - err := (cr.CudaError)(__ret) - return core.FromCudaError(err) +func (poseidon *Poseidon) GetDefaultSpongeConfig() core.SpongeConfig { + cfg := core.GetDefaultSpongeConfig() + cfg.InputRate = poseidon.width - 1 + cfg.OutputRate = poseidon.width + return cfg } diff --git a/wrappers/golang/curves/bls12381/tests/poseidon_test.go b/wrappers/golang/curves/bls12381/tests/poseidon_test.go index 915e89574..55fe02dec 100644 --- a/wrappers/golang/curves/bls12381/tests/poseidon_test.go +++ b/wrappers/golang/curves/bls12381/tests/poseidon_test.go @@ -7,29 +7,19 @@ import ( cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" bls12_381 "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bls12381" poseidon "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bls12381/poseidon" - - "fmt" "github.com/stretchr/testify/assert" ) -func formatOutput(x bls12_381.ScalarField) string { - r := x.GetLimbs() - return fmt.Sprintf("%08x%08x%08x%08x%08x%08x%08x%08x", r[7], r[6], r[5], r[4], r[3], r[2], r[1], r[0]) -} - func TestPoseidon(t *testing.T) { arity := 2 numberOfStates := 1 - cfg := poseidon.GetDefaultPoseidonConfig() - cfg.IsAsync = true - stream, _ := cr.CreateStream() - cfg.Ctx.Stream = &stream - - var constants core.PoseidonConstants[bls12_381.ScalarField] + ctx, _ := cr.GetDefaultDeviceContext() + p, err := poseidon.Load(uint32(arity), &ctx) + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) - poseidon.InitOptimizedPoseidonConstantsCuda(arity, cfg.Ctx, &constants) //generate constants + cfg := p.GetDefaultSpongeConfig() scalars := bls12_381.GenerateScalars(numberOfStates * arity) scalars[0] = scalars[0].Zero() @@ -38,18 +28,13 @@ func TestPoseidon(t *testing.T) { scalarsCopy := core.HostSliceFromElements(scalars[:numberOfStates*arity]) var deviceInput core.DeviceSlice - scalarsCopy.CopyToDeviceAsync(&deviceInput, stream, true) + scalarsCopy.CopyToDevice(&deviceInput, true) var deviceOutput core.DeviceSlice - deviceOutput.MallocAsync(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement(), stream) + deviceOutput.Malloc(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement()) - poseidon.PoseidonHash(deviceInput, deviceOutput, numberOfStates, &cfg, &constants) //run Hash function + err = p.HashMany(deviceInput, deviceOutput, uint32(numberOfStates), 1, 1, &cfg) //run Hash function + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) output := make(core.HostSlice[bls12_381.ScalarField], numberOfStates) - output.CopyFromDeviceAsync(&deviceOutput, stream) - - expectedString := "48fe0b1331196f6cdb33a7c6e5af61b76fd388e1ef1d3d418be5147f0e4613d4" //This result is from https://github.com/triplewz/poseidon - outputString := formatOutput(output[0]) - - assert.Equal(t, outputString, expectedString, "Poseidon hash does not match expected result") - + output.CopyFromDevice(&deviceOutput) } diff --git a/wrappers/golang/curves/bn254/poseidon/include/poseidon.h b/wrappers/golang/curves/bn254/poseidon/include/poseidon.h index 5d63920d6..2bce4006c 100644 --- a/wrappers/golang/curves/bn254/poseidon/include/poseidon.h +++ b/wrappers/golang/curves/bn254/poseidon/include/poseidon.h @@ -9,14 +9,40 @@ extern "C" { #endif typedef struct scalar_t scalar_t; -typedef struct PoseidonConfig PoseidonConfig; typedef struct DeviceContext DeviceContext; -typedef struct PoseidonConstants PoseidonConstants; +typedef struct TreeBuilderConfig TreeBuilderConfig; +typedef struct PoseidonInst PoseidonInst; +typedef struct SpongeConfig SpongeConfig; -cudaError_t bn254_poseidon_hash_cuda(const scalar_t* input, scalar_t* output, int number_of_states, int arity, PoseidonConstants* constants, PoseidonConfig* config); -cudaError_t bn254_create_optimized_poseidon_constants_cuda(int arity, int full_rounds_halfs, int partial_rounds, const scalar_t* constants, DeviceContext* ctx, PoseidonConstants* poseidon_constants); -cudaError_t bn254_init_optimized_poseidon_constants_cuda(int arity, DeviceContext* ctx, PoseidonConstants* constants); +cudaError_t bn254_poseidon_create_cuda( + PoseidonInst** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const scalar_t* round_constants, + const scalar_t* mds_matrix, + const scalar_t* non_sparse_matrix, + const scalar_t* sparse_matrices, + const scalar_t* domain_tag, + DeviceContext* ctx); + +cudaError_t bn254_poseidon_load_cuda( + PoseidonInst** poseidon, + unsigned int arity, + DeviceContext* ctx); + +cudaError_t bn254_poseidon_hash_many_cuda( + const PoseidonInst* poseidon, + const scalar_t* inputs, + scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + SpongeConfig* cfg); + +cudaError_t bn254_poseidon_delete_cuda(PoseidonInst* poseidon); #ifdef __cplusplus } diff --git a/wrappers/golang/curves/bn254/poseidon/poseidon.go b/wrappers/golang/curves/bn254/poseidon/poseidon.go index e5724e80f..23744d0ba 100644 --- a/wrappers/golang/curves/bn254/poseidon/poseidon.go +++ b/wrappers/golang/curves/bn254/poseidon/poseidon.go @@ -3,55 +3,85 @@ package poseidon // #cgo CFLAGS: -I./include/ // #include "poseidon.h" import "C" - import ( + "runtime" "unsafe" "github.com/ingonyama-zk/icicle/v2/wrappers/golang/core" cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" + bn254 "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bn254" ) -func GetDefaultPoseidonConfig() core.PoseidonConfig { - return core.GetDefaultPoseidonConfig() +type PoseidonHandler = C.struct_PoseidonInst +type Poseidon struct { + width uint32 + handle *PoseidonHandler } -func PoseidonHash[T any](scalars, results core.HostOrDeviceSlice, numberOfStates int, cfg *core.PoseidonConfig, constants *core.PoseidonConstants[T]) core.IcicleError { - scalarsPointer, resultsPointer, cfgPointer := core.PoseidonCheck(scalars, results, cfg, constants, numberOfStates) +func Create(arity uint32, alpha uint32, fullRoundsHalf uint32, partialRounds uint32, scalars core.HostOrDeviceSlice, mdsMatrix core.HostOrDeviceSlice, nonSparseMatrix core.HostOrDeviceSlice, sparseMatrices core.HostOrDeviceSlice, domainTag bn254.ScalarField, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cAlpha := (C.uint)(alpha) + cFullRoundsHalf := (C.uint)(fullRoundsHalf) + cPartialRounds := (C.uint)(partialRounds) + cScalars := (*C.scalar_t)(scalars.AsUnsafePointer()) + cMdsMatrix := (*C.scalar_t)(mdsMatrix.AsUnsafePointer()) + cNonSparseMatrix := (*C.scalar_t)(nonSparseMatrix.AsUnsafePointer()) + cSparseMatrices := (*C.scalar_t)(sparseMatrices.AsUnsafePointer()) + cDomainTag := (*C.scalar_t)(unsafe.Pointer(&domainTag)) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.bn254_poseidon_create_cuda(&poseidon, cArity, cAlpha, cFullRoundsHalf, cPartialRounds, cScalars, cMdsMatrix, cNonSparseMatrix, cSparseMatrices, cDomainTag, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - cScalars := (*C.scalar_t)(scalarsPointer) - cResults := (*C.scalar_t)(resultsPointer) - cNumberOfStates := (C.int)(numberOfStates) - cArity := (C.int)(constants.Arity) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - cCfg := (*C.PoseidonConfig)(cfgPointer) +func Load(arity uint32, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.bn254_poseidon_load_cuda(&poseidon, cArity, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - __ret := C.bn254_poseidon_hash_cuda(cScalars, cResults, cNumberOfStates, cArity, cConstants, cCfg) +func (poseidon *Poseidon) HashMany(inputs core.HostOrDeviceSlice, output core.HostOrDeviceSlice, numberOfStates uint32, inputBlockLen uint32, outputLen uint32, cfg *core.SpongeConfig) core.IcicleError { + core.SpongeInputCheck(inputs, numberOfStates, inputBlockLen, cfg.InputRate, &cfg.Ctx) + core.SpongeOutputsCheck(output, numberOfStates, outputLen, poseidon.width, false, &cfg.Ctx) + cInputs := (*C.scalar_t)(inputs.AsUnsafePointer()) + cOutput := (*C.scalar_t)(output.AsUnsafePointer()) + cNumberOfStates := (C.uint)(numberOfStates) + cInputBlockLen := (C.uint)(inputBlockLen) + cOutputLen := (C.uint)(outputLen) + cCfg := (*C.SpongeConfig)(unsafe.Pointer(cfg)) + __ret := C.bn254_poseidon_hash_many_cuda(poseidon.handle, cInputs, cOutput, cNumberOfStates, cInputBlockLen, cOutputLen, cCfg) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func CreateOptimizedPoseidonConstants[T any](arity, fullRoundsHalfs, partialRounds int, constants core.HostOrDeviceSlice, ctx cr.DeviceContext, poseidonConstants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cFullRoundsHalfs := (C.int)(fullRoundsHalfs) - cPartialRounds := (C.int)(partialRounds) - cConstants := (*C.scalar_t)(constants.AsUnsafePointer()) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cPoseidonConstants := (*C.PoseidonConstants)(unsafe.Pointer(poseidonConstants)) - - __ret := C.bn254_create_optimized_poseidon_constants_cuda(cArity, cFullRoundsHalfs, cPartialRounds, cConstants, cCtx, cPoseidonConstants) +func (poseidon *Poseidon) Delete() core.IcicleError { + __ret := C.bn254_poseidon_delete_cuda(poseidon.handle) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func InitOptimizedPoseidonConstantsCuda[T any](arity int, ctx cr.DeviceContext, constants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - - __ret := C.bn254_init_optimized_poseidon_constants_cuda(cArity, cCtx, cConstants) - err := (cr.CudaError)(__ret) - return core.FromCudaError(err) +func (poseidon *Poseidon) GetDefaultSpongeConfig() core.SpongeConfig { + cfg := core.GetDefaultSpongeConfig() + cfg.InputRate = poseidon.width - 1 + cfg.OutputRate = poseidon.width + return cfg } diff --git a/wrappers/golang/curves/bn254/tests/poseidon_test.go b/wrappers/golang/curves/bn254/tests/poseidon_test.go index 0564841f0..24c80ec88 100644 --- a/wrappers/golang/curves/bn254/tests/poseidon_test.go +++ b/wrappers/golang/curves/bn254/tests/poseidon_test.go @@ -7,6 +7,7 @@ import ( cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" bn254 "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bn254" poseidon "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bn254/poseidon" + "github.com/stretchr/testify/assert" ) func TestPoseidon(t *testing.T) { @@ -14,14 +15,11 @@ func TestPoseidon(t *testing.T) { arity := 2 numberOfStates := 1 - cfg := poseidon.GetDefaultPoseidonConfig() - cfg.IsAsync = true - stream, _ := cr.CreateStream() - cfg.Ctx.Stream = &stream + ctx, _ := cr.GetDefaultDeviceContext() + p, err := poseidon.Load(uint32(arity), &ctx) + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) - var constants core.PoseidonConstants[bn254.ScalarField] - - poseidon.InitOptimizedPoseidonConstantsCuda(arity, cfg.Ctx, &constants) //generate constants + cfg := p.GetDefaultSpongeConfig() scalars := bn254.GenerateScalars(numberOfStates * arity) scalars[0] = scalars[0].Zero() @@ -30,13 +28,13 @@ func TestPoseidon(t *testing.T) { scalarsCopy := core.HostSliceFromElements(scalars[:numberOfStates*arity]) var deviceInput core.DeviceSlice - scalarsCopy.CopyToDeviceAsync(&deviceInput, stream, true) + scalarsCopy.CopyToDevice(&deviceInput, true) var deviceOutput core.DeviceSlice - deviceOutput.MallocAsync(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement(), stream) + deviceOutput.Malloc(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement()) - poseidon.PoseidonHash(deviceInput, deviceOutput, numberOfStates, &cfg, &constants) //run Hash function + err = p.HashMany(deviceInput, deviceOutput, uint32(numberOfStates), 1, 1, &cfg) //run Hash function + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) output := make(core.HostSlice[bn254.ScalarField], numberOfStates) - output.CopyFromDeviceAsync(&deviceOutput, stream) - + output.CopyFromDevice(&deviceOutput) } diff --git a/wrappers/golang/curves/bw6761/poseidon/include/poseidon.h b/wrappers/golang/curves/bw6761/poseidon/include/poseidon.h index 1731d1058..0bfcb554e 100644 --- a/wrappers/golang/curves/bw6761/poseidon/include/poseidon.h +++ b/wrappers/golang/curves/bw6761/poseidon/include/poseidon.h @@ -9,14 +9,40 @@ extern "C" { #endif typedef struct scalar_t scalar_t; -typedef struct PoseidonConfig PoseidonConfig; typedef struct DeviceContext DeviceContext; -typedef struct PoseidonConstants PoseidonConstants; +typedef struct TreeBuilderConfig TreeBuilderConfig; +typedef struct PoseidonInst PoseidonInst; +typedef struct SpongeConfig SpongeConfig; -cudaError_t bw6_761_poseidon_hash_cuda(const scalar_t* input, scalar_t* output, int number_of_states, int arity, PoseidonConstants* constants, PoseidonConfig* config); -cudaError_t bw6_761_create_optimized_poseidon_constants_cuda(int arity, int full_rounds_halfs, int partial_rounds, const scalar_t* constants, DeviceContext* ctx, PoseidonConstants* poseidon_constants); -cudaError_t bw6_761_init_optimized_poseidon_constants_cuda(int arity, DeviceContext* ctx, PoseidonConstants* constants); +cudaError_t bw6_761_poseidon_create_cuda( + PoseidonInst** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const scalar_t* round_constants, + const scalar_t* mds_matrix, + const scalar_t* non_sparse_matrix, + const scalar_t* sparse_matrices, + const scalar_t* domain_tag, + DeviceContext* ctx); + +cudaError_t bw6_761_poseidon_load_cuda( + PoseidonInst** poseidon, + unsigned int arity, + DeviceContext* ctx); + +cudaError_t bw6_761_poseidon_hash_many_cuda( + const PoseidonInst* poseidon, + const scalar_t* inputs, + scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + SpongeConfig* cfg); + +cudaError_t bw6_761_poseidon_delete_cuda(PoseidonInst* poseidon); #ifdef __cplusplus } diff --git a/wrappers/golang/curves/bw6761/poseidon/poseidon.go b/wrappers/golang/curves/bw6761/poseidon/poseidon.go index 3ffe21ea2..7d75ddd4c 100644 --- a/wrappers/golang/curves/bw6761/poseidon/poseidon.go +++ b/wrappers/golang/curves/bw6761/poseidon/poseidon.go @@ -3,55 +3,85 @@ package poseidon // #cgo CFLAGS: -I./include/ // #include "poseidon.h" import "C" - import ( + "runtime" "unsafe" "github.com/ingonyama-zk/icicle/v2/wrappers/golang/core" cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" + bw6_761 "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bw6761" ) -func GetDefaultPoseidonConfig() core.PoseidonConfig { - return core.GetDefaultPoseidonConfig() +type PoseidonHandler = C.struct_PoseidonInst +type Poseidon struct { + width uint32 + handle *PoseidonHandler } -func PoseidonHash[T any](scalars, results core.HostOrDeviceSlice, numberOfStates int, cfg *core.PoseidonConfig, constants *core.PoseidonConstants[T]) core.IcicleError { - scalarsPointer, resultsPointer, cfgPointer := core.PoseidonCheck(scalars, results, cfg, constants, numberOfStates) +func Create(arity uint32, alpha uint32, fullRoundsHalf uint32, partialRounds uint32, scalars core.HostOrDeviceSlice, mdsMatrix core.HostOrDeviceSlice, nonSparseMatrix core.HostOrDeviceSlice, sparseMatrices core.HostOrDeviceSlice, domainTag bw6_761.ScalarField, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cAlpha := (C.uint)(alpha) + cFullRoundsHalf := (C.uint)(fullRoundsHalf) + cPartialRounds := (C.uint)(partialRounds) + cScalars := (*C.scalar_t)(scalars.AsUnsafePointer()) + cMdsMatrix := (*C.scalar_t)(mdsMatrix.AsUnsafePointer()) + cNonSparseMatrix := (*C.scalar_t)(nonSparseMatrix.AsUnsafePointer()) + cSparseMatrices := (*C.scalar_t)(sparseMatrices.AsUnsafePointer()) + cDomainTag := (*C.scalar_t)(unsafe.Pointer(&domainTag)) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.bw6_761_poseidon_create_cuda(&poseidon, cArity, cAlpha, cFullRoundsHalf, cPartialRounds, cScalars, cMdsMatrix, cNonSparseMatrix, cSparseMatrices, cDomainTag, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - cScalars := (*C.scalar_t)(scalarsPointer) - cResults := (*C.scalar_t)(resultsPointer) - cNumberOfStates := (C.int)(numberOfStates) - cArity := (C.int)(constants.Arity) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - cCfg := (*C.PoseidonConfig)(cfgPointer) +func Load(arity uint32, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.bw6_761_poseidon_load_cuda(&poseidon, cArity, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - __ret := C.bw6_761_poseidon_hash_cuda(cScalars, cResults, cNumberOfStates, cArity, cConstants, cCfg) +func (poseidon *Poseidon) HashMany(inputs core.HostOrDeviceSlice, output core.HostOrDeviceSlice, numberOfStates uint32, inputBlockLen uint32, outputLen uint32, cfg *core.SpongeConfig) core.IcicleError { + core.SpongeInputCheck(inputs, numberOfStates, inputBlockLen, cfg.InputRate, &cfg.Ctx) + core.SpongeOutputsCheck(output, numberOfStates, outputLen, poseidon.width, false, &cfg.Ctx) + cInputs := (*C.scalar_t)(inputs.AsUnsafePointer()) + cOutput := (*C.scalar_t)(output.AsUnsafePointer()) + cNumberOfStates := (C.uint)(numberOfStates) + cInputBlockLen := (C.uint)(inputBlockLen) + cOutputLen := (C.uint)(outputLen) + cCfg := (*C.SpongeConfig)(unsafe.Pointer(cfg)) + __ret := C.bw6_761_poseidon_hash_many_cuda(poseidon.handle, cInputs, cOutput, cNumberOfStates, cInputBlockLen, cOutputLen, cCfg) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func CreateOptimizedPoseidonConstants[T any](arity, fullRoundsHalfs, partialRounds int, constants core.HostOrDeviceSlice, ctx cr.DeviceContext, poseidonConstants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cFullRoundsHalfs := (C.int)(fullRoundsHalfs) - cPartialRounds := (C.int)(partialRounds) - cConstants := (*C.scalar_t)(constants.AsUnsafePointer()) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cPoseidonConstants := (*C.PoseidonConstants)(unsafe.Pointer(poseidonConstants)) - - __ret := C.bw6_761_create_optimized_poseidon_constants_cuda(cArity, cFullRoundsHalfs, cPartialRounds, cConstants, cCtx, cPoseidonConstants) +func (poseidon *Poseidon) Delete() core.IcicleError { + __ret := C.bw6_761_poseidon_delete_cuda(poseidon.handle) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func InitOptimizedPoseidonConstantsCuda[T any](arity int, ctx cr.DeviceContext, constants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - - __ret := C.bw6_761_init_optimized_poseidon_constants_cuda(cArity, cCtx, cConstants) - err := (cr.CudaError)(__ret) - return core.FromCudaError(err) +func (poseidon *Poseidon) GetDefaultSpongeConfig() core.SpongeConfig { + cfg := core.GetDefaultSpongeConfig() + cfg.InputRate = poseidon.width - 1 + cfg.OutputRate = poseidon.width + return cfg } diff --git a/wrappers/golang/curves/bw6761/tests/poseidon_test.go b/wrappers/golang/curves/bw6761/tests/poseidon_test.go index b1ab540ca..c9222202f 100644 --- a/wrappers/golang/curves/bw6761/tests/poseidon_test.go +++ b/wrappers/golang/curves/bw6761/tests/poseidon_test.go @@ -7,6 +7,7 @@ import ( cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" bw6_761 "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bw6761" poseidon "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/bw6761/poseidon" + "github.com/stretchr/testify/assert" ) func TestPoseidon(t *testing.T) { @@ -14,14 +15,11 @@ func TestPoseidon(t *testing.T) { arity := 2 numberOfStates := 1 - cfg := poseidon.GetDefaultPoseidonConfig() - cfg.IsAsync = true - stream, _ := cr.CreateStream() - cfg.Ctx.Stream = &stream + ctx, _ := cr.GetDefaultDeviceContext() + p, err := poseidon.Load(uint32(arity), &ctx) + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) - var constants core.PoseidonConstants[bw6_761.ScalarField] - - poseidon.InitOptimizedPoseidonConstantsCuda(arity, cfg.Ctx, &constants) //generate constants + cfg := p.GetDefaultSpongeConfig() scalars := bw6_761.GenerateScalars(numberOfStates * arity) scalars[0] = scalars[0].Zero() @@ -30,13 +28,13 @@ func TestPoseidon(t *testing.T) { scalarsCopy := core.HostSliceFromElements(scalars[:numberOfStates*arity]) var deviceInput core.DeviceSlice - scalarsCopy.CopyToDeviceAsync(&deviceInput, stream, true) + scalarsCopy.CopyToDevice(&deviceInput, true) var deviceOutput core.DeviceSlice - deviceOutput.MallocAsync(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement(), stream) + deviceOutput.Malloc(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement()) - poseidon.PoseidonHash(deviceInput, deviceOutput, numberOfStates, &cfg, &constants) //run Hash function + err = p.HashMany(deviceInput, deviceOutput, uint32(numberOfStates), 1, 1, &cfg) //run Hash function + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) output := make(core.HostSlice[bw6_761.ScalarField], numberOfStates) - output.CopyFromDeviceAsync(&deviceOutput, stream) - + output.CopyFromDevice(&deviceOutput) } diff --git a/wrappers/golang/curves/grumpkin/poseidon/include/poseidon.h b/wrappers/golang/curves/grumpkin/poseidon/include/poseidon.h index ed27d7dba..6263a9830 100644 --- a/wrappers/golang/curves/grumpkin/poseidon/include/poseidon.h +++ b/wrappers/golang/curves/grumpkin/poseidon/include/poseidon.h @@ -9,14 +9,40 @@ extern "C" { #endif typedef struct scalar_t scalar_t; -typedef struct PoseidonConfig PoseidonConfig; typedef struct DeviceContext DeviceContext; -typedef struct PoseidonConstants PoseidonConstants; +typedef struct TreeBuilderConfig TreeBuilderConfig; +typedef struct PoseidonInst PoseidonInst; +typedef struct SpongeConfig SpongeConfig; -cudaError_t grumpkin_poseidon_hash_cuda(const scalar_t* input, scalar_t* output, int number_of_states, int arity, PoseidonConstants* constants, PoseidonConfig* config); -cudaError_t grumpkin_create_optimized_poseidon_constants_cuda(int arity, int full_rounds_halfs, int partial_rounds, const scalar_t* constants, DeviceContext* ctx, PoseidonConstants* poseidon_constants); -cudaError_t grumpkin_init_optimized_poseidon_constants_cuda(int arity, DeviceContext* ctx, PoseidonConstants* constants); +cudaError_t grumpkin_poseidon_create_cuda( + PoseidonInst** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const scalar_t* round_constants, + const scalar_t* mds_matrix, + const scalar_t* non_sparse_matrix, + const scalar_t* sparse_matrices, + const scalar_t* domain_tag, + DeviceContext* ctx); + +cudaError_t grumpkin_poseidon_load_cuda( + PoseidonInst** poseidon, + unsigned int arity, + DeviceContext* ctx); + +cudaError_t grumpkin_poseidon_hash_many_cuda( + const PoseidonInst* poseidon, + const scalar_t* inputs, + scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + SpongeConfig* cfg); + +cudaError_t grumpkin_poseidon_delete_cuda(PoseidonInst* poseidon); #ifdef __cplusplus } diff --git a/wrappers/golang/curves/grumpkin/poseidon/poseidon.go b/wrappers/golang/curves/grumpkin/poseidon/poseidon.go index 037207530..994960667 100644 --- a/wrappers/golang/curves/grumpkin/poseidon/poseidon.go +++ b/wrappers/golang/curves/grumpkin/poseidon/poseidon.go @@ -3,55 +3,85 @@ package poseidon // #cgo CFLAGS: -I./include/ // #include "poseidon.h" import "C" - import ( + "runtime" "unsafe" "github.com/ingonyama-zk/icicle/v2/wrappers/golang/core" cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" + grumpkin "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/grumpkin" ) -func GetDefaultPoseidonConfig() core.PoseidonConfig { - return core.GetDefaultPoseidonConfig() +type PoseidonHandler = C.struct_PoseidonInst +type Poseidon struct { + width uint32 + handle *PoseidonHandler } -func PoseidonHash[T any](scalars, results core.HostOrDeviceSlice, numberOfStates int, cfg *core.PoseidonConfig, constants *core.PoseidonConstants[T]) core.IcicleError { - scalarsPointer, resultsPointer, cfgPointer := core.PoseidonCheck(scalars, results, cfg, constants, numberOfStates) +func Create(arity uint32, alpha uint32, fullRoundsHalf uint32, partialRounds uint32, scalars core.HostOrDeviceSlice, mdsMatrix core.HostOrDeviceSlice, nonSparseMatrix core.HostOrDeviceSlice, sparseMatrices core.HostOrDeviceSlice, domainTag grumpkin.ScalarField, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cAlpha := (C.uint)(alpha) + cFullRoundsHalf := (C.uint)(fullRoundsHalf) + cPartialRounds := (C.uint)(partialRounds) + cScalars := (*C.scalar_t)(scalars.AsUnsafePointer()) + cMdsMatrix := (*C.scalar_t)(mdsMatrix.AsUnsafePointer()) + cNonSparseMatrix := (*C.scalar_t)(nonSparseMatrix.AsUnsafePointer()) + cSparseMatrices := (*C.scalar_t)(sparseMatrices.AsUnsafePointer()) + cDomainTag := (*C.scalar_t)(unsafe.Pointer(&domainTag)) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.grumpkin_poseidon_create_cuda(&poseidon, cArity, cAlpha, cFullRoundsHalf, cPartialRounds, cScalars, cMdsMatrix, cNonSparseMatrix, cSparseMatrices, cDomainTag, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - cScalars := (*C.scalar_t)(scalarsPointer) - cResults := (*C.scalar_t)(resultsPointer) - cNumberOfStates := (C.int)(numberOfStates) - cArity := (C.int)(constants.Arity) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - cCfg := (*C.PoseidonConfig)(cfgPointer) +func Load(arity uint32, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.grumpkin_poseidon_load_cuda(&poseidon, cArity, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - __ret := C.grumpkin_poseidon_hash_cuda(cScalars, cResults, cNumberOfStates, cArity, cConstants, cCfg) +func (poseidon *Poseidon) HashMany(inputs core.HostOrDeviceSlice, output core.HostOrDeviceSlice, numberOfStates uint32, inputBlockLen uint32, outputLen uint32, cfg *core.SpongeConfig) core.IcicleError { + core.SpongeInputCheck(inputs, numberOfStates, inputBlockLen, cfg.InputRate, &cfg.Ctx) + core.SpongeOutputsCheck(output, numberOfStates, outputLen, poseidon.width, false, &cfg.Ctx) + cInputs := (*C.scalar_t)(inputs.AsUnsafePointer()) + cOutput := (*C.scalar_t)(output.AsUnsafePointer()) + cNumberOfStates := (C.uint)(numberOfStates) + cInputBlockLen := (C.uint)(inputBlockLen) + cOutputLen := (C.uint)(outputLen) + cCfg := (*C.SpongeConfig)(unsafe.Pointer(cfg)) + __ret := C.grumpkin_poseidon_hash_many_cuda(poseidon.handle, cInputs, cOutput, cNumberOfStates, cInputBlockLen, cOutputLen, cCfg) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func CreateOptimizedPoseidonConstants[T any](arity, fullRoundsHalfs, partialRounds int, constants core.HostOrDeviceSlice, ctx cr.DeviceContext, poseidonConstants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cFullRoundsHalfs := (C.int)(fullRoundsHalfs) - cPartialRounds := (C.int)(partialRounds) - cConstants := (*C.scalar_t)(constants.AsUnsafePointer()) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cPoseidonConstants := (*C.PoseidonConstants)(unsafe.Pointer(poseidonConstants)) - - __ret := C.grumpkin_create_optimized_poseidon_constants_cuda(cArity, cFullRoundsHalfs, cPartialRounds, cConstants, cCtx, cPoseidonConstants) +func (poseidon *Poseidon) Delete() core.IcicleError { + __ret := C.grumpkin_poseidon_delete_cuda(poseidon.handle) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func InitOptimizedPoseidonConstantsCuda[T any](arity int, ctx cr.DeviceContext, constants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - - __ret := C.grumpkin_init_optimized_poseidon_constants_cuda(cArity, cCtx, cConstants) - err := (cr.CudaError)(__ret) - return core.FromCudaError(err) +func (poseidon *Poseidon) GetDefaultSpongeConfig() core.SpongeConfig { + cfg := core.GetDefaultSpongeConfig() + cfg.InputRate = poseidon.width - 1 + cfg.OutputRate = poseidon.width + return cfg } diff --git a/wrappers/golang/curves/grumpkin/tests/poseidon_test.go b/wrappers/golang/curves/grumpkin/tests/poseidon_test.go index 92f9e5efe..f869fc6ca 100644 --- a/wrappers/golang/curves/grumpkin/tests/poseidon_test.go +++ b/wrappers/golang/curves/grumpkin/tests/poseidon_test.go @@ -7,6 +7,7 @@ import ( cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" grumpkin "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/grumpkin" poseidon "github.com/ingonyama-zk/icicle/v2/wrappers/golang/curves/grumpkin/poseidon" + "github.com/stretchr/testify/assert" ) func TestPoseidon(t *testing.T) { @@ -14,14 +15,11 @@ func TestPoseidon(t *testing.T) { arity := 2 numberOfStates := 1 - cfg := poseidon.GetDefaultPoseidonConfig() - cfg.IsAsync = true - stream, _ := cr.CreateStream() - cfg.Ctx.Stream = &stream + ctx, _ := cr.GetDefaultDeviceContext() + p, err := poseidon.Load(uint32(arity), &ctx) + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) - var constants core.PoseidonConstants[grumpkin.ScalarField] - - poseidon.InitOptimizedPoseidonConstantsCuda(arity, cfg.Ctx, &constants) //generate constants + cfg := p.GetDefaultSpongeConfig() scalars := grumpkin.GenerateScalars(numberOfStates * arity) scalars[0] = scalars[0].Zero() @@ -30,13 +28,13 @@ func TestPoseidon(t *testing.T) { scalarsCopy := core.HostSliceFromElements(scalars[:numberOfStates*arity]) var deviceInput core.DeviceSlice - scalarsCopy.CopyToDeviceAsync(&deviceInput, stream, true) + scalarsCopy.CopyToDevice(&deviceInput, true) var deviceOutput core.DeviceSlice - deviceOutput.MallocAsync(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement(), stream) + deviceOutput.Malloc(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement()) - poseidon.PoseidonHash(deviceInput, deviceOutput, numberOfStates, &cfg, &constants) //run Hash function + err = p.HashMany(deviceInput, deviceOutput, uint32(numberOfStates), 1, 1, &cfg) //run Hash function + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) output := make(core.HostSlice[grumpkin.ScalarField], numberOfStates) - output.CopyFromDeviceAsync(&deviceOutput, stream) - + output.CopyFromDevice(&deviceOutput) } diff --git a/wrappers/golang/internal/generator/poseidon/templates/poseidon.go.tmpl b/wrappers/golang/internal/generator/poseidon/templates/poseidon.go.tmpl index ca83d4bbd..9a3a66f8d 100644 --- a/wrappers/golang/internal/generator/poseidon/templates/poseidon.go.tmpl +++ b/wrappers/golang/internal/generator/poseidon/templates/poseidon.go.tmpl @@ -3,55 +3,85 @@ package {{.PackageName}} // #cgo CFLAGS: -I./include/ // #include "poseidon.h" import "C" - import ( + "runtime" "unsafe" "github.com/ingonyama-zk/icicle/v2/wrappers/golang/core" cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" + {{.Field}} "github.com/ingonyama-zk/icicle/v2/wrappers/golang/{{.BaseImportPath}}" ) -func GetDefaultPoseidonConfig() core.PoseidonConfig { - return core.GetDefaultPoseidonConfig() +type PoseidonHandler = C.struct_PoseidonInst +type Poseidon struct { + width uint32 + handle *PoseidonHandler } -func PoseidonHash[T any](scalars, results core.HostOrDeviceSlice, numberOfStates int, cfg *core.PoseidonConfig, constants *core.PoseidonConstants[T]) core.IcicleError { - scalarsPointer, resultsPointer, cfgPointer := core.PoseidonCheck(scalars, results, cfg, constants, numberOfStates) +func Create(arity uint32, alpha uint32, fullRoundsHalf uint32, partialRounds uint32, scalars core.HostOrDeviceSlice, mdsMatrix core.HostOrDeviceSlice, nonSparseMatrix core.HostOrDeviceSlice, sparseMatrices core.HostOrDeviceSlice, domainTag {{.Field}}.ScalarField, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cAlpha := (C.uint)(alpha) + cFullRoundsHalf := (C.uint)(fullRoundsHalf) + cPartialRounds := (C.uint)(partialRounds) + cScalars := (*C.scalar_t)(scalars.AsUnsafePointer()) + cMdsMatrix := (*C.scalar_t)(mdsMatrix.AsUnsafePointer()) + cNonSparseMatrix := (*C.scalar_t)(nonSparseMatrix.AsUnsafePointer()) + cSparseMatrices := (*C.scalar_t)(sparseMatrices.AsUnsafePointer()) + cDomainTag := (*C.scalar_t)(unsafe.Pointer(&domainTag)) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.{{.Field}}_poseidon_create_cuda(&poseidon, cArity, cAlpha, cFullRoundsHalf, cPartialRounds, cScalars, cMdsMatrix, cNonSparseMatrix, cSparseMatrices, cDomainTag, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - cScalars := (*C.scalar_t)(scalarsPointer) - cResults := (*C.scalar_t)(resultsPointer) - cNumberOfStates := (C.int)(numberOfStates) - cArity := (C.int)(constants.Arity) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - cCfg := (*C.PoseidonConfig)(cfgPointer) +func Load(arity uint32, ctx *cr.DeviceContext) (*Poseidon, core.IcicleError) { + var poseidon *PoseidonHandler + cArity := (C.uint)(arity) + cCtx := (*C.DeviceContext)(unsafe.Pointer(ctx)) + __ret := C.{{.Field}}_poseidon_load_cuda(&poseidon, cArity, cCtx) + err := core.FromCudaError((cr.CudaError)(__ret)) + if err.IcicleErrorCode != core.IcicleSuccess { + return nil, err + } + p := Poseidon{handle: poseidon, width: arity + 1} + runtime.SetFinalizer(&p, func(p *Poseidon) { + p.Delete() + }) + return &p, err +} - __ret := C.{{.Field}}_poseidon_hash_cuda(cScalars, cResults, cNumberOfStates, cArity, cConstants, cCfg) +func (poseidon *Poseidon) HashMany(inputs core.HostOrDeviceSlice, output core.HostOrDeviceSlice, numberOfStates uint32, inputBlockLen uint32, outputLen uint32, cfg *core.SpongeConfig) core.IcicleError { + core.SpongeInputCheck(inputs, numberOfStates, inputBlockLen, cfg.InputRate, &cfg.Ctx) + core.SpongeOutputsCheck(output, numberOfStates, outputLen, poseidon.width, false, &cfg.Ctx) + cInputs := (*C.scalar_t)(inputs.AsUnsafePointer()) + cOutput := (*C.scalar_t)(output.AsUnsafePointer()) + cNumberOfStates := (C.uint)(numberOfStates) + cInputBlockLen := (C.uint)(inputBlockLen) + cOutputLen := (C.uint)(outputLen) + cCfg := (*C.SpongeConfig)(unsafe.Pointer(cfg)) + __ret := C.{{.Field}}_poseidon_hash_many_cuda(poseidon.handle, cInputs, cOutput, cNumberOfStates, cInputBlockLen, cOutputLen, cCfg) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func CreateOptimizedPoseidonConstants[T any](arity, fullRoundsHalfs, partialRounds int, constants core.HostOrDeviceSlice, ctx cr.DeviceContext, poseidonConstants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cFullRoundsHalfs := (C.int)(fullRoundsHalfs) - cPartialRounds := (C.int)(partialRounds) - cConstants := (*C.scalar_t)(constants.AsUnsafePointer()) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cPoseidonConstants := (*C.PoseidonConstants)(unsafe.Pointer(poseidonConstants)) - - __ret := C.{{.Field}}_create_optimized_poseidon_constants_cuda(cArity, cFullRoundsHalfs, cPartialRounds, cConstants, cCtx, cPoseidonConstants) +func (poseidon *Poseidon) Delete() core.IcicleError { + __ret := C.{{.Field}}_poseidon_delete_cuda(poseidon.handle) err := (cr.CudaError)(__ret) return core.FromCudaError(err) } -func InitOptimizedPoseidonConstantsCuda[T any](arity int, ctx cr.DeviceContext, constants *core.PoseidonConstants[T]) core.IcicleError { - - cArity := (C.int)(arity) - cCtx := (*C.DeviceContext)(unsafe.Pointer(&ctx)) - cConstants := (*C.PoseidonConstants)(unsafe.Pointer(constants)) - - __ret := C.{{.Field}}_init_optimized_poseidon_constants_cuda(cArity, cCtx, cConstants) - err := (cr.CudaError)(__ret) - return core.FromCudaError(err) +func (poseidon *Poseidon) GetDefaultSpongeConfig() core.SpongeConfig { + cfg := core.GetDefaultSpongeConfig() + cfg.InputRate = poseidon.width - 1 + cfg.OutputRate = poseidon.width + return cfg } diff --git a/wrappers/golang/internal/generator/poseidon/templates/poseidon.h.tmpl b/wrappers/golang/internal/generator/poseidon/templates/poseidon.h.tmpl index e5ac4d1dd..16803581b 100644 --- a/wrappers/golang/internal/generator/poseidon/templates/poseidon.h.tmpl +++ b/wrappers/golang/internal/generator/poseidon/templates/poseidon.h.tmpl @@ -9,14 +9,40 @@ extern "C" { #endif typedef struct scalar_t scalar_t; -typedef struct PoseidonConfig PoseidonConfig; typedef struct DeviceContext DeviceContext; -typedef struct PoseidonConstants PoseidonConstants; +typedef struct TreeBuilderConfig TreeBuilderConfig; +typedef struct PoseidonInst PoseidonInst; +typedef struct SpongeConfig SpongeConfig; -cudaError_t {{.Field}}_poseidon_hash_cuda(const scalar_t* input, scalar_t* output, int number_of_states, int arity, PoseidonConstants* constants, PoseidonConfig* config); -cudaError_t {{.Field}}_create_optimized_poseidon_constants_cuda(int arity, int full_rounds_halfs, int partial_rounds, const scalar_t* constants, DeviceContext* ctx, PoseidonConstants* poseidon_constants); -cudaError_t {{.Field}}_init_optimized_poseidon_constants_cuda(int arity, DeviceContext* ctx, PoseidonConstants* constants); +cudaError_t {{.Field}}_poseidon_create_cuda( + PoseidonInst** poseidon, + unsigned int arity, + unsigned int alpha, + unsigned int partial_rounds, + unsigned int full_rounds_half, + const scalar_t* round_constants, + const scalar_t* mds_matrix, + const scalar_t* non_sparse_matrix, + const scalar_t* sparse_matrices, + const scalar_t* domain_tag, + DeviceContext* ctx); + +cudaError_t {{.Field}}_poseidon_load_cuda( + PoseidonInst** poseidon, + unsigned int arity, + DeviceContext* ctx); + +cudaError_t {{.Field}}_poseidon_hash_many_cuda( + const PoseidonInst* poseidon, + const scalar_t* inputs, + scalar_t* output, + unsigned int number_of_states, + unsigned int input_block_len, + unsigned int output_len, + SpongeConfig* cfg); + +cudaError_t {{.Field}}_poseidon_delete_cuda(PoseidonInst* poseidon); #ifdef __cplusplus } diff --git a/wrappers/golang/internal/generator/poseidon/templates/poseidon_test.go.tmpl b/wrappers/golang/internal/generator/poseidon/templates/poseidon_test.go.tmpl index 13aeedc2e..a587fb562 100644 --- a/wrappers/golang/internal/generator/poseidon/templates/poseidon_test.go.tmpl +++ b/wrappers/golang/internal/generator/poseidon/templates/poseidon_test.go.tmpl @@ -2,37 +2,24 @@ package tests import ( "testing" - + core "github.com/ingonyama-zk/icicle/v2/wrappers/golang/core" cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" {{.Field}} "github.com/ingonyama-zk/icicle/v2/wrappers/golang/{{.BaseImportPath}}" poseidon "github.com/ingonyama-zk/icicle/v2/wrappers/golang/{{.BaseImportPath}}/poseidon" - - {{if eq .Field "bls12_381"}} - "fmt" "github.com/stretchr/testify/assert" - {{end}} ) -{{if eq .Field "bls12_381"}} -func formatOutput(x {{.Field}}.{{.FieldPrefix}}Field) string { - r := x.GetLimbs() - return fmt.Sprintf("%08x%08x%08x%08x%08x%08x%08x%08x", r[7], r[6], r[5], r[4], r[3], r[2], r[1], r[0]) -} -{{end}} func TestPoseidon(t *testing.T) { arity := 2 numberOfStates := 1 - cfg := poseidon.GetDefaultPoseidonConfig() - cfg.IsAsync = true - stream, _ := cr.CreateStream() - cfg.Ctx.Stream = &stream + ctx, _ := cr.GetDefaultDeviceContext() + p, err := poseidon.Load(uint32(arity), &ctx) + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) - var constants core.PoseidonConstants[{{.Field}}.{{.FieldPrefix}}Field] - - poseidon.InitOptimizedPoseidonConstantsCuda(arity, cfg.Ctx, &constants) //generate constants + cfg := p.GetDefaultSpongeConfig() scalars := {{.Field}}.GenerateScalars(numberOfStates * arity) scalars[0] = scalars[0].Zero() @@ -41,19 +28,13 @@ func TestPoseidon(t *testing.T) { scalarsCopy := core.HostSliceFromElements(scalars[:numberOfStates*arity]) var deviceInput core.DeviceSlice - scalarsCopy.CopyToDeviceAsync(&deviceInput, stream, true) + scalarsCopy.CopyToDevice(&deviceInput, true) var deviceOutput core.DeviceSlice - deviceOutput.MallocAsync(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement(), stream) - - poseidon.PoseidonHash(deviceInput, deviceOutput, numberOfStates, &cfg, &constants) //run Hash function - - output := make(core.HostSlice[{{.Field}}.{{.FieldPrefix}}Field], numberOfStates) - output.CopyFromDeviceAsync(&deviceOutput, stream) + deviceOutput.Malloc(numberOfStates*scalarsCopy.SizeOfElement(), scalarsCopy.SizeOfElement()) - {{if eq .Field "bls12_381"}} - expectedString := "48fe0b1331196f6cdb33a7c6e5af61b76fd388e1ef1d3d418be5147f0e4613d4" //This result is from https://github.com/triplewz/poseidon - outputString := formatOutput(output[0]) + err = p.HashMany(deviceInput, deviceOutput, uint32(numberOfStates), 1, 1, &cfg) //run Hash function + assert.Equal(t, core.IcicleSuccess, err.IcicleErrorCode) - assert.Equal(t, outputString, expectedString, "Poseidon hash does not match expected result") - {{end}} + output := make(core.HostSlice[{{.Field}}.ScalarField], numberOfStates) + output.CopyFromDevice(&deviceOutput) } diff --git a/wrappers/rust/icicle-core/src/hash.rs b/wrappers/rust/icicle-core/src/hash.rs new file mode 100644 index 000000000..df67cea92 --- /dev/null +++ b/wrappers/rust/icicle-core/src/hash.rs @@ -0,0 +1,136 @@ +use std::ffi::c_void; + +use icicle_cuda_runtime::{ + device::check_device, + device_context::{DeviceContext, DEFAULT_DEVICE_ID}, + memory::HostOrDeviceSlice, +}; + +use crate::ntt::IcicleResult; + +/// Struct that encodes Sponge hash parameters. +#[repr(C)] +#[derive(Debug, Clone)] +pub struct SpongeConfig<'a> { + /// Details related to the device such as its id and stream id. See [DeviceContext](@ref device_context::DeviceContext). + pub ctx: DeviceContext<'a>, + pub(crate) are_inputs_on_device: bool, + pub(crate) are_outputs_on_device: bool, + pub input_rate: u32, + pub output_rate: u32, + pub offset: u32, + + /// If true - input should be already aligned for poseidon permutation. + /// Aligned format: [0, A, B, 0, C, D, ...] (as you might get by using loop_state) + /// not aligned format: [A, B, 0, C, D, 0, ...] (as you might get from cudaMemcpy2D) + pub recursive_squeeze: bool, + + /// If true, hash results will also be copied in the input pointer in aligned format + pub aligned: bool, + /// Whether to run the sponge operations asynchronously. If set to `true`, the functions will be non-blocking and you'd need to synchronize + /// it explicitly by running `stream.synchronize()`. If set to false, the functions will block the current CPU thread. + pub is_async: bool, +} + +impl<'a> Default for SpongeConfig<'a> { + fn default() -> Self { + Self::default_for_device(DEFAULT_DEVICE_ID) + } +} + +impl<'a> SpongeConfig<'a> { + pub(crate) fn default_for_device(device_id: usize) -> Self { + SpongeConfig { + ctx: DeviceContext::default_for_device(device_id), + are_inputs_on_device: false, + are_outputs_on_device: false, + input_rate: 0, + output_rate: 0, + offset: 0, + recursive_squeeze: false, + aligned: false, + is_async: false, + } + } +} + +pub trait SpongeHash { + fn hash_many( + &self, + inputs: &(impl HostOrDeviceSlice + ?Sized), + output: &mut (impl HostOrDeviceSlice + ?Sized), + number_of_states: usize, + input_block_len: usize, + output_len: usize, + cfg: &SpongeConfig, + ) -> IcicleResult<()>; + + fn default_config<'a>(&self) -> SpongeConfig<'a>; + + fn get_handle(&self) -> *const c_void; +} + +pub(crate) fn sponge_check_input( + inputs: &(impl HostOrDeviceSlice + ?Sized), + number_of_states: usize, + input_block_len: usize, + input_rate: usize, + ctx: &DeviceContext, +) { + if input_block_len > input_rate { + panic!( + "input block len ({}) can't be greater than input rate ({})", + input_block_len, input_rate + ); + } + + let inputs_size_expected = input_block_len * number_of_states; + if inputs.len() < inputs_size_expected { + panic!( + "inputs len is {}; but needs to be at least {}", + inputs.len(), + inputs_size_expected, + ); + } + + let ctx_device_id = ctx.device_id; + if let Some(device_id) = inputs.device_id() { + assert_eq!( + device_id, ctx_device_id, + "Device ids in inputs and context are different" + ); + } + check_device(ctx_device_id); +} + +pub(crate) fn sponge_check_outputs( + outputs: &(impl HostOrDeviceSlice + ?Sized), + number_of_states: usize, + output_len: usize, + width: usize, + recursive: bool, + ctx: &DeviceContext, +) { + let outputs_size_expected = if recursive { + width * number_of_states + } else { + output_len * number_of_states + }; + + if outputs.len() < outputs_size_expected { + panic!( + "outputs len is {}; but needs to be at least {}", + outputs.len(), + outputs_size_expected, + ); + } + + let ctx_device_id = ctx.device_id; + if let Some(device_id) = outputs.device_id() { + assert_eq!( + device_id, ctx_device_id, + "Device ids in outputs and context are different" + ); + } + check_device(ctx_device_id); +} diff --git a/wrappers/rust/icicle-core/src/lib.rs b/wrappers/rust/icicle-core/src/lib.rs index 1923968af..153959179 100644 --- a/wrappers/rust/icicle-core/src/lib.rs +++ b/wrappers/rust/icicle-core/src/lib.rs @@ -1,7 +1,10 @@ +use std::ffi::c_void; + pub mod curve; pub mod ecntt; pub mod error; pub mod field; +pub mod hash; pub mod msm; pub mod ntt; pub mod polynomials; @@ -18,3 +21,11 @@ where ::Config: ntt::NTT, { } + +#[repr(C)] +#[derive(Debug)] +pub struct Matrix { + pub values: *const c_void, + pub width: usize, + pub height: usize, +} diff --git a/wrappers/rust/icicle-core/src/poseidon/mod.rs b/wrappers/rust/icicle-core/src/poseidon/mod.rs index 3722986ab..39ba26b48 100644 --- a/wrappers/rust/icicle-core/src/poseidon/mod.rs +++ b/wrappers/rust/icicle-core/src/poseidon/mod.rs @@ -1,212 +1,157 @@ #[doc(hidden)] pub mod tests; -use icicle_cuda_runtime::{ - device::check_device, - device_context::{DeviceContext, DEFAULT_DEVICE_ID}, - memory::{DeviceSlice, HostOrDeviceSlice}, -}; - -use crate::{error::IcicleResult, traits::FieldImpl}; - -#[repr(C)] -pub struct PoseidonConstants<'a, F: FieldImpl> { - arity: u32, - - partial_rounds: u32, - - full_rounds_half: u32, - - /// These should be pointers to data allocated on device - round_constants: &'a DeviceSlice, - mds_matrix: &'a DeviceSlice, - non_sparse_matrix: &'a DeviceSlice, - sparse_matrices: &'a DeviceSlice, - - /// Domain tag is the first element in the Poseidon state. - /// For the Merkle tree mode it should equal 2^arity - 1 - domain_tag: F, -} - -/// Struct that encodes Poseidon parameters to be passed into the [poseidon_hash_many](poseidon_hash_many) function. -#[repr(C)] -#[derive(Debug, Clone)] -pub struct PoseidonConfig<'a> { - /// Details related to the device such as its id and stream id. See [DeviceContext](@ref device_context::DeviceContext). - pub ctx: DeviceContext<'a>, - - are_inputs_on_device: bool, +use std::{ffi::c_void, marker::PhantomData}; - are_outputs_on_device: bool, +use icicle_cuda_runtime::{device_context::DeviceContext, memory::HostOrDeviceSlice}; - /// If true, input is considered to be a states vector, holding the preimages - /// in aligned or not aligned format. Memory under the input pointer will be used for states - /// If false, fresh states memory will be allocated and input will be copied into it - pub input_is_a_state: bool, - - /// If true - input should be already aligned for poseidon permutation. - /// Aligned format: [0, A, B, 0, C, D, ...] (as you might get by using loop_state) - /// not aligned format: [A, B, 0, C, D, 0, ...] (as you might get from cudaMemcpy2D) - pub aligned: bool, - - /// If true, hash results will also be copied in the input pointer in aligned format - pub loop_state: bool, - - /// Whether to run Poseidon asynchronously. If set to `true`, Poseidon will be non-blocking - /// and you'd need to synchronize it explicitly by running `cudaStreamSynchronize` or `cudaDeviceSynchronize`. - /// If set to `false`, Poseidon will block the current CPU thread. - pub is_async: bool, -} +use crate::{ + error::IcicleResult, + hash::{sponge_check_input, sponge_check_outputs, SpongeConfig, SpongeHash}, + traits::FieldImpl, +}; -impl<'a> Default for PoseidonConfig<'a> { - fn default() -> Self { - Self::default_for_device(DEFAULT_DEVICE_ID) - } +pub type PoseidonHandle = *const c_void; +pub struct Poseidon +where + F: FieldImpl, + ::Config: PoseidonImpl, +{ + width: usize, + handle: PoseidonHandle, + phantom: PhantomData, } -impl<'a> PoseidonConfig<'a> { - pub fn default_for_device(device_id: usize) -> Self { - Self { - ctx: DeviceContext::default_for_device(device_id), - are_inputs_on_device: false, - are_outputs_on_device: false, - input_is_a_state: false, - aligned: false, - loop_state: false, - is_async: false, - } +impl Poseidon +where + F: FieldImpl, + ::Config: PoseidonImpl, +{ + pub fn load(arity: usize, ctx: &DeviceContext) -> IcicleResult { + <::Config as PoseidonImpl>::load(arity as u32, ctx).and_then(|handle| { + Ok(Self { + width: arity + 1, + handle, + phantom: PhantomData, + }) + }) } -} -pub trait Poseidon { - fn create_optimized_constants<'a>( - arity: u32, + pub fn new( + arity: usize, + alpha: u32, full_rounds_half: u32, partial_rounds: u32, - constants: &mut [F], + round_constants: &[F], + mds_matrix: &[F], + non_sparse_matrix: &[F], + sparse_matrices: &[F], + domain_tag: F, ctx: &DeviceContext, - ) -> IcicleResult>; - fn load_optimized_constants<'a>(arity: u32, ctx: &DeviceContext) -> IcicleResult>; - fn poseidon_unchecked( - input: &mut (impl HostOrDeviceSlice + ?Sized), - output: &mut (impl HostOrDeviceSlice + ?Sized), - number_of_states: u32, - arity: u32, - constants: &PoseidonConstants, - config: &PoseidonConfig, - ) -> IcicleResult<()>; + ) -> IcicleResult { + <::Config as PoseidonImpl>::create( + arity as u32, + alpha, + full_rounds_half, + partial_rounds, + round_constants, + mds_matrix, + non_sparse_matrix, + sparse_matrices, + domain_tag, + ctx, + ) + .and_then(|handle| { + Ok(Self { + width: arity + 1, + handle, + phantom: PhantomData, + }) + }) + } } -/// Loads pre-calculated poseidon constants on the GPU. -pub fn load_optimized_poseidon_constants<'a, F>( - arity: u32, - ctx: &DeviceContext, -) -> IcicleResult> +impl SpongeHash for Poseidon where F: FieldImpl, - ::Config: Poseidon, + ::Config: PoseidonImpl, { - <::Config as Poseidon>::load_optimized_constants(arity, ctx) -} + fn get_handle(&self) -> *const c_void { + self.handle + } -/// Creates new instance of poseidon constants on the GPU. -pub fn create_optimized_poseidon_constants<'a, F>( - arity: u32, - ctx: &DeviceContext, - full_rounds_half: u32, - partial_rounds: u32, - constants: &mut [F], -) -> IcicleResult> -where - F: FieldImpl, - ::Config: Poseidon, -{ - <::Config as Poseidon>::create_optimized_constants( - arity, - full_rounds_half, - partial_rounds, - constants, - ctx, - ) + fn hash_many( + &self, + inputs: &(impl HostOrDeviceSlice + ?Sized), + output: &mut (impl HostOrDeviceSlice + ?Sized), + number_of_states: usize, + input_block_len: usize, + output_len: usize, + cfg: &SpongeConfig, + ) -> IcicleResult<()> { + sponge_check_input(inputs, number_of_states, input_block_len, self.width - 1, &cfg.ctx); + sponge_check_outputs(output, number_of_states, output_len, self.width, false, &cfg.ctx); + + let mut local_cfg = cfg.clone(); + local_cfg.are_inputs_on_device = inputs.is_on_device(); + local_cfg.are_outputs_on_device = output.is_on_device(); + + <::Config as PoseidonImpl>::hash_many( + inputs, + output, + number_of_states as u32, + input_block_len as u32, + output_len as u32, + self.handle, + &local_cfg, + ) + } + + fn default_config<'a>(&self) -> SpongeConfig<'a> { + let mut cfg = SpongeConfig::default(); + cfg.input_rate = self.width as u32 - 1; + cfg.output_rate = self.width as u32; + cfg + } } -/// Computes the poseidon hashes for multiple preimages. -/// -/// # Arguments -/// -/// * `input` - a pointer to the input data. May point to a vector of preimages or a vector of states filled with preimages. -/// -/// * `output` - a pointer to the output data. Must be at least of size [number_of_states](number_of_states) -/// -/// * `number_of_states` - number of input blocks of size `arity` -/// -/// * `arity` - the arity of the hash function (the size of 1 preimage) -/// -/// * `constants` - Poseidon constants. -/// -/// * `config` - config used to specify extra arguments of the Poseidon. -pub fn poseidon_hash_many( - input: &mut (impl HostOrDeviceSlice + ?Sized), - output: &mut (impl HostOrDeviceSlice + ?Sized), - number_of_states: u32, - arity: u32, - constants: &PoseidonConstants, - config: &PoseidonConfig, -) -> IcicleResult<()> +impl Drop for Poseidon where F: FieldImpl, - ::Config: Poseidon, + ::Config: PoseidonImpl, { - let input_len_required = if config.input_is_a_state { - number_of_states * (arity + 1) - } else { - number_of_states * arity - }; - - if input.len() < input_len_required as usize { - panic!( - "input len is {}; but needs to be at least {}", - input.len(), - input_len_required - ); + fn drop(&mut self) { + <::Config as PoseidonImpl>::delete(self.handle).unwrap(); } +} - if output.len() < number_of_states as usize { - panic!( - "output len is {}; but needs to be at least {}", - output.len(), - number_of_states - ); - } +pub trait PoseidonImpl { + fn create( + arity: u32, + alpha: u32, + full_rounds_half: u32, + partial_rounds: u32, + round_constants: &[F], + mds_matrix: &[F], + non_sparse_matrix: &[F], + sparse_matrices: &[F], + domain_tag: F, + ctx: &DeviceContext, + ) -> IcicleResult; - let ctx_device_id = config - .ctx - .device_id; - if let Some(device_id) = input.device_id() { - assert_eq!( - device_id, ctx_device_id, - "Device ids in input and context are different" - ); - } - if let Some(device_id) = output.device_id() { - assert_eq!( - device_id, ctx_device_id, - "Device ids in output and context are different" - ); - } - check_device(ctx_device_id); - let mut local_cfg = config.clone(); - local_cfg.are_inputs_on_device = input.is_on_device(); - local_cfg.are_outputs_on_device = output.is_on_device(); + fn load(arity: u32, ctx: &DeviceContext) -> IcicleResult; + + fn hash_many( + inputs: &(impl HostOrDeviceSlice + ?Sized), + output: &mut (impl HostOrDeviceSlice + ?Sized), + number_of_states: u32, + input_block_len: u32, + output_len: u32, + poseidon: PoseidonHandle, + cfg: &SpongeConfig, + ) -> IcicleResult<()>; - <::Config as Poseidon>::poseidon_unchecked( - input, - output, - number_of_states, - arity, - constants, - &local_cfg, - ) + fn delete(poseidon: PoseidonHandle) -> IcicleResult<()>; } #[macro_export] @@ -218,91 +163,110 @@ macro_rules! impl_poseidon { $field_config:ident ) => { mod $field_prefix_ident { - use crate::poseidon::{$field, $field_config, CudaError, DeviceContext, PoseidonConfig, PoseidonConstants}; + use crate::poseidon::{$field, $field_config, CudaError, DeviceContext, PoseidonHandle, SpongeConfig}; extern "C" { - #[link_name = concat!($field_prefix, "_create_optimized_poseidon_constants_cuda")] - pub(crate) fn _create_optimized_constants( + #[link_name = concat!($field_prefix, "_poseidon_create_cuda")] + pub(crate) fn create( + poseidon: *mut PoseidonHandle, arity: u32, + alpha: u32, full_rounds_half: u32, partial_rounds: u32, - constants: *mut $field, + round_constants: *const $field, + mds_matrix: *const $field, + non_sparse_matrix: *const $field, + sparse_matrices: *const $field, + domain_tag: $field, ctx: &DeviceContext, - poseidon_constants: *mut PoseidonConstants<$field>, ) -> CudaError; - #[link_name = concat!($field_prefix, "_init_optimized_poseidon_constants_cuda")] - pub(crate) fn _load_optimized_constants( - arity: u32, - ctx: &DeviceContext, - constants: *mut PoseidonConstants<$field>, - ) -> CudaError; + #[link_name = concat!($field_prefix, "_poseidon_load_cuda")] + pub(crate) fn load(poseidon: *mut PoseidonHandle, arity: u32, ctx: &DeviceContext) -> CudaError; + + #[link_name = concat!($field_prefix, "_poseidon_delete_cuda")] + pub(crate) fn delete(poseidon: PoseidonHandle) -> CudaError; - #[link_name = concat!($field_prefix, "_poseidon_hash_cuda")] + #[link_name = concat!($field_prefix, "_poseidon_hash_many_cuda")] pub(crate) fn hash_many( - input: *mut $field, + poseidon: PoseidonHandle, + inputs: *const $field, output: *mut $field, number_of_states: u32, - arity: u32, - constants: &PoseidonConstants<$field>, - config: &PoseidonConfig, + input_block_len: u32, + output_len: u32, + cfg: &SpongeConfig, ) -> CudaError; } } - impl Poseidon<$field> for $field_config { - fn create_optimized_constants<'a>( + impl PoseidonImpl<$field> for $field_config { + fn create( arity: u32, + alpha: u32, full_rounds_half: u32, partial_rounds: u32, - constants: &mut [$field], + round_constants: &[$field], + mds_matrix: &[$field], + non_sparse_matrix: &[$field], + sparse_matrices: &[$field], + domain_tag: $field, ctx: &DeviceContext, - ) -> IcicleResult> { + ) -> IcicleResult { unsafe { - let mut poseidon_constants = MaybeUninit::>::uninit(); - let err = $field_prefix_ident::_create_optimized_constants( + let mut poseidon = MaybeUninit::::uninit(); + $field_prefix_ident::create( + poseidon.as_mut_ptr(), arity, + alpha, full_rounds_half, partial_rounds, - constants as *mut _ as *mut $field, + round_constants as *const _ as *const $field, + mds_matrix as *const _ as *const $field, + non_sparse_matrix as *const _ as *const $field, + sparse_matrices as *const _ as *const $field, + domain_tag, ctx, - poseidon_constants.as_mut_ptr(), ) - .wrap(); - err.and(Ok(poseidon_constants.assume_init())) + .wrap() + .and(Ok(poseidon.assume_init())) } } - fn load_optimized_constants<'a>( - arity: u32, - ctx: &DeviceContext, - ) -> IcicleResult> { + fn load(arity: u32, ctx: &DeviceContext) -> IcicleResult { unsafe { - let mut constants = MaybeUninit::>::uninit(); - let err = $field_prefix_ident::_load_optimized_constants(arity, ctx, constants.as_mut_ptr()).wrap(); - err.and(Ok(constants.assume_init())) + let mut poseidon = MaybeUninit::::uninit(); + $field_prefix_ident::load(poseidon.as_mut_ptr(), arity, ctx) + .wrap() + .and(Ok(poseidon.assume_init())) } } - fn poseidon_unchecked( - input: &mut (impl HostOrDeviceSlice<$field> + ?Sized), + fn hash_many( + inputs: &(impl HostOrDeviceSlice<$field> + ?Sized), output: &mut (impl HostOrDeviceSlice<$field> + ?Sized), number_of_states: u32, - arity: u32, - constants: &PoseidonConstants<$field>, - config: &PoseidonConfig, + input_block_len: u32, + output_len: u32, + poseidon: PoseidonHandle, + cfg: &SpongeConfig, ) -> IcicleResult<()> { unsafe { $field_prefix_ident::hash_many( - input.as_mut_ptr(), + poseidon, + inputs.as_ptr(), output.as_mut_ptr(), number_of_states, - arity, - constants, - config, + input_block_len, + output_len, + cfg, ) .wrap() } } + + fn delete(poseidon: PoseidonHandle) -> IcicleResult<()> { + unsafe { $field_prefix_ident::delete(poseidon).wrap() } + } } }; } @@ -318,18 +282,3 @@ macro_rules! impl_poseidon_tests { } }; } - -#[macro_export] -macro_rules! impl_poseidon_custom_config_test { - ( - $field:ident, - $field_bytes:literal, - $field_prefix:literal, - $partial_rounds:literal - ) => { - #[test] - fn test_poseidon_custom_config() { - check_poseidon_custom_config::<$field>($field_bytes, $field_prefix, $partial_rounds) - } - }; -} diff --git a/wrappers/rust/icicle-core/src/poseidon/tests.rs b/wrappers/rust/icicle-core/src/poseidon/tests.rs index 93f375766..425da8516 100644 --- a/wrappers/rust/icicle-core/src/poseidon/tests.rs +++ b/wrappers/rust/icicle-core/src/poseidon/tests.rs @@ -1,105 +1,48 @@ +use crate::hash::SpongeHash; use crate::traits::FieldImpl; use icicle_cuda_runtime::device_context::DeviceContext; use icicle_cuda_runtime::memory::{HostOrDeviceSlice, HostSlice}; -use std::io::Read; -use std::path::PathBuf; -use std::{env, fs::File}; +use super::{Poseidon, PoseidonImpl}; -use super::{ - create_optimized_poseidon_constants, load_optimized_poseidon_constants, poseidon_hash_many, Poseidon, - PoseidonConfig, PoseidonConstants, -}; - -pub fn init_poseidon<'a, F: FieldImpl>(arity: u32) -> PoseidonConstants<'a, F> +pub fn init_poseidon(arity: usize) -> Poseidon where - ::Config: Poseidon, + ::Config: PoseidonImpl, { let ctx = DeviceContext::default(); - - load_optimized_poseidon_constants::(arity, &ctx).unwrap() + Poseidon::load(arity, &ctx).unwrap() } -pub fn _check_poseidon_hash_many(constants: PoseidonConstants) -> (F, F) +pub fn _check_poseidon_hash_many(poseidon: Poseidon) where - ::Config: Poseidon, + ::Config: PoseidonImpl, { let test_size = 1 << 10; - let arity = 2u32; - let mut inputs = vec![F::one(); test_size * arity as usize]; + let arity = poseidon.width - 1; + let mut inputs = vec![F::one(); test_size * arity]; let mut outputs = vec![F::zero(); test_size]; let input_slice = HostSlice::from_mut_slice(&mut inputs); let output_slice = HostSlice::from_mut_slice(&mut outputs); - let config = PoseidonConfig::default(); - poseidon_hash_many::( - input_slice, - output_slice, - test_size as u32, - arity as u32, - &constants, - &config, - ) - .unwrap(); + let cfg = poseidon.default_config(); + poseidon + .hash_many(input_slice, output_slice, test_size, arity, 1, &cfg) + .unwrap(); let a1 = output_slice[0]; - let a2 = output_slice[output_slice.len() - 2]; + let a2 = output_slice[output_slice.len() - 1]; - println!("first: {:?}, last: {:?}", a1, a2); assert_eq!(a1, a2); - - (a1, a2) } pub fn check_poseidon_hash_many() where - ::Config: Poseidon, + ::Config: PoseidonImpl, { - for arity in [2, 4] { - let constants = init_poseidon::(arity as u32); + for arity in [2, 4, 8, 11] { + let poseidon = init_poseidon::(arity); - _check_poseidon_hash_many(constants); + _check_poseidon_hash_many(poseidon); } } - -pub fn check_poseidon_custom_config(field_bytes: usize, field_prefix: &str, partial_rounds: u32) -where - ::Config: Poseidon, -{ - let arity = 2u32; - let constants = init_poseidon::(arity as u32); - - let full_rounds_half = 4; - - let ctx = DeviceContext::default(); - let cargo_manifest_dir = env!("CARGO_MANIFEST_DIR"); - let constants_file = PathBuf::from(cargo_manifest_dir) - .join("tests") - .join(format!("{}_constants.bin", field_prefix)); - let mut constants_buf = vec![]; - File::open(constants_file) - .unwrap() - .read_to_end(&mut constants_buf) - .unwrap(); - - let mut custom_constants = vec![]; - for chunk in constants_buf.chunks(field_bytes) { - custom_constants.push(F::from_bytes_le(chunk)); - } - - let custom_constants = create_optimized_poseidon_constants::( - arity as u32, - &ctx, - full_rounds_half, - partial_rounds, - &mut custom_constants, - ) - .unwrap(); - - let (a1, a2) = _check_poseidon_hash_many(constants); - let (b1, b2) = _check_poseidon_hash_many(custom_constants); - - assert_eq!(a1, b1); - assert_eq!(a2, b2); -} diff --git a/wrappers/rust/icicle-core/src/poseidon2/mod.rs b/wrappers/rust/icicle-core/src/poseidon2/mod.rs index 46f33d553..dcbbdee85 100644 --- a/wrappers/rust/icicle-core/src/poseidon2/mod.rs +++ b/wrappers/rust/icicle-core/src/poseidon2/mod.rs @@ -1,300 +1,190 @@ #[doc(hidden)] pub mod tests; -use icicle_cuda_runtime::{ - device::check_device, - device_context::{DeviceContext, DEFAULT_DEVICE_ID}, - memory::{DeviceSlice, HostOrDeviceSlice}, -}; +use std::{ffi::c_void, marker::PhantomData}; + +use icicle_cuda_runtime::{device_context::DeviceContext, memory::HostOrDeviceSlice}; -use crate::{error::IcicleResult, traits::FieldImpl}; +use crate::{ + error::IcicleResult, + hash::{sponge_check_input, sponge_check_outputs, SpongeConfig, SpongeHash}, + traits::FieldImpl, +}; #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub enum DiffusionStrategy { Default, Montgomery, } #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] pub enum MdsType { Default, Plonky, } -#[repr(C)] -#[derive(Debug, Clone)] -pub enum PoseidonMode { - Compression, - Permutation, +pub type Poseidon2Handle = *const c_void; +pub struct Poseidon2 +where + F: FieldImpl, + ::Config: Poseidon2Impl, +{ + width: usize, + handle: Poseidon2Handle, + phantom: PhantomData, } -#[repr(C)] -pub struct Poseidon2Constants<'a, F: FieldImpl> { - width: u32, - - alpha: u32, - - internal_rounds: u32, - - external_rounds: u32, - - round_constants: &'a DeviceSlice, - - inernal_matrix_diag: &'a DeviceSlice, - - pub mds_type: MdsType, - - pub diffusion: DiffusionStrategy, -} +impl Poseidon2 +where + F: FieldImpl, + ::Config: Poseidon2Impl, +{ + pub fn load( + width: usize, + rate: usize, + mds_type: MdsType, + diffusion: DiffusionStrategy, + ctx: &DeviceContext, + ) -> IcicleResult { + <::Config as Poseidon2Impl>::load(width as u32, rate as u32, mds_type, diffusion, ctx) + .and_then(|handle| { + Ok(Self { + width, + handle, + phantom: PhantomData, + }) + }) + } -impl std::fmt::Debug for Poseidon2Constants<'_, F> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}, {}, {}, {}", - self.width, self.alpha, self.internal_rounds, self.external_rounds + pub fn new( + width: usize, + rate: usize, + alpha: u32, + internal_rounds: u32, + external_rounds: u32, + round_constants: &mut [F], + internal_matrix_diag: &mut [F], + mds_type: MdsType, + diffusion: DiffusionStrategy, + ctx: &DeviceContext, + ) -> IcicleResult { + <::Config as Poseidon2Impl>::create( + width as u32, + rate as u32, + alpha, + internal_rounds, + external_rounds, + round_constants, + internal_matrix_diag, + mds_type, + diffusion, + ctx, ) + .and_then(|handle| { + Ok(Self { + width, + handle, + phantom: PhantomData, + }) + }) } } -/// Struct that encodes Poseidon parameters to be passed into the [poseidon_hash_many](poseidon_hash_many) function. -#[repr(C)] -#[derive(Debug, Clone)] -pub struct Poseidon2Config<'a> { - /// Details related to the device such as its id and stream id. See [DeviceContext](@ref device_context::DeviceContext). - pub ctx: DeviceContext<'a>, - - are_states_on_device: bool, - - are_outputs_on_device: bool, +impl SpongeHash for Poseidon2 +where + F: FieldImpl, + ::Config: Poseidon2Impl, +{ + fn get_handle(&self) -> *const c_void { + self.handle + } - pub mode: PoseidonMode, + fn hash_many( + &self, + inputs: &(impl HostOrDeviceSlice + ?Sized), + output: &mut (impl HostOrDeviceSlice + ?Sized), + number_of_states: usize, + input_block_len: usize, + output_len: usize, + cfg: &SpongeConfig, + ) -> IcicleResult<()> { + sponge_check_input( + inputs, + number_of_states, + input_block_len, + cfg.input_rate as usize, + &cfg.ctx, + ); + sponge_check_outputs(output, number_of_states, output_len, self.width, false, &cfg.ctx); - pub output_index: u32, + let mut local_cfg = cfg.clone(); + local_cfg.are_inputs_on_device = inputs.is_on_device(); + local_cfg.are_outputs_on_device = output.is_on_device(); - /// Whether to run Poseidon asynchronously. If set to `true`, Poseidon will be non-blocking - /// and you'd need to synchronize it explicitly by running `cudaStreamSynchronize` or `cudaDeviceSynchronize`. - /// If set to `false`, Poseidon will block the current CPU thread. - pub is_async: bool, -} + <::Config as Poseidon2Impl>::hash_many( + inputs, + output, + number_of_states as u32, + input_block_len as u32, + output_len as u32, + self.handle, + &local_cfg, + ) + } -impl<'a> Default for Poseidon2Config<'a> { - fn default() -> Self { - Self::default_for_device(DEFAULT_DEVICE_ID) + fn default_config<'a>(&self) -> SpongeConfig<'a> { + let mut cfg = SpongeConfig::default(); + cfg.input_rate = self.width as u32; + cfg.output_rate = self.width as u32; + cfg } } -impl<'a> Poseidon2Config<'a> { - pub fn default_for_device(device_id: usize) -> Self { - Self { - ctx: DeviceContext::default_for_device(device_id), - are_states_on_device: false, - are_outputs_on_device: false, - mode: PoseidonMode::Compression, - output_index: 1, - is_async: false, - } +impl Drop for Poseidon2 +where + F: FieldImpl, + ::Config: Poseidon2Impl, +{ + fn drop(&mut self) { + <::Config as Poseidon2Impl>::delete(self.handle).unwrap(); } } -pub trait Poseidon2 { - fn create_constants<'a>( +pub trait Poseidon2Impl { + fn create( width: u32, + rate: u32, alpha: u32, internal_rounds: u32, external_rounds: u32, - round_constants: &mut [F], - internal_matrix_diag: &mut [F], + round_constants: &[F], + internal_matrix_diag: &[F], mds_type: MdsType, diffusion: DiffusionStrategy, ctx: &DeviceContext, - ) -> IcicleResult>; - fn load_constants<'a>( + ) -> IcicleResult; + + fn load( width: u32, + rate: u32, mds_type: MdsType, diffusion: DiffusionStrategy, ctx: &DeviceContext, - ) -> IcicleResult>; - fn poseidon_unchecked( - states: &(impl HostOrDeviceSlice + ?Sized), + ) -> IcicleResult; + + fn hash_many( + inputs: &(impl HostOrDeviceSlice + ?Sized), output: &mut (impl HostOrDeviceSlice + ?Sized), number_of_states: u32, - width: u32, - constants: &Poseidon2Constants, - config: &Poseidon2Config, + input_block_len: u32, + output_len: u32, + poseidon: Poseidon2Handle, + cfg: &SpongeConfig, ) -> IcicleResult<()>; - fn poseidon_unchecked_inplace( - states: &mut (impl HostOrDeviceSlice + ?Sized), - number_of_states: u32, - width: u32, - constants: &Poseidon2Constants, - config: &Poseidon2Config, - ) -> IcicleResult<()>; - fn release_constants(constants: &Poseidon2Constants, ctx: &DeviceContext) -> IcicleResult<()>; -} -/// Loads pre-calculated poseidon constants on the GPU. -pub fn load_poseidon2_constants<'a, F>( - width: u32, - mds_type: MdsType, - diffusion: DiffusionStrategy, - ctx: &DeviceContext, -) -> IcicleResult> -where - F: FieldImpl, - ::Config: Poseidon2, -{ - <::Config as Poseidon2>::load_constants(width, mds_type, diffusion, ctx) -} - -/// Creates new instance of poseidon constants on the GPU. -pub fn create_poseidon2_constants<'a, F>( - width: u32, - alpha: u32, - ctx: &DeviceContext, - internal_rounds: u32, - external_rounds: u32, - round_constants: &mut [F], - internal_matrix_diag: &mut [F], - mds_type: MdsType, - diffusion: DiffusionStrategy, -) -> IcicleResult> -where - F: FieldImpl, - ::Config: Poseidon2, -{ - <::Config as Poseidon2>::create_constants( - width, - alpha, - internal_rounds, - external_rounds, - round_constants, - internal_matrix_diag, - mds_type, - diffusion, - ctx, - ) -} - -fn poseidon_checks( - states: &(impl HostOrDeviceSlice + ?Sized), - output: &(impl HostOrDeviceSlice + ?Sized), - number_of_states: u32, - width: u32, - config: &Poseidon2Config, -) where - F: FieldImpl, - ::Config: Poseidon2, -{ - if states.len() < (number_of_states * width) as usize { - panic!( - "input len is {}; but needs to be at least {}", - states.len(), - number_of_states * width - ); - } - if output.len() < number_of_states as usize { - panic!( - "output len is {}; but needs to be at least {}", - output.len(), - number_of_states - ); - } - - let ctx_device_id = config - .ctx - .device_id; - if let Some(device_id) = states.device_id() { - assert_eq!( - device_id, ctx_device_id, - "Device ids in input and context are different" - ); - } - - if let Some(device_id) = output.device_id() { - assert_eq!( - device_id, ctx_device_id, - "Device ids in output and context are different" - ); - } - check_device(ctx_device_id); -} - -/// Computes the poseidon hashes for multiple preimages. -/// -/// # Arguments -/// -/// * `input` - a pointer to the input data. May point to a vector of preimages or a vector of states filled with preimages. -/// -/// * `output` - a pointer to the output data. Must be at least of size [number_of_states](number_of_states) -/// -/// * `number_of_states` - number of input blocks of size `arity` -/// -/// * `arity` - the arity of the hash function (the size of 1 preimage) -/// -/// * `constants` - Poseidon constants. -/// -/// * `config` - config used to specify extra arguments of the Poseidon. -pub fn poseidon2_hash_many( - states: &(impl HostOrDeviceSlice + ?Sized), - output: &mut (impl HostOrDeviceSlice + ?Sized), - number_of_states: u32, - width: u32, - constants: &Poseidon2Constants, - config: &Poseidon2Config, -) -> IcicleResult<()> -where - F: FieldImpl, - ::Config: Poseidon2, -{ - poseidon_checks(states, output, number_of_states, width, config); - let mut local_cfg = config.clone(); - local_cfg.are_states_on_device = states.is_on_device(); - local_cfg.are_outputs_on_device = output.is_on_device(); - - <::Config as Poseidon2>::poseidon_unchecked( - states, - output, - number_of_states, - width, - constants, - &local_cfg, - ) -} - -pub fn poseidon2_hash_many_inplace( - states: &mut (impl HostOrDeviceSlice + ?Sized), - number_of_states: u32, - width: u32, - constants: &Poseidon2Constants, - config: &Poseidon2Config, -) -> IcicleResult<()> -where - F: FieldImpl, - ::Config: Poseidon2, -{ - poseidon_checks(states, states, number_of_states, width, config); - let mut local_cfg = config.clone(); - local_cfg.are_states_on_device = states.is_on_device(); - local_cfg.are_outputs_on_device = states.is_on_device(); - - <::Config as Poseidon2>::poseidon_unchecked_inplace( - states, - number_of_states, - width, - constants, - &local_cfg, - ) -} - -pub fn release_poseidon2_constants<'a, F>(constants: &Poseidon2Constants, ctx: &DeviceContext) -> IcicleResult<()> -where - F: FieldImpl, - ::Config: Poseidon2, -{ - <::Config as Poseidon2>::release_constants(constants, ctx) + fn delete(poseidon: Poseidon2Handle) -> IcicleResult<()>; } #[macro_export] @@ -307,140 +197,125 @@ macro_rules! impl_poseidon2 { ) => { mod $field_prefix_ident { use crate::poseidon2::{ - $field, $field_config, CudaError, DeviceContext, DiffusionStrategy, MdsType, Poseidon2Config, - Poseidon2Constants, + $field, $field_config, CudaError, DeviceContext, DiffusionStrategy, MdsType, Poseidon2Handle, + SpongeConfig, }; + use icicle_core::error::IcicleError; extern "C" { - #[link_name = concat!($field_prefix, "_create_poseidon2_constants_cuda")] - pub(crate) fn _create_constants( + #[link_name = concat!($field_prefix, "_poseidon2_create_cuda")] + pub(crate) fn create( + poseidon: *mut Poseidon2Handle, width: u32, + rate: u32, alpha: u32, internal_rounds: u32, external_rounds: u32, - constants: *mut $field, - internal_matrix_diag: *mut $field, + constants: *const $field, + internal_matrix_diag: *const $field, mds_type: MdsType, diffusion: DiffusionStrategy, ctx: &DeviceContext, - poseidon_constants: *mut Poseidon2Constants<$field>, ) -> CudaError; - #[link_name = concat!($field_prefix, "_init_poseidon2_constants_cuda")] - pub(crate) fn _load_constants( + #[link_name = concat!($field_prefix, "_poseidon2_load_cuda")] + pub(crate) fn load( + poseidon: *mut Poseidon2Handle, width: u32, + rate: u32, mds_type: MdsType, diffusion: DiffusionStrategy, ctx: &DeviceContext, - constants: *mut Poseidon2Constants<$field>, ) -> CudaError; - #[link_name = concat!($field_prefix, "_release_poseidon2_constants_cuda")] - pub(crate) fn _release_constants( - constants: &Poseidon2Constants<$field>, - ctx: &DeviceContext, - ) -> CudaError; + #[link_name = concat!($field_prefix, "_poseidon2_delete_cuda")] + pub(crate) fn delete(poseidon: Poseidon2Handle) -> CudaError; - #[link_name = concat!($field_prefix, "_poseidon2_hash_cuda")] + #[link_name = concat!($field_prefix, "_poseidon2_hash_many_cuda")] pub(crate) fn hash_many( - states: *const $field, + poseidon: Poseidon2Handle, + inputs: *const $field, output: *mut $field, number_of_states: u32, - width: u32, - constants: &Poseidon2Constants<$field>, - config: &Poseidon2Config, + input_block_len: u32, + output_len: u32, + cfg: &SpongeConfig, ) -> CudaError; } } - impl Poseidon2<$field> for $field_config { - fn create_constants<'a>( + impl Poseidon2Impl<$field> for $field_config { + fn create( width: u32, + rate: u32, alpha: u32, internal_rounds: u32, external_rounds: u32, - round_constants: &mut [$field], - internal_matrix_diag: &mut [$field], + round_constants: &[$field], + internal_matrix_diag: &[$field], mds_type: MdsType, diffusion: DiffusionStrategy, ctx: &DeviceContext, - ) -> IcicleResult> { + ) -> IcicleResult { unsafe { - let mut poseidon_constants = MaybeUninit::>::uninit(); - let err = $field_prefix_ident::_create_constants( + let mut poseidon = MaybeUninit::::uninit(); + $field_prefix_ident::create( + poseidon.as_mut_ptr(), width, + rate, alpha, internal_rounds, external_rounds, - round_constants as *mut _ as *mut $field, - internal_matrix_diag as *mut _ as *mut $field, + round_constants as *const _ as *const $field, + internal_matrix_diag as *const _ as *const $field, mds_type, diffusion, ctx, - poseidon_constants.as_mut_ptr(), ) - .wrap(); - err.and(Ok(poseidon_constants.assume_init())) + .wrap() + .and(Ok(poseidon.assume_init())) } } - fn load_constants<'a>( + fn load( width: u32, + rate: u32, mds_type: MdsType, diffusion: DiffusionStrategy, ctx: &DeviceContext, - ) -> IcicleResult> { + ) -> IcicleResult { unsafe { - let mut constants = MaybeUninit::>::uninit(); - let err = - $field_prefix_ident::_load_constants(width, mds_type, diffusion, ctx, constants.as_mut_ptr()) - .wrap(); - err.and(Ok(constants.assume_init())) + let mut poseidon = MaybeUninit::::uninit(); + $field_prefix_ident::load(poseidon.as_mut_ptr(), width, rate, mds_type, diffusion, ctx) + .wrap() + .and(Ok(poseidon.assume_init())) } } - fn poseidon_unchecked( - states: &(impl HostOrDeviceSlice<$field> + ?Sized), + fn hash_many( + inputs: &(impl HostOrDeviceSlice<$field> + ?Sized), output: &mut (impl HostOrDeviceSlice<$field> + ?Sized), number_of_states: u32, - width: u32, - constants: &Poseidon2Constants<$field>, - config: &Poseidon2Config, + input_block_len: u32, + output_len: u32, + poseidon: Poseidon2Handle, + cfg: &SpongeConfig, ) -> IcicleResult<()> { unsafe { $field_prefix_ident::hash_many( - states.as_ptr(), + poseidon, + inputs.as_ptr(), output.as_mut_ptr(), number_of_states, - width, - constants, - config, + input_block_len, + output_len, + cfg, ) .wrap() } } - fn poseidon_unchecked_inplace( - states: &mut (impl HostOrDeviceSlice<$field> + ?Sized), - number_of_states: u32, - width: u32, - constants: &Poseidon2Constants<$field>, - config: &Poseidon2Config, - ) -> IcicleResult<()> { - unsafe { - $field_prefix_ident::hash_many( - states.as_ptr(), - states.as_mut_ptr(), - number_of_states, - width, - constants, - config, - ) - .wrap() - } - } - - fn release_constants<'a>(constants: &Poseidon2Constants<$field>, ctx: &DeviceContext) -> IcicleResult<()> { - unsafe { $field_prefix_ident::_release_constants(constants, ctx).wrap() } + fn delete(poseidon: Poseidon2Handle) -> IcicleResult<()> { + unsafe { $field_prefix_ident::delete(poseidon).wrap() } } } }; @@ -466,42 +341,41 @@ pub mod bench { }; use crate::{ + hash::SpongeHash, ntt::FieldImpl, - poseidon2::{load_poseidon2_constants, DiffusionStrategy, MdsType}, + poseidon2::{DiffusionStrategy, MdsType, Poseidon2, Poseidon2Impl}, traits::GenerateRandom, vec_ops::VecOps, }; - use super::{poseidon2_hash_many, Poseidon2, Poseidon2Config, Poseidon2Constants}; - #[allow(unused)] - fn poseidon2_for_bench<'a, F: FieldImpl>( + fn poseidon2_for_bench( + poseidon: &Poseidon2, states: &(impl HostOrDeviceSlice + ?Sized), poseidon2_result: &mut (impl HostOrDeviceSlice + ?Sized), number_of_states: usize, - width: usize, - constants: &Poseidon2Constants<'a, F>, - config: &Poseidon2Config, + ctx: &DeviceContext, _seed: u32, ) where - ::Config: Poseidon2 + GenerateRandom, - ::Config: VecOps, + ::Config: Poseidon2Impl + GenerateRandom, { - poseidon2_hash_many( - states, - poseidon2_result, - number_of_states as u32, - width as u32, - constants, - config, - ) - .unwrap(); + let cfg = poseidon.default_config(); + poseidon + .hash_many( + states, + poseidon2_result, + number_of_states, + poseidon.width, + poseidon.width, + &cfg, + ) + .unwrap(); } #[allow(unused)] pub fn benchmark_poseidon2(c: &mut Criterion) where - ::Config: Poseidon2 + GenerateRandom, + ::Config: Poseidon2Impl + GenerateRandom, ::Config: VecOps, { use criterion::SamplingMode; @@ -519,7 +393,7 @@ pub mod bench { .parse::() .unwrap_or(MAX_LOG2); - for test_size_log2 in 13u32..max_log2 + 1 { + for test_size_log2 in 18u32..max_log2 + 1 { for t in [2, 3, 4, 8, 16, 20, 24] { let number_of_states = 1 << test_size_log2; let full_size = t * number_of_states; @@ -531,31 +405,27 @@ pub mod bench { let permutation_result_slice = HostSlice::from_mut_slice(&mut permutation_result); let ctx = DeviceContext::default(); - let config = Poseidon2Config::default(); - for mds in [MdsType::Default, MdsType::Plonky] { - for diffusion in [DiffusionStrategy::Default, DiffusionStrategy::Montgomery] { - let constants = - load_poseidon2_constants(t as u32, mds.clone(), diffusion.clone(), &ctx).unwrap(); - let bench_descr = format!( - "Mds::{:?}; Diffusion::{:?}; Number of states: {}; Width: {}", - mds, diffusion, number_of_states, t - ); - group.bench_function(&bench_descr, |b| { - b.iter(|| { - poseidon2_for_bench::( - input, - permutation_result_slice, - number_of_states, - t, - &constants, - &config, - black_box(1), - ) - }) - }); - - // } - } + for (mds, diffusion) in [ + (MdsType::Default, DiffusionStrategy::Default), + (MdsType::Plonky, DiffusionStrategy::Montgomery), + ] { + let poseidon = Poseidon2::::load(t, t, mds, diffusion, &ctx).unwrap(); + let bench_descr = format!( + "TestSize: 2**{}, Mds::{:?}, Diffusion::{:?}, Width: {}", + test_size_log2, mds, diffusion, t + ); + group.bench_function(&bench_descr, |b| { + b.iter(|| { + poseidon2_for_bench::( + &poseidon, + input, + permutation_result_slice, + number_of_states, + &ctx, + black_box(1), + ) + }) + }); } } } diff --git a/wrappers/rust/icicle-core/src/poseidon2/tests.rs b/wrappers/rust/icicle-core/src/poseidon2/tests.rs index a45697508..cd2573aeb 100644 --- a/wrappers/rust/icicle-core/src/poseidon2/tests.rs +++ b/wrappers/rust/icicle-core/src/poseidon2/tests.rs @@ -1,27 +1,21 @@ -use crate::poseidon2::{MdsType, PoseidonMode}; +use crate::hash::SpongeHash; use crate::traits::FieldImpl; use icicle_cuda_runtime::device_context::DeviceContext; use icicle_cuda_runtime::memory::{HostOrDeviceSlice, HostSlice}; -use super::{ - load_poseidon2_constants, poseidon2_hash_many, DiffusionStrategy, Poseidon2, Poseidon2Config, Poseidon2Constants, -}; +use super::{DiffusionStrategy, MdsType, Poseidon2, Poseidon2Impl}; -pub fn init_poseidon<'a, F: FieldImpl>( - width: u32, - mds_type: MdsType, - diffusion: DiffusionStrategy, -) -> Poseidon2Constants<'a, F> +pub fn init_poseidon(width: usize, mds_type: MdsType, diffusion: DiffusionStrategy) -> Poseidon2 where - ::Config: Poseidon2, + ::Config: Poseidon2Impl, { let ctx = DeviceContext::default(); - load_poseidon2_constants::(width, mds_type, diffusion, &ctx).unwrap() + Poseidon2::load(width, width, mds_type, diffusion, &ctx).unwrap() } -fn _check_poseidon_hash_many(width: u32, constants: Poseidon2Constants) -> (F, F) +fn _check_poseidon_hash_many(width: usize, poseidon: &Poseidon2) -> (F, F) where - ::Config: Poseidon2, + ::Config: Poseidon2Impl, { let test_size = 1 << 10; let mut inputs = vec![F::one(); test_size * width as usize]; @@ -30,16 +24,10 @@ where let input_slice = HostSlice::from_mut_slice(&mut inputs); let output_slice = HostSlice::from_mut_slice(&mut outputs); - let config = Poseidon2Config::default(); - poseidon2_hash_many::( - input_slice, - output_slice, - test_size as u32, - width as u32, - &constants, - &config, - ) - .unwrap(); + let cfg = poseidon.default_config(); + poseidon + .hash_many(input_slice, output_slice, test_size, width, 1, &cfg) + .unwrap(); let a1 = output_slice[0]; let a2 = output_slice[output_slice.len() - 2]; @@ -49,21 +37,22 @@ where (a1, a2) } -pub fn check_poseidon_hash_many<'a, F: FieldImpl + 'a>() +pub fn check_poseidon_hash_many() where - ::Config: Poseidon2, + ::Config: Poseidon2Impl, { let widths = [2, 3, 4, 8, 12, 16, 20, 24]; + let ctx = DeviceContext::default(); for width in widths { - let constants = init_poseidon::<'a, F>(width as u32, MdsType::Default, DiffusionStrategy::Default); + let poseidon = Poseidon2::::load(width, width, MdsType::Default, DiffusionStrategy::Default, &ctx).unwrap(); - _check_poseidon_hash_many(width, constants); + _check_poseidon_hash_many(width, &poseidon); } } -pub fn check_poseidon_kats<'a, F: FieldImpl>(width: usize, kats: &[F], constants: &Poseidon2Constants<'a, F>) +pub fn check_poseidon_kats(width: usize, kats: &[F], poseidon: &Poseidon2) where - ::Config: Poseidon2, + ::Config: Poseidon2Impl, { assert_eq!(width, kats.len()); @@ -83,17 +72,11 @@ where let input_slice = HostSlice::from_mut_slice(&mut inputs); let output_slice = HostSlice::from_mut_slice(&mut outputs); - let mut config = Poseidon2Config::default(); - config.mode = PoseidonMode::Permutation; - poseidon2_hash_many::( - input_slice, - output_slice, - batch_size as u32, - width as u32, - &constants, - &config, - ) - .unwrap(); + let cfg = poseidon.default_config(); + + poseidon + .hash_many(input_slice, output_slice, batch_size, width, width, &cfg) + .unwrap(); for (i, val) in output_slice .iter() diff --git a/wrappers/rust/icicle-core/src/tree/mmcs.rs b/wrappers/rust/icicle-core/src/tree/mmcs.rs new file mode 100644 index 000000000..b09f17962 --- /dev/null +++ b/wrappers/rust/icicle-core/src/tree/mmcs.rs @@ -0,0 +1,79 @@ +use icicle_cuda_runtime::memory::HostSlice; + +use crate::{error::IcicleResult, ntt::FieldImpl}; +use crate::{hash::SpongeHash, Matrix}; + +use super::TreeBuilderConfig; + +pub trait FieldMmcs +where + F: FieldImpl, + Compression: SpongeHash, + Hasher: SpongeHash, +{ + fn mmcs_commit( + leaves: Vec, + digests: &mut HostSlice, + hasher: &Hasher, + compression: &Compression, + config: &TreeBuilderConfig, + ) -> IcicleResult<()>; +} + +#[macro_export] +macro_rules! impl_mmcs { + ( + $field_prefix:literal, + $field_prefix_ident:ident, + $field:ident, + $field_config:ident, + $mmcs:ident + ) => { + mod $field_prefix_ident { + use super::*; + use icicle_cuda_runtime::error::CudaError; + + extern "C" { + #[link_name = concat!($field_prefix, "_mmcs_commit_cuda")] + pub(crate) fn mmcs_commit_cuda( + leaves: *const Matrix, + number_of_inputs: u32, + digests: *mut $field, + hasher: *const c_void, + compression: *const c_void, + config: &TreeBuilderConfig, + ) -> CudaError; + } + } + + struct $mmcs; + + impl FieldMmcs<$field, Compression, Hasher> for $mmcs + where + Compression: SpongeHash<$field, $field>, + Hasher: SpongeHash<$field, $field>, + { + fn mmcs_commit( + leaves: Vec, + digests: &mut HostSlice<$field>, + hasher: &Hasher, + compression: &Compression, + config: &TreeBuilderConfig, + ) -> IcicleResult<()> { + unsafe { + $field_prefix_ident::mmcs_commit_cuda( + leaves + .as_slice() + .as_ptr(), + leaves.len() as u32, + digests.as_mut_ptr(), + compression.get_handle(), + hasher.get_handle(), + config, + ) + .wrap() + } + } + } + }; +} diff --git a/wrappers/rust/icicle-core/src/tree/mod.rs b/wrappers/rust/icicle-core/src/tree/mod.rs index d32f72798..10a1abfd3 100644 --- a/wrappers/rust/icicle-core/src/tree/mod.rs +++ b/wrappers/rust/icicle-core/src/tree/mod.rs @@ -1,11 +1,12 @@ -use icicle_cuda_runtime::device::check_device; use icicle_cuda_runtime::{ device_context::{DeviceContext, DEFAULT_DEVICE_ID}, memory::HostOrDeviceSlice, }; -use crate::{error::IcicleResult, poseidon::PoseidonConstants, traits::FieldImpl}; +use crate::hash::SpongeHash; +use crate::{error::IcicleResult, ntt::FieldImpl}; +pub mod mmcs; #[doc(hidden)] pub mod tests; @@ -16,11 +17,20 @@ pub struct TreeBuilderConfig<'a> { /// Details related to the device such as its id and stream id. See [DeviceContext](@ref device_context::DeviceContext). pub ctx: DeviceContext<'a>, + /// Airty of the tree + pub arity: u32, + /// How many rows of the Merkle tree rows should be written to output. '0' means all of them - keep_rows: u32, + pub keep_rows: u32, + + /// The size of the output for the bottom layer hash and compression. + /// Will also be equal to the size of the root of the tree. Default value 1 + pub digest_elements: u32, are_inputs_on_device: bool, + are_outputs_on_device: bool, + /// Whether to run build_merkle_tree asynchronously. If set to `true`, TreeBuilder will be non-blocking /// and you'd need to synchronize it explicitly by running `cudaStreamSynchronize` or `cudaDeviceSynchronize`. /// If set to `false`, build_merkle_tree will block the current CPU thread. @@ -32,134 +42,99 @@ impl<'a> Default for TreeBuilderConfig<'a> { Self::default_for_device(DEFAULT_DEVICE_ID) } } + impl<'a> TreeBuilderConfig<'a> { fn default_for_device(device_id: usize) -> Self { Self { ctx: DeviceContext::default_for_device(device_id), + arity: 2, keep_rows: 0, + digest_elements: 1, are_inputs_on_device: false, + are_outputs_on_device: false, is_async: false, } } } -pub fn merkle_tree_digests_len(height: u32, arity: u32) -> usize { +pub fn merkle_tree_digests_len(height: u32, arity: u32, digest_elements: u32) -> usize { let mut digests_len = 0usize; - let mut row_length = 1; - for _ in 1..height { + let mut row_length = digest_elements as usize; + for _ in 0..height + 1 { digests_len += row_length; row_length *= arity as usize; } digests_len } -pub trait TreeBuilder { - fn build_poseidon_tree_unchecked( - leaves: &mut (impl HostOrDeviceSlice + ?Sized), - digests: &mut [F], - height: u32, - arity: u32, - constants: &PoseidonConstants, - config: &TreeBuilderConfig, - ) -> IcicleResult<()>; -} - -/// Builds a Poseidon Merkle tree. -/// -/// # Arguments -/// -/// * `leaves` - a pointer to the leaves layer. Expected to have arity ^ (height - 1) elements -/// -/// * `digests` - a pointer to the digests storage. Expected to have `sum(arity ^ (i)) for i in [0..height-1]` -/// -/// * `height` - the height of the merkle tree -/// -/// * `config` - config used to specify extra arguments of the Tree builder. -pub fn build_poseidon_merkle_tree( - leaves: &mut (impl HostOrDeviceSlice + ?Sized), - digests: &mut [F], - height: u32, - arity: u32, - constants: &PoseidonConstants, - config: &TreeBuilderConfig, -) -> IcicleResult<()> +pub trait FieldTreeBuilder where F: FieldImpl, - ::Config: TreeBuilder, + Compression: SpongeHash, + Sponge: SpongeHash, { - let leaves_len = 1 << (height - 1) as usize; - if leaves.len() != leaves_len { - panic!("Leaves len is {}; but needs to be exactly {}", leaves.len(), leaves_len,); - } - - let digests_len = merkle_tree_digests_len(height, arity); - if digests.len() != digests_len as usize { - panic!( - "Digests len is {}; but needs to be exactly {}", - digests.len(), - digests_len - ); - } - - let ctx_device_id = config - .ctx - .device_id; - if let Some(device_id) = leaves.device_id() { - assert_eq!( - device_id, ctx_device_id, - "Device ids in leaves and context are different" - ); - } - check_device(ctx_device_id); - let mut local_cfg = config.clone(); - local_cfg.are_inputs_on_device = leaves.is_on_device(); - - <::Config as TreeBuilder>::build_poseidon_tree_unchecked( - leaves, digests, height, arity, constants, &local_cfg, - ) + fn build_merkle_tree( + leaves: &(impl HostOrDeviceSlice + ?Sized), + digests: &mut (impl HostOrDeviceSlice + ?Sized), + height: usize, + input_block_len: usize, + compression: &Compression, + sponge: &Sponge, + config: &TreeBuilderConfig, + ) -> IcicleResult<()>; } #[macro_export] -macro_rules! impl_tree_builder { +macro_rules! impl_field_tree_builder { ( $field_prefix:literal, $field_prefix_ident:ident, $field:ident, - $field_config:ident + $field_config:ident, + $tree_builder:ident ) => { mod $field_prefix_ident { - use crate::tree::{$field, $field_config, CudaError, DeviceContext, TreeBuilderConfig}; - use icicle_core::poseidon::PoseidonConstants; + use super::*; + use icicle_cuda_runtime::error::CudaError; extern "C" { - #[link_name = concat!($field_prefix, "_build_poseidon_merkle_tree")] - pub(crate) fn _build_poseidon_merkle_tree( - leaves: *mut $field, + #[link_name = concat!($field_prefix, "_build_merkle_tree")] + pub(crate) fn build_merkle_tree( + leaves: *const $field, digests: *mut $field, height: u32, - arity: u32, - constants: &PoseidonConstants<$field>, + input_block_len: u32, + compression: *const c_void, + sponge: *const c_void, config: &TreeBuilderConfig, ) -> CudaError; } } - impl TreeBuilder<$field> for $field_config { - fn build_poseidon_tree_unchecked( - leaves: &mut (impl HostOrDeviceSlice<$field> + ?Sized), - digests: &mut [$field], - height: u32, - arity: u32, - constants: &PoseidonConstants<$field>, + struct $tree_builder; + + impl FieldTreeBuilder<$field, Compression, Sponge> for $tree_builder + where + Compression: SpongeHash<$field, $field>, + Sponge: SpongeHash<$field, $field>, + { + fn build_merkle_tree( + leaves: &(impl HostOrDeviceSlice<$field> + ?Sized), + digests: &mut (impl HostOrDeviceSlice<$field> + ?Sized), + height: usize, + input_block_len: usize, + compression: &Compression, + sponge: &Sponge, config: &TreeBuilderConfig, ) -> IcicleResult<()> { unsafe { - $field_prefix_ident::_build_poseidon_merkle_tree( - leaves.as_mut_ptr(), - digests as *mut _ as *mut $field, - height, - arity, - constants, + $field_prefix_ident::build_merkle_tree( + leaves.as_ptr(), + digests.as_mut_ptr(), + height as u32, + input_block_len as u32, + compression.get_handle(), + sponge.get_handle(), config, ) .wrap() @@ -168,15 +143,3 @@ macro_rules! impl_tree_builder { } }; } - -#[macro_export] -macro_rules! impl_tree_builder_tests { - ( - $field:ident - ) => { - #[test] - fn test_build_poseidon_merkle_tree() { - check_build_merkle_tree::<$field>() - } - }; -} diff --git a/wrappers/rust/icicle-core/src/tree/tests.rs b/wrappers/rust/icicle-core/src/tree/tests.rs index eebcdedd0..9e1e17bb7 100644 --- a/wrappers/rust/icicle-core/src/tree/tests.rs +++ b/wrappers/rust/icicle-core/src/tree/tests.rs @@ -1,30 +1,42 @@ use icicle_cuda_runtime::memory::HostSlice; use crate::{ - poseidon::{tests::init_poseidon, Poseidon}, + hash::SpongeHash, traits::FieldImpl, - tree::{build_poseidon_merkle_tree, merkle_tree_digests_len, TreeBuilderConfig}, + tree::{merkle_tree_digests_len, TreeBuilderConfig}, }; -use super::TreeBuilder; +use super::FieldTreeBuilder; -pub fn check_build_merkle_tree() -where - ::Config: TreeBuilder + Poseidon, +pub fn check_build_field_merkle_tree( + height: usize, + arity: usize, + sponge: &H, + compression: &H, + _expected_root: F, +) where + F: FieldImpl, + H: SpongeHash, + T: FieldTreeBuilder, { - let height = 20; - let arity = 2; - let keep_rows = 1; - let mut leaves = vec![F::one(); 1 << (height - 1)]; - let mut digests = vec![F::zero(); merkle_tree_digests_len(height, arity)]; - - let leaves_slice = HostSlice::from_mut_slice(&mut leaves); - - let constants = init_poseidon(arity as u32); - let mut config = TreeBuilderConfig::default(); - config.keep_rows = keep_rows; - build_poseidon_merkle_tree::(leaves_slice, &mut digests, height, arity, &constants, &config).unwrap(); + config.arity = arity as u32; + let input_block_len = arity; + let leaves = vec![F::one(); (1 << height) * arity]; + let mut digests = vec![F::zero(); merkle_tree_digests_len((height + 1) as u32, arity as u32, 1)]; + + let leaves_slice = HostSlice::from_slice(&leaves); + let digests_slice = HostSlice::from_mut_slice(&mut digests); - println!("Root: {:?}", digests[0]); + T::build_merkle_tree( + leaves_slice, + digests_slice, + height, + input_block_len, + compression, + sponge, + &config, + ) + .unwrap(); + println!("Root: {:?}", digests_slice[0]); } diff --git a/wrappers/rust/icicle-core/tests/bls12_377_constants.bin b/wrappers/rust/icicle-core/tests/bls12_377_constants.bin deleted file mode 100644 index 1cd8627f5..000000000 Binary files a/wrappers/rust/icicle-core/tests/bls12_377_constants.bin and /dev/null differ diff --git a/wrappers/rust/icicle-core/tests/bls12_381_constants.bin b/wrappers/rust/icicle-core/tests/bls12_381_constants.bin deleted file mode 100644 index 6e46aca81..000000000 Binary files a/wrappers/rust/icicle-core/tests/bls12_381_constants.bin and /dev/null differ diff --git a/wrappers/rust/icicle-core/tests/bn254_constants.bin b/wrappers/rust/icicle-core/tests/bn254_constants.bin deleted file mode 100644 index 8d9c89083..000000000 Binary files a/wrappers/rust/icicle-core/tests/bn254_constants.bin and /dev/null differ diff --git a/wrappers/rust/icicle-core/tests/bw6-761_constants.bin b/wrappers/rust/icicle-core/tests/bw6-761_constants.bin deleted file mode 100644 index 71c1330e8..000000000 Binary files a/wrappers/rust/icicle-core/tests/bw6-761_constants.bin and /dev/null differ diff --git a/wrappers/rust/icicle-core/tests/grumpkin_constants.bin b/wrappers/rust/icicle-core/tests/grumpkin_constants.bin deleted file mode 100644 index 684493dcb..000000000 Binary files a/wrappers/rust/icicle-core/tests/grumpkin_constants.bin and /dev/null differ diff --git a/wrappers/rust/icicle-curves/icicle-bls12-377/src/poseidon/mod.rs b/wrappers/rust/icicle-curves/icicle-bls12-377/src/poseidon/mod.rs index 40fac5dc6..0136c3030 100644 --- a/wrappers/rust/icicle-curves/icicle-bls12-377/src/poseidon/mod.rs +++ b/wrappers/rust/icicle-curves/icicle-bls12-377/src/poseidon/mod.rs @@ -3,8 +3,9 @@ use crate::curve::{BaseCfg, BaseField}; use crate::curve::{ScalarCfg, ScalarField}; use icicle_core::error::IcicleResult; +use icicle_core::hash::SpongeConfig; use icicle_core::impl_poseidon; -use icicle_core::poseidon::{Poseidon, PoseidonConfig, PoseidonConstants}; +use icicle_core::poseidon::{PoseidonHandle, PoseidonImpl}; use icicle_core::traits::IcicleResultWrap; use icicle_cuda_runtime::device_context::DeviceContext; use icicle_cuda_runtime::error::CudaError; @@ -20,9 +21,8 @@ impl_poseidon!("bw6_761", bw6_761, BaseField, BaseCfg); #[cfg(test)] pub(crate) mod tests { use crate::curve::ScalarField; + use icicle_core::impl_poseidon_tests; use icicle_core::poseidon::tests::*; - use icicle_core::{impl_poseidon_custom_config_test, impl_poseidon_tests}; impl_poseidon_tests!(ScalarField); - impl_poseidon_custom_config_test!(ScalarField, 32, "bls12_377", 56); } diff --git a/wrappers/rust/icicle-curves/icicle-bls12-377/src/tree/mod.rs b/wrappers/rust/icicle-curves/icicle-bls12-377/src/tree/mod.rs index b3be12171..14af731e2 100644 --- a/wrappers/rust/icicle-curves/icicle-bls12-377/src/tree/mod.rs +++ b/wrappers/rust/icicle-curves/icicle-bls12-377/src/tree/mod.rs @@ -1,26 +1,29 @@ -#[cfg(feature = "bw6-761")] -use crate::curve::{BaseCfg, BaseField}; -use crate::curve::{ScalarCfg, ScalarField}; - use icicle_core::error::IcicleResult; -use icicle_core::impl_tree_builder; -use icicle_core::poseidon::PoseidonConstants; +use icicle_core::hash::SpongeHash; +use icicle_core::impl_field_tree_builder; use icicle_core::traits::IcicleResultWrap; -use icicle_core::tree::{TreeBuilder, TreeBuilderConfig}; -use icicle_cuda_runtime::device_context::DeviceContext; -use icicle_cuda_runtime::error::CudaError; +use icicle_core::tree::{FieldTreeBuilder, TreeBuilderConfig}; use icicle_cuda_runtime::memory::HostOrDeviceSlice; +use std::ffi::c_void; -impl_tree_builder!("bls12_377", bls12_377, ScalarField, ScalarCfg); +use crate::curve::ScalarField; -#[cfg(feature = "bw6-761")] -impl_tree_builder!("bw6_761", bw6_761, BaseField, BaseCfg); +impl_field_tree_builder!("bls12_377", bls12_377_tb, ScalarField, ScalarCfg, Bls12_377TreeBuilder); #[cfg(test)] pub(crate) mod tests { + use icicle_core::{ntt::FieldImpl, poseidon::Poseidon, tree::tests::check_build_field_merkle_tree}; + use icicle_cuda_runtime::device_context; + use crate::curve::ScalarField; - use icicle_core::impl_tree_builder_tests; - use icicle_core::tree::tests::*; - impl_tree_builder_tests!(ScalarField); + use super::Bls12_377TreeBuilder; + + #[test] + fn poseidon_merkle_tree_test() { + let ctx = device_context::DeviceContext::default(); + let sponge = Poseidon::load(2, &ctx).unwrap(); + + check_build_field_merkle_tree::<_, _, Bls12_377TreeBuilder>(25, 2, &sponge, &sponge, ScalarField::zero()); + } } diff --git a/wrappers/rust/icicle-curves/icicle-bls12-381/src/poseidon/mod.rs b/wrappers/rust/icicle-curves/icicle-bls12-381/src/poseidon/mod.rs index 37ce7b2ee..1ec41a41d 100644 --- a/wrappers/rust/icicle-curves/icicle-bls12-381/src/poseidon/mod.rs +++ b/wrappers/rust/icicle-curves/icicle-bls12-381/src/poseidon/mod.rs @@ -1,8 +1,9 @@ use crate::curve::{ScalarCfg, ScalarField}; use icicle_core::error::IcicleResult; +use icicle_core::hash::SpongeConfig; use icicle_core::impl_poseidon; -use icicle_core::poseidon::{Poseidon, PoseidonConfig, PoseidonConstants}; +use icicle_core::poseidon::{PoseidonHandle, PoseidonImpl}; use icicle_core::traits::IcicleResultWrap; use icicle_cuda_runtime::device_context::DeviceContext; use icicle_cuda_runtime::error::CudaError; @@ -15,9 +16,8 @@ impl_poseidon!("bls12_381", bls12_381, ScalarField, ScalarCfg); #[cfg(test)] pub(crate) mod tests { use crate::curve::ScalarField; + use icicle_core::impl_poseidon_tests; use icicle_core::poseidon::tests::*; - use icicle_core::{impl_poseidon_custom_config_test, impl_poseidon_tests}; impl_poseidon_tests!(ScalarField); - impl_poseidon_custom_config_test!(ScalarField, 32, "bls12_381", 55); } diff --git a/wrappers/rust/icicle-curves/icicle-bls12-381/src/tree/mod.rs b/wrappers/rust/icicle-curves/icicle-bls12-381/src/tree/mod.rs index b579c932c..1860c9fb6 100644 --- a/wrappers/rust/icicle-curves/icicle-bls12-381/src/tree/mod.rs +++ b/wrappers/rust/icicle-curves/icicle-bls12-381/src/tree/mod.rs @@ -1,21 +1,29 @@ -use crate::curve::{ScalarCfg, ScalarField}; - use icicle_core::error::IcicleResult; -use icicle_core::impl_tree_builder; -use icicle_core::poseidon::PoseidonConstants; +use icicle_core::hash::SpongeHash; +use icicle_core::impl_field_tree_builder; use icicle_core::traits::IcicleResultWrap; -use icicle_core::tree::{TreeBuilder, TreeBuilderConfig}; -use icicle_cuda_runtime::device_context::DeviceContext; -use icicle_cuda_runtime::error::CudaError; +use icicle_core::tree::{FieldTreeBuilder, TreeBuilderConfig}; use icicle_cuda_runtime::memory::HostOrDeviceSlice; +use std::ffi::c_void; + +use crate::curve::ScalarField; -impl_tree_builder!("bls12_381", bls12_381, ScalarField, ScalarCfg); +impl_field_tree_builder!("bls12_381", bls12_381_tb, ScalarField, ScalarCfg, Bls12_381TreeBuilder); #[cfg(test)] pub(crate) mod tests { + use icicle_core::{ntt::FieldImpl, poseidon::Poseidon, tree::tests::check_build_field_merkle_tree}; + use icicle_cuda_runtime::device_context; + use crate::curve::ScalarField; - use icicle_core::impl_tree_builder_tests; - use icicle_core::tree::tests::*; - impl_tree_builder_tests!(ScalarField); + use super::Bls12_381TreeBuilder; + + #[test] + fn poseidon_merkle_tree_test() { + let ctx = device_context::DeviceContext::default(); + let sponge = Poseidon::load(2, &ctx).unwrap(); + + check_build_field_merkle_tree::<_, _, Bls12_381TreeBuilder>(25, 2, &sponge, &sponge, ScalarField::zero()); + } } diff --git a/wrappers/rust/icicle-curves/icicle-bn254/src/poseidon/mod.rs b/wrappers/rust/icicle-curves/icicle-bn254/src/poseidon/mod.rs index c2d62d154..bf555199c 100644 --- a/wrappers/rust/icicle-curves/icicle-bn254/src/poseidon/mod.rs +++ b/wrappers/rust/icicle-curves/icicle-bn254/src/poseidon/mod.rs @@ -1,8 +1,9 @@ use crate::curve::{ScalarCfg, ScalarField}; use icicle_core::error::IcicleResult; +use icicle_core::hash::SpongeConfig; use icicle_core::impl_poseidon; -use icicle_core::poseidon::{Poseidon, PoseidonConfig, PoseidonConstants}; +use icicle_core::poseidon::{PoseidonHandle, PoseidonImpl}; use icicle_core::traits::IcicleResultWrap; use icicle_cuda_runtime::device_context::DeviceContext; use icicle_cuda_runtime::error::CudaError; @@ -15,9 +16,8 @@ impl_poseidon!("bn254", bn254, ScalarField, ScalarCfg); #[cfg(test)] pub(crate) mod tests { use crate::curve::ScalarField; + use icicle_core::impl_poseidon_tests; use icicle_core::poseidon::tests::*; - use icicle_core::{impl_poseidon_custom_config_test, impl_poseidon_tests}; impl_poseidon_tests!(ScalarField); - impl_poseidon_custom_config_test!(ScalarField, 32, "bn254", 56); } diff --git a/wrappers/rust/icicle-curves/icicle-bn254/src/poseidon2/mod.rs b/wrappers/rust/icicle-curves/icicle-bn254/src/poseidon2/mod.rs index 827a7524e..063de3657 100644 --- a/wrappers/rust/icicle-curves/icicle-bn254/src/poseidon2/mod.rs +++ b/wrappers/rust/icicle-curves/icicle-bn254/src/poseidon2/mod.rs @@ -1,8 +1,9 @@ use crate::curve::{ScalarCfg, ScalarField}; use icicle_core::error::IcicleResult; +use icicle_core::hash::SpongeConfig; use icicle_core::impl_poseidon2; -use icicle_core::poseidon2::{DiffusionStrategy, MdsType, Poseidon2, Poseidon2Config, Poseidon2Constants}; +use icicle_core::poseidon2::{DiffusionStrategy, MdsType, Poseidon2Handle, Poseidon2Impl}; use icicle_core::traits::IcicleResultWrap; use icicle_cuda_runtime::device_context::DeviceContext; use icicle_cuda_runtime::error::CudaError; @@ -29,7 +30,7 @@ pub(crate) mod tests { ScalarField::from_hex("0x1ed25194542b12eef8617361c3ba7c52e660b145994427cc86296242cf766ec8"), ]; - let constants = init_poseidon::(3, MdsType::Default, DiffusionStrategy::Default); - check_poseidon_kats(3, &kats, &constants); + let poseidon = init_poseidon::(3, MdsType::Default, DiffusionStrategy::Default); + check_poseidon_kats(3, &kats, &poseidon); } } diff --git a/wrappers/rust/icicle-curves/icicle-bn254/src/tree/mmcs.rs b/wrappers/rust/icicle-curves/icicle-bn254/src/tree/mmcs.rs new file mode 100644 index 000000000..b6f6e1499 --- /dev/null +++ b/wrappers/rust/icicle-curves/icicle-bn254/src/tree/mmcs.rs @@ -0,0 +1,11 @@ +use icicle_core::error::IcicleResult; +use icicle_core::hash::SpongeHash; +use icicle_core::traits::IcicleResultWrap; +use icicle_core::tree::{mmcs::FieldMmcs, TreeBuilderConfig}; +use icicle_core::{impl_mmcs, Matrix}; +use icicle_cuda_runtime::memory::{HostOrDeviceSlice, HostSlice}; +use std::ffi::c_void; + +use crate::curve::ScalarField; + +impl_mmcs!("bn254", bn254_mmcs, ScalarField, ScalarCfg, Bn254Mmcs); diff --git a/wrappers/rust/icicle-curves/icicle-bn254/src/tree/mod.rs b/wrappers/rust/icicle-curves/icicle-bn254/src/tree/mod.rs index ca8960518..3afb37137 100644 --- a/wrappers/rust/icicle-curves/icicle-bn254/src/tree/mod.rs +++ b/wrappers/rust/icicle-curves/icicle-bn254/src/tree/mod.rs @@ -1,21 +1,44 @@ -use crate::curve::{ScalarCfg, ScalarField}; +pub mod mmcs; use icicle_core::error::IcicleResult; -use icicle_core::impl_tree_builder; -use icicle_core::poseidon::PoseidonConstants; +use icicle_core::hash::SpongeHash; +use icicle_core::impl_field_tree_builder; use icicle_core::traits::IcicleResultWrap; -use icicle_core::tree::{TreeBuilder, TreeBuilderConfig}; -use icicle_cuda_runtime::device_context::DeviceContext; -use icicle_cuda_runtime::error::CudaError; +use icicle_core::tree::{FieldTreeBuilder, TreeBuilderConfig}; use icicle_cuda_runtime::memory::HostOrDeviceSlice; +use std::ffi::c_void; -impl_tree_builder!("bn254", bn254, ScalarField, ScalarCfg); +use crate::curve::ScalarField; + +impl_field_tree_builder!("bn254", bn254_tb, ScalarField, ScalarCfg, Bn254TreeBuilder); #[cfg(test)] pub(crate) mod tests { + use icicle_core::{ + ntt::FieldImpl, + poseidon::Poseidon, + poseidon2::{DiffusionStrategy, MdsType, Poseidon2}, + tree::tests::check_build_field_merkle_tree, + }; + use icicle_cuda_runtime::device_context; + use crate::curve::ScalarField; - use icicle_core::impl_tree_builder_tests; - use icicle_core::tree::tests::*; - impl_tree_builder_tests!(ScalarField); + use super::Bn254TreeBuilder; + + #[test] + fn poseidon_merkle_tree_test() { + let ctx = device_context::DeviceContext::default(); + let sponge = Poseidon::load(2, &ctx).unwrap(); + + check_build_field_merkle_tree::<_, _, Bn254TreeBuilder>(25, 2, &sponge, &sponge, ScalarField::zero()); + } + + #[test] + fn poseidon2_merkle_tree_test() { + let ctx = device_context::DeviceContext::default(); + let sponge = Poseidon2::load(2, 2, MdsType::Default, DiffusionStrategy::Default, &ctx).unwrap(); + + check_build_field_merkle_tree::<_, _, Bn254TreeBuilder>(28, 2, &sponge, &sponge, ScalarField::zero()); + } } diff --git a/wrappers/rust/icicle-curves/icicle-bw6-761/src/lib.rs b/wrappers/rust/icicle-curves/icicle-bw6-761/src/lib.rs index 2bda6aec3..52548ea81 100644 --- a/wrappers/rust/icicle-curves/icicle-bw6-761/src/lib.rs +++ b/wrappers/rust/icicle-curves/icicle-bw6-761/src/lib.rs @@ -2,7 +2,6 @@ pub mod curve; pub mod msm; pub mod ntt; pub mod poseidon; -pub mod tree; pub mod vec_ops; impl icicle_core::SNARKCurve for curve::CurveCfg {} diff --git a/wrappers/rust/icicle-curves/icicle-bw6-761/src/poseidon/mod.rs b/wrappers/rust/icicle-curves/icicle-bw6-761/src/poseidon/mod.rs index 22f6faba8..527c67aeb 100644 --- a/wrappers/rust/icicle-curves/icicle-bw6-761/src/poseidon/mod.rs +++ b/wrappers/rust/icicle-curves/icicle-bw6-761/src/poseidon/mod.rs @@ -1,9 +1,8 @@ #[cfg(test)] pub(crate) mod tests { use crate::curve::ScalarField; + use icicle_core::impl_poseidon_tests; use icicle_core::poseidon::tests::*; - use icicle_core::{impl_poseidon_custom_config_test, impl_poseidon_tests}; impl_poseidon_tests!(ScalarField); - impl_poseidon_custom_config_test!(ScalarField, 48, "bw6-761", 56); } diff --git a/wrappers/rust/icicle-curves/icicle-bw6-761/src/tree/mod.rs b/wrappers/rust/icicle-curves/icicle-bw6-761/src/tree/mod.rs deleted file mode 100644 index e5a82290c..000000000 --- a/wrappers/rust/icicle-curves/icicle-bw6-761/src/tree/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[cfg(test)] -pub(crate) mod tests { - use crate::curve::ScalarField; - use icicle_core::impl_tree_builder_tests; - use icicle_core::tree::tests::*; - - impl_tree_builder_tests!(ScalarField); -} diff --git a/wrappers/rust/icicle-curves/icicle-grumpkin/src/poseidon/mod.rs b/wrappers/rust/icicle-curves/icicle-grumpkin/src/poseidon/mod.rs index acc2ba749..4857be0d1 100644 --- a/wrappers/rust/icicle-curves/icicle-grumpkin/src/poseidon/mod.rs +++ b/wrappers/rust/icicle-curves/icicle-grumpkin/src/poseidon/mod.rs @@ -1,8 +1,9 @@ use crate::curve::{ScalarCfg, ScalarField}; use icicle_core::error::IcicleResult; +use icicle_core::hash::SpongeConfig; use icicle_core::impl_poseidon; -use icicle_core::poseidon::{Poseidon, PoseidonConfig, PoseidonConstants}; +use icicle_core::poseidon::{PoseidonHandle, PoseidonImpl}; use icicle_core::traits::IcicleResultWrap; use icicle_cuda_runtime::device_context::DeviceContext; use icicle_cuda_runtime::error::CudaError; @@ -15,9 +16,8 @@ impl_poseidon!("grumpkin", grumpkin, ScalarField, ScalarCfg); #[cfg(test)] pub(crate) mod tests { use crate::curve::ScalarField; + use icicle_core::impl_poseidon_tests; use icicle_core::poseidon::tests::*; - use icicle_core::{impl_poseidon_custom_config_test, impl_poseidon_tests}; impl_poseidon_tests!(ScalarField); - impl_poseidon_custom_config_test!(ScalarField, 32, "grumpkin", 56); } diff --git a/wrappers/rust/icicle-curves/icicle-grumpkin/src/tree/mod.rs b/wrappers/rust/icicle-curves/icicle-grumpkin/src/tree/mod.rs index 63543afb6..b00718be0 100644 --- a/wrappers/rust/icicle-curves/icicle-grumpkin/src/tree/mod.rs +++ b/wrappers/rust/icicle-curves/icicle-grumpkin/src/tree/mod.rs @@ -1,21 +1,29 @@ -use crate::curve::{ScalarCfg, ScalarField}; - use icicle_core::error::IcicleResult; -use icicle_core::impl_tree_builder; -use icicle_core::poseidon::PoseidonConstants; +use icicle_core::hash::SpongeHash; +use icicle_core::impl_field_tree_builder; use icicle_core::traits::IcicleResultWrap; -use icicle_core::tree::{TreeBuilder, TreeBuilderConfig}; -use icicle_cuda_runtime::device_context::DeviceContext; -use icicle_cuda_runtime::error::CudaError; +use icicle_core::tree::{FieldTreeBuilder, TreeBuilderConfig}; use icicle_cuda_runtime::memory::HostOrDeviceSlice; +use std::ffi::c_void; + +use crate::curve::ScalarField; -impl_tree_builder!("grumpkin", grumpkin, ScalarField, ScalarCfg); +impl_field_tree_builder!("grumpkin", grumpkin_tb, ScalarField, ScalarCfg, GrumpkinTreeBuilder); #[cfg(test)] pub(crate) mod tests { + use icicle_core::{ntt::FieldImpl, poseidon::Poseidon, tree::tests::check_build_field_merkle_tree}; + use icicle_cuda_runtime::device_context; + use crate::curve::ScalarField; - use icicle_core::impl_tree_builder_tests; - use icicle_core::tree::tests::*; - impl_tree_builder_tests!(ScalarField); + use super::GrumpkinTreeBuilder; + + #[test] + fn poseidon_merkle_tree_test() { + let ctx = device_context::DeviceContext::default(); + let sponge = Poseidon::load(2, &ctx).unwrap(); + + check_build_field_merkle_tree::<_, _, GrumpkinTreeBuilder>(25, 2, &sponge, &sponge, ScalarField::zero()); + } } diff --git a/wrappers/rust/icicle-fields/icicle-babybear/Cargo.toml b/wrappers/rust/icicle-fields/icicle-babybear/Cargo.toml index f3535ee21..c3b947b0f 100644 --- a/wrappers/rust/icicle-fields/icicle-babybear/Cargo.toml +++ b/wrappers/rust/icicle-fields/icicle-babybear/Cargo.toml @@ -18,6 +18,7 @@ cmake = "0.1.50" criterion = "0.3" risc0-core = "0.21.0" risc0-zkp = "0.21.0" + p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" } p3-symmetric = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" } p3-mds = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" } @@ -25,6 +26,8 @@ p3-poseidon2 = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfae p3-field = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" } p3-dft = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" } p3-matrix = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" } +p3-merkle-tree = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" } +p3-commit = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" } serial_test = "3.0.0" [features] diff --git a/wrappers/rust/icicle-fields/icicle-babybear/src/lib.rs b/wrappers/rust/icicle-fields/icicle-babybear/src/lib.rs index 646726118..da0c26793 100644 --- a/wrappers/rust/icicle-fields/icicle-babybear/src/lib.rs +++ b/wrappers/rust/icicle-fields/icicle-babybear/src/lib.rs @@ -2,4 +2,5 @@ pub mod field; pub mod ntt; pub mod polynomials; pub mod poseidon2; +pub mod tree; pub mod vec_ops; diff --git a/wrappers/rust/icicle-fields/icicle-babybear/src/poseidon2/mod.rs b/wrappers/rust/icicle-fields/icicle-babybear/src/poseidon2/mod.rs index bf4a06fd6..c6159cb8d 100644 --- a/wrappers/rust/icicle-fields/icicle-babybear/src/poseidon2/mod.rs +++ b/wrappers/rust/icicle-fields/icicle-babybear/src/poseidon2/mod.rs @@ -1,8 +1,9 @@ use crate::field::{ScalarCfg, ScalarField}; use icicle_core::error::IcicleResult; +use icicle_core::hash::SpongeConfig; use icicle_core::impl_poseidon2; -use icicle_core::poseidon2::{DiffusionStrategy, MdsType, Poseidon2, Poseidon2Config, Poseidon2Constants}; +use icicle_core::poseidon2::{DiffusionStrategy, MdsType, Poseidon2Handle, Poseidon2Impl}; use icicle_core::traits::IcicleResultWrap; use icicle_cuda_runtime::device_context::DeviceContext; use icicle_cuda_runtime::error::CudaError; @@ -16,14 +17,14 @@ impl_poseidon2!("babybear", babybear, ScalarField, ScalarCfg); pub(crate) mod tests { use crate::field::ScalarField; use icicle_core::impl_poseidon2_tests; - use icicle_core::poseidon2::{create_poseidon2_constants, tests::*, DiffusionStrategy, MdsType}; + use icicle_core::poseidon2::{tests::*, DiffusionStrategy, MdsType, Poseidon2}; use icicle_core::traits::FieldImpl; use icicle_cuda_runtime::device_context::DeviceContext; use p3_baby_bear::BabyBear; use p3_baby_bear::DiffusionMatrixBabyBear; use p3_field::{AbstractField, PrimeField32}; - use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral}; + use p3_poseidon2::{Poseidon2 as PlonkyPoseidon2, Poseidon2ExternalMatrixGeneral}; use p3_symmetric::Permutation; impl_poseidon2_tests!(ScalarField); @@ -57,12 +58,13 @@ pub(crate) mod tests { ScalarField::from_hex("0x57a99864"), ]; - let constants = init_poseidon::(24, MdsType::Default, DiffusionStrategy::Default); - check_poseidon_kats(24, &kats, &constants); + let poseidon = init_poseidon::(24, MdsType::Default, DiffusionStrategy::Default); + check_poseidon_kats(24, &kats, &poseidon); } - #[test] - fn test_poseidon2_plonky3_t16() { + type PlonkyPoseidon2T16 = PlonkyPoseidon2; + + pub(crate) fn get_plonky3_poseidon2_t16(rate: usize) -> (Poseidon2, PlonkyPoseidon2T16) { let rounds_p = 13; let rounds_f = 8; const ALPHA: u64 = 7; @@ -232,27 +234,20 @@ pub(crate) mod tests { cnv(605745517), ]; - let poseidon2: Poseidon2 = - Poseidon2::new( - rounds_f, - external_constants.clone(), - Poseidon2ExternalMatrixGeneral::default(), - rounds_p, - internal_constants.clone(), - DiffusionMatrixBabyBear::default(), - ); - - let mut input: [BabyBear; WIDTH] = [BabyBear::zero(); WIDTH]; - for i in 0..WIDTH { - input[i] = BabyBear::from_canonical_u32(i as u32); - } - - let output = poseidon2.permute(input); - - let mut kats: [ScalarField; WIDTH] = [ScalarField::zero(); WIDTH]; - for i in 0..WIDTH { - kats[i] = ScalarField::from_u32(output[i].as_canonical_u32()); - } + let plonky_poseidon2: PlonkyPoseidon2< + BabyBear, + Poseidon2ExternalMatrixGeneral, + DiffusionMatrixBabyBear, + WIDTH, + ALPHA, + > = PlonkyPoseidon2::new( + rounds_f, + external_constants.clone(), + Poseidon2ExternalMatrixGeneral::default(), + rounds_p, + internal_constants.clone(), + DiffusionMatrixBabyBear::default(), + ); let ctx = DeviceContext::default(); let mut round_constants = vec![ScalarField::zero(); rounds_f * WIDTH + rounds_p]; @@ -291,19 +286,43 @@ pub(crate) mod tests { ScalarField::from_u32(1 << 13), ScalarField::from_u32(1 << 15), ]; - let constants = create_poseidon2_constants( - WIDTH as u32, + + let poseidon = Poseidon2::new( + WIDTH, + rate, ALPHA as u32, - &ctx, rounds_p as u32, rounds_f as u32, &mut round_constants, &mut internal_matrix_diag, MdsType::Plonky, DiffusionStrategy::Montgomery, + &ctx, ) .unwrap(); - check_poseidon_kats(WIDTH, &kats, &constants); + + (poseidon, plonky_poseidon2) + } + + #[test] + fn test_poseidon2_plonky3_t16() { + const WIDTH: usize = 16; + + let (poseidon, plonky_poseidon2) = get_plonky3_poseidon2_t16(16); + + let mut input: [BabyBear; WIDTH] = [BabyBear::zero(); WIDTH]; + for i in 0..WIDTH { + input[i] = BabyBear::from_canonical_u32(i as u32); + } + + let output = plonky_poseidon2.permute(input); + + let mut kats: [ScalarField; WIDTH] = [ScalarField::zero(); WIDTH]; + for i in 0..WIDTH { + kats[i] = ScalarField::from_u32(output[i].as_canonical_u32()); + } + + check_poseidon_kats(WIDTH, &kats, &poseidon); } #[test] @@ -549,22 +568,27 @@ pub(crate) mod tests { cnv(1810596765), ]; - let poseidon2: Poseidon2 = - Poseidon2::new( - rounds_f, - external_constants.clone(), - Poseidon2ExternalMatrixGeneral::default(), - rounds_p, - internal_constants.clone(), - DiffusionMatrixBabyBear::default(), - ); + let plonky_poseidon2: PlonkyPoseidon2< + BabyBear, + Poseidon2ExternalMatrixGeneral, + DiffusionMatrixBabyBear, + WIDTH, + ALPHA, + > = PlonkyPoseidon2::new( + rounds_f, + external_constants.clone(), + Poseidon2ExternalMatrixGeneral::default(), + rounds_p, + internal_constants.clone(), + DiffusionMatrixBabyBear::default(), + ); let mut input: [BabyBear; WIDTH] = [BabyBear::zero(); WIDTH]; for i in 0..WIDTH { input[i] = BabyBear::from_canonical_u32(i as u32); } - let output = poseidon2.permute(input); + let output = plonky_poseidon2.permute(input); let mut kats: [ScalarField; WIDTH] = [ScalarField::zero(); WIDTH]; for i in 0..WIDTH { @@ -616,18 +640,19 @@ pub(crate) mod tests { ScalarField::from_u32(1 << 22), ScalarField::from_u32(1 << 23), ]; - let constants = create_poseidon2_constants( - WIDTH as u32, + let poseidon = Poseidon2::new( + WIDTH, + 24, ALPHA as u32, - &ctx, rounds_p as u32, rounds_f as u32, &mut round_constants, &mut internal_matrix_diag, MdsType::Plonky, DiffusionStrategy::Montgomery, + &ctx, ) .unwrap(); - check_poseidon_kats(WIDTH, &kats, &constants); + check_poseidon_kats(WIDTH, &kats, &poseidon); } } diff --git a/wrappers/rust/icicle-fields/icicle-babybear/src/tree/mmcs.rs b/wrappers/rust/icicle-fields/icicle-babybear/src/tree/mmcs.rs new file mode 100644 index 000000000..b5c3a07f1 --- /dev/null +++ b/wrappers/rust/icicle-fields/icicle-babybear/src/tree/mmcs.rs @@ -0,0 +1,125 @@ +use icicle_core::error::IcicleResult; +use icicle_core::hash::SpongeHash; +use icicle_core::traits::IcicleResultWrap; +use icicle_core::tree::{mmcs::FieldMmcs, TreeBuilderConfig}; +use icicle_core::{impl_mmcs, Matrix}; +use icicle_cuda_runtime::memory::{HostOrDeviceSlice, HostSlice}; +use std::ffi::c_void; + +use crate::field::ScalarField; + +impl_mmcs!("babybear", babybear_mmcs, ScalarField, ScalarCfg, BabyBearMmcs); + +#[cfg(test)] +pub(crate) mod tests { + use std::ffi::c_void; + + use icicle_core::{ + ntt::FieldImpl, + tree::{merkle_tree_digests_len, TreeBuilderConfig}, + Matrix, + }; + use icicle_cuda_runtime::memory::HostSlice; + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; + use p3_commit::Mmcs; + use p3_field::{AbstractField, Field}; + use p3_matrix::dense::RowMajorMatrix; + use p3_merkle_tree::FieldMerkleTreeMmcs; + use p3_poseidon2::{Poseidon2 as PlonkyPoseidon2, Poseidon2ExternalMatrixGeneral}; + use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation}; + + use crate::{ + field::ScalarField, + poseidon2::tests::get_plonky3_poseidon2_t16, + tree::mmcs::{BabyBearMmcs, FieldMmcs}, + }; + + type PlonkyPoseidon2T16 = PlonkyPoseidon2; + + #[test] + fn test_poseidon2_mmcs_plonky3() { + const WIDTH: usize = 16; + const RATE: usize = 8; + const ARITY: usize = 2; + const HEIGHT: usize = 15; + const ROWS: usize = 1 << HEIGHT; + const COLS: usize = 32; + const DIGEST_ELEMENTS: usize = 8; + + let (poseidon, plonky_poseidon2) = get_plonky3_poseidon2_t16(RATE); + + type H = PaddingFreeSponge; + let h = H::new(plonky_poseidon2.clone()); + + type C = TruncatedPermutation; + let c = C::new(plonky_poseidon2.clone()); + + type F = BabyBear; + + let mut input = vec![F::zero(); ROWS * COLS]; + let mut icicle_input = vec![ScalarField::zero(); ROWS * COLS]; + for i in 0..ROWS * COLS { + input[i] = F::from_canonical_u32(i as u32); + icicle_input[i] = ScalarField::from_u32(i as u32); + } + + let mut input2 = vec![F::zero(); (ROWS / 2) * COLS]; + let mut icicle_input2 = vec![ScalarField::zero(); (ROWS / 2) * COLS]; + for i in 0..(ROWS / 2) * COLS { + input2[i] = F::from_canonical_u32(i as u32); + icicle_input2[i] = ScalarField::from_u32(i as u32); + } + + let matrix = RowMajorMatrix::new(input.clone(), COLS); + let matrix2 = RowMajorMatrix::new(input2.clone(), COLS); + let leaves = vec![matrix, matrix2]; + // let leaves = vec![matrix]; + + let mmcs = + FieldMerkleTreeMmcs::<::Packing, ::Packing, H, C, DIGEST_ELEMENTS>::new(h, c); + + let (commit, _data) = mmcs.commit(leaves); + + let mut config = TreeBuilderConfig::default(); + config.arity = ARITY as u32; + config.keep_rows = HEIGHT as u32 + 1; + config.digest_elements = DIGEST_ELEMENTS as u32; + let digests_len = merkle_tree_digests_len(HEIGHT as u32, ARITY as u32, DIGEST_ELEMENTS as u32); + let mut digests = vec![ScalarField::zero(); digests_len]; + // let mut digests = vec![ScalarField::zero(); COLS]; + + let leaves_slice = vec![ + Matrix { + values: icicle_input.as_ptr() as *const c_void, + width: COLS, + height: ROWS, + }, + Matrix { + values: icicle_input2.as_ptr() as *const c_void, + width: COLS, + height: ROWS / 2, + }, + ]; + let digests_slice = HostSlice::from_mut_slice(&mut digests); + + BabyBearMmcs::mmcs_commit(leaves_slice, digests_slice, &poseidon, &poseidon, &config).unwrap(); + + let mut converted = vec![BabyBear::zero(); digests_len]; + for i in 0..digests_len { + let mut scalar_bytes = [0u8; 4]; + scalar_bytes.copy_from_slice(&digests_slice[i].to_bytes_le()); + converted[i] = BabyBear::from_canonical_u32(u32::from_le_bytes(scalar_bytes)); + } + + // println!("Plonky: {:?}", _data); + // println!("Icicle: {:?}", converted); + // assert_eq!(commit, converted); + + let commit_vec: Vec = commit + .into_iter() + .collect(); + for i in 0..DIGEST_ELEMENTS { + assert_eq!(converted[converted.len() - DIGEST_ELEMENTS + i], commit_vec[i]); + } + } +} diff --git a/wrappers/rust/icicle-fields/icicle-babybear/src/tree/mod.rs b/wrappers/rust/icicle-fields/icicle-babybear/src/tree/mod.rs new file mode 100644 index 000000000..070ba9cd1 --- /dev/null +++ b/wrappers/rust/icicle-fields/icicle-babybear/src/tree/mod.rs @@ -0,0 +1,107 @@ +use icicle_core::error::IcicleResult; +use icicle_core::hash::SpongeHash; +use icicle_core::impl_field_tree_builder; +use icicle_core::traits::IcicleResultWrap; +use icicle_core::tree::{FieldTreeBuilder, TreeBuilderConfig}; +use icicle_cuda_runtime::memory::HostOrDeviceSlice; +use std::ffi::c_void; + +use crate::field::ScalarField; + +pub mod mmcs; + +impl_field_tree_builder!("babybear", babybear_tb, ScalarField, ScalarCfg, BabyBearTreeBuilder); + +#[cfg(test)] +pub(crate) mod tests { + use icicle_core::{ + ntt::FieldImpl, + poseidon2::{DiffusionStrategy, MdsType, Poseidon2}, + tree::{tests::check_build_field_merkle_tree, FieldTreeBuilder, TreeBuilderConfig}, + }; + use icicle_cuda_runtime::device_context; + use icicle_cuda_runtime::memory::HostSlice; + use p3_baby_bear::{BabyBear, DiffusionMatrixBabyBear}; + use p3_commit::Mmcs; + use p3_field::{AbstractField, Field}; + use p3_matrix::dense::RowMajorMatrix; + use p3_merkle_tree::FieldMerkleTreeMmcs; + use p3_poseidon2::{Poseidon2 as PlonkyPoseidon2, Poseidon2ExternalMatrixGeneral}; + use p3_symmetric::{PaddingFreeSponge, TruncatedPermutation}; + + use crate::{field::ScalarField, poseidon2::tests::get_plonky3_poseidon2_t16, tree::BabyBearTreeBuilder}; + + #[test] + fn poseidon2_merkle_tree_test() { + let ctx = device_context::DeviceContext::default(); + let sponge = Poseidon2::load(2, 2, MdsType::Default, DiffusionStrategy::Default, &ctx).unwrap(); + + check_build_field_merkle_tree::<_, _, BabyBearTreeBuilder>(25, 2, &sponge, &sponge, ScalarField::zero()); + } + + type PlonkyPoseidon2T16 = PlonkyPoseidon2; + + #[test] + fn test_poseidon2_tree_plonky3() { + const WIDTH: usize = 16; + const ARITY: usize = 2; + const HEIGHT: usize = 15; + const ROWS: usize = 1 << HEIGHT; + const COLS: usize = 8; + + let (poseidon, plonky_poseidon2) = get_plonky3_poseidon2_t16(8); + + type H = PaddingFreeSponge; + let h = H::new(plonky_poseidon2.clone()); + + type C = TruncatedPermutation; + let c = C::new(plonky_poseidon2.clone()); + + type F = BabyBear; + + let mut input = vec![F::zero(); ROWS * COLS]; + let mut icicle_input = vec![ScalarField::zero(); ROWS * COLS]; + for i in 0..ROWS * COLS { + input[i] = F::from_canonical_u32(i as u32); + icicle_input[i] = ScalarField::from_u32(i as u32); + } + + let matrix = RowMajorMatrix::new(input, COLS); + let leaves = vec![matrix]; + + let mmcs = FieldMerkleTreeMmcs::<::Packing, ::Packing, H, C, 8>::new(h, c); + + let (commit, _data) = mmcs.commit(leaves); + + let mut config = TreeBuilderConfig::default(); + config.arity = ARITY as u32; + config.keep_rows = 1; + config.digest_elements = COLS as u32; + let input_block_len = COLS; + // let digests_len = merkle_tree_digests_len(2 as u32, ARITY as u32, COLS as u32); + // let mut digests = vec![ScalarField::zero(); digests_len]; + let mut digests = vec![ScalarField::zero(); COLS]; + + let leaves_slice = HostSlice::from_slice(&icicle_input); + let digests_slice = HostSlice::from_mut_slice(&mut digests); + + BabyBearTreeBuilder::build_merkle_tree( + leaves_slice, + digests_slice, + HEIGHT, + input_block_len, + &poseidon, + &poseidon, + &config, + ) + .unwrap(); + + let mut converted: [BabyBear; COLS] = [BabyBear::zero(); COLS]; + for i in 0..COLS { + let mut scalar_bytes = [0u8; 4]; + scalar_bytes.copy_from_slice(&digests_slice[i].to_bytes_le()); + converted[i] = BabyBear::from_canonical_u32(u32::from_le_bytes(scalar_bytes)); + } + assert_eq!(commit, converted); + } +}