More work on the new wallet code.

This commit is contained in:
JoelKatz
2011-12-27 19:18:42 -08:00
parent 67a5544458
commit 4b88113a51
4 changed files with 164 additions and 72 deletions

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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
View File

@@ -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);
}