1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
use std::ffi::FromBytesUntilNulError;
use elf::ParseError;
use thiserror::Error;
#[derive(Debug, Clone, Error)]
/// Errors that can occur in this crate.
pub enum Error {
/// An error occurred when running a circuit on a
/// [`parasol_runtime::CircuitProcessor`].
#[error("Circuit error: {0}")]
CircuitError(#[from] parasol_runtime::RuntimeError),
/// Illegal instruction.
#[error("Illegal instruction encountered at 0x{0:8x}")]
IllegalInstruction(u32),
/// Illegal operands to an instruction.
#[error("(inst:{inst_id}, pc:0x{pc:x}) Illegal operands executing instruction at PC")]
IllegalOperands {
/// The faulting instruction's id.
inst_id: usize,
/// The program counter at time of error.
pc: u32,
},
/// Operands have mismatched bit widths.
#[error("(inst:{inst_id}, pc:0x{pc:x}): Operation width mismatch")]
WidthMismatch {
/// The faulting instruction's id.
inst_id: usize,
/// The program counter at time of error.
pc: u32,
},
/// The instruction attempted an unaligned memory operation.
#[error("Unaligned access at 0x{0:8x}")]
UnalignedAccess(u32),
/// Processor violated a register mutability invariant. This is an internal error and should
/// be reported as a bug.
#[error("Internal error: Attempted to mutably access immutable register")]
RegisterMutabilityViolation,
/// A bind instruction attempted to bind a buffer of a different encrypted-ness than the bind
/// instruction specified.
#[error(
"(inst_id:{inst_id}, pc:0x{pc:x}) Program input/output expected plaintext/ciphertext buffer, but found the other"
)]
BufferMismatch {
/// The faulting instruction's id.
inst_id: usize,
/// The program counter at time of error.
pc: u32,
},
/// The user-passed memory array did not have a buffer corresponding to a bind instructions
/// buffer index.
#[error("(inst_id:{inst_id}, pc:0x{pc:x}) No buffer at the given index")]
NoBuffer {
/// The faulting instruction's id.
inst_id: usize,
/// The program counter at time of error.
pc: u32,
},
/// Encountered multiple bind instructions with the same buffer index.
#[error(
"(inst_id:{inst_id}, pc:0x{pc:x}) Buffer {buffer_id} is already declared as an input or output"
)]
AliasingViolation {
/// The faulting instruction's id.
inst_id: usize,
/// The program counter at time of error.
pc: u32,
/// The buffer's index in a call to [`crate::FheComputer::run_program`].
buffer_id: usize,
},
/// A load or store occured out of a memory's bounds.
#[error("Attempted to access unmapped address 0x{0:8x}")]
AccessViolation(u32),
/// Cannot load or store a value of the requested width (> 128 bits).
#[error("(inst:{inst_id}, pc:0x{pc:x}) Attempted load or store with zero or > 128 width")]
UnsupportedWidth {
/// The faulting instruction's id.
inst_id: usize,
/// The program counter at time of error.
pc: u32,
},
/// An instruction's immediate value is too large.
#[error("(inst:{inst_id}, pc:0x{pc:x}) Immediate value is out of range for the given width")]
OutOfRange {
/// The faulting instruction's id.
inst_id: usize,
/// The program counter at time of error.
pc: u32,
},
/// The given buffer wasn't a plaintext.
#[error("The given buffer wasn't a plaintext")]
BufferNotAPlaintext,
/// The given buffer wasn't encrypted.
#[error("The given buffer wasn't a ciphertext")]
BufferNotACiphertext,
/// The buffer had the wrong size.
#[error("The given buffer is the wrong size for the given type")]
BufferSizeMismatch,
/// Attempted to mix plaintext and ciphertext data in a multi-byte type.
#[error("The given value has a mix of plaintext and encrypted data")]
MixedData,
/// Encountered a different byte encrypted-ness than expected.
#[error("Encountered a different byte encrypted-ness than expected.")]
EncryptionMismatch,
/// Encountered an illegal micro-op. This is a bug.
#[error("The processor executed an illegal uop")]
IllegalUop,
/// A micro-op encountered an unexpected ciphertext type. This is a bug.
#[error("Encountered an invalid ciphertext type executing a uop")]
UopCiphertextMismatch,
/// Attempted to branch on an encrypted value.
#[error("Branch condition is not a plaintext value")]
BranchConditionNotPlaintext,
/// Internally used to signal a program halting. Should never be encountered.
#[error("Program halted")]
Halt,
/// The given ELF file is not runnable. It has no section headers.
#[error("ELF file has no section headers")]
ElfNoSectionHeaders,
/// Failed to parse the given ELF file.
#[error("ELF parse error: {0}")]
ElfParseError(String),
/// Encountered an illegal string in the given ELF program.
#[error("Elf malformed string: {0}")]
ElfMalformedString(#[from] FromBytesUntilNulError),
/// An unexpected error occurred. This should never happen.
#[error("The ELF file is malformed in a way that should be impossible")]
ElfUnreachable,
/// Attempted to load an elf file with an unsupported ABI version.
#[error("ELF file has an unsupported ABI version: {0}")]
ElfUnsupportedAbiVersion(u8),
/// The ELF file lacks a symbol table, and thus cannot be loaded.
#[error("ELF file has no symbol table")]
ElfNoSymbolTable,
/// The ELF file lacks a segment table, and thus cannot be loaded.
#[error("ELF file has no segment table")]
ElfNoSegmentTable,
/// The given ELF file is ELF64.
#[error("ELF file is not ELF32")]
ElfNotElf32,
/// Encountered an STT_FUNC symbol out of range.
#[error("Encountered an STT_FUNC symbol out of range.")]
ElfBadSymbolValue,
/// The specified symbol does not exist the ELF file.
#[error("The ELF file does not contain the specified symbol: {0}")]
ElfSymbolNotFound(String),
/// When parsing the ELF file, encountered an out-of-bounds file offset.
#[error("The given ELF byte offset {0} exceeds the file's length")]
ElfByteOutOfBounds(u32),
/// Attempted to allocate a virtual address that's already mapped.
#[error("Failed to allocate virtual address space. Already in use")]
VirtualAddressInUse,
/// Failed to create a [`std::ffi::CString`]`
#[error("Failed to create CString: {0}")]
CStringCreationError(#[from] std::ffi::NulError),
/// Cannot fulfill the given mmap request as no contiguous address region exists of the
/// requested length
#[error("Failed to mmap {0} bytes")]
NoContiguousChunk(u32),
/// Attempted to mmap zero bytes.
#[error("Cannot mmap zero bytes")]
ZeroAllocation,
/// Attempted an operation that resulted in pointer overflow.
#[error("32-bit Pointer overflow")]
PointerOverflow,
/// Running out of allowed fee quota
#[error("Used gas amount {0} is exceeding quota {1}")]
OutOfGas(u32, u32),
/// The given byte should have been a plaintext, but was encrypted
#[error(
"Byte at address 0x{0:8x} was encrypted. Expected plaintext (was this a CPU instruction?)."
)]
UnexpectedEncryptedByte(u32),
/// Too many bytes given to `Word::try_from()`.
#[error("When trying to construct a Word, too many bytes were given.")]
WordConversionTooManyBytes,
/// When trying to convert to an encrypted byte, found more or less than 8 bits.
#[error("Expected 8 encrypted bits.")]
NotAByte,
/// Attempted to create a value from an incorrect number of bytes.
#[error("Attempted to create a value from an incorrect number of bytes.")]
TypeSizeMismatch,
}
// Stupid ParseError isn't Clone, so we gotta stringify it
impl From<ParseError> for Error {
fn from(value: ParseError) -> Self {
Self::ElfParseError(format!("{value:#?}"))
}
}
impl Error {
/// Create an [`Error::AliasingViolation`].
pub fn aliasing_violation(inst_id: usize, pc: u32, buffer_id: usize) -> Self {
Self::AliasingViolation {
inst_id,
pc,
buffer_id,
}
}
/// Create an [`Error::UnsupportedWidth`].
pub fn unsupported_width(inst_id: usize, pc: u32) -> Self {
Self::UnsupportedWidth { inst_id, pc }
}
/// Create an [`Error::BufferNotAPlaintext`].
pub fn buffer_not_a_plaintext() -> Self {
Self::BufferNotAPlaintext
}
/// Create an [`Error::BufferNotACiphertext`].
pub fn buffer_not_a_ciphertext() -> Self {
Self::BufferNotACiphertext
}
/// Create an [`Error::BufferSizeMismatch`].
pub fn buffer_size_mismatch() -> Self {
Self::BufferSizeMismatch
}
/// Create an [`Error::UopCiphertextMismatch`].
pub fn uop_ciphertext_mismatch() -> Self {
Self::UopCiphertextMismatch
}
/// Create an [`Error::OutOfRange`].
pub fn out_of_range(inst_id: usize, pc: u32) -> Self {
Self::OutOfRange { inst_id, pc }
}
/// Create an [`Error::NoBuffer`].
pub fn no_buffer(inst_id: usize, pc: u32) -> Self {
Error::NoBuffer { inst_id, pc }
}
}
/// Results for this crate.
pub type Result<T> = std::result::Result<T, Error>;