diff --git a/docs/docs/icicle/golang-bindings/keccak.md b/docs/docs/icicle/golang-bindings/keccak.md new file mode 100644 index 000000000..fd81f7adc --- /dev/null +++ b/docs/docs/icicle/golang-bindings/keccak.md @@ -0,0 +1,94 @@ +# Keccak + +## Keccak Example + +```go +package main + +import ( + "encoding/hex" + + "github.com/ingonyama-zk/icicle/v2/wrappers/golang/core" + cr "github.com/ingonyama-zk/icicle/v2/wrappers/golang/cuda_runtime" + "github.com/ingonyama-zk/icicle/v2/wrappers/golang/hash/keccak" +) + +func createHostSliceFromHexString(hexString string) core.HostSlice[uint8] { + byteArray, err := hex.DecodeString(hexString) + if err != nil { + panic("Not a hex string") + } + return core.HostSliceFromElements([]uint8(byteArray)) +} + +func main() { + input := createHostSliceFromHexString("1725b6") + outHost256 := make(core.HostSlice[uint8], 32) + + cfg := keccak.GetDefaultKeccakConfig() + e := keccak.Keccak256(input, int32(input.Len()), 1, outHost256, &cfg) + if e.CudaErrorCode != cr.CudaSuccess { + panic("Keccak256 hashing failed") + } + + outHost512 := make(core.HostSlice[uint8], 64) + e = keccak.Keccak512(input, int32(input.Len()), 1, outHost512, &cfg) + if e.CudaErrorCode != cr.CudaSuccess { + panic("Keccak512 hashing failed") + } + + numberOfBlocks := 3 + outHostBatch256 := make(core.HostSlice[uint8], 32*numberOfBlocks) + e = keccak.Keccak256(input, int32(input.Len()/numberOfBlocks), int32(numberOfBlocks), outHostBatch256, &cfg) + if e.CudaErrorCode != cr.CudaSuccess { + panic("Keccak256 batch hashing failed") + } +} +``` + +## Keccak Methods + +```go +func Keccak256(input core.HostOrDeviceSlice, inputBlockSize, numberOfBlocks int32, output core.HostOrDeviceSlice, config *KeccakConfig) core.IcicleError +func Keccak512(input core.HostOrDeviceSlice, inputBlockSize, numberOfBlocks int32, output core.HostOrDeviceSlice, config *KeccakConfig) core.IcicleError +``` + +### Parameters + +- **`input`**: A slice containing the input data for the Keccak256 hash function. It can reside in either host memory or device memory. +- **`inputBlockSize`**: An integer specifying the size of the input data for a single hash. +- **`numberOfBlocks`**: An integer specifying the number of results in the hash batch. +- **`output`**: A slice where the resulting hash will be stored. This slice can be in host or device memory. +- **`config`**: A pointer to a `KeccakConfig` object, which contains various configuration options for the Keccak256 operation. + +### Return Value + +- **`CudaError`**: Returns a CUDA error code indicating the success or failure of the Keccak256/Keccak512 operation. + +## KeccakConfig + +The `KeccakConfig` structure holds configuration parameters for the Keccak256/Keccak512 operation, allowing customization of its behavior to optimize performance based on the specifics of the operation or the underlying hardware. + +```go +type KeccakConfig struct { + Ctx cr.DeviceContext + areInputsOnDevice bool + areOutputsOnDevice bool + IsAsync bool +} +``` + +### Fields + +- **`Ctx`**: Device context containing details like device id and stream. +- **`areInputsOnDevice`**: Indicates if input data is located on the device. +- **`areOutputsOnDevice`**: Indicates if output hash is stored on the device. +- **`IsAsync`**: If true, runs the Keccak256/Keccak512 operation asynchronously. + +### Default Configuration + +Use `GetDefaultKeccakConfig` to obtain a default configuration, which can then be customized as needed. + +```go +func GetDefaultKeccakConfig() KeccakConfig +``` \ No newline at end of file diff --git a/docs/docs/icicle/primitives/keccak.md b/docs/docs/icicle/primitives/keccak.md new file mode 100644 index 000000000..11beb7a76 --- /dev/null +++ b/docs/docs/icicle/primitives/keccak.md @@ -0,0 +1,22 @@ +# Keccak + +[Keccak](https://keccak.team/files/Keccak-implementation-3.2.pdf) is a cryptographic hash function designed by Guido Bertoni, Joan Daemen, Michaƫl Peeters, and Gilles Van Assche. It was selected as the winner of the NIST hash function competition, becoming the basis for the [SHA-3 standard](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf). + +Keccak operates on a message input of any length and produces a fixed-size hash output. The hash function is built upon the sponge construction, which involves absorbing the input data followed by squeezing out the hash value. + +At its core, Keccak consists of a permutation function operating on a state array. The permutation function employs a round function that operates iteratively on the state array. Each round consists of five main steps: + +- **Theta:** This step introduces diffusion by performing a bitwise XOR operation between the state and a linear combination of its neighboring columns. +- **Rho:** This step performs bit rotation operations on each lane of the state array. +- **Pi:** This step rearranges the positions of the lanes in the state array. +- **Chi:** This step applies a nonlinear mixing operation to each lane of the state array. +- **Iota:** This step introduces a round constant to the state array. + +## Using Keccak + +ICICLE Keccak supports batch hashing, which can be utilized for constructing a merkle tree. + +### Supported Bindings + +- [Golang](https://github.com/ingonyama-zk/icicle/tree/main/wrappers/golang/hash/keccak) +- [Rust](https://github.com/ingonyama-zk/icicle/tree/main/wrappers/rust/icicle-hash) \ No newline at end of file diff --git a/docs/docs/icicle/primitives/overview.md b/docs/docs/icicle/primitives/overview.md index c21add02b..67956f3e2 100644 --- a/docs/docs/icicle/primitives/overview.md +++ b/docs/docs/icicle/primitives/overview.md @@ -8,4 +8,5 @@ This section of the documentation is dedicated to the ICICLE primitives, we will - [MSM](./msm.md) - [NTT](./ntt.md) +- [Keccak Hash](./keccak.md) - [Poseidon Hash](./poseidon.md) diff --git a/docs/docs/icicle/rust-bindings/keccak.md b/docs/docs/icicle/rust-bindings/keccak.md new file mode 100644 index 000000000..a2d648183 --- /dev/null +++ b/docs/docs/icicle/rust-bindings/keccak.md @@ -0,0 +1,96 @@ +# Keccak + +## Keccak Example + +```rust +use icicle_cuda_runtime::memory::{DeviceVec, HostSlice}; +use icicle_hash::keccak::{keccak256, KeccakConfig}; +use rand::{self, Rng}; + +fn main() { + let mut rng = rand::thread_rng(); + let initial_data: Vec = (0..120).map(|_| rng.gen::()).collect(); + println!("initial data: {}", hex::encode(&initial_data)); + let input = HostSlice::::from_slice(initial_data.as_slice()); + let mut output = DeviceVec::::cuda_malloc(32).unwrap(); + + let mut config = KeccakConfig::default(); + keccak256(input, initial_data.len() as i32, 1, &mut output[..], &mut config).expect("Failed to execute keccak256 hashing"); + + let mut output_host = vec![0_u8; 32]; + output.copy_to_host(HostSlice::from_mut_slice(&mut output_host[..])).unwrap(); + + println!("keccak256 result: {}", hex::encode(&output_host)); +} +``` + +## Keccak Methods + +```rust +pub fn keccak256( + input: &(impl HostOrDeviceSlice + ?Sized), + input_block_size: i32, + number_of_blocks: i32, + output: &mut (impl HostOrDeviceSlice + ?Sized), + config: &mut KeccakConfig, +) -> IcicleResult<()> + +pub fn keccak512( + input: &(impl HostOrDeviceSlice + ?Sized), + input_block_size: i32, + number_of_blocks: i32, + output: &mut (impl HostOrDeviceSlice + ?Sized), + config: &mut KeccakConfig, +) -> IcicleResult<()> +``` + +### Parameters + +- **`input`**: A slice containing the input data for the Keccak256 hash function. It can reside in either host memory or device memory. +- **`input_block_size`**: An integer specifying the size of the input data for a single hash. +- **`number_of_blocks`**: An integer specifying the number of results in the hash batch. +- **`output`**: A slice where the resulting hash will be stored. This slice can be in host or device memory. +- **`config`**: A pointer to a `KeccakConfig` object, which contains various configuration options for the Keccak256 operation. + +### Return Value + +- **`IcicleResult`**: Returns a CUDA error code indicating the success or failure of the Keccak256/Keccak512 operation. + +## KeccakConfig + +The `KeccakConfig` structure holds configuration parameters for the Keccak256/Keccak512 operation, allowing customization of its behavior to optimize performance based on the specifics of the operation or the underlying hardware. + +```rust +pub struct KeccakConfig<'a> { + pub ctx: DeviceContext<'a>, + pub are_inputs_on_device: bool, + pub are_outputs_on_device: bool, + pub is_async: bool, +} +``` + +### Fields + +- **`ctx`**: Device context containing details like device id and stream. +- **`are_inputs_on_device`**: Indicates if input data is located on the device. +- **`are_outputs_on_device`**: Indicates if output hash is stored on the device. +- **`is_async`**: If true, runs the Keccak256/Keccak512 operation asynchronously. + +### Usage + +Example initialization with default settings: + +```rust +let default_config = KeccakConfig::default(); +``` + +Customizing the configuration: + +```rust +let custom_config = NTTConfig { + ctx: custom_device_context, + are_inputs_on_device: true, + are_outputs_on_device: true, + is_async: false, +}; +``` \ No newline at end of file diff --git a/docs/sidebars.js b/docs/sidebars.js index e622af9c7..df8015740 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -43,6 +43,11 @@ module.exports = { label: "NTT", id: "icicle/primitives/ntt", }, + { + type: "doc", + label: "Keccak Hash", + id: "icicle/primitives/keccak", + }, { type: "doc", label: "Poseidon Hash", @@ -100,6 +105,11 @@ module.exports = { label: "Vector operations", id: "icicle/golang-bindings/vec-ops", }, + { + type: "doc", + label: "Keccak Hash", + id: "icicle/golang-bindings/keccak", + }, { type: "doc", label: "Multi GPU Support", @@ -147,6 +157,11 @@ module.exports = { label: "Vector operations", id: "icicle/rust-bindings/vec-ops", }, + { + type: "doc", + label: "Keccak Hash", + id: "icicle/rust-bindings/keccak", + }, { type: "doc", label: "Multi GPU Support", diff --git a/wrappers/rust/icicle-hash/src/keccak/mod.rs b/wrappers/rust/icicle-hash/src/keccak/mod.rs index 7d5ea2b61..c24ae7d02 100644 --- a/wrappers/rust/icicle-hash/src/keccak/mod.rs +++ b/wrappers/rust/icicle-hash/src/keccak/mod.rs @@ -16,16 +16,16 @@ pub struct KeccakConfig<'a> { pub ctx: DeviceContext<'a>, /// True if inputs are on device and false if they're on host. Default value: false. - are_inputs_on_device: bool, + pub are_inputs_on_device: bool, /// If true, output is preserved on device, otherwise on host. Default value: false. - are_outputs_on_device: bool, + pub are_outputs_on_device: bool, /// Whether to run the Keccak asynchronously. If set to `true`, the keccak_hash function will be /// non-blocking and you'd need to synchronize it explicitly by running /// `cudaStreamSynchronize` or `cudaDeviceSynchronize`. If set to false, keccak_hash /// function will block the current CPU thread. - is_async: bool, + pub is_async: bool, } impl<'a> Default for KeccakConfig<'a> { @@ -68,8 +68,10 @@ pub fn keccak256( input_block_size: i32, number_of_blocks: i32, output: &mut (impl HostOrDeviceSlice + ?Sized), - config: &KeccakConfig, + config: &mut KeccakConfig, ) -> IcicleResult<()> { + config.are_inputs_on_device = input.is_on_device(); + config.are_outputs_on_device = output.is_on_device(); unsafe { keccak256_cuda( input.as_ptr(), @@ -87,8 +89,10 @@ pub fn keccak512( input_block_size: i32, number_of_blocks: i32, output: &mut (impl HostOrDeviceSlice + ?Sized), - config: &KeccakConfig, + config: &mut KeccakConfig, ) -> IcicleResult<()> { + config.are_inputs_on_device = input.is_on_device(); + config.are_outputs_on_device = output.is_on_device(); unsafe { keccak512_cuda( input.as_ptr(),