essential_constraint_vm/
error.rs

1//! The types of errors that might occur throughout constraint checking.
2
3use crate::{
4    asm::{self, Word},
5    Stack,
6};
7use core::fmt;
8use thiserror::Error;
9
10/// Shorthand for a `Result` where the error type is a `CheckError`.
11pub type CheckResult<T> = Result<T, CheckError>;
12
13/// Predicate checking error.
14#[derive(Debug, Error)]
15pub enum CheckError {
16    /// Errors occurred while executing one or more constraints.
17    #[error("errors occurred while executing one or more constraints: {0}")]
18    ConstraintErrors(#[from] ConstraintErrors),
19    /// One or more constraints were unsatisfied.
20    #[error("one or more constraints were unsatisfied: {0}")]
21    ConstraintsUnsatisfied(#[from] ConstraintsUnsatisfied),
22}
23
24/// The index of each failed constraint alongside the error it produced.
25#[derive(Debug, Error)]
26pub struct ConstraintErrors(pub Vec<(usize, ConstraintError)>);
27
28/// The index of each constraint that was not satisfied.
29#[derive(Debug, Error)]
30pub struct ConstraintsUnsatisfied(pub Vec<usize>);
31
32/// Shorthand for a `Result` where the error type is a `ConstraintError`.
33pub type ConstraintResult<T> = Result<T, ConstraintError>;
34
35/// Constraint checking error.
36#[derive(Debug, Error)]
37pub enum ConstraintError {
38    /// Evaluation should have resulted with a `0` (false) or `1` (true) at the
39    /// top of the stack, but did not.
40    #[error(
41        "invalid constraint evaluation result\n  \
42        expected: [0] (false) or [1] (true)\n  \
43        found:    {0:?}"
44    )]
45    InvalidEvaluation(Stack),
46    /// The operation at the specified index failed.
47    #[error("operation at index {0} failed: {1}")]
48    Op(usize, OpError),
49}
50
51/// Shorthand for a `Result` where the error type is an `OpError`.
52pub type OpResult<T> = Result<T, OpError>;
53
54/// An individual operation failed during constraint checking error.
55#[derive(Debug, Error)]
56pub enum OpError {
57    /// An error occurred during an `Access` operation.
58    #[error("access operation error: {0}")]
59    Access(#[from] AccessError),
60    /// An error occurred during an `Alu` operation.
61    #[error("ALU operation error: {0}")]
62    Alu(#[from] AluError),
63    /// An error occurred during a `Crypto` operation.
64    #[error("crypto operation error: {0}")]
65    Crypto(#[from] CryptoError),
66    /// An error occurred during a `Stack` operation.
67    #[error("stack operation error: {0}")]
68    Stack(#[from] StackError),
69    /// An error occurred during a `Repeat` operation.
70    #[error("repeat operation error: {0}")]
71    Repeat(#[from] RepeatError),
72    /// An error occurred during a `TotalControlFlow` operation.
73    #[error("total control flow operation error: {0}")]
74    TotalControlFlow(#[from] TotalControlFlowError),
75    /// An error occurred during a `Temporary` operation.
76    #[error("temporary operation error: {0}")]
77    Temporary(#[from] TemporaryError),
78    /// An error occurred while parsing an operation from bytes.
79    #[error("bytecode error: {0}")]
80    FromBytes(#[from] asm::FromBytesError),
81    /// Pc counter overflowed.
82    #[error("PC counter overflowed")]
83    PcOverflow,
84    /// An error occurred while decoding some data.
85    #[error("decoding error: {0}")]
86    Decode(#[from] DecodeError),
87    /// An error occurred while encoding some data.
88    #[error("encoding error: {0}")]
89    Encode(#[from] EncodeError),
90}
91
92/// Access operation error.
93#[derive(Debug, Error)]
94pub enum AccessError {
95    /// A decision variable slot was out of bounds.
96    #[error("decision variable slot out of bounds: {0}")]
97    DecisionSlotIxOutOfBounds(Word),
98    /// A decision variable slot index was out of bounds.
99    #[error("decision variable slot index out of bounds")]
100    DecisionIndexOutOfBounds,
101    /// A decision variable length was too large.
102    #[error("the length of a decision variable slot is too large: {0}")]
103    DecisionLengthTooLarge(usize),
104    /// A decision var index was out of bounds.
105    #[error("decision var value_ix out of bounds: {0}..{1}")]
106    DecisionValueRangeOutOfBounds(Word, Word),
107    /// A solution data index was out of bounds.
108    #[error("solution data index out of bounds")]
109    SolutionDataOutOfBounds,
110    /// A state slot index was out of bounds.
111    #[error("state slot_ix out of bounds: {0}")]
112    StateSlotIxOutOfBounds(Word),
113    /// A state slot index was out of bounds.
114    #[error("state value_ix out of bounds: {0}..{1}")]
115    StateValueRangeOutOfBounds(Word, Word),
116    /// A state slot delta value was invalid. Must be `0` (pre) or `1` (post).
117    #[error("invalid state slot delta: expected `0` or `1`, found {0}")]
118    InvalidStateSlotDelta(Word),
119    /// The total length of the set of state mutations was too large.
120    #[error("the total length of the set of state mutations was too large: {0}")]
121    StateMutationsLengthTooLarge(usize),
122    /// The state slot value was too large.
123    #[error("the state slot value was too large: {0}")]
124    StateValueTooLarge(usize),
125    /// Key length was out of bounds.
126    #[error("key length out of bounds: {0}")]
127    KeyLengthOutOfBounds(Word),
128    /// The access range was invalid
129    #[error("invalid access range")]
130    InvalidAccessRange,
131    /// The length of the slots was too large large to fit in a `Word`.
132    #[error("the length of the slots was too large: {0}")]
133    SlotsLengthTooLarge(usize),
134    /// The `which_slots` argument was invalid.
135    #[error("invalid `which_slots` argument: {0}")]
136    InvalidSlotType(Word),
137    /// Missing argument error.
138    #[error("missing `Access` argument: {0}")]
139    MissingArg(#[from] MissingAccessArgError),
140}
141
142/// Missing argument error.
143#[derive(Debug, Error)]
144pub enum MissingAccessArgError {
145    /// Missing `delta` argument for `State` operation.
146    #[error("missing `delta` argument for `State` operation")]
147    StateDelta,
148    /// Missing `len` argument for `State` operation.
149    #[error("missing `len` argument for `State` operation")]
150    StateLen,
151    /// Missing `value_ix` argument for `State` operation.
152    #[error("missing `value_ix` argument for `State` operation")]
153    StateValueIx,
154    /// Missing `slot_ix` argument for `State` operation.
155    #[error("missing `slot_ix` argument for `State` operation")]
156    StateSlotIx,
157    /// Missing `len` argument for `DecisionVar` operation.
158    #[error("missing `len` argument for `DecisionVar` operation")]
159    DecVarLen,
160    /// Missing `value_ix` argument for `DecisionVar` operation.
161    #[error("missing `value_ix` argument for `DecisionVar` operation")]
162    DecVarValueIx,
163    /// Missing `slot_ix` argument for `DecisionVar` operation.
164    #[error("missing `slot_ix` argument for `DecisionVar` operation")]
165    DecVarSlotIx,
166}
167
168/// ALU operation error.
169#[derive(Debug, Error)]
170pub enum AluError {
171    /// An ALU operation overflowed a `Word` value.
172    #[error("word overflow")]
173    Overflow,
174    /// An ALU operation underflowed a `Word` value.
175    #[error("word underflow")]
176    Underflow,
177    /// An ALU operation (either Div or Mod) attempted to divide by zero.
178    #[error("attempted to divide by zero")]
179    DivideByZero,
180}
181
182/// Crypto operation error.
183#[derive(Debug, Error)]
184pub enum CryptoError {
185    /// Failed to verify a ED25519 signature.
186    #[error("failed to verify ed25519 signature: {0}")]
187    Ed25519(#[from] ed25519_dalek::ed25519::Error),
188    /// Failed to recover a SECP256k1 public key.
189    #[error("failed to recover secp256k1 public key: {0}")]
190    Secp256k1(#[from] secp256k1::Error),
191    /// Failed to parse SECP256k1 recovery id
192    #[error("failed to parse secp256k1 recovery id")]
193    Secp256k1RecoveryId,
194}
195
196/// Shorthand for a `Result` where the error type is a `StackError`.
197pub type StackResult<T> = Result<T, StackError>;
198
199/// Stack operation error.
200#[derive(Debug, Error)]
201pub enum StackError {
202    /// Attempted to pop a word from an empty stack.
203    #[error("attempted to pop an empty stack")]
204    Empty,
205    /// An index into the stack was out of bounds.
206    #[error("indexed stack out of bounds")]
207    IndexOutOfBounds,
208    /// The stack size exceeded the size limit.
209    #[error("the {}-word stack size limit was exceeded", crate::Stack::SIZE_LIMIT)]
210    Overflow,
211    /// The condition for Select or SelectRange is not `0` (false) or `1` (true).
212    #[error(
213        "invalid condition\n  \
214        expected: [0] (false) or [1] (true)\n  \
215        found:    {0}"
216    )]
217    InvalidCondition(Word),
218    /// There was an error while calling a `len words` function.
219    #[error(transparent)]
220    LenWords(#[from] LenWordsError),
221}
222
223/// A `len words` error.
224#[derive(Debug, Error)]
225pub enum LenWordsError {
226    /// A `len words` function was called with a missing length.
227    #[error("missing length argument for `len words` operation")]
228    MissingLength,
229    /// A `len words` function was called with an invalid length.
230    #[error("invalid length argument for `len words` operation: {0}")]
231    InvalidLength(Word),
232    /// A `len words` function was called with an out-of-bounds length.
233    #[error("length argument for `len words` operation out of bounds: {0}")]
234    OutOfBounds(Word),
235    /// The additional length was too large for the `len words` function.
236    #[error("additional length too large for `len words` operation: {0} + {1}")]
237    AdditionalOutOfBounds(usize, usize),
238}
239
240/// Shorthand for a `Result` where the error type is a `RepeatError`.
241pub type RepeatResult<T> = Result<T, RepeatError>;
242
243/// Repeat operation error.
244#[derive(Debug, Error)]
245pub enum RepeatError {
246    /// Repeat end hit with no corresponding repeat start on the stack
247    #[error("attempted to repeat to empty stack")]
248    Empty,
249    /// Repeat counter called when stack is empty
250    #[error("attempted to access repeat counter with empty stack")]
251    NoCounter,
252    /// Repeat counter called with an invalid count direction
253    #[error("The count direction must be 0 or 1")]
254    InvalidCountDirection,
255    /// The repeat stack size exceeded the size limit.
256    #[error("the {}-word stack size limit was exceeded", crate::Stack::SIZE_LIMIT)]
257    Overflow,
258}
259
260/// Shorthand for a `Result` where the error type is a `TotalControlFlowError`.
261pub type TotalControlFlowResult<T> = Result<T, TotalControlFlowError>;
262
263/// Total control flow operation error.
264#[derive(Debug, Error)]
265pub enum TotalControlFlowError {
266    /// Attempted to jump forward if with an invalid condition
267    #[error("jump forward if requires a boolean condition")]
268    InvalidJumpForwardIfCondition,
269    /// Attempted to jump forward if to the same location
270    #[error("jump forward if requires to jump at least one instruction")]
271    JumpedToSelf,
272    /// Attempted to halt if with an invalid condition
273    #[error("halt if requires a boolean condition")]
274    InvalidHaltIfCondition,
275    /// Attempted to panic if with an invalid condition
276    #[error("panic if requires a boolean condition")]
277    InvalidPanicIfCondition,
278    /// The `PanicIf` operation was called with a `true` argument
279    #[error("program panicked with `PanicIf` operation. The stack at the time of panic: {0:?}")]
280    Panic(Vec<Word>),
281}
282
283/// Shorthand for a `Result` where the error type is a `TemporaryError`.
284pub type TemporaryResult<T> = Result<T, TemporaryError>;
285
286/// Temporary operation error.
287#[derive(Debug, Error)]
288pub enum TemporaryError {
289    /// Attempted to pop a word from an empty memory.
290    #[error("attempted to pop an empty memory")]
291    Empty,
292    /// Index into memory was out of bounds.
293    #[error("indexed memory out of bounds")]
294    IndexOutOfBounds,
295    /// The memory size exceeded the size limit.
296    #[error("the {}-word stack size limit was exceeded", crate::Memory::SIZE_LIMIT)]
297    Overflow,
298}
299
300/// Decode error.
301#[derive(Debug, Error)]
302pub enum DecodeError {
303    /// Decoding a set failed.
304    #[error("failed to decode set: {0:?}")]
305    Set(Vec<Word>),
306    /// Decoding item failed because it was too large.
307    #[error("item length too large: {0}")]
308    ItemLengthTooLarge(usize),
309}
310
311/// Encode error.
312#[derive(Debug, Error)]
313pub enum EncodeError {
314    /// Encoding item failed because it was too large.
315    #[error("item length too large: {0}")]
316    ItemLengthTooLarge(usize),
317}
318
319impl fmt::Display for ConstraintErrors {
320    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
321        f.write_str("the constraints at the following indices failed: \n")?;
322        for (ix, err) in &self.0 {
323            f.write_str(&format!("  {ix}: {err}\n"))?;
324        }
325        Ok(())
326    }
327}
328
329impl fmt::Display for ConstraintsUnsatisfied {
330    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
331        f.write_str("the constraints at the following indices returned false: \n")?;
332        for ix in &self.0 {
333            f.write_str(&format!("  {ix}\n"))?;
334        }
335        Ok(())
336    }
337}
338
339impl From<core::convert::Infallible> for OpError {
340    fn from(err: core::convert::Infallible) -> Self {
341        match err {}
342    }
343}
344impl From<MissingAccessArgError> for OpError {
345    fn from(err: MissingAccessArgError) -> Self {
346        AccessError::MissingArg(err).into()
347    }
348}