Files
icicle/wrappers/rust/icicle-core/src/tree/mod.rs
ChickenLover 7fd9ed1b49 Feat/roman/tree builder (#525)
# Updates:

## Hashing

 - Added SpongeHasher class
 - Can be used to accept any hash function as an argument
 - Absorb and squeeze are now separated
- Memory management is now mostly done by SpongeHasher class, each hash
function only describes permutation kernels

## Tree builder

 - Tree builder is now hash-agnostic. 
 - Tree builder now supports 2D input (matrices)
- Tree builder can now use two different hash functions for layer 0 and
compression layers

## Poseidon1

 - Interface changed to classes
 - Now allows for any alpha
 - Now allows passing constants not in a single vector
 - Now allows for any domain tag
 - Constants are now released upon going out of scope
 - Rust wrappers changed to Poseidon struct
 
 ## Poseidon2
 
 - Interface changed to classes
 - Constants are now released upon going out of scope
 - Rust wrappers changed to Poseidon2 struct
 
## Keccak

 - Added Keccak class which inherits SpongeHasher
 - Now doesn't use gpu registers for storing states
 
 To do:
- [x] Update poseidon1 golang bindings
- [x] Update poseidon1 examples
- [x] Fix poseidon2 cuda test
- [x] Fix poseidon2 merkle tree builder test
- [x] Update keccak class with new design
- [x] Update keccak test
- [x] Check keccak correctness
- [x] Update tree builder rust wrappers
- [x] Leave doc comments

Future work:  
- [ ] Add keccak merkle tree builder externs
- [ ] Add keccak rust tree builder wrappers
- [ ] Write docs
- [ ] Add example
- [ ] Fix device output for tree builder

---------

Co-authored-by: Jeremy Felder <jeremy.felder1@gmail.com>
Co-authored-by: nonam3e <71525212+nonam3e@users.noreply.github.com>
2024-07-11 13:46:25 +07:00

146 lines
4.5 KiB
Rust

use icicle_cuda_runtime::{
device_context::{DeviceContext, DEFAULT_DEVICE_ID},
memory::HostOrDeviceSlice,
};
use crate::hash::SpongeHash;
use crate::{error::IcicleResult, ntt::FieldImpl};
pub mod mmcs;
#[doc(hidden)]
pub mod tests;
/// Struct that encodes Tree Builder parameters to be passed into the [build_merkle_tree](build_merkle_tree) function.
#[repr(C)]
#[derive(Debug, Clone)]
pub struct TreeBuilderConfig<'a> {
/// Details related to the device such as its id and stream id. See [DeviceContext](@ref device_context::DeviceContext).
pub ctx: DeviceContext<'a>,
/// Airty of the tree
pub arity: u32,
/// How many rows of the Merkle tree rows should be written to output. '0' means all of them
pub keep_rows: u32,
/// The size of the output for the bottom layer hash and compression.
/// Will also be equal to the size of the root of the tree. Default value 1
pub digest_elements: u32,
are_inputs_on_device: bool,
are_outputs_on_device: bool,
/// Whether to run build_merkle_tree asynchronously. If set to `true`, TreeBuilder will be non-blocking
/// and you'd need to synchronize it explicitly by running `cudaStreamSynchronize` or `cudaDeviceSynchronize`.
/// If set to `false`, build_merkle_tree will block the current CPU thread.
pub is_async: bool,
}
impl<'a> Default for TreeBuilderConfig<'a> {
fn default() -> Self {
Self::default_for_device(DEFAULT_DEVICE_ID)
}
}
impl<'a> TreeBuilderConfig<'a> {
fn default_for_device(device_id: usize) -> Self {
Self {
ctx: DeviceContext::default_for_device(device_id),
arity: 2,
keep_rows: 0,
digest_elements: 1,
are_inputs_on_device: false,
are_outputs_on_device: false,
is_async: false,
}
}
}
pub fn merkle_tree_digests_len(height: u32, arity: u32, digest_elements: u32) -> usize {
let mut digests_len = 0usize;
let mut row_length = digest_elements as usize;
for _ in 0..height + 1 {
digests_len += row_length;
row_length *= arity as usize;
}
digests_len
}
pub trait FieldTreeBuilder<F, Compression, Sponge>
where
F: FieldImpl,
Compression: SpongeHash<F, F>,
Sponge: SpongeHash<F, F>,
{
fn build_merkle_tree(
leaves: &(impl HostOrDeviceSlice<F> + ?Sized),
digests: &mut (impl HostOrDeviceSlice<F> + ?Sized),
height: usize,
input_block_len: usize,
compression: &Compression,
sponge: &Sponge,
config: &TreeBuilderConfig,
) -> IcicleResult<()>;
}
#[macro_export]
macro_rules! impl_field_tree_builder {
(
$field_prefix:literal,
$field_prefix_ident:ident,
$field:ident,
$field_config:ident,
$tree_builder:ident
) => {
mod $field_prefix_ident {
use super::*;
use icicle_cuda_runtime::error::CudaError;
extern "C" {
#[link_name = concat!($field_prefix, "_build_merkle_tree")]
pub(crate) fn build_merkle_tree(
leaves: *const $field,
digests: *mut $field,
height: u32,
input_block_len: u32,
compression: *const c_void,
sponge: *const c_void,
config: &TreeBuilderConfig,
) -> CudaError;
}
}
struct $tree_builder;
impl<Compression, Sponge> FieldTreeBuilder<$field, Compression, Sponge> for $tree_builder
where
Compression: SpongeHash<$field, $field>,
Sponge: SpongeHash<$field, $field>,
{
fn build_merkle_tree(
leaves: &(impl HostOrDeviceSlice<$field> + ?Sized),
digests: &mut (impl HostOrDeviceSlice<$field> + ?Sized),
height: usize,
input_block_len: usize,
compression: &Compression,
sponge: &Sponge,
config: &TreeBuilderConfig,
) -> IcicleResult<()> {
unsafe {
$field_prefix_ident::build_merkle_tree(
leaves.as_ptr(),
digests.as_mut_ptr(),
height as u32,
input_block_len as u32,
compression.get_handle(),
sponge.get_handle(),
config,
)
.wrap()
}
}
}
};
}