Skip to content

Commit

Permalink
feat: reenable constrained config for roots (#10605)
Browse files Browse the repository at this point in the history
This PR replaces the oracle calls used to calculate the roots of unity
with constants which can be written directly into the bytecode now that
we're not passing it across the unconstrained boundary.

---------

Co-authored-by: Michael Connor <mike@aztecprotocol.com>
  • Loading branch information
TomAFrench and iAmMichaelConnor authored Jan 16, 2025
1 parent d254f49 commit a6ebc2e
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 28 deletions.
61 changes: 38 additions & 23 deletions noir-projects/noir-protocol-circuits/crates/blob/src/blob.nr
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// 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};
// Fixed hash method:
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},
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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],
Expand Down Expand Up @@ -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

Expand All @@ -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 {
Expand All @@ -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();

Expand All @@ -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);
Expand All @@ -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);
}
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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] };
Expand Down
Original file line number Diff line number Diff line change
@@ -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.

0 comments on commit a6ebc2e

Please sign in to comment.