From 9c54764973c46ae821fb0a38aa2cdf9b4fbc9746 Mon Sep 17 00:00:00 2001 From: danny-shterman Date: Wed, 15 Jan 2025 17:55:19 +0200 Subject: [PATCH 1/8] WIP. Works for CPU on macbook --- icicle/backend/cpu/src/hash/cpu_poseidon2.cpp | 233 +++++++++++++----- icicle/tests/test_hash_api.cpp | 168 ++++++++++--- 2 files changed, 310 insertions(+), 91 deletions(-) diff --git a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp index df1c519cd..270781a6b 100644 --- a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp +++ b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp @@ -147,7 +147,7 @@ namespace icicle { ICICLE_LOG_ERROR << "cpu_poseidon2_init_default_constants: T (width) must be one of [2, 3, 4, 8, 12, 16, 20, 24]\n"; return eIcicleError::INVALID_ARGUMENT; - } // switch (T) { + } // switch (T) { if (full_rounds == 0 && partial_rounds == 0) { // All arrays are empty in this case. continue; } @@ -196,48 +196,33 @@ namespace icicle { // For merkle tree size should be equal to the arity of a single hasher multiplier by sizeof(S). // For sponge function it could be any number. + // Size parameter here is in bytes. eIcicleError hash(const std::byte* input, uint64_t size, const HashConfig& config, std::byte* output) const override { - unsigned int arity = m_use_domain_tag ? m_t - 1 : m_t; - - // Currently sponge and padding functionalities are not supported. - if (size != arity * sizeof(S)) { + const unsigned arity = m_use_domain_tag ? m_t - 1 : m_t; + bool is_sponge = false; + int size_in_scalars = size / sizeof(S); + if (size_in_scalars > (m_use_domain_tag ? m_t - 1 : m_t)) { // Sponge function. Check input size granularity. + is_sponge = true; + // Capacity width (in scalars) = 1. + // Output width (in scalars) = 1. + if ((m_use_domain_tag ? size_in_scalars : size_in_scalars - 1) % (m_t - 1) != 0) { + ICICLE_LOG_ERROR + << "Padding isn't supported for sponge function hash. The following should be true: ((m_use_domain_tag ? size : size-1) % (m_t-1) != 0).\n"; + return eIcicleError::INVALID_ARGUMENT; + } + if (config.batch != 1) { + ICICLE_LOG_ERROR + << "The only suppoorted value of config.batch is 1.\n"; + return eIcicleError::INVALID_ARGUMENT; + } + } + else if (size_in_scalars < (m_use_domain_tag ? m_t - 1 : m_t)) { ICICLE_LOG_ERROR - << "Sponge function still isn't supported. The following should be true: (size == T) but it is not.\n"; + << "Padding isn't supported for sponge function hash. The following should be true: ((use_domain_tag ? size + 1 : size) % T = 0).\n"; return eIcicleError::INVALID_ARGUMENT; } - // Call hash_single config.batch times. - for (int batch_hash_idx = 0; batch_hash_idx < config.batch; batch_hash_idx++) { - eIcicleError err = hash_single(input, output); - if (err != eIcicleError::SUCCESS) return err; - input += arity * sizeof(S); - output += sizeof(S); - } - return eIcicleError::SUCCESS; - } - - private: - // // DEBUG start. Do not remove!!! - // void print_state(std::string str, S* state_to_print) const { - // std::cout << str << std::endl; - // unsigned int T = m_t; - // for (int state_idx = 0; state_idx < T; state_idx++) { // Columns of matrix. - // std::cout << std::hex << state_to_print[state_idx] << std::endl; - // } - // } - // void print_matrix(std::string str, S* matrix_to_print) const { - // std::cout << str << std::endl; - // unsigned int T = m_t; - // for (int matrix_idx = 0; matrix_idx < T*T; matrix_idx++) { // Columns of matrix. - // std::cout << std::hex << matrix_to_print[matrix_idx] << std::endl; - // } - // } - // // DEBUG end - - // This function performs a single hash according to parameters in the poseidon2_constants[] struct. - eIcicleError hash_single(const std::byte* input, std::byte* output) const - { const unsigned int T = m_t; bool is_unsupported_T_for_this_field = poseidon2_constants[T].nof_upper_full_rounds == 0; if (is_unsupported_T_for_this_field) { @@ -245,35 +230,164 @@ namespace icicle { return eIcicleError::API_NOT_IMPLEMENTED; } - unsigned int alpha = poseidon2_constants[T].alpha; - unsigned int nof_upper_full_rounds = poseidon2_constants[T].nof_upper_full_rounds; - unsigned int nof_partial_rounds = poseidon2_constants[T].nof_partial_rounds; - unsigned int nof_bottom_full_rounds = poseidon2_constants[T].nof_bottom_full_rounds; - // S* rounds_constants = poseidon2_constants[T].rounds_constants; + int alpha = poseidon2_constants[T].alpha; + int nof_upper_full_rounds = poseidon2_constants[T].nof_upper_full_rounds; + int nof_partial_rounds = poseidon2_constants[T].nof_partial_rounds; + int nof_bottom_full_rounds = poseidon2_constants[T].nof_bottom_full_rounds; S* rounds_constants = poseidon2_constants[T].rounds_constants; S* mds_matrix = poseidon2_constants[T].mds_matrix; - // S* partial_matrix_diagonal = poseidon2_constants[T].partial_matrix_diagonal; S* partial_matrix_diagonal_m1 = poseidon2_constants[T].partial_matrix_diagonal_m1; - // Allocate temporary memory for intermediate calcs. - S* tmp_fields = new S[T]; - // Casting from bytes to scalar. + + // Allocate temporary memory for intermediate calcs and in order not to change the input. + int sponge_nof_hashers = m_use_domain_tag ? (size_in_scalars / arity) : ((size_in_scalars - 1) / (arity - 1)); + int tmp_fields_nof_scalars = is_sponge ? (T * sponge_nof_hashers) : (T * config.batch); + // std::cout << "tmp_fields_nof_scalars = " << tmp_fields_nof_scalars << std::endl; + S* tmp_fields = new S[tmp_fields_nof_scalars]; + std::cout << "tmp_fields (new) = " << tmp_fields << std::endl; const S* in_fields = (S*)(input); - // Copy input scalar to the output (as a temp storage) to be used in the rounds. - // *tmp_fields are used as a temp storage during the calculations in this function. - if (m_use_domain_tag) { - // in that case we hash [domain_tag, t-1 field elements] - memcpy(tmp_fields, &m_domain_tag, sizeof(S)); - memcpy(tmp_fields + 1, in_fields, (T - 1) * sizeof(S)); - } else { - // in that case we hash [t field elements] - memcpy(tmp_fields, in_fields, T * sizeof(S)); + if (m_use_domain_tag) { + if (is_sponge) { + // std::cout << "is_sponge sponge_nof_hashers = " << sponge_nof_hashers << std::endl; + // Domain tag exists only for the first hasher. For the rest of the hashers this + // input is undefined at this stage and its value will be set later. + // tmp_fields = {{dt, in0}, {undef, in1}, {undef, in2}, etc.} + memcpy(tmp_fields, &m_domain_tag, sizeof(S)); + for (int hasher_idx = 0; hasher_idx < sponge_nof_hashers; hasher_idx++) { + memcpy(tmp_fields + 1, in_fields, (T - 1) * sizeof(S)); + in_fields += (T - 1); + tmp_fields += T; + } + tmp_fields -= T * sponge_nof_hashers; + } + else { // Not a sponge function. Input of each hash should have domain tag at its input. + // tmp_fields = {{dt, in0}, {dt, in1}, {dt, in2}, etc.} + for (int batch_idx = 0; batch_idx < config.batch; batch_idx++) { + memcpy(tmp_fields, &m_domain_tag, sizeof(S)); + memcpy(tmp_fields + 1, in_fields, (T - 1) * sizeof(S)); + in_fields += (T - 1); + tmp_fields += T; + } + tmp_fields -= T * config.batch; + } + } + else { // There is no domain tag. + if (is_sponge) { + // tmp_fields = {{in0 (T inputs)}, {undef, in1}, {under, in2}, etc.} + // std::cout << "is_sponge sponge_nof_hashers = " << sponge_nof_hashers << std::endl; + memcpy(tmp_fields, in_fields, T * sizeof(S)); // 1st hasher uses T inputs. + // print_state("tmp_fields 1st hasher external input: ", tmp_fields); + in_fields += T; + tmp_fields += T; + // Rest of the hashers use T-1 inputs and 1 output from the previous hasher. + // The value of the 1st input of each of these hashers is undef at this stage. + for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { + memcpy(&tmp_fields[1], in_fields, (T - 1) * sizeof(S)); + // print_state("tmp_fields 2nd hasher external input (1st scalar doesnt matter): ", tmp_fields); + in_fields += (T - 1); + tmp_fields += T; + } + tmp_fields -= T * sponge_nof_hashers; + } + else { + // tmp_fields = {{in0 (T inputs)}, {in1 (T inputs)}, {in2 (T inputs)}, etc.} + memcpy(tmp_fields, in_fields, T * config.batch * sizeof(S)); + } } - // Pre-rounds full maatrix multiplication. + // std::cout << "tmp_fields (start processing) = " << tmp_fields << std::endl; + if (is_sponge) { + S* tmp_fields_tmp_ptr; // This pointer is used to assist in addition of the hasher outputs + // with new inputs. + // Call hash_single for hasher[0] + // print_state("tmp_fields input to the first hasher: ", tmp_fields); + eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, + alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, + rounds_constants, mds_matrix, partial_matrix_diagonal_m1); + // print_state("tmp_fields output of the first hasher: ", tmp_fields); + tmp_fields[T] = tmp_fields[0]; // Current first output is an input to the next hasher. + tmp_fields_tmp_ptr = tmp_fields; // Save current pointer. + tmp_fields += T; + for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { + // std::cout << "hasher_idx = " << hasher_idx << std::endl; + // print_state("tmp_fields taken from external input (1st scalar doesnt matter): ", tmp_fields); + // print_state("tmp_fields taken from prev hasher: ", tmp_fields_tmp_ptr); + // The first output of the prev hasher is the first input of the current hasher. + // The T-1 new inputs of the current hasher should be added to the T-1 outputs of the + // prev hasher (starting fom index 1). + for (int i = 1; i < T; i++) { + tmp_fields[i] = tmp_fields_tmp_ptr[i] + tmp_fields[i]; + } + // print_state("tmp_fields after addition: ", tmp_fields); + tmp_fields_tmp_ptr = tmp_fields; // Save current pointer. + eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, + alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, + rounds_constants, mds_matrix, partial_matrix_diagonal_m1); + // print_state("tmp_fields output of the non-first hasher: ", tmp_fields); + if (err != eIcicleError::SUCCESS) return err; + if (hasher_idx != sponge_nof_hashers - 1) // Not to do in the last loop to prevent mem leak. + tmp_fields[T] = tmp_fields[0]; // Current first output is an input to the next hasher. + tmp_fields += T; // Proceed to the next hash. + } + tmp_fields -= T; // Rollback to the last hasher output. + memcpy(output, (std::byte*)(&tmp_fields[1]), sizeof(S)); + tmp_fields -= T * (sponge_nof_hashers - 1); + } + else { // Not a sponge function. + for (int batch_hash_idx = 0; batch_hash_idx < config.batch; batch_hash_idx++) { + // print_state("tmp_fields before hash_single: ", tmp_fields); + eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, + alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, + rounds_constants, mds_matrix, partial_matrix_diagonal_m1); + // print_state("tmp_fields after hash_single: ", tmp_fields); + if (err != eIcicleError::SUCCESS) return err; + memcpy(output, (std::byte*)(&tmp_fields[1]), sizeof(S)); + tmp_fields += T; + output += sizeof(S); + } + tmp_fields -= T * config.batch; + } + + // std::cout << "tmp_fields (delete) = " << tmp_fields<< std::endl; + delete[] tmp_fields; + tmp_fields = nullptr; + + return eIcicleError::SUCCESS; + } + + private: + // DEBUG start. Do not remove!!! + void print_state(std::string str, S* state_to_print) const { + std::cout << str << std::endl; + unsigned int T = m_t; + for (int state_idx = 0; state_idx < T; state_idx++) { // Columns of matrix. + std::cout << std::hex << state_to_print[state_idx] << std::endl; + } + } + void print_matrix(std::string str, S* matrix_to_print) const { + std::cout << str << std::endl; + unsigned int T = m_t; + for (int matrix_idx = 0; matrix_idx < T*T; matrix_idx++) { // Columns of matrix. + std::cout << std::hex << matrix_to_print[matrix_idx] << std::endl; + } + } + // DEBUG end + + // This function performs a single hash according to parameters in the poseidon2_constants[] struct. + // eIcicleError hash_single(const std::byte* input, std::byte* output) const + eIcicleError hash_single(S* tmp_fields, S* hasher_output, int alpha, int nof_upper_full_rounds, + int nof_partial_rounds, int nof_bottom_full_rounds, + S* rounds_constants, S* mds_matrix, S* partial_matrix_diagonal_m1) const + { + const unsigned int T = m_t; + + // Pre-rounds full matrix multiplication. full_matrix_mul_by_vector(tmp_fields, mds_matrix, tmp_fields); + // print_matrix("mds_matrix: ", mds_matrix); + // print_state("Pre-rounds mds matrix multiplication: ", tmp_fields); // Upper full rounds. full_rounds(nof_upper_full_rounds, tmp_fields, rounds_constants); + // print_state("Upper full rounds: ", tmp_fields); // Partial rounds. Perform calculation only for the first element of *tmp_fields. for (int partial_rounds_idx = 0; partial_rounds_idx < nof_partial_rounds; partial_rounds_idx++) { @@ -288,10 +402,11 @@ namespace icicle { // Bottom full rounds. full_rounds(nof_bottom_full_rounds, tmp_fields, rounds_constants); - memcpy(output, (std::byte*)(&tmp_fields[1]), sizeof(S)); + memcpy(hasher_output, (std::byte*)(tmp_fields), T * sizeof(S)); + // memcpy(output, (std::byte*)(&tmp_fields[1]), sizeof(S)); - delete[] tmp_fields; - tmp_fields = nullptr; + // delete[] tmp_fields; + // tmp_fields = nullptr; return eIcicleError::SUCCESS; } // eIcicleError hash_single(const std::byte* input, std::byte* output) const diff --git a/icicle/tests/test_hash_api.cpp b/icicle/tests/test_hash_api.cpp index 860e42e35..c537ea581 100644 --- a/icicle/tests/test_hash_api.cpp +++ b/icicle/tests/test_hash_api.cpp @@ -8,6 +8,7 @@ #include "icicle/hash/keccak.h" #include "icicle/hash/blake2s.h" #include "icicle/hash/blake3.h" +#include "icicle/hash/poseidon2.h" #include "icicle/merkle/merkle_tree.h" #include "icicle/fields/field.h" @@ -1149,49 +1150,152 @@ TEST_F(HashApiTest, poseidon_tree) #endif // POSEIDON #ifdef POSEIDON2 -// p = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +// DEBUG. This test could run only with bn254 curve. Dont remove!!! +// bn254: p = 0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570 +#include "icicle/fields/field_config.h" +using namespace field_config; +#if FIELD_ID == BN254 +TEST_F(HashApiTest, poseidon2_3_single_hash_cpu_only) +{ + const unsigned t = 3; + auto config = default_hash_config(); + config.batch = 1 << 10; - #include "icicle/fields/field_config.h" + auto input = std::make_unique(config.batch * t); + // scalar_t::rand_host_many(input.get(), t); + // DEBUG - sets known inputs. Do not remove!!! + for (int i=0; i(t); -// auto input = std::make_unique(t); -// scalar_t::rand_host_many(input.get(), t); + START_TIMER(POSEIDON2_sync) + for (int i = 0; i < iters; ++i) { + ICICLE_CHECK(poseidon2.hash(input.get(), t, config, out)); + } + END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); + }; -// auto run = [&](const std::string& dev_type, scalar_t* out, bool measure, const char* msg, int iters) { -// Device dev = {dev_type, 0}; -// icicle_set_device(dev); + auto output_cpu = std::make_unique(config.batch); -// std::ostringstream oss; -// oss << dev_type << " " << msg; + run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + scalar_t expected_res = + scalar_t::hex_str2scalar("0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570"); + std::cout << "End of test\n" << std::endl; + std::cout << "*(output_cpu.get()) = " << std::hex << *(output_cpu.get()) << std::endl; + std::cout << "expected_res = " << std::hex << expected_res << std::endl; + ASSERT_EQ(expected_res, *(output_cpu.get())); +} // poseidon2_3_single_hash_cpu_only +// Test for CPU only. +// Test to check correctness of the second hasher of the poseidon2_3_sponge_hash_2_without_dt_cpu_only test. +TEST_F(HashApiTest, poseidon2_3_sponge_2nd_hasher_without_dt_cpu_only) +{ + const unsigned t = 3; + auto config = default_hash_config(); + config.batch = 1; -// auto poseidon2 = Poseidon2::create(t); + auto input = std::make_unique(t); + // scalar_t::rand_host_many(input.get(), t); + // DEBUG - sets known inputs. Do not remove!!! + input[0] = scalar_t::hex_str2scalar("0x0bb61d24daca55eebcb1929a82650f328134334da98ea4f847f760054f4a3033"); + input[1] = scalar_t::hex_str2scalar("0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03571"); + input[2] = scalar_t::hex_str2scalar("0x1ed25194542b12eef8617361c3ba7c52e660b145994427cc86296242cf766eca"); + // for (int i=1; i(config.batch); + std::ostringstream oss; + oss << dev_type << " " << msg; -// run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); -// scalar_t expected_res = -// scalar_t::hex_str2scalar("0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570"); std::cout << "End -// of test\n" << std::endl; ASSERT_EQ(expected_res, *(output_cpu.get())); -// } -// // DEBUG + auto poseidon2 = Poseidon2::create(t); + + START_TIMER(POSEIDON2_sync) + for (int i = 0; i < iters; ++i) { + ICICLE_CHECK(poseidon2.hash(input.get(), t, config, out)); + } + END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); + }; + + auto output_cpu = std::make_unique(config.batch); + + run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + scalar_t expected_res = + scalar_t::hex_str2scalar("0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570"); + std::cout << "End of test\n" << std::endl; + std::cout << "*(output_cpu.get()) = " << std::hex << *(output_cpu.get()) << std::endl; + std::cout << "expected_res = " << std::hex << expected_res << std::endl; + // ASSERT_EQ(expected_res, *(output_cpu.get())); // No need to compere. +} // poseidon2_3_sponge_2nd_hasher_without_dt_cpu_only +TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt_cpu_only) +{ + const unsigned t = 3; + auto config = default_hash_config(); + int nof_hashers = 2; + + auto input = std::make_unique(nof_hashers * t); + // scalar_t::rand_host_many(input.get(), t); + // DEBUG - sets known inputs. Do not remove!!! + for (int i=0; i(t); + + START_TIMER(POSEIDON2_sync) + for (int i = 0; i < iters; ++i) { + ICICLE_CHECK(poseidon2.hash(input.get(), t + (nof_hashers-1) * (t-1), config, out)); + } + END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); + }; + + auto output_cpu = std::make_unique(config.batch); + + run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + scalar_t expected_res = + scalar_t::hex_str2scalar("0x0d54b4b71781dc4f30afe3a90f76559379f6f75aea6968d4c986512e2711ad20"); + std::cout << "End of test\n" << std::endl; + std::cout << "*(output_cpu.get()) = " << std::hex << *(output_cpu.get()) << std::endl; + std::cout << "expected_res = " << std::hex << expected_res << std::endl; + ASSERT_EQ(expected_res, *(output_cpu.get())); +} // poseidon2_3_sponge_hash_2_without_dt_cpu_only +#endif +// DEBUG // Test check single hash without domain tag. TEST_F(HashApiTest, poseidon2_3_single_hash_without_dt) From f6e9d0d5a4597c1e9b7372c34b4c1a1318469271 Mon Sep 17 00:00:00 2001 From: LeonHibnik Date: Mon, 20 Jan 2025 19:01:43 +0000 Subject: [PATCH 2/8] Commit for PR --- docs/docs/icicle/primitives/hash.md | 10 +- icicle/backend/cpu/src/hash/cpu_poseidon2.cpp | 76 +++---- icicle/tests/test_hash_api.cpp | 188 +++++++++++------- 3 files changed, 150 insertions(+), 124 deletions(-) diff --git a/docs/docs/icicle/primitives/hash.md b/docs/docs/icicle/primitives/hash.md index a88bc996f..631bc270e 100644 --- a/docs/docs/icicle/primitives/hash.md +++ b/docs/docs/icicle/primitives/hash.md @@ -62,17 +62,13 @@ It is an improved version of the original [Poseidon](https://eprint.iacr.org/201 The optional `domain_tag` pointer parameter enables domain separation, allowing isolation of hash outputs across different contexts or applications. -:::info - The supported values of state size ***t*** as defined in [eprint 2023/323](https://eprint.iacr.org/2023/323.pdf) are 2, 3, 4, 8, 12, 16, 20 and 24. Note that ***t*** sizes 8, 12, 16, 20 and 24 are supported only for small fields (babybear and m31). -::: - -:::info - The S box power alpha, number of full rounds and partial rounds, rounds constants, MDS matrix, and partial matrix for each field and ***t*** can be found in this [folder](https://github.com/ingonyama-zk/icicle/tree/9b1506cda9eab30fc6a8d0a338e2cfab877402f7/icicle/include/icicle/hash/poseidon2_constants/constants). -::: +There are two modes for using the Poseidon2 hash - sponge function and non-sponge (merkle tree) function. The key difference between these modes is their execution pattern. The sponge function is inherently serial (each hash must wait for the previous hash to complete before starting its own process), while the non-sponge function (which consists of multiple independent hashes that don't share inputs) runs in parallel using GPU threads, with the number of threads equal to config.batch. + +The hash function automatically chooses between these modes based on the input size. It runs in sponge mode if the input size (including the domain_tag if present) is greater than the single hash width (in this case, config.batch should be set to one). Otherwise, it uses the non-sponge mode. In the current version the padding is not supported and should be performed by the user. diff --git a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp index 270781a6b..fd27d2519 100644 --- a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp +++ b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp @@ -201,23 +201,23 @@ namespace icicle { { const unsigned arity = m_use_domain_tag ? m_t - 1 : m_t; bool is_sponge = false; - int size_in_scalars = size / sizeof(S); - if (size_in_scalars > (m_use_domain_tag ? m_t - 1 : m_t)) { // Sponge function. Check input size granularity. + int input_size_in_scalars = size / sizeof(S); + if (input_size_in_scalars > (m_use_domain_tag ? m_t - 1 : m_t)) { // Sponge function. Check input size granularity. is_sponge = true; // Capacity width (in scalars) = 1. // Output width (in scalars) = 1. - if ((m_use_domain_tag ? size_in_scalars : size_in_scalars - 1) % (m_t - 1) != 0) { + if ((m_use_domain_tag ? input_size_in_scalars : input_size_in_scalars - 1) % (m_t - 1) != 0) { ICICLE_LOG_ERROR << "Padding isn't supported for sponge function hash. The following should be true: ((m_use_domain_tag ? size : size-1) % (m_t-1) != 0).\n"; return eIcicleError::INVALID_ARGUMENT; } if (config.batch != 1) { ICICLE_LOG_ERROR - << "The only suppoorted value of config.batch is 1.\n"; + << "The only suppoorted value of config.batch for sponge functions is 1.\n"; return eIcicleError::INVALID_ARGUMENT; } } - else if (size_in_scalars < (m_use_domain_tag ? m_t - 1 : m_t)) { + else if (input_size_in_scalars < (m_use_domain_tag ? m_t - 1 : m_t)) { ICICLE_LOG_ERROR << "Padding isn't supported for sponge function hash. The following should be true: ((use_domain_tag ? size + 1 : size) % T = 0).\n"; return eIcicleError::INVALID_ARGUMENT; @@ -226,7 +226,7 @@ namespace icicle { const unsigned int T = m_t; bool is_unsupported_T_for_this_field = poseidon2_constants[T].nof_upper_full_rounds == 0; if (is_unsupported_T_for_this_field) { - ICICLE_LOG_ERROR << "Unsupported poseidon width (t=" << T << ") for this field! Planned for next version"; + ICICLE_LOG_ERROR << "Unsupported poseidon width (t = " << T << ") for this field! Planned for next version"; return eIcicleError::API_NOT_IMPLEMENTED; } @@ -239,15 +239,12 @@ namespace icicle { S* partial_matrix_diagonal_m1 = poseidon2_constants[T].partial_matrix_diagonal_m1; // Allocate temporary memory for intermediate calcs and in order not to change the input. - int sponge_nof_hashers = m_use_domain_tag ? (size_in_scalars / arity) : ((size_in_scalars - 1) / (arity - 1)); + int sponge_nof_hashers = m_use_domain_tag ? (input_size_in_scalars / arity) : ((input_size_in_scalars - 1) / (arity - 1)); int tmp_fields_nof_scalars = is_sponge ? (T * sponge_nof_hashers) : (T * config.batch); - // std::cout << "tmp_fields_nof_scalars = " << tmp_fields_nof_scalars << std::endl; S* tmp_fields = new S[tmp_fields_nof_scalars]; - std::cout << "tmp_fields (new) = " << tmp_fields << std::endl; const S* in_fields = (S*)(input); if (m_use_domain_tag) { if (is_sponge) { - // std::cout << "is_sponge sponge_nof_hashers = " << sponge_nof_hashers << std::endl; // Domain tag exists only for the first hasher. For the rest of the hashers this // input is undefined at this stage and its value will be set later. // tmp_fields = {{dt, in0}, {undef, in1}, {undef, in2}, etc.} @@ -260,7 +257,7 @@ namespace icicle { tmp_fields -= T * sponge_nof_hashers; } else { // Not a sponge function. Input of each hash should have domain tag at its input. - // tmp_fields = {{dt, in0}, {dt, in1}, {dt, in2}, etc.} + // tmp_fields = {{dt, in0 (T-1 inputs)}, {dt, in1 (T-1 inputs)}, {dt, in2 (T-1 inputs)}, etc.} for (int batch_idx = 0; batch_idx < config.batch; batch_idx++) { memcpy(tmp_fields, &m_domain_tag, sizeof(S)); memcpy(tmp_fields + 1, in_fields, (T - 1) * sizeof(S)); @@ -272,17 +269,14 @@ namespace icicle { } else { // There is no domain tag. if (is_sponge) { - // tmp_fields = {{in0 (T inputs)}, {undef, in1}, {under, in2}, etc.} - // std::cout << "is_sponge sponge_nof_hashers = " << sponge_nof_hashers << std::endl; + // tmp_fields = {{in0 (T inputs)}, {undef, in1 (T-1 inputs)}, {under, in2 (T-1 inputs)}, etc.} memcpy(tmp_fields, in_fields, T * sizeof(S)); // 1st hasher uses T inputs. - // print_state("tmp_fields 1st hasher external input: ", tmp_fields); in_fields += T; tmp_fields += T; // Rest of the hashers use T-1 inputs and 1 output from the previous hasher. // The value of the 1st input of each of these hashers is undef at this stage. for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { memcpy(&tmp_fields[1], in_fields, (T - 1) * sizeof(S)); - // print_state("tmp_fields 2nd hasher external input (1st scalar doesnt matter): ", tmp_fields); in_fields += (T - 1); tmp_fields += T; } @@ -294,35 +288,27 @@ namespace icicle { } } - // std::cout << "tmp_fields (start processing) = " << tmp_fields << std::endl; if (is_sponge) { S* tmp_fields_tmp_ptr; // This pointer is used to assist in addition of the hasher outputs // with new inputs. - // Call hash_single for hasher[0] - // print_state("tmp_fields input to the first hasher: ", tmp_fields); + // Call hash_single for hasher[0] eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, - rounds_constants, mds_matrix, partial_matrix_diagonal_m1); - // print_state("tmp_fields output of the first hasher: ", tmp_fields); + rounds_constants, mds_matrix, partial_matrix_diagonal_m1); tmp_fields[T] = tmp_fields[0]; // Current first output is an input to the next hasher. tmp_fields_tmp_ptr = tmp_fields; // Save current pointer. tmp_fields += T; - for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { - // std::cout << "hasher_idx = " << hasher_idx << std::endl; - // print_state("tmp_fields taken from external input (1st scalar doesnt matter): ", tmp_fields); - // print_state("tmp_fields taken from prev hasher: ", tmp_fields_tmp_ptr); + for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { // The first output of the prev hasher is the first input of the current hasher. // The T-1 new inputs of the current hasher should be added to the T-1 outputs of the // prev hasher (starting fom index 1). for (int i = 1; i < T; i++) { tmp_fields[i] = tmp_fields_tmp_ptr[i] + tmp_fields[i]; } - // print_state("tmp_fields after addition: ", tmp_fields); tmp_fields_tmp_ptr = tmp_fields; // Save current pointer. eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, rounds_constants, mds_matrix, partial_matrix_diagonal_m1); - // print_state("tmp_fields output of the non-first hasher: ", tmp_fields); if (err != eIcicleError::SUCCESS) return err; if (hasher_idx != sponge_nof_hashers - 1) // Not to do in the last loop to prevent mem leak. tmp_fields[T] = tmp_fields[0]; // Current first output is an input to the next hasher. @@ -334,11 +320,9 @@ namespace icicle { } else { // Not a sponge function. for (int batch_hash_idx = 0; batch_hash_idx < config.batch; batch_hash_idx++) { - // print_state("tmp_fields before hash_single: ", tmp_fields); eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, rounds_constants, mds_matrix, partial_matrix_diagonal_m1); - // print_state("tmp_fields after hash_single: ", tmp_fields); if (err != eIcicleError::SUCCESS) return err; memcpy(output, (std::byte*)(&tmp_fields[1]), sizeof(S)); tmp_fields += T; @@ -347,7 +331,6 @@ namespace icicle { tmp_fields -= T * config.batch; } - // std::cout << "tmp_fields (delete) = " << tmp_fields<< std::endl; delete[] tmp_fields; tmp_fields = nullptr; @@ -355,22 +338,22 @@ namespace icicle { } private: - // DEBUG start. Do not remove!!! - void print_state(std::string str, S* state_to_print) const { - std::cout << str << std::endl; - unsigned int T = m_t; - for (int state_idx = 0; state_idx < T; state_idx++) { // Columns of matrix. - std::cout << std::hex << state_to_print[state_idx] << std::endl; - } - } - void print_matrix(std::string str, S* matrix_to_print) const { - std::cout << str << std::endl; - unsigned int T = m_t; - for (int matrix_idx = 0; matrix_idx < T*T; matrix_idx++) { // Columns of matrix. - std::cout << std::hex << matrix_to_print[matrix_idx] << std::endl; - } - } - // DEBUG end + // // DEBUG start. Do not remove!!! + // void print_state(std::string str, S* state_to_print) const { + // std::cout << str << std::endl; + // unsigned int T = m_t; + // for (int state_idx = 0; state_idx < T; state_idx++) { // Columns of matrix. + // std::cout << std::hex << state_to_print[state_idx] << std::endl; + // } + // } + // void print_matrix(std::string str, S* matrix_to_print) const { + // std::cout << str << std::endl; + // unsigned int T = m_t; + // for (int matrix_idx = 0; matrix_idx < T*T; matrix_idx++) { // Columns of matrix. + // std::cout << std::hex << matrix_to_print[matrix_idx] << std::endl; + // } + // } + // // DEBUG end // This function performs a single hash according to parameters in the poseidon2_constants[] struct. // eIcicleError hash_single(const std::byte* input, std::byte* output) const @@ -382,12 +365,9 @@ namespace icicle { // Pre-rounds full matrix multiplication. full_matrix_mul_by_vector(tmp_fields, mds_matrix, tmp_fields); - // print_matrix("mds_matrix: ", mds_matrix); - // print_state("Pre-rounds mds matrix multiplication: ", tmp_fields); // Upper full rounds. full_rounds(nof_upper_full_rounds, tmp_fields, rounds_constants); - // print_state("Upper full rounds: ", tmp_fields); // Partial rounds. Perform calculation only for the first element of *tmp_fields. for (int partial_rounds_idx = 0; partial_rounds_idx < nof_partial_rounds; partial_rounds_idx++) { diff --git a/icicle/tests/test_hash_api.cpp b/icicle/tests/test_hash_api.cpp index c537ea581..0849ebdb6 100644 --- a/icicle/tests/test_hash_api.cpp +++ b/icicle/tests/test_hash_api.cpp @@ -1162,15 +1162,12 @@ TEST_F(HashApiTest, poseidon2_3_single_hash_cpu_only) config.batch = 1 << 10; auto input = std::make_unique(config.batch * t); - // scalar_t::rand_host_many(input.get(), t); - // DEBUG - sets known inputs. Do not remove!!! for (int i=0; i(nof_hashers * t); - // scalar_t::rand_host_many(input.get(), t); - // DEBUG - sets known inputs. Do not remove!!! + auto input = std::make_unique(1 + nof_hashers * (t - 1)); for (int i=0; i(t); + + START_TIMER(POSEIDON2_sync) + for (int i = 0; i < iters; ++i) { + ICICLE_CHECK(poseidon2.hash(input.get(), 1 + nof_hashers * (t-1), config, out)); + } + END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); + }; + + auto output_cpu = std::make_unique(1); + auto output_mainDev = std::make_unique(1); + + run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + // std::cout << "*(output_cpu.get()) = " << std::hex << *(output_cpu.get()) << std::endl; + run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + // std::cout << "*(output_mainDev.get()) = " << std::hex << *(output_mainDev.get()) << std::endl; + + ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); + int a = 5; +} // poseidon2_3_sponge_hash_2_without_dt + +TEST_F(HashApiTest, poseidon2_3_sponge_hash_1K_without_dt) +{ + const unsigned t = 3; + auto config = default_hash_config(); + int nof_hashers = 1<<10; + + auto input = std::make_unique(1 + nof_hashers * (t - 1)); + scalar_t::rand_host_many(input.get(), 1 + nof_hashers * (t - 1)); + // // DEBUG - sets known inputs. Do not remove!!! + // for (int i=0; i(t); + + ICICLE_CHECK(poseidon2.hash(input.get(), 1 + nof_hashers * (t-1), config, out)); + START_TIMER(POSEIDON2_sync) + for (int i = 0; i < iters; ++i) { + ICICLE_CHECK(poseidon2.hash(input.get(), 1 + nof_hashers * (t-1), config, out)); + } + END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); + }; + + auto output_cpu = std::make_unique(1); + auto output_mainDev = std::make_unique(1); + + run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + // std::cout << "*(output_cpu.get()) = " << std::hex << *(output_cpu.get()) << std::endl; + run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + // std::cout << "*(output_mainDev.get()) = " << std::hex << *(output_mainDev.get()) << std::endl; + + ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); + int a = 5; +} // poseidon2_3_sponge_hash_1K_without_dt + TEST_F(HashApiTest, poseidon2_invalid_t) { // Large fields do not support some t's at this moment. @@ -1344,7 +1436,7 @@ TEST_F(HashApiTest, poseidon2_invalid_t) auto output = std::make_unique(config.batch); scalar_t::rand_host_many(input.get(), t * config.batch); - const bool large_field = sizeof(scalar_t) > 4; + const bool large_field = sizeof(scalar_t) > 8; for (const auto& device : s_registered_devices) { icicle_set_device(device); @@ -1401,8 +1493,6 @@ TEST_F(HashApiTest, poseidon2_3_batch_without_dt_debug) const unsigned t = 3; auto config = default_hash_config(); config.batch = 1 << 10; - std::cout << "poseidon2_3_batch_without_dt_debug: t = %d\n" << t << std::endl; - std::cout << "poseidon2_3_batch_without_dt_debug: config.batch = %d\n" << config.batch << std::endl; auto input = std::make_unique(t * config.batch); scalar_t::rand_host_many(input.get(), t * config.batch); @@ -1411,7 +1501,7 @@ TEST_F(HashApiTest, poseidon2_3_batch_without_dt_debug) // input[i] = scalar_t::from(i % t); // } // for (int i = 0; i < config.batch * t; i++) { - // std::cout << "poseidon2_3_batch_without_dt input " << input[i] << std::endl; + // std::cout << "poseidon2_3_batch_without_dt_debug input " << input[i] << std::endl; // } // // DEBUG @@ -1427,7 +1517,7 @@ TEST_F(HashApiTest, poseidon2_3_batch_without_dt_debug) START_TIMER(POSEIDON2_sync) for (int i = 0; i < iters; ++i) { - std::cout << "poseidon2_3_batch_without_dt: t = " << std::dec << t << std::endl; + std::cout << "poseidon2_3_batch_without_dt_debug: t = " << std::dec << t << std::endl; ICICLE_CHECK(poseidon2.hash(input.get(), t, config, out)); } END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); @@ -1439,10 +1529,6 @@ TEST_F(HashApiTest, poseidon2_3_batch_without_dt_debug) run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); - std::cout << "output_cpu[" << config.batch - 2 << "] = " << output_cpu.get()[config.batch - 2] << std::endl; - std::cout << "output_mainDev[" << config.batch - 2 << "] = " << output_mainDev.get()[config.batch - 2] << std::endl; - std::cout << "output_cpu[" << config.batch - 1 << "] = " << output_cpu.get()[config.batch - 1] << std::endl; - std::cout << "output_mainDev[" << config.batch - 1 << "] = " << output_mainDev.get()[config.batch - 1] << std::endl; ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); } @@ -1467,7 +1553,6 @@ TEST_F(HashApiTest, poseidon2_3_batch_without_dt) START_TIMER(POSEIDON2_sync) for (int i = 0; i < iters; ++i) { - std::cout << "poseidon2_3_batch_without_dt: t = " << std::dec << t << std::endl; ICICLE_CHECK(poseidon2.hash(input.get(), t, config, out)); } END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); @@ -1482,41 +1567,6 @@ TEST_F(HashApiTest, poseidon2_3_batch_without_dt) ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); } -// Danny TODO - to add tree test with diff T's for the levels. -// TEST_F(HashApiTest, poseidon2_3x2_to_2x1_two_level_tree_no_dt) -// { -// const unsigned t = 3; -// auto config = default_hash_config(); - -// config.batch = 1 << 10; -// auto input = std::make_unique(t * config.batch); -// scalar_t::rand_host_many(input.get(), t * config.batch); - -// auto run = [&](const std::string& dev_type, scalar_t* out, bool measure, const char* msg, int iters) { -// std::cout << "iters = " << iters << std::endl; -// Device dev = {dev_type, 0}; -// icicle_set_device(dev); - -// std::ostringstream oss; -// oss << dev_type << " " << msg; - -// auto poseidon2 = Poseidon2::create(t); - -// START_TIMER(POSEIDON2_sync) -// for (int i = 0; i < iters; ++i) { -// ICICLE_CHECK(poseidon2.hash(input.get(), t, config, out)); -// } -// END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); -// }; - -// auto output_cpu = std::make_unique(config.batch); -// auto output_mainDev = std::make_unique(config.batch); - -// run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); -// run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); - -// ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); -// } #endif // POSEIDON2 #ifdef SUMCHECK @@ -1567,4 +1617,4 @@ TEST_F(SumcheckTest, InitializeWithByteVector) EXPECT_TRUE(config.is_little_endian()); EXPECT_EQ(config.get_seed_rng(), seed); } -#endif // SUMCHECK \ No newline at end of file +#endif // SUMCHECK From 88a37995cf9bcd69762862122a6475f239c9f6e6 Mon Sep 17 00:00:00 2001 From: danny-shterman Date: Thu, 23 Jan 2025 11:08:51 +0200 Subject: [PATCH 3/8] WIP --- icicle/backend/cpu/src/hash/cpu_poseidon2.cpp | 91 ++++++++++++------- icicle/tests/test_hash_api.cpp | 6 +- 2 files changed, 63 insertions(+), 34 deletions(-) diff --git a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp index fd27d2519..94f038392 100644 --- a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp +++ b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp @@ -239,48 +239,74 @@ namespace icicle { S* partial_matrix_diagonal_m1 = poseidon2_constants[T].partial_matrix_diagonal_m1; // Allocate temporary memory for intermediate calcs and in order not to change the input. - int sponge_nof_hashers = m_use_domain_tag ? (input_size_in_scalars / arity) : ((input_size_in_scalars - 1) / (arity - 1)); - int tmp_fields_nof_scalars = is_sponge ? (T * sponge_nof_hashers) : (T * config.batch); - S* tmp_fields = new S[tmp_fields_nof_scalars]; + // int sponge_nof_hashers = m_use_domain_tag ? (input_size_in_scalars / arity) : ((input_size_in_scalars - 1) / (arity - 1)); + // int tmp_fields_nof_scalars = is_sponge ? (T * sponge_nof_hashers) : (T * config.batch); + // S* tmp_fields = new S[tmp_fields_nof_scalars]; + S* tmp_fields; + int sponge_nof_hashers; const S* in_fields = (S*)(input); - if (m_use_domain_tag) { - if (is_sponge) { + int padding_size = 0; + S* padding; + if (is_sponge) { + if (input_size_in_scalars <= T) { + sponge_nof_hashers = 1; + padding_size = T - (input_size_in_scalars + (m_use_domain_tag == 1)); + } else { + sponge_nof_hashers = (input_size_in_scalars + (m_use_domain_tag == 1) + 1 /* for domain_tag */ - T + (T - 2)) / (T - 1); + padding_size = (input_size_in_scalars + (m_use_domain_tag == 1) - T) % (T - 1); + } + if (padding_size > 0) { // Fill padding array with 1,0,0,... + padding = new S[padding_size]; + padding[0] = S::from(1); + for (int i = 1; i < padding_size; i++) { + padding[i] = S::from(0); + } + } + tmp_fields = new S[T * sponge_nof_hashers]; + if (m_use_domain_tag) { // Domain tag exists only for the first hasher. For the rest of the hashers this // input is undefined at this stage and its value will be set later. // tmp_fields = {{dt, in0}, {undef, in1}, {undef, in2}, etc.} memcpy(tmp_fields, &m_domain_tag, sizeof(S)); - for (int hasher_idx = 0; hasher_idx < sponge_nof_hashers; hasher_idx++) { + } + else { + // tmp_fields = {{in0 (T inputs)}, {undef, in1 (T-1 inputs)}, {under, in2 (T-1 inputs)}, etc.} + memcpy(tmp_fields, in_fields, T * sizeof(S)); // 1st hasher uses T inputs. + in_fields += T; + tmp_fields += T; + } + for (int hasher_idx = 0; hasher_idx < sponge_nof_hashers; hasher_idx++) { + if (hasher_idx == sponge_nof_hashers-1 && padding_size > 0) { + // Last hasher in the chain. Take care of padding. + if (hasher_idx == 0) { + memcpy(tmp_fields + 1, in_fields, (T - padding_size) * sizeof(S)); + memcpy(tmp_fields + 1 + T - padding_size, in_fields, padding_size * sizeof(S)); + } + else { + memcpy(tmp_fields + 1, in_fields, (T - padding_size - 1) * sizeof(S)); + memcpy(tmp_fields + 1 + T - padding_size - 1, in_fields, padding_size * sizeof(S)); + } + } + else { // Not a last hasher in the chain. There is no padding. memcpy(tmp_fields + 1, in_fields, (T - 1) * sizeof(S)); - in_fields += (T - 1); - tmp_fields += T; } - tmp_fields -= T * sponge_nof_hashers; + in_fields += (T - 1); + tmp_fields += T; } - else { // Not a sponge function. Input of each hash should have domain tag at its input. - // tmp_fields = {{dt, in0 (T-1 inputs)}, {dt, in1 (T-1 inputs)}, {dt, in2 (T-1 inputs)}, etc.} + tmp_fields -= T * sponge_nof_hashers; + } // if (is_sponge) { + else { // Not a sponge function. The is no padding. + // Input of each hash should have domain tag at its input. + // tmp_fields = {{dt, in0 (T-1 inputs)}, {dt, in1 (T-1 inputs)}, {dt, in2 (T-1 inputs)}, etc.} + tmp_fields = new S[T * config.batch]; + if (m_use_domain_tag) { for (int batch_idx = 0; batch_idx < config.batch; batch_idx++) { memcpy(tmp_fields, &m_domain_tag, sizeof(S)); memcpy(tmp_fields + 1, in_fields, (T - 1) * sizeof(S)); in_fields += (T - 1); tmp_fields += T; } - tmp_fields -= T * config.batch; - } - } - else { // There is no domain tag. - if (is_sponge) { - // tmp_fields = {{in0 (T inputs)}, {undef, in1 (T-1 inputs)}, {under, in2 (T-1 inputs)}, etc.} - memcpy(tmp_fields, in_fields, T * sizeof(S)); // 1st hasher uses T inputs. - in_fields += T; - tmp_fields += T; - // Rest of the hashers use T-1 inputs and 1 output from the previous hasher. - // The value of the 1st input of each of these hashers is undef at this stage. - for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { - memcpy(&tmp_fields[1], in_fields, (T - 1) * sizeof(S)); - in_fields += (T - 1); - tmp_fields += T; - } - tmp_fields -= T * sponge_nof_hashers; + tmp_fields -= T * config.batch; } else { // tmp_fields = {{in0 (T inputs)}, {in1 (T inputs)}, {in2 (T inputs)}, etc.} @@ -288,6 +314,7 @@ namespace icicle { } } + // Hashes processing. if (is_sponge) { S* tmp_fields_tmp_ptr; // This pointer is used to assist in addition of the hasher outputs // with new inputs. @@ -295,6 +322,7 @@ namespace icicle { eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, rounds_constants, mds_matrix, partial_matrix_diagonal_m1); + if (err != eIcicleError::SUCCESS) return err; tmp_fields[T] = tmp_fields[0]; // Current first output is an input to the next hasher. tmp_fields_tmp_ptr = tmp_fields; // Save current pointer. tmp_fields += T; @@ -311,9 +339,9 @@ namespace icicle { rounds_constants, mds_matrix, partial_matrix_diagonal_m1); if (err != eIcicleError::SUCCESS) return err; if (hasher_idx != sponge_nof_hashers - 1) // Not to do in the last loop to prevent mem leak. - tmp_fields[T] = tmp_fields[0]; // Current first output is an input to the next hasher. - tmp_fields += T; // Proceed to the next hash. - } + tmp_fields[T] = tmp_fields[0]; // Fill first scalar of the input to the next hasher. + tmp_fields += T; // Proceed to the next hasher. + } // for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { tmp_fields -= T; // Rollback to the last hasher output. memcpy(output, (std::byte*)(&tmp_fields[1]), sizeof(S)); tmp_fields -= T * (sponge_nof_hashers - 1); @@ -332,6 +360,7 @@ namespace icicle { } delete[] tmp_fields; + if (padding_size != 0) delete[] padding; tmp_fields = nullptr; return eIcicleError::SUCCESS; diff --git a/icicle/tests/test_hash_api.cpp b/icicle/tests/test_hash_api.cpp index 0849ebdb6..b69b2a6df 100644 --- a/icicle/tests/test_hash_api.cpp +++ b/icicle/tests/test_hash_api.cpp @@ -1205,7 +1205,7 @@ TEST_F(HashApiTest, poseidon2_3_sponge_2nd_hasher_without_dt_cpu_only) input[1] = scalar_t::hex_str2scalar("0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03571"); input[2] = scalar_t::hex_str2scalar("0x1ed25194542b12eef8617361c3ba7c52e660b145994427cc86296242cf766eca"); for (int i = 0; i < t; i++) { - // std::cout << "poseidon2_3_single_hash_cpu_only input " << input[i] << std::endl; + // std::cout << "poseidon2_3_sponge_2nd_hasher_without_dt_cpu_only input " << input[i] << std::endl; } // DEBUG @@ -1248,7 +1248,7 @@ TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt_cpu_only) } } for (int i = 0; i < t + (nof_hashers-1) * (t-1); i++) { - // std::cout << "poseidon2_3_sponge_hash_2_without_dt_cpu_only input " << input[i] << std::endl; + std::cout << "poseidon2_3_sponge_hash_2_without_dt_cpu_only input " << input[i] << std::endl; } auto run = [&](const std::string& dev_type, scalar_t* out, bool measure, const char* msg, int iters) { @@ -1267,7 +1267,7 @@ TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt_cpu_only) END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); }; - auto output_cpu = std::make_unique(config.batch); + auto output_cpu = std::make_unique(config.batch); // config.batch = 1 here. run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); scalar_t expected_res = From 66a2de8bcb961698b35796159d324dd3d43fcaf6 Mon Sep 17 00:00:00 2001 From: danny-shterman Date: Thu, 30 Jan 2025 08:10:55 +0000 Subject: [PATCH 4/8] For PR --- docs/docs/icicle/primitives/hash.md | 26 +- icicle/backend/cpu/src/hash/cpu_poseidon2.cpp | 91 ++++--- icicle/tests/test_hash_api.cpp | 246 +++++++++++++++--- 3 files changed, 269 insertions(+), 94 deletions(-) diff --git a/docs/docs/icicle/primitives/hash.md b/docs/docs/icicle/primitives/hash.md index 631bc270e..4d6bc5f90 100644 --- a/docs/docs/icicle/primitives/hash.md +++ b/docs/docs/icicle/primitives/hash.md @@ -58,19 +58,27 @@ The optional `domain_tag` pointer parameter enables domain separation, allowing ### Poseidon2 [Poseidon2](https://eprint.iacr.org/2023/323.pdf) is a cryptographic hash function designed specifically for field elements. -It is an improved version of the original [Poseidon](https://eprint.iacr.org/2019/458) hash, offering better performance on modern hardware. Poseidon2 is optimized for use with elliptic curve cryptography and finite fields, making it ideal for decentralized systems like blockchain. Its main advantage is balancing strong security with efficient computation, which is crucial for applications that require fast, reliable hashing. +It is an improved version of the original [Poseidon](https://eprint.iacr.org/2019/458) hash, offering better performance on modern hardware. +Poseidon2 is optimized for use with elliptic curve cryptography and finite fields, making it ideal for decentralized systems like blockchain. +Its main advantage is balancing strong security with efficient computation, which is crucial for applications that require fast, reliable hashing. The optional `domain_tag` pointer parameter enables domain separation, allowing isolation of hash outputs across different contexts or applications. -The supported values of state size ***t*** as defined in [eprint 2023/323](https://eprint.iacr.org/2023/323.pdf) are 2, 3, 4, 8, 12, 16, 20 and 24. Note that ***t*** sizes 8, 12, 16, 20 and 24 are supported only for small fields (babybear and m31). +The supported values of state size ***t*** as defined in [eprint 2023/323](https://eprint.iacr.org/2023/323.pdf) are 2, 3, 4, 8, 12, 16, 20 and 24. +Note that ***t*** sizes 8, 12, 16, 20 and 24 are supported only for small fields (babybear and m31). -The S box power alpha, number of full rounds and partial rounds, rounds constants, MDS matrix, and partial matrix for each field and ***t*** can be found in this [folder](https://github.com/ingonyama-zk/icicle/tree/9b1506cda9eab30fc6a8d0a338e2cfab877402f7/icicle/include/icicle/hash/poseidon2_constants/constants). +The S box power alpha, number of full rounds and partial rounds, rounds constants, MDS matrix, and partial matrix for each field and ***t*** can be +found in this [folder](https://github.com/ingonyama-zk/icicle/tree/9b1506cda9eab30fc6a8d0a338e2cfab877402f7/icicle/include/icicle/hash/poseidon2_constants/constants). -There are two modes for using the Poseidon2 hash - sponge function and non-sponge (merkle tree) function. The key difference between these modes is their execution pattern. The sponge function is inherently serial (each hash must wait for the previous hash to complete before starting its own process), while the non-sponge function (which consists of multiple independent hashes that don't share inputs) runs in parallel using GPU threads, with the number of threads equal to config.batch. +There are two modes for using the Poseidon2 hash - sponge function and non-sponge (merkle tree) function. The key difference between these +modes is their execution pattern. The sponge function is inherently serial (each hash must wait for the previous hash to complete before +starting its own process), while the non-sponge function (which consists of multiple independent hashes that don't share inputs) runs in +parallel using GPU threads, with the number of threads equal to config.batch. +Another difference between two modes is that currently padding is supported for the sponge function and is not supported for the non-sponge. +For the sponge function the config.batch should be equal one. -The hash function automatically chooses between these modes based on the input size. It runs in sponge mode if the input size (including the domain_tag if present) is greater than the single hash width (in this case, config.batch should be set to one). Otherwise, it uses the non-sponge mode. - -In the current version the padding is not supported and should be performed by the user. +The hash function automatically chooses between these modes based on the input size. It runs in sponge mode if the input size (including the +domain_tag if present) is greater than the single hash width (in this case, config.batch should be set to one). Otherwise, it uses the non-sponge mode. ## Using Hash API @@ -173,10 +181,6 @@ eIcicleErr err = keccak256.hash(input.data(), input.size() / config.batch, confi Currently the poseidon sponge mode (sponge function description could be found in Sec 2.1 of [eprint 2019/458](https://eprint.iacr.org/2019/458.pdf)) isn't implemented. -### 5. Poseidon2 sponge function - -Currently the poseidon2 is implemented in compression mode, the sponge mode discussed in [eprint 2023/323](https://eprint.iacr.org/2023/323.pdf) is not implemented. - ### Supported Bindings - [Rust](../rust-bindings/hash) diff --git a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp index 94f038392..3e2d3f423 100644 --- a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp +++ b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp @@ -202,26 +202,21 @@ namespace icicle { const unsigned arity = m_use_domain_tag ? m_t - 1 : m_t; bool is_sponge = false; int input_size_in_scalars = size / sizeof(S); - if (input_size_in_scalars > (m_use_domain_tag ? m_t - 1 : m_t)) { // Sponge function. Check input size granularity. + if ((config.batch == 1) && (input_size_in_scalars != (m_use_domain_tag ? m_t - 1 : m_t))) { // Check if sponge function. is_sponge = true; - // Capacity width (in scalars) = 1. - // Output width (in scalars) = 1. - if ((m_use_domain_tag ? input_size_in_scalars : input_size_in_scalars - 1) % (m_t - 1) != 0) { + if (config.batch != 1) { ICICLE_LOG_ERROR - << "Padding isn't supported for sponge function hash. The following should be true: ((m_use_domain_tag ? size : size-1) % (m_t-1) != 0).\n"; + << "The only suppoorted value of config.batch for sponge functions is 1.\n"; return eIcicleError::INVALID_ARGUMENT; } - if (config.batch != 1) { + } // sponge function + else { // Non-sponge function. + if ((m_use_domain_tag ? input_size_in_scalars : input_size_in_scalars - 1) % (m_t - 1) != 0) { ICICLE_LOG_ERROR - << "The only suppoorted value of config.batch for sponge functions is 1.\n"; + << "Padding isn't supported for non-sponge function hash. The following should be true: ((m_use_domain_tag ? size : size-1) % (m_t-1) != 0).\n"; return eIcicleError::INVALID_ARGUMENT; } - } - else if (input_size_in_scalars < (m_use_domain_tag ? m_t - 1 : m_t)) { - ICICLE_LOG_ERROR - << "Padding isn't supported for sponge function hash. The following should be true: ((use_domain_tag ? size + 1 : size) % T = 0).\n"; - return eIcicleError::INVALID_ARGUMENT; - } + } // Non-sponge function. const unsigned int T = m_t; bool is_unsupported_T_for_this_field = poseidon2_constants[T].nof_upper_full_rounds == 0; @@ -243,17 +238,21 @@ namespace icicle { // int tmp_fields_nof_scalars = is_sponge ? (T * sponge_nof_hashers) : (T * config.batch); // S* tmp_fields = new S[tmp_fields_nof_scalars]; S* tmp_fields; + S* tmp_fields_init_ptr; // This pointer to keep initial tmp_fields value to perform a easy rollback when needed. int sponge_nof_hashers; const S* in_fields = (S*)(input); int padding_size = 0; S* padding; if (is_sponge) { - if (input_size_in_scalars <= T) { + if (input_size_in_scalars < T) { // Single hasher in the chain. sponge_nof_hashers = 1; - padding_size = T - (input_size_in_scalars + (m_use_domain_tag == 1)); - } else { - sponge_nof_hashers = (input_size_in_scalars + (m_use_domain_tag == 1) + 1 /* for domain_tag */ - T + (T - 2)) / (T - 1); - padding_size = (input_size_in_scalars + (m_use_domain_tag == 1) - T) % (T - 1); + padding_size = T - (input_size_in_scalars + (m_use_domain_tag == true)); + } else if (input_size_in_scalars >= T) { // More than a single hasher in the chain. + sponge_nof_hashers = (input_size_in_scalars - !(m_use_domain_tag == true) + (T - 2)) / (T - 1); + bool is_padding_needed = (input_size_in_scalars - !(m_use_domain_tag == true)) % (T - 1); + if (is_padding_needed ) { + padding_size = (T - 1) - ((input_size_in_scalars - !(m_use_domain_tag == true)) % (T - 1)); + } } if (padding_size > 0) { // Fill padding array with 1,0,0,... padding = new S[padding_size]; @@ -263,42 +262,40 @@ namespace icicle { } } tmp_fields = new S[T * sponge_nof_hashers]; + tmp_fields_init_ptr = tmp_fields; + // Take care of hasher 0. It's done separately of the rest of the hashers because of the domain tag. if (m_use_domain_tag) { // Domain tag exists only for the first hasher. For the rest of the hashers this // input is undefined at this stage and its value will be set later. // tmp_fields = {{dt, in0}, {undef, in1}, {undef, in2}, etc.} - memcpy(tmp_fields, &m_domain_tag, sizeof(S)); + memcpy(tmp_fields, &m_domain_tag, sizeof(S)); } else { // tmp_fields = {{in0 (T inputs)}, {undef, in1 (T-1 inputs)}, {under, in2 (T-1 inputs)}, etc.} - memcpy(tmp_fields, in_fields, T * sizeof(S)); // 1st hasher uses T inputs. - in_fields += T; - tmp_fields += T; + memcpy(tmp_fields, &in_fields[0], sizeof(S)); + in_fields += 1; } + tmp_fields += 1; + // Take care of rest of the hashers (T-1 scalar to each hasher). for (int hasher_idx = 0; hasher_idx < sponge_nof_hashers; hasher_idx++) { if (hasher_idx == sponge_nof_hashers-1 && padding_size > 0) { - // Last hasher in the chain. Take care of padding. - if (hasher_idx == 0) { - memcpy(tmp_fields + 1, in_fields, (T - padding_size) * sizeof(S)); - memcpy(tmp_fields + 1 + T - padding_size, in_fields, padding_size * sizeof(S)); - } - else { - memcpy(tmp_fields + 1, in_fields, (T - padding_size - 1) * sizeof(S)); - memcpy(tmp_fields + 1 + T - padding_size - 1, in_fields, padding_size * sizeof(S)); - } + // Last hasher in the chain. Take care of padding if needed. + memcpy(tmp_fields, in_fields, (T - padding_size - 1) * sizeof(S)); + memcpy(tmp_fields + T - padding_size - 1, padding, padding_size * sizeof(S)); } else { // Not a last hasher in the chain. There is no padding. - memcpy(tmp_fields + 1, in_fields, (T - 1) * sizeof(S)); + memcpy(tmp_fields, in_fields, (T - 1) * sizeof(S)); } in_fields += (T - 1); tmp_fields += T; } - tmp_fields -= T * sponge_nof_hashers; + tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. } // if (is_sponge) { else { // Not a sponge function. The is no padding. // Input of each hash should have domain tag at its input. // tmp_fields = {{dt, in0 (T-1 inputs)}, {dt, in1 (T-1 inputs)}, {dt, in2 (T-1 inputs)}, etc.} tmp_fields = new S[T * config.batch]; + tmp_fields_init_ptr = tmp_fields; // Keep tmp_fields pointer for delete. if (m_use_domain_tag) { for (int batch_idx = 0; batch_idx < config.batch; batch_idx++) { memcpy(tmp_fields, &m_domain_tag, sizeof(S)); @@ -306,7 +303,7 @@ namespace icicle { in_fields += (T - 1); tmp_fields += T; } - tmp_fields -= T * config.batch; + tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. } else { // tmp_fields = {{in0 (T inputs)}, {in1 (T inputs)}, {in2 (T inputs)}, etc.} @@ -316,16 +313,17 @@ namespace icicle { // Hashes processing. if (is_sponge) { - S* tmp_fields_tmp_ptr; // This pointer is used to assist in addition of the hasher outputs - // with new inputs. // Call hash_single for hasher[0] eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, - rounds_constants, mds_matrix, partial_matrix_diagonal_m1); + rounds_constants, mds_matrix, partial_matrix_diagonal_m1); + S* tmp_fields_tmp_ptr = tmp_fields; // Save current pointer in order to access prev output. if (err != eIcicleError::SUCCESS) return err; - tmp_fields[T] = tmp_fields[0]; // Current first output is an input to the next hasher. - tmp_fields_tmp_ptr = tmp_fields; // Save current pointer. + if (sponge_nof_hashers != 1) { + tmp_fields[T] = tmp_fields[0]; // Current first output is an input to the next hasher. + } tmp_fields += T; + // Process rest of the hashers. for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { // The first output of the prev hasher is the first input of the current hasher. // The T-1 new inputs of the current hasher should be added to the T-1 outputs of the @@ -333,18 +331,18 @@ namespace icicle { for (int i = 1; i < T; i++) { tmp_fields[i] = tmp_fields_tmp_ptr[i] + tmp_fields[i]; } - tmp_fields_tmp_ptr = tmp_fields; // Save current pointer. eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, rounds_constants, mds_matrix, partial_matrix_diagonal_m1); + tmp_fields_tmp_ptr = tmp_fields; // Save current pointer in order to access prev output. if (err != eIcicleError::SUCCESS) return err; if (hasher_idx != sponge_nof_hashers - 1) // Not to do in the last loop to prevent mem leak. tmp_fields[T] = tmp_fields[0]; // Fill first scalar of the input to the next hasher. - tmp_fields += T; // Proceed to the next hasher. + tmp_fields += T; // Now tmp_fields points to input of the next hasher before the addition. } // for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { tmp_fields -= T; // Rollback to the last hasher output. memcpy(output, (std::byte*)(&tmp_fields[1]), sizeof(S)); - tmp_fields -= T * (sponge_nof_hashers - 1); + tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. } else { // Not a sponge function. for (int batch_hash_idx = 0; batch_hash_idx < config.batch; batch_hash_idx++) { @@ -356,7 +354,7 @@ namespace icicle { tmp_fields += T; output += sizeof(S); } - tmp_fields -= T * config.batch; + tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. } delete[] tmp_fields; @@ -364,14 +362,13 @@ namespace icicle { tmp_fields = nullptr; return eIcicleError::SUCCESS; - } + } // eIcicleError hash(const std::byte* input, uint64_t size, const HashConfig& config, std::byte* output) const override private: // // DEBUG start. Do not remove!!! - // void print_state(std::string str, S* state_to_print) const { + // void print_state(std::string str, const S* state_to_print, int count) const { // std::cout << str << std::endl; - // unsigned int T = m_t; - // for (int state_idx = 0; state_idx < T; state_idx++) { // Columns of matrix. + // for (int state_idx = 0; state_idx < count; state_idx++) { // Columns of matrix. // std::cout << std::hex << state_to_print[state_idx] << std::endl; // } // } diff --git a/icicle/tests/test_hash_api.cpp b/icicle/tests/test_hash_api.cpp index b69b2a6df..0a2eea7f1 100644 --- a/icicle/tests/test_hash_api.cpp +++ b/icicle/tests/test_hash_api.cpp @@ -1154,20 +1154,19 @@ TEST_F(HashApiTest, poseidon_tree) // bn254: p = 0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570 #include "icicle/fields/field_config.h" using namespace field_config; -#if FIELD_ID == BN254 -TEST_F(HashApiTest, poseidon2_3_single_hash_cpu_only) +TEST_F(HashApiTest, poseidon2_3_single_hasher) { const unsigned t = 3; auto config = default_hash_config(); - config.batch = 1 << 10; + config.batch = 1; auto input = std::make_unique(config.batch * t); for (int i=0; i(config.batch); - run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); +#if FIELD_ID == BN254 scalar_t expected_res = scalar_t::hex_str2scalar("0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570"); ASSERT_EQ(expected_res, *(output_cpu.get())); -} // poseidon2_3_single_hash_cpu_only -// Test for CPU only. -// Test to check correctness of the second hasher of the poseidon2_3_sponge_hash_2_without_dt_cpu_only test. -TEST_F(HashApiTest, poseidon2_3_sponge_2nd_hasher_without_dt_cpu_only) +#endif + + if (IcicleTestBase::main_device() == "CUDA") { + std::cout << "Run CUDA test " << std::endl; + auto output_mainDev = std::make_unique(config.batch); + run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); + std::cout << "End CUDA test " << std::endl; + } +} // poseidon2_3_single_hasher + + +// Test used to generate expected result of the nd hasher. +TEST_F(HashApiTest, poseidon2_3_gen_hasher_expected_result_cpu_only) { +#if FIELD_ID == BN254 const unsigned t = 3; auto config = default_hash_config(); config.batch = 1; auto input = std::make_unique(t); - input[0] = scalar_t::hex_str2scalar("0x0bb61d24daca55eebcb1929a82650f328134334da98ea4f847f760054f4a3033"); - input[1] = scalar_t::hex_str2scalar("0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03571"); - input[2] = scalar_t::hex_str2scalar("0x1ed25194542b12eef8617361c3ba7c52e660b145994427cc86296242cf766eca"); - for (int i = 0; i < t; i++) { - // std::cout << "poseidon2_3_sponge_2nd_hasher_without_dt_cpu_only input " << input[i] << std::endl; - } - // DEBUG + input[0] = scalar_t::hex_str2scalar("0x00e6997915531bf1cdb5d90acacc4a14d0960a3de8ac56b520de319b627db7bf"); + // input[1] = scalar_t::hex_str2scalar("0x17e49ca947671143af1f5038d0ed615d4db68cb2b475b00fb253a1f0886a80c0"); + // input[2] = scalar_t::hex_str2scalar("0x0001e7319635c0fdeabf4dbc8c539c296682a0c9260a8f457b3565e49299d308"); + // input[3] = scalar_t::hex_str2scalar("0x1aa6c65a496292747d2667b5e72a3521637b4d4d8dbc99d0b555696c1cdb9a34"); + // input[0] = scalar_t::from(4); + input[1] = scalar_t::from(7); + input[2] = scalar_t::from(8); + // input[3] = scalar_t::from(7); + // for (int i = 0; i < t; i++) { + // std::cout << "poseidon2_3_gen_hasher_expected_result_cpu_only input " << input[i] << std::endl; + // } auto run = [&](const std::string& dev_type, scalar_t* out, bool measure, const char* msg, int iters) { Device dev = {dev_type, 0}; @@ -1226,13 +1241,13 @@ TEST_F(HashApiTest, poseidon2_3_sponge_2nd_hasher_without_dt_cpu_only) }; auto output_cpu = std::make_unique(config.batch); - run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); - scalar_t expected_res = - scalar_t::hex_str2scalar("0x0d54b4b71781dc4f30afe3a90f76559379f6f75aea6968d4c986512e2711ad20"); - ASSERT_EQ(expected_res, *(output_cpu.get())); // No need to compere. -} // poseidon2_3_sponge_2nd_hasher_without_dt_cpu_only -TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt_cpu_only) +#endif +} // poseidon2_3_gen_hasher_expected_result_cpu_only + + +// Sponge, chain of 2 hashers, no padding, no domain tag. +TEST_F(HashApiTest, poseidon2_3_sponge_2_hashers_without_dt) { const unsigned t = 3; auto config = default_hash_config(); @@ -1247,9 +1262,9 @@ TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt_cpu_only) input[hasher_idx * (t-1) + i] = scalar_t::from(i); } } - for (int i = 0; i < t + (nof_hashers-1) * (t-1); i++) { - std::cout << "poseidon2_3_sponge_hash_2_without_dt_cpu_only input " << input[i] << std::endl; - } + // for (int i = 0; i < t + (nof_hashers-1) * (t-1); i++) { + // std::cout << "poseidon2_3_sponge_2_hashers_without_dt input " << input[i] << std::endl; + // } auto run = [&](const std::string& dev_type, scalar_t* out, bool measure, const char* msg, int iters) { Device dev = {dev_type, 0}; @@ -1267,15 +1282,178 @@ TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt_cpu_only) END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); }; + std::cout << "Run CPU test " << std::endl; auto output_cpu = std::make_unique(config.batch); // config.batch = 1 here. - run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); +#if FIELD_ID == BN254 scalar_t expected_res = scalar_t::hex_str2scalar("0x0d54b4b71781dc4f30afe3a90f76559379f6f75aea6968d4c986512e2711ad20"); ASSERT_EQ(expected_res, *(output_cpu.get())); -} // poseidon2_3_sponge_hash_2_without_dt_cpu_only +#endif + + std::string main_device = IcicleTestBase::main_device(); + if (IcicleTestBase::main_device() == "CUDA") { + std::cout << "Run CUDA test " << std::endl; + auto output_mainDev = std::make_unique(config.batch); + run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); + } +} // poseidon2_3_sponge_2_hashers_without_dt + + +// Sponge, chain of 2 hashers, no padding, with domain tag. +TEST_F(HashApiTest, poseidon2_3_sponge_2_hashers_with_dt) +{ + const unsigned t = 3; + auto config = default_hash_config(); + const scalar_t domain_tag = scalar_t::from(4); + std::cout << "poseidon2_3_sponge_2_hashers_with_dt domain_tag " << domain_tag << std::endl; + int nof_hashers = 2; + int nof_valid_inputs = 4; + + // Input will be 4,5,6,8. + // With dt and padding it will be 4,5,6,7,8,1,0. + auto input = std::make_unique(nof_valid_inputs); + for (int i=0; i(t, &domain_tag); + + START_TIMER(POSEIDON2_sync) + for (int i = 0; i < iters; ++i) { + ICICLE_CHECK(poseidon2.hash(input.get(), nof_valid_inputs, config, out)); + } + END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); + }; + + std::cout << "Run CPU test " << std::endl; + auto output_cpu = std::make_unique(config.batch); // config.batch = 1 here. + run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); +#if FIELD_ID == BN254 + scalar_t expected_res = + scalar_t::hex_str2scalar("0x286786cd695dbe838456c72a5edb4d2717a17a0971006671c26c0219c3de5abe"); + ASSERT_EQ(expected_res, *(output_cpu.get())); +#endif + + if (IcicleTestBase::main_device() == "CUDA") { + std::cout << "Run CUDA test " << std::endl; + auto output_mainDev = std::make_unique(config.batch); + run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); + } +} // poseidon2_3_sponge_2_hashers_with_dt + + +// Sponge, chain of 1 hasher, with padding (2 scalars 1,0), no domain tag. +TEST_F(HashApiTest, poseidon2_3_sponge_1_hasher_without_dt_with_padding) +{ + const unsigned t = 4; + auto config = default_hash_config(); + int nof_hashers = 1; + int nof_valid_inputs = 2; + + auto input = std::make_unique(nof_valid_inputs); + for (int i=0; i(t); + + START_TIMER(POSEIDON2_sync) + for (int i = 0; i < iters; ++i) { + ICICLE_CHECK(poseidon2.hash(input.get(), nof_valid_inputs, config, out)); + } + END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); + }; + + std::cout << "Run CPU test " << std::endl; + auto output_cpu = std::make_unique(config.batch); // config.batch = 1 here. + run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); +#if FIELD_ID == BN254 + scalar_t expected_res = + scalar_t::hex_str2scalar("0x2645a6e432f38bb4f197b1b4a69d6fac977cdb4927cfbb62f133a9e427dee146"); + ASSERT_EQ(expected_res, *(output_cpu.get())); +#endif + + if (IcicleTestBase::main_device() == "CUDA") { + std::cout << "Run CUDA test " << std::endl; + auto output_mainDev = std::make_unique(config.batch); + run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); + } +} // poseidon2_3_sponge_1_hasher_without_dt_with_padding + + +// Sponge, chain of 2 hashers, with padding (2 scalars 1,0), no domain tag. +TEST_F(HashApiTest, poseidon2_4_sponge_2_hashers_without_dt_with_padding) +{ + const unsigned t = 4; + auto config = default_hash_config(); + int nof_hashers = 2; + int nof_valid_inputs = 5; + + auto input = std::make_unique(nof_valid_inputs); + for (int i=0; i(t); + + START_TIMER(POSEIDON2_sync) + for (int i = 0; i < iters; ++i) { + ICICLE_CHECK(poseidon2.hash(input.get(), nof_valid_inputs, config, out)); + } + END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); + }; + + std::cout << "Run CPU test " << std::endl; + auto output_cpu = std::make_unique(config.batch); // config.batch = 1 here. + run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); +#if FIELD_ID == BN254 + scalar_t expected_res = + scalar_t::hex_str2scalar("0x0353fae9638ef80c9a80786ce24c42d6e087695a40cd5ca29207f20b72f25379"); + ASSERT_EQ(expected_res, *(output_cpu.get())); #endif -// DEBUG + + if (IcicleTestBase::main_device() == "CUDA") { + std::cout << "Run CUDA test " << std::endl; + auto output_mainDev = std::make_unique(config.batch); + run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); + ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); + } +} // poseidon2_4_sponge_2_hashers_without_dt_with_padding + // Test check single hash without domain tag. TEST_F(HashApiTest, poseidon2_3_single_hash_without_dt) @@ -1294,7 +1472,7 @@ TEST_F(HashApiTest, poseidon2_3_single_hash_without_dt) // // input[i] = scalar_t::from(i % t); // // } // for (int i = 0; i < t; i++) { - // // std::cout << "poseidon2_3_single_hash_cpu_only input " << input[i] << std::endl; + // // std::cout << "poseidon2_3_single_hash_without_dt input " << input[i] << std::endl; // } // // DEBUG @@ -1322,7 +1500,7 @@ TEST_F(HashApiTest, poseidon2_3_single_hash_without_dt) run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); -} +} // poseidon2_3_single_hash_without_dt TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt) { @@ -1366,9 +1544,7 @@ TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt) auto output_mainDev = std::make_unique(1); run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); - // std::cout << "*(output_cpu.get()) = " << std::hex << *(output_cpu.get()) << std::endl; run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); - // std::cout << "*(output_mainDev.get()) = " << std::hex << *(output_mainDev.get()) << std::endl; ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); int a = 5; @@ -1417,9 +1593,7 @@ TEST_F(HashApiTest, poseidon2_3_sponge_hash_1K_without_dt) auto output_mainDev = std::make_unique(1); run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); - // std::cout << "*(output_cpu.get()) = " << std::hex << *(output_cpu.get()) << std::endl; run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); - // std::cout << "*(output_mainDev.get()) = " << std::hex << *(output_mainDev.get()) << std::endl; ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); int a = 5; From 3ec02aee0ad9f1345c7a3a6c0d8f56093de556a7 Mon Sep 17 00:00:00 2001 From: danny-shterman Date: Thu, 30 Jan 2025 09:05:25 +0000 Subject: [PATCH 5/8] Spell checker --- icicle/backend/cpu/src/hash/cpu_poseidon2.cpp | 126 +++++++++--------- .../include/icicle/fields/quartic_extension.h | 2 +- icicle/include/icicle/fields/storage.h | 12 +- icicle/tests/test_hash_api.cpp | 108 +++++++-------- 4 files changed, 125 insertions(+), 123 deletions(-) diff --git a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp index b737d361d..98fc0d9d8 100644 --- a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp +++ b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp @@ -202,21 +202,21 @@ namespace icicle { const unsigned arity = m_use_domain_tag ? m_t - 1 : m_t; bool is_sponge = false; int input_size_in_scalars = size / sizeof(S); - if ((config.batch == 1) && (input_size_in_scalars != (m_use_domain_tag ? m_t - 1 : m_t))) { // Check if sponge function. + if ((config.batch == 1) && (input_size_in_scalars != (m_use_domain_tag ? m_t - 1 : m_t))) { // Check if sponge + // function. is_sponge = true; if (config.batch != 1) { - ICICLE_LOG_ERROR - << "The only suppoorted value of config.batch for sponge functions is 1.\n"; + ICICLE_LOG_ERROR << "The only suppoorted value of config.batch for sponge functions is 1.\n"; return eIcicleError::INVALID_ARGUMENT; } - } // sponge function - else { // Non-sponge function. + } // sponge function + else { // Non-sponge function. if ((m_use_domain_tag ? input_size_in_scalars : input_size_in_scalars - 1) % (m_t - 1) != 0) { - ICICLE_LOG_ERROR - << "Padding isn't supported for non-sponge function hash. The following should be true: ((m_use_domain_tag ? size : size-1) % (m_t-1) != 0).\n"; + ICICLE_LOG_ERROR << "Padding isn't supported for non-sponge function hash. The following should be true: " + "((m_use_domain_tag ? size : size-1) % (m_t-1) != 0).\n"; return eIcicleError::INVALID_ARGUMENT; } - } // Non-sponge function. + } // Non-sponge function. const unsigned int T = m_t; bool is_unsupported_T_for_this_field = poseidon2_constants[T].nof_upper_full_rounds == 0; @@ -234,27 +234,27 @@ namespace icicle { S* partial_matrix_diagonal_m1 = poseidon2_constants[T].partial_matrix_diagonal_m1; // Allocate temporary memory for intermediate calcs and in order not to change the input. - // int sponge_nof_hashers = m_use_domain_tag ? (input_size_in_scalars / arity) : ((input_size_in_scalars - 1) / (arity - 1)); - // int tmp_fields_nof_scalars = is_sponge ? (T * sponge_nof_hashers) : (T * config.batch); - // S* tmp_fields = new S[tmp_fields_nof_scalars]; + // int sponge_nof_hashers = m_use_domain_tag ? (input_size_in_scalars / arity) : ((input_size_in_scalars - 1) / + // (arity - 1)); int tmp_fields_nof_scalars = is_sponge ? (T * sponge_nof_hashers) : (T * config.batch); S* + // tmp_fields = new S[tmp_fields_nof_scalars]; S* tmp_fields; - S* tmp_fields_init_ptr; // This pointer to keep initial tmp_fields value to perform a easy rollback when needed. + S* tmp_fields_init_ptr; // This pointer to keep initial tmp_fields value to perform a easy rollback when needed. int sponge_nof_hashers; const S* in_fields = (S*)(input); int padding_size = 0; S* padding; if (is_sponge) { - if (input_size_in_scalars < T) { // Single hasher in the chain. + if (input_size_in_scalars < T) { // Single hasher in the chain. sponge_nof_hashers = 1; padding_size = T - (input_size_in_scalars + (m_use_domain_tag == true)); - } else if (input_size_in_scalars >= T) { // More than a single hasher in the chain. - sponge_nof_hashers = (input_size_in_scalars - !(m_use_domain_tag == true) + (T - 2)) / (T - 1); - bool is_padding_needed = (input_size_in_scalars - !(m_use_domain_tag == true)) % (T - 1); - if (is_padding_needed ) { + } else if (input_size_in_scalars >= T) { // More than a single hasher in the chain. + sponge_nof_hashers = (input_size_in_scalars - !(m_use_domain_tag == true) + (T - 2)) / (T - 1); + bool is_padding_needed = (input_size_in_scalars - !(m_use_domain_tag == true)) % (T - 1); + if (is_padding_needed) { padding_size = (T - 1) - ((input_size_in_scalars - !(m_use_domain_tag == true)) % (T - 1)); } } - if (padding_size > 0) { // Fill padding array with 1,0,0,... + if (padding_size > 0) { // Fill padding array with 1,0,0,... padding = new S[padding_size]; padding[0] = S::from(1); for (int i = 1; i < padding_size; i++) { @@ -264,48 +264,45 @@ namespace icicle { tmp_fields = new S[T * sponge_nof_hashers]; tmp_fields_init_ptr = tmp_fields; // Take care of hasher 0. It's done separately of the rest of the hashers because of the domain tag. - if (m_use_domain_tag) { + if (m_use_domain_tag) { // Domain tag exists only for the first hasher. For the rest of the hashers this // input is undefined at this stage and its value will be set later. // tmp_fields = {{dt, in0}, {undef, in1}, {undef, in2}, etc.} memcpy(tmp_fields, &m_domain_tag, sizeof(S)); - } - else { + } else { // tmp_fields = {{in0 (T inputs)}, {undef, in1 (T-1 inputs)}, {under, in2 (T-1 inputs)}, etc.} memcpy(tmp_fields, &in_fields[0], sizeof(S)); - in_fields += 1; + in_fields += 1; } - tmp_fields += 1; + tmp_fields += 1; // Take care of rest of the hashers (T-1 scalar to each hasher). for (int hasher_idx = 0; hasher_idx < sponge_nof_hashers; hasher_idx++) { - if (hasher_idx == sponge_nof_hashers-1 && padding_size > 0) { + if (hasher_idx == sponge_nof_hashers - 1 && padding_size > 0) { // Last hasher in the chain. Take care of padding if needed. memcpy(tmp_fields, in_fields, (T - padding_size - 1) * sizeof(S)); memcpy(tmp_fields + T - padding_size - 1, padding, padding_size * sizeof(S)); - } - else { // Not a last hasher in the chain. There is no padding. + } else { // Not a last hasher in the chain. There is no padding. memcpy(tmp_fields, in_fields, (T - 1) * sizeof(S)); } in_fields += (T - 1); tmp_fields += T; } - tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. - } // if (is_sponge) { - else { // Not a sponge function. The is no padding. + tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. + } // if (is_sponge) { + else { // Not a sponge function. The is no padding. // Input of each hash should have domain tag at its input. // tmp_fields = {{dt, in0 (T-1 inputs)}, {dt, in1 (T-1 inputs)}, {dt, in2 (T-1 inputs)}, etc.} tmp_fields = new S[T * config.batch]; - tmp_fields_init_ptr = tmp_fields; // Keep tmp_fields pointer for delete. - if (m_use_domain_tag) { + tmp_fields_init_ptr = tmp_fields; // Keep tmp_fields pointer for delete. + if (m_use_domain_tag) { for (int batch_idx = 0; batch_idx < config.batch; batch_idx++) { memcpy(tmp_fields, &m_domain_tag, sizeof(S)); memcpy(tmp_fields + 1, in_fields, (T - 1) * sizeof(S)); in_fields += (T - 1); tmp_fields += T; } - tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. - } - else { + tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. + } else { // tmp_fields = {{in0 (T inputs)}, {in1 (T inputs)}, {in2 (T inputs)}, etc.} memcpy(tmp_fields, in_fields, T * config.batch * sizeof(S)); } @@ -313,48 +310,47 @@ namespace icicle { // Hashes processing. if (is_sponge) { - // Call hash_single for hasher[0] - eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, - alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, - rounds_constants, mds_matrix, partial_matrix_diagonal_m1); - S* tmp_fields_tmp_ptr = tmp_fields; // Save current pointer in order to access prev output. + // Call hash_single for hasher[0] + eIcicleError err = hash_single( + tmp_fields /* input */, tmp_fields /* output */, alpha, nof_upper_full_rounds, nof_partial_rounds, + nof_bottom_full_rounds, rounds_constants, mds_matrix, partial_matrix_diagonal_m1); + S* tmp_fields_tmp_ptr = tmp_fields; // Save current pointer in order to access prev output. if (err != eIcicleError::SUCCESS) return err; if (sponge_nof_hashers != 1) { - tmp_fields[T] = tmp_fields[0]; // Current first output is an input to the next hasher. + tmp_fields[T] = tmp_fields[0]; // Current first output is an input to the next hasher. } tmp_fields += T; // Process rest of the hashers. - for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { + for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { // The first output of the prev hasher is the first input of the current hasher. // The T-1 new inputs of the current hasher should be added to the T-1 outputs of the // prev hasher (starting fom index 1). for (int i = 1; i < T; i++) { tmp_fields[i] = tmp_fields_tmp_ptr[i] + tmp_fields[i]; } - eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, - alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, - rounds_constants, mds_matrix, partial_matrix_diagonal_m1); - tmp_fields_tmp_ptr = tmp_fields; // Save current pointer in order to access prev output. + eIcicleError err = hash_single( + tmp_fields /* input */, tmp_fields /* output */, alpha, nof_upper_full_rounds, nof_partial_rounds, + nof_bottom_full_rounds, rounds_constants, mds_matrix, partial_matrix_diagonal_m1); + tmp_fields_tmp_ptr = tmp_fields; // Save current pointer in order to access prev output. if (err != eIcicleError::SUCCESS) return err; - if (hasher_idx != sponge_nof_hashers - 1) // Not to do in the last loop to prevent mem leak. - tmp_fields[T] = tmp_fields[0]; // Fill first scalar of the input to the next hasher. - tmp_fields += T; // Now tmp_fields points to input of the next hasher before the addition. - } // for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { - tmp_fields -= T; // Rollback to the last hasher output. + if (hasher_idx != sponge_nof_hashers - 1) // Not to do in the last loop to prevent mem leak. + tmp_fields[T] = tmp_fields[0]; // Fill first scalar of the input to the next hasher. + tmp_fields += T; // Now tmp_fields points to input of the next hasher before the addition. + } // for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { + tmp_fields -= T; // Rollback to the last hasher output. memcpy(output, (std::byte*)(&tmp_fields[1]), sizeof(S)); - tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. - } - else { // Not a sponge function. + tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. + } else { // Not a sponge function. for (int batch_hash_idx = 0; batch_hash_idx < config.batch; batch_hash_idx++) { - eIcicleError err = hash_single(tmp_fields /* input */, tmp_fields /* output */, - alpha, nof_upper_full_rounds, nof_partial_rounds, nof_bottom_full_rounds, - rounds_constants, mds_matrix, partial_matrix_diagonal_m1); + eIcicleError err = hash_single( + tmp_fields /* input */, tmp_fields /* output */, alpha, nof_upper_full_rounds, nof_partial_rounds, + nof_bottom_full_rounds, rounds_constants, mds_matrix, partial_matrix_diagonal_m1); if (err != eIcicleError::SUCCESS) return err; memcpy(output, (std::byte*)(&tmp_fields[1]), sizeof(S)); tmp_fields += T; output += sizeof(S); } - tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. + tmp_fields = tmp_fields_init_ptr; // Rollback to initial value. } delete[] tmp_fields; @@ -362,7 +358,8 @@ namespace icicle { tmp_fields = nullptr; return eIcicleError::SUCCESS; - } // eIcicleError hash(const std::byte* input, uint64_t size, const HashConfig& config, std::byte* output) const override + } // eIcicleError hash(const std::byte* input, uint64_t size, const HashConfig& config, std::byte* output) const + // override private: // // DEBUG start. Do not remove!!! @@ -383,9 +380,16 @@ namespace icicle { // This function performs a single hash according to parameters in the poseidon2_constants[] struct. // eIcicleError hash_single(const std::byte* input, std::byte* output) const - eIcicleError hash_single(S* tmp_fields, S* hasher_output, int alpha, int nof_upper_full_rounds, - int nof_partial_rounds, int nof_bottom_full_rounds, - S* rounds_constants, S* mds_matrix, S* partial_matrix_diagonal_m1) const + eIcicleError hash_single( + S* tmp_fields, + S* hasher_output, + int alpha, + int nof_upper_full_rounds, + int nof_partial_rounds, + int nof_bottom_full_rounds, + S* rounds_constants, + S* mds_matrix, + S* partial_matrix_diagonal_m1) const { const unsigned int T = m_t; diff --git a/icicle/include/icicle/fields/quartic_extension.h b/icicle/include/icicle/fields/quartic_extension.h index 6478e915c..784298cac 100644 --- a/icicle/include/icicle/fields/quartic_extension.h +++ b/icicle/include/icicle/fields/quartic_extension.h @@ -241,7 +241,7 @@ class QuarticExtensionField FF::reduce( (CONFIG::nonresidue_is_negative ? (FF::mul_wide(xs.real, x0) + FF::template mul_unsigned(FF::mul_wide(xs.im2, x2))) - : (FF::mul_wide(xs.real, x0))-FF::template mul_unsigned(FF::mul_wide(xs.im2, x2)))), + : (FF::mul_wide(xs.real, x0)) - FF::template mul_unsigned(FF::mul_wide(xs.im2, x2)))), FF::reduce( (CONFIG::nonresidue_is_negative ? FWide::neg(FF::template mul_unsigned(FF::mul_wide(xs.im3, x2))) diff --git a/icicle/include/icicle/fields/storage.h b/icicle/include/icicle/fields/storage.h index 097db881f..76245db16 100644 --- a/icicle/include/icicle/fields/storage.h +++ b/icicle/include/icicle/fields/storage.h @@ -16,7 +16,8 @@ struct #ifdef __CUDA_ARCH__ __align__(LIMBS_ALIGNMENT(1)) #endif - storage<1> { + storage<1> +{ static constexpr unsigned LC = 1; uint32_t limbs[1]; }; @@ -27,7 +28,8 @@ struct #ifdef __CUDA_ARCH__ __align__(LIMBS_ALIGNMENT(1)) #endif - storage<3> { + storage<3> +{ static constexpr unsigned LC = 3; uint32_t limbs[3]; }; @@ -38,7 +40,8 @@ struct #ifdef __CUDA_ARCH__ __align__(LIMBS_ALIGNMENT(LIMBS_COUNT)) #endif - storage { + storage +{ static_assert(LIMBS_COUNT % 2 == 0, "odd number of limbs is not supported\n"); static constexpr unsigned LC = LIMBS_COUNT; union { // works only with even LIMBS_COUNT @@ -52,6 +55,7 @@ struct #ifdef __CUDA_ARCH__ __align__(LIMBS_ALIGNMENT(LIMBS_COUNT)) #endif - storage_array { + storage_array +{ storage storages[OMEGAS_COUNT]; }; \ No newline at end of file diff --git a/icicle/tests/test_hash_api.cpp b/icicle/tests/test_hash_api.cpp index 0a2eea7f1..8062d825b 100644 --- a/icicle/tests/test_hash_api.cpp +++ b/icicle/tests/test_hash_api.cpp @@ -1150,9 +1150,9 @@ TEST_F(HashApiTest, poseidon_tree) #endif // POSEIDON #ifdef POSEIDON2 -// DEBUG. This test could run only with bn254 curve. Dont remove!!! -// bn254: p = 0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570 -#include "icicle/fields/field_config.h" + // DEBUG. This test could run only with bn254 curve. Dont remove!!! + // bn254: p = 0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570 + #include "icicle/fields/field_config.h" using namespace field_config; TEST_F(HashApiTest, poseidon2_3_single_hasher) { @@ -1161,11 +1161,11 @@ TEST_F(HashApiTest, poseidon2_3_single_hasher) config.batch = 1; auto input = std::make_unique(config.batch * t); - for (int i=0; i(config.batch); run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); -#if FIELD_ID == BN254 + #if FIELD_ID == BN254 scalar_t expected_res = - scalar_t::hex_str2scalar("0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570"); + scalar_t::hex_str2scalar("0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570"); ASSERT_EQ(expected_res, *(output_cpu.get())); -#endif + #endif if (IcicleTestBase::main_device() == "CUDA") { std::cout << "Run CUDA test " << std::endl; @@ -1200,13 +1200,12 @@ TEST_F(HashApiTest, poseidon2_3_single_hasher) ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); std::cout << "End CUDA test " << std::endl; } -} // poseidon2_3_single_hasher - +} // poseidon2_3_single_hasher // Test used to generate expected result of the nd hasher. TEST_F(HashApiTest, poseidon2_3_gen_hasher_expected_result_cpu_only) { -#if FIELD_ID == BN254 + #if FIELD_ID == BN254 const unsigned t = 3; auto config = default_hash_config(); config.batch = 1; @@ -1221,7 +1220,7 @@ TEST_F(HashApiTest, poseidon2_3_gen_hasher_expected_result_cpu_only) input[2] = scalar_t::from(8); // input[3] = scalar_t::from(7); // for (int i = 0; i < t; i++) { - // std::cout << "poseidon2_3_gen_hasher_expected_result_cpu_only input " << input[i] << std::endl; + // std::cout << "poseidon2_3_gen_hasher_expected_result_cpu_only input " << input[i] << std::endl; // } auto run = [&](const std::string& dev_type, scalar_t* out, bool measure, const char* msg, int iters) { @@ -1242,9 +1241,8 @@ TEST_F(HashApiTest, poseidon2_3_gen_hasher_expected_result_cpu_only) auto output_cpu = std::make_unique(config.batch); run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); -#endif -} // poseidon2_3_gen_hasher_expected_result_cpu_only - + #endif +} // poseidon2_3_gen_hasher_expected_result_cpu_only // Sponge, chain of 2 hashers, no padding, no domain tag. TEST_F(HashApiTest, poseidon2_3_sponge_2_hashers_without_dt) @@ -1254,12 +1252,12 @@ TEST_F(HashApiTest, poseidon2_3_sponge_2_hashers_without_dt) int nof_hashers = 2; auto input = std::make_unique(1 + nof_hashers * (t - 1)); - for (int i=0; i(config.batch); // config.batch = 1 here. + auto output_cpu = std::make_unique(config.batch); // config.batch = 1 here. run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); -#if FIELD_ID == BN254 + #if FIELD_ID == BN254 scalar_t expected_res = - scalar_t::hex_str2scalar("0x0d54b4b71781dc4f30afe3a90f76559379f6f75aea6968d4c986512e2711ad20"); + scalar_t::hex_str2scalar("0x0d54b4b71781dc4f30afe3a90f76559379f6f75aea6968d4c986512e2711ad20"); ASSERT_EQ(expected_res, *(output_cpu.get())); -#endif + #endif std::string main_device = IcicleTestBase::main_device(); if (IcicleTestBase::main_device() == "CUDA") { @@ -1298,8 +1296,7 @@ TEST_F(HashApiTest, poseidon2_3_sponge_2_hashers_without_dt) run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); } -} // poseidon2_3_sponge_2_hashers_without_dt - +} // poseidon2_3_sponge_2_hashers_without_dt // Sponge, chain of 2 hashers, no padding, with domain tag. TEST_F(HashApiTest, poseidon2_3_sponge_2_hashers_with_dt) @@ -1314,8 +1311,8 @@ TEST_F(HashApiTest, poseidon2_3_sponge_2_hashers_with_dt) // Input will be 4,5,6,8. // With dt and padding it will be 4,5,6,7,8,1,0. auto input = std::make_unique(nof_valid_inputs); - for (int i=0; i(config.batch); // config.batch = 1 here. + auto output_cpu = std::make_unique(config.batch); // config.batch = 1 here. run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); -#if FIELD_ID == BN254 + #if FIELD_ID == BN254 scalar_t expected_res = - scalar_t::hex_str2scalar("0x286786cd695dbe838456c72a5edb4d2717a17a0971006671c26c0219c3de5abe"); + scalar_t::hex_str2scalar("0x286786cd695dbe838456c72a5edb4d2717a17a0971006671c26c0219c3de5abe"); ASSERT_EQ(expected_res, *(output_cpu.get())); -#endif + #endif if (IcicleTestBase::main_device() == "CUDA") { std::cout << "Run CUDA test " << std::endl; @@ -1352,8 +1349,7 @@ TEST_F(HashApiTest, poseidon2_3_sponge_2_hashers_with_dt) run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); } -} // poseidon2_3_sponge_2_hashers_with_dt - +} // poseidon2_3_sponge_2_hashers_with_dt // Sponge, chain of 1 hasher, with padding (2 scalars 1,0), no domain tag. TEST_F(HashApiTest, poseidon2_3_sponge_1_hasher_without_dt_with_padding) @@ -1364,8 +1360,8 @@ TEST_F(HashApiTest, poseidon2_3_sponge_1_hasher_without_dt_with_padding) int nof_valid_inputs = 2; auto input = std::make_unique(nof_valid_inputs); - for (int i=0; i(config.batch); // config.batch = 1 here. + auto output_cpu = std::make_unique(config.batch); // config.batch = 1 here. run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); -#if FIELD_ID == BN254 + #if FIELD_ID == BN254 scalar_t expected_res = - scalar_t::hex_str2scalar("0x2645a6e432f38bb4f197b1b4a69d6fac977cdb4927cfbb62f133a9e427dee146"); + scalar_t::hex_str2scalar("0x2645a6e432f38bb4f197b1b4a69d6fac977cdb4927cfbb62f133a9e427dee146"); ASSERT_EQ(expected_res, *(output_cpu.get())); -#endif + #endif if (IcicleTestBase::main_device() == "CUDA") { std::cout << "Run CUDA test " << std::endl; @@ -1402,8 +1398,7 @@ TEST_F(HashApiTest, poseidon2_3_sponge_1_hasher_without_dt_with_padding) run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); } -} // poseidon2_3_sponge_1_hasher_without_dt_with_padding - +} // poseidon2_3_sponge_1_hasher_without_dt_with_padding // Sponge, chain of 2 hashers, with padding (2 scalars 1,0), no domain tag. TEST_F(HashApiTest, poseidon2_4_sponge_2_hashers_without_dt_with_padding) @@ -1414,8 +1409,8 @@ TEST_F(HashApiTest, poseidon2_4_sponge_2_hashers_without_dt_with_padding) int nof_valid_inputs = 5; auto input = std::make_unique(nof_valid_inputs); - for (int i=0; i(config.batch); // config.batch = 1 here. + auto output_cpu = std::make_unique(config.batch); // config.batch = 1 here. run(IcicleTestBase::reference_device(), output_cpu.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); -#if FIELD_ID == BN254 + #if FIELD_ID == BN254 scalar_t expected_res = - scalar_t::hex_str2scalar("0x0353fae9638ef80c9a80786ce24c42d6e087695a40cd5ca29207f20b72f25379"); + scalar_t::hex_str2scalar("0x0353fae9638ef80c9a80786ce24c42d6e087695a40cd5ca29207f20b72f25379"); ASSERT_EQ(expected_res, *(output_cpu.get())); -#endif + #endif if (IcicleTestBase::main_device() == "CUDA") { std::cout << "Run CUDA test " << std::endl; @@ -1452,8 +1447,7 @@ TEST_F(HashApiTest, poseidon2_4_sponge_2_hashers_without_dt_with_padding) run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); } -} // poseidon2_4_sponge_2_hashers_without_dt_with_padding - +} // poseidon2_4_sponge_2_hashers_without_dt_with_padding // Test check single hash without domain tag. TEST_F(HashApiTest, poseidon2_3_single_hash_without_dt) @@ -1500,7 +1494,7 @@ TEST_F(HashApiTest, poseidon2_3_single_hash_without_dt) run(IcicleTestBase::main_device(), output_mainDev.get(), VERBOSE /*=measure*/, "poseidon2", ITERS); ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); -} // poseidon2_3_single_hash_without_dt +} // poseidon2_3_single_hash_without_dt TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt) { @@ -1535,7 +1529,7 @@ TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt) START_TIMER(POSEIDON2_sync) for (int i = 0; i < iters; ++i) { - ICICLE_CHECK(poseidon2.hash(input.get(), 1 + nof_hashers * (t-1), config, out)); + ICICLE_CHECK(poseidon2.hash(input.get(), 1 + nof_hashers * (t - 1), config, out)); } END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); }; @@ -1548,13 +1542,13 @@ TEST_F(HashApiTest, poseidon2_3_sponge_hash_2_without_dt) ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); int a = 5; -} // poseidon2_3_sponge_hash_2_without_dt +} // poseidon2_3_sponge_hash_2_without_dt TEST_F(HashApiTest, poseidon2_3_sponge_hash_1K_without_dt) { const unsigned t = 3; auto config = default_hash_config(); - int nof_hashers = 1<<10; + int nof_hashers = 1 << 10; auto input = std::make_unique(1 + nof_hashers * (t - 1)); scalar_t::rand_host_many(input.get(), 1 + nof_hashers * (t - 1)); @@ -1581,10 +1575,10 @@ TEST_F(HashApiTest, poseidon2_3_sponge_hash_1K_without_dt) auto poseidon2 = Poseidon2::create(t); - ICICLE_CHECK(poseidon2.hash(input.get(), 1 + nof_hashers * (t-1), config, out)); + ICICLE_CHECK(poseidon2.hash(input.get(), 1 + nof_hashers * (t - 1), config, out)); START_TIMER(POSEIDON2_sync) for (int i = 0; i < iters; ++i) { - ICICLE_CHECK(poseidon2.hash(input.get(), 1 + nof_hashers * (t-1), config, out)); + ICICLE_CHECK(poseidon2.hash(input.get(), 1 + nof_hashers * (t - 1), config, out)); } END_TIMER(POSEIDON2_sync, oss.str().c_str(), measure); }; @@ -1597,7 +1591,7 @@ TEST_F(HashApiTest, poseidon2_3_sponge_hash_1K_without_dt) ASSERT_EQ(0, memcmp(output_cpu.get(), output_mainDev.get(), config.batch * sizeof(scalar_t))); int a = 5; -} // poseidon2_3_sponge_hash_1K_without_dt +} // poseidon2_3_sponge_hash_1K_without_dt TEST_F(HashApiTest, poseidon2_invalid_t) { From 0ae3d8496945b13b5ac0a9df6e6f5e2942fa4821 Mon Sep 17 00:00:00 2001 From: danny-shterman Date: Thu, 30 Jan 2025 09:35:56 +0000 Subject: [PATCH 6/8] Fix spell checker output --- docs/versioned_docs/version-2.8.0/icicle/primitives/msm.md | 2 +- examples/c++/polynomial-multiplication/example.cpp | 4 ++-- icicle/backend/cpu/src/hash/cpu_poseidon2.cpp | 4 ++-- icicle/tests/test_hash_api.cpp | 2 +- wrappers/rust/icicle-core/src/msm/mod.rs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/versioned_docs/version-2.8.0/icicle/primitives/msm.md b/docs/versioned_docs/version-2.8.0/icicle/primitives/msm.md index 7cb4a0abf..234cbae1c 100644 --- a/docs/versioned_docs/version-2.8.0/icicle/primitives/msm.md +++ b/docs/versioned_docs/version-2.8.0/icicle/primitives/msm.md @@ -79,7 +79,7 @@ The MSM supports batch mode - running multiple MSMs in parallel. It's always bet struct MSMConfig { device_context::DeviceContext ctx; /**< Details related to the device such as its id and stream id. */ int points_size; /**< Number of points in the MSM. If a batch of MSMs needs to be computed, this should be - * a number of different points. So, if each MSM re-uses the same set of points, this + * a number of different points. So, if each MSM reuses the same set of points, this * variable is set equal to the MSM size. And if every MSM uses a distinct set of * points, it should be set to the product of MSM size and [batch_size](@ref * batch_size). Default value: 0 (meaning it's equal to the MSM size). */ diff --git a/examples/c++/polynomial-multiplication/example.cpp b/examples/c++/polynomial-multiplication/example.cpp index bbc50bfa0..6c95ee66b 100644 --- a/examples/c++/polynomial-multiplication/example.cpp +++ b/examples/c++/polynomial-multiplication/example.cpp @@ -23,7 +23,7 @@ void incremental_values(scalar_t* res, uint32_t count) } } -// calcaulting polynomial multiplication A*B via NTT,pointwise-multiplication and INTT +// calculating polynomial multiplication A*B via NTT,pointwise-multiplication and INTT // (1) allocate A,B on HOST. Randomize first half, zero second half // (2) allocate A,B,Res on device // (3) calc NTT for A and for B from host to device @@ -99,4 +99,4 @@ int main(int argc, char** argv) ntt_release_domain(); return 0; -} \ No newline at end of file +} diff --git a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp index 98fc0d9d8..84e665f62 100644 --- a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp +++ b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp @@ -206,7 +206,7 @@ namespace icicle { // function. is_sponge = true; if (config.batch != 1) { - ICICLE_LOG_ERROR << "The only suppoorted value of config.batch for sponge functions is 1.\n"; + ICICLE_LOG_ERROR << "The only supported value of config.batch for sponge functions is 1.\n"; return eIcicleError::INVALID_ARGUMENT; } } // sponge function @@ -324,7 +324,7 @@ namespace icicle { for (int hasher_idx = 1; hasher_idx < sponge_nof_hashers; hasher_idx++) { // The first output of the prev hasher is the first input of the current hasher. // The T-1 new inputs of the current hasher should be added to the T-1 outputs of the - // prev hasher (starting fom index 1). + // prev hasher (starting from index 1). for (int i = 1; i < T; i++) { tmp_fields[i] = tmp_fields_tmp_ptr[i] + tmp_fields[i]; } diff --git a/icicle/tests/test_hash_api.cpp b/icicle/tests/test_hash_api.cpp index 8062d825b..fdedb36b5 100644 --- a/icicle/tests/test_hash_api.cpp +++ b/icicle/tests/test_hash_api.cpp @@ -1202,7 +1202,7 @@ TEST_F(HashApiTest, poseidon2_3_single_hasher) } } // poseidon2_3_single_hasher -// Test used to generate expected result of the nd hasher. +// Test used to generate expected result of any hasher ccording to the parameters inside. TEST_F(HashApiTest, poseidon2_3_gen_hasher_expected_result_cpu_only) { #if FIELD_ID == BN254 diff --git a/wrappers/rust/icicle-core/src/msm/mod.rs b/wrappers/rust/icicle-core/src/msm/mod.rs index 17a4ed1a8..73a2dceb3 100644 --- a/wrappers/rust/icicle-core/src/msm/mod.rs +++ b/wrappers/rust/icicle-core/src/msm/mod.rs @@ -95,7 +95,7 @@ pub trait MSM { /// * `scalars` - scalar values `s1, s2, ..., sn`. /// /// * `bases` - bases `P1, P2, ..., Pn`. The number of bases can be smaller than the number of scalars -/// in the case of batch MSM. In this case bases are re-used periodically. Alternatively, there can be more bases +/// in the case of batch MSM. In this case bases are reused periodically. Alternatively, there can be more bases /// than scalars if precomputation has been performed, you need to set `cfg.precompute_factor` in that case. /// /// * `cfg` - config used to specify extra arguments of the MSM. From ab98d0abf32f0b372f1aff6a7ecd0cfccd9a51e3 Mon Sep 17 00:00:00 2001 From: danny-shterman Date: Thu, 30 Jan 2025 10:51:03 +0000 Subject: [PATCH 7/8] Spell check --- icicle/include/icicle/fields/quartic_extension.h | 2 +- icicle/include/icicle/fields/storage.h | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/icicle/include/icicle/fields/quartic_extension.h b/icicle/include/icicle/fields/quartic_extension.h index 784298cac..6478e915c 100644 --- a/icicle/include/icicle/fields/quartic_extension.h +++ b/icicle/include/icicle/fields/quartic_extension.h @@ -241,7 +241,7 @@ class QuarticExtensionField FF::reduce( (CONFIG::nonresidue_is_negative ? (FF::mul_wide(xs.real, x0) + FF::template mul_unsigned(FF::mul_wide(xs.im2, x2))) - : (FF::mul_wide(xs.real, x0)) - FF::template mul_unsigned(FF::mul_wide(xs.im2, x2)))), + : (FF::mul_wide(xs.real, x0))-FF::template mul_unsigned(FF::mul_wide(xs.im2, x2)))), FF::reduce( (CONFIG::nonresidue_is_negative ? FWide::neg(FF::template mul_unsigned(FF::mul_wide(xs.im3, x2))) diff --git a/icicle/include/icicle/fields/storage.h b/icicle/include/icicle/fields/storage.h index 76245db16..097db881f 100644 --- a/icicle/include/icicle/fields/storage.h +++ b/icicle/include/icicle/fields/storage.h @@ -16,8 +16,7 @@ struct #ifdef __CUDA_ARCH__ __align__(LIMBS_ALIGNMENT(1)) #endif - storage<1> -{ + storage<1> { static constexpr unsigned LC = 1; uint32_t limbs[1]; }; @@ -28,8 +27,7 @@ struct #ifdef __CUDA_ARCH__ __align__(LIMBS_ALIGNMENT(1)) #endif - storage<3> -{ + storage<3> { static constexpr unsigned LC = 3; uint32_t limbs[3]; }; @@ -40,8 +38,7 @@ struct #ifdef __CUDA_ARCH__ __align__(LIMBS_ALIGNMENT(LIMBS_COUNT)) #endif - storage -{ + storage { static_assert(LIMBS_COUNT % 2 == 0, "odd number of limbs is not supported\n"); static constexpr unsigned LC = LIMBS_COUNT; union { // works only with even LIMBS_COUNT @@ -55,7 +52,6 @@ struct #ifdef __CUDA_ARCH__ __align__(LIMBS_ALIGNMENT(LIMBS_COUNT)) #endif - storage_array -{ + storage_array { storage storages[OMEGAS_COUNT]; }; \ No newline at end of file From 1a3d432224a9458d10996c830c118de6cd41f6ce Mon Sep 17 00:00:00 2001 From: danny-shterman Date: Sun, 2 Feb 2025 09:38:18 +0000 Subject: [PATCH 8/8] Remove comments. --- icicle/backend/cpu/src/hash/cpu_poseidon2.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp index 84e665f62..e28bb3a83 100644 --- a/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp +++ b/icicle/backend/cpu/src/hash/cpu_poseidon2.cpp @@ -415,9 +415,6 @@ namespace icicle { memcpy(hasher_output, (std::byte*)(tmp_fields), T * sizeof(S)); // memcpy(output, (std::byte*)(&tmp_fields[1]), sizeof(S)); - // delete[] tmp_fields; - // tmp_fields = nullptr; - return eIcicleError::SUCCESS; } // eIcicleError hash_single(const std::byte* input, std::byte* output) const