From 06afe430a7f0ab771bde642e285e7aaa8894bad9 Mon Sep 17 00:00:00 2001 From: Ben Edgington Date: Sat, 13 Feb 2021 10:27:36 +0000 Subject: [PATCH] Initialise FK20 multi proofs --- src/blst_util.c | 4 +- src/blst_util.h | 5 +- src/blst_util_test.c | 22 +++++++-- src/fk20_proofs.c | 102 +++++++++++++++++++++++++++++++++++++---- src/fk20_proofs.h | 10 ++-- src/fk20_proofs_test.c | 37 +++++++++++---- src/kzg_proofs.h | 2 +- src/kzg_proofs_test.c | 28 ++++------- src/test_util.c | 14 ++---- src/test_util.h | 3 +- 10 files changed, 165 insertions(+), 62 deletions(-) diff --git a/src/blst_util.c b/src/blst_util.c index 3657b00..74a2ad9 100644 --- a/src/blst_util.c +++ b/src/blst_util.c @@ -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 diff --git a/src/blst_util.h b/src/blst_util.h index d5c7ee9..2c7d34e 100644 --- a/src/blst_util.h +++ b/src/blst_util.h @@ -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); diff --git a/src/blst_util_test.c b/src/blst_util_test.c index e96686b..e1d00d1 100644 --- a/src/blst_util_test.c +++ b/src/blst_util_test.c @@ -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 */ diff --git a/src/fk20_proofs.c b/src/fk20_proofs.c index d4bed20..19a59a8 100644 --- a/src/fk20_proofs.c +++ b/src/fk20_proofs.c @@ -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; +} diff --git a/src/fk20_proofs.h b/src/fk20_proofs.h index e6ed660..b55a671 100644 --- a/src/fk20_proofs.h +++ b/src/fk20_proofs.h @@ -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); diff --git a/src/fk20_proofs_test.c b/src/fk20_proofs_test.c index 5a92479..601014f 100644 --- a/src/fk20_proofs_test.c +++ b/src/fk20_proofs_test.c @@ -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 */ }; diff --git a/src/kzg_proofs.h b/src/kzg_proofs.h index 9629f1d..7a6067f 100644 --- a/src/kzg_proofs.h +++ b/src/kzg_proofs.h @@ -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); diff --git a/src/kzg_proofs_test.c b/src/kzg_proofs_test.c index bca8ceb..3e19ab5 100644 --- a/src/kzg_proofs_test.c +++ b/src/kzg_proofs_test.c @@ -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 = { diff --git a/src/test_util.c b/src/test_util.c index 291b7d2..ed655f0 100644 --- a/src/test_util.c +++ b/src/test_util.c @@ -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) {} diff --git a/src/test_util.h b/src/test_util.h index 51c7cdf..ad93536 100644 --- a/src/test_util.h +++ b/src/test_util.h @@ -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);