diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 407cdf0a17f..5f180edd05c 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -236,7 +236,10 @@ impl AcirContext { self.acir_ir.call_stack = call_stack; } - fn get_or_create_witness_var(&mut self, var: AcirVar) -> Result { + pub(crate) fn get_or_create_witness_var( + &mut self, + var: AcirVar, + ) -> Result { if self.var_to_expression(var)?.to_witness().is_some() { // If called with a variable which is already a witness then return the same variable. return Ok(var); diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 05d2e3e3e6a..2430a00fd4c 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -2605,6 +2605,15 @@ impl<'a> Context<'a> { Ok(result) } + + Intrinsic::AsWitness => { + let arg = arguments[0]; + let input = self.convert_value(arg, dfg).into_var()?; + Ok(self + .acir_context + .get_or_create_witness_var(input) + .map(|val| self.convert_vars_to_values(vec![val], dfg, result_ids))?) + } _ => todo!("expected a black box function"), } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 7cc19e9f2b8..f136d3c5fb2 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -64,6 +64,7 @@ pub(crate) enum Intrinsic { BlackBox(BlackBoxFunc), FromField, AsField, + AsWitness, } impl std::fmt::Display for Intrinsic { @@ -87,6 +88,7 @@ impl std::fmt::Display for Intrinsic { Intrinsic::BlackBox(function) => write!(f, "{function}"), Intrinsic::FromField => write!(f, "from_field"), Intrinsic::AsField => write!(f, "as_field"), + Intrinsic::AsWitness => write!(f, "as_witness"), } } } @@ -97,7 +99,9 @@ impl Intrinsic { /// If there are no side effects then the `Intrinsic` can be removed if the result is unused. pub(crate) fn has_side_effects(&self) -> bool { match self { - Intrinsic::AssertConstant | Intrinsic::ApplyRangeConstraint => true, + Intrinsic::AssertConstant | Intrinsic::ApplyRangeConstraint | Intrinsic::AsWitness => { + true + } // These apply a constraint that the input must fit into a specified number of limbs. Intrinsic::ToBits(_) | Intrinsic::ToRadix(_) => true, @@ -140,6 +144,7 @@ impl Intrinsic { "to_be_bits" => Some(Intrinsic::ToBits(Endian::Big)), "from_field" => Some(Intrinsic::FromField), "as_field" => Some(Intrinsic::AsField), + "as_witness" => Some(Intrinsic::AsWitness), other => BlackBoxFunc::lookup(other).map(Intrinsic::BlackBox), } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 7ad6a625f9c..8e320de9337 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -293,6 +293,7 @@ pub(super) fn simplify_call( let instruction = Instruction::Cast(truncated_value, target_type); SimplifyResult::SimplifiedToInstruction(instruction) } + Intrinsic::AsWitness => SimplifyResult::None, } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs index ea37d857e58..9309652d508 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs @@ -157,7 +157,8 @@ impl Context { | Intrinsic::BlackBox(_) | Intrinsic::FromField | Intrinsic::AsField - | Intrinsic::AsSlice => false, + | Intrinsic::AsSlice + | Intrinsic::AsWitness => false, }, // We must assume that functions contain a side effect as we cannot inspect more deeply. diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs index fc915756110..3d2b5142219 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs @@ -231,6 +231,7 @@ fn slice_capacity_change( | Intrinsic::StrAsBytes | Intrinsic::BlackBox(_) | Intrinsic::FromField - | Intrinsic::AsField => SizeChange::None, + | Intrinsic::AsField + | Intrinsic::AsWitness => SizeChange::None, } } diff --git a/noir_stdlib/src/lib.nr b/noir_stdlib/src/lib.nr index 33504be0b9a..4e83fc59276 100644 --- a/noir_stdlib/src/lib.nr +++ b/noir_stdlib/src/lib.nr @@ -67,3 +67,6 @@ pub fn wrapping_sub(x: T, y: T) -> T { pub fn wrapping_mul(x: T, y: T) -> T { crate::from_field(crate::as_field(x) * crate::as_field(y)) } + +#[builtin(as_witness)] +pub fn as_witness(x: Field) {} \ No newline at end of file