Documentation and tidy up
This commit is contained in:
parent
9111f47f13
commit
19f58f25fa
|
@ -29,7 +29,7 @@
|
||||||
* called routines has been deallocated. However, in the case of @p C_KZG_ERROR or @p C_KZG_MALLOC being returned, these
|
* called routines has been deallocated. However, in the case of @p C_KZG_ERROR or @p C_KZG_MALLOC being returned, these
|
||||||
* are unrecoverable and memory may have been leaked.
|
* are unrecoverable and memory may have been leaked.
|
||||||
*
|
*
|
||||||
* @todo Check that memory is not leaked in the case of C_KZG_BADARGS.
|
* @todo Check that memory is not leaked anywhere in the case of C_KZG_BADARGS.
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
C_KZG_OK = 0, /**< Success! */
|
C_KZG_OK = 0, /**< Success! */
|
||||||
|
|
|
@ -14,9 +14,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file fk20_proofs.c */
|
/**
|
||||||
|
* @file fk20_proofs.c
|
||||||
// FK20 refers to this technique: https://github.com/khovratovich/Kate/blob/master/Kate_amortized.pdf
|
*
|
||||||
|
* Implements amortised KZG proofs as per the [FK20
|
||||||
|
* paper](https://github.com/khovratovich/Kate/blob/master/Kate_amortized.pdf).
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdlib.h> // free()
|
#include <stdlib.h> // free()
|
||||||
#include <string.h> // memcpy()
|
#include <string.h> // memcpy()
|
||||||
|
@ -24,7 +27,16 @@
|
||||||
#include "fft_g1.h"
|
#include "fft_g1.h"
|
||||||
#include "c_kzg_util.h"
|
#include "c_kzg_util.h"
|
||||||
|
|
||||||
// Log base 2 - only works for n a power of two
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
int log2_pow2(uint32_t n) {
|
int log2_pow2(uint32_t n) {
|
||||||
const uint32_t b[] = {0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000};
|
const uint32_t b[] = {0xAAAAAAAA, 0xCCCCCCCC, 0xF0F0F0F0, 0xFF00FF00, 0xFFFF0000};
|
||||||
register uint32_t r;
|
register uint32_t r;
|
||||||
|
@ -36,18 +48,44 @@ int log2_pow2(uint32_t n) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This simply wraps the macro to enforce the type check
|
/**
|
||||||
|
* Reverse the bit order in a 32 bit integer.
|
||||||
|
*
|
||||||
|
* @remark This simply wraps the macro to enforce the type check.
|
||||||
|
*
|
||||||
|
* @param[in] a The integer to be reversed
|
||||||
|
* @return An integer with the bits of @p a reversed
|
||||||
|
*/
|
||||||
uint32_t reverse_bits(uint32_t a) {
|
uint32_t reverse_bits(uint32_t a) {
|
||||||
return rev_4byte(a);
|
return rev_4byte(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t reverse_bits_limited(uint32_t length, uint32_t value) {
|
/**
|
||||||
int unused_bit_len = 32 - log2_pow2(length);
|
* Reverse the low-order bits in a 32 bit integer.
|
||||||
|
*
|
||||||
|
* The lowest log_base_two(@p n) bits of @p value are returned reversed. @p n must be a power of two.
|
||||||
|
*
|
||||||
|
* @param[in] n To reverse `b` bits, set `n = 2 ^ b`
|
||||||
|
* @param[in] value The bits to be reversed
|
||||||
|
* @return The reversal of the lowest log_2(@p n) bits of the input @p value
|
||||||
|
*/
|
||||||
|
uint32_t reverse_bits_limited(uint32_t n, uint32_t value) {
|
||||||
|
int unused_bit_len = 32 - log2_pow2(n);
|
||||||
return reverse_bits(value) >> unused_bit_len;
|
return reverse_bits(value) >> unused_bit_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In-place re-ordering of an array by the bit-reversal of the indices
|
/**
|
||||||
// Can handle arrays of any type: provide the element size in `size`
|
* 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.
|
||||||
|
*
|
||||||
|
* @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 less that 2^32
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_BADARGS Invalid parameters were supplied
|
||||||
|
*/
|
||||||
C_KZG_RET reverse_bit_order(void *values, size_t size, uint64_t n) {
|
C_KZG_RET reverse_bit_order(void *values, size_t size, uint64_t n) {
|
||||||
ASSERT(n >> 32 == 0, C_KZG_BADARGS);
|
ASSERT(n >> 32 == 0, C_KZG_BADARGS);
|
||||||
ASSERT(is_power_of_two(n), C_KZG_BADARGS);
|
ASSERT(is_power_of_two(n), C_KZG_BADARGS);
|
||||||
|
@ -67,9 +105,21 @@ C_KZG_RET reverse_bit_order(void *values, size_t size, uint64_t n) {
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs the first part of the Toeplitz matrix multiplication algorithm, which is a Fourier
|
/**
|
||||||
// transform of the vector x extended
|
* The first part of the Toeplitz matrix multiplication algorithm: the Fourier
|
||||||
C_KZG_RET toeplitz_part_1(blst_p1 *out, const blst_p1 *x, uint64_t n, KZGSettings *ks) {
|
* transform of the vector @p x extended.
|
||||||
|
*
|
||||||
|
* Used in #new_fk20_single_settings to calculate `x_ext_fft`.
|
||||||
|
*
|
||||||
|
* @param[out] out The FFT of the extension of @p x, size @p n * 2
|
||||||
|
* @param[in] x The input vector, size @p n
|
||||||
|
* @param[in] n The length of the input vector @p x
|
||||||
|
* @param[in] fs The FFT settings previously initialised with #new_fft_settings
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
|
* @retval C_CZK_MALLOC Memory allocation failed
|
||||||
|
*/
|
||||||
|
C_KZG_RET toeplitz_part_1(blst_p1 *out, const blst_p1 *x, uint64_t n, const FFTSettings *fs) {
|
||||||
uint64_t n2 = n * 2;
|
uint64_t n2 = n * 2;
|
||||||
blst_p1 identity_g1, *x_ext;
|
blst_p1 identity_g1, *x_ext;
|
||||||
|
|
||||||
|
@ -83,13 +133,23 @@ C_KZG_RET toeplitz_part_1(blst_p1 *out, const blst_p1 *x, uint64_t n, KZGSetting
|
||||||
x_ext[i] = identity_g1;
|
x_ext[i] = identity_g1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(fft_g1(out, x_ext, false, n2, ks->fs) == C_KZG_OK, C_KZG_ERROR);
|
ASSERT(fft_g1(out, x_ext, false, n2, fs) == C_KZG_OK, C_KZG_ERROR);
|
||||||
|
|
||||||
free(x_ext);
|
free(x_ext);
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Performs the second part of the Toeplitz matrix multiplication algorithm
|
/**
|
||||||
|
* The second part of the Toeplitz matrix multiplication algorithm.
|
||||||
|
*
|
||||||
|
* @param[out] out Array of G1 group elements, length `n`
|
||||||
|
* @param[in] toeplitz_coeffs Toeplitz coefficients, a polynomial length `n`
|
||||||
|
* @param[in] fk FK20 single settings previously initialised by #new_fk20_single_settings
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_BADARGS Invalid parameters were supplied
|
||||||
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
|
* @retval C_CZK_MALLOC Memory allocation failed
|
||||||
|
*/
|
||||||
C_KZG_RET toeplitz_part_2(blst_p1 *out, const poly *toeplitz_coeffs, const FK20SingleSettings *fk) {
|
C_KZG_RET toeplitz_part_2(blst_p1 *out, const poly *toeplitz_coeffs, const FK20SingleSettings *fk) {
|
||||||
blst_fr *toeplitz_coeffs_fft;
|
blst_fr *toeplitz_coeffs_fft;
|
||||||
|
|
||||||
|
@ -109,7 +169,16 @@ C_KZG_RET toeplitz_part_2(blst_p1 *out, const poly *toeplitz_coeffs, const FK20S
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part 3: transform back and zero the top half
|
/**
|
||||||
|
* The third part of the Toeplitz matrix multiplication algorithm: transform back and zero the top half.
|
||||||
|
*
|
||||||
|
* @param[out] out Array of G1 group elements, length @p n2
|
||||||
|
* @param[in] h_ext_fft FFT of the extended `h` values, length @p n2
|
||||||
|
* @param[in] n2 Size of the arrays
|
||||||
|
* @param[in] fk FK20 single settings previously initialised by #new_fk20_single_settings
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
|
*/
|
||||||
C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, const FK20SingleSettings *fk) {
|
C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, const FK20SingleSettings *fk) {
|
||||||
uint64_t n = n2 / 2;
|
uint64_t n = n2 / 2;
|
||||||
blst_p1 identity_g1;
|
blst_p1 identity_g1;
|
||||||
|
@ -125,9 +194,21 @@ C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, c
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void toeplitz_coeffs_step(poly *out, const poly *in) {
|
/**
|
||||||
|
* Reorder and extend polynomial coefficients for the toeplitz method.
|
||||||
|
*
|
||||||
|
* @warning Allocates space for the return polynomial that needs to be freed by calling #free_poly.
|
||||||
|
*
|
||||||
|
* @param[out] out The reordered polynomial, size `n * 2`
|
||||||
|
* @param[in] in The input polynomial, size `n`
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_MALLOC Memory allocation failed
|
||||||
|
*/
|
||||||
|
C_KZG_RET toeplitz_coeffs_step(poly *out, const poly *in) {
|
||||||
uint64_t n = in->length, n2 = n * 2;
|
uint64_t n = in->length, n2 = n * 2;
|
||||||
|
|
||||||
|
ASSERT(init_poly(out, n2) == C_KZG_OK, C_KZG_MALLOC);
|
||||||
|
|
||||||
out->coeffs[0] = in->coeffs[n - 1];
|
out->coeffs[0] = in->coeffs[n - 1];
|
||||||
for (uint64_t i = 1; i <= n + 1; i++) {
|
for (uint64_t i = 1; i <= n + 1; i++) {
|
||||||
out->coeffs[i] = fr_zero;
|
out->coeffs[i] = fr_zero;
|
||||||
|
@ -135,11 +216,26 @@ void toeplitz_coeffs_step(poly *out, const poly *in) {
|
||||||
for (uint64_t i = n + 2; i < n2; i++) {
|
for (uint64_t i = n + 2; i < n2; i++) {
|
||||||
out->coeffs[i] = in->coeffs[i - (n + 1)];
|
out->coeffs[i] = in->coeffs[i - (n + 1)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special version of the FK20 for the situation of data availability checks:
|
/**
|
||||||
// The upper half of the polynomial coefficients is always 0, so we do not need to extend to twice the size
|
* Optimised version of the FK20 algorithm for use in data availability checks.
|
||||||
// for Toeplitz matrix multiplication
|
*
|
||||||
|
* The upper half of the polynomial coefficients is always 0, so we do not need to extend to twice the size
|
||||||
|
* for Toeplitz matrix multiplication.
|
||||||
|
*
|
||||||
|
* @param[out] out Array size `n * 2`
|
||||||
|
* @param[in] p Polynomial, size `n`
|
||||||
|
* @param[in] fk FK20 single settings previously initialised by #new_fk20_single_settings
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_BADARGS Invalid parameters were supplied
|
||||||
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
|
* @retval C_CZK_MALLOC Memory allocation failed
|
||||||
|
*
|
||||||
|
* @todo Better parameter descriptions
|
||||||
|
*/
|
||||||
C_KZG_RET fk20_single_da_opt(blst_p1 *out, const poly *p, FK20SingleSettings *fk) {
|
C_KZG_RET fk20_single_da_opt(blst_p1 *out, const poly *p, FK20SingleSettings *fk) {
|
||||||
uint64_t n = p->length, n2 = n * 2;
|
uint64_t n = p->length, n2 = n * 2;
|
||||||
blst_p1 *h, *h_ext_fft;
|
blst_p1 *h, *h_ext_fft;
|
||||||
|
@ -149,8 +245,7 @@ C_KZG_RET fk20_single_da_opt(blst_p1 *out, const poly *p, FK20SingleSettings *fk
|
||||||
ASSERT(n2 <= fk->ks->fs->max_width, C_KZG_BADARGS);
|
ASSERT(n2 <= fk->ks->fs->max_width, C_KZG_BADARGS);
|
||||||
ASSERT(is_power_of_two(n), C_KZG_BADARGS);
|
ASSERT(is_power_of_two(n), C_KZG_BADARGS);
|
||||||
|
|
||||||
ASSERT(init_poly(&toeplitz_coeffs, n2) == C_KZG_OK, C_KZG_MALLOC);
|
ASSERT(toeplitz_coeffs_step(&toeplitz_coeffs, p) == C_KZG_OK, C_KZG_MALLOC);
|
||||||
toeplitz_coeffs_step(&toeplitz_coeffs, p);
|
|
||||||
|
|
||||||
ASSERT(c_kzg_malloc((void **)&h_ext_fft, toeplitz_coeffs.length * sizeof *h_ext_fft) == C_KZG_OK, C_KZG_MALLOC);
|
ASSERT(c_kzg_malloc((void **)&h_ext_fft, toeplitz_coeffs.length * sizeof *h_ext_fft) == C_KZG_OK, C_KZG_MALLOC);
|
||||||
ASSERT((ret = toeplitz_part_2(h_ext_fft, &toeplitz_coeffs, fk)) == C_KZG_OK,
|
ASSERT((ret = toeplitz_part_2(h_ext_fft, &toeplitz_coeffs, fk)) == C_KZG_OK,
|
||||||
|
@ -167,6 +262,18 @@ C_KZG_RET fk20_single_da_opt(blst_p1 *out, const poly *p, FK20SingleSettings *fk
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data availability using FK20 single.
|
||||||
|
*
|
||||||
|
* @param[out] out Array size `n * 2`
|
||||||
|
* @param[in] p Polynomial, size `n`
|
||||||
|
* @param[in] fk FK20 single settings previously initialised by #new_fk20_single_settings
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_BADARGS Invalid parameters were supplied
|
||||||
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
|
*
|
||||||
|
* @todo Better parameter descriptions
|
||||||
|
*/
|
||||||
C_KZG_RET da_using_fk20_single(blst_p1 *out, const poly *p, FK20SingleSettings *fk) {
|
C_KZG_RET da_using_fk20_single(blst_p1 *out, const poly *p, FK20SingleSettings *fk) {
|
||||||
uint64_t n = p->length, n2 = n * 2;
|
uint64_t n = p->length, n2 = n * 2;
|
||||||
|
|
||||||
|
@ -182,15 +289,17 @@ C_KZG_RET da_using_fk20_single(blst_p1 *out, const poly *p, FK20SingleSettings *
|
||||||
/**
|
/**
|
||||||
* Initialise settings for an FK20 single proof.
|
* Initialise settings for an FK20 single proof.
|
||||||
*
|
*
|
||||||
* free_fk20_single_settings must be called to deallocate this structure.
|
* #free_fk20_single_settings must be called to deallocate this structure.
|
||||||
*
|
*
|
||||||
* @param fk[out] The initialised settings
|
* @param[out] fk The initialised settings
|
||||||
* @param n2[in] The size
|
* @param[in] n2 The desired size of `x_ext_fft`, a power of two
|
||||||
* @param ks[in] KZGSettings that have already been initialised
|
* @param[in] ks KZGSettings that have already been initialised
|
||||||
*
|
* @retval C_CZK_OK All is well
|
||||||
* @return C_KZG_RET
|
* @retval C_CZK_BADARGS Invalid parameters were supplied
|
||||||
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
|
* @retval C_CZK_MALLOC Memory allocation failed
|
||||||
*/
|
*/
|
||||||
C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, KZGSettings *ks) {
|
C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, const KZGSettings *ks) {
|
||||||
int n = n2 / 2;
|
int n = n2 / 2;
|
||||||
blst_p1 *x;
|
blst_p1 *x;
|
||||||
|
|
||||||
|
@ -209,12 +318,18 @@ C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, KZGSetti
|
||||||
}
|
}
|
||||||
blst_p1_from_affine(&x[n - 1], &identity_g1_affine);
|
blst_p1_from_affine(&x[n - 1], &identity_g1_affine);
|
||||||
|
|
||||||
ASSERT(toeplitz_part_1(fk->x_ext_fft, x, n, ks) == C_KZG_OK, C_KZG_ERROR);
|
ASSERT(toeplitz_part_1(fk->x_ext_fft, x, n, ks->fs) == C_KZG_OK, C_KZG_ERROR);
|
||||||
|
|
||||||
free(x);
|
free(x);
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the memory that was previously allocated by #new_fk20_single_settings.
|
||||||
|
*
|
||||||
|
* @param fk The settings to be freed
|
||||||
|
*/
|
||||||
void free_fk20_single_settings(FK20SingleSettings *fk) {
|
void free_fk20_single_settings(FK20SingleSettings *fk) {
|
||||||
free(fk->x_ext_fft);
|
free(fk->x_ext_fft);
|
||||||
}
|
fk->x_ext_fft_len = 0;
|
||||||
|
}
|
||||||
|
|
|
@ -19,31 +19,57 @@
|
||||||
#include "c_kzg.h"
|
#include "c_kzg.h"
|
||||||
#include "kzg_proofs.h"
|
#include "kzg_proofs.h"
|
||||||
|
|
||||||
// TODO: Benchmark some of the other options at https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
|
/**
|
||||||
|
* Reverse the bits in a byte.
|
||||||
|
*
|
||||||
|
* From https://graphics.stanford.edu/~seander/bithacks.html#ReverseByteWith64BitsDiv
|
||||||
|
*
|
||||||
|
* @param a A byte
|
||||||
|
* @return A byte that is bit-reversed with respect to @p a
|
||||||
|
*
|
||||||
|
* @todo Benchmark some of the other bit-reversal options in the list. Maybe.
|
||||||
|
*/
|
||||||
#define rev_byte(a) ((((a)&0xff) * 0x0202020202ULL & 0x010884422010ULL) % 1023)
|
#define rev_byte(a) ((((a)&0xff) * 0x0202020202ULL & 0x010884422010ULL) % 1023)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the bits in a 32 bit word.
|
||||||
|
*
|
||||||
|
* @param a A 32 bit unsigned integer
|
||||||
|
* @return A 32 bit unsigned integer that is bit-reversed with respect to @p a
|
||||||
|
*/
|
||||||
#define rev_4byte(a) (rev_byte(a) << 24 | rev_byte((a) >> 8) << 16 | rev_byte((a) >> 16) << 8 | rev_byte((a) >> 24))
|
#define rev_4byte(a) (rev_byte(a) << 24 | rev_byte((a) >> 8) << 16 | rev_byte((a) >> 16) << 8 | rev_byte((a) >> 24))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the setup and parameters needed for computing FK20 single proofs.
|
||||||
|
*
|
||||||
|
* Initialise with #new_fk20_single_settings. Free after use with #free_fk20_single_settings.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
KZGSettings *ks;
|
const KZGSettings *ks; /**< The corresponding settings for performing KZG proofs */
|
||||||
blst_p1 *x_ext_fft;
|
blst_p1 *x_ext_fft; /**< The output of the first part of the Toeplitz process */
|
||||||
uint64_t x_ext_fft_len;
|
uint64_t x_ext_fft_len; /**< The length of the `x_ext_fft_len` array */
|
||||||
} FK20SingleSettings;
|
} FK20SingleSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the setup and parameters needed for computing FK20 multi proofs.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
typedef struct {
|
typedef struct {
|
||||||
KZGSettings *ks;
|
KZGSettings *ks;
|
||||||
uint64_t chunk_len;
|
uint64_t chunk_len;
|
||||||
blst_p1 **x_ext_fft_files;
|
blst_p1 **x_ext_fft_files;
|
||||||
uint64_t length;
|
uint64_t length;
|
||||||
} FK20MultiSettings;
|
} FK20MultiSettings;
|
||||||
|
*/
|
||||||
|
|
||||||
int log2_pow2(uint32_t n);
|
int log2_pow2(uint32_t n);
|
||||||
uint32_t reverse_bits(uint32_t a);
|
uint32_t reverse_bits(uint32_t a);
|
||||||
uint32_t reverse_bits_limited(uint32_t length, uint32_t value);
|
uint32_t reverse_bits_limited(uint32_t n, uint32_t value);
|
||||||
C_KZG_RET reverse_bit_order(void *values, size_t size, uint64_t n);
|
C_KZG_RET reverse_bit_order(void *values, size_t size, uint64_t n);
|
||||||
C_KZG_RET toeplitz_part_1(blst_p1 *out, const blst_p1 *x, uint64_t n, KZGSettings *ks);
|
C_KZG_RET toeplitz_part_1(blst_p1 *out, const blst_p1 *x, uint64_t n, const FFTSettings *fs);
|
||||||
C_KZG_RET toeplitz_part_2(blst_p1 *out, const poly *toeplitz_coeffs, const FK20SingleSettings *fk);
|
C_KZG_RET toeplitz_part_2(blst_p1 *out, const poly *toeplitz_coeffs, const FK20SingleSettings *fk);
|
||||||
C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, const FK20SingleSettings *fk);
|
C_KZG_RET toeplitz_part_3(blst_p1 *out, const blst_p1 *h_ext_fft, uint64_t n2, const FK20SingleSettings *fk);
|
||||||
C_KZG_RET fk20_single_da_opt(blst_p1 *out, const poly *p, FK20SingleSettings *fk);
|
C_KZG_RET fk20_single_da_opt(blst_p1 *out, const poly *p, FK20SingleSettings *fk);
|
||||||
C_KZG_RET da_using_fk20_single(blst_p1 *out, const poly *p, FK20SingleSettings *fk);
|
C_KZG_RET da_using_fk20_single(blst_p1 *out, const poly *p, FK20SingleSettings *fk);
|
||||||
C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, KZGSettings *ks);
|
C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, const KZGSettings *ks);
|
||||||
void free_fk20_single_settings(FK20SingleSettings *fk);
|
void free_fk20_single_settings(FK20SingleSettings *fk);
|
||||||
|
|
115
src/kzg_proofs.c
115
src/kzg_proofs.c
|
@ -14,22 +14,59 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file kzg_proofs.c */
|
/**
|
||||||
|
* @file kzg_proofs.c
|
||||||
|
*
|
||||||
|
* Implements KZG proofs for making, opening, and verifying polynomial commitments.
|
||||||
|
*
|
||||||
|
* See the paper [Constant-Size Commitments to Polynomials andTheir
|
||||||
|
* Applications](https://www.iacr.org/archive/asiacrypt2010/6477178/6477178.pdf) for the theoretical background.
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stddef.h> // NULL
|
#include <stddef.h> // NULL
|
||||||
#include <stdlib.h> // free()
|
#include <stdlib.h> // free()
|
||||||
#include "kzg_proofs.h"
|
#include "kzg_proofs.h"
|
||||||
#include "c_kzg_util.h"
|
#include "c_kzg_util.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make a KZG commitment to a polynomial.
|
||||||
|
*
|
||||||
|
* @param[out] out The commitment to the polynomial, in the form of a G1 group point
|
||||||
|
* @param[in] p The polynomial to be committed to
|
||||||
|
* @param[in] ks The settings containing the secrets, previously initialised with #new_kzg_settings
|
||||||
|
*/
|
||||||
void commit_to_poly(blst_p1 *out, const poly *p, const KZGSettings *ks) {
|
void commit_to_poly(blst_p1 *out, const poly *p, const KZGSettings *ks) {
|
||||||
linear_combination_g1(out, ks->secret_g1, p->coeffs, p->length);
|
linear_combination_g1(out, ks->secret_g1, p->coeffs, p->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute KZG proof for polynomial at position x0
|
/**
|
||||||
C_KZG_RET compute_proof_single(blst_p1 *out, poly *p, const blst_fr *x0, const KZGSettings *ks) {
|
* Compute KZG proof for polynomial at position x0.
|
||||||
|
*
|
||||||
|
* @param[out] out The proof, in the form of a G1 point
|
||||||
|
* @param[in] p The polynomial
|
||||||
|
* @param[in] x0 The x-value the polynomial is to be proved at
|
||||||
|
* @param[in] ks The settings containing the secrets, previously initialised with #new_kzg_settings
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
|
* @retval C_CZK_MALLOC Memory allocation failed
|
||||||
|
*/
|
||||||
|
C_KZG_RET compute_proof_single(blst_p1 *out, const poly *p, const blst_fr *x0, const KZGSettings *ks) {
|
||||||
return compute_proof_multi(out, p, x0, 1, ks);
|
return compute_proof_multi(out, p, x0, 1, ks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check a KZG proof at a point against a commitment.
|
||||||
|
*
|
||||||
|
* Given a @p commitment to a polynomial, a @p proof for @p x, and the claimed value @p y at @p x, verify the claim.
|
||||||
|
*
|
||||||
|
* @param[out] out `true` if the proof is valid, `false` if not
|
||||||
|
* @param[in] commitment The commitment to a polynomial
|
||||||
|
* @param[in] proof A proof of the value of the polynomial at the point @p x
|
||||||
|
* @param[in] x The point at which the proof is to be checked (opened)
|
||||||
|
* @param[in] y The claimed value of the polynomial at @p x
|
||||||
|
* @param[in] ks The settings containing the secrets, previously initialised with #new_kzg_settings
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
*/
|
||||||
C_KZG_RET check_proof_single(bool *out, const blst_p1 *commitment, const blst_p1 *proof, const blst_fr *x, blst_fr *y,
|
C_KZG_RET check_proof_single(bool *out, const blst_p1 *commitment, const blst_p1 *proof, const blst_fr *x, blst_fr *y,
|
||||||
const KZGSettings *ks) {
|
const KZGSettings *ks) {
|
||||||
blst_p2 x_g2, s_minus_x;
|
blst_p2 x_g2, s_minus_x;
|
||||||
|
@ -44,13 +81,28 @@ C_KZG_RET check_proof_single(bool *out, const blst_p1 *commitment, const blst_p1
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute KZG proof for polynomial in coefficient form at positions x * w^y where w is
|
/**
|
||||||
// an n-th root of unity (this is the proof for one data availability sample, which consists
|
* Compute KZG proof for polynomial at positions x * w^y where w is an n-th root of unity.
|
||||||
// of several polynomial evaluations)
|
*
|
||||||
C_KZG_RET compute_proof_multi(blst_p1 *out, poly *p, const blst_fr *x0, uint64_t n, const KZGSettings *ks) {
|
* This constitutes the proof for one data availability sample, which consists
|
||||||
|
* of several polynomial evaluations.
|
||||||
|
*
|
||||||
|
* @param[out] out The combined proof as a single G1 element
|
||||||
|
* @param[in] p The polynomial
|
||||||
|
* @param[in] x0 The generator x-value for the evaluation points
|
||||||
|
* @param[in] n The number of points at which to evaluate the polynomial, must be a power of two
|
||||||
|
* @param[in] ks The settings containing the secrets, previously initialised with #new_kzg_settings
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_BADARGS Invalid parameters were supplied
|
||||||
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
|
* @retval C_CZK_MALLOC Memory allocation failed
|
||||||
|
*/
|
||||||
|
C_KZG_RET compute_proof_multi(blst_p1 *out, const poly *p, const blst_fr *x0, uint64_t n, const KZGSettings *ks) {
|
||||||
poly divisor, q;
|
poly divisor, q;
|
||||||
blst_fr x_pow_n;
|
blst_fr x_pow_n;
|
||||||
|
|
||||||
|
ASSERT(is_power_of_two(n), C_KZG_BADARGS);
|
||||||
|
|
||||||
// Construct x^n - x0^n = (x - w^0)(x - w^1)...(x - w^(n-1))
|
// Construct x^n - x0^n = (x - w^0)(x - w^1)...(x - w^(n-1))
|
||||||
ASSERT(init_poly(&divisor, n + 1) == C_KZG_OK, C_KZG_MALLOC);
|
ASSERT(init_poly(&divisor, n + 1) == C_KZG_OK, C_KZG_MALLOC);
|
||||||
|
|
||||||
|
@ -77,8 +129,24 @@ C_KZG_RET compute_proof_multi(blst_p1 *out, poly *p, const blst_fr *x0, uint64_t
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check a proof for a KZG commitment for an evaluation f(x w^i) = y_i
|
/**
|
||||||
// The ys must have a power of 2 length
|
* Check a proof for a KZG commitment for evaluations `f(x * w^i) = y_i`.
|
||||||
|
*
|
||||||
|
* Given a @p commitment to a polynomial, a @p proof for @p x, and the claimed values @p y at values @p x `* w^i`,
|
||||||
|
* verify the claim. Here, `w` is an `n`th root of unity.
|
||||||
|
*
|
||||||
|
* @param[out] out `true` if the proof is valid, `false` if not
|
||||||
|
* @param[in] commitment The commitment to a polynomial
|
||||||
|
* @param[in] proof A proof of the value of the polynomial at the points @p x * w^i
|
||||||
|
* @param[in] x The generator x-value for the evaluation points
|
||||||
|
* @param[in] ys The claimed value of the polynomial at the points @p x * w^i
|
||||||
|
* @param[in] n The number of points at which to evaluate the polynomial, must be a power of two
|
||||||
|
* @param[in] ks The settings containing the secrets, previously initialised with #new_kzg_settings
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_BADARGS Invalid parameters were supplied
|
||||||
|
* @retval C_CZK_ERROR An internal error occurred
|
||||||
|
* @retval C_CZK_MALLOC Memory allocation failed
|
||||||
|
*/
|
||||||
C_KZG_RET check_proof_multi(bool *out, const blst_p1 *commitment, const blst_p1 *proof, const blst_fr *x,
|
C_KZG_RET check_proof_multi(bool *out, const blst_p1 *commitment, const blst_p1 *proof, const blst_fr *x,
|
||||||
const blst_fr *ys, uint64_t n, const KZGSettings *ks) {
|
const blst_fr *ys, uint64_t n, const KZGSettings *ks) {
|
||||||
poly interp;
|
poly interp;
|
||||||
|
@ -86,9 +154,11 @@ C_KZG_RET check_proof_multi(bool *out, const blst_p1 *commitment, const blst_p1
|
||||||
blst_p2 xn2, xn_minus_yn;
|
blst_p2 xn2, xn_minus_yn;
|
||||||
blst_p1 is1, commit_minus_interp;
|
blst_p1 is1, commit_minus_interp;
|
||||||
|
|
||||||
|
ASSERT(is_power_of_two(n), C_KZG_BADARGS);
|
||||||
|
|
||||||
// Interpolate at a coset.
|
// Interpolate at a coset.
|
||||||
ASSERT(init_poly(&interp, n) == C_KZG_OK, C_KZG_MALLOC);
|
ASSERT(init_poly(&interp, n) == C_KZG_OK, C_KZG_MALLOC);
|
||||||
ASSERT(fft_fr(interp.coeffs, ys, true, n, ks->fs) == C_KZG_OK, C_KZG_BADARGS);
|
ASSERT(fft_fr(interp.coeffs, ys, true, n, ks->fs) == C_KZG_OK, C_KZG_ERROR);
|
||||||
|
|
||||||
// Because it is a coset, not the subgroup, we have to multiply the polynomial coefficients by x^-i
|
// Because it is a coset, not the subgroup, we have to multiply the polynomial coefficients by x^-i
|
||||||
blst_fr_eucl_inverse(&inv_x, x);
|
blst_fr_eucl_inverse(&inv_x, x);
|
||||||
|
@ -117,7 +187,24 @@ C_KZG_RET check_proof_multi(bool *out, const blst_p1 *commitment, const blst_p1
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
C_KZG_RET new_kzg_settings(KZGSettings *ks, blst_p1 *secret_g1, blst_p2 *secret_g2, uint64_t length, FFTSettings *fs) {
|
/**
|
||||||
|
* Initialise a KZGSettings structure.
|
||||||
|
*
|
||||||
|
* Space is allocated for the provided secrets (the "trusted setup"), and copies of the secrets are made.
|
||||||
|
*
|
||||||
|
* @remark This structure *must* be deallocated after use by calling #free_kzg_settings.
|
||||||
|
*
|
||||||
|
* @param[out] ks The new settings
|
||||||
|
* @param[in] secret_g1 The G1 points from the trusted setup (an array of length at least @p length)
|
||||||
|
* @param[in] secret_g2 The G2 points from the trusted setup (an array of length at least @p length)
|
||||||
|
* @param[in] length The length of the secrets arrays to create, must be at least @p fs->max_width
|
||||||
|
* @param[in] fs A previously initialised FFTSettings structure
|
||||||
|
* @retval C_CZK_OK All is well
|
||||||
|
* @retval C_CZK_BADARGS Invalid parameters were supplied
|
||||||
|
* @retval C_CZK_MALLOC Memory allocation failed
|
||||||
|
*/
|
||||||
|
C_KZG_RET new_kzg_settings(KZGSettings *ks, const blst_p1 *secret_g1, const blst_p2 *secret_g2, uint64_t length,
|
||||||
|
FFTSettings const *fs) {
|
||||||
|
|
||||||
ASSERT(length >= fs->max_width, C_KZG_BADARGS);
|
ASSERT(length >= fs->max_width, C_KZG_BADARGS);
|
||||||
ks->length = length;
|
ks->length = length;
|
||||||
|
@ -132,11 +219,15 @@ C_KZG_RET new_kzg_settings(KZGSettings *ks, blst_p1 *secret_g1, blst_p2 *secret_
|
||||||
ks->secret_g2[i] = secret_g2[i];
|
ks->secret_g2[i] = secret_g2[i];
|
||||||
}
|
}
|
||||||
ks->fs = fs;
|
ks->fs = fs;
|
||||||
ks->extended_secret_g1 = NULL; // What's this for?
|
|
||||||
|
|
||||||
return C_KZG_OK;
|
return C_KZG_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the memory that was previously allocated by #new_kzg_settings.
|
||||||
|
*
|
||||||
|
* @param ks The settings to be freed
|
||||||
|
*/
|
||||||
void free_kzg_settings(KZGSettings *ks) {
|
void free_kzg_settings(KZGSettings *ks) {
|
||||||
free(ks->secret_g1);
|
free(ks->secret_g1);
|
||||||
free(ks->secret_g2);
|
free(ks->secret_g2);
|
||||||
|
|
|
@ -20,20 +20,25 @@
|
||||||
#include "fft_fr.h"
|
#include "fft_fr.h"
|
||||||
#include "poly.h"
|
#include "poly.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the setup and parameters needed for computing KZG proofs.
|
||||||
|
*
|
||||||
|
* Initialise with #new_kzg_settings. Free after use with #free_kzg_settings.
|
||||||
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FFTSettings *fs;
|
const FFTSettings *fs; /**< The corresponding settings for performing FFTs */
|
||||||
blst_p1 *secret_g1;
|
blst_p1 *secret_g1; /**< G1 group elements from the trusted setup */
|
||||||
blst_p1 *extended_secret_g1;
|
blst_p2 *secret_g2; /**< G2 group elements from the trusted setup */
|
||||||
blst_p2 *secret_g2;
|
uint64_t length; /**< The number of elements from the trusted setup that are stored in this structure */
|
||||||
uint64_t length;
|
|
||||||
} KZGSettings;
|
} KZGSettings;
|
||||||
|
|
||||||
void commit_to_poly(blst_p1 *out, const poly *p, const KZGSettings *ks);
|
void commit_to_poly(blst_p1 *out, const poly *p, const KZGSettings *ks);
|
||||||
C_KZG_RET compute_proof_single(blst_p1 *out, poly *p, const blst_fr *x0, const KZGSettings *ks);
|
C_KZG_RET compute_proof_single(blst_p1 *out, const poly *p, const blst_fr *x0, const KZGSettings *ks);
|
||||||
C_KZG_RET check_proof_single(bool *out, const blst_p1 *commitment, const blst_p1 *proof, const blst_fr *x, blst_fr *y,
|
C_KZG_RET check_proof_single(bool *out, const blst_p1 *commitment, const blst_p1 *proof, const blst_fr *x, blst_fr *y,
|
||||||
const KZGSettings *ks);
|
const KZGSettings *ks);
|
||||||
C_KZG_RET compute_proof_multi(blst_p1 *out, poly *p, const blst_fr *x0, uint64_t n, const KZGSettings *ks);
|
C_KZG_RET compute_proof_multi(blst_p1 *out, const poly *p, const blst_fr *x0, uint64_t n, const KZGSettings *ks);
|
||||||
C_KZG_RET check_proof_multi(bool *out, const blst_p1 *commitment, const blst_p1 *proof, const blst_fr *x,
|
C_KZG_RET check_proof_multi(bool *out, const blst_p1 *commitment, const blst_p1 *proof, const blst_fr *x,
|
||||||
const blst_fr *ys, uint64_t n, const KZGSettings *ks);
|
const blst_fr *ys, uint64_t n, const KZGSettings *ks);
|
||||||
C_KZG_RET new_kzg_settings(KZGSettings *ks, blst_p1 *secret_g1, blst_p2 *secret_g2, uint64_t length, FFTSettings *fs);
|
C_KZG_RET new_kzg_settings(KZGSettings *ks, const blst_p1 *secret_g1, const blst_p2 *secret_g2, uint64_t length,
|
||||||
|
const FFTSettings *fs);
|
||||||
void free_kzg_settings(KZGSettings *ks);
|
void free_kzg_settings(KZGSettings *ks);
|
||||||
|
|
Loading…
Reference in New Issue