From 0655ecf39fad55489bc137d791b2bb64cbbc7fc9 Mon Sep 17 00:00:00 2001 From: jacobkaufmann Date: Wed, 27 Mar 2024 14:28:41 -0600 Subject: [PATCH] feat: add C bindings for KZG functions --- Cargo.toml | 3 ++ build.rs | 19 +++++++++++++ kateth.h | 52 +++++++++++++++++++++++++++++++++++ src/blob.rs | 2 ++ src/bls.rs | 1 + src/ffi.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/math.rs | 4 +-- 8 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 build.rs create mode 100644 kateth.h create mode 100644 src/ffi.rs diff --git a/Cargo.toml b/Cargo.toml index eae4e50..dbc9ffa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,9 @@ serde_yaml = { version = "0.9.25", optional = true } criterion = "0.5.1" rand = "0.8.5" +[build-dependencies] +cbindgen = "0.26.0" + [features] default = [] rand = ["dep:rand"] diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..04c8f38 --- /dev/null +++ b/build.rs @@ -0,0 +1,19 @@ +extern crate cbindgen; + +use std::env; + +fn main() { + let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); + let mut config = cbindgen::Config::default(); + config.autogen_warning = + Some("/* WARNING: this file was auto-generated by cbindgen. do not modify. */".into()); + config.tab_width = 4; + + cbindgen::Builder::new() + .with_crate(crate_dir) + .with_language(cbindgen::Language::C) + .with_cpp_compat(false) + .generate() + .expect("cbindgen unable to generate C bindings") + .write_to_file("kateth.h"); +} diff --git a/kateth.h b/kateth.h new file mode 100644 index 0000000..c7a7674 --- /dev/null +++ b/kateth.h @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +typedef struct Setup_4096__65 Setup_4096__65; + +typedef P1 Proof; + +typedef blst_fr Fr; +#define Fr_BITS 256 +#define Fr_BYTES (Fr_BITS / 8) + +typedef struct KzgProofAndEval { + Proof proof; + Fr eval; +} KzgProofAndEval; + +typedef struct Setup_4096__65 EthSetup; + +typedef uint8_t EthBlob[131072]; + +typedef uint8_t Bytes32[32]; + +typedef uint8_t Bytes48[48]; + +typedef P1 Commitment; + +struct KzgProofAndEval compute_kzg_proof(const EthSetup *setup, + const EthBlob *blob, + const Bytes32 *z); + +bool verify_kzg_proof(const EthSetup *setup, + const Bytes48 *commitment, + const Bytes32 *z, + const Bytes32 *y, + const Bytes48 *proof); + +Commitment blob_to_kzg_commitment(const EthSetup *setup, const EthBlob *blob); + +Proof compute_blob_kzg_proof(const EthSetup *setup, const EthBlob *blob, const Bytes48 *commitment); + +bool verify_blob_kzg_proof(const EthSetup *setup, + const EthBlob *blob, + const Bytes48 *commitment, + const Bytes48 *proof); + +bool verify_blob_kzg_proof_batch(const EthSetup *setup, + const EthBlob *blobs, + const Bytes48 *commitments, + const Bytes48 *proofs, + uintptr_t n); diff --git a/src/blob.rs b/src/blob.rs index efebf2b..083a326 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -16,11 +16,13 @@ impl From for Error { } #[derive(Clone, Debug)] +#[repr(C)] pub struct Blob { pub(crate) elements: Box<[Fr; N]>, } impl Blob { + /// cbindgen:no-export pub const BYTES: usize = Fr::BYTES * N; pub fn from_slice(bytes: impl AsRef<[u8]>) -> Result { diff --git a/src/bls.rs b/src/bls.rs index 2a338a0..4aac67f 100644 --- a/src/bls.rs +++ b/src/bls.rs @@ -76,6 +76,7 @@ pub trait Decompress: Sized { } #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +#[repr(transparent)] pub struct Fr { element: blst_fr, } diff --git a/src/ffi.rs b/src/ffi.rs new file mode 100644 index 0000000..2cb360b --- /dev/null +++ b/src/ffi.rs @@ -0,0 +1,79 @@ +use core::slice; + +use crate::{ + bls::Fr, + kzg::{Bytes32, Bytes48, Commitment, Proof, Setup}, +}; + +pub type EthBlob = [u8; 131072]; + +#[repr(transparent)] +pub struct EthSetup(Setup<4096, 65>); + +#[repr(C)] +pub struct KzgProofAndEval { + proof: Proof, + eval: Fr, +} + +#[no_mangle] +pub extern "C" fn compute_kzg_proof( + setup: &EthSetup, + blob: &EthBlob, + z: &Bytes32, +) -> KzgProofAndEval { + let (proof, eval) = setup.0.proof(blob, z).unwrap(); + KzgProofAndEval { proof, eval } +} + +#[no_mangle] +pub extern "C" fn verify_kzg_proof( + setup: &EthSetup, + commitment: &Bytes48, + z: &Bytes32, + y: &Bytes32, + proof: &Bytes48, +) -> bool { + setup.0.verify_proof(proof, commitment, z, y).unwrap() +} + +#[no_mangle] +pub extern "C" fn blob_to_kzg_commitment(setup: &EthSetup, blob: &EthBlob) -> Commitment { + setup.0.blob_to_commitment(blob).unwrap() +} + +#[no_mangle] +pub extern "C" fn compute_blob_kzg_proof( + setup: &EthSetup, + blob: &EthBlob, + commitment: &Bytes48, +) -> Proof { + setup.0.blob_proof(blob, commitment).unwrap() +} + +#[no_mangle] +pub extern "C" fn verify_blob_kzg_proof( + setup: &EthSetup, + blob: &EthBlob, + commitment: &Bytes48, + proof: &Bytes48, +) -> bool { + setup.0.verify_blob_proof(blob, commitment, proof).unwrap() +} + +#[no_mangle] +pub extern "C" fn verify_blob_kzg_proof_batch( + setup: &EthSetup, + blobs: *const EthBlob, + commitments: *const Bytes48, + proofs: *const Bytes48, + n: usize, +) -> bool { + let blobs = unsafe { slice::from_raw_parts(blobs, n) }; + let commitments = unsafe { slice::from_raw_parts(commitments, n) }; + let proofs = unsafe { slice::from_raw_parts(proofs, n) }; + setup + .0 + .verify_blob_proof_batch(blobs, commitments, proofs) + .unwrap() +} diff --git a/src/lib.rs b/src/lib.rs index 4d9b1c0..e2a5d59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ mod bls; mod bytes; +mod ffi; mod math; pub use bls::{Compress, Decompress}; diff --git a/src/math.rs b/src/math.rs index 54e22d7..59e879f 100644 --- a/src/math.rs +++ b/src/math.rs @@ -31,7 +31,7 @@ pub fn roots_of_unity() -> [Fr; ORDER] { /// # Panics /// /// This function will panic if the length of `elements` is not a power of 2. -pub(crate) fn bit_reversal_permutation(elements: impl AsRef<[T]>) -> Vec +pub fn bit_reversal_permutation(elements: impl AsRef<[T]>) -> Vec where T: Copy, { @@ -50,7 +50,7 @@ where /// This function will panic if the length of `elements` is not equal to `N`. /// /// This function will panic if the length of `elements` is not a power of 2. -pub(crate) fn bit_reversal_permutation_boxed_array( +pub fn bit_reversal_permutation_boxed_array( elements: impl AsRef<[T]>, ) -> Box<[T; N]> where