Files
xahaud/src/cpp/ripple/DeterministicKeys.cpp
Vinnie Falco 2c525b03c6 Enormous cleanup of RippleAddress et. al. into ripple_data
Start cleanup into ripple_data, split out some hash_value() instances
Tidy up CBigNum into ripple_data, moving definitions to .cpp
Split and clean up base58 stuff
Remove unused files from VS2012 project
Clean up some bignum stuff and remove unused files
Partial cleanup of RFC1751
Enormous cleanup with RippleAddress and related, into ripple_data
Remove unused VS project files
Move ECIES stuff into CKey
2013-05-30 10:16:22 -07:00

340 lines
7.7 KiB
C++

#include <openssl/ec.h>
#include <openssl/bn.h>
#include <openssl/ecdsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
// #define EC_DEBUG
// Functions to add CKey support for deterministic EC keys
#include <boost/test/unit_test.hpp>
// <-- seed
uint128 CKey::PassPhraseToKey(const std::string& passPhrase)
{
Serializer s;
s.addRaw(passPhrase);
uint256 hash256 = s.getSHA512Half();
uint128 ret(hash256);
s.secureErase();
return ret;
}
// --> seed
// <-- private root generator + public root generator
EC_KEY* CKey::GenerateRootDeterministicKey(const uint128& seed)
{
BN_CTX* ctx=BN_CTX_new();
if(!ctx) return NULL;
EC_KEY* pkey=EC_KEY_new_by_curve_name(NID_secp256k1);
if(!pkey)
{
BN_CTX_free(ctx);
return NULL;
}
EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
BIGNUM* order=BN_new();
if(!order)
{
BN_CTX_free(ctx);
EC_KEY_free(pkey);
return NULL;
}
if(!EC_GROUP_get_order(EC_KEY_get0_group(pkey), order, ctx))
{
assert(false);
BN_free(order);
EC_KEY_free(pkey);
BN_CTX_free(ctx);
return NULL;
}
BIGNUM *privKey=NULL;
int seq=0;
do
{ // private key must be non-zero and less than the curve's order
Serializer s((128+32)/8);
s.add128(seed);
s.add32(seq++);
uint256 root=s.getSHA512Half();
s.secureErase();
privKey=BN_bin2bn((const unsigned char *) &root, sizeof(root), privKey);
if(privKey==NULL)
{
EC_KEY_free(pkey);
BN_free(order);
BN_CTX_free(ctx);
}
root.zero();
} while(BN_is_zero(privKey) || (BN_cmp(privKey, order)>=0));
BN_free(order);
if(!EC_KEY_set_private_key(pkey, privKey))
{ // set the random point as the private key
assert(false);
EC_KEY_free(pkey);
BN_clear_free(privKey);
BN_CTX_free(ctx);
return NULL;
}
EC_POINT *pubKey=EC_POINT_new(EC_KEY_get0_group(pkey));
if(!EC_POINT_mul(EC_KEY_get0_group(pkey), pubKey, privKey, NULL, NULL, ctx))
{ // compute the corresponding public key point
assert(false);
BN_clear_free(privKey);
EC_POINT_free(pubKey);
EC_KEY_free(pkey);
BN_CTX_free(ctx);
return NULL;
}
BN_clear_free(privKey);
if(!EC_KEY_set_public_key(pkey, pubKey))
{
assert(false);
EC_POINT_free(pubKey);
EC_KEY_free(pkey);
BN_CTX_free(ctx);
return NULL;
}
EC_POINT_free(pubKey);
BN_CTX_free(ctx);
#ifdef EC_DEBUG
assert(EC_KEY_check_key(pkey)==1); // CAUTION: This check is *very* expensive
#endif
return pkey;
}
// Take ripple address.
// --> root public generator (consumes)
// <-- root public generator in EC format
EC_KEY* CKey::GenerateRootPubKey(BIGNUM* pubGenerator)
{
if (pubGenerator == NULL)
{
assert(false);
return NULL;
}
EC_KEY* pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
if (!pkey)
{
BN_free(pubGenerator);
return NULL;
}
EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
EC_POINT* pubPoint = EC_POINT_bn2point(EC_KEY_get0_group(pkey), pubGenerator, NULL, NULL);
BN_free(pubGenerator);
if(!pubPoint)
{
assert(false);
EC_KEY_free(pkey);
return NULL;
}
if(!EC_KEY_set_public_key(pkey, pubPoint))
{
assert(false);
EC_POINT_free(pubPoint);
EC_KEY_free(pkey);
return NULL;
}
EC_POINT_free(pubPoint);
return pkey;
}
// --> public generator
static BIGNUM* makeHash(const RippleAddress& pubGen, int seq, BIGNUM* order)
{
int subSeq=0;
BIGNUM* ret=NULL;
do
{
Serializer s((33*8+32+32)/8);
s.addRaw(pubGen.getGenerator());
s.add32(seq);
s.add32(subSeq++);
uint256 root=s.getSHA512Half();
s.secureErase();
ret=BN_bin2bn((const unsigned char *) &root, sizeof(root), ret);
if(!ret) return NULL;
} while (BN_is_zero(ret) || (BN_cmp(ret, order)>=0));
return ret;
}
// --> public generator
EC_KEY* CKey::GeneratePublicDeterministicKey(const RippleAddress& pubGen, int seq)
{ // publicKey(n) = rootPublicKey EC_POINT_+ Hash(pubHash|seq)*point
EC_KEY* rootKey = CKey::GenerateRootPubKey(pubGen.getGeneratorBN());
const EC_POINT* rootPubKey = EC_KEY_get0_public_key(rootKey);
BN_CTX* ctx = BN_CTX_new();
EC_KEY* pkey = EC_KEY_new_by_curve_name(NID_secp256k1);
EC_POINT* newPoint = 0;
BIGNUM* order = 0;
BIGNUM* hash = 0;
bool success = true;
if (!ctx || !pkey) success = false;
if (success)
EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
if (success) {
newPoint = EC_POINT_new(EC_KEY_get0_group(pkey));
if(!newPoint) success = false;
}
if (success) {
order = BN_new();
if(!order || !EC_GROUP_get_order(EC_KEY_get0_group(pkey), order, ctx))
success = false;
}
// Calculate the private additional key.
if (success) {
hash = makeHash(pubGen, seq, order);
if(!hash) success = false;
}
if (success) {
// Calculate the corresponding public key.
EC_POINT_mul(EC_KEY_get0_group(pkey), newPoint, hash, NULL, NULL, ctx);
// Add the master public key and set.
EC_POINT_add(EC_KEY_get0_group(pkey), newPoint, newPoint, rootPubKey, ctx);
EC_KEY_set_public_key(pkey, newPoint);
}
if (order) BN_free(order);
if (hash) BN_free(hash);
if (newPoint) EC_POINT_free(newPoint);
if (ctx) BN_CTX_free(ctx);
if (rootKey) EC_KEY_free(rootKey);
if (pkey && !success) EC_KEY_free(pkey);
return success ? pkey : NULL;
}
EC_KEY* CKey::GeneratePrivateDeterministicKey(const RippleAddress& pubGen, const uint256& u, int seq)
{
CBigNum bn(u);
return GeneratePrivateDeterministicKey(pubGen, static_cast<BIGNUM*>(&bn), seq);
}
// --> root private key
EC_KEY* CKey::GeneratePrivateDeterministicKey(const RippleAddress& pubGen, const BIGNUM* rootPrivKey, int seq)
{ // privateKey(n) = (rootPrivateKey + Hash(pubHash|seq)) % order
BN_CTX* ctx=BN_CTX_new();
if(ctx==NULL) return NULL;
EC_KEY* pkey=EC_KEY_new_by_curve_name(NID_secp256k1);
if(pkey==NULL)
{
BN_CTX_free(ctx);
return NULL;
}
EC_KEY_set_conv_form(pkey, POINT_CONVERSION_COMPRESSED);
BIGNUM* order=BN_new();
if(order==NULL)
{
BN_CTX_free(ctx);
EC_KEY_free(pkey);
return NULL;
}
if(!EC_GROUP_get_order(EC_KEY_get0_group(pkey), order, ctx))
{
BN_free(order);
BN_CTX_free(ctx);
EC_KEY_free(pkey);
return NULL;
}
// calculate the private additional key
BIGNUM* privKey=makeHash(pubGen, seq, order);
if(privKey==NULL)
{
BN_free(order);
BN_CTX_free(ctx);
EC_KEY_free(pkey);
return NULL;
}
// calculate the final private key
BN_mod_add(privKey, privKey, rootPrivKey, order, ctx);
BN_free(order);
EC_KEY_set_private_key(pkey, privKey);
// compute the corresponding public key
EC_POINT* pubKey=EC_POINT_new(EC_KEY_get0_group(pkey));
if(!pubKey)
{
BN_clear_free(privKey);
BN_CTX_free(ctx);
EC_KEY_free(pkey);
return NULL;
}
if(EC_POINT_mul(EC_KEY_get0_group(pkey), pubKey, privKey, NULL, NULL, ctx)==0)
{
BN_clear_free(privKey);
EC_POINT_free(pubKey);
EC_KEY_free(pkey);
BN_CTX_free(ctx);
return NULL;
}
BN_clear_free(privKey);
EC_KEY_set_public_key(pkey, pubKey);
EC_POINT_free(pubKey);
BN_CTX_free(ctx);
return pkey;
}
BOOST_AUTO_TEST_SUITE(DeterministicKeys_test)
BOOST_AUTO_TEST_CASE(DeterminsticKeys_test1)
{
Log(lsDEBUG) << "Beginning deterministic key test";
uint128 seed1, seed2;
seed1.SetHex("71ED064155FFADFA38782C5E0158CB26");
seed2.SetHex("CF0C3BE4485961858C4198515AE5B965");
CKey root1(seed1), root2(seed2);
uint256 priv1, priv2;
root1.GetPrivateKeyU(priv1);
root2.GetPrivateKeyU(priv2);
if (priv1.GetHex() != "7CFBA64F771E93E817E15039215430B53F7401C34931D111EAB3510B22DBB0D8")
BOOST_FAIL("Incorrect private key for generator");
if (priv2.GetHex() != "98BC2EACB26EB021D1A6293C044D88BA2F0B6729A2772DEEBF2E21A263C1740B")
BOOST_FAIL("Incorrect private key for generator");
RippleAddress nSeed;
nSeed.setSeed(seed1);
if (nSeed.humanSeed() != "shHM53KPZ87Gwdqarm1bAmPeXg8Tn")
BOOST_FAIL("Incorrect human seed");
if (nSeed.humanSeed1751() != "MAD BODY ACE MINT OKAY HUB WHAT DATA SACK FLAT DANA MATH")
BOOST_FAIL("Incorrect 1751 seed");
}
BOOST_AUTO_TEST_SUITE_END();
// vim:ts=4