Skip to content

Commit

Permalink
Headers for C API for EIP4844
Browse files Browse the repository at this point in the history
  • Loading branch information
mratsim committed Nov 26, 2023
1 parent 19cd5ef commit ce8e665
Show file tree
Hide file tree
Showing 6 changed files with 236 additions and 16 deletions.
1 change: 1 addition & 0 deletions bindings/lib_constantine.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import
./lib_hashes,
./lib_curves,
../constantine/csprngs,
# Protocols
../constantine/ethereum_bls_signatures,
../constantine/ethereum_eip4844_kzg
10 changes: 10 additions & 0 deletions constantine/csprngs.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Constantine
# Copyright (c) 2018-2019 Status Research & Development GmbH
# Copyright (c) 2020-Present Mamy André-Ratsimbazafy
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.

import csprngs/sysrand
export sysrand
39 changes: 23 additions & 16 deletions constantine/csprngs/sysrand.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
type
CSPRNG = object

const prefix_ffi = "ctt_csprng_"
import ../zoo_exports

when defined(windows):
# There are several Windows CSPRNG APIs:
# - CryptGenRandom
Expand Down Expand Up @@ -51,9 +54,10 @@ when defined(windows):
# BOOLEAN (to not be confused with winapi BOOL)
# is `typedef BYTE BOOLEAN;` and so has the same representation as Nim bools.

proc sysrand*[T](buffer: var T): bool {.inline.} =
proc sysrand*(buffer: pointer, len: csize_t): bool {.libPrefix: prefix_ffi.} =
## Fills the buffer with cryptographically secure random data
return RtlGenRandom(buffer.addr, culong sizeof(T))
## Returns true on success, false otherwise
return RtlGenRandom(buffer.addr, culong len)

elif defined(linux):
proc syscall(sysno: clong): cint {.importc, header:"<unistd.h>", varargs.}
Expand All @@ -75,13 +79,14 @@ elif defined(linux):
#
# We choose to handle partial buffer fills to limit the number of syscalls

proc urandom(pbuffer: pointer, len: int): bool {.sideeffect, tags: [CSPRNG].} =

var cur = 0
proc sysrand*(buffer: pointer, len: csize_t): bool {.libPrefix: prefix_ffi, sideeffect, tags: [CSPRNG].} =
## Fills the buffer with cryptographically secure random data
## Returns true on success, false otherwise
var cur = csize_t 0
while cur < len:
let bytesRead = syscall(SYS_getrandom, pbuffer, len-cur, 0)
let bytesRead = syscall(SYS_getrandom, buffer, len-cur, 0)
if bytesRead > 0:
cur += bytesRead
cur += csize_t bytesRead
elif bytesRead == 0:
# According to documentation this should never happen,
# either we read a positive number of bytes, or we have a negative error code
Expand All @@ -96,11 +101,7 @@ elif defined(linux):

return true

proc sysrand*[T](buffer: var T): bool {.inline.} =
## Fills the buffer with cryptographically secure random data
return urandom(buffer.addr, sizeof(T))

elif defined(ios) or defined(macosx):
elif defined(ios) or defined(macosx) or defined(macos):
# There are 4 APIs we can use
# - The getentropy(2) system call (similar to OpenBSD)
# - The random device (/dev/random)
Expand Down Expand Up @@ -129,14 +130,20 @@ elif defined(ios) or defined(macosx):

func `==`(x, y: CCRNGStatus): bool {.borrow.}

proc CCRandomGenerateBytes(pbuffer: pointer, len: int): CCRNGStatus {.sideeffect, tags: [CSPRNG], importc, header: "<CommonCrypto/CommonRandom.h>".}
proc CCRandomGenerateBytes(pbuffer: pointer, len: csize_t): CCRNGStatus {.sideeffect, tags: [CSPRNG], importc, header: "<CommonCrypto/CommonRandom.h>".}
# https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60178.40.2/include/CommonRandom.h.auto.html

proc sysrand*[T](buffer: var T): bool {.inline.} =
proc sysrand*[T](buffer: pointer, len: csize_t): bool {.libPrefix: prefix_ffi.} =
## Fills the buffer with cryptographically secure random data
if kCCSuccess == CCRandomGenerateBytes(buffer.addr, sizeof(T)):
## Returns true on success, false otherwise
if kCCSuccess == CCRandomGenerateBytes(buffer.addr, len):
return true
return false

else:
{.error: "The OS '" & $hostOS & "' has no CSPRNG configured.".}
{.error: "The OS '" & $hostOS & "' has no CSPRNG configured.".}

proc sysrand*[T](buffer: var T): bool {.inline.} =
## Fills the buffer with cryptographically secure random data
## Returns true on success, false otherwise
return sysrand(buffer.addr, csize_t sizeof(T))
4 changes: 4 additions & 0 deletions include/constantine.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
// Hash functions
#include "constantine/hashes/sha256.h"

// Cryptographically Secure Random Number Generators
#include "constantine/csprngs/sysrand.h"

// Curves
#include "constantine/curves/bls12_381.h"
#include "constantine/curves/bn254_snarks.h"
Expand All @@ -20,5 +23,6 @@

// Protocols
#include "constantine/protocols/ethereum_bls_signatures.h"
#include "constantine/protocols/ethereum_kzg4844.h"

#endif
24 changes: 24 additions & 0 deletions include/constantine/csprngs/sysrand.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/** Constantine
* Copyright (c) 2018-2019 Status Research & Development GmbH
* Copyright (c) 2020-Present Mamy André-Ratsimbazafy
* Licensed and distributed under either of
* * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
* * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
* at your option. This file may not be copied, modified, or distributed except according to those terms.
*/
#ifndef __CTT_H_SYSRAND__
#define __CTT_H_SYSRAND__

#include "constantine/core/datatypes.h"

#ifdef __cplusplus
extern "C" {
#endif

ctt_bool ctt_csprng_sysrand(void* buffer, size_t len);

#ifdef __cplusplus
}
#endif

#endif
174 changes: 174 additions & 0 deletions include/constantine/protocols/ethereum_kzg4844.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@

/** Constantine
* Copyright (c) 2018-2019 Status Research & Development GmbH
* Copyright (c) 2020-Present Mamy André-Ratsimbazafy
* Licensed and distributed under either of
* * MIT license (license terms in the root directory or at http://opensource.org/licenses/MIT).
* * Apache v2 license (license terms in the root directory or at http://www.apache.org/licenses/LICENSE-2.0).
* at your option. This file may not be copied, modified, or distributed except according to those terms.
*/
#ifndef __CTT_H_ETHEREUM_KZG_4844__
#define __CTT_H_ETHEREUM_KZG_4844__

#include "constantine/core/datatypes.h"

#ifdef __cplusplus
extern "C" {
#endif

// Ethereum EIP-4844 KZG types
// ------------------------------------------------------------------------------------------------

#define BYTES_PER_COMMITMENT 48
#define BYTES_PER_PROOF 48
#define BYTES_PER_FIELD_ELEMENT 32
#define FIELD_ELEMENTS_PER_BLOB 4096
#define BYTES_PER_BLOB (FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT)

typedef struct ctt_eth_kzg4844_commitment { byte raw[BYTES_PER_COMMITMENT]; } ctt_eth_kzg4844_commitment;
typedef struct ctt_eth_kzg4844_proof { byte raw[BYTES_PER_PROOF]; } ctt_eth_kzg4844_proof;
typedef struct ctt_eth_kzg4844_blob { byte raw[BYTES_PER_BLOB]; } ctt_eth_kzg4844_blob;
typedef struct ctt_eth_kzg4844_challenge { byte raw[BYTES_PER_FIELD_ELEMENT]; } ctt_eth_kzg4844_challenge;
typedef struct ctt_eth_kzg4844_eval_at_challenge { byte raw[BYTES_PER_FIELD_ELEMENT]; } ctt_eth_kzg4844_eval_at_challenge;

typedef enum __attribute__((__packed__)) {
cttEthKzg_Success,
cttEthKzg_VerificationFailure,
cttEthKzg_ScalarZero,
cttEthKzg_ScalarLargerThanCurveOrder,
cttEthKzg_EccInvalidEncoding,
cttEthKzg_EccCoordinateGreaterThanOrEqualModulus,
cttEthKzg_EccPointNotOnCurve,
cttEthKzg_EccPointNotInSubgroup,
} ctt_eth_kzg4844_status;

static const char* ctt_eth_kzg4844_status_to_string(ctt_eth_kzg4844_status status) {
static const char* const statuses[] = {
"cttEthKzg_Success",
"cttEthKzg_VerificationFailure",
"cttEthKzg_ScalarZero",
"cttEthKzg_ScalarLargerThanCurveOrder",
"cttEthKzg_EccInvalidEncoding",
"cttEthKzg_EccCoordinateGreaterThanOrEqualModulus",
"cttEthKzg_EccPointNotOnCurve",
"cttEthKzg_EccPointNotInSubgroup",
};
size_t length = sizeof statuses / sizeof *statuses;
if (0 <= status && status < length) {
return statuses[status];
}
return "cttEthKzg_InvalidStatusCode";
}

typedef struct ctt_eth_kzg4844_context_struct ctt_eth_kzg4844_context;


// Ethereum EIP-4844 KZG Interface
// ------------------------------------------------------------------------------------------------

/** Compute a commitment to the `blob`.
* The commitment can be verified without needing the full `blob`
*
* Mathematical description
* commitment = [p(τ)]₁
*
* The blob data is used as a polynomial,
* the polynomial is evaluated at powers of tau τ, a trusted setup.
*
* Verification can be done by verifying the relation:
* proof.(τ - z) = p(τ)-p(z)
* which doesn't require the full blob but only evaluations of it
* - at τ, p(τ) is the commitment
* - and at the verification challenge z.
*/
ctt_eth_kzg4844_status ctt_eth_kzg4844_blob_to_kzg_commitment(
const ctt_eth_kzg4844_context* ctx,
ctt_eth_kzg4844_commitment* dst,
const ctt_eth_kzg4844_blob* blob
);

/** Generate:
* - A proof of correct evaluation.
* - y = p(z), the evaluation of p at the challenge z, with p being the Blob interpreted as a polynomial.
*
* Mathematical description
* [proof]₁ = [(p(τ) - p(z)) / (τ-z)]₁, with p(τ) being the commitment, i.e. the evaluation of p at the powers of τ
* The notation [a]₁ corresponds to the scalar multiplication of a by the generator of 𝔾1
*
* Verification can be done by verifying the relation:
* proof.(τ - z) = p(τ)-p(z)
* which doesn't require the full blob but only evaluations of it
* - at τ, p(τ) is the commitment
*/
ctt_eth_kzg4844_status ctt_eth_kzg4844_compute_kzg_proof(
const ctt_eth_kzg4844_context* ctx,
ctt_eth_kzg4844_proof* proof,
ctt_eth_kzg4844_eval_at_challenge* y,
const ctt_eth_kzg4844_blob* blob,
const ctt_eth_kzg4844_challenge* z
);

/** Verify KZG proof
* that p(z) == y where
* - z is a random challenge
* - y is the evaluation of the "KZG polynomial" p at z
* - commitment is p(τ), the evaluation of p at the trusted setup τ,
* - [proof]₁ = [(p(τ) - p(z)) / (τ-z)]₁, ensure that p(z) evaluation was correct
* without needing access to the polynomial p itself.
*/
ctt_eth_kzg4844_status ctt_eth_kzg4844_verify_kzg_proof(
const ctt_eth_kzg4844_context* ctx,
const ctt_eth_kzg4844_commitment* commitment,
const ctt_eth_kzg4844_challenge* z,
const ctt_eth_kzg4844_eval_at_challenge* y,
const ctt_eth_kzg4844_proof* proof
);

/** Given a blob, return the KZG proof that is used to verify it against the commitment.
* This method does not verify that the commitment is correct with respect to `blob`.
*/
ctt_eth_kzg4844_status ctt_eth_kzg4844_compute_blob_kzg_proof(
const ctt_eth_kzg4844_context* ctx,
ctt_eth_kzg4844_proof* proof,
const ctt_eth_kzg4844_blob* blob,
const ctt_eth_kzg4844_commitment* commitment
);

/** Given a blob and a KZG proof, verify that the blob data corresponds to the provided commitment.
*/
ctt_eth_kzg4844_status ctt_eth_kzg4844_verify_blob_kzg_proof(
const ctt_eth_kzg4844_context* ctx,
const ctt_eth_kzg4844_blob* blob,
const ctt_eth_kzg4844_commitment* commitment,
const ctt_eth_kzg4844_proof* proof
);

/** Verify `n` (blob, commitment, proof) sets efficiently
*
* `n` is the number of verifications set
* - if n is negative, this procedure returns verification failure
* - if n is zero, this procedure returns verification success
*
* `secure_random_bytes` random bytes must come from a cryptographically secure RNG
* or computed through the Fiat-Shamir heuristic.
* It serves as a random number
* that is not in the control of a potential attacker to prevent potential
* rogue commitments attacks due to homomorphic properties of pairings,
* i.e. commitments that are linear combination of others and sum would be zero.
*/
ctt_eth_kzg4844_status ctt_eth_kzg4844_verify_blob_kzg_proof_batch(
const ctt_eth_kzg4844_context* ctx,
const ctt_eth_kzg4844_blob blobs[],
const ctt_eth_kzg4844_commitment commitments[],
const ctt_eth_kzg4844_proof proofs[],
size_t n,
byte secure_random_bytes[32]
);



#ifdef __cplusplus
}
#endif

#endif

0 comments on commit ce8e665

Please sign in to comment.