Skip to content
This repository has been archived by the owner on Apr 9, 2024. It is now read-only.

feat!: Assertion messages embedded in the circuit #484

Merged
merged 13 commits into from
Aug 30, 2023
Merged
10 changes: 8 additions & 2 deletions acir/src/circuit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::native_types::Witness;
pub use opcodes::Opcode;
use thiserror::Error;

use std::{io::prelude::*, num::ParseIntError, str::FromStr};
use std::{collections::BTreeMap, io::prelude::*, num::ParseIntError, str::FromStr};

use flate2::Compression;

Expand All @@ -30,6 +30,10 @@ pub struct Circuit {
pub public_parameters: PublicInputs,
/// The set of public inputs calculated within the circuit.
pub return_values: PublicInputs,
/// Maps opcode locations to failed assertion messages.
/// These messages are embedded in the circuit to provide useful feedback to users
/// when a constraint in the circuit is not satisfied.
pub assert_messages: BTreeMap<OpcodeLocation, String>,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize)]
Expand Down Expand Up @@ -195,7 +199,7 @@ impl PublicInputs {

#[cfg(test)]
mod tests {
use std::collections::BTreeSet;
use std::collections::{BTreeMap, BTreeSet};

use super::{
opcodes::{BlackBoxFuncCall, FunctionInput},
Expand Down Expand Up @@ -231,6 +235,7 @@ mod tests {
private_parameters: BTreeSet::new(),
public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(12)])),
return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(4), Witness(12)])),
assert_messages: BTreeMap::new(),
};

fn read_write(circuit: Circuit) -> (Circuit, Circuit) {
Expand Down Expand Up @@ -260,6 +265,7 @@ mod tests {
private_parameters: BTreeSet::new(),
public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])),
return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])),
assert_messages: BTreeMap::new(),
};

let json = serde_json::to_string_pretty(&circuit).unwrap();
Expand Down
98 changes: 48 additions & 50 deletions acir/tests/test_program_serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,20 @@ fn addition_circuit() {
current_witness_index: 4,
opcodes: vec![addition],
private_parameters: BTreeSet::from([Witness(1), Witness(2)]),
public_parameters: PublicInputs::default(),
return_values: PublicInputs([Witness(3)].into()),
..Circuit::default()
};

let mut bytes = Vec::new();
circuit.write(&mut bytes).unwrap();

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 187, 13, 192, 32, 12, 68, 249, 100, 32, 27,
219, 96, 119, 89, 37, 40, 176, 255, 8, 81, 36, 23, 72, 41, 195, 53, 215, 61, 221, 189, 35,
132, 16, 195, 55, 217, 251, 244, 134, 127, 193, 184, 145, 149, 22, 22, 65, 101, 30, 173,
12, 36, 188, 160, 88, 87, 1, 150, 94, 21, 21, 69, 229, 46, 74, 52, 148, 181, 89, 183, 6,
134, 76, 3, 167, 24, 77, 135, 229, 125, 187, 32, 57, 231, 253, 154, 22, 151, 113, 113, 250,
0, 123, 50, 20, 220, 112, 1, 0, 0,
219, 96, 119, 89, 37, 40, 176, 255, 8, 17, 18, 5, 74, 202, 240, 154, 235, 158, 238, 238,
112, 206, 121, 247, 37, 206, 60, 103, 194, 63, 208, 111, 116, 133, 197, 69, 144, 153, 91,
73, 13, 9, 47, 72, 86, 85, 128, 165, 102, 69, 69, 81, 185, 147, 18, 53, 101, 45, 86, 173,
128, 33, 83, 195, 46, 70, 125, 202, 226, 190, 94, 16, 166, 103, 108, 13, 203, 151, 254,
245, 233, 224, 1, 1, 52, 166, 127, 120, 1, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand All @@ -69,17 +69,17 @@ fn fixed_base_scalar_mul_circuit() {
current_witness_index: 4,
opcodes: vec![fixed_base_scalar_mul],
private_parameters: BTreeSet::from([Witness(1)]),
public_parameters: PublicInputs::default(),
return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(3)])),
..Circuit::default()
};

let mut bytes = Vec::new();
circuit.write(&mut bytes).unwrap();

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 201, 9, 0, 0, 8, 195, 234, 241, 114, 255, 121,
69, 69, 5, 49, 16, 242, 104, 21, 0, 161, 169, 218, 212, 83, 78, 229, 237, 11, 159, 214, 39,
0, 55, 132, 28, 78, 72, 0, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 137, 91, 10, 0, 0, 4, 4, 215, 227, 203, 253, 207,
43, 132, 146, 169, 105, 106, 87, 1, 16, 154, 170, 77, 61, 229, 84, 222, 191, 240, 169, 156,
61, 0, 36, 111, 164, 5, 80, 0, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand All @@ -97,17 +97,17 @@ fn pedersen_circuit() {
current_witness_index: 4,
opcodes: vec![pedersen],
private_parameters: BTreeSet::from([Witness(1)]),
public_parameters: PublicInputs::default(),
return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(3)])),
..Circuit::default()
};

let mut bytes = Vec::new();
circuit.write(&mut bytes).unwrap();

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 65, 10, 0, 64, 8, 2, 103, 183, 232, 255, 47,
142, 138, 58, 68, 130, 168, 140, 10, 60, 90, 149, 118, 182, 79, 255, 105, 57, 140, 197,
246, 39, 0, 246, 174, 71, 87, 84, 0, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 9, 10, 0, 64, 8, 2, 103, 15, 250, 255, 139,
163, 162, 130, 72, 16, 149, 241, 3, 135, 84, 164, 172, 173, 213, 175, 251, 45, 198, 96,
243, 211, 50, 152, 67, 220, 211, 92, 0, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand Down Expand Up @@ -139,30 +139,30 @@ fn schnorr_verify_circuit() {
current_witness_index: 100,
opcodes: vec![schnorr],
private_parameters: BTreeSet::from_iter((1..=last_input).map(Witness)),
public_parameters: PublicInputs::default(),
return_values: PublicInputs(BTreeSet::from([output])),
..Circuit::default()
};

let mut bytes = Vec::new();
circuit.write(&mut bytes).unwrap();

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 233, 50, 66, 1, 24, 199, 225, 99, 223, 247,
125, 15, 73, 146, 36, 73, 146, 36, 73, 194, 93, 184, 255, 75, 48, 122, 167, 167, 25, 103,
230, 204, 83, 211, 151, 230, 253, 255, 126, 146, 36, 25, 73, 6, 79, 56, 193, 223, 254, 59,
202, 166, 223, 199, 250, 239, 116, 255, 29, 231, 4, 39, 57, 197, 225, 59, 195, 89, 206,
113, 158, 11, 92, 228, 18, 151, 185, 194, 85, 174, 113, 157, 27, 220, 228, 22, 183, 185,
195, 93, 238, 113, 159, 7, 60, 228, 17, 83, 60, 230, 9, 79, 153, 230, 25, 51, 60, 103, 150,
23, 204, 241, 146, 121, 94, 177, 192, 107, 22, 121, 195, 18, 111, 89, 230, 29, 43, 188,
103, 149, 15, 172, 241, 145, 117, 62, 177, 193, 103, 54, 249, 194, 214, 191, 29, 227, 121,
245, 189, 205, 55, 118, 248, 206, 46, 63, 216, 227, 39, 191, 248, 237, 115, 60, 209, 94,
116, 23, 173, 69, 103, 209, 88, 244, 53, 108, 107, 198, 255, 136, 150, 162, 163, 104, 40,
250, 137, 118, 162, 155, 104, 38, 122, 137, 86, 162, 147, 104, 36, 250, 136, 54, 162, 139,
104, 34, 122, 136, 22, 162, 131, 104, 32, 246, 143, 237, 83, 201, 96, 243, 216, 59, 182,
78, 219, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, 182, 42,
219, 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, 55, 111, 185, 113, 219,
109, 59, 110, 218, 117, 203, 158, 27, 14, 111, 54, 188, 91, 226, 150, 127, 214, 93, 14,
165, 212, 3, 0, 0,
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 87, 78, 2, 1, 20, 134, 209, 177, 247, 222, 123,
71, 68, 68, 68, 68, 68, 68, 68, 68, 68, 221, 133, 251, 95, 130, 145, 27, 206, 36, 78, 50,
57, 16, 94, 200, 253, 191, 159, 36, 73, 134, 146, 193, 19, 142, 241, 183, 255, 14, 179,
233, 247, 145, 254, 59, 217, 127, 71, 57, 198, 113, 78, 48, 125, 167, 56, 205, 25, 206,
114, 142, 243, 92, 224, 34, 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184,
205, 29, 238, 114, 143, 251, 60, 224, 33, 143, 120, 204, 19, 158, 242, 140, 25, 158, 51,
203, 11, 230, 120, 201, 60, 175, 88, 224, 53, 139, 188, 97, 137, 183, 44, 243, 142, 21,
222, 179, 202, 7, 214, 248, 200, 58, 159, 216, 224, 51, 155, 124, 97, 235, 223, 142, 241,
188, 250, 222, 230, 27, 59, 124, 103, 151, 31, 236, 241, 147, 95, 252, 246, 57, 158, 104,
47, 186, 139, 214, 162, 179, 104, 44, 250, 74, 219, 154, 242, 63, 162, 165, 232, 40, 26,
138, 126, 162, 157, 232, 38, 154, 137, 94, 162, 149, 232, 36, 26, 137, 62, 162, 141, 232,
34, 154, 136, 30, 162, 133, 232, 32, 26, 136, 253, 99, 251, 195, 100, 176, 121, 236, 29,
91, 159, 218, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, 182,
42, 219, 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, 55, 111, 185, 113,
219, 109, 59, 110, 218, 117, 203, 158, 27, 166, 55, 75, 239, 150, 184, 101, 250, 252, 1,
19, 89, 159, 101, 220, 3, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand Down Expand Up @@ -240,24 +240,23 @@ fn simple_brillig_foreign_call() {
current_witness_index: 8,
opcodes,
private_parameters: BTreeSet::from([Witness(1), Witness(2)]),
public_parameters: PublicInputs::default(),
return_values: PublicInputs::default(),
..Circuit::default()
};

let mut bytes = Vec::new();
circuit.write(&mut bytes).unwrap();

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 181, 148, 209, 10, 195, 32, 12, 69, 99, 109, 183, 126,
78, 82, 181, 198, 183, 253, 202, 100, 22, 246, 178, 135, 49, 246, 253, 219, 152, 131, 176,
250, 214, 244, 130, 68, 130, 28, 188, 55, 232, 8, 0, 3, 124, 101, 223, 171, 131, 181, 126,
189, 83, 173, 184, 77, 100, 20, 89, 157, 30, 11, 27, 214, 213, 216, 86, 48, 15, 34, 239,
143, 142, 141, 172, 229, 190, 23, 61, 83, 235, 40, 56, 215, 219, 179, 220, 31, 166, 113,
74, 246, 154, 178, 186, 54, 119, 27, 173, 195, 217, 251, 18, 167, 66, 142, 206, 56, 165,
204, 1, 125, 200, 51, 19, 83, 224, 112, 153, 216, 185, 194, 158, 99, 202, 41, 98, 34, 239,
10, 45, 33, 185, 165, 194, 122, 189, 123, 161, 28, 203, 240, 23, 180, 150, 119, 201, 6,
197, 28, 4, 114, 245, 172, 183, 178, 173, 162, 255, 97, 135, 121, 25, 104, 127, 111, 47,
112, 131, 248, 45, 3, 5, 0, 0,
78, 82, 181, 141, 111, 251, 149, 201, 44, 236, 101, 15, 99, 236, 251, 183, 49, 11, 161,
245, 173, 233, 5, 137, 4, 57, 120, 111, 208, 30, 0, 58, 248, 203, 126, 87, 3, 91, 45, 189,
75, 169, 184, 79, 100, 20, 89, 141, 30, 11, 43, 214, 213, 216, 86, 48, 79, 34, 239, 159,
206, 149, 172, 229, 190, 21, 61, 83, 106, 47, 56, 247, 199, 59, 63, 95, 166, 114, 74, 246,
170, 178, 186, 54, 15, 27, 173, 195, 209, 251, 60, 13, 153, 28, 93, 113, 136, 137, 3, 250,
144, 70, 38, 166, 192, 225, 54, 176, 115, 153, 61, 79, 49, 197, 9, 35, 121, 151, 105, 14,
209, 205, 5, 214, 234, 221, 11, 229, 88, 186, 85, 208, 90, 222, 37, 27, 20, 115, 16, 200,
205, 179, 222, 203, 182, 138, 254, 187, 3, 230, 101, 160, 254, 189, 45, 250, 0, 87, 206,
28, 176, 11, 5, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand Down Expand Up @@ -323,21 +322,20 @@ fn complex_brillig_foreign_call() {
current_witness_index: 8,
opcodes,
private_parameters: BTreeSet::from([Witness(1), Witness(2), Witness(3)]),
public_parameters: PublicInputs::default(),
return_values: PublicInputs::default(),
..Circuit::default()
};

let mut bytes = Vec::new();
circuit.write(&mut bytes).unwrap();

let expected_serialization: Vec<u8> = vec![
31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 219, 10, 128, 48, 8, 245, 210, 101, 159, 179,
254, 160, 127, 137, 222, 138, 122, 236, 243, 91, 228, 64, 44, 232, 33, 7, 117, 64, 156,
206, 201, 193, 51, 3, 0, 32, 156, 224, 100, 36, 103, 148, 88, 35, 215, 245, 226, 227, 59,
116, 232, 215, 43, 150, 226, 72, 63, 224, 200, 5, 56, 230, 255, 240, 81, 189, 61, 117, 113,
157, 31, 223, 236, 79, 149, 172, 78, 214, 72, 220, 138, 15, 106, 214, 168, 114, 249, 126,
88, 230, 117, 26, 55, 54, 37, 90, 26, 155, 39, 227, 31, 223, 232, 230, 4, 215, 157, 63,
176, 3, 89, 64, 134, 157, 36, 4, 0, 0,
254, 160, 127, 137, 222, 138, 122, 236, 243, 27, 228, 64, 44, 232, 33, 7, 237, 128, 56,
157, 147, 131, 103, 6, 0, 64, 184, 192, 201, 72, 206, 40, 177, 70, 174, 27, 197, 199, 111,
24, 208, 175, 87, 44, 197, 145, 42, 224, 200, 5, 56, 230, 255, 240, 83, 189, 61, 117, 113,
157, 31, 63, 236, 79, 147, 172, 77, 214, 73, 220, 139, 15, 106, 214, 168, 114, 249, 126,
218, 214, 125, 153, 15, 54, 37, 90, 26, 155, 39, 227, 95, 223, 232, 230, 4, 247, 157, 215,
56, 1, 153, 86, 63, 138, 44, 4, 0, 0,
];

assert_eq!(bytes, expected_serialization)
Expand Down
26 changes: 22 additions & 4 deletions acvm/src/compiler/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::collections::BTreeMap;

use acir::{
circuit::{
brillig::BrilligOutputs, directives::Directive, opcodes::UnsupportedMemoryOpcode, Circuit,
Expand Down Expand Up @@ -58,6 +60,19 @@ impl AcirTransformationMap {
}
}

fn transform_assert_messages(
assert_messages: BTreeMap<OpcodeLocation, String>,
map: &AcirTransformationMap,
) -> BTreeMap<OpcodeLocation, String> {
assert_messages
.into_iter()
.flat_map(|(location, message)| {
let new_locations = map.new_locations(location);
new_locations.into_iter().map(move |new_location| (new_location, message.clone()))
})
.collect()
}

/// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] specific optimizations to a [`Circuit`].
pub fn compile(
acir: Circuit,
Expand Down Expand Up @@ -90,12 +105,14 @@ pub fn compile(

// Range optimization pass
let range_optimizer = RangeOptimizer::new(acir);
let (acir, acir_opcode_positions) =
let (mut acir, acir_opcode_positions) =
range_optimizer.replace_redundant_ranges(acir_opcode_positions);

let mut transformer = match &np_language {
crate::Language::R1CS => {
let transformation_map = AcirTransformationMap { acir_opcode_positions };
acir.assert_messages =
transform_assert_messages(acir.assert_messages, &transformation_map);
let transformer = R1CSTransformer::new(acir);
return Ok((transformer.transform(), transformation_map));
}
Expand Down Expand Up @@ -252,17 +269,18 @@ pub fn compile(

let current_witness_index = next_witness_index - 1;

let transformation_map =
AcirTransformationMap { acir_opcode_positions: new_acir_opcode_positions };

let acir = Circuit {
current_witness_index,
opcodes: transformed_opcodes,
// The optimizer does not add new public inputs
private_parameters: acir.private_parameters,
public_parameters: acir.public_parameters,
return_values: acir.return_values,
assert_messages: transform_assert_messages(acir.assert_messages, &transformation_map),
};

let transformation_map =
AcirTransformationMap { acir_opcode_positions: new_acir_opcode_positions };

Ok((acir, transformation_map))
}
7 changes: 3 additions & 4 deletions acvm/src/compiler/optimizers/redundant_range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,7 @@ impl RangeOptimizer {
Circuit {
current_witness_index: self.circuit.current_witness_index,
opcodes: optimized_opcodes,
private_parameters: self.circuit.private_parameters,
public_parameters: self.circuit.public_parameters,
return_values: self.circuit.return_values,
..self.circuit
},
new_order_list,
)
Expand All @@ -137,7 +135,7 @@ fn extract_range_opcode(opcode: &Opcode) -> Option<(Witness, u32)> {

#[cfg(test)]
mod tests {
use std::collections::BTreeSet;
use std::collections::{BTreeMap, BTreeSet};

use crate::compiler::optimizers::redundant_range::{extract_range_opcode, RangeOptimizer};
use acir::{
Expand Down Expand Up @@ -166,6 +164,7 @@ mod tests {
private_parameters: BTreeSet::new(),
public_parameters: PublicInputs::default(),
return_values: PublicInputs::default(),
assert_messages: BTreeMap::new(),
}
}

Expand Down
8 changes: 1 addition & 7 deletions acvm/src/compiler/transformers/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,7 @@ impl FallbackTransformer {
}

Ok((
Circuit {
current_witness_index: witness_idx,
opcodes: acir_supported_opcodes,
private_parameters: acir.private_parameters,
public_parameters: acir.public_parameters,
return_values: acir.return_values,
},
Circuit { current_witness_index: witness_idx, opcodes: acir_supported_opcodes, ..acir },
new_opcode_positions,
))
}
Expand Down
4 changes: 2 additions & 2 deletions acvm/tests/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ fn unsatisfied_opcode_resolved() {
assert_eq!(
solver_status,
ACVMStatus::Failure(OpcodeResolutionError::UnsatisfiedConstrain {
opcode_location: ErrorLocation::Resolved(OpcodeLocation::Acir(0))
opcode_location: ErrorLocation::Resolved(OpcodeLocation::Acir(0)),
}),
"The first opcode is not satisfiable, expected an error indicating this"
);
Expand Down Expand Up @@ -623,7 +623,7 @@ fn unsatisfied_opcode_resolved_brillig() {
opcode_location: ErrorLocation::Resolved(OpcodeLocation::Brillig {
acir_index: 0,
brillig_index: 2
})
}),
}),
"The first opcode is not satisfiable, expected an error indicating this"
);
Expand Down
9 changes: 4 additions & 5 deletions acvm/tests/stdlib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::solver::StubbedBackend;
use acir::{
circuit::{
opcodes::{BlackBoxFuncCall, FunctionInput},
Circuit, Opcode, PublicInputs,
Circuit, Opcode,
},
native_types::{Expression, Witness},
FieldElement,
Expand Down Expand Up @@ -285,8 +285,8 @@ macro_rules! test_hashes {
current_witness_index: witness_assignments.len() as u32 + 32,
opcodes,
private_parameters: BTreeSet::new(), // This is not correct but is unused in this test.
public_parameters: PublicInputs(BTreeSet::new()),
return_values: PublicInputs(BTreeSet::new()) };
..Circuit::default()
};
let circuit = compile(circuit, Language::PLONKCSat{ width: 3 }, $opcode_support).unwrap().0;

// solve witnesses
Expand Down Expand Up @@ -341,8 +341,7 @@ proptest! {
current_witness_index: witness_assignments.len() as u32 + 1,
opcodes,
private_parameters: BTreeSet::new(), // This is not correct but is unused in this test.
public_parameters: PublicInputs(BTreeSet::new()),
return_values: PublicInputs(BTreeSet::new())
..Circuit::default()
};
let circuit = compile(circuit, Language::PLONKCSat{ width: 3 }, does_not_support_hash_to_field).unwrap().0;

Expand Down
Loading
Loading