Cryptoconditions: PREFIX-SHA-256 (RIPD-1211)

This commit is contained in:
Nik Bougalis
2016-08-10 01:34:40 -07:00
parent 5711e7caa9
commit 83aa5517c0
7 changed files with 820 additions and 0 deletions

View File

@@ -1802,6 +1802,8 @@
</ClCompile>
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\conditions\PrefixSha256.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\conditions\PreimageSha256.h">
</ClInclude>
<ClInclude Include="..\..\src\ripple\core\Config.h">
@@ -4555,6 +4557,9 @@
<ClCompile Include="..\..\src\test\conditions\Ed25519_test.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\test\conditions\PrefixSha256_test.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
<ExcludedFromBuild>True</ExcludedFromBuild>
</ClCompile>

View File

@@ -2442,6 +2442,9 @@
<ClInclude Include="..\..\src\ripple\conditions\impl\utils.h">
<Filter>ripple\conditions\impl</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\conditions\PrefixSha256.h">
<Filter>ripple\conditions</Filter>
</ClInclude>
<ClInclude Include="..\..\src\ripple\conditions\PreimageSha256.h">
<Filter>ripple\conditions</Filter>
</ClInclude>
@@ -5337,6 +5340,9 @@
<ClCompile Include="..\..\src\test\conditions\Ed25519_test.cpp">
<Filter>test\conditions</Filter>
</ClCompile>
<ClCompile Include="..\..\src\test\conditions\PrefixSha256_test.cpp">
<Filter>test\conditions</Filter>
</ClCompile>
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
<Filter>test\conditions</Filter>
</ClCompile>

View File

@@ -127,6 +127,29 @@ validate (Condition const& c)
if (c.type == condition_hashlock)
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)
return (c.featureBitmask == feature_ed25519);

View 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

View File

@@ -20,6 +20,7 @@
#include <ripple/conditions/Condition.h>
#include <ripple/conditions/Fulfillment.h>
#include <ripple/conditions/PreimageSha256.h>
#include <ripple/conditions/PrefixSha256.h>
#include <ripple/conditions/Ed25519.h>
#include <ripple/conditions/impl/utils.h>
#include <boost/regex.hpp>
@@ -80,6 +81,10 @@ loadFulfillment (std::uint16_t type, Slice payload)
p = std::make_unique<PreimageSha256>();
break;
case condition_prefix_sha256:
p = std::make_unique<PrefixSha256>();
break;
case condition_ed25519:
p = std::make_unique<Ed25519>();
break;

View 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);
}
}

View File

@@ -18,4 +18,5 @@
//==============================================================================
#include <test/conditions/PreimageSha256_test.cpp>
#include <test/conditions/PrefixSha256_test.cpp>
#include <test/conditions/Ed25519_test.cpp>