Files
xahaud/modules/ripple_data/crypto/ripple_CKeyDeterministic.cpp
2013-06-14 08:45:13 -07:00

379 lines
9.0 KiB
C++

// #define EC_DEBUG
// Functions to add CKey support for deterministic EC keys
// <-- 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, uint256 const& 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