Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Poseidon2 hash function #673

Merged
merged 33 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
37e8fc6
WIP
Nov 20, 2024
98896b6
Working cpu version
Nov 24, 2024
7590f68
WIP
Nov 25, 2024
7d5e10f
WIP
Nov 26, 2024
5f948ee
WIP
Nov 30, 2024
c0bcd95
WIP. Partial rounds work
Nov 30, 2024
e322961
Added tests for poseidon2
Nov 30, 2024
042b45d
Poseidon2 code PR
Dec 3, 2024
9267c00
1. Fix Leon's comments
Dec 4, 2024
101db36
1. Fix PR comments
Dec 4, 2024
0453550
Cotinue to fix PR rejects.
Dec 4, 2024
2f1770d
Conflicts resolve
Dec 5, 2024
ffea645
Merge branch 'main' into danny_poseidon2/v3.2
LeonHibnik Dec 5, 2024
10c9b8c
spelling fix and remove dump file
LeonHibnik Dec 5, 2024
0c6bb4f
add rust tests
LeonHibnik Dec 5, 2024
a7135ec
clang format
LeonHibnik Dec 5, 2024
db8601e
Rename grumkin -> grumpkin
LeonHibnik Dec 5, 2024
2abb571
rename grumkin to grumpkin
LeonHibnik Dec 5, 2024
9d4320d
clang-format
LeonHibnik Dec 5, 2024
769612d
Fix Rust test import
LeonHibnik Dec 5, 2024
3d7bcdb
Fix merge mistakes
LeonHibnik Dec 5, 2024
bf6a0c3
fix merge test hash
yshekel Dec 5, 2024
9ff595d
revert golang formatting
yshekel Dec 5, 2024
145cc15
Fix Rust tests
LeonHibnik Dec 5, 2024
4a17172
cargo fmt
LeonHibnik Dec 5, 2024
c48f478
Fix spelling
LeonHibnik Dec 5, 2024
971d3c9
test unsupported t error message
yshekel Dec 5, 2024
7e8a225
mistake in test
yshekel Dec 5, 2024
613ecff
test all cases but skip large field for t>4
yshekel Dec 5, 2024
b7ce832
add poseidon2 golang support and tests
LeonHibnik Dec 5, 2024
a42c8a3
add tests to golang
LeonHibnik Dec 5, 2024
3241bcc
Update Hash documentation
LeonHibnik Dec 5, 2024
f003886
initialize constants to zero
yshekel Dec 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions icicle/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ option(G2 "Build G2 MSM" ON)
option(EXT_FIELD "Build extension field" ON)
option(HASH "Build hashes and tree builders" ON)
option(POSEIDON "Build poseidon hash" ON)
option(POSEIDON2 "Build poseidon2 hash" ON)
option(SANITIZE "Enable memory address sanitizer" OFF)

# address sanitizer
Expand Down
5 changes: 5 additions & 0 deletions icicle/backend/cpu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ if (FIELD)
endif()
if (POSEIDON)
target_sources(icicle_field PRIVATE src/hash/cpu_poseidon.cpp)
message(STATUS "Building with POSEIDON hash support")
endif()
if (POSEIDON2)
target_sources(icicle_field PRIVATE src/hash/cpu_poseidon2.cpp)
message(STATUS "Building with POSEIDON2 hash support")
endif()
target_include_directories(icicle_field PRIVATE include)
endif() # FIELD
Expand Down
365 changes: 365 additions & 0 deletions icicle/backend/cpu/src/hash/cpu_poseidon2.cpp

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions icicle/cmake/field.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ function(setup_field_target FIELD FIELD_INDEX FEATURES_STRING)
handle_ntt(icicle_field "${FEATURES_LIST}")
handle_ext_field(icicle_field "${FEATURES_LIST}")
handle_poseidon(icicle_field "${FEATURES_LIST}")
handle_poseidon2(icicle_field "${FEATURES_LIST}")
# Add additional feature handling calls here

set_target_properties(icicle_field PROPERTIES OUTPUT_NAME "icicle_field_${FIELD}")
Expand Down
18 changes: 9 additions & 9 deletions icicle/cmake/fields_and_curves.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@
# Define available fields with an index and their supported features
# Format: index:field:features
set(ICICLE_FIELDS
1001:babybear:NTT,EXT_FIELD,POSEIDON
1002:stark252:NTT,POSEIDON
1003:m31:EXT_FIELD,POSEIDON
1001:babybear:NTT,EXT_FIELD,POSEIDON,POSEIDON2
1002:stark252:NTT,POSEIDON,POSEIDON2
1003:m31:EXT_FIELD,POSEIDON,POSEIDON2
)

# Define available curves with an index and their supported features
# Format: index:curve:features
set(ICICLE_CURVES
1:bn254:NTT,MSM,G2,ECNTT,POSEIDON
2:bls12_381:NTT,MSM,G2,ECNTT,POSEIDON
3:bls12_377:NTT,MSM,G2,ECNTT,POSEIDON
4:bw6_761:NTT,MSM,G2,ECNTT,POSEIDON
5:grumpkin:MSM,POSEIDON
)
1:bn254:NTT,MSM,G2,ECNTT,POSEIDON,POSEIDON2
2:bls12_381:NTT,MSM,G2,ECNTT,POSEIDON,POSEIDON2
3:bls12_377:NTT,MSM,G2,ECNTT,POSEIDON,POSEIDON2
4:bw6_761:NTT,MSM,G2,ECNTT,POSEIDON,POSEIDON2
5:grumpkin:MSM,POSEIDON,POSEIDON2
)
10 changes: 10 additions & 0 deletions icicle/cmake/target_editor.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,13 @@ function(handle_poseidon TARGET FEATURE_LIST)
set(POSEIDON OFF CACHE BOOL "POSEIDON not available for this field" FORCE)
endif()
endfunction()

function(handle_poseidon2 TARGET FEATURE_LIST)
if(POSEIDON2 AND "POSEIDON2" IN_LIST FEATURE_LIST)
target_compile_definitions(${TARGET} PUBLIC POSEIDON2=${POSEIDON2})
target_sources(${TARGET} PRIVATE src/hash/poseidon2.cpp src/hash/poseidon2_c_api.cpp)
set(POSEIDON2 ON CACHE BOOL "Enable POSEIDON2 feature" FORCE)
else()
set(POSEIDON2 OFF CACHE BOOL "POSEIDON2 not available for this field" FORCE)
endif()
endfunction()
62 changes: 62 additions & 0 deletions icicle/include/icicle/backend/hash/poseidon2_backend.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#pragma once

#include <functional>
#include "icicle/utils/utils.h"
#include "icicle/device.h"
#include "icicle/hash/poseidon2.h"

#include "icicle/fields/field_config.h"
using namespace field_config;

namespace icicle {

// Options for generating the on-device Poseidon2 constants.
// This struct will hold parameters needed to initialize Poseidon2 constants with custom settings.
// The fields will include:
// - `t`: The t (branching factor) of the Poseidon2 hash.
// - `alpha`: The exponent used in the S-box function.
// - `nof_rounds`: The number of rounds (both full and partial) for the Poseidon2 hash.
// - `mds_matrix`: The Maximum Distance Separable (MDS) matrix used for mixing the state.
// The struct should be FFI (Foreign Function Interface) compatible, meaning it should use basic types or pointers
// that can easily be shared between languages. The template parameter `S` represents the field type for which the
// Poseidon2 constants are being initialized.
template <typename S>
struct Poseidon2ConstantsOptions {
unsigned int t = 0;
unsigned int alpha = 5; ///< Sbox power.
bool use_all_zeroes_padding = true; ///< If true use [0,0,..,0] for padding. Otherwise use [1,0,..,0].
unsigned int nof_upper_full_rounds; ///< Number of upper full rounds of a single hash.
unsigned int nof_partial_rounds; ///< Number of partial rounds of a single hash.
unsigned int nof_bottom_full_rounds; ///< Number of bottom full rounds of a single hash.
S* rounds_constants; ///< Round constants (both of the full and the partial rounds). The order of the constants in
///< the memory is according to the rounds order.
S* mds_matrix; ///> MDS matrix is used in the full rounds. The same matrix is used for all such rounds.
// S* partial_matrix_diagonal; ///< Partial matrix is used in the partial rounds. The same matrix is used for all such rounds.
// ///< Only M[i,i] member are different from 1. These members are here.
S* partial_matrix_diagonal_m1; ///< This partial matrix is used in the partial rounds instead of partial_matrix_diagonal
///< (using this matrix improves the performance of the partial rounds). The same matrix
///< is used for all such rounds. Only M[i,i] member are different from 1.
///< These members are here.
Poseidon2ConstantsOptions() {}
};

/*************************** Backend registration ***************************/

// Note: 'phantom' is a workaround for the function required per field but need to differentiate by type when
// calling.

using CreatePoseidon2Impl = std::function<eIcicleError(
const Device& device, unsigned t, const scalar_t* domain_tag, std::shared_ptr<HashBackend>& /*OUT*/)>;

// poseidon2 init constants
void register_create_poseidon2(const std::string& deviceType, CreatePoseidon2Impl impl);

#define REGISTER_CREATE_POSEIDON2_BACKEND(DEVICE_TYPE, FUNC) \
namespace { \
static bool UNIQUE(_reg_create_poseidon2) = []() -> bool { \
register_create_poseidon2(DEVICE_TYPE, FUNC); \
return true; \
}(); \
}

} // namespace icicle
19 changes: 19 additions & 0 deletions icicle/include/icicle/fields/field.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <random>
#include <sstream>
#include <string>
#include <cassert>

using namespace icicle;

Expand Down Expand Up @@ -82,6 +83,24 @@ class Field
return omega;
}

static HOST_INLINE Field hex_str2scalar(const std::string& in_str) // The input string should be in a hex format - 0xABCD....
{
assert(in_str.substr(0, 2) == "0x" && "The input string is not in hex format!");
danny-shterman marked this conversation as resolved.
Show resolved Hide resolved
std::string tmp_str = in_str.substr(2); // Stript "0x" from the string.
int length = tmp_str.length();
// Split string into chuncks of 8 chars (for uint32_t) and store in scalar storage.
storage<TLC> scalar{};
// for (int str_idx=((int)((length-8)/8))*8, limb_idx = 0; str_idx>=0; str_idx-=8, limb_idx++) { // ((int)((length-8)/8))*8 is for case if length<8.
for (int str_idx=length-8, limb_idx = 0; str_idx>=-7; str_idx-=8, limb_idx++) { // ((int)((length-8)/8))*8 is for case if length<8.
if (str_idx < 0) {
scalar.limbs[limb_idx] = strtoul(tmp_str.substr(0, str_idx+8).c_str(), nullptr, 16);
} else {
scalar.limbs[limb_idx] = strtoul(tmp_str.substr(str_idx, 8).c_str(), nullptr, 16);
}
}
return Field{scalar};
}

static HOST_DEVICE_INLINE Field inv_log_size(uint32_t logn)
{
if (logn == 0) { return Field{CONFIG::one}; }
Expand Down
4 changes: 2 additions & 2 deletions icicle/include/icicle/hash/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace icicle {
* @brief Class representing a high-level hash interface.
*
* This class provides a unified interface for performing hash operations using a
* device-specific backend hash implementation (e.g., Keccak, Blake2, Poseidon).
* device-specific backend hash implementation (e.g., Keccak, Blake2, Poseidon, Poseidon2).
* The actual hashing logic is delegated to the backend, allowing users to work with
* the same interface regardless of the backend.
*/
Expand Down Expand Up @@ -79,4 +79,4 @@ namespace icicle {
std::shared_ptr<HashBackend> m_backend; ///< Shared pointer to the backend performing the hash operation.
};

} // namespace icicle
} // namespace icicle
2 changes: 1 addition & 1 deletion icicle/include/icicle/hash/hash_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace icicle {
*/
struct HashConfig {
icicleStreamHandle stream = nullptr; /**< Stream for asynchronous execution. Default is nullptr. */
uint64_t batch = 1; /**< Number of input chunks to hash in batch. Default is 1. */
uint64_t batch = 1; /**< Number of hashes to perform in parallel (independently). Default is 1. */
bool are_inputs_on_device =
false; /**< True if inputs reside on the device (e.g., GPU), false if on the host (CPU). Default is false. */
bool are_outputs_on_device =
Expand Down
44 changes: 44 additions & 0 deletions icicle/include/icicle/hash/poseidon2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include "icicle/hash/hash.h"

namespace icicle {
/**
* @brief Creates a Poseidon2 hash instance with the specified width and optional domain tag.
*
* This function generates a Poseidon2 hash with customizable parameters to suit various cryptographic
* contexts and use cases. The width parameter (`t`) determines the number of elements in the state,
* influencing the security level and output structure of the hash. The optional `domain_tag` parameter
* enables domain separation, allowing isolation of hash outputs across different contexts or applications.
*
* @param S Represents the type of the field element used by the hash (e.g., a field element class).
*
* @param t The width of the Poseidon2 hash state, representing the number of elements in the hash state.
* Ensure that the selected `t` is compatible with the Poseidon2 implementation
* and use case. Currently supported values are 3, 5, 9, or 12.
*
* @param domain_tag A pointer to an optional domain tag of type `S`. If provided, this tag is used for
* domain separation, isolating hash outputs across different contexts. Passing `nullptr`
* indicates that no domain separation is required, which may be sufficient for general use
* cases where isolation between domains is not needed.
*
* @return Hash An instance of the Poseidon2 hash initialized with the specified parameters, ready
* for hashing operations.
*
* @note The value of `t` should align with the desired security and performance requirements of
* the application. The function may throw an exception or produce undefined behavior if an
* unsupported value for `t` is provided.
*/
template <typename S>
Hash create_poseidon2_hash(unsigned t, const S* domain_tag = nullptr);

// Poseidon2 struct providing a static interface to Poseidon2-related operations.
struct Poseidon2 {
template <typename S>
inline static Hash create(unsigned t, const S* domain_tag = nullptr)
{
return create_poseidon2_hash<S>(t, domain_tag);
}
};

} // namespace icicle
Loading
Loading