Skip to content

Commit 919020d

Browse files
committed
chore: add documentation to to_be_bytes, etc. (noir-lang/noir#5843)
feat: simplify constant calls to `poseidon2_permutation`, `schnorr_verify` and `embedded_curve_add` (noir-lang/noir#5140) chore: don't require empty `Prover.toml` for programs with zero arguments but a return value (noir-lang/noir#5845) fix!: Check unused generics are bound (noir-lang/noir#5840) chore(perf): Simplify poseidon2 algorithm (noir-lang/noir#5811) chore: redo typo PR by nnsW3 (noir-lang/noir#5834) fix(sha256): Perform compression per block and utilize ROM instead of RAM when setting up the message block (noir-lang/noir#5760) chore(perf): Update to stdlib keccak for reduced Brillig code size (noir-lang/noir#5827)
2 parents 65549e4 + c7d5ee9 commit 919020d

File tree

27 files changed

+432
-54
lines changed

27 files changed

+432
-54
lines changed

.noir-sync-commit

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
86c151aa43ba990a0e900995064a88fc2ae6637d
1+
c7473c6fcc6cbfd118b0352229ff86001cde3a64

noir/noir-repo/Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

noir/noir-repo/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ criterion = "0.5.0"
130130
# https://github.com/tikv/pprof-rs/pull/172
131131
pprof = { version = "0.13", features = ["flamegraph", "criterion"] }
132132

133-
133+
cfg-if = "1.0.0"
134134
dirs = "4"
135135
serde = { version = "1.0.136", features = ["derive"] }
136136
serde_json = "1.0"

noir/noir-repo/acvm-repo/acir_field/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ ark-bn254.workspace = true
2424
ark-bls12-381 = { workspace = true, optional = true }
2525
ark-ff.workspace = true
2626

27-
cfg-if = "1.0.0"
27+
cfg-if.workspace = true
2828

2929
[dev-dependencies]
3030
proptest.workspace = true

noir/noir-repo/compiler/noirc_driver/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@ rust-embed.workspace = true
2929
tracing.workspace = true
3030

3131
aztec_macros = { path = "../../aztec_macros" }
32+
33+
[features]
34+
bn254 = ["noirc_frontend/bn254", "noirc_evaluator/bn254"]
35+
bls12_381 = ["noirc_frontend/bls12_381", "noirc_evaluator/bls12_381"]

noir/noir-repo/compiler/noirc_driver/src/lib.rs

-5
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,6 @@ pub struct CompileOptions {
129129
/// This check should always be run on production code.
130130
#[arg(long)]
131131
pub skip_underconstrained_check: bool,
132-
133-
/// A workspace is compiled in parallel by default. This flag will compile it sequentially.
134-
/// This flag is useful to reduce memory consumption or to avoid using rayon threads for compilation (which don't have dynamic stacks).
135-
#[arg(long)]
136-
pub sequential: bool,
137132
}
138133

139134
pub fn parse_expression_width(input: &str) -> Result<ExpressionWidth, std::io::Error> {

noir/noir-repo/compiler/noirc_evaluator/Cargo.toml

+6-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ serde_json.workspace = true
2626
serde_with = "3.2.0"
2727
tracing.workspace = true
2828
chrono = "0.4.37"
29+
cfg-if.workspace = true
2930

3031
[dev-dependencies]
31-
proptest.workspace = true
32+
proptest.workspace = true
33+
34+
[features]
35+
bn254 = ["noirc_frontend/bn254"]
36+
bls12_381= []

noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use crate::ssa::ir::{instruction::Endian, types::NumericType};
1010
use acvm::acir::circuit::brillig::{BrilligFunctionId, BrilligInputs, BrilligOutputs};
1111
use acvm::acir::circuit::opcodes::{AcirFunctionId, BlockId, BlockType, MemOp};
1212
use acvm::acir::circuit::{AssertionPayload, ExpressionOrMemory, ExpressionWidth, Opcode};
13-
use acvm::blackbox_solver;
1413
use acvm::brillig_vm::{MemoryValue, VMStatus, VM};
1514
use acvm::{
1615
acir::AcirField,
@@ -2152,7 +2151,11 @@ fn execute_brillig<F: AcirField>(
21522151
}
21532152

21542153
// Instantiate a Brillig VM given the solved input registers and memory, along with the Brillig bytecode.
2155-
let mut vm = VM::new(calldata, code, Vec::new(), &blackbox_solver::StubbedBlackBoxSolver);
2154+
//
2155+
// We pass a stubbed solver here as a concrete solver implies a field choice which conflicts with this function
2156+
// being generic.
2157+
let solver = acvm::blackbox_solver::StubbedBlackBoxSolver;
2158+
let mut vm = VM::new(calldata, code, Vec::new(), &solver);
21562159

21572160
// Run the Brillig VM on these inputs, bytecode, etc!
21582161
let vm_status = vm.process_opcodes();

noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs

+31-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use fxhash::FxHashMap as HashMap;
22
use std::{collections::VecDeque, rc::Rc};
33

4-
use acvm::{acir::AcirField, acir::BlackBoxFunc, BlackBoxResolutionError, FieldElement};
4+
use acvm::{
5+
acir::{AcirField, BlackBoxFunc},
6+
BlackBoxResolutionError, FieldElement,
7+
};
58
use bn254_blackbox_solver::derive_generators;
69
use iter_extended::vecmap;
710
use num_bigint::BigUint;
@@ -20,6 +23,8 @@ use crate::ssa::{
2023

2124
use super::{Binary, BinaryOp, Endian, Instruction, SimplifyResult};
2225

26+
mod blackbox;
27+
2328
/// Try to simplify this call instruction. If the instruction can be simplified to a known value,
2429
/// that value is returned. Otherwise None is returned.
2530
///
@@ -468,11 +473,17 @@ fn simplify_black_box_func(
468473
arguments: &[ValueId],
469474
dfg: &mut DataFlowGraph,
470475
) -> SimplifyResult {
476+
cfg_if::cfg_if! {
477+
if #[cfg(feature = "bn254")] {
478+
let solver = bn254_blackbox_solver::Bn254BlackBoxSolver;
479+
} else {
480+
let solver = acvm::blackbox_solver::StubbedBlackBoxSolver;
481+
}
482+
};
471483
match bb_func {
472484
BlackBoxFunc::SHA256 => simplify_hash(dfg, arguments, acvm::blackbox_solver::sha256),
473485
BlackBoxFunc::Blake2s => simplify_hash(dfg, arguments, acvm::blackbox_solver::blake2s),
474486
BlackBoxFunc::Blake3 => simplify_hash(dfg, arguments, acvm::blackbox_solver::blake3),
475-
BlackBoxFunc::PedersenCommitment | BlackBoxFunc::PedersenHash => SimplifyResult::None,
476487
BlackBoxFunc::Keccakf1600 => {
477488
if let Some((array_input, _)) = dfg.get_array_constant(arguments[0]) {
478489
if array_is_constant(dfg, &array_input) {
@@ -503,20 +514,26 @@ fn simplify_black_box_func(
503514
BlackBoxFunc::Keccak256 => {
504515
unreachable!("Keccak256 should have been replaced by calls to Keccakf1600")
505516
}
506-
BlackBoxFunc::Poseidon2Permutation => SimplifyResult::None, //TODO(Guillaume)
507-
BlackBoxFunc::EcdsaSecp256k1 => {
508-
simplify_signature(dfg, arguments, acvm::blackbox_solver::ecdsa_secp256k1_verify)
509-
}
510-
BlackBoxFunc::EcdsaSecp256r1 => {
511-
simplify_signature(dfg, arguments, acvm::blackbox_solver::ecdsa_secp256r1_verify)
517+
BlackBoxFunc::Poseidon2Permutation => {
518+
blackbox::simplify_poseidon2_permutation(dfg, solver, arguments)
512519
}
520+
BlackBoxFunc::EcdsaSecp256k1 => blackbox::simplify_signature(
521+
dfg,
522+
arguments,
523+
acvm::blackbox_solver::ecdsa_secp256k1_verify,
524+
),
525+
BlackBoxFunc::EcdsaSecp256r1 => blackbox::simplify_signature(
526+
dfg,
527+
arguments,
528+
acvm::blackbox_solver::ecdsa_secp256r1_verify,
529+
),
530+
531+
BlackBoxFunc::PedersenCommitment
532+
| BlackBoxFunc::PedersenHash
533+
| BlackBoxFunc::MultiScalarMul => SimplifyResult::None,
534+
BlackBoxFunc::EmbeddedCurveAdd => blackbox::simplify_ec_add(dfg, solver, arguments),
535+
BlackBoxFunc::SchnorrVerify => blackbox::simplify_schnorr_verify(dfg, solver, arguments),
513536

514-
BlackBoxFunc::MultiScalarMul
515-
| BlackBoxFunc::SchnorrVerify
516-
| BlackBoxFunc::EmbeddedCurveAdd => {
517-
// Currently unsolvable here as we rely on an implementation in the backend.
518-
SimplifyResult::None
519-
}
520537
BlackBoxFunc::BigIntAdd
521538
| BlackBoxFunc::BigIntSub
522539
| BlackBoxFunc::BigIntMul
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
use std::rc::Rc;
2+
3+
use acvm::{acir::AcirField, BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement};
4+
use iter_extended::vecmap;
5+
6+
use crate::ssa::ir::{
7+
dfg::DataFlowGraph, instruction::SimplifyResult, types::Type, value::ValueId,
8+
};
9+
10+
use super::{array_is_constant, make_constant_array, to_u8_vec};
11+
12+
pub(super) fn simplify_ec_add(
13+
dfg: &mut DataFlowGraph,
14+
solver: impl BlackBoxFunctionSolver<FieldElement>,
15+
arguments: &[ValueId],
16+
) -> SimplifyResult {
17+
match (
18+
dfg.get_numeric_constant(arguments[0]),
19+
dfg.get_numeric_constant(arguments[1]),
20+
dfg.get_numeric_constant(arguments[2]),
21+
dfg.get_numeric_constant(arguments[3]),
22+
dfg.get_numeric_constant(arguments[4]),
23+
dfg.get_numeric_constant(arguments[5]),
24+
) {
25+
(
26+
Some(point1_x),
27+
Some(point1_y),
28+
Some(point1_is_infinity),
29+
Some(point2_x),
30+
Some(point2_y),
31+
Some(point2_is_infinity),
32+
) => {
33+
let Ok((result_x, result_y, result_is_infinity)) = solver.ec_add(
34+
&point1_x,
35+
&point1_y,
36+
&point1_is_infinity,
37+
&point2_x,
38+
&point2_y,
39+
&point2_is_infinity,
40+
) else {
41+
return SimplifyResult::None;
42+
};
43+
44+
let result_x = dfg.make_constant(result_x, Type::field());
45+
let result_y = dfg.make_constant(result_y, Type::field());
46+
let result_is_infinity = dfg.make_constant(result_is_infinity, Type::bool());
47+
48+
let typ = Type::Array(Rc::new(vec![Type::field()]), 3);
49+
let result_array =
50+
dfg.make_array(im::vector![result_x, result_y, result_is_infinity], typ);
51+
52+
SimplifyResult::SimplifiedTo(result_array)
53+
}
54+
_ => SimplifyResult::None,
55+
}
56+
}
57+
58+
pub(super) fn simplify_poseidon2_permutation(
59+
dfg: &mut DataFlowGraph,
60+
solver: impl BlackBoxFunctionSolver<FieldElement>,
61+
arguments: &[ValueId],
62+
) -> SimplifyResult {
63+
match (dfg.get_array_constant(arguments[0]), dfg.get_numeric_constant(arguments[1])) {
64+
(Some((state, _)), Some(state_length)) if array_is_constant(dfg, &state) => {
65+
let state: Vec<FieldElement> = state
66+
.iter()
67+
.map(|id| {
68+
dfg.get_numeric_constant(*id)
69+
.expect("value id from array should point at constant")
70+
})
71+
.collect();
72+
73+
let Some(state_length) = state_length.try_to_u32() else {
74+
return SimplifyResult::None;
75+
};
76+
77+
let Ok(new_state) = solver.poseidon2_permutation(&state, state_length) else {
78+
return SimplifyResult::None;
79+
};
80+
81+
let result_array = make_constant_array(dfg, new_state, Type::field());
82+
83+
SimplifyResult::SimplifiedTo(result_array)
84+
}
85+
_ => SimplifyResult::None,
86+
}
87+
}
88+
89+
pub(super) fn simplify_schnorr_verify(
90+
dfg: &mut DataFlowGraph,
91+
solver: impl BlackBoxFunctionSolver<FieldElement>,
92+
arguments: &[ValueId],
93+
) -> SimplifyResult {
94+
match (
95+
dfg.get_numeric_constant(arguments[0]),
96+
dfg.get_numeric_constant(arguments[1]),
97+
dfg.get_array_constant(arguments[2]),
98+
dfg.get_array_constant(arguments[3]),
99+
) {
100+
(Some(public_key_x), Some(public_key_y), Some((signature, _)), Some((message, _)))
101+
if array_is_constant(dfg, &signature) && array_is_constant(dfg, &message) =>
102+
{
103+
let signature = to_u8_vec(dfg, signature);
104+
let signature: [u8; 64] =
105+
signature.try_into().expect("Compiler should produce correctly sized signature");
106+
107+
let message = to_u8_vec(dfg, message);
108+
109+
let Ok(valid_signature) =
110+
solver.schnorr_verify(&public_key_x, &public_key_y, &signature, &message)
111+
else {
112+
return SimplifyResult::None;
113+
};
114+
115+
let valid_signature = dfg.make_constant(valid_signature.into(), Type::bool());
116+
SimplifyResult::SimplifiedTo(valid_signature)
117+
}
118+
_ => SimplifyResult::None,
119+
}
120+
}
121+
122+
pub(super) fn simplify_hash(
123+
dfg: &mut DataFlowGraph,
124+
arguments: &[ValueId],
125+
hash_function: fn(&[u8]) -> Result<[u8; 32], BlackBoxResolutionError>,
126+
) -> SimplifyResult {
127+
match dfg.get_array_constant(arguments[0]) {
128+
Some((input, _)) if array_is_constant(dfg, &input) => {
129+
let input_bytes: Vec<u8> = to_u8_vec(dfg, input);
130+
131+
let hash = hash_function(&input_bytes)
132+
.expect("Rust solvable black box function should not fail");
133+
134+
let hash_values = vecmap(hash, |byte| FieldElement::from_be_bytes_reduce(&[byte]));
135+
136+
let result_array = make_constant_array(dfg, hash_values, Type::unsigned(8));
137+
SimplifyResult::SimplifiedTo(result_array)
138+
}
139+
_ => SimplifyResult::None,
140+
}
141+
}
142+
143+
type ECDSASignatureVerifier = fn(
144+
hashed_msg: &[u8],
145+
public_key_x: &[u8; 32],
146+
public_key_y: &[u8; 32],
147+
signature: &[u8; 64],
148+
) -> Result<bool, BlackBoxResolutionError>;
149+
150+
pub(super) fn simplify_signature(
151+
dfg: &mut DataFlowGraph,
152+
arguments: &[ValueId],
153+
signature_verifier: ECDSASignatureVerifier,
154+
) -> SimplifyResult {
155+
match (
156+
dfg.get_array_constant(arguments[0]),
157+
dfg.get_array_constant(arguments[1]),
158+
dfg.get_array_constant(arguments[2]),
159+
dfg.get_array_constant(arguments[3]),
160+
) {
161+
(
162+
Some((public_key_x, _)),
163+
Some((public_key_y, _)),
164+
Some((signature, _)),
165+
Some((hashed_message, _)),
166+
) if array_is_constant(dfg, &public_key_x)
167+
&& array_is_constant(dfg, &public_key_y)
168+
&& array_is_constant(dfg, &signature)
169+
&& array_is_constant(dfg, &hashed_message) =>
170+
{
171+
let public_key_x: [u8; 32] = to_u8_vec(dfg, public_key_x)
172+
.try_into()
173+
.expect("ECDSA public key fields are 32 bytes");
174+
let public_key_y: [u8; 32] = to_u8_vec(dfg, public_key_y)
175+
.try_into()
176+
.expect("ECDSA public key fields are 32 bytes");
177+
let signature: [u8; 64] =
178+
to_u8_vec(dfg, signature).try_into().expect("ECDSA signatures are 64 bytes");
179+
let hashed_message: Vec<u8> = to_u8_vec(dfg, hashed_message);
180+
181+
let valid_signature =
182+
signature_verifier(&hashed_message, &public_key_x, &public_key_y, &signature)
183+
.expect("Rust solvable black box function should not fail");
184+
185+
let valid_signature = dfg.make_constant(valid_signature.into(), Type::bool());
186+
SimplifyResult::SimplifiedTo(valid_signature)
187+
}
188+
_ => SimplifyResult::None,
189+
}
190+
}

noir/noir-repo/compiler/noirc_frontend/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ num-traits.workspace = true
2727
rustc-hash = "1.1.0"
2828
small-ord-set = "0.1.3"
2929
regex = "1.9.1"
30-
cfg-if = "1.0.0"
30+
cfg-if.workspace = true
3131
tracing.workspace = true
3232
petgraph = "0.6"
3333
rangemap = "1.4.0"

noir/noir-repo/noir_stdlib/src/array.nr

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::option::Option;
33
use crate::convert::From;
44

55
impl<T, let N: u32> [T; N] {
6+
/// Returns the length of the slice.
67
#[builtin(array_len)]
78
pub fn len(self) -> u32 {}
89

0 commit comments

Comments
 (0)