mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-18 17:45:48 +00:00
Cryptoconditions Framework (RIPD-1139):
Cryptoconditions provide a mechanism to describe a signed message such
that multiple actors in a distributed system can all verify the same
signed message and agree on whether it matches the description. This
provides a useful primitive for event-based systems that are distributed
on the Internet since we can describe events in a standard deterministic
manner (represented by signed messages) and therefore define generic
authenticated event handlers.
The cryptoconditions specification implemented is available at:
https://tools.ietf.org/html/draft-thomas-crypto-conditions-01
This commit is contained in:
@@ -1780,6 +1780,22 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\beast\xor_shift_engine.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\conditions\Condition.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\conditions\Fulfillment.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\conditions\impl\base64.h">
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\conditions\impl\Condition.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\conditions\impl\Fulfillment.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\core\ConfigSections.h">
|
||||
@@ -3326,6 +3342,10 @@
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\beast.cpp">
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\conditions.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\core.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||
@@ -4820,6 +4840,10 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\unity\conditions_test_unity.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\unity\core_test_unity.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug.classic|x64'">True</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release.classic|x64'">True</ExcludedFromBuild>
|
||||
|
||||
@@ -193,6 +193,12 @@
|
||||
<Filter Include="ripple\beast\utility\src">
|
||||
<UniqueIdentifier>{C94B6C51-E253-633B-0AA8-8D18CD695D5E}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ripple\conditions">
|
||||
<UniqueIdentifier>{44E216F9-ACFD-B770-C6C9-BFFAD162566D}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ripple\conditions\impl">
|
||||
<UniqueIdentifier>{155DC1A3-8A60-BC74-A7E4-1AC1A679FFF9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="ripple\core">
|
||||
<UniqueIdentifier>{235DCF23-2CF8-4F03-1A54-C159823A7E8D}</UniqueIdentifier>
|
||||
</Filter>
|
||||
@@ -2409,6 +2415,24 @@
|
||||
<ClInclude Include="..\..\src\ripple\beast\xor_shift_engine.h">
|
||||
<Filter>ripple\beast</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\conditions\Condition.h">
|
||||
<Filter>ripple\conditions</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\conditions\Fulfillment.h">
|
||||
<Filter>ripple\conditions</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\conditions\impl\base64.h">
|
||||
<Filter>ripple\conditions\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ripple\conditions\impl\Condition.cpp">
|
||||
<Filter>ripple\conditions\impl</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\conditions\impl\Fulfillment.cpp">
|
||||
<Filter>ripple\conditions\impl</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
|
||||
<Filter>ripple\conditions\impl</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
||||
<Filter>ripple\core</Filter>
|
||||
</ClInclude>
|
||||
@@ -3939,6 +3963,9 @@
|
||||
<ClCompile Include="..\..\src\ripple\unity\beast.cpp">
|
||||
<Filter>ripple\unity</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\conditions.cpp">
|
||||
<Filter>ripple\unity</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\ripple\unity\core.cpp">
|
||||
<Filter>ripple\unity</Filter>
|
||||
</ClCompile>
|
||||
@@ -5508,6 +5535,9 @@
|
||||
<ClCompile Include="..\..\src\unity\beast_test_unity.cpp">
|
||||
<Filter>unity</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\unity\conditions_test_unity.cpp">
|
||||
<Filter>unity</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\unity\core_test_unity.cpp">
|
||||
<Filter>unity</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -180,6 +180,7 @@ app_main.cpp
|
||||
app_misc.cpp
|
||||
app_paths.cpp
|
||||
app_tx.cpp
|
||||
conditions.cpp
|
||||
core.cpp
|
||||
basics.cpp
|
||||
crypto.cpp
|
||||
@@ -199,6 +200,7 @@ src/unity/
|
||||
app_test_unity.cpp
|
||||
basics_test_unity.cpp
|
||||
beast_test_unity.cpp
|
||||
conditions_test_unity.cpp
|
||||
core_test_unity.cpp
|
||||
json_test_unity.cpp
|
||||
ledger_test_unity.cpp
|
||||
@@ -250,6 +252,7 @@ foreach(curdir
|
||||
beast/utility
|
||||
app
|
||||
basics
|
||||
conditions
|
||||
crypto
|
||||
json
|
||||
ledger
|
||||
|
||||
@@ -924,6 +924,7 @@ def get_classic_sources(toolchain):
|
||||
append_sources(result, *list_sources('src/ripple/beast/utility', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/app', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/basics', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/conditions', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/crypto', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/json', '.cpp'))
|
||||
append_sources(result, *list_sources('src/ripple/ledger', '.cpp'))
|
||||
@@ -986,6 +987,7 @@ def get_unity_sources(toolchain):
|
||||
'src/ripple/unity/app_misc.cpp',
|
||||
'src/ripple/unity/app_paths.cpp',
|
||||
'src/ripple/unity/app_tx.cpp',
|
||||
'src/ripple/unity/conditions.cpp',
|
||||
'src/ripple/unity/core.cpp',
|
||||
'src/ripple/unity/basics.cpp',
|
||||
'src/ripple/unity/crypto.cpp',
|
||||
@@ -1003,6 +1005,7 @@ def get_unity_sources(toolchain):
|
||||
'src/unity/basics_test_unity.cpp',
|
||||
'src/unity/beast_test_unity.cpp',
|
||||
'src/unity/core_test_unity.cpp',
|
||||
'src/unity/conditions_test_unity.cpp',
|
||||
'src/unity/json_test_unity.cpp',
|
||||
'src/unity/ledger_test_unity.cpp',
|
||||
'src/unity/overlay_test_unity.cpp',
|
||||
|
||||
175
src/ripple/conditions/Condition.h
Normal file
175
src/ripple/conditions/Condition.h
Normal file
@@ -0,0 +1,175 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2016 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CONDITIONS_CONDITION_H
|
||||
#define RIPPLE_CONDITIONS_CONDITION_H
|
||||
|
||||
#include <ripple/conditions/impl/base64.h> // use Beast implementation
|
||||
#include <ripple/conditions/impl/utils.h>
|
||||
#include <boost/optional.hpp>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace ripple {
|
||||
namespace cryptoconditions {
|
||||
|
||||
// NIKB-TODO: These should move to a separate file:
|
||||
std::uint16_t constexpr condition_hashlock = 0;
|
||||
std::uint16_t constexpr condition_prefix_sha256 = 1;
|
||||
std::uint16_t constexpr condition_threshold_sha256 = 2;
|
||||
std::uint16_t constexpr condition_rsa_sha256 = 3;
|
||||
std::uint16_t constexpr condition_ed25519 = 4;
|
||||
|
||||
// NIKB-TODO: These should be `enum class : std::uint32_t`
|
||||
std::uint32_t constexpr feature_sha256 = 1;
|
||||
std::uint32_t constexpr feature_preimage = 2;
|
||||
std::uint32_t constexpr feature_prefix = 4;
|
||||
std::uint32_t constexpr feature_threshold = 8;
|
||||
std::uint32_t constexpr feature_rsa_pss = 16;
|
||||
std::uint32_t constexpr feature_ed25519 = 32;
|
||||
|
||||
/** The list of all feature suited defined in the RFC */
|
||||
std::uint32_t constexpr definedFeatures =
|
||||
feature_sha256 |
|
||||
feature_preimage |
|
||||
feature_prefix |
|
||||
feature_threshold |
|
||||
feature_rsa_pss |
|
||||
feature_ed25519;
|
||||
|
||||
/** The largest fulfillment supported by this implementation.
|
||||
|
||||
Fulfillments larger than this value cannot be processed
|
||||
and will not be generated.
|
||||
*/
|
||||
constexpr std::size_t maxSupportedFulfillmentLength = 65535;
|
||||
|
||||
struct Condition
|
||||
{
|
||||
std::uint16_t type;
|
||||
|
||||
/** The maximum length of a fulfillment for this condition.
|
||||
|
||||
While it is possible for a fulfillment to be smaller
|
||||
it can never be bigger than this.
|
||||
*/
|
||||
std::uint16_t maxFulfillmentLength;
|
||||
|
||||
/** The features suites required to process a fulfillment. */
|
||||
std::uint32_t featureBitmask;
|
||||
|
||||
/** An identifier for this condition.
|
||||
|
||||
This fingerprint is meant to be unique only with
|
||||
respect to other conditions of the same type.
|
||||
*/
|
||||
std::array<std::uint8_t, 32> fingerprint;
|
||||
|
||||
// Can this be deleted?
|
||||
Condition () = default;
|
||||
|
||||
Condition (Condition const&) = default;
|
||||
Condition (Condition&&) = default;
|
||||
};
|
||||
|
||||
inline
|
||||
bool
|
||||
operator== (Condition const& lhs, Condition const& rhs)
|
||||
{
|
||||
return
|
||||
lhs.type == rhs.type &&
|
||||
lhs.featureBitmask == rhs.featureBitmask &&
|
||||
lhs.maxFulfillmentLength == rhs.maxFulfillmentLength &&
|
||||
lhs.fingerprint == rhs.fingerprint;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
operator!= (Condition const& lhs, Condition const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/** Determine if a given condition is valid.
|
||||
|
||||
@note this function checks whether it understands the
|
||||
type of the condition, and if so, whether it meets
|
||||
the requirements mandated by the RFC.
|
||||
*/
|
||||
inline
|
||||
bool
|
||||
validate (Condition const& c)
|
||||
{
|
||||
// This check can never trigger because of the range of
|
||||
// the maxFulfillmentLength type. It's here in case the
|
||||
// type is changed in the future.
|
||||
|
||||
if (c.maxFulfillmentLength > maxSupportedFulfillmentLength)
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/** True if condition type is specified in the RFC.
|
||||
|
||||
@note: this function may return true even if the type
|
||||
of condition isn't presently supported by this
|
||||
implementation.
|
||||
*/
|
||||
inline
|
||||
bool
|
||||
isCondition (std::uint16_t type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case condition_hashlock:
|
||||
case condition_prefix_sha256:
|
||||
case condition_threshold_sha256:
|
||||
case condition_rsa_sha256:
|
||||
case condition_ed25519:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Load a serialized condition either from its string or binary form */
|
||||
/** @{ */
|
||||
boost::optional<Condition>
|
||||
loadCondition(std::string const& s);
|
||||
|
||||
boost::optional<Condition>
|
||||
loadCondition(Slice s);
|
||||
/** @} */
|
||||
|
||||
// Convert a condition to its string form
|
||||
std::string
|
||||
to_string (Condition const& c);
|
||||
|
||||
// Convert a condition to its binary form
|
||||
std::vector<std::uint8_t>
|
||||
to_blob (Condition const& c);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
176
src/ripple/conditions/Fulfillment.h
Normal file
176
src/ripple/conditions/Fulfillment.h
Normal file
@@ -0,0 +1,176 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2016 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CONDITIONS_FULFILLMENT_H
|
||||
#define RIPPLE_CONDITIONS_FULFILLMENT_H
|
||||
|
||||
#include <ripple/basics/Buffer.h>
|
||||
#include <ripple/basics/Slice.h>
|
||||
#include <ripple/conditions/Condition.h>
|
||||
#include <ripple/conditions/impl/utils.h>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace ripple {
|
||||
namespace cryptoconditions {
|
||||
|
||||
struct Fulfillment
|
||||
{
|
||||
public:
|
||||
virtual ~Fulfillment() = default;
|
||||
|
||||
Fulfillment () = default;
|
||||
|
||||
/** Returns the size of the fulfillment's payload. */
|
||||
virtual
|
||||
std::size_t
|
||||
payloadSize() const = 0;
|
||||
|
||||
/** Returns the fulfillment's payload */
|
||||
virtual
|
||||
Buffer
|
||||
payload() const = 0;
|
||||
|
||||
/** Generates the condition */
|
||||
virtual
|
||||
Condition
|
||||
condition() const = 0;
|
||||
|
||||
/** Returns the type */
|
||||
virtual
|
||||
std::uint16_t
|
||||
type () const = 0;
|
||||
|
||||
/** Returns the features suites required.
|
||||
|
||||
For any given fulfillment, the result includes all
|
||||
the feature suites that an implementation must
|
||||
support in order to be able to successfully parse
|
||||
the fulfillment.
|
||||
|
||||
@note fulfillments of the same type may require
|
||||
different features.
|
||||
*/
|
||||
virtual
|
||||
std::uint32_t
|
||||
features () const = 0;
|
||||
|
||||
/** Determines if this fulfillment is well-formed */
|
||||
virtual
|
||||
bool
|
||||
ok () const = 0;
|
||||
|
||||
/** Validates a fulfillment. */
|
||||
virtual
|
||||
bool
|
||||
validate (Slice data) const = 0;
|
||||
|
||||
/** Parses the fulfillment's payload. */
|
||||
virtual
|
||||
bool
|
||||
parsePayload (Slice s) = 0;
|
||||
};
|
||||
|
||||
inline
|
||||
bool
|
||||
operator== (Fulfillment const& lhs, Fulfillment const& rhs)
|
||||
{
|
||||
return
|
||||
lhs.type() == rhs.type() &&
|
||||
lhs.ok() == rhs.ok() &&
|
||||
lhs.payload() == rhs.payload();
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
operator!= (Fulfillment const& lhs, Fulfillment const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
/** Load a fulfillment from its string serialization.
|
||||
|
||||
The format is specified in Section 2.5.1 of the
|
||||
cryptoconditions RFC:
|
||||
|
||||
https://tools.ietf.org/html/draft-thomas-crypto-conditions-00#section-2.5.1
|
||||
*/
|
||||
std::unique_ptr<Fulfillment>
|
||||
loadFulfillment (std::string const& s);
|
||||
|
||||
/** Load a fulfillment from its binary serialization.
|
||||
|
||||
The format is specified in Section 2.5.2 of the
|
||||
cryptoconditions RFC:
|
||||
|
||||
https://tools.ietf.org/html/draft-thomas-crypto-conditions-00#section-2.5.2
|
||||
*/
|
||||
std::unique_ptr<Fulfillment>
|
||||
loadFulfillment (Slice s);
|
||||
|
||||
// Convert a fulfillment to its string form
|
||||
std::string
|
||||
to_string (Fulfillment const& f);
|
||||
|
||||
// Convert a fulfillment to its binary form
|
||||
std::vector<std::uint8_t>
|
||||
to_blob (Fulfillment const& f);
|
||||
|
||||
/** Determine whether a fulfillment fulfills a given condition */
|
||||
bool
|
||||
fulfills (
|
||||
Fulfillment const& f,
|
||||
Condition const& c);
|
||||
|
||||
/** Verify if the given message satisfies the fulfillment.
|
||||
|
||||
@param f The fulfillment
|
||||
@param c The condition
|
||||
@param m The message; note that the message is not
|
||||
relevant for some conditions (e.g. hashlocks)
|
||||
and a fulfillment will successfully satisfy its
|
||||
condition for any given message.
|
||||
*/
|
||||
bool
|
||||
validate (
|
||||
Fulfillment const& f,
|
||||
Condition const& c,
|
||||
Slice m);
|
||||
|
||||
/** Verify a cryptoconditional trigger.
|
||||
|
||||
A cryptoconditional trigger is a cryptocondition with
|
||||
an empty message.
|
||||
|
||||
When using such triggers, it is recommended that the
|
||||
trigger be of type preimage, prefix or threshold. If
|
||||
a signature type is used (i.e. Ed25519 or RSA-SHA256)
|
||||
then the Ed25519 or RSA keys should be single-use keys.
|
||||
|
||||
@param f The fulfillment
|
||||
@param c The condition
|
||||
*/
|
||||
bool
|
||||
validateTrigger (
|
||||
Fulfillment const& f,
|
||||
Condition const& c);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
188
src/ripple/conditions/impl/Condition.cpp
Normal file
188
src/ripple/conditions/impl/Condition.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2016 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/basics/contract.h>
|
||||
#include <ripple/conditions/Condition.h>
|
||||
#include <ripple/conditions/Fulfillment.h>
|
||||
#include <ripple/conditions/impl/utils.h>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
namespace ripple {
|
||||
namespace cryptoconditions {
|
||||
|
||||
boost::optional<Condition>
|
||||
loadCondition(std::string const& s)
|
||||
{
|
||||
static boost::regex const re_current (
|
||||
"^" // start of line
|
||||
"cc:" // 'cc' for cryptocondition
|
||||
"([1-9a-f][0-9a-f]{0,3}|0):" // type (hexadecimal)
|
||||
"([1-9a-f][0-9a-f]{0,15}):" // feature bitmask (hexadecimal)
|
||||
"([a-zA-Z0-9_-]{0,86}):" // fingerprint (base64url)
|
||||
"([1-9][0-9]{0,17}|0)" // fulfillment length (decimal)
|
||||
"$" // end of line
|
||||
, boost::regex_constants::optimize
|
||||
);
|
||||
|
||||
boost::smatch match;
|
||||
|
||||
if (!boost::regex_match (s, match, re_current))
|
||||
return boost::none;
|
||||
|
||||
try
|
||||
{
|
||||
Condition c;
|
||||
|
||||
c.type = parse_hexadecimal<std::uint16_t> (match[1]);
|
||||
|
||||
if (!isCondition (c.type))
|
||||
return boost::none;
|
||||
|
||||
c.featureBitmask = parse_hexadecimal<std::uint32_t>(match[2]);
|
||||
c.maxFulfillmentLength = parse_decimal<std::uint16_t>(match[4]);
|
||||
|
||||
if (c.maxFulfillmentLength > maxSupportedFulfillmentLength)
|
||||
return boost::none;
|
||||
|
||||
// TODO: Avoid copying by decoding directly
|
||||
// into the condition's buffer
|
||||
auto fingerprint = base64url_decode(match[3]);
|
||||
|
||||
if (fingerprint.size() != c.fingerprint.size())
|
||||
return boost::none;
|
||||
|
||||
std::memcpy(
|
||||
c.fingerprint.data(),
|
||||
fingerprint.data(),
|
||||
fingerprint.size());
|
||||
|
||||
return c;
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<Condition>
|
||||
loadCondition(Slice s)
|
||||
{
|
||||
if (s.empty())
|
||||
return boost::none;
|
||||
|
||||
try
|
||||
{
|
||||
auto start = s.data();
|
||||
auto finish = s.data() + s.size();
|
||||
|
||||
Condition c;
|
||||
|
||||
std::tie (start, c.type) =
|
||||
oer::decode_integer<std::uint16_t> (
|
||||
start, finish);
|
||||
|
||||
if (!isCondition (c.type))
|
||||
return boost::none;
|
||||
|
||||
std::tie (start, c.featureBitmask) =
|
||||
oer::decode_varuint<std::uint32_t> (
|
||||
start, finish);
|
||||
|
||||
{
|
||||
std::size_t len;
|
||||
|
||||
std::tie (start, len) =
|
||||
oer::decode_length (start, finish);
|
||||
|
||||
// Incorrect signature length
|
||||
if (len != c.fingerprint.size())
|
||||
return boost::none;
|
||||
|
||||
// Short buffer
|
||||
if (std::distance (start, finish) < len)
|
||||
return boost::none;
|
||||
|
||||
auto p = c.fingerprint.data();
|
||||
|
||||
while (len--)
|
||||
*p++ = *start++;
|
||||
}
|
||||
|
||||
if (start == finish)
|
||||
return boost::none;
|
||||
|
||||
std::tie (start, c.maxFulfillmentLength) =
|
||||
oer::decode_varuint<std::uint16_t> (
|
||||
start, finish);
|
||||
|
||||
// The maximum supported length of a fulfillment is
|
||||
// the largest allowable value, so checking here is
|
||||
// not helpful.
|
||||
return c;
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
to_string (Condition const& c)
|
||||
{
|
||||
return std::string("cc:") +
|
||||
to_hex (c.type) + ":" +
|
||||
to_hex (c.featureBitmask) + ":" +
|
||||
base64url_encode(c.fingerprint) + ":" +
|
||||
to_dec (c.maxFulfillmentLength);
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t>
|
||||
to_blob (Condition const& c)
|
||||
{
|
||||
// TODO: optimize this
|
||||
std::vector<std::uint8_t> v;
|
||||
v.reserve (48);
|
||||
|
||||
oer::encode_integer (
|
||||
c.type,
|
||||
std::back_inserter(v));
|
||||
|
||||
oer::encode_varuint (
|
||||
c.featureBitmask,
|
||||
std::back_inserter(v));
|
||||
|
||||
oer::encode_octetstring (
|
||||
c.fingerprint.size(),
|
||||
c.fingerprint.begin(),
|
||||
c.fingerprint.end(),
|
||||
std::back_inserter(v));
|
||||
|
||||
oer::encode_varuint (
|
||||
c.maxFulfillmentLength,
|
||||
std::back_inserter(v));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
209
src/ripple/conditions/impl/Fulfillment.cpp
Normal file
209
src/ripple/conditions/impl/Fulfillment.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2016 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/conditions/Condition.h>
|
||||
#include <ripple/conditions/Fulfillment.h>
|
||||
#include <ripple/conditions/impl/utils.h>
|
||||
#include <boost/regex.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace ripple {
|
||||
namespace cryptoconditions {
|
||||
|
||||
bool
|
||||
fulfills (
|
||||
Fulfillment const& f,
|
||||
Condition const& c)
|
||||
{
|
||||
// Fast check: the fulfillment's type must match the
|
||||
// conditions's type:
|
||||
if (f.type() != c.type)
|
||||
return false;
|
||||
|
||||
// Ensure that the condition is well-formed
|
||||
if (!validate (c))
|
||||
return false;
|
||||
|
||||
// The fulfillment payload can be no larger than the
|
||||
// what the condition allows.
|
||||
if (f.payloadSize() > c.maxFulfillmentLength)
|
||||
return false;
|
||||
|
||||
return f.condition() == c;
|
||||
}
|
||||
|
||||
bool
|
||||
validate (
|
||||
Fulfillment const& f,
|
||||
Condition const& c,
|
||||
Slice m)
|
||||
{
|
||||
return fulfills (f, c) && f.validate (m);
|
||||
}
|
||||
|
||||
bool
|
||||
validateTrigger (
|
||||
Fulfillment const& f,
|
||||
Condition const& c)
|
||||
{
|
||||
return validate (f, c, {});
|
||||
}
|
||||
|
||||
std::unique_ptr<Fulfillment>
|
||||
loadFulfillment (std::uint16_t type, Slice payload)
|
||||
{
|
||||
std::unique_ptr<Fulfillment> p;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
default:
|
||||
throw std::domain_error (
|
||||
"Unknown cryptocondition type " +
|
||||
std::to_string (type));
|
||||
}
|
||||
|
||||
// If the payload can't be parsed, the load should
|
||||
// fail.
|
||||
if (p && !p->parsePayload(payload))
|
||||
p.reset();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// Parse a condition from its string form
|
||||
std::unique_ptr<Fulfillment>
|
||||
loadFulfillment (std::string const& s)
|
||||
{
|
||||
// CHECKME: custom parser maybe? probably faster but
|
||||
// more work and probability of error.
|
||||
|
||||
// TODO: use two regex: one that accepts anything the
|
||||
// standard supports and one which accepts only what
|
||||
// we support. Parse with both for improved errors?
|
||||
static boost::regex const re_current (
|
||||
"^" // start of line
|
||||
"cf:" // 'cf' for fulfillment
|
||||
"([1-9a-f][0-9a-f]{0,3}|0):" // type
|
||||
"([a-zA-Z0-9_-]*)" // fulfillment payload (base64url)
|
||||
"$" // end of line
|
||||
, boost::regex_constants::optimize
|
||||
);
|
||||
|
||||
try
|
||||
{
|
||||
boost::smatch match;
|
||||
|
||||
if (!boost::regex_match (s, match, re_current))
|
||||
return nullptr;
|
||||
|
||||
std::uint16_t const type =
|
||||
parse_hexadecimal<std::uint16_t>(match[1]);
|
||||
|
||||
auto payload = base64url_decode (match[2]);
|
||||
|
||||
if (payload.size() > maxSupportedFulfillmentLength)
|
||||
return nullptr;
|
||||
|
||||
return loadFulfillment (type, makeSlice (payload));
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Fulfillment>
|
||||
loadFulfillment (Slice s)
|
||||
{
|
||||
if (s.empty())
|
||||
return nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
auto start = s.data();
|
||||
auto finish = s.data() + s.size();
|
||||
|
||||
std::uint16_t type;
|
||||
std::size_t len;
|
||||
|
||||
std::tie (start, type) =
|
||||
oer::decode_integer<std::uint16_t> (
|
||||
start, finish);
|
||||
|
||||
if (!isCondition (type))
|
||||
return nullptr;
|
||||
|
||||
if (start == finish)
|
||||
return nullptr;
|
||||
|
||||
std::tie (start, len) =
|
||||
oer::decode_length(
|
||||
start, finish);
|
||||
|
||||
if (len)
|
||||
{
|
||||
if (len > maxSupportedFulfillmentLength)
|
||||
return nullptr;
|
||||
|
||||
if (std::distance (start, finish) < len)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return loadFulfillment (type, Slice{ start, len });
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
to_string (Fulfillment const& f)
|
||||
{
|
||||
return std::string("cf:") + to_hex(f.type())
|
||||
+ ":" + base64url_encode (f.payload());
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t>
|
||||
to_blob (Fulfillment const& f)
|
||||
{
|
||||
// NIKB TODO optimize this
|
||||
std::vector<std::uint8_t> v;
|
||||
|
||||
auto const p = f.payload();
|
||||
|
||||
oer::encode_integer (
|
||||
f.type(),
|
||||
std::back_inserter(v));
|
||||
|
||||
oer::encode_length (
|
||||
p.size(), std::back_inserter(v));
|
||||
|
||||
oer::encode_octetstring (
|
||||
p.data(),
|
||||
p.data() + p.size(),
|
||||
std::back_inserter(v));
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
204
src/ripple/conditions/impl/base64.h
Normal file
204
src/ripple/conditions/impl/base64.h
Normal file
@@ -0,0 +1,204 @@
|
||||
//
|
||||
// Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com)
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BEAST_DETAIL_BASE64_HPP
|
||||
#define BEAST_DETAIL_BASE64_HPP
|
||||
|
||||
#include <ripple/basics/Buffer.h>
|
||||
#include <ripple/basics/Slice.h>
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
/*
|
||||
Portions from http://www.adp-gmbh.ch/cpp/common/base64.html
|
||||
Copyright notice:
|
||||
|
||||
base64.cpp and base64.h
|
||||
|
||||
Copyright (C) 2004-2008 Ren<65> Nyffenegger
|
||||
|
||||
This source code is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the author be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this source code must not be misrepresented; you must not
|
||||
claim that you wrote the original source code. If you use this source code
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original source code.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Ren<65> Nyffenegger rene.nyffenegger@adp-gmbh.ch
|
||||
|
||||
*/
|
||||
|
||||
namespace ripple {
|
||||
namespace cryptoconditions {
|
||||
|
||||
// NIKB NOTE: This has *NOT* standard base64 - it's base64url,
|
||||
// which replaces the `+` with a `-` and the the `/` with a `_`
|
||||
// with the padding suppressed on encoding and rejected on
|
||||
// decoding.
|
||||
|
||||
template <class = void>
|
||||
std::string const&
|
||||
base64url_alphabet()
|
||||
{
|
||||
static std::string const alphabet =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789-_";
|
||||
return alphabet;
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
is_base64url(unsigned char c)
|
||||
{
|
||||
return (std::isalnum(c) || (c == '-') || (c == '_'));
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
std::string
|
||||
base64url_encode (std::uint8_t const* data,
|
||||
std::size_t in_len)
|
||||
{
|
||||
unsigned char c3[3], c4[4];
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
std::string ret;
|
||||
ret.reserve (3 + in_len * 8 / 6);
|
||||
|
||||
char const* alphabet (base64url_alphabet().data());
|
||||
|
||||
while(in_len--)
|
||||
{
|
||||
c3[i++] = *(data++);
|
||||
if(i == 3)
|
||||
{
|
||||
c4[0] = (c3[0] & 0xfc) >> 2;
|
||||
c4[1] = ((c3[0] & 0x03) << 4) + ((c3[1] & 0xf0) >> 4);
|
||||
c4[2] = ((c3[1] & 0x0f) << 2) + ((c3[2] & 0xc0) >> 6);
|
||||
c4[3] = c3[2] & 0x3f;
|
||||
for(i = 0; (i < 4); i++)
|
||||
ret += alphabet[c4[i]];
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(i)
|
||||
{
|
||||
for(j = i; j < 3; j++)
|
||||
c3[j] = '\0';
|
||||
|
||||
c4[0] = (c3[0] & 0xfc) >> 2;
|
||||
c4[1] = ((c3[0] & 0x03) << 4) + ((c3[1] & 0xf0) >> 4);
|
||||
c4[2] = ((c3[1] & 0x0f) << 2) + ((c3[2] & 0xc0) >> 6);
|
||||
c4[3] = c3[2] & 0x3f;
|
||||
|
||||
for(j = 0; (j < i + 1); j++)
|
||||
ret += alphabet[c4[j]];
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
template <size_t N>
|
||||
std::string
|
||||
base64url_encode (std::array<std::uint8_t, N> const& d)
|
||||
{
|
||||
return base64url_encode (d.data(), d.size());
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
std::string
|
||||
base64url_encode (std::vector<std::uint8_t> const& d)
|
||||
{
|
||||
return base64url_encode (d.data(), d.size());
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
std::string
|
||||
base64url_encode (Buffer const& d)
|
||||
{
|
||||
return base64url_encode (d.data(), d.size());
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
std::string
|
||||
base64url_encode (Slice d)
|
||||
{
|
||||
return base64url_encode (d.data(), d.size());
|
||||
}
|
||||
|
||||
template <class = void>
|
||||
std::vector<std::uint8_t>
|
||||
base64url_decode(std::string const& data)
|
||||
{
|
||||
int in_len = data.size();
|
||||
std::uint8_t c4[4];
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int in_ = 0;
|
||||
|
||||
std::vector<std::uint8_t> ret;
|
||||
ret.reserve (in_len * 6 / 8);
|
||||
|
||||
while(in_len-- && is_base64url(data[in_]))
|
||||
{
|
||||
c4[i++] = data[in_]; in_++;
|
||||
if(i == 4) {
|
||||
for(i = 0; i < 4; i++)
|
||||
c4[i] = static_cast<unsigned char>(
|
||||
base64url_alphabet().find(c4[i]));
|
||||
|
||||
ret.push_back ((c4[0] << 2) + ((c4[1] & 0x30) >> 4));
|
||||
ret.push_back (((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2));
|
||||
ret.push_back (((c4[2] & 0x3) << 6) + c4[3]);
|
||||
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if(i)
|
||||
{
|
||||
for(j = i; j < 4; j++)
|
||||
c4[j] = 0;
|
||||
|
||||
for(j = 0; j < 4; j++)
|
||||
c4[j] = static_cast<unsigned char>(
|
||||
base64url_alphabet().find(c4[j]));
|
||||
|
||||
std::uint8_t c3[3];
|
||||
|
||||
c3[0] = (c4[0] << 2) + ((c4[1] & 0x30) >> 4);
|
||||
c3[1] = ((c4[1] & 0xf) << 4) + ((c4[2] & 0x3c) >> 2);
|
||||
c3[2] = ((c4[2] & 0x3) << 6) + c4[3];
|
||||
|
||||
for(j = 0; (j < i - 1); j++)
|
||||
ret.push_back (c3[j]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
368
src/ripple/conditions/impl/utils.h
Normal file
368
src/ripple/conditions/impl/utils.h
Normal file
@@ -0,0 +1,368 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2016 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_CONDITIONS_UTILS_H
|
||||
#define RIPPLE_CONDITIONS_UTILS_H
|
||||
|
||||
#include <ripple/basics/strHex.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
namespace ripple {
|
||||
namespace cryptoconditions {
|
||||
|
||||
inline
|
||||
std::string
|
||||
hexstr (std::vector<std::uint8_t> const& data)
|
||||
{
|
||||
std::string s;
|
||||
s.reserve (data.size() * 2);
|
||||
|
||||
for (auto d : data)
|
||||
{
|
||||
s.push_back (charHex (d >> 4));
|
||||
s.push_back (charHex (d & 15));
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
inline
|
||||
std::vector<std::uint8_t>
|
||||
hexblob (std::string const& s)
|
||||
{
|
||||
std::vector<std::uint8_t> result;
|
||||
result.reserve (1 + (s.size () / 2));
|
||||
|
||||
auto iter = s.cbegin ();
|
||||
|
||||
if (s.size () & 1)
|
||||
{
|
||||
int c = charUnHex (*iter++);
|
||||
|
||||
if (c < 0)
|
||||
Throw<std::runtime_error>("Invalid hex in blob");
|
||||
|
||||
result.push_back(c);
|
||||
}
|
||||
|
||||
while (iter != s.cend ())
|
||||
{
|
||||
int cHigh = charUnHex (*iter++);
|
||||
|
||||
if (cHigh < 0)
|
||||
Throw<std::runtime_error>("Invalid hex in blob");
|
||||
|
||||
int cLow = charUnHex (*iter);
|
||||
|
||||
if (cLow < 0)
|
||||
Throw<std::runtime_error>("Invalid hex in blob");
|
||||
|
||||
iter++;
|
||||
|
||||
result.push_back (
|
||||
static_cast<std::uint8_t>(cHigh << 4) |
|
||||
static_cast<std::uint8_t>(cLow));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T parse_decimal(std::string const& s)
|
||||
{
|
||||
T t = 0;
|
||||
|
||||
for (auto const c : s)
|
||||
{
|
||||
if (c < '0' || c > '9')
|
||||
throw std::domain_error ("invalid decimal digit");
|
||||
|
||||
t = (t * 10) + (c - '0');
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T parse_hexadecimal(std::string const& s)
|
||||
{
|
||||
T t = 0;
|
||||
|
||||
for (auto const c : s)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
t = (t * 16) + (c - '0');
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
t = (t * 16) + 10 + (c - 'a');
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
t = (t * 16) + 10 + (c - 'A');
|
||||
else
|
||||
throw std::domain_error ("invalid hexadecimal digit");
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
std::string
|
||||
to_hex (Integer value)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::hex << value;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template <class Integer>
|
||||
std::string
|
||||
to_dec (Integer value)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << std::dec << value;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
// ISO/IEC 8825/7 or ITU-T X.696: Octet Encoding Rules
|
||||
// FIXME: This assumes a little-endian architecture!
|
||||
namespace oer
|
||||
{
|
||||
|
||||
// Simple conversion: write integer as big-endian byte stream
|
||||
// This needs to be improved and optimized:
|
||||
template <class Integer, class OutputIt>
|
||||
void
|
||||
encode_integer(Integer value, OutputIt out)
|
||||
{
|
||||
static_assert (
|
||||
std::is_same<Integer, std::uint8_t>::value ||
|
||||
std::is_same<Integer, std::uint16_t>::value ||
|
||||
std::is_same<Integer, std::uint32_t>::value ||
|
||||
std::is_same<Integer, std::uint64_t>::value,
|
||||
"encode_integer accepts only std::uint{8,16,32,64}_t");
|
||||
|
||||
std::size_t n = sizeof(Integer);
|
||||
|
||||
while(n--)
|
||||
{
|
||||
*out++ = static_cast<std::uint8_t>(
|
||||
(value >> (n * 8)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
// Simple conversion: big-endian byte stream to integer
|
||||
template <class Integer, class InputIt>
|
||||
std::pair<InputIt, Integer>
|
||||
decode_integer(InputIt begin, InputIt end)
|
||||
{
|
||||
static_assert (
|
||||
std::is_same<Integer, std::uint8_t>::value ||
|
||||
std::is_same<Integer, std::uint16_t>::value ||
|
||||
std::is_same<Integer, std::uint32_t>::value ||
|
||||
std::is_same<Integer, std::uint64_t>::value,
|
||||
"decode_integer accepts only std::uint{8,16,32,64}_t");
|
||||
|
||||
std::size_t size = std::distance (begin, end);
|
||||
|
||||
if (size < sizeof(Integer))
|
||||
Throw<std::length_error>("short integer: " + std::to_string(size));
|
||||
|
||||
Integer res = 0;
|
||||
|
||||
for (std::size_t i = 0; i < sizeof(Integer); ++i)
|
||||
res = (res << 8) | *begin++;
|
||||
|
||||
return { begin, res };
|
||||
}
|
||||
|
||||
template <class OutputIt>
|
||||
inline
|
||||
OutputIt
|
||||
encode_length (std::size_t len, OutputIt out)
|
||||
{
|
||||
if (len <= 0x7F)
|
||||
{
|
||||
*out++ = static_cast<std::uint8_t>(len & 0x7F);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Decide how many bytes we need:
|
||||
if (len <= 0xFFFF)
|
||||
{
|
||||
*out++ = 0x82;
|
||||
*out++ = static_cast<std::uint8_t>((len >> 8) & 0xFF);
|
||||
*out++ = static_cast<std::uint8_t>(len & 0xFF);
|
||||
return out;
|
||||
}
|
||||
|
||||
if (len <= 0xFFFFFF)
|
||||
{
|
||||
*out++ = 0x83;
|
||||
*out++ = static_cast<std::uint8_t>((len >> 16) & 0xFF);
|
||||
*out++ = static_cast<std::uint8_t>((len >> 8) & 0xFF);
|
||||
*out++ = static_cast<std::uint8_t>(len & 0xFF);
|
||||
return out;
|
||||
}
|
||||
|
||||
if (len <= 0xFFFFFFFF)
|
||||
{
|
||||
*out++ = 0x84;
|
||||
*out++ = static_cast<std::uint8_t>((len >> 24) & 0xFF);
|
||||
*out++ = static_cast<std::uint8_t>((len >> 16) & 0xFF);
|
||||
*out++ = static_cast<std::uint8_t>((len >> 8) & 0xFF);
|
||||
*out++ = static_cast<std::uint8_t>(len & 0xFF);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Note: OER can represent lengths up to (2^1016) - 1,
|
||||
// which is, truly, enough for everyone. We never
|
||||
// exceed 2^32.
|
||||
Throw<std::length_error>("overlong encoding length: " + std::to_string(len));
|
||||
}
|
||||
|
||||
// A "streambuf" would serve us better here - instead of the
|
||||
// crazy paired return, we consume data from it and things
|
||||
// just magically work.
|
||||
template <class InputIt>
|
||||
std::pair<InputIt, std::size_t>
|
||||
decode_length (InputIt begin, InputIt end)
|
||||
{
|
||||
if (begin == end)
|
||||
Throw<std::length_error>("empty buffer");
|
||||
|
||||
std::size_t bytes = *begin++;
|
||||
|
||||
if (bytes < 128)
|
||||
return { begin, bytes };
|
||||
|
||||
bytes &= 0x7F;
|
||||
|
||||
if (bytes > 4)
|
||||
Throw<std::length_error>("overlong encoded length: " + std::to_string(bytes));
|
||||
|
||||
std::size_t len = 0;
|
||||
|
||||
if (std::distance (begin, end) < bytes)
|
||||
Throw<std::length_error>("short encoded length: " + std::to_string(bytes));
|
||||
|
||||
while (bytes--)
|
||||
len = (len << 8) | *begin++;
|
||||
|
||||
return { begin, len };
|
||||
}
|
||||
|
||||
/** Encode a fixed-size octet string: OER 2.6 (2) */
|
||||
template <class InputIt, class OutputIt>
|
||||
OutputIt
|
||||
encode_octetstring(InputIt begin, InputIt end, OutputIt out)
|
||||
{
|
||||
while (begin != end)
|
||||
*out++ = *begin++;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Encode a dynamic size octet string: OER 2.6 (1) */
|
||||
inline
|
||||
std::size_t
|
||||
predict_octetstring_size(std::size_t size)
|
||||
{
|
||||
// Alternatively, always guess 4 + size and call it a day?
|
||||
if (size <= 0x7F)
|
||||
return size + 1;
|
||||
|
||||
// Decide how many bytes we need:
|
||||
if (size <= 0xFFFF)
|
||||
return size + 3;
|
||||
|
||||
if (size <= 0xFFFFFF)
|
||||
return size + 4;
|
||||
|
||||
if (size <= 0xFFFFFFFF)
|
||||
return size + 5;
|
||||
|
||||
Throw<std::length_error>("overlong encoding length: " + std::to_string(size));
|
||||
}
|
||||
|
||||
/** Encode an dynamic size octet string: OER 2.6 (1) */
|
||||
template <class InputIt, class OutputIt>
|
||||
OutputIt
|
||||
encode_octetstring(std::size_t size, InputIt begin, InputIt end, OutputIt out)
|
||||
{
|
||||
// This will encode the length first, followed by the
|
||||
// payload octets:
|
||||
return encode_octetstring (
|
||||
begin,
|
||||
end,
|
||||
oer::encode_length (size, out));
|
||||
}
|
||||
|
||||
template <class Integer, class OutputIt>
|
||||
std::enable_if_t<std::is_unsigned<Integer>::value>
|
||||
encode_varuint (Integer value, OutputIt out)
|
||||
{
|
||||
auto count = [](Integer n)
|
||||
{
|
||||
std::size_t c = 0;
|
||||
|
||||
do
|
||||
{
|
||||
n >>= 8;
|
||||
++c;
|
||||
} while (n);
|
||||
|
||||
return c;
|
||||
};
|
||||
|
||||
std::size_t c = count (value);
|
||||
|
||||
out = encode_length (c, out);
|
||||
|
||||
while(c--)
|
||||
{
|
||||
*out++ = static_cast<std::uint8_t>(
|
||||
(value >> (c * 8)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Integer, class InputIt>
|
||||
std::enable_if_t<std::is_unsigned<Integer>::value, std::pair<InputIt, Integer>>
|
||||
decode_varuint (InputIt begin, InputIt end)
|
||||
{
|
||||
auto y = decode_length (begin, end);
|
||||
|
||||
if (y.second > sizeof(Integer))
|
||||
Throw<std::length_error>("Encoded integer exceeds allowable range: " + std::to_string(y.second));
|
||||
|
||||
Integer x = 0;
|
||||
|
||||
for (std::size_t i = 0; i != y.second; ++i)
|
||||
x = (x << 8) + *y.first++;
|
||||
|
||||
return { y.first, x };
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
23
src/ripple/unity/conditions.cpp
Normal file
23
src/ripple/unity/conditions.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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/conditions/impl/Condition.cpp>
|
||||
#include <ripple/conditions/impl/Fulfillment.cpp>
|
||||
19
src/unity/conditions_test_unity.cpp
Normal file
19
src/unity/conditions_test_unity.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
Reference in New Issue
Block a user