@coti-io/coti-contracts 1.0.8 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/contracts/mocks/utils/mpc/Arithmetic128BitTestsContract.sol +260 -0
- package/contracts/mocks/utils/mpc/Arithmetic256BitTestsContract.sol +264 -0
- package/contracts/mocks/utils/mpc/Bitwise128BitTestsContract.sol +91 -0
- package/contracts/mocks/utils/mpc/Bitwise256BitTestsContract.sol +91 -0
- package/contracts/mocks/utils/mpc/Comparison128BitTestsContract.sol +158 -0
- package/contracts/mocks/utils/mpc/Comparison256BitTestsContract.sol +158 -0
- package/contracts/mocks/utils/mpc/Miscellaneous128BitTestsContract.sol +185 -0
- package/contracts/mocks/utils/mpc/Miscellaneous256BitTestsContract.sol +190 -0
- package/contracts/utils/mpc/MpcCore.sol +2804 -180
- package/hardhat.config.ts +6 -2
- package/package.json +2 -2
- package/test/token/PrivateERC20/PrivateERC20.test.ts +3 -3
- package/test/utils/mpc/Unsigned128BitIntegers.test.ts +945 -0
- package/test/utils/mpc/Unsigned256BitIntegers.test.ts +1124 -0
- package/test/utils/mpc/helpers.ts +77 -0
- package/typechain-types/contracts/mocks/utils/mpc/Arithmetic128BitTestsContract.ts +341 -0
- package/typechain-types/contracts/mocks/utils/mpc/Arithmetic256BitTestsContract.ts +347 -0
- package/typechain-types/contracts/mocks/utils/mpc/Bitwise128BitTestsContract.ts +186 -0
- package/typechain-types/contracts/mocks/utils/mpc/Bitwise256BitTestsContract.ts +186 -0
- package/typechain-types/contracts/mocks/utils/mpc/Comparison128BitTestsContract.ts +260 -0
- package/typechain-types/contracts/mocks/utils/mpc/Comparison256BitTestsContract.ts +260 -0
- package/typechain-types/contracts/mocks/utils/mpc/Miscellaneous128BitTestsContract.ts +302 -0
- package/typechain-types/contracts/mocks/utils/mpc/Miscellaneous256BitTestsContract.ts +322 -0
- package/typechain-types/contracts/mocks/utils/mpc/index.ts +8 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Arithmetic128BitTestsContract__factory.ts +349 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Arithmetic256BitTestsContract__factory.ts +364 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Bitwise128BitTestsContract__factory.ts +182 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Bitwise256BitTestsContract__factory.ts +182 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison128BitTestsContract__factory.ts +255 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Comparison256BitTestsContract__factory.ts +255 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Miscellaneous128BitTestsContract__factory.ts +332 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/Miscellaneous256BitTestsContract__factory.ts +380 -0
- package/typechain-types/factories/contracts/mocks/utils/mpc/index.ts +8 -0
- package/typechain-types/hardhat.d.ts +144 -0
- package/typechain-types/index.ts +16 -0
- package/contracts/package.json +0 -11
|
@@ -8,6 +8,18 @@ type gtUint16 is uint256;
|
|
|
8
8
|
type gtUint32 is uint256;
|
|
9
9
|
type gtUint64 is uint256;
|
|
10
10
|
|
|
11
|
+
// we use a struct because user-defined value types can only be elementary value types
|
|
12
|
+
struct gtUint128 {
|
|
13
|
+
gtUint64 high;
|
|
14
|
+
gtUint64 low;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// we use a struct because user-defined value types can only be elementary value types
|
|
18
|
+
struct gtUint256 {
|
|
19
|
+
gtUint128 high;
|
|
20
|
+
gtUint128 low;
|
|
21
|
+
}
|
|
22
|
+
|
|
11
23
|
// we use a struct because user-defined value types can only be elementary value types
|
|
12
24
|
// 8 characters (in byte form) per cell and the final cell padded with zeroes if needed
|
|
13
25
|
struct gtString {
|
|
@@ -20,6 +32,18 @@ type ctUint16 is uint256;
|
|
|
20
32
|
type ctUint32 is uint256;
|
|
21
33
|
type ctUint64 is uint256;
|
|
22
34
|
|
|
35
|
+
// we use a struct because user-defined value types can only be elementary value types
|
|
36
|
+
struct ctUint128 {
|
|
37
|
+
ctUint64 high;
|
|
38
|
+
ctUint64 low;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// we use a struct because user-defined value types can only be elementary value types
|
|
42
|
+
struct ctUint256 {
|
|
43
|
+
ctUint128 high;
|
|
44
|
+
ctUint128 low;
|
|
45
|
+
}
|
|
46
|
+
|
|
23
47
|
// we use a struct because user-defined value types can only be elementary value types
|
|
24
48
|
// 8 characters (in byte form) per cell and the final cell padded with zeroes if needed
|
|
25
49
|
struct ctString {
|
|
@@ -46,6 +70,14 @@ struct itUint64 {
|
|
|
46
70
|
ctUint64 ciphertext;
|
|
47
71
|
bytes signature;
|
|
48
72
|
}
|
|
73
|
+
struct itUint128 {
|
|
74
|
+
ctUint128 ciphertext;
|
|
75
|
+
bytes[2] signature;
|
|
76
|
+
}
|
|
77
|
+
struct itUint256 {
|
|
78
|
+
ctUint256 ciphertext;
|
|
79
|
+
bytes[2][2] signature;
|
|
80
|
+
}
|
|
49
81
|
struct itString {
|
|
50
82
|
ctString ciphertext;
|
|
51
83
|
bytes[] signature;
|
|
@@ -71,6 +103,14 @@ struct utUint64 {
|
|
|
71
103
|
ctUint64 ciphertext;
|
|
72
104
|
ctUint64 userCiphertext;
|
|
73
105
|
}
|
|
106
|
+
struct utUint128 {
|
|
107
|
+
ctUint128 ciphertext;
|
|
108
|
+
ctUint128 userCiphertext;
|
|
109
|
+
}
|
|
110
|
+
struct utUint256 {
|
|
111
|
+
ctUint256 ciphertext;
|
|
112
|
+
ctUint256 userCiphertext;
|
|
113
|
+
}
|
|
74
114
|
struct utString {
|
|
75
115
|
ctString ciphertext;
|
|
76
116
|
ctString userCiphertext;
|
|
@@ -998,288 +1038,1202 @@ library MpcCore {
|
|
|
998
1038
|
}
|
|
999
1039
|
|
|
1000
1040
|
|
|
1001
|
-
// ===========
|
|
1041
|
+
// =========== 128 bit operations ============
|
|
1002
1042
|
|
|
1003
|
-
function
|
|
1004
|
-
|
|
1043
|
+
function _splitUint128(uint128 number) private returns (uint64, uint64) {
|
|
1044
|
+
return (uint64(number >> 64), uint64(number));
|
|
1045
|
+
}
|
|
1005
1046
|
|
|
1006
|
-
|
|
1047
|
+
function validateCiphertext(itUint128 memory input) internal returns (gtUint128 memory) {
|
|
1048
|
+
gtUint128 memory result;
|
|
1049
|
+
|
|
1050
|
+
itUint64 memory highInput;
|
|
1051
|
+
highInput.ciphertext = input.ciphertext.high;
|
|
1052
|
+
highInput.signature = input.signature[0];
|
|
1053
|
+
|
|
1054
|
+
itUint64 memory lowInput;
|
|
1055
|
+
lowInput.ciphertext = input.ciphertext.low;
|
|
1056
|
+
lowInput.signature = input.signature[1];
|
|
1057
|
+
|
|
1058
|
+
result.high = validateCiphertext(highInput);
|
|
1059
|
+
result.low = validateCiphertext(lowInput);
|
|
1060
|
+
|
|
1061
|
+
return result;
|
|
1062
|
+
}
|
|
1007
1063
|
|
|
1008
|
-
|
|
1064
|
+
function onBoard(ctUint128 memory ct) internal returns (gtUint128 memory) {
|
|
1065
|
+
gtUint128 memory result;
|
|
1009
1066
|
|
|
1010
|
-
|
|
1067
|
+
result.high = onBoard(ct.high);
|
|
1068
|
+
result.low = onBoard(ct.low);
|
|
1011
1069
|
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
it_.signature = input.signature[i];
|
|
1070
|
+
return result;
|
|
1071
|
+
}
|
|
1015
1072
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1073
|
+
function offBoard(gtUint128 memory pt) internal returns (ctUint128 memory) {
|
|
1074
|
+
ctUint128 memory result;
|
|
1018
1075
|
|
|
1019
|
-
|
|
1020
|
-
|
|
1076
|
+
result.high = offBoard(pt.high);
|
|
1077
|
+
result.low = offBoard(pt.low);
|
|
1021
1078
|
|
|
1022
|
-
|
|
1023
|
-
|
|
1079
|
+
return result;
|
|
1080
|
+
}
|
|
1024
1081
|
|
|
1025
|
-
|
|
1082
|
+
function offBoardToUser(gtUint128 memory pt, address addr) internal returns (ctUint128 memory) {
|
|
1083
|
+
ctUint128 memory result;
|
|
1026
1084
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
}
|
|
1085
|
+
result.high = offBoardToUser(pt.high, addr);
|
|
1086
|
+
result.low = offBoardToUser(pt.low, addr);
|
|
1030
1087
|
|
|
1031
|
-
return
|
|
1088
|
+
return result;
|
|
1032
1089
|
}
|
|
1033
1090
|
|
|
1034
|
-
function
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
ctString memory ct_ = ctString(new ctUint64[](len_));
|
|
1091
|
+
function offBoardCombined(gtUint128 memory pt, address addr) internal returns (utUint128 memory) {
|
|
1092
|
+
utUint128 memory result;
|
|
1038
1093
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
}
|
|
1094
|
+
result.ciphertext = offBoard(pt);
|
|
1095
|
+
result.userCiphertext = offBoardToUser(pt, addr);
|
|
1042
1096
|
|
|
1043
|
-
return
|
|
1097
|
+
return result;
|
|
1044
1098
|
}
|
|
1045
1099
|
|
|
1046
|
-
function
|
|
1047
|
-
|
|
1100
|
+
function setPublic128(uint128 pt) internal returns (gtUint128 memory) {
|
|
1101
|
+
gtUint128 memory result;
|
|
1048
1102
|
|
|
1049
|
-
|
|
1103
|
+
// Split the 128-bit value into high and low 64-bit parts
|
|
1104
|
+
uint64 low = uint64(pt);
|
|
1105
|
+
uint64 high = uint64(pt >> 64);
|
|
1106
|
+
|
|
1107
|
+
result.high = setPublic64(high);
|
|
1108
|
+
result.low = setPublic64(low);
|
|
1109
|
+
|
|
1110
|
+
return result;
|
|
1111
|
+
}
|
|
1050
1112
|
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
}
|
|
1113
|
+
function rand128() internal returns (gtUint128 memory) {
|
|
1114
|
+
gtUint128 memory result;
|
|
1054
1115
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1116
|
+
result.high = rand64();
|
|
1117
|
+
result.low = rand64();
|
|
1057
1118
|
|
|
1058
|
-
|
|
1059
|
-
ut.ciphertext = offBoard(pt);
|
|
1060
|
-
ut.userCiphertext = offBoardToUser(pt, addr);
|
|
1119
|
+
return result;
|
|
1061
1120
|
}
|
|
1062
1121
|
|
|
1063
|
-
function
|
|
1064
|
-
|
|
1065
|
-
uint256 len_ = strBytes_.length;
|
|
1066
|
-
uint256 count_ = (len_ + 7) / 8; // Number of bytes8 elements needed
|
|
1122
|
+
function randBoundedBits128(uint8 numBits) internal returns (gtUint128 memory) {
|
|
1123
|
+
gtUint128 memory result;
|
|
1067
1124
|
|
|
1068
|
-
|
|
1125
|
+
uint8 numBits_ = numBits > 64 ? 64 : numBits;
|
|
1069
1126
|
|
|
1070
|
-
|
|
1127
|
+
result.low = randBoundedBits64(numBits_);
|
|
1071
1128
|
|
|
1072
|
-
|
|
1073
|
-
if (i % 8 == 0) {
|
|
1074
|
-
cell_ = bytes8(0);
|
|
1075
|
-
} else {
|
|
1076
|
-
cell_ <<= 8;
|
|
1077
|
-
}
|
|
1129
|
+
numBits_ = numBits > 64 ? numBits - 64 : 0;
|
|
1078
1130
|
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1131
|
+
result.high = randBoundedBits64(numBits_);
|
|
1132
|
+
|
|
1133
|
+
return result;
|
|
1134
|
+
}
|
|
1082
1135
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1136
|
+
function add(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1137
|
+
gtUint128 memory result;
|
|
1138
|
+
|
|
1139
|
+
// Add low parts
|
|
1140
|
+
result.low = add(a.low, b.low);
|
|
1141
|
+
|
|
1142
|
+
// Check if there's a carry from low addition
|
|
1143
|
+
gtBool carry = lt(result.low, a.low);
|
|
1144
|
+
|
|
1145
|
+
// Add high parts with carry if needed
|
|
1146
|
+
result.high = add(a.high, b.high);
|
|
1147
|
+
|
|
1148
|
+
// Add carry to high part if needed
|
|
1149
|
+
result.high = mux(carry, result.high, add(result.high, uint64(1)));
|
|
1150
|
+
|
|
1151
|
+
return result;
|
|
1152
|
+
}
|
|
1087
1153
|
|
|
1088
|
-
|
|
1154
|
+
function checkedAdd(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1155
|
+
gtUint128 memory result;
|
|
1156
|
+
|
|
1157
|
+
// Add low parts
|
|
1158
|
+
result.low = add(a.low, b.low);
|
|
1159
|
+
|
|
1160
|
+
// Check if there's a carry from low addition
|
|
1161
|
+
gtBool carry = lt(result.low, a.low);
|
|
1162
|
+
|
|
1163
|
+
// Add high parts with carry if needed
|
|
1164
|
+
result.high = checkedAdd(a.high, b.high);
|
|
1165
|
+
|
|
1166
|
+
// Add carry to high part if needed
|
|
1167
|
+
result.high = mux(carry, result.high, checkedAdd(result.high, uint64(1)));
|
|
1168
|
+
|
|
1169
|
+
return result;
|
|
1089
1170
|
}
|
|
1090
1171
|
|
|
1091
|
-
function
|
|
1092
|
-
|
|
1093
|
-
|
|
1172
|
+
function checkedAddWithOverflowBit(gtUint128 memory a, gtUint128 memory b) internal returns (gtBool, gtUint128 memory) {
|
|
1173
|
+
gtBool bit = setPublic(false);
|
|
1174
|
+
gtUint128 memory result;
|
|
1175
|
+
|
|
1176
|
+
// Add low parts
|
|
1177
|
+
result.low = add(a.low, b.low);
|
|
1178
|
+
|
|
1179
|
+
// Check if there's a carry from low addition
|
|
1180
|
+
gtBool carry = lt(result.low, a.low);
|
|
1181
|
+
|
|
1182
|
+
// Add high parts with carry if needed
|
|
1183
|
+
(gtBool overflow, gtUint64 high) = checkedAddWithOverflowBit(a.high, b.high);
|
|
1184
|
+
(gtBool overflowWithCarry, gtUint64 highWithCarry) = checkedAddWithOverflowBit(high, uint64(1));
|
|
1094
1185
|
|
|
1095
|
-
|
|
1186
|
+
// Handle carry if needed
|
|
1187
|
+
bit = mux(carry, overflow, or(overflow, overflowWithCarry));
|
|
1188
|
+
result.high = mux(carry, high, highWithCarry);
|
|
1189
|
+
|
|
1190
|
+
return (bit, result);
|
|
1191
|
+
}
|
|
1096
1192
|
|
|
1097
|
-
|
|
1193
|
+
function sub(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1194
|
+
gtUint128 memory result;
|
|
1098
1195
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1196
|
+
// Subtract low parts
|
|
1197
|
+
result.low = sub(a.low, b.low);
|
|
1198
|
+
|
|
1199
|
+
// Check if there's a borrow from low subtraction
|
|
1200
|
+
gtBool borrow = lt(a.low, b.low);
|
|
1201
|
+
|
|
1202
|
+
// Subtract high parts with borrow if needed
|
|
1203
|
+
result.high = sub(a.high, b.high);
|
|
1204
|
+
|
|
1205
|
+
// Subtract borrow from high part if needed
|
|
1206
|
+
result.high = mux(borrow, result.high, sub(result.high, uint64(1)));
|
|
1207
|
+
|
|
1208
|
+
return result;
|
|
1209
|
+
}
|
|
1101
1210
|
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1211
|
+
function checkedSub(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1212
|
+
gtUint128 memory result;
|
|
1213
|
+
|
|
1214
|
+
// Subtract low parts
|
|
1215
|
+
result.low = sub(a.low, b.low);
|
|
1216
|
+
|
|
1217
|
+
// Check if there's a borrow from low subtraction
|
|
1218
|
+
gtBool borrow = lt(a.low, b.low);
|
|
1219
|
+
|
|
1220
|
+
// Subtract high parts with borrow if needed
|
|
1221
|
+
result.high = checkedSub(a.high, b.high);
|
|
1222
|
+
|
|
1223
|
+
// Subtract borrow from high part if needed
|
|
1224
|
+
result.high = mux(
|
|
1225
|
+
borrow,
|
|
1226
|
+
result.high,
|
|
1227
|
+
checkedSub(
|
|
1228
|
+
mux(borrow, add(result.high, uint64(1)), result.high),
|
|
1229
|
+
uint64(1)
|
|
1230
|
+
)
|
|
1231
|
+
);
|
|
1232
|
+
|
|
1233
|
+
return result;
|
|
1234
|
+
}
|
|
1106
1235
|
|
|
1107
|
-
|
|
1108
|
-
|
|
1236
|
+
function checkedSubWithOverflowBit(gtUint128 memory a, gtUint128 memory b) internal returns (gtBool, gtUint128 memory) {
|
|
1237
|
+
gtBool bit = setPublic(false);
|
|
1238
|
+
gtUint128 memory result;
|
|
1239
|
+
|
|
1240
|
+
// Subtract low parts
|
|
1241
|
+
result.low = sub(a.low, b.low);
|
|
1242
|
+
|
|
1243
|
+
// Check if there's a borrow from low subtraction
|
|
1244
|
+
gtBool borrow = lt(a.low, b.low);
|
|
1245
|
+
|
|
1246
|
+
// Subtract high parts with borrow if needed
|
|
1247
|
+
(gtBool overflow, gtUint64 high) = checkedSubWithOverflowBit(a.high, b.high);
|
|
1248
|
+
(gtBool overflowWithCarry, gtUint64 highWithCarry) = checkedSubWithOverflowBit(high, uint64(1));
|
|
1109
1249
|
|
|
1110
|
-
|
|
1250
|
+
// Handle borrow if needed
|
|
1251
|
+
bit = mux(borrow, overflow, or(overflow, overflowWithCarry));
|
|
1252
|
+
result.high = mux(borrow, high, highWithCarry);
|
|
1253
|
+
|
|
1254
|
+
return (bit, result);
|
|
1111
1255
|
}
|
|
1112
1256
|
|
|
1113
|
-
function
|
|
1114
|
-
|
|
1257
|
+
function _mul64(gtUint64 a, gtUint64 b) private returns (gtUint64, gtUint64) {
|
|
1258
|
+
uint64 MAX_UINT32 = uint64(type(uint32).max);
|
|
1115
1259
|
|
|
1116
|
-
|
|
1117
|
-
|
|
1260
|
+
gtUint64 pp0;
|
|
1261
|
+
gtUint64 pp1;
|
|
1262
|
+
gtUint64 pp2;
|
|
1263
|
+
gtUint64 pp3;
|
|
1118
1264
|
|
|
1119
|
-
|
|
1265
|
+
{
|
|
1266
|
+
// Split the numbers into 32-bit parts
|
|
1267
|
+
gtUint64 aLow = and(a, MAX_UINT32);
|
|
1268
|
+
gtUint64 aHigh = shr(a, 32);
|
|
1269
|
+
gtUint64 bLow = and(b, MAX_UINT32);
|
|
1270
|
+
gtUint64 bHigh = shr(b, 32);
|
|
1120
1271
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1272
|
+
// Compute partial products
|
|
1273
|
+
pp0 = mul(aLow, bLow);
|
|
1274
|
+
pp1 = mul(aLow, bHigh);
|
|
1275
|
+
pp2 = mul(aHigh, bLow);
|
|
1276
|
+
pp3 = mul(aHigh, bHigh);
|
|
1123
1277
|
}
|
|
1124
1278
|
|
|
1125
|
-
|
|
1279
|
+
// Compute high and low parts
|
|
1280
|
+
gtUint64 mid = add(
|
|
1281
|
+
add(
|
|
1282
|
+
shr(pp0, 32),
|
|
1283
|
+
and(pp1, MAX_UINT32)
|
|
1284
|
+
),
|
|
1285
|
+
and(pp2, MAX_UINT32)
|
|
1286
|
+
);
|
|
1287
|
+
gtUint64 carry = shr(mid, 32);
|
|
1288
|
+
|
|
1289
|
+
gtUint64 high = add(
|
|
1290
|
+
add(pp3, shr(pp1, 32)),
|
|
1291
|
+
add(shr(pp2, 32), carry)
|
|
1292
|
+
);
|
|
1293
|
+
gtUint64 low = or(
|
|
1294
|
+
and(pp0, MAX_UINT32),
|
|
1295
|
+
shl(and(mid, MAX_UINT32), 32)
|
|
1296
|
+
);
|
|
1297
|
+
|
|
1298
|
+
return (high, low);
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
function mul(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1302
|
+
gtUint128 memory result;
|
|
1303
|
+
|
|
1304
|
+
// Compute partial products
|
|
1305
|
+
(gtUint64 pp0, gtUint64 low) = _mul64(a.low, b.low);
|
|
1306
|
+
(, gtUint64 pp1) = _mul64(a.high, b.low);
|
|
1307
|
+
(, gtUint64 pp2) = _mul64(a.low, b.high);
|
|
1308
|
+
|
|
1309
|
+
// Compute the high and low parts
|
|
1310
|
+
result.high = add(
|
|
1311
|
+
add(pp0, pp1),
|
|
1312
|
+
pp2
|
|
1313
|
+
);
|
|
1314
|
+
result.low = low;
|
|
1315
|
+
|
|
1316
|
+
return result;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
function checkedMul(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1320
|
+
gtUint128 memory result;
|
|
1321
|
+
|
|
1322
|
+
// Compute partial products
|
|
1323
|
+
(gtUint64 pp0, gtUint64 low) = _mul64(a.low, b.low);
|
|
1324
|
+
(gtUint64 pp2, gtUint64 pp1) = _mul64(a.high, b.low);
|
|
1325
|
+
(gtUint64 pp4, gtUint64 pp3) = _mul64(a.low, b.high);
|
|
1326
|
+
(gtUint64 pp6, gtUint64 pp5) = _mul64(a.high, b.high);
|
|
1327
|
+
|
|
1328
|
+
// Compute the high and low parts
|
|
1329
|
+
result.high = checkedAdd(
|
|
1330
|
+
checkedAdd(pp0, pp1),
|
|
1331
|
+
pp3
|
|
1332
|
+
);
|
|
1333
|
+
result.low = low;
|
|
1334
|
+
|
|
1335
|
+
// Check for overflow
|
|
1336
|
+
checkedSub(
|
|
1337
|
+
uint64(0),
|
|
1338
|
+
add(
|
|
1339
|
+
add(pp2, pp4),
|
|
1340
|
+
add(pp5, pp6)
|
|
1341
|
+
)
|
|
1342
|
+
);
|
|
1343
|
+
|
|
1344
|
+
return result;
|
|
1126
1345
|
}
|
|
1127
1346
|
|
|
1128
|
-
function
|
|
1129
|
-
|
|
1347
|
+
function checkedMulWithOverflowBit(gtUint128 memory a, gtUint128 memory b) internal returns (gtBool, gtUint128 memory) {
|
|
1348
|
+
gtUint128 memory result;
|
|
1130
1349
|
|
|
1131
|
-
//
|
|
1132
|
-
|
|
1350
|
+
// Compute partial products
|
|
1351
|
+
(gtUint64 pp0, gtUint64 low) = _mul64(a.low, b.low);
|
|
1352
|
+
(gtUint64 pp2, gtUint64 pp1) = _mul64(a.high, b.low);
|
|
1353
|
+
(gtUint64 pp4, gtUint64 pp3) = _mul64(a.low, b.high);
|
|
1354
|
+
(gtUint64 pp6, gtUint64 pp5) = _mul64(a.high, b.high);
|
|
1133
1355
|
|
|
1134
|
-
|
|
1356
|
+
// Compute the high and low parts
|
|
1357
|
+
gtBool overflow1;
|
|
1135
1358
|
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
}
|
|
1359
|
+
(gtBool overflow0, gtUint64 high) = checkedAddWithOverflowBit(pp0, pp1);
|
|
1360
|
+
(overflow1, result.high) = checkedAddWithOverflowBit(high, pp3);
|
|
1139
1361
|
|
|
1140
|
-
|
|
1141
|
-
}
|
|
1362
|
+
result.low = low;
|
|
1142
1363
|
|
|
1364
|
+
// Check for overflow
|
|
1365
|
+
gtBool bit = or(
|
|
1366
|
+
or(overflow0, overflow1),
|
|
1367
|
+
gt(
|
|
1368
|
+
add(
|
|
1369
|
+
add(pp2, pp4),
|
|
1370
|
+
add(pp5, pp6)
|
|
1371
|
+
),
|
|
1372
|
+
uint64(0)
|
|
1373
|
+
)
|
|
1374
|
+
);
|
|
1375
|
+
|
|
1376
|
+
return (bit, result);
|
|
1377
|
+
}
|
|
1143
1378
|
|
|
1144
|
-
|
|
1145
|
-
|
|
1379
|
+
function and(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1380
|
+
gtUint128 memory result;
|
|
1146
1381
|
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1382
|
+
result.low = and(a.low, b.low);
|
|
1383
|
+
result.high = and(a.high, b.high);
|
|
1384
|
+
|
|
1385
|
+
return result;
|
|
1150
1386
|
}
|
|
1151
1387
|
|
|
1152
|
-
function
|
|
1153
|
-
|
|
1154
|
-
CheckedAdd(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
1388
|
+
function or(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1389
|
+
gtUint128 memory result;
|
|
1155
1390
|
|
|
1156
|
-
|
|
1391
|
+
result.low = or(a.low, b.low);
|
|
1392
|
+
result.high = or(a.high, b.high);
|
|
1393
|
+
|
|
1394
|
+
return result;
|
|
1157
1395
|
}
|
|
1158
1396
|
|
|
1159
|
-
function
|
|
1160
|
-
|
|
1161
|
-
CheckedAdd(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
1397
|
+
function xor(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1398
|
+
gtUint128 memory result;
|
|
1162
1399
|
|
|
1163
|
-
|
|
1400
|
+
result.low = xor(a.low, b.low);
|
|
1401
|
+
result.high = xor(a.high, b.high);
|
|
1402
|
+
|
|
1403
|
+
return result;
|
|
1164
1404
|
}
|
|
1165
1405
|
|
|
1166
|
-
function
|
|
1167
|
-
return
|
|
1168
|
-
Sub(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
1406
|
+
function eq(gtUint128 memory a, gtUint128 memory b) internal returns (gtBool) {
|
|
1407
|
+
return and(eq(a.low, b.low), eq(a.high, b.high));
|
|
1169
1408
|
}
|
|
1170
1409
|
|
|
1171
|
-
function
|
|
1172
|
-
(
|
|
1173
|
-
CheckedSub(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
1174
|
-
|
|
1175
|
-
return checkRes8(gtBool.wrap(bit), gtUint8.wrap(res));
|
|
1410
|
+
function ne(gtUint128 memory a, gtUint128 memory b) internal returns (gtBool) {
|
|
1411
|
+
return or(ne(a.low, b.low), ne(a.high, b.high));
|
|
1176
1412
|
}
|
|
1177
1413
|
|
|
1178
|
-
function
|
|
1179
|
-
|
|
1180
|
-
CheckedSub(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
1414
|
+
function ge(gtUint128 memory a, gtUint128 memory b) internal returns (gtBool) {
|
|
1415
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1181
1416
|
|
|
1182
|
-
return (
|
|
1417
|
+
return mux(highEqual, gt(a.high, b.high), ge(a.low, b.low));
|
|
1183
1418
|
}
|
|
1184
1419
|
|
|
1185
|
-
function
|
|
1186
|
-
|
|
1187
|
-
|
|
1420
|
+
function gt(gtUint128 memory a, gtUint128 memory b) internal returns (gtBool) {
|
|
1421
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1422
|
+
|
|
1423
|
+
return mux(highEqual, gt(a.high, b.high), gt(a.low, b.low));
|
|
1188
1424
|
}
|
|
1189
1425
|
|
|
1190
|
-
function
|
|
1191
|
-
|
|
1192
|
-
CheckedMul(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
1426
|
+
function le(gtUint128 memory a, gtUint128 memory b) internal returns (gtBool) {
|
|
1427
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1193
1428
|
|
|
1194
|
-
return
|
|
1429
|
+
return mux(highEqual, lt(a.high, b.high), le(a.low, b.low));
|
|
1195
1430
|
}
|
|
1196
1431
|
|
|
1197
|
-
function
|
|
1198
|
-
|
|
1199
|
-
CheckedMul(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
1432
|
+
function lt(gtUint128 memory a, gtUint128 memory b) internal returns (gtBool) {
|
|
1433
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1200
1434
|
|
|
1201
|
-
return (
|
|
1435
|
+
return mux(highEqual, lt(a.high, b.high), lt(a.low, b.low));
|
|
1202
1436
|
}
|
|
1203
1437
|
|
|
1204
|
-
function
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1438
|
+
function min(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1439
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1440
|
+
gtBool aHighLessThan = lt(a.high, b.high);
|
|
1441
|
+
gtBool aLowLessThan = lt(a.low, b.low);
|
|
1208
1442
|
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1443
|
+
return mux(
|
|
1444
|
+
highEqual,
|
|
1445
|
+
mux(aHighLessThan, b, a),
|
|
1446
|
+
mux(aLowLessThan, b, a)
|
|
1447
|
+
);
|
|
1212
1448
|
}
|
|
1213
1449
|
|
|
1214
|
-
function
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1450
|
+
function max(gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1451
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1452
|
+
gtBool aHighGreaterThan = gt(a.high, b.high);
|
|
1453
|
+
gtBool aLowGreaterThan = gt(a.low, b.low);
|
|
1218
1454
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1455
|
+
return mux(
|
|
1456
|
+
highEqual,
|
|
1457
|
+
mux(aHighGreaterThan, b, a),
|
|
1458
|
+
mux(aLowGreaterThan, b, a)
|
|
1459
|
+
);
|
|
1222
1460
|
}
|
|
1223
1461
|
|
|
1224
|
-
function
|
|
1225
|
-
|
|
1226
|
-
|
|
1462
|
+
function decrypt(gtUint128 memory ct) internal returns (uint128) {
|
|
1463
|
+
uint64 highPart = decrypt(ct.high);
|
|
1464
|
+
uint64 lowPart = decrypt(ct.low);
|
|
1465
|
+
|
|
1466
|
+
// Combine high and low parts
|
|
1467
|
+
return uint128(highPart) << 64 | uint128(lowPart);
|
|
1227
1468
|
}
|
|
1228
1469
|
|
|
1229
|
-
function
|
|
1230
|
-
|
|
1231
|
-
Eq(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
1232
|
-
}
|
|
1470
|
+
function mux(gtBool bit, gtUint128 memory a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
1471
|
+
gtUint128 memory result;
|
|
1233
1472
|
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1473
|
+
result.low = mux(bit, a.low, b.low);
|
|
1474
|
+
result.high = mux(bit, a.high, b.high);
|
|
1475
|
+
|
|
1476
|
+
return result;
|
|
1237
1477
|
}
|
|
1238
1478
|
|
|
1239
|
-
function
|
|
1240
|
-
|
|
1241
|
-
Ge(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
1242
|
-
}
|
|
1479
|
+
function transfer(gtUint128 memory a, gtUint128 memory b, gtUint128 memory amount) internal returns (gtUint128 memory, gtUint128 memory, gtBool) {
|
|
1480
|
+
gtBool success = MpcCore.ge(a, amount);
|
|
1243
1481
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1482
|
+
gtUint128 memory a_ = MpcCore.mux(success, a, MpcCore.sub(a, amount));
|
|
1483
|
+
gtUint128 memory b_ = MpcCore.mux(success, b, MpcCore.add(b, amount));
|
|
1484
|
+
|
|
1485
|
+
return (a_, b_, success);
|
|
1247
1486
|
}
|
|
1248
1487
|
|
|
1249
|
-
function
|
|
1250
|
-
|
|
1251
|
-
Le(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
1252
|
-
}
|
|
1488
|
+
function transferWithAllowance(gtUint128 memory a, gtUint128 memory b, gtUint128 memory amount, gtUint128 memory allowance) internal returns (gtUint128 memory, gtUint128 memory, gtBool, gtUint128 memory) {
|
|
1489
|
+
gtBool success = MpcCore.and(MpcCore.ge(a, amount), MpcCore.le(amount, allowance));
|
|
1253
1490
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1491
|
+
gtUint128 memory a_ = MpcCore.mux(success, a, MpcCore.sub(a, amount));
|
|
1492
|
+
gtUint128 memory b_ = MpcCore.mux(success, b, MpcCore.add(b, amount));
|
|
1493
|
+
gtUint128 memory allowance_ = MpcCore.mux(success, allowance, MpcCore.sub(allowance, amount));
|
|
1494
|
+
|
|
1495
|
+
return (a_, b_, success, allowance_);
|
|
1257
1496
|
}
|
|
1258
1497
|
|
|
1259
|
-
|
|
1260
|
-
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
1261
|
-
Min(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
1262
|
-
}
|
|
1498
|
+
// =========== 256 bit operations ============
|
|
1263
1499
|
|
|
1264
|
-
function
|
|
1265
|
-
return
|
|
1266
|
-
Max(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
1500
|
+
function _splitUint256(uint256 number) private returns (uint128, uint128) {
|
|
1501
|
+
return (uint128(number >> 128), uint128(number));
|
|
1267
1502
|
}
|
|
1268
1503
|
|
|
1269
|
-
function
|
|
1270
|
-
|
|
1271
|
-
|
|
1504
|
+
function validateCiphertext(itUint256 memory input) internal returns (gtUint256 memory) {
|
|
1505
|
+
gtUint256 memory result;
|
|
1506
|
+
|
|
1507
|
+
itUint128 memory highInput;
|
|
1508
|
+
highInput.ciphertext = input.ciphertext.high;
|
|
1509
|
+
highInput.signature = input.signature[0];
|
|
1510
|
+
|
|
1511
|
+
itUint128 memory lowInput;
|
|
1512
|
+
lowInput.ciphertext = input.ciphertext.low;
|
|
1513
|
+
lowInput.signature = input.signature[1];
|
|
1514
|
+
|
|
1515
|
+
result.high = validateCiphertext(highInput);
|
|
1516
|
+
result.low = validateCiphertext(lowInput);
|
|
1517
|
+
|
|
1518
|
+
return result;
|
|
1272
1519
|
}
|
|
1273
1520
|
|
|
1521
|
+
function onBoard(ctUint256 memory ct) internal returns (gtUint256 memory) {
|
|
1522
|
+
gtUint256 memory result;
|
|
1274
1523
|
|
|
1275
|
-
|
|
1524
|
+
result.high = onBoard(ct.high);
|
|
1525
|
+
result.low = onBoard(ct.low);
|
|
1276
1526
|
|
|
1277
|
-
|
|
1278
|
-
return gtUint16.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
1279
|
-
Add(combineEnumsToBytes3(MPC_TYPE.SUINT16_T, MPC_TYPE.SUINT16_T, ARGS.LHS_PUBLIC), uint256(a), gtUint16.unwrap(b)));
|
|
1527
|
+
return result;
|
|
1280
1528
|
}
|
|
1281
1529
|
|
|
1282
|
-
function
|
|
1530
|
+
function offBoard(gtUint256 memory pt) internal returns (ctUint256 memory) {
|
|
1531
|
+
ctUint256 memory result;
|
|
1532
|
+
|
|
1533
|
+
result.high = offBoard(pt.high);
|
|
1534
|
+
result.low = offBoard(pt.low);
|
|
1535
|
+
|
|
1536
|
+
return result;
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
function offBoardToUser(gtUint256 memory pt, address addr) internal returns (ctUint256 memory) {
|
|
1540
|
+
ctUint256 memory result;
|
|
1541
|
+
|
|
1542
|
+
result.high = offBoardToUser(pt.high, addr);
|
|
1543
|
+
result.low = offBoardToUser(pt.low, addr);
|
|
1544
|
+
|
|
1545
|
+
return result;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
function offBoardCombined(gtUint256 memory pt, address addr) internal returns (utUint256 memory) {
|
|
1549
|
+
utUint256 memory result;
|
|
1550
|
+
|
|
1551
|
+
result.ciphertext = offBoard(pt);
|
|
1552
|
+
result.userCiphertext = offBoardToUser(pt, addr);
|
|
1553
|
+
|
|
1554
|
+
return result;
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
function setPublic256(uint256 pt) internal returns (gtUint256 memory) {
|
|
1558
|
+
gtUint256 memory result;
|
|
1559
|
+
|
|
1560
|
+
// Split the 256-bit value into high and low 128-bit parts
|
|
1561
|
+
uint128 low = uint128(pt);
|
|
1562
|
+
uint128 high = uint128(pt >> 128);
|
|
1563
|
+
|
|
1564
|
+
result.high = setPublic128(high);
|
|
1565
|
+
result.low = setPublic128(low);
|
|
1566
|
+
|
|
1567
|
+
return result;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
function rand256() internal returns (gtUint256 memory) {
|
|
1571
|
+
gtUint256 memory result;
|
|
1572
|
+
|
|
1573
|
+
result.high = rand128();
|
|
1574
|
+
result.low = rand128();
|
|
1575
|
+
|
|
1576
|
+
return result;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
function randBoundedBits256(uint8 numBits) internal returns (gtUint256 memory) {
|
|
1580
|
+
gtUint256 memory result;
|
|
1581
|
+
|
|
1582
|
+
uint8 numBits_ = numBits > 128 ? 128 : numBits;
|
|
1583
|
+
|
|
1584
|
+
result.low = randBoundedBits128(numBits_);
|
|
1585
|
+
|
|
1586
|
+
numBits_ = numBits > 128 ? numBits - 128 : 0;
|
|
1587
|
+
|
|
1588
|
+
result.high = randBoundedBits128(numBits_);
|
|
1589
|
+
|
|
1590
|
+
return result;
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
function add(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1594
|
+
gtUint256 memory result;
|
|
1595
|
+
|
|
1596
|
+
// Add low parts
|
|
1597
|
+
result.low = add(a.low, b.low);
|
|
1598
|
+
|
|
1599
|
+
// Check if there's a carry from low addition
|
|
1600
|
+
gtBool carry = lt(result.low, a.low);
|
|
1601
|
+
|
|
1602
|
+
// Add high parts with carry if needed
|
|
1603
|
+
result.high = add(a.high, b.high);
|
|
1604
|
+
|
|
1605
|
+
// Add carry to high part if needed
|
|
1606
|
+
result.high = mux(carry, result.high, add(result.high, uint128(1)));
|
|
1607
|
+
|
|
1608
|
+
return result;
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
function checkedAdd(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1612
|
+
gtUint256 memory result;
|
|
1613
|
+
|
|
1614
|
+
// Add low parts
|
|
1615
|
+
result.low = add(a.low, b.low);
|
|
1616
|
+
|
|
1617
|
+
// Check if there's a carry from low addition
|
|
1618
|
+
gtBool carry = lt(result.low, a.low);
|
|
1619
|
+
|
|
1620
|
+
// Add high parts with carry if needed
|
|
1621
|
+
result.high = checkedAdd(a.high, b.high);
|
|
1622
|
+
|
|
1623
|
+
// Add carry to high part if needed
|
|
1624
|
+
result.high = mux(carry, result.high, checkedAdd(result.high, uint128(1)));
|
|
1625
|
+
|
|
1626
|
+
return result;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
function checkedAddWithOverflowBit(gtUint256 memory a, gtUint256 memory b) internal returns (gtBool, gtUint256 memory) {
|
|
1630
|
+
gtBool bit = setPublic(false);
|
|
1631
|
+
gtUint256 memory result;
|
|
1632
|
+
|
|
1633
|
+
// Add low parts
|
|
1634
|
+
result.low = add(a.low, b.low);
|
|
1635
|
+
|
|
1636
|
+
// Check if there's a carry from low addition
|
|
1637
|
+
gtBool carry = lt(result.low, a.low);
|
|
1638
|
+
|
|
1639
|
+
// Add high parts with carry if needed
|
|
1640
|
+
(gtBool overflow, gtUint128 memory high) = checkedAddWithOverflowBit(a.high, b.high);
|
|
1641
|
+
(gtBool overflowWithCarry, gtUint128 memory highWithCarry) = checkedAddWithOverflowBit(high, uint128(1));
|
|
1642
|
+
|
|
1643
|
+
// Handle carry if needed
|
|
1644
|
+
bit = mux(carry, overflow, or(overflow, overflowWithCarry));
|
|
1645
|
+
result.high = mux(carry, high, highWithCarry);
|
|
1646
|
+
|
|
1647
|
+
return (bit, result);
|
|
1648
|
+
}
|
|
1649
|
+
|
|
1650
|
+
function sub(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1651
|
+
gtUint256 memory result;
|
|
1652
|
+
|
|
1653
|
+
// Subtract low parts
|
|
1654
|
+
result.low = sub(a.low, b.low);
|
|
1655
|
+
|
|
1656
|
+
// Check if there's a borrow from low subtraction
|
|
1657
|
+
gtBool borrow = lt(a.low, b.low);
|
|
1658
|
+
|
|
1659
|
+
// Subtract high parts with borrow if needed
|
|
1660
|
+
result.high = sub(a.high, b.high);
|
|
1661
|
+
|
|
1662
|
+
// Subtract borrow from high part if needed
|
|
1663
|
+
result.high = mux(borrow, result.high, sub(result.high, uint128(1)));
|
|
1664
|
+
|
|
1665
|
+
return result;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
function checkedSub(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1669
|
+
gtUint256 memory result;
|
|
1670
|
+
|
|
1671
|
+
// Subtract low parts
|
|
1672
|
+
result.low = sub(a.low, b.low);
|
|
1673
|
+
|
|
1674
|
+
// Check if there's a borrow from low subtraction
|
|
1675
|
+
gtBool borrow = lt(a.low, b.low);
|
|
1676
|
+
|
|
1677
|
+
// Subtract high parts with borrow if needed
|
|
1678
|
+
result.high = checkedSub(a.high, b.high);
|
|
1679
|
+
|
|
1680
|
+
// Subtract borrow from high part if needed
|
|
1681
|
+
result.high = mux(
|
|
1682
|
+
borrow,
|
|
1683
|
+
result.high,
|
|
1684
|
+
checkedSub(
|
|
1685
|
+
mux(borrow, add(result.high, uint128(1)), result.high),
|
|
1686
|
+
uint128(1)
|
|
1687
|
+
)
|
|
1688
|
+
);
|
|
1689
|
+
|
|
1690
|
+
return result;
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
function checkedSubWithOverflowBit(gtUint256 memory a, gtUint256 memory b) internal returns (gtBool, gtUint256 memory) {
|
|
1694
|
+
gtBool bit = setPublic(false);
|
|
1695
|
+
gtUint256 memory result;
|
|
1696
|
+
|
|
1697
|
+
// Subtract low parts
|
|
1698
|
+
result.low = sub(a.low, b.low);
|
|
1699
|
+
|
|
1700
|
+
// Check if there's a borrow from low subtraction
|
|
1701
|
+
gtBool borrow = lt(a.low, b.low);
|
|
1702
|
+
|
|
1703
|
+
// Subtract high parts with borrow if needed
|
|
1704
|
+
(gtBool overflow, gtUint128 memory high) = checkedSubWithOverflowBit(a.high, b.high);
|
|
1705
|
+
(gtBool overflowWithCarry, gtUint128 memory highWithCarry) = checkedSubWithOverflowBit(high, uint128(1));
|
|
1706
|
+
|
|
1707
|
+
// Handle borrow if needed
|
|
1708
|
+
bit = mux(borrow, overflow, or(overflow, overflowWithCarry));
|
|
1709
|
+
result.high = mux(borrow, high, highWithCarry);
|
|
1710
|
+
|
|
1711
|
+
return (bit, result);
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
function _mul128(gtUint128 memory a, gtUint128 memory b) private returns (gtUint128 memory, gtUint128 memory) {
|
|
1715
|
+
uint128 MAX_UINT64 = uint128(type(uint64).max);
|
|
1716
|
+
|
|
1717
|
+
gtUint128 memory pp0;
|
|
1718
|
+
gtUint128 memory pp1;
|
|
1719
|
+
gtUint128 memory pp2;
|
|
1720
|
+
gtUint128 memory pp3;
|
|
1721
|
+
|
|
1722
|
+
{
|
|
1723
|
+
// Split the numbers into 32-bit parts
|
|
1724
|
+
gtUint128 memory aLow = and(a, MAX_UINT64);
|
|
1725
|
+
gtUint128 memory aHigh = shr(a, 64);
|
|
1726
|
+
gtUint128 memory bLow = and(b, MAX_UINT64);
|
|
1727
|
+
gtUint128 memory bHigh = shr(b, 64);
|
|
1728
|
+
|
|
1729
|
+
// Compute partial products
|
|
1730
|
+
pp0 = mul(aLow, bLow);
|
|
1731
|
+
pp1 = mul(aLow, bHigh);
|
|
1732
|
+
pp2 = mul(aHigh, bLow);
|
|
1733
|
+
pp3 = mul(aHigh, bHigh);
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1736
|
+
// Compute high and low parts
|
|
1737
|
+
gtUint128 memory mid = add(
|
|
1738
|
+
add(
|
|
1739
|
+
shr(pp0, 64),
|
|
1740
|
+
and(pp1, MAX_UINT64)
|
|
1741
|
+
),
|
|
1742
|
+
and(pp2, MAX_UINT64)
|
|
1743
|
+
);
|
|
1744
|
+
gtUint128 memory carry = shr(mid, 64);
|
|
1745
|
+
|
|
1746
|
+
gtUint128 memory high = add(
|
|
1747
|
+
add(pp3, shr(pp1, 64)),
|
|
1748
|
+
add(shr(pp2, 64), carry)
|
|
1749
|
+
);
|
|
1750
|
+
gtUint128 memory low = or(
|
|
1751
|
+
and(pp0, MAX_UINT64),
|
|
1752
|
+
shl(and(mid, MAX_UINT64), 64)
|
|
1753
|
+
);
|
|
1754
|
+
|
|
1755
|
+
return (high, low);
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
function mul(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1759
|
+
gtUint256 memory result;
|
|
1760
|
+
|
|
1761
|
+
// Compute partial products
|
|
1762
|
+
(gtUint128 memory pp0, gtUint128 memory low) = _mul128(a.low, b.low);
|
|
1763
|
+
(, gtUint128 memory pp1) = _mul128(a.high, b.low);
|
|
1764
|
+
(, gtUint128 memory pp2) = _mul128(a.low, b.high);
|
|
1765
|
+
|
|
1766
|
+
// Compute the high and low parts
|
|
1767
|
+
result.high = add(
|
|
1768
|
+
add(pp0, pp1),
|
|
1769
|
+
pp2
|
|
1770
|
+
);
|
|
1771
|
+
result.low = low;
|
|
1772
|
+
|
|
1773
|
+
return result;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
function checkedMul(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1777
|
+
gtUint256 memory result;
|
|
1778
|
+
|
|
1779
|
+
// Compute partial products
|
|
1780
|
+
(gtUint128 memory pp0, gtUint128 memory low) = _mul128(a.low, b.low);
|
|
1781
|
+
(gtUint128 memory pp2, gtUint128 memory pp1) = _mul128(a.high, b.low);
|
|
1782
|
+
(gtUint128 memory pp4, gtUint128 memory pp3) = _mul128(a.low, b.high);
|
|
1783
|
+
(gtUint128 memory pp6, gtUint128 memory pp5) = _mul128(a.high, b.high);
|
|
1784
|
+
|
|
1785
|
+
// Compute the high and low parts
|
|
1786
|
+
result.high = checkedAdd(
|
|
1787
|
+
checkedAdd(pp0, pp1),
|
|
1788
|
+
pp3
|
|
1789
|
+
);
|
|
1790
|
+
result.low = low;
|
|
1791
|
+
|
|
1792
|
+
// Check for overflow
|
|
1793
|
+
checkedSub(
|
|
1794
|
+
uint128(0),
|
|
1795
|
+
add(
|
|
1796
|
+
add(pp2, pp4),
|
|
1797
|
+
add(pp5, pp6)
|
|
1798
|
+
)
|
|
1799
|
+
);
|
|
1800
|
+
|
|
1801
|
+
return result;
|
|
1802
|
+
}
|
|
1803
|
+
|
|
1804
|
+
function checkedMulWithOverflowBit(gtUint256 memory a, gtUint256 memory b) internal returns (gtBool, gtUint256 memory) {
|
|
1805
|
+
gtUint256 memory result;
|
|
1806
|
+
|
|
1807
|
+
// Compute partial products
|
|
1808
|
+
(gtUint128 memory pp0, gtUint128 memory low) = _mul128(a.low, b.low);
|
|
1809
|
+
(gtUint128 memory pp2, gtUint128 memory pp1) = _mul128(a.high, b.low);
|
|
1810
|
+
(gtUint128 memory pp4, gtUint128 memory pp3) = _mul128(a.low, b.high);
|
|
1811
|
+
(gtUint128 memory pp6, gtUint128 memory pp5) = _mul128(a.high, b.high);
|
|
1812
|
+
|
|
1813
|
+
// Compute the high and low parts
|
|
1814
|
+
gtBool overflow1;
|
|
1815
|
+
|
|
1816
|
+
(gtBool overflow0, gtUint128 memory high) = checkedAddWithOverflowBit(pp0, pp1);
|
|
1817
|
+
(overflow1, result.high) = checkedAddWithOverflowBit(high, pp3);
|
|
1818
|
+
|
|
1819
|
+
result.low = low;
|
|
1820
|
+
|
|
1821
|
+
// Check for overflow
|
|
1822
|
+
gtBool bit = or(
|
|
1823
|
+
or(overflow0, overflow1),
|
|
1824
|
+
gt(
|
|
1825
|
+
add(
|
|
1826
|
+
add(pp2, pp4),
|
|
1827
|
+
add(pp5, pp6)
|
|
1828
|
+
),
|
|
1829
|
+
uint128(0)
|
|
1830
|
+
)
|
|
1831
|
+
);
|
|
1832
|
+
|
|
1833
|
+
return (bit, result);
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
function and(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1837
|
+
gtUint256 memory result;
|
|
1838
|
+
|
|
1839
|
+
result.low = and(a.low, b.low);
|
|
1840
|
+
result.high = and(a.high, b.high);
|
|
1841
|
+
|
|
1842
|
+
return result;
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
function or(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1846
|
+
gtUint256 memory result;
|
|
1847
|
+
|
|
1848
|
+
result.low = or(a.low, b.low);
|
|
1849
|
+
result.high = or(a.high, b.high);
|
|
1850
|
+
|
|
1851
|
+
return result;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
function xor(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1855
|
+
gtUint256 memory result;
|
|
1856
|
+
|
|
1857
|
+
result.low = xor(a.low, b.low);
|
|
1858
|
+
result.high = xor(a.high, b.high);
|
|
1859
|
+
|
|
1860
|
+
return result;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
function eq(gtUint256 memory a, gtUint256 memory b) internal returns (gtBool) {
|
|
1864
|
+
return and(eq(a.low, b.low), eq(a.high, b.high));
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
function ne(gtUint256 memory a, gtUint256 memory b) internal returns (gtBool) {
|
|
1868
|
+
return or(ne(a.low, b.low), ne(a.high, b.high));
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
function ge(gtUint256 memory a, gtUint256 memory b) internal returns (gtBool) {
|
|
1872
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1873
|
+
|
|
1874
|
+
return mux(highEqual, gt(a.high, b.high), ge(a.low, b.low));
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
function gt(gtUint256 memory a, gtUint256 memory b) internal returns (gtBool) {
|
|
1878
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1879
|
+
|
|
1880
|
+
return mux(highEqual, gt(a.high, b.high), gt(a.low, b.low));
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
function le(gtUint256 memory a, gtUint256 memory b) internal returns (gtBool) {
|
|
1884
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1885
|
+
|
|
1886
|
+
return mux(highEqual, lt(a.high, b.high), le(a.low, b.low));
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
function lt(gtUint256 memory a, gtUint256 memory b) internal returns (gtBool) {
|
|
1890
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1891
|
+
|
|
1892
|
+
return mux(highEqual, lt(a.high, b.high), lt(a.low, b.low));
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
function min(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1896
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1897
|
+
gtBool aHighLessThan = lt(a.high, b.high);
|
|
1898
|
+
gtBool aLowLessThan = lt(a.low, b.low);
|
|
1899
|
+
|
|
1900
|
+
return mux(
|
|
1901
|
+
highEqual,
|
|
1902
|
+
mux(aHighLessThan, b, a),
|
|
1903
|
+
mux(aLowLessThan, b, a)
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
function max(gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1908
|
+
gtBool highEqual = eq(a.high, b.high);
|
|
1909
|
+
gtBool aHighGreaterThan = gt(a.high, b.high);
|
|
1910
|
+
gtBool aLowGreaterThan = gt(a.low, b.low);
|
|
1911
|
+
|
|
1912
|
+
return mux(
|
|
1913
|
+
highEqual,
|
|
1914
|
+
mux(aHighGreaterThan, b, a),
|
|
1915
|
+
mux(aLowGreaterThan, b, a)
|
|
1916
|
+
);
|
|
1917
|
+
}
|
|
1918
|
+
|
|
1919
|
+
function decrypt(gtUint256 memory ct) internal returns (uint256) {
|
|
1920
|
+
uint128 highPart = decrypt(ct.high);
|
|
1921
|
+
uint128 lowPart = decrypt(ct.low);
|
|
1922
|
+
|
|
1923
|
+
// Combine high and low parts
|
|
1924
|
+
return uint256(highPart) << 128 | uint256(lowPart);
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1927
|
+
function mux(gtBool bit, gtUint256 memory a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
1928
|
+
gtUint256 memory result;
|
|
1929
|
+
|
|
1930
|
+
result.low = mux(bit, a.low, b.low);
|
|
1931
|
+
result.high = mux(bit, a.high, b.high);
|
|
1932
|
+
|
|
1933
|
+
return result;
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
function transfer(gtUint256 memory a, gtUint256 memory b, gtUint256 memory amount) internal returns (gtUint256 memory, gtUint256 memory, gtBool) {
|
|
1937
|
+
gtBool success = MpcCore.ge(a, amount);
|
|
1938
|
+
|
|
1939
|
+
gtUint256 memory a_ = MpcCore.mux(success, a, MpcCore.sub(a, amount));
|
|
1940
|
+
gtUint256 memory b_ = MpcCore.mux(success, b, MpcCore.add(b, amount));
|
|
1941
|
+
|
|
1942
|
+
return (a_, b_, success);
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
function transferWithAllowance(gtUint256 memory a, gtUint256 memory b, gtUint256 memory amount, gtUint256 memory allowance) internal returns (gtUint256 memory, gtUint256 memory, gtBool, gtUint256 memory) {
|
|
1946
|
+
gtBool success = MpcCore.and(MpcCore.ge(a, amount), MpcCore.le(amount, allowance));
|
|
1947
|
+
|
|
1948
|
+
gtUint256 memory a_ = MpcCore.mux(success, a, MpcCore.sub(a, amount));
|
|
1949
|
+
gtUint256 memory b_ = MpcCore.mux(success, b, MpcCore.add(b, amount));
|
|
1950
|
+
gtUint256 memory allowance_ = MpcCore.mux(success, allowance, MpcCore.sub(allowance, amount));
|
|
1951
|
+
|
|
1952
|
+
return (a_, b_, success, allowance_);
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
// =========== String operations ============
|
|
1956
|
+
|
|
1957
|
+
function validateCiphertext(itString memory input) internal returns (gtString memory) {
|
|
1958
|
+
uint256 len_ = input.signature.length;
|
|
1959
|
+
|
|
1960
|
+
require(input.ciphertext.value.length == len_, "MPC_CORE: INVALID_INPUT_TEXT");
|
|
1961
|
+
|
|
1962
|
+
gtString memory gt_ = gtString(new gtUint64[](len_));
|
|
1963
|
+
|
|
1964
|
+
itUint64 memory it_;
|
|
1965
|
+
|
|
1966
|
+
for (uint256 i = 0; i < len_; ++i) {
|
|
1967
|
+
it_.ciphertext = input.ciphertext.value[i];
|
|
1968
|
+
it_.signature = input.signature[i];
|
|
1969
|
+
|
|
1970
|
+
gt_.value[i] = validateCiphertext(it_);
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
return gt_;
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
function onBoard(ctString memory ct) internal returns (gtString memory) {
|
|
1977
|
+
uint256 len_ = ct.value.length;
|
|
1978
|
+
|
|
1979
|
+
gtString memory gt_ = gtString(new gtUint64[](len_));
|
|
1980
|
+
|
|
1981
|
+
for (uint256 i = 0; i < len_; ++i) {
|
|
1982
|
+
gt_.value[i] = onBoard(ct.value[i]);
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
return gt_;
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
function offBoard(gtString memory pt) internal returns (ctString memory) {
|
|
1989
|
+
uint256 len_ = pt.value.length;
|
|
1990
|
+
|
|
1991
|
+
ctString memory ct_ = ctString(new ctUint64[](len_));
|
|
1992
|
+
|
|
1993
|
+
for (uint256 i = 0; i < len_; ++i) {
|
|
1994
|
+
ct_.value[i] = offBoard(pt.value[i]);
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
return ct_;
|
|
1998
|
+
}
|
|
1999
|
+
|
|
2000
|
+
function offBoardToUser(gtString memory pt, address addr) internal returns (ctString memory) {
|
|
2001
|
+
uint256 len_ = pt.value.length;
|
|
2002
|
+
|
|
2003
|
+
ctString memory ct_ = ctString(new ctUint64[](len_));
|
|
2004
|
+
|
|
2005
|
+
for (uint256 i = 0; i < len_; ++i) {
|
|
2006
|
+
ct_.value[i] = offBoardToUser(pt.value[i], addr);
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
return ct_;
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
function offBoardCombined(gtString memory pt, address addr) internal returns (utString memory ut) {
|
|
2013
|
+
ut.ciphertext = offBoard(pt);
|
|
2014
|
+
ut.userCiphertext = offBoardToUser(pt, addr);
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
function setPublicString(string memory pt) internal returns (gtString memory) {
|
|
2018
|
+
bytes memory strBytes_ = bytes(pt);
|
|
2019
|
+
uint256 len_ = strBytes_.length;
|
|
2020
|
+
uint256 count_ = (len_ + 7) / 8; // Number of bytes8 elements needed
|
|
2021
|
+
|
|
2022
|
+
gtString memory result_ = gtString(new gtUint64[](count_));
|
|
2023
|
+
|
|
2024
|
+
bytes8 cell_;
|
|
2025
|
+
|
|
2026
|
+
for (uint256 i = 0; i < count_ * 8; ++i) {
|
|
2027
|
+
if (i % 8 == 0) {
|
|
2028
|
+
cell_ = bytes8(0);
|
|
2029
|
+
} else {
|
|
2030
|
+
cell_ <<= 8;
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
if (i < len_) {
|
|
2034
|
+
cell_ |= bytes8(strBytes_[i]) >> 56;
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
if (i % 8 == 7) {
|
|
2038
|
+
result_.value[i / 8] = setPublic64(uint64(cell_));
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
return result_;
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
function decrypt(gtString memory ct) internal returns (string memory){
|
|
2046
|
+
uint256 len_ = ct.value.length;
|
|
2047
|
+
bytes memory result_ = new bytes(len_ * 8);
|
|
2048
|
+
|
|
2049
|
+
bytes8 temp_;
|
|
2050
|
+
|
|
2051
|
+
uint256 resultIndex;
|
|
2052
|
+
|
|
2053
|
+
for (uint256 i = 0; i < len_; ++i) {
|
|
2054
|
+
temp_ = bytes8(decrypt(ct.value[i]));
|
|
2055
|
+
|
|
2056
|
+
assembly {
|
|
2057
|
+
// Copy the bytes directly into the result array using assembly.
|
|
2058
|
+
mstore(add(result_, add(0x20, resultIndex)), temp_)
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
resultIndex += 8;
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
return string(result_);
|
|
2065
|
+
}
|
|
2066
|
+
|
|
2067
|
+
function eq(gtString memory a, gtString memory b) internal returns (gtBool) {
|
|
2068
|
+
uint256 len = a.value.length;
|
|
2069
|
+
|
|
2070
|
+
// note that we are not leaking information since the array length is visible to all
|
|
2071
|
+
if (len != b.value.length) return setPublic(false);
|
|
2072
|
+
|
|
2073
|
+
gtBool result_ = eq(a.value[0], b.value[0]);
|
|
2074
|
+
|
|
2075
|
+
for (uint256 i = 1; i < len; ++i) {
|
|
2076
|
+
result_ = and(result_, eq(a.value[i], b.value[i]));
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
return result_;
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
function ne(gtString memory a, gtString memory b) internal returns (gtBool) {
|
|
2083
|
+
uint256 len = a.value.length;
|
|
2084
|
+
|
|
2085
|
+
// note that we are not leaking information since the array length is visible to all
|
|
2086
|
+
if (len != b.value.length) return setPublic(true);
|
|
2087
|
+
|
|
2088
|
+
gtBool result_ = ne(a.value[0], b.value[0]);
|
|
2089
|
+
|
|
2090
|
+
for (uint256 i = 1; i < len; ++i) {
|
|
2091
|
+
result_ = or(result_, ne(a.value[i], b.value[i]));
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
return result_;
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
|
|
2098
|
+
// =========== Operations with LHS_PUBLIC parameter ===========
|
|
2099
|
+
// =========== 8 bit operations ==============
|
|
2100
|
+
|
|
2101
|
+
function add(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2102
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2103
|
+
Add(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
function checkedAdd(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2107
|
+
(uint256 bit, uint256 res) = ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2108
|
+
CheckedAdd(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
2109
|
+
|
|
2110
|
+
return checkRes8(gtBool.wrap(bit), gtUint8.wrap(res));
|
|
2111
|
+
}
|
|
2112
|
+
|
|
2113
|
+
function checkedAddWithOverflowBit(uint8 a, gtUint8 b) internal returns (gtBool, gtUint8) {
|
|
2114
|
+
(uint256 bit, uint256 res) = ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2115
|
+
CheckedAdd(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
2116
|
+
|
|
2117
|
+
return (gtBool.wrap(bit), gtUint8.wrap(res));
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
function sub(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2121
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2122
|
+
Sub(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
function checkedSub(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2126
|
+
(uint256 bit, uint256 res) = ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2127
|
+
CheckedSub(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
2128
|
+
|
|
2129
|
+
return checkRes8(gtBool.wrap(bit), gtUint8.wrap(res));
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
function checkedSubWithOverflowBit(uint8 a, gtUint8 b) internal returns (gtBool, gtUint8) {
|
|
2133
|
+
(uint256 bit, uint256 res) = ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2134
|
+
CheckedSub(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
2135
|
+
|
|
2136
|
+
return (gtBool.wrap(bit), gtUint8.wrap(res));
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
function mul(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2140
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2141
|
+
Mul(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
function checkedMul(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2145
|
+
(uint256 bit, uint256 res) = ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2146
|
+
CheckedMul(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
2147
|
+
|
|
2148
|
+
return checkRes8(gtBool.wrap(bit), gtUint8.wrap(res));
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
function checkedMulWithOverflowBit(uint8 a, gtUint8 b) internal returns (gtBool, gtUint8) {
|
|
2152
|
+
(uint256 bit, uint256 res) = ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2153
|
+
CheckedMul(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b));
|
|
2154
|
+
|
|
2155
|
+
return (gtBool.wrap(bit), gtUint8.wrap(res));
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
function div(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2159
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2160
|
+
Div(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
function rem(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2164
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2165
|
+
Rem(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
function and(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2169
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2170
|
+
And(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
function or(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2174
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2175
|
+
Or(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
function xor(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2179
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2180
|
+
Xor(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
function eq(uint8 a, gtUint8 b) internal returns (gtBool) {
|
|
2184
|
+
return gtBool.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2185
|
+
Eq(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2186
|
+
}
|
|
2187
|
+
|
|
2188
|
+
function ne(uint8 a, gtUint8 b) internal returns (gtBool) {
|
|
2189
|
+
return gtBool.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2190
|
+
Ne(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
function ge(uint8 a, gtUint8 b) internal returns (gtBool) {
|
|
2194
|
+
return gtBool.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2195
|
+
Ge(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
function gt(uint8 a, gtUint8 b) internal returns (gtBool) {
|
|
2199
|
+
return gtBool.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2200
|
+
Gt(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
function le(uint8 a, gtUint8 b) internal returns (gtBool) {
|
|
2204
|
+
return gtBool.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2205
|
+
Le(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
function lt(uint8 a, gtUint8 b) internal returns (gtBool) {
|
|
2209
|
+
return gtBool.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2210
|
+
Lt(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
function min(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2214
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2215
|
+
Min(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
function max(uint8 a, gtUint8 b) internal returns (gtUint8) {
|
|
2219
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2220
|
+
Max(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), uint256(a), gtUint8.unwrap(b)));
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
function mux(gtBool bit, uint8 a, gtUint8 b) internal returns (gtUint8){
|
|
2224
|
+
return gtUint8.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2225
|
+
Mux(combineEnumsToBytes3(MPC_TYPE.SUINT8_T, MPC_TYPE.SUINT8_T, ARGS.LHS_PUBLIC), gtBool.unwrap(bit), uint256(a), gtUint8.unwrap(b)));
|
|
2226
|
+
}
|
|
2227
|
+
|
|
2228
|
+
|
|
2229
|
+
// =========== 16 bit operations ==============
|
|
2230
|
+
|
|
2231
|
+
function add(uint16 a, gtUint16 b) internal returns (gtUint16) {
|
|
2232
|
+
return gtUint16.wrap(ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
2233
|
+
Add(combineEnumsToBytes3(MPC_TYPE.SUINT16_T, MPC_TYPE.SUINT16_T, ARGS.LHS_PUBLIC), uint256(a), gtUint16.unwrap(b)));
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
function checkedAdd(uint16 a, gtUint16 b) internal returns (gtUint16) {
|
|
1283
2237
|
(uint256 bit, uint256 res) = ExtendedOperations(address(MPC_PRECOMPILE)).
|
|
1284
2238
|
CheckedAdd(combineEnumsToBytes3(MPC_TYPE.SUINT16_T, MPC_TYPE.SUINT16_T, ARGS.LHS_PUBLIC), uint256(a), gtUint16.unwrap(b));
|
|
1285
2239
|
|
|
@@ -1662,6 +2616,791 @@ library MpcCore {
|
|
|
1662
2616
|
}
|
|
1663
2617
|
|
|
1664
2618
|
|
|
2619
|
+
// =========== 128 bit operations ===========
|
|
2620
|
+
|
|
2621
|
+
function add(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2622
|
+
gtUint128 memory result;
|
|
2623
|
+
|
|
2624
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2625
|
+
|
|
2626
|
+
// Add low parts
|
|
2627
|
+
result.low = add(aLow, b.low);
|
|
2628
|
+
|
|
2629
|
+
// Check if there's a carry from low addition
|
|
2630
|
+
gtBool carry = lt(result.low, aLow);
|
|
2631
|
+
|
|
2632
|
+
// Add high parts with carry if needed
|
|
2633
|
+
result.high = add(aHigh, b.high);
|
|
2634
|
+
|
|
2635
|
+
// Add carry to high part if needed
|
|
2636
|
+
result.high = mux(carry, result.high, add(result.high, uint64(1)));
|
|
2637
|
+
|
|
2638
|
+
return result;
|
|
2639
|
+
}
|
|
2640
|
+
|
|
2641
|
+
function checkedAdd(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2642
|
+
gtUint128 memory result;
|
|
2643
|
+
|
|
2644
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2645
|
+
|
|
2646
|
+
// Add low parts
|
|
2647
|
+
result.low = add(aLow, b.low);
|
|
2648
|
+
|
|
2649
|
+
// Check if there's a carry from low addition
|
|
2650
|
+
gtBool carry = lt(result.low, aLow);
|
|
2651
|
+
|
|
2652
|
+
// Add high parts with carry if needed
|
|
2653
|
+
result.high = checkedAdd(aHigh, b.high);
|
|
2654
|
+
|
|
2655
|
+
// Add carry to high part if needed
|
|
2656
|
+
result.high = mux(carry, result.high, checkedAdd(result.high, uint64(1)));
|
|
2657
|
+
|
|
2658
|
+
return result;
|
|
2659
|
+
}
|
|
2660
|
+
|
|
2661
|
+
function checkedAddWithOverflowBit(uint128 a, gtUint128 memory b) internal returns (gtBool, gtUint128 memory) {
|
|
2662
|
+
gtBool bit = setPublic(false);
|
|
2663
|
+
gtUint128 memory result;
|
|
2664
|
+
|
|
2665
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2666
|
+
|
|
2667
|
+
// Add low parts
|
|
2668
|
+
result.low = add(aLow, b.low);
|
|
2669
|
+
|
|
2670
|
+
// Check if there's a carry from low addition
|
|
2671
|
+
gtBool carry = lt(result.low, aLow);
|
|
2672
|
+
|
|
2673
|
+
// Add high parts with carry if needed
|
|
2674
|
+
(gtBool overflow, gtUint64 high) = checkedAddWithOverflowBit(aHigh, b.high);
|
|
2675
|
+
(gtBool overflowWithCarry, gtUint64 highWithCarry) = checkedAddWithOverflowBit(high, uint64(1));
|
|
2676
|
+
|
|
2677
|
+
// Handle carry if needed
|
|
2678
|
+
bit = mux(carry, overflow, or(overflow, overflowWithCarry));
|
|
2679
|
+
result.high = mux(carry, high, highWithCarry);
|
|
2680
|
+
|
|
2681
|
+
return (bit, result);
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
function sub(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2685
|
+
gtUint128 memory result;
|
|
2686
|
+
|
|
2687
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2688
|
+
|
|
2689
|
+
// Subtract low parts
|
|
2690
|
+
result.low = sub(aLow, b.low);
|
|
2691
|
+
|
|
2692
|
+
// Check if there's a borrow from low subtraction
|
|
2693
|
+
gtBool borrow = lt(aLow, b.low);
|
|
2694
|
+
|
|
2695
|
+
// Subtract high parts with borrow if needed
|
|
2696
|
+
result.high = sub(aHigh, b.high);
|
|
2697
|
+
|
|
2698
|
+
// Subtract borrow from high part if needed
|
|
2699
|
+
result.high = mux(borrow, result.high, sub(result.high, uint64(1)));
|
|
2700
|
+
|
|
2701
|
+
return result;
|
|
2702
|
+
}
|
|
2703
|
+
|
|
2704
|
+
function checkedSub(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2705
|
+
gtUint128 memory result;
|
|
2706
|
+
|
|
2707
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2708
|
+
|
|
2709
|
+
// Subtract low parts
|
|
2710
|
+
result.low = sub(aLow, b.low);
|
|
2711
|
+
|
|
2712
|
+
// Check if there's a borrow from low subtraction
|
|
2713
|
+
gtBool borrow = lt(aLow, b.low);
|
|
2714
|
+
|
|
2715
|
+
// Subtract high parts with borrow if needed
|
|
2716
|
+
result.high = checkedSub(aHigh, b.high);
|
|
2717
|
+
|
|
2718
|
+
// Subtract borrow from high part if needed
|
|
2719
|
+
result.high = mux(
|
|
2720
|
+
borrow,
|
|
2721
|
+
result.high,
|
|
2722
|
+
checkedSub(
|
|
2723
|
+
mux(borrow, add(result.high, uint64(1)), result.high),
|
|
2724
|
+
uint64(1)
|
|
2725
|
+
)
|
|
2726
|
+
);
|
|
2727
|
+
|
|
2728
|
+
return result;
|
|
2729
|
+
}
|
|
2730
|
+
|
|
2731
|
+
function checkedSubWithOverflowBit(uint128 a, gtUint128 memory b) internal returns (gtBool, gtUint128 memory) {
|
|
2732
|
+
gtBool bit = setPublic(false);
|
|
2733
|
+
gtUint128 memory result;
|
|
2734
|
+
|
|
2735
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2736
|
+
|
|
2737
|
+
// Subtract low parts
|
|
2738
|
+
result.low = sub(aLow, b.low);
|
|
2739
|
+
|
|
2740
|
+
// Check if there's a borrow from low subtraction
|
|
2741
|
+
gtBool borrow = lt(aLow, b.low);
|
|
2742
|
+
|
|
2743
|
+
// Subtract high parts with borrow if needed
|
|
2744
|
+
(gtBool overflow, gtUint64 high) = checkedSubWithOverflowBit(aHigh, b.high);
|
|
2745
|
+
(gtBool overflowWithCarry, gtUint64 highWithCarry) = checkedSubWithOverflowBit(high, uint64(1));
|
|
2746
|
+
|
|
2747
|
+
// Handle borrow if needed
|
|
2748
|
+
bit = mux(borrow, overflow, or(overflow, overflowWithCarry));
|
|
2749
|
+
result.high = mux(borrow, high, highWithCarry);
|
|
2750
|
+
|
|
2751
|
+
return (bit, result);
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
function _mul64(uint64 a, gtUint64 b) private returns (gtUint64, gtUint64) {
|
|
2755
|
+
uint64 MAX_UINT32 = uint64(type(uint32).max);
|
|
2756
|
+
|
|
2757
|
+
gtUint64 pp0;
|
|
2758
|
+
gtUint64 pp1;
|
|
2759
|
+
gtUint64 pp2;
|
|
2760
|
+
gtUint64 pp3;
|
|
2761
|
+
|
|
2762
|
+
{
|
|
2763
|
+
// Split the numbers into 32-bit parts
|
|
2764
|
+
uint64 aLow = a & type(uint32).max;
|
|
2765
|
+
uint64 aHigh = a >> 32;
|
|
2766
|
+
gtUint64 bLow = and(b, MAX_UINT32);
|
|
2767
|
+
gtUint64 bHigh = shr(b, 32);
|
|
2768
|
+
|
|
2769
|
+
// Compute partial products
|
|
2770
|
+
pp0 = mul(aLow, bLow);
|
|
2771
|
+
pp1 = mul(aLow, bHigh);
|
|
2772
|
+
pp2 = mul(aHigh, bLow);
|
|
2773
|
+
pp3 = mul(aHigh, bHigh);
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
// Compute high and low parts
|
|
2777
|
+
gtUint64 mid = add(
|
|
2778
|
+
add(
|
|
2779
|
+
shr(pp0, 32),
|
|
2780
|
+
and(pp1, MAX_UINT32)
|
|
2781
|
+
),
|
|
2782
|
+
and(pp2, MAX_UINT32)
|
|
2783
|
+
);
|
|
2784
|
+
gtUint64 carry = shr(mid, 32);
|
|
2785
|
+
|
|
2786
|
+
gtUint64 high = add(
|
|
2787
|
+
add(pp3, shr(pp1, 32)),
|
|
2788
|
+
add(shr(pp2, 32), carry)
|
|
2789
|
+
);
|
|
2790
|
+
gtUint64 low = or(
|
|
2791
|
+
and(pp0, MAX_UINT32),
|
|
2792
|
+
shl(and(mid, MAX_UINT32), 32)
|
|
2793
|
+
);
|
|
2794
|
+
|
|
2795
|
+
return (high, low);
|
|
2796
|
+
}
|
|
2797
|
+
|
|
2798
|
+
function mul(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2799
|
+
gtUint128 memory result;
|
|
2800
|
+
|
|
2801
|
+
uint64 aLow = uint64(a & type(uint64).max);
|
|
2802
|
+
uint64 aHigh = uint64(a >> 64);
|
|
2803
|
+
|
|
2804
|
+
// Compute partial products
|
|
2805
|
+
(gtUint64 pp0, gtUint64 low) = _mul64(aLow, b.low);
|
|
2806
|
+
(, gtUint64 pp1) = _mul64(aHigh, b.low);
|
|
2807
|
+
(, gtUint64 pp2) = _mul64(aLow, b.high);
|
|
2808
|
+
|
|
2809
|
+
// Compute the high and low parts
|
|
2810
|
+
result.high = add(
|
|
2811
|
+
add(pp0, pp1),
|
|
2812
|
+
pp2
|
|
2813
|
+
);
|
|
2814
|
+
result.low = low;
|
|
2815
|
+
|
|
2816
|
+
return result;
|
|
2817
|
+
}
|
|
2818
|
+
|
|
2819
|
+
function checkedMul(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2820
|
+
gtUint128 memory result;
|
|
2821
|
+
|
|
2822
|
+
uint64 aLow = uint64(a & type(uint64).max);
|
|
2823
|
+
uint64 aHigh = uint64(a >> 64);
|
|
2824
|
+
|
|
2825
|
+
// Compute partial products
|
|
2826
|
+
(gtUint64 pp0, gtUint64 low) = _mul64(aLow, b.low);
|
|
2827
|
+
(gtUint64 pp2, gtUint64 pp1) = _mul64(aHigh, b.low);
|
|
2828
|
+
(gtUint64 pp4, gtUint64 pp3) = _mul64(aLow, b.high);
|
|
2829
|
+
(gtUint64 pp6, gtUint64 pp5) = _mul64(aHigh, b.high);
|
|
2830
|
+
|
|
2831
|
+
// Compute the high and low parts
|
|
2832
|
+
result.high = checkedAdd(
|
|
2833
|
+
checkedAdd(pp0, pp1),
|
|
2834
|
+
pp3
|
|
2835
|
+
);
|
|
2836
|
+
result.low = low;
|
|
2837
|
+
|
|
2838
|
+
// Check for overflow
|
|
2839
|
+
checkedSub(
|
|
2840
|
+
uint64(0),
|
|
2841
|
+
add(
|
|
2842
|
+
add(pp2, pp4),
|
|
2843
|
+
add(pp5, pp6)
|
|
2844
|
+
)
|
|
2845
|
+
);
|
|
2846
|
+
|
|
2847
|
+
return result;
|
|
2848
|
+
}
|
|
2849
|
+
|
|
2850
|
+
function checkedMulWithOverflowBit(uint128 a, gtUint128 memory b) internal returns (gtBool, gtUint128 memory) {
|
|
2851
|
+
gtUint128 memory result;
|
|
2852
|
+
|
|
2853
|
+
gtUint64 low;
|
|
2854
|
+
gtUint64 pp0;
|
|
2855
|
+
gtUint64 pp1;
|
|
2856
|
+
gtUint64 pp2;
|
|
2857
|
+
gtUint64 pp3;
|
|
2858
|
+
gtUint64 pp4;
|
|
2859
|
+
gtUint64 pp5;
|
|
2860
|
+
gtUint64 pp6;
|
|
2861
|
+
|
|
2862
|
+
{
|
|
2863
|
+
uint64 aLow = uint64(a & type(uint64).max);
|
|
2864
|
+
uint64 aHigh = uint64(a >> 64);
|
|
2865
|
+
|
|
2866
|
+
// Compute partial products
|
|
2867
|
+
(pp0, low) = _mul64(aLow, b.low);
|
|
2868
|
+
(pp2, pp1) = _mul64(aHigh, b.low);
|
|
2869
|
+
(pp4, pp3) = _mul64(aLow, b.high);
|
|
2870
|
+
(pp6, pp5) = _mul64(aHigh, b.high);
|
|
2871
|
+
}
|
|
2872
|
+
|
|
2873
|
+
// Compute the high and low parts
|
|
2874
|
+
gtBool overflow1;
|
|
2875
|
+
|
|
2876
|
+
(gtBool overflow0, gtUint64 high) = checkedAddWithOverflowBit(pp0, pp1);
|
|
2877
|
+
(overflow1, result.high) = checkedAddWithOverflowBit(high, pp3);
|
|
2878
|
+
|
|
2879
|
+
result.low = low;
|
|
2880
|
+
|
|
2881
|
+
// Check for overflow
|
|
2882
|
+
gtBool bit = or(
|
|
2883
|
+
or(overflow0, overflow1),
|
|
2884
|
+
gt(
|
|
2885
|
+
add(
|
|
2886
|
+
add(pp2, pp4),
|
|
2887
|
+
add(pp5, pp6)
|
|
2888
|
+
),
|
|
2889
|
+
uint64(0)
|
|
2890
|
+
)
|
|
2891
|
+
);
|
|
2892
|
+
|
|
2893
|
+
return (bit, result);
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
function and(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2897
|
+
gtUint128 memory result;
|
|
2898
|
+
|
|
2899
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2900
|
+
|
|
2901
|
+
result.low = and(aLow, b.low);
|
|
2902
|
+
result.high = and(aHigh, b.high);
|
|
2903
|
+
|
|
2904
|
+
return result;
|
|
2905
|
+
}
|
|
2906
|
+
|
|
2907
|
+
function or(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2908
|
+
gtUint128 memory result;
|
|
2909
|
+
|
|
2910
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2911
|
+
|
|
2912
|
+
result.low = or(aLow, b.low);
|
|
2913
|
+
result.high = or(aHigh, b.high);
|
|
2914
|
+
|
|
2915
|
+
return result;
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
function xor(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2919
|
+
gtUint128 memory result;
|
|
2920
|
+
|
|
2921
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2922
|
+
|
|
2923
|
+
result.low = xor(aLow, b.low);
|
|
2924
|
+
result.high = xor(aHigh, b.high);
|
|
2925
|
+
|
|
2926
|
+
return result;
|
|
2927
|
+
}
|
|
2928
|
+
|
|
2929
|
+
function eq(uint128 a, gtUint128 memory b) internal returns (gtBool) {
|
|
2930
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2931
|
+
|
|
2932
|
+
return and(eq(aLow, b.low), eq(aHigh, b.high));
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
function ne(uint128 a, gtUint128 memory b) internal returns (gtBool) {
|
|
2936
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2937
|
+
|
|
2938
|
+
return or(ne(aLow, b.low), ne(aHigh, b.high));
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
function ge(uint128 a, gtUint128 memory b) internal returns (gtBool) {
|
|
2942
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2943
|
+
|
|
2944
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
2945
|
+
|
|
2946
|
+
return mux(highEqual, gt(aHigh, b.high), ge(aLow, b.low));
|
|
2947
|
+
}
|
|
2948
|
+
|
|
2949
|
+
function gt(uint128 a, gtUint128 memory b) internal returns (gtBool) {
|
|
2950
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2951
|
+
|
|
2952
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
2953
|
+
|
|
2954
|
+
return mux(highEqual, gt(aHigh, b.high), gt(aLow, b.low));
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2957
|
+
function le(uint128 a, gtUint128 memory b) internal returns (gtBool) {
|
|
2958
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2959
|
+
|
|
2960
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
2961
|
+
|
|
2962
|
+
return mux(highEqual, lt(aHigh, b.high), le(aLow, b.low));
|
|
2963
|
+
}
|
|
2964
|
+
|
|
2965
|
+
function lt(uint128 a, gtUint128 memory b) internal returns (gtBool) {
|
|
2966
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2967
|
+
|
|
2968
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
2969
|
+
|
|
2970
|
+
return mux(highEqual, lt(aHigh, b.high), lt(aLow, b.low));
|
|
2971
|
+
}
|
|
2972
|
+
|
|
2973
|
+
function min(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2974
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2975
|
+
|
|
2976
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
2977
|
+
gtBool aHighLessThan = lt(aHigh, b.high);
|
|
2978
|
+
gtBool aLowLessThan = lt(aLow, b.low);
|
|
2979
|
+
|
|
2980
|
+
return mux(
|
|
2981
|
+
highEqual,
|
|
2982
|
+
mux(aHighLessThan, b, a),
|
|
2983
|
+
mux(aLowLessThan, b, a)
|
|
2984
|
+
);
|
|
2985
|
+
}
|
|
2986
|
+
|
|
2987
|
+
function max(uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
2988
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
2989
|
+
|
|
2990
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
2991
|
+
gtBool aHighGreaterThan = gt(aHigh, b.high);
|
|
2992
|
+
gtBool aLowGreaterThan = gt(aLow, b.low);
|
|
2993
|
+
|
|
2994
|
+
return mux(
|
|
2995
|
+
highEqual,
|
|
2996
|
+
mux(aHighGreaterThan, b, a),
|
|
2997
|
+
mux(aLowGreaterThan, b, a)
|
|
2998
|
+
);
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
function mux(gtBool bit, uint128 a, gtUint128 memory b) internal returns (gtUint128 memory) {
|
|
3002
|
+
gtUint128 memory result;
|
|
3003
|
+
|
|
3004
|
+
(uint64 aHigh, uint64 aLow) = _splitUint128(a);
|
|
3005
|
+
|
|
3006
|
+
result.low = mux(bit, aLow, b.low);
|
|
3007
|
+
result.high = mux(bit, aHigh, b.high);
|
|
3008
|
+
|
|
3009
|
+
return result;
|
|
3010
|
+
}
|
|
3011
|
+
|
|
3012
|
+
|
|
3013
|
+
// =========== 256 bit operations ===========
|
|
3014
|
+
|
|
3015
|
+
function add(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3016
|
+
gtUint256 memory result;
|
|
3017
|
+
|
|
3018
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3019
|
+
|
|
3020
|
+
// Add low parts
|
|
3021
|
+
result.low = add(aLow, b.low);
|
|
3022
|
+
|
|
3023
|
+
// Check if there's a carry from low addition
|
|
3024
|
+
gtBool carry = lt(result.low, aLow);
|
|
3025
|
+
|
|
3026
|
+
// Add high parts with carry if needed
|
|
3027
|
+
result.high = add(aHigh, b.high);
|
|
3028
|
+
|
|
3029
|
+
// Add carry to high part if needed
|
|
3030
|
+
result.high = mux(carry, result.high, add(result.high, uint128(1)));
|
|
3031
|
+
|
|
3032
|
+
return result;
|
|
3033
|
+
}
|
|
3034
|
+
|
|
3035
|
+
function checkedAdd(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3036
|
+
gtUint256 memory result;
|
|
3037
|
+
|
|
3038
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3039
|
+
|
|
3040
|
+
// Add low parts
|
|
3041
|
+
result.low = add(aLow, b.low);
|
|
3042
|
+
|
|
3043
|
+
// Check if there's a carry from low addition
|
|
3044
|
+
gtBool carry = lt(result.low, aLow);
|
|
3045
|
+
|
|
3046
|
+
// Add high parts with carry if needed
|
|
3047
|
+
result.high = checkedAdd(aHigh, b.high);
|
|
3048
|
+
|
|
3049
|
+
// Add carry to high part if needed
|
|
3050
|
+
result.high = mux(carry, result.high, checkedAdd(result.high, uint128(1)));
|
|
3051
|
+
|
|
3052
|
+
return result;
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
function checkedAddWithOverflowBit(uint256 a, gtUint256 memory b) internal returns (gtBool, gtUint256 memory) {
|
|
3056
|
+
gtBool bit = setPublic(false);
|
|
3057
|
+
gtUint256 memory result;
|
|
3058
|
+
|
|
3059
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3060
|
+
|
|
3061
|
+
// Add low parts
|
|
3062
|
+
result.low = add(aLow, b.low);
|
|
3063
|
+
|
|
3064
|
+
// Check if there's a carry from low addition
|
|
3065
|
+
gtBool carry = lt(result.low, aLow);
|
|
3066
|
+
|
|
3067
|
+
// Add high parts with carry if needed
|
|
3068
|
+
(gtBool overflow, gtUint128 memory high) = checkedAddWithOverflowBit(aHigh, b.high);
|
|
3069
|
+
(gtBool overflowWithCarry, gtUint128 memory highWithCarry) = checkedAddWithOverflowBit(high, uint128(1));
|
|
3070
|
+
|
|
3071
|
+
// Handle carry if needed
|
|
3072
|
+
bit = mux(carry, overflow, or(overflow, overflowWithCarry));
|
|
3073
|
+
result.high = mux(carry, high, highWithCarry);
|
|
3074
|
+
|
|
3075
|
+
return (bit, result);
|
|
3076
|
+
}
|
|
3077
|
+
|
|
3078
|
+
function sub(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3079
|
+
gtUint256 memory result;
|
|
3080
|
+
|
|
3081
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3082
|
+
|
|
3083
|
+
// Subtract low parts
|
|
3084
|
+
result.low = sub(aLow, b.low);
|
|
3085
|
+
|
|
3086
|
+
// Check if there's a borrow from low subtraction
|
|
3087
|
+
gtBool borrow = lt(aLow, b.low);
|
|
3088
|
+
|
|
3089
|
+
// Subtract high parts with borrow if needed
|
|
3090
|
+
result.high = sub(aHigh, b.high);
|
|
3091
|
+
|
|
3092
|
+
// Subtract borrow from high part if needed
|
|
3093
|
+
result.high = mux(borrow, result.high, sub(result.high, uint128(1)));
|
|
3094
|
+
|
|
3095
|
+
return result;
|
|
3096
|
+
}
|
|
3097
|
+
|
|
3098
|
+
function checkedSub(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3099
|
+
gtUint256 memory result;
|
|
3100
|
+
|
|
3101
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3102
|
+
|
|
3103
|
+
// Subtract low parts
|
|
3104
|
+
result.low = sub(aLow, b.low);
|
|
3105
|
+
|
|
3106
|
+
// Check if there's a borrow from low subtraction
|
|
3107
|
+
gtBool borrow = lt(aLow, b.low);
|
|
3108
|
+
|
|
3109
|
+
// Subtract high parts with borrow if needed
|
|
3110
|
+
result.high = checkedSub(aHigh, b.high);
|
|
3111
|
+
|
|
3112
|
+
// Subtract borrow from high part if needed
|
|
3113
|
+
result.high = mux(
|
|
3114
|
+
borrow,
|
|
3115
|
+
result.high,
|
|
3116
|
+
checkedSub(
|
|
3117
|
+
mux(borrow, add(result.high, uint128(1)), result.high),
|
|
3118
|
+
uint128(1)
|
|
3119
|
+
)
|
|
3120
|
+
);
|
|
3121
|
+
|
|
3122
|
+
return result;
|
|
3123
|
+
}
|
|
3124
|
+
|
|
3125
|
+
function checkedSubWithOverflowBit(uint256 a, gtUint256 memory b) internal returns (gtBool, gtUint256 memory) {
|
|
3126
|
+
gtBool bit = setPublic(false);
|
|
3127
|
+
gtUint256 memory result;
|
|
3128
|
+
|
|
3129
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3130
|
+
|
|
3131
|
+
// Subtract low parts
|
|
3132
|
+
result.low = sub(aLow, b.low);
|
|
3133
|
+
|
|
3134
|
+
// Check if there's a borrow from low subtraction
|
|
3135
|
+
gtBool borrow = lt(aLow, b.low);
|
|
3136
|
+
|
|
3137
|
+
// Subtract high parts with borrow if needed
|
|
3138
|
+
(gtBool overflow, gtUint128 memory high) = checkedSubWithOverflowBit(aHigh, b.high);
|
|
3139
|
+
(gtBool overflowWithCarry, gtUint128 memory highWithCarry) = checkedSubWithOverflowBit(high, uint128(1));
|
|
3140
|
+
|
|
3141
|
+
// Handle borrow if needed
|
|
3142
|
+
bit = mux(borrow, overflow, or(overflow, overflowWithCarry));
|
|
3143
|
+
result.high = mux(borrow, high, highWithCarry);
|
|
3144
|
+
|
|
3145
|
+
return (bit, result);
|
|
3146
|
+
}
|
|
3147
|
+
|
|
3148
|
+
function _mul128(uint128 a, gtUint128 memory b) private returns (gtUint128 memory, gtUint128 memory) {
|
|
3149
|
+
uint128 MAX_UINT64 = uint128(type(uint64).max);
|
|
3150
|
+
|
|
3151
|
+
gtUint128 memory pp0;
|
|
3152
|
+
gtUint128 memory pp1;
|
|
3153
|
+
gtUint128 memory pp2;
|
|
3154
|
+
gtUint128 memory pp3;
|
|
3155
|
+
|
|
3156
|
+
{
|
|
3157
|
+
// Split the numbers into 64-bit parts
|
|
3158
|
+
uint128 aLow = a & type(uint64).max;
|
|
3159
|
+
uint128 aHigh = a >> 64;
|
|
3160
|
+
gtUint128 memory bLow = and(b, MAX_UINT64);
|
|
3161
|
+
gtUint128 memory bHigh = shr(b, 64);
|
|
3162
|
+
|
|
3163
|
+
// Compute partial products
|
|
3164
|
+
pp0 = mul(aLow, bLow);
|
|
3165
|
+
pp1 = mul(aLow, bHigh);
|
|
3166
|
+
pp2 = mul(aHigh, bLow);
|
|
3167
|
+
pp3 = mul(aHigh, bHigh);
|
|
3168
|
+
}
|
|
3169
|
+
|
|
3170
|
+
// Compute high and low parts
|
|
3171
|
+
gtUint128 memory mid = add(
|
|
3172
|
+
add(
|
|
3173
|
+
shr(pp0, 64),
|
|
3174
|
+
and(pp1, MAX_UINT64)
|
|
3175
|
+
),
|
|
3176
|
+
and(pp2, MAX_UINT64)
|
|
3177
|
+
);
|
|
3178
|
+
gtUint128 memory carry = shr(mid, 64);
|
|
3179
|
+
|
|
3180
|
+
gtUint128 memory high = add(
|
|
3181
|
+
add(pp3, shr(pp1, 64)),
|
|
3182
|
+
add(shr(pp2, 64), carry)
|
|
3183
|
+
);
|
|
3184
|
+
gtUint128 memory low = or(
|
|
3185
|
+
and(pp0, MAX_UINT64),
|
|
3186
|
+
shl(and(mid, MAX_UINT64), 64)
|
|
3187
|
+
);
|
|
3188
|
+
|
|
3189
|
+
return (high, low);
|
|
3190
|
+
}
|
|
3191
|
+
|
|
3192
|
+
function mul(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3193
|
+
gtUint256 memory result;
|
|
3194
|
+
|
|
3195
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3196
|
+
|
|
3197
|
+
// Compute partial products
|
|
3198
|
+
(gtUint128 memory pp0, gtUint128 memory low) = _mul128(aLow, b.low);
|
|
3199
|
+
(, gtUint128 memory pp1) = _mul128(aHigh, b.low);
|
|
3200
|
+
(, gtUint128 memory pp2) = _mul128(aLow, b.high);
|
|
3201
|
+
|
|
3202
|
+
// Compute the high and low parts
|
|
3203
|
+
result.high = add(
|
|
3204
|
+
add(pp0, pp1),
|
|
3205
|
+
pp2
|
|
3206
|
+
);
|
|
3207
|
+
result.low = low;
|
|
3208
|
+
|
|
3209
|
+
return result;
|
|
3210
|
+
}
|
|
3211
|
+
|
|
3212
|
+
function checkedMul(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3213
|
+
gtUint256 memory result;
|
|
3214
|
+
|
|
3215
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3216
|
+
|
|
3217
|
+
// Compute partial products
|
|
3218
|
+
(gtUint128 memory pp0, gtUint128 memory low) = _mul128(aLow, b.low);
|
|
3219
|
+
(gtUint128 memory pp2, gtUint128 memory pp1) = _mul128(aHigh, b.low);
|
|
3220
|
+
(gtUint128 memory pp4, gtUint128 memory pp3) = _mul128(aLow, b.high);
|
|
3221
|
+
(gtUint128 memory pp6, gtUint128 memory pp5) = _mul128(aHigh, b.high);
|
|
3222
|
+
|
|
3223
|
+
// Compute the high and low parts
|
|
3224
|
+
result.high = checkedAdd(
|
|
3225
|
+
checkedAdd(pp0, pp1),
|
|
3226
|
+
pp3
|
|
3227
|
+
);
|
|
3228
|
+
result.low = low;
|
|
3229
|
+
|
|
3230
|
+
// Check for overflow
|
|
3231
|
+
checkedSub(
|
|
3232
|
+
uint128(0),
|
|
3233
|
+
add(
|
|
3234
|
+
add(pp2, pp4),
|
|
3235
|
+
add(pp5, pp6)
|
|
3236
|
+
)
|
|
3237
|
+
);
|
|
3238
|
+
|
|
3239
|
+
return result;
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
function checkedMulWithOverflowBit(uint256 a, gtUint256 memory b) internal returns (gtBool, gtUint256 memory) {
|
|
3243
|
+
gtUint256 memory result;
|
|
3244
|
+
|
|
3245
|
+
gtUint128 memory low;
|
|
3246
|
+
gtUint128 memory pp0;
|
|
3247
|
+
gtUint128 memory pp1;
|
|
3248
|
+
gtUint128 memory pp2;
|
|
3249
|
+
gtUint128 memory pp3;
|
|
3250
|
+
gtUint128 memory pp4;
|
|
3251
|
+
gtUint128 memory pp5;
|
|
3252
|
+
gtUint128 memory pp6;
|
|
3253
|
+
|
|
3254
|
+
{
|
|
3255
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3256
|
+
|
|
3257
|
+
// Compute partial products
|
|
3258
|
+
(pp0, low) = _mul128(aLow, b.low);
|
|
3259
|
+
(pp2, pp1) = _mul128(aHigh, b.low);
|
|
3260
|
+
(pp4, pp3) = _mul128(aLow, b.high);
|
|
3261
|
+
(pp6, pp5) = _mul128(aHigh, b.high);
|
|
3262
|
+
}
|
|
3263
|
+
|
|
3264
|
+
// Compute the high and low parts
|
|
3265
|
+
gtBool overflow1;
|
|
3266
|
+
|
|
3267
|
+
(gtBool overflow0, gtUint128 memory high) = checkedAddWithOverflowBit(pp0, pp1);
|
|
3268
|
+
(overflow1, result.high) = checkedAddWithOverflowBit(high, pp3);
|
|
3269
|
+
|
|
3270
|
+
result.low = low;
|
|
3271
|
+
|
|
3272
|
+
// Check for overflow
|
|
3273
|
+
gtBool bit = or(
|
|
3274
|
+
or(overflow0, overflow1),
|
|
3275
|
+
gt(
|
|
3276
|
+
add(
|
|
3277
|
+
add(pp2, pp4),
|
|
3278
|
+
add(pp5, pp6)
|
|
3279
|
+
),
|
|
3280
|
+
uint128(0)
|
|
3281
|
+
)
|
|
3282
|
+
);
|
|
3283
|
+
|
|
3284
|
+
return (bit, result);
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
function and(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3288
|
+
gtUint256 memory result;
|
|
3289
|
+
|
|
3290
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3291
|
+
|
|
3292
|
+
result.low = and(aLow, b.low);
|
|
3293
|
+
result.high = and(aHigh, b.high);
|
|
3294
|
+
|
|
3295
|
+
return result;
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
function or(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3299
|
+
gtUint256 memory result;
|
|
3300
|
+
|
|
3301
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3302
|
+
|
|
3303
|
+
result.low = or(aLow, b.low);
|
|
3304
|
+
result.high = or(aHigh, b.high);
|
|
3305
|
+
|
|
3306
|
+
return result;
|
|
3307
|
+
}
|
|
3308
|
+
|
|
3309
|
+
function xor(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3310
|
+
gtUint256 memory result;
|
|
3311
|
+
|
|
3312
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3313
|
+
|
|
3314
|
+
result.low = xor(aLow, b.low);
|
|
3315
|
+
result.high = xor(aHigh, b.high);
|
|
3316
|
+
|
|
3317
|
+
return result;
|
|
3318
|
+
}
|
|
3319
|
+
|
|
3320
|
+
function eq(uint256 a, gtUint256 memory b) internal returns (gtBool) {
|
|
3321
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3322
|
+
|
|
3323
|
+
return and(eq(aLow, b.low), eq(aHigh, b.high));
|
|
3324
|
+
}
|
|
3325
|
+
|
|
3326
|
+
function ne(uint256 a, gtUint256 memory b) internal returns (gtBool) {
|
|
3327
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3328
|
+
|
|
3329
|
+
return or(ne(aLow, b.low), ne(aHigh, b.high));
|
|
3330
|
+
}
|
|
3331
|
+
|
|
3332
|
+
function ge(uint256 a, gtUint256 memory b) internal returns (gtBool) {
|
|
3333
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3334
|
+
|
|
3335
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
3336
|
+
|
|
3337
|
+
return mux(highEqual, gt(aHigh, b.high), ge(aLow, b.low));
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
function gt(uint256 a, gtUint256 memory b) internal returns (gtBool) {
|
|
3341
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3342
|
+
|
|
3343
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
3344
|
+
|
|
3345
|
+
return mux(highEqual, gt(aHigh, b.high), gt(aLow, b.low));
|
|
3346
|
+
}
|
|
3347
|
+
|
|
3348
|
+
function le(uint256 a, gtUint256 memory b) internal returns (gtBool) {
|
|
3349
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3350
|
+
|
|
3351
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
3352
|
+
|
|
3353
|
+
return mux(highEqual, lt(aHigh, b.high), le(aLow, b.low));
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3356
|
+
function lt(uint256 a, gtUint256 memory b) internal returns (gtBool) {
|
|
3357
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3358
|
+
|
|
3359
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
3360
|
+
|
|
3361
|
+
return mux(highEqual, lt(aHigh, b.high), lt(aLow, b.low));
|
|
3362
|
+
}
|
|
3363
|
+
|
|
3364
|
+
function min(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3365
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3366
|
+
|
|
3367
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
3368
|
+
gtBool aHighLessThan = lt(aHigh, b.high);
|
|
3369
|
+
gtBool aLowLessThan = lt(aLow, b.low);
|
|
3370
|
+
|
|
3371
|
+
return mux(
|
|
3372
|
+
highEqual,
|
|
3373
|
+
mux(aHighLessThan, b, a),
|
|
3374
|
+
mux(aLowLessThan, b, a)
|
|
3375
|
+
);
|
|
3376
|
+
}
|
|
3377
|
+
|
|
3378
|
+
function max(uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3379
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3380
|
+
|
|
3381
|
+
gtBool highEqual = eq(aHigh, b.high);
|
|
3382
|
+
gtBool aHighGreaterThan = gt(aHigh, b.high);
|
|
3383
|
+
gtBool aLowGreaterThan = gt(aLow, b.low);
|
|
3384
|
+
|
|
3385
|
+
return mux(
|
|
3386
|
+
highEqual,
|
|
3387
|
+
mux(aHighGreaterThan, b, a),
|
|
3388
|
+
mux(aLowGreaterThan, b, a)
|
|
3389
|
+
);
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3392
|
+
function mux(gtBool bit, uint256 a, gtUint256 memory b) internal returns (gtUint256 memory) {
|
|
3393
|
+
gtUint256 memory result;
|
|
3394
|
+
|
|
3395
|
+
(uint128 aHigh, uint128 aLow) = _splitUint256(a);
|
|
3396
|
+
|
|
3397
|
+
result.low = mux(bit, aLow, b.low);
|
|
3398
|
+
result.high = mux(bit, aHigh, b.high);
|
|
3399
|
+
|
|
3400
|
+
return result;
|
|
3401
|
+
}
|
|
3402
|
+
|
|
3403
|
+
|
|
1665
3404
|
// =========== Operations with RHS_PUBLIC parameter ===========
|
|
1666
3405
|
// =========== 8 bit operations ==============
|
|
1667
3406
|
|
|
@@ -2220,6 +3959,891 @@ library MpcCore {
|
|
|
2220
3959
|
Mux(combineEnumsToBytes3(MPC_TYPE.SUINT64_T, MPC_TYPE.SUINT64_T, ARGS.RHS_PUBLIC), gtBool.unwrap(bit), gtUint64.unwrap(a), uint256(b)));
|
|
2221
3960
|
}
|
|
2222
3961
|
|
|
3962
|
+
// =========== 128 bit operations ==============
|
|
3963
|
+
|
|
3964
|
+
function add(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
3965
|
+
gtUint128 memory result;
|
|
3966
|
+
|
|
3967
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
3968
|
+
|
|
3969
|
+
// Add low parts
|
|
3970
|
+
result.low = add(a.low, bLow);
|
|
3971
|
+
|
|
3972
|
+
// Check if there's a carry from low addition
|
|
3973
|
+
gtBool carry = lt(result.low, a.low);
|
|
3974
|
+
|
|
3975
|
+
// Add high parts with carry if needed
|
|
3976
|
+
result.high = add(a.high, bHigh);
|
|
3977
|
+
|
|
3978
|
+
// Add carry to high part if needed
|
|
3979
|
+
result.high = mux(carry, result.high, add(result.high, uint64(1)));
|
|
3980
|
+
|
|
3981
|
+
return result;
|
|
3982
|
+
}
|
|
3983
|
+
|
|
3984
|
+
function checkedAdd(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
3985
|
+
gtUint128 memory result;
|
|
3986
|
+
|
|
3987
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
3988
|
+
|
|
3989
|
+
// Add low parts
|
|
3990
|
+
result.low = add(a.low, bLow);
|
|
3991
|
+
|
|
3992
|
+
// Check if there's a carry from low addition
|
|
3993
|
+
gtBool carry = lt(result.low, a.low);
|
|
3994
|
+
|
|
3995
|
+
// Add high parts with carry if needed
|
|
3996
|
+
result.high = checkedAdd(a.high, bHigh);
|
|
3997
|
+
|
|
3998
|
+
// Add carry to high part if needed
|
|
3999
|
+
result.high = mux(carry, result.high, checkedAdd(result.high, uint64(1)));
|
|
4000
|
+
|
|
4001
|
+
return result;
|
|
4002
|
+
}
|
|
4003
|
+
|
|
4004
|
+
function checkedAddWithOverflowBit(gtUint128 memory a, uint128 b) internal returns (gtBool, gtUint128 memory) {
|
|
4005
|
+
gtBool bit = setPublic(false);
|
|
4006
|
+
gtUint128 memory result;
|
|
4007
|
+
|
|
4008
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4009
|
+
|
|
4010
|
+
// Add low parts
|
|
4011
|
+
result.low = add(a.low, bLow);
|
|
4012
|
+
|
|
4013
|
+
// Check if there's a carry from low addition
|
|
4014
|
+
gtBool carry = lt(result.low, a.low);
|
|
4015
|
+
|
|
4016
|
+
// Add high parts with carry if needed
|
|
4017
|
+
(gtBool overflow, gtUint64 high) = checkedAddWithOverflowBit(a.high, bHigh);
|
|
4018
|
+
(gtBool overflowWithCarry, gtUint64 highWithCarry) = checkedAddWithOverflowBit(high, uint64(1));
|
|
4019
|
+
|
|
4020
|
+
// Handle carry if needed
|
|
4021
|
+
bit = mux(carry, overflow, or(overflow, overflowWithCarry));
|
|
4022
|
+
result.high = mux(carry, high, highWithCarry);
|
|
4023
|
+
|
|
4024
|
+
return (bit, result);
|
|
4025
|
+
}
|
|
4026
|
+
|
|
4027
|
+
function sub(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
4028
|
+
gtUint128 memory result;
|
|
4029
|
+
|
|
4030
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4031
|
+
|
|
4032
|
+
// Subtract low parts
|
|
4033
|
+
result.low = sub(a.low, bLow);
|
|
4034
|
+
|
|
4035
|
+
// Check if there's a borrow from low subtraction
|
|
4036
|
+
gtBool borrow = lt(a.low, bLow);
|
|
4037
|
+
|
|
4038
|
+
// Subtract high parts with borrow if needed
|
|
4039
|
+
result.high = sub(a.high, bHigh);
|
|
4040
|
+
|
|
4041
|
+
// Subtract borrow from high part if needed
|
|
4042
|
+
result.high = mux(borrow, result.high, sub(result.high, uint64(1)));
|
|
4043
|
+
|
|
4044
|
+
return result;
|
|
4045
|
+
}
|
|
4046
|
+
|
|
4047
|
+
function checkedSub(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
4048
|
+
gtUint128 memory result;
|
|
4049
|
+
|
|
4050
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4051
|
+
|
|
4052
|
+
// Subtract low parts
|
|
4053
|
+
result.low = sub(a.low, bLow);
|
|
4054
|
+
|
|
4055
|
+
// Check if there's a borrow from low subtraction
|
|
4056
|
+
gtBool borrow = lt(a.low, bLow);
|
|
4057
|
+
|
|
4058
|
+
// Subtract high parts with borrow if needed
|
|
4059
|
+
result.high = checkedSub(a.high, bHigh);
|
|
4060
|
+
|
|
4061
|
+
// Subtract borrow from high part if needed
|
|
4062
|
+
result.high = mux(
|
|
4063
|
+
borrow,
|
|
4064
|
+
result.high,
|
|
4065
|
+
checkedSub(
|
|
4066
|
+
mux(borrow, add(result.high, uint64(1)), result.high),
|
|
4067
|
+
uint64(1)
|
|
4068
|
+
)
|
|
4069
|
+
);
|
|
4070
|
+
return result;
|
|
4071
|
+
}
|
|
4072
|
+
|
|
4073
|
+
function checkedSubWithOverflowBit(gtUint128 memory a, uint128 b) internal returns (gtBool, gtUint128 memory) {
|
|
4074
|
+
gtBool bit = setPublic(false);
|
|
4075
|
+
gtUint128 memory result;
|
|
4076
|
+
|
|
4077
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4078
|
+
|
|
4079
|
+
// Subtract low parts
|
|
4080
|
+
result.low = sub(a.low, bLow);
|
|
4081
|
+
|
|
4082
|
+
// Check if there's a borrow from low subtraction
|
|
4083
|
+
gtBool borrow = lt(a.low, bLow);
|
|
4084
|
+
|
|
4085
|
+
// Subtract high parts with borrow if needed
|
|
4086
|
+
(gtBool overflow, gtUint64 high) = checkedSubWithOverflowBit(a.high, bHigh);
|
|
4087
|
+
(gtBool overflowWithCarry, gtUint64 highWithCarry) = checkedSubWithOverflowBit(high, uint64(1));
|
|
4088
|
+
|
|
4089
|
+
// Handle borrow if needed
|
|
4090
|
+
bit = mux(borrow, overflow, or(overflow, overflowWithCarry));
|
|
4091
|
+
result.high = mux(borrow, high, highWithCarry);
|
|
4092
|
+
|
|
4093
|
+
return (bit, result);
|
|
4094
|
+
}
|
|
4095
|
+
|
|
4096
|
+
function _mul64(gtUint64 a, uint64 b) private returns (gtUint64, gtUint64) {
|
|
4097
|
+
uint64 MAX_UINT32 = uint64(type(uint32).max);
|
|
4098
|
+
|
|
4099
|
+
gtUint64 pp0;
|
|
4100
|
+
gtUint64 pp1;
|
|
4101
|
+
gtUint64 pp2;
|
|
4102
|
+
gtUint64 pp3;
|
|
4103
|
+
|
|
4104
|
+
{
|
|
4105
|
+
// Split the numbers into 32-bit parts
|
|
4106
|
+
gtUint64 aLow = and(a, MAX_UINT32);
|
|
4107
|
+
gtUint64 aHigh = shr(a, 32);
|
|
4108
|
+
uint64 bLow = b & type(uint32).max;
|
|
4109
|
+
uint64 bHigh = b >> 32;
|
|
4110
|
+
|
|
4111
|
+
// Compute partial products
|
|
4112
|
+
pp0 = mul(aLow, bLow);
|
|
4113
|
+
pp1 = mul(aLow, bHigh);
|
|
4114
|
+
pp2 = mul(aHigh, bLow);
|
|
4115
|
+
pp3 = mul(aHigh, bHigh);
|
|
4116
|
+
}
|
|
4117
|
+
|
|
4118
|
+
// Compute high and low parts
|
|
4119
|
+
gtUint64 mid = add(
|
|
4120
|
+
add(
|
|
4121
|
+
shr(pp0, 32),
|
|
4122
|
+
and(pp1, MAX_UINT32)
|
|
4123
|
+
),
|
|
4124
|
+
and(pp2, MAX_UINT32)
|
|
4125
|
+
);
|
|
4126
|
+
gtUint64 carry = shr(mid, 32);
|
|
4127
|
+
|
|
4128
|
+
gtUint64 high = add(
|
|
4129
|
+
add(pp3, shr(pp1, 32)),
|
|
4130
|
+
add(shr(pp2, 32), carry)
|
|
4131
|
+
);
|
|
4132
|
+
gtUint64 low = or(
|
|
4133
|
+
and(pp0, MAX_UINT32),
|
|
4134
|
+
shl(and(mid, MAX_UINT32), 32)
|
|
4135
|
+
);
|
|
4136
|
+
|
|
4137
|
+
return (high, low);
|
|
4138
|
+
}
|
|
4139
|
+
|
|
4140
|
+
function mul(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
4141
|
+
gtUint128 memory result;
|
|
4142
|
+
|
|
4143
|
+
uint64 bLow = uint64(b & type(uint64).max);
|
|
4144
|
+
uint64 bHigh = uint64(b >> 64);
|
|
4145
|
+
|
|
4146
|
+
// Compute partial products
|
|
4147
|
+
(gtUint64 pp0, gtUint64 low) = _mul64(a.low, bLow);
|
|
4148
|
+
(, gtUint64 pp1) = _mul64(a.high, bLow);
|
|
4149
|
+
(, gtUint64 pp2) = _mul64(a.low, bHigh);
|
|
4150
|
+
|
|
4151
|
+
// Compute the high and low parts
|
|
4152
|
+
result.high = add(
|
|
4153
|
+
add(pp0, pp1),
|
|
4154
|
+
pp2
|
|
4155
|
+
);
|
|
4156
|
+
result.low = low;
|
|
4157
|
+
|
|
4158
|
+
return result;
|
|
4159
|
+
}
|
|
4160
|
+
|
|
4161
|
+
function checkedMul(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
4162
|
+
gtUint128 memory result;
|
|
4163
|
+
|
|
4164
|
+
uint64 bLow = uint64(b & type(uint64).max);
|
|
4165
|
+
uint64 bHigh = uint64(b >> 64);
|
|
4166
|
+
|
|
4167
|
+
// Compute partial products
|
|
4168
|
+
(gtUint64 pp0, gtUint64 low) = _mul64(a.low, bLow);
|
|
4169
|
+
(gtUint64 pp2, gtUint64 pp1) = _mul64(a.high, bLow);
|
|
4170
|
+
(gtUint64 pp4, gtUint64 pp3) = _mul64(a.low, bHigh);
|
|
4171
|
+
(gtUint64 pp6, gtUint64 pp5) = _mul64(a.high, bHigh);
|
|
4172
|
+
|
|
4173
|
+
// Compute the high and low parts
|
|
4174
|
+
result.high = checkedAdd(
|
|
4175
|
+
checkedAdd(pp0, pp1),
|
|
4176
|
+
pp3
|
|
4177
|
+
);
|
|
4178
|
+
result.low = low;
|
|
4179
|
+
|
|
4180
|
+
// Check for overflow
|
|
4181
|
+
checkedSub(
|
|
4182
|
+
uint64(0),
|
|
4183
|
+
add(
|
|
4184
|
+
add(pp2, pp4),
|
|
4185
|
+
add(pp5, pp6)
|
|
4186
|
+
)
|
|
4187
|
+
);
|
|
4188
|
+
|
|
4189
|
+
return result;
|
|
4190
|
+
}
|
|
4191
|
+
|
|
4192
|
+
function checkedMulWithOverflowBit(gtUint128 memory a, uint128 b) internal returns (gtBool, gtUint128 memory) {
|
|
4193
|
+
gtUint128 memory result;
|
|
4194
|
+
|
|
4195
|
+
gtUint64 low;
|
|
4196
|
+
gtUint64 pp0;
|
|
4197
|
+
gtUint64 pp1;
|
|
4198
|
+
gtUint64 pp2;
|
|
4199
|
+
gtUint64 pp3;
|
|
4200
|
+
gtUint64 pp4;
|
|
4201
|
+
gtUint64 pp5;
|
|
4202
|
+
gtUint64 pp6;
|
|
4203
|
+
|
|
4204
|
+
{
|
|
4205
|
+
uint64 bLow = uint64(b & type(uint64).max);
|
|
4206
|
+
uint64 bHigh = uint64(b >> 64);
|
|
4207
|
+
|
|
4208
|
+
// Compute partial products
|
|
4209
|
+
(pp0, low) = _mul64(a.low, bLow);
|
|
4210
|
+
(pp2, pp1) = _mul64(a.high, bLow);
|
|
4211
|
+
(pp4, pp3) = _mul64(a.low, bHigh);
|
|
4212
|
+
(pp6, pp5) = _mul64(a.high, bHigh);
|
|
4213
|
+
}
|
|
4214
|
+
|
|
4215
|
+
// Compute the high and low parts
|
|
4216
|
+
gtBool overflow1;
|
|
4217
|
+
|
|
4218
|
+
(gtBool overflow0, gtUint64 high) = checkedAddWithOverflowBit(pp0, pp1);
|
|
4219
|
+
(overflow1, result.high) = checkedAddWithOverflowBit(high, pp3);
|
|
4220
|
+
|
|
4221
|
+
result.low = low;
|
|
4222
|
+
|
|
4223
|
+
// Check for overflow
|
|
4224
|
+
gtBool bit = or(
|
|
4225
|
+
or(overflow0, overflow1),
|
|
4226
|
+
gt(
|
|
4227
|
+
add(
|
|
4228
|
+
add(pp2, pp4),
|
|
4229
|
+
add(pp5, pp6)
|
|
4230
|
+
),
|
|
4231
|
+
uint64(0)
|
|
4232
|
+
)
|
|
4233
|
+
);
|
|
4234
|
+
|
|
4235
|
+
return (bit, result);
|
|
4236
|
+
}
|
|
4237
|
+
|
|
4238
|
+
function and(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
4239
|
+
gtUint128 memory result;
|
|
4240
|
+
|
|
4241
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4242
|
+
|
|
4243
|
+
result.low = and(a.low, bLow);
|
|
4244
|
+
result.high = and(a.high, bHigh);
|
|
4245
|
+
|
|
4246
|
+
return result;
|
|
4247
|
+
}
|
|
4248
|
+
|
|
4249
|
+
function or(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
4250
|
+
gtUint128 memory result;
|
|
4251
|
+
|
|
4252
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4253
|
+
|
|
4254
|
+
result.low = or(a.low, bLow);
|
|
4255
|
+
result.high = or(a.high, bHigh);
|
|
4256
|
+
|
|
4257
|
+
return result;
|
|
4258
|
+
}
|
|
4259
|
+
|
|
4260
|
+
function xor(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
4261
|
+
gtUint128 memory result;
|
|
4262
|
+
|
|
4263
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4264
|
+
|
|
4265
|
+
result.low = xor(a.low, bLow);
|
|
4266
|
+
result.high = xor(a.high, bHigh);
|
|
4267
|
+
|
|
4268
|
+
return result;
|
|
4269
|
+
}
|
|
4270
|
+
|
|
4271
|
+
function shl(gtUint128 memory a, uint8 b) internal returns (gtUint128 memory) {
|
|
4272
|
+
gtUint128 memory result;
|
|
4273
|
+
|
|
4274
|
+
if (b >= 64) {
|
|
4275
|
+
shl(a.high, b); // check for overflow in high part
|
|
4276
|
+
|
|
4277
|
+
result.low = setPublic64(0);
|
|
4278
|
+
result.high = shl(a.low, b - 64);
|
|
4279
|
+
} else if (b > 0) {
|
|
4280
|
+
// Mask to clear the bits of the low part that will be shifted out
|
|
4281
|
+
uint64 mask = uint64(type(uint64).max >> b);
|
|
4282
|
+
|
|
4283
|
+
result.low = shl(and(a.low, mask), b);
|
|
4284
|
+
|
|
4285
|
+
// Mask to clear the bits of the low part that remain in the low part
|
|
4286
|
+
mask = uint64(type(uint64).max << 64 - b);
|
|
4287
|
+
|
|
4288
|
+
result.high = or(shl(a.high, b), shr(and(a.low, mask), 64 - b));
|
|
4289
|
+
} else {
|
|
4290
|
+
result.low = a.low;
|
|
4291
|
+
result.high = a.high;
|
|
4292
|
+
}
|
|
4293
|
+
|
|
4294
|
+
return result;
|
|
4295
|
+
}
|
|
4296
|
+
|
|
4297
|
+
function shr(gtUint128 memory a, uint8 b) internal returns (gtUint128 memory) {
|
|
4298
|
+
gtUint128 memory result;
|
|
4299
|
+
|
|
4300
|
+
if (b >= 64) {
|
|
4301
|
+
shr(a.low, b); // check for overflow in low part
|
|
4302
|
+
|
|
4303
|
+
result.low = shr(a.high, b - 64);
|
|
4304
|
+
result.high = setPublic64(0);
|
|
4305
|
+
} else if (b > 0) {
|
|
4306
|
+
// Mask to clear the bits of the low part that will be shifted out
|
|
4307
|
+
uint64 mask = uint64(type(uint64).max >> 64 - b);
|
|
4308
|
+
|
|
4309
|
+
result.low = or(shr(a.low, b), shl(and(a.high, mask), 64 - b));
|
|
4310
|
+
|
|
4311
|
+
// Mask to clear the bits of the low part that remain in the low part
|
|
4312
|
+
mask = uint64(type(uint64).max << b);
|
|
4313
|
+
|
|
4314
|
+
result.high = shr(and(a.high, mask), b);
|
|
4315
|
+
} else {
|
|
4316
|
+
result.low = a.low;
|
|
4317
|
+
result.high = a.high;
|
|
4318
|
+
}
|
|
4319
|
+
|
|
4320
|
+
return result;
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
function eq(gtUint128 memory a, uint128 b) internal returns (gtBool) {
|
|
4324
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4325
|
+
|
|
4326
|
+
return and(eq(a.low, bLow), eq(a.high, bHigh));
|
|
4327
|
+
}
|
|
4328
|
+
|
|
4329
|
+
function ne(gtUint128 memory a, uint128 b) internal returns (gtBool) {
|
|
4330
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4331
|
+
|
|
4332
|
+
return or(ne(a.low, bLow), ne(a.high, bHigh));
|
|
4333
|
+
}
|
|
4334
|
+
|
|
4335
|
+
function ge(gtUint128 memory a, uint128 b) internal returns (gtBool) {
|
|
4336
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4337
|
+
|
|
4338
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4339
|
+
|
|
4340
|
+
return mux(highEqual, gt(a.high, bHigh), ge(a.low, bLow));
|
|
4341
|
+
}
|
|
4342
|
+
|
|
4343
|
+
function gt(gtUint128 memory a, uint128 b) internal returns (gtBool) {
|
|
4344
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4345
|
+
|
|
4346
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4347
|
+
|
|
4348
|
+
return mux(highEqual, gt(a.high, bHigh), gt(a.low, bLow));
|
|
4349
|
+
}
|
|
4350
|
+
|
|
4351
|
+
function le(gtUint128 memory a, uint128 b) internal returns (gtBool) {
|
|
4352
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4353
|
+
|
|
4354
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4355
|
+
|
|
4356
|
+
return mux(highEqual, lt(a.high, bHigh), le(a.low, bLow));
|
|
4357
|
+
}
|
|
4358
|
+
|
|
4359
|
+
function lt(gtUint128 memory a, uint128 b) internal returns (gtBool) {
|
|
4360
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4361
|
+
|
|
4362
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4363
|
+
|
|
4364
|
+
return mux(highEqual, lt(a.high, bHigh), lt(a.low, bLow));
|
|
4365
|
+
}
|
|
4366
|
+
|
|
4367
|
+
function min(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
4368
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4369
|
+
|
|
4370
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4371
|
+
gtBool aHighLessThan = lt(a.high, bHigh);
|
|
4372
|
+
gtBool aLowLessThan = lt(a.low, bLow);
|
|
4373
|
+
|
|
4374
|
+
return mux(
|
|
4375
|
+
highEqual,
|
|
4376
|
+
mux(aHighLessThan, b, a),
|
|
4377
|
+
mux(aLowLessThan, b, a)
|
|
4378
|
+
);
|
|
4379
|
+
}
|
|
4380
|
+
|
|
4381
|
+
function max(gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
4382
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4383
|
+
|
|
4384
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4385
|
+
gtBool aHighGreaterThan = gt(a.high, bHigh);
|
|
4386
|
+
gtBool aLowGreaterThan = gt(a.low, bLow);
|
|
4387
|
+
|
|
4388
|
+
return mux(
|
|
4389
|
+
highEqual,
|
|
4390
|
+
mux(aHighGreaterThan, b, a),
|
|
4391
|
+
mux(aLowGreaterThan, b, a)
|
|
4392
|
+
);
|
|
4393
|
+
}
|
|
4394
|
+
|
|
4395
|
+
function mux(gtBool bit, gtUint128 memory a, uint128 b) internal returns (gtUint128 memory) {
|
|
4396
|
+
gtUint128 memory result;
|
|
4397
|
+
|
|
4398
|
+
(uint64 bHigh, uint64 bLow) = _splitUint128(b);
|
|
4399
|
+
|
|
4400
|
+
result.low = mux(bit, a.low, bLow);
|
|
4401
|
+
result.high = mux(bit, a.high, bHigh);
|
|
4402
|
+
|
|
4403
|
+
return result;
|
|
4404
|
+
}
|
|
4405
|
+
|
|
4406
|
+
// =========== 256 bit operations ==============
|
|
4407
|
+
|
|
4408
|
+
function add(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4409
|
+
gtUint256 memory result;
|
|
4410
|
+
|
|
4411
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4412
|
+
|
|
4413
|
+
// Add low parts
|
|
4414
|
+
result.low = add(a.low, bLow);
|
|
4415
|
+
|
|
4416
|
+
// Check if there's a carry from low addition
|
|
4417
|
+
gtBool carry = lt(result.low, a.low);
|
|
4418
|
+
|
|
4419
|
+
// Add high parts with carry if needed
|
|
4420
|
+
result.high = add(a.high, bHigh);
|
|
4421
|
+
|
|
4422
|
+
// Add carry to high part if needed
|
|
4423
|
+
result.high = mux(carry, result.high, add(result.high, uint128(1)));
|
|
4424
|
+
|
|
4425
|
+
return result;
|
|
4426
|
+
}
|
|
4427
|
+
|
|
4428
|
+
function checkedAdd(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4429
|
+
gtUint256 memory result;
|
|
4430
|
+
|
|
4431
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4432
|
+
|
|
4433
|
+
// Add low parts
|
|
4434
|
+
result.low = add(a.low, bLow);
|
|
4435
|
+
|
|
4436
|
+
// Check if there's a carry from low addition
|
|
4437
|
+
gtBool carry = lt(result.low, a.low);
|
|
4438
|
+
|
|
4439
|
+
// Add high parts with carry if needed
|
|
4440
|
+
result.high = checkedAdd(a.high, bHigh);
|
|
4441
|
+
|
|
4442
|
+
// Add carry to high part if needed
|
|
4443
|
+
result.high = mux(carry, result.high, checkedAdd(result.high, uint128(1)));
|
|
4444
|
+
|
|
4445
|
+
return result;
|
|
4446
|
+
}
|
|
4447
|
+
|
|
4448
|
+
function checkedAddWithOverflowBit(gtUint256 memory a, uint256 b) internal returns (gtBool, gtUint256 memory) {
|
|
4449
|
+
gtBool bit = setPublic(false);
|
|
4450
|
+
gtUint256 memory result;
|
|
4451
|
+
|
|
4452
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4453
|
+
|
|
4454
|
+
// Add low parts
|
|
4455
|
+
result.low = add(a.low, bLow);
|
|
4456
|
+
|
|
4457
|
+
// Check if there's a carry from low addition
|
|
4458
|
+
gtBool carry = lt(result.low, a.low);
|
|
4459
|
+
|
|
4460
|
+
// Add high parts with carry if needed
|
|
4461
|
+
(gtBool overflow, gtUint128 memory high) = checkedAddWithOverflowBit(a.high, bHigh);
|
|
4462
|
+
(gtBool overflowWithCarry, gtUint128 memory highWithCarry) = checkedAddWithOverflowBit(high, uint128(1));
|
|
4463
|
+
|
|
4464
|
+
// Handle carry if needed
|
|
4465
|
+
bit = mux(carry, overflow, or(overflow, overflowWithCarry));
|
|
4466
|
+
result.high = mux(carry, high, highWithCarry);
|
|
4467
|
+
|
|
4468
|
+
return (bit, result);
|
|
4469
|
+
}
|
|
4470
|
+
|
|
4471
|
+
function sub(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4472
|
+
gtUint256 memory result;
|
|
4473
|
+
|
|
4474
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4475
|
+
|
|
4476
|
+
// Subtract low parts
|
|
4477
|
+
result.low = sub(a.low, bLow);
|
|
4478
|
+
|
|
4479
|
+
// Check if there's a borrow from low subtraction
|
|
4480
|
+
gtBool borrow = lt(a.low, bLow);
|
|
4481
|
+
|
|
4482
|
+
// Subtract high parts with borrow if needed
|
|
4483
|
+
result.high = sub(a.high, bHigh);
|
|
4484
|
+
|
|
4485
|
+
// Subtract borrow from high part if needed
|
|
4486
|
+
result.high = mux(borrow, result.high, sub(result.high, uint128(1)));
|
|
4487
|
+
|
|
4488
|
+
return result;
|
|
4489
|
+
}
|
|
4490
|
+
|
|
4491
|
+
function checkedSub(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4492
|
+
gtUint256 memory result;
|
|
4493
|
+
|
|
4494
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4495
|
+
|
|
4496
|
+
// Subtract low parts
|
|
4497
|
+
result.low = sub(a.low, bLow);
|
|
4498
|
+
|
|
4499
|
+
// Check if there's a borrow from low subtraction
|
|
4500
|
+
gtBool borrow = lt(a.low, bLow);
|
|
4501
|
+
|
|
4502
|
+
// Subtract high parts with borrow if needed
|
|
4503
|
+
result.high = checkedSub(a.high, bHigh);
|
|
4504
|
+
|
|
4505
|
+
// Subtract borrow from high part if needed
|
|
4506
|
+
result.high = mux(
|
|
4507
|
+
borrow,
|
|
4508
|
+
result.high,
|
|
4509
|
+
checkedSub(
|
|
4510
|
+
mux(borrow, add(result.high, uint128(1)), result.high),
|
|
4511
|
+
uint128(1)
|
|
4512
|
+
)
|
|
4513
|
+
);
|
|
4514
|
+
return result;
|
|
4515
|
+
}
|
|
4516
|
+
|
|
4517
|
+
function checkedSubWithOverflowBit(gtUint256 memory a, uint256 b) internal returns (gtBool, gtUint256 memory) {
|
|
4518
|
+
gtBool bit = setPublic(false);
|
|
4519
|
+
gtUint256 memory result;
|
|
4520
|
+
|
|
4521
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4522
|
+
|
|
4523
|
+
// Subtract low parts
|
|
4524
|
+
result.low = sub(a.low, bLow);
|
|
4525
|
+
|
|
4526
|
+
// Check if there's a borrow from low subtraction
|
|
4527
|
+
gtBool borrow = lt(a.low, bLow);
|
|
4528
|
+
|
|
4529
|
+
// Subtract high parts with borrow if needed
|
|
4530
|
+
(gtBool overflow, gtUint128 memory high) = checkedSubWithOverflowBit(a.high, bHigh);
|
|
4531
|
+
(gtBool overflowWithCarry, gtUint128 memory highWithCarry) = checkedSubWithOverflowBit(high, uint128(1));
|
|
4532
|
+
|
|
4533
|
+
// Handle borrow if needed
|
|
4534
|
+
bit = mux(borrow, overflow, or(overflow, overflowWithCarry));
|
|
4535
|
+
result.high = mux(borrow, high, highWithCarry);
|
|
4536
|
+
|
|
4537
|
+
return (bit, result);
|
|
4538
|
+
}
|
|
4539
|
+
|
|
4540
|
+
function _mul128(gtUint128 memory a, uint128 b) private returns (gtUint128 memory, gtUint128 memory) {
|
|
4541
|
+
uint128 MAX_UINT64 = uint128(type(uint64).max);
|
|
4542
|
+
|
|
4543
|
+
gtUint128 memory pp0;
|
|
4544
|
+
gtUint128 memory pp1;
|
|
4545
|
+
gtUint128 memory pp2;
|
|
4546
|
+
gtUint128 memory pp3;
|
|
4547
|
+
|
|
4548
|
+
{
|
|
4549
|
+
// Split the numbers into 64-bit parts
|
|
4550
|
+
gtUint128 memory aLow = and(a, MAX_UINT64);
|
|
4551
|
+
gtUint128 memory aHigh = shr(a, 64);
|
|
4552
|
+
uint128 bLow = b & type(uint64).max;
|
|
4553
|
+
uint128 bHigh = b >> 64;
|
|
4554
|
+
|
|
4555
|
+
// Compute partial products
|
|
4556
|
+
pp0 = mul(aLow, bLow);
|
|
4557
|
+
pp1 = mul(aLow, bHigh);
|
|
4558
|
+
pp2 = mul(aHigh, bLow);
|
|
4559
|
+
pp3 = mul(aHigh, bHigh);
|
|
4560
|
+
}
|
|
4561
|
+
|
|
4562
|
+
// Compute high and low parts
|
|
4563
|
+
gtUint128 memory mid = add(
|
|
4564
|
+
add(
|
|
4565
|
+
shr(pp0, 64),
|
|
4566
|
+
and(pp1, MAX_UINT64)
|
|
4567
|
+
),
|
|
4568
|
+
and(pp2, MAX_UINT64)
|
|
4569
|
+
);
|
|
4570
|
+
gtUint128 memory carry = shr(mid, 64);
|
|
4571
|
+
|
|
4572
|
+
gtUint128 memory high = add(
|
|
4573
|
+
add(pp3, shr(pp1, 64)),
|
|
4574
|
+
add(shr(pp2, 64), carry)
|
|
4575
|
+
);
|
|
4576
|
+
gtUint128 memory low = or(
|
|
4577
|
+
and(pp0, MAX_UINT64),
|
|
4578
|
+
shl(and(mid, MAX_UINT64), 64)
|
|
4579
|
+
);
|
|
4580
|
+
|
|
4581
|
+
return (high, low);
|
|
4582
|
+
}
|
|
4583
|
+
|
|
4584
|
+
function mul(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4585
|
+
gtUint256 memory result;
|
|
4586
|
+
|
|
4587
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4588
|
+
|
|
4589
|
+
// Compute partial products
|
|
4590
|
+
(gtUint128 memory pp0, gtUint128 memory low) = _mul128(a.low, bLow);
|
|
4591
|
+
(, gtUint128 memory pp1) = _mul128(a.high, bLow);
|
|
4592
|
+
(, gtUint128 memory pp2) = _mul128(a.low, bHigh);
|
|
4593
|
+
|
|
4594
|
+
// Compute the high and low parts
|
|
4595
|
+
result.high = add(
|
|
4596
|
+
add(pp0, pp1),
|
|
4597
|
+
pp2
|
|
4598
|
+
);
|
|
4599
|
+
result.low = low;
|
|
4600
|
+
|
|
4601
|
+
return result;
|
|
4602
|
+
}
|
|
4603
|
+
|
|
4604
|
+
function checkedMul(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4605
|
+
gtUint256 memory result;
|
|
4606
|
+
|
|
4607
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4608
|
+
|
|
4609
|
+
// Compute partial products
|
|
4610
|
+
(gtUint128 memory pp0, gtUint128 memory low) = _mul128(a.low, bLow);
|
|
4611
|
+
(gtUint128 memory pp2, gtUint128 memory pp1) = _mul128(a.high, bLow);
|
|
4612
|
+
(gtUint128 memory pp4, gtUint128 memory pp3) = _mul128(a.low, bHigh);
|
|
4613
|
+
(gtUint128 memory pp6, gtUint128 memory pp5) = _mul128(a.high, bHigh);
|
|
4614
|
+
|
|
4615
|
+
// Compute the high and low parts
|
|
4616
|
+
result.high = checkedAdd(
|
|
4617
|
+
checkedAdd(pp0, pp1),
|
|
4618
|
+
pp3
|
|
4619
|
+
);
|
|
4620
|
+
result.low = low;
|
|
4621
|
+
|
|
4622
|
+
// Check for overflow
|
|
4623
|
+
checkedSub(
|
|
4624
|
+
uint128(0),
|
|
4625
|
+
add(
|
|
4626
|
+
add(pp2, pp4),
|
|
4627
|
+
add(pp5, pp6)
|
|
4628
|
+
)
|
|
4629
|
+
);
|
|
4630
|
+
|
|
4631
|
+
return result;
|
|
4632
|
+
}
|
|
4633
|
+
|
|
4634
|
+
function checkedMulWithOverflowBit(gtUint256 memory a, uint256 b) internal returns (gtBool, gtUint256 memory) {
|
|
4635
|
+
gtUint256 memory result;
|
|
4636
|
+
|
|
4637
|
+
gtUint128 memory low;
|
|
4638
|
+
gtUint128 memory pp0;
|
|
4639
|
+
gtUint128 memory pp1;
|
|
4640
|
+
gtUint128 memory pp2;
|
|
4641
|
+
gtUint128 memory pp3;
|
|
4642
|
+
gtUint128 memory pp4;
|
|
4643
|
+
gtUint128 memory pp5;
|
|
4644
|
+
gtUint128 memory pp6;
|
|
4645
|
+
|
|
4646
|
+
{
|
|
4647
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4648
|
+
|
|
4649
|
+
// Compute partial products
|
|
4650
|
+
(pp0, low) = _mul128(a.low, bLow);
|
|
4651
|
+
(pp2, pp1) = _mul128(a.high, bLow);
|
|
4652
|
+
(pp4, pp3) = _mul128(a.low, bHigh);
|
|
4653
|
+
(pp6, pp5) = _mul128(a.high, bHigh);
|
|
4654
|
+
}
|
|
4655
|
+
|
|
4656
|
+
// Compute the high and low parts
|
|
4657
|
+
gtBool overflow1;
|
|
4658
|
+
|
|
4659
|
+
(gtBool overflow0, gtUint128 memory high) = checkedAddWithOverflowBit(pp0, pp1);
|
|
4660
|
+
(overflow1, result.high) = checkedAddWithOverflowBit(high, pp3);
|
|
4661
|
+
|
|
4662
|
+
result.low = low;
|
|
4663
|
+
|
|
4664
|
+
// Check for overflow
|
|
4665
|
+
gtBool bit = or(
|
|
4666
|
+
or(overflow0, overflow1),
|
|
4667
|
+
gt(
|
|
4668
|
+
add(
|
|
4669
|
+
add(pp2, pp4),
|
|
4670
|
+
add(pp5, pp6)
|
|
4671
|
+
),
|
|
4672
|
+
uint128(0)
|
|
4673
|
+
)
|
|
4674
|
+
);
|
|
4675
|
+
|
|
4676
|
+
return (bit, result);
|
|
4677
|
+
}
|
|
4678
|
+
|
|
4679
|
+
function and(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4680
|
+
gtUint256 memory result;
|
|
4681
|
+
|
|
4682
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4683
|
+
|
|
4684
|
+
result.low = and(a.low, bLow);
|
|
4685
|
+
result.high = and(a.high, bHigh);
|
|
4686
|
+
|
|
4687
|
+
return result;
|
|
4688
|
+
}
|
|
4689
|
+
|
|
4690
|
+
function or(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4691
|
+
gtUint256 memory result;
|
|
4692
|
+
|
|
4693
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4694
|
+
|
|
4695
|
+
result.low = or(a.low, bLow);
|
|
4696
|
+
result.high = or(a.high, bHigh);
|
|
4697
|
+
|
|
4698
|
+
return result;
|
|
4699
|
+
}
|
|
4700
|
+
|
|
4701
|
+
function xor(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4702
|
+
gtUint256 memory result;
|
|
4703
|
+
|
|
4704
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4705
|
+
|
|
4706
|
+
result.low = xor(a.low, bLow);
|
|
4707
|
+
result.high = xor(a.high, bHigh);
|
|
4708
|
+
|
|
4709
|
+
return result;
|
|
4710
|
+
}
|
|
4711
|
+
|
|
4712
|
+
function shl(gtUint256 memory a, uint8 b) internal returns (gtUint256 memory) {
|
|
4713
|
+
gtUint256 memory result;
|
|
4714
|
+
|
|
4715
|
+
if (b >= 128) {
|
|
4716
|
+
shl(a.high, b); // check for overflow in high part
|
|
4717
|
+
|
|
4718
|
+
result.low = setPublic128(0);
|
|
4719
|
+
result.high = shl(a.low, b - 128);
|
|
4720
|
+
} else if (b > 0) {
|
|
4721
|
+
// Mask to clear the bits of the low part that will be shifted out
|
|
4722
|
+
uint128 mask = uint128(type(uint128).max >> b);
|
|
4723
|
+
|
|
4724
|
+
result.low = shl(and(a.low, mask), b);
|
|
4725
|
+
|
|
4726
|
+
// Mask to clear the bits of the low part that remain in the low part
|
|
4727
|
+
mask = uint128(type(uint128).max << 128 - b);
|
|
4728
|
+
|
|
4729
|
+
result.high = or(shl(a.high, b), shr(and(a.low, mask), 128 - b));
|
|
4730
|
+
} else {
|
|
4731
|
+
result.low = a.low;
|
|
4732
|
+
result.high = a.high;
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4735
|
+
return result;
|
|
4736
|
+
}
|
|
4737
|
+
|
|
4738
|
+
function shr(gtUint256 memory a, uint8 b) internal returns (gtUint256 memory) {
|
|
4739
|
+
gtUint256 memory result;
|
|
4740
|
+
|
|
4741
|
+
if (b >= 128) {
|
|
4742
|
+
shr(a.low, b); // check for overflow in low part
|
|
4743
|
+
|
|
4744
|
+
result.low = shr(a.high, b - 128);
|
|
4745
|
+
result.high = setPublic128(0);
|
|
4746
|
+
} else if (b > 0) {
|
|
4747
|
+
// Mask to clear the bits of the low part that will be shifted out
|
|
4748
|
+
uint128 mask = uint128(type(uint128).max >> 128 - b);
|
|
4749
|
+
|
|
4750
|
+
result.low = or(shr(a.low, b), shl(and(a.high, mask), 128 - b));
|
|
4751
|
+
|
|
4752
|
+
// Mask to clear the bits of the low part that remain in the low part
|
|
4753
|
+
mask = uint128(type(uint128).max << b);
|
|
4754
|
+
|
|
4755
|
+
result.high = shr(and(a.high, mask), b);
|
|
4756
|
+
} else {
|
|
4757
|
+
result.low = a.low;
|
|
4758
|
+
result.high = a.high;
|
|
4759
|
+
}
|
|
4760
|
+
|
|
4761
|
+
return result;
|
|
4762
|
+
}
|
|
4763
|
+
|
|
4764
|
+
function eq(gtUint256 memory a, uint256 b) internal returns (gtBool) {
|
|
4765
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4766
|
+
|
|
4767
|
+
return and(eq(a.low, bLow), eq(a.high, bHigh));
|
|
4768
|
+
}
|
|
4769
|
+
|
|
4770
|
+
function ne(gtUint256 memory a, uint256 b) internal returns (gtBool) {
|
|
4771
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4772
|
+
|
|
4773
|
+
return or(ne(a.low, bLow), ne(a.high, bHigh));
|
|
4774
|
+
}
|
|
4775
|
+
|
|
4776
|
+
function ge(gtUint256 memory a, uint256 b) internal returns (gtBool) {
|
|
4777
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4778
|
+
|
|
4779
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4780
|
+
|
|
4781
|
+
return mux(highEqual, gt(a.high, bHigh), ge(a.low, bLow));
|
|
4782
|
+
}
|
|
4783
|
+
|
|
4784
|
+
function gt(gtUint256 memory a, uint256 b) internal returns (gtBool) {
|
|
4785
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4786
|
+
|
|
4787
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4788
|
+
|
|
4789
|
+
return mux(highEqual, gt(a.high, bHigh), gt(a.low, bLow));
|
|
4790
|
+
}
|
|
4791
|
+
|
|
4792
|
+
function le(gtUint256 memory a, uint256 b) internal returns (gtBool) {
|
|
4793
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4794
|
+
|
|
4795
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4796
|
+
|
|
4797
|
+
return mux(highEqual, lt(a.high, bHigh), le(a.low, bLow));
|
|
4798
|
+
}
|
|
4799
|
+
|
|
4800
|
+
function lt(gtUint256 memory a, uint256 b) internal returns (gtBool) {
|
|
4801
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4802
|
+
|
|
4803
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4804
|
+
|
|
4805
|
+
return mux(highEqual, lt(a.high, bHigh), lt(a.low, bLow));
|
|
4806
|
+
}
|
|
4807
|
+
|
|
4808
|
+
function min(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4809
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4810
|
+
|
|
4811
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4812
|
+
gtBool aHighLessThan = lt(a.high, bHigh);
|
|
4813
|
+
gtBool aLowLessThan = lt(a.low, bLow);
|
|
4814
|
+
|
|
4815
|
+
return mux(
|
|
4816
|
+
highEqual,
|
|
4817
|
+
mux(aHighLessThan, b, a),
|
|
4818
|
+
mux(aLowLessThan, b, a)
|
|
4819
|
+
);
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4822
|
+
function max(gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4823
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4824
|
+
|
|
4825
|
+
gtBool highEqual = eq(a.high, bHigh);
|
|
4826
|
+
gtBool aHighGreaterThan = gt(a.high, bHigh);
|
|
4827
|
+
gtBool aLowGreaterThan = gt(a.low, bLow);
|
|
4828
|
+
|
|
4829
|
+
return mux(
|
|
4830
|
+
highEqual,
|
|
4831
|
+
mux(aHighGreaterThan, b, a),
|
|
4832
|
+
mux(aLowGreaterThan, b, a)
|
|
4833
|
+
);
|
|
4834
|
+
}
|
|
4835
|
+
|
|
4836
|
+
function mux(gtBool bit, gtUint256 memory a, uint256 b) internal returns (gtUint256 memory) {
|
|
4837
|
+
gtUint256 memory result;
|
|
4838
|
+
|
|
4839
|
+
(uint128 bHigh, uint128 bLow) = _splitUint256(b);
|
|
4840
|
+
|
|
4841
|
+
result.low = mux(bit, a.low, bLow);
|
|
4842
|
+
result.high = mux(bit, a.high, bHigh);
|
|
4843
|
+
|
|
4844
|
+
return result;
|
|
4845
|
+
}
|
|
4846
|
+
|
|
2223
4847
|
// In the context of a transfer, scalar balances are irrelevant;
|
|
2224
4848
|
// The only possibility for a scalar value is within the "amount" parameter.
|
|
2225
4849
|
// Therefore, in this scenario, LHS_PUBLIC signifies a scalar amount, not balance1.
|