Skip to content

Commit 145b909

Browse files
authored
fix: use predicate for curve operations (#5076)
# Description ## Problem\* Resolves #5045 ## Summary\* use predicate to set is_infinite to true when side_effects are disabled, to ensure that the curve operation will not fail. ## Additional Context ## Documentation\* Check one: - [X] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[For Experimental Features]** Documentation to be submitted in a separate PR. # PR Checklist\* - [X] I have tested the changes locally. - [X] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings.
1 parent e73cdbb commit 145b909

File tree

5 files changed

+83
-2
lines changed

5 files changed

+83
-2
lines changed

compiler/noirc_evaluator/src/ssa/ir/instruction.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,12 @@ impl Intrinsic {
123123
| Intrinsic::IsUnconstrained => false,
124124

125125
// Some black box functions have side-effects
126-
Intrinsic::BlackBox(func) => matches!(func, BlackBoxFunc::RecursiveAggregation),
126+
Intrinsic::BlackBox(func) => matches!(
127+
func,
128+
BlackBoxFunc::RecursiveAggregation
129+
| BlackBoxFunc::MultiScalarMul
130+
| BlackBoxFunc::EmbeddedCurveAdd
131+
),
127132
}
128133
}
129134

@@ -340,6 +345,9 @@ impl Instruction {
340345

341346
// Some `Intrinsic`s have side effects so we must check what kind of `Call` this is.
342347
Call { func, .. } => match dfg[*func] {
348+
// Explicitly allows removal of unused ec operations, even if they can fail
349+
Value::Intrinsic(Intrinsic::BlackBox(BlackBoxFunc::MultiScalarMul))
350+
| Value::Intrinsic(Intrinsic::BlackBox(BlackBoxFunc::EmbeddedCurveAdd)) => true,
343351
Value::Intrinsic(intrinsic) => !intrinsic.has_side_effects(),
344352

345353
// All foreign functions are treated as having side effects.

compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@
134134
use fxhash::FxHashMap as HashMap;
135135
use std::collections::{BTreeMap, HashSet};
136136

137-
use acvm::{acir::AcirField, FieldElement};
137+
use acvm::{acir::AcirField, acir::BlackBoxFunc, FieldElement};
138138
use iter_extended::vecmap;
139139

140140
use crate::ssa::{
@@ -769,7 +769,38 @@ impl<'f> Context<'f> {
769769

770770
Instruction::Call { func, arguments }
771771
}
772+
//Issue #5045: We set curve points to infinity if condition is false
773+
Value::Intrinsic(Intrinsic::BlackBox(BlackBoxFunc::EmbeddedCurveAdd)) => {
774+
arguments[2] = self.var_or_one(arguments[2], condition, call_stack.clone());
775+
arguments[5] = self.var_or_one(arguments[5], condition, call_stack.clone());
772776

777+
Instruction::Call { func, arguments }
778+
}
779+
Value::Intrinsic(Intrinsic::BlackBox(BlackBoxFunc::MultiScalarMul)) => {
780+
let mut array_with_predicate = im::Vector::new();
781+
let array_typ;
782+
if let Value::Array { array, typ } =
783+
&self.inserter.function.dfg[arguments[0]]
784+
{
785+
array_typ = typ.clone();
786+
for (i, value) in array.clone().iter().enumerate() {
787+
if i % 3 == 2 {
788+
array_with_predicate.push_back(self.var_or_one(
789+
*value,
790+
condition,
791+
call_stack.clone(),
792+
));
793+
} else {
794+
array_with_predicate.push_back(*value);
795+
}
796+
}
797+
} else {
798+
unreachable!();
799+
}
800+
arguments[0] =
801+
self.inserter.function.dfg.make_array(array_with_predicate, array_typ);
802+
Instruction::Call { func, arguments }
803+
}
773804
_ => Instruction::Call { func, arguments },
774805
},
775806
other => other,
@@ -779,6 +810,20 @@ impl<'f> Context<'f> {
779810
}
780811
}
781812

813+
// Computes: if condition { var } else { 1 }
814+
fn var_or_one(&mut self, var: ValueId, condition: ValueId, call_stack: CallStack) -> ValueId {
815+
let field = self.insert_instruction(
816+
Instruction::binary(BinaryOp::Mul, var, condition),
817+
call_stack.clone(),
818+
);
819+
let not_condition =
820+
self.insert_instruction(Instruction::Not(condition), call_stack.clone());
821+
self.insert_instruction(
822+
Instruction::binary(BinaryOp::Add, field, not_condition),
823+
call_stack,
824+
)
825+
}
826+
782827
fn undo_stores_in_then_branch(&mut self, store_values: &HashMap<ValueId, Store>) {
783828
for (address, store) in store_values {
784829
let address = *address;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "regression_5045"
3+
version = "0.1.0"
4+
type = "bin"
5+
authors = [""]
6+
7+
[dependencies]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
is_active = false
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use dep::std::embedded_curve_ops::EmbeddedCurvePoint;
2+
use dep::std::embedded_curve_ops::EmbeddedCurveScalar;
3+
4+
fn main(is_active: bool) {
5+
let a = EmbeddedCurvePoint {
6+
x: 0x1d8eb4378a3bde41e0b6a9a8dcbd21b7ff9c51bdd6ca13ce989abbbf90df3666,
7+
y: 0x06075b63354f2504f9cddba0b94ed0cef35fc88615e69ec1f853b51eb79a24a0,
8+
is_infinite: false
9+
};
10+
11+
if is_active {
12+
let bad = EmbeddedCurvePoint { x: 0, y: 5, is_infinite: false };
13+
let d = bad.double();
14+
let e = dep::std::embedded_curve_ops::multi_scalar_mul(
15+
[a, bad],
16+
[EmbeddedCurveScalar { lo: 1, hi: 0 }, EmbeddedCurveScalar { lo: 1, hi: 0 }]
17+
);
18+
assert(e[0] != d.x);
19+
}
20+
}

0 commit comments

Comments
 (0)