Add some comments & fix some nits (#275)
This commit is contained in:
parent
8c8f39a099
commit
b9e476857c
295
src/c_kzg_4844.c
295
src/c_kzg_4844.c
|
@ -48,9 +48,7 @@
|
|||
// Types
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Internal representation of a polynomial.
|
||||
*/
|
||||
/** Internal representation of a polynomial. */
|
||||
typedef struct {
|
||||
fr_t evals[FIELD_ELEMENTS_PER_BLOB];
|
||||
} Polynomial;
|
||||
|
@ -59,8 +57,10 @@ typedef struct {
|
|||
// Constants
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/** The Fiat-Shamir protocol domains. */
|
||||
/** The domain separator for the Fiat-Shamir protocol. */
|
||||
static const char *FIAT_SHAMIR_PROTOCOL_DOMAIN = "FSBLOBVERIFY_V1_";
|
||||
|
||||
/** The domain separator for a random challenge. */
|
||||
static const char *RANDOM_CHALLENGE_KZG_BATCH_DOMAIN = "RCKZGBATCH___V1_";
|
||||
|
||||
/** Length of the domain strings above. */
|
||||
|
@ -495,29 +495,6 @@ static bool pairings_verify(
|
|||
return blst_fp12_is_one(>_point);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate log base two of a power of two.
|
||||
*
|
||||
* In other words, the bit index of the one bit.
|
||||
*
|
||||
* @remark Works only for n a power of two, and only for n up to 2^31.
|
||||
*
|
||||
* @param[in] n The power of two
|
||||
*
|
||||
* @return the log base two of n
|
||||
*/
|
||||
static int log2_pow2(uint32_t n) {
|
||||
const uint32_t b[] = {
|
||||
0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000};
|
||||
register uint32_t r;
|
||||
r = (n & b[0]) != 0;
|
||||
r |= ((n & b[1]) != 0) << 1;
|
||||
r |= ((n & b[2]) != 0) << 2;
|
||||
r |= ((n & b[3]) != 0) << 3;
|
||||
r |= ((n & b[4]) != 0) << 4;
|
||||
return r;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Bytes Conversion Helper Functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -557,89 +534,6 @@ static void bytes_from_uint64(uint8_t out[8], uint64_t n) {
|
|||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Bit-reversal Permutation Functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Utility function to test whether the argument is a power of two.
|
||||
*
|
||||
* @remark This method returns `true` for `is_power_of_two(0)` which is a bit
|
||||
* weird, but not an issue in the contexts in which we use it.
|
||||
*
|
||||
* @param[in] n The number to test
|
||||
* @retval true if @p n is a power of two or zero
|
||||
* @retval false otherwise
|
||||
*/
|
||||
static bool is_power_of_two(uint64_t n) {
|
||||
return (n & (n - 1)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the bit order in a 32 bit integer.
|
||||
*
|
||||
* @param[in] a The integer to be reversed
|
||||
* @return An integer with the bits of @p a reversed
|
||||
*/
|
||||
static uint32_t reverse_bits(uint32_t n) {
|
||||
uint32_t result = 0;
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
result <<= 1;
|
||||
result |= (n & 1);
|
||||
n >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder an array in reverse bit order of its indices.
|
||||
*
|
||||
* @remark This means that input[n] == output[n'], where input and output
|
||||
* denote the input and output array and n' is obtained from n by
|
||||
* bit-reversing n. As opposed to reverse_bits, this bit-reversal
|
||||
* operates on log2(@p n)-bit numbers.
|
||||
*
|
||||
* @remark Operates in-place on the array.
|
||||
* @remark Can handle arrays of any type: provide the element size in @p size.
|
||||
*
|
||||
* @param[in,out] values The array, which is re-ordered in-place
|
||||
* @param[in] size The size in bytes of an element of the array
|
||||
* @param[in] n The length of the array, must be a power of two
|
||||
* strictly greater than 1 and less than 2^32.
|
||||
*/
|
||||
static C_KZG_RET bit_reversal_permutation(
|
||||
void *values, size_t size, uint64_t n
|
||||
) {
|
||||
CHECK(n != 0);
|
||||
CHECK(n >> 32 == 0);
|
||||
CHECK(is_power_of_two(n));
|
||||
CHECK(log2_pow2(n) != 0);
|
||||
|
||||
/* copy pointer and convert from void* to byte* */
|
||||
byte *v = values;
|
||||
|
||||
/* allocate scratch space for swapping an entry of the values array */
|
||||
byte *tmp = NULL;
|
||||
C_KZG_RET ret = c_kzg_malloc((void **)&tmp, size);
|
||||
if (ret != C_KZG_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unused_bit_len = 32 - log2_pow2(n);
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
uint32_t r = reverse_bits(i) >> unused_bit_len;
|
||||
if (r > i) {
|
||||
/* Swap the two elements */
|
||||
memcpy(tmp, v + (i * size), size);
|
||||
memcpy(v + (i * size), v + (r * size), size);
|
||||
memcpy(v + (r * size), tmp, size);
|
||||
}
|
||||
}
|
||||
c_kzg_free(tmp);
|
||||
|
||||
return C_KZG_OK;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BLS12-381 Helper Functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1037,6 +931,7 @@ C_KZG_RET verify_kzg_proof(
|
|||
|
||||
*ok = false;
|
||||
|
||||
/* Convert untrusted inputs to trusted inputs */
|
||||
ret = bytes_to_kzg_commitment(&commitment_g1, commitment_bytes);
|
||||
if (ret != C_KZG_OK) return ret;
|
||||
ret = bytes_to_bls_field(&z_fr, z_bytes);
|
||||
|
@ -1046,6 +941,7 @@ C_KZG_RET verify_kzg_proof(
|
|||
ret = bytes_to_kzg_proof(&proof_g1, proof_bytes);
|
||||
if (ret != C_KZG_OK) return ret;
|
||||
|
||||
/* Call helper to do pairings check */
|
||||
return verify_kzg_proof_impl(
|
||||
ok, &commitment_g1, &z_fr, &y_fr, &proof_g1, s
|
||||
);
|
||||
|
@ -1248,14 +1144,16 @@ C_KZG_RET compute_blob_kzg_proof(
|
|||
fr_t evaluation_challenge_fr;
|
||||
fr_t y;
|
||||
|
||||
/* Do conversions first to fail fast, compute_challenge is expensive */
|
||||
ret = bytes_to_kzg_commitment(&commitment_g1, commitment_bytes);
|
||||
if (ret != C_KZG_OK) goto out;
|
||||
|
||||
ret = blob_to_polynomial(&polynomial, blob);
|
||||
if (ret != C_KZG_OK) goto out;
|
||||
|
||||
/* Compute the challenge for the given blob/commitment */
|
||||
compute_challenge(&evaluation_challenge_fr, blob, &commitment_g1);
|
||||
|
||||
/* Call helper function to compute proof and y */
|
||||
ret = compute_kzg_proof_impl(
|
||||
out, &y, &polynomial, &evaluation_challenge_fr, s
|
||||
);
|
||||
|
@ -1289,22 +1187,24 @@ C_KZG_RET verify_blob_kzg_proof(
|
|||
|
||||
*ok = false;
|
||||
|
||||
/* Do conversions first to fail fast, compute_challenge is expensive */
|
||||
ret = bytes_to_kzg_commitment(&commitment_g1, commitment_bytes);
|
||||
if (ret != C_KZG_OK) return ret;
|
||||
|
||||
ret = blob_to_polynomial(&polynomial, blob);
|
||||
if (ret != C_KZG_OK) return ret;
|
||||
ret = bytes_to_kzg_proof(&proof_g1, proof_bytes);
|
||||
if (ret != C_KZG_OK) return ret;
|
||||
|
||||
/* Compute challenge for the blob/commitment */
|
||||
compute_challenge(&evaluation_challenge_fr, blob, &commitment_g1);
|
||||
|
||||
/* Evaluate challenge to get y */
|
||||
ret = evaluate_polynomial_in_evaluation_form(
|
||||
&y_fr, &polynomial, &evaluation_challenge_fr, s
|
||||
);
|
||||
if (ret != C_KZG_OK) return ret;
|
||||
|
||||
ret = bytes_to_kzg_proof(&proof_g1, proof_bytes);
|
||||
if (ret != C_KZG_OK) return ret;
|
||||
|
||||
/* Call helper to do pairings check */
|
||||
return verify_kzg_proof_impl(
|
||||
ok, &commitment_g1, &evaluation_challenge_fr, &y_fr, &proof_g1, s
|
||||
);
|
||||
|
@ -1565,6 +1465,103 @@ out:
|
|||
// Trusted Setup Functions
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Utility function to test whether the argument is a power of two.
|
||||
*
|
||||
* @remark This method returns `true` for `is_power_of_two(0)` which is a bit
|
||||
* weird, but not an issue in the contexts in which we use it.
|
||||
*
|
||||
* @param[in] n The number to test
|
||||
* @retval true if @p n is a power of two or zero
|
||||
* @retval false otherwise
|
||||
*/
|
||||
static bool is_power_of_two(uint64_t n) {
|
||||
return (n & (n - 1)) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the bit order in a 32 bit integer.
|
||||
*
|
||||
* @param[in] a The integer to be reversed
|
||||
* @return An integer with the bits of @p a reversed
|
||||
*/
|
||||
static uint32_t reverse_bits(uint32_t n) {
|
||||
uint32_t result = 0;
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
result <<= 1;
|
||||
result |= (n & 1);
|
||||
n >>= 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate log base two of a power of two.
|
||||
*
|
||||
* In other words, the bit index of the one bit.
|
||||
*
|
||||
* @remark Works only for n a power of two, and only for n up to 2^31.
|
||||
* @remark Not the fastest implementation, but it doesn't need to be fast.
|
||||
*
|
||||
* @param[in] n The power of two
|
||||
*
|
||||
* @return the log base two of n
|
||||
*/
|
||||
static int log2_pow2(uint32_t n) {
|
||||
int position = 0;
|
||||
while (n >>= 1)
|
||||
position++;
|
||||
return position;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reorder an array in reverse bit order of its indices.
|
||||
*
|
||||
* @remark Operates in-place on the array.
|
||||
* @remark Can handle arrays of any type: provide the element size in @p size.
|
||||
* @remark This means that input[n] == output[n'], where input and output
|
||||
* denote the input and output array and n' is obtained from n by
|
||||
* bit-reversing n. As opposed to reverse_bits, this bit-reversal
|
||||
* operates on log2(@p n)-bit numbers.
|
||||
*
|
||||
* @param[in,out] values The array, which is re-ordered in-place
|
||||
* @param[in] size The size in bytes of an element of the array
|
||||
* @param[in] n The length of the array, must be a power of two
|
||||
* strictly greater than 1 and less than 2^32.
|
||||
*/
|
||||
static C_KZG_RET bit_reversal_permutation(
|
||||
void *values, size_t size, uint64_t n
|
||||
) {
|
||||
CHECK(n != 0);
|
||||
CHECK(n >> 32 == 0);
|
||||
CHECK(is_power_of_two(n));
|
||||
CHECK(log2_pow2(n) != 0);
|
||||
|
||||
/* copy pointer and convert from void* to byte* */
|
||||
byte *v = values;
|
||||
|
||||
/* allocate scratch space for swapping an entry of the values array */
|
||||
byte *tmp = NULL;
|
||||
C_KZG_RET ret = c_kzg_malloc((void **)&tmp, size);
|
||||
if (ret != C_KZG_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int unused_bit_len = 32 - log2_pow2(n);
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
uint32_t r = reverse_bits(i) >> unused_bit_len;
|
||||
if (r > i) {
|
||||
/* Swap the two elements */
|
||||
memcpy(tmp, v + (i * size), size);
|
||||
memcpy(v + (i * size), v + (r * size), size);
|
||||
memcpy(v + (r * size), tmp, size);
|
||||
}
|
||||
}
|
||||
c_kzg_free(tmp);
|
||||
|
||||
return C_KZG_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fast Fourier Transform.
|
||||
*
|
||||
|
@ -1689,7 +1686,7 @@ static C_KZG_RET new_fft_settings(FFTSettings *fs, unsigned int max_scale) {
|
|||
C_KZG_RET ret;
|
||||
fr_t root_of_unity;
|
||||
|
||||
fs->max_width = (uint64_t)1 << max_scale;
|
||||
fs->max_width = 1ULL << max_scale;
|
||||
fs->expanded_roots_of_unity = NULL;
|
||||
fs->reverse_roots_of_unity = NULL;
|
||||
fs->roots_of_unity = NULL;
|
||||
|
@ -1740,35 +1737,6 @@ out_success:
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the memory that was previously allocated by new_fft_settings().
|
||||
*
|
||||
* @remark It's a NOP if `fs` is NULL.
|
||||
*
|
||||
* @param[in] fs The settings to be freed
|
||||
*/
|
||||
static void free_fft_settings(FFTSettings *fs) {
|
||||
if (fs == NULL) return;
|
||||
c_kzg_free(fs->expanded_roots_of_unity);
|
||||
c_kzg_free(fs->reverse_roots_of_unity);
|
||||
c_kzg_free(fs->roots_of_unity);
|
||||
fs->max_width = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the memory that was previously allocated by new_kzg_settings().
|
||||
*
|
||||
* @remark It's a NOP if `ks` is NULL.
|
||||
*
|
||||
* @param[in] ks The settings to be freed
|
||||
*/
|
||||
static void free_kzg_settings(KZGSettings *s) {
|
||||
if (s == NULL) return;
|
||||
c_kzg_free(s->fs);
|
||||
c_kzg_free(s->g1_values);
|
||||
c_kzg_free(s->g2_values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load trusted setup into a KZGSettings.
|
||||
*
|
||||
|
@ -1796,9 +1764,11 @@ C_KZG_RET load_trusted_setup(
|
|||
out->g1_values = NULL;
|
||||
out->g2_values = NULL;
|
||||
|
||||
/* Sanity check in case this is called directly */
|
||||
CHECK(n1 == TRUSTED_SETUP_NUM_G1_POINTS);
|
||||
CHECK(n2 == TRUSTED_SETUP_NUM_G2_POINTS);
|
||||
|
||||
/* Allocate all of our arrays */
|
||||
ret = new_g1_array(&out->g1_values, n1);
|
||||
if (ret != C_KZG_OK) goto out_error;
|
||||
ret = new_g2_array(&out->g2_values, n2);
|
||||
|
@ -1806,6 +1776,7 @@ C_KZG_RET load_trusted_setup(
|
|||
ret = new_g1_array(&g1_projective, n1);
|
||||
if (ret != C_KZG_OK) goto out_error;
|
||||
|
||||
/* Convert all g1 bytes to g1 points */
|
||||
for (i = 0; i < n1; i++) {
|
||||
ret = validate_kzg_g1(
|
||||
&g1_projective[i], (Bytes48 *)&g1_bytes[BYTES_PER_G1 * i]
|
||||
|
@ -1813,15 +1784,18 @@ C_KZG_RET load_trusted_setup(
|
|||
if (ret != C_KZG_OK) goto out_error;
|
||||
}
|
||||
|
||||
/* Convert all g2 bytes to g2 points */
|
||||
for (i = 0; i < n2; i++) {
|
||||
blst_p2_uncompress(&g2_affine, &g2_bytes[BYTES_PER_G2 * i]);
|
||||
blst_p2_from_affine(&out->g2_values[i], &g2_affine);
|
||||
}
|
||||
|
||||
/* It's the smallest power of 2 >= n1 */
|
||||
unsigned int max_scale = 0;
|
||||
while (((uint64_t)1 << max_scale) < n1)
|
||||
while ((1ULL << max_scale) < n1)
|
||||
max_scale++;
|
||||
|
||||
/* Initialize the KZGSettings struct */
|
||||
ret = c_kzg_malloc((void **)&out->fs, sizeof(FFTSettings));
|
||||
if (ret != C_KZG_OK) goto out_error;
|
||||
ret = new_fft_settings(out->fs, max_scale);
|
||||
|
@ -1892,6 +1866,35 @@ C_KZG_RET load_trusted_setup_file(KZGSettings *out, FILE *in) {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the memory that was previously allocated by new_fft_settings().
|
||||
*
|
||||
* @remark It's a NOP if `fs` is NULL.
|
||||
*
|
||||
* @param[in] fs The settings to be freed
|
||||
*/
|
||||
static void free_fft_settings(FFTSettings *fs) {
|
||||
if (fs == NULL) return;
|
||||
c_kzg_free(fs->expanded_roots_of_unity);
|
||||
c_kzg_free(fs->reverse_roots_of_unity);
|
||||
c_kzg_free(fs->roots_of_unity);
|
||||
fs->max_width = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the memory that was previously allocated by new_kzg_settings().
|
||||
*
|
||||
* @remark It's a NOP if `ks` is NULL.
|
||||
*
|
||||
* @param[in] ks The settings to be freed
|
||||
*/
|
||||
static void free_kzg_settings(KZGSettings *s) {
|
||||
if (s == NULL) return;
|
||||
c_kzg_free(s->fs);
|
||||
c_kzg_free(s->g1_values);
|
||||
c_kzg_free(s->g2_values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a trusted setup (KZGSettings).
|
||||
*
|
||||
|
|
|
@ -36,34 +36,46 @@ extern "C" {
|
|||
// Macros
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
* This value represents the number of field elements in a blob. It must be
|
||||
* supplied externally. It is expected to be 4096 for mainnet and 4 for minimal.
|
||||
*/
|
||||
#ifndef FIELD_ELEMENTS_PER_BLOB
|
||||
#error FIELD_ELEMENTS_PER_BLOB must be defined
|
||||
#endif // FIELD_ELEMENTS_PER_BLOB
|
||||
/**
|
||||
#endif /* FIELD_ELEMENTS_PER_BLOB */
|
||||
|
||||
/*
|
||||
* There are only 1<<32 2-adic roots of unity in the field, limiting the
|
||||
* possible values of FIELD_ELEMENTS_PER_BLOB. The restriction to 1<<31 is a
|
||||
* current implementation limitation. Notably, the size of the FFT setup would
|
||||
* overflow uint32_t, which would cause issues.
|
||||
*/
|
||||
#if (FIELD_ELEMENTS_PER_BLOB <= 0) || (FIELD_ELEMENTS_PER_BLOB > (1UL << 31))
|
||||
#if FIELD_ELEMENTS_PER_BLOB <= 0 || FIELD_ELEMENTS_PER_BLOB > (1UL << 31)
|
||||
#error FIELD_ELEMENTS_PER_BLOB must be between 1 and 2^31
|
||||
#endif // FIELD_ELEMENTS_PER_BLOB
|
||||
#endif /* FIELD_ELEMENTS_PER_BLOB */
|
||||
|
||||
/**
|
||||
/*
|
||||
* If FIELD_ELEMENTS_PER_BLOB is not a power of 2, the size of the FFT domain
|
||||
* should be chosen as the the next-largest power of two and polynomials
|
||||
* represented by their evaluations at a subset of the 2^i'th roots of unity.
|
||||
* While the code in this library tries to take this into account,
|
||||
* we do not need the case where FIELD_ELEMENTS_PER_BLOB is not a power of 2.
|
||||
* As this case is neither maintained nor tested, we prefer to not support it.
|
||||
* While the code in this library tries to take this into account, we do not
|
||||
* need the case where FIELD_ELEMENTS_PER_BLOB is not a power of 2. As this
|
||||
* case is neither maintained nor tested, we prefer to not support it.
|
||||
*/
|
||||
#if ((FIELD_ELEMENTS_PER_BLOB) & (FIELD_ELEMENTS_PER_BLOB)-1) != 0
|
||||
#error FIELD_ELEMENTS_PER_BLOB is not a power of two
|
||||
#endif
|
||||
#if (FIELD_ELEMENTS_PER_BLOB & (FIELD_ELEMENTS_PER_BLOB - 1)) != 0
|
||||
#error FIELD_ELEMENTS_PER_BLOB must be a power of two
|
||||
#endif /* FIELD_ELEMENTS_PER_BLOB */
|
||||
|
||||
/** The number of bytes in a KZG commitment. */
|
||||
#define BYTES_PER_COMMITMENT 48
|
||||
|
||||
/** The number of bytes in a KZG proof. */
|
||||
#define BYTES_PER_PROOF 48
|
||||
|
||||
/** The number of bytes in a BLS scalar field element. */
|
||||
#define BYTES_PER_FIELD_ELEMENT 32
|
||||
|
||||
/** The number of bytes in a blob. */
|
||||
#define BYTES_PER_BLOB (FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue