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

GateOps #750

Draft
wants to merge 22 commits into
base: emir/inverse
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 15 additions & 15 deletions docs/docs/icicle/primitives/hash.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +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.

:::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).

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).

:::
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.

:::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).

:::

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

Expand Down Expand Up @@ -177,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)
Expand Down
2 changes: 1 addition & 1 deletion examples/c++/polynomial-multiplication/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,4 @@ int main(int argc, char** argv)
ntt_release_domain<scalar_t>();

return 0;
}
}
9 changes: 5 additions & 4 deletions examples/rust/arkworks-icicle-conversions/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::time::Instant;

use ark_bn254::{Fq, Fr, G1Affine as ArkAffine, G1Projective as ArkProjective};
use ark_ec::{AffineRepr, CurveGroup, VariableBaseMSM};
use ark_ff::{BigInteger, PrimeField};
use ark_ff::{BigInteger, PrimeField, Field};

use icicle_bn254::curve::{G1Affine as IcicleAffine, G1Projective as IcicleProjective, ScalarField as IcicleScalar};
use icicle_core::{
Expand Down Expand Up @@ -69,10 +69,11 @@ fn incremental_ark_projective_points(size: usize) -> Vec<ArkProjective> {
//============================================================================================//
fn from_ark<T, I>(ark: &T) -> I
where
T: PrimeField,
T: Field,
I: FieldImpl,
{
let mut ark_bytes = Vec::with_capacity(T::BigInt::NUM_LIMBS * 8 * T::extension_degree() as usize);

let mut ark_bytes = vec![];
for base_elem in ark.to_base_prime_field_elements() {
ark_bytes.extend_from_slice(
&base_elem
Expand All @@ -85,7 +86,7 @@ where

fn to_ark<T, I>(icicle: &I) -> T
where
T: PrimeField,
T: Field,
I: FieldImpl,
{
T::from_random_bytes(&icicle.to_bytes_le()).unwrap()
Expand Down
1 change: 1 addition & 0 deletions icicle/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ option(HASH "Build hashes and tree builders" ON)
option(POSEIDON "Build poseidon hash" ON)
option(POSEIDON2 "Build poseidon2 hash" ON)
option(SUMCHECK "Build sumcheck" ON)
option(GATEOPS "Build gateops" ON)
option(SANITIZE "Enable memory address sanitizer" OFF)

# address sanitizer
Expand Down
11 changes: 1 addition & 10 deletions icicle/backend/cpu/include/cpu_sumcheck_transcript.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class CpuSumcheckTranscript
std::vector<std::byte> hash_result(hasher.output_size());
hasher.hash(hash_input.data(), hash_input.size(), m_config, hash_result.data());
m_round_idx++;
reduce_hash_result_to_field(m_prev_alpha, hash_result);
m_prev_alpha = S::from(hash_result.data(), hasher.output_size());
return m_prev_alpha;
}

Expand All @@ -56,15 +56,6 @@ class CpuSumcheckTranscript
byte_vec.insert(byte_vec.end(), label.begin(), label.end());
}

// convert a vector of bytes to a field
void reduce_hash_result_to_field(S& alpha, const std::vector<std::byte>& hash_result)
{
alpha = S::zero();
const int nof_bytes_to_copy = std::min(sizeof(alpha), hash_result.size());
memcpy(&alpha, hash_result.data(), nof_bytes_to_copy);
alpha = alpha * S::one();
}

// append an integer uint32_t to hash input
void append_u32(std::vector<std::byte>& byte_vec, const uint32_t data)
{
Expand Down
23 changes: 22 additions & 1 deletion icicle/backend/cpu/src/field/cpu_vec_ops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ enum VecOperation {
VECTOR_MUL,
VECTOR_DIV,
VECTOR_INV,
VECTOR_INPLACE_INV,
CONVERT_TO_MONTGOMERY,
CONVERT_FROM_MONTGOMERY,
VECTOR_SUM,
Expand Down Expand Up @@ -453,7 +454,7 @@ cpu_vector_accumulate(const Device& device, T* vec_a, const T* vec_b, uint64_t s
return cpu_2vectors_op(VecOperation::VECTOR_ADD, vec_a, vec_b, size, config, vec_a);
}

REGISTER_VECTOR_ACCUMULATE_BACKEND("CPU", cpu_vector_accumulate<scalar_t>);
REGISTER_VECTOR_MUL_ACCUMULATE_BACKEND("CPU", cpu_vector_accumulate<scalar_t>);

/*********************************** SUB ***********************************/
template <typename T>
Expand All @@ -475,6 +476,16 @@ eIcicleError cpu_vector_mul(

REGISTER_VECTOR_MUL_BACKEND("CPU", (cpu_vector_mul<scalar_t, scalar_t>));

/*********************************** MUL ACCUMULATE ***********************************/
template <typename T>
eIcicleError
cpu_vector_mul_accumulate(const Device& device, T* vec_a, const T* vec_b, uint64_t size, const VecOpsConfig& config)
{
return cpu_2vectors_op(VecOperation::VECTOR_MUL, vec_a, vec_b, size, config, vec_a);
}

REGISTER_VECTOR_ACCUMULATE_BACKEND("CPU", cpu_vector_mul_accumulate<scalar_t>);

/*********************************** DIV ***********************************/
template <typename T>
eIcicleError cpu_vector_div(
Expand All @@ -494,6 +505,15 @@ eIcicleError cpu_vector_inv(const Device& device, const T* vec_a, uint64_t size,

REGISTER_VECTOR_INV_BACKEND("CPU", cpu_vector_inv<scalar_t>);

/*********************************** INPLACE INV ***********************************/
template <typename T>
eIcicleError cpu_vector_inplace_inv(const Device& device, T* vec_a, uint64_t size, const VecOpsConfig& config)
{
return cpu_2vectors_op(VecOperation::VECTOR_INPLACE_INV, vec_a, vec_a, size, config, vec_a);
}

REGISTER_VECTOR_INPLACE_INV_BACKEND("CPU", cpu_vector_inplace_inv<scalar_t>);

/*********************************** CONVERT MONTGOMERY ***********************************/
template <typename T>
eIcicleError cpu_convert_montgomery(
Expand Down Expand Up @@ -1015,6 +1035,7 @@ REGISTER_VECTOR_ADD_EXT_FIELD_BACKEND("CPU", cpu_vector_add<extension_t>);
REGISTER_VECTOR_ACCUMULATE_EXT_FIELD_BACKEND("CPU", cpu_vector_accumulate<extension_t>);
REGISTER_VECTOR_SUB_EXT_FIELD_BACKEND("CPU", cpu_vector_sub<extension_t>);
REGISTER_VECTOR_MUL_EXT_FIELD_BACKEND("CPU", (cpu_vector_mul<extension_t, extension_t>));
REGISTER_VECTOR_MUL_ACCUMULATE_EXT_FIELD_BACKEND("CPU", (cpu_vector_mul_accumulate<extension_t, extension_t>));
REGISTER_VECTOR_MIXED_MUL_BACKEND("CPU", (cpu_vector_mul<extension_t, scalar_t>));
REGISTER_VECTOR_DIV_EXT_FIELD_BACKEND("CPU", cpu_vector_div<extension_t>);
REGISTER_VECTOR_INV_EXT_FIELD_BACKEND("CPU", cpu_vector_inv<extension_t>);
Expand Down
Loading