-
Notifications
You must be signed in to change notification settings - Fork 2
/
EncryptedErrors.sol
198 lines (169 loc) · 8.78 KB
/
EncryptedErrors.sol
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
// SPDX-License-Identifier: BSD-3-Clause-Clear
pragma solidity ^0.8.24;
import "fhevm/lib/TFHE.sol";
/**
* @title EncryptedErrors.
* @notice This abstract contract is used for error handling in the fhEVM.
* Error codes are encrypted in the constructor inside the `_errorCodeDefinitions` mapping.
* @dev `_errorCodeDefinitions[0]` should always refer to the `NO_ERROR` code, by default.
*/
abstract contract EncryptedErrors {
/// @notice Returned if the error index is invalid.
error ErrorIndexInvalid();
/// @notice Returned if the error index is null.
error ErrorIndexIsNull();
/// @notice Returned if the total number of errors is equal to zero.
error TotalNumberErrorCodesEqualToZero();
/// @notice Total number of error codes.
/// @dev Should hold the constant size of the `_errorCodeDefinitions` mapping.
uint8 private immutable _TOTAL_NUMBER_ERROR_CODES;
/// @notice Used to keep track of number of emitted errors.
/// @dev Should hold the size of the _errorCodesEmitted mapping.
uint256 private _errorCounter;
/// @notice Mapping of trivially encrypted error codes definitions.
/// @dev In storage because solc does not support immutable mapping, neither immutable arrays, yet.
mapping(uint8 errorCode => euint8 encryptedErrorCode) private _errorCodeDefinitions;
/// @notice Mapping of encrypted error codes emitted.
mapping(uint256 errorIndex => euint8 encryptedErrorCode) private _errorCodesEmitted;
/**
* @notice Sets the non-null value for `_TOTAL_NUMBER_ERROR_CODES`
* corresponding to the total number of errors.
* @param totalNumberErrorCodes_ Total number of different errors.
* @dev `totalNumberErrorCodes_` must be non-null
* (`_errorCodeDefinitions[0]` corresponds to the `NO_ERROR` code).
*/
constructor(uint8 totalNumberErrorCodes_) {
if (totalNumberErrorCodes_ == 0) {
revert TotalNumberErrorCodesEqualToZero();
}
for (uint8 i; i <= totalNumberErrorCodes_; i++) {
euint8 errorCode = TFHE.asEuint8(i);
_errorCodeDefinitions[i] = errorCode;
TFHE.allowThis(errorCode);
}
_TOTAL_NUMBER_ERROR_CODES = totalNumberErrorCodes_;
}
/**
* @notice Computes an encrypted error code, result will be either a reencryption of
* `_errorCodeDefinitions[indexCode]` if `condition` is an encrypted `true`
* or of `errorCode` otherwise.
* @param condition Encrypted boolean used in the select operator.
* @param errorCode Selected error code if `condition` encrypts `true`.
* @return newErrorCode New reencrypted error code depending on `condition` value.
* @dev ` indexCode` must be below the total number of error codes.
*/
function _errorChangeIf(
ebool condition,
uint8 indexCode,
euint8 errorCode
) internal virtual returns (euint8 newErrorCode) {
if (indexCode > _TOTAL_NUMBER_ERROR_CODES) {
revert ErrorIndexInvalid();
}
newErrorCode = TFHE.select(condition, _errorCodeDefinitions[indexCode], errorCode);
}
/**
* @notice Does the opposite of `changeErrorIf`, i.e result will be either a reencryption of
* `_errorCodeDefinitions[indexCode]` if `condition` is an encrypted `false`
* or of `errorCode` otherwise.
* @param condition The encrypted boolean used in the `TFHE.select`.
* @param errorCode The selected error code if `condition` encrypts `false`.
* @return newErrorCode New error code depending on `condition` value.
* @dev `indexCode` must be below the total number of error codes.
*/
function _errorChangeIfNot(
ebool condition,
uint8 indexCode,
euint8 errorCode
) internal virtual returns (euint8 newErrorCode) {
if (indexCode > _TOTAL_NUMBER_ERROR_CODES) {
revert ErrorIndexInvalid();
}
newErrorCode = TFHE.select(condition, errorCode, _errorCodeDefinitions[indexCode]);
}
/**
* @notice Computes an encrypted error code, result will be either a reencryption of
* `_errorCodeDefinitions[indexCode]` if `condition` is an encrypted `true`
* or of `NO_ERROR` otherwise.
* @param condition Encrypted boolean used in the select operator.
* @param indexCode Index of the selected error code if `condition` encrypts `true`.
* @return errorCode Reencrypted error code depending on `condition` value.
* @dev `indexCode` must be non-null and below the total number of defined error codes.
*/
function _errorDefineIf(ebool condition, uint8 indexCode) internal virtual returns (euint8 errorCode) {
if (indexCode == 0) {
revert ErrorIndexIsNull();
}
if (indexCode > _TOTAL_NUMBER_ERROR_CODES) {
revert ErrorIndexInvalid();
}
errorCode = TFHE.select(condition, _errorCodeDefinitions[indexCode], _errorCodeDefinitions[0]);
}
/**
* @notice Does the opposite of `defineErrorIf`, i.e result will be either a reencryption of
* `_errorCodeDefinitions[indexCode]` if `condition` is an encrypted `false` or
* of `NO_ERROR` otherwise.
* @param condition Encrypted boolean used in the select operator.
* @param indexCode Index of the selected error code if `condition` encrypts `false`.
* @return errorCode Reencrypted error code depending on `condition` value.
* @dev `indexCode` must be non-null and below the total number of defined error codes.
*/
function _errorDefineIfNot(ebool condition, uint8 indexCode) internal virtual returns (euint8 errorCode) {
if (indexCode == 0) {
revert ErrorIndexIsNull();
}
if (indexCode > _TOTAL_NUMBER_ERROR_CODES) {
revert ErrorIndexInvalid();
}
errorCode = TFHE.select(condition, _errorCodeDefinitions[0], _errorCodeDefinitions[indexCode]);
}
/**
* @notice Saves `errorCode` in storage, in the `_errorCodesEmitted` mapping.
* @param errorCode Encrypted error code to be saved in storage.
* @return errorId The `errorId` key in `_errorCodesEmitted` where `errorCode` is stored.
*/
function _errorSave(euint8 errorCode) internal virtual returns (uint256 errorId) {
errorId = _errorCounter;
_errorCounter++;
_errorCodesEmitted[errorId] = errorCode;
TFHE.allowThis(errorCode);
}
/**
* @notice Returns the trivially encrypted error code at index `indexCodeDefinition`.
* @param indexCodeDefinition Index of the requested error code definition.
* @return errorCode Encrypted error code located at `indexCodeDefinition` in `_errorCodeDefinitions`.
*/
function _errorGetCodeDefinition(uint8 indexCodeDefinition) internal view virtual returns (euint8 errorCode) {
if (indexCodeDefinition >= _TOTAL_NUMBER_ERROR_CODES) {
revert ErrorIndexInvalid();
}
errorCode = _errorCodeDefinitions[indexCodeDefinition];
}
/**
* @notice Returns the encrypted error code which was stored in `_errorCodesEmitted`
* at key `errorId`.
* @param errorId Requested key stored in the `_errorCodesEmitted` mapping.
* @return errorCode Encrypted error code located at the `errorId` key.
* @dev `errorId` must be a valid id, i.e below the error counter.
*/
function _errorGetCodeEmitted(uint256 errorId) internal view virtual returns (euint8 errorCode) {
if (errorId >= _errorCounter) {
revert ErrorIndexInvalid();
}
errorCode = _errorCodesEmitted[errorId];
}
/**
* @notice Returns the total counter of emitted of error codes.
* @return countErrors Number of errors emitted.
*/
function _errorGetCounter() internal view virtual returns (uint256 countErrors) {
countErrors = _errorCounter;
}
/**
* @notice Returns the total number of the possible error codes defined.
* @return totalNumberErrorCodes Total number of the different possible error codes.
*/
function _errorGetNumCodesDefined() internal view virtual returns (uint8 totalNumberErrorCodes) {
totalNumberErrorCodes = _TOTAL_NUMBER_ERROR_CODES;
}
}