From 87bb61eaad94f9574c470ac6730c931fa6c5acd3 Mon Sep 17 00:00:00 2001 From: Justin Traglia <95511699+jtraglia@users.noreply.github.com> Date: Fri, 16 Aug 2024 08:27:18 -0500 Subject: [PATCH] Pre-compute root of unity in fr-form (#491) * Pre-compute root of unity in fr-form * Remove NUM_ELEMENTS macro * Reformat shift factors * Regenerate Rust bindings * Add back a test * Fix comment * Delete double space * Delete unnecessary max_scale computation * Add back tests + a new one * Fix comment --- bindings/rust/src/bindings/generated.rs | 2 - src/eip7594/fft.c | 10 +--- src/setup/setup.c | 60 +++++++++++++++--------- src/setup/setup.h | 62 ------------------------- src/test/tests.c | 46 +++++++++++++++--- 5 files changed, 80 insertions(+), 100 deletions(-) diff --git a/bindings/rust/src/bindings/generated.rs b/bindings/rust/src/bindings/generated.rs index 05541295..1ac5cce2 100644 --- a/bindings/rust/src/bindings/generated.rs +++ b/bindings/rust/src/bindings/generated.rs @@ -177,8 +177,6 @@ extern "C" { num_cells: u64, s: *const KZGSettings, ) -> C_KZG_RET; - #[doc = " The first 32 roots of unity in the finite field F_r. SCALE2_ROOT_OF_UNITY[i] is a 2^i'th root of\n unity.\n\n For element `{A, B, C, D}`, the field element value is `A + B * 2^64 + C * 2^128 + D * 2^192`.\n This format may be converted to an `fr_t` type via the blst_fr_from_uint64() function.\n\n The decimal values may be calculated with the following Python code:\n @code{.py}\n MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513\n PRIMITIVE_ROOT = 7\n [pow(PRIMITIVE_ROOT, (MODULUS - 1) // (2**i), MODULUS) for i in range(32)]\n @endcode\n\n Note: Being a \"primitive root\" in this context means that `r^k != 1` for any `k < q-1` where q is\n the modulus. So powers of r generate the field. This is also known as being a \"primitive\n element\".\n\n In the formula above, the restriction can be slightly relaxed to `r` being a non-square. This is\n easy to check: We just require that r^((q-1)/2) == -1. Instead of 7, we could use 10, 13, 14, 15,\n 20... to create the 2^i'th roots of unity below. Generally, there are a lot of primitive roots:\n https://crypto.stanford.edu/pbc/notes/numbertheory/gen.html"] - pub static mut SCALE2_ROOT_OF_UNITY: [[u64; 4usize]; 32usize]; pub fn load_trusted_setup( out: *mut KZGSettings, g1_monomial_bytes: *const u8, diff --git a/src/eip7594/fft.c b/src/eip7594/fft.c index 81114eba..429c8371 100644 --- a/src/eip7594/fft.c +++ b/src/eip7594/fft.c @@ -35,10 +35,7 @@ * printf("%#018llxL,\n", a.l[i]); */ static const fr_t RECOVERY_SHIFT_FACTOR = { - 0x0000000efffffff1L, - 0x17e363d300189c0fL, - 0xff9c57876f8457b0L, - 0x351332208fc5a8c4L, + 0x0000000efffffff1L, 0x17e363d300189c0fL, 0xff9c57876f8457b0L, 0x351332208fc5a8c4L }; /** @@ -51,10 +48,7 @@ static const fr_t RECOVERY_SHIFT_FACTOR = { * printf("%#018llxL,\n", a.l[i]); */ static const fr_t INV_RECOVERY_SHIFT_FACTOR = { - 0xdb6db6dadb6db6dcL, - 0xe6b5824adb6cc6daL, - 0xf8b356e005810db9L, - 0x66d0f1e660ec4796L, + 0xdb6db6dadb6db6dcL, 0xe6b5824adb6cc6daL, 0xf8b356e005810db9L, 0x66d0f1e660ec4796L }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/setup/setup.c b/src/setup/setup.c index 1e99aa97..a1d0b69a 100644 --- a/src/setup/setup.c +++ b/src/setup/setup.c @@ -42,8 +42,42 @@ /** The number of g2 points in a trusted setup. */ #define NUM_G2_POINTS 65 -/** Returns number of elements in a statically defined array. */ -#define NUM_ELEMENTS(a) (sizeof(a) / sizeof(a[0])) +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Constants +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * This is the root of unity associated with FIELD_ELEMENTS_PER_EXT_BLOB. + * + * Compute this constant with the scripts below: + * + * @code{.py} + * import math + * + * FIELD_ELEMENTS_PER_EXT_BLOB = 8192 + * PRIMITIVE_ROOT_OF_UNITY = 7 + * BLS_MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513 + * + * order = int(math.log2(FIELD_ELEMENTS_PER_EXT_BLOB)) + * root_of_unity = pow(PRIMITIVE_ROOT_OF_UNITY, (BLS_MODULUS - 1) // (2**order), BLS_MODULUS) + * uint64s = [(root_of_unity >> (64 * i)) & 0xFFFFFFFFFFFFFFFF for i in range(4)] + * values = [f"0x{uint64:016x}L" for uint64 in uint64s] + * print(f"{{{', '.join(values)}}}") + * @endcode + * + * Then paste the output into the following: + * + * @code{.c} + * fr_t root_of_unity; + * uint64_t values[4] = ; + * blst_fr_from_uint64(&root_of_unity, values); + * for (size_t i = 0; i < 4; i++) + * printf("%#018llxL,\n", root_of_unity.l[i]); + * @endcode + */ +static const fr_t ROOT_OF_UNITY = { + 0xa33d279ff0ccffc9L, 0x41fac79f59e91972L, 0x065d227fead1139bL, 0x71db41abda03e055L +}; //////////////////////////////////////////////////////////////////////////////////////////////////// // Trusted Setup Functions @@ -92,22 +126,9 @@ static C_KZG_RET expand_root_of_unity(fr_t *out, const fr_t *root, size_t width) */ static C_KZG_RET compute_roots_of_unity(KZGSettings *s) { C_KZG_RET ret; - fr_t root_of_unity; - - size_t max_scale = 0; - while ((1ULL << max_scale) < FIELD_ELEMENTS_PER_EXT_BLOB) - max_scale++; - - /* Ensure this element will exist */ - if (max_scale >= NUM_ELEMENTS(SCALE2_ROOT_OF_UNITY)) { - return C_KZG_BADARGS; - } - - /* Get the right subgroup generator */ - blst_fr_from_uint64(&root_of_unity, SCALE2_ROOT_OF_UNITY[max_scale]); /* Populate the roots of unity */ - ret = expand_root_of_unity(s->roots_of_unity, &root_of_unity, FIELD_ELEMENTS_PER_EXT_BLOB); + ret = expand_root_of_unity(s->roots_of_unity, &ROOT_OF_UNITY, FIELD_ELEMENTS_PER_EXT_BLOB); if (ret != C_KZG_OK) goto out; /* Copy all but the last root to the roots of unity */ @@ -146,7 +167,7 @@ void free_trusted_setup(KZGSettings *s) { /* * If for whatever reason we accidentally call free_trusted_setup() on an uninitialized - * structure, we don't want to deference these 2d arrays. Without these NULL checks, it's + * structure, we don't want to deference these 2d arrays. Without these NULL checks, it's * possible for there to be a segmentation fault via null pointer dereference. */ if (s->x_ext_fft_columns != NULL) { @@ -381,11 +402,6 @@ C_KZG_RET load_trusted_setup( goto out_error; } - /* 1<= n1 */ - size_t max_scale = 0; - while ((1ULL << max_scale) < NUM_G1_POINTS) - max_scale++; - /* Allocate all of our arrays */ ret = new_fr_array(&out->brp_roots_of_unity, FIELD_ELEMENTS_PER_EXT_BLOB); if (ret != C_KZG_OK) goto out_error; diff --git a/src/setup/setup.h b/src/setup/setup.h index fa315513..c102e051 100644 --- a/src/setup/setup.h +++ b/src/setup/setup.h @@ -20,68 +20,6 @@ #include /* For FILE */ -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Constants -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * The first 32 roots of unity in the finite field F_r. SCALE2_ROOT_OF_UNITY[i] is a 2^i'th root of - * unity. - * - * For element `{A, B, C, D}`, the field element value is `A + B * 2^64 + C * 2^128 + D * 2^192`. - * This format may be converted to an `fr_t` type via the blst_fr_from_uint64() function. - * - * The decimal values may be calculated with the following Python code: - * @code{.py} - * MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513 - * PRIMITIVE_ROOT = 7 - * [pow(PRIMITIVE_ROOT, (MODULUS - 1) // (2**i), MODULUS) for i in range(32)] - * @endcode - * - * Note: Being a "primitive root" in this context means that `r^k != 1` for any `k < q-1` where q is - * the modulus. So powers of r generate the field. This is also known as being a "primitive - * element". - * - * In the formula above, the restriction can be slightly relaxed to `r` being a non-square. This is - * easy to check: We just require that r^((q-1)/2) == -1. Instead of 7, we could use 10, 13, 14, 15, - * 20... to create the 2^i'th roots of unity below. Generally, there are a lot of primitive roots: - * https://crypto.stanford.edu/pbc/notes/numbertheory/gen.html - */ -static const uint64_t SCALE2_ROOT_OF_UNITY[][4] = { - {0x0000000000000001L, 0x0000000000000000L, 0x0000000000000000L, 0x0000000000000000L}, - {0xffffffff00000000L, 0x53bda402fffe5bfeL, 0x3339d80809a1d805L, 0x73eda753299d7d48L}, - {0x0001000000000000L, 0xec03000276030000L, 0x8d51ccce760304d0L, 0x0000000000000000L}, - {0x7228fd3397743f7aL, 0xb38b21c28713b700L, 0x8c0625cd70d77ce2L, 0x345766f603fa66e7L}, - {0x53ea61d87742bcceL, 0x17beb312f20b6f76L, 0xdd1c0af834cec32cL, 0x20b1ce9140267af9L}, - {0x360c60997369df4eL, 0xbf6e88fb4c38fb8aL, 0xb4bcd40e22f55448L, 0x50e0903a157988baL}, - {0x8140d032f0a9ee53L, 0x2d967f4be2f95155L, 0x14a1e27164d8fdbdL, 0x45af6345ec055e4dL}, - {0x5130c2c1660125beL, 0x98d0caac87f5713cL, 0xb7c68b4d7fdd60d0L, 0x6898111413588742L}, - {0x4935bd2f817f694bL, 0x0a0865a899e8deffL, 0x6b368121ac0cf4adL, 0x4f9b4098e2e9f12eL}, - {0x4541b8ff2ee0434eL, 0xd697168a3a6000feL, 0x39feec240d80689fL, 0x095166525526a654L}, - {0x3c28d666a5c2d854L, 0xea437f9626fc085eL, 0x8f4de02c0f776af3L, 0x325db5c3debf77a1L}, - {0x4a838b5d59cd79e5L, 0x55ea6811be9c622dL, 0x09f1ca610a08f166L, 0x6d031f1b5c49c834L}, - {0xe206da11a5d36306L, 0x0ad1347b378fbf96L, 0xfc3e8acfe0f8245fL, 0x564c0a11a0f704f4L}, - {0x6fdd00bfc78c8967L, 0x146b58bc434906acL, 0x2ccddea2972e89edL, 0x485d512737b1da3dL}, - {0x034d2ff22a5ad9e1L, 0xae4622f6a9152435L, 0xdc86b01c0d477fa6L, 0x56624634b500a166L}, - {0xfbd047e11279bb6eL, 0xc8d5f51db3f32699L, 0x483405417a0cbe39L, 0x3291357ee558b50dL}, - {0xd7118f85cd96b8adL, 0x67a665ae1fcadc91L, 0x88f39a78f1aeb578L, 0x2155379d12180caaL}, - {0x08692405f3b70f10L, 0xcd7f2bd6d0711b7dL, 0x473a2eef772c33d6L, 0x224262332d8acbf4L}, - {0x6f421a7d8ef674fbL, 0xbb97a3bf30ce40fdL, 0x652f717ae1c34bb0L, 0x2d3056a530794f01L}, - {0x194e8c62ecb38d9dL, 0xad8e16e84419c750L, 0xdf625e80d0adef90L, 0x520e587a724a6955L}, - {0xfece7e0e39898d4bL, 0x2f69e02d265e09d9L, 0xa57a6e07cb98de4aL, 0x03e1c54bcb947035L}, - {0xcd3979122d3ea03aL, 0x46b3105f04db5844L, 0xc70d0874b0691d4eL, 0x47c8b5817018af4fL}, - {0xc6e7a6ffb08e3363L, 0xe08fec7c86389beeL, 0xf2d38f10fbb8d1bbL, 0x0abe6a5e5abcaa32L}, - {0x5616c57de0ec9eaeL, 0xc631ffb2585a72dbL, 0x5121af06a3b51e3cL, 0x73560252aa0655b2L}, - {0x92cf4deb77bd779cL, 0x72cf6a8029b7d7bcL, 0x6e0bcd91ee762730L, 0x291cf6d68823e687L}, - {0xce32ef844e11a51eL, 0xc0ba12bb3da64ca5L, 0x0454dc1edc61a1a3L, 0x019fe632fd328739L}, - {0x531a11a0d2d75182L, 0x02c8118402867ddcL, 0x116168bffbedc11dL, 0x0a0a77a3b1980c0dL}, - {0xe2d0a7869f0319edL, 0xb94f1101b1d7a628L, 0xece8ea224f31d25dL, 0x23397a9300f8f98bL}, - {0xd7b688830a4f2089L, 0x6558e9e3f6ac7b41L, 0x99e276b571905a7dL, 0x52dd465e2f094256L}, - {0x474650359d8e211bL, 0x84d37b826214abc6L, 0x8da40c1ef2bb4598L, 0x0c83ea7744bf1beeL}, - {0x694341f608c9dd56L, 0xed3a181fabb30adcL, 0x1339a815da8b398fL, 0x2c6d4e4511657e1eL}, - {0x63e7cb4906ffc93fL, 0xf070bb00e28a193dL, 0xad1715b02e5713b5L, 0x4b5371495990693fL} -}; - //////////////////////////////////////////////////////////////////////////////////////////////////// // Public Functions //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/test/tests.c b/src/test/tests.c index 970a2fc6..1c3d9c3a 100644 --- a/src/test/tests.c +++ b/src/test/tests.c @@ -261,11 +261,10 @@ static void test_fr_pow__test_power_of_two(void) { } static void test_fr_pow__test_inverse_on_root_of_unity(void) { - fr_t a, r; + fr_t r; - blst_fr_from_uint64(&a, SCALE2_ROOT_OF_UNITY[31]); - - fr_pow(&r, &a, 1ULL << 31); + size_t order = log2_pow2(FIELD_ELEMENTS_PER_EXT_BLOB); + fr_pow(&r, &ROOT_OF_UNITY, 1ULL << order); bool ok = fr_equal(&r, &FR_ONE); ASSERT_EQUALS(ok, true); @@ -1612,12 +1611,44 @@ static void test_verify_kzg_proof_batch__fails_invalid_blob(void) { // Tests for expand_root_of_unity //////////////////////////////////////////////////////////////////////////////////////////////////// +/** The 2**7th (128th) root of unity. */ +static uint64_t root_of_unity_parts_7[] = { + 0x5130c2c1660125beL, 0x98d0caac87f5713cL, 0xb7c68b4d7fdd60d0L, 0x6898111413588742L +}; + +/** The 2**8th (256th) root of unity. */ +static uint64_t root_of_unity_parts_8[] = { + 0x4935bd2f817f694bL, 0x0a0865a899e8deffL, 0x6b368121ac0cf4adL, 0x4f9b4098e2e9f12eL +}; + +/** + * The 2**13th (8192th) root of unity. + * + * @note We are removing the SCALE2_ROOT_OF_UNITY array and only exposing the root of unity we need, + * but in fr_t form directly. For posterity, we have added this test to ensure the new value + * matches. For EIP-7594, we need the 8192th root of unity, order of log2(8192)=13. Please confirm + * that this value matches SCALE2_ROOT_OF_UNITY[13] as defined here: + * https://github.com/ethereum/c-kzg-4844/blob/e3ef368c67c7877636c66d6c66beb1bcbf883493/src/setup/setup.h#L64 + */ +static uint64_t root_of_unity_parts_13[] = { + 0x6fdd00bfc78c8967L, 0x146b58bc434906acL, 0x2ccddea2972e89edL, 0x485d512737b1da3dL +}; + +static void test_expand_root_of_unity__global_matches_expected(void) { + fr_t root_of_unity; + + /* The global value*/ + blst_fr_from_uint64(&root_of_unity, root_of_unity_parts_13); + ASSERT_EQUALS(fr_equal(&ROOT_OF_UNITY, &root_of_unity), true); +} + static void test_expand_root_of_unity__succeeds_with_root(void) { C_KZG_RET ret; fr_t roots[257], root_of_unity; - blst_fr_from_uint64(&root_of_unity, SCALE2_ROOT_OF_UNITY[8]); + blst_fr_from_uint64(&root_of_unity, root_of_unity_parts_8); + /* We gave it the correct root of unity, so this should succeed */ ret = expand_root_of_unity(roots, &root_of_unity, 256); ASSERT_EQUALS(ret, C_KZG_OK); } @@ -1628,6 +1659,7 @@ static void test_expand_root_of_unity__fails_not_root_of_unity(void) { fr_from_uint64(&root_of_unity, 3); + /* We gave it a bogus root of unity, so this should fail */ ret = expand_root_of_unity(roots, &root_of_unity, 256); ASSERT_EQUALS(ret, C_KZG_BADARGS); } @@ -1636,8 +1668,9 @@ static void test_expand_root_of_unity__fails_wrong_root_of_unity(void) { C_KZG_RET ret; fr_t roots[257], root_of_unity; - blst_fr_from_uint64(&root_of_unity, SCALE2_ROOT_OF_UNITY[7]); + blst_fr_from_uint64(&root_of_unity, root_of_unity_parts_7); + /* We expected the 2**8th root of unity, so this should fail */ ret = expand_root_of_unity(roots, &root_of_unity, 256); ASSERT_EQUALS(ret, C_KZG_BADARGS); } @@ -2268,6 +2301,7 @@ int main(void) { RUN(test_verify_kzg_proof_batch__fails_proof_not_in_g1); RUN(test_verify_kzg_proof_batch__fails_commitment_not_in_g1); RUN(test_verify_kzg_proof_batch__fails_invalid_blob); + RUN(test_expand_root_of_unity__global_matches_expected); RUN(test_expand_root_of_unity__succeeds_with_root); RUN(test_expand_root_of_unity__fails_not_root_of_unity); RUN(test_expand_root_of_unity__fails_wrong_root_of_unity);