Skip to content

Commit

Permalink
implement sumcheck ffi for rust
Browse files Browse the repository at this point in the history
  • Loading branch information
yshekel committed Dec 5, 2024
1 parent 4b346d9 commit 0172d99
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 53 deletions.
24 changes: 22 additions & 2 deletions icicle/include/icicle/sumcheck/sumcheck.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,30 @@

namespace icicle {

/**
* @brief Sumcheck protocol implementation for a given field type.
*
* This class encapsulates the Sumcheck protocol, including its transcript configuration.
*
* @tparam F The field type used in the Sumcheck protocol.
*/
template <typename F>
struct Sumcheck {
class Sumcheck
{
public:
SumcheckTranscriptConfig<F> config;
/**
* @brief Constructs a Sumcheck instance with the given transcript configuration.
* @param transcript_config The configuration for the Sumcheck transcript.
*/
explicit Sumcheck(SumcheckTranscriptConfig<F>&& transcript_config)
: m_transcript_config(std::move(transcript_config))
{
}

// Add public methods for protocol operations, e.g., prove, verify.

private:
SumcheckTranscriptConfig<F> m_transcript_config; ///< Transcript configuration for the protocol.
};

} // namespace icicle
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ namespace icicle {

// Move Constructor
SumcheckTranscriptConfig(SumcheckTranscriptConfig&& other) noexcept
: m_domain_separator_label(std::move(other.m_domain_separator_label)),
: m_hasher(other.m_hasher), m_domain_separator_label(std::move(other.m_domain_separator_label)),
m_round_poly_label(std::move(other.m_round_poly_label)),
m_round_challenge_label(std::move(other.m_round_challenge_label)), m_little_endian(other.m_little_endian),
m_seed_rng(other.m_seed_rng)
Expand Down
69 changes: 65 additions & 4 deletions icicle/src/sumcheck/sumcheck_c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,77 @@

using namespace field_config;

// TODO: Add methods for `prove`, `verify`, and the `proof` struct.

namespace icicle {
extern "C" {

// Define the Sumcheck handle type
typedef Sumcheck<scalar_t> SumcheckHandle;

SumcheckHandle* CONCAT_EXPAND(FIELD, sumcheck_create)()
// Structure to represent the FFI transcript configuration
struct TranscriptConfigFFI {
Hash* hasher;
std::byte* domain_separator_label;
size_t domain_separator_label_len;
std::byte* round_poly_label;
size_t round_poly_label_len;
std::byte* round_challenge_label;
size_t round_challenge_label_len;
bool little_endian;
const scalar_t* seed_rng;
};

/**
* @brief Creates a new Sumcheck instance from the given FFI transcript configuration.
* @param ffi_transcript_config Pointer to the FFI transcript configuration structure.
* @return Pointer to the created Sumcheck instance.
*/
SumcheckHandle* CONCAT_EXPAND(FIELD, sumcheck_create)(const TranscriptConfigFFI* ffi_transcript_config)
{
ICICLE_LOG_INFO << "hello world";
// TODO Yuval update params and implement
return nullptr;
if (!ffi_transcript_config || !ffi_transcript_config->hasher || !ffi_transcript_config->seed_rng) {
ICICLE_LOG_ERROR << "Invalid FFI transcript configuration.";
return nullptr;
}

ICICLE_LOG_DEBUG << "Constructing Sumcheck instance from FFI";

// Convert byte arrays to vectors
std::vector<std::byte> domain_separator_label(
ffi_transcript_config->domain_separator_label,
ffi_transcript_config->domain_separator_label + ffi_transcript_config->domain_separator_label_len);
std::vector<std::byte> round_poly_label(
ffi_transcript_config->round_poly_label,
ffi_transcript_config->round_poly_label + ffi_transcript_config->round_poly_label_len);
std::vector<std::byte> round_challenge_label(
ffi_transcript_config->round_challenge_label,
ffi_transcript_config->round_challenge_label + ffi_transcript_config->round_challenge_label_len);

// Construct the SumcheckTranscriptConfig
SumcheckTranscriptConfig config{*ffi_transcript_config->hasher, std::move(domain_separator_label),
std::move(round_poly_label), std::move(round_challenge_label),
*ffi_transcript_config->seed_rng, ffi_transcript_config->little_endian};

// Create and return the Sumcheck instance
return new Sumcheck<scalar_t>(std::move(config));
}

/**
* @brief Deletes the given Sumcheck instance.
* @param sumcheck_handle Pointer to the Sumcheck instance to be deleted.
* @return eIcicleError indicating the success or failure of the operation.
*/
eIcicleError CONCAT_EXPAND(FIELD, sumcheck_delete)(const SumcheckHandle* sumcheck_handle)
{
if (!sumcheck_handle) {
ICICLE_LOG_ERROR << "Cannot delete a null Sumcheck instance.";
return eIcicleError::INVALID_ARGUMENT;
}

ICICLE_LOG_DEBUG << "Destructing Sumcheck instance from FFI";
delete sumcheck_handle;

return eIcicleError::SUCCESS;
}

} // extern "C"
Expand Down
2 changes: 1 addition & 1 deletion wrappers/rust/icicle-core/src/merkle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ pub struct MerkleTree {
// External C functions
extern "C" {
fn icicle_merkle_tree_create(
layer_hashes: *const MerkleTreeHandle, // expecting c-style-array of those
layer_hashes: *const HasherHandle, // expecting c-style-array of those
layer_hashes_len: u64,
leaf_element_size: u64,
output_store_min_layer: u64,
Expand Down
142 changes: 101 additions & 41 deletions wrappers/rust/icicle-core/src/sumcheck/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ pub mod tests;
use crate::hash::Hasher;
use crate::traits::FieldImpl;
use icicle_runtime::{eIcicleError, memory::HostOrDeviceSlice};
use std::ffi::c_void;

/// Configuration for the Sumcheck protocol's transcript.
pub struct SumcheckTranscriptConfig<'a, S> {
pub hash: &'a Hasher,
pub domain_separator_label: Vec<u8>,
Expand All @@ -13,34 +15,44 @@ pub struct SumcheckTranscriptConfig<'a, S> {
pub little_endian: bool,
pub seed_rng: S,
}
// This trait is implemented on FieldConfig to enable Sumcheck struct to create a sumcheck prover

/// Trait for constructing a Sumcheck prover instance.
pub trait SumcheckConstructor<F> {
// TODO Yuval: instead of returning an 'impl SumcheckOps<F>' I could return a Box<dyn SumcheckOps<F>>.
// This will make it runtime polymorphism but allow the returned object to be stored in a user struct. REQUIRED?
/// Creates a new Sumcheck prover instance.
/// Optionally, consider returning `Box<dyn SumcheckOps<F>>` for runtime polymorphism.
fn new(transcript_config: &SumcheckTranscriptConfig<F>) -> Result<impl SumcheckOps<F>, eIcicleError>;
}

/// Trait for Sumcheck operations, including proving and verification.
pub trait SumcheckOps<F> {
// TODO replace with sumcheck proof type
fn prove(&self, input: &(impl HostOrDeviceSlice<F> + ?Sized)) -> String;
fn prove(&self, input: &(impl HostOrDeviceSlice<F> + ?Sized)) -> String; // TODO: Replace `String` with proof type.
fn verify(&self, proof: &str) -> bool;
}

// This struct is used simply to construct a sumcheck instance that implements sumcheck ops in a generic way
/// Empty struct used to represent Sumcheck operations generically.
pub struct Sumcheck;

/*******************/
impl Sumcheck {
fn new<'a, F: FieldImpl>(
transcript_config: &'a SumcheckTranscriptConfig<'a, F>,
) -> Result<impl SumcheckOps<F> + 'a, eIcicleError>
where
F: FieldImpl,
F::Config: SumcheckConstructor<F>,
{
<<F as FieldImpl>::Config as SumcheckConstructor<F>>::new(&transcript_config)
}
}

impl<'a, S> SumcheckTranscriptConfig<'a, S> {
/// Constructor for `SumcheckTranscriptConfig` with explicit parameters.
impl<'a, F> SumcheckTranscriptConfig<'a, F> {
/// Constructs a new `SumcheckTranscriptConfig` with explicit parameters.
pub fn new(
hash: &'a Hasher,
domain_separator_label: Vec<u8>,
round_poly_label: Vec<u8>,
round_challenge_label: Vec<u8>,
little_endian: bool,
seed_rng: S,
seed_rng: F,
) -> Self {
Self {
hash,
Expand All @@ -52,14 +64,14 @@ impl<'a, S> SumcheckTranscriptConfig<'a, S> {
}
}

/// Convenience constructor for `SumcheckTranscriptConfig` using string labels.
/// Convenience constructor using string labels.
pub fn from_string_labels(
hash: &'a Hasher,
domain_separator_label: &str,
round_poly_label: &str,
round_challenge_label: &str,
little_endian: bool,
seed_rng: S,
seed_rng: F,
) -> Self {
Self {
hash,
Expand All @@ -78,68 +90,116 @@ impl<'a, S> SumcheckTranscriptConfig<'a, S> {
}
}

impl Sumcheck {
fn new<'a, F: FieldImpl>(
transcript_config: &'a SumcheckTranscriptConfig<'a, F>,
) -> Result<impl SumcheckOps<F> + 'a, eIcicleError>
where
F: FieldImpl,
F::Config: SumcheckConstructor<F>,
{
<<F as FieldImpl>::Config as SumcheckConstructor<F>>::new(&transcript_config)
/// Converts `SumcheckTranscriptConfig` to its FFI-compatible equivalent.
#[repr(C)]
pub struct FFISumcheckTranscriptConfig<F> {
hash: *const c_void,
domain_separator_label: *const u8,
domain_separator_label_len: usize,
round_poly_label: *const u8,
round_poly_label_len: usize,
round_challenge_label: *const u8,
round_challenge_label_len: usize,
little_endian: bool,
pub seed_rng: *const F,
}

impl<'a, F> From<&SumcheckTranscriptConfig<'a, F>> for FFISumcheckTranscriptConfig<F>
where
F: FieldImpl,
{
fn from(config: &SumcheckTranscriptConfig<'a, F>) -> Self {
FFISumcheckTranscriptConfig {
hash: config
.hash
.handle,
domain_separator_label: config
.domain_separator_label
.as_ptr(),
domain_separator_label_len: config
.domain_separator_label
.len(),
round_poly_label: config
.round_poly_label
.as_ptr(),
round_poly_label_len: config
.round_poly_label
.len(),
round_challenge_label: config
.round_challenge_label
.as_ptr(),
round_challenge_label_len: config
.round_challenge_label
.len(),
little_endian: config.little_endian,
seed_rng: &config.seed_rng,
}
}
}

/// Macro to implement Sumcheck functionality for a specific field.
#[macro_export]
macro_rules! impl_sumcheck {
(
$field_prefix:literal,
$field_prefix_ident:ident,
$field:ident,
$field_cfg:ident
) => {
use icicle_core::sumcheck::{SumcheckConstructor, SumcheckOps, SumcheckTranscriptConfig};
($field_prefix:literal, $field_prefix_ident:ident, $field:ident, $field_cfg:ident) => {
use icicle_core::sumcheck::{
FFISumcheckTranscriptConfig, SumcheckConstructor, SumcheckOps, SumcheckTranscriptConfig,
};
use icicle_core::traits::FieldImpl;
use icicle_runtime::{eIcicleError, memory::HostOrDeviceSlice};
use std::ffi::c_void;

pub type SumcheckHandle = *const c_void;

pub struct SumcheckInternal {
handle: SumcheckHandle,
}

extern "C" {
#[link_name = concat!($field_prefix, "_sumcheck_create")]
fn create() -> SumcheckHandle;
fn icicle_sumcheck_create(config: *const FFISumcheckTranscriptConfig<$field>) -> SumcheckHandle;

#[link_name = concat!($field_prefix, "_sumcheck_delete")]
fn icicle_sumcheck_delete(handle: SumcheckHandle) -> eIcicleError;
}

impl SumcheckConstructor<$field> for $field_cfg {
fn new(
transcript_config: &SumcheckTranscriptConfig<$field>,
) -> Result<impl SumcheckOps<$field>, eIcicleError> {
let handle: SumcheckHandle = unsafe {
// TODO add params
create()
};
// if handle.is_null() {
// return Err(eIcicleError::UnknownError);
// }
let handle = unsafe { icicle_sumcheck_create(&transcript_config.into()) };
if handle.is_null() {
return Err(eIcicleError::UnknownError);
}
Ok(SumcheckInternal { handle })
}
}

impl SumcheckOps<$field> for SumcheckInternal {
fn prove(&self, input: &(impl HostOrDeviceSlice<$field> + ?Sized)) -> String {
String::from("hello")
fn prove(&self, _input: &(impl HostOrDeviceSlice<$field> + ?Sized)) -> String {
String::from("Proof")
}

fn verify(&self, _: &str) -> bool {
fn verify(&self, _proof: &str) -> bool {
true
}
}

impl Drop for SumcheckInternal {
fn drop(&mut self) {
if !self
.handle
.is_null()
{
unsafe {
let _ = icicle_sumcheck_delete(self.handle);
}
}
}
}
};
}

/// Macro to define tests for a specific field.
#[macro_export]
macro_rules! impl_sumcheck_tests {
($field:ident) => {
Expand All @@ -149,13 +209,13 @@ macro_rules! impl_sumcheck_tests {
#[test]
fn test_sumcheck_transcript_config() {
let hash = Keccak256::new(0).unwrap();
check_sumcheck_transcript_config::<$field>(&hash)
check_sumcheck_transcript_config::<$field>(&hash);
}

#[test]
fn test_sumcheck_simple() {
let hash = Keccak256::new(0).unwrap();
check_sumcheck_simple::<$field>(&hash)
check_sumcheck_simple::<$field>(&hash);
}
};
}
Loading

0 comments on commit 0172d99

Please sign in to comment.