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

Rust wrappers for hash and merkle API #614

Merged
merged 25 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
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
32 changes: 16 additions & 16 deletions icicle/backend/cpu/src/hash/cpu_keccak.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ namespace icicle {
class KeccakBackend : public HashBackend
{
public:
KeccakBackend(uint64_t input_chunk_size, uint64_t output_size, uint64_t rate, int padding_const)
: HashBackend(output_size, input_chunk_size)
KeccakBackend(uint64_t input_chunk_size, uint64_t output_size, uint64_t rate, int padding_const, const char* name)
: HashBackend(name, output_size, input_chunk_size)
{
}

eIcicleError hash(const std::byte* input, uint64_t size, const HashConfig& config, std::byte* output) const override
{
ICICLE_LOG_INFO << "Keccak CPU hash() called";
// TODO implement
ICICLE_LOG_DEBUG << "Keccak/sha3 CPU hash() called, batch=" << config.batch
<< ", single_output_size=" << output_size();
// TODO implement real logic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer to add asserion

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes it's just that it will fail in CI. Aviad has a PR for that already.

for (int i = 0; i < output_size() * config.batch; ++i) {
output[i] = std::byte(i % 256);
}
return eIcicleError::SUCCESS;
}
};
Expand All @@ -33,9 +37,10 @@ namespace icicle {
Keccak256Backend(int input_chunk_size)
: KeccakBackend(
input_chunk_size,
KECCAK_256_DIGEST * sizeof(uint64_t) / sizeof(std::byte),
KECCAK_256_DIGEST * sizeof(uint64_t),
KECCAK_256_RATE,
KECCAK_PADDING_CONST)
KECCAK_PADDING_CONST,
"Keccak-256-CPU")
{
}
};
Expand All @@ -46,9 +51,10 @@ namespace icicle {
Keccak512Backend(int input_chunk_size)
: KeccakBackend(
input_chunk_size,
KECCAK_512_DIGEST * sizeof(uint64_t) / sizeof(std::byte),
KECCAK_512_DIGEST * sizeof(uint64_t),
KECCAK_512_RATE,
KECCAK_PADDING_CONST)
KECCAK_PADDING_CONST,
"Keccak-512-CPU")
{
}
};
Expand All @@ -58,10 +64,7 @@ namespace icicle {
public:
Sha3_256Backend(int input_chunk_size)
: KeccakBackend(
input_chunk_size,
KECCAK_256_DIGEST * sizeof(uint64_t) / sizeof(std::byte),
KECCAK_256_RATE,
SHA3_PADDING_CONST)
input_chunk_size, KECCAK_256_DIGEST * sizeof(uint64_t), KECCAK_256_RATE, SHA3_PADDING_CONST, "SHA3-256-CPU")
{
}
};
Expand All @@ -71,10 +74,7 @@ namespace icicle {
public:
Sha3_512Backend(int input_chunk_size)
: KeccakBackend(
input_chunk_size,
KECCAK_512_DIGEST * sizeof(uint64_t) / sizeof(std::byte),
KECCAK_512_RATE,
SHA3_PADDING_CONST)
input_chunk_size, KECCAK_512_DIGEST * sizeof(uint64_t), KECCAK_512_RATE, SHA3_PADDING_CONST, "SHA3-512-CPU")
{
}
};
Expand Down
17 changes: 13 additions & 4 deletions icicle/backend/cpu/src/hash/cpu_merkle_tree.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,21 @@ namespace icicle {
const std::vector<Hash>& layer_hashes, uint64_t leaf_element_size, uint64_t output_store_min_layer = 0)
: MerkleTreeBackend(layer_hashes, leaf_element_size, output_store_min_layer)
{
ICICLE_LOG_DEBUG << "in CPUMerkleTreeBackend, have " << layer_hashes.size() << " layer hashes";
for (const auto& layer_hash : layer_hashes) {
ICICLE_LOG_DEBUG << "layer hash (" << &layer_hash << "), name: " << layer_hash.name();
}
}

eIcicleError build(const std::byte* leaves, uint64_t size, const MerkleTreeConfig& config) override
{
ICICLE_LOG_INFO << "CPU CPUMerkleTreeBackend::build() called with " << size << " bytes of leaves";
ICICLE_LOG_DEBUG << "CPU CPUMerkleTreeBackend::build() called with " << size << " bytes of leaves";
return eIcicleError::SUCCESS; // TODO: Implement tree-building logic
}

std::pair<std::byte*, size_t> get_merkle_root() const override
{
ICICLE_LOG_INFO << "CPU CPUMerkleTreeBackend::get_merkle_root() called";
ICICLE_LOG_DEBUG << "CPU CPUMerkleTreeBackend::get_merkle_root() called";
return {nullptr, 0}; // TODO: Implement root retrieval logic
}

Expand All @@ -31,7 +35,12 @@ namespace icicle {
const MerkleTreeConfig& config,
MerkleProof& merkle_proof) const override
{
ICICLE_LOG_INFO << "CPU CPUMerkleTreeBackend::get_merkle_proof() called for element index " << element_idx;
ICICLE_LOG_DEBUG << "CPU CPUMerkleTreeBackend::get_merkle_proof() called for element index " << element_idx;
// Dummy implementation. TODO implement
uint64_t root = 123;
merkle_proof.allocate(
false /*pruned*/, element_idx, leaves + element_idx * get_leaf_element_size(), get_leaf_element_size(),
(const std::byte*)&root, sizeof(root));
return eIcicleError::SUCCESS; // TODO: Implement proof generation logic
}
};
Expand All @@ -43,7 +52,7 @@ namespace icicle {
uint64_t output_store_min_layer,
std::shared_ptr<MerkleTreeBackend>& backend)
{
ICICLE_LOG_INFO << "Creating CPU MerkleTreeBackend";
ICICLE_LOG_DEBUG << "Creating CPU MerkleTreeBackend";
backend = std::make_shared<CPUMerkleTreeBackend>(layer_hashes, leaf_element_size, output_store_min_layer);
return eIcicleError::SUCCESS;
}
Expand Down
46 changes: 11 additions & 35 deletions icicle/backend/cpu/src/hash/cpu_poseidon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,19 @@

namespace icicle {

template <typename S>
class PoseidonConstantsCPU : PoseidonConstants<S>
{
// TODO add field here
S* m_dummy_poseidon_constant;
};

static eIcicleError cpu_poseidon_init_constants(
const Device& device,
unsigned arity,
unsigned alpha,
unsigned nof_partial_rounds,
unsigned nof_upper_full_rounds,
unsigned nof_end_full_rounds,
const scalar_t* rounds_constants,
const scalar_t* mds_matrix,
const scalar_t* pre_matrix,
const scalar_t* sparse_matrix,
std::shared_ptr<PoseidonConstants<scalar_t>>& constants /*out*/)
static eIcicleError
cpu_poseidon_init_constants(const Device& device, const PoseidonConstantsInitOptions<scalar_t>* options)
{
ICICLE_LOG_INFO << "in cpu_poseidon_init_constants()";
ICICLE_LOG_DEBUG << "in cpu_poseidon_init_constants() for type " << demangle<scalar_t>();
// TODO implement
return eIcicleError::SUCCESS;
}

REGISTER_POSEIDON_INIT_CONSTANTS_BACKEND("CPU", cpu_poseidon_init_constants);

static eIcicleError cpu_poseidon_init_default_constants(
const Device& device, unsigned arity, std::shared_ptr<PoseidonConstants<scalar_t>>& constants /*out*/)
static eIcicleError cpu_poseidon_init_default_constants(const Device& device, const scalar_t& phantom)
{
ICICLE_LOG_INFO << "in cpu_poseidon_init_default_constants()";
ICICLE_LOG_DEBUG << "in cpu_poseidon_init_default_constants() for type " << demangle<scalar_t>();
// TODO implement
return eIcicleError::SUCCESS;
}
Expand All @@ -44,28 +26,22 @@ namespace icicle {
class PoseidonBackendCPU : public HashBackend
{
public:
PoseidonBackendCPU(std::shared_ptr<PoseidonConstants<S>> constants)
: HashBackend(sizeof(S), 0 /*TODO get from constants arity of whatever*/), m_constants{constants}
{
}
PoseidonBackendCPU(unsigned arity) : HashBackend("Poseidon-CPU", sizeof(S), arity * sizeof(S)) {}

eIcicleError hash(const std::byte* input, uint64_t size, const HashConfig& config, std::byte* output) const override
{
ICICLE_LOG_INFO << "Poseidon CPU hash() " << size << " bytes, for type " << demangle<S>();
ICICLE_LOG_DEBUG << "Poseidon CPU hash() " << size << " bytes, for type " << demangle<S>()
<< ", batch=" << config.batch;
// TODO implement
return eIcicleError::SUCCESS;
}

private:
std::shared_ptr<PoseidonConstants<S>> m_constants = nullptr;
};

static eIcicleError create_cpu_poseidon_hash_backend(
const Device& device,
std::shared_ptr<PoseidonConstants<scalar_t>> constants,
std::shared_ptr<HashBackend>& backend /*OUT*/)
const Device& device, unsigned arity, std::shared_ptr<HashBackend>& backend /*OUT*/, const scalar_t& phantom)
{
backend = std::make_shared<PoseidonBackendCPU<scalar_t>>(constants);
ICICLE_LOG_DEBUG << "in create_cpu_poseidon_hash_backend(arity=" << arity << ")";
backend = std::make_shared<PoseidonBackendCPU<scalar_t>>(arity);
return eIcicleError::SUCCESS;
}

Expand Down
2 changes: 2 additions & 0 deletions icicle/cmake/hash.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ function(setup_hash_target)
target_sources(icicle_hash PRIVATE
src/hash/keccak.cpp
src/hash/merkle_tree.cpp
src/hash/hash_c_api.cpp
src/hash/merkle_c_api.cpp
)

target_link_libraries(icicle_hash PUBLIC icicle_device)
Expand Down
2 changes: 1 addition & 1 deletion icicle/cmake/target_editor.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ endfunction()
function(handle_poseidon TARGET FEATURE_LIST)
if(POSEIDON AND "POSEIDON" IN_LIST FEATURE_LIST)
target_compile_definitions(${TARGET} PUBLIC POSEIDON=${POSEIDON})
target_sources(${TARGET} PRIVATE src/hash/poseidon.cpp)
target_sources(${TARGET} PRIVATE src/hash/poseidon.cpp src/hash/poseidon_c_api.cpp)
set(POSEIDON ON CACHE BOOL "Enable POSEIDON feature" FORCE)
else()
set(POSEIDON OFF CACHE BOOL "POSEIDON not available for this field" FORCE)
Expand Down
7 changes: 5 additions & 2 deletions icicle/include/icicle/backend/hash/hash_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ namespace icicle {
* @param output_size The size of the output in bytes.
* @param default_input_chunk_size The default size of a single input chunk in bytes. Useful for Merkle trees.
*/
HashBackend(uint64_t output_size, uint64_t default_input_chunk_size = 0)
: m_output_size{output_size}, m_default_input_chunk_size{default_input_chunk_size}
HashBackend(const char* name, uint64_t output_size, uint64_t default_input_chunk_size = 0)
: m_name_hint(name), m_output_size{output_size}, m_default_input_chunk_size{default_input_chunk_size}
{
}

Expand Down Expand Up @@ -58,9 +58,12 @@ namespace icicle {
*/
uint64_t output_size() const { return m_output_size; }

const std::string& name() { return m_name_hint; }

protected:
const uint64_t m_output_size; ///< The number of output bytes produced by the hash.
const uint64_t m_default_input_chunk_size; ///< Expected input chunk size for hashing operations.
const std::string m_name_hint; ///< Name of hash, for debug purposes

inline uint64_t get_single_chunk_size(uint64_t size_or_zero) const
{
Expand Down
21 changes: 6 additions & 15 deletions icicle/include/icicle/backend/hash/poseidon_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,8 @@ namespace icicle {

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

using InitPoseidonConstantsImpl = std::function<eIcicleError(
const Device& device,
unsigned arity,
unsigned alpha,
unsigned nof_partial_rounds,
unsigned nof_upper_full_rounds,
unsigned nof_end_full_rounds,
const scalar_t* rounds_constants,
const scalar_t* mds_matrix,
const scalar_t* pre_matrix,
const scalar_t* sparse_matrix,
std::shared_ptr<PoseidonConstants<scalar_t>>& constants /*out*/)>;
using InitPoseidonConstantsImpl =
std::function<eIcicleError(const Device& device, const PoseidonConstantsInitOptions<scalar_t>* options)>;

// poseidon init constants
void register_poseidon_init_constants(const std::string& deviceType, InitPoseidonConstantsImpl impl);
Expand All @@ -36,8 +26,9 @@ namespace icicle {
}(); \
}

using InitPoseidonDefaultConstantsImpl = std::function<eIcicleError(
const Device& device, unsigned arity, std::shared_ptr<PoseidonConstants<scalar_t>>& constants /*out*/)>;
// Note: 'phantom' is a workaround for the function required per field but need to differentiate by type when
// calling.
using InitPoseidonDefaultConstantsImpl = std::function<eIcicleError(const Device& device, const scalar_t& phantom)>;

// poseidon init constants
void register_poseidon_init_default_constants(const std::string& deviceType, InitPoseidonDefaultConstantsImpl impl);
Expand All @@ -51,7 +42,7 @@ namespace icicle {
}

using CreatePoseidonImpl = std::function<eIcicleError(
const Device& device, std::shared_ptr<PoseidonConstants<scalar_t>>, std::shared_ptr<HashBackend>& /*OUT*/)>;
const Device& device, unsigned arity, std::shared_ptr<HashBackend>& /*OUT*/, const scalar_t& phantom)>;

// poseidon init constants
void register_create_poseidon(const std::string& deviceType, CreatePoseidonImpl impl);
Expand Down
6 changes: 3 additions & 3 deletions icicle/include/icicle/backend/ntt_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ namespace icicle {
}

/*************************** RELEASE DOMAIN ***************************/
// Note: 'dummy' is a workaround for the function required per field but need to differentiate by type when
// calling. TODO Yuval: avoid this param somehow
using NttReleaseDomainImpl = std::function<eIcicleError(const Device& device, const scalar_t& dummy)>;
// Note: 'phantom' is a workaround for the function required per field but need to differentiate by type when
// calling.
using NttReleaseDomainImpl = std::function<eIcicleError(const Device& device, const scalar_t& phantom)>;

void register_ntt_release_domain(const std::string& deviceType, NttReleaseDomainImpl);

Expand Down
2 changes: 1 addition & 1 deletion icicle/include/icicle/device_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace icicle {
/**
* @brief Enum for specifying the direction of data copy.
*/
enum eCopyDirection { HostToDevice, DeviceToHost, DeviceToDevice };
enum eCopyDirection { HostToDevice, DeviceToHost, DeviceToDevice, HostToHost };

/**
* @brief Typedef for an abstract stream used for asynchronous operations.
Expand Down
2 changes: 1 addition & 1 deletion icicle/include/icicle/fields/host_math.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ namespace host_math {
r = left_shift<NLIMBS_DENOM, 1>(r);
r.limbs[0] |= ((num.limbs[limb_idx] >> bit_idx) & 1);
uint32_t c = add_sub_limbs<NLIMBS_DENOM, true, true, USE_32>(r, denom, temp);
if (limb_idx < NLIMBS_Q & !c) {
if ((limb_idx < NLIMBS_Q) & !c) {
r = temp;
q.limbs[limb_idx] |= 1 << bit_idx;
}
Expand Down
2 changes: 2 additions & 0 deletions icicle/include/icicle/hash/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ namespace icicle {
*/
inline uint64_t output_size() const { return m_backend->output_size(); }

const std::string& name() const { return m_backend->name(); }

private:
std::shared_ptr<HashBackend> m_backend; ///< Shared pointer to the backend performing the hash operation.
};
Expand Down
Loading
Loading