Compare commits

...

1 commit

Author SHA1 Message Date
Sandip Patel
f1b3ae72b1 Range proof mantissa minimum bit length 2019-09-13 12:52:37 +05:30
2 changed files with 99 additions and 3 deletions

View file

@ -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 {
@ -4795,12 +4799,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;
@ -4908,7 +4914,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;

View file

@ -438,3 +438,92 @@ BOOST_FIXTURE_TEST_CASE( cli_vote_for_2_witnesses, cli_fixture )
throw;
}
}
///////////////////
// 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_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;
}
}