mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Remove RippleAddress:
The RippleAddress class was used to represent a number of fundamentally different types: account public keys, account secret keys, node public keys, node secret keys, seeds and generators. The class is replaced by the following types: * PublicKey for account and node public keys * SecretKey for account and node private keys * Generator for generating secp256k1 accounts * Seed for account, node and generator seeds
This commit is contained in:
@@ -79,64 +79,6 @@ sigPart (Slice& buf)
|
||||
return number;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
void
|
||||
swizzle (void* p);
|
||||
|
||||
template<>
|
||||
void
|
||||
swizzle<4>(void* p)
|
||||
{
|
||||
(*reinterpret_cast<std::uint32_t*>(p))=
|
||||
beast::ByteOrder::swapIfLittleEndian(
|
||||
*reinterpret_cast<std::uint32_t*>(p));
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
swizzle<8>(void* p)
|
||||
{
|
||||
(*reinterpret_cast<std::uint64_t*>(p))=
|
||||
beast::ByteOrder::swapIfLittleEndian(
|
||||
*reinterpret_cast<std::uint64_t*>(p));
|
||||
}
|
||||
|
||||
template <class Number>
|
||||
static
|
||||
void
|
||||
load (Number& mp, Slice const& buf)
|
||||
{
|
||||
assert(buf.size() != 0);
|
||||
auto& b = mp.backend(); // backend
|
||||
auto const a = &b.limbs()[0]; // limb array
|
||||
using Limb = std::decay_t<
|
||||
decltype(a[0])>; // word type
|
||||
b.resize((buf.size() + sizeof(Limb) - 1) / sizeof(Limb), 1);
|
||||
std::memset(&a[0], 0,
|
||||
b.size() * sizeof(Limb)); // zero fill
|
||||
auto n =
|
||||
buf.size() / sizeof(Limb);
|
||||
auto s = reinterpret_cast<Limb const*>(
|
||||
buf.data() + buf.size() - sizeof(Limb));
|
||||
auto d = a;
|
||||
while(n--)
|
||||
{
|
||||
*d = *s;
|
||||
swizzle<sizeof(Limb)>(d);
|
||||
d++;
|
||||
s--;
|
||||
}
|
||||
auto const r =
|
||||
buf.size() % sizeof(Limb);
|
||||
if (r > 0)
|
||||
{
|
||||
std::memcpy(
|
||||
reinterpret_cast<std::uint8_t*>(d) + sizeof(Limb) - r,
|
||||
buf.data(), r);
|
||||
swizzle<sizeof(Limb)>(d);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
std::string
|
||||
sliceToHex (Slice const& slice)
|
||||
@@ -189,15 +131,9 @@ ecdsaCanonicality (Slice const& sig)
|
||||
auto s = sigPart(p);
|
||||
if (! r || ! s || ! p.empty())
|
||||
return boost::none;
|
||||
#if 0
|
||||
uint264 R;
|
||||
uint264 S;
|
||||
load(R, *r);
|
||||
load(S, *s);
|
||||
#else
|
||||
|
||||
uint264 R(sliceToHex(*r));
|
||||
uint264 S(sliceToHex(*s));
|
||||
#endif
|
||||
|
||||
if (R >= G)
|
||||
return boost::none;
|
||||
@@ -260,48 +196,6 @@ PublicKey::operator=(
|
||||
return *this;
|
||||
}
|
||||
|
||||
KeyType
|
||||
PublicKey::type() const
|
||||
{
|
||||
auto const result =
|
||||
publicKeyType(Slice{ buf_, size_ });
|
||||
if (! result)
|
||||
LogicError("PublicKey::type: invalid type");
|
||||
return *result;
|
||||
}
|
||||
|
||||
bool
|
||||
PublicKey::verify (Slice const& m,
|
||||
Slice const& sig, bool mustBeFullyCanonical) const
|
||||
{
|
||||
switch(type())
|
||||
{
|
||||
case KeyType::secp256k1:
|
||||
{
|
||||
auto const digest = sha512Half(m);
|
||||
auto const canonicality = ecdsaCanonicality(sig);
|
||||
if (! canonicality)
|
||||
return false;
|
||||
if (mustBeFullyCanonical && canonicality !=
|
||||
ECDSACanonicality::fullyCanonical)
|
||||
return false;
|
||||
return secp256k1_ecdsa_verify(
|
||||
secp256k1Context(), secpp(digest.data()),
|
||||
secpp(sig.data()), sig.size(),
|
||||
secpp(buf_), size_) == 1;
|
||||
}
|
||||
default:
|
||||
case KeyType::ed25519:
|
||||
{
|
||||
if (! ed25519Canonical(sig))
|
||||
return false;
|
||||
return ed25519_sign_open(
|
||||
m.data(), m.size(), buf_ + 1,
|
||||
sig.data()) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
boost::optional<KeyType>
|
||||
@@ -318,31 +212,54 @@ publicKeyType (Slice const& slice)
|
||||
}
|
||||
|
||||
bool
|
||||
verify (PublicKey const& pk,
|
||||
Slice const& m, Slice const& sig)
|
||||
verifyDigest (PublicKey const& publicKey,
|
||||
uint256 const& digest,
|
||||
Slice const& sig,
|
||||
bool mustBeFullyCanonical)
|
||||
{
|
||||
switch(pk.type())
|
||||
if (publicKeyType(publicKey) != KeyType::secp256k1)
|
||||
LogicError("sign: secp256k1 required for digest signing");
|
||||
|
||||
auto const canonicality = ecdsaCanonicality(sig);
|
||||
if (! canonicality)
|
||||
return false;
|
||||
if (mustBeFullyCanonical &&
|
||||
(*canonicality != ECDSACanonicality::fullyCanonical))
|
||||
return false;
|
||||
return secp256k1_ecdsa_verify(
|
||||
secp256k1Context(), secpp(digest.data()),
|
||||
secpp(sig.data()), sig.size(),
|
||||
secpp(publicKey.data()), publicKey.size()) == 1;
|
||||
}
|
||||
|
||||
bool
|
||||
verify (PublicKey const& publicKey,
|
||||
Slice const& m,
|
||||
Slice const& sig,
|
||||
bool mustBeFullyCanonical)
|
||||
{
|
||||
if (auto const type = publicKeyType(publicKey))
|
||||
{
|
||||
default:
|
||||
case KeyType::secp256k1:
|
||||
{
|
||||
sha512_half_hasher h;
|
||||
h(m.data(), m.size());
|
||||
auto const digest =
|
||||
sha512_half_hasher::result_type(h);
|
||||
return secp256k1_ecdsa_verify(
|
||||
secp256k1Context(), digest.data(),
|
||||
sig.data(), sig.size(),
|
||||
pk.data(), pk.size()) == 1;
|
||||
}
|
||||
case KeyType::ed25519:
|
||||
{
|
||||
if (sig.size() != 64)
|
||||
return false;
|
||||
return ed25519_sign_open(m.data(),
|
||||
m.size(), pk.data(), sig.data()) == 0;
|
||||
}
|
||||
if (*type == KeyType::secp256k1)
|
||||
{
|
||||
return verifyDigest (publicKey,
|
||||
sha512Half(m), sig, mustBeFullyCanonical);
|
||||
}
|
||||
else if (*type == KeyType::ed25519)
|
||||
{
|
||||
if (! ed25519Canonical(sig))
|
||||
return false;
|
||||
|
||||
// We internally prefix Ed25519 keys with a 0xED
|
||||
// byte to distinguish them from secp256k1 keys
|
||||
// so when verifying the signature, we need to
|
||||
// first strip that prefix.
|
||||
return ed25519_sign_open(
|
||||
m.data(), m.size(), publicKey.data() + 1,
|
||||
sig.data()) == 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NodeID
|
||||
|
||||
@@ -1,881 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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 <BeastConfig.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/random.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/crypto/ECDSA.h>
|
||||
#include <ripple/crypto/ECIES.h>
|
||||
#include <ripple/crypto/GenerateDeterministicKey.h>
|
||||
#include <ripple/crypto/csprng.h>
|
||||
#include <ripple/crypto/RFC1751.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <ripple/protocol/RippleAddress.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <ripple/protocol/RipplePublicKey.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
#include <beast/rngfill.h>
|
||||
#include <beast/unit_test/suite.h>
|
||||
#include <ed25519-donna/ed25519.h>
|
||||
#include <openssl/ripemd.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <algorithm>
|
||||
#include <mutex>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
static
|
||||
bool isCanonicalEd25519Signature (std::uint8_t const* signature)
|
||||
{
|
||||
using std::uint8_t;
|
||||
|
||||
// Big-endian `l`, the Ed25519 subgroup order
|
||||
char const* const order = "\x10\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x00"
|
||||
"\x14\xDE\xF9\xDE\xA2\xF7\x9C\xD6"
|
||||
"\x58\x12\x63\x1A\x5C\xF5\xD3\xED";
|
||||
|
||||
uint8_t const* const l = reinterpret_cast<uint8_t const*> (order);
|
||||
|
||||
// Take the second half of signature and byte-reverse it to big-endian.
|
||||
uint8_t const* S_le = signature + 32;
|
||||
uint8_t S[32];
|
||||
std::reverse_copy (S_le, S_le + 32, S);
|
||||
|
||||
return std::lexicographical_compare (S, S + 32, l, l + 32);
|
||||
}
|
||||
|
||||
// <-- seed
|
||||
static
|
||||
uint128 PassPhraseToKey (std::string const& passPhrase)
|
||||
{
|
||||
return uint128::fromVoid(sha512Half_s(
|
||||
makeSlice(passPhrase)).data());
|
||||
}
|
||||
|
||||
static
|
||||
bool verifySignature (Blob const& pubkey, uint256 const& hash, Blob const& sig,
|
||||
ECDSA fullyCanonical)
|
||||
{
|
||||
if (! isCanonicalECDSASig (sig, fullyCanonical))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ECDSAVerify (hash, sig, &pubkey[0], pubkey.size());
|
||||
}
|
||||
|
||||
RippleAddress::RippleAddress ()
|
||||
: mIsValid (false)
|
||||
{
|
||||
nVersion = TOKEN_NONE;
|
||||
}
|
||||
|
||||
void RippleAddress::clear ()
|
||||
{
|
||||
nVersion = TOKEN_NONE;
|
||||
vchData.clear ();
|
||||
mIsValid = false;
|
||||
}
|
||||
|
||||
bool RippleAddress::isSet () const
|
||||
{
|
||||
return nVersion != TOKEN_NONE;
|
||||
}
|
||||
|
||||
//
|
||||
// NodePublic
|
||||
//
|
||||
|
||||
static
|
||||
uint160 Hash160 (Blob const& vch)
|
||||
{
|
||||
uint256 hash1;
|
||||
SHA256 (vch.data (), vch.size (), hash1.data ());
|
||||
|
||||
uint160 hash2;
|
||||
RIPEMD160 (hash1.data (), hash1.size (), hash2.data ());
|
||||
|
||||
return hash2;
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createNodePublic (RippleAddress const& naSeed)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
// YYY Should there be a GetPubKey() equiv that returns a uint256?
|
||||
naNew.setNodePublic (generateRootDeterministicPublicKey (naSeed.getSeed()));
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createNodePublic (Blob const& vPublic)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setNodePublic (vPublic);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createNodePublic (std::string const& strPublic)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setNodePublic (strPublic);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
RipplePublicKey
|
||||
RippleAddress::toPublicKey() const
|
||||
{
|
||||
assert (nVersion == TOKEN_NODE_PUBLIC);
|
||||
return RipplePublicKey (vchData.begin(), vchData.end());
|
||||
}
|
||||
|
||||
NodeID RippleAddress::getNodeID () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - getNodeID");
|
||||
|
||||
case TOKEN_NODE_PUBLIC:
|
||||
{
|
||||
// Note, we are encoding the left.
|
||||
NodeID node;
|
||||
node.copyFrom(Hash160 (vchData));
|
||||
return node;
|
||||
}
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return {}; // Silence compiler warning.
|
||||
}
|
||||
|
||||
Blob const& RippleAddress::getNodePublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - getNodePublic");
|
||||
|
||||
case TOKEN_NODE_PUBLIC:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error>("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return vchData; // Silence compiler warning.
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanNodePublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - humanNodePublic");
|
||||
|
||||
case TOKEN_NODE_PUBLIC:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error>("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return {}; // Silence compiler warning.
|
||||
}
|
||||
|
||||
bool RippleAddress::setNodePublic (std::string const& strPublic)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPublic, TOKEN_NODE_PUBLIC, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setNodePublic (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (TOKEN_NODE_PUBLIC, vPublic);
|
||||
}
|
||||
|
||||
bool RippleAddress::verifyNodePublic (
|
||||
uint256 const& hash, Blob const& vchSig, ECDSA fullyCanonical) const
|
||||
{
|
||||
return verifySignature (getNodePublic(), hash, vchSig, fullyCanonical);
|
||||
}
|
||||
|
||||
bool RippleAddress::verifyNodePublic (
|
||||
uint256 const& hash, std::string const& strSig, ECDSA fullyCanonical) const
|
||||
{
|
||||
Blob vchSig (strSig.begin (), strSig.end ());
|
||||
|
||||
return verifyNodePublic (hash, vchSig, fullyCanonical);
|
||||
}
|
||||
|
||||
//
|
||||
// NodePrivate
|
||||
//
|
||||
|
||||
RippleAddress RippleAddress::createNodePrivate (RippleAddress const& naSeed)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setNodePrivate (generateRootDeterministicPrivateKey (naSeed.getSeed()));
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
Blob const& RippleAddress::getNodePrivateData () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - getNodePrivateData");
|
||||
|
||||
case TOKEN_NODE_PRIVATE:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return vchData; // Silence compiler warning.
|
||||
}
|
||||
|
||||
uint256 RippleAddress::getNodePrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source = getNodePrivate");
|
||||
|
||||
case TOKEN_NODE_PRIVATE:
|
||||
return uint256 (vchData);
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return {}; // Silence compiler warning.
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanNodePrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - humanNodePrivate");
|
||||
|
||||
case TOKEN_NODE_PRIVATE:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return {}; // Silence compiler warning.
|
||||
}
|
||||
|
||||
bool RippleAddress::setNodePrivate (std::string const& strPrivate)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPrivate, TOKEN_NODE_PRIVATE, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setNodePrivate (Blob const& vPrivate)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (TOKEN_NODE_PRIVATE, vPrivate);
|
||||
}
|
||||
|
||||
void RippleAddress::setNodePrivate (uint256 hash256)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (TOKEN_NODE_PRIVATE, hash256);
|
||||
}
|
||||
|
||||
void RippleAddress::signNodePrivate (uint256 const& hash, Blob& vchSig) const
|
||||
{
|
||||
vchSig = ECDSASign (hash, getNodePrivate());
|
||||
|
||||
if (vchSig.empty())
|
||||
Throw<std::runtime_error> ("Signing failed.");
|
||||
}
|
||||
|
||||
//
|
||||
// AccountPublic
|
||||
//
|
||||
|
||||
RippleAddress RippleAddress::createAccountPublic (
|
||||
RippleAddress const& generator, int iSeq)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setAccountPublic (generator, iSeq);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
Blob const& RippleAddress::getAccountPublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - getAccountPublic");
|
||||
|
||||
case TOKEN_ACCOUNT_ID:
|
||||
Throw<std::runtime_error> ("public not available from account id");
|
||||
|
||||
case TOKEN_ACCOUNT_PUBLIC:
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return vchData; // Silence compiler warning.
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanAccountPublic () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - humanAccountPublic");
|
||||
|
||||
case TOKEN_ACCOUNT_ID:
|
||||
Throw<std::runtime_error> ("public not available from account id");
|
||||
|
||||
case TOKEN_ACCOUNT_PUBLIC:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return {}; // Silence compiler warning.
|
||||
}
|
||||
|
||||
bool RippleAddress::setAccountPublic (std::string const& strPublic)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPublic, TOKEN_ACCOUNT_PUBLIC, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPublic (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (TOKEN_ACCOUNT_PUBLIC, vPublic);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPublic (RippleAddress const& generator, int seq)
|
||||
{
|
||||
setAccountPublic (generatePublicDeterministicKey (
|
||||
generator.getGenerator(), seq));
|
||||
}
|
||||
|
||||
bool RippleAddress::accountPublicVerify (
|
||||
Blob const& message, Blob const& vucSig, ECDSA fullyCanonical) const
|
||||
{
|
||||
if (vchData.size() == 33 && vchData[0] == 0xED)
|
||||
{
|
||||
if (vucSig.size() != 64)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t const* publicKey = &vchData[1];
|
||||
uint8_t const* signature = &vucSig[0];
|
||||
|
||||
return !ed25519_sign_open (message.data(), message.size(),
|
||||
publicKey, signature)
|
||||
&& isCanonicalEd25519Signature (signature);
|
||||
}
|
||||
|
||||
return verifySignature (getAccountPublic(),
|
||||
sha512Half(makeSlice(message)), vucSig,
|
||||
fullyCanonical);
|
||||
}
|
||||
|
||||
//
|
||||
// AccountPrivate
|
||||
//
|
||||
|
||||
RippleAddress RippleAddress::createAccountPrivate (
|
||||
RippleAddress const& generator, RippleAddress const& naSeed, int iSeq)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setAccountPrivate (generator, naSeed, iSeq);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
uint256 RippleAddress::getAccountPrivate () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - getAccountPrivate");
|
||||
|
||||
case TOKEN_ACCOUNT_SECRET:
|
||||
return uint256::fromVoid (vchData.data() + (vchData.size() - 32));
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return {}; // Silence compiler warning.
|
||||
}
|
||||
|
||||
bool RippleAddress::setAccountPrivate (std::string const& strPrivate)
|
||||
{
|
||||
mIsValid = SetString (
|
||||
strPrivate, TOKEN_ACCOUNT_SECRET, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPrivate (Blob const& vPrivate)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (TOKEN_ACCOUNT_SECRET, vPrivate);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPrivate (uint256 hash256)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (TOKEN_ACCOUNT_SECRET, hash256);
|
||||
}
|
||||
|
||||
void RippleAddress::setAccountPrivate (
|
||||
RippleAddress const& generator, RippleAddress const& naSeed, int seq)
|
||||
{
|
||||
uint256 secretKey = generatePrivateDeterministicKey (
|
||||
generator.getGenerator(), naSeed.getSeed(), seq);
|
||||
|
||||
setAccountPrivate (secretKey);
|
||||
}
|
||||
|
||||
Blob RippleAddress::accountPrivateSign (Blob const& message) const
|
||||
{
|
||||
if (vchData.size() == 33 && vchData[0] == 0xED)
|
||||
{
|
||||
uint8_t const* secretKey = &vchData[1];
|
||||
ed25519_public_key publicKey;
|
||||
Blob signature (sizeof (ed25519_signature));
|
||||
|
||||
ed25519_publickey (secretKey, publicKey);
|
||||
|
||||
ed25519_sign (
|
||||
message.data(), message.size(), secretKey, publicKey,
|
||||
&signature[0]);
|
||||
|
||||
assert (isCanonicalEd25519Signature (signature.data()));
|
||||
|
||||
return signature;
|
||||
}
|
||||
|
||||
Blob result = ECDSASign(
|
||||
sha512Half(makeSlice(message)), getAccountPrivate());
|
||||
bool const ok = !result.empty();
|
||||
|
||||
CondLog (!ok, lsWARNING, RippleAddress)
|
||||
<< "accountPrivateSign: Signing failed.";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Blob RippleAddress::accountPrivateEncrypt (
|
||||
RippleAddress const& naPublicTo, Blob const& vucPlainText) const
|
||||
{
|
||||
uint256 secretKey = getAccountPrivate();
|
||||
Blob publicKey = naPublicTo.getAccountPublic();
|
||||
|
||||
Blob vucCipherText;
|
||||
|
||||
{
|
||||
try
|
||||
{
|
||||
vucCipherText = encryptECIES (secretKey, publicKey, vucPlainText);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
// TODO: log this or explain why this is unimportant!
|
||||
}
|
||||
}
|
||||
|
||||
return vucCipherText;
|
||||
}
|
||||
|
||||
Blob RippleAddress::accountPrivateDecrypt (
|
||||
RippleAddress const& naPublicFrom, Blob const& vucCipherText) const
|
||||
{
|
||||
uint256 secretKey = getAccountPrivate();
|
||||
Blob publicKey = naPublicFrom.getAccountPublic();
|
||||
|
||||
Blob vucPlainText;
|
||||
|
||||
{
|
||||
try
|
||||
{
|
||||
vucPlainText = decryptECIES (secretKey, publicKey, vucCipherText);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
// TODO: log this or explain why this is unimportant!
|
||||
}
|
||||
}
|
||||
|
||||
return vucPlainText;
|
||||
}
|
||||
|
||||
//
|
||||
// Generators
|
||||
//
|
||||
|
||||
Blob const& RippleAddress::getGenerator () const
|
||||
{
|
||||
// returns the public generator
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - getGenerator");
|
||||
|
||||
case TOKEN_FAMILY_GENERATOR:
|
||||
// Do nothing.
|
||||
return vchData;
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return vchData; // Silence compiler warning.
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanGenerator () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - humanGenerator");
|
||||
|
||||
case TOKEN_FAMILY_GENERATOR:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return {}; // Silence compiler warning.
|
||||
}
|
||||
|
||||
void RippleAddress::setGenerator (Blob const& vPublic)
|
||||
{
|
||||
mIsValid = true;
|
||||
SetData (TOKEN_FAMILY_GENERATOR, vPublic);
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createGeneratorPublic (RippleAddress const& naSeed)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
naNew.setGenerator (generateRootDeterministicPublicKey (naSeed.getSeed()));
|
||||
return naNew;
|
||||
}
|
||||
|
||||
//
|
||||
// Seed
|
||||
//
|
||||
|
||||
uint128 RippleAddress::getSeed () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - getSeed");
|
||||
|
||||
case TOKEN_FAMILY_SEED:
|
||||
return uint128 (vchData);
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return {}; // Silence compiler warning.
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanSeed1751 () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - humanSeed1751");
|
||||
|
||||
case TOKEN_FAMILY_SEED:
|
||||
{
|
||||
std::string strHuman;
|
||||
std::string strLittle;
|
||||
std::string strBig;
|
||||
uint128 uSeed = getSeed ();
|
||||
|
||||
strLittle.assign (uSeed.begin (), uSeed.end ());
|
||||
|
||||
strBig.assign (strLittle.rbegin (), strLittle.rend ());
|
||||
|
||||
RFC1751::getEnglishFromKey (strHuman, strBig);
|
||||
|
||||
return strHuman;
|
||||
}
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return {}; // Silence compiler warning.
|
||||
}
|
||||
|
||||
std::string RippleAddress::humanSeed () const
|
||||
{
|
||||
switch (nVersion)
|
||||
{
|
||||
case TOKEN_NONE:
|
||||
Throw<std::runtime_error> ("unset source - humanSeed");
|
||||
|
||||
case TOKEN_FAMILY_SEED:
|
||||
return ToString ();
|
||||
|
||||
default:
|
||||
Throw<std::runtime_error> ("bad source: " + std::to_string(nVersion));
|
||||
}
|
||||
return {}; // Silence compiler warning.
|
||||
}
|
||||
|
||||
int RippleAddress::setSeed1751 (std::string const& strHuman1751)
|
||||
{
|
||||
std::string strKey;
|
||||
int iResult = RFC1751::getKeyFromEnglish (strKey, strHuman1751);
|
||||
|
||||
if (1 == iResult)
|
||||
{
|
||||
Blob vchLittle (strKey.rbegin (), strKey.rend ());
|
||||
uint128 uSeed (vchLittle);
|
||||
|
||||
setSeed (uSeed);
|
||||
}
|
||||
|
||||
return iResult;
|
||||
}
|
||||
|
||||
bool RippleAddress::setSeed (std::string const& strSeed)
|
||||
{
|
||||
mIsValid = SetString (strSeed, TOKEN_FAMILY_SEED, Base58::getRippleAlphabet ());
|
||||
|
||||
return mIsValid;
|
||||
}
|
||||
|
||||
bool RippleAddress::setSeedGeneric (std::string const& strText)
|
||||
{
|
||||
RippleAddress naTemp;
|
||||
bool bResult = true;
|
||||
uint128 uSeed;
|
||||
|
||||
if (parseBase58<AccountID>(strText))
|
||||
return false;
|
||||
|
||||
if (strText.empty ()
|
||||
|| naTemp.setAccountPublic (strText)
|
||||
|| naTemp.setAccountPrivate (strText)
|
||||
|| naTemp.setNodePublic (strText)
|
||||
|| naTemp.setNodePrivate (strText))
|
||||
{
|
||||
bResult = false;
|
||||
}
|
||||
else if (strText.length () == 32 && uSeed.SetHex (strText, true))
|
||||
{
|
||||
setSeed (uSeed);
|
||||
}
|
||||
else if (setSeed (strText))
|
||||
{
|
||||
// Log::out() << "Recognized seed.";
|
||||
}
|
||||
else if (1 == setSeed1751 (strText))
|
||||
{
|
||||
// Log::out() << "Recognized 1751 seed.";
|
||||
}
|
||||
else
|
||||
{
|
||||
setSeed (PassPhraseToKey (strText));
|
||||
}
|
||||
|
||||
return bResult;
|
||||
}
|
||||
|
||||
void RippleAddress::setSeed (uint128 hash128)
|
||||
{
|
||||
mIsValid = true;
|
||||
|
||||
SetData (TOKEN_FAMILY_SEED, hash128);
|
||||
}
|
||||
|
||||
void RippleAddress::setSeedRandom ()
|
||||
{
|
||||
// XXX Maybe we should call MakeNewKey
|
||||
uint128 key;
|
||||
|
||||
beast::rngfill (
|
||||
key.begin(),
|
||||
key.size(),
|
||||
crypto_prng());
|
||||
|
||||
RippleAddress::setSeed (key);
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createSeedRandom ()
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setSeedRandom ();
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
RippleAddress RippleAddress::createSeedGeneric (std::string const& strText)
|
||||
{
|
||||
RippleAddress naNew;
|
||||
|
||||
naNew.setSeedGeneric (strText);
|
||||
|
||||
return naNew;
|
||||
}
|
||||
|
||||
uint256 keyFromSeed (uint128 const& seed)
|
||||
{
|
||||
return sha512Half_s(Slice(
|
||||
seed.data(), seed.size()));
|
||||
}
|
||||
|
||||
RippleAddress getSeedFromRPC (Json::Value const& params)
|
||||
{
|
||||
// This function is only called when `key_type` is present.
|
||||
assert (params.isMember (jss::key_type));
|
||||
|
||||
bool const has_passphrase = params.isMember (jss::passphrase);
|
||||
bool const has_seed = params.isMember (jss::seed);
|
||||
bool const has_seed_hex = params.isMember (jss::seed_hex);
|
||||
|
||||
int const n_secrets = has_passphrase + has_seed + has_seed_hex;
|
||||
|
||||
if (n_secrets > 1)
|
||||
{
|
||||
// `passphrase`, `seed`, and `seed_hex` are mutually exclusive.
|
||||
return RippleAddress();
|
||||
}
|
||||
|
||||
RippleAddress result;
|
||||
|
||||
if (has_seed)
|
||||
{
|
||||
std::string const seed = params[jss::seed].asString();
|
||||
|
||||
result.setSeed (seed);
|
||||
}
|
||||
else if (has_seed_hex)
|
||||
{
|
||||
uint128 seed;
|
||||
std::string const seed_hex = params[jss::seed_hex].asString();
|
||||
|
||||
if (seed_hex.size() != 32 || !seed.SetHex (seed_hex, true))
|
||||
{
|
||||
return RippleAddress();
|
||||
}
|
||||
|
||||
result.setSeed (seed);
|
||||
}
|
||||
else if (has_passphrase)
|
||||
{
|
||||
std::string const passphrase = params[jss::passphrase].asString();
|
||||
|
||||
// Given `key_type`, `passphrase` is always the passphrase.
|
||||
uint128 const seed = PassPhraseToKey (passphrase);
|
||||
result.setSeed (seed);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
KeyPair generateKeysFromSeed (KeyType type, RippleAddress const& seed)
|
||||
{
|
||||
KeyPair result;
|
||||
|
||||
if (! seed.isSet())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
if (type == KeyType::secp256k1)
|
||||
{
|
||||
RippleAddress generator = RippleAddress::createGeneratorPublic (seed);
|
||||
result.secretKey.setAccountPrivate (generator, seed, 0);
|
||||
result.publicKey.setAccountPublic (generator, 0);
|
||||
}
|
||||
else if (type == KeyType::ed25519)
|
||||
{
|
||||
uint256 secretkey = keyFromSeed (seed.getSeed());
|
||||
|
||||
Blob ed25519_key (33);
|
||||
ed25519_key[0] = 0xED;
|
||||
|
||||
assert (secretkey.size() + 1 == ed25519_key.size());
|
||||
memcpy (&ed25519_key[1], secretkey.data(), secretkey.size());
|
||||
result.secretKey.setAccountPrivate (ed25519_key);
|
||||
|
||||
ed25519_publickey (secretkey.data(), &ed25519_key[1]);
|
||||
result.publicKey.setAccountPublic (ed25519_key);
|
||||
|
||||
secretkey.zero(); // security erase
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (false); // not reached
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// DEPRECATED
|
||||
AccountID
|
||||
calcAccountID (RippleAddress const& publicKey)
|
||||
{
|
||||
auto const& pk =
|
||||
publicKey.getAccountPublic();
|
||||
ripesha_hasher rsh;
|
||||
rsh(pk.data(), pk.size());
|
||||
auto const d = static_cast<
|
||||
ripesha_hasher::result_type>(rsh);
|
||||
AccountID id;
|
||||
static_assert(sizeof(d) == sizeof(id), "");
|
||||
std::memcpy(id.data(), d.data(), d.size());
|
||||
return id;
|
||||
}
|
||||
|
||||
} // ripple
|
||||
@@ -657,6 +657,12 @@ void STObject::setFieldVL (SField const& field, Blob const& v)
|
||||
setFieldUsingSetValue <STBlob> (field, Buffer(v.data (), v.size ()));
|
||||
}
|
||||
|
||||
void STObject::setFieldVL (SField const& field, Slice const& s)
|
||||
{
|
||||
setFieldUsingSetValue <STBlob>
|
||||
(field, Buffer(s.data(), s.size()));
|
||||
}
|
||||
|
||||
void STObject::setFieldAmount (SField const& field, STAmount const& v)
|
||||
{
|
||||
setFieldUsingAssignment (field, v);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/protocol/HashPrefix.h>
|
||||
#include <ripple/protocol/JsonFields.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/Protocol.h>
|
||||
#include <ripple/protocol/Sign.h>
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
@@ -165,10 +166,18 @@ Blob STTx::getSignature () const
|
||||
}
|
||||
}
|
||||
|
||||
void STTx::sign (RippleAddress const& private_key)
|
||||
void STTx::sign (
|
||||
PublicKey const& publicKey,
|
||||
SecretKey const& secretKey)
|
||||
{
|
||||
Blob const signature = private_key.accountPrivateSign (getSigningData (*this));
|
||||
setFieldVL (sfTxnSignature, signature);
|
||||
auto const data = getSigningData (*this);
|
||||
|
||||
auto const sig = ripple::sign (
|
||||
publicKey,
|
||||
secretKey,
|
||||
makeSlice(data));
|
||||
|
||||
setFieldVL (sfTxnSignature, sig);
|
||||
tid_ = getHash(HashPrefix::transactionID);
|
||||
}
|
||||
|
||||
@@ -261,25 +270,30 @@ STTx::checkSingleSign () const
|
||||
if (isFieldPresent (sfSigners))
|
||||
return false;
|
||||
|
||||
bool ret = false;
|
||||
bool validSig = false;
|
||||
try
|
||||
{
|
||||
ECDSA const fullyCanonical = (getFlags() & tfFullyCanonicalSig)
|
||||
? ECDSA::strict
|
||||
: ECDSA::not_strict;
|
||||
bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig);
|
||||
auto const spk = getFieldVL (sfSigningPubKey);
|
||||
|
||||
RippleAddress n;
|
||||
n.setAccountPublic (getFieldVL (sfSigningPubKey));
|
||||
if (publicKeyType (makeSlice(spk)))
|
||||
{
|
||||
Blob const signature = getFieldVL (sfTxnSignature);
|
||||
Blob const data = getSigningData (*this);
|
||||
|
||||
ret = n.accountPublicVerify (getSigningData (*this),
|
||||
getFieldVL (sfTxnSignature), fullyCanonical);
|
||||
validSig = verify (
|
||||
PublicKey (makeSlice(spk)),
|
||||
makeSlice(data),
|
||||
makeSlice(signature),
|
||||
fullyCanonical);
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
// Assume it was a signature failure.
|
||||
ret = false;
|
||||
validSig = false;
|
||||
}
|
||||
return ret;
|
||||
return validSig;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -310,9 +324,7 @@ STTx::checkMultiSign () const
|
||||
auto const txnAccountID = getAccountID (sfAccount);
|
||||
|
||||
// Determine whether signatures must be full canonical.
|
||||
ECDSA const fullyCanonical = (getFlags() & tfFullyCanonicalSig)
|
||||
? ECDSA::strict
|
||||
: ECDSA::not_strict;
|
||||
bool const fullyCanonical = (getFlags() & tfFullyCanonicalSig);
|
||||
|
||||
// Signers must be in sorted order by AccountID.
|
||||
AccountID lastAccountID (beast::zero);
|
||||
@@ -339,14 +351,19 @@ STTx::checkMultiSign () const
|
||||
Serializer s = dataStart;
|
||||
finishMultiSigningData (accountID, s);
|
||||
|
||||
RippleAddress const pubKey =
|
||||
RippleAddress::createAccountPublic (
|
||||
signer.getFieldVL (sfSigningPubKey));
|
||||
auto spk = signer.getFieldVL (sfSigningPubKey);
|
||||
|
||||
Blob const signature = signer.getFieldVL (sfTxnSignature);
|
||||
if (publicKeyType (makeSlice(spk)))
|
||||
{
|
||||
Blob const signature =
|
||||
signer.getFieldVL (sfTxnSignature);
|
||||
|
||||
validSig = pubKey.accountPublicVerify (
|
||||
s.getData(), signature, fullyCanonical);
|
||||
validSig = verify (
|
||||
PublicKey (makeSlice(spk)),
|
||||
s.slice(),
|
||||
makeSlice(signature),
|
||||
fullyCanonical);
|
||||
}
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace ripple {
|
||||
STValidation::STValidation (SerialIter& sit, bool checkSignature)
|
||||
: STObject (getFormat (), sit, sfValidation)
|
||||
{
|
||||
mNodeID = RippleAddress::createNodePublic (getFieldVL (sfSigningPubKey)).getNodeID ();
|
||||
mNodeID = calcNodeID(
|
||||
PublicKey(makeSlice (getFieldVL (sfSigningPubKey))));
|
||||
assert (mNodeID.isNonZero ());
|
||||
|
||||
if (checkSignature && !isValid ())
|
||||
@@ -40,8 +41,10 @@ STValidation::STValidation (SerialIter& sit, bool checkSignature)
|
||||
}
|
||||
|
||||
STValidation::STValidation (
|
||||
uint256 const& ledgerHash, NetClock::time_point signTime,
|
||||
RippleAddress const& raPub, bool isFull)
|
||||
uint256 const& ledgerHash,
|
||||
NetClock::time_point signTime,
|
||||
PublicKey const& publicKey,
|
||||
bool isFull)
|
||||
: STObject (getFormat (), sfValidation)
|
||||
, mSeen (signTime)
|
||||
{
|
||||
@@ -49,23 +52,21 @@ STValidation::STValidation (
|
||||
setFieldH256 (sfLedgerHash, ledgerHash);
|
||||
setFieldU32 (sfSigningTime, signTime.time_since_epoch().count());
|
||||
|
||||
setFieldVL (sfSigningPubKey, raPub.getNodePublic ());
|
||||
mNodeID = raPub.getNodeID ();
|
||||
setFieldVL (sfSigningPubKey, publicKey.slice());
|
||||
mNodeID = calcNodeID(publicKey);
|
||||
assert (mNodeID.isNonZero ());
|
||||
|
||||
if (!isFull)
|
||||
setFlag (kFullFlag);
|
||||
}
|
||||
|
||||
uint256 STValidation::sign (RippleAddress const& raPriv)
|
||||
uint256 STValidation::sign (SecretKey const& secretKey)
|
||||
{
|
||||
setFlag (vfFullyCanonicalSig);
|
||||
|
||||
auto signingHash = getSigningHash ();
|
||||
Blob signature;
|
||||
raPriv.signNodePrivate (signingHash, signature);
|
||||
setFieldVL (sfSignature, signature);
|
||||
|
||||
auto const signingHash = getSigningHash();
|
||||
setFieldVL (sfSignature,
|
||||
signDigest (getSignerPublic(), secretKey, signingHash));
|
||||
return signingHash;
|
||||
}
|
||||
|
||||
@@ -104,11 +105,10 @@ bool STValidation::isValid (uint256 const& signingHash) const
|
||||
{
|
||||
try
|
||||
{
|
||||
const ECDSA fullyCanonical = getFlags () & vfFullyCanonicalSig ?
|
||||
ECDSA::strict : ECDSA::not_strict;
|
||||
RippleAddress raPublicKey = RippleAddress::createNodePublic (getFieldVL (sfSigningPubKey));
|
||||
return raPublicKey.isValid () &&
|
||||
raPublicKey.verifyNodePublic (signingHash, getFieldVL (sfSignature), fullyCanonical);
|
||||
return verifyDigest (getSignerPublic(),
|
||||
signingHash,
|
||||
makeSlice(getFieldVL (sfSignature)),
|
||||
getFlags () & vfFullyCanonicalSig);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
@@ -117,11 +117,9 @@ bool STValidation::isValid (uint256 const& signingHash) const
|
||||
}
|
||||
}
|
||||
|
||||
RippleAddress STValidation::getSignerPublic () const
|
||||
PublicKey STValidation::getSignerPublic () const
|
||||
{
|
||||
RippleAddress a;
|
||||
a.setNodePublic (getFieldVL (sfSigningPubKey));
|
||||
return a;
|
||||
return PublicKey(makeSlice (getFieldVL (sfSigningPubKey)));
|
||||
}
|
||||
|
||||
bool STValidation::isFull () const
|
||||
|
||||
@@ -31,22 +31,6 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
Seed::~Seed()
|
||||
{
|
||||
beast::secure_erase(
|
||||
buf_.data(), buf_.size());
|
||||
}
|
||||
|
||||
Seed::Seed (Slice const& slice)
|
||||
{
|
||||
if (slice.size() != buf_.size())
|
||||
LogicError("Seed::Seed: invalid size");
|
||||
std::memcpy(buf_.data(),
|
||||
slice.data(), buf_.size());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
SecretKey::~SecretKey()
|
||||
{
|
||||
beast::secure_erase(buf_, sizeof(buf_));
|
||||
@@ -61,51 +45,56 @@ SecretKey::SecretKey (Slice const& slice)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Produces a sequence of secp256k1 key pairs. */
|
||||
class Generator
|
||||
Generator::Generator (Seed const& seed)
|
||||
{
|
||||
private:
|
||||
Blob gen_; // VFALCO compile time size?
|
||||
uint128 ui;
|
||||
std::memcpy(ui.data(),
|
||||
seed.data(), seed.size());
|
||||
gen_ = generateRootDeterministicPublicKey(ui);
|
||||
}
|
||||
|
||||
public:
|
||||
explicit
|
||||
Generator (Seed const& seed)
|
||||
{
|
||||
uint128 ui;
|
||||
std::memcpy(ui.data(),
|
||||
seed.data(), seed.size());
|
||||
gen_ = generateRootDeterministicPublicKey(ui);
|
||||
}
|
||||
std::pair<PublicKey, SecretKey>
|
||||
Generator::operator()(Seed const& seed, std::size_t ordinal) const
|
||||
{
|
||||
uint128 ui;
|
||||
std::memcpy(ui.data(), seed.data(), seed.size());
|
||||
auto gsk = generatePrivateDeterministicKey(gen_, ui, ordinal);
|
||||
auto gpk = generatePublicDeterministicKey(gen_, ordinal);
|
||||
SecretKey const sk(Slice{ gsk.data(), gsk.size() });
|
||||
PublicKey const pk(Slice{ gpk.data(), gpk.size() });
|
||||
beast::secure_erase(ui.data(), ui.size());
|
||||
beast::secure_erase(gsk.data(), gsk.size());
|
||||
return { pk, sk };
|
||||
}
|
||||
|
||||
/** Generate the nth key pair.
|
||||
|
||||
The seed is required to produce the private key.
|
||||
*/
|
||||
std::pair<PublicKey, SecretKey>
|
||||
operator()(Seed const& seed, std::size_t ordinal) const
|
||||
{
|
||||
uint128 ui;
|
||||
std::memcpy(ui.data(), seed.data(), seed.size());
|
||||
auto gsk = generatePrivateDeterministicKey(gen_, ui, ordinal);
|
||||
auto gpk = generatePublicDeterministicKey(gen_, ordinal);
|
||||
SecretKey const sk(Slice{ gsk.data(), gsk.size() });
|
||||
PublicKey const pk(Slice{ gpk.data(), gpk.size() });
|
||||
beast::secure_erase(ui.data(), ui.size());
|
||||
beast::secure_erase(gsk.data(), gsk.size());
|
||||
return { pk, sk };
|
||||
}
|
||||
|
||||
/** Generate the nth public key. */
|
||||
PublicKey
|
||||
operator()(std::size_t ordinal) const
|
||||
{
|
||||
auto gpk = generatePublicDeterministicKey(gen_, ordinal);
|
||||
return PublicKey(Slice{ gpk.data(), gpk.size() });
|
||||
}
|
||||
};
|
||||
PublicKey
|
||||
Generator::operator()(std::size_t ordinal) const
|
||||
{
|
||||
auto gpk = generatePublicDeterministicKey(gen_, ordinal);
|
||||
return PublicKey(Slice{ gpk.data(), gpk.size() });
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Buffer
|
||||
signDigest (PublicKey const& pk, SecretKey const& sk,
|
||||
uint256 const& digest)
|
||||
{
|
||||
if (publicKeyType(pk.slice()) != KeyType::secp256k1)
|
||||
LogicError("sign: secp256k1 required for digest signing");
|
||||
|
||||
int siglen = 72;
|
||||
unsigned char sig[72];
|
||||
auto const result = secp256k1_ecdsa_sign(
|
||||
secp256k1Context(),
|
||||
digest.data(), sig, &siglen,
|
||||
sk.data(), secp256k1_nonce_function_rfc6979,
|
||||
nullptr);
|
||||
if (result != 1)
|
||||
LogicError("sign: secp256k1_ecdsa_sign failed");
|
||||
return Buffer(sig, siglen);
|
||||
}
|
||||
|
||||
Buffer
|
||||
sign (PublicKey const& pk,
|
||||
SecretKey const& sk, Slice const& m)
|
||||
@@ -147,29 +136,6 @@ sign (PublicKey const& pk,
|
||||
}
|
||||
}
|
||||
|
||||
Seed
|
||||
randomSeed()
|
||||
{
|
||||
std::uint8_t buf[16];
|
||||
beast::rngfill(
|
||||
buf,
|
||||
sizeof(buf),
|
||||
crypto_prng());
|
||||
Seed seed(Slice{ buf, sizeof(buf) });
|
||||
beast::secure_erase(buf, sizeof(buf));
|
||||
return seed;
|
||||
}
|
||||
|
||||
Seed
|
||||
generateSeed (std::string const& passPhrase)
|
||||
{
|
||||
sha512_half_hasher_s h;
|
||||
h(passPhrase.data(), passPhrase.size());
|
||||
auto const digest =
|
||||
sha512_half_hasher::result_type(h);
|
||||
return Seed({ digest.data(), 16 });
|
||||
}
|
||||
|
||||
SecretKey
|
||||
randomSecretKey()
|
||||
{
|
||||
@@ -185,16 +151,27 @@ randomSecretKey()
|
||||
|
||||
// VFALCO TODO Rewrite all this without using OpenSSL
|
||||
// or calling into GenerateDetermisticKey
|
||||
|
||||
SecretKey
|
||||
generateSecretKey (Seed const& seed)
|
||||
generateSecretKey (KeyType type, Seed const& seed)
|
||||
{
|
||||
uint128 ps;
|
||||
std::memcpy(ps.data(),
|
||||
seed.data(), seed.size());
|
||||
auto const upk =
|
||||
generateRootDeterministicPrivateKey(ps);
|
||||
return SecretKey(Slice{ upk.data(), upk.size() });
|
||||
if (type == KeyType::ed25519)
|
||||
{
|
||||
auto const key = sha512Half_s(Slice(
|
||||
seed.data(), seed.size()));
|
||||
return SecretKey(Slice{ key.data(), key.size() });
|
||||
}
|
||||
|
||||
if (type == KeyType::secp256k1)
|
||||
{
|
||||
uint128 ps;
|
||||
std::memcpy(ps.data(),
|
||||
seed.data(), seed.size());
|
||||
auto const upk =
|
||||
generateRootDeterministicPrivateKey(ps);
|
||||
return SecretKey(Slice{ upk.data(), upk.size() });
|
||||
}
|
||||
|
||||
LogicError ("generateSecretKey: unknown key type");
|
||||
}
|
||||
|
||||
PublicKey
|
||||
@@ -240,7 +217,7 @@ generateKeyPair (KeyType type, Seed const& seed)
|
||||
default:
|
||||
case KeyType::ed25519:
|
||||
{
|
||||
auto const sk = generateSecretKey(seed);
|
||||
auto const sk = generateSecretKey(type, seed);
|
||||
return { derivePublicKey(type, sk), sk };
|
||||
}
|
||||
}
|
||||
@@ -253,5 +230,17 @@ randomKeyPair (KeyType type)
|
||||
return { derivePublicKey(type, sk), sk };
|
||||
}
|
||||
|
||||
template <>
|
||||
boost::optional<SecretKey>
|
||||
parseBase58 (TokenType type, std::string const& s)
|
||||
{
|
||||
auto const result = decodeBase58Token(s, type);
|
||||
if (result.empty())
|
||||
return boost::none;
|
||||
if (result.size() != 32)
|
||||
return boost::none;
|
||||
return SecretKey(makeSlice(result));
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
|
||||
149
src/ripple/protocol/impl/Seed.cpp
Normal file
149
src/ripple/protocol/impl/Seed.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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 <BeastConfig.h>
|
||||
#include <ripple/basics/Buffer.h>
|
||||
#include <ripple/protocol/AccountID.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/SecretKey.h>
|
||||
#include <ripple/protocol/Seed.h>
|
||||
#include <ripple/protocol/digest.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
#include <ripple/crypto/RFC1751.h>
|
||||
#include <ripple/crypto/csprng.h>
|
||||
#include <beast/crypto/secure_erase.h>
|
||||
#include <beast/rngfill.h>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
Seed::~Seed()
|
||||
{
|
||||
beast::secure_erase(buf_.data(), buf_.size());
|
||||
}
|
||||
|
||||
Seed::Seed (Slice const& slice)
|
||||
{
|
||||
if (slice.size() != buf_.size())
|
||||
LogicError("Seed::Seed: invalid size");
|
||||
std::memcpy(buf_.data(),
|
||||
slice.data(), buf_.size());
|
||||
}
|
||||
|
||||
Seed::Seed (uint128 const& seed)
|
||||
{
|
||||
if (seed.size() != buf_.size())
|
||||
LogicError("Seed::Seed: invalid size");
|
||||
std::memcpy(buf_.data(),
|
||||
seed.data(), buf_.size());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
Seed
|
||||
randomSeed()
|
||||
{
|
||||
std::array <std::uint8_t, 16> buffer;
|
||||
beast::rngfill (
|
||||
buffer.data(),
|
||||
buffer.size(),
|
||||
crypto_prng());
|
||||
Seed seed (makeSlice (buffer));
|
||||
beast::secure_erase(buffer.data(), buffer.size());
|
||||
return seed;
|
||||
}
|
||||
|
||||
Seed
|
||||
generateSeed (std::string const& passPhrase)
|
||||
{
|
||||
sha512_half_hasher_s h;
|
||||
h(passPhrase.data(), passPhrase.size());
|
||||
auto const digest =
|
||||
sha512_half_hasher::result_type(h);
|
||||
return Seed({ digest.data(), 16 });
|
||||
}
|
||||
|
||||
template <>
|
||||
boost::optional<Seed>
|
||||
parseBase58 (std::string const& s)
|
||||
{
|
||||
auto const result = decodeBase58Token(
|
||||
s, TokenType::TOKEN_FAMILY_SEED);
|
||||
if (result.empty())
|
||||
return boost::none;
|
||||
if (result.size() != 16)
|
||||
return boost::none;
|
||||
return Seed(makeSlice(result));
|
||||
}
|
||||
|
||||
boost::optional<Seed>
|
||||
parseGenericSeed (std::string const& str)
|
||||
{
|
||||
if (str.empty ())
|
||||
return boost::none;
|
||||
|
||||
if (parseBase58<AccountID>(str) ||
|
||||
parseBase58<PublicKey>(TokenType::TOKEN_NODE_PUBLIC, str) ||
|
||||
parseBase58<PublicKey>(TokenType::TOKEN_ACCOUNT_PUBLIC, str) ||
|
||||
parseBase58<SecretKey>(TokenType::TOKEN_NODE_PRIVATE, str) ||
|
||||
parseBase58<SecretKey>(TokenType::TOKEN_ACCOUNT_SECRET, str))
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
{
|
||||
uint128 seed;
|
||||
|
||||
if (seed.SetHexExact (str))
|
||||
return Seed { Slice(seed.data(), seed.size()) };
|
||||
}
|
||||
|
||||
if (auto seed = parseBase58<Seed> (str))
|
||||
return seed;
|
||||
|
||||
{
|
||||
std::string key;
|
||||
if (RFC1751::getKeyFromEnglish (key, str) == 1)
|
||||
{
|
||||
Blob const blob (key.rbegin(), key.rend());
|
||||
return Seed{ uint128{blob} };
|
||||
}
|
||||
}
|
||||
|
||||
return generateSeed (str);
|
||||
}
|
||||
|
||||
std::string
|
||||
seedAs1751 (Seed const& seed)
|
||||
{
|
||||
std::string key;
|
||||
|
||||
std::reverse_copy (
|
||||
seed.data(),
|
||||
seed.data() + 16,
|
||||
std::back_inserter(key));
|
||||
|
||||
std::string encodedKey;
|
||||
RFC1751::getEnglishFromKey (encodedKey, key);
|
||||
return encodedKey;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -242,6 +242,14 @@ int Serializer::addVL (Blob const& vector)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::addVL (Slice const& slice)
|
||||
{
|
||||
int ret = addEncoded (slice.size());
|
||||
if (slice.size())
|
||||
addRaw (slice.data(), slice.size());
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Serializer::addVL (const void* ptr, int len)
|
||||
{
|
||||
int ret = addEncoded (len);
|
||||
|
||||
@@ -45,10 +45,9 @@ verify (STObject const& st,
|
||||
Serializer ss;
|
||||
ss.add32(prefix);
|
||||
st.addWithoutSigningFields(ss);
|
||||
return pk.verify(
|
||||
return verify(pk,
|
||||
Slice(ss.data(), ss.size()),
|
||||
Slice(sig->data(), sig->size()),
|
||||
true);
|
||||
Slice(sig->data(), sig->size()));
|
||||
}
|
||||
|
||||
// Questions regarding buildMultiSigningData:
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <ripple/protocol/SystemParameters.h>
|
||||
#include <ripple/protocol/RippleAddress.h>
|
||||
#include <ripple/protocol/UintTypes.h>
|
||||
#include <ripple/protocol/types.h>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user