diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp index 29b6aa99eda8..4771cc896eb5 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fq.hpp @@ -8,22 +8,30 @@ // NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays) namespace bb { class Bn254FqParams { + // There is a helper script in ecc/fields/parameter_helper.py that can be used to extract these parameters from the + // source code public: + // A little-endian representation of the modulus split into 4 64-bit words static constexpr uint64_t modulus_0 = 0x3C208C16D87CFD47UL; static constexpr uint64_t modulus_1 = 0x97816a916871ca8dUL; static constexpr uint64_t modulus_2 = 0xb85045b68181585dUL; static constexpr uint64_t modulus_3 = 0x30644e72e131a029UL; + // A little-endian representation of R^2 modulo the modulus (R=2^256 mod modulus) split into 4 64-bit words + // This paremeter is used to convert an element of Fq in standard from to Montgomery form static constexpr uint64_t r_squared_0 = 0xF32CFC5B538AFA89UL; static constexpr uint64_t r_squared_1 = 0xB5E71911D44501FBUL; static constexpr uint64_t r_squared_2 = 0x47AB1EFF0A417FF6UL; static constexpr uint64_t r_squared_3 = 0x06D89F71CAB8351FUL; + // A little-endian representation of the cube root of 1 in Fq in Montgomery form split into 4 64-bit words static constexpr uint64_t cube_root_0 = 0x71930c11d782e155UL; static constexpr uint64_t cube_root_1 = 0xa6bb947cffbe3323UL; static constexpr uint64_t cube_root_2 = 0xaa303344d4741444UL; static constexpr uint64_t cube_root_3 = 0x2c3b3f0d26594943UL; + // A little-endian representation of the modulus split into 9 29-bit limbs + // This is used in wasm because we can only do multiplication with 64-bit result instead of 128-bit like in x86_64 static constexpr uint64_t modulus_wasm_0 = 0x187cfd47; static constexpr uint64_t modulus_wasm_1 = 0x10460b6; static constexpr uint64_t modulus_wasm_2 = 0x1c72a34f; @@ -34,26 +42,34 @@ class Bn254FqParams { static constexpr uint64_t modulus_wasm_7 = 0xe5c2634; static constexpr uint64_t modulus_wasm_8 = 0x30644e; + // A little-endian representation of R^2 modulo the modulus (R=2^261 mod modulus) split into 4 64-bit words + // We use 2^261 in wasm, because 261=29*9, the 9 29-bit limbs used for arithmetic in static constexpr uint64_t r_squared_wasm_0 = 0xe1a2a074659bac10UL; static constexpr uint64_t r_squared_wasm_1 = 0x639855865406005aUL; static constexpr uint64_t r_squared_wasm_2 = 0xff54c5802d3e2632UL; static constexpr uint64_t r_squared_wasm_3 = 0x2a11a68c34ea65a6UL; + // A little-endian representation of the cube root of 1 in Fq in Montgomery form for wasm (R=2^261 mod modulus) + // split into 4 64-bit words static constexpr uint64_t cube_root_wasm_0 = 0x62b1a3a46a337995UL; static constexpr uint64_t cube_root_wasm_1 = 0xadc97d2722e2726eUL; static constexpr uint64_t cube_root_wasm_2 = 0x64ee82ede2db85faUL; static constexpr uint64_t cube_root_wasm_3 = 0x0c0afea1488a03bbUL; + // Not used for Fq, but required for all field types static constexpr uint64_t primitive_root_0 = 0UL; static constexpr uint64_t primitive_root_1 = 0UL; static constexpr uint64_t primitive_root_2 = 0UL; static constexpr uint64_t primitive_root_3 = 0UL; + // Not used for Fq, but required for all field types static constexpr uint64_t primitive_root_wasm_0 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_1 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_2 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_3 = 0x0000000000000000UL; + // Parameters used for quickly splitting a scalar into two endomorphism scalars for faster scalar multiplication + // For specifics on how these have been derived, ask @zac-williamson static constexpr uint64_t endo_g1_lo = 0x7a7bd9d4391eb18d; static constexpr uint64_t endo_g1_mid = 0x4ccef014a773d2cfUL; static constexpr uint64_t endo_g1_hi = 0x0000000000000002UL; @@ -64,8 +80,36 @@ class Bn254FqParams { static constexpr uint64_t endo_b2_lo = 0x89d3256894d213e2UL; static constexpr uint64_t endo_b2_mid = 0UL; + // -(Modulus^-1) mod 2^64 + // This is used to compute k = r_inv * lower_limb(scalar), such that scalar + k*modulus in integers would have 0 in + // the lowest limb By performing this sequentially for 4 limbs, we get an 8-limb representation of the scalar, where + // the lowest 4 limbs are zeros. Then we can immediately divide by 2^256 by simply getting rid of the lowest 4 limbs static constexpr uint64_t r_inv = 0x87d20782e4866389UL; + // 2^(-64) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 5 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_0 = 0x327d7c1b18f7bd41UL; + static constexpr uint64_t r_inv_1 = 0xdb8ed52f824ed32fUL; + static constexpr uint64_t r_inv_2 = 0x29b67b05eb29a6a1UL; + static constexpr uint64_t r_inv_3 = 0x19ac99126b459ddaUL; + + // 2^(-29) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 10 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_wasm_0 = 0x17789a9f; + static constexpr uint64_t r_inv_wasm_1 = 0x5ffc3dc; + static constexpr uint64_t r_inv_wasm_2 = 0xd6bde42; + static constexpr uint64_t r_inv_wasm_3 = 0x1cf152e3; + static constexpr uint64_t r_inv_wasm_4 = 0x18eb055f; + static constexpr uint64_t r_inv_wasm_5 = 0xed815e2; + static constexpr uint64_t r_inv_wasm_6 = 0x16626d2; + static constexpr uint64_t r_inv_wasm_7 = 0xb8bab0f; + static constexpr uint64_t r_inv_wasm_8 = 0x6d7c4; + + // Coset generators in Montgomery form for R=2^256 mod Modulus. Used in FFT-based proving systems static constexpr uint64_t coset_generators_0[8]{ 0x7a17caa950ad28d7ULL, 0x4d750e37163c3674ULL, 0x20d251c4dbcb4411ULL, 0xf42f9552a15a51aeULL, 0x4f4bc0b2b5ef64bdULL, 0x22a904407b7e725aULL, 0xf60647ce410d7ff7ULL, 0xc9638b5c069c8d94ULL, @@ -83,6 +127,7 @@ class Bn254FqParams { 0x180a96573d3d9f8ULL, 0xf8b21270ddbb927ULL, 0x1d9598e8a7e39857ULL, 0x2ba010aa41eb7786ULL, }; + // Coset generators in Montgomery form for R=2^261 mod Modulus. Used in FFT-based proving systems static constexpr uint64_t coset_generators_wasm_0[8] = { 0xeb8a8ec140766463ULL, 0xfded87957d76333dULL, 0x4c710c8092f2ff5eULL, 0x9af4916ba86fcb7fULL, 0xe9781656bdec97a0ULL, 0xfbdb0f2afaec667aULL, diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fr.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fr.hpp index 4d4146180664..f26be2147ea9 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fr.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/bn254/fr.hpp @@ -10,31 +10,39 @@ namespace bb { class Bn254FrParams { + // There is a helper script in ecc/fields/parameter_helper.py that can be used to extract these parameters from the public: // Note: limbs here are combined as concat(_3, _2, _1, _0) // E.g. this modulus forms the value: // 0x30644E72E131A029B85045B68181585D2833E84879B9709143E1F593F0000001 // = 21888242871839275222246405745257275088548364400416034343698204186575808495617 + // A little-endian representation of the modulus split into 4 64-bit words static constexpr uint64_t modulus_0 = 0x43E1F593F0000001UL; static constexpr uint64_t modulus_1 = 0x2833E84879B97091UL; static constexpr uint64_t modulus_2 = 0xB85045B68181585DUL; static constexpr uint64_t modulus_3 = 0x30644E72E131A029UL; + // A little-endian representation of R^2 modulo the modulus (R=2^256 mod modulus) split into 4 64-bit words static constexpr uint64_t r_squared_0 = 0x1BB8E645AE216DA7UL; static constexpr uint64_t r_squared_1 = 0x53FE3AB1E35C59E3UL; static constexpr uint64_t r_squared_2 = 0x8C49833D53BB8085UL; static constexpr uint64_t r_squared_3 = 0x216D0B17F4E44A5UL; + // A little-endian representation of the cubic root of 1 in Fr in Montgomery form split into 4 64-bit words static constexpr uint64_t cube_root_0 = 0x93e7cede4a0329b3UL; static constexpr uint64_t cube_root_1 = 0x7d4fdca77a96c167UL; static constexpr uint64_t cube_root_2 = 0x8be4ba08b19a750aUL; static constexpr uint64_t cube_root_3 = 0x1cbd5653a5661c25UL; + // A little-endian representation of the primitive root of 1 Fr split into 4 64-bit words in Montgomery form + // (R=2^256 mod modulus) This is a root of unity in a large power of 2 subgroup of Fr static constexpr uint64_t primitive_root_0 = 0x636e735580d13d9cUL; static constexpr uint64_t primitive_root_1 = 0xa22bf3742445ffd6UL; static constexpr uint64_t primitive_root_2 = 0x56452ac01eb203d8UL; static constexpr uint64_t primitive_root_3 = 0x1860ef942963f9e7UL; + // Parameters used for quickly splitting a scalar into two endomorphism scalars for faster scalar multiplication + // For specifics on how these have been derived, ask @zac-williamson static constexpr uint64_t endo_g1_lo = 0x7a7bd9d4391eb18dUL; static constexpr uint64_t endo_g1_mid = 0x4ccef014a773d2cfUL; static constexpr uint64_t endo_g1_hi = 0x0000000000000002UL; @@ -45,8 +53,36 @@ class Bn254FrParams { static constexpr uint64_t endo_b2_lo = 0x89d3256894d213e3UL; static constexpr uint64_t endo_b2_mid = 0UL; + // -(Modulus^-1) mod 2^64 + // This is used to compute k = r_inv * lower_limb(scalar), such that scalar + k*modulus in integers would have 0 in + // the lowest limb By performing this sequentially for 4 limbs, we get an 8-limb representation of the scalar, where + // the lowest 4 limbs are zeros. Then we can immediately divide by 2^256 by simply getting rid of the lowest 4 limbs static constexpr uint64_t r_inv = 0xc2e1f593efffffffUL; + // 2^(-64) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 5 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_0 = 0x2d3e8053e396ee4dUL; + static constexpr uint64_t r_inv_1 = 0xca478dbeab3c92cdUL; + static constexpr uint64_t r_inv_2 = 0xb2d8f06f77f52a93UL; + static constexpr uint64_t r_inv_3 = 0x24d6ba07f7aa8f04UL; + + // 2^(-29) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 10 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_wasm_0 = 0x18f05361; + static constexpr uint64_t r_inv_wasm_1 = 0x12bb1fe; + static constexpr uint64_t r_inv_wasm_2 = 0xf5d8135; + static constexpr uint64_t r_inv_wasm_3 = 0x1e6275f6; + static constexpr uint64_t r_inv_wasm_4 = 0x7e7a880; + static constexpr uint64_t r_inv_wasm_5 = 0x10c6bf1f; + static constexpr uint64_t r_inv_wasm_6 = 0x11f74a6c; + static constexpr uint64_t r_inv_wasm_7 = 0x6fdaecb; + static constexpr uint64_t r_inv_wasm_8 = 0x183227; + + // Coset generators in Montgomery form for R=2^256 mod Modulus. Used in FFT-based proving systems static constexpr uint64_t coset_generators_0[8]{ 0x5eef048d8fffffe7ULL, 0xb8538a9dfffffe2ULL, 0x3057819e4fffffdbULL, 0xdcedb5ba9fffffd6ULL, 0x8983e9d6efffffd1ULL, 0x361a1df33fffffccULL, 0xe2b0520f8fffffc7ULL, 0x8f46862bdfffffc2ULL, @@ -64,6 +100,8 @@ class Bn254FrParams { 0x1d9598e8a7e39857ULL, 0x2ba010aa41eb7786ULL, 0x39aa886bdbf356b5ULL, 0x47b5002d75fb35e5ULL, }; + // A little-endian representation of the modulus split into 9 29-bit limbs + // This is used in wasm because we can only do multiplication with 64-bit result instead of 128-bit like in x86_64 static constexpr uint64_t modulus_wasm_0 = 0x10000001; static constexpr uint64_t modulus_wasm_1 = 0x1f0fac9f; static constexpr uint64_t modulus_wasm_2 = 0xe5c2450; @@ -74,21 +112,28 @@ class Bn254FrParams { static constexpr uint64_t modulus_wasm_7 = 0xe5c2634; static constexpr uint64_t modulus_wasm_8 = 0x30644e; + // A little-endian representation of R^2 modulo the modulus (R=2^261 mod modulus) split into 4 64-bit words + // We use 2^261 in wasm, because 261=29*9, the 9 29-bit limbs used for arithmetic in static constexpr uint64_t r_squared_wasm_0 = 0x38c2e14b45b69bd4UL; static constexpr uint64_t r_squared_wasm_1 = 0x0ffedb1885883377UL; static constexpr uint64_t r_squared_wasm_2 = 0x7840f9f0abc6e54dUL; static constexpr uint64_t r_squared_wasm_3 = 0x0a054a3e848b0f05UL; + // A little-endian representation of the cubic root of 1 in Fr in Montgomery form for wasm (R=2^261 mod modulus) + // split into 4 64-bit words static constexpr uint64_t cube_root_wasm_0 = 0x7334a1ce7065364dUL; static constexpr uint64_t cube_root_wasm_1 = 0xae21578e4a14d22aUL; static constexpr uint64_t cube_root_wasm_2 = 0xcea2148a96b51265UL; static constexpr uint64_t cube_root_wasm_3 = 0x0038f7edf614a198UL; + // A little-endian representation of the primitive root of 1 Fr in Montgomery form for wasm (R=2^261 mod modulus) + // split into 4 64-bit words static constexpr uint64_t primitive_root_wasm_0 = 0x2faf11711a27b370UL; static constexpr uint64_t primitive_root_wasm_1 = 0xc23fe9fced28f1b8UL; static constexpr uint64_t primitive_root_wasm_2 = 0x43a0fc9bbe2af541UL; static constexpr uint64_t primitive_root_wasm_3 = 0x05d90b5719653a4fUL; + // Coset generators in Montgomery form for R=2^261 mod Modulus. Used in FFT-based proving systems static constexpr uint64_t coset_generators_wasm_0[8] = { 0xab46711cdffffcb2ULL, 0xdb1b52736ffffc09ULL, 0x0af033c9fffffb60ULL, 0xf6e31f8c9ffffab6ULL, 0x26b800e32ffffa0dULL, 0x568ce239bffff964ULL, diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/secp256k1/secp256k1.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/secp256k1/secp256k1.hpp index 81b575ad67ba..51bc376aa768 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/secp256k1/secp256k1.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/secp256k1/secp256k1.hpp @@ -8,16 +8,22 @@ namespace bb::secp256k1 { struct FqParams { + // There is a helper script in ecc/fields/parameter_helper.py that can be used to extract these parameters from the + // source code + + // A little-endian representation of the modulus split into 4 64-bit words static constexpr uint64_t modulus_0 = 0xFFFFFFFEFFFFFC2FULL; static constexpr uint64_t modulus_1 = 0xFFFFFFFFFFFFFFFFULL; static constexpr uint64_t modulus_2 = 0xFFFFFFFFFFFFFFFFULL; static constexpr uint64_t modulus_3 = 0xFFFFFFFFFFFFFFFFULL; + // A little-endian representation of R^2 modulo the modulus (R=2^256 mod modulus) split into 4 64-bit words static constexpr uint64_t r_squared_0 = 8392367050913ULL; static constexpr uint64_t r_squared_1 = 1; static constexpr uint64_t r_squared_2 = 0; static constexpr uint64_t r_squared_3 = 0; + // Coset generators in Montgomery form for R=2^256 mod Modulus. Used in FFT-based proving systems static constexpr uint64_t coset_generators_0[8]{ 0x300000b73ULL, 0x400000f44ULL, 0x500001315ULL, 0x6000016e6ULL, 0x700001ab7ULL, 0x800001e88ULL, 0x900002259ULL, 0xa0000262aULL, @@ -32,18 +38,49 @@ struct FqParams { 0, 0, 0, 0, 0, 0, 0, 0, }; + // -(Modulus^-1) mod 2^64 + // This is used to compute k = r_inv * lower_limb(scalar), such that scalar + k*modulus in integers would have 0 in + // the lowest limb By performing this sequentially for 4 limbs, we get an 8-limb representation of the scalar, where + // the lowest 4 limbs are zeros. Then we can immediately divide by 2^256 by simply getting rid of the lowest 4 limbs static constexpr uint64_t r_inv = 15580212934572586289ULL; + // 2^(-64) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 5 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_0 = 0xffffffff27c7f3a9UL; + static constexpr uint64_t r_inv_1 = 0xffffffffffffffffUL; + static constexpr uint64_t r_inv_2 = 0xffffffffffffffffUL; + static constexpr uint64_t r_inv_3 = 0xd838091dd2253530UL; + + // 2^(-29) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 10 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_wasm_0 = 0xed6544e; + static constexpr uint64_t r_inv_wasm_1 = 0x1ffffffb; + static constexpr uint64_t r_inv_wasm_2 = 0x1fffffff; + static constexpr uint64_t r_inv_wasm_3 = 0x1fffffff; + static constexpr uint64_t r_inv_wasm_4 = 0x1fffffff; + static constexpr uint64_t r_inv_wasm_5 = 0x1fffffff; + static constexpr uint64_t r_inv_wasm_6 = 0x1fffffff; + static constexpr uint64_t r_inv_wasm_7 = 0x10ffffff; + static constexpr uint64_t r_inv_wasm_8 = 0x9129a9; + + // A little-endian representation of the cubic root of 1 in Fq in Montgomery form split into 4 64-bit words static constexpr uint64_t cube_root_0 = 0x58a4361c8e81894eULL; static constexpr uint64_t cube_root_1 = 0x03fde1631c4b80afULL; static constexpr uint64_t cube_root_2 = 0xf8e98978d02e3905ULL; static constexpr uint64_t cube_root_3 = 0x7a4a36aebcbb3d53ULL; + // Not used for secp256k1 static constexpr uint64_t primitive_root_0 = 0UL; static constexpr uint64_t primitive_root_1 = 0UL; static constexpr uint64_t primitive_root_2 = 0UL; static constexpr uint64_t primitive_root_3 = 0UL; + // A little-endian representation of the modulus split into 9 29-bit limbs + // This is used in wasm because we can only do multiplication with 64-bit result instead of 128-bit like in x86_64 static constexpr uint64_t modulus_wasm_0 = 0x1ffffc2f; static constexpr uint64_t modulus_wasm_1 = 0x1ffffff7; static constexpr uint64_t modulus_wasm_2 = 0x1fffffff; @@ -54,21 +91,28 @@ struct FqParams { static constexpr uint64_t modulus_wasm_7 = 0x1fffffff; static constexpr uint64_t modulus_wasm_8 = 0xffffff; + // A little-endian representation of R^2 modulo the modulus (R=2^261 mod modulus) split into 4 64-bit words + // We use 2^261 in wasm, because 261=29*9, the 9 29-bit limbs used for arithmetic in static constexpr uint64_t r_squared_wasm_0 = 0x001e88003a428400UL; static constexpr uint64_t r_squared_wasm_1 = 0x0000000000000400UL; static constexpr uint64_t r_squared_wasm_2 = 0x0000000000000000UL; static constexpr uint64_t r_squared_wasm_3 = 0x0000000000000000UL; + // A little-endian representation of the cube root of 1 in Fq in Montgomery form for wasm (R=2^261 mod modulus) + // split into 4 64-bit words static constexpr uint64_t cube_root_wasm_0 = 0x1486c3a0d03162ffUL; static constexpr uint64_t cube_root_wasm_1 = 0x7fbc2c63897015ebUL; static constexpr uint64_t cube_root_wasm_2 = 0x1d312f1a05c720a0UL; static constexpr uint64_t cube_root_wasm_3 = 0x4946d5d79767aa7fUL; + // Not used in secp256k1, since this is not for proving systems static constexpr uint64_t primitive_root_wasm_0 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_1 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_2 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_3 = 0x0000000000000000UL; + // Coset generators in Montgomery form for R=2^261 mod Modulus. Used in FFT-based proving systems, don't really need + // them here static constexpr uint64_t coset_generators_wasm_0[8] = { 0x0000006000016e60ULL, 0x000000800001e880ULL, 0x000000a0000262a0ULL, 0x000000c00002dcc0ULL, 0x000000e0000356e0ULL, 0x000001000003d100ULL, @@ -89,18 +133,50 @@ struct FqParams { using fq = field; struct FrParams { + + // A little-endian representation of the modulus split into 4 64-bit words static constexpr uint64_t modulus_0 = 0xBFD25E8CD0364141ULL; static constexpr uint64_t modulus_1 = 0xBAAEDCE6AF48A03BULL; static constexpr uint64_t modulus_2 = 0xFFFFFFFFFFFFFFFEULL; static constexpr uint64_t modulus_3 = 0xFFFFFFFFFFFFFFFFULL; + // A little-endian representation of R^2 modulo the modulus (R=2^256 mod modulus) split into 4 64-bit words static constexpr uint64_t r_squared_0 = 9902555850136342848ULL; static constexpr uint64_t r_squared_1 = 8364476168144746616ULL; static constexpr uint64_t r_squared_2 = 16616019711348246470ULL; static constexpr uint64_t r_squared_3 = 11342065889886772165ULL; + // -(Modulus^-1) mod 2^64 + // This is used to compute k = r_inv * lower_limb(scalar), such that scalar + k*modulus in integers would have 0 in + // the lowest limb By performing this sequentially for 4 limbs, we get an 8-limb representation of the scalar, where + // the lowest 4 limbs are zeros. Then we can immediately divide by 2^256 by simply getting rid of the lowest 4 limbs static constexpr uint64_t r_inv = 5408259542528602431ULL; + // 2^(-64) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 5 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_0 = 0x9d4ad302583de6dcUL; + static constexpr uint64_t r_inv_1 = 0xa09f710af0155525UL; + static constexpr uint64_t r_inv_2 = 0xffffffffffffffffUL; + static constexpr uint64_t r_inv_3 = 0x4b0dff665588b13eUL; + + // 2^(-29) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 10 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_wasm_0 = 0x3d864e; + static constexpr uint64_t r_inv_wasm_1 = 0x8b9f61c; + static constexpr uint64_t r_inv_wasm_2 = 0x3df60c0; + static constexpr uint64_t r_inv_wasm_3 = 0xa3c71eb; + static constexpr uint64_t r_inv_wasm_4 = 0x1ffff251; + static constexpr uint64_t r_inv_wasm_5 = 0x1fffffff; + static constexpr uint64_t r_inv_wasm_6 = 0x1fffffff; + static constexpr uint64_t r_inv_wasm_7 = 0x1effffff; + static constexpr uint64_t r_inv_wasm_8 = 0xac4589; + + // Coset generators in Montgomery form for R=2^261 mod Modulus. Used in FFT-based proving systems, don't really need + // them here static constexpr uint64_t coset_generators_0[8]{ 0x40e4273feef0b9bbULL, 0x8111c8b31eba787aULL, 0xc13f6a264e843739ULL, 0x16d0b997e4df5f8ULL, 0x419aad0cae17b4b7ULL, 0x81c84e7fdde17376ULL, 0xc1f5eff30dab3235ULL, 0x22391663d74f0f4ULL, @@ -116,11 +192,13 @@ struct FrParams { 0, 0, 0, 0, 0, 0, 0, 0, }; + // A little-endian representation of the cubic root of 1 in Fr in Montgomery form split into 4 64-bit words static constexpr uint64_t cube_root_0 = 0xf07deb3dc9926c9eULL; static constexpr uint64_t cube_root_1 = 0x2c93e7ad83c6944cULL; static constexpr uint64_t cube_root_2 = 0x73a9660652697d91ULL; static constexpr uint64_t cube_root_3 = 0x532840178558d639ULL; + // Not needed, since there is no endomorphism for secp256k1 static constexpr uint64_t endo_minus_b1_lo = 0x6F547FA90ABFE4C3ULL; static constexpr uint64_t endo_minus_b1_mid = 0xE4437ED6010E8828ULL; @@ -137,11 +215,14 @@ struct FrParams { static constexpr uint64_t endo_g2_hi = 0x6F547FA90ABFE4C4ULL; static constexpr uint64_t endo_g2_hihi = 0xE4437ED6010E8828ULL; + // Not used in secp256k1 static constexpr uint64_t primitive_root_0 = 0UL; static constexpr uint64_t primitive_root_1 = 0UL; static constexpr uint64_t primitive_root_2 = 0UL; static constexpr uint64_t primitive_root_3 = 0UL; + // A little-endian representation of the modulus split into 9 29-bit limbs + // This is used in wasm because we can only do multiplication with 64-bit result instead of 128-bit like in x86_64 static constexpr uint64_t modulus_wasm_0 = 0x10364141; static constexpr uint64_t modulus_wasm_1 = 0x1e92f466; static constexpr uint64_t modulus_wasm_2 = 0x12280eef; @@ -152,21 +233,28 @@ struct FrParams { static constexpr uint64_t modulus_wasm_7 = 0x1fffffff; static constexpr uint64_t modulus_wasm_8 = 0xffffff; + // A little-endian representation of R^2 modulo the modulus (R=2^261 mod modulus) split into 4 64-bit words + // We use 2^261 in wasm, because 261=29*9, the 9 29-bit limbs used for arithmetic in static constexpr uint64_t r_squared_wasm_0 = 0x63e601a3c9f6ab4bUL; static constexpr uint64_t r_squared_wasm_1 = 0xa2b6456d46702f57UL; static constexpr uint64_t r_squared_wasm_2 = 0x5fd7916f341f1cefUL; static constexpr uint64_t r_squared_wasm_3 = 0x9c7356071a6f179aUL; + // A little-endian representation of the cube root of 1 in Fr in Montgomery form for wasm (R=2^261 mod modulus) + // split into 4 64-bit words static constexpr uint64_t cube_root_wasm_0 = 0x9185b639102f0736UL; static constexpr uint64_t cube_root_wasm_1 = 0x47a854ad9ffc4748UL; static constexpr uint64_t cube_root_wasm_2 = 0x752cc0ca4d2fb232UL; static constexpr uint64_t cube_root_wasm_3 = 0x650802f0ab1ac72eUL; + // Not used in secp256k1 static constexpr uint64_t primitive_root_wasm_0 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_1 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_2 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_3 = 0x0000000000000000UL; + // Coset generators in Montgomery form for R=2^261 mod Modulus. Used in FFT-based proving systems, don't really need + // them here static constexpr uint64_t coset_generators_wasm_0[8] = { 0x1c84e7fdde173760ULL, 0x22391663d74f0f40ULL, 0x27ed44c9d086e720ULL, 0x2da1732fc9bebf00ULL, 0x3355a195c2f696e0ULL, 0x3909cffbbc2e6ec0ULL, diff --git a/barretenberg/cpp/src/barretenberg/ecc/curves/secp256r1/secp256r1.hpp b/barretenberg/cpp/src/barretenberg/ecc/curves/secp256r1/secp256r1.hpp index 69e8e89b477a..f0a454cf66aa 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/curves/secp256r1/secp256r1.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/curves/secp256r1/secp256r1.hpp @@ -6,18 +6,49 @@ namespace bb::secp256r1 { // NOLINTBEGIN(cppcoreguidelines-avoid-c-arrays) struct FqParams { + // A little-endian representation of the modulus split into 4 64-bit words static constexpr uint64_t modulus_0 = 0xFFFFFFFFFFFFFFFFULL; static constexpr uint64_t modulus_1 = 0x00000000FFFFFFFFULL; static constexpr uint64_t modulus_2 = 0x0000000000000000ULL; static constexpr uint64_t modulus_3 = 0xFFFFFFFF00000001ULL; + // A little-endian representation of R^2 modulo the modulus (R=2^256 mod modulus) split into 4 64-bit words static constexpr uint64_t r_squared_0 = 3ULL; static constexpr uint64_t r_squared_1 = 18446744056529682431ULL; static constexpr uint64_t r_squared_2 = 18446744073709551614ULL; static constexpr uint64_t r_squared_3 = 21474836477ULL; + // -(Modulus^-1) mod 2^64 + // This is used to compute k = r_inv * lower_limb(scalar), such that scalar + k*modulus in integers would have 0 in + // the lowest limb By performing this sequentially for 4 limbs, we get an 8-limb representation of the scalar, where + // the lowest 4 limbs are zeros. Then we can immediately divide by 2^256 by simply getting rid of the lowest 4 limbs static constexpr uint64_t r_inv = 1; + // 2^(-64) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 5 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_0 = 0x100000000UL; + static constexpr uint64_t r_inv_1 = 0x0UL; + static constexpr uint64_t r_inv_2 = 0xffffffff00000001UL; + static constexpr uint64_t r_inv_3 = 0x0UL; + + // 2^(-29) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 10 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_wasm_0 = 0x0; + static constexpr uint64_t r_inv_wasm_1 = 0x0; + static constexpr uint64_t r_inv_wasm_2 = 0x200; + static constexpr uint64_t r_inv_wasm_3 = 0x0; + static constexpr uint64_t r_inv_wasm_4 = 0x0; + static constexpr uint64_t r_inv_wasm_5 = 0x40000; + static constexpr uint64_t r_inv_wasm_6 = 0x1fe00000; + static constexpr uint64_t r_inv_wasm_7 = 0xffffff; + static constexpr uint64_t r_inv_wasm_8 = 0x0; + + // Coset generators in Montgomery form for R=2^256 mod Modulus. Used in FFT-based proving systems, don't really need + // them here static constexpr uint64_t coset_generators_0[8]{ 0x3ULL, 0x4ULL, 0x5ULL, 0x6ULL, 0x7ULL, 0x8ULL, 0x9ULL, 0xaULL, }; @@ -33,16 +64,21 @@ struct FqParams { 0x2fffffffcULL, 0x3fffffffbULL, 0x4fffffffaULL, 0x5fffffff9ULL, 0x6fffffff8ULL, 0x7fffffff7ULL, 0x8fffffff6ULL, 0x9fffffff5ULL, }; + + // Not used for secp256r1 static constexpr uint64_t cube_root_0 = 0UL; static constexpr uint64_t cube_root_1 = 0UL; static constexpr uint64_t cube_root_2 = 0UL; static constexpr uint64_t cube_root_3 = 0UL; + // Not used for secp256r1 static constexpr uint64_t primitive_root_0 = 0UL; static constexpr uint64_t primitive_root_1 = 0UL; static constexpr uint64_t primitive_root_2 = 0UL; static constexpr uint64_t primitive_root_3 = 0UL; + // A little-endian representation of the modulus split into 9 29-bit limbs + // This is used in wasm because we can only do multiplication with 64-bit result instead of 128-bit like in x86_64 static constexpr uint64_t modulus_wasm_0 = 0x1fffffff; static constexpr uint64_t modulus_wasm_1 = 0x1fffffff; static constexpr uint64_t modulus_wasm_2 = 0x1fffffff; @@ -53,21 +89,27 @@ struct FqParams { static constexpr uint64_t modulus_wasm_7 = 0x1fe00000; static constexpr uint64_t modulus_wasm_8 = 0xffffff; + // A little-endian representation of R^2 modulo the modulus (R=2^261 mod modulus) split into 4 64-bit words + // We use 2^261 in wasm, because 261=29*9, the 9 29-bit limbs used for arithmetic static constexpr uint64_t r_squared_wasm_0 = 0x0000000000000c00UL; static constexpr uint64_t r_squared_wasm_1 = 0xffffeffffffffc00UL; static constexpr uint64_t r_squared_wasm_2 = 0xfffffffffffffbffUL; static constexpr uint64_t r_squared_wasm_3 = 0x000013fffffff7ffUL; + // Not used for secp256r1 static constexpr uint64_t cube_root_wasm_0 = 0x0000000000000000UL; static constexpr uint64_t cube_root_wasm_1 = 0x0000000000000000UL; static constexpr uint64_t cube_root_wasm_2 = 0x0000000000000000UL; static constexpr uint64_t cube_root_wasm_3 = 0x0000000000000000UL; + // Not used for secp256r1 static constexpr uint64_t primitive_root_wasm_0 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_1 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_2 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_3 = 0x0000000000000000UL; + // Coset generators in Montgomery form for R=2^261 mod Modulus. Used in FFT-based proving systems, don't really need + // them here static constexpr uint64_t coset_generators_wasm_0[8] = { 0x0000000000000060ULL, 0x0000000000000080ULL, 0x00000000000000a0ULL, 0x00000000000000c0ULL, 0x00000000000000e0ULL, 0x0000000000000100ULL, @@ -88,18 +130,50 @@ struct FqParams { using fq = field; struct FrParams { + + // A little-endian representation of the modulus split into 4 64-bit words static constexpr uint64_t modulus_0 = 0xF3B9CAC2FC632551ULL; static constexpr uint64_t modulus_1 = 0xBCE6FAADA7179E84ULL; static constexpr uint64_t modulus_2 = 0xFFFFFFFFFFFFFFFFULL; static constexpr uint64_t modulus_3 = 0xFFFFFFFF00000000ULL; + // A little-endian representation of R^2 modulo the modulus (R=2^256 mod modulus) split into 4 64-bit words static constexpr uint64_t r_squared_0 = 9449762124159643298ULL; static constexpr uint64_t r_squared_1 = 5087230966250696614ULL; static constexpr uint64_t r_squared_2 = 2901921493521525849ULL; static constexpr uint64_t r_squared_3 = 7413256579398063648ULL; + // -(Modulus^-1) mod 2^64 + // This is used to compute k = r_inv * lower_limb(scalar), such that scalar + k*modulus in integers would have 0 in + // the lowest limb By performing this sequentially for 4 limbs, we get an 8-limb representation of the scalar, where + // the lowest 4 limbs are zeros. Then we can immediately divide by 2^256 by simply getting rid of the lowest 4 limbs static constexpr uint64_t r_inv = 14758798090332847183ULL; + // 2^(-64) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 5 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_0 = 0x230102a06d6251dcUL; + static constexpr uint64_t r_inv_1 = 0xca5113bcafc4ea28UL; + static constexpr uint64_t r_inv_2 = 0xded10c5bee00bc4eUL; + static constexpr uint64_t r_inv_3 = 0xccd1c8aa212ef3a4UL; + + // 2^(-29) mod Modulus + // Used in the reduction mechanism from https://hackmd.io/@Ingonyama/Barret-Montgomery + // Instead of computing k, we multiply the lowest limb by this value and then add to the following 5 limbs. + // This saves us from having to compute k + static constexpr uint64_t r_inv_wasm_0 = 0x8517c79; + static constexpr uint64_t r_inv_wasm_1 = 0x1edc694; + static constexpr uint64_t r_inv_wasm_2 = 0x459ee5c; + static constexpr uint64_t r_inv_wasm_3 = 0x705a6a8; + static constexpr uint64_t r_inv_wasm_4 = 0x1ffffe2a; + static constexpr uint64_t r_inv_wasm_5 = 0x113bffff; + static constexpr uint64_t r_inv_wasm_6 = 0x1621c017; + static constexpr uint64_t r_inv_wasm_7 = 0xef1ff43; + static constexpr uint64_t r_inv_wasm_8 = 0x7005e2; + + // Coset generators in Montgomery form for R=2^256 mod Modulus. Used in FFT-based proving systems, don't really need + // them here static constexpr uint64_t coset_generators_0[8]{ 0x55eb74ab1949fac9ULL, 0x6231a9e81ce6d578ULL, 0x6e77df252083b027ULL, 0x7abe146224208ad6ULL, 0x8704499f27bd6585ULL, 0x934a7edc2b5a4034ULL, 0x9f90b4192ef71ae3ULL, 0xabd6e9563293f592ULL, @@ -116,16 +190,20 @@ struct FrParams { 0xafffffff5ULL, 0xbfffffff4ULL, 0xcfffffff3ULL, 0xdfffffff2ULL, }; + // Not used for secp256r1 static constexpr uint64_t cube_root_0 = 0UL; static constexpr uint64_t cube_root_1 = 0UL; static constexpr uint64_t cube_root_2 = 0UL; static constexpr uint64_t cube_root_3 = 0UL; + // Not used for secp256r1 static constexpr uint64_t primitive_root_0 = 0UL; static constexpr uint64_t primitive_root_1 = 0UL; static constexpr uint64_t primitive_root_2 = 0UL; static constexpr uint64_t primitive_root_3 = 0UL; + // A little-endian representation of the modulus split into 9 29-bit limbs + // This is used in wasm because we can only do multiplication with 64-bit result instead of 128-bit like in x86_64 static constexpr uint64_t modulus_wasm_0 = 0x1c632551; static constexpr uint64_t modulus_wasm_1 = 0x1dce5617; static constexpr uint64_t modulus_wasm_2 = 0x5e7a13c; @@ -136,21 +214,27 @@ struct FrParams { static constexpr uint64_t modulus_wasm_7 = 0x1fe00000; static constexpr uint64_t modulus_wasm_8 = 0xffffff; + // A little-endian representation of R^2 modulo the modulus (R=2^261 mod modulus) split into 4 64-bit words + // We use 2^261 in wasm, because 261=29*9, the 9 29-bit limbs used for arithmetic static constexpr uint64_t r_squared_wasm_0 = 0x45e9cfeeb48d9ef5UL; static constexpr uint64_t r_squared_wasm_1 = 0x1f11fc5bb2d31a99UL; static constexpr uint64_t r_squared_wasm_2 = 0x16c8e4adafb16586UL; static constexpr uint64_t r_squared_wasm_3 = 0x84b6556a65587f06UL; + // Not used for secp256r1 static constexpr uint64_t cube_root_wasm_0 = 0x0000000000000000UL; static constexpr uint64_t cube_root_wasm_1 = 0x0000000000000000UL; static constexpr uint64_t cube_root_wasm_2 = 0x0000000000000000UL; static constexpr uint64_t cube_root_wasm_3 = 0x0000000000000000UL; + // Not used for secp256r1 static constexpr uint64_t primitive_root_wasm_0 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_1 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_2 = 0x0000000000000000UL; static constexpr uint64_t primitive_root_wasm_3 = 0x0000000000000000UL; + // Coset generators in Montgomery form for R=2^261 mod Modulus. Used in FFT-based proving systems, don't really need + // them here static constexpr uint64_t coset_generators_wasm_0[8] = { 0xbd6e9563293f5920ULL, 0x46353d039cdaaf00ULL, 0xcefbe4a4107604e0ULL, 0x57c28c4484115ac0ULL, 0xe08933e4f7acb0a0ULL, 0x694fdb856b480680ULL, diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp index 50d01844e0ea..edac5d79d2ba 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp @@ -195,6 +195,10 @@ template struct alignas(32) field { Params::modulus_wasm_4, Params::modulus_wasm_5, Params::modulus_wasm_6, Params::modulus_wasm_7, Params::modulus_wasm_8 }; + static constexpr std::array wasm_r_inv = { + Params::r_inv_wasm_0, Params::r_inv_wasm_1, Params::r_inv_wasm_2, Params::r_inv_wasm_3, Params::r_inv_wasm_4, + Params::r_inv_wasm_5, Params::r_inv_wasm_6, Params::r_inv_wasm_7, Params::r_inv_wasm_8 + }; #endif static constexpr field cube_root_of_unity() @@ -617,6 +621,16 @@ template struct alignas(32) field { uint64_t& result_6, uint64_t& result_7, uint64_t& result_8); + BB_INLINE static constexpr void wasm_reduce_yuval(uint64_t& result_0, + uint64_t& result_1, + uint64_t& result_2, + uint64_t& result_3, + uint64_t& result_4, + uint64_t& result_5, + uint64_t& result_6, + uint64_t& result_7, + uint64_t& result_8, + uint64_t& result_9); BB_INLINE static constexpr std::array wasm_convert(const uint64_t* data); #endif BB_INLINE static constexpr std::pair mul_wide(uint64_t a, uint64_t b) noexcept; diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_generic.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_generic.hpp index cb3b152d33ed..12caafe2f5aa 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_generic.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_generic.hpp @@ -514,6 +514,36 @@ constexpr void field::wasm_reduce(uint64_t& result_0, result_7 += k * wasm_modulus[7]; result_8 += k * wasm_modulus[8]; } + +/** + * @brief Perform 29-bit montgomery reduction on 1 limb using Yuval's method * + * @details https://hackmd.io/@Ingonyama/Barret-Montgomery + * + */ +template +constexpr void field::wasm_reduce_yuval(uint64_t& result_0, + uint64_t& result_1, + uint64_t& result_2, + uint64_t& result_3, + uint64_t& result_4, + uint64_t& result_5, + uint64_t& result_6, + uint64_t& result_7, + uint64_t& result_8, + uint64_t& result_9) +{ + constexpr uint64_t mask = 0x1fffffff; + const uint64_t result_0_masked = result_0 & mask; + result_1 += result_0_masked * wasm_r_inv[0] + (result_0 >> WASM_LIMB_BITS); + result_2 += result_0_masked * wasm_r_inv[1]; + result_3 += result_0_masked * wasm_r_inv[2]; + result_4 += result_0_masked * wasm_r_inv[3]; + result_5 += result_0_masked * wasm_r_inv[4]; + result_6 += result_0_masked * wasm_r_inv[5]; + result_7 += result_0_masked * wasm_r_inv[6]; + result_8 += result_0_masked * wasm_r_inv[7]; + result_9 += result_0_masked * wasm_r_inv[8]; +} /** * @brief Convert 4 64-bit limbs into 9 29-bit limbs * @@ -617,14 +647,32 @@ template constexpr field field::montgomery_mul(const field& othe wasm_madd(left[6], right, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14); wasm_madd(left[7], right, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15); wasm_madd(left[8], right, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15, temp_16); - wasm_reduce(temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8); - wasm_reduce(temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9); - wasm_reduce(temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10); - wasm_reduce(temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11); - wasm_reduce(temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12); - wasm_reduce(temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13); - wasm_reduce(temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14); - wasm_reduce(temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15); + + wasm_reduce_yuval(temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9); + wasm_reduce_yuval(temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10); + wasm_reduce_yuval(temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11); + wasm_reduce_yuval(temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12); + wasm_reduce_yuval(temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13); + wasm_reduce_yuval(temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14); + wasm_reduce_yuval(temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15); + wasm_reduce_yuval(temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15, temp_16); + + // In case there is some unforseen edge case encountered in wasm multiplications, we can quickly restore previous + // functionality. Comment all "wasm_reduce_yuval" and uncomment the following: + + // wasm_reduce(temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8); + // wasm_reduce(temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9); + // wasm_reduce(temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10); + // wasm_reduce(temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11); + // wasm_reduce(temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12); + // wasm_reduce(temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13); + // wasm_reduce(temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14); + // wasm_reduce(temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15); + + // The first 8 limbs are reduced using Yuval's method, the last one is reduced using the regular method + // The reason for this is that Yuval's method produces a 10-limb representation of the reduced limb, which is then + // added to the higher limbs. If we do this for the last limb we reduce, we'll get a 10-limb representation instead + // of a 9-limb one, so we'll have to reduce it again in some other way. wasm_reduce(temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15, temp_16); // Convert result to unrelaxed form (all limbs are 29 bits) @@ -804,14 +852,32 @@ template constexpr field field::montgomery_square() const noexce temp_16 += left[8] * left[8]; // Perform reductions - wasm_reduce(temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8); - wasm_reduce(temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9); - wasm_reduce(temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10); - wasm_reduce(temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11); - wasm_reduce(temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12); - wasm_reduce(temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13); - wasm_reduce(temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14); - wasm_reduce(temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15); + + wasm_reduce_yuval(temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9); + wasm_reduce_yuval(temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10); + wasm_reduce_yuval(temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11); + wasm_reduce_yuval(temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12); + wasm_reduce_yuval(temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13); + wasm_reduce_yuval(temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14); + wasm_reduce_yuval(temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15); + wasm_reduce_yuval(temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15, temp_16); + + // In case there is some unforseen edge case encountered in wasm multiplications, we can quickly restore previous + // functionality. Comment all "wasm_reduce_yuval" and uncomment the following: + + // wasm_reduce(temp_0, temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8); + // wasm_reduce(temp_1, temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9); + // wasm_reduce(temp_2, temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10); + // wasm_reduce(temp_3, temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11); + // wasm_reduce(temp_4, temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12); + // wasm_reduce(temp_5, temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13); + // wasm_reduce(temp_6, temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14); + // wasm_reduce(temp_7, temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15); + + // The first 8 limbs are reduced using Yuval's method, the last one is reduced using the regular method + // The reason for this is that Yuval's method produces a 10-limb representation of the reduced limb, which is then + // added to the higher limbs. If we do this for the last limb we reduce, we'll get a 10-limb representation instead + // of a 9-limb one, so we'll have to reduce it again in some other way. wasm_reduce(temp_8, temp_9, temp_10, temp_11, temp_12, temp_13, temp_14, temp_15, temp_16); // Convert to unrelaxed 29-bit form diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/parameter_helper.py b/barretenberg/cpp/src/barretenberg/ecc/fields/parameter_helper.py new file mode 100644 index 000000000000..7713a18d61b6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/parameter_helper.py @@ -0,0 +1,208 @@ +# coding: utf-8 +# A helper script to parse the field parameters from the source code + +import os + +parameter_files = ['src/barretenberg/ecc/curves/bn254/fq.hpp', 'src/barretenberg/ecc/curves/bn254/fr.hpp', + 'src/barretenberg/ecc/curves/secp256k1/secp256k1.hpp','src/barretenberg/ecc/curves/secp256r1/secp256r1.hpp'] + + +def get_file_location(): + """ + Returns the current file's location relative to the execution folder. + + Returns: + str: The path to the current file relative to the execution folder. + """ + return os.path.abspath(__file__) +full_paths=[os.path.join(os.path.join(os.path.dirname(get_file_location()),'../../../../'), file) for file in parameter_files] + +print(full_paths) + +import re +def parse_field_params(s): + def parse_number(line): + """Expects a string without whitespaces""" + line=line.replace('U','').replace('L','') # Clear away all postfixes + if line.find('0x')!=-1: # We have to parse hex + value= int(line,16) + else: + value = int(line) + return value + + def recover_single_value(name): + """Extract a single value from the source code by finding its name, equals sign, and semicolon""" + nonlocal s + index=s.find(name) + if index==-1: + raise ValueError("Couldn't find value with name "+name) + eq_position=s[index:].find('=') + line_end=s[index:].find(';') + return parse_number(s[index+eq_position+1:index+line_end]) + + def recover_single_value_if_present(name): + """Same as recover_single_value but returns None if the value is not found""" + nonlocal s + index=s.find(name) + if index==-1: + return None + eq_position=s[index:].find('=') + line_end=s[index:].find(';') + return parse_number(s[index+eq_position+1:index+line_end]) + + def recover_array(name): + """Extract an array of values from the source code by finding its name and contents between braces""" + nonlocal s + index = s.find(name) + number_of_elements=int(re.findall(r'(?<='+name+r'\[)\d+',s)[0]) + start_index=s[index:].find('{') + end_index=s[index:].find('}') + all_values=s[index+start_index+1:index+end_index] + result=[parse_number(x) for (i,x) in enumerate(all_values.split(',')) if i>=l + return limbs +def limbs_to_header_string(name,limbs,bool_wasm): + """Convert a list of limbs to a header string""" + return '\n\t'+'\n\t'.join([f"static constexpr uint64_t {name}_wasm_{i} = 0x{limbs[i]:x};" if bool_wasm else f"static constexpr uint64_t {name}_{i} = 0x{limbs[i]:x}UL;" for i in range(len(limbs))]) + + +def generate_pow_2_inverse_for_all_files(): + all_params=parse_all_files() + for file,param_name,params in all_params: + limb_64_inverse=generate_power_of_2_inverse(params,64) + limbs_64=convert_to_n_limbs_of_l_bits(limb_64_inverse,4,64) + header_string=limbs_to_header_string("r_inv",limbs_64,False) + limb_29_inverse=generate_power_of_2_inverse(params,29) + limbs_29=convert_to_n_limbs_of_l_bits(limb_29_inverse,9,29) + header_string+=limbs_to_header_string("r_inv",limbs_29,True) + short_file=file.split('/')[-1] + print(f"{short_file} {param_name}:") + print(header_string) + +parse_all_files()