mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 10:35:50 +00:00
More work on the new wallet code.
This commit is contained in:
@@ -103,6 +103,38 @@ EC_KEY* CKey::GenerateRootDeterministicKey(const uint256& key)
|
||||
return pkey;
|
||||
}
|
||||
|
||||
EC_KEY* CKey::GenerateRootPubKey(const std::string& pubHex)
|
||||
{
|
||||
BIGNUM* bn=NULL;
|
||||
BN_hex2bn(&bn, pubHex.c_str());
|
||||
if(bn==NULL) return NULL;
|
||||
|
||||
EC_KEY* pkey=EC_KEY_new_by_curve_name(NID_secp256k1);
|
||||
if(!pkey)
|
||||
{
|
||||
BN_free(bn);
|
||||
return NULL;
|
||||
}
|
||||
EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
|
||||
|
||||
EC_POINT* pubPoint=EC_POINT_bn2point(EC_KEY_get0_group(pkey), bn, NULL, NULL);
|
||||
BN_free(bn);
|
||||
if(!pubPoint)
|
||||
{
|
||||
EC_KEY_free(pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!EC_KEY_set_public_key(pkey, pubPoint))
|
||||
{
|
||||
EC_POINT_free(pubPoint);
|
||||
EC_KEY_free(pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pkey;
|
||||
}
|
||||
|
||||
static BIGNUM* makeHash(const uint160& family, int seq)
|
||||
{
|
||||
Serializer s;
|
||||
@@ -113,7 +145,7 @@ static BIGNUM* makeHash(const uint160& family, int seq)
|
||||
return BN_bin2bn((const unsigned char *) &root, sizeof(root), NULL);
|
||||
}
|
||||
|
||||
EC_KEY* CKey::GeneratePublicDeterministicKey(const uint160& family, EC_POINT* rootPubKey, int seq)
|
||||
EC_KEY* CKey::GeneratePublicDeterministicKey(const uint160& family, const EC_POINT* rootPubKey, int seq)
|
||||
{ // publicKey(n) = rootPublicKey EC_POINT_+ Hash(pubHash|seq)*point
|
||||
BN_CTX* ctx=BN_CTX_new();
|
||||
if(ctx==NULL) return NULL;
|
||||
@@ -154,8 +186,8 @@ EC_KEY* CKey::GeneratePublicDeterministicKey(const uint160& family, EC_POINT* ro
|
||||
|
||||
return pkey;
|
||||
}
|
||||
|
||||
EC_KEY* CKey::GeneratePrivateDeterministicKey(const uint160& family, BIGNUM* rootPrivKey, int seq)
|
||||
|
||||
EC_KEY* CKey::GeneratePrivateDeterministicKey(const uint160& family, const BIGNUM* rootPrivKey, int seq)
|
||||
{ // privateKey(n) = (rootPrivateKey + Hash(pubHash|seq)) % order
|
||||
BN_CTX* ctx=BN_CTX_new();
|
||||
if(ctx==NULL) return NULL;
|
||||
|
||||
163
Wallet.cpp
163
Wallet.cpp
@@ -17,7 +17,7 @@ LocalAccountEntry::LocalAccountEntry(const uint160& accountFamily, int accountSe
|
||||
if(theApp!=NULL) mPublicKey=theApp->getPubKeyCache().store(mAcctID, mPublicKey);
|
||||
}
|
||||
|
||||
void LocalAccountEntry::unlock(BIGNUM* rootPrivKey)
|
||||
void LocalAccountEntry::unlock(const BIGNUM* rootPrivKey)
|
||||
{
|
||||
if((mPrivateKey==NULL) && (rootPrivKey!=NULL))
|
||||
mPrivateKey=CKey::pointer(new CKey(mAccountFamily, rootPrivKey, mAccountSeq));
|
||||
@@ -35,7 +35,16 @@ std::string LocalAccountEntry::getLocalAccountName() const
|
||||
|
||||
LocalAccountFamily::LocalAccountFamily(const uint160& family, EC_POINT* pubKey) :
|
||||
mFamily(family), mRootPubKey(pubKey), mLastSeq(0), mRootPrivateKey(NULL)
|
||||
{ ; }
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "LocalAccountFamily::LocalAccountFamily(" << family.GetHex() << "," << std::endl;
|
||||
EC_GROUP *grp=EC_GROUP_new_by_curve_name(NID_secp256k1);
|
||||
char *p2h=EC_POINT_point2hex(grp, pubKey, POINT_CONVERSION_COMPRESSED, NULL);
|
||||
EC_GROUP_free(grp);
|
||||
std::cerr << " " << p2h << ")" << std::endl;
|
||||
OPENSSL_free(p2h);
|
||||
#endif
|
||||
}
|
||||
|
||||
LocalAccountFamily::~LocalAccountFamily()
|
||||
{
|
||||
@@ -54,10 +63,9 @@ uint160 LocalAccountFamily::getAccount(int seq)
|
||||
return lae->getAccountID();
|
||||
}
|
||||
|
||||
void LocalAccountFamily::unlock(BIGNUM* privateKey)
|
||||
void LocalAccountFamily::unlock(const BIGNUM* privateKey)
|
||||
{
|
||||
if(mRootPrivateKey!=NULL) BN_free(mRootPrivateKey);
|
||||
mRootPrivateKey=privateKey;
|
||||
if(mRootPrivateKey!=NULL) mRootPrivateKey=BN_dup(privateKey);
|
||||
}
|
||||
|
||||
void LocalAccountFamily::lock()
|
||||
@@ -83,6 +91,7 @@ std::string LocalAccountFamily::getPubKeyHex() const
|
||||
if(!pubBase) return "";
|
||||
char *hex=BN_bn2hex(pubBase);
|
||||
BN_free(pubBase);
|
||||
|
||||
if(!hex) return "";
|
||||
std::string ret(hex);
|
||||
OPENSSL_free(hex);
|
||||
@@ -126,44 +135,23 @@ LocalAccountEntry::pointer LocalAccountFamily::get(int seq)
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint160 Wallet::addFamily(const uint256& key, bool lock)
|
||||
{
|
||||
LocalAccountFamily::pointer fam(doPrivate(key, true, !lock));
|
||||
if(!fam) return uint160();
|
||||
return fam->getFamily();
|
||||
}
|
||||
|
||||
uint160 Wallet::addFamily(const std::string& payPhrase, bool lock)
|
||||
{
|
||||
return doPrivate(CKey::PassPhraseToKey(payPhrase), true, !lock);
|
||||
return addFamily(CKey::PassPhraseToKey(payPhrase), lock);
|
||||
}
|
||||
|
||||
LocalAccountFamily::pointer Wallet::getFamily(const uint160& family, const std::string& pubKey)
|
||||
uint160 Wallet::addFamily(const std::string& pubKey)
|
||||
{
|
||||
std::map<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(family);
|
||||
if(fit!=families.end()) // already added
|
||||
return fit->second;
|
||||
|
||||
EC_GROUP *grp=EC_GROUP_new_by_curve_name(NID_secp256k1);
|
||||
if(!grp) return LocalAccountFamily::pointer();
|
||||
|
||||
BIGNUM* pbn=NULL;
|
||||
BN_hex2bn(&pbn, pubKey.c_str());
|
||||
if(!pbn)
|
||||
{
|
||||
EC_GROUP_free(grp);
|
||||
return LocalAccountFamily::pointer();
|
||||
}
|
||||
EC_POINT* rootPub=EC_POINT_bn2point(grp, pbn, NULL, NULL);
|
||||
EC_GROUP_free(grp);
|
||||
BN_free(pbn);
|
||||
if(!rootPub)
|
||||
{
|
||||
assert(false);
|
||||
return LocalAccountFamily::pointer();
|
||||
}
|
||||
|
||||
LocalAccountFamily::pointer fam(new LocalAccountFamily(family, rootPub));
|
||||
families.insert(std::make_pair(family, fam));
|
||||
return fam;
|
||||
}
|
||||
|
||||
bool Wallet::addFamily(const uint160& familyName, const std::string& pubKey)
|
||||
{
|
||||
return !!getFamily(familyName, pubKey);
|
||||
LocalAccountFamily::pointer fam(doPublic(pubKey));
|
||||
if(!fam) return uint160();
|
||||
return fam->getFamily();
|
||||
}
|
||||
|
||||
uint160 LocalAccount::getAddress() const
|
||||
@@ -221,9 +209,10 @@ void Wallet::load()
|
||||
uint160 fb;
|
||||
fb.SetHex(family);
|
||||
|
||||
LocalAccountFamily::pointer f(getFamily(fb, rootpub));
|
||||
LocalAccountFamily::pointer f(doPublic(rootpub));
|
||||
if(f)
|
||||
{
|
||||
assert(f->getFamily()==fb);
|
||||
f->setSeq(seq);
|
||||
f->setName(name);
|
||||
f->setComment(comment);
|
||||
@@ -236,6 +225,7 @@ std::string Wallet::getPubKeyHex(const uint160& famBase)
|
||||
{
|
||||
std::map<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(famBase);
|
||||
if(fit==families.end()) return "";
|
||||
assert(fit->second->getFamily()==famBase);
|
||||
return fit->second->getPubKeyHex();
|
||||
}
|
||||
|
||||
@@ -253,7 +243,51 @@ LocalAccount::pointer Wallet::getLocalAccount(const uint160& family, int seq)
|
||||
return lac;
|
||||
}
|
||||
|
||||
uint160 Wallet::doPrivate(const uint256& passPhrase, bool create, bool unlock)
|
||||
void Wallet::delFamily(const uint160& familyName)
|
||||
{
|
||||
std::map<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(familyName);
|
||||
if(fit==families.end()) return;
|
||||
|
||||
std::map<int, LocalAccountEntry::pointer>& acctMap=fit->second->getAcctMap();
|
||||
for(std::map<int, LocalAccountEntry::pointer>::iterator it=acctMap.begin(); it!=acctMap.end(); ++it)
|
||||
accounts.erase(it->second->getAccountID());
|
||||
|
||||
families.erase(familyName);
|
||||
}
|
||||
|
||||
LocalAccountFamily::pointer Wallet::doPublic(const std::string& pubKey)
|
||||
{
|
||||
// Generate root key
|
||||
EC_KEY *pkey=CKey::GenerateRootPubKey(pubKey);
|
||||
|
||||
// Extract family name
|
||||
std::vector<unsigned char> rootPubKey(33, 0);
|
||||
unsigned char *begin=&rootPubKey[0];
|
||||
i2o_ECPublicKey(pkey, &begin);
|
||||
while(rootPubKey.size()<33) rootPubKey.push_back((unsigned char)0);
|
||||
uint160 family=NewcoinAddress(rootPubKey).GetHash160();
|
||||
|
||||
std::map<uint160, LocalAccountFamily::pointer>::iterator fit=families.find(family);
|
||||
if(fit!=families.end()) // already added
|
||||
{
|
||||
EC_KEY_free(pkey);
|
||||
return fit->second;
|
||||
}
|
||||
|
||||
EC_POINT* rootPub=EC_POINT_dup(EC_KEY_get0_public_key(pkey), EC_KEY_get0_group(pkey));
|
||||
EC_KEY_free(pkey);
|
||||
if(!rootPub)
|
||||
{
|
||||
assert(false);
|
||||
return LocalAccountFamily::pointer();
|
||||
}
|
||||
|
||||
LocalAccountFamily::pointer fam(new LocalAccountFamily(family, rootPub));
|
||||
families.insert(std::make_pair(family, fam));
|
||||
return fam;
|
||||
}
|
||||
|
||||
LocalAccountFamily::pointer Wallet::doPrivate(const uint256& passPhrase, bool do_create, bool do_unlock)
|
||||
{
|
||||
// Generate root key
|
||||
EC_KEY *base=CKey::GenerateRootDeterministicKey(passPhrase);
|
||||
@@ -269,30 +303,35 @@ uint160 Wallet::doPrivate(const uint256& passPhrase, bool create, bool unlock)
|
||||
std::map<uint160, LocalAccountFamily::pointer>::iterator it=families.find(family);
|
||||
if(it==families.end())
|
||||
{ // family not found
|
||||
if(!create)
|
||||
if(!do_create)
|
||||
{
|
||||
EC_KEY_free(base);
|
||||
return family;
|
||||
return LocalAccountFamily::pointer();
|
||||
}
|
||||
fam=LocalAccountFamily::pointer(new LocalAccountFamily(family,
|
||||
EC_POINT_dup(EC_KEY_get0_public_key(base), EC_KEY_get0_group(base))));
|
||||
families[family]=fam;
|
||||
EC_POINT *pubKey=EC_POINT_dup(EC_KEY_get0_public_key(base), EC_KEY_get0_group(base));
|
||||
if(!pubKey)
|
||||
{
|
||||
EC_KEY_free(base);
|
||||
return LocalAccountFamily::pointer();
|
||||
}
|
||||
fam=LocalAccountFamily::pointer(new LocalAccountFamily(family, pubKey));
|
||||
families.insert(std::make_pair(family, fam));
|
||||
}
|
||||
else fam=it->second;
|
||||
|
||||
if(unlock && fam->isLocked())
|
||||
fam->unlock(BN_dup(EC_KEY_get0_private_key(base)));
|
||||
if(do_unlock && fam->isLocked())
|
||||
fam->unlock(EC_KEY_get0_private_key(base));
|
||||
|
||||
EC_KEY_free(base);
|
||||
return family;
|
||||
return fam;
|
||||
}
|
||||
|
||||
bool Wallet::unitTest()
|
||||
{ // Create 100 keys for each of 1,000 families Ensure all keys match
|
||||
Wallet pub, priv;
|
||||
|
||||
uint256 privBase;
|
||||
privBase.SetHex("102031459e");
|
||||
uint256 privBase(time(NULL)^(getpid()<<16));
|
||||
// privBase.SetHex("102031459e");
|
||||
|
||||
for(int i=0; i<1000; i++, privBase++)
|
||||
{
|
||||
@@ -307,12 +346,24 @@ bool Wallet::unitTest()
|
||||
std::cerr << "Pub: " << pubkey << std::endl;
|
||||
#endif
|
||||
|
||||
if(!pub.addFamily(fam, pubkey))
|
||||
if(pub.addFamily(pubkey)!=fam)
|
||||
{
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(pub.getPubKeyHex(fam)!=pubkey)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << std::endl;
|
||||
std::cerr << "PuK: " << pub.getPubKeyHex(fam) << std::endl;
|
||||
std::cerr << "PrK: " << priv.getPubKeyHex(fam) << std::endl;
|
||||
std::cerr << "Fam: " << fam.GetHex() << std::endl;
|
||||
#endif
|
||||
assert(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
for(int j=0; j<100; j++)
|
||||
{
|
||||
LocalAccount::pointer lpub=pub.getLocalAccount(fam, j);
|
||||
@@ -325,8 +376,9 @@ bool Wallet::unitTest()
|
||||
uint160 lpuba=lpub->getAddress();
|
||||
uint160 lpriva=lpriv->getAddress();
|
||||
#ifdef DEBUG
|
||||
std::cerr << "pubA(" << j << "): " << lpuba.GetHex() << std::endl;
|
||||
std::cerr << "prvA(" << j << "): " << lpriva.GetHex() << std::endl;
|
||||
// std::cerr << "pubA(" << j << "): " << lpuba.GetHex() << std::endl;
|
||||
// std::cerr << "prvA(" << j << "): " << lpriva.GetHex() << std::endl;
|
||||
std::cerr << "." << std::flush;
|
||||
#endif
|
||||
if(!lpuba || (lpuba!=lpriva))
|
||||
{
|
||||
@@ -334,6 +386,11 @@ bool Wallet::unitTest()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
pub.delFamily(fam);
|
||||
priv.delFamily(fam);
|
||||
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
26
Wallet.h
26
Wallet.h
@@ -35,11 +35,11 @@ protected:
|
||||
public:
|
||||
LocalAccountEntry(const uint160& accountFamily, int accountSeq, EC_POINT* rootPubKey);
|
||||
|
||||
void unlock(BIGNUM* rootPrivKey);
|
||||
void unlock(const BIGNUM* rootPrivKey);
|
||||
void lock() { mPrivateKey=CKey::pointer(); }
|
||||
|
||||
void write();
|
||||
void read();
|
||||
bool write(bool create);
|
||||
bool read();
|
||||
|
||||
const uint160& getAccountID() const { return mAcctID; }
|
||||
int getAccountSeq() const { return mAccountSeq; }
|
||||
@@ -81,13 +81,14 @@ public:
|
||||
|
||||
const uint160& getFamily() { return mFamily; }
|
||||
bool isLocked() const { return mRootPrivateKey==NULL; }
|
||||
void unlock(BIGNUM* privateKey);
|
||||
void unlock(const BIGNUM* privateKey);
|
||||
void lock();
|
||||
|
||||
void setSeq(uint32 s) { mLastSeq=s; }
|
||||
void setName(const std::string& n) { mName=n; }
|
||||
void setComment(const std::string& c) { mComment=c; }
|
||||
|
||||
std::map<int, LocalAccountEntry::pointer>& getAcctMap() { return mAccounts; }
|
||||
LocalAccountEntry::pointer get(int seq);
|
||||
uint160 getAccount(int seq);
|
||||
|
||||
@@ -99,7 +100,9 @@ public:
|
||||
};
|
||||
|
||||
class LocalAccount
|
||||
{ // tracks a single local account
|
||||
{ // tracks a single local account in a form that can be passed to other code.
|
||||
// We can't hand other code a LocalAccountEntry because an orphaned entry
|
||||
// could hold a private key we can't lock.
|
||||
public:
|
||||
typedef boost::shared_ptr<LocalAccount> pointer;
|
||||
|
||||
@@ -107,7 +110,6 @@ protected:
|
||||
LocalAccountFamily::pointer mFamily;
|
||||
int mSeq;
|
||||
|
||||
|
||||
public:
|
||||
LocalAccount(LocalAccountFamily::pointer fam, int seq) : mFamily(fam), mSeq(seq) { ; }
|
||||
uint160 getAddress() const;
|
||||
@@ -131,9 +133,8 @@ protected:
|
||||
std::map<uint160, LocalAccountFamily::pointer> families;
|
||||
std::map<uint160, LocalAccount::pointer> accounts;
|
||||
|
||||
uint160 doPrivate(const uint256& passPhrase, bool create, bool unlock);
|
||||
|
||||
LocalAccountFamily::pointer getFamily(const uint160& family, const std::string& pubKey);
|
||||
LocalAccountFamily::pointer doPrivate(const uint256& passPhrase, bool do_create, bool do_unlock);
|
||||
LocalAccountFamily::pointer doPublic(const std::string& pubKey);
|
||||
|
||||
void addFamily(const uint160& family, const std::string& pubKey, int seq,
|
||||
const std::string& name, const std::string& comment);
|
||||
@@ -142,11 +143,12 @@ public:
|
||||
Wallet() { ; }
|
||||
|
||||
uint160 addFamily(const std::string& passPhrase, bool lock);
|
||||
uint160 addFamily(const uint256& passPhrase, bool lock) { return doPrivate(passPhrase, true, !lock); }
|
||||
bool addFamily(const uint160& familyName, const std::string& pubKey);
|
||||
uint160 addFamily(const uint256& passPhrase, bool lock);
|
||||
uint160 addFamily(const std::string& pubKey);
|
||||
|
||||
uint160 unlock(const uint256& passPhrase) { return doPrivate(passPhrase, false, true); }
|
||||
void delFamily(const uint160& familyName);
|
||||
|
||||
uint160 unlock(const uint256& passPhrase);
|
||||
bool lock(const uint160& familyName);
|
||||
|
||||
void load(void);
|
||||
|
||||
9
key.h
9
key.h
@@ -125,20 +125,21 @@ public:
|
||||
|
||||
static uint256 PassPhraseToKey(const std::string& passPhrase);
|
||||
static EC_KEY* GenerateRootDeterministicKey(const uint256& passPhrase);
|
||||
static EC_KEY* GeneratePublicDeterministicKey(const uint160& family, EC_POINT* rootPub, int n);
|
||||
static EC_KEY* GeneratePrivateDeterministicKey(const uint160& family, BIGNUM* rootPriv, int n);
|
||||
static EC_KEY* GenerateRootPubKey(const std::string& pubHex);
|
||||
static EC_KEY* GeneratePublicDeterministicKey(const uint160& family, const EC_POINT* rootPub, int n);
|
||||
static EC_KEY* GeneratePrivateDeterministicKey(const uint160& family, const BIGNUM* rootPriv, int n);
|
||||
|
||||
CKey(const uint256& passPhrase) : fSet(true)
|
||||
{
|
||||
pkey = GenerateRootDeterministicKey(passPhrase);
|
||||
}
|
||||
|
||||
CKey(const uint160& base, EC_POINT* rootPubKey, int n) : fSet(true)
|
||||
CKey(const uint160& base, const EC_POINT* rootPubKey, int n) : fSet(true)
|
||||
{ // public deterministic key
|
||||
pkey = GeneratePublicDeterministicKey(base, rootPubKey, n);
|
||||
}
|
||||
|
||||
CKey(const uint160& base, BIGNUM* rootPrivKey, int n) : fSet(true)
|
||||
CKey(const uint160& base, const BIGNUM* rootPrivKey, int n) : fSet(true)
|
||||
{ // private deterministic key
|
||||
pkey = GeneratePrivateDeterministicKey(base, rootPrivKey, n);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user