mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Levelization, improve structure of source files:
Source files are moved between modules, includes changed and added, and some code rewritten, with the goal of reducing cross-module dependencies and eliminating cycles in the dependency graph of classes. * Remove RippleAddress dependency in CKey_test * ByteOrder.h, Blob.h, and strHex.h are moved to basics/. This makes the basics/ module fully independent of other ripple sources. * types/ is merged into protocol/. The protocol module now contains all primitive types specific to the Ripple protocol. * Move ErrorCodes to protocol/ * Move base_uint to basics/ * Move Base58 to crypto/ * Remove dependence on Serializer in GenerateDeterministicKey * Eliminate unity header json.h * Remove obsolete unity headers * Remove unnecessary includes
This commit is contained in:
261
src/ripple/crypto/impl/Base58.cpp
Normal file
261
src/ripple/crypto/impl/Base58.cpp
Normal file
@@ -0,0 +1,261 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/crypto/Base58.h>
|
||||
#include <ripple/crypto/CAutoBN_CTX.h>
|
||||
#include <ripple/crypto/CBigNum.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2011 The Bitcoin Developers
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file license.txt or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
namespace ripple {
|
||||
|
||||
uint256 SHA256Hash (unsigned char const* pbegin, unsigned char const* pend)
|
||||
{
|
||||
uint256 hash1;
|
||||
SHA256 (pbegin, pend - pbegin, hash1.begin ());
|
||||
|
||||
uint256 hash2;
|
||||
SHA256 (hash1.begin (), hash1.size (), hash2.begin());
|
||||
|
||||
return hash2;
|
||||
}
|
||||
|
||||
void Base58::fourbyte_hash256 (void* out, void const* in, std::size_t bytes)
|
||||
{
|
||||
auto p = static_cast <unsigned char const*>(in);
|
||||
uint256 hash (SHA256Hash (p, p + bytes));
|
||||
memcpy (out, hash.begin(), 4);
|
||||
}
|
||||
|
||||
Base58::Alphabet const& Base58::getBitcoinAlphabet ()
|
||||
{
|
||||
static Alphabet alphabet (
|
||||
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
);
|
||||
return alphabet;
|
||||
}
|
||||
|
||||
Base58::Alphabet const& Base58::getRippleAlphabet ()
|
||||
{
|
||||
static Alphabet alphabet (
|
||||
"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"
|
||||
);
|
||||
return alphabet;
|
||||
}
|
||||
|
||||
std::string Base58::raw_encode (unsigned char const* begin,
|
||||
unsigned char const* end, Alphabet const& alphabet)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum bn58 = 58;
|
||||
CBigNum bn0 = 0;
|
||||
|
||||
// Convert little endian data to bignum
|
||||
CBigNum bn (begin, end);
|
||||
std::size_t const size (std::distance (begin, end));
|
||||
|
||||
// Convert bignum to std::string
|
||||
std::string str;
|
||||
// Expected size increase from base58 conversion is approximately 137%
|
||||
// use 138% to be safe
|
||||
str.reserve (size * 138 / 100 + 1);
|
||||
CBigNum dv;
|
||||
CBigNum rem;
|
||||
|
||||
while (bn > bn0)
|
||||
{
|
||||
if (!BN_div (&dv, &rem, &bn, &bn58, pctx))
|
||||
throw std::runtime_error ("EncodeBase58 : BN_div failed");
|
||||
|
||||
bn = dv;
|
||||
unsigned int c = rem.getuint ();
|
||||
str += alphabet [c];
|
||||
}
|
||||
|
||||
for (const unsigned char* p = end-2; p >= begin && *p == 0; p--)
|
||||
str += alphabet [0];
|
||||
|
||||
// Convert little endian std::string to big endian
|
||||
reverse (str.begin (), str.end ());
|
||||
return str;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
bool Base58::raw_decode (char const* first, char const* last, void* dest,
|
||||
std::size_t size, bool checked, Alphabet const& alphabet)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
CBigNum bn58 = 58;
|
||||
CBigNum bn = 0;
|
||||
CBigNum bnChar;
|
||||
|
||||
// Convert big endian string to bignum
|
||||
for (char const* p = first; p != last; ++p)
|
||||
{
|
||||
int i (alphabet.from_char (*p));
|
||||
if (i == -1)
|
||||
return false;
|
||||
bnChar.setuint ((unsigned int) i);
|
||||
|
||||
int const success (BN_mul (&bn, &bn, &bn58, pctx));
|
||||
|
||||
assert (success);
|
||||
(void) success;
|
||||
|
||||
bn += bnChar;
|
||||
}
|
||||
|
||||
// Get bignum as little endian data
|
||||
Blob vchTmp = bn.getvch ();
|
||||
|
||||
// Trim off sign byte if present
|
||||
if (vchTmp.size () >= 2 && vchTmp.end ()[-1] == 0 && vchTmp.end ()[-2] >= 0x80)
|
||||
vchTmp.erase (vchTmp.end () - 1);
|
||||
|
||||
char* const out (static_cast <char*> (dest));
|
||||
|
||||
// Count leading zeros
|
||||
int nLeadingZeros = 0;
|
||||
for (char const* p = first; p!=last && *p==alphabet[0]; p++)
|
||||
nLeadingZeros++;
|
||||
|
||||
// Verify that the size is correct
|
||||
if (vchTmp.size() + nLeadingZeros != size)
|
||||
return false;
|
||||
|
||||
// Fill the leading zeros
|
||||
memset (out, 0, nLeadingZeros);
|
||||
|
||||
// Copy little endian data to big endian
|
||||
std::reverse_copy (vchTmp.begin (), vchTmp.end (),
|
||||
out + nLeadingZeros);
|
||||
|
||||
if (checked)
|
||||
{
|
||||
char hash4 [4];
|
||||
fourbyte_hash256 (hash4, out, size - 4);
|
||||
if (memcmp (hash4, out + size - 4, 4) != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Base58::decode (const char* psz, Blob& vchRet, Alphabet const& alphabet)
|
||||
{
|
||||
CAutoBN_CTX pctx;
|
||||
vchRet.clear ();
|
||||
CBigNum bn58 = 58;
|
||||
CBigNum bn = 0;
|
||||
CBigNum bnChar;
|
||||
|
||||
while (isspace (*psz))
|
||||
psz++;
|
||||
|
||||
// Convert big endian string to bignum
|
||||
for (const char* p = psz; *p; p++)
|
||||
{
|
||||
// VFALCO TODO Make this use the inverse table!
|
||||
// Or better yet ditch this and call raw_decode
|
||||
//
|
||||
const char* p1 = strchr (alphabet.chars(), *p);
|
||||
|
||||
if (p1 == nullptr)
|
||||
{
|
||||
while (isspace (*p))
|
||||
p++;
|
||||
|
||||
if (*p != '\0')
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
bnChar.setuint (p1 - alphabet.chars());
|
||||
|
||||
if (!BN_mul (&bn, &bn, &bn58, pctx))
|
||||
throw std::runtime_error ("DecodeBase58 : BN_mul failed");
|
||||
|
||||
bn += bnChar;
|
||||
}
|
||||
|
||||
// Get bignum as little endian data
|
||||
Blob vchTmp = bn.getvch ();
|
||||
|
||||
// Trim off sign byte if present
|
||||
if (vchTmp.size () >= 2 && vchTmp.end ()[-1] == 0 && vchTmp.end ()[-2] >= 0x80)
|
||||
vchTmp.erase (vchTmp.end () - 1);
|
||||
|
||||
// Restore leading zeros
|
||||
int nLeadingZeros = 0;
|
||||
|
||||
for (const char* p = psz; *p == alphabet.chars()[0]; p++)
|
||||
nLeadingZeros++;
|
||||
|
||||
vchRet.assign (nLeadingZeros + vchTmp.size (), 0);
|
||||
|
||||
// Convert little endian data to big endian
|
||||
std::reverse_copy (vchTmp.begin (), vchTmp.end (), vchRet.end () - vchTmp.size ());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Base58::decode (std::string const& str, Blob& vchRet)
|
||||
{
|
||||
return decode (str.c_str (), vchRet);
|
||||
}
|
||||
|
||||
bool Base58::decodeWithCheck (const char* psz, Blob& vchRet, Alphabet const& alphabet)
|
||||
{
|
||||
if (!decode (psz, vchRet, alphabet))
|
||||
return false;
|
||||
|
||||
auto size = vchRet.size ();
|
||||
|
||||
if (size < 4)
|
||||
{
|
||||
vchRet.clear ();
|
||||
return false;
|
||||
}
|
||||
|
||||
uint256 hash = SHA256Hash (vchRet.data (), vchRet.data () + size - 4);
|
||||
|
||||
if (memcmp (&hash, &vchRet.end ()[-4], 4) != 0)
|
||||
{
|
||||
vchRet.clear ();
|
||||
return false;
|
||||
}
|
||||
|
||||
vchRet.resize (size - 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Base58::decodeWithCheck (std::string const& str, Blob& vchRet, Alphabet const& alphabet)
|
||||
{
|
||||
return decodeWithCheck (str.c_str (), vchRet, alphabet);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,15 +18,34 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/crypto/GenerateDeterministicKey.h>
|
||||
|
||||
#include <ripple/crypto/Base58.h>
|
||||
#include <ripple/crypto/CBigNum.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <array>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
using openssl::ec_key;
|
||||
|
||||
uint256
|
||||
getSHA512Half (void const* data, std::size_t bytes)
|
||||
{
|
||||
uint256 j[2];
|
||||
SHA512 (reinterpret_cast<unsigned char const*>(data), bytes,
|
||||
reinterpret_cast<unsigned char*> (j));
|
||||
return j[0];
|
||||
}
|
||||
|
||||
template <class FwdIt>
|
||||
void
|
||||
copy_uint32 (FwdIt out, std::uint32_t v)
|
||||
{
|
||||
*out++ = v >> 24;
|
||||
*out++ = (v >> 16) & 0xff;
|
||||
*out++ = (v >> 8) & 0xff;
|
||||
*out = v & 0xff;
|
||||
}
|
||||
|
||||
// #define EC_DEBUG
|
||||
|
||||
// Functions to add support for deterministic EC keys
|
||||
@@ -67,19 +86,20 @@ ec_key GenerateRootDeterministicKey (uint128 const& seed)
|
||||
return ec_key::invalid;
|
||||
}
|
||||
|
||||
// find non-zero private key less than the curve's order
|
||||
BIGNUM* privKey = nullptr;
|
||||
int seq = 0;
|
||||
|
||||
std::uint32_t 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 ();
|
||||
// buf: 0 seed 16 seq 20
|
||||
// |<--------------------------------->|<------>|
|
||||
std::array<std::uint8_t, 20> buf;
|
||||
std::copy(seed.begin(), seed.end(), buf.begin());
|
||||
copy_uint32 (buf.begin() + 16, seq++);
|
||||
++seq;
|
||||
uint256 root = getSHA512Half (buf.data(), buf.size());
|
||||
std::fill (buf.begin(), buf.end(), 0); // security erase
|
||||
privKey = BN_bin2bn ((const unsigned char*) &root, sizeof (root), privKey);
|
||||
|
||||
if (privKey == nullptr)
|
||||
{
|
||||
EC_KEY_free (pkey);
|
||||
@@ -88,7 +108,7 @@ ec_key GenerateRootDeterministicKey (uint128 const& seed)
|
||||
return ec_key::invalid;
|
||||
}
|
||||
|
||||
root.zero ();
|
||||
root.zero(); // security erase
|
||||
}
|
||||
while (BN_is_zero (privKey) || (BN_cmp (privKey, order) >= 0));
|
||||
|
||||
@@ -188,17 +208,20 @@ static BIGNUM* makeHash (Blob const& pubGen, int seq, BIGNUM const* order)
|
||||
int subSeq = 0;
|
||||
BIGNUM* ret = nullptr;
|
||||
|
||||
assert(pubGen.size() == 33);
|
||||
do
|
||||
{
|
||||
Serializer s ((33 * 8 + 32 + 32) / 8);
|
||||
s.addRaw (pubGen);
|
||||
s.add32 (seq);
|
||||
s.add32 (subSeq++);
|
||||
uint256 root = s.getSHA512Half ();
|
||||
s.secureErase ();
|
||||
// buf: 0 pubGen 33 seq 37 subSeq 41
|
||||
// |<--------------------------->|<------>|<-------->|
|
||||
std::array<std::uint8_t, 41> buf;
|
||||
std::copy (pubGen.begin(), pubGen.end(), buf.begin());
|
||||
copy_uint32 (buf.begin() + 33, seq);
|
||||
copy_uint32 (buf.begin() + 37, subSeq++);
|
||||
uint256 root = getSHA512Half (buf.data(), buf.size());
|
||||
std::fill(buf.begin(), buf.end(), 0); // security erase
|
||||
ret = BN_bin2bn ((const unsigned char*) &root, sizeof (root), ret);
|
||||
|
||||
if (!ret) return nullptr;
|
||||
root.zero(); // security erase
|
||||
}
|
||||
while (BN_is_zero (ret) || (BN_cmp (ret, order) >= 0));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user