Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: pedersen hash in Noir #5217

Merged
merged 16 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

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 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 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
6 changes: 5 additions & 1 deletion compiler/noirc_evaluator/src/ssa/ir/instruction.rs
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
52 changes: 52 additions & 0 deletions compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs
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 @@ -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
3 changes: 2 additions & 1 deletion compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs
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,
}
}
30 changes: 26 additions & 4 deletions 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};

#[foreign(sha256)]
// docs:start:sha256
Expand All @@ -28,7 +28,12 @@ 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)]
Expand All @@ -46,8 +51,25 @@ pub fn pedersen_hash<N>(input: [Field; N]) -> Field
pedersen_hash_with_separator(input, 0)
}

#[foreign(pedersen_hash)]
pub fn pedersen_hash_with_separator<N>(input: [Field; N], separator: u32) -> Field {}
#[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)]
guipublic marked this conversation as resolved.
Show resolved Hide resolved
#[field(bn254)]
fn __derive_generators<N, M>(domain_separator_bytes: [u8; M], starting_index: u32) -> [EmbeddedCurvePoint; N] {}

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

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