diff --git a/cpp/docs/src/sumcheck-outline.md b/cpp/docs/src/sumcheck-outline.md index 85081c448..651ce0189 100644 --- a/cpp/docs/src/sumcheck-outline.md +++ b/cpp/docs/src/sumcheck-outline.md @@ -16,7 +16,7 @@ The implementation consists of several components. At the stage of proving their evaluations at the challenge point, the multilinear witness polynomials fed to Sumcheck must not reveal any private information. We use a modification of Construction 3 described in Libra allowing the prover to open a new multilinear polynomial in \f$d\f$ variables, where \f$2^d\f$ is the circuit size, which is derived from the witnesses by adding a product of a random scalar and a public quadratic polynomial in \f$d\f$ variables -- [Total Costs:](#ZKCosts) The effect of adding Libra technique and masking evaluations of multilinear witnesses is assessed, and the theoretical upper bound on prover's work is compared to the implemenation costs. +- [Total Costs:](#ZKCosts) The effect of adding Libra technique and masking evaluations of multilinear witnesses is assessed, and the theoretical upper bound on prover's work is compared to the implementation costs. # Non ZK-Sumcheck Outline {#NonZKSumcheck} @@ -331,7 +331,7 @@ Using the PCS introduced in Section 4 of ::create_evaluation_masking_table "creates the vector" of univariates +To facilitate the computation of Sumcheck Round Univariates, the prover \ref bb::SumcheckProver< Flavor >::create_evaluation_masking_table "creates the vector" of univariates \f{align}{ \texttt{masking_terms_evaluations}_j(k)\gets \texttt{eval_masking_scalars}_j \cdot (1-k) k \f} @@ -424,7 +424,7 @@ In contrast to non-ZK-Sumcheck, the prover needs to compute \f$\tilde{D} \sim D+ \f{align}{ ((D+D_w)\cdot N + C_a \cdot (D+D_w) + 2\cdot N + 2\cdot (D+D_w) N_w ) (2^d - 1) \f} -addditions and +additions and \f{align}{ (C_m\cdot (D+D_w) + N) \cdot (2^d -1) \f} diff --git a/cpp/src/barretenberg/ecc/fields/field_docs.md b/cpp/src/barretenberg/ecc/fields/field_docs.md index 76f1bc306..912804f40 100644 --- a/cpp/src/barretenberg/ecc/fields/field_docs.md +++ b/cpp/src/barretenberg/ecc/fields/field_docs.md @@ -1,6 +1,6 @@ Prime field documentation {#field_docs} === -Barretenberg has its own implementation of finite field arithmetic. The implementation targets 254 (bn254, grumpkin) and 256-bit (secp256k1, secp256r1) fields. Internally the field is representate as a little-endian C-array of 4 uint64_t limbs. +Barretenberg has its own implementation of finite field arithmetic. The implementation targets 254 (bn254, grumpkin) and 256-bit (secp256k1, secp256r1) fields. Internally the field is represented as a little-endian C-array of 4 uint64_t limbs. ## Field arithmetic ### Introduction to Montgomery form {#field_docs_montgomery_explainer} @@ -18,7 +18,7 @@ The goal of using Montgomery form is to avoid heavy division modulo \f$p\f$. To Why does this work? Originally both \f$aR\f$ and \f$bR\f$ are less than the modulus \f$p\f$ in integers, so $$aR\cdot bR <= (p-1)^2$$ During each of the \f$k\cdot p\f$ addition rounds we can add at most \f$(2^{64}-1)p\f$ to corresponding digits, so at most we add \f$(2^{256}-1)p\f$ and the total is $$aR\cdot bR + k_{0,1,2,3}p \le (p-1)^2+(2^{256}-1)p < 2\cdot 2^{256}p \Rightarrow c_{r.high} = \frac{aR\cdot bR + k_{0,1,2,3}p}{2^{256}} < 2p$$. -For bn254 scalar and base fields we can do even better by employing a simple trick. The moduli of both fields are 254 bits, while 4 64-bit limbs allow 256 bits of storage. We relax the internal representation to use values in range \f$[0,2p)\f$. The addition, negation and subtraction operation logic doesn't change, we simply replace the modulus \f$p\f$ with \f$2p\f$, but the mutliplication becomes more efficient. The multiplicands are in range \f$[0,2p)\f$, but we add multiples of modulus \f$p\f$ to reduce limbs, not \f$2p\f$. If we revisit the \f$c_r\f$ formula: +For bn254 scalar and base fields we can do even better by employing a simple trick. The moduli of both fields are 254 bits, while 4 64-bit limbs allow 256 bits of storage. We relax the internal representation to use values in range \f$[0,2p)\f$. The addition, negation and subtraction operation logic doesn't change, we simply replace the modulus \f$p\f$ with \f$2p\f$, but the multiplication becomes more efficient. The multiplicands are in range \f$[0,2p)\f$, but we add multiples of modulus \f$p\f$ to reduce limbs, not \f$2p\f$. If we revisit the \f$c_r\f$ formula: $$aR\cdot bR + k_{0,1,2,3}p \le (2p-1)^2+(2^{256}-1)p = 2^{256}p+4p^2-5p+1 \Rightarrow$$ $$\Rightarrow c_{r.high} = \frac{aR\cdot bR + k_{0,1,2,3}p}{2^{256}} \le \frac{2^{256}p+4p^2-5p+1}{2^{256}}=p +\frac{4p^2 - 5p +1}{2^{256}}, 4p < 2^{256} \Rightarrow$$ $$\Rightarrow p +\frac{4p^2 - 5p +1}{2^{256}} < 2p$$ So we ended in the same range and we don't have to perform additional reductions. **N.B.** In the code we refer to this form as coarse @@ -42,7 +42,7 @@ You could say that for each multiplication or squaring primitive there are 3 imp 3. Implementation targeting WASM The generic implementation has 2 purposes: -1. Building barretenberg on platforms we haven't targetted in the past (new ARM-based Macs, for example) +1. Building barretenberg on platforms we haven't targeted in the past (new ARM-based Macs, for example) 2. Compile-time computation of constant expressions, since we can't use the assembly implementation for those. The assembly implementation for x86_64 is optimised. There are 2 versions: @@ -174,7 +174,7 @@ def parse_field_params(s): assert(parameter_dictionary['cube_root']*r_wasm_divided_by_r_regular%modulus==parameter_dictionary['cube_root_wasm']) assert(pow(parameter_dictionary['cube_root']*pow(2,-256,modulus),3,modulus)==1) # Check cubic root assert(pow(parameter_dictionary['cube_root_wasm']*pow(2,-29*9,modulus),3,modulus)==1) # Check cubic root for wasm - assert(parameter_dictionary['primitive_root']*r_wasm_divided_by_r_regular%modulus==parameter_dictionary['primitive_root_wasm']) # Check pritimitve roots are equivalent + assert(parameter_dictionary['primitive_root']*r_wasm_divided_by_r_regular%modulus==parameter_dictionary['primitive_root_wasm']) # Check primitive roots are equivalent for i in range(8): regular_coset_generator=reconstruct_field_from_4_parts([parameter_dictionary[f'coset_generators_{j}'][i] for j in range(4)]) wasm_coset_generator=reconstruct_field_from_4_parts([parameter_dictionary[f'coset_generators_wasm_{j}'][i] for j in range(4)]) @@ -187,4 +187,4 @@ Convert value from python to string for easy addition to bb's tests: ```python def to_ff(value): print ("FF(uint256_t{"+','.join(["0x%xUL"%((value>>(i*64))&((1<<64)-1))for i in range(4)])+"})") -``` \ No newline at end of file +```