mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-27 14:35:52 +00:00
General refactoring, using C++11
* Remove broken RecycledObjectPool * Fix beast::ServiceQueue using List instead of LockFreeStack * Add class semaphore, fixes broken Semaphore * Move crytpo module files to new beast directory * Use c++11 replacements for boost and beast types: - std::atomic instead of beast::Atomic - std::function instead of boost::function, beast::function - std::unique_ptr instead of beast::ScopedPointer - std::shared_ptr instead of boost::shared_ptr * Remove modules: - beast_db - beast_crypto - beast_extras * Remove unnecessary classes: - AbstractFifo - AddConst - AtomicCounter - AtomicFlag - AtomicPointer - AtomicState - CopyConst - Expression - ForwardList - IfCond - Interval - IntrusiveArray - KeyvaDB - PointerToOther - PointerTraits - RemoveConst - RemoveConstVolatile - RemoveReference - RemoveVolatile - SharedObjectArray - SingleThreadedSharedObject - SophiaDB factory - SortedSet - WeakReference - beast::unique_ptr
This commit is contained in:
405
beast/crypto/impl/BinaryEncoding.cpp
Normal file
405
beast/crypto/impl/BinaryEncoding.cpp
Normal file
@@ -0,0 +1,405 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of Beast: https://github.com/vinniefalco/Beast
|
||||
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
|
||||
|
||||
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 "../BinaryEncoding.h"
|
||||
#include "../UnsignedInteger.h"
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
|
||||
namespace beast {
|
||||
|
||||
/** Generic algorithms for base encoding and decoding. */
|
||||
class BinaryEncoding
|
||||
{
|
||||
public:
|
||||
/** Concept: Conversion
|
||||
|
||||
X denotes a Conversion class, a is a value of type X,
|
||||
i is an integral type.
|
||||
|
||||
Requirements:
|
||||
|
||||
Expression Type Notes/Contracts
|
||||
------------- ----------- ------------------
|
||||
X a;
|
||||
X::radix size_type constexpr
|
||||
a.map (i) char maps base numeral to a char
|
||||
*/
|
||||
|
||||
/** Encode the unsigned integer into a string using the specified conversion. */
|
||||
template <typename Conversion, std::size_t Bytes>
|
||||
static std::string encode (UnsignedInteger <Bytes> v, Conversion c = Conversion ())
|
||||
{
|
||||
// bi is destroyed in this process
|
||||
typename UnsignedInteger <Bytes>::CalcType bi (v.toCalcType ());
|
||||
std::size_t const radix (Conversion::radix);
|
||||
std::string s;
|
||||
s.reserve (bi.size() * 3); // guess
|
||||
while (bi.isNotZero ())
|
||||
{
|
||||
std::size_t const m (bi % radix);
|
||||
bi /= radix;
|
||||
s.push_back (c.map (m));
|
||||
}
|
||||
std::reverse (s.begin(), s.end());
|
||||
return s;
|
||||
}
|
||||
|
||||
/** Decode the string into an unsigned integer.
|
||||
The size must match exactly
|
||||
@return `true` on success.
|
||||
*/
|
||||
template <typename Conversion, std::size_t Bytes>
|
||||
static bool decode (UnsignedInteger <Bytes>& rv,
|
||||
std::string const& s, Conversion c = Conversion ())
|
||||
{
|
||||
typename UnsignedInteger <Bytes>::CalcType bi (rv.toCalcType (false));
|
||||
std::size_t const radix (Conversion::radix);
|
||||
bi.clear ();
|
||||
for (std::string::const_iterator iter (s.begin()); iter != s.end(); ++iter)
|
||||
{
|
||||
int const v (c.invert (*iter));
|
||||
if (v == -1)
|
||||
return false;
|
||||
bi *= radix;
|
||||
bi += v;
|
||||
}
|
||||
bi.toCanonical();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Some common code
|
||||
template <class Conversion>
|
||||
class BaseConversion
|
||||
{
|
||||
public:
|
||||
char map (std::size_t i) const
|
||||
{
|
||||
return Conversion::alphabet () [i];
|
||||
}
|
||||
|
||||
int invert (char c) const
|
||||
{
|
||||
return Conversion::inverse_alphabet () [c];
|
||||
}
|
||||
|
||||
static std::vector <int> const& inverse_alphabet ()
|
||||
{
|
||||
static std::vector <int> t (invert (Conversion::alphabet(), Conversion::radix));
|
||||
return t;
|
||||
}
|
||||
|
||||
/** Build the inverse mapping table from characters to digits. */
|
||||
static std::vector <int> invert (std::string const& alphabet, std::size_t radix)
|
||||
{
|
||||
std::vector <int> table (256, -1);
|
||||
for (std::size_t i (0); i < radix; ++i)
|
||||
table [alphabet [i]] = i;
|
||||
return table;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Foolproof hexadecimal encoding and decoding facility.
|
||||
This is to check the correctness of the more complex converters.
|
||||
*/
|
||||
class HexEncoding
|
||||
{
|
||||
public:
|
||||
template <std::size_t Bytes>
|
||||
static std::string encode (UnsignedInteger <Bytes> const& v)
|
||||
{
|
||||
std::string s;
|
||||
uint8 const* src (v.cbegin()-1);
|
||||
char const* const tab (alphabet().c_str());
|
||||
s.reserve (Bytes * 2);
|
||||
for (std::size_t bytes (v.size);bytes--;)
|
||||
{
|
||||
uint8 const v (*++src);
|
||||
s.push_back (tab [v>>4]);
|
||||
s.push_back (tab [v&0x0f]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
template <std::size_t Bytes>
|
||||
static bool decode (UnsignedInteger <Bytes>& rv,
|
||||
std::string const& s)
|
||||
{
|
||||
// can't have an odd size
|
||||
if (s.size() & 1)
|
||||
return false;
|
||||
uint8* dest (rv.begin()-1);
|
||||
int const* const tab (&inverse_alphabet().front());
|
||||
for (std::string::const_iterator iter (s.begin()); iter != s.end();)
|
||||
{
|
||||
int const n1 (tab [*iter++]);
|
||||
if (n1 == -1)
|
||||
return false;
|
||||
int const n2 (tab [*iter++]);
|
||||
if (n2 == -1)
|
||||
return false;
|
||||
*++dest = ((uint8)((n1<<4)|n2));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string const& alphabet ()
|
||||
{
|
||||
static std::string s ("0123456789ABCDEF");
|
||||
return s;
|
||||
}
|
||||
|
||||
static std::vector <int> const& inverse_alphabet ()
|
||||
{
|
||||
static std::vector <int> s (invert (alphabet(), 16));
|
||||
return s;
|
||||
}
|
||||
|
||||
/** Build the inverse mapping table from characters to digits. */
|
||||
static std::vector <int> invert (std::string const& alphabet, std::size_t radix)
|
||||
{
|
||||
std::vector <int> table (256, -1);
|
||||
for (std::size_t i (0); i < radix; ++i)
|
||||
table [alphabet [i]] = i;
|
||||
return table;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Base58 conversion used by Bitcoin. */
|
||||
class BitcoinBase58Conversion : public BaseConversion <BitcoinBase58Conversion>
|
||||
{
|
||||
public:
|
||||
static std::size_t const radix = 58;
|
||||
|
||||
char const* name () const
|
||||
{
|
||||
return "BitcoinBase58";
|
||||
}
|
||||
|
||||
static std::string const& alphabet ()
|
||||
{
|
||||
static std::string s (
|
||||
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
/** Base58 conversion used by Ripple. */
|
||||
class RippleBase58Conversion : public BaseConversion <RippleBase58Conversion>
|
||||
{
|
||||
public:
|
||||
static std::size_t const radix = 58;
|
||||
|
||||
char const* name () const
|
||||
{
|
||||
return "RippleBase58";
|
||||
}
|
||||
|
||||
static std::string const& alphabet ()
|
||||
{
|
||||
static std::string s (
|
||||
"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"
|
||||
);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Base64Conversion : public BaseConversion <Base64Conversion>
|
||||
{
|
||||
public:
|
||||
static std::size_t const radix = 64;
|
||||
|
||||
char const* name () const
|
||||
{
|
||||
return "Base64";
|
||||
}
|
||||
|
||||
static std::string const& alphabet ()
|
||||
{
|
||||
static std::string s (
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class Base16Conversion : public BaseConversion <Base16Conversion>
|
||||
{
|
||||
public:
|
||||
static std::size_t const radix = 16;
|
||||
|
||||
char const* name () const
|
||||
{
|
||||
return "Hex";
|
||||
}
|
||||
|
||||
static std::string const& alphabet ()
|
||||
{
|
||||
static std::string s (
|
||||
"0123456789ABCDEF"
|
||||
);
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
class BinaryEncodingTests : public UnitTest
|
||||
{
|
||||
public:
|
||||
// This is a baseline for the other tests
|
||||
template <std::size_t Bytes>
|
||||
void testBase16 ()
|
||||
{
|
||||
beginTestCase ("base16");
|
||||
for (int i = 0; i < 50; ++i)
|
||||
{
|
||||
typedef UnsignedInteger <Bytes> UInt;
|
||||
UInt v0;
|
||||
random().fillBitsRandomly (v0.begin(), UInt::size);
|
||||
std::string const good (HexEncoding::encode (v0));
|
||||
|
||||
UInt v1;
|
||||
bool const success (HexEncoding::decode (v1, good));
|
||||
if (expect (success))
|
||||
{
|
||||
expect (v0 == v1);
|
||||
|
||||
Base16Conversion c;
|
||||
std::string const check (BinaryEncoding::encode (v0, c));
|
||||
if (! expect (good == check))
|
||||
logMessage (String ("expected ") + good + " but got " + check);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t Bytes>
|
||||
void testBase64Bytes (
|
||||
std::string const& vin, std::string const& vout,
|
||||
Base64Conversion c = Base64Conversion ())
|
||||
{
|
||||
typedef UnsignedInteger <Bytes> UInt;
|
||||
UInt v1 (vin.c_str());
|
||||
std::string const s1 (BinaryEncoding::encode (v1, c));
|
||||
logMessage (vout + " to " + s1);
|
||||
expect (vout == s1);
|
||||
|
||||
UInt v2;
|
||||
bool const success (BinaryEncoding::decode (v2, vout, c));
|
||||
if (expect (success))
|
||||
{
|
||||
std::string const s2 (BinaryEncoding::encode (v2, c));
|
||||
logMessage (vin + " to " + s2);
|
||||
//expect (vin == v2);
|
||||
}
|
||||
}
|
||||
|
||||
void testBase64 ()
|
||||
{
|
||||
beginTestCase ("Base64");
|
||||
|
||||
// input (uint)
|
||||
std::string const vin [] = {
|
||||
"","f","fo","foo","foob","fooba","foobar"
|
||||
};
|
||||
|
||||
// output (encoded string)
|
||||
std::string const vout [] = {
|
||||
"","Zg==","Zm8=","Zm9v","Zm9vYg==","Zm9vYmE=","Zm9vYmFy"
|
||||
};
|
||||
|
||||
//testBase64Bytes <0> (vin [0], vout [0]);
|
||||
testBase64Bytes <1> (vin [1], vout [1]);
|
||||
testBase64Bytes <2> (vin [2], vout [2]);
|
||||
testBase64Bytes <3> (vin [3], vout [3]);
|
||||
testBase64Bytes <4> (vin [4], vout [4]);
|
||||
testBase64Bytes <5> (vin [5], vout [5]);
|
||||
testBase64Bytes <6> (vin [6], vout [6]);
|
||||
}
|
||||
|
||||
template <typename Conversion, std::size_t Bytes>
|
||||
void testEncode (Conversion c = Conversion())
|
||||
{
|
||||
typedef UnsignedInteger <Bytes> UInt;
|
||||
|
||||
beginTestCase (String (c.name()) + " <" + String::fromNumber (Bytes) + ">");
|
||||
|
||||
for (int i = 0; i < 50; ++i)
|
||||
{
|
||||
UInt v1;
|
||||
random().fillBitsRandomly (v1.begin(), UInt::size);
|
||||
std::string const s1 (BinaryEncoding::encode (v1, c));
|
||||
|
||||
UInt v2;
|
||||
bool success (BinaryEncoding::decode (v2, s1, c));
|
||||
if (expect (success))
|
||||
expect (v1 == v2);
|
||||
}
|
||||
}
|
||||
|
||||
void runTest ()
|
||||
{
|
||||
testBase16 <10> ();
|
||||
|
||||
#if 0
|
||||
testEncode <Base16Conversion, 1> ();
|
||||
testEncode <Base16Conversion, 2> ();
|
||||
testEncode <Base16Conversion, 3> ();
|
||||
testEncode <Base16Conversion, 4> ();
|
||||
testEncode <Base16Conversion, 5> ();
|
||||
testEncode <Base16Conversion, 6> ();
|
||||
testEncode <Base16Conversion, 7> ();
|
||||
testEncode <Base16Conversion, 8> ();
|
||||
testEncode <Base16Conversion, 9> ();
|
||||
testEncode <Base16Conversion, 10> ();
|
||||
|
||||
testBase64 ();
|
||||
testEncode <Base64Conversion, 20> ();
|
||||
testEncode <Base64Conversion, 33> ();
|
||||
testEncode <RippleBase58Conversion, 20> ();
|
||||
testEncode <RippleBase58Conversion, 33> ();
|
||||
testEncode <BitcoinBase58Conversion, 20> ();
|
||||
testEncode <BitcoinBase58Conversion, 33> ();
|
||||
#endif
|
||||
}
|
||||
|
||||
BinaryEncodingTests () : UnitTest ("BinaryEncoding", "beast", runManual)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static BinaryEncodingTests BinaryEncodingTests;
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user