Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow tx without budget #2846

Open
wants to merge 44 commits into
base: privacy-feature
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
e47cd6f
extend replica api to return some necessry objects needed for utt
yontyon Oct 3, 2022
8a156f9
Add INTERNAL_FLAG to message's flags
yontyon Oct 3, 2022
e939276
Add INTERNAL_FLAG to message's flags
yontyon Oct 6, 2022
5b61892
Fix internal flags issues
yontyon Oct 6, 2022
8762dbf
fix compilation error
yontyon Oct 6, 2022
e9dbf59
add pragma once
yontyon Oct 6, 2022
60d1573
add some necessary libutt api
yontyon Oct 12, 2022
da746f2
Fix an error with randomness when creating a coin by the replicas
yontyon Oct 19, 2022
ae5f62e
add an option to create determisitc coin commitment for coins created…
yontyon Oct 19, 2022
9f486ff
Separate the wallet in its own source file
Oct 11, 2022
24f3186
The wallet now assumes only a single user. The user id is provided as…
Oct 11, 2022
d889deb
WIP budget, mint, transfer, burn operations
Oct 12, 2022
956d153
wallet fixes
Oct 13, 2022
b56ae6f
utt client api user now has more consistent error handling by throwin…
Oct 13, 2022
72912a2
Add support for mint transactions originating from the wallet
Oct 13, 2022
a34418f
Add number of outputs to utt::Transaction
Oct 14, 2022
7ac2db1
TestUTTClientApi now relies on the fact that updateBurnTx and updateM…
Oct 15, 2022
54de749
Multiplex multiple users in the same wallet for initial testing purposes
Oct 16, 2022
17ac7b9
Rename wallet command 'info' to 'show'
Oct 18, 2022
66c7c22
Add a way to pre-create budget tokens in the sample wallet
Oct 18, 2022
e44dbe1
Fix creation of budget locally to not happen before registration
Oct 18, 2022
c639459
Check if the wallet exists when processing commands
Oct 19, 2022
8f8b876
Add comment about the workaround dealing with the wallet service not …
Oct 20, 2022
95c257a
Add public balance to wallet-cli
Oct 21, 2022
17b3d46
Refactor wallet cli app to avoid excessive nesting when validating in…
Oct 21, 2022
2982b1e
Rework wallet-cli to use a bi-directional stream for all wallet requests
Oct 24, 2022
e36b04d
Fix pki was referenced as a local variable. Renaming
Oct 25, 2022
fdf54e4
Initial split of the privacy-admin-cli application with just the depl…
Oct 25, 2022
6d85b56
Transform the deploy command into a configure command in the wallet-c…
Oct 26, 2022
a1c93be
Use the public config obtained from the privacy contract
Oct 26, 2022
126abb6
Make wallet-cli single user by providing a user-id as an argument
Oct 27, 2022
12c7110
Add full validation capabilites
yontyon Oct 31, 2022
70c9e36
Fix a bug where the new api transaction object exposes the input coins
yontyon Nov 2, 2022
916eab9
Cleanup admin and wallet cli outputs. Demote some loginfo to logdbg s…
Nov 2, 2022
e596644
Improve the new utt api testing framework, integrating it with gtest …
yontyon Nov 3, 2022
9044b5f
Fix clang-tidy checks
yontyon Nov 3, 2022
d1f1a78
Add getter for partial signatures map from the complete signature mes…
yontyon Nov 3, 2022
df5d5be
complete rebase
yontyon Nov 3, 2022
eaaec88
Add debug logs to user in utt-client-api
Nov 8, 2022
304afac
Allow transaction without budget in libutt
yontyon Nov 9, 2022
db42d35
Allow transaction without budget in clientAPI
yontyon Nov 9, 2022
6608a17
Improve the input for budget policy in the admin cli
yontyon Nov 9, 2022
312455f
clean some redundent comments
yontyon Nov 9, 2022
c512040
remove defaults and beautify the code
yontyon Nov 9, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion utt/admin-cli/include/admin.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Admin {
/// [TODO-UTT] Should be performed by an admin app
/// @brief Deploy a privacy application
/// @return The public configuration of the deployed application
static bool deployApp(Channel& chan, bool budget_policy = true);
static bool deployApp(Channel& chan, bool budget_policy);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this PR also include a change to the wallet app?
as it checks

const size_t budget = getPrivacyBudget();
  if (budget < amount) throw std::runtime_error("User has insufficient privacy budget!");```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't it more elegant to define the non-budget configuration as a budget coin with infinite value?
It will eliminate the need for if - else on the transaction and will reduce the configuration changes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's more elegant for the code but will it be more elegant for the system if we still need to create and manage a 'hidden infinite' budget coin? And how does it reduce the configuration changes?


/// @brief Request the creation of a privacy budget. The amount of the budget is predetermined by the deployed app.
/// This operation could be performed entirely by an administrator, but we add it in the admin
Expand Down
2 changes: 1 addition & 1 deletion utt/include/UTTParams.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ class UTTParams {
UTTParams& operator=(UTTParams&&) = default;

bool getBudgetPolicy() const;
bool budget_policy = true;

private:
friend std::ostream& ::operator<<(std::ostream& out, const libutt::api::UTTParams& params);
friend std::istream& ::operator>>(std::istream& in, libutt::api::UTTParams& params);
friend bool ::operator==(const libutt::api::UTTParams& params1, const libutt::api::UTTParams& params2);
std::unique_ptr<libutt::Params> params;
bool budget_policy = true;
};
} // namespace libutt::api
2 changes: 1 addition & 1 deletion utt/include/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class Configuration {
/// @brief Constructs a UTT instance configuration
/// @param n The number of validators for multiparty signature computation
/// @param t The number of validator shares required to reconstruct a signature
Configuration(uint16_t n, uint16_t t, bool budget_policy = true);
Configuration(uint16_t n, uint16_t t, bool budget_policy);
~Configuration();

Configuration(Configuration&& o);
Expand Down
3 changes: 1 addition & 2 deletions utt/include/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ class Transaction {
const std::vector<Coin>& input_coins,
const std::optional<Coin>& budget_coin,
const std::vector<std::tuple<std::string, uint64_t>>& recipients,
const IEncryptor& encryptor,
bool budget_policy = true);
const IEncryptor& encryptor);
Transaction();
Transaction(const Transaction&);
Transaction(Transaction&&) = default;
Expand Down
2 changes: 1 addition & 1 deletion utt/libutt/bench/BenchTxn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ class BenchTxn {
tqv.endLap();

tv.startLap();
if (!tx.validate(p, bpk, rpk)) {
if (!tx.validate(p, bpk, rpk, true)) {
testAssertFail("TXN should have verified");
}
tv.endLap();
Expand Down
2 changes: 1 addition & 1 deletion utt/libutt/include/utt/Tx.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ class Tx {

bool quickPayValidate(const Params& p, const RandSigPK& bpk, const RegAuthPK& rpk, bool budget_policy) const;

bool validate(const Params& p, const RandSigPK& bpk, const RegAuthPK& rpk, bool budget_policy = true) const;
bool validate(const Params& p, const RandSigPK& bpk, const RegAuthPK& rpk, bool budget_policy) const;

/**
* Returns the nullifiers of all coins spent by this TXN, including the budget coin's.
Expand Down
5 changes: 3 additions & 2 deletions utt/libutt/src/BurnOp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ BurnOp::BurnOp(const Params& p,
recip,
std::move(bpk),
rpk.vk,
libutt::IBEEncryptor(rpk.mpk));
libutt::IBEEncryptor(rpk.mpk),
false);

assertTrue(internalTx.outs.size() == 1);

Expand Down Expand Up @@ -181,7 +182,7 @@ size_t BurnOp::getSize() const {
bool BurnOp::validate(const Params& p, const RandSigPK& bpk, const RegAuthPK& rpk) const {
InternalDataOfBurnOp* d = (InternalDataOfBurnOp*)this->p;
if (d == nullptr) return false;
if (!d->tx.validate(p, bpk, rpk)) return false;
if (!d->tx.validate(p, bpk, rpk, false)) return false;
if (d->tx.outs.size() != 1) return false;

Fr hashPid = AddrSK::pidHash(d->pid);
Expand Down
2 changes: 1 addition & 1 deletion utt/libutt/src/Simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Tx sendValidTxOnNetwork(const Context& ctx, const Tx& inTx) {
testAssertEqual(inTx, outTx);
testAssertEqual(oldHash, newHash);

if (!outTx.validate(ctx.p_, ctx.bpk_, ctx.rpk_)) {
if (!outTx.validate(ctx.p_, ctx.bpk_, ctx.rpk_, true)) {
testAssertFail("TXN should have verified");
}

Expand Down
39 changes: 24 additions & 15 deletions utt/libutt/src/Tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

std::ostream& operator<<(std::ostream& out, const libutt::Tx& tx) {
out << tx.budgetPolicy << endl;
out << tx.is_budgeted << endl;
out << tx.isSplitOwnCoins << endl;
out << tx.rcm;
out << tx.regsig;
Expand All @@ -35,8 +34,7 @@ std::ostream& operator<<(std::ostream& out, const libutt::Tx& tx) {
std::istream& operator>>(std::istream& in, libutt::Tx& tx) {
in >> tx.budgetPolicy;
libff::consume_OUTPUT_NEWLINE(in);
in >> tx.is_budgeted;
libff::consume_OUTPUT_NEWLINE(in);

in >> tx.isSplitOwnCoins;
libff::consume_OUTPUT_NEWLINE(in);
in >> tx.rcm;
Expand All @@ -46,6 +44,10 @@ std::istream& operator>>(std::istream& in, libutt::Tx& tx) {
libutt::deserializeVector(in, tx.outs);

in >> tx.budget_pi;

for (auto& txin : tx.ins) {
tx.is_budgeted = tx.is_budgeted || (txin.coin_type == libutt::Coin::BudgetType());
}
return in;
}

Expand Down Expand Up @@ -86,7 +88,6 @@ Tx::Tx(const Params& p,
const RandSigPK& rpk,
const IEncryptor& encryptor,
bool budget_policy) {
budgetPolicy = budget_policy;
#ifndef NDEBUG
(void)bpk;
#endif
Expand All @@ -99,10 +100,7 @@ Tx::Tx(const Params& p,

isSplitOwnCoins = true; // true when this TXN simply splits the sender's coins
is_budgeted = b.has_value(); // true when this TXN is budgeted
if (!budgetPolicy && is_budgeted) {
logerror << "budget policy is false, but a budget coin was given" << endl;
throw std::runtime_error("budget policy is false, but a budget coin was given");
}

size_t totalIn = Coin::totalValue(coins); // total in value
size_t totalOut = 0; // total out value
size_t paidOut = 0; // total amount paid out to someone else
Expand Down Expand Up @@ -141,7 +139,16 @@ Tx::Tx(const Params& p,
forMeOutputs.insert(j);
}
}
budgetPolicy = isSplitOwnCoins ? false : budget_policy;
if (!budgetPolicy && is_budgeted) {
logerror << "budget policy is disabled, but a budget coin was given" << endl;
throw std::runtime_error("budget policy is false, but a budget coin was given");
}

if (budgetPolicy && !is_budgeted) {
logerror << "budget policy is enabled, but the budget is missing" << endl;
throw std::runtime_error("budget policy is enabled, but the budget coin is missing");
}
// are you spending more than you have?
if (totalIn != totalOut) {
logerror << "Total-in is " << totalIn << " but total-out is " << totalOut << endl;
Expand Down Expand Up @@ -384,18 +391,20 @@ bool Tx::quickPayValidate(const Params& p, const RandSigPK& bpk, const RegAuthPK
return false;
}

if (budget_policy) {
if (!budgetPolicy) {
logerror << "budget policy is enforced but the transaction's budget policy is false" << endl;
return false;
}
}

if (budget_policy && !isSplitOwnCoins && !is_budgeted) {
logerror << "budget policy is enforced and budget is needed, but the transaction doesn't have a budget coin"
<< endl;
return false;
}
if (!budget_policy && !isSplitOwnCoins && is_budgeted) {
logerror << "budget policy is disabled and budget is not needed, but the transaction does have a budget coin"
<< endl;
return false;
}

if ((budget_policy && !budgetPolicy) || (!budget_policy && budgetPolicy)) {
logerror << "mismatch between transaction's budget policy and the configuration budget policy" << endl;
}

assertTrue(!is_budgeted || budget_pi.has_value());

Expand Down
5 changes: 2 additions & 3 deletions utt/libutt/src/api/transaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ Transaction::Transaction(const UTTParams& d,
const std::vector<Coin>& coins,
const std::optional<Coin>& bc,
const std::vector<std::tuple<std::string, uint64_t>>& recipients,
const IEncryptor& encryptor,
bool budget_policy) {
const IEncryptor& encryptor) {
Fr fr_pidhash;
fr_pidhash.from_words(cid.getPidHash());
Fr prf;
Expand Down Expand Up @@ -59,7 +58,7 @@ Transaction::Transaction(const UTTParams& d,
std::nullopt,
rpk.vk,
encryptor,
budget_policy));
d.getBudgetPolicy()));
}
Transaction::Transaction() { tx_.reset(new libutt::Tx()); }
Transaction::Transaction(const Transaction& other) {
Expand Down
2 changes: 1 addition & 1 deletion utt/libutt/test/TestTxn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ void testBudgeted2to2Txn(size_t thresh, size_t n, size_t numCycles, bool isBudge
testAssertFail("TXN should have QuickPay-verified");
}
} else {
if (!tx.validate(p, bpk, rpk)) {
if (!tx.validate(p, bpk, rpk, true)) {
testAssertFail("TXN should have verified");
}
}
Expand Down
33 changes: 23 additions & 10 deletions utt/tests/TestUttNewApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ TEST_F(ibe_based_test_system_minted, test_invalid_burn) {
}

TEST_F(ibe_based_test_system, test_serialization_configuration) {
auto config = libutt::api::Configuration((uint16_t)n, (uint16_t)thresh);
auto config = libutt::api::Configuration((uint16_t)n, (uint16_t)thresh, true);
ASSERT_TRUE(config.isValid());
auto serialized_config = libutt::api::serialize<libutt::api::Configuration>(config);
auto deserialized_config = libutt::api::deserialize<libutt::api::Configuration>(serialized_config);
Expand Down Expand Up @@ -566,24 +566,38 @@ TEST_F(ibe_based_test_system_minted, test_transaction_without_budget) {
for (size_t i = 0; i < clients.size(); i++) {
auto& issuer = clients[i];
auto& receiver = clients[(i + 1) % clients.size()];
// We let the client to cheat and create a non-budgeted transaction
d.budget_policy = false;
Transaction tx(d,
issuer,
{coins[issuer.getPid()].front()},
std::nullopt,
{{issuer.getPid(), 50}, {receiver.getPid(), 50}},
*(encryptors_.at((i + 1) % clients.size())),
true);
for (auto& b : banks) {
ASSERT_FALSE(b->validate(d, tx));
}
*(encryptors_.at((i + 1) % clients.size())));

ASSERT_ANY_THROW(Transaction(d,
issuer,
{coins[issuer.getPid()].front()},
{bcoins[issuer.getPid()].front()},
{{issuer.getPid(), 50}, {receiver.getPid(), 50}},
*(encryptors_.at((i + 1) % clients.size())),
false));
*(encryptors_.at((i + 1) % clients.size()))));

d.budget_policy = true;
for (auto& b : banks) {
ASSERT_FALSE(b->validate(d, tx));
}

Transaction tx2(d,
issuer,
{coins[issuer.getPid()].front()},
{bcoins[issuer.getPid()].front()},
{{issuer.getPid(), 50}, {receiver.getPid(), 50}},
*(encryptors_.at((i + 1) % clients.size())));

d.budget_policy = false;
for (auto& b : banks) {
ASSERT_FALSE(b->validate(d, tx2));
}
}
}

Expand All @@ -600,8 +614,7 @@ TEST_F(ibe_based_test_system_minted_budget_policy_disabled, test_transaction) {
{coins[issuer.getPid()].front()},
std::nullopt,
{{issuer.getPid(), 50}, {receiver.getPid(), 50}},
*(encryptors_.at((i + 1) % clients.size())),
false);
*(encryptors_.at((i + 1) % clients.size())));
coins[issuer.getPid()].erase(coins[issuer.getPid()].begin());
std::map<size_t, std::vector<types::Signature>> shares;
std::vector<uint16_t> shares_signers;
Expand Down