Skip to content

Commit 2fcbb3c

Browse files
committed
Range proof mantissa minimum bit length
1 parent b5ec44f commit 2fcbb3c

2 files changed

Lines changed: 94 additions & 87 deletions

File tree

libraries/wallet/wallet.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@
9090
#endif
9191

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

9498
namespace graphene { namespace wallet {
9599

@@ -5015,12 +5019,14 @@ blind_confirmation wallet_api::blind_transfer_help( string from_key_or_label,
50155019

50165020
if( blind_tr.outputs.size() > 1 )
50175021
{
5018-
to_out.range_proof = fc::ecc::range_proof_sign( 0, to_out.commitment, blind_factor, nonce, 0, 0, amount.amount.value );
5022+
to_out.range_proof = fc::ecc::range_proof_sign( 0, to_out.commitment, blind_factor, nonce,
5023+
0, RANGE_PROOF_MANTISSA, amount.amount.value );
50195024

50205025
blind_output change_out;
50215026
change_out.owner = authority( 1, public_key_type( from_pub_key.child( from_child ) ), 1 );
50225027
change_out.commitment = fc::ecc::blind( change_blind_factor, change.amount.value );
5023-
change_out.range_proof = fc::ecc::range_proof_sign( 0, change_out.commitment, change_blind_factor, from_nonce, 0, 0, change.amount.value );
5028+
change_out.range_proof = fc::ecc::range_proof_sign( 0, change_out.commitment, change_blind_factor, from_nonce,
5029+
0, RANGE_PROOF_MANTISSA, change.amount.value );
50245030
blind_tr.outputs[1] = change_out;
50255031

50265032

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

51335140

51345141
blind_confirmation::output conf_output;

tests/cli/main.cpp

Lines changed: 84 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -613,91 +613,91 @@ BOOST_FIXTURE_TEST_CASE( cli_set_voting_proxy, cli_fixture )
613613
///////////////////
614614
// Test blind transactions and mantissa length of range proofs.
615615
///////////////////
616-
// BOOST_FIXTURE_TEST_CASE( cli_confidential_tx_test, cli_fixture )
617-
// {
618-
// using namespace graphene::wallet;
619-
// try {
620-
// // we need to increase the default max transaction size to run this test.
621-
// this->app1->chain_database()->modify(
622-
// this->app1->chain_database()->get_global_properties(),
623-
// []( global_property_object& p) {
624-
// p.parameters.maximum_transaction_size = 8192;
625-
// });
626-
// std::vector<signed_transaction> import_txs;
616+
BOOST_FIXTURE_TEST_CASE( cli_confidential_tx_test, cli_fixture )
617+
{
618+
using namespace graphene::wallet;
619+
try {
620+
// we need to increase the default max transaction size to run this test.
621+
this->app1->chain_database()->modify(
622+
this->app1->chain_database()->get_global_properties(),
623+
[]( global_property_object& p) {
624+
p.parameters.maximum_transaction_size = 8192;
625+
});
626+
std::vector<signed_transaction> import_txs;
627627

628-
// BOOST_TEST_MESSAGE("Importing nathan's balance");
629-
// import_txs = con.wallet_api_ptr->import_balance("nathan", nathan_keys, true);
630-
631-
// unsigned int head_block = 0;
632-
// auto & W = *con.wallet_api_ptr; // Wallet alias
633-
634-
// BOOST_TEST_MESSAGE("Creating blind accounts");
635-
// graphene::wallet::brain_key_info bki_nathan = W.suggest_brain_key();
636-
// graphene::wallet::brain_key_info bki_alice = W.suggest_brain_key();
637-
// graphene::wallet::brain_key_info bki_bob = W.suggest_brain_key();
638-
// W.create_blind_account("nathan", bki_nathan.brain_priv_key);
639-
// W.create_blind_account("alice", bki_alice.brain_priv_key);
640-
// W.create_blind_account("bob", bki_bob.brain_priv_key);
641-
// BOOST_CHECK(W.get_blind_accounts().size() == 3);
642-
643-
// // ** Block 1: Import Nathan account:
644-
// BOOST_TEST_MESSAGE("Importing nathan key and balance");
645-
// std::vector<std::string> nathan_keys{"5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"};
646-
// W.import_key("nathan", nathan_keys[0]);
647-
// W.import_balance("nathan", nathan_keys, true);
648-
// generate_block(app1); head_block++;
649-
650-
// // ** Block 2: Nathan will blind 100M CORE token:
651-
// BOOST_TEST_MESSAGE("Blinding a large balance");
652-
// W.transfer_to_blind("nathan", GRAPHENE_SYMBOL, {{"nathan","100000000"}}, true);
653-
// BOOST_CHECK( W.get_blind_balances("nathan")[0].amount == 10000000000000 );
654-
// generate_block(app1); head_block++;
655-
656-
// // ** Block 3: Nathan will send 1M CORE token to alice and 10K CORE token to bob. We
657-
// // then confirm that balances are received, and then analyze the range
658-
// // prooofs to make sure the mantissa length does not reveal approximate
659-
// // balance (issue #480).
660-
// std::map<std::string, share_type> to_list = {{"alice",100000000000},
661-
// {"bob", 1000000000}};
662-
// vector<blind_confirmation> bconfs;
663-
// asset_object core_asset = W.get_asset("1.3.0");
664-
// BOOST_TEST_MESSAGE("Sending blind transactions to alice and bob");
665-
// for (auto to : to_list) {
666-
// string amount = core_asset.amount_to_string(to.second);
667-
// bconfs.push_back(W.blind_transfer("nathan",to.first,amount,core_asset.symbol,true));
668-
// BOOST_CHECK( W.get_blind_balances(to.first)[0].amount == to.second );
669-
// }
670-
// BOOST_TEST_MESSAGE("Inspecting range proof mantissa lengths");
671-
// vector<int> rp_mantissabits;
672-
// for (auto conf : bconfs) {
673-
// for (auto out : conf.trx.operations[0].get<blind_transfer_operation>().outputs) {
674-
// rp_mantissabits.push_back(1+out.range_proof[1]); // 2nd byte encodes mantissa length
675-
// }
676-
// }
677-
// // We are checking the mantissa length of the range proofs for several Pedersen
678-
// // commitments of varying magnitude. We don't want the mantissa lengths to give
679-
// // away magnitude. Deprecated wallet behavior was to use "just enough" mantissa
680-
// // bits to prove range, but this gives away value to within a factor of two. As a
681-
// // naive test, we assume that if all mantissa lengths are equal, then they are not
682-
// // revealing magnitude. However, future more-sophisticated wallet behavior
683-
// // *might* randomize mantissa length to achieve some space savings in the range
684-
// // proof. The following test will fail in that case and a more sophisticated test
685-
// // will be needed.
686-
// auto adjacent_unequal = std::adjacent_find(rp_mantissabits.begin(),
687-
// rp_mantissabits.end(), // find unequal adjacent values
688-
// std::not_equal_to<int>());
689-
// BOOST_CHECK(adjacent_unequal == rp_mantissabits.end());
690-
// generate_block(app1); head_block++;
691-
692-
// // ** Check head block:
693-
// BOOST_TEST_MESSAGE("Check that all expected blocks have processed");
694-
// dynamic_global_property_object dgp = W.get_dynamic_global_properties();
695-
// BOOST_CHECK(dgp.head_block_number == head_block);
696-
// } catch( fc::exception& e ) {
697-
// edump((e.to_detail_string()));
698-
// throw;
699-
// }
700-
// }
628+
BOOST_TEST_MESSAGE("Importing nathan's balance");
629+
import_txs = con.wallet_api_ptr->import_balance("nathan", nathan_keys, true);
630+
631+
unsigned int head_block = 0;
632+
auto & W = *con.wallet_api_ptr; // Wallet alias
633+
634+
BOOST_TEST_MESSAGE("Creating blind accounts");
635+
graphene::wallet::brain_key_info bki_nathan = W.suggest_brain_key();
636+
graphene::wallet::brain_key_info bki_alice = W.suggest_brain_key();
637+
graphene::wallet::brain_key_info bki_bob = W.suggest_brain_key();
638+
W.create_blind_account("nathan", bki_nathan.brain_priv_key);
639+
W.create_blind_account("alice", bki_alice.brain_priv_key);
640+
W.create_blind_account("bob", bki_bob.brain_priv_key);
641+
BOOST_CHECK(W.get_blind_accounts().size() == 3);
642+
643+
// ** Block 1: Import Nathan account:
644+
BOOST_TEST_MESSAGE("Importing nathan key and balance");
645+
std::vector<std::string> nathan_keys{"5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3"};
646+
W.import_key("nathan", nathan_keys[0]);
647+
W.import_balance("nathan", nathan_keys, true);
648+
generate_block(app1); head_block++;
649+
650+
// ** Block 2: Nathan will blind 100M CORE token:
651+
BOOST_TEST_MESSAGE("Blinding a large balance");
652+
W.transfer_to_blind("nathan", GRAPHENE_SYMBOL, {{"nathan","100000000"}}, true);
653+
BOOST_CHECK( W.get_blind_balances("nathan")[0].amount == 10000000000000 );
654+
generate_block(app1); head_block++;
655+
656+
// ** Block 3: Nathan will send 1M CORE token to alice and 10K CORE token to bob. We
657+
// then confirm that balances are received, and then analyze the range
658+
// prooofs to make sure the mantissa length does not reveal approximate
659+
// balance (issue #480).
660+
std::map<std::string, share_type> to_list = {{"alice",100000000000},
661+
{"bob", 1000000000}};
662+
vector<blind_confirmation> bconfs;
663+
asset_object core_asset = W.get_asset("1.3.0");
664+
BOOST_TEST_MESSAGE("Sending blind transactions to alice and bob");
665+
for (auto to : to_list) {
666+
string amount = core_asset.amount_to_string(to.second);
667+
bconfs.push_back(W.blind_transfer("nathan",to.first,amount,core_asset.symbol,true));
668+
BOOST_CHECK( W.get_blind_balances(to.first)[0].amount == to.second );
669+
}
670+
BOOST_TEST_MESSAGE("Inspecting range proof mantissa lengths");
671+
vector<int> rp_mantissabits;
672+
for (auto conf : bconfs) {
673+
for (auto out : conf.trx.operations[0].get<blind_transfer_operation>().outputs) {
674+
rp_mantissabits.push_back(1+out.range_proof[1]); // 2nd byte encodes mantissa length
675+
}
676+
}
677+
// We are checking the mantissa length of the range proofs for several Pedersen
678+
// commitments of varying magnitude. We don't want the mantissa lengths to give
679+
// away magnitude. Deprecated wallet behavior was to use "just enough" mantissa
680+
// bits to prove range, but this gives away value to within a factor of two. As a
681+
// naive test, we assume that if all mantissa lengths are equal, then they are not
682+
// revealing magnitude. However, future more-sophisticated wallet behavior
683+
// *might* randomize mantissa length to achieve some space savings in the range
684+
// proof. The following test will fail in that case and a more sophisticated test
685+
// will be needed.
686+
auto adjacent_unequal = std::adjacent_find(rp_mantissabits.begin(),
687+
rp_mantissabits.end(), // find unequal adjacent values
688+
std::not_equal_to<int>());
689+
BOOST_CHECK(adjacent_unequal == rp_mantissabits.end());
690+
generate_block(app1); head_block++;
691+
692+
// ** Check head block:
693+
BOOST_TEST_MESSAGE("Check that all expected blocks have processed");
694+
dynamic_global_property_object dgp = W.get_dynamic_global_properties();
695+
BOOST_CHECK(dgp.head_block_number == head_block);
696+
} catch( fc::exception& e ) {
697+
edump((e.to_detail_string()));
698+
throw;
699+
}
700+
}
701701

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

0 commit comments

Comments
 (0)