Compare commits
1 commit
master
...
feature/GR
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1b3ae72b1 |
2 changed files with 99 additions and 3 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue