Add some comments & fix some nits (#275)

This commit is contained in:
Justin Traglia 2023-04-04 10:09:12 -05:00 committed by GitHub
parent 8c8f39a099
commit b9e476857c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 172 additions and 157 deletions

View File

@ -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(&gt_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).
*

View File

@ -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)
///////////////////////////////////////////////////////////////////////////////