From 4b88113a519d21faf3ef1dc2f1fd643b4f56ccab Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 27 Dec 2011 19:18:42 -0800 Subject: [PATCH] More work on the new wallet code. --- DeterministicKeys.cpp | 38 +++++++++- Wallet.cpp | 163 ++++++++++++++++++++++++++++-------------- Wallet.h | 26 +++---- key.h | 9 +-- 4 files changed, 164 insertions(+), 72 deletions(-) diff --git a/DeterministicKeys.cpp b/DeterministicKeys.cpp index 2a190a14e..4f6ef591e 100644 --- a/DeterministicKeys.cpp +++ b/DeterministicKeys.cpp @@ -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; diff --git a/Wallet.cpp b/Wallet.cpp index 4195f44de..633526fc5 100644 --- a/Wallet.cpp +++ b/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::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::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::iterator fit=families.find(familyName); + if(fit==families.end()) return; + + std::map& acctMap=fit->second->getAcctMap(); + for(std::map::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 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::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::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; } diff --git a/Wallet.h b/Wallet.h index 5b1a18f2d..50484b6ba 100644 --- a/Wallet.h +++ b/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& 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 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 families; std::map 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); diff --git a/key.h b/key.h index 64e485d03..081858a21 100644 --- a/key.h +++ b/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); }