diff --git a/noir-projects/noir-protocol-circuits/crates/blob/src/blob.nr b/noir-projects/noir-protocol-circuits/crates/blob/src/blob.nr index 6b1903e8c5b5..862dfad250c1 100644 --- a/noir-projects/noir-protocol-circuits/crates/blob/src/blob.nr +++ b/noir-projects/noir-protocol-circuits/crates/blob/src/blob.nr @@ -1,7 +1,7 @@ -// TODO(#9982): Replace unconstrained_config with config and import ROOTS - calculating ROOTS in unconstrained is insecure. use crate::{ blob_public_inputs::{BlobCommitment, BlobPublicInputs, BlockBlobPublicInputs}, - unconstrained_config::{compute_roots_of_unity, D_INV, F, LOG_FIELDS_PER_BLOB}, + config::{D_INV, F, LOG_FIELDS_PER_BLOB, ROOTS}, + unconstrained_config::compute_roots_of_unity, }; use bigint::{BigNum, BigNumTrait}; @@ -9,6 +9,7 @@ use bigint::{BigNum, BigNumTrait}; use types::hash::poseidon2_hash_subarray; // Variable hash method: // use types::hash::poseidon2_cheaper_variable_hash; +use std::ops::{Mul, Neg}; use types::{ abis::sponge_blob::SpongeBlob, constants::{BLOBS_PER_BLOCK, FIELDS_PER_BLOB}, @@ -185,7 +186,7 @@ pub fn evaluate_blobs( */ fn barycentric_evaluate_blob_at_z(z: F, ys: [F; FIELDS_PER_BLOB]) -> F { // TODO(#9982): Delete below and go back to using config.nr - calculating ROOTS in unconstrained is insecure. - let ROOTS = unsafe { compute_roots_of_unity() }; + let UNCONSTRAINED_ROOTS = unsafe { compute_roots_of_unity() }; // Note: it's more efficient (saving 30k constraints) to compute: // ___d-1 @@ -205,7 +206,7 @@ fn barycentric_evaluate_blob_at_z(z: F, ys: [F; FIELDS_PER_BLOB]) -> F { // i=0 // // perhaps because all the omega^i terms are constant witnesses? - let fracs = compute_fracs(z, ys, ROOTS); + let fracs = compute_fracs(z, ys, UNCONSTRAINED_ROOTS); // OK so...we can add multiple product terms into a sum...but I am not sure how many! // we are computing 254 * 254 bit products and we need to ensure each product limb doesn't overflow @@ -223,7 +224,8 @@ fn barycentric_evaluate_blob_at_z(z: F, ys: [F; FIELDS_PER_BLOB]) -> F { // i=0 let NUM_PARTIAL_SUMS = FIELDS_PER_BLOB / 8; /// Safety: This sum is checked by the following `BigNum::evaluate_quadratic_expression` calls. - let partial_sums: [F; FIELDS_PER_BLOB / 8] = unsafe { __compute_partial_sums(fracs, ROOTS) }; + let partial_sums: [F; FIELDS_PER_BLOB / 8] = + unsafe { __compute_partial_sums(fracs, UNCONSTRAINED_ROOTS) }; if !std::runtime::is_unconstrained() { // We split off the first term to check the initial sum @@ -269,20 +271,31 @@ fn barycentric_evaluate_blob_at_z(z: F, ys: [F; FIELDS_PER_BLOB]) -> F { // partial_sums[i] <- partial_sums[i-1] + (lhs[8*i] * rhs[8*i] + ... + lhs[8*i + 7] * rhs[8*i + 7]) // => (lhs[8*i] * rhs[8*i] + ... + lhs[8*i + 7] * rhs[8*i + 7]) + partial_sums[i-1] - partial_sums[i] == 0 - let mut lhs: [[F; 1]; 8] = [std::mem::zeroed(); 8]; - let mut rhs: [[F; 1]; 8] = [std::mem::zeroed(); 8]; - for j in 0..8 { - let k = i * 8 + j; - lhs[j] = [ROOTS[k]]; // omega^k - rhs[j] = [fracs[k]]; // y_k / (z - omega^k) - } - let linear_terms = [partial_sums[i - 1], partial_sums[i]]; BigNum::evaluate_quadratic_expression( - lhs, + /* lhs */ [ + [ROOTS[i * 8 + 0]], + [ROOTS[i * 8 + 1]], + [ROOTS[i * 8 + 2]], + [ROOTS[i * 8 + 3]], + [ROOTS[i * 8 + 4]], + [ROOTS[i * 8 + 5]], + [ROOTS[i * 8 + 6]], + [ROOTS[i * 8 + 7]], + ], [[false], [false], [false], [false], [false], [false], [false], [false]], - rhs, + /* rhs */ + [ + [fracs[i * 8 + 0]], + [fracs[i * 8 + 1]], + [fracs[i * 8 + 2]], + [fracs[i * 8 + 3]], + [fracs[i * 8 + 4]], + [fracs[i * 8 + 5]], + [fracs[i * 8 + 6]], + [fracs[i * 8 + 7]], + ], [[false], [false], [false], [false], [false], [false], [false], [false]], linear_terms, [false, true], @@ -343,11 +356,11 @@ fn compute_factor(z: F) -> F { unconstrained fn __compute_fracs( z: F, ys: [F; FIELDS_PER_BLOB], - ROOTS: [F; FIELDS_PER_BLOB], + unconstrained_roots: [F; FIELDS_PER_BLOB], ) -> [F; FIELDS_PER_BLOB] { let mut denoms = [BigNum::new(); FIELDS_PER_BLOB]; for i in 0..FIELDS_PER_BLOB { - denoms[i] = z.__sub(ROOTS[i]); // (z - omega^i) + denoms[i] = z.__sub(unconstrained_roots[i]); // (z - omega^i) } let inv_denoms = __batch_invert_impl(denoms); // 1 / (z - omega^i), for all i @@ -365,11 +378,11 @@ unconstrained fn __compute_fracs( fn compute_fracs( z: F, ys: [F; FIELDS_PER_BLOB], - ROOTS: [F; FIELDS_PER_BLOB], + unconstrained_roots: [F; FIELDS_PER_BLOB], ) -> [F; FIELDS_PER_BLOB] { /// Safety: We immediately constrain these `fracs` to be correct in the following call /// to `BigNum::evaluate_quadratic_expression`. - let mut fracs: [F; FIELDS_PER_BLOB] = unsafe { __compute_fracs(z, ys, ROOTS) }; + let mut fracs: [F; FIELDS_PER_BLOB] = unsafe { __compute_fracs(z, ys, unconstrained_roots) }; if !std::runtime::is_unconstrained() { for i in 0..FIELDS_PER_BLOB { @@ -392,7 +405,7 @@ fn compute_fracs( // TODO: Clean me unconstrained fn __compute_partial_sums( fracs: [F; FIELDS_PER_BLOB], - ROOTS: [F; FIELDS_PER_BLOB], + unconstrained_roots: [F; FIELDS_PER_BLOB], ) -> [F; FIELDS_PER_BLOB / 8] { let mut partial_sums: [F; FIELDS_PER_BLOB / 8] = std::mem::zeroed(); @@ -407,7 +420,7 @@ unconstrained fn __compute_partial_sums( let mut partial_sum: F = BigNum::new(); for i in 0..8 { // y_k * ( omega^k / (z - omega^k) ) - let summand = ROOTS[i].__mul(fracs[i]); + let summand = unconstrained_roots[i].__mul(fracs[i]); // partial_sum + ( y_k * ( omega^k / (z - omega^k) ) -> partial_sum partial_sum = partial_sum.__add(summand); @@ -426,7 +439,7 @@ unconstrained fn __compute_partial_sums( for j in 0..8 { let k = i * 8 + j; // y_k * ( omega^k / (z - omega^k) ) - let summand = ROOTS[k].__mul(fracs[k]); + let summand = unconstrained_roots[k].__mul(fracs[k]); // partial_sum + ( y_k * ( omega^k / (z - omega^k) ) -> partial_sum partial_sum = partial_sum.__add(summand); } @@ -444,14 +457,16 @@ mod tests { field_to_bignum, }, blob_public_inputs::BlobCommitment, - unconstrained_config::{D, D_INV, F}, + config::{D, D_INV, F}, }; use bigint::{BigNum, fields::bls12_381Fr::BLS12_381_Fr_Params}; + use bigint::bignum::BigNumTrait; use types::{ abis::sponge_blob::SpongeBlob, constants::{BLOBS_PER_BLOCK, FIELDS_PER_BLOB}, tests::{fixture_builder::FixtureBuilder, utils::pad_end}, }; + use types::traits::Serialize; #[test] unconstrained fn test_one_note() { diff --git a/noir-projects/noir-protocol-circuits/crates/blob/src/blob_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/blob/src/blob_public_inputs.nr index a318fd00ed9c..cbbe9f419482 100644 --- a/noir-projects/noir-protocol-circuits/crates/blob/src/blob_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/blob/src/blob_public_inputs.nr @@ -1,5 +1,4 @@ -use crate::unconstrained_config::F; -// TODO(#9982): Replace unconstrained_config with config. +use crate::config::F; use bigint::BigNum; use types::{ constants::{BLOB_PUBLIC_INPUTS, BLOBS_PER_BLOCK}, diff --git a/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr b/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr index 53f72447e2b1..a3a698e629b7 100644 --- a/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr +++ b/noir-projects/noir-protocol-circuits/crates/blob/src/config.nr @@ -7,8 +7,8 @@ pub type F = BigNum<3, 255, BLS12_381_Fr_Params>; pub global LOG_FIELDS_PER_BLOB: u32 = 12; pub global EXTRA_FIELDS_PER_BLOB: u32 = 16; // 16 = floor(4096 FIELDS_PER_BLOB / 254 noir_field_bits), wasting only 32 bits. -pub global NOIR_FIELDS_PER_BLOB: u32 = FIELDS_PER_BLOB + EXTRA_FIELDS_PER_BLOB; -pub global FIELDS_CARRYING_AN_EXTRA_BIT_PER_BLOB: u32 = EXTRA_FIELDS_PER_BLOB * 254; // EXTRA_FIELDS_PER_BLOB * 254 = 4064. So the first 4064 bls Fr fields in the blob will carry an extra bit in their 255th bit position, that will be used to reconstitute 16 extra fields. +// pub global NOIR_FIELDS_PER_BLOB: u32 = FIELDS_PER_BLOB + EXTRA_FIELDS_PER_BLOB; +// pub global FIELDS_CARRYING_AN_EXTRA_BIT_PER_BLOB: u32 = EXTRA_FIELDS_PER_BLOB * 254; // EXTRA_FIELDS_PER_BLOB * 254 = 4064. So the first 4064 bls Fr fields in the blob will carry an extra bit in their 255th bit position, that will be used to reconstitute 16 extra fields. pub global D: F = BigNum { limbs: [4096, 0, 0] }; pub global D_INV: F = BigNum { limbs: [0x686828bfce5c19400fffff00100001, 0x6878b46ae3705eb6a46a89213de7d3, 0x73e6] }; diff --git a/noir-projects/noir-protocol-circuits/crates/blob/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/blob/src/lib.nr index 1f83b3bb669f..560b6d8d4367 100644 --- a/noir-projects/noir-protocol-circuits/crates/blob/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/crates/blob/src/lib.nr @@ -1,5 +1,5 @@ mod blob_public_inputs; mod blob; mod mock_blob_oracle; +mod config; mod unconstrained_config; -// TODO(#9982): Replace unconstrained_config with config and import ROOTS - calculating ROOTS in unconstrained is insecure.