mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Cryptoconditions: PREFIX-SHA-256 (RIPD-1211)
This commit is contained in:
@@ -1802,6 +1802,8 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
|
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\conditions\PrefixSha256.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\PreimageSha256.h">
|
<ClInclude Include="..\..\src\ripple\conditions\PreimageSha256.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
||||||
@@ -4555,6 +4557,9 @@
|
|||||||
<ClCompile Include="..\..\src\test\conditions\Ed25519_test.cpp">
|
<ClCompile Include="..\..\src\test\conditions\Ed25519_test.cpp">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\conditions\PrefixSha256_test.cpp">
|
||||||
|
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
|
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
|
||||||
<ExcludedFromBuild>True</ExcludedFromBuild>
|
<ExcludedFromBuild>True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@@ -2442,6 +2442,9 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
|
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
|
||||||
<Filter>ripple\conditions\impl</Filter>
|
<Filter>ripple\conditions\impl</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\..\src\ripple\conditions\PrefixSha256.h">
|
||||||
|
<Filter>ripple\conditions</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\PreimageSha256.h">
|
<ClInclude Include="..\..\src\ripple\conditions\PreimageSha256.h">
|
||||||
<Filter>ripple\conditions</Filter>
|
<Filter>ripple\conditions</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -5337,6 +5340,9 @@
|
|||||||
<ClCompile Include="..\..\src\test\conditions\Ed25519_test.cpp">
|
<ClCompile Include="..\..\src\test\conditions\Ed25519_test.cpp">
|
||||||
<Filter>test\conditions</Filter>
|
<Filter>test\conditions</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\conditions\PrefixSha256_test.cpp">
|
||||||
|
<Filter>test\conditions</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
|
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
|
||||||
<Filter>test\conditions</Filter>
|
<Filter>test\conditions</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@@ -127,6 +127,29 @@ validate (Condition const& c)
|
|||||||
if (c.type == condition_hashlock)
|
if (c.type == condition_hashlock)
|
||||||
return (c.featureBitmask == (feature_sha256 | feature_preimage));
|
return (c.featureBitmask == (feature_sha256 | feature_preimage));
|
||||||
|
|
||||||
|
// A prefix condition contains a subfulfillment; it
|
||||||
|
// requires all the features its child may require.
|
||||||
|
if (c.type == condition_prefix_sha256)
|
||||||
|
{
|
||||||
|
auto const mask = (feature_sha256 | feature_prefix);
|
||||||
|
|
||||||
|
// We need to have at least our own feature suites:
|
||||||
|
auto const cf1 = c.featureBitmask & mask;
|
||||||
|
|
||||||
|
if (cf1 != mask)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// And at least one more feature suite for our
|
||||||
|
// subfulfillment (since you need to terminate a
|
||||||
|
// chain of prefix conditions with a non-prefix)
|
||||||
|
auto const cf2 = c.featureBitmask & ~mask;
|
||||||
|
|
||||||
|
if (cf2 == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return (cf2 & definedFeatures) == cf2;
|
||||||
|
}
|
||||||
|
|
||||||
if (c.type == condition_ed25519)
|
if (c.type == condition_ed25519)
|
||||||
return (c.featureBitmask == feature_ed25519);
|
return (c.featureBitmask == feature_ed25519);
|
||||||
|
|
||||||
|
|||||||
218
src/ripple/conditions/PrefixSha256.h
Normal file
218
src/ripple/conditions/PrefixSha256.h
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
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_PREFIX_SHA256_H
|
||||||
|
#define RIPPLE_CONDITIONS_PREFIX_SHA256_H
|
||||||
|
|
||||||
|
#include <ripple/basics/base_uint.h>
|
||||||
|
#include <ripple/conditions/Condition.h>
|
||||||
|
#include <ripple/conditions/Fulfillment.h>
|
||||||
|
#include <ripple/conditions/impl/base64.h>
|
||||||
|
#include <ripple/protocol/digest.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iterator>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace cryptoconditions {
|
||||||
|
|
||||||
|
class PrefixSha256 final
|
||||||
|
: public Fulfillment
|
||||||
|
{
|
||||||
|
Buffer prefix_;
|
||||||
|
std::unique_ptr<Fulfillment> subfulfillment_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PrefixSha256 () = default;
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
payloadSize () const override
|
||||||
|
{
|
||||||
|
return
|
||||||
|
oer::predict_octetstring_size(prefix_.size()) +
|
||||||
|
subfulfillment_->payloadSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer
|
||||||
|
payload() const override
|
||||||
|
{
|
||||||
|
// We should never have a condition in a state that
|
||||||
|
// isn't ok to call payload on.
|
||||||
|
if (!ok())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto const subpayload = to_blob (*subfulfillment_);
|
||||||
|
|
||||||
|
Buffer b (subpayload.size() +
|
||||||
|
oer::predict_octetstring_size (prefix_.size()));
|
||||||
|
|
||||||
|
auto out = oer::encode_octetstring (
|
||||||
|
prefix_.size(),
|
||||||
|
prefix_.data(),
|
||||||
|
prefix_.data() + prefix_.size(),
|
||||||
|
b.data());
|
||||||
|
|
||||||
|
std::memcpy (out, subpayload.data(), subpayload.size());
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
Condition
|
||||||
|
condition() const override
|
||||||
|
{
|
||||||
|
auto const sc = subcondition();
|
||||||
|
auto const blob = to_blob (sc);
|
||||||
|
|
||||||
|
Buffer b (blob.size() +
|
||||||
|
oer::predict_octetstring_size (prefix_.size()));
|
||||||
|
|
||||||
|
auto out = oer::encode_octetstring (
|
||||||
|
prefix_.size(),
|
||||||
|
prefix_.data(),
|
||||||
|
prefix_.data() + prefix_.size(),
|
||||||
|
b.data());
|
||||||
|
|
||||||
|
std::memcpy (out, blob.data(), blob.size());
|
||||||
|
|
||||||
|
sha256_hasher h;
|
||||||
|
h (b.data(), b.size());
|
||||||
|
|
||||||
|
Condition cc;
|
||||||
|
cc.type = type();
|
||||||
|
cc.featureBitmask = features();
|
||||||
|
cc.maxFulfillmentLength = payloadSize();
|
||||||
|
cc.fingerprint = static_cast<sha256_hasher::result_type>(h);
|
||||||
|
|
||||||
|
return cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint16_t
|
||||||
|
type () const override
|
||||||
|
{
|
||||||
|
return condition_prefix_sha256;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t
|
||||||
|
features () const override
|
||||||
|
{
|
||||||
|
return
|
||||||
|
feature_sha256 |
|
||||||
|
feature_prefix |
|
||||||
|
subfulfillment_->features();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ok () const override
|
||||||
|
{
|
||||||
|
return static_cast<bool>(subfulfillment_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
validate (Slice m) const override
|
||||||
|
{
|
||||||
|
if (!ok())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Prepend the prefix to the message:
|
||||||
|
Buffer b (prefix_.size() + m.size());
|
||||||
|
|
||||||
|
if (prefix_.size())
|
||||||
|
std::memcpy (b.data(), prefix_.data(), prefix_.size());
|
||||||
|
|
||||||
|
if (m.size())
|
||||||
|
std::memcpy (b.data() + prefix_.size(), m.data(), m.size());
|
||||||
|
|
||||||
|
return subfulfillment_->validate (b);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fulfillment const&
|
||||||
|
subfulfillment () const
|
||||||
|
{
|
||||||
|
return *subfulfillment_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Condition
|
||||||
|
subcondition () const
|
||||||
|
{
|
||||||
|
return subfulfillment_->condition();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
parsePayload (Slice s) override
|
||||||
|
{
|
||||||
|
// The payload consists of the prefix, followed by
|
||||||
|
// a subfulfillment. It cannot be empty:
|
||||||
|
if (s.empty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto start = s.data();
|
||||||
|
auto finish = s.data() + s.size();
|
||||||
|
|
||||||
|
std::size_t len;
|
||||||
|
|
||||||
|
std::tie (start, len) = oer::decode_length (
|
||||||
|
start, finish);
|
||||||
|
|
||||||
|
if (len != 0)
|
||||||
|
{
|
||||||
|
if (std::distance (start, finish) < len)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::memcpy (prefix_.alloc (len), start, len);
|
||||||
|
std::advance (start, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
s += std::distance (s.data(), start);
|
||||||
|
|
||||||
|
// The remaining bytes in the slice are a fulfillment
|
||||||
|
// so we parse it as such. If we can, then we've
|
||||||
|
// succeeded.
|
||||||
|
subfulfillment_ = loadFulfillment (s);
|
||||||
|
|
||||||
|
if (!subfulfillment_)
|
||||||
|
{
|
||||||
|
prefix_.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPrefix (Slice prefix)
|
||||||
|
{
|
||||||
|
prefix_ = prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
Slice prefix() const
|
||||||
|
{
|
||||||
|
return prefix_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSubfulfillment (std::unique_ptr<Fulfillment> subfulfillment)
|
||||||
|
{
|
||||||
|
subfulfillment_ = std::move (subfulfillment);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <ripple/conditions/Condition.h>
|
#include <ripple/conditions/Condition.h>
|
||||||
#include <ripple/conditions/Fulfillment.h>
|
#include <ripple/conditions/Fulfillment.h>
|
||||||
#include <ripple/conditions/PreimageSha256.h>
|
#include <ripple/conditions/PreimageSha256.h>
|
||||||
|
#include <ripple/conditions/PrefixSha256.h>
|
||||||
#include <ripple/conditions/Ed25519.h>
|
#include <ripple/conditions/Ed25519.h>
|
||||||
#include <ripple/conditions/impl/utils.h>
|
#include <ripple/conditions/impl/utils.h>
|
||||||
#include <boost/regex.hpp>
|
#include <boost/regex.hpp>
|
||||||
@@ -80,6 +81,10 @@ loadFulfillment (std::uint16_t type, Slice payload)
|
|||||||
p = std::make_unique<PreimageSha256>();
|
p = std::make_unique<PreimageSha256>();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case condition_prefix_sha256:
|
||||||
|
p = std::make_unique<PrefixSha256>();
|
||||||
|
break;
|
||||||
|
|
||||||
case condition_ed25519:
|
case condition_ed25519:
|
||||||
p = std::make_unique<Ed25519>();
|
p = std::make_unique<Ed25519>();
|
||||||
break;
|
break;
|
||||||
|
|||||||
562
src/test/conditions/PrefixSha256_test.cpp
Normal file
562
src/test/conditions/PrefixSha256_test.cpp
Normal file
@@ -0,0 +1,562 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
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/strHex.h>
|
||||||
|
#include <ripple/beast/unit_test.h>
|
||||||
|
#include <ripple/conditions/Condition.h>
|
||||||
|
#include <ripple/conditions/Fulfillment.h>
|
||||||
|
#include <ripple/conditions/PrefixSha256.h>
|
||||||
|
#include <ripple/conditions/PreimageSha256.h>
|
||||||
|
#include <ripple/conditions/Ed25519.h>
|
||||||
|
#include <ripple/conditions/impl/utils.h>
|
||||||
|
#include <numeric>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace cryptoconditions {
|
||||||
|
|
||||||
|
class PrefixSha256_test : public beast::unit_test::suite
|
||||||
|
{
|
||||||
|
void check (
|
||||||
|
Fulfillment const& f,
|
||||||
|
Condition const& c,
|
||||||
|
Slice test,
|
||||||
|
Slice good)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT (validate (f, c, test) ==
|
||||||
|
((test == good) && (f.condition() == c)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void testMalformedCondition ()
|
||||||
|
{
|
||||||
|
testcase ("Malformed Condition");
|
||||||
|
|
||||||
|
// This is malformed and will not load because a
|
||||||
|
// feature suite of 0 is not supported.
|
||||||
|
auto c1 = loadCondition (
|
||||||
|
"cc:1:0:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
||||||
|
BEAST_EXPECT (!c1);
|
||||||
|
|
||||||
|
// The following will load but fail in different ways
|
||||||
|
auto c2 = loadCondition ( // only sha256
|
||||||
|
"cc:1:1:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
||||||
|
BEAST_EXPECT (c2 && !validate(*c2));
|
||||||
|
|
||||||
|
auto c3 = loadCondition ( // only preimage
|
||||||
|
"cc:1:4:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
||||||
|
BEAST_EXPECT (c3 && !validate(*c3));
|
||||||
|
|
||||||
|
auto c4 = loadCondition ( // only sha256+preimage
|
||||||
|
"cc:1:5:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
||||||
|
BEAST_EXPECT (c4 && !validate(*c4));
|
||||||
|
}
|
||||||
|
|
||||||
|
void testPrefix ()
|
||||||
|
{
|
||||||
|
testcase ("Prefix");
|
||||||
|
|
||||||
|
std::string const prefix1 = "prefix1";
|
||||||
|
std::string const prefix2 = "prefix2";
|
||||||
|
|
||||||
|
std::uint8_t msg[8];
|
||||||
|
std::iota (std::begin(msg), std::end(msg), std::uint8_t(39));
|
||||||
|
|
||||||
|
std::array<std::uint8_t, 32> const sk =
|
||||||
|
{{
|
||||||
|
0x50, 0xd8, 0x58, 0xe0, 0x98, 0x5e, 0xcc, 0x7f,
|
||||||
|
0x60, 0x41, 0x8a, 0xaf, 0x0c, 0xc5, 0xab, 0x58,
|
||||||
|
0x7f, 0x42, 0xc2, 0x57, 0x0a, 0x88, 0x40, 0x95,
|
||||||
|
0xa9, 0xe8, 0xcc, 0xac, 0xd0, 0xf6, 0x54, 0x5c
|
||||||
|
}};
|
||||||
|
|
||||||
|
{
|
||||||
|
PrefixSha256 f1;
|
||||||
|
f1.setPrefix(makeSlice (prefix1));
|
||||||
|
f1.setSubfulfillment(std::make_unique<PreimageSha256> (
|
||||||
|
makeSlice (prefix1)));
|
||||||
|
|
||||||
|
PrefixSha256 f2;
|
||||||
|
f2.setPrefix(makeSlice (prefix2));
|
||||||
|
f2.setSubfulfillment(std::make_unique<PreimageSha256> (
|
||||||
|
makeSlice (prefix1)));
|
||||||
|
|
||||||
|
BEAST_EXPECT (f1 != f2);
|
||||||
|
BEAST_EXPECT (f1.condition() != f2.condition());
|
||||||
|
|
||||||
|
// Validating with own condition should succeed.
|
||||||
|
BEAST_EXPECT (validate (f1, f1.condition(), {}));
|
||||||
|
BEAST_EXPECT (validate (f2, f2.condition(), {}));
|
||||||
|
|
||||||
|
for (std::size_t i = 1; i != sizeof(msg); ++i)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT (validate (f1, f1.condition(),
|
||||||
|
Slice{msg, i}));
|
||||||
|
BEAST_EXPECT (validate (f2, f2.condition(),
|
||||||
|
Slice{msg, i}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The rest should fail:
|
||||||
|
BEAST_EXPECT (! validate (f1, f2.condition(), {}));
|
||||||
|
BEAST_EXPECT (! validate (f2, f1.condition(), {}));
|
||||||
|
|
||||||
|
for (std::size_t i = 1; i != sizeof(msg); ++i)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT (! validate (f1, f2.condition(),
|
||||||
|
Slice{msg, i}));
|
||||||
|
BEAST_EXPECT (! validate (f2, f1.condition(),
|
||||||
|
Slice{msg, i}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
PrefixSha256 f1;
|
||||||
|
f1.setPrefix(makeSlice (prefix1));
|
||||||
|
f1.setSubfulfillment(std::make_unique<PreimageSha256> (
|
||||||
|
makeSlice (prefix1)));
|
||||||
|
|
||||||
|
PrefixSha256 f2;
|
||||||
|
f2.setPrefix(makeSlice (prefix2));
|
||||||
|
f2.setSubfulfillment(std::make_unique<PreimageSha256> (
|
||||||
|
makeSlice (prefix2)));
|
||||||
|
|
||||||
|
BEAST_EXPECT (f1 != f2);
|
||||||
|
BEAST_EXPECT (f1.condition() != f2.condition());
|
||||||
|
BEAST_EXPECT (validate (f1, f1.condition(), {}));
|
||||||
|
BEAST_EXPECT (validate (f2, f2.condition(), {}));
|
||||||
|
BEAST_EXPECT (! validate (f1, f2.condition(), {}));
|
||||||
|
BEAST_EXPECT (! validate (f2, f1.condition(), {}));
|
||||||
|
|
||||||
|
// For preimage conditions, the message shouldn't
|
||||||
|
// matter, so verify that it does not:
|
||||||
|
for (std::size_t i = 1; i != sizeof(msg); ++i)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT (validate (f1, f1.condition(),
|
||||||
|
Slice(msg, i)));
|
||||||
|
BEAST_EXPECT (validate (f2, f2.condition(),
|
||||||
|
Slice(msg, i)));
|
||||||
|
BEAST_EXPECT (! validate (f1, f2.condition(),
|
||||||
|
Slice(msg, i)));
|
||||||
|
BEAST_EXPECT (! validate (f2, f1.condition(),
|
||||||
|
Slice(msg, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
PrefixSha256 f1;
|
||||||
|
f1.setPrefix(makeSlice (prefix1));
|
||||||
|
f1.setSubfulfillment(std::make_unique<Ed25519> (
|
||||||
|
SecretKey{ sk }, makeSlice (prefix1)));
|
||||||
|
|
||||||
|
PrefixSha256 f2;
|
||||||
|
f2.setPrefix(makeSlice (prefix2));
|
||||||
|
f2.setSubfulfillment(std::make_unique<Ed25519> (
|
||||||
|
SecretKey{ sk }, makeSlice (prefix2)));
|
||||||
|
|
||||||
|
BEAST_EXPECT (f1 != f2);
|
||||||
|
BEAST_EXPECT (f1.condition() != f2.condition());
|
||||||
|
BEAST_EXPECT (validate (f1, f1.condition(), {}));
|
||||||
|
BEAST_EXPECT (validate (f2, f2.condition(), {}));
|
||||||
|
BEAST_EXPECT (! validate (f1, f2.condition(), {}));
|
||||||
|
BEAST_EXPECT (! validate (f2, f1.condition(), {}));
|
||||||
|
|
||||||
|
// For non-prefix conditions, the message matters
|
||||||
|
// so verify that it does:
|
||||||
|
for (std::size_t i = 1; i < sizeof(msg); ++i)
|
||||||
|
{
|
||||||
|
BEAST_EXPECT (! validate (f1, f1.condition(),
|
||||||
|
Slice(msg, i)));
|
||||||
|
BEAST_EXPECT (! validate (f2, f2.condition(),
|
||||||
|
Slice(msg, i)));
|
||||||
|
BEAST_EXPECT (! validate (f1, f2.condition(),
|
||||||
|
Slice(msg, i)));
|
||||||
|
BEAST_EXPECT (! validate (f2, f1.condition(),
|
||||||
|
Slice(msg, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Test signing with non-empty prefix and non-empty
|
||||||
|
// message to ensure that the prefix is properly
|
||||||
|
// prepended to the message:
|
||||||
|
std::string const m = prefix1 + prefix2;
|
||||||
|
|
||||||
|
// Construct a prefix condition with the prefix
|
||||||
|
// prefix1, containing a Ed25519 signature for prefix1+prefix2
|
||||||
|
// and check that it passing prefix2 validates, while
|
||||||
|
// passing anything else fails:
|
||||||
|
PrefixSha256 f;
|
||||||
|
f.setPrefix(makeSlice (prefix1));
|
||||||
|
f.setSubfulfillment(std::make_unique<Ed25519> (
|
||||||
|
SecretKey{ sk }, makeSlice (m)));
|
||||||
|
|
||||||
|
BEAST_EXPECT (to_string(f) ==
|
||||||
|
"cf:1:B3ByZWZpeDEABGBEKZMGUASqHkxI9N0BWBlMA"
|
||||||
|
"jSbzGZM2W5ADqJpkYqNUTiaLmMYVDHrc-tKqXcmRIT"
|
||||||
|
"RFqtYxru4rMSIplCYRP71H9tD09mnfqw4eu5FAJZw1"
|
||||||
|
"wa_NOmw78ADIlB4_ENJWAo");
|
||||||
|
|
||||||
|
auto const c = f.condition();
|
||||||
|
|
||||||
|
BEAST_EXPECT (validate (f, c, makeSlice(prefix2)));
|
||||||
|
|
||||||
|
BEAST_EXPECT (! validate (f, c, {}));
|
||||||
|
BEAST_EXPECT (! validate (f, c, makeSlice(prefix1)));
|
||||||
|
BEAST_EXPECT (! validate (f, c, makeSlice(m)));
|
||||||
|
|
||||||
|
for (std::size_t i = 1; i < sizeof(msg); ++i)
|
||||||
|
BEAST_EXPECT (! validate (f, c, Slice(msg, i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testKnown ()
|
||||||
|
{
|
||||||
|
testcase ("Known");
|
||||||
|
|
||||||
|
Slice const empty {};
|
||||||
|
Slice const abc { "abc", 3 };
|
||||||
|
Slice const abcd { "abcd", 4 };
|
||||||
|
Slice const vwxyz { "vwxyz", 5 };
|
||||||
|
|
||||||
|
{ // empty prefix with an empty PREIMAGE-SHA256 subfulfillment
|
||||||
|
auto f = loadFulfillment ("cf:1:AAAAAA");
|
||||||
|
BEAST_EXPECT (f);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const f2 = loadFulfillment(makeSlice(to_blob(*f)));
|
||||||
|
BEAST_EXPECT (f2);
|
||||||
|
BEAST_EXPECT (*f == *f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto c = loadCondition ("cc:1:7:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
||||||
|
BEAST_EXPECT (c);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto c1 = loadCondition (to_string(*c));
|
||||||
|
BEAST_EXPECT (c1);
|
||||||
|
BEAST_EXPECT (*c == *c1);
|
||||||
|
|
||||||
|
auto c2 = loadCondition (makeSlice(to_blob(*c)));
|
||||||
|
BEAST_EXPECT (c2);
|
||||||
|
BEAST_EXPECT (*c == *c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that it has the correct features set
|
||||||
|
BEAST_EXPECT (f->features() ==
|
||||||
|
(feature_sha256 | feature_prefix | feature_preimage));
|
||||||
|
|
||||||
|
// Test manual construction
|
||||||
|
{
|
||||||
|
PrefixSha256 f2;
|
||||||
|
f2.setPrefix({});
|
||||||
|
f2.setSubfulfillment(loadFulfillment ("cf:0:"));
|
||||||
|
|
||||||
|
BEAST_EXPECT (f2 == *f);
|
||||||
|
BEAST_EXPECT (f2.condition() == *c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The PREIMAGE-SHA256 we contain validates for
|
||||||
|
// any message. So, this condition should work
|
||||||
|
// with any buffer:
|
||||||
|
check (*f, c.get(), empty, empty);
|
||||||
|
check (*f, c.get(), abc, abc);
|
||||||
|
check (*f, c.get(), abcd, abcd);
|
||||||
|
check (*f, c.get(), vwxyz, vwxyz);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // A PREFIX-SHA256 with an empty prefix, wrapping
|
||||||
|
// the PREFIX-SHA256 condition we created above
|
||||||
|
// which contains a PREIMAGE-SHA256
|
||||||
|
auto f = loadFulfillment ("cf:1:AAABBAAAAAA");
|
||||||
|
BEAST_EXPECT (f);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const f2 = loadFulfillment(makeSlice(to_blob(*f)));
|
||||||
|
BEAST_EXPECT (f2);
|
||||||
|
BEAST_EXPECT (*f == *f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto c = loadCondition ("cc:1:7:Mp5A0CLrJOMAUMe0-qFb-_5U2C0X-iuwwfvumOT0go8:2");
|
||||||
|
BEAST_EXPECT (c);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto c1 = loadCondition (to_string(*c));
|
||||||
|
BEAST_EXPECT (c1);
|
||||||
|
BEAST_EXPECT (*c == *c1);
|
||||||
|
|
||||||
|
auto c2 = loadCondition (makeSlice(to_blob(*c)));
|
||||||
|
BEAST_EXPECT (c2);
|
||||||
|
BEAST_EXPECT (*c == *c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that it has the correct features set
|
||||||
|
BEAST_EXPECT (f->features() ==
|
||||||
|
(feature_sha256 | feature_prefix | feature_preimage));
|
||||||
|
|
||||||
|
// Test manual construction
|
||||||
|
{
|
||||||
|
PrefixSha256 f2;
|
||||||
|
f2.setPrefix({});
|
||||||
|
f2.setSubfulfillment(loadFulfillment ("cf:1:AAAAAA"));
|
||||||
|
|
||||||
|
BEAST_EXPECT (f2 == *f);
|
||||||
|
BEAST_EXPECT (f2.condition() == *c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The PREIMAGE-SHA256 we contain validates for
|
||||||
|
// any message. So, this condition should work
|
||||||
|
// with any buffer:
|
||||||
|
check (*f, c.get(), empty, empty);
|
||||||
|
check (*f, c.get(), abc, abc);
|
||||||
|
check (*f, c.get(), abcd, abcd);
|
||||||
|
check (*f, c.get(), vwxyz, vwxyz);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // A PREFIX-SHA256, with the prefix set to 'abc'
|
||||||
|
// that wraps around an ED25519 condition signing
|
||||||
|
// the message 'abc':
|
||||||
|
auto f = loadFulfillment (
|
||||||
|
"cf:1:A2FiYwAEYHahWSBEpuT1ESZbynOmBNkLBSnR32Ar4woZqSV2YNH1rsara"
|
||||||
|
"pEir_D33Llmf_YTE2iUcytueMJvW2cxAeJn_i4rZfpNU9rUeKGtpk1Q_R39t9l"
|
||||||
|
"JINw-GlZKZHscujVgAQ");
|
||||||
|
BEAST_EXPECT (f);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const f2 = loadFulfillment(makeSlice(to_blob(*f)));
|
||||||
|
BEAST_EXPECT (f2);
|
||||||
|
BEAST_EXPECT (*f == *f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto c = loadCondition ("cc:1:25:KHqL2K2uisoMhxznwl-6pai-ENDk2x9Wru6Ls63O5Vs:100");
|
||||||
|
BEAST_EXPECT (c);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto c1 = loadCondition (to_string(*c));
|
||||||
|
BEAST_EXPECT (c1);
|
||||||
|
BEAST_EXPECT (*c == *c1);
|
||||||
|
|
||||||
|
auto c2 = loadCondition (makeSlice(to_blob(*c)));
|
||||||
|
BEAST_EXPECT (c2);
|
||||||
|
BEAST_EXPECT (*c == *c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure that it has the correct features set
|
||||||
|
BEAST_EXPECT (f->features() ==
|
||||||
|
(feature_sha256 | feature_prefix | feature_ed25519));
|
||||||
|
|
||||||
|
// Test manual construction
|
||||||
|
{
|
||||||
|
PrefixSha256 f2;
|
||||||
|
f2.setPrefix(abc);
|
||||||
|
f2.setSubfulfillment(loadFulfillment (
|
||||||
|
"cf:4:dqFZIESm5PURJlvKc6YE2QsFKdHfYCvjChmpJXZg0fWuxqtqkSKv8"
|
||||||
|
"PfcuWZ_9hMTaJRzK254wm9bZzEB4mf-Litl-k1T2tR4oa2mTVD9Hf232Uk"
|
||||||
|
"g3D4aVkpkexy6NWAB"));
|
||||||
|
|
||||||
|
// Check the subfulfillment directly:
|
||||||
|
auto sc = f2.subcondition();
|
||||||
|
|
||||||
|
check (f2.subfulfillment(), sc, empty, abc);
|
||||||
|
check (f2.subfulfillment(), sc, abc, abc);
|
||||||
|
check (f2.subfulfillment(), sc, abcd, abc);
|
||||||
|
check (f2.subfulfillment(), sc, vwxyz, abc);
|
||||||
|
|
||||||
|
// This may seem counterintuitive, but it's
|
||||||
|
// not: the subfulfillment signed the message
|
||||||
|
// "abc"; our prefix is also "abc" so in order
|
||||||
|
// to verify this condition successfully, the
|
||||||
|
// message must be empty:
|
||||||
|
check (f2, c.get(), empty, empty);
|
||||||
|
check (f2, c.get(), abc, empty);
|
||||||
|
check (f2, c.get(), abcd, empty);
|
||||||
|
check (f2, c.get(), vwxyz, empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Like before, the ED25519 condition we contain
|
||||||
|
// signed the message 'abc' which is our prefix
|
||||||
|
// which means that this will only validate with
|
||||||
|
// an empty message:
|
||||||
|
check (*f, c.get(), empty, empty);
|
||||||
|
check (*f, c.get(), abc, empty);
|
||||||
|
check (*f, c.get(), abcd, empty);
|
||||||
|
check (*f, c.get(), vwxyz, empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testBinaryCodec()
|
||||||
|
{
|
||||||
|
testcase ("Binary Encoding");
|
||||||
|
|
||||||
|
// A sample prefix+Ed25519 fulfillment and its
|
||||||
|
// associated condition:
|
||||||
|
std::string const xf =
|
||||||
|
"cf:1:DUhlbGxvIFdvcmxkISAABGDsFyuTrV5WO_STL"
|
||||||
|
"HDhJFA0w1Rn7y79TWTr-BloNGfiv7YikfrZQy-PKYu"
|
||||||
|
"cSkiV2-KT9v_aGmja3wzN719HoMchKl_qPNqXo_TAP"
|
||||||
|
"qny6Kwc7IalHUUhJ6vboJ0bbzMcBwo";
|
||||||
|
|
||||||
|
std::string const xc =
|
||||||
|
"cc:1:25:1EMtp3YUOBZgeW3lX1lOIoAbUjx9maUty9TMJpMgXo4:110";
|
||||||
|
|
||||||
|
// The subfulfillment for the above, along with its
|
||||||
|
// associated condition:
|
||||||
|
std::string const xsf =
|
||||||
|
"cf:4:7Bcrk61eVjv0kyxw4SRQNMNUZ-8u_U1k6_gZa"
|
||||||
|
"DRn4r-2IpH62UMvjymLnEpIldvik_b_2hpo2t8Mze9"
|
||||||
|
"fR6DHISpf6jzal6P0wD6p8uisHOyGpR1FISer26CdG"
|
||||||
|
"28zHAcK";
|
||||||
|
|
||||||
|
std::string const xsc =
|
||||||
|
"cc:4:20:7Bcrk61eVjv0kyxw4SRQNMNUZ-8u_U1k6_gZaDRn4r8:96";
|
||||||
|
|
||||||
|
auto f = loadFulfillment (xf);
|
||||||
|
BEAST_EXPECT (f);
|
||||||
|
BEAST_EXPECT (to_string(*f) == xf);
|
||||||
|
|
||||||
|
auto c = loadCondition (xc);
|
||||||
|
BEAST_EXPECT (c);
|
||||||
|
BEAST_EXPECT (to_string(*c) == xc);
|
||||||
|
|
||||||
|
BEAST_EXPECT (f->condition() == c);
|
||||||
|
BEAST_EXPECT (to_string(f->condition()) == xc);
|
||||||
|
|
||||||
|
auto subf = loadFulfillment (xsf);
|
||||||
|
BEAST_EXPECT (subf);
|
||||||
|
BEAST_EXPECT (to_string(*subf) == xsf);
|
||||||
|
|
||||||
|
auto subc = loadCondition (xsc);
|
||||||
|
BEAST_EXPECT (subc);
|
||||||
|
BEAST_EXPECT (to_string(*subc) == xsc);
|
||||||
|
|
||||||
|
// Now generate the binary versions and ensure
|
||||||
|
// that they match what we expect. Then load them
|
||||||
|
// and ensure they're identical:
|
||||||
|
{
|
||||||
|
auto const fblob1 = hexblob(
|
||||||
|
"0001710d48656c6c6f20576f726c642120000460ec172b93ad5e563bf4"
|
||||||
|
"932c70e1245034c35467ef2efd4d64ebf819683467e2bfb62291fad943"
|
||||||
|
"2f8f298b9c4a4895dbe293f6ffda1a68dadf0ccdef5f47a0c7212a5fea"
|
||||||
|
"3cda97a3f4c03ea9f2e8ac1cec86a51d452127abdba09d1b6f331c070a");
|
||||||
|
|
||||||
|
auto const fblob2 = to_blob(*f);
|
||||||
|
BEAST_EXPECT (fblob1 == fblob2);
|
||||||
|
|
||||||
|
auto f2 = loadFulfillment(makeSlice(fblob2));
|
||||||
|
BEAST_EXPECT (f2);
|
||||||
|
BEAST_EXPECT (*f == *f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const cblob1 = hexblob (
|
||||||
|
"0001012520d4432da77614381660796de55f594e22801b523c7d99a52d"
|
||||||
|
"cbd4cc2693205e8e016e");
|
||||||
|
|
||||||
|
auto const cblob2 = to_blob(*c);
|
||||||
|
BEAST_EXPECT (cblob1 == cblob2);
|
||||||
|
|
||||||
|
auto c2 = loadCondition(makeSlice(cblob2));
|
||||||
|
BEAST_EXPECT (c2);
|
||||||
|
BEAST_EXPECT (*c == c2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void testNested()
|
||||||
|
{
|
||||||
|
testcase ("Nested");
|
||||||
|
|
||||||
|
std::string const abc = "abc";
|
||||||
|
std::string const def = "def";
|
||||||
|
std::string const abcdef = abc + def;
|
||||||
|
|
||||||
|
{ // prefix ("abc", prefix ("def", ed25519 (..., "abcdef")))
|
||||||
|
std::array<std::uint8_t, 32> sk =
|
||||||
|
{{
|
||||||
|
0x50, 0xd8, 0x58, 0xe0, 0x98, 0x5e, 0xcc, 0x7f,
|
||||||
|
0x60, 0x41, 0x8a, 0xaf, 0x0c, 0xc5, 0xab, 0x58,
|
||||||
|
0x7f, 0x42, 0xc2, 0x57, 0x0a, 0x88, 0x40, 0x95,
|
||||||
|
0xa9, 0xe8, 0xcc, 0xac, 0xd0, 0xf6, 0x54, 0x5c
|
||||||
|
}};
|
||||||
|
|
||||||
|
auto edf = std::make_unique<Ed25519> (
|
||||||
|
SecretKey{ sk }, makeSlice (abcdef));
|
||||||
|
|
||||||
|
// Inner
|
||||||
|
auto pif = std::make_unique<PrefixSha256>();
|
||||||
|
pif->setPrefix(makeSlice (abc));
|
||||||
|
pif->setSubfulfillment (std::move(edf));
|
||||||
|
|
||||||
|
// Outer
|
||||||
|
auto pof = std::make_unique<PrefixSha256>();
|
||||||
|
pof->setPrefix(makeSlice (def));
|
||||||
|
pof->setSubfulfillment (std::move (pif));
|
||||||
|
|
||||||
|
auto const c = pof->condition();
|
||||||
|
|
||||||
|
// The condition should validate with an empty
|
||||||
|
// message, since the nested prefixes contain
|
||||||
|
// the full message.
|
||||||
|
check (*pof, c, {}, {});
|
||||||
|
|
||||||
|
// It should fail with anything else.
|
||||||
|
check (*pof, c, makeSlice (abc), {});
|
||||||
|
check (*pof, c, makeSlice (def), {});
|
||||||
|
check (*pof, c, makeSlice (abcdef), {});
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // prefix ("abc", prefix ("def", preimage (...)))
|
||||||
|
auto const v = hexblob (
|
||||||
|
"6B62BA0A77D5C7A423A5FC937EE5FF09");
|
||||||
|
|
||||||
|
auto img = std::make_unique<PreimageSha256> (
|
||||||
|
makeSlice (v));
|
||||||
|
|
||||||
|
// Inner
|
||||||
|
auto pif = std::make_unique<PrefixSha256>();
|
||||||
|
pif->setPrefix(makeSlice (abc));
|
||||||
|
pif->setSubfulfillment (std::move(img));
|
||||||
|
|
||||||
|
// Outer
|
||||||
|
auto pof = std::make_unique<PrefixSha256>();
|
||||||
|
pof->setPrefix(makeSlice (def));
|
||||||
|
pof->setSubfulfillment (std::move (pif));
|
||||||
|
|
||||||
|
auto const c = pof->condition();
|
||||||
|
|
||||||
|
// The condition should validate with any message
|
||||||
|
// since it terminates at a preimage, which
|
||||||
|
// validates for any message:
|
||||||
|
check (*pof, c, {}, {});
|
||||||
|
check (*pof, c, makeSlice (abc), makeSlice (abc));
|
||||||
|
check (*pof, c, makeSlice (def), makeSlice (def));
|
||||||
|
check (*pof, c, makeSlice (abcdef), makeSlice (abcdef));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run ()
|
||||||
|
{
|
||||||
|
testKnown ();
|
||||||
|
testNested ();
|
||||||
|
testPrefix ();
|
||||||
|
testBinaryCodec ();
|
||||||
|
testMalformedCondition ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
BEAST_DEFINE_TESTSUITE (PrefixSha256, conditions, ripple);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,4 +18,5 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <test/conditions/PreimageSha256_test.cpp>
|
#include <test/conditions/PreimageSha256_test.cpp>
|
||||||
|
#include <test/conditions/PrefixSha256_test.cpp>
|
||||||
#include <test/conditions/Ed25519_test.cpp>
|
#include <test/conditions/Ed25519_test.cpp>
|
||||||
|
|||||||
Reference in New Issue
Block a user