69 Env env{*
this, features};
72 MPTTester mptAlice(env, alice, {.holders = {bob}});
76 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
82 mptAlice.pay(alice, bob, 100);
84 mptAlice.generateKeyPair(alice);
86 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
88 mptAlice.generateKeyPair(bob);
93 .holderPubKey = mptAlice.getPubKey(bob),
114 Env env{*
this, features};
117 MPTTester mptAlice(env, alice, {.holders = {bob}});
121 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
127 mptAlice.pay(alice, bob, 1);
129 mptAlice.generateKeyPair(alice);
130 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
132 mptAlice.generateKeyPair(bob);
136 .holderPubKey = mptAlice.getPubKey(bob),
149 Env env{*
this, features};
152 MPTTester mptAlice(env, alice, {.holders = {bob}});
156 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
164 mptAlice.generateKeyPair(alice);
165 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
167 mptAlice.generateKeyPair(bob);
173 .holderPubKey = mptAlice.getPubKey(bob),
178 auto const holderCiphertext =
180 auto const issuerCiphertext =
184 jv[jss::Account] = bob.human();
185 jv[jss::TransactionType] = jss::ConfidentialMPTConvert;
186 jv[sfMPTokenIssuanceID] =
to_string(mptAlice.issuanceID());
188 jv[sfHolderEncryptedAmount.jsonName] =
strHex(holderCiphertext);
189 jv[sfIssuerEncryptedAmount.jsonName] =
strHex(issuerCiphertext);
190 jv[sfBlindingFactor.jsonName] =
strHex(blindingFactor);
195 env.require(MptBalance(mptAlice, bob, 0));
263 Env env{*
this, features};
265 MPTTester mptAlice(env, alice);
268 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
270 mptAlice.generateKeyPair(alice);
275 .holderPubKey = mptAlice.getPubKey(alice),
281 Env env{*
this, features - featureConfidentialTransfer};
284 MPTTester mptAlice(env, alice, {.holders = {bob}});
288 .flags = tfMPTCanTransfer | tfMPTCanLock,
294 mptAlice.pay(alice, bob, 100);
296 mptAlice.generateKeyPair(alice);
297 mptAlice.generateKeyPair(bob);
301 .issuerPubKey = mptAlice.getPubKey(alice),
308 .holderPubKey = mptAlice.getPubKey(bob),
314 Env env{*
this, features};
317 MPTTester mptAlice(env, alice, {.holders = {bob}});
321 .flags = tfMPTCanTransfer | tfMPTCanLock,
327 mptAlice.pay(alice, bob, 100);
329 mptAlice.generateKeyPair(alice);
330 mptAlice.generateKeyPair(bob);
335 .holderPubKey = mptAlice.getPubKey(bob),
343 .holderPubKey = mptAlice.getPubKey(bob),
344 .holderEncryptedAmt =
Buffer{},
352 .holderPubKey = mptAlice.getPubKey(bob),
353 .issuerEncryptedAmt =
Buffer{},
361 .holderPubKey = mptAlice.getPubKey(bob),
362 .auditorEncryptedAmt = gMakeZeroBuffer(10),
370 .holderPubKey = mptAlice.getPubKey(bob),
379 .holderPubKey = mptAlice.getPubKey(bob),
387 .holderPubKey = mptAlice.getPubKey(bob),
397 .holderPubKey = mptAlice.getPubKey(bob),
422 Env env{*
this, features};
425 MPTTester mptAlice(env, alice, {.holders = {bob}});
429 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
435 mptAlice.pay(alice, bob, 100);
437 mptAlice.generateKeyPair(alice);
438 mptAlice.generateKeyPair(bob);
440 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
445 .fillSchnorrProof =
false,
446 .holderPubKey = mptAlice.getPubKey(bob),
453 .fillSchnorrProof =
false,
454 .holderPubKey = mptAlice.getPubKey(bob),
463 .holderPubKey = mptAlice.getPubKey(bob),
471 Env env{*
this, features};
474 MPTTester mptAlice(env, alice, {.holders = {bob}});
478 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
484 mptAlice.pay(alice, bob, 100);
486 mptAlice.generateKeyPair(alice);
487 mptAlice.generateKeyPair(bob);
489 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
496 .holderPubKey = mptAlice.getPubKey(bob),
503 .fillSchnorrProof =
true,
772 Env env{*
this, features};
774 MPTTester mptAlice(env, alice, {.holders = {}});
778 .flags = tfMPTCanTransfer | tfMPTCanLock,
781 mptAlice.generateKeyPair(alice);
785 .issuerPubKey = mptAlice.getPubKey(alice),
792 Env env{*
this, features};
795 MPTTester mptAlice(env, alice, {.holders = {bob}});
799 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
802 mptAlice.generateKeyPair(alice);
803 mptAlice.generateKeyPair(bob);
808 .issuerPubKey = mptAlice.getPubKey(alice),
814 .issuerPubKey = mptAlice.getPubKey(bob),
823 Env env{*
this, features};
826 Account const auditor(
"auditor");
827 MPTTester mptAlice(env, alice, {.holders = {bob}, .auditor = auditor});
831 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
834 mptAlice.generateKeyPair(alice);
835 mptAlice.generateKeyPair(bob);
836 mptAlice.generateKeyPair(auditor);
841 .issuerPubKey = mptAlice.getPubKey(alice),
842 .auditorPubKey = mptAlice.getPubKey(auditor),
848 .issuerPubKey = mptAlice.getPubKey(bob),
849 .auditorPubKey = mptAlice.getPubKey(alice),
856 Env env{*
this, features};
858 Account const auditor(
"auditor");
859 MPTTester mptAlice(env, alice, {.holders = {}, .auditor = auditor});
863 .flags = tfMPTCanTransfer | tfMPTCanLock,
866 mptAlice.generateKeyPair(alice);
867 mptAlice.generateKeyPair(auditor);
871 .issuerPubKey = mptAlice.getPubKey(alice),
872 .auditorPubKey = mptAlice.getPubKey(auditor),
879 Env env{*
this, features};
881 MPTTester mptAlice(env, alice, {.holders = {}});
886 .flags = tfMPTCanTransfer | tfMPTCanLock,
890 mptAlice.generateKeyPair(alice);
896 .flags = tfMPTSetCanHoldConfidentialBalance,
897 .issuerPubKey = mptAlice.getPubKey(alice),
904 Env env{*
this, features};
906 Account const auditor(
"auditor");
907 MPTTester mptAlice(env, alice, {.holders = {}, .auditor = auditor});
911 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
914 mptAlice.generateKeyPair(alice);
915 mptAlice.generateKeyPair(auditor);
920 .issuerPubKey = mptAlice.getPubKey(alice),
928 .issuerPubKey = mptAlice.getPubKey(alice),
929 .auditorPubKey = mptAlice.getPubKey(auditor),
1028 Env env{*
this, features};
1031 MPTTester mptAlice(env, alice, {.holders = {bob}});
1035 .flags = tfMPTCanTransfer | tfMPTCanLock,
1038 mptAlice.authorize({
1041 mptAlice.pay(alice, bob, 100);
1043 mptAlice.generateKeyPair(alice);
1044 mptAlice.generateKeyPair(bob);
1049 .holderPubKey = mptAlice.getPubKey(bob),
1056 Env env{*
this, features};
1059 MPTTester mptAlice(env, alice, {.holders = {bob}});
1063 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1066 mptAlice.authorize({
1069 mptAlice.pay(alice, bob, 100);
1071 mptAlice.generateKeyPair(alice);
1072 mptAlice.generateKeyPair(bob);
1077 .holderPubKey = mptAlice.getPubKey(bob),
1084 Env env{*
this, features};
1087 MPTTester mptAlice(env, alice, {.holders = {bob}});
1091 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1094 mptAlice.authorize({
1097 mptAlice.generateKeyPair(alice);
1099 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1102 mptAlice.generateKeyPair(bob);
1107 .holderPubKey = mptAlice.getPubKey(bob),
1114 Env env{*
this, features};
1117 MPTTester mptAlice(env, alice, {.holders = {bob}});
1121 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1124 mptAlice.generateKeyPair(alice);
1125 mptAlice.generateKeyPair(bob);
1127 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1132 .holderPubKey = mptAlice.getPubKey(bob),
1139 Env env{*
this, features};
1143 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
1147 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1150 mptAlice.authorize({
1153 mptAlice.pay(alice, bob, 100);
1155 mptAlice.generateKeyPair(alice);
1156 mptAlice.generateKeyPair(bob);
1157 mptAlice.generateKeyPair(carol);
1159 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1164 .holderPubKey = mptAlice.getPubKey(bob),
1172 .holderPubKey = mptAlice.getPubKey(bob),
1179 Buffer const holderCiphertext = mptAlice.encryptAmount(bob, amount, blindingFactor);
1184 Buffer const wrongIssuerCiphertext =
1185 mptAlice.encryptAmount(carol, amount, blindingFactor);
1190 .holderPubKey = mptAlice.getPubKey(bob),
1191 .holderEncryptedAmt = holderCiphertext,
1192 .issuerEncryptedAmt = wrongIssuerCiphertext,
1193 .blindingFactor = blindingFactor,
1200 Env env{*
this, features};
1203 MPTTester mptAlice(env, alice, {.holders = {bob}});
1207 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1210 mptAlice.authorize({
1213 mptAlice.pay(alice, bob, 100);
1215 mptAlice.generateKeyPair(alice);
1217 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1219 mptAlice.generateKeyPair(bob);
1224 .holderPubKey = mptAlice.getPubKey(bob),
1231 Env env{*
this, features};
1234 MPTTester mptAlice(env, alice, {.holders = {bob}});
1238 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1241 mptAlice.authorize({
1244 mptAlice.pay(alice, bob, 100);
1246 mptAlice.generateKeyPair(alice);
1248 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1250 mptAlice.generateKeyPair(bob);
1252 mptAlice.convert({.account = bob, .amt = 10, .holderPubKey = mptAlice.getPubKey(bob)});
1258 .holderPubKey = mptAlice.getPubKey(bob),
1265 Env env{*
this, features};
1268 MPTTester mptAlice(env, alice, {.holders = {bob}});
1272 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1275 mptAlice.authorize({
1278 mptAlice.pay(alice, bob, 100);
1280 mptAlice.generateKeyPair(alice);
1282 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1290 mptAlice.generateKeyPair(bob);
1295 .holderPubKey = mptAlice.getPubKey(bob),
1302 .flags = tfMPTUnlock,
1308 .holderPubKey = mptAlice.getPubKey(bob),
1314 Env env{*
this, features};
1317 MPTTester mptAlice(env, alice, {.holders = {bob}});
1321 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth |
1322 tfMPTCanHoldConfidentialBalance,
1325 mptAlice.authorize({
1328 mptAlice.authorize({
1332 mptAlice.pay(alice, bob, 100);
1334 mptAlice.generateKeyPair(alice);
1336 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1338 mptAlice.generateKeyPair(bob);
1341 mptAlice.authorize({
1344 .flags = tfMPTUnauthorize,
1350 .holderPubKey = mptAlice.getPubKey(bob),
1355 mptAlice.authorize({
1363 .holderPubKey = mptAlice.getPubKey(bob),
1369 Env env{*
this, features};
1372 MPTTester mptAlice(env, alice, {.holders = {bob}});
1376 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1379 mptAlice.authorize({
1382 mptAlice.pay(alice, bob, 100);
1384 mptAlice.generateKeyPair(alice);
1386 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1395 mptAlice.generateKeyPair(bob);
1401 .holderPubKey = mptAlice.getPubKey(bob),
1408 Env env{*
this, features};
1411 MPTTester mptAlice(env, alice, {.holders = {bob}});
1415 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth |
1416 tfMPTCanHoldConfidentialBalance,
1419 mptAlice.authorize({
1422 mptAlice.authorize({
1426 mptAlice.pay(alice, bob, 100);
1428 mptAlice.generateKeyPair(alice);
1430 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1432 mptAlice.generateKeyPair(bob);
1435 mptAlice.authorize({
1438 .flags = tfMPTUnauthorize,
1445 .holderPubKey = mptAlice.getPubKey(bob),
1453 Env env{*
this, features};
1456 Account const auditor(
"auditor");
1467 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1470 mptAlice.authorize({
1473 mptAlice.pay(alice, bob, 100);
1475 mptAlice.generateKeyPair(alice);
1476 mptAlice.generateKeyPair(bob);
1477 mptAlice.generateKeyPair(auditor);
1481 .issuerPubKey = mptAlice.getPubKey(alice),
1482 .auditorPubKey = mptAlice.getPubKey(auditor)});
1488 .fillAuditorEncryptedAmt =
false,
1489 .holderPubKey = mptAlice.getPubKey(bob),
1497 Env env{*
this, features};
1500 MPTTester mptAlice(env, alice, {.holders = {bob}});
1504 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1507 mptAlice.authorize({
1510 mptAlice.pay(alice, bob, 100);
1512 mptAlice.generateKeyPair(alice);
1513 mptAlice.generateKeyPair(bob);
1516 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1521 .holderPubKey = mptAlice.getPubKey(bob),
1530 Env env{*
this, features};
1533 Account const auditor(
"auditor");
1543 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1546 mptAlice.authorize({
1549 mptAlice.pay(alice, bob, 100);
1551 mptAlice.generateKeyPair(alice);
1552 mptAlice.generateKeyPair(bob);
1553 mptAlice.generateKeyPair(auditor);
1557 .issuerPubKey = mptAlice.getPubKey(alice),
1558 .auditorPubKey = mptAlice.getPubKey(auditor)});
1563 .holderPubKey = mptAlice.getPubKey(bob),
1571 Env env{*
this, features};
1574 MPTTester mptAlice(env, alice, {.holders = {bob}});
1578 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1581 mptAlice.authorize({
1584 mptAlice.pay(alice, bob, 100);
1586 mptAlice.generateKeyPair(alice);
1587 mptAlice.generateKeyPair(bob);
1589 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1595 .holderPubKey = mptAlice.getPubKey(bob),
1602 Env env{*
this, features};
1605 MPTTester mptAlice(env, alice, {.holders = {bob}});
1609 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1612 mptAlice.authorize({
1615 mptAlice.pay(alice, bob, 100);
1617 mptAlice.generateKeyPair(alice);
1618 mptAlice.generateKeyPair(bob);
1620 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1632 Env env{*
this, features};
1635 MPTTester mptAlice(env, alice, {.holders = {bob}});
1639 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1642 mptAlice.authorize({
1645 mptAlice.pay(alice, bob, 100);
1647 mptAlice.generateKeyPair(alice);
1649 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1651 mptAlice.generateKeyPair(bob);
1657 .holderPubKey = mptAlice.getPubKey(bob),
1660 env.require(MptBalance(mptAlice, bob, 0));
1813 Env env{*
this, features};
1816 MPTTester mptAlice(env, alice, {.holders = {bob}});
1820 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1823 mptAlice.authorize({
1826 mptAlice.generateKeyPair(alice);
1828 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1831 mptAlice.generateKeyPair(bob);
1833 mptAlice.mergeInbox({
1841 Env env{*
this, features};
1844 MPTTester mptAlice(env, alice, {.holders = {bob}});
1848 .flags = tfMPTCanTransfer | tfMPTCanLock,
1851 mptAlice.authorize({
1854 mptAlice.pay(alice, bob, 100);
1856 mptAlice.generateKeyPair(alice);
1857 mptAlice.generateKeyPair(bob);
1859 mptAlice.mergeInbox({
1867 Env env{*
this, features};
1870 MPTTester mptAlice(env, alice, {.holders = {bob}});
1874 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1877 mptAlice.generateKeyPair(alice);
1879 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1881 mptAlice.mergeInbox({
1889 Env env{*
this, features};
1892 MPTTester mptAlice(env, alice, {.holders = {bob}});
1896 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1899 mptAlice.authorize({
1902 mptAlice.pay(alice, bob, 100);
1904 mptAlice.generateKeyPair(alice);
1906 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1908 mptAlice.generateKeyPair(bob);
1910 mptAlice.mergeInbox({
1918 Env env{*
this, features};
1921 MPTTester mptAlice(env, alice, {.holders = {bob}});
1925 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
1928 mptAlice.authorize({
1931 mptAlice.pay(alice, bob, 100);
1933 mptAlice.generateKeyPair(alice);
1934 mptAlice.generateKeyPair(bob);
1936 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1941 .holderPubKey = mptAlice.getPubKey(bob),
1951 mptAlice.mergeInbox({
1960 .flags = tfMPTUnlock,
1964 mptAlice.mergeInbox({
1971 Env env{*
this, features};
1974 MPTTester mptAlice(env, alice, {.holders = {bob}});
1978 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance |
1982 mptAlice.authorize({
1985 mptAlice.authorize({
1989 mptAlice.pay(alice, bob, 100);
1991 mptAlice.generateKeyPair(alice);
1992 mptAlice.generateKeyPair(bob);
1994 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
1999 .holderPubKey = mptAlice.getPubKey(bob),
2003 mptAlice.authorize({
2006 .flags = tfMPTUnauthorize,
2009 mptAlice.mergeInbox({
2015 mptAlice.authorize({
2021 mptAlice.mergeInbox({
2115 testcase(
"test ConfidentialMPTSend Preflight");
2120 Env env{*
this, features - featureConfidentialTransfer};
2124 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
2127 mptAlice.authorize({
2130 mptAlice.authorize({
2147 Env env{*
this, features};
2151 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
2155 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
2158 mptAlice.authorize({
2161 mptAlice.authorize({
2164 mptAlice.generateKeyPair(alice);
2165 mptAlice.generateKeyPair(bob);
2166 mptAlice.generateKeyPair(carol);
2167 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
2168 mptAlice.pay(alice, bob, 100);
2169 mptAlice.pay(alice, carol, 50);
2174 .holderPubKey = mptAlice.getPubKey(bob),
2180 .holderPubKey = mptAlice.getPubKey(carol),
2212 .senderEncryptedAmt = gMakeZeroBuffer(10),
2221 .destEncryptedAmt = gMakeZeroBuffer(10),
2230 .issuerEncryptedAmt = gMakeZeroBuffer(10),
2287 .amountCommitment = gMakeZeroBuffer(100),
2299 .balanceCommitment = gMakeZeroBuffer(100),
2328 Env env{*
this, features};
2332 Account const auditor(
"auditor");
2337 .holders = {bob, carol},
2343 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
2346 mptAlice.authorize({
2349 mptAlice.authorize({
2352 mptAlice.generateKeyPair(alice);
2353 mptAlice.generateKeyPair(bob);
2354 mptAlice.generateKeyPair(carol);
2355 mptAlice.generateKeyPair(auditor);
2359 .issuerPubKey = mptAlice.getPubKey(alice),
2360 .auditorPubKey = mptAlice.getPubKey(auditor)});
2361 mptAlice.pay(alice, bob, 100);
2362 mptAlice.pay(alice, carol, 50);
2367 .holderPubKey = mptAlice.getPubKey(bob),
2373 .holderPubKey = mptAlice.getPubKey(carol),
2382 .auditorEncryptedAmt = gMakeZeroBuffer(10),
2405 testcase(
"test ConfidentialMPTSend Preclaim");
2408 Env env{*
this, features};
2414 MPTTester mptAlice(env, alice, {.holders = {bob, carol, dave, eve}});
2418 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth |
2419 tfMPTCanHoldConfidentialBalance,
2421 mptAlice.authorize({
2424 mptAlice.authorize({
2428 mptAlice.authorize({
2431 mptAlice.authorize({
2435 mptAlice.authorize({
2438 mptAlice.authorize({
2444 mptAlice.pay(alice, bob, 100);
2445 mptAlice.pay(alice, carol, 50);
2447 mptAlice.generateKeyPair(alice);
2448 mptAlice.generateKeyPair(bob);
2449 mptAlice.generateKeyPair(carol);
2450 mptAlice.generateKeyPair(dave);
2451 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
2457 .holderPubKey = mptAlice.getPubKey(bob),
2463 .holderPubKey = mptAlice.getPubKey(carol),
2468 mptAlice.mergeInbox({
2471 mptAlice.mergeInbox({
2477 Env env{*
this, features};
2481 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
2484 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
2486 mptAlice.authorize({
2489 mptAlice.authorize({
2492 mptAlice.generateKeyPair(alice);
2493 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
2499 jv[jss::Account] = bob.human();
2500 jv[jss::Destination] = carol.human();
2501 jv[jss::TransactionType] = jss::ConfidentialMPTSend;
2502 jv[sfMPTokenIssuanceID] =
to_string(mptAlice.issuanceID());
2515 Account const unknown(
"unknown");
2532 env(fset(carol, asfRequireDest));
2548 env(fclear(carol, asfRequireDest));
2612 .flags = tfMPTUnlock,
2640 .flags = tfMPTUnlock,
2668 .flags = tfMPTUnlock,
2681 mptAlice.authorize({
2684 .flags = tfMPTUnauthorize,
2693 mptAlice.authorize({
2708 mptAlice.authorize({
2711 .flags = tfMPTUnauthorize,
2720 mptAlice.authorize({
2734 Env env{*
this, features};
2741 {{.account = bob, .payAmount = 100, .convertAmount = 60},
2742 {.account = carol, .payAmount = 50, .convertAmount = 20}},
2743 tfMPTCanLock | tfMPTCanHoldConfidentialBalance};
2744 auto& mptAlice = confEnv.
mpt;
2758 Env env{*
this, features};
2765 {{.account = bob, .payAmount = 100, .convertAmount = 60},
2766 {.account = carol, .payAmount = 50, .convertAmount = 20}}};
2767 auto& mptAlice = confEnv.
mpt;
2770 auto const issuance = std::const_pointer_cast<SLE>(
2771 view.read(keylet::mptokenIssuance(mptAlice.issuanceID())));
2775 issuance->setFieldU16(sfTransferFee, 1);
2776 view.rawReplace(issuance);
2791 Env env{*
this, features};
2798 {{.account = bob, .payAmount = 100, .convertAmount = 60},
2799 {.account = carol, .payAmount = 50, .convertAmount = 20}}};
2800 auto& mptAlice = confEnv.
mpt;
2825 Env env{*
this, features};
2829 Account const auditor(
"auditor");
2834 .holders = {bob, carol},
2840 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
2843 mptAlice.authorize({
2846 mptAlice.authorize({
2849 mptAlice.generateKeyPair(alice);
2850 mptAlice.generateKeyPair(bob);
2851 mptAlice.generateKeyPair(carol);
2852 mptAlice.generateKeyPair(auditor);
2856 .issuerPubKey = mptAlice.getPubKey(alice),
2857 .auditorPubKey = mptAlice.getPubKey(auditor)});
2858 mptAlice.pay(alice, bob, 100);
2859 mptAlice.pay(alice, carol, 50);
2864 .holderPubKey = mptAlice.getPubKey(bob),
2870 .holderPubKey = mptAlice.getPubKey(carol),
3082 Env env{*
this, features};
3085 MPTTester mptAlice(env, alice, {.holders = {bob}});
3089 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
3092 mptAlice.authorize({
3095 mptAlice.pay(alice, bob, 100);
3097 mptAlice.generateKeyPair(alice);
3099 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
3101 mptAlice.generateKeyPair(bob);
3106 .holderPubKey = mptAlice.getPubKey(bob),
3109 mptAlice.authorize({
3111 .flags = tfMPTUnauthorize,
3118 Env env{*
this, features};
3122 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
3126 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
3129 mptAlice.authorize({
3132 mptAlice.authorize({
3135 mptAlice.pay(alice, bob, 100);
3137 mptAlice.generateKeyPair(alice);
3139 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
3141 mptAlice.generateKeyPair(bob);
3142 mptAlice.generateKeyPair(carol);
3147 .holderPubKey = mptAlice.getPubKey(bob),
3153 .holderPubKey = mptAlice.getPubKey(carol),
3157 mptAlice.authorize({
3159 .flags = tfMPTUnauthorize,
3166 Env env{*
this, features};
3169 MPTTester mptAlice(env, alice, {.holders = {bob}});
3173 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
3176 mptAlice.authorize({
3179 mptAlice.generateKeyPair(alice);
3181 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
3183 mptAlice.generateKeyPair(bob);
3188 .holderPubKey = mptAlice.getPubKey(bob),
3191 mptAlice.authorize({
3193 .flags = tfMPTUnauthorize,
3200 Env env{*
this, features};
3203 MPTTester mptAlice(env, alice, {.holders = {bob}});
3207 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
3210 mptAlice.authorize({
3213 mptAlice.generateKeyPair(alice);
3215 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
3217 mptAlice.generateKeyPair(bob);
3222 .holderPubKey = mptAlice.getPubKey(bob),
3227 mptAlice.authorize({
3229 .flags = tfMPTUnauthorize,
3235 Env env{*
this, features};
3239 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 100}}};
3240 auto& mptAlice = confEnv.
mpt;
3247 mptAlice.pay(bob, alice, 100);
3250 mptAlice.authorize({
3252 .flags = tfMPTUnauthorize,
3259 Env env{*
this, features | featureSingleAssetVault};
3260 Account const issuer(
"issuer");
3262 Account const depositor(
"depositor");
3264 MPTTester mptt{env, issuer, {.holders = {owner, depositor}}};
3266 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback,
3268 PrettyAsset
const asset = mptt.issuanceID();
3269 mptt.authorize({.account = owner});
3270 mptt.authorize({.account = depositor});
3271 env(pay(issuer, depositor, asset(1000)));
3275 auto [tx, vaultKeylet] = vault.create({.owner = owner, .asset = asset});
3280 auto const vaultSle = env.le(vaultKeylet);
3281 BEAST_EXPECT(vaultSle !=
nullptr);
3282 auto const share = vaultSle->at(sfShareMPTID);
3286 {.depositor = depositor, .id = vaultKeylet.key, .amount = asset(100)});
3292 BEAST_EXPECT(shareMpt !=
nullptr);
3304 issuance->setFlag(lsfMPTCanHoldConfidentialBalance);
3318 sle->setFieldVL(sfConfidentialBalanceSpending, dummyCiphertext);
3319 sle->setFieldVL(sfConfidentialBalanceInbox, dummyCiphertext);
3320 sle->setFieldVL(sfIssuerEncryptedBalance, dummyCiphertext);
3326 tx = vault.withdraw(
3327 {.depositor = depositor, .id = vaultKeylet.key, .amount = asset(100)});
3333 BEAST_EXPECT(shareMpt !=
nullptr);
3345 Env env{*
this, features};
3349 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 40}}};
3350 auto& mptAlice = confEnv.
mpt;
3357 mptAlice.convertBack({
3365 Env env{*
this, features};
3369 env, alice, {{.account = bob, .payAmount = 2, .convertAmount = 2}}};
3370 auto& mptAlice = confEnv.
mpt;
3384 Env env{*
this, features};
3387 MPTTester mptAlice(env, alice, {.holders = {bob}});
3391 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
3394 mptAlice.authorize({
3399 mptAlice.generateKeyPair(alice);
3400 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
3402 mptAlice.generateKeyPair(bob);
3406 auto const convertHolderCiphertext =
3408 auto const convertIssuerCiphertext =
3410 auto const convertContextHash =
3413 mptAlice.getSchnorrProof(bob, convertContextHash),
"Missing schnorr proof");
3417 jv[jss::Account] = bob.human();
3418 jv[jss::TransactionType] = jss::ConfidentialMPTConvert;
3419 jv[sfMPTokenIssuanceID] =
to_string(mptAlice.issuanceID());
3421 jv[sfHolderEncryptionKey.jsonName] =
3423 jv[sfHolderEncryptedAmount.jsonName] =
strHex(convertHolderCiphertext);
3424 jv[sfIssuerEncryptedAmount.jsonName] =
strHex(convertIssuerCiphertext);
3425 jv[sfBlindingFactor.jsonName] =
strHex(convertBlindingFactor);
3426 jv[sfZKProof.jsonName] =
strHex(schnorrProof);
3434 jv[jss::Account] = bob.human();
3435 jv[jss::TransactionType] = jss::ConfidentialMPTMergeInbox;
3436 jv[sfMPTokenIssuanceID] =
to_string(mptAlice.issuanceID());
3447 auto const convertBackHolderCiphertext =
3448 mptAlice.encryptAmount(bob, convertBackAmt, convertBackBlindingFactor);
3449 auto const convertBackIssuerCiphertext =
3450 mptAlice.encryptAmount(alice, convertBackAmt, convertBackBlindingFactor);
3454 mptAlice.getEncryptedBalance(bob, MPTTester::holderEncryptedSpending),
3455 "Missing encrypted spending balance");
3459 Buffer const pedersenCommitment =
3463 auto const version = mptAlice.getMPTokenVersion(bob);
3464 uint256 const convertBackContextHash =
3467 Buffer const proof = mptAlice.getConvertBackProof(
3470 convertBackContextHash,
3472 .pedersenCommitment = pedersenCommitment,
3474 .encryptedAmt = encryptedSpendingBalance,
3475 .blindingFactor = pcBlindingFactor,
3480 jv[jss::Account] = bob.human();
3481 jv[jss::TransactionType] = jss::ConfidentialMPTConvertBack;
3482 jv[sfMPTokenIssuanceID] =
to_string(mptAlice.issuanceID());
3484 jv[sfHolderEncryptedAmount.jsonName] =
strHex(convertBackHolderCiphertext);
3485 jv[sfIssuerEncryptedAmount.jsonName] =
strHex(convertBackIssuerCiphertext);
3486 jv[sfBlindingFactor.jsonName] =
strHex(convertBackBlindingFactor);
3487 jv[sfBalanceCommitment.jsonName] =
strHex(pedersenCommitment);
3488 jv[sfZKProof.jsonName] =
strHex(proof);
3494 env.require(MptBalance(mptAlice, bob, convertBackAmt));
3655 Env env{*
this, features};
3658 MPTTester mptAlice(env, alice, {.holders = {bob}});
3662 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
3665 mptAlice.authorize({
3668 mptAlice.generateKeyPair(alice);
3670 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
3673 mptAlice.generateKeyPair(bob);
3675 mptAlice.convertBack({
3684 Env env{*
this, features};
3687 MPTTester mptAlice(env, alice, {.holders = {bob}});
3691 .flags = tfMPTCanTransfer | tfMPTCanLock,
3694 mptAlice.authorize({
3697 mptAlice.pay(alice, bob, 100);
3699 mptAlice.generateKeyPair(alice);
3700 mptAlice.generateKeyPair(bob);
3702 mptAlice.convertBack({
3711 Env env{*
this, features};
3714 MPTTester mptAlice(env, alice, {.holders = {bob}});
3718 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
3721 mptAlice.generateKeyPair(alice);
3722 mptAlice.generateKeyPair(bob);
3724 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
3726 mptAlice.convertBack({
3735 Env env{*
this, features};
3738 MPTTester mptAlice(env, alice, {.holders = {bob}});
3742 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
3745 mptAlice.authorize({
3749 mptAlice.pay(alice, bob, 100);
3750 mptAlice.generateKeyPair(alice);
3751 mptAlice.generateKeyPair(bob);
3752 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
3755 auto const sleBobMpt = env.le(
keylet::mptoken(mptAlice.issuanceID(), bob.id()));
3756 BEAST_EXPECT(sleBobMpt);
3757 BEAST_EXPECT(!sleBobMpt->isFieldPresent(sfHolderEncryptionKey));
3758 BEAST_EXPECT(!sleBobMpt->isFieldPresent(sfConfidentialBalanceSpending));
3759 BEAST_EXPECT(!sleBobMpt->isFieldPresent(sfIssuerEncryptedBalance));
3761 mptAlice.convertBack({
3770 Env env{*
this, features};
3774 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
3778 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
3781 mptAlice.authorize({
3784 mptAlice.authorize({
3787 mptAlice.pay(alice, bob, 100);
3788 mptAlice.pay(alice, carol, 100);
3790 mptAlice.generateKeyPair(alice);
3792 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
3794 mptAlice.generateKeyPair(bob);
3795 mptAlice.generateKeyPair(carol);
3800 .holderPubKey = mptAlice.getPubKey(bob),
3803 mptAlice.mergeInbox({
3810 .holderPubKey = mptAlice.getPubKey(carol),
3813 mptAlice.convertBack({
3822 Env env{*
this, features};
3825 MPTTester mptAlice(env, alice, {.holders = {bob}});
3829 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTRequireAuth |
3830 tfMPTCanHoldConfidentialBalance,
3833 mptAlice.authorize({
3836 mptAlice.authorize({
3840 mptAlice.pay(alice, bob, 100);
3842 mptAlice.generateKeyPair(alice);
3844 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
3846 mptAlice.generateKeyPair(bob);
3851 .holderPubKey = mptAlice.getPubKey(bob),
3854 mptAlice.mergeInbox({
3864 mptAlice.convertBack({
3873 .flags = tfMPTUnlock,
3876 mptAlice.convertBack({
3881 mptAlice.authorize({
3884 .flags = tfMPTUnauthorize,
3887 mptAlice.convertBack({
3893 mptAlice.authorize({
3898 mptAlice.convertBack({
3906 Env env{*
this, features};
3910 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 50}}};
3911 auto& mptAlice = confEnv.
mpt;
3924 mptAlice.convertBack({
3935 Env env{*
this, features};
3939 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 50}}};
3940 auto& mptAlice = confEnv.
mpt;
3953 Env env{*
this, features};
3956 Account const auditor(
"auditor");
3960 {{.account = bob, .payAmount = 100, .convertAmount = 50}},
3961 tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
3963 auto& mptAlice = confEnv.
mpt;
3969 .fillAuditorEncryptedAmt =
false,
3975 mptAlice.convertBack({
3987 testcase(
"test ConfidentialMPTClawback");
3990 Env env{*
this, features};
3995 MPTTester mptAlice(env, alice, {.holders = {bob, carol, dave}});
3998 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanClawback |
3999 tfMPTCanHoldConfidentialBalance,
4001 mptAlice.authorize({
4004 mptAlice.pay(alice, bob, 100);
4005 mptAlice.authorize({
4008 mptAlice.pay(alice, carol, 200);
4009 mptAlice.authorize({
4012 mptAlice.pay(alice, dave, 300);
4014 mptAlice.generateKeyPair(alice);
4015 mptAlice.generateKeyPair(bob);
4016 mptAlice.generateKeyPair(carol);
4017 mptAlice.generateKeyPair(dave);
4018 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
4024 mptAlice.convert({.account = bob, .amt = 60, .holderPubKey = mptAlice.getPubKey(bob)});
4027 mptAlice.mergeInbox({
4037 {.account = carol, .amt = 120, .holderPubKey = mptAlice.getPubKey(carol)});
4040 mptAlice.mergeInbox({
4048 mptAlice.convert({.account = dave, .amt = 200, .holderPubKey = mptAlice.getPubKey(dave)});
4062 auto const preBobPublicBalance = mptAlice.getBalance(bob);
4063 auto const preOutstandingAmount = mptAlice.getIssuanceOutstandingBalance();
4064 auto const preConfidentialOutstandingAmount = mptAlice.getIssuanceConfidentialBalance();
4065 BEAST_EXPECT(!env.le(
keylet::mptoken(mptAlice.issuanceID(), alice.id())));
4071 mptAlice.confidentialClaw({
4076 BEAST_EXPECT(mptAlice.getBalance(bob) == preBobPublicBalance);
4077 auto const postOutstandingAmount = mptAlice.getIssuanceOutstandingBalance();
4079 preOutstandingAmount && postOutstandingAmount &&
4080 *postOutstandingAmount == *preOutstandingAmount - 110);
4082 mptAlice.getIssuanceConfidentialBalance() == preConfidentialOutstandingAmount - 110);
4083 BEAST_EXPECT(!env.le(
keylet::mptoken(mptAlice.issuanceID(), alice.id())));
4087 mptAlice.confidentialClaw({
4095 mptAlice.confidentialClaw({
4409 testcase(
"Clawback Preclaim Errors");
4416 Env env{*
this, features};
4421 MPTTester mptAlice(env, alice, {.holders = {bob, carol, dave}});
4424 .flags = tfMPTCanTransfer | tfMPTCanClawback | tfMPTRequireAuth |
4425 tfMPTCanHoldConfidentialBalance,
4427 mptAlice.authorize({
4430 mptAlice.authorize({
4434 mptAlice.authorize({
4437 mptAlice.authorize({
4442 mptAlice.pay(alice, bob, 100);
4443 mptAlice.pay(alice, carol, 50);
4444 mptAlice.generateKeyPair(alice);
4445 mptAlice.generateKeyPair(bob);
4446 mptAlice.generateKeyPair(carol);
4447 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
4452 .holderPubKey = mptAlice.getPubKey(bob),
4454 mptAlice.mergeInbox({
4460 Account const unknown(
"unknown");
4461 mptAlice.confidentialClaw({
4471 mptAlice.confidentialClaw({
4481 mptAlice.confidentialClaw({
4492 Env env{*
this, features};
4495 MPTTester mptAlice(env, alice, {.holders = {bob}});
4498 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
4500 mptAlice.authorize({
4503 mptAlice.generateKeyPair(alice);
4504 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
4506 mptAlice.confidentialClaw({
4516 Env env{*
this, features};
4519 MPTTester mptAlice(env, alice, {.holders = {bob}});
4521 .flags = tfMPTCanClawback | tfMPTCanHoldConfidentialBalance,
4523 mptAlice.authorize({
4526 mptAlice.generateKeyPair(alice);
4528 mptAlice.confidentialClaw({
4538 Env env{*
this, features};
4541 MPTTester mptAlice(env, alice, {.holders = {bob}});
4543 .flags = tfMPTCanClawback | tfMPTCanHoldConfidentialBalance,
4545 mptAlice.authorize({
4548 mptAlice.generateKeyPair(alice);
4549 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
4555 jv[jss::Account] = alice.human();
4556 jv[sfHolder] = bob.human();
4557 jv[jss::TransactionType] = jss::ConfidentialMPTClawback;
4560 jv[sfZKProof] = dummyProof;
4561 jv[sfMPTokenIssuanceID] =
to_string(mptAlice.issuanceID());
4567 std::uint32_t const setupFlags = tfMPTCanTransfer | tfMPTCanClawback | tfMPTRequireAuth |
4568 tfMPTCanLock | tfMPTCanHoldConfidentialBalance;
4571 auto removeMPTokenField =
4572 [&](Env& env, MPTTester
const& mpt,
Account const& holder,
SField const& field) {
4574 auto const sle = std::const_pointer_cast<SLE>(
4575 view.read(keylet::mptoken(mpt.issuanceID(), holder.id())));
4579 sle->makeFieldAbsent(field);
4580 view.rawReplace(sle);
4589 Env env{*
this, features};
4593 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, setupFlags};
4594 auto& mptAlice = confEnv.
mpt;
4602 mptAlice.confidentialClaw({
4606 .proof = dummyClawbackProof,
4614 Env env{*
this, features};
4618 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, setupFlags};
4619 auto& mptAlice = confEnv.
mpt;
4621 removeMPTokenField(env, mptAlice, bob, sfIssuerEncryptedBalance);
4622 mptAlice.confidentialClaw({
4626 .proof = dummyClawbackProof,
4633 Env env{*
this, features};
4637 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, setupFlags};
4638 auto& mptAlice = confEnv.
mpt;
4640 removeMPTokenField(env, mptAlice, bob, sfHolderEncryptionKey);
4641 mptAlice.confidentialClaw({
4645 .proof = dummyClawbackProof,
4652 Env env{*
this, features};
4656 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, setupFlags};
4657 auto& mptAlice = confEnv.
mpt;
4665 mptAlice.confidentialClaw({
4674 Env env{*
this, features};
4678 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, setupFlags};
4679 auto& mptAlice = confEnv.
mpt;
4686 mptAlice.confidentialClaw({
4695 Env env{*
this, features};
4699 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, setupFlags};
4700 auto& mptAlice = confEnv.
mpt;
4706 .flags = tfMPTUnauthorize,
4709 mptAlice.confidentialClaw({
4719 Env env{*
this, features};
4723 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 60}}, setupFlags};
4724 auto& mptAlice = confEnv.
mpt;
4738 testcase(
"ConfidentialMPTClawback Proof");
4748 auto setupEnv = [&](Env& env) -> MPTTester {
4749 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
4752 .flags = tfMPTCanTransfer | tfMPTCanClawback | tfMPTCanHoldConfidentialBalance,
4755 for (
auto const& [acct, amt] : {
std::pair{bob, 1000}, {carol, 2000}})
4757 mptAlice.authorize({
4760 mptAlice.pay(alice, acct, amt);
4761 mptAlice.generateKeyPair(acct);
4764 mptAlice.generateKeyPair(alice);
4765 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
4772 auto checkBadProofs =
4774 for (
auto const badAmt : amts)
4776 mpt.confidentialClaw({
4790 Env env{*
this, features};
4791 auto mptAlice = setupEnv(env);
4794 mptAlice.convert({.account = bob, .amt = 500, .holderPubKey = mptAlice.getPubKey(bob)});
4795 mptAlice.mergeInbox({
4800 {.account = carol, .amt = 1000, .holderPubKey = mptAlice.getPubKey(carol)});
4836 mptAlice.confidentialClaw({
4841 mptAlice.confidentialClaw({
4855 Env env{*
this, features};
4856 auto mptAlice = setupEnv(env);
4858 mptAlice.convert({.account = bob, .amt = 300, .holderPubKey = mptAlice.getPubKey(bob)});
4859 mptAlice.mergeInbox({
4863 {.account = carol, .amt = 400, .holderPubKey = mptAlice.getPubKey(carol)});
4864 mptAlice.mergeInbox({
4911 mptAlice.confidentialClaw({
4916 mptAlice.confidentialClaw({
4928 Env env{*
this, features};
4929 auto mptAlice = setupEnv(env);
4931 mptAlice.convert({.account = bob, .amt = 500, .holderPubKey = mptAlice.getPubKey(bob)});
4932 mptAlice.mergeInbox({
4936 auto const privKey = mptAlice.getPrivKey(alice);
4937 if (!BEAST_EXPECT(privKey.has_value()))
4940 auto const proof = mptAlice.getClawbackProof(
4945 alice.id(), mptAlice.issuanceID(), env.seq(alice), bob.id()));
4946 if (!BEAST_EXPECT(proof.has_value()))
4952 auto const versionBefore = mptAlice.getMPTokenVersion(bob);
4953 mptAlice.mergeInbox({.account = bob});
4954 BEAST_EXPECT(mptAlice.getMPTokenVersion(bob) != versionBefore);
4957 mptAlice.confidentialClaw({
4969 testcase(
"Public transfers after clearing Confidential Flag");
4979 auto runPublicPayments = [&](MPTTester& mpt) {
4980 mpt.pay(bob, carol, 10);
4981 mpt.pay(carol, bob, 5);
4982 mpt.pay(alice, bob, 1);
4983 mpt.pay(carol, alice, 5);
4986 auto drainAndDeleteBobMPToken = [&](Env& env, MPTTester& mpt) {
4987 auto const bobBalance = mpt.getBalance(bob);
4988 BEAST_EXPECT(bobBalance > 0);
4990 mpt.pay(bob, alice, bobBalance);
4991 BEAST_EXPECT(mpt.getBalance(bob) == 0);
4993 mpt.authorize({.account = bob, .flags = tfMPTUnauthorize});
5000 Env env{*
this, features};
5004 {{.account = bob, .payAmount = 100, .convertAmount = 50}},
5005 tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance};
5007 env.fund(XRP(1'000), carol);
5009 ct.
mpt.
pay(alice, carol, 50);
5013 runPublicPayments(ct.
mpt);
5014 drainAndDeleteBobMPToken(env, ct.
mpt);
5019 Env env{*
this, features};
5020 Account const auditor(
"auditor");
5021 MPTTester mptAlice(env, alice, {.holders = {bob, carol}, .auditor = auditor});
5025 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
5028 mptAlice.authorize({.account = bob});
5029 mptAlice.authorize({.account = carol});
5030 mptAlice.pay(alice, bob, 100);
5031 mptAlice.pay(alice, carol, 50);
5033 mptAlice.generateKeyPair(alice);
5034 mptAlice.generateKeyPair(bob);
5035 mptAlice.generateKeyPair(auditor);
5038 .issuerPubKey = mptAlice.getPubKey(alice),
5039 .auditorPubKey = mptAlice.getPubKey(auditor)});
5044 .holderPubKey = mptAlice.getPubKey(bob),
5046 mptAlice.mergeInbox({.account = bob});
5047 mptAlice.convertBack({.account = bob, .amt = 50});
5049 runPublicPayments(mptAlice);
5050 drainAndDeleteBobMPToken(env, mptAlice);
5056 Env env{*
this, features};
5060 {{.account = bob, .payAmount = 100, .convertAmount = 50}},
5061 tfMPTCanTransfer | tfMPTCanClawback | tfMPTCanHoldConfidentialBalance};
5063 env.fund(XRP(1'000), carol);
5065 ct.
mpt.
pay(alice, carol, 50);
5069 runPublicPayments(ct.
mpt);
5070 drainAndDeleteBobMPToken(env, ct.
mpt);
5077 testcase(
"mutate lsfMPTCanHoldConfidentialBalance");
5083 Env env{*
this, features - featureDynamicMPT};
5086 MPTTester mptAlice(env, alice, {.holders = {bob}});
5098 Env env{*
this, features - featureConfidentialTransfer};
5101 MPTTester mptAlice(env, alice, {.holders = {bob}});
5113 Env env{*
this, features};
5116 MPTTester mptAlice(env, alice, {.holders = {bob}});
5120 .flags = tfMPTCanTransfer,
5126 .flags = tfMPTSetCanHoldConfidentialBalance,
5133 Env env{*
this, features};
5136 MPTTester mptAlice(env, alice, {.holders = {bob}});
5140 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
5144 mptAlice.authorize({
5147 mptAlice.pay(alice, bob, 100);
5149 mptAlice.generateKeyPair(alice);
5150 mptAlice.generateKeyPair(bob);
5151 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
5153 auto holderPubKeySet =
false;
5154 auto verifyToggle = [&](
TER expectedResult, uint64_t amt) {
5155 if (!holderPubKeySet)
5160 .holderPubKey = mptAlice.getPubKey(bob),
5161 .err = expectedResult,
5169 .err = expectedResult,
5175 holderPubKeySet =
true;
5176 mptAlice.mergeInbox({
5182 mptAlice.convertBack({
5193 .flags = tfMPTSetCanHoldConfidentialBalance,
5200 .flags = tfMPTSetCanHoldConfidentialBalance,
5208 Env env{*
this, features};
5211 MPTTester mptAlice(env, alice, {.holders = {bob}});
5217 .flags = tfMPTCanTransfer | tfMPTCanHoldConfidentialBalance,
5220 mptAlice.authorize({
5223 mptAlice.pay(alice, bob, 100);
5225 mptAlice.generateKeyPair(alice);
5226 mptAlice.generateKeyPair(bob);
5227 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
5230 mptAlice.convert({.account = bob, .amt = 50, .holderPubKey = mptAlice.getPubKey(bob)});
5236 .flags = tfMPTSetCanHoldConfidentialBalance,
5245 testcase(
"Convert back pedersen proof");
5248 Env env{*
this, features};
5252 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 40}}};
5253 auto& mptAlice = confEnv.
mpt;
5257 uint64_t
const amt = 10;
5262 mptAlice.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending),
5263 "Missing spending balance");
5265 mptAlice.getEncryptedBalance(bob, MPTTester::holderEncryptedSpending),
5266 "Missing encrypted spending balance");
5267 BEAST_EXPECT(!encryptedSpendingBalance.empty());
5269 Buffer const pedersenCommitment =
5270 mptAlice.getPedersenCommitment(spendingBalance, pcBlindingFactor);
5271 Buffer const issuerCiphertext = mptAlice.encryptAmount(alice, amt, blindingFactor);
5272 Buffer const bobCiphertext = mptAlice.encryptAmount(bob, amt, blindingFactor);
5273 auto const version = mptAlice.getMPTokenVersion(bob);
5286 Buffer const badPedersenCommitment =
5287 mptAlice.getPedersenCommitment(1, pcBlindingFactor);
5288 Buffer const proof = mptAlice.getConvertBackProof(
5293 .pedersenCommitment = badPedersenCommitment,
5294 .amt = spendingBalance,
5295 .encryptedAmt = encryptedSpendingBalance,
5296 .blindingFactor = pcBlindingFactor,
5299 mptAlice.convertBack({
5303 .holderEncryptedAmt = bobCiphertext,
5304 .issuerEncryptedAmt = issuerCiphertext,
5305 .blindingFactor = blindingFactor,
5306 .pedersenCommitment = pedersenCommitment,
5318 Buffer const proof = mptAlice.getConvertBackProof(
5323 .pedersenCommitment = pedersenCommitment,
5324 .amt = spendingBalance,
5325 .encryptedAmt = encryptedSpendingBalance,
5329 mptAlice.convertBack({
5333 .holderEncryptedAmt = bobCiphertext,
5334 .issuerEncryptedAmt = issuerCiphertext,
5335 .blindingFactor = blindingFactor,
5336 .pedersenCommitment = pedersenCommitment,
5348 Buffer const proof = mptAlice.getConvertBackProof(
5353 .pedersenCommitment = pedersenCommitment,
5355 .encryptedAmt = encryptedSpendingBalance,
5356 .blindingFactor = pcBlindingFactor,
5359 mptAlice.convertBack({
5363 .holderEncryptedAmt = bobCiphertext,
5364 .issuerEncryptedAmt = issuerCiphertext,
5365 .blindingFactor = blindingFactor,
5366 .pedersenCommitment = pedersenCommitment,
5378 Buffer const badPedersenCommitment =
5379 mptAlice.getPedersenCommitment(1, pcBlindingFactor);
5380 Buffer const proof = mptAlice.getConvertBackProof(
5385 .pedersenCommitment = pedersenCommitment,
5386 .amt = spendingBalance,
5387 .encryptedAmt = encryptedSpendingBalance,
5388 .blindingFactor = pcBlindingFactor,
5391 mptAlice.convertBack({
5395 .holderEncryptedAmt = bobCiphertext,
5396 .issuerEncryptedAmt = issuerCiphertext,
5397 .blindingFactor = blindingFactor,
5398 .pedersenCommitment = badPedersenCommitment,
5408 uint256 const badContextHash{1};
5410 Buffer const proof = mptAlice.getConvertBackProof(
5415 .pedersenCommitment = pedersenCommitment,
5416 .amt = spendingBalance,
5417 .encryptedAmt = encryptedSpendingBalance,
5418 .blindingFactor = pcBlindingFactor,
5421 mptAlice.convertBack({
5425 .holderEncryptedAmt = bobCiphertext,
5426 .issuerEncryptedAmt = issuerCiphertext,
5427 .blindingFactor = blindingFactor,
5428 .pedersenCommitment = pedersenCommitment,
5439 Buffer const proof = mptAlice.getConvertBackProof(
5444 .pedersenCommitment = pedersenCommitment,
5445 .amt = spendingBalance,
5446 .encryptedAmt = encryptedSpendingBalance,
5447 .blindingFactor = pcBlindingFactor,
5450 mptAlice.convertBack({
5454 .holderEncryptedAmt = bobCiphertext,
5455 .issuerEncryptedAmt = issuerCiphertext,
5456 .blindingFactor = blindingFactor,
5457 .pedersenCommitment = pedersenCommitment,
5473 testcase(
"Send: overdraft prevention via bulletproof");
5482 Env env{*
this, features};
5483 Account const alice(
"alice"), bob(
"bob"), issuer(
"issuer");
5485 uint64_t
const aliceBalance = balance;
5486 uint64_t
const aliceAmount = amt;
5487 uint64_t
const aliceRemaining = aliceBalance - aliceAmount;
5493 {{.account = alice, .payAmount = 1000, .convertAmount = aliceBalance},
5494 {.account = bob, .payAmount = 1000, .convertAmount = 30}}};
5495 auto& mptIssuer = confEnv.
mpt;
5501 unsigned const numParticipants = 3;
5506 mptIssuer.getDecryptedBalance(alice, MPTTester::holderEncryptedSpending),
5507 "Missing Alice's balance");
5508 BEAST_EXPECT(balance == aliceBalance);
5520 Buffer const aliceEncAmt = mptIssuer.encryptAmount(alice, aliceAmount, randomElgamal);
5521 Buffer const bobEncAmt = mptIssuer.encryptAmount(bob, aliceAmount, randomElgamal);
5522 Buffer const issuerEncAmt = mptIssuer.encryptAmount(issuer, aliceAmount, randomElgamal);
5526 Buffer const amtCommit = mptIssuer.getPedersenCommitment(aliceAmount, randomElgamal);
5527 Buffer const balanceCommit = mptIssuer.getPedersenCommitment(aliceBalance, randomBalance);
5531 mptIssuer.getEncryptedBalance(alice, MPTTester::holderEncryptedSpending),
5532 "Missing Alice's encrypted spending balance");
5534 uint32_t
const version = mptIssuer.getMPTokenVersion(alice);
5536 alice.id(), mptIssuer.issuanceID(), env.seq(alice), bob.id(), version);
5544 auto* ctx = mpt_secp256k1_context();
5545 Buffer sigmaProof(SECP256K1_COMPACT_STANDARD_PROOF_SIZE);
5548 secp256k1_pubkey c1, c2Alice, c2Bob, c2Issuer;
5551 if (!BEAST_EXPECTS(x == 1,
"Failed to parse C1"))
5554 x = secp256k1_ec_pubkey_parse(
5556 auto y = secp256k1_ec_pubkey_parse(
5558 auto z = secp256k1_ec_pubkey_parse(
5563 if (!BEAST_EXPECTS(x == 1 && y == 1 && z == 1,
"Failed to parse C2 components"))
5565 secp256k1_pubkey c2Vec[] = {c2Alice, c2Bob, c2Issuer};
5568 secp256k1_pubkey pkAlice, pkBob, pkIssuer;
5569 auto alicePubKey =
requireOptional(mptIssuer.getPubKey(alice),
"Missing alice pubkey");
5570 auto bobPubKey =
requireOptional(mptIssuer.getPubKey(bob),
"Missing bob pubkey");
5571 auto issuerPubKey =
requireOptional(mptIssuer.getPubKey(issuer),
"Missing issuer pubkey");
5574 z = secp256k1_ec_pubkey_parse(
5576 if (!BEAST_EXPECTS(x == 1 && y == 1 && z == 1,
"Failed to parse public keys"))
5578 secp256k1_pubkey pkVec[] = {pkAlice, pkBob, pkIssuer};
5581 secp256k1_pubkey pcAmount, pcBalance, b1, b2;
5583 y = secp256k1_ec_pubkey_parse(
5585 if (!BEAST_EXPECTS(x == 1 && y == 1,
"Failed to parse commitments"))
5589 y = secp256k1_ec_pubkey_parse(
5591 if (!BEAST_EXPECTS(x == 1 && y == 1,
"Failed to parse balance ciphertext"))
5595 auto alicePrivKey =
requireOptional(mptIssuer.getPrivKey(alice),
"Missing alice privkey");
5599 x = secp256k1_compact_standard_prove(
5604 randomElgamal.
data(),
5605 alicePrivKey.data(),
5606 randomBalance.
data(),
5617 if (!BEAST_EXPECTS(x == 1,
"Failed to generate sigma proof"))
5621 x = secp256k1_compact_standard_verify(
5634 if (!BEAST_EXPECTS(x == 1,
"Sigma verification failed"))
5642 secp256k1_mpt_scalar_negate(negRandomElgamal.
data(), randomElgamal.
data());
5643 secp256k1_mpt_scalar_add(
5644 randomRemaining.
data(), randomBalance.
data(), negRandomElgamal.
data());
5648 {aliceAmount, aliceRemaining}, {randomElgamal, randomRemaining}, ctxHash);
5652 std::memcpy(combinedProof.data(), sigmaProof.
data(), SECP256K1_COMPACT_STANDARD_PROOF_SIZE);
5654 combinedProof.data() + SECP256K1_COMPACT_STANDARD_PROOF_SIZE,
5655 forgedBulletproof.data(),
5659 x = mpt_verify_send_range_proof(
5660 combinedProof.data() + SECP256K1_COMPACT_STANDARD_PROOF_SIZE,
5662 balanceCommit.
data(),
5664 if (!BEAST_EXPECTS(x == errors.
first,
"Forged proof passed validation"))
5673 .proof =
strHex(combinedProof),
5674 .senderEncryptedAmt = aliceEncAmt,
5675 .destEncryptedAmt = bobEncAmt,
5676 .issuerEncryptedAmt = issuerEncAmt,
5677 .amountCommitment = amtCommit,
5678 .balanceCommitment = balanceCommit,
5685 mptIssuer.getDecryptedBalance(alice, MPTTester::holderEncryptedSpending),
5686 "Missing post-attack balance");
5687 if (aliceAmount > aliceBalance)
5689 BEAST_EXPECT(balance == aliceBalance);
5693 BEAST_EXPECT(balance < aliceBalance);
5709 testcase(
"Convert back: overdraft prevention via bulletproof");
5718 Env env{*
this, features};
5719 Account const alice(
"alice"), bob(
"bob"), carol(
"carol");
5721 uint64_t
const bobBalance = balance;
5732 {.account = bob, .payAmount = 1000, .convertAmount = bobBalance},
5737 auto& mptAlice = confEnv.
mpt;
5746 mptAlice.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending),
5747 "Missing Bob's balance");
5748 BEAST_EXPECT(balance == bobBalance);
5763 Buffer const balanceCommit = mptAlice.getPedersenCommitment(bobBalance, pcBlindingFactor);
5767 mptAlice.getEncryptedBalance(bob, MPTTester::holderEncryptedSpending),
5768 "Missing Bob's encrypted spending balance");
5770 uint32_t
const version = mptAlice.getMPTokenVersion(bob);
5771 auto const ctxHash =
5775 auto* ctx = mpt_secp256k1_context();
5776 Buffer sigmaProof(SECP256K1_COMPACT_CONVERTBACK_PROOF_SIZE);
5779 secp256k1_pubkey pkBob;
5780 auto bobPubKey =
requireOptional(mptAlice.getPubKey(bob),
"Missing bob pubkey");
5782 if (!BEAST_EXPECTS(x == 1,
"Failed to parse Bob's public key"))
5786 secp256k1_pubkey pcBalance;
5787 x = secp256k1_ec_pubkey_parse(
5789 if (!BEAST_EXPECTS(x == 1,
"Failed to parse balance commitment"))
5793 secp256k1_pubkey b1, b2;
5795 auto y = secp256k1_ec_pubkey_parse(
5797 if (!BEAST_EXPECTS(x == 1 && y == 1,
"Failed to parse balance ciphertext"))
5801 auto bobPrivKey =
requireOptional(mptAlice.getPrivKey(bob),
"Missing bob privkey");
5805 x = secp256k1_compact_convertback_prove(
5810 pcBlindingFactor.
data(),
5816 if (!BEAST_EXPECTS(x == 1,
"Failed to generate convertback sigma proof"))
5820 x = secp256k1_compact_convertback_verify(
5821 ctx, sigmaProof.
data(), &pkBob, &b1, &b2, &pcBalance, ctxHash.data());
5822 if (!BEAST_EXPECTS(x == 1,
"Sigma verification failed"))
5833 auto const forgedBulletproof =
5839 combinedProof.
data(), sigmaProof.
data(), SECP256K1_COMPACT_CONVERTBACK_PROOF_SIZE);
5841 combinedProof.
data() + SECP256K1_COMPACT_CONVERTBACK_PROOF_SIZE,
5842 forgedBulletproof.data(),
5846 x = mpt_verify_convert_back_proof(
5847 combinedProof.
data(),
5849 bobEncBalance.
data(),
5850 balanceCommit.
data(),
5853 if (!BEAST_EXPECTS(x == errors.
first,
"Forged proof verification mismatch"))
5858 mptAlice.convertBack({
5861 .proof = combinedProof,
5862 .holderEncryptedAmt = bobEncAmt,
5863 .issuerEncryptedAmt = issuerEncAmt,
5864 .blindingFactor = blindingFactor,
5865 .pedersenCommitment = balanceCommit,
5872 mptAlice.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending),
5873 "Missing post-attack balance");
5876 BEAST_EXPECT(postBalance == bobBalance);
5880 BEAST_EXPECT(postBalance < bobBalance);
5888 testcase(
"Convert back bulletproof");
5891 Env env{*
this, features};
5895 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 40}}};
5896 auto& mptAlice = confEnv.
mpt;
5900 uint64_t
const amt = 10;
5905 mptAlice.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending),
5906 "Missing spending balance");
5908 mptAlice.getEncryptedBalance(bob, MPTTester::holderEncryptedSpending),
5909 "Missing encrypted spending balance");
5910 BEAST_EXPECT(!encryptedSpendingBalance.empty());
5912 Buffer const pedersenCommitment =
5913 mptAlice.getPedersenCommitment(spendingBalance, pcBlindingFactor);
5914 Buffer const issuerCiphertext = mptAlice.encryptAmount(alice, amt, blindingFactor);
5915 Buffer const bobCiphertext = mptAlice.encryptAmount(bob, amt, blindingFactor);
5916 auto const version = mptAlice.getMPTokenVersion(bob);
5930 Buffer const proof = mptAlice.getConvertBackProof(
5935 .pedersenCommitment = pedersenCommitment,
5937 .encryptedAmt = encryptedSpendingBalance,
5938 .blindingFactor = pcBlindingFactor,
5941 mptAlice.convertBack({
5945 .holderEncryptedAmt = bobCiphertext,
5946 .issuerEncryptedAmt = issuerCiphertext,
5947 .blindingFactor = blindingFactor,
5948 .pedersenCommitment = pedersenCommitment,
5961 Buffer const proof = mptAlice.getConvertBackProof(
5966 .pedersenCommitment = pedersenCommitment,
5967 .amt = spendingBalance,
5968 .encryptedAmt = encryptedSpendingBalance,
5972 mptAlice.convertBack({
5976 .holderEncryptedAmt = bobCiphertext,
5977 .issuerEncryptedAmt = issuerCiphertext,
5978 .blindingFactor = blindingFactor,
5979 .pedersenCommitment = pedersenCommitment,
5989 uint256 const badContextHash{1};
5990 Buffer const proof = mptAlice.getConvertBackProof(
5995 .pedersenCommitment = pedersenCommitment,
5996 .amt = spendingBalance,
5997 .encryptedAmt = encryptedSpendingBalance,
5998 .blindingFactor = pcBlindingFactor,
6001 mptAlice.convertBack({
6005 .holderEncryptedAmt = bobCiphertext,
6006 .issuerEncryptedAmt = issuerCiphertext,
6007 .blindingFactor = blindingFactor,
6008 .pedersenCommitment = pedersenCommitment,
6019 Buffer const proof = mptAlice.getConvertBackProof(
6024 .pedersenCommitment = pedersenCommitment,
6025 .amt = spendingBalance,
6026 .encryptedAmt = encryptedSpendingBalance,
6027 .blindingFactor = pcBlindingFactor,
6030 mptAlice.convertBack({
6034 .holderEncryptedAmt = bobCiphertext,
6035 .issuerEncryptedAmt = issuerCiphertext,
6036 .blindingFactor = blindingFactor,
6037 .pedersenCommitment = pedersenCommitment,
6049 testcase(
"ConvertBack proof context binding");
6052 auto runBadProof = [&](
auto makeContextHash) {
6053 Env env{*
this, features};
6058 env, alice, {{.account = bob, .payAmount = 100, .convertAmount = 40}}};
6059 auto& mptAlice = confEnv.
mpt;
6065 auto const spendingBalance =
6066 mptAlice.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending);
6067 auto const encryptedSpendingBalance =
6068 mptAlice.getEncryptedBalance(bob, MPTTester::holderEncryptedSpending);
6069 if (!BEAST_EXPECT(spendingBalance && encryptedSpendingBalance))
6072 Buffer const pedersenCommitment = mptAlice.getPedersenCommitment(
6073 requireOptional(spendingBalance,
"Missing spending balance"), pcBlindingFactor);
6074 Buffer const issuerCiphertext = mptAlice.encryptAmount(alice, amt, blindingFactor);
6075 Buffer const bobCiphertext = mptAlice.encryptAmount(bob, amt, blindingFactor);
6076 auto const version = mptAlice.getMPTokenVersion(bob);
6078 Buffer const proof = mptAlice.getConvertBackProof(
6081 makeContextHash(env, mptAlice, alice, bob, carol, version),
6083 .pedersenCommitment = pedersenCommitment,
6086 encryptedSpendingBalance,
"Missing encrypted spending balance"),
6087 .blindingFactor = pcBlindingFactor,
6090 mptAlice.convertBack({
6094 .holderEncryptedAmt = bobCiphertext,
6095 .issuerEncryptedAmt = issuerCiphertext,
6096 .blindingFactor = blindingFactor,
6097 .pedersenCommitment = pedersenCommitment,
6103 runBadProof([&](Env& env,
6104 MPTTester
const& mpt,
6113 runBadProof([&](Env& env,
6120 bob.id(),
makeMptID(env.seq(alice) + 100, alice), env.seq(bob), version);
6124 runBadProof([&](Env& env,
6125 MPTTester
const& mpt,
6134 runBadProof([&](Env& env,
6135 MPTTester
const& mpt,
6959 testcase(
"divergent C1 across participants in ConfidentialMPTSend");
6962 Env env{*
this, features};
6966 Account const auditor(
"auditor");
6970 {{.account = bob, .payAmount = 100, .convertAmount = 50},
6971 {.account = carol, .payAmount = 50, .convertAmount = 50}},
6972 tfMPTCanLock | tfMPTCanHoldConfidentialBalance | tfMPTCanTransfer,
6974 auto& mptAlice = confEnv.
mpt;
6977 uint64_t
const amt = 10;
6979 enum class Participant { Sender, Dest, Issuer, Auditor };
6990 auto const proofOpt =
7004 case Participant::Sender:
7005 senderCt = mptAlice.encryptAmount(bob, amt, bfDivergent);
7007 case Participant::Dest:
7008 destCt = mptAlice.encryptAmount(carol, amt, bfDivergent);
7010 case Participant::Issuer:
7011 issuerCt = mptAlice.encryptAmount(alice, amt, bfDivergent);
7013 case Participant::Auditor:
7014 auditorCt = mptAlice.encryptAmount(auditor, amt, bfDivergent);
7025 .proof =
strHex(proofOpt),
7026 .senderEncryptedAmt = senderCt,
7027 .destEncryptedAmt = destCt,
7028 .issuerEncryptedAmt = issuerCt,
7029 .auditorEncryptedAmt = auditorCt,
7037 auto const spendingAfter =
7038 mptAlice.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending);
7045 BEAST_EXPECT(spendingAfter == setup.
prevSpending - amt);
7051 submitWithDivergentC1(std::nullopt);
7054 submitWithDivergentC1(Participant::Sender);
7055 submitWithDivergentC1(Participant::Dest);
7056 submitWithDivergentC1(Participant::Issuer);
7057 submitWithDivergentC1(Participant::Auditor);
7063 testcase(
"test confidential transactions fee");
7070 .flags = tfMPTCanLock | tfMPTCanHoldConfidentialBalance | tfMPTCanTransfer |
7073 mpt.authorize({.account = bob});
7074 mpt.authorize({.account = carol});
7075 mpt.pay(alice, bob, 100);
7076 mpt.pay(alice, carol, 50);
7077 mpt.generateKeyPair(alice);
7078 mpt.generateKeyPair(bob);
7079 mpt.generateKeyPair(carol);
7080 mpt.set({.account = alice, .issuerPubKey = mpt.getPubKey(alice)});
7085 Env env{*
this, features};
7086 Account const alice(
"alice"), bob(
"bob"), carol(
"carol");
7087 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
7088 setup(mptAlice, alice, bob, carol);
7090 auto const baseFee = env.current()->fees().base;
7095 auto checkFee = [&](
Account const& acct,
auto&& submitFn) {
7096 auto const before = env.balance(acct);
7098 auto const after = env.balance(acct);
7099 BEAST_EXPECT(before -
after == expectedFee);
7102 checkFee(bob, [&]() {
7106 .holderPubKey = mptAlice.getPubKey(bob),
7107 .fee = expectedFee});
7109 checkFee(carol, [&]() {
7113 .holderPubKey = mptAlice.getPubKey(carol),
7114 .fee = expectedFee});
7116 checkFee(bob, [&]() { mptAlice.mergeInbox({.account = bob, .fee = expectedFee}); });
7117 checkFee(carol, [&]() { mptAlice.mergeInbox({.account = carol, .fee = expectedFee}); });
7118 checkFee(bob, [&]() {
7119 mptAlice.send({.account = bob, .dest = carol, .amt = 5, .fee = expectedFee});
7121 checkFee(bob, [&]() {
7122 mptAlice.convertBack({.account = bob, .amt = 5, .fee = expectedFee});
7124 checkFee(alice, [&]() {
7125 mptAlice.confidentialClaw(
7126 {.account = alice, .holder = carol, .amt = 15, .fee = expectedFee});
7132 Env env{*
this, features};
7133 Account const alice(
"alice"), bob(
"bob"), carol(
"carol");
7134 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
7135 setup(mptAlice, alice, bob, carol);
7136 auto const baseFee = env.current()->fees().base;
7142 .holderPubKey = mptAlice.getPubKey(bob),
7143 .fee = expectedFee - 1,
7145 mptAlice.mergeInbox({.account = bob, .fee = baseFee, .err =
telINSUF_FEE_P});
7152 mptAlice.convertBack({.account = bob, .amt = 1, .fee = baseFee, .err =
telINSUF_FEE_P});
7153 mptAlice.confidentialClaw(
7163 Env env{*
this, features};
7164 Account const alice(
"alice"), bob(
"bob"), carol(
"carol");
7165 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
7166 setup(mptAlice, alice, bob, carol);
7168 auto const baseFee = env.current()->fees().base;
7170 auto const bobBefore = env.balance(bob);
7174 .holderPubKey = mptAlice.getPubKey(bob),
7176 BEAST_EXPECT(env.balance(bob) == bobBefore - highFee);
7595 testcase(
"Send: special witness values");
7598 Env env{*
this, features};
7599 Account const alice(
"alice"), bob(
"bob"), carol(
"carol");
7603 {{.account = bob}, {.account = carol, .payAmount = 1000, .convertAmount = 50}}};
7604 auto& mptAlice = confEnv.
mpt;
7610 auto const proof = setup.
generateProof(mptAlice, env, bob, carol);
7611 if (!BEAST_EXPECT(proof.has_value()))
7616 static constexpr size_t kSigmaScalarSize = 32;
7617 static constexpr size_t kChallengeOffset = 0;
7618 static constexpr size_t kResponseOffset = kChallengeOffset + kSigmaScalarSize;
7619 static constexpr size_t kResponseSize = 5 * kSigmaScalarSize;
7627 auto const proof = setup.
generateProof(mptAlice, env, bob, carol);
7628 if (!BEAST_EXPECT(proof.has_value()))
7637 mptAlice.send(args);
7642 auto const proof = setup.
generateProof(mptAlice, env, bob, carol);
7643 if (!BEAST_EXPECT(proof.has_value()))
7652 mptAlice.send(args);
7657 auto const proof = setup.
generateProof(mptAlice, env, bob, carol);
7658 if (!BEAST_EXPECT(proof.has_value()))
7663 static constexpr unsigned char kCurveOrder[32] = {
7664 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
7665 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
7666 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
7667 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x41
7677 auto const proof = setup.
generateProof(mptAlice, env, bob, carol);
7678 if (!BEAST_EXPECT(proof.has_value()))
7683 static constexpr unsigned char kOverflowScalar[32] = {
7684 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
7685 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
7686 0xBA, 0xAE, 0xDC, 0xE6, 0xAF, 0x48, 0xA0, 0x3B,
7687 0xBF, 0xD2, 0x5E, 0x8C, 0xD0, 0x36, 0x41, 0x42
7699 testcase(
"Send: cross-statement proof substitution");
7706 Env env{*
this, features};
7707 Account const alice(
"alice"), bob(
"bob"), carol(
"carol");
7711 {{.account = bob}, {.account = carol, .payAmount = 1000, .convertAmount = 50}},
7712 tfMPTCanLock | tfMPTCanHoldConfidentialBalance | tfMPTCanTransfer | tfMPTCanClawback};
7713 auto& mptAlice = confEnv.
mpt;
7715 uint64_t
const sendAmount = 10;
7732 mptAlice.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending),
7733 "Missing spending balance");
7735 mptAlice.getEncryptedBalance(bob, MPTTester::holderEncryptedSpending),
7736 "Missing encrypted spending balance");
7739 Buffer const pedersenCommitment =
7740 mptAlice.getPedersenCommitment(spendingBalance, pcBlindingFactor);
7742 auto const version = mptAlice.getMPTokenVersion(bob);
7743 uint256 const convertBackCtxHash =
7746 Buffer const convertBackProof = mptAlice.getConvertBackProof(
7751 .pedersenCommitment = pedersenCommitment,
7752 .amt = spendingBalance,
7753 .encryptedAmt = encryptedSpending,
7754 .blindingFactor = pcBlindingFactor,
7761 Buffer resizedProof(expectedSendSize);
7762 auto const copyLen =
std::min(convertBackProof.
size(), expectedSendSize);
7765 if (copyLen < expectedSendSize)
7766 std::memset(resizedProof.
data() + copyLen, 0, expectedSendSize - copyLen);
7782 uint192 const fakeIssuanceID{1};
7784 bob.id(), fakeIssuanceID, env.seq(bob), carol.id(), setup.
version);
7787 auto const wrongProof = mptAlice.getConfidentialSendProof(
7794 .pedersenCommitment = setup.amountCommitment,
7796 .encryptedAmt = setup.senderAmt,
7797 .blindingFactor = setup.amountBlindingFactor,
7800 .pedersenCommitment = setup.balanceCommitment,
7801 .amt = setup.prevSpending,
7802 .encryptedAmt = setup.prevEncryptedSpending,
7803 .blindingFactor = setup.balanceBlindingFactor,
7806 if (!BEAST_EXPECT(wrongProof.has_value()))
8349 testcase(
"Send: recipient inbox rerandomization prevents merge cancellation");
8355 auto getCanonicalZeroBlindingFactor = [](
AccountID const& account,
MPTID const& mptID) {
8376 if (secp256k1_ec_seckey_verify(mpt_secp256k1_context(), scalar.data()))
8385 auto negateScalarSum = [](
Buffer const& lhs,
Buffer const& rhs) {
8388 secp256k1_mpt_scalar_add(
sum.data(), lhs.
data(), rhs.data());
8389 secp256k1_mpt_scalar_negate(negated.
data(),
sum.data());
8397 Env env{*
this, features};
8398 Account const alice(
"alice"), bob(
"bob"), carol(
"carol");
8399 MPTTester mptAlice(env, alice, {.holders = {bob, carol}});
8403 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
8406 mptAlice.authorize({.account = bob});
8407 mptAlice.authorize({.account = carol});
8408 mptAlice.pay(alice, bob, 100);
8409 mptAlice.pay(alice, carol, 100);
8411 mptAlice.generateKeyPair(alice);
8412 mptAlice.generateKeyPair(bob);
8413 mptAlice.generateKeyPair(carol);
8414 mptAlice.set({.account = alice, .issuerPubKey = mptAlice.getPubKey(alice)});
8419 .holderPubKey = mptAlice.getPubKey(carol),
8421 mptAlice.mergeInbox({.account = carol});
8427 .holderPubKey = mptAlice.getPubKey(bob),
8428 .blindingFactor = convertBlindingFactor,
8431 Buffer const canonicalZeroBlindingFactor =
8432 getCanonicalZeroBlindingFactor(bob.id(), mptAlice.issuanceID());
8436 Buffer const maliciousSendBlindingFactor =
8437 negateScalarSum(canonicalZeroBlindingFactor, convertBlindingFactor);
8443 .blindingFactor = maliciousSendBlindingFactor,
8446 mptAlice.mergeInbox({.account = bob});
8448 auto const bobSpending =
8449 mptAlice.getDecryptedBalance(bob, MPTTester::holderEncryptedSpending);
8450 BEAST_EXPECT(bobSpending && *bobSpending == 25);
8458 Env env{*
this, features};
8459 Account const alice(
"alice"), bob(
"bob"), carol(
"carol"), auditor(
"auditor");
8460 MPTTester mptAlice(env, alice, {.holders = {bob, carol}, .auditor = auditor});
8464 .flags = tfMPTCanTransfer | tfMPTCanLock | tfMPTCanHoldConfidentialBalance,
8467 mptAlice.authorize({.account = bob});
8468 mptAlice.authorize({.account = carol});
8469 mptAlice.pay(alice, bob, 100);
8470 mptAlice.pay(alice, carol, 100);
8472 mptAlice.generateKeyPair(alice);
8473 mptAlice.generateKeyPair(bob);
8474 mptAlice.generateKeyPair(carol);
8475 mptAlice.generateKeyPair(auditor);
8478 .issuerPubKey = mptAlice.getPubKey(alice),
8479 .auditorPubKey = mptAlice.getPubKey(auditor),
8485 .holderPubKey = mptAlice.getPubKey(carol),
8487 mptAlice.mergeInbox({.account = carol});
8493 .holderPubKey = mptAlice.getPubKey(bob),
8494 .blindingFactor = convertBlindingFactor,
8498 Buffer const maliciousSendBlindingFactor =
8505 .blindingFactor = maliciousSendBlindingFactor,
8508 auto const bobAuditor =
8509 mptAlice.getDecryptedBalance(bob, MPTTester::auditorEncryptedBalance);
8510 BEAST_EXPECT(bobAuditor && *bobAuditor == 25);