Rebase onto master

This commit is contained in:
Vikram Rajkumar 2015-06-12 19:46:09 -04:00
parent 571555a253
commit cff606c9e2
7 changed files with 309 additions and 6 deletions

6
.gitignore vendored
View file

@ -1,11 +1,11 @@
*.a
*.sw*
*.cmake
CMakeCache.txt
CMakeFiles
Makefile
compile_commands.json
*.cmake
libraries/utilities/git_revision.cpp
@ -19,7 +19,7 @@ tests/chain_test
tests/intense_test
tests/performance_test
/doxygen
doxygen
witness_node_data_dir
wallet.json
witness_node_data_dir

View file

@ -19,5 +19,40 @@
namespace graphene { namespace chain {
/**
* @class blinded_balance_object
* @brief tracks a blinded balance commitment
* @ingroup object
* @ingroup protocol
*/
class blinded_balance_object : public graphene::db::abstract_object<blinded_balance_object>
{
public:
static const uint8_t space_id = protocol_ids;
static const uint8_t type_id = blinded_balance_object_type;
fc::ecc::commitment_type commitment;
asset_id_type asset_id;
static_variant<address,account_id_type> owner;
};
struct by_asset;
struct by_owner;
struct by_commitment;
/**
* @ingroup object_index
*/
typedef multi_index_container<
blinded_balance_object,
indexed_by<
ordered_unique< tag<by_id>, member< object, object_id_type, &object::id > >,
hashed_unique< tag<by_commitment>, member<blinded_balance_object, commitment_type, &blinded_balance_object::commitment> >
>
> blinded_balance_object_multi_index_type;
typedef generic_index<blinded_balance_object, blinded_balance_object_multi_index_type> balance_index;
} } // graphene::chain
FC_REFLECT( graphene::chain::blinded_balance_object, (commitment)(asset_id)(last_update_block_num)(owner) )

View file

@ -114,3 +114,13 @@
#define GRAPHENE_MAX_INTEREST_APR uint16_t( 10000 )
#define GRAPHENE_LEGACY_NAME_IMPORT_PERIOD 3000000 /** 3 million blocks */
/**
* Reserved Account IDs with special meaning
*/
///@{
#define GRAPHENE_GENESIS_ACCOUNT (graphene::chain::account_id_type(0))
#define GRAPHENE_WITNESS_ACCOUNT (graphene::chain::account_id_type(1))
#define GRAPHENE_DELEGATE_ACCOUNT (graphene::chain::account_id_type(2))
#define GRAPHENE_NULL_ACCOUNT (graphene::chain::account_id_type(3))
#define GRAPHENE_TEMP_ACCOUNT (graphene::chain::account_id_type(4))
///@}

View file

@ -465,6 +465,185 @@ namespace graphene { namespace chain {
acc.adjust( to, amount );
}
};
/**
* @defgroup stealth Stealth Transfer
* @brief Operations related to stealth transfer of value
*
* Stealth Transfers enable users to maintain their finanical privacy against even
* though all transactions are public. Every account has three balances:
*
* 1. Public Balance - every can see the balance changes and the parties involved
* 2. Blinded Balance - everyone can see who is transacting but not the amounts involved
* 3. Stealth Balance - both the amounts and parties involved are obscured
*
* Account owners may set a flag that allows their account to receive(or not) transfers of these kinds
* Asset issuers can enable or disable the use of each of these types of accounts.
*
* Using the "temp account" which has no permissions required, users can transfer a
* stealth balance to the temp account and then use the temp account to register a new
* account. In this way users can use stealth funds to create anonymous accounts with which
* they can perform other actions that are not compatible with blinded balances (such as market orders)
*
* @section referral_program Referral Progam
*
* Stealth transfers that do not specify any account id cannot pay referral fees so 100% of the
* transaction fee is paid to the network.
*
* @section transaction_fees Fees
*
* Stealth transfers can have an arbitrarylly large size and therefore the transaction fee for
* stealth transfers is based purley on the data size of the transaction.
*/
///@{
/**
* @ingroup stealth
* This data is encrypted and stored in the
* encrypted memo portion of the blind output.
*/
struct blind_memo
{
account_id_type from;
share_type amount;
string message;
/** set to the first 4 bytes of the shared secret
* used to encrypt the memo. Used to verify that
* decryption was successful.
*/
uint32_t check= 0;
};
/**
* @ingroup stealth
*/
struct blind_input
{
fc::ecc::commitment_type commitment;
/** provided to maintain the invariant that all authority
* required by an operation is explicit in the operation. Must
* match blinded_balance_id->owner
*/
static_variant<address,account_id_type> owner;
};
/**
* @class blind_output
* @brief Defines data required to create a new blind commitment
* @ingroup stealth
*
* The blinded output that must be proven to be greater than 0
*/
struct blind_output
{
fc::ecc::commitment_type commitment;
/** only required if there is more than one blind output */
range_proof_type range_proof;
static_variant<address,account_id_type> owner;
public_key_type one_time_key;
/** encrypted via aes with shared secret derived from
* one_time_key and (owner or owner.memo_key)
*/
vector<char> encrypted_memo;
};
/**
* @class transfer_to_blind_operation
* @ingroup stealth
* @brief Converts public account balance to a blinded or stealth balance
*/
struct transfer_to_blind_operation
{
asset fee;
asset amount;
account_id_type from;
vector<blind_output> outputs;
account_id_type fee_payer()const;
void get_required_auth( flat_set<account_id_type>& active_auth_set,
flat_set<account_id_type>& )const;
void validate()const;
share_type calculate_fee( const fee_schedule_type& k )const;
void get_balance_delta( balance_accumulator& acc, const operation_result& result = asset())const;
};
/**
* @ingroup stealth
* @brief Converts blinded/stealth balance to a public account balance
*/
struct transfer_from_blind_operation
{
asset fee;
asset amount;
account_id_type to;
vector<blind_input> inputs;
account_id_type fee_payer()const;
void get_required_auth( flat_set<account_id_type>& active_auth_set,
flat_set<account_id_type>& )const;
void validate()const;
share_type calculate_fee( const fee_schedule_type& k )const;
void get_balance_delta( balance_accumulator& acc, const operation_result& result = asset())const;
};
/**
* @ingroup stealth
* @brief Transfers from blind to blind
*
* There are two ways to transfer value while maintaining privacy:
* 1. account to account with amount kept secret
* 2. stealth transfers with amount sender/receiver kept secret
*
* When doing account to account transfers, everyone with access to the
* memo key can see the amounts, but they will not have access to the funds.
*
* When using stealth transfers the same key is used for control and reading
* the memo.
*
* This operation is more expensive than a normal transfer and has
* a fee proportional to the size of the operation.
*
* All assets in a blind transfer must be of the same type: fee.asset_id
* The fee_payer is the temp account and can be funded from the blinded values.
*
* Using this operation you can transfer from an account and/or blinded balances
* to an account and/or blinded balances.
*
* Stealth Transfers:
*
* Assuming Receiver has key pair R,r and has shared public key R with Sender
* Assuming Sender has key pair S,s
* Generate one time key pair O,o as s.child(nonce) where nonce can be inferred from transaction
* Calculate secret V = o*R
* blinding_factor = sha256(V)
* memo is encrypted via aes of V
* owner = R.child(sha256(blinding_factor))
*
* Sender gives Receiver output ID to complete the payment.
*
* This process can also be used to send money to a cold wallet without having to
* pre-register any accounts.
*
* Outputs are assigned the same IDs as the inputs until no more input IDs are available,
* in which case a the return value will be the *first* ID allocated for an output. Additional
* output IDs are allocated sequentially thereafter. If there are fewer outputs than inputs
* then the input IDs are freed and never used again.
*/
struct blind_transfer_operation
{
asset fee;
account_id_type fee_payer_id;
vector<blind_input> inputs;
vector<blind_output> outputs;
account_id_type fee_payer()const;
void get_required_auth( flat_set<account_id_type>& active_auth_set,
flat_set<account_id_type>& )const;
void validate()const;
share_type calculate_fee( const fee_schedule_type& k )const;
void get_balance_delta( balance_accumulator& acc, const operation_result& result = asset())const;
};
///@} endgroup stealth
/**
* @ingroup operations
@ -1868,5 +2047,16 @@ FC_REFLECT( graphene::chain::worker_create_operation,
FC_REFLECT( graphene::chain::custom_operation, (fee)(payer)(required_auths)(id)(data) )
FC_REFLECT( graphene::chain::void_result, )
FC_REFLECT( graphene::chain::blind_transfer_operation::blind_memo,
(from)(amount)(message)(check) )
FC_REFLECT( graphene::chain::blind_transfer_operation::blind_input,
(commitment)(owner) )
FC_REFLECT( graphene::chain::blind_transfer_operation::blind_output,
(commitment)(range_proof)(owner)(one_time_key)(encrypted_memo) )
FC_REFLECT( graphene::chain::blind_transfer_operation,
(fee)(fee_payer_id)
(from_account)(from_amount)
(to_account)(to_account_name)(to_address)(to_amount) )
FC_REFLECT_TYPENAME( graphene::chain::operation )
FC_REFLECT_TYPENAME( fc::flat_set<graphene::chain::vote_id_type> )

View file

@ -142,10 +142,17 @@ namespace graphene { namespace chain {
: transaction(trx){}
void sign( key_id_type id, const private_key_type& key );
flat_map<key_id_type,signature_type> signatures;
/** some operations may depend only upon a signature and not
* require account approval. This allows those extra signatures
* to be added to the transaction.
*/
flat_map<address,signature_type> extra_signatures;
/// Removes all operations and signatures
void clear() { operations.clear(); signatures.clear(); }
void clear() { operations.clear(); signatures.clear(); extra_signatures.clear(); }
};
/**
@ -177,6 +184,5 @@ namespace graphene { namespace chain {
} }
FC_REFLECT( graphene::chain::transaction, (ref_block_num)(ref_block_prefix)(relative_expiration)(operations) )
FC_REFLECT_DERIVED( graphene::chain::signed_transaction, (graphene::chain::transaction), (signatures) )
FC_REFLECT_DERIVED( graphene::chain::signed_transaction, (graphene::chain::transaction), (signatures)(extra_signatures) )
FC_REFLECT_DERIVED( graphene::chain::processed_transaction, (graphene::chain::signed_transaction), (operation_results) )

View file

@ -63,6 +63,9 @@ namespace graphene { namespace chain {
using fc::flat_map;
using fc::flat_set;
using fc::static_variant;
using fc::ecc::range_proof_type;
using fc::ecc::range_proof_info;
using fc::ecc::commitment_type;
typedef fc::ecc::private_key private_key_type;

View file

@ -935,4 +935,63 @@ share_type account_upgrade_operation::calculate_fee(const fee_schedule_type& k)
return k.membership_annual_fee;
}
/**
* If fee_payer = temp_account_id, then the fee is paid by the surplus balance of inputs-outputs and
* 100% of the fee goes to the network.
*/
account_id_type blind_transfer_operation::fee_payer()const
{
return fee_payer_id;
}
void blind_transfer_operation::get_required_auth(flat_set<account_id_type>& active_auth_set, flat_set<account_id_type>&)const
{
active_auth_set.insert( fee_payer_id );
active_auth_set.insert( from_account );
for( auto input : inputs )
{
if( input.owner.which() == static_variant<address,account_id_type>::tag<account_id_type>::value )
active_auth_set.insert( input.owner.get<account_id_type>() );
}
}
/**
* This method can be computationally intensive because it verifies that input commitments - output commitments add up to 0
*/
void blind_transfer_operation::validate()const
{
vector<commitment_type> in(inputs.size());
vector<commitment_type> out(outputs.size());
int64_t net_public = from_amount.value - to_amount.value;
for( uint32_t i = 0; i < in.size(); ++i ) in[i] = inputs[i].commitment;
for( uint32_t i = 0; i < out.size(); ++i ) out[i] = outputs[i].commitment;
FC_ASSERT( in.size() + out.size() || net_public == 0 );
if( fee_payer_id == GRAPHENE_TEMP_ACCOUNT ) net_public -= fee.amount.value;
FC_ASSERT( fc::ecc::verify_sum( in, out, net_public ) );
if( outputs.size() > 1 )
{
for( auto out : outputs )
{
auto info = fc::ecc::range_get_info( out.range_proof );
FC_ASSERT( info.min_value >= 0 );
FC_ASSERT( info.max_value <= GRAPHENE_MAX_SHARE_SUPPLY );
}
}
}
share_type blind_transfer_operation::calculate_fee( const fee_schedule_type& k )const
{
auto size = 1024 + fc::raw::pack_size(*this);
return (k.blind_transfer_fee * size)/1024;
}
void blind_transfer_operation::get_balance_delta( balance_accumulator& acc,
const operation_result& result)const
{
acc.adjust( fee_payer(), -fee );
acc.adjust( from_account, asset(-from_amount,fee.asset_id) );
acc.adjust( to_account, asset(to_amount,fee.asset_id) );
}
} } // namespace graphene::chain