Initialise FK20 multi proofs

This commit is contained in:
Ben Edgington 2021-02-13 10:27:36 +00:00
parent 5fbd3af10d
commit 06afe430a7
10 changed files with 165 additions and 62 deletions

View File

@ -195,7 +195,7 @@ void p2_sub(blst_p2 *out, const blst_p2 *a, const blst_p2 *b) {
*/
void linear_combination_g1(blst_p1 *out, const blst_p1 *p, const blst_fr *coeffs, const uint64_t len) {
blst_p1 tmp;
blst_p1_from_affine(out, &identity_g1_affine);
*out = g1_identity;
for (uint64_t i = 0; i < len; i++) {
p1_mul(&tmp, &p[i], &coeffs[i]);
blst_p1_add_or_double(out, out, &tmp);
@ -205,7 +205,7 @@ void linear_combination_g1(blst_p1 *out, const blst_p1 *p, const blst_fr *coeffs
/**
* Perform pairings and test whether the outcomes are equal in G_T.
*
* Tests whether `e(a1, a2) == e(b1, b2)`
* Tests whether `e(a1, a2) == e(b1, b2)`.
*
* @param[in] a1 A G1 group point for the first pairing
* @param[in] a2 A G2 group point for the first pairing

View File

@ -24,7 +24,10 @@ static const blst_fr fr_zero = {0L, 0L, 0L, 0L};
static const blst_fr fr_one = {0x00000001fffffffeL, 0x5884b7fa00034802L, 0x998c4fefecbc4ff5L, 0x1824b159acc5056fL};
// The G1 identity/infinity in affine representation
static const blst_p1_affine identity_g1_affine = {{0L, 0L, 0L, 0L, 0L, 0L}, {0L, 0L, 0L, 0L, 0L, 0L}};
static const blst_p1_affine g1_identity_affine = {{0L, 0L, 0L, 0L, 0L, 0L}, {0L, 0L, 0L, 0L, 0L, 0L}};
// The G1 identity/infinity
static const blst_p1 g1_identity = {{0L, 0L, 0L, 0L, 0L, 0L}, {0L, 0L, 0L, 0L, 0L, 0L}, {0L, 0L, 0L, 0L, 0L, 0L}};
bool fr_is_zero(const blst_fr *p);
bool fr_is_one(const blst_fr *p);

View File

@ -144,10 +144,20 @@ void p2_sub_works(void) {
TEST_CHECK(blst_p2_is_equal(&tmp, &res));
}
void identity_g1_is_infinity(void) {
blst_p1 identity_g1;
blst_p1_from_affine(&identity_g1, &identity_g1_affine);
TEST_CHECK(blst_p1_is_inf(&identity_g1));
void g1_identity_affine_is_infinity(void) {
blst_p1 actual;
blst_p1_from_affine(&actual, &g1_identity_affine);
TEST_CHECK(blst_p1_is_inf(&actual));
}
void g1_identity_is_infinity(void) {
TEST_CHECK(blst_p1_is_inf(&g1_identity));
}
void g1_identity_is_identity(void) {
blst_p1 actual;
blst_p1_add(&actual, blst_p1_generator(), &g1_identity);
TEST_CHECK(blst_p1_is_equal(blst_p1_generator(), &actual));
}
void g1_linear_combination(void) {
@ -201,7 +211,9 @@ TEST_LIST = {
{"p1_sub_works", p1_sub_works},
{"p2_mul_works", p2_mul_works},
{"p2_sub_works", p2_sub_works},
{"identity_g1_is_infinity", identity_g1_is_infinity},
{"g1_identity_affine_is_infinity", g1_identity_affine_is_infinity},
{"g1_identity_is_infinity", g1_identity_is_infinity},
{"g1_identity_is_identity", g1_identity_is_identity},
{"g1_linear_combination", g1_linear_combination},
{"pairings_work", pairings_work},
{NULL, NULL} /* zero record marks the end of the list */

View File

@ -121,16 +121,15 @@ 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, const FFTSettings *fs) {
uint64_t n2 = n * 2;
blst_p1 identity_g1, *x_ext;
blst_p1 *x_ext;
ASSERT(c_kzg_malloc((void **)&x_ext, n2 * sizeof *x_ext) == C_KZG_OK, C_KZG_MALLOC);
blst_p1_from_affine(&identity_g1, &identity_g1_affine);
for (uint64_t i = 0; i < n; i++) {
x_ext[i] = x[i];
}
for (uint64_t i = n; i < n2; i++) {
x_ext[i] = identity_g1;
x_ext[i] = g1_identity;
}
ASSERT(fft_g1(out, x_ext, false, n2, fs) == C_KZG_OK, C_KZG_ERROR);
@ -181,14 +180,12 @@ C_KZG_RET toeplitz_part_2(blst_p1 *out, const poly *toeplitz_coeffs, const FK20S
*/
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;
blst_p1 identity_g1;
ASSERT(fft_g1(out, h_ext_fft, true, n2, fk->ks->fs) == C_KZG_OK, C_KZG_ERROR);
// Zero the second half of h
blst_p1_from_affine(&identity_g1, &identity_g1_affine);
for (uint64_t i = n; i < n2; i++) {
out[i] = identity_g1;
out[i] = g1_identity;
}
return C_KZG_OK;
@ -239,7 +236,7 @@ C_KZG_RET toeplitz_coeffs_step(poly *out, const poly *in) {
* @retval C_CZK_ERROR An internal error occurred
* @retval C_CZK_MALLOC Memory allocation failed
*/
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, const FK20SingleSettings *fk) {
uint64_t n = p->length, n2 = n * 2;
blst_p1 *h, *h_ext_fft;
poly toeplitz_coeffs;
@ -281,7 +278,7 @@ C_KZG_RET fk20_single_da_opt(blst_p1 *out, const poly *p, FK20SingleSettings *fk
* @retval C_CZK_BADARGS Invalid parameters were supplied
* @retval C_CZK_ERROR An internal error occurred
*/
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, const FK20SingleSettings *fk) {
uint64_t n = p->length, n2 = n * 2;
ASSERT(n2 <= fk->ks->fs->max_width, C_KZG_BADARGS);
@ -293,6 +290,23 @@ C_KZG_RET da_using_fk20_single(blst_p1 *out, const poly *p, FK20SingleSettings *
return C_KZG_OK;
}
/**
* FK20 Method to compute all proofs - multi proof method
*
* Toeplitz multiplication as per http://www.netlib.org/utk/people/JackDongarra/etemplates/node384.html
*
* For a polynomial of size `n`, let `w` be a `n`th root of unity. Then this method will return
* `k = n / l` KZG proofs for the points:
*
* ```
* proof[0]: w^(0*l + 0), w^(0*l + 1), ... w^(0*l + l - 1)
* proof[1]: w^(1*l + 0), w^(1*l + 1), ... w^(1*l + l - 1)
* ...
* proof[i]: w^(i*l + 0), w^(i*l + 1), ... w^(i*l + l - 1)
* ```
*/
void fk20_multi(void) {}
/**
* Initialise settings for an FK20 single proof.
*
@ -323,7 +337,7 @@ C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, const KZ
for (uint64_t i = 0; i < n - 1; i++) {
x[i] = ks->secret_g1[n - 2 - i];
}
blst_p1_from_affine(&x[n - 1], &identity_g1_affine);
x[n - 1] = g1_identity;
ASSERT(toeplitz_part_1(fk->x_ext_fft, x, n, ks->fs) == C_KZG_OK, C_KZG_ERROR);
@ -331,6 +345,62 @@ C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, const KZ
return C_KZG_OK;
}
/**
* Initialise settings for an FK20 multi proof.
*
* #free_fk20_single_settings must be called to deallocate this structure.
*
* @param[out] fk The initialised settings
* @param[in] n2 The desired size of `x_ext_fft`, a power of two
* @param[in] ks KZGSettings that have already been initialised
* @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 new_fk20_multi_settings(FK20MultiSettings *fk, uint64_t n2, uint64_t chunk_len, const KZGSettings *ks) {
uint64_t n, k;
blst_p1 *x;
C_KZG_RET ret;
ASSERT(n2 <= ks->fs->max_width, C_KZG_BADARGS);
ASSERT(is_power_of_two(n2), C_KZG_BADARGS);
ASSERT(n2 >= 2, C_KZG_BADARGS);
ASSERT(chunk_len <= n2, C_KZG_BADARGS);
ASSERT(is_power_of_two(chunk_len), C_KZG_BADARGS);
ASSERT(chunk_len > 0, C_KZG_BADARGS);
n = n2 / 2;
k = n / chunk_len;
fk->ks = ks;
fk->chunk_len = chunk_len;
// TODO check this!
ASSERT(c_kzg_malloc((void **)&fk->x_ext_fft_files, chunk_len * sizeof *fk->x_ext_fft_files) == C_KZG_OK,
C_KZG_MALLOC);
// Temporary array
ASSERT(c_kzg_malloc((void **)&x, k * sizeof *x) == C_KZG_OK, C_KZG_MALLOC);
for (uint64_t offset = 0; offset < chunk_len; offset++) {
uint64_t start = n - chunk_len - 1 - offset;
for (uint64_t i = 0, j = start; i + 1 < k; i++, j -= chunk_len) {
x[i] = ks->secret_g1[j];
}
x[k - 1] = g1_identity;
ASSERT(c_kzg_malloc((void **)&fk->x_ext_fft_files[offset], 2 * k * sizeof *fk->x_ext_fft_files[offset]) ==
C_KZG_OK,
C_KZG_MALLOC);
ASSERT(ret = toeplitz_part_1(fk->x_ext_fft_files[offset], x, k, ks->fs) == C_KZG_OK,
ret == C_KZG_MALLOC ? ret : C_KZG_ERROR);
}
free(x);
return C_KZG_OK;
}
/**
* Free the memory that was previously allocated by #new_fk20_single_settings.
*
@ -340,3 +410,17 @@ void free_fk20_single_settings(FK20SingleSettings *fk) {
free(fk->x_ext_fft);
fk->x_ext_fft_len = 0;
}
/**
* Free the memory that was previously allocated by #new_fk20_multi_settings.
*
* @param fk The settings to be freed
*/
void free_fk20_multi_settings(FK20MultiSettings *fk) {
for (uint64_t i = 0; i < fk->chunk_len; i++) {
free((fk->x_ext_fft_files)[i]);
}
free(fk->x_ext_fft_files);
fk->chunk_len = 0;
fk->length = 0;
}

View File

@ -53,14 +53,12 @@ typedef struct {
/**
* Stores the setup and parameters needed for computing FK20 multi proofs.
*/
/*
typedef struct {
KZGSettings *ks;
const KZGSettings *ks; /**< The corresponding settings for performing KZG proofs */
uint64_t chunk_len;
blst_p1 **x_ext_fft_files;
uint64_t length;
} FK20MultiSettings;
*/
int log2_pow2(uint32_t n);
uint32_t reverse_bits(uint32_t a);
@ -69,7 +67,9 @@ 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, const FFTSettings *fs);
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 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 fk20_single_da_opt(blst_p1 *out, const poly *p, const FK20SingleSettings *fk);
C_KZG_RET da_using_fk20_single(blst_p1 *out, const poly *p, const FK20SingleSettings *fk);
C_KZG_RET new_fk20_single_settings(FK20SingleSettings *fk, uint64_t n2, const KZGSettings *ks);
C_KZG_RET new_fk20_multi_settings(FK20MultiSettings *fk, uint64_t n2, uint64_t chunk_len, const KZGSettings *ks);
void free_fk20_single_settings(FK20SingleSettings *fk);
void free_fk20_multi_settings(FK20MultiSettings *fk);

View File

@ -104,8 +104,8 @@ void fk_single(void) {
KZGSettings ks;
FK20SingleSettings fk;
uint64_t secrets_len = n_len + 1;
blst_p1 *s1;
blst_p2 *s2;
blst_p1 s1[secrets_len];
blst_p2 s2[secrets_len];
poly p;
blst_p1 commitment, all_proofs[2 * poly_len], proof;
blst_fr x, y;
@ -118,7 +118,7 @@ void fk_single(void) {
}
// Initialise the secrets and data structures
generate_trusted_setup(&s1, &s2, &secret, secrets_len);
generate_trusted_setup(s1, s2, &secret, secrets_len);
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, n));
TEST_CHECK(C_KZG_OK == new_kzg_settings(&ks, s1, s2, secrets_len, &fs));
TEST_CHECK(C_KZG_OK == new_fk20_single_settings(&fk, 2 * poly_len, &ks));
@ -161,7 +161,6 @@ void fk_single(void) {
free_fft_settings(&fs);
free_kzg_settings(&ks);
free_fk20_single_settings(&fk);
free_trusted_setup(s1, s2);
}
void fk_single_strided(void) {
@ -178,8 +177,8 @@ void fk_single_strided(void) {
KZGSettings ks;
FK20SingleSettings fk;
uint64_t secrets_len = n_len + 1;
blst_p1 *s1;
blst_p2 *s2;
blst_p1 s1[secrets_len];
blst_p2 s2[secrets_len];
poly p;
blst_p1 commitment, all_proofs[2 * poly_len], proof;
blst_fr x, y;
@ -192,7 +191,7 @@ void fk_single_strided(void) {
}
// Initialise the secrets and data structures
generate_trusted_setup(&s1, &s2, &secret, secrets_len);
generate_trusted_setup(s1, s2, &secret, secrets_len);
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, n));
TEST_CHECK(C_KZG_OK == new_kzg_settings(&ks, s1, s2, secrets_len, &fs));
TEST_CHECK(C_KZG_OK == new_fk20_single_settings(&fk, 2 * poly_len, &ks));
@ -218,7 +217,28 @@ void fk_single_strided(void) {
free_fft_settings(&fs);
free_kzg_settings(&ks);
free_fk20_single_settings(&fk);
free_trusted_setup(s1, s2);
}
void fk_multi_settings(void) {
FFTSettings fs;
KZGSettings ks;
FK20MultiSettings fk;
uint64_t n = 5;
uint64_t secrets_len = 33;
blst_p1 s1[secrets_len];
blst_p2 s2[secrets_len];
// Initialise the secrets and data structures
generate_trusted_setup(s1, s2, &secret, secrets_len);
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, n));
TEST_CHECK(C_KZG_OK == new_kzg_settings(&ks, s1, s2, secrets_len, &fs));
TEST_CHECK(C_KZG_OK == new_fk20_multi_settings(&fk, 32, 4, &ks));
// Don't do anything. Run this with `valgrind` to check that memory is correctly allocated and freed.
free_fft_settings(&fs);
free_kzg_settings(&ks);
free_fk20_multi_settings(&fk);
}
TEST_LIST = {
@ -231,5 +251,6 @@ TEST_LIST = {
{"test_reverse_bit_order_fr", test_reverse_bit_order_fr},
{"fk_single", fk_single},
{"fk_single_strided", fk_single_strided},
{"fk_multi_settings", fk_multi_settings},
{NULL, NULL} /* zero record marks the end of the list */
};

View File

@ -29,7 +29,7 @@ typedef struct {
const FFTSettings *fs; /**< The corresponding settings for performing FFTs */
blst_p1 *secret_g1; /**< G1 group elements from the trusted setup */
blst_p2 *secret_g2; /**< G2 group elements from the trusted setup */
uint64_t length; /**< The number of elements from the trusted setup that are stored in this structure */
uint64_t length; /**< The number of elements in secret_g1 and secret_g2 */
} KZGSettings;
void commit_to_poly(blst_p1 *out, const poly *p, const KZGSettings *ks);

View File

@ -27,8 +27,8 @@ void proof_single(void) {
FFTSettings fs;
KZGSettings ks;
blst_p1 *s1;
blst_p2 *s2;
blst_p1 s1[secrets_len];
blst_p2 s2[secrets_len];
poly p;
blst_p1 commitment, proof;
blst_fr x, value;
@ -41,7 +41,7 @@ void proof_single(void) {
}
// Initialise the secrets and data structures
generate_trusted_setup(&s1, &s2, &secret, secrets_len);
generate_trusted_setup(s1, s2, &secret, secrets_len);
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, 4)); // ln_2 of poly_len
TEST_CHECK(C_KZG_OK == new_kzg_settings(&ks, s1, s2, secrets_len, &fs));
@ -64,8 +64,6 @@ void proof_single(void) {
free_fft_settings(&fs);
free_kzg_settings(&ks);
free_poly(&p);
free(s1);
free(s2);
}
void proof_multi(void) {
@ -75,8 +73,6 @@ void proof_multi(void) {
FFTSettings fs1, fs2;
KZGSettings ks1, ks2;
blst_p1 *s1;
blst_p2 *s2;
poly p;
blst_p1 commitment, proof;
blst_fr x, tmp;
@ -87,6 +83,8 @@ void proof_multi(void) {
blst_fr y[coset_len];
uint64_t secrets_len = poly_len > coset_len ? poly_len + 1 : coset_len + 1;
blst_p1 s1[secrets_len];
blst_p2 s2[secrets_len];
// Create the polynomial
init_poly(&p, poly_len);
@ -95,7 +93,7 @@ void proof_multi(void) {
}
// Initialise the secrets and data structures
generate_trusted_setup(&s1, &s2, &secret, secrets_len);
generate_trusted_setup(s1, s2, &secret, secrets_len);
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs1, 4)); // ln_2 of poly_len
TEST_CHECK(C_KZG_OK == new_kzg_settings(&ks1, s1, s2, secrets_len, &fs1));
@ -129,8 +127,6 @@ void proof_multi(void) {
free_kzg_settings(&ks1);
free_kzg_settings(&ks2);
free_poly(&p);
free(s1);
free(s2);
}
void commit_to_nil_poly(void) {
@ -138,25 +134,21 @@ void commit_to_nil_poly(void) {
FFTSettings fs;
KZGSettings ks;
uint64_t secrets_len = 16;
blst_p1 *s1;
blst_p2 *s2;
blst_p1 s1[secrets_len];
blst_p2 s2[secrets_len];
blst_p1 result;
blst_p1_affine result_affine;
// Initialise the (arbitrary) secrets and data structures
generate_trusted_setup(&s1, &s2, &secret, secrets_len);
generate_trusted_setup(s1, s2, &secret, secrets_len);
TEST_CHECK(C_KZG_OK == new_fft_settings(&fs, 4));
TEST_CHECK(C_KZG_OK == new_kzg_settings(&ks, s1, s2, secrets_len, &fs));
init_poly(&a, 0);
commit_to_poly(&result, &a, &ks);
blst_p1_to_affine(&result_affine, &result);
TEST_CHECK(blst_p1_affine_is_equal(&identity_g1_affine, &result_affine));
TEST_CHECK(blst_p1_is_equal(&g1_identity, &result));
free_fft_settings(&fs);
free_kzg_settings(&ks);
free(s1);
free(s2);
}
TEST_LIST = {

View File

@ -18,25 +18,17 @@
#include "test_util.h"
#include "blst_util.h"
void generate_trusted_setup(blst_p1 **s1, blst_p2 **s2, const blst_scalar *secret, const uint64_t n) {
void generate_trusted_setup(blst_p1 *s1, blst_p2 *s2, const blst_scalar *secret, const uint64_t n) {
blst_fr s_pow, s;
blst_fr_from_scalar(&s, secret);
s_pow = fr_one;
*s1 = malloc(n * sizeof(blst_p1));
*s2 = malloc(n * sizeof(blst_p2));
for (uint64_t i = 0; i < n; i++) {
p1_mul((*s1) + i, blst_p1_generator(), &s_pow);
p2_mul((*s2) + i, blst_p2_generator(), &s_pow);
p1_mul(s1 + i, blst_p1_generator(), &s_pow);
p2_mul(s2 + i, blst_p2_generator(), &s_pow);
blst_fr_mul(&s_pow, &s_pow, &s);
}
}
void free_trusted_setup(blst_p1 *s1, blst_p2 *s2) {
free(s1);
free(s2);
}
// Dummy function used to get the test-suite to print a title
void title(void) {}

View File

@ -21,6 +21,5 @@ static const blst_scalar secret = {0xa4, 0x73, 0x31, 0x95, 0x28, 0xc8, 0xb6, 0xe
0x53, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // Little-endian?
void generate_trusted_setup(blst_p1 **s1, blst_p2 **s2, const blst_scalar *secret, const uint64_t n);
void free_trusted_setup(blst_p1 *s1, blst_p2 *s2);
void generate_trusted_setup(blst_p1 *s1, blst_p2 *s2, const blst_scalar *secret, const uint64_t n);
void title(void);