Skip to content

Commit

Permalink
Range proof mantissa minimum bit length
Browse files Browse the repository at this point in the history
  • Loading branch information
srpatel19590 committed Sep 4, 2019
1 parent b5ec44f commit 2fcbb3c
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 87 deletions.
13 changes: 10 additions & 3 deletions libraries/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@
#endif

#define BRAIN_KEY_WORD_COUNT 16
#define RANGE_PROOF_MANTISSA 49 // Minimum mantissa bits to "hide" in the range proof.
// If this number is set too low, then for large value
// commitments the length of the range proof will hint
// strongly at the value amount that is being hidden.

namespace graphene { namespace wallet {

Expand Down Expand Up @@ -5015,12 +5019,14 @@ blind_confirmation wallet_api::blind_transfer_help( string from_key_or_label,

if( blind_tr.outputs.size() > 1 )
{
to_out.range_proof = fc::ecc::range_proof_sign( 0, to_out.commitment, blind_factor, nonce, 0, 0, amount.amount.value );
to_out.range_proof = fc::ecc::range_proof_sign( 0, to_out.commitment, blind_factor, nonce,
0, RANGE_PROOF_MANTISSA, amount.amount.value );

blind_output change_out;
change_out.owner = authority( 1, public_key_type( from_pub_key.child( from_child ) ), 1 );
change_out.commitment = fc::ecc::blind( change_blind_factor, change.amount.value );
change_out.range_proof = fc::ecc::range_proof_sign( 0, change_out.commitment, change_blind_factor, from_nonce, 0, 0, change.amount.value );
change_out.range_proof = fc::ecc::range_proof_sign( 0, change_out.commitment, change_blind_factor, from_nonce,
0, RANGE_PROOF_MANTISSA, change.amount.value );
blind_tr.outputs[1] = change_out;


Expand Down Expand Up @@ -5128,7 +5134,8 @@ blind_confirmation wallet_api::transfer_to_blind( string from_account_id_or_name
out.owner = authority( 1, public_key_type( to_pub_key.child( child ) ), 1 );
out.commitment = fc::ecc::blind( blind_factor, amount.amount.value );
if( to_amounts.size() > 1 )
out.range_proof = fc::ecc::range_proof_sign( 0, out.commitment, blind_factor, nonce, 0, 0, amount.amount.value );
out.range_proof = fc::ecc::range_proof_sign( 0, out.commitment, blind_factor, nonce,
0, RANGE_PROOF_MANTISSA, amount.amount.value );


blind_confirmation::output conf_output;
Expand Down
168 changes: 84 additions & 84 deletions tests/cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -613,91 +613,91 @@ BOOST_FIXTURE_TEST_CASE( cli_set_voting_proxy, cli_fixture )
///////////////////
// Test blind transactions and mantissa length of range proofs.
///////////////////
// BOOST_FIXTURE_TEST_CASE( cli_confidential_tx_test, cli_fixture )
// {
// using namespace graphene::wallet;
// try {
// // we need to increase the default max transaction size to run this test.
// this->app1->chain_database()->modify(
// this->app1->chain_database()->get_global_properties(),
// []( global_property_object& p) {
// p.parameters.maximum_transaction_size = 8192;
// });
// std::vector<signed_transaction> import_txs;
BOOST_FIXTURE_TEST_CASE( cli_confidential_tx_test, cli_fixture )
{
using namespace graphene::wallet;
try {
// we need to increase the default max transaction size to run this test.
this->app1->chain_database()->modify(
this->app1->chain_database()->get_global_properties(),
[]( global_property_object& p) {
p.parameters.maximum_transaction_size = 8192;
});
std::vector<signed_transaction> import_txs;

// BOOST_TEST_MESSAGE("Importing nathan's balance");
// import_txs = con.wallet_api_ptr->import_balance("nathan", nathan_keys, true);

// unsigned int head_block = 0;
// auto & W = *con.wallet_api_ptr; // Wallet alias

// BOOST_TEST_MESSAGE("Creating blind accounts");
// graphene::wallet::brain_key_info bki_nathan = W.suggest_brain_key();
// graphene::wallet::brain_key_info bki_alice = W.suggest_brain_key();
// graphene::wallet::brain_key_info bki_bob = W.suggest_brain_key();
// W.create_blind_account("nathan", bki_nathan.brain_priv_key);
// W.create_blind_account("alice", bki_alice.brain_priv_key);
// W.create_blind_account("bob", bki_bob.brain_priv_key);
// BOOST_CHECK(W.get_blind_accounts().size() == 3);

// // ** Block 1: Import Nathan account:
// BOOST_TEST_MESSAGE("Importing nathan key and balance");
// std::vector<std::string> nathan_keys{"5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"};
// W.import_key("nathan", nathan_keys[0]);
// W.import_balance("nathan", nathan_keys, true);
// generate_block(app1); head_block++;

// // ** Block 2: Nathan will blind 100M CORE token:
// BOOST_TEST_MESSAGE("Blinding a large balance");
// W.transfer_to_blind("nathan", GRAPHENE_SYMBOL, {{"nathan","100000000"}}, true);
// BOOST_CHECK( W.get_blind_balances("nathan")[0].amount == 10000000000000 );
// generate_block(app1); head_block++;

// // ** Block 3: Nathan will send 1M CORE token to alice and 10K CORE token to bob. We
// // then confirm that balances are received, and then analyze the range
// // prooofs to make sure the mantissa length does not reveal approximate
// // balance (issue #480).
// std::map<std::string, share_type> to_list = {{"alice",100000000000},
// {"bob", 1000000000}};
// vector<blind_confirmation> bconfs;
// asset_object core_asset = W.get_asset("1.3.0");
// BOOST_TEST_MESSAGE("Sending blind transactions to alice and bob");
// for (auto to : to_list) {
// string amount = core_asset.amount_to_string(to.second);
// bconfs.push_back(W.blind_transfer("nathan",to.first,amount,core_asset.symbol,true));
// BOOST_CHECK( W.get_blind_balances(to.first)[0].amount == to.second );
// }
// BOOST_TEST_MESSAGE("Inspecting range proof mantissa lengths");
// vector<int> rp_mantissabits;
// for (auto conf : bconfs) {
// for (auto out : conf.trx.operations[0].get<blind_transfer_operation>().outputs) {
// rp_mantissabits.push_back(1+out.range_proof[1]); // 2nd byte encodes mantissa length
// }
// }
// // We are checking the mantissa length of the range proofs for several Pedersen
// // commitments of varying magnitude. We don't want the mantissa lengths to give
// // away magnitude. Deprecated wallet behavior was to use "just enough" mantissa
// // bits to prove range, but this gives away value to within a factor of two. As a
// // naive test, we assume that if all mantissa lengths are equal, then they are not
// // revealing magnitude. However, future more-sophisticated wallet behavior
// // *might* randomize mantissa length to achieve some space savings in the range
// // proof. The following test will fail in that case and a more sophisticated test
// // will be needed.
// auto adjacent_unequal = std::adjacent_find(rp_mantissabits.begin(),
// rp_mantissabits.end(), // find unequal adjacent values
// std::not_equal_to<int>());
// BOOST_CHECK(adjacent_unequal == rp_mantissabits.end());
// generate_block(app1); head_block++;

// // ** Check head block:
// BOOST_TEST_MESSAGE("Check that all expected blocks have processed");
// dynamic_global_property_object dgp = W.get_dynamic_global_properties();
// BOOST_CHECK(dgp.head_block_number == head_block);
// } catch( fc::exception& e ) {
// edump((e.to_detail_string()));
// throw;
// }
// }
BOOST_TEST_MESSAGE("Importing nathan's balance");
import_txs = con.wallet_api_ptr->import_balance("nathan", nathan_keys, true);

unsigned int head_block = 0;
auto & W = *con.wallet_api_ptr; // Wallet alias

BOOST_TEST_MESSAGE("Creating blind accounts");
graphene::wallet::brain_key_info bki_nathan = W.suggest_brain_key();
graphene::wallet::brain_key_info bki_alice = W.suggest_brain_key();
graphene::wallet::brain_key_info bki_bob = W.suggest_brain_key();
W.create_blind_account("nathan", bki_nathan.brain_priv_key);
W.create_blind_account("alice", bki_alice.brain_priv_key);
W.create_blind_account("bob", bki_bob.brain_priv_key);
BOOST_CHECK(W.get_blind_accounts().size() == 3);

// ** Block 1: Import Nathan account:
BOOST_TEST_MESSAGE("Importing nathan key and balance");
std::vector<std::string> nathan_keys{"5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"};
W.import_key("nathan", nathan_keys[0]);
W.import_balance("nathan", nathan_keys, true);
generate_block(app1); head_block++;

// ** Block 2: Nathan will blind 100M CORE token:
BOOST_TEST_MESSAGE("Blinding a large balance");
W.transfer_to_blind("nathan", GRAPHENE_SYMBOL, {{"nathan","100000000"}}, true);
BOOST_CHECK( W.get_blind_balances("nathan")[0].amount == 10000000000000 );
generate_block(app1); head_block++;

// ** Block 3: Nathan will send 1M CORE token to alice and 10K CORE token to bob. We
// then confirm that balances are received, and then analyze the range
// prooofs to make sure the mantissa length does not reveal approximate
// balance (issue #480).
std::map<std::string, share_type> to_list = {{"alice",100000000000},
{"bob", 1000000000}};
vector<blind_confirmation> bconfs;
asset_object core_asset = W.get_asset("1.3.0");
BOOST_TEST_MESSAGE("Sending blind transactions to alice and bob");
for (auto to : to_list) {
string amount = core_asset.amount_to_string(to.second);
bconfs.push_back(W.blind_transfer("nathan",to.first,amount,core_asset.symbol,true));
BOOST_CHECK( W.get_blind_balances(to.first)[0].amount == to.second );
}
BOOST_TEST_MESSAGE("Inspecting range proof mantissa lengths");
vector<int> rp_mantissabits;
for (auto conf : bconfs) {
for (auto out : conf.trx.operations[0].get<blind_transfer_operation>().outputs) {
rp_mantissabits.push_back(1+out.range_proof[1]); // 2nd byte encodes mantissa length
}
}
// We are checking the mantissa length of the range proofs for several Pedersen
// commitments of varying magnitude. We don't want the mantissa lengths to give
// away magnitude. Deprecated wallet behavior was to use "just enough" mantissa
// bits to prove range, but this gives away value to within a factor of two. As a
// naive test, we assume that if all mantissa lengths are equal, then they are not
// revealing magnitude. However, future more-sophisticated wallet behavior
// *might* randomize mantissa length to achieve some space savings in the range
// proof. The following test will fail in that case and a more sophisticated test
// will be needed.
auto adjacent_unequal = std::adjacent_find(rp_mantissabits.begin(),
rp_mantissabits.end(), // find unequal adjacent values
std::not_equal_to<int>());
BOOST_CHECK(adjacent_unequal == rp_mantissabits.end());
generate_block(app1); head_block++;

// ** Check head block:
BOOST_TEST_MESSAGE("Check that all expected blocks have processed");
dynamic_global_property_object dgp = W.get_dynamic_global_properties();
BOOST_CHECK(dgp.head_block_number == head_block);
} catch( fc::exception& e ) {
edump((e.to_detail_string()));
throw;
}
}

// TODO: Enable this test after incorporating https://github.com/bitshares/bitshares-core/issues/1176
/******
Expand Down

0 comments on commit 2fcbb3c

Please sign in to comment.