1use std::fmt;
6
7use crate::constraint_system::{Composition, ConstraintKind, ValueSegment};
8
9#[allow(missing_docs)] #[derive(Debug, thiserror::Error)]
12pub enum ConstraintSystemError {
13 #[error("{constraint_kind} #{constraint_index} operand {operand_name} is malformed: {source}")]
14 ConstraintOperand {
15 constraint_kind: ConstraintKind,
16 constraint_index: usize,
17 operand_name: &'static str,
18 #[source]
19 source: OperandFault,
20 },
21 #[error("chip call #{call_index} has a malformed operand #{operand_index}: {source}")]
22 ChipCallOperand {
23 call_index: usize,
24 operand_index: usize,
25 #[source]
26 source: OperandFault,
27 },
28 #[error("{} calls chip {chip_id}, but the system has {n_chips} chips", ChipName(*chip_index))]
29 OutOfRangeChipId {
30 chip_index: Option<usize>,
31 chip_id: usize,
32 n_chips: usize,
33 },
34 #[error(
35 "{}'s call #{call_index} passes {arity} operands to chip {chip_id}, which has {n_inout} inout values",
36 ChipName(*chip_index)
37 )]
38 WrongCallArity {
39 chip_index: Option<usize>,
40 call_index: usize,
41 chip_id: usize,
42 arity: usize,
43 n_inout: usize,
44 },
45 #[error("chip #{chip_index} calls chip {callee}, which is not a later chip")]
46 CallOutOfOrder { chip_index: usize, callee: usize },
47 #[error(
48 "{}'s call #{call_index} names instance {first_instance}, but the call graph gives it {expected}",
49 ChipName(*chip_index)
50 )]
51 WrongCallInstance {
52 chip_index: Option<usize>,
53 call_index: usize,
54 first_instance: usize,
55 expected: usize,
56 },
57 #[error("chip #{chip_id} declares {declared} active instances, but {actual} calls claim it")]
58 WrongActiveInstanceCount {
59 chip_id: usize,
60 declared: usize,
61 actual: usize,
62 },
63 #[error("more invocations reach chip #{chip_id} than a usize can count")]
64 TooManyInstances { chip_id: usize },
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72pub struct ChipName(pub Option<usize>);
73
74impl fmt::Display for ChipName {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 match self.0 {
77 Some(chip_index) => write!(f, "chip #{chip_index}"),
78 None => f.write_str("the main chip"),
79 }
80 }
81}
82
83#[allow(missing_docs)] #[derive(Debug, thiserror::Error)]
89pub enum OperandFault {
90 #[error("the shift is not canonical")]
91 NonCanonicalShift,
92 #[error("the shift amount n={shift_amount}>={max_amount}")]
93 ShiftAmountTooLarge {
94 shift_amount: usize,
95 max_amount: usize,
96 },
97 #[error("a lone shift sits in the outer slot; the canonical form places it inner")]
98 NonCanonicalShiftSequence,
99 #[error("a shift pair composes to {composition:?} rather than staying a pair")]
100 CollapsibleShiftSequence { composition: Composition },
101 #[error("it refers to a scratch value")]
102 ScratchValueIndex,
103 #[error("it refers to {segment:?} index {value_index} >= segment length {segment_len}")]
104 OutOfRangeValueIndex {
105 segment: ValueSegment,
106 value_index: u32,
107 segment_len: usize,
108 },
109}
110
111#[derive(Debug, thiserror::Error)]
116pub enum ConstraintViolation {
117 #[error("{val:016x} != 0")]
119 Zero {
120 val: u64,
122 },
123 #[error("({a:016x} & {b:016x}) ^ {c:016x} = {residue:016x} != 0")]
125 And {
126 a: u64,
128 b: u64,
130 c: u64,
132 residue: u64,
134 },
135 #[error("{a:016x} * {b:016x} = {expected_hi:016x}{expected_lo:016x}, got {hi:016x}{lo:016x}")]
137 Imul {
138 a: u64,
140 b: u64,
142 lo: u64,
144 hi: u64,
146 expected_lo: u64,
148 expected_hi: u64,
150 },
151 #[error("{a:032x} * {b:032x} = {expected:032x}, got {c:032x}")]
153 Bmul {
154 a: u128,
156 b: u128,
158 c: u128,
160 expected: u128,
162 },
163}
164
165impl ConstraintViolation {
166 pub const fn kind(&self) -> ConstraintKind {
171 match self {
172 Self::Zero { .. } => ConstraintKind::Zero,
173 Self::And { .. } => ConstraintKind::And,
174 Self::Imul { .. } => ConstraintKind::Imul,
175 Self::Bmul { .. } => ConstraintKind::Bmul,
176 }
177 }
178}
179
180#[derive(Debug, thiserror::Error)]
182pub enum VerificationError {
183 #[error(
188 "value {value_index} is {actual:016x}, but the system declares the constant {expected:016x}"
189 )]
190 ConstantMismatch {
191 value_index: u32,
193 expected: u64,
195 actual: u64,
197 },
198 #[error("{} #{constraint_index} is unsatisfied: {source}", source.kind())]
200 Unsatisfied {
201 constraint_index: usize,
203 source: ConstraintViolation,
205 },
206}
207
208struct CallerName(Option<(usize, usize)>);
213
214impl fmt::Display for CallerName {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 match self.0 {
217 Some((chip_index, instance)) => write!(f, "chip #{chip_index} instance #{instance}"),
218 None => f.write_str("the main chip"),
219 }
220 }
221}
222
223#[allow(missing_docs)] #[derive(Debug, thiserror::Error)]
230pub enum VerificationM4Error {
231 #[error("the witness covers {n_witness_chips} chips, but the system has {n_chips}")]
232 WrongChipCount {
233 n_witness_chips: usize,
234 n_chips: usize,
235 },
236 #[error("the main chip is not satisfied: {0}")]
237 Main(#[from] VerificationError),
238 #[error("chip #{chip_id} instance #{instance} is not satisfied: {source}")]
239 ChipInstance {
240 chip_id: usize,
241 instance: usize,
242 #[source]
243 source: VerificationError,
244 },
245 #[error("chip #{chip_id} has {n_instances} instances, fewer than its {n_active} active ones")]
246 MissingInstances {
247 chip_id: usize,
248 n_instances: usize,
249 n_active: usize,
250 },
251 #[error(
252 "call #{call_index} of {} reaches chip #{chip_id} as invocation #{row}, passing {passed:016x} \
253 as inout value {word}, but the instance holds {served:016x}",
254 CallerName(*caller)
255 )]
256 CallMismatch {
257 chip_id: usize,
258 row: usize,
259 caller: Option<(usize, usize)>,
261 call_index: usize,
262 word: usize,
263 passed: u64,
264 served: u64,
265 },
266}