Skip to content

Commit

Permalink
chore: pull out pedersen generator builtin from sync PR (#7210)
Browse files Browse the repository at this point in the history
This PR pulls out the changes related to implementing the pedersen
generator builtin from the sync PR to reduce the diff.
  • Loading branch information
TomAFrench committed Jun 27, 2024
1 parent f3c8166 commit 412f02e
Show file tree
Hide file tree
Showing 11 changed files with 132 additions and 18 deletions.
1 change: 1 addition & 0 deletions noir/noir-repo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use acvm_blackbox_solver::{blake2s, blake3, keccak256, keccakf1600, sha256};

use self::{
aes128::solve_aes128_encryption_opcode, bigint::AcvmBigIntSolver,
hash::solve_poseidon2_permutation_opcode, pedersen::pedersen_hash,
hash::solve_poseidon2_permutation_opcode,
};

use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError};
Expand All @@ -27,7 +27,7 @@ use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul};
// Hash functions should eventually be exposed for external consumers.
use hash::{solve_generic_256_hash_opcode, solve_sha_256_permutation_opcode};
use logic::{and, xor};
use pedersen::pedersen;
use pedersen::{pedersen, pedersen_hash};
pub(crate) use range::solve_range_opcode;
use signature::{
ecdsa::{secp256k1_prehashed, secp256r1_prehashed},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn default_generators() -> &'static [Affine<GrumpkinParameters>; NUM_DEFAULT_GEN
/// index-addressable generators.
///
/// [hash_to_curve]: super::hash_to_curve::hash_to_curve
pub(crate) fn derive_generators(
pub fn derive_generators(
domain_separator_bytes: &[u8],
num_generators: u32,
starting_index: u32,
Expand Down
13 changes: 8 additions & 5 deletions noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod schnorr;

use ark_ec::AffineRepr;
pub use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul};
pub use generator::generators::derive_generators;
pub use poseidon2::poseidon2_permutation;

// Temporary hack, this ensure that we always use a bn254 field here
Expand Down Expand Up @@ -47,11 +48,13 @@ impl BlackBoxFunctionSolver<FieldElement> for Bn254BlackBoxSolver {
) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> {
let inputs: Vec<grumpkin::Fq> = inputs.iter().map(|input| input.into_repr()).collect();
let result = pedersen::commitment::commit_native_with_index(&inputs, domain_separator);
let res_x =
FieldElement::from_repr(*result.x().expect("should not commit to point at infinity"));
let res_y =
FieldElement::from_repr(*result.y().expect("should not commit to point at infinity"));
Ok((res_x, res_y))
let result = if let Some((x, y)) = result.xy() {
(FieldElement::from_repr(*x), FieldElement::from_repr(*y))
} else {
(FieldElement::from(0_u128), FieldElement::from(0_u128))
};

Ok(result)
}

fn pedersen_hash(
Expand Down
1 change: 1 addition & 0 deletions noir/noir-repo/compiler/noirc_evaluator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ license.workspace = true
noirc_frontend.workspace = true
noirc_errors.workspace = true
acvm.workspace = true
bn254_blackbox_solver.workspace = true
fxhash.workspace = true
iter-extended.workspace = true
thiserror.workspace = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub(crate) enum Intrinsic {
AsField,
AsWitness,
IsUnconstrained,
DerivePedersenGenerators,
}

impl std::fmt::Display for Intrinsic {
Expand All @@ -92,6 +93,7 @@ impl std::fmt::Display for Intrinsic {
Intrinsic::AsField => write!(f, "as_field"),
Intrinsic::AsWitness => write!(f, "as_witness"),
Intrinsic::IsUnconstrained => write!(f, "is_unconstrained"),
Intrinsic::DerivePedersenGenerators => write!(f, "derive_pedersen_generators"),
}
}
}
Expand Down Expand Up @@ -120,7 +122,8 @@ impl Intrinsic {
| Intrinsic::StrAsBytes
| Intrinsic::FromField
| Intrinsic::AsField
| Intrinsic::IsUnconstrained => false,
| Intrinsic::IsUnconstrained
| Intrinsic::DerivePedersenGenerators => false,

// Some black box functions have side-effects
Intrinsic::BlackBox(func) => matches!(
Expand Down Expand Up @@ -155,6 +158,7 @@ impl Intrinsic {
"as_field" => Some(Intrinsic::AsField),
"as_witness" => Some(Intrinsic::AsWitness),
"is_unconstrained" => Some(Intrinsic::IsUnconstrained),
"derive_pedersen_generators" => Some(Intrinsic::DerivePedersenGenerators),
other => BlackBoxFunc::lookup(other).map(Intrinsic::BlackBox),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use fxhash::FxHashMap as HashMap;
use std::{collections::VecDeque, rc::Rc};

use acvm::{acir::AcirField, acir::BlackBoxFunc, BlackBoxResolutionError, FieldElement};
use bn254_blackbox_solver::derive_generators;
use iter_extended::vecmap;
use num_bigint::BigUint;

Expand Down Expand Up @@ -295,6 +296,13 @@ pub(super) fn simplify_call(
}
Intrinsic::AsWitness => SimplifyResult::None,
Intrinsic::IsUnconstrained => SimplifyResult::None,
Intrinsic::DerivePedersenGenerators => {
if let Some(Type::Array(_, len)) = ctrl_typevars.unwrap().first() {
simplify_derive_generators(dfg, arguments, *len as u32)
} else {
unreachable!("Derive Pedersen Generators must return an array");
}
}
}
}

Expand Down Expand Up @@ -438,7 +446,9 @@ fn simplify_black_box_func(
BlackBoxFunc::SHA256 => simplify_hash(dfg, arguments, acvm::blackbox_solver::sha256),
BlackBoxFunc::Blake2s => simplify_hash(dfg, arguments, acvm::blackbox_solver::blake2s),
BlackBoxFunc::Blake3 => simplify_hash(dfg, arguments, acvm::blackbox_solver::blake3),
BlackBoxFunc::Keccakf1600 => SimplifyResult::None, //TODO(Guillaume)
BlackBoxFunc::PedersenCommitment
| BlackBoxFunc::PedersenHash
| BlackBoxFunc::Keccakf1600 => SimplifyResult::None, //TODO(Guillaume)
BlackBoxFunc::Keccak256 => {
match (dfg.get_array_constant(arguments[0]), dfg.get_numeric_constant(arguments[1])) {
(Some((input, _)), Some(num_bytes)) if array_is_constant(dfg, &input) => {
Expand Down Expand Up @@ -468,8 +478,6 @@ fn simplify_black_box_func(

BlackBoxFunc::MultiScalarMul
| BlackBoxFunc::SchnorrVerify
| BlackBoxFunc::PedersenCommitment
| BlackBoxFunc::PedersenHash
| BlackBoxFunc::EmbeddedCurveAdd => {
// Currently unsolvable here as we rely on an implementation in the backend.
SimplifyResult::None
Expand Down Expand Up @@ -626,3 +634,47 @@ fn simplify_signature(
_ => SimplifyResult::None,
}
}

fn simplify_derive_generators(
dfg: &mut DataFlowGraph,
arguments: &[ValueId],
num_generators: u32,
) -> SimplifyResult {
if arguments.len() == 2 {
let domain_separator_string = dfg.get_array_constant(arguments[0]);
let starting_index = dfg.get_numeric_constant(arguments[1]);
if let (Some(domain_separator_string), Some(starting_index)) =
(domain_separator_string, starting_index)
{
let domain_separator_bytes = domain_separator_string
.0
.iter()
.map(|&x| dfg.get_numeric_constant(x).unwrap().to_u128() as u8)
.collect::<Vec<u8>>();
let generators = derive_generators(
&domain_separator_bytes,
num_generators,
starting_index.try_to_u32().expect("argument is declared as u32"),
);
let is_infinite = dfg.make_constant(FieldElement::zero(), Type::bool());
let mut results = Vec::new();
for gen in generators {
let x_big: BigUint = gen.x.into();
let x = FieldElement::from_be_bytes_reduce(&x_big.to_bytes_be());
let y_big: BigUint = gen.y.into();
let y = FieldElement::from_be_bytes_reduce(&y_big.to_bytes_be());
results.push(dfg.make_constant(x, Type::field()));
results.push(dfg.make_constant(y, Type::field()));
results.push(is_infinite);
}
let len = results.len();
let result =
dfg.make_array(results.into(), Type::Array(vec![Type::field()].into(), len));
SimplifyResult::SimplifiedTo(result)
} else {
SimplifyResult::None
}
} else {
unreachable!("Unexpected number of arguments to derive_generators");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,8 @@ impl Context {
| Intrinsic::AsField
| Intrinsic::AsSlice
| Intrinsic::AsWitness
| Intrinsic::IsUnconstrained => false,
| Intrinsic::IsUnconstrained
| Intrinsic::DerivePedersenGenerators => false,
},

// We must assume that functions contain a side effect as we cannot inspect more deeply.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ fn slice_capacity_change(
| Intrinsic::FromField
| Intrinsic::AsField
| Intrinsic::AsWitness
| Intrinsic::IsUnconstrained => SizeChange::None,
| Intrinsic::IsUnconstrained
| Intrinsic::DerivePedersenGenerators => SizeChange::None,
}
}
8 changes: 8 additions & 0 deletions noir/noir-repo/noir_stdlib/src/embedded_curve_ops.nr
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ struct EmbeddedCurveScalar {
hi: Field,
}

impl EmbeddedCurveScalar {
#[field(bn254)]
fn from_field(scalar: Field) -> EmbeddedCurveScalar {
let (a,b) = crate::field::bn254::decompose(scalar);
EmbeddedCurveScalar { lo: a, hi: b }
}
}

// Computes a multi scalar multiplication over the embedded curve.
// For bn254, We have Grumpkin and Baby JubJub.
// For bls12-381, we have JubJub and Bandersnatch.
Expand Down
51 changes: 47 additions & 4 deletions noir/noir-repo/noir_stdlib/src/hash.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod poseidon2;
use crate::default::Default;
use crate::uint128::U128;
use crate::sha256::{digest, sha256_var};
use crate::embedded_curve_ops::EmbeddedCurvePoint;
use crate::embedded_curve_ops::{EmbeddedCurvePoint, EmbeddedCurveScalar, multi_scalar_mul};

#[foreign(sha256)]
// docs:start:sha256
Expand All @@ -28,11 +28,23 @@ pub fn blake3<N>(input: [u8; N]) -> [u8; 32]
// docs:start:pedersen_commitment
pub fn pedersen_commitment<N>(input: [Field; N]) -> EmbeddedCurvePoint {
// docs:end:pedersen_commitment
pedersen_commitment_with_separator(input, 0)
let value = pedersen_commitment_with_separator(input, 0);
if (value.x == 0) & (value.y == 0) {
EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true }
} else {
EmbeddedCurvePoint { x: value.x, y: value.y, is_infinite: false }
}
}

#[foreign(pedersen_commitment)]
pub fn __pedersen_commitment_with_separator<N>(input: [Field; N], separator: u32) -> [Field; 2] {}
fn pedersen_commitment_with_separator_noir<N>(input: [Field; N], separator: u32) -> EmbeddedCurvePoint {
let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N];
for i in 0..N {
points[i] = EmbeddedCurveScalar::from_field(input[i]);
}
let generators = derive_generators("DEFAULT_DOMAIN_SEPARATOR".as_bytes(), separator);
let values = multi_scalar_mul(generators, points);
EmbeddedCurvePoint { x: values[0], y: values[1], is_infinite: values[2] as bool }
}

pub fn pedersen_commitment_with_separator<N>(input: [Field; N], separator: u32) -> EmbeddedCurvePoint {
let values = __pedersen_commitment_with_separator(input, separator);
Expand All @@ -46,9 +58,32 @@ pub fn pedersen_hash<N>(input: [Field; N]) -> Field
pedersen_hash_with_separator(input, 0)
}

#[field(bn254)]
fn derive_generators<N, M>(domain_separator_bytes: [u8; M], starting_index: u32) -> [EmbeddedCurvePoint; N] {
crate::assert_constant(domain_separator_bytes);
crate::assert_constant(starting_index);
__derive_generators(domain_separator_bytes, starting_index)
}

#[builtin(derive_pedersen_generators)]
#[field(bn254)]
fn __derive_generators<N, M>(domain_separator_bytes: [u8; M], starting_index: u32) -> [EmbeddedCurvePoint; N] {}

fn pedersen_hash_with_separator_noir<N>(input: [Field; N], separator: u32) -> Field {
let v1 = pedersen_commitment_with_separator(input, separator);
let length_generator : [EmbeddedCurvePoint; 1] = derive_generators("pedersen_hash_length".as_bytes(), 0);
multi_scalar_mul(
[length_generator[0], v1],
[EmbeddedCurveScalar { lo: N as Field, hi: 0 }, EmbeddedCurveScalar { lo: 1, hi: 0 }]
)[0]
}

#[foreign(pedersen_hash)]
pub fn pedersen_hash_with_separator<N>(input: [Field; N], separator: u32) -> Field {}

#[foreign(pedersen_commitment)]
fn __pedersen_commitment_with_separator<N>(input: [Field; N], separator: u32) -> [Field; 2] {}

pub fn hash_to_field(inputs: [Field]) -> Field {
let mut sum = 0;

Expand Down Expand Up @@ -222,3 +257,11 @@ impl<A, B, C, D, E> Hash for (A, B, C, D, E) where A: Hash, B: Hash, C: Hash, D:
self.4.hash(state);
}
}

#[test]
fn assert_pedersen_noir() {
// TODO: make this a fuzzer test once fuzzer supports curve-specific blackbox functions.
let input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq(pedersen_hash_with_separator(input, 4), pedersen_hash_with_separator_noir(input, 4));
assert_eq(pedersen_commitment_with_separator(input, 4), pedersen_commitment_with_separator_noir(input, 4));
}

0 comments on commit 412f02e

Please sign in to comment.