mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-19 10:05:48 +00:00
Add Escrow support:
Escrow replaces the existing SusPay implementation with improved code that also adds hashlock support to escrow payments, making RCL ILP enabled. The new functionality is under the `Escrow` amendment, which supersedes and replaces the `SusPay` amendment. This commit also deprecates the `CryptoConditions` amendment which is replaced by the `CryptoConditionSuite` amendment which, once enabled, will allow use of cryptoconditions others than hashlocks.
This commit is contained in:
@@ -1325,6 +1325,12 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\app\tx\impl\CreateTicket.h">
|
<ClInclude Include="..\..\src\ripple\app\tx\impl\CreateTicket.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\app\tx\impl\Escrow.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\app\tx\impl\Escrow.h">
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\tx\impl\Offer.h">
|
<ClInclude Include="..\..\src\ripple\app\tx\impl\Offer.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ripple\app\tx\impl\OfferStream.cpp">
|
<ClCompile Include="..\..\src\ripple\app\tx\impl\OfferStream.cpp">
|
||||||
@@ -1375,12 +1381,6 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\..\src\ripple\app\tx\impl\SignerEntries.h">
|
<ClInclude Include="..\..\src\ripple\app\tx\impl\SignerEntries.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ripple\app\tx\impl\SusPay.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\tx\impl\SusPay.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\tx\impl\Taker.cpp">
|
<ClCompile Include="..\..\src\ripple\app\tx\impl\Taker.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
@@ -1821,36 +1821,26 @@
|
|||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\Condition.h">
|
<ClInclude Include="..\..\src\ripple\conditions\Condition.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\Ed25519.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\Fulfillment.h">
|
<ClInclude Include="..\..\src\ripple\conditions\Fulfillment.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\impl\base64.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\conditions\impl\Condition.cpp">
|
<ClCompile Include="..\..\src\ripple\conditions\impl\Condition.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\conditions\impl\Ed25519.cpp">
|
<ClCompile Include="..\..\src\ripple\conditions\impl\error.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\conditions\impl\error.h">
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ripple\conditions\impl\Fulfillment.cpp">
|
<ClCompile Include="..\..\src\ripple\conditions\impl\Fulfillment.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\conditions\impl\RsaSha256.cpp">
|
<ClInclude Include="..\..\src\ripple\conditions\impl\PreimageSha256.h">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
</ClInclude>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</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>
|
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\RsaSha256.h">
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\core\ConfigSections.h">
|
<ClInclude Include="..\..\src\ripple\core\ConfigSections.h">
|
||||||
@@ -4187,6 +4177,10 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\app\Escrow_test.cpp">
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\app\Flow_test.cpp">
|
<ClCompile Include="..\..\src\test\app\Flow_test.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
@@ -4255,10 +4249,6 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\app\SusPay_test.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\test\app\Taker_test.cpp">
|
<ClCompile Include="..\..\src\test\app\Taker_test.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
@@ -4399,22 +4389,10 @@
|
|||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\conditions\Ed25519_test.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\test\conditions\PrefixSha256_test.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
|
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\conditions\RsaSha256_test.cpp">
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\test\core\Config_test.cpp">
|
<ClCompile Include="..\..\src\test\core\Config_test.cpp">
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='debug|x64'">True</ExcludedFromBuild>
|
||||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='release|x64'">True</ExcludedFromBuild>
|
||||||
|
|||||||
@@ -1839,6 +1839,12 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\app\tx\impl\CreateTicket.h">
|
<ClInclude Include="..\..\src\ripple\app\tx\impl\CreateTicket.h">
|
||||||
<Filter>ripple\app\tx\impl</Filter>
|
<Filter>ripple\app\tx\impl</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClCompile Include="..\..\src\ripple\app\tx\impl\Escrow.cpp">
|
||||||
|
<Filter>ripple\app\tx\impl</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\app\tx\impl\Escrow.h">
|
||||||
|
<Filter>ripple\app\tx\impl</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\app\tx\impl\Offer.h">
|
<ClInclude Include="..\..\src\ripple\app\tx\impl\Offer.h">
|
||||||
<Filter>ripple\app\tx\impl</Filter>
|
<Filter>ripple\app\tx\impl</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -1890,12 +1896,6 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\app\tx\impl\SignerEntries.h">
|
<ClInclude Include="..\..\src\ripple\app\tx\impl\SignerEntries.h">
|
||||||
<Filter>ripple\app\tx\impl</Filter>
|
<Filter>ripple\app\tx\impl</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ripple\app\tx\impl\SusPay.cpp">
|
|
||||||
<Filter>ripple\app\tx\impl</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\..\src\ripple\app\tx\impl\SusPay.h">
|
|
||||||
<Filter>ripple\app\tx\impl</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\app\tx\impl\Taker.cpp">
|
<ClCompile Include="..\..\src\ripple\app\tx\impl\Taker.cpp">
|
||||||
<Filter>ripple\app\tx\impl</Filter>
|
<Filter>ripple\app\tx\impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -2439,39 +2439,27 @@
|
|||||||
<ClInclude Include="..\..\src\ripple\conditions\Condition.h">
|
<ClInclude Include="..\..\src\ripple\conditions\Condition.h">
|
||||||
<Filter>ripple\conditions</Filter>
|
<Filter>ripple\conditions</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\Ed25519.h">
|
|
||||||
<Filter>ripple\conditions</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\Fulfillment.h">
|
<ClInclude Include="..\..\src\ripple\conditions\Fulfillment.h">
|
||||||
<Filter>ripple\conditions</Filter>
|
<Filter>ripple\conditions</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\impl\base64.h">
|
|
||||||
<Filter>ripple\conditions\impl</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClCompile Include="..\..\src\ripple\conditions\impl\Condition.cpp">
|
<ClCompile Include="..\..\src\ripple\conditions\impl\Condition.cpp">
|
||||||
<Filter>ripple\conditions\impl</Filter>
|
<Filter>ripple\conditions\impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\conditions\impl\Ed25519.cpp">
|
<ClCompile Include="..\..\src\ripple\conditions\impl\error.cpp">
|
||||||
<Filter>ripple\conditions\impl</Filter>
|
<Filter>ripple\conditions\impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClInclude Include="..\..\src\ripple\conditions\impl\error.h">
|
||||||
|
<Filter>ripple\conditions\impl</Filter>
|
||||||
|
</ClInclude>
|
||||||
<ClCompile Include="..\..\src\ripple\conditions\impl\Fulfillment.cpp">
|
<ClCompile Include="..\..\src\ripple\conditions\impl\Fulfillment.cpp">
|
||||||
<Filter>ripple\conditions\impl</Filter>
|
<Filter>ripple\conditions\impl</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\ripple\conditions\impl\RsaSha256.cpp">
|
<ClInclude Include="..\..\src\ripple\conditions\impl\PreimageSha256.h">
|
||||||
<Filter>ripple\conditions\impl</Filter>
|
<Filter>ripple\conditions\impl</Filter>
|
||||||
</ClCompile>
|
</ClInclude>
|
||||||
<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">
|
|
||||||
<Filter>ripple\conditions</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\conditions\RsaSha256.h">
|
|
||||||
<Filter>ripple\conditions</Filter>
|
|
||||||
</ClInclude>
|
|
||||||
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
<ClInclude Include="..\..\src\ripple\core\Config.h">
|
||||||
<Filter>ripple\core</Filter>
|
<Filter>ripple\core</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
@@ -4983,6 +4971,9 @@
|
|||||||
<ClCompile Include="..\..\src\test\app\Discrepancy_test.cpp">
|
<ClCompile Include="..\..\src\test\app\Discrepancy_test.cpp">
|
||||||
<Filter>test\app</Filter>
|
<Filter>test\app</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\..\src\test\app\Escrow_test.cpp">
|
||||||
|
<Filter>test\app</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\app\Flow_test.cpp">
|
<ClCompile Include="..\..\src\test\app\Flow_test.cpp">
|
||||||
<Filter>test\app</Filter>
|
<Filter>test\app</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -5034,9 +5025,6 @@
|
|||||||
<ClCompile Include="..\..\src\test\app\SHAMapStore_test.cpp">
|
<ClCompile Include="..\..\src\test\app\SHAMapStore_test.cpp">
|
||||||
<Filter>test\app</Filter>
|
<Filter>test\app</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\app\SusPay_test.cpp">
|
|
||||||
<Filter>test\app</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\test\app\Taker_test.cpp">
|
<ClCompile Include="..\..\src\test\app\Taker_test.cpp">
|
||||||
<Filter>test\app</Filter>
|
<Filter>test\app</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@@ -5142,18 +5130,9 @@
|
|||||||
<ClCompile Include="..\..\src\test\beast\SemanticVersion_test.cpp">
|
<ClCompile Include="..\..\src\test\beast\SemanticVersion_test.cpp">
|
||||||
<Filter>test\beast</Filter>
|
<Filter>test\beast</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<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">
|
<ClCompile Include="..\..\src\test\conditions\PreimageSha256_test.cpp">
|
||||||
<Filter>test\conditions</Filter>
|
<Filter>test\conditions</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="..\..\src\test\conditions\RsaSha256_test.cpp">
|
|
||||||
<Filter>test\conditions</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClCompile Include="..\..\src\test\core\Config_test.cpp">
|
<ClCompile Include="..\..\src\test\core\Config_test.cpp">
|
||||||
<Filter>test\core</Filter>
|
<Filter>test\core</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ supportedAmendments ()
|
|||||||
{ "C6970A8B603D8778783B61C0D445C23D1633CCFAEF0D43E7DBCD1521D34BD7C3 SHAMapV2" },
|
{ "C6970A8B603D8778783B61C0D445C23D1633CCFAEF0D43E7DBCD1521D34BD7C3 SHAMapV2" },
|
||||||
{ "4C97EBA926031A7CF7D7B36FDE3ED66DDA5421192D63DE53FFB46E43B9DC8373 MultiSign" },
|
{ "4C97EBA926031A7CF7D7B36FDE3ED66DDA5421192D63DE53FFB46E43B9DC8373 MultiSign" },
|
||||||
{ "C1B8D934087225F509BEB5A8EC24447854713EE447D277F69545ABFA0E0FD490 Tickets" },
|
{ "C1B8D934087225F509BEB5A8EC24447854713EE447D277F69545ABFA0E0FD490 Tickets" },
|
||||||
{ "DA1BD556B42D85EA9C84066D028D355B52416734D3283F85E216EA5DA6DB7E13 SusPay" },
|
|
||||||
{ "6781F8368C4771B83E8B821D88F580202BCB4228075297B19E4FDC5233F1EFDC TrustSetAuth" },
|
{ "6781F8368C4771B83E8B821D88F580202BCB4228075297B19E4FDC5233F1EFDC TrustSetAuth" },
|
||||||
{ "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE FeeEscalation" },
|
{ "42426C4D4F1009EE67080A9B7965B44656D7714D104A72F9B4369F97ABF044EE FeeEscalation" },
|
||||||
{ "9178256A980A86CF3D70D0260A7DA6402AAFE43632FDBCB88037978404188871 OwnerPaysFee" },
|
{ "9178256A980A86CF3D70D0260A7DA6402AAFE43632FDBCB88037978404188871 OwnerPaysFee" },
|
||||||
@@ -50,7 +49,9 @@ supportedAmendments ()
|
|||||||
{ "740352F2412A9909880C23A559FCECEDA3BE2126FED62FC7660D628A06927F11 Flow" },
|
{ "740352F2412A9909880C23A559FCECEDA3BE2126FED62FC7660D628A06927F11 Flow" },
|
||||||
{ "1562511F573A19AE9BD103B5D6B9E01B3B46805AEC5D3C4805C902B514399146 CryptoConditions" },
|
{ "1562511F573A19AE9BD103B5D6B9E01B3B46805AEC5D3C4805C902B514399146 CryptoConditions" },
|
||||||
{ "532651B4FD58DF8922A49BA101AB3E996E5BFBF95A913B3E392504863E63B164 TickSize" },
|
{ "532651B4FD58DF8922A49BA101AB3E996E5BFBF95A913B3E392504863E63B164 TickSize" },
|
||||||
{ "67431BE4A5F355C45E36EED94B38DFACC1F111F547360F444642512CBC0E18E1 RIPD1368" }
|
{ "67431BE4A5F355C45E36EED94B38DFACC1F111F547360F444642512CBC0E18E1 RIPD1368" },
|
||||||
|
{ "07D43DCE529B15A10827E5E04943B496762F9A88E3268269D69C44BE49E21104 Escrow" },
|
||||||
|
{ "86E83A7D2ECE3AD5FA87AB2195AE015C950469ABF0B72EAACED318F74886AE90 CryptoConditionsSuite" }
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <BeastConfig.h>
|
#include <BeastConfig.h>
|
||||||
#include <ripple/app/tx/impl/SusPay.h>
|
#include <ripple/app/tx/impl/Escrow.h>
|
||||||
#include <ripple/app/misc/HashRouter.h>
|
#include <ripple/app/misc/HashRouter.h>
|
||||||
#include <ripple/basics/chrono.h>
|
#include <ripple/basics/chrono.h>
|
||||||
#include <ripple/basics/Log.h>
|
#include <ripple/basics/Log.h>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
#include <ripple/protocol/XRPAmount.h>
|
#include <ripple/protocol/XRPAmount.h>
|
||||||
#include <ripple/ledger/View.h>
|
#include <ripple/ledger/View.h>
|
||||||
|
|
||||||
// During a SusPayFinish, the transaction must specify both
|
// During an EscrowFinish, the transaction must specify both
|
||||||
// a condition and a fulfillment. We track whether that
|
// a condition and a fulfillment. We track whether that
|
||||||
// fulfillment matches and validates the condition.
|
// fulfillment matches and validates the condition.
|
||||||
#define SF_CF_INVALID SF_PRIVATE5
|
#define SF_CF_INVALID SF_PRIVATE5
|
||||||
@@ -41,88 +41,88 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SuspendedPayment
|
Escrow allows an account holder to sequester any amount
|
||||||
|
of XRP in its own ledger entry, until the escrow process
|
||||||
|
either finishes or is canceled.
|
||||||
|
|
||||||
A suspended payment ("SusPay") sequesters XRP in its
|
If the escrow process finishes successfully, then the
|
||||||
own ledger entry until a SusPayFinish or a SusPayCancel
|
destination account (which must exist) will receives the
|
||||||
transaction mentioning the ledger entry is successfully
|
sequestered XRP. If the escrow is, instead, canceled,
|
||||||
applied to the ledger. If the SusPayFinish succeeds,
|
the account which created the escrow will receive the
|
||||||
the destination account (which must exist) receives the
|
sequestered XRP back instead.
|
||||||
XRP. If the SusPayCancel succeeds, the account which
|
|
||||||
created the SusPay is credited the XRP.
|
|
||||||
|
|
||||||
SusPayCreate
|
EscrowCreate
|
||||||
|
|
||||||
When the SusPay is created, an optional condition may
|
When an escrow is created, an optional condition may
|
||||||
be attached. The condition is specified by providing
|
be attached. If present, that condition must be
|
||||||
the cryptographic digest of the condition to be met.
|
fulfilled for the escrow to successfully finish.
|
||||||
|
|
||||||
At the time of creation, one or both of the fields
|
At the time of creation, one or both of the fields
|
||||||
sfCancelAfter and sfFinishAfter may be provided. If
|
sfCancelAfter and sfFinishAfter may be provided. If
|
||||||
neither field is specified, the transaction is
|
neither field is specified, the transaction is
|
||||||
malformed.
|
malformed.
|
||||||
|
|
||||||
Since the SusPay eventually becomes a payment, an
|
Since the escrow eventually becomes a payment, an
|
||||||
optional DestinationTag and an optional SourceTag
|
optional DestinationTag and an optional SourceTag
|
||||||
is supported in the SusPayCreate transaction.
|
are supported in the EscrowCreate transaction.
|
||||||
|
|
||||||
Validation rules:
|
Validation rules:
|
||||||
|
|
||||||
sfCondition
|
sfCondition
|
||||||
If present, specifies a condition, and the
|
If present, specifies a condition; the same
|
||||||
condition along with its matching fulfillment
|
condition along with its matching fulfillment
|
||||||
is required on a SusPayFinish.
|
are required during EscrowFinish.
|
||||||
|
|
||||||
sfCancelAfter
|
sfCancelAfter
|
||||||
If present, SusPay may be canceled after the
|
If present, escrow may be canceled after the
|
||||||
specified time (seconds after the Ripple epoch).
|
specified time (seconds after the Ripple epoch).
|
||||||
|
|
||||||
sfFinishAfter
|
sfFinishAfter
|
||||||
If present, must be prior to sfCancelAfter.
|
If present, must be prior to sfCancelAfter.
|
||||||
A SusPayFinish succeeds only in ledgers after
|
A EscrowFinish succeeds only in ledgers after
|
||||||
sfFinishAfter but before sfCancelAfter.
|
sfFinishAfter but before sfCancelAfter.
|
||||||
|
|
||||||
If absent, same as parentCloseTime
|
If absent, same as parentCloseTime
|
||||||
|
|
||||||
Malformed if both sfCancelAfter, sfFinishAfter
|
Malformed if both sfCancelAfter, sfFinishAfter
|
||||||
are absent.
|
are absent.
|
||||||
|
|
||||||
Malformed if both sfFinishAfter, sfCancelAfter
|
Malformed if both sfFinishAfter, sfCancelAfter
|
||||||
specified and sfCancelAfter <= sfFinishAfter
|
specified and sfCancelAfter <= sfFinishAfter
|
||||||
|
|
||||||
SusPayFinish
|
EscrowFinish
|
||||||
|
|
||||||
Any account may submit a SusPayFinish. If the SusPay
|
Any account may submit a EscrowFinish. If the escrow
|
||||||
ledger entry specifies a condition, the SusPayFinish
|
ledger entry specifies a condition, the EscrowFinish
|
||||||
must provide the same condition and its associated
|
must provide the same condition and its associated
|
||||||
fulfillment in the sfFulfillment field, or else the
|
fulfillment in the sfCondition and sfFulfillment
|
||||||
SusPayFinish will fail.
|
fields, or else the EscrowFinish will fail.
|
||||||
|
|
||||||
If the SusPay ledger entry specifies sfFinishAfter, the
|
If the escrow ledger entry specifies sfFinishAfter, the
|
||||||
transaction will fail if parentCloseTime <= sfFinishAfter.
|
transaction will fail if parentCloseTime <= sfFinishAfter.
|
||||||
|
|
||||||
SusPayFinish transactions must be submitted before a
|
EscrowFinish transactions must be submitted before
|
||||||
SusPay's sfCancelAfter if present.
|
the escrow's sfCancelAfter if present.
|
||||||
|
|
||||||
If the SusPay ledger entry specifies sfCancelAfter, the
|
If the escrow ledger entry specifies sfCancelAfter, the
|
||||||
transaction will fail if sfCancelAfter <= parentCloseTime.
|
transaction will fail if sfCancelAfter <= parentCloseTime.
|
||||||
|
|
||||||
NOTE: The reason the condition must be specified again
|
NOTE: The reason the condition must be specified again
|
||||||
is because it must always be possible to verify
|
is because it must always be possible to verify
|
||||||
the condition without retrieving the SusPay
|
the condition without retrieving the escrow
|
||||||
ledger entry.
|
ledger entry.
|
||||||
|
|
||||||
SusPayCancel
|
EscrowCancel
|
||||||
|
|
||||||
Any account may submit a SusPayCancel transaction.
|
Any account may submit a EscrowCancel transaction.
|
||||||
|
|
||||||
If the SusPay ledger entry does not specify a
|
If the escrow ledger entry does not specify a
|
||||||
sfCancelAfter, the cancel transaction will fail.
|
sfCancelAfter, the cancel transaction will fail.
|
||||||
|
|
||||||
If parentCloseTime <= sfCancelAfter, the transaction
|
If parentCloseTime <= sfCancelAfter, the transaction
|
||||||
will fail.
|
will fail.
|
||||||
|
|
||||||
When a SusPay is canceled, the funds are returned to
|
When a escrow is canceled, the funds are returned to
|
||||||
the source account.
|
the source account.
|
||||||
|
|
||||||
By careful selection of fields in each transaction,
|
By careful selection of fields in each transaction,
|
||||||
@@ -135,15 +135,15 @@ namespace ripple {
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
XRPAmount
|
XRPAmount
|
||||||
SusPayCreate::calculateMaxSpend(STTx const& tx)
|
EscrowCreate::calculateMaxSpend(STTx const& tx)
|
||||||
{
|
{
|
||||||
return tx[sfAmount].xrp();
|
return tx[sfAmount].xrp();
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
TER
|
||||||
SusPayCreate::preflight (PreflightContext const& ctx)
|
EscrowCreate::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featureSusPay))
|
if (! ctx.rules.enabled(featureEscrow))
|
||||||
return temDISABLED;
|
return temDISABLED;
|
||||||
|
|
||||||
auto const ret = preflight1 (ctx);
|
auto const ret = preflight1 (ctx);
|
||||||
@@ -166,43 +166,30 @@ SusPayCreate::preflight (PreflightContext const& ctx)
|
|||||||
|
|
||||||
if (auto const cb = ctx.tx[~sfCondition])
|
if (auto const cb = ctx.tx[~sfCondition])
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featureCryptoConditions))
|
|
||||||
return temDISABLED;
|
|
||||||
|
|
||||||
using namespace ripple::cryptoconditions;
|
using namespace ripple::cryptoconditions;
|
||||||
|
|
||||||
// TODO: Remove this try/catch once cryptoconditions
|
std::error_code ec;
|
||||||
// no longer use exceptions.
|
|
||||||
try
|
auto condition = Condition::deserialize(*cb, ec);
|
||||||
{
|
if (!condition)
|
||||||
auto condition = loadCondition(*cb);
|
|
||||||
|
|
||||||
if (!condition)
|
|
||||||
return temMALFORMED;
|
|
||||||
|
|
||||||
{
|
|
||||||
// TODO: This is here temporarily to ensure
|
|
||||||
// that the condition given doesn't
|
|
||||||
// contain unnecessary trailing junk.
|
|
||||||
// The new parsing API will simplify
|
|
||||||
// the checking here.
|
|
||||||
|
|
||||||
auto b = to_blob(*condition);
|
|
||||||
if (*cb != makeSlice(b))
|
|
||||||
return temMALFORMED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
{
|
||||||
|
JLOG(ctx.j.debug()) <<
|
||||||
|
"Malformed condition during escrow creation: " << ec.message();
|
||||||
return temMALFORMED;
|
return temMALFORMED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Conditions other than PrefixSha256 require the
|
||||||
|
// "CryptoConditionsSuite" amendment:
|
||||||
|
if (condition->type != Type::preimageSha256 &&
|
||||||
|
!ctx.rules.enabled(featureCryptoConditionsSuite))
|
||||||
|
return temDISABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
return preflight2 (ctx);
|
return preflight2 (ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
TER
|
||||||
SusPayCreate::doApply()
|
EscrowCreate::doApply()
|
||||||
{
|
{
|
||||||
auto const closeTime = ctx_.view ().info ().parentCloseTime;
|
auto const closeTime = ctx_.view ().info ().parentCloseTime;
|
||||||
|
|
||||||
@@ -252,9 +239,9 @@ SusPayCreate::doApply()
|
|||||||
return tecNO_TARGET;
|
return tecNO_TARGET;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create SusPay in ledger
|
// Create escrow in ledger
|
||||||
auto const slep = std::make_shared<SLE>(
|
auto const slep = std::make_shared<SLE>(
|
||||||
keylet::susPay(account, (*sle)[sfSequence] - 1));
|
keylet::escrow(account, (*sle)[sfSequence] - 1));
|
||||||
(*slep)[sfAmount] = ctx_.tx[sfAmount];
|
(*slep)[sfAmount] = ctx_.tx[sfAmount];
|
||||||
(*slep)[sfAccount] = account;
|
(*slep)[sfAccount] = account;
|
||||||
(*slep)[~sfCondition] = ctx_.tx[~sfCondition];
|
(*slep)[~sfCondition] = ctx_.tx[~sfCondition];
|
||||||
@@ -266,7 +253,7 @@ SusPayCreate::doApply()
|
|||||||
|
|
||||||
ctx_.view().insert(slep);
|
ctx_.view().insert(slep);
|
||||||
|
|
||||||
// Add SusPay to owner directory
|
// Add escrow to owner directory
|
||||||
{
|
{
|
||||||
uint64_t page;
|
uint64_t page;
|
||||||
auto result = dirAdd(ctx_.view(), page,
|
auto result = dirAdd(ctx_.view(), page,
|
||||||
@@ -293,48 +280,23 @@ checkCondition (Slice f, Slice c)
|
|||||||
{
|
{
|
||||||
using namespace ripple::cryptoconditions;
|
using namespace ripple::cryptoconditions;
|
||||||
|
|
||||||
// TODO: Remove this try/catch once cryptoconditions
|
std::error_code ec;
|
||||||
// no longer use exceptions.
|
|
||||||
try
|
|
||||||
{
|
|
||||||
auto condition = loadCondition(c);
|
|
||||||
|
|
||||||
if (!condition)
|
auto condition = Condition::deserialize(c, ec);
|
||||||
return false;
|
if (!condition)
|
||||||
|
|
||||||
auto fulfillment = loadFulfillment(f);
|
|
||||||
|
|
||||||
if (!fulfillment)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
{
|
|
||||||
// TODO: This is here temporarily to ensure
|
|
||||||
// that the condition & fulfillment
|
|
||||||
// given don't contain unnecessary
|
|
||||||
// trailing junk. The new parsing API
|
|
||||||
// will simplify the checking here.
|
|
||||||
|
|
||||||
auto cb = to_blob(*condition);
|
|
||||||
if (c != makeSlice(cb))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto fb = to_blob(*fulfillment);
|
|
||||||
if (f != makeSlice(fb))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return validateTrigger (*fulfillment, *condition);
|
|
||||||
}
|
|
||||||
catch (...)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
auto fulfillment = Fulfillment::deserialize(f, ec);
|
||||||
|
if (!fulfillment)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return validate (*fulfillment, *condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
TER
|
TER
|
||||||
SusPayFinish::preflight (PreflightContext const& ctx)
|
EscrowFinish::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featureSusPay))
|
if (! ctx.rules.enabled(featureEscrow))
|
||||||
return temDISABLED;
|
return temDISABLED;
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -346,12 +308,6 @@ SusPayFinish::preflight (PreflightContext const& ctx)
|
|||||||
auto const cb = ctx.tx[~sfCondition];
|
auto const cb = ctx.tx[~sfCondition];
|
||||||
auto const fb = ctx.tx[~sfFulfillment];
|
auto const fb = ctx.tx[~sfFulfillment];
|
||||||
|
|
||||||
if (cb || fb)
|
|
||||||
{
|
|
||||||
if (! ctx.rules.enabled(featureCryptoConditions))
|
|
||||||
return temDISABLED;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If you specify a condition, then you must also specify
|
// If you specify a condition, then you must also specify
|
||||||
// a fulfillment.
|
// a fulfillment.
|
||||||
if (static_cast<bool>(cb) != static_cast<bool>(fb))
|
if (static_cast<bool>(cb) != static_cast<bool>(fb))
|
||||||
@@ -388,7 +344,7 @@ SusPayFinish::preflight (PreflightContext const& ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t
|
std::uint64_t
|
||||||
SusPayFinish::calculateBaseFee (PreclaimContext const& ctx)
|
EscrowFinish::calculateBaseFee (PreclaimContext const& ctx)
|
||||||
{
|
{
|
||||||
std::uint64_t extraFee = 0;
|
std::uint64_t extraFee = 0;
|
||||||
|
|
||||||
@@ -401,12 +357,10 @@ SusPayFinish::calculateBaseFee (PreclaimContext const& ctx)
|
|||||||
return Transactor::calculateBaseFee (ctx) + extraFee;
|
return Transactor::calculateBaseFee (ctx) + extraFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TER
|
TER
|
||||||
SusPayFinish::doApply()
|
EscrowFinish::doApply()
|
||||||
{
|
{
|
||||||
// peek SusPay SLE
|
auto const k = keylet::escrow(
|
||||||
auto const k = keylet::susPay(
|
|
||||||
ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
|
ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
|
||||||
auto const slep = ctx_.view().peek(k);
|
auto const slep = ctx_.view().peek(k);
|
||||||
if (! slep)
|
if (! slep)
|
||||||
@@ -473,7 +427,7 @@ SusPayFinish::doApply()
|
|||||||
|
|
||||||
AccountID const account = (*slep)[sfAccount];
|
AccountID const account = (*slep)[sfAccount];
|
||||||
|
|
||||||
// Remove SusPay from owner directory
|
// Remove escrow from owner directory
|
||||||
{
|
{
|
||||||
auto const page = (*slep)[sfOwnerNode];
|
auto const page = (*slep)[sfOwnerNode];
|
||||||
TER const ter = dirDelete(ctx_.view(), true,
|
TER const ter = dirDelete(ctx_.view(), true,
|
||||||
@@ -501,7 +455,7 @@ SusPayFinish::doApply()
|
|||||||
(*sle)[sfOwnerCount] = (*sle)[sfOwnerCount] - 1;
|
(*sle)[sfOwnerCount] = (*sle)[sfOwnerCount] - 1;
|
||||||
ctx_.view().update(sle);
|
ctx_.view().update(sle);
|
||||||
|
|
||||||
// Remove SusPay from ledger
|
// Remove escrow from ledger
|
||||||
ctx_.view().erase(slep);
|
ctx_.view().erase(slep);
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
@@ -510,9 +464,9 @@ SusPayFinish::doApply()
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
TER
|
TER
|
||||||
SusPayCancel::preflight (PreflightContext const& ctx)
|
EscrowCancel::preflight (PreflightContext const& ctx)
|
||||||
{
|
{
|
||||||
if (! ctx.rules.enabled(featureSusPay))
|
if (! ctx.rules.enabled(featureEscrow))
|
||||||
return temDISABLED;
|
return temDISABLED;
|
||||||
|
|
||||||
auto const ret = preflight1 (ctx);
|
auto const ret = preflight1 (ctx);
|
||||||
@@ -523,10 +477,9 @@ SusPayCancel::preflight (PreflightContext const& ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TER
|
TER
|
||||||
SusPayCancel::doApply()
|
EscrowCancel::doApply()
|
||||||
{
|
{
|
||||||
// peek SusPay SLE
|
auto const k = keylet::escrow(
|
||||||
auto const k = keylet::susPay(
|
|
||||||
ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
|
ctx_.tx[sfOwner], ctx_.tx[sfOfferSequence]);
|
||||||
auto const slep = ctx_.view().peek(k);
|
auto const slep = ctx_.view().peek(k);
|
||||||
if (! slep)
|
if (! slep)
|
||||||
@@ -540,7 +493,7 @@ SusPayCancel::doApply()
|
|||||||
|
|
||||||
AccountID const account = (*slep)[sfAccount];
|
AccountID const account = (*slep)[sfAccount];
|
||||||
|
|
||||||
// Remove SusPay from owner directory
|
// Remove escrow from owner directory
|
||||||
{
|
{
|
||||||
auto const page = (*slep)[sfOwnerNode];
|
auto const page = (*slep)[sfOwnerNode];
|
||||||
TER const ter = dirDelete(ctx_.view(), true,
|
TER const ter = dirDelete(ctx_.view(), true,
|
||||||
@@ -557,7 +510,7 @@ SusPayCancel::doApply()
|
|||||||
(*sle)[sfOwnerCount] = (*sle)[sfOwnerCount] - 1;
|
(*sle)[sfOwnerCount] = (*sle)[sfOwnerCount] - 1;
|
||||||
ctx_.view().update(sle);
|
ctx_.view().update(sle);
|
||||||
|
|
||||||
// Remove SusPay from ledger
|
// Remove escrow from ledger
|
||||||
ctx_.view().erase(slep);
|
ctx_.view().erase(slep);
|
||||||
|
|
||||||
return tesSUCCESS;
|
return tesSUCCESS;
|
||||||
@@ -17,19 +17,19 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef RIPPLE_TX_SUSPAY_H_INCLUDED
|
#ifndef RIPPLE_TX_ESCROW_H_INCLUDED
|
||||||
#define RIPPLE_TX_SUSPAY_H_INCLUDED
|
#define RIPPLE_TX_ESCROW_H_INCLUDED
|
||||||
|
|
||||||
#include <ripple/app/tx/impl/Transactor.h>
|
#include <ripple/app/tx/impl/Transactor.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
|
|
||||||
class SusPayCreate
|
class EscrowCreate
|
||||||
: public Transactor
|
: public Transactor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit
|
explicit
|
||||||
SusPayCreate (ApplyContext& ctx)
|
EscrowCreate (ApplyContext& ctx)
|
||||||
: Transactor(ctx)
|
: Transactor(ctx)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -48,12 +48,12 @@ public:
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
class SusPayFinish
|
class EscrowFinish
|
||||||
: public Transactor
|
: public Transactor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit
|
explicit
|
||||||
SusPayFinish (ApplyContext& ctx)
|
EscrowFinish (ApplyContext& ctx)
|
||||||
: Transactor(ctx)
|
: Transactor(ctx)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -72,12 +72,12 @@ public:
|
|||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
class SusPayCancel
|
class EscrowCancel
|
||||||
: public Transactor
|
: public Transactor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit
|
explicit
|
||||||
SusPayCancel (ApplyContext& ctx)
|
EscrowCancel (ApplyContext& ctx)
|
||||||
: Transactor(ctx)
|
: Transactor(ctx)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -25,12 +25,12 @@
|
|||||||
#include <ripple/app/tx/impl/Change.h>
|
#include <ripple/app/tx/impl/Change.h>
|
||||||
#include <ripple/app/tx/impl/CreateOffer.h>
|
#include <ripple/app/tx/impl/CreateOffer.h>
|
||||||
#include <ripple/app/tx/impl/CreateTicket.h>
|
#include <ripple/app/tx/impl/CreateTicket.h>
|
||||||
|
#include <ripple/app/tx/impl/Escrow.h>
|
||||||
#include <ripple/app/tx/impl/Payment.h>
|
#include <ripple/app/tx/impl/Payment.h>
|
||||||
#include <ripple/app/tx/impl/SetAccount.h>
|
#include <ripple/app/tx/impl/SetAccount.h>
|
||||||
#include <ripple/app/tx/impl/SetRegularKey.h>
|
#include <ripple/app/tx/impl/SetRegularKey.h>
|
||||||
#include <ripple/app/tx/impl/SetSignerList.h>
|
#include <ripple/app/tx/impl/SetSignerList.h>
|
||||||
#include <ripple/app/tx/impl/SetTrust.h>
|
#include <ripple/app/tx/impl/SetTrust.h>
|
||||||
#include <ripple/app/tx/impl/SusPay.h>
|
|
||||||
#include <ripple/app/tx/impl/PayChan.h>
|
#include <ripple/app/tx/impl/PayChan.h>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -45,9 +45,9 @@ invoke_preflight (PreflightContext const& ctx)
|
|||||||
case ttOFFER_CANCEL: return CancelOffer ::preflight(ctx);
|
case ttOFFER_CANCEL: return CancelOffer ::preflight(ctx);
|
||||||
case ttOFFER_CREATE: return CreateOffer ::preflight(ctx);
|
case ttOFFER_CREATE: return CreateOffer ::preflight(ctx);
|
||||||
case ttPAYMENT: return Payment ::preflight(ctx);
|
case ttPAYMENT: return Payment ::preflight(ctx);
|
||||||
case ttSUSPAY_CREATE: return SusPayCreate ::preflight(ctx);
|
case ttESCROW_CREATE: return EscrowCreate ::preflight(ctx);
|
||||||
case ttSUSPAY_FINISH: return SusPayFinish ::preflight(ctx);
|
case ttESCROW_FINISH: return EscrowFinish ::preflight(ctx);
|
||||||
case ttSUSPAY_CANCEL: return SusPayCancel ::preflight(ctx);
|
case ttESCROW_CANCEL: return EscrowCancel ::preflight(ctx);
|
||||||
case ttREGULAR_KEY_SET: return SetRegularKey ::preflight(ctx);
|
case ttREGULAR_KEY_SET: return SetRegularKey ::preflight(ctx);
|
||||||
case ttSIGNER_LIST_SET: return SetSignerList ::preflight(ctx);
|
case ttSIGNER_LIST_SET: return SetSignerList ::preflight(ctx);
|
||||||
case ttTICKET_CANCEL: return CancelTicket ::preflight(ctx);
|
case ttTICKET_CANCEL: return CancelTicket ::preflight(ctx);
|
||||||
@@ -118,9 +118,9 @@ invoke_preclaim (PreclaimContext const& ctx)
|
|||||||
case ttOFFER_CANCEL: return invoke_preclaim<CancelOffer>(ctx);
|
case ttOFFER_CANCEL: return invoke_preclaim<CancelOffer>(ctx);
|
||||||
case ttOFFER_CREATE: return invoke_preclaim<CreateOffer>(ctx);
|
case ttOFFER_CREATE: return invoke_preclaim<CreateOffer>(ctx);
|
||||||
case ttPAYMENT: return invoke_preclaim<Payment>(ctx);
|
case ttPAYMENT: return invoke_preclaim<Payment>(ctx);
|
||||||
case ttSUSPAY_CREATE: return invoke_preclaim<SusPayCreate>(ctx);
|
case ttESCROW_CREATE: return invoke_preclaim<EscrowCreate>(ctx);
|
||||||
case ttSUSPAY_FINISH: return invoke_preclaim<SusPayFinish>(ctx);
|
case ttESCROW_FINISH: return invoke_preclaim<EscrowFinish>(ctx);
|
||||||
case ttSUSPAY_CANCEL: return invoke_preclaim<SusPayCancel>(ctx);
|
case ttESCROW_CANCEL: return invoke_preclaim<EscrowCancel>(ctx);
|
||||||
case ttREGULAR_KEY_SET: return invoke_preclaim<SetRegularKey>(ctx);
|
case ttREGULAR_KEY_SET: return invoke_preclaim<SetRegularKey>(ctx);
|
||||||
case ttSIGNER_LIST_SET: return invoke_preclaim<SetSignerList>(ctx);
|
case ttSIGNER_LIST_SET: return invoke_preclaim<SetSignerList>(ctx);
|
||||||
case ttTICKET_CANCEL: return invoke_preclaim<CancelTicket>(ctx);
|
case ttTICKET_CANCEL: return invoke_preclaim<CancelTicket>(ctx);
|
||||||
@@ -147,9 +147,9 @@ invoke_calculateBaseFee(PreclaimContext const& ctx)
|
|||||||
case ttOFFER_CANCEL: return CancelOffer::calculateBaseFee(ctx);
|
case ttOFFER_CANCEL: return CancelOffer::calculateBaseFee(ctx);
|
||||||
case ttOFFER_CREATE: return CreateOffer::calculateBaseFee(ctx);
|
case ttOFFER_CREATE: return CreateOffer::calculateBaseFee(ctx);
|
||||||
case ttPAYMENT: return Payment::calculateBaseFee(ctx);
|
case ttPAYMENT: return Payment::calculateBaseFee(ctx);
|
||||||
case ttSUSPAY_CREATE: return SusPayCreate::calculateBaseFee(ctx);
|
case ttESCROW_CREATE: return EscrowCreate::calculateBaseFee(ctx);
|
||||||
case ttSUSPAY_FINISH: return SusPayFinish::calculateBaseFee(ctx);
|
case ttESCROW_FINISH: return EscrowFinish::calculateBaseFee(ctx);
|
||||||
case ttSUSPAY_CANCEL: return SusPayCancel::calculateBaseFee(ctx);
|
case ttESCROW_CANCEL: return EscrowCancel::calculateBaseFee(ctx);
|
||||||
case ttREGULAR_KEY_SET: return SetRegularKey::calculateBaseFee(ctx);
|
case ttREGULAR_KEY_SET: return SetRegularKey::calculateBaseFee(ctx);
|
||||||
case ttSIGNER_LIST_SET: return SetSignerList::calculateBaseFee(ctx);
|
case ttSIGNER_LIST_SET: return SetSignerList::calculateBaseFee(ctx);
|
||||||
case ttTICKET_CANCEL: return CancelTicket::calculateBaseFee(ctx);
|
case ttTICKET_CANCEL: return CancelTicket::calculateBaseFee(ctx);
|
||||||
@@ -189,9 +189,9 @@ invoke_calculateConsequences(STTx const& tx)
|
|||||||
case ttOFFER_CANCEL: return invoke_calculateConsequences<CancelOffer>(tx);
|
case ttOFFER_CANCEL: return invoke_calculateConsequences<CancelOffer>(tx);
|
||||||
case ttOFFER_CREATE: return invoke_calculateConsequences<CreateOffer>(tx);
|
case ttOFFER_CREATE: return invoke_calculateConsequences<CreateOffer>(tx);
|
||||||
case ttPAYMENT: return invoke_calculateConsequences<Payment>(tx);
|
case ttPAYMENT: return invoke_calculateConsequences<Payment>(tx);
|
||||||
case ttSUSPAY_CREATE: return invoke_calculateConsequences<SusPayCreate>(tx);
|
case ttESCROW_CREATE: return invoke_calculateConsequences<EscrowCreate>(tx);
|
||||||
case ttSUSPAY_FINISH: return invoke_calculateConsequences<SusPayFinish>(tx);
|
case ttESCROW_FINISH: return invoke_calculateConsequences<EscrowFinish>(tx);
|
||||||
case ttSUSPAY_CANCEL: return invoke_calculateConsequences<SusPayCancel>(tx);
|
case ttESCROW_CANCEL: return invoke_calculateConsequences<EscrowCancel>(tx);
|
||||||
case ttREGULAR_KEY_SET: return invoke_calculateConsequences<SetRegularKey>(tx);
|
case ttREGULAR_KEY_SET: return invoke_calculateConsequences<SetRegularKey>(tx);
|
||||||
case ttSIGNER_LIST_SET: return invoke_calculateConsequences<SetSignerList>(tx);
|
case ttSIGNER_LIST_SET: return invoke_calculateConsequences<SetSignerList>(tx);
|
||||||
case ttTICKET_CANCEL: return invoke_calculateConsequences<CancelTicket>(tx);
|
case ttTICKET_CANCEL: return invoke_calculateConsequences<CancelTicket>(tx);
|
||||||
@@ -220,9 +220,9 @@ invoke_apply (ApplyContext& ctx)
|
|||||||
case ttOFFER_CANCEL: { CancelOffer p(ctx); return p(); }
|
case ttOFFER_CANCEL: { CancelOffer p(ctx); return p(); }
|
||||||
case ttOFFER_CREATE: { CreateOffer p(ctx); return p(); }
|
case ttOFFER_CREATE: { CreateOffer p(ctx); return p(); }
|
||||||
case ttPAYMENT: { Payment p(ctx); return p(); }
|
case ttPAYMENT: { Payment p(ctx); return p(); }
|
||||||
case ttSUSPAY_CREATE: { SusPayCreate p(ctx); return p(); }
|
case ttESCROW_CREATE: { EscrowCreate p(ctx); return p(); }
|
||||||
case ttSUSPAY_FINISH: { SusPayFinish p(ctx); return p(); }
|
case ttESCROW_FINISH: { EscrowFinish p(ctx); return p(); }
|
||||||
case ttSUSPAY_CANCEL: { SusPayCancel p(ctx); return p(); }
|
case ttESCROW_CANCEL: { EscrowCancel p(ctx); return p(); }
|
||||||
case ttREGULAR_KEY_SET: { SetRegularKey p(ctx); return p(); }
|
case ttREGULAR_KEY_SET: { SetRegularKey p(ctx); return p(); }
|
||||||
case ttSIGNER_LIST_SET: { SetSignerList p(ctx); return p(); }
|
case ttSIGNER_LIST_SET: { SetSignerList p(ctx); return p(); }
|
||||||
case ttTICKET_CANCEL: { CancelTicket p(ctx); return p(); }
|
case ttTICKET_CANCEL: { CancelTicket p(ctx); return p(); }
|
||||||
@@ -341,4 +341,4 @@ doApply(PreclaimResult const& preclaimResult,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -20,73 +20,91 @@
|
|||||||
#ifndef RIPPLE_CONDITIONS_CONDITION_H
|
#ifndef RIPPLE_CONDITIONS_CONDITION_H
|
||||||
#define RIPPLE_CONDITIONS_CONDITION_H
|
#define RIPPLE_CONDITIONS_CONDITION_H
|
||||||
|
|
||||||
#include <ripple/conditions/impl/base64.h> // use Beast implementation
|
#include <ripple/basics/Buffer.h>
|
||||||
|
#include <ripple/basics/Slice.h>
|
||||||
#include <ripple/conditions/impl/utils.h>
|
#include <ripple/conditions/impl/utils.h>
|
||||||
#include <boost/optional.hpp>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <system_error>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace cryptoconditions {
|
namespace cryptoconditions {
|
||||||
|
|
||||||
// NIKB-TODO: These should move to a separate file:
|
enum class Type
|
||||||
std::uint16_t constexpr condition_hashlock = 0;
|
: std::uint8_t
|
||||||
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;
|
preimageSha256 = 0,
|
||||||
|
prefixSha256 = 1,
|
||||||
|
thresholdSha256 = 2,
|
||||||
|
rsaSha256 = 3,
|
||||||
|
ed25519Sha256 = 4
|
||||||
|
};
|
||||||
|
|
||||||
/** The maximum length of a fulfillment for this condition.
|
class Condition
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The largest binary condition we support.
|
||||||
|
|
||||||
While it is possible for a fulfillment to be smaller
|
@note This value will be increased in the future, but it
|
||||||
it can never be bigger than this.
|
must never decrease, as that could cause conditions
|
||||||
|
that were previously considered valid to no longer
|
||||||
|
be allowed.
|
||||||
*/
|
*/
|
||||||
std::uint16_t maxFulfillmentLength;
|
static constexpr std::size_t maxSerializedCondition = 128;
|
||||||
|
|
||||||
/** The features suites required to process a fulfillment. */
|
/** Load a condition from its binary form
|
||||||
std::uint32_t featureBitmask;
|
|
||||||
|
@param s The buffer containing the fulfillment to load.
|
||||||
|
@param ec Set to the error, if any occurred.
|
||||||
|
|
||||||
|
The binary format for a condition is specified in the
|
||||||
|
cryptoconditions RFC. See:
|
||||||
|
|
||||||
|
https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-7.2
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
std::unique_ptr<Condition>
|
||||||
|
deserialize(Slice s, std::error_code& ec);
|
||||||
|
|
||||||
|
public:
|
||||||
|
Type type;
|
||||||
|
|
||||||
/** An identifier for this condition.
|
/** An identifier for this condition.
|
||||||
|
|
||||||
This fingerprint is meant to be unique only with
|
This fingerprint is meant to be unique only with
|
||||||
respect to other conditions of the same type.
|
respect to other conditions of the same type.
|
||||||
*/
|
*/
|
||||||
std::array<std::uint8_t, 32> fingerprint;
|
Buffer fingerprint;
|
||||||
|
|
||||||
// Can this be deleted?
|
/** The cost associated with this condition. */
|
||||||
Condition () = default;
|
std::uint32_t cost;
|
||||||
|
|
||||||
Condition (Condition const&) = default;
|
/** For compound conditions, set of conditions includes */
|
||||||
Condition (Condition&&) = default;
|
std::set<Type> subtypes;
|
||||||
|
|
||||||
|
Condition(Type t, std::uint32_t c, Slice fp)
|
||||||
|
: type(t)
|
||||||
|
, fingerprint(fp)
|
||||||
|
, cost(c)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Condition(Type t, std::uint32_t c, Buffer&& fp)
|
||||||
|
: type(t)
|
||||||
|
, fingerprint(std::move(fp))
|
||||||
|
, cost(c)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Condition() = default;
|
||||||
|
|
||||||
|
Condition(Condition const&) = default;
|
||||||
|
Condition(Condition&&) = default;
|
||||||
|
|
||||||
|
Condition() = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
inline
|
||||||
@@ -95,9 +113,9 @@ operator== (Condition const& lhs, Condition const& rhs)
|
|||||||
{
|
{
|
||||||
return
|
return
|
||||||
lhs.type == rhs.type &&
|
lhs.type == rhs.type &&
|
||||||
lhs.featureBitmask == rhs.featureBitmask &&
|
lhs.cost == rhs.cost &&
|
||||||
lhs.maxFulfillmentLength == rhs.maxFulfillmentLength &&
|
lhs.subtypes == rhs.subtypes &&
|
||||||
lhs.fingerprint == rhs.fingerprint;
|
lhs.fingerprint == rhs.fingerprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
@@ -107,99 +125,6 @@ operator!= (Condition const& lhs, Condition const& rhs)
|
|||||||
return !(lhs == 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;
|
|
||||||
|
|
||||||
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_rsa_sha256)
|
|
||||||
return (c.featureBitmask == (feature_rsa_pss | feature_sha256));
|
|
||||||
|
|
||||||
if (c.type == condition_ed25519)
|
|
||||||
return (c.featureBitmask == feature_ed25519);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
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_ED25519_H
|
|
||||||
#define RIPPLE_CONDITIONS_ED25519_H
|
|
||||||
|
|
||||||
#include <ripple/conditions/Condition.h>
|
|
||||||
#include <ripple/conditions/Fulfillment.h>
|
|
||||||
#include <ripple/protocol/PublicKey.h>
|
|
||||||
#include <ripple/protocol/SecretKey.h>
|
|
||||||
#include <array>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
namespace cryptoconditions {
|
|
||||||
|
|
||||||
class Ed25519 final
|
|
||||||
: public Fulfillment
|
|
||||||
{
|
|
||||||
static std::size_t constexpr signature_size_ = 64;
|
|
||||||
static std::size_t constexpr pubkey_size_ = 32;
|
|
||||||
|
|
||||||
std::array<std::uint8_t,
|
|
||||||
pubkey_size_ + signature_size_> payload_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Ed25519 () = default;
|
|
||||||
|
|
||||||
/** Create a fulfillment given a keypair and the message */
|
|
||||||
Ed25519 (
|
|
||||||
SecretKey const& secretKey,
|
|
||||||
PublicKey const& publicKey,
|
|
||||||
Slice message);
|
|
||||||
|
|
||||||
/** Create a fulfillment given a secret key and the message */
|
|
||||||
Ed25519 (
|
|
||||||
SecretKey const& secretKey,
|
|
||||||
Slice message);
|
|
||||||
|
|
||||||
Condition
|
|
||||||
condition() const override;
|
|
||||||
|
|
||||||
std::uint16_t
|
|
||||||
type () const override
|
|
||||||
{
|
|
||||||
return condition_ed25519;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint32_t
|
|
||||||
features () const override
|
|
||||||
{
|
|
||||||
return feature_ed25519;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ok () const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t
|
|
||||||
payloadSize () const override
|
|
||||||
{
|
|
||||||
return payload_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer
|
|
||||||
payload() const override
|
|
||||||
{
|
|
||||||
return { payload_.data(), payload_.size() };
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
validate (Slice data) const override;
|
|
||||||
|
|
||||||
bool
|
|
||||||
parsePayload (Slice s) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -31,69 +31,86 @@ namespace cryptoconditions {
|
|||||||
|
|
||||||
struct Fulfillment
|
struct Fulfillment
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
/** The largest binary fulfillment we support.
|
||||||
|
|
||||||
|
@note This value will be increased in the future, but it
|
||||||
|
must never decrease, as that could cause fulfillments
|
||||||
|
that were previously considered valid to no longer
|
||||||
|
be allowed.
|
||||||
|
*/
|
||||||
|
static constexpr std::size_t maxSerializedFulfillment = 256;
|
||||||
|
|
||||||
|
/** Load a fulfillment from its binary form
|
||||||
|
|
||||||
|
@param s The buffer containing the fulfillment to load.
|
||||||
|
@param ec Set to the error, if any occurred.
|
||||||
|
|
||||||
|
The binary format for a fulfillment is specified in the
|
||||||
|
cryptoconditions RFC. See:
|
||||||
|
|
||||||
|
https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-7.3
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
std::unique_ptr<Fulfillment>
|
||||||
|
deserialize(
|
||||||
|
Slice s,
|
||||||
|
std::error_code& ec);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~Fulfillment() = default;
|
virtual ~Fulfillment() = default;
|
||||||
|
|
||||||
Fulfillment () = default;
|
/** Returns the fulfillment's fingerprint:
|
||||||
|
|
||||||
/** Returns the size of the fulfillment's payload. */
|
The fingerprint is an octet string uniquely
|
||||||
virtual
|
representing this fulfillment's condition
|
||||||
std::size_t
|
with respect to other conditions of the
|
||||||
payloadSize() const = 0;
|
same type.
|
||||||
|
*/
|
||||||
/** Returns the fulfillment's payload */
|
|
||||||
virtual
|
virtual
|
||||||
Buffer
|
Buffer
|
||||||
payload() const = 0;
|
fingerprint() const = 0;
|
||||||
|
|
||||||
/** Generates the condition */
|
/** Returns the type of this condition. */
|
||||||
virtual
|
virtual
|
||||||
Condition
|
Type
|
||||||
condition() const = 0;
|
|
||||||
|
|
||||||
/** Returns the type */
|
|
||||||
virtual
|
|
||||||
std::uint16_t
|
|
||||||
type () const = 0;
|
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. */
|
/** Validates a fulfillment. */
|
||||||
virtual
|
virtual
|
||||||
bool
|
bool
|
||||||
validate (Slice data) const = 0;
|
validate (Slice data) const = 0;
|
||||||
|
|
||||||
/** Parses the fulfillment's payload. */
|
/** Calculates the cost associated with this fulfillment. *
|
||||||
|
|
||||||
|
The cost function is deterministic and depends on the
|
||||||
|
type and properties of the condition and the fulfillment
|
||||||
|
that the condition is generated from.
|
||||||
|
*/
|
||||||
virtual
|
virtual
|
||||||
bool
|
std::uint32_t
|
||||||
parsePayload (Slice s) = 0;
|
cost() const = 0;
|
||||||
|
|
||||||
|
/** Returns the condition associated with the given fulfillment.
|
||||||
|
|
||||||
|
This process is completely deterministic. All implementations
|
||||||
|
will, if compliant, produce the identical condition for the
|
||||||
|
same fulfillment.
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
Condition
|
||||||
|
condition() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool
|
bool
|
||||||
operator== (Fulfillment const& lhs, Fulfillment const& rhs)
|
operator== (Fulfillment const& lhs, Fulfillment const& rhs)
|
||||||
{
|
{
|
||||||
|
// FIXME: for compound conditions, need to also check subtypes
|
||||||
return
|
return
|
||||||
lhs.type() == rhs.type() &&
|
lhs.type() == rhs.type() &&
|
||||||
lhs.ok() == rhs.ok() &&
|
lhs.cost() == rhs.cost() &&
|
||||||
lhs.payload() == rhs.payload();
|
lhs.fingerprint() == rhs.fingerprint();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
@@ -103,37 +120,9 @@ operator!= (Fulfillment const& lhs, Fulfillment const& rhs)
|
|||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Load a fulfillment from its string serialization.
|
/** Determine whether the given fulfillment and condition match */
|
||||||
|
|
||||||
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
|
bool
|
||||||
fulfills (
|
match (
|
||||||
Fulfillment const& f,
|
Fulfillment const& f,
|
||||||
Condition const& c);
|
Condition const& c);
|
||||||
|
|
||||||
@@ -141,10 +130,11 @@ fulfills (
|
|||||||
|
|
||||||
@param f The fulfillment
|
@param f The fulfillment
|
||||||
@param c The condition
|
@param c The condition
|
||||||
@param m The message; note that the message is not
|
@param m The message
|
||||||
relevant for some conditions (e.g. hashlocks)
|
|
||||||
and a fulfillment will successfully satisfy its
|
@note the message is not relevant for some conditions
|
||||||
condition for any given message.
|
and a fulfillment will successfully satisfy its
|
||||||
|
condition for any given message.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
validate (
|
validate (
|
||||||
@@ -166,7 +156,7 @@ validate (
|
|||||||
@param c The condition
|
@param c The condition
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
validateTrigger (
|
validate (
|
||||||
Fulfillment const& f,
|
Fulfillment const& f,
|
||||||
Condition const& c);
|
Condition const& c);
|
||||||
|
|
||||||
|
|||||||
@@ -1,218 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
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
|
|
||||||
@@ -1,123 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
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_PREIMAGE_SHA256_H
|
|
||||||
#define RIPPLE_CONDITIONS_PREIMAGE_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 <vector>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
namespace cryptoconditions {
|
|
||||||
|
|
||||||
class PreimageSha256 final
|
|
||||||
: public Fulfillment
|
|
||||||
{
|
|
||||||
Buffer payload_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
PreimageSha256() = default;
|
|
||||||
|
|
||||||
PreimageSha256 (Slice s)
|
|
||||||
: payload_ (s)
|
|
||||||
{
|
|
||||||
// TODO: We don't want to throw. Devise better
|
|
||||||
// interface for constructing hashlock from
|
|
||||||
// given buffer.
|
|
||||||
if (payload_.size() > maxSupportedFulfillmentLength)
|
|
||||||
throw std::length_error (
|
|
||||||
"Maximum fulfillment length exceeded");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t
|
|
||||||
payloadSize () const override
|
|
||||||
{
|
|
||||||
return payload_.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer
|
|
||||||
payload() const override
|
|
||||||
{
|
|
||||||
return { payload_.data(), payload_.size() };
|
|
||||||
}
|
|
||||||
|
|
||||||
Condition
|
|
||||||
condition() const override
|
|
||||||
{
|
|
||||||
sha256_hasher h;
|
|
||||||
h (payload_.data(), payload_.size());
|
|
||||||
|
|
||||||
Condition cc;
|
|
||||||
cc.type = type();
|
|
||||||
cc.featureBitmask = features();
|
|
||||||
cc.maxFulfillmentLength = payload_.size();
|
|
||||||
cc.fingerprint = static_cast<sha256_hasher::result_type>(h);
|
|
||||||
|
|
||||||
return cc;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint16_t
|
|
||||||
type () const override
|
|
||||||
{
|
|
||||||
return condition_hashlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::uint32_t
|
|
||||||
features () const override
|
|
||||||
{
|
|
||||||
return feature_sha256 | feature_preimage;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ok () const override
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
validate (Slice) const override
|
|
||||||
{
|
|
||||||
// Perhaps counterintuitively, the message isn't
|
|
||||||
// relevant.
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
parsePayload (Slice s) override
|
|
||||||
{
|
|
||||||
// The payload may be empty
|
|
||||||
if (s.size() > maxSupportedFulfillmentLength)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
payload_ = s;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <ripple/basics/contract.h>
|
#include <ripple/basics/contract.h>
|
||||||
#include <ripple/conditions/Condition.h>
|
#include <ripple/conditions/Condition.h>
|
||||||
#include <ripple/conditions/Fulfillment.h>
|
#include <ripple/conditions/Fulfillment.h>
|
||||||
|
#include <ripple/conditions/impl/PreimageSha256.h>
|
||||||
#include <ripple/conditions/impl/utils.h>
|
#include <ripple/conditions/impl/utils.h>
|
||||||
#include <boost/regex.hpp>
|
#include <boost/regex.hpp>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
@@ -29,160 +30,212 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace cryptoconditions {
|
namespace cryptoconditions {
|
||||||
|
|
||||||
boost::optional<Condition>
|
namespace detail {
|
||||||
loadCondition(std::string const& s)
|
// The binary encoding of conditions differs based on their
|
||||||
|
// type. All types define at least a fingerprint and cost
|
||||||
|
// sub-field. Some types, such as the compound condition
|
||||||
|
// types, define additional sub-fields that are required to
|
||||||
|
// convey essential properties of the cryptocondition (such
|
||||||
|
// as the sub-types used by sub-conditions in the case of
|
||||||
|
// the compound types).
|
||||||
|
//
|
||||||
|
// Conditions are encoded as follows:
|
||||||
|
//
|
||||||
|
// Condition ::= CHOICE {
|
||||||
|
// preimageSha256 [0] SimpleSha256Condition,
|
||||||
|
// prefixSha256 [1] CompoundSha256Condition,
|
||||||
|
// thresholdSha256 [2] CompoundSha256Condition,
|
||||||
|
// rsaSha256 [3] SimpleSha256Condition,
|
||||||
|
// ed25519Sha256 [4] SimpleSha256Condition
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// SimpleSha256Condition ::= SEQUENCE {
|
||||||
|
// fingerprint OCTET STRING (SIZE(32)),
|
||||||
|
// cost INTEGER (0..4294967295)
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// CompoundSha256Condition ::= SEQUENCE {
|
||||||
|
// fingerprint OCTET STRING (SIZE(32)),
|
||||||
|
// cost INTEGER (0..4294967295),
|
||||||
|
// subtypes ConditionTypes
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ConditionTypes ::= BIT STRING {
|
||||||
|
// preImageSha256 (0),
|
||||||
|
// prefixSha256 (1),
|
||||||
|
// thresholdSha256 (2),
|
||||||
|
// rsaSha256 (3),
|
||||||
|
// ed25519Sha256 (4)
|
||||||
|
// }
|
||||||
|
|
||||||
|
constexpr std::size_t fingerprintSize = 32;
|
||||||
|
|
||||||
|
std::unique_ptr<Condition>
|
||||||
|
loadSimpleSha256(Type type, Slice s, std::error_code& ec)
|
||||||
{
|
{
|
||||||
static boost::regex const re_current (
|
using namespace der;
|
||||||
"^" // 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;
|
auto p = parsePreamble(s, ec);
|
||||||
|
|
||||||
if (!boost::regex_match (s, match, re_current))
|
if (ec)
|
||||||
return boost::none;
|
return {};
|
||||||
|
|
||||||
try
|
if (!isPrimitive(p) || !isContextSpecific(p))
|
||||||
{
|
{
|
||||||
Condition c;
|
ec = error::incorrect_encoding;
|
||||||
|
return {};
|
||||||
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&)
|
|
||||||
|
if (p.tag != 0)
|
||||||
{
|
{
|
||||||
return boost::none;
|
ec = error::unexpected_tag;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
boost::optional<Condition>
|
if (p.length != fingerprintSize)
|
||||||
loadCondition(Slice s)
|
|
||||||
{
|
|
||||||
if (s.empty())
|
|
||||||
return boost::none;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
auto start = s.data();
|
ec = error::fingerprint_size;
|
||||||
auto finish = s.data() + s.size();
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Condition c;
|
Buffer b = parseOctetString(s, p.length, ec);
|
||||||
|
|
||||||
std::tie (start, c.type) =
|
if (ec)
|
||||||
oer::decode_integer<std::uint16_t> (
|
return {};
|
||||||
start, finish);
|
|
||||||
|
|
||||||
if (!isCondition (c.type))
|
p = parsePreamble(s, ec);
|
||||||
return boost::none;
|
|
||||||
|
|
||||||
std::tie (start, c.featureBitmask) =
|
if (ec)
|
||||||
oer::decode_varuint<std::uint32_t> (
|
return {};
|
||||||
start, finish);
|
|
||||||
|
|
||||||
|
if (!isPrimitive(p) || !isContextSpecific(p))
|
||||||
|
{
|
||||||
|
ec = error::malformed_encoding;
|
||||||
|
return{};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.tag != 1)
|
||||||
|
{
|
||||||
|
ec = error::unexpected_tag;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cost = parseInteger<std::uint32_t>(s, p.length, ec);
|
||||||
|
|
||||||
|
if (ec)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
if (!s.empty())
|
||||||
|
{
|
||||||
|
ec = error::trailing_garbage;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Type::preimageSha256:
|
||||||
|
if (cost > PreimageSha256::maxPreimageLength)
|
||||||
{
|
{
|
||||||
std::size_t len;
|
ec = error::preimage_too_long;
|
||||||
|
return {};
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
if (start == finish)
|
default:
|
||||||
return boost::none;
|
break;
|
||||||
|
|
||||||
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 std::make_unique<Condition>(type, cost, std::move(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Condition>
|
||||||
|
Condition::deserialize(Slice s, std::error_code& ec)
|
||||||
|
{
|
||||||
|
// Per the RFC, in a condition we choose a type based
|
||||||
|
// on the tag of the item we contain:
|
||||||
|
//
|
||||||
|
// Condition ::= CHOICE {
|
||||||
|
// preimageSha256 [0] SimpleSha256Condition,
|
||||||
|
// prefixSha256 [1] CompoundSha256Condition,
|
||||||
|
// thresholdSha256 [2] CompoundSha256Condition,
|
||||||
|
// rsaSha256 [3] SimpleSha256Condition,
|
||||||
|
// ed25519Sha256 [4] SimpleSha256Condition
|
||||||
|
// }
|
||||||
|
if (s.empty())
|
||||||
{
|
{
|
||||||
return boost::none;
|
ec = error::buffer_empty;
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
using namespace der;
|
||||||
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>
|
auto const p = parsePreamble(s, ec);
|
||||||
to_blob (Condition const& c)
|
if (ec)
|
||||||
{
|
return {};
|
||||||
// TODO: optimize this
|
|
||||||
std::vector<std::uint8_t> v;
|
|
||||||
v.reserve (48);
|
|
||||||
|
|
||||||
oer::encode_integer (
|
// All fulfillments are context-specific, constructed
|
||||||
c.type,
|
// types
|
||||||
std::back_inserter(v));
|
if (!isConstructed(p) || !isContextSpecific(p))
|
||||||
|
{
|
||||||
|
ec = error::malformed_encoding;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
oer::encode_varuint (
|
if (p.length > s.size())
|
||||||
c.featureBitmask,
|
{
|
||||||
std::back_inserter(v));
|
ec = error::buffer_underfull;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
oer::encode_octetstring (
|
if (s.size() > maxSerializedCondition)
|
||||||
c.fingerprint.size(),
|
{
|
||||||
c.fingerprint.begin(),
|
ec = error::large_size;
|
||||||
c.fingerprint.end(),
|
return {};
|
||||||
std::back_inserter(v));
|
}
|
||||||
|
|
||||||
oer::encode_varuint (
|
std::unique_ptr<Condition> c;
|
||||||
c.maxFulfillmentLength,
|
|
||||||
std::back_inserter(v));
|
|
||||||
|
|
||||||
return v;
|
switch (p.tag)
|
||||||
|
{
|
||||||
|
case 0: // PreimageSha256
|
||||||
|
c = detail::loadSimpleSha256(
|
||||||
|
Type::preimageSha256,
|
||||||
|
Slice(s.data(), p.length), ec);
|
||||||
|
if (!ec)
|
||||||
|
s += p.length;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1: // PrefixSha256
|
||||||
|
ec = error::unsupported_type;
|
||||||
|
return {};
|
||||||
|
|
||||||
|
case 2: // ThresholdSha256
|
||||||
|
ec = error::unsupported_type;
|
||||||
|
return {};
|
||||||
|
|
||||||
|
case 3: // RsaSha256
|
||||||
|
ec = error::unsupported_type;
|
||||||
|
return {};
|
||||||
|
|
||||||
|
case 4: // Ed25519Sha256
|
||||||
|
ec = error::unsupported_type;
|
||||||
|
return {};
|
||||||
|
|
||||||
|
default:
|
||||||
|
ec = error::unknown_type;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s.empty())
|
||||||
|
{
|
||||||
|
ec = error::trailing_garbage;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,115 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
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/Ed25519.h>
|
|
||||||
#include <ripple/conditions/impl/base64.h>
|
|
||||||
#include <ripple/basics/contract.h>
|
|
||||||
#include <ed25519-donna/ed25519.h>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
namespace cryptoconditions {
|
|
||||||
|
|
||||||
Ed25519::Ed25519 (
|
|
||||||
SecretKey const& secretKey,
|
|
||||||
PublicKey const& publicKey,
|
|
||||||
Slice message)
|
|
||||||
{
|
|
||||||
if (publicKeyType (publicKey) != KeyType::ed25519)
|
|
||||||
LogicError ("An Ed25519 public key is required.");
|
|
||||||
|
|
||||||
// When PublicKey wraps an Ed25519 key it prefixes
|
|
||||||
// the key itself with a 0xED byte. We carefully
|
|
||||||
// skip that byte.
|
|
||||||
std::memcpy (
|
|
||||||
payload_.data(),
|
|
||||||
publicKey.data() + 1,
|
|
||||||
publicKey.size() - 1);
|
|
||||||
|
|
||||||
// Now sign:
|
|
||||||
ed25519_sign (
|
|
||||||
message.data(),
|
|
||||||
message.size(),
|
|
||||||
secretKey.data(),
|
|
||||||
payload_.data(),
|
|
||||||
payload_.data() + pubkey_size_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create a fulfillment given a secret key and the message */
|
|
||||||
Ed25519::Ed25519 (
|
|
||||||
SecretKey const& secretKey,
|
|
||||||
Slice message)
|
|
||||||
{
|
|
||||||
// First derive the public key, and place it in the
|
|
||||||
// payload:
|
|
||||||
ed25519_publickey (
|
|
||||||
secretKey.data(),
|
|
||||||
payload_.data());
|
|
||||||
|
|
||||||
ed25519_sign (
|
|
||||||
message.data(),
|
|
||||||
message.size(),
|
|
||||||
secretKey.data(),
|
|
||||||
payload_.data(),
|
|
||||||
payload_.data() + pubkey_size_);
|
|
||||||
}
|
|
||||||
|
|
||||||
Condition
|
|
||||||
Ed25519::condition() const
|
|
||||||
{
|
|
||||||
Condition cc;
|
|
||||||
cc.type = type();
|
|
||||||
cc.featureBitmask = features();
|
|
||||||
cc.maxFulfillmentLength = payloadSize();
|
|
||||||
|
|
||||||
std::memcpy (
|
|
||||||
cc.fingerprint.data(),
|
|
||||||
payload_.data(),
|
|
||||||
pubkey_size_);
|
|
||||||
|
|
||||||
return cc;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Ed25519::validate (Slice data) const
|
|
||||||
{
|
|
||||||
return ed25519_sign_open (
|
|
||||||
data.data(),
|
|
||||||
data.size(),
|
|
||||||
payload_.data(),
|
|
||||||
payload_.data() + pubkey_size_) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
Ed25519::parsePayload (Slice s)
|
|
||||||
{
|
|
||||||
// The payload consists of 96 consecutive bytes:
|
|
||||||
// The public key is the first 32 and the
|
|
||||||
// remaining 64 bytes are the signature.
|
|
||||||
if (s.size() != sizeof(payload_))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::memcpy (payload_.data(), s.data(), s.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -19,10 +19,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/impl/PreimageSha256.h>
|
||||||
#include <ripple/conditions/PrefixSha256.h>
|
|
||||||
#include <ripple/conditions/RsaSha256.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>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
@@ -33,7 +30,7 @@ namespace ripple {
|
|||||||
namespace cryptoconditions {
|
namespace cryptoconditions {
|
||||||
|
|
||||||
bool
|
bool
|
||||||
fulfills (
|
match (
|
||||||
Fulfillment const& f,
|
Fulfillment const& f,
|
||||||
Condition const& c)
|
Condition const& c)
|
||||||
{
|
{
|
||||||
@@ -42,16 +39,9 @@ fulfills (
|
|||||||
if (f.type() != c.type)
|
if (f.type() != c.type)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Ensure that the condition is well-formed
|
// Derive the condition from the given fulfillment
|
||||||
if (!validate (c))
|
// and ensure that it matches the given condition.
|
||||||
return false;
|
return c == f.condition();
|
||||||
|
|
||||||
// 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
|
bool
|
||||||
@@ -60,11 +50,11 @@ validate (
|
|||||||
Condition const& c,
|
Condition const& c,
|
||||||
Slice m)
|
Slice m)
|
||||||
{
|
{
|
||||||
return fulfills (f, c) && f.validate (m);
|
return match (f, c) && f.validate (m);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
validateTrigger (
|
validate (
|
||||||
Fulfillment const& f,
|
Fulfillment const& f,
|
||||||
Condition const& c)
|
Condition const& c)
|
||||||
{
|
{
|
||||||
@@ -72,157 +62,100 @@ validateTrigger (
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Fulfillment>
|
std::unique_ptr<Fulfillment>
|
||||||
loadFulfillment (std::uint16_t type, Slice payload)
|
Fulfillment::deserialize(
|
||||||
|
Slice s,
|
||||||
|
std::error_code& ec)
|
||||||
{
|
{
|
||||||
std::unique_ptr<Fulfillment> p;
|
// Per the RFC, in a fulfillment we choose a type based
|
||||||
|
// on the tag of the item we contain:
|
||||||
|
//
|
||||||
|
// Fulfillment ::= CHOICE {
|
||||||
|
// preimageSha256 [0] PreimageFulfillment ,
|
||||||
|
// prefixSha256 [1] PrefixFulfillment,
|
||||||
|
// thresholdSha256 [2] ThresholdFulfillment,
|
||||||
|
// rsaSha256 [3] RsaSha256Fulfillment,
|
||||||
|
// ed25519Sha256 [4] Ed25519Sha512Fulfillment
|
||||||
|
// }
|
||||||
|
|
||||||
switch (type)
|
if (s.empty())
|
||||||
{
|
{
|
||||||
case condition_hashlock:
|
ec = error::buffer_empty;
|
||||||
p = std::make_unique<PreimageSha256>();
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace der;
|
||||||
|
|
||||||
|
auto const p = parsePreamble(s, ec);
|
||||||
|
if (ec)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
// All fulfillments are context-specific, constructed types
|
||||||
|
if (!isConstructed(p) || !isContextSpecific(p))
|
||||||
|
{
|
||||||
|
ec = error::malformed_encoding;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.length > s.size())
|
||||||
|
{
|
||||||
|
ec = error::buffer_underfull;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.length < s.size())
|
||||||
|
{
|
||||||
|
ec = error::buffer_overfull;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.length > maxSerializedFulfillment)
|
||||||
|
{
|
||||||
|
ec = error::large_size;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<Fulfillment> f;
|
||||||
|
|
||||||
|
switch (static_cast<Type>(p.tag))
|
||||||
|
{
|
||||||
|
case Type::preimageSha256:
|
||||||
|
f = PreimageSha256::deserialize(Slice(s.data(), p.length), ec);
|
||||||
|
if (ec)
|
||||||
|
return {};
|
||||||
|
s += p.length;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case condition_prefix_sha256:
|
case Type::prefixSha256:
|
||||||
p = std::make_unique<PrefixSha256>();
|
ec = error::unsupported_type;
|
||||||
|
return {};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case condition_rsa_sha256:
|
case Type::thresholdSha256:
|
||||||
p = std::make_unique<RsaSha256>();
|
ec = error::unsupported_type;
|
||||||
|
return {};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case condition_ed25519:
|
case Type::rsaSha256:
|
||||||
p = std::make_unique<Ed25519>();
|
ec = error::unsupported_type;
|
||||||
|
return {};
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Type::ed25519Sha256:
|
||||||
|
ec = error::unsupported_type;
|
||||||
|
return {};
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw std::domain_error (
|
ec = error::unknown_type;
|
||||||
"Unknown cryptocondition type " +
|
return {};
|
||||||
std::to_string (type));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the payload can't be parsed, the load should
|
if (!s.empty())
|
||||||
// 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;
|
ec = error::trailing_garbage;
|
||||||
|
return {};
|
||||||
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>
|
return f;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
158
src/ripple/conditions/impl/PreimageSha256.h
Normal file
158
src/ripple/conditions/impl/PreimageSha256.h
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
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_PREIMAGE_SHA256_H
|
||||||
|
#define RIPPLE_CONDITIONS_PREIMAGE_SHA256_H
|
||||||
|
|
||||||
|
#include <ripple/basics/Buffer.h>
|
||||||
|
#include <ripple/basics/Slice.h>
|
||||||
|
#include <ripple/conditions/Condition.h>
|
||||||
|
#include <ripple/conditions/Fulfillment.h>
|
||||||
|
#include <ripple/conditions/impl/error.h>
|
||||||
|
#include <ripple/protocol/digest.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace cryptoconditions {
|
||||||
|
|
||||||
|
class PreimageSha256 final
|
||||||
|
: public Fulfillment
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** The maximum allowed length of a preimage.
|
||||||
|
|
||||||
|
The specification does not specify a minimum supported
|
||||||
|
length, nor does it require all conditions to support
|
||||||
|
the same minimum length.
|
||||||
|
|
||||||
|
While future versions of this code will never lower
|
||||||
|
this limit, they may opt to raise it.
|
||||||
|
*/
|
||||||
|
static constexpr std::size_t maxPreimageLength = 128;
|
||||||
|
|
||||||
|
/** Parse the payload for a PreimageSha256 condition
|
||||||
|
|
||||||
|
@param s A slice containing the DER encoded payload
|
||||||
|
@param ec indicates success or failure of the operation
|
||||||
|
@return the preimage, if successful; empty pointer otherwise.
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
std::unique_ptr<Fulfillment>
|
||||||
|
deserialize(
|
||||||
|
Slice s,
|
||||||
|
std::error_code& ec)
|
||||||
|
{
|
||||||
|
// Per the RFC, a preimage fulfulliment is defined as
|
||||||
|
// follows:
|
||||||
|
//
|
||||||
|
// PreimageFulfillment ::= SEQUENCE {
|
||||||
|
// preimage OCTET STRING
|
||||||
|
// }
|
||||||
|
|
||||||
|
using namespace der;
|
||||||
|
|
||||||
|
auto p = parsePreamble(s, ec);
|
||||||
|
if (ec)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (!isPrimitive(p) || !isContextSpecific(p))
|
||||||
|
{
|
||||||
|
ec = error::incorrect_encoding;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p.tag != 0)
|
||||||
|
{
|
||||||
|
ec = error::unexpected_tag;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.size() != p.length)
|
||||||
|
{
|
||||||
|
ec = error::trailing_garbage;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s.size() > maxPreimageLength)
|
||||||
|
{
|
||||||
|
ec = error::preimage_too_long;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto b = parseOctetString(s, p.length, ec);
|
||||||
|
if (ec)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return std::make_unique<PreimageSha256>(std::move(b));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Buffer payload_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
PreimageSha256(Buffer&& b) noexcept
|
||||||
|
: payload_(std::move(b))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PreimageSha256(Slice s) noexcept
|
||||||
|
: payload_(s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Type
|
||||||
|
type() const override
|
||||||
|
{
|
||||||
|
return Type::preimageSha256;
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer
|
||||||
|
fingerprint() const override
|
||||||
|
{
|
||||||
|
sha256_hasher h;
|
||||||
|
h(payload_.data(), payload_.size());
|
||||||
|
auto const d = static_cast<sha256_hasher::result_type>(h);
|
||||||
|
return{ d.data(), d.size() };
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t
|
||||||
|
cost() const override
|
||||||
|
{
|
||||||
|
return static_cast<std::uint32_t>(payload_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
Condition
|
||||||
|
condition() const override
|
||||||
|
{
|
||||||
|
return { type(), cost(), fingerprint() };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
validate(Slice) const override
|
||||||
|
{
|
||||||
|
// Perhaps counterintuitively, the message isn't
|
||||||
|
// relevant.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,314 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
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/RsaSha256.h>
|
|
||||||
#include <ripple/conditions/impl/base64.h>
|
|
||||||
#include <ripple/protocol/digest.h>
|
|
||||||
#include <openssl/bn.h>
|
|
||||||
#include <openssl/evp.h>
|
|
||||||
#include <openssl/rsa.h>
|
|
||||||
#include <openssl/pem.h>
|
|
||||||
#include <openssl/sha.h>
|
|
||||||
|
|
||||||
#include <boost/algorithm/clamp.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
namespace cryptoconditions {
|
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
struct rsa_deleter
|
|
||||||
{
|
|
||||||
void operator() (RSA* rsa) const
|
|
||||||
{
|
|
||||||
RSA_free (rsa);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using RsaKey = std::unique_ptr<RSA, rsa_deleter>;
|
|
||||||
|
|
||||||
struct bn_deleter
|
|
||||||
{
|
|
||||||
void operator() (BIGNUM* bn) const
|
|
||||||
{
|
|
||||||
BN_free (bn);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using BigNum = std::unique_ptr<BIGNUM, bn_deleter>;
|
|
||||||
|
|
||||||
// Check whether the public modulus meets the length
|
|
||||||
// requirements imposed by section 4.4.1 of the RFC.
|
|
||||||
bool
|
|
||||||
checkModulusLength (int len)
|
|
||||||
{
|
|
||||||
if (len <= 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return len == boost::algorithm::clamp(len, 128, 512);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
signHelper (
|
|
||||||
RSA* key,
|
|
||||||
Slice message,
|
|
||||||
Buffer& modulus,
|
|
||||||
Buffer& signature)
|
|
||||||
{
|
|
||||||
int const keySize = RSA_size(key);
|
|
||||||
if (!checkModulusLength (keySize))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
sha256_hasher h;
|
|
||||||
h (message.data(), message.size());
|
|
||||||
auto digest = static_cast<sha256_hasher::result_type>(h);
|
|
||||||
|
|
||||||
Buffer buf;
|
|
||||||
|
|
||||||
// Pad the result (-1 -> use hash length as salt length)
|
|
||||||
if (!RSA_padding_add_PKCS1_PSS(key,
|
|
||||||
buf.alloc(keySize), digest.data(),
|
|
||||||
EVP_sha256(), -1))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Sign - we've manually padded the input already.
|
|
||||||
auto ret = RSA_private_encrypt(keySize, buf.data(),
|
|
||||||
signature.alloc (buf.size()), key, RSA_NO_PADDING);
|
|
||||||
|
|
||||||
if (ret == -1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
BN_bn2bin (key->n, modulus.alloc(BN_num_bytes (key->n)));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
validateHelper (
|
|
||||||
RSA* key,
|
|
||||||
Slice message,
|
|
||||||
Slice signature)
|
|
||||||
{
|
|
||||||
int const keySize = RSA_size(key);
|
|
||||||
if (!checkModulusLength (keySize))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Buffer buf;
|
|
||||||
|
|
||||||
auto ret = RSA_public_decrypt(
|
|
||||||
keySize,
|
|
||||||
signature.data(),
|
|
||||||
buf.alloc (keySize),
|
|
||||||
key,
|
|
||||||
RSA_NO_PADDING);
|
|
||||||
|
|
||||||
if (ret == -1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
sha256_hasher h;
|
|
||||||
h (message.data(), message.size());
|
|
||||||
auto digest = static_cast<sha256_hasher::result_type>(h);
|
|
||||||
|
|
||||||
return RSA_verify_PKCS1_PSS(key, digest.data(), EVP_sha256(), buf.data(), -1) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
parsePayloadHelper(
|
|
||||||
Slice s,
|
|
||||||
Buffer& modulus,
|
|
||||||
Buffer& signature)
|
|
||||||
{
|
|
||||||
auto start = s.data ();
|
|
||||||
auto finish = s.data () + s.size();
|
|
||||||
|
|
||||||
std::size_t len;
|
|
||||||
|
|
||||||
std::tie (start, len) = oer::decode_length (
|
|
||||||
start, finish);
|
|
||||||
|
|
||||||
if (std::distance (start, finish) < len)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::memcpy (modulus.alloc (len), start, len);
|
|
||||||
std::advance (start, len);
|
|
||||||
|
|
||||||
std::tie (start, len) = oer::decode_length (
|
|
||||||
start, finish);
|
|
||||||
|
|
||||||
if (std::distance (start, finish) < len)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
std::memcpy (signature.alloc (len), start, len);
|
|
||||||
std::advance (start, len);
|
|
||||||
|
|
||||||
// Per 4.4.2 of the RFC we must check whether the
|
|
||||||
// signature and modulus consist of the same number
|
|
||||||
// of octets:
|
|
||||||
if (signature.size() != modulus.size())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Enforce constraints from the RFC:
|
|
||||||
BigNum sig (BN_bin2bn (
|
|
||||||
signature.data(), signature.size(), nullptr));
|
|
||||||
|
|
||||||
BigNum mod (BN_bin2bn (
|
|
||||||
modulus.data(), modulus.size(), nullptr));
|
|
||||||
|
|
||||||
if (!sig || !mod)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Per 4.4.1 of the RFC we are required to reject
|
|
||||||
// moduli smaller than 128 bytes or greater than
|
|
||||||
// 512 bytes.
|
|
||||||
int modBytes = BN_num_bytes (mod.get());
|
|
||||||
|
|
||||||
if (!checkModulusLength (modBytes))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Per 4.4.2 of the RFC we must check that the signature
|
|
||||||
// is numerically less than the modulus:
|
|
||||||
return BN_cmp (sig.get(), mod.get()) < 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Condition
|
|
||||||
RsaSha256::condition() const
|
|
||||||
{
|
|
||||||
std::vector<std::uint8_t> m;
|
|
||||||
m.reserve (1024);
|
|
||||||
|
|
||||||
oer::encode_octetstring (
|
|
||||||
modulus_.size(),
|
|
||||||
modulus_.data(),
|
|
||||||
modulus_.data() + modulus_.size(),
|
|
||||||
std::back_inserter(m));
|
|
||||||
|
|
||||||
sha256_hasher h;
|
|
||||||
h (m.data(), m.size());
|
|
||||||
|
|
||||||
Condition cc;
|
|
||||||
cc.type = type();
|
|
||||||
cc.featureBitmask = features();
|
|
||||||
cc.maxFulfillmentLength = payloadSize();
|
|
||||||
|
|
||||||
cc.fingerprint = static_cast<sha256_hasher::result_type>(h);
|
|
||||||
|
|
||||||
return cc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::size_t
|
|
||||||
RsaSha256::payloadSize () const
|
|
||||||
{
|
|
||||||
return
|
|
||||||
oer::predict_octetstring_size (modulus_.size()) +
|
|
||||||
oer::predict_octetstring_size (signature_.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer
|
|
||||||
RsaSha256::payload() const
|
|
||||||
{
|
|
||||||
Buffer b (payloadSize());
|
|
||||||
|
|
||||||
auto out = oer::encode_octetstring (
|
|
||||||
modulus_.size(),
|
|
||||||
modulus_.data(),
|
|
||||||
modulus_.data() + modulus_.size(),
|
|
||||||
b.data());
|
|
||||||
|
|
||||||
oer::encode_octetstring (
|
|
||||||
signature_.size(),
|
|
||||||
signature_.data(),
|
|
||||||
signature_.data() + modulus_.size(),
|
|
||||||
out);
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
RsaSha256::validate (Slice data) const
|
|
||||||
{
|
|
||||||
if (!ok())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
detail::RsaKey rsa (RSA_new());
|
|
||||||
|
|
||||||
rsa->n = BN_new();
|
|
||||||
BN_bin2bn(modulus_.data(), modulus_.size(), rsa->n);
|
|
||||||
|
|
||||||
rsa->e = BN_new();
|
|
||||||
BN_set_word (rsa->e, 65537);
|
|
||||||
|
|
||||||
return detail::validateHelper (rsa.get(), data, signature_);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Sign the given message with an RSA key */
|
|
||||||
bool
|
|
||||||
RsaSha256::sign (
|
|
||||||
std::string const& key,
|
|
||||||
Slice message)
|
|
||||||
{
|
|
||||||
// This ugly const_cast/reinterpret_cast is needed
|
|
||||||
// on some machines. Although the documentation
|
|
||||||
// suggests that the function accepts a void const*
|
|
||||||
// argument, apparently some platforms have OpenSSL
|
|
||||||
// libraries that are up-to-date but accept void*.
|
|
||||||
auto bio = BIO_new_mem_buf(
|
|
||||||
const_cast<void*>(static_cast<void const*>(key.data())),
|
|
||||||
key.size());
|
|
||||||
|
|
||||||
if (!bio)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
detail::RsaKey rsa (PEM_read_bio_RSAPrivateKey(
|
|
||||||
bio, NULL, NULL, NULL));
|
|
||||||
|
|
||||||
BIO_free(bio);
|
|
||||||
|
|
||||||
if (!rsa)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (detail::signHelper (rsa.get(), message, modulus_, signature_))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
modulus_.clear();
|
|
||||||
signature_.clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
RsaSha256::parsePayload (Slice s)
|
|
||||||
{
|
|
||||||
// The payload may not be empty
|
|
||||||
if (!s.empty() && detail::parsePayloadHelper (s, modulus_, signature_))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Clear the state
|
|
||||||
modulus_.clear();
|
|
||||||
signature_.clear();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,204 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
143
src/ripple/conditions/impl/error.cpp
Normal file
143
src/ripple/conditions/impl/error.cpp
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
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/impl/error.h>
|
||||||
|
#include <system_error>
|
||||||
|
#include <string>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace ripple {
|
||||||
|
namespace cryptoconditions {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
class cryptoconditions_error_category
|
||||||
|
: public std::error_category
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const char*
|
||||||
|
name() const noexcept override
|
||||||
|
{
|
||||||
|
return "cryptoconditions";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
message(int ev) const override
|
||||||
|
{
|
||||||
|
switch (static_cast<error>(ev))
|
||||||
|
{
|
||||||
|
case error::unsupported_type:
|
||||||
|
return "Specification: Requested type not supported.";
|
||||||
|
|
||||||
|
case error::unsupported_subtype:
|
||||||
|
return "Specification: Requested subtype not supported.";
|
||||||
|
|
||||||
|
case error::unknown_type:
|
||||||
|
return "Specification: Requested type not recognized.";
|
||||||
|
|
||||||
|
case error::unknown_subtype:
|
||||||
|
return "Specification: Requested subtypes not recognized.";
|
||||||
|
|
||||||
|
case error::fingerprint_size:
|
||||||
|
return "Specification: Incorrect fingerprint size.";
|
||||||
|
|
||||||
|
case error::incorrect_encoding:
|
||||||
|
return "Specification: Incorrect encoding.";
|
||||||
|
|
||||||
|
case error::trailing_garbage:
|
||||||
|
return "Bad buffer: contains trailing garbage.";
|
||||||
|
|
||||||
|
case error::buffer_empty:
|
||||||
|
return "Bad buffer: no data.";
|
||||||
|
|
||||||
|
case error::buffer_overfull:
|
||||||
|
return "Bad buffer: overfull.";
|
||||||
|
|
||||||
|
case error::buffer_underfull:
|
||||||
|
return "Bad buffer: underfull.";
|
||||||
|
|
||||||
|
case error::malformed_encoding:
|
||||||
|
return "Malformed DER encoding.";
|
||||||
|
|
||||||
|
case error::unexpected_tag:
|
||||||
|
return "Malformed DER encoding: Unexpected tag.";
|
||||||
|
|
||||||
|
case error::short_preamble:
|
||||||
|
return "Malformed DER encoding: Short preamble.";
|
||||||
|
|
||||||
|
case error::long_tag:
|
||||||
|
return "Implementation limit: Overlong tag.";
|
||||||
|
|
||||||
|
case error::large_size:
|
||||||
|
return "Implementation limit: Large payload.";
|
||||||
|
|
||||||
|
case error::preimage_too_long:
|
||||||
|
return "Implementation limit: Specified preimage is too long.";
|
||||||
|
|
||||||
|
case error::generic:
|
||||||
|
default:
|
||||||
|
return "generic error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::error_condition
|
||||||
|
default_error_condition(int ev) const noexcept override
|
||||||
|
{
|
||||||
|
return std::error_condition{ ev, *this };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
equivalent(
|
||||||
|
int ev,
|
||||||
|
std::error_condition const& condition) const noexcept override
|
||||||
|
{
|
||||||
|
return &condition.category() == this &&
|
||||||
|
condition.value() == ev;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
equivalent(
|
||||||
|
std::error_code const& error,
|
||||||
|
int ev) const noexcept override
|
||||||
|
{
|
||||||
|
return &error.category() == this &&
|
||||||
|
error.value() == ev;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline
|
||||||
|
std::error_category const&
|
||||||
|
get_cryptoconditions_error_category()
|
||||||
|
{
|
||||||
|
static cryptoconditions_error_category const cat{};
|
||||||
|
return cat;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // detail
|
||||||
|
|
||||||
|
std::error_code
|
||||||
|
make_error_code(error ev)
|
||||||
|
{
|
||||||
|
return std::error_code {
|
||||||
|
static_cast<std::underlying_type<error>::type>(ev),
|
||||||
|
detail::get_cryptoconditions_error_category()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,67 +17,51 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#ifndef RIPPLE_CONDITIONS_RSA_SHA256_H
|
#ifndef RIPPLE_CONDITIONS_ERROR_H
|
||||||
#define RIPPLE_CONDITIONS_RSA_SHA256_H
|
#define RIPPLE_CONDITIONS_ERROR_H
|
||||||
|
|
||||||
#include <ripple/conditions/Condition.h>
|
#include <system_error>
|
||||||
#include <ripple/conditions/Fulfillment.h>
|
#include <string>
|
||||||
#include <ripple/basics/Buffer.h>
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace cryptoconditions {
|
namespace cryptoconditions {
|
||||||
|
|
||||||
class RsaSha256 final
|
enum class error
|
||||||
: public Fulfillment
|
|
||||||
{
|
{
|
||||||
Buffer modulus_;
|
generic = 1,
|
||||||
Buffer signature_;
|
unsupported_type,
|
||||||
|
unsupported_subtype,
|
||||||
public:
|
unknown_type,
|
||||||
RsaSha256 () = default;
|
unknown_subtype,
|
||||||
|
fingerprint_size,
|
||||||
Condition
|
incorrect_encoding,
|
||||||
condition() const override;
|
trailing_garbage,
|
||||||
|
buffer_empty,
|
||||||
std::uint16_t
|
buffer_overfull,
|
||||||
type () const override
|
buffer_underfull,
|
||||||
{
|
malformed_encoding,
|
||||||
return condition_rsa_sha256;
|
short_preamble,
|
||||||
}
|
unexpected_tag,
|
||||||
|
long_tag,
|
||||||
std::uint32_t
|
large_size,
|
||||||
features () const override
|
preimage_too_long
|
||||||
{
|
|
||||||
return feature_rsa_pss | feature_sha256;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
ok () const override
|
|
||||||
{
|
|
||||||
return !modulus_.empty() && !signature_.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t
|
|
||||||
payloadSize () const override;
|
|
||||||
|
|
||||||
Buffer
|
|
||||||
payload() const override;
|
|
||||||
|
|
||||||
bool
|
|
||||||
validate (Slice data) const override;
|
|
||||||
|
|
||||||
/** Sign the given message with an RSA key */
|
|
||||||
bool sign (
|
|
||||||
std::string const& key,
|
|
||||||
Slice message);
|
|
||||||
|
|
||||||
bool
|
|
||||||
parsePayload (Slice s) override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
std::error_code
|
||||||
|
make_error_code(error ev);
|
||||||
|
|
||||||
}
|
} // cryptoconditions
|
||||||
|
} // ripple
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct is_error_code_enum<ripple::cryptoconditions::error>
|
||||||
|
{
|
||||||
|
static bool const value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // std
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -21,6 +21,9 @@
|
|||||||
#define RIPPLE_CONDITIONS_UTILS_H
|
#define RIPPLE_CONDITIONS_UTILS_H
|
||||||
|
|
||||||
#include <ripple/basics/strHex.h>
|
#include <ripple/basics/strHex.h>
|
||||||
|
#include <ripple/conditions/impl/error.h>
|
||||||
|
#include <boost/dynamic_bitset.hpp>
|
||||||
|
#include <limits>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -31,338 +34,208 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace cryptoconditions {
|
namespace cryptoconditions {
|
||||||
|
|
||||||
inline
|
// A collection of functions to decode binary blobs
|
||||||
std::string
|
// encoded with X.690 Distinguished Encoding Rules.
|
||||||
hexstr (std::vector<std::uint8_t> const& data)
|
//
|
||||||
|
// This is a very trivial decoder and only implements
|
||||||
|
// the bare minimum needed to support PreimageSha256.
|
||||||
|
namespace der {
|
||||||
|
|
||||||
|
// The preamble encapsulates the DER identifier and
|
||||||
|
// length octets:
|
||||||
|
struct Preamble
|
||||||
{
|
{
|
||||||
std::string s;
|
std::uint8_t type = 0;
|
||||||
s.reserve (data.size() * 2);
|
std::size_t tag = 0;
|
||||||
|
std::size_t length = 0;
|
||||||
|
};
|
||||||
|
|
||||||
for (auto d : data)
|
inline
|
||||||
{
|
bool
|
||||||
s.push_back (charHex (d >> 4));
|
isPrimitive(Preamble const& p)
|
||||||
s.push_back (charHex (d & 15));
|
{
|
||||||
}
|
return (p.type & 0x20) == 0;
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
std::vector<std::uint8_t>
|
bool
|
||||||
hexblob (std::string const& s)
|
isConstructed(Preamble const& p)
|
||||||
{
|
{
|
||||||
std::vector<std::uint8_t> result;
|
return !isPrimitive(p);
|
||||||
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
|
inline
|
||||||
OutputIt
|
bool
|
||||||
encode_length (std::size_t len, OutputIt out)
|
isUniversal(Preamble const& p)
|
||||||
{
|
{
|
||||||
if (len <= 0x7F)
|
return (p.type & 0xC0) == 0;
|
||||||
{
|
|
||||||
*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
|
inline
|
||||||
std::size_t
|
bool
|
||||||
predict_octetstring_size(std::size_t size)
|
isApplication(Preamble const& p)
|
||||||
{
|
{
|
||||||
// Alternatively, always guess 4 + size and call it a day?
|
return (p.type & 0xC0) == 0x40;
|
||||||
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) */
|
inline
|
||||||
template <class InputIt, class OutputIt>
|
bool
|
||||||
OutputIt
|
isContextSpecific(Preamble const& p)
|
||||||
encode_octetstring(std::size_t size, InputIt begin, InputIt end, OutputIt out)
|
|
||||||
{
|
{
|
||||||
// This will encode the length first, followed by the
|
return (p.type & 0xC0) == 0x80;
|
||||||
// payload octets:
|
|
||||||
return encode_octetstring (
|
|
||||||
begin,
|
|
||||||
end,
|
|
||||||
oer::encode_length (size, out));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Integer, class OutputIt>
|
inline
|
||||||
std::enable_if_t<std::is_unsigned<Integer>::value>
|
bool
|
||||||
encode_varuint (Integer value, OutputIt out)
|
isPrivate(Preamble const& p)
|
||||||
{
|
{
|
||||||
auto count = [](Integer n)
|
return (p.type & 0xC0) == 0xC0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
Preamble
|
||||||
|
parsePreamble(Slice& s, std::error_code& ec)
|
||||||
|
{
|
||||||
|
Preamble p;
|
||||||
|
|
||||||
|
if (s.size() < 2)
|
||||||
{
|
{
|
||||||
std::size_t c = 0;
|
ec = error::short_preamble;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
do
|
p.type = s[0] & 0xE0;
|
||||||
|
p.tag = s[0] & 0x1F;
|
||||||
|
|
||||||
|
s += 1;
|
||||||
|
|
||||||
|
if (p.tag == 0x1F)
|
||||||
|
{ // Long tag form, which we do not support:
|
||||||
|
ec = error::long_tag;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.length = s[0];
|
||||||
|
s += 1;
|
||||||
|
|
||||||
|
if (p.length & 0x80)
|
||||||
|
{ // Long form length:
|
||||||
|
std::size_t const cnt = p.length & 0x7F;
|
||||||
|
|
||||||
|
if (cnt == 0)
|
||||||
{
|
{
|
||||||
n >>= 8;
|
ec = error::malformed_encoding;
|
||||||
++c;
|
return p;
|
||||||
} while (n);
|
}
|
||||||
|
|
||||||
return c;
|
if (cnt > sizeof(std::size_t))
|
||||||
};
|
{
|
||||||
|
ec = error::large_size;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t c = count (value);
|
if (cnt > s.size())
|
||||||
|
{
|
||||||
|
ec = error::short_preamble;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
out = encode_length (c, out);
|
p.length = 0;
|
||||||
|
|
||||||
while(c--)
|
for (std::size_t i = 0; i != cnt; ++i)
|
||||||
{
|
p.length = (p.length << 8) + s[i];
|
||||||
*out++ = static_cast<std::uint8_t>(
|
|
||||||
(value >> (c * 8)) & 0xFF);
|
s += cnt;
|
||||||
|
|
||||||
|
if (p.length == 0)
|
||||||
|
{
|
||||||
|
ec = error::malformed_encoding;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Integer, class InputIt>
|
inline
|
||||||
std::enable_if_t<std::is_unsigned<Integer>::value, std::pair<InputIt, Integer>>
|
Buffer
|
||||||
decode_varuint (InputIt begin, InputIt end)
|
parseOctetString(Slice& s, std::uint32_t count, std::error_code& ec)
|
||||||
{
|
{
|
||||||
auto y = decode_length (begin, end);
|
if (count > s.size())
|
||||||
|
{
|
||||||
|
ec = error::buffer_underfull;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
if (y.second > sizeof(Integer))
|
if (count > 65535)
|
||||||
Throw<std::length_error>("Encoded integer exceeds allowable range: " + std::to_string(y.second));
|
{
|
||||||
|
ec = error::large_size;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Integer x = 0;
|
Buffer b(s.data(), count);
|
||||||
|
s += count;
|
||||||
for (std::size_t i = 0; i != y.second; ++i)
|
return b;
|
||||||
x = (x << 8) + *y.first++;
|
|
||||||
|
|
||||||
return { y.first, x };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Integer>
|
||||||
|
Integer
|
||||||
|
parseInteger(Slice& s, std::size_t count, std::error_code& ec)
|
||||||
|
{
|
||||||
|
Integer v{0};
|
||||||
|
|
||||||
|
if (s.empty())
|
||||||
|
{
|
||||||
|
// can never have zero sized integers
|
||||||
|
ec = error::malformed_encoding;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count > s.size())
|
||||||
|
{
|
||||||
|
ec = error::buffer_underfull;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool isSigned = std::numeric_limits<Integer>::is_signed;
|
||||||
|
// unsigned types may have a leading zero octet
|
||||||
|
const size_t maxLength = isSigned ? sizeof(Integer) : sizeof(Integer) + 1;
|
||||||
|
if (count > maxLength)
|
||||||
|
{
|
||||||
|
ec = error::large_size;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSigned && (s[0] & (1 << 7)))
|
||||||
|
{
|
||||||
|
// trying to decode a negative number into a positive value
|
||||||
|
ec = error::malformed_encoding;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isSigned && count == sizeof(Integer) + 1 && s[0])
|
||||||
|
{
|
||||||
|
// since integers are coded as two's complement, the first byte may
|
||||||
|
// be zero for unsigned reps
|
||||||
|
ec = error::malformed_encoding;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = 0;
|
||||||
|
for (size_t i = 0; i < count; ++i)
|
||||||
|
v = (v << 8) | (s[i] & 0xff);
|
||||||
|
|
||||||
|
if (isSigned && (s[0] & (1 << 7)))
|
||||||
|
{
|
||||||
|
for (int i = count; i < sizeof(Integer); ++i)
|
||||||
|
v |= (Integer(0xff) << (8 * i));
|
||||||
|
}
|
||||||
|
s += count;
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
} // der
|
||||||
|
} // cryptoconditions
|
||||||
|
} // ripple
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -623,7 +623,7 @@ ApplyStateTable::threadOwners (ReadView const& base,
|
|||||||
// Nothing to do
|
// Nothing to do
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ltSUSPAY:
|
case ltESCROW:
|
||||||
{
|
{
|
||||||
threadTx (base, meta, (*sle)[sfAccount], mods, j);
|
threadTx (base, meta, (*sle)[sfAccount], mods, j);
|
||||||
threadTx (base, meta, (*sle)[sfDestination], mods, j);
|
threadTx (base, meta, (*sle)[sfDestination], mods, j);
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ feature (const char* name);
|
|||||||
|
|
||||||
extern uint256 const featureMultiSign;
|
extern uint256 const featureMultiSign;
|
||||||
extern uint256 const featureTickets;
|
extern uint256 const featureTickets;
|
||||||
extern uint256 const featureSusPay;
|
|
||||||
extern uint256 const featureTrustSetAuth;
|
extern uint256 const featureTrustSetAuth;
|
||||||
extern uint256 const featureFeeEscalation;
|
extern uint256 const featureFeeEscalation;
|
||||||
extern uint256 const featureOwnerPaysFee;
|
extern uint256 const featureOwnerPaysFee;
|
||||||
@@ -47,6 +46,8 @@ extern uint256 const featureFlow;
|
|||||||
extern uint256 const featureCryptoConditions;
|
extern uint256 const featureCryptoConditions;
|
||||||
extern uint256 const featureTickSize;
|
extern uint256 const featureTickSize;
|
||||||
extern uint256 const featureRIPD1368;
|
extern uint256 const featureRIPD1368;
|
||||||
|
extern uint256 const featureEscrow;
|
||||||
|
extern uint256 const featureCryptoConditionsSuite;
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|
||||||
|
|||||||
@@ -234,9 +234,9 @@ Keylet page (uint256 const& key)
|
|||||||
return { ltDIR_NODE, key };
|
return { ltDIR_NODE, key };
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A SuspendedPayment */
|
/** An escrow entry */
|
||||||
Keylet
|
Keylet
|
||||||
susPay (AccountID const& source, std::uint32_t seq);
|
escrow (AccountID const& source, std::uint32_t seq);
|
||||||
|
|
||||||
/** A PaymentChannel */
|
/** A PaymentChannel */
|
||||||
Keylet
|
Keylet
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ enum LedgerEntryType
|
|||||||
|
|
||||||
ltFEE_SETTINGS = 's',
|
ltFEE_SETTINGS = 's',
|
||||||
|
|
||||||
ltSUSPAY = 'u',
|
ltESCROW = 'u',
|
||||||
|
|
||||||
// Simple unidirection xrp channel
|
// Simple unidirection xrp channel
|
||||||
ltPAYCHAN = 'x',
|
ltPAYCHAN = 'x',
|
||||||
@@ -105,7 +105,7 @@ enum LedgerNameSpace
|
|||||||
spaceBookDir = 'B', // Directory of order books.
|
spaceBookDir = 'B', // Directory of order books.
|
||||||
spaceContract = 'c',
|
spaceContract = 'c',
|
||||||
spaceSkipList = 's',
|
spaceSkipList = 's',
|
||||||
spaceSusPay = 'u',
|
spaceEscrow = 'u',
|
||||||
spaceAmendment = 'f',
|
spaceAmendment = 'f',
|
||||||
spaceFee = 'e',
|
spaceFee = 'e',
|
||||||
spaceTicket = 'T',
|
spaceTicket = 'T',
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ enum TxType
|
|||||||
ttINVALID = -1,
|
ttINVALID = -1,
|
||||||
|
|
||||||
ttPAYMENT = 0,
|
ttPAYMENT = 0,
|
||||||
ttSUSPAY_CREATE = 1,
|
ttESCROW_CREATE = 1,
|
||||||
ttSUSPAY_FINISH = 2,
|
ttESCROW_FINISH = 2,
|
||||||
ttACCOUNT_SET = 3,
|
ttACCOUNT_SET = 3,
|
||||||
ttSUSPAY_CANCEL = 4,
|
ttESCROW_CANCEL = 4,
|
||||||
ttREGULAR_KEY_SET = 5,
|
ttREGULAR_KEY_SET = 5,
|
||||||
ttNICKNAME_SET = 6, // open
|
ttNICKNAME_SET = 6, // open
|
||||||
ttOFFER_CREATE = 7,
|
ttOFFER_CREATE = 7,
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ feature (const char* name)
|
|||||||
|
|
||||||
uint256 const featureMultiSign = feature("MultiSign");
|
uint256 const featureMultiSign = feature("MultiSign");
|
||||||
uint256 const featureTickets = feature("Tickets");
|
uint256 const featureTickets = feature("Tickets");
|
||||||
uint256 const featureSusPay = feature("SusPay");
|
|
||||||
uint256 const featureTrustSetAuth = feature("TrustSetAuth");
|
uint256 const featureTrustSetAuth = feature("TrustSetAuth");
|
||||||
uint256 const featureFeeEscalation = feature("FeeEscalation");
|
uint256 const featureFeeEscalation = feature("FeeEscalation");
|
||||||
uint256 const featureOwnerPaysFee = feature("OwnerPaysFee");
|
uint256 const featureOwnerPaysFee = feature("OwnerPaysFee");
|
||||||
@@ -58,5 +57,7 @@ uint256 const featureFlow = feature("Flow");
|
|||||||
uint256 const featureCryptoConditions = feature("CryptoConditions");
|
uint256 const featureCryptoConditions = feature("CryptoConditions");
|
||||||
uint256 const featureTickSize = feature("TickSize");
|
uint256 const featureTickSize = feature("TickSize");
|
||||||
uint256 const featureRIPD1368 = feature("RIPD1368");
|
uint256 const featureRIPD1368 = feature("RIPD1368");
|
||||||
|
uint256 const featureEscrow = feature("Escrow");
|
||||||
|
uint256 const featureCryptoConditionsSuite = feature("CryptoConditionsSuite");
|
||||||
|
|
||||||
} // ripple
|
} // ripple
|
||||||
|
|||||||
@@ -313,14 +313,14 @@ Keylet page(Keylet const& root,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Keylet
|
Keylet
|
||||||
susPay (AccountID const& source, std::uint32_t seq)
|
escrow (AccountID const& source, std::uint32_t seq)
|
||||||
{
|
{
|
||||||
sha512_half_hasher h;
|
sha512_half_hasher h;
|
||||||
using beast::hash_append;
|
using beast::hash_append;
|
||||||
hash_append(h, spaceSusPay);
|
hash_append(h, spaceEscrow);
|
||||||
hash_append(h, source);
|
hash_append(h, source);
|
||||||
hash_append(h, seq);
|
hash_append(h, seq);
|
||||||
return { ltSUSPAY, static_cast<uint256>(h) };
|
return { ltESCROW, static_cast<uint256>(h) };
|
||||||
}
|
}
|
||||||
|
|
||||||
Keylet
|
Keylet
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ LedgerFormats::LedgerFormats ()
|
|||||||
<< SOElement (sfHighQualityOut, SOE_OPTIONAL)
|
<< SOElement (sfHighQualityOut, SOE_OPTIONAL)
|
||||||
;
|
;
|
||||||
|
|
||||||
add ("SuspendedPayment", ltSUSPAY) <<
|
add ("Escrow", ltESCROW) <<
|
||||||
SOElement (sfAccount, SOE_REQUIRED) <<
|
SOElement (sfAccount, SOE_REQUIRED) <<
|
||||||
SOElement (sfDestination, SOE_REQUIRED) <<
|
SOElement (sfDestination, SOE_REQUIRED) <<
|
||||||
SOElement (sfAmount, SOE_REQUIRED) <<
|
SOElement (sfAmount, SOE_REQUIRED) <<
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ TxFormats::TxFormats ()
|
|||||||
<< SOElement (sfDeliverMin, SOE_OPTIONAL)
|
<< SOElement (sfDeliverMin, SOE_OPTIONAL)
|
||||||
;
|
;
|
||||||
|
|
||||||
add ("SuspendedPaymentCreate", ttSUSPAY_CREATE) <<
|
add ("EscrowCreate", ttESCROW_CREATE) <<
|
||||||
SOElement (sfDestination, SOE_REQUIRED) <<
|
SOElement (sfDestination, SOE_REQUIRED) <<
|
||||||
SOElement (sfAmount, SOE_REQUIRED) <<
|
SOElement (sfAmount, SOE_REQUIRED) <<
|
||||||
SOElement (sfCondition, SOE_OPTIONAL) <<
|
SOElement (sfCondition, SOE_OPTIONAL) <<
|
||||||
@@ -75,13 +75,13 @@ TxFormats::TxFormats ()
|
|||||||
SOElement (sfFinishAfter, SOE_OPTIONAL) <<
|
SOElement (sfFinishAfter, SOE_OPTIONAL) <<
|
||||||
SOElement (sfDestinationTag, SOE_OPTIONAL);
|
SOElement (sfDestinationTag, SOE_OPTIONAL);
|
||||||
|
|
||||||
add ("SuspendedPaymentFinish", ttSUSPAY_FINISH) <<
|
add ("EscrowFinish", ttESCROW_FINISH) <<
|
||||||
SOElement (sfOwner, SOE_REQUIRED) <<
|
SOElement (sfOwner, SOE_REQUIRED) <<
|
||||||
SOElement (sfOfferSequence, SOE_REQUIRED) <<
|
SOElement (sfOfferSequence, SOE_REQUIRED) <<
|
||||||
SOElement (sfFulfillment, SOE_OPTIONAL) <<
|
SOElement (sfFulfillment, SOE_OPTIONAL) <<
|
||||||
SOElement (sfCondition, SOE_OPTIONAL);
|
SOElement (sfCondition, SOE_OPTIONAL);
|
||||||
|
|
||||||
add ("SuspendedPaymentCancel", ttSUSPAY_CANCEL) <<
|
add ("EscrowCancel", ttESCROW_CANCEL) <<
|
||||||
SOElement (sfOwner, SOE_REQUIRED) <<
|
SOElement (sfOwner, SOE_REQUIRED) <<
|
||||||
SOElement (sfOfferSequence, SOE_REQUIRED);
|
SOElement (sfOfferSequence, SOE_REQUIRED);
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <ripple/app/tx/impl/Change.cpp>
|
#include <ripple/app/tx/impl/Change.cpp>
|
||||||
#include <ripple/app/tx/impl/CreateOffer.cpp>
|
#include <ripple/app/tx/impl/CreateOffer.cpp>
|
||||||
#include <ripple/app/tx/impl/CreateTicket.cpp>
|
#include <ripple/app/tx/impl/CreateTicket.cpp>
|
||||||
|
#include <ripple/app/tx/impl/Escrow.cpp>
|
||||||
#include <ripple/app/tx/impl/OfferStream.cpp>
|
#include <ripple/app/tx/impl/OfferStream.cpp>
|
||||||
#include <ripple/app/tx/impl/Payment.cpp>
|
#include <ripple/app/tx/impl/Payment.cpp>
|
||||||
#include <ripple/app/tx/impl/PayChan.cpp>
|
#include <ripple/app/tx/impl/PayChan.cpp>
|
||||||
@@ -35,7 +36,6 @@
|
|||||||
#include <ripple/app/tx/impl/SetSignerList.cpp>
|
#include <ripple/app/tx/impl/SetSignerList.cpp>
|
||||||
#include <ripple/app/tx/impl/SetTrust.cpp>
|
#include <ripple/app/tx/impl/SetTrust.cpp>
|
||||||
#include <ripple/app/tx/impl/SignerEntries.cpp>
|
#include <ripple/app/tx/impl/SignerEntries.cpp>
|
||||||
#include <ripple/app/tx/impl/SusPay.cpp>
|
|
||||||
#include <ripple/app/tx/impl/Taker.cpp>
|
#include <ripple/app/tx/impl/Taker.cpp>
|
||||||
#include <ripple/app/tx/impl/ApplyContext.cpp>
|
#include <ripple/app/tx/impl/ApplyContext.cpp>
|
||||||
#include <ripple/app/tx/impl/Transactor.cpp>
|
#include <ripple/app/tx/impl/Transactor.cpp>
|
||||||
|
|||||||
@@ -21,5 +21,4 @@
|
|||||||
|
|
||||||
#include <ripple/conditions/impl/Condition.cpp>
|
#include <ripple/conditions/impl/Condition.cpp>
|
||||||
#include <ripple/conditions/impl/Fulfillment.cpp>
|
#include <ripple/conditions/impl/Fulfillment.cpp>
|
||||||
#include <ripple/conditions/impl/Ed25519.cpp>
|
#include <ripple/conditions/impl/error.cpp>
|
||||||
#include <ripple/conditions/impl/RsaSha256.cpp>
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
/*
|
/*
|
||||||
This file is part of rippled: https://github.com/ripple/rippled
|
This file is part of rippled: https://github.com/ripple/rippled
|
||||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||||
@@ -28,67 +28,48 @@
|
|||||||
namespace ripple {
|
namespace ripple {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
struct SusPay_test : public beast::unit_test::suite
|
struct Escrow_test : public beast::unit_test::suite
|
||||||
{
|
{
|
||||||
// An Ed25519 conditional trigger fulfillment and its
|
// A PreimageSha256 fulfillments and its associated condition.
|
||||||
// condition
|
std::array<std::uint8_t, 4> const fb1 =
|
||||||
std::array<std::uint8_t, 99> const fb1 =
|
|
||||||
{{
|
{{
|
||||||
0x00, 0x04, 0x60, 0x3B, 0x6A, 0x27, 0xBC, 0xCE, 0xB6, 0xA4, 0x2D, 0x62,
|
0xA0, 0x02, 0x80, 0x00
|
||||||
0xA3, 0xA8, 0xD0, 0x2A, 0x6F, 0x0D, 0x73, 0x65, 0x32, 0x15, 0x77, 0x1D,
|
|
||||||
0xE2, 0x43, 0xA6, 0x3A, 0xC0, 0x48, 0xA1, 0x8B, 0x59, 0xDA, 0x29, 0x8F,
|
|
||||||
0x89, 0x5B, 0x3C, 0xAF, 0xE2, 0xC9, 0x50, 0x60, 0x39, 0xD0, 0xE2, 0xA6,
|
|
||||||
0x63, 0x82, 0x56, 0x80, 0x04, 0x67, 0x4F, 0xE8, 0xD2, 0x37, 0x78, 0x50,
|
|
||||||
0x92, 0xE4, 0x0D, 0x6A, 0xAF, 0x48, 0x3E, 0x4F, 0xC6, 0x01, 0x68, 0x70,
|
|
||||||
0x5F, 0x31, 0xF1, 0x01, 0x59, 0x61, 0x38, 0xCE, 0x21, 0xAA, 0x35, 0x7C,
|
|
||||||
0x0D, 0x32, 0xA0, 0x64, 0xF4, 0x23, 0xDC, 0x3E, 0xE4, 0xAA, 0x3A, 0xBF,
|
|
||||||
0x53, 0xF8, 0x03,
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
std::array<std::uint8_t, 39> const cb1 =
|
std::array<std::uint8_t, 39> const cb1 =
|
||||||
{{
|
{{
|
||||||
0x00, 0x04, 0x01, 0x20, 0x20, 0x3B, 0x6A, 0x27, 0xBC, 0xCE, 0xB6, 0xA4,
|
0xA0, 0x25, 0x80, 0x20, 0xE3, 0xB0, 0xC4, 0x42, 0x98, 0xFC, 0x1C, 0x14,
|
||||||
0x2D, 0x62, 0xA3, 0xA8, 0xD0, 0x2A, 0x6F, 0x0D, 0x73, 0x65, 0x32, 0x15,
|
0x9A, 0xFB, 0xF4, 0xC8, 0x99, 0x6F, 0xB9, 0x24, 0x27, 0xAE, 0x41, 0xE4,
|
||||||
0x77, 0x1D, 0xE2, 0x43, 0xA6, 0x3A, 0xC0, 0x48, 0xA1, 0x8B, 0x59, 0xDA,
|
0x64, 0x9B, 0x93, 0x4C, 0xA4, 0x95, 0x99, 0x1B, 0x78, 0x52, 0xB8, 0x55,
|
||||||
0x29, 0x01, 0x60
|
0x81, 0x01, 0x00
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// A prefix.prefix.ed25519 conditional trigger fulfillment:
|
// Another PreimageSha256 fulfillments and its associated condition.
|
||||||
std::array<std::uint8_t, 106> const fb2 =
|
std::array<std::uint8_t, 7> const fb2 =
|
||||||
{{
|
{{
|
||||||
0x00, 0x01, 0x67, 0x03, 0x61, 0x62, 0x63, 0x00, 0x04, 0x60, 0x76, 0xA1,
|
0xA0, 0x05, 0x80, 0x03, 0x61, 0x61, 0x61
|
||||||
0x59, 0x20, 0x44, 0xA6, 0xE4, 0xF5, 0x11, 0x26, 0x5B, 0xCA, 0x73, 0xA6,
|
|
||||||
0x04, 0xD9, 0x0B, 0x05, 0x29, 0xD1, 0xDF, 0x60, 0x2B, 0xE3, 0x0A, 0x19,
|
|
||||||
0xA9, 0x25, 0x76, 0x60, 0xD1, 0xF5, 0xAE, 0xC6, 0xAB, 0x6A, 0x91, 0x22,
|
|
||||||
0xAF, 0xF0, 0xF7, 0xDC, 0xB9, 0x66, 0x7F, 0xF6, 0x13, 0x13, 0x68, 0x94,
|
|
||||||
0x73, 0x2B, 0x6E, 0x78, 0xC2, 0x6F, 0x5B, 0x67, 0x31, 0x01, 0xE2, 0x67,
|
|
||||||
0xFE, 0x2E, 0x2B, 0x65, 0xFA, 0x4D, 0x53, 0xDA, 0xD4, 0x78, 0xA1, 0xAD,
|
|
||||||
0xA6, 0x4D, 0x50, 0xFD, 0x1D, 0xFD, 0xB7, 0xD9, 0x49, 0x20, 0xDC, 0x3E,
|
|
||||||
0x1A, 0x56, 0x4A, 0x64, 0x7B, 0x1C, 0xBA, 0x35, 0x60, 0x01,
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
std::array<std::uint8_t, 39> const cb2 =
|
std::array<std::uint8_t, 39> const cb2 =
|
||||||
{{
|
{{
|
||||||
|
0xA0, 0x25, 0x80, 0x20, 0x98, 0x34, 0x87, 0x6D, 0xCF, 0xB0, 0x5C, 0xB1,
|
||||||
0x00, 0x01, 0x01, 0x25, 0x20, 0x28, 0x7A, 0x8B, 0xD8, 0xAD, 0xAE, 0x8A,
|
0x67, 0xA5, 0xC2, 0x49, 0x53, 0xEB, 0xA5, 0x8C, 0x4A, 0xC8, 0x9B, 0x1A,
|
||||||
0xCA, 0x0C, 0x87, 0x1C, 0xE7, 0xC2, 0x5F, 0xBA, 0xA5, 0xA8, 0xBE, 0x10,
|
0xDF, 0x57, 0xF2, 0x8F, 0x2F, 0x9D, 0x09, 0xAF, 0x10, 0x7E, 0xE8, 0xF0,
|
||||||
0xD0, 0xE4, 0xDB, 0x1F, 0x56, 0xAE, 0xEE, 0x8B, 0xB3, 0xAD, 0xCE, 0xE5,
|
0x81, 0x01, 0x03
|
||||||
0x5B, 0x01, 0x64
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// A prefix+preimage conditional trigger fulfillment
|
// Another PreimageSha256 fulfillment and its associated condition.
|
||||||
std::array<std::uint8_t, 7> const fb3 =
|
std::array<std::uint8_t, 8> const fb3 =
|
||||||
{{
|
{{
|
||||||
0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00,
|
0xA0, 0x06, 0x80, 0x04, 0x6E, 0x69, 0x6B, 0x62
|
||||||
}};
|
}};
|
||||||
|
|
||||||
std::array<std::uint8_t, 39> const cb3 =
|
std::array<std::uint8_t, 39> const cb3 =
|
||||||
{{
|
{{
|
||||||
|
0xA0, 0x25, 0x80, 0x20, 0x6E, 0x4C, 0x71, 0x45, 0x30, 0xC0, 0xA4, 0x26,
|
||||||
0x00, 0x01, 0x01, 0x07, 0x20, 0x62, 0x36, 0xB7, 0xA8, 0x58, 0xFB, 0x35,
|
0x8B, 0x3F, 0xA6, 0x3B, 0x1B, 0x60, 0x6F, 0x2D, 0x26, 0x4A, 0x2D, 0x85,
|
||||||
0x2F, 0xD5, 0xC3, 0x01, 0x3B, 0x68, 0x98, 0xCF, 0x26, 0x8B, 0x3E, 0xB8,
|
0x7B, 0xE8, 0xA0, 0x9C, 0x1D, 0xFD, 0x57, 0x0D, 0x15, 0x85, 0x8B, 0xD4,
|
||||||
0x50, 0xB3, 0x4A, 0xD2, 0x65, 0x24, 0xB0, 0xF8, 0x56, 0xC3, 0x72, 0xD9,
|
0x81, 0x01, 0x04
|
||||||
0x73, 0x01, 0x01
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
static
|
static
|
||||||
@@ -99,7 +80,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
{
|
{
|
||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
Json::Value jv;
|
Json::Value jv;
|
||||||
jv[jss::TransactionType] = "SuspendedPaymentCreate";
|
jv[jss::TransactionType] = "EscrowCreate";
|
||||||
jv[jss::Flags] = tfUniversal;
|
jv[jss::Flags] = tfUniversal;
|
||||||
jv[jss::Account] = account.human();
|
jv[jss::Account] = account.human();
|
||||||
jv[jss::Destination] = to.human();
|
jv[jss::Destination] = to.human();
|
||||||
@@ -129,7 +110,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
{
|
{
|
||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
Json::Value jv;
|
Json::Value jv;
|
||||||
jv[jss::TransactionType] = "SuspendedPaymentCreate";
|
jv[jss::TransactionType] = "EscrowCreate";
|
||||||
jv[jss::Flags] = tfUniversal;
|
jv[jss::Flags] = tfUniversal;
|
||||||
jv[jss::Account] = account.human();
|
jv[jss::Account] = account.human();
|
||||||
jv[jss::Destination] = to.human();
|
jv[jss::Destination] = to.human();
|
||||||
@@ -147,7 +128,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
{
|
{
|
||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
Json::Value jv;
|
Json::Value jv;
|
||||||
jv[jss::TransactionType] = "SuspendedPaymentCreate";
|
jv[jss::TransactionType] = "EscrowCreate";
|
||||||
jv[jss::Flags] = tfUniversal;
|
jv[jss::Flags] = tfUniversal;
|
||||||
jv[jss::Account] = account.human();
|
jv[jss::Account] = account.human();
|
||||||
jv[jss::Destination] = to.human();
|
jv[jss::Destination] = to.human();
|
||||||
@@ -164,7 +145,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
jtx::Account const& from, std::uint32_t seq)
|
jtx::Account const& from, std::uint32_t seq)
|
||||||
{
|
{
|
||||||
Json::Value jv;
|
Json::Value jv;
|
||||||
jv[jss::TransactionType] = "SuspendedPaymentFinish";
|
jv[jss::TransactionType] = "EscrowFinish";
|
||||||
jv[jss::Flags] = tfUniversal;
|
jv[jss::Flags] = tfUniversal;
|
||||||
jv[jss::Account] = account.human();
|
jv[jss::Account] = account.human();
|
||||||
jv["Owner"] = from.human();
|
jv["Owner"] = from.human();
|
||||||
@@ -179,7 +160,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
Slice condition, Slice fulfillment)
|
Slice condition, Slice fulfillment)
|
||||||
{
|
{
|
||||||
Json::Value jv;
|
Json::Value jv;
|
||||||
jv[jss::TransactionType] = "SuspendedPaymentFinish";
|
jv[jss::TransactionType] = "EscrowFinish";
|
||||||
jv[jss::Flags] = tfUniversal;
|
jv[jss::Flags] = tfUniversal;
|
||||||
jv[jss::Account] = account.human();
|
jv[jss::Account] = account.human();
|
||||||
jv["Owner"] = from.human();
|
jv["Owner"] = from.human();
|
||||||
@@ -195,7 +176,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
jtx::Account const& from, std::uint32_t seq)
|
jtx::Account const& from, std::uint32_t seq)
|
||||||
{
|
{
|
||||||
Json::Value jv;
|
Json::Value jv;
|
||||||
jv[jss::TransactionType] = "SuspendedPaymentCancel";
|
jv[jss::TransactionType] = "EscrowCancel";
|
||||||
jv[jss::Flags] = tfUniversal;
|
jv[jss::Flags] = tfUniversal;
|
||||||
jv[jss::Account] = account.human();
|
jv[jss::Account] = account.human();
|
||||||
jv["Owner"] = from.human();
|
jv["Owner"] = from.human();
|
||||||
@@ -211,13 +192,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
{ // SusPay enabled
|
{ // Escrow not enabled
|
||||||
Env env(*this, features(featureSusPay));
|
|
||||||
env.fund(XRP(5000), "alice", "bob");
|
|
||||||
env(lockup("alice", "bob", XRP(1000), env.now() + 1s));
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // SusPay not enabled
|
|
||||||
Env env(*this);
|
Env env(*this);
|
||||||
env.fund(XRP(5000), "alice", "bob");
|
env.fund(XRP(5000), "alice", "bob");
|
||||||
env(lockup("alice", "bob", XRP(1000), env.now() + 1s), ter(temDISABLED));
|
env(lockup("alice", "bob", XRP(1000), env.now() + 1s), ter(temDISABLED));
|
||||||
@@ -225,50 +200,11 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
env(cancel("bob", "alice", 1), ter(temDISABLED));
|
env(cancel("bob", "alice", 1), ter(temDISABLED));
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // SusPay enabled, CryptoConditions disabled
|
{ // Escrow enabled
|
||||||
Env env(*this,
|
Env env(*this, features(featureEscrow));
|
||||||
features(featureSusPay));
|
|
||||||
|
|
||||||
env.fund(XRP(5000), "alice", "bob");
|
env.fund(XRP(5000), "alice", "bob");
|
||||||
|
env(lockup("alice", "bob", XRP(1000), env.now() + 1s));
|
||||||
auto const seq = env.seq("alice");
|
|
||||||
|
|
||||||
// Fail: no cryptoconditions allowed
|
|
||||||
env(condpay("alice", "bob", XRP(1000),
|
|
||||||
makeSlice (cb1), env.now() + 1s), ter(temDISABLED));
|
|
||||||
|
|
||||||
// Succeed: doesn't have a cryptocondition
|
|
||||||
env(lockup("alice", "bob", XRP(1000),
|
|
||||||
env.now() + 1s));
|
|
||||||
|
|
||||||
// Fail: can't specify conditional finishes if
|
|
||||||
// cryptoconditions aren't allowed.
|
|
||||||
{
|
|
||||||
auto f = finish("bob", "alice", seq,
|
|
||||||
makeSlice(cb1), makeSlice(fb1));
|
|
||||||
env (f, ter(temDISABLED));
|
|
||||||
|
|
||||||
auto fnc = f;
|
|
||||||
fnc.removeMember ("Condition");
|
|
||||||
env (fnc, ter(temDISABLED));
|
|
||||||
|
|
||||||
auto fnf = f;
|
|
||||||
fnf.removeMember ("Fulfillment");
|
|
||||||
env (fnf, ter(temDISABLED));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Succeeds
|
|
||||||
env.close();
|
env.close();
|
||||||
env(finish("bob", "alice", seq));
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // SusPay enabled, CryptoConditions enabled
|
|
||||||
Env env(*this,
|
|
||||||
features(featureSusPay),
|
|
||||||
features(featureCryptoConditions));
|
|
||||||
|
|
||||||
env.fund(XRP(5000), "alice", "bob");
|
|
||||||
|
|
||||||
auto const seq = env.seq("alice");
|
auto const seq = env.seq("alice");
|
||||||
|
|
||||||
@@ -287,23 +223,20 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
{
|
Env env(*this, features(featureEscrow));
|
||||||
Env env(*this,
|
|
||||||
features(featureSusPay),
|
|
||||||
features(featureCryptoConditions));
|
|
||||||
|
|
||||||
auto const alice = Account("alice");
|
auto const alice = Account("alice");
|
||||||
env.fund(XRP(5000), alice, "bob");
|
env.fund(XRP(5000), alice, "bob");
|
||||||
|
|
||||||
auto const seq = env.seq(alice);
|
auto const seq = env.seq(alice);
|
||||||
// set source and dest tags
|
// set source and dest tags
|
||||||
env(condpay(alice, "bob", XRP(1000),
|
env(condpay(alice, "bob", XRP(1000),
|
||||||
makeSlice (cb1), env.now() + 1s),
|
makeSlice (cb1), env.now() + 1s),
|
||||||
stag(1), dtag(2));
|
stag(1), dtag(2));
|
||||||
auto const sle = env.le(keylet::susPay(alice.id(), seq));
|
auto const sle = env.le(keylet::escrow(alice.id(), seq));
|
||||||
BEAST_EXPECT((*sle)[sfSourceTag] == 1);
|
BEAST_EXPECT(sle);
|
||||||
BEAST_EXPECT((*sle)[sfDestinationTag] == 2);
|
BEAST_EXPECT((*sle)[sfSourceTag] == 1);
|
||||||
}
|
BEAST_EXPECT((*sle)[sfDestinationTag] == 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -314,9 +247,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
Env env(*this,
|
Env env(*this, features(featureEscrow));
|
||||||
features(featureSusPay),
|
|
||||||
features(featureCryptoConditions));
|
|
||||||
env.fund(XRP(5000), "alice", "bob");
|
env.fund(XRP(5000), "alice", "bob");
|
||||||
env.close();
|
env.close();
|
||||||
|
|
||||||
@@ -419,7 +350,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
{ // Unconditional
|
{ // Unconditional
|
||||||
Env env(*this, features(featureSusPay));
|
Env env(*this, features(featureEscrow));
|
||||||
env.fund(XRP(5000), "alice", "bob");
|
env.fund(XRP(5000), "alice", "bob");
|
||||||
auto const seq = env.seq("alice");
|
auto const seq = env.seq("alice");
|
||||||
env(lockup("alice", "alice", XRP(1000), env.now() + 1s));
|
env(lockup("alice", "alice", XRP(1000), env.now() + 1s));
|
||||||
@@ -434,9 +365,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Conditional
|
{ // Conditional
|
||||||
Env env(*this,
|
Env env(*this, features(featureEscrow));
|
||||||
features(featureSusPay),
|
|
||||||
features(featureCryptoConditions));
|
|
||||||
env.fund(XRP(5000), "alice", "bob");
|
env.fund(XRP(5000), "alice", "bob");
|
||||||
auto const seq = env.seq("alice");
|
auto const seq = env.seq("alice");
|
||||||
env(lockup("alice", "alice", XRP(1000), makeSlice(cb2), env.now() + 1s));
|
env(lockup("alice", "alice", XRP(1000), makeSlice(cb2), env.now() + 1s));
|
||||||
@@ -459,9 +388,9 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testCondPay()
|
testEscrowConditions()
|
||||||
{
|
{
|
||||||
testcase ("Conditional Payments");
|
testcase ("Escrow Conditions");
|
||||||
|
|
||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
@@ -469,8 +398,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
{ // Test cryptoconditions
|
{ // Test cryptoconditions
|
||||||
Env env(*this,
|
Env env(*this,
|
||||||
features(featureSusPay),
|
features(featureEscrow));
|
||||||
features(featureCryptoConditions));
|
|
||||||
auto T = [&env](NetClock::duration const& d)
|
auto T = [&env](NetClock::duration const& d)
|
||||||
{ return env.now() + d; };
|
{ return env.now() + d; };
|
||||||
env.fund(XRP(5000), "alice", "bob", "carol");
|
env.fund(XRP(5000), "alice", "bob", "carol");
|
||||||
@@ -507,7 +435,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
// Attempt to finish with the correct condition & fulfillment
|
// Attempt to finish with the correct condition & fulfillment
|
||||||
env(finish("bob", "alice", seq, makeSlice(cb1), makeSlice(fb1)), fee(1500));
|
env(finish("bob", "alice", seq, makeSlice(cb1), makeSlice(fb1)), fee(1500));
|
||||||
// SLE removed on finish
|
// SLE removed on finish
|
||||||
BEAST_EXPECT(! env.le(keylet::susPay(Account("alice").id(), seq)));
|
BEAST_EXPECT(! env.le(keylet::escrow(Account("alice").id(), seq)));
|
||||||
BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
|
BEAST_EXPECT((*env.le("alice"))[sfOwnerCount] == 0);
|
||||||
env.require(balance("carol", XRP(6000)));
|
env.require(balance("carol", XRP(6000)));
|
||||||
env(cancel("bob", "alice", seq), ter(tecNO_TARGET));
|
env(cancel("bob", "alice", seq), ter(tecNO_TARGET));
|
||||||
@@ -518,8 +446,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
{ // Test cancel when condition is present
|
{ // Test cancel when condition is present
|
||||||
Env env(*this,
|
Env env(*this,
|
||||||
features(featureSusPay),
|
features(featureEscrow));
|
||||||
features(featureCryptoConditions));
|
|
||||||
auto T = [&env](NetClock::duration const& d)
|
auto T = [&env](NetClock::duration const& d)
|
||||||
{ return env.now() + d; };
|
{ return env.now() + d; };
|
||||||
env.fund(XRP(5000), "alice", "bob", "carol");
|
env.fund(XRP(5000), "alice", "bob", "carol");
|
||||||
@@ -532,13 +459,11 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
env(cancel("bob", "alice", seq));
|
env(cancel("bob", "alice", seq));
|
||||||
env.require(balance("alice", XRP(5000) - drops(10)));
|
env.require(balance("alice", XRP(5000) - drops(10)));
|
||||||
// SLE removed on cancel
|
// SLE removed on cancel
|
||||||
BEAST_EXPECT(! env.le(keylet::susPay(Account("alice").id(), seq)));
|
BEAST_EXPECT(! env.le(keylet::escrow(Account("alice").id(), seq)));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
Env env(*this,
|
Env env(*this, features(featureEscrow));
|
||||||
features(featureSusPay),
|
|
||||||
features(featureCryptoConditions));
|
|
||||||
auto T = [&env](NetClock::duration const& d)
|
auto T = [&env](NetClock::duration const& d)
|
||||||
{ return env.now() + d; };
|
{ return env.now() + d; };
|
||||||
env.fund(XRP(5000), "alice", "bob", "carol");
|
env.fund(XRP(5000), "alice", "bob", "carol");
|
||||||
@@ -558,9 +483,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
}
|
}
|
||||||
|
|
||||||
{ // Test long & short conditions during creation
|
{ // Test long & short conditions during creation
|
||||||
Env env(*this,
|
Env env(*this, features(featureEscrow));
|
||||||
features(featureSusPay),
|
|
||||||
features(featureCryptoConditions));
|
|
||||||
auto T = [&env](NetClock::duration const& d)
|
auto T = [&env](NetClock::duration const& d)
|
||||||
{ return env.now() + d; };
|
{ return env.now() + d; };
|
||||||
env.fund(XRP(5000), "alice", "bob", "carol");
|
env.fund(XRP(5000), "alice", "bob", "carol");
|
||||||
@@ -601,8 +524,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
{ // Test long and short conditions & fulfillments during finish
|
{ // Test long and short conditions & fulfillments during finish
|
||||||
Env env(*this,
|
Env env(*this,
|
||||||
features(featureSusPay),
|
features(featureEscrow));
|
||||||
features(featureCryptoConditions));
|
|
||||||
auto T = [&env](NetClock::duration const& d)
|
auto T = [&env](NetClock::duration const& d)
|
||||||
{ return env.now() + d; };
|
{ return env.now() + d; };
|
||||||
env.fund(XRP(5000), "alice", "bob", "carol");
|
env.fund(XRP(5000), "alice", "bob", "carol");
|
||||||
@@ -687,9 +609,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
{ // Test empty condition during creation and
|
{ // Test empty condition during creation and
|
||||||
// empty condition & fulfillment during finish
|
// empty condition & fulfillment during finish
|
||||||
Env env(*this,
|
Env env(*this, features(featureEscrow));
|
||||||
features(featureSusPay),
|
|
||||||
features(featureCryptoConditions));
|
|
||||||
auto T = [&env](NetClock::duration const& d)
|
auto T = [&env](NetClock::duration const& d)
|
||||||
{ return env.now() + d; };
|
{ return env.now() + d; };
|
||||||
env.fund(XRP(5000), "alice", "bob", "carol");
|
env.fund(XRP(5000), "alice", "bob", "carol");
|
||||||
@@ -726,6 +646,28 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
env.require(balance ("carol", XRP(6000)));
|
env.require(balance ("carol", XRP(6000)));
|
||||||
env.require(balance ("alice", XRP(4000) - drops(10)));
|
env.require(balance ("alice", XRP(4000) - drops(10)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ // Test a condition other than PreimageSha256, which
|
||||||
|
// would require a separate amendment
|
||||||
|
Env env(*this, features(featureEscrow));
|
||||||
|
auto T = [&env](NetClock::duration const& d)
|
||||||
|
{ return env.now() + d; };
|
||||||
|
env.fund(XRP(5000), "alice", "bob", "carol");
|
||||||
|
|
||||||
|
std::array<std::uint8_t, 45> cb =
|
||||||
|
{{
|
||||||
|
0xA2, 0x2B, 0x80, 0x20, 0x42, 0x4A, 0x70, 0x49, 0x49, 0x52,
|
||||||
|
0x92, 0x67, 0xB6, 0x21, 0xB3, 0xD7, 0x91, 0x19, 0xD7, 0x29,
|
||||||
|
0xB2, 0x38, 0x2C, 0xED, 0x8B, 0x29, 0x6C, 0x3C, 0x02, 0x8F,
|
||||||
|
0xA9, 0x7D, 0x35, 0x0F, 0x6D, 0x07, 0x81, 0x03, 0x06, 0x34,
|
||||||
|
0xD2, 0x82, 0x02, 0x03, 0xC8
|
||||||
|
}};
|
||||||
|
|
||||||
|
// FIXME: this transaction should, eventually, return temDISABLED
|
||||||
|
// instead of temMALFORMED.
|
||||||
|
env(condpay("alice", "carol", XRP(1000), makeSlice(cb), T(S{1})),
|
||||||
|
ter(temMALFORMED));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -735,9 +677,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
Env env(*this,
|
Env env(*this, features(featureEscrow));
|
||||||
features(featureSusPay),
|
|
||||||
features(featureCryptoConditions));
|
|
||||||
|
|
||||||
env.fund(XRP(5000), "alice", "bob", "carol");
|
env.fund(XRP(5000), "alice", "bob", "carol");
|
||||||
env(condpay("alice", "carol", XRP(1000), makeSlice(cb1), env.now() + 1s));
|
env(condpay("alice", "carol", XRP(1000), makeSlice(cb1), env.now() + 1s));
|
||||||
@@ -751,9 +691,7 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
|
|
||||||
using namespace jtx;
|
using namespace jtx;
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
Env env(*this,
|
Env env(*this, features(featureEscrow));
|
||||||
features(featureSusPay),
|
|
||||||
features(featureCryptoConditions));
|
|
||||||
|
|
||||||
env.memoize("alice");
|
env.memoize("alice");
|
||||||
env.memoize("bob");
|
env.memoize("bob");
|
||||||
@@ -806,13 +744,13 @@ struct SusPay_test : public beast::unit_test::suite
|
|||||||
testTags();
|
testTags();
|
||||||
testFails();
|
testFails();
|
||||||
testLockup();
|
testLockup();
|
||||||
testCondPay();
|
testEscrowConditions();
|
||||||
testMeta();
|
testMeta();
|
||||||
testConsequences();
|
testConsequences();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(SusPay,app,ripple);
|
BEAST_DEFINE_TESTSUITE(Escrow,app,ripple);
|
||||||
|
|
||||||
} // test
|
} // test
|
||||||
} // ripple
|
} // ripple
|
||||||
@@ -1,199 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
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/Ed25519.h>
|
|
||||||
#include <ripple/protocol/PublicKey.h>
|
|
||||||
#include <ripple/protocol/SecretKey.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
namespace cryptoconditions {
|
|
||||||
|
|
||||||
class Ed25519_test : public beast::unit_test::suite
|
|
||||||
{
|
|
||||||
void
|
|
||||||
check (
|
|
||||||
std::array<std::uint8_t, 32> const& secretKey,
|
|
||||||
std::vector<std::uint8_t> const& message,
|
|
||||||
std::string const& fulfillment,
|
|
||||||
std::string const& condition)
|
|
||||||
{
|
|
||||||
SecretKey const sk { makeSlice (secretKey) };
|
|
||||||
PublicKey const pk = derivePublicKey (KeyType::ed25519, sk);
|
|
||||||
|
|
||||||
auto f = loadFulfillment (fulfillment);
|
|
||||||
auto c = loadCondition (condition);
|
|
||||||
|
|
||||||
BEAST_EXPECT (f);
|
|
||||||
BEAST_EXPECT (c);
|
|
||||||
|
|
||||||
if (f && c)
|
|
||||||
{
|
|
||||||
// Ensure that loading works correctly
|
|
||||||
BEAST_EXPECT (to_string (*f) == fulfillment);
|
|
||||||
BEAST_EXPECT (to_string (*c) == condition);
|
|
||||||
|
|
||||||
// Ensures that the fulfillment generates
|
|
||||||
// the condition correctly:
|
|
||||||
BEAST_EXPECT (f->condition() == c);
|
|
||||||
|
|
||||||
// Check fulfillment
|
|
||||||
BEAST_EXPECT (validate (*f, *c, makeSlice(message)));
|
|
||||||
|
|
||||||
// Check correct creation of fulfillment
|
|
||||||
BEAST_EXPECT (*f == Ed25519 (sk, pk, makeSlice(message)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testKnownVectors ()
|
|
||||||
{
|
|
||||||
testcase ("Known Vectors");
|
|
||||||
|
|
||||||
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
|
|
||||||
}};
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> const payload (512, 0x21);
|
|
||||||
|
|
||||||
check (sk, payload,
|
|
||||||
"cf:4:RCmTBlAEqh5MSPTdAVgZTAI0m8xmTNluQA6iaZGKjVGfTbzglso5Uo3i2O2WVP6abH1dz5k0H5DLylizTeL5UC0VSptUN4VCkhtbwx3B00pCeWNy1H78rq6OTXzok-EH",
|
|
||||||
"cc:4:20:RCmTBlAEqh5MSPTdAVgZTAI0m8xmTNluQA6iaZGKjVE:96");
|
|
||||||
|
|
||||||
sk.fill (0x00);
|
|
||||||
check (sk, hexblob (""),
|
|
||||||
"cf:4:O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2imPiVs8r-LJUGA50OKmY4JWgARnT-jSN3hQkuQNaq9IPk_GAWhwXzHxAVlhOM4hqjV8DTKgZPQj3D7kqjq_U_gD",
|
|
||||||
"cc:4:20:O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik:96");
|
|
||||||
|
|
||||||
sk.fill (0xff);
|
|
||||||
check (sk, hexblob ("616263"),
|
|
||||||
"cf:4:dqFZIESm5PURJlvKc6YE2QsFKdHfYCvjChmpJXZg0fWuxqtqkSKv8PfcuWZ_9hMTaJRzK254wm9bZzEB4mf-Litl-k1T2tR4oa2mTVD9Hf232Ukg3D4aVkpkexy6NWAB",
|
|
||||||
"cc:4:20:dqFZIESm5PURJlvKc6YE2QsFKdHfYCvjChmpJXZg0fU:96");
|
|
||||||
}
|
|
||||||
|
|
||||||
void testFulfillment ()
|
|
||||||
{
|
|
||||||
testcase ("Fulfillment");
|
|
||||||
|
|
||||||
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
|
|
||||||
}};
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> const v1 (512, 0x21);
|
|
||||||
std::vector<std::uint8_t> const v2 (512, 0x22);
|
|
||||||
|
|
||||||
Ed25519 const f ({ sk }, makeSlice(v1));
|
|
||||||
|
|
||||||
// First check against incorrect conditions:
|
|
||||||
char const* const ccs[] =
|
|
||||||
{
|
|
||||||
"cc:0:3:PWh2oBRt6FdusjlahY3hIT0bksZbd53zozHP1aRYRUY:256",
|
|
||||||
"cc:1:25:XkflBmyISKuevH8-850LuMrzN-HT1Ds9zKUEzaZ2Wk0:103",
|
|
||||||
"cc:2:2b:d3O4epRCo_3rj17Bf3v8hp5ig7vq84ivPok07T9Rdl0:146",
|
|
||||||
"cc:3:11:uKkFs6dhGZCwD51c69vVvHYSp25cRi9IlvXfFaxhMjo:518",
|
|
||||||
"cc:4:20:O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik:96"
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto cc : ccs)
|
|
||||||
{
|
|
||||||
auto c = loadCondition (cc);
|
|
||||||
|
|
||||||
if (BEAST_EXPECT (c))
|
|
||||||
{
|
|
||||||
BEAST_EXPECT (! validate (f, c.get(), makeSlice(v1)));
|
|
||||||
BEAST_EXPECT (! validate (f, c.get(), makeSlice(v2)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, finally, check the correct condition:
|
|
||||||
auto c = loadCondition (
|
|
||||||
"cc:4:20:RCmTBlAEqh5MSPTdAVgZTAI0m8xmTNluQA6iaZGKjVE:96");
|
|
||||||
|
|
||||||
if (BEAST_EXPECT (c))
|
|
||||||
{
|
|
||||||
BEAST_EXPECT (validate (f, c.get(), makeSlice(v1)));
|
|
||||||
BEAST_EXPECT (! validate (f, c.get(), makeSlice(v2)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Under the existing spec, multiple messages sharing
|
|
||||||
// the same key should generate the same fulfillment:
|
|
||||||
{
|
|
||||||
Ed25519 const f1 ({ sk }, makeSlice (v1));
|
|
||||||
Ed25519 const f2 ({ sk }, makeSlice (v2));
|
|
||||||
|
|
||||||
BEAST_EXPECT (f1.condition () == f2.condition ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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:4:0:RCmTBlAEqh5MSPTdAVgZTAI0m8xmTNluQA6iaZGKjVE:96");
|
|
||||||
BEAST_EXPECT (!c1);
|
|
||||||
|
|
||||||
// The following will load but fail in different ways
|
|
||||||
auto c2 = loadCondition ( // only sha256
|
|
||||||
"cc:4:1:RCmTBlAEqh5MSPTdAVgZTAI0m8xmTNluQA6iaZGKjVE:96");
|
|
||||||
BEAST_EXPECT (c2 && !validate(*c2));
|
|
||||||
|
|
||||||
auto c3 = loadCondition ( // only preimage
|
|
||||||
"cc:4:2:RCmTBlAEqh5MSPTdAVgZTAI0m8xmTNluQA6iaZGKjVE:96");
|
|
||||||
BEAST_EXPECT (c3 && !validate(*c3));
|
|
||||||
|
|
||||||
auto c4 = loadCondition ( // sha256+preimage
|
|
||||||
"cc:4:3:RCmTBlAEqh5MSPTdAVgZTAI0m8xmTNluQA6iaZGKjVE:96");
|
|
||||||
BEAST_EXPECT (c4 && !validate(*c4));
|
|
||||||
|
|
||||||
auto c5 = loadCondition ( // Ed25519+sha256+preimage
|
|
||||||
"cc:1:23:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
|
||||||
BEAST_EXPECT (c5 && !validate(*c5));
|
|
||||||
|
|
||||||
auto c6 = loadCondition ( // Ed25519+threshold
|
|
||||||
"cc:1:28:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
|
||||||
BEAST_EXPECT (c6 && !validate(*c6));
|
|
||||||
}
|
|
||||||
|
|
||||||
void run ()
|
|
||||||
{
|
|
||||||
testKnownVectors ();
|
|
||||||
testFulfillment ();
|
|
||||||
testMalformedCondition ();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE (Ed25519, conditions, ripple);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,562 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -17,13 +17,16 @@
|
|||||||
*/
|
*/
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
|
#include <ripple/basics/Buffer.h>
|
||||||
#include <ripple/basics/strHex.h>
|
#include <ripple/basics/strHex.h>
|
||||||
|
#include <ripple/basics/Slice.h>
|
||||||
#include <ripple/beast/unit_test.h>
|
#include <ripple/beast/unit_test.h>
|
||||||
#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/impl/PreimageSha256.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <numeric>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace ripple {
|
namespace ripple {
|
||||||
@@ -31,305 +34,155 @@ namespace cryptoconditions {
|
|||||||
|
|
||||||
class PreimageSha256_test : public beast::unit_test::suite
|
class PreimageSha256_test : public beast::unit_test::suite
|
||||||
{
|
{
|
||||||
void
|
inline
|
||||||
check (
|
Buffer
|
||||||
std::vector<std::uint8_t> const& payload,
|
hexblob(std::string const& s)
|
||||||
std::string const& fulfillment,
|
|
||||||
std::string const& condition)
|
|
||||||
{
|
{
|
||||||
auto f = loadFulfillment (fulfillment);
|
std::vector<std::uint8_t> x;
|
||||||
auto c = loadCondition (condition);
|
x.reserve(s.size() / 2);
|
||||||
|
|
||||||
BEAST_EXPECT (f);
|
auto iter = s.cbegin();
|
||||||
BEAST_EXPECT (c);
|
|
||||||
|
|
||||||
if (f && c)
|
while (iter != s.cend())
|
||||||
{
|
{
|
||||||
// Ensure that loading works correctly
|
int cHigh = charUnHex(*iter++);
|
||||||
BEAST_EXPECT (to_string (*f) == fulfillment);
|
|
||||||
|
|
||||||
{
|
if (cHigh < 0)
|
||||||
auto f2 = loadFulfillment (makeSlice(to_blob (*f)));
|
return {};
|
||||||
BEAST_EXPECT (f2);
|
|
||||||
BEAST_EXPECT (*f == *f2);
|
|
||||||
}
|
|
||||||
|
|
||||||
BEAST_EXPECT (to_string (*c) == condition);
|
int cLow = charUnHex(*iter++);
|
||||||
|
|
||||||
{
|
if (cLow < 0)
|
||||||
auto c1 = loadCondition (makeSlice(to_blob (*c)));
|
return {};
|
||||||
BEAST_EXPECT (c1);
|
|
||||||
BEAST_EXPECT (*c == *c1);
|
|
||||||
|
|
||||||
auto c2 = loadCondition (to_string (*c));
|
x.push_back(
|
||||||
BEAST_EXPECT (c2);
|
static_cast<std::uint8_t>(cHigh << 4) |
|
||||||
BEAST_EXPECT (*c == *c2);
|
static_cast<std::uint8_t>(cLow));
|
||||||
}
|
|
||||||
|
|
||||||
// Ensures that the fulfillment generates
|
|
||||||
// the condition correctly:
|
|
||||||
BEAST_EXPECT (f->condition() == c);
|
|
||||||
|
|
||||||
// Ensure that the fulfillment contains the
|
|
||||||
// correct payload:
|
|
||||||
BEAST_EXPECT (f->payload() == makeSlice(payload));
|
|
||||||
|
|
||||||
// Check fulfillment
|
|
||||||
BEAST_EXPECT (validate (*f, *c, {}));
|
|
||||||
|
|
||||||
// Preimage ignores the message. Verify that it does:
|
|
||||||
std::string test = "aaabbc";
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
for (Slice t = makeSlice (test); !t.empty(); t += 1)
|
|
||||||
BEAST_EXPECT (validate (*f, *c, t));
|
|
||||||
} while (std::next_permutation(test.begin(), test.end()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { x.data(), x.size() };
|
||||||
}
|
}
|
||||||
|
|
||||||
void testKnownVectors ()
|
void
|
||||||
|
testKnownVectors()
|
||||||
{
|
{
|
||||||
testcase ("Known Vectors");
|
testcase("Known Vectors");
|
||||||
|
|
||||||
check (hexblob (""),
|
std::pair<std::string, std::string> const known[] =
|
||||||
"cf:0:",
|
|
||||||
"cc:0:3:47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU:0");
|
|
||||||
check (hexblob ("00"),
|
|
||||||
"cf:0:AA",
|
|
||||||
"cc:0:3:bjQLnP-zepicpUTmu3gKLHiQHT-zNzh2hRGjBhevoB0:1");
|
|
||||||
check (hexblob ("ff"),
|
|
||||||
"cf:0:_w",
|
|
||||||
"cc:0:3:qBAK5qoZQNC2Y7sxzUZhQuu9vVGHExuS2TgYmHgy64k:1");
|
|
||||||
check (hexblob ("feff"),
|
|
||||||
"cf:0:_v8",
|
|
||||||
"cc:0:3:8ZdpKBDUV-KX_OnFZTsCWB_5mlCFI3DynX5f5H2dN-Y:2");
|
|
||||||
check (hexblob ("fffe"),
|
|
||||||
"cf:0:__4",
|
|
||||||
"cc:0:3:s9UQ7wQnXKjmmOWzy7Ds45Se-SUvDNyDnp7jR0CaIgk:2");
|
|
||||||
check (hexblob ("00ff"),
|
|
||||||
"cf:0:AP8",
|
|
||||||
"cc:0:3:But9amnuGeX733SQGNPSq_oEvL0TZdsxLrhtxxaTibg:2");
|
|
||||||
check (hexblob ("0001"),
|
|
||||||
"cf:0:AAE",
|
|
||||||
"cc:0:3:tBP0fRPuL-bIRbLuFBr4HehY307FSaWLeXC7lmRbyNI:2");
|
|
||||||
check (hexblob ("616263"),
|
|
||||||
"cf:0:YWJj",
|
|
||||||
"cc:0:3:ungWv48Bz-pBQUDeXa4iI7ADYaOWF3qctBD_YfIAFa0:3");
|
|
||||||
check (hexblob ("f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
|
|
||||||
"cf:0:8fLz9PX29_j5-vv8_f7_",
|
|
||||||
"cc:0:3:ipyQ4jcC1AbAYiuzYDZ1YkAr4O1IxOe5XBKJdJ17nPA:15");
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> const v1 (256, 0x00);
|
|
||||||
check (v1,
|
|
||||||
"cf:0:"
|
|
||||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
|
||||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
|
||||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
|
||||||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
|
||||||
"AAAAAAAAAAAAAA",
|
|
||||||
"cc:0:3:U0HmsmRpeacOV2UwB6HzEBaUIeyb3Z8aVkj3Wt4AWvE:256");
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> const v2 (256, 0xFF);
|
|
||||||
check (v2,
|
|
||||||
"cf:0:"
|
|
||||||
"__________________________________________________________________________________"
|
|
||||||
"__________________________________________________________________________________"
|
|
||||||
"__________________________________________________________________________________"
|
|
||||||
"__________________________________________________________________________________"
|
|
||||||
"_____________w",
|
|
||||||
"cc:0:3:PWh2oBRt6FdusjlahY3hIT0bksZbd53zozHP1aRYRUY:256");
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> v3 (256);
|
|
||||||
std::iota (v3.begin(), v3.end(), std::uint8_t(0));
|
|
||||||
|
|
||||||
check (v3,
|
|
||||||
"cf:0:"
|
|
||||||
"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD"
|
|
||||||
"0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6"
|
|
||||||
"e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7"
|
|
||||||
"i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T1"
|
|
||||||
"9vf4-fr7_P3-_w",
|
|
||||||
"cc:0:3:QK_y6dLYki5Hr9RkjmlnSXFYeF-9Hahw5xECZr-USIA:256");
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> v4 (4096);
|
|
||||||
std::iota (v4.begin(), v4.end(), std::uint8_t(0));
|
|
||||||
|
|
||||||
check (v4,
|
|
||||||
"cf:0:"
|
|
||||||
"AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD"
|
|
||||||
"0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6"
|
|
||||||
"e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7"
|
|
||||||
"i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T1"
|
|
||||||
"9vf4-fr7_P3-_wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMj"
|
|
||||||
"M0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9w"
|
|
||||||
"cXJzdHV2d3h5ent8fX5_gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp-goaKjpKWmp6ipqqusra"
|
|
||||||
"6vsLGys7S1tre4ubq7vL2-v8DBwsPExcbHyMnKy8zNzs_Q0dLT1NXW19jZ2tvc3d7f4OHi4-Tl5ufo6err"
|
|
||||||
"7O3u7_Dx8vP09fb3-Pn6-_z9_v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKC"
|
|
||||||
"kqKywtLi8wMTIzNDU2Nzg5Ojs8PT4_QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVm"
|
|
||||||
"Z2hpamtsbW5vcHFyc3R1dnd4eXp7fH1-f4CBgoOEhYaHiImKi4yNjo-QkZKTlJWWl5iZmpucnZ6foKGio6"
|
|
||||||
"SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr_AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3-Dh"
|
|
||||||
"4uPk5ebn6Onq6-zt7u_w8fLz9PX29_j5-vv8_f7_AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh"
|
|
||||||
"8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltc"
|
|
||||||
"XV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZ"
|
|
||||||
"qbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX"
|
|
||||||
"2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_wABAgMEBQYHCAkKCwwNDg8QERITFB"
|
|
||||||
"UWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFS"
|
|
||||||
"U1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5_gIGCg4SFhoeIiYqLjI2Oj5"
|
|
||||||
"CRkpOUlZaXmJmam5ydnp-goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2-v8DBwsPExcbHyMnKy8zN"
|
|
||||||
"zs_Q0dLT1NXW19jZ2tvc3d7f4OHi4-Tl5ufo6err7O3u7_Dx8vP09fb3-Pn6-_z9_v8AAQIDBAUGBwgJCg"
|
|
||||||
"sMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4_QEFCQ0RFRkdI"
|
|
||||||
"SUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1-f4CBgoOEhY"
|
|
||||||
"aHiImKi4yNjo-QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr_AwcLD"
|
|
||||||
"xMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3-Dh4uPk5ebn6Onq6-zt7u_w8fLz9PX29_j5-vv8_f7_AA"
|
|
||||||
"ECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-"
|
|
||||||
"P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3"
|
|
||||||
"x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5"
|
|
||||||
"uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19v"
|
|
||||||
"f4-fr7_P3-_wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0"
|
|
||||||
"NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcX"
|
|
||||||
"JzdHV2d3h5ent8fX5_gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp-goaKjpKWmp6ipqqusra6v"
|
|
||||||
"sLGys7S1tre4ubq7vL2-v8DBwsPExcbHyMnKy8zNzs_Q0dLT1NXW19jZ2tvc3d7f4OHi4-Tl5ufo6err7O"
|
|
||||||
"3u7_Dx8vP09fb3-Pn6-_z9_v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkq"
|
|
||||||
"KywtLi8wMTIzNDU2Nzg5Ojs8PT4_QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2"
|
|
||||||
"hpamtsbW5vcHFyc3R1dnd4eXp7fH1-f4CBgoOEhYaHiImKi4yNjo-QkZKTlJWWl5iZmpucnZ6foKGio6Sl"
|
|
||||||
"pqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr_AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3-Dh4u"
|
|
||||||
"Pk5ebn6Onq6-zt7u_w8fLz9PX29_j5-vv8_f7_AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8g"
|
|
||||||
"ISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV"
|
|
||||||
"5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqb"
|
|
||||||
"nJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2N"
|
|
||||||
"na29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_wABAgMEBQYHCAkKCwwNDg8QERITFBUW"
|
|
||||||
"FxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1"
|
|
||||||
"RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5_gIGCg4SFhoeIiYqLjI2Oj5CR"
|
|
||||||
"kpOUlZaXmJmam5ydnp-goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2-v8DBwsPExcbHyMnKy8zNzs"
|
|
||||||
"_Q0dLT1NXW19jZ2tvc3d7f4OHi4-Tl5ufo6err7O3u7_Dx8vP09fb3-Pn6-_z9_v8AAQIDBAUGBwgJCgsM"
|
|
||||||
"DQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4_QEFCQ0RFRkdISU"
|
|
||||||
"pLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1-f4CBgoOEhYaH"
|
|
||||||
"iImKi4yNjo-QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr_AwcLDxM"
|
|
||||||
"XGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3-Dh4uPk5ebn6Onq6-zt7u_w8fLz9PX29_j5-vv8_f7_AAEC"
|
|
||||||
"AwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0"
|
|
||||||
"BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9"
|
|
||||||
"fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5ur"
|
|
||||||
"u8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4"
|
|
||||||
"-fr7_P3-_wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NT"
|
|
||||||
"Y3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJz"
|
|
||||||
"dHV2d3h5ent8fX5_gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp-goaKjpKWmp6ipqqusra6vsL"
|
|
||||||
"Gys7S1tre4ubq7vL2-v8DBwsPExcbHyMnKy8zNzs_Q0dLT1NXW19jZ2tvc3d7f4OHi4-Tl5ufo6err7O3u"
|
|
||||||
"7_Dx8vP09fb3-Pn6-_z9_v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKy"
|
|
||||||
"wtLi8wMTIzNDU2Nzg5Ojs8PT4_QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hp"
|
|
||||||
"amtsbW5vcHFyc3R1dnd4eXp7fH1-f4CBgoOEhYaHiImKi4yNjo-QkZKTlJWWl5iZmpucnZ6foKGio6Slpq"
|
|
||||||
"eoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr_AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3-Dh4uPk"
|
|
||||||
"5ebn6Onq6-zt7u_w8fLz9PX29_j5-vv8_f7_AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gIS"
|
|
||||||
"IjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0-P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f"
|
|
||||||
"YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn-AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ"
|
|
||||||
"2en6ChoqOkpaanqKmqq6ytrq-wsbKztLW2t7i5uru8vb6_wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna"
|
|
||||||
"29zd3t_g4eLj5OXm5-jp6uvs7e7v8PHy8_T19vf4-fr7_P3-_w",
|
|
||||||
"cc:0:3:yPXQNB1U2VGnGxNubir8sU0R7YSJp64Sao_uDfbs8ZM:4096");
|
|
||||||
}
|
|
||||||
|
|
||||||
void testOverlong ()
|
|
||||||
{
|
|
||||||
testcase ("Fulfillment Maximum Payload Length");
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> v;
|
|
||||||
|
|
||||||
// As long as we don't exceed the fulfillment length
|
|
||||||
// we should succeed:
|
|
||||||
unexcept ([this, &v]()
|
|
||||||
{
|
{
|
||||||
v.resize(maxSupportedFulfillmentLength - 1);
|
{ "A0028000",
|
||||||
PreimageSha256 h1 { makeSlice(v) };
|
"A0258020E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855810100" },
|
||||||
auto c1 = h1.condition();
|
{ "A0058003616161",
|
||||||
BEAST_EXPECT (c1.maxFulfillmentLength == h1.payload().size());
|
"A02580209834876DCFB05CB167A5C24953EBA58C4AC89B1ADF57F28F2F9D09AF107EE8F0810103" },
|
||||||
|
|
||||||
v.resize(maxSupportedFulfillmentLength);
|
|
||||||
PreimageSha256 h2 { makeSlice(v) };
|
|
||||||
auto c2 = h2.condition();
|
|
||||||
BEAST_EXPECT (c2.maxFulfillmentLength == h2.payload().size());
|
|
||||||
});
|
|
||||||
|
|
||||||
except ([this, &v] ()
|
|
||||||
{
|
|
||||||
v.resize(maxSupportedFulfillmentLength + 1);
|
|
||||||
PreimageSha256 h3 { makeSlice(v) };
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void testFulfillment ()
|
|
||||||
{
|
|
||||||
testcase ("Fulfillment");
|
|
||||||
|
|
||||||
std::vector<std::uint8_t> const v (256, 0x00);
|
|
||||||
PreimageSha256 const f (makeSlice(v));
|
|
||||||
|
|
||||||
// First check against incorrect conditions:
|
|
||||||
char const* const ccs[] =
|
|
||||||
{
|
|
||||||
"cc:0:3:PWh2oBRt6FdusjlahY3hIT0bksZbd53zozHP1aRYRUY:256",
|
|
||||||
"cc:1:25:XkflBmyISKuevH8-850LuMrzN-HT1Ds9zKUEzaZ2Wk0:103",
|
|
||||||
"cc:2:2b:d3O4epRCo_3rj17Bf3v8hp5ig7vq84ivPok07T9Rdl0:146",
|
|
||||||
"cc:3:11:uKkFs6dhGZCwD51c69vVvHYSp25cRi9IlvXfFaxhMjo:518",
|
|
||||||
"cc:4:20:O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik:96"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto cc : ccs)
|
std::error_code ec;
|
||||||
{
|
|
||||||
auto c = loadCondition (cc);
|
|
||||||
|
|
||||||
if (BEAST_EXPECT (c))
|
auto f1 = Fulfillment::deserialize (hexblob(known[0].first), ec);
|
||||||
{
|
BEAST_EXPECT (f1);
|
||||||
BEAST_EXPECT (! validate (f, c.get(), {}));
|
BEAST_EXPECT (!ec);
|
||||||
for (Slice m = makeSlice(v); !m.empty(); m += 1)
|
|
||||||
BEAST_EXPECT (! validate (f, c.get(), m));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, finally, check the correct condition:
|
auto c1 = Condition::deserialize (hexblob(known[0].second), ec);
|
||||||
auto c = loadCondition (
|
BEAST_EXPECT (c1);
|
||||||
"cc:0:3:U0HmsmRpeacOV2UwB6HzEBaUIeyb3Z8aVkj3Wt4AWvE:256");
|
BEAST_EXPECT (!ec);
|
||||||
|
|
||||||
if (BEAST_EXPECT (c))
|
auto f2 = Fulfillment::deserialize(hexblob(known[1].first), ec);
|
||||||
{
|
BEAST_EXPECT(f2);
|
||||||
// Note that the message may not, necessarily
|
BEAST_EXPECT(!ec);
|
||||||
// have anything to do with the fulfillment, so
|
|
||||||
// we expect the validation to succeed with any
|
auto c2 = Condition::deserialize(hexblob(known[1].second), ec);
|
||||||
// message:
|
BEAST_EXPECT(c2);
|
||||||
BEAST_EXPECT (validate (f, c.get(), {}));
|
BEAST_EXPECT(!ec);
|
||||||
for (Slice m = makeSlice(v); !m.empty(); m += 1)
|
|
||||||
BEAST_EXPECT (validate (f, c.get(), m));
|
// Check equality and inequality
|
||||||
}
|
BEAST_EXPECT (f1->condition() == *c1);
|
||||||
|
BEAST_EXPECT (f1->condition() != *c2);
|
||||||
|
BEAST_EXPECT (f2->condition() == *c2);
|
||||||
|
BEAST_EXPECT (f2->condition() != *c1);
|
||||||
|
BEAST_EXPECT (*c1 != *c2);
|
||||||
|
BEAST_EXPECT (*c1 == *c1);
|
||||||
|
BEAST_EXPECT (f1->condition() == f1->condition());
|
||||||
|
|
||||||
|
// Should validate with the empty string
|
||||||
|
BEAST_EXPECT (validate (*f1, *c1));
|
||||||
|
BEAST_EXPECT (validate(*f2, *c2));
|
||||||
|
|
||||||
|
// And with any string - the message doesn't matter for PrefixSha256
|
||||||
|
BEAST_EXPECT (validate (*f1, *c1, makeSlice(known[0].first)));
|
||||||
|
BEAST_EXPECT (validate(*f1, *c1, makeSlice(known[0].second)));
|
||||||
|
BEAST_EXPECT (validate(*f2, *c2, makeSlice(known[0].first)));
|
||||||
|
BEAST_EXPECT (validate(*f2, *c2, makeSlice(known[0].second)));
|
||||||
|
|
||||||
|
// Shouldn't validate if the fulfillment & condition don't match
|
||||||
|
// regardless of the message.
|
||||||
|
BEAST_EXPECT (! validate(*f2, *c1));
|
||||||
|
BEAST_EXPECT (! validate(*f2, *c1, makeSlice(known[0].first)));
|
||||||
|
BEAST_EXPECT (! validate(*f2, *c1, makeSlice(known[0].second)));
|
||||||
|
BEAST_EXPECT (! validate(*f1, *c2));
|
||||||
|
BEAST_EXPECT (! validate(*f1, *c2, makeSlice(known[0].first)));
|
||||||
|
BEAST_EXPECT (! validate(*f1, *c2, makeSlice(known[0].second)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void testMalformedCondition ()
|
void testOtherTypes()
|
||||||
{
|
{
|
||||||
testcase ("Malformed Condition");
|
testcase ("Other Types");
|
||||||
|
|
||||||
// This is malformed and will not load because a
|
std::pair<std::string, std::string> const others[] =
|
||||||
// feature suite of 0 is not supported.
|
{
|
||||||
auto c1 = loadCondition (
|
// PREFIX + PREIMAGE:
|
||||||
"cc:0:0:U0HmsmRpeacOV2UwB6HzEBaUIeyb3Z8aVkj3Wt4AWvE:256");
|
{ "A10B8000810100A204A0028000",
|
||||||
BEAST_EXPECT (!c1);
|
|
||||||
|
|
||||||
// The following will load but fail in different ways
|
"A12A8020BB1AC5260C0141B7E54B26EC2330637C5597BF811951AC09E744AD20FF77E287810204"
|
||||||
auto c2 = loadCondition ( // only sha256
|
"0082020780" },
|
||||||
"cc:0:1:U0HmsmRpeacOV2UwB6HzEBaUIeyb3Z8aVkj3Wt4AWvE:256");
|
|
||||||
BEAST_EXPECT (c2 && !validate(*c2));
|
// THRESHOLD:
|
||||||
|
{ "A208A004A0028000A100",
|
||||||
|
|
||||||
|
"A22A8020B4B84136DF48A71D73F4985C04C6767A778ECB65BA7023B4506823BEEE7631B9810204"
|
||||||
|
"0082020780" },
|
||||||
|
|
||||||
|
// RSA:
|
||||||
|
{ "A382020880820100E1EF8B24D6F76B09C81ED7752AA262F044F04A874D43809D31CEA612F99B0C97"
|
||||||
|
"A8B4374153E3EEF3D66616843E0E41C293264B71B6173DB1CF0D6CD558C58657706FCF097F704C48"
|
||||||
|
"3E59CBFDFD5B3EE7BC80D740C5E0F047F3E85FC0D75815776A6F3F23C5DC5E797139A6882E38336A"
|
||||||
|
"4A5FB36137620FF3663DBAE328472801862F72F2F87B202B9C89ADD7CD5B0A076F7C53E35039F67E"
|
||||||
|
"D17EC815E5B4305CC63197068D5E6E579BA6DE5F4E3E57DF5E4E072FF2CE4C66EB45233973875275"
|
||||||
|
"9639F0257BF57DBD5C443FB5158CCE0A3D36ADC7BA01F33A0BB6DBB2BF989D607112F2344D993E77"
|
||||||
|
"E563C1D361DEDF57DA96EF2CFC685F002B638246A5B309B981820100BD42D6569F6599AED455F96B"
|
||||||
|
"C0ED08ED1480BF36CD9E1467F9C6F74461C9E3A749334B2F6404AA5F9F6BAFE76C347D069250B35D"
|
||||||
|
"1C970C793059EE733A8193F30FA78FEC7CAE459E3DDFD7633805D476940D0CB53D7FB389DCDAEAF6"
|
||||||
|
"E8CF48C4B5635430E4F2BCDFE505C2C0FC17B40D93C7EDB7C261EBF43895A705E024AA0549A660F7"
|
||||||
|
"0A32150647522DBE6B63520497CFF8F8D5D74768A27C5B86E580BE3FCDC96F1976293CBA0D58DFC6"
|
||||||
|
"0B518B632A6DC1E950C43E231FE1A379AA6DDCC52C70EDF851C6C0123A964261CFDB3857CD6CD5AD"
|
||||||
|
"C37D8DA2CC924EDAE1D84CF6124587F274C1FA3697DA2901F0269F03B243C03B614E0385E1961FAC"
|
||||||
|
"5000F9BB",
|
||||||
|
|
||||||
|
"A32580204849505152535455484950515253545548495051525354554849505152535455810101" },
|
||||||
|
|
||||||
|
// ED25519:
|
||||||
|
{ "A4648020D75A980182B10AB7D54BFED3C964073A0EE172F3DAA62325AF021A68F707511A8140E556"
|
||||||
|
"4300C360AC729086E2CC806E828A84877F1EB8E5D974D873E065224901555FB8821590A33BACC61E"
|
||||||
|
"39701CF9B46BD25BF5F0595BBE24655141438E7A100B",
|
||||||
|
|
||||||
|
"A4278020799239ABA8FC4FF7EABFBC4C44E69E8BDFED993324E12ED64792ABE289CF1D5F810302"
|
||||||
|
"0000" }
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto x : others)
|
||||||
|
{
|
||||||
|
std::error_code ec;
|
||||||
|
|
||||||
|
BEAST_EXPECT (!Fulfillment::deserialize(hexblob(x.first), ec));
|
||||||
|
BEAST_EXPECT (!Condition::deserialize (hexblob(x.second), ec));
|
||||||
|
}
|
||||||
|
|
||||||
auto c3 = loadCondition ( // only preimage
|
|
||||||
"cc:1:2:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
|
||||||
BEAST_EXPECT (c3 && !validate(*c3));
|
|
||||||
|
|
||||||
auto c4 = loadCondition ( // only prefix+sha256
|
|
||||||
"cc:1:20:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
|
||||||
BEAST_EXPECT (c4 && !validate(*c4));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void run ()
|
void run ()
|
||||||
{
|
{
|
||||||
testKnownVectors ();
|
testKnownVectors();
|
||||||
testOverlong ();
|
testOtherTypes();
|
||||||
testFulfillment ();
|
|
||||||
testMalformedCondition ();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,362 +0,0 @@
|
|||||||
//------------------------------------------------------------------------------
|
|
||||||
/*
|
|
||||||
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/RsaSha256.h>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
namespace ripple {
|
|
||||||
namespace cryptoconditions {
|
|
||||||
|
|
||||||
class RsaSha256_test : public beast::unit_test::suite
|
|
||||||
{
|
|
||||||
// A well-known message, its fulfillment and its condition
|
|
||||||
std::string const knownMessage = "aaa";
|
|
||||||
|
|
||||||
std::string const knownFulfillment =
|
|
||||||
"cf:3:ggEA4e-LJNb3awnIHtd1KqJi8ETwSodNQ4CdMc6mEvmbDJeotDdBU-Pu89ZmF"
|
|
||||||
"oQ-DkHCkyZLcbYXPbHPDWzVWMWGV3Bvzwl_cExIPlnL_f1bPue8gNdAxeDwR_PoX8D"
|
|
||||||
"XWBV3am8_I8XcXnlxOaaILjgzakpfs2E3Yg_zZj264yhHKAGGL3Ly-HsgK5yJrdfNW"
|
|
||||||
"woHb3xT41A59n7RfsgV5bQwXMYxlwaNXm5Xm6beX04-V99eTgcv8s5MZutFIzlzh1J"
|
|
||||||
"1ljnwJXv1fb1cRD-1FYzOCj02rce6AfM6C7bbsr-YnWBxEvI0TZk-d-VjwdNh3t9X2"
|
|
||||||
"pbvLPxoXwArY4JGpbMJuYIBAEjolF7-AHVW1b9NXySeSAj3MH4pUR0yYtrvYdiAmPm"
|
|
||||||
"qSovAYjqMl1c49l1r9FnVQ_KJ1zy8evTqOjP78-xEQER5EdcilAkeVhgzYo5Jp3LtY"
|
|
||||||
"I3mxEWVqR4-F9bPXsOyUo1j0q3WRjmJsS7sV332Rwlg32gyqdhMNg0cIXrWTIYlvbW"
|
|
||||||
"U-wraCGzey73lgNQkv5dG0vDDEoJtu7AK1otSxMt9RxVro146mByXOGN5LMgNBKGAI"
|
|
||||||
"QpSQVhltks6YXdLHTl114qYsIIe5Vyg-GMF1CUp4Q6wFc79QC-1myq7je7lKm8kR9I"
|
|
||||||
"oRgPSGc1OjPnP_dVJiInDeAtZ3WpX731zJiA";
|
|
||||||
|
|
||||||
std::string const knownCondition =
|
|
||||||
"cc:3:11:uKkFs6dhGZCwD51c69vVvHYSp25cRi9IlvXfFaxhMjo:518";
|
|
||||||
|
|
||||||
// Some RSA keys we use to check
|
|
||||||
std::string const goodKey =
|
|
||||||
"-----BEGIN RSA PRIVATE KEY-----\n"
|
|
||||||
"MIIEpAIBAAKCAQEAq9QZZzSmdXaAFeSkUgK8/xuyKPQEFNkiEzatMSmmGN+DpCR7\n"
|
|
||||||
"HAK4W3wHfW6jegQFPlsvWLWbtnwgwCHhv1oW4jiL7BDD3prJIuJmhCE/w6WPKTFb\n"
|
|
||||||
"WhvxQY5sbqCDnjcd0x/adKjNLaTpSRANscR+hahbQA1vqPperHz/Z20reRPQ6aDn\n"
|
|
||||||
"w+qBL7dnVFgCPu8QrueyaZ0I5xQMIJiF0CnLXbPbU0ybxDVNgBDXsYeHE4VEM7ek\n"
|
|
||||||
"NQAMrsr6wodD5y94jynXHharEv5dzKsQFPRAGKzTvwQqWSiZr+Fgq4q1GqQW+oUa\n"
|
|
||||||
"xssbXWkGHEOxPBz6RFqLOFd8JnM9yVlWs2nWDwIDAQABAoIBAQCW9WNQCbCImBBV\n"
|
|
||||||
"q6c1qdQzaDiwxBjl3BGUwb+M5qNXTN9RkP9bj4Q6U5AdAdu7sdaNfvzsubjQrOL1\n"
|
|
||||||
"CY9UVqiuHLHJNr1uT5yP+knIoZFsqIJK1WMFmnDtgFwBISIhGRkpx91cCoUgKbcO\n"
|
|
||||||
"in0Nha0Gbe+lKWjFExmj/rlAO2grGO4yYd+P27BZ99mHBXPMQIIwQbSeRUTBLiRy\n"
|
|
||||||
"VhN7Mb60wag2m4F9zriEzhcj7pePNKHvpqNiuT5FCVoUNZW2CqFoXgEghF1VdWj5\n"
|
|
||||||
"UovZITUCN9zrGdFHWQj3Hx1LZo3UQz3auUp4XQ89dIm1GefqcZYpnzth+D43UXtC\n"
|
|
||||||
"f33nK9shAoGBANOm6aAhAh8Ahtc+52u3ykTnRGwI+H3QvgvzE7keZGIUb0yKtd/+\n"
|
|
||||||
"yuxYI3DgN/Mn69p3pLrYh/CJ9VonhELYv4oekGZfCmqEtUxmkTa9EgTKAIxIDw9W\n"
|
|
||||||
"t/jNBzzBccF22kl9w+nYHNOqo8M9yUlx0xwLnfioVX45G4jouucfPUDxAoGBAM/V\n"
|
|
||||||
"CmykuH8vIYluyobldKFglXKeFMQKlKG+Dv9wG71RSYPyamd7lu3fPgZyGcbAGd49\n"
|
|
||||||
"/Wewpq8ieagjrTuCEGlI0lhrL35axvBDKQcS+LTp+uD6vpxnFm986cxLgYRTNq0/\n"
|
|
||||||
"eMUvJy72Ms5zajZUMdjM/nqTA9zpVDofL+xb6Ib/AoGAVheU/H+wvy+VqcR6mgRe\n"
|
|
||||||
"kHyKBm/3tCXOyEmOAkTsjEDHrRjXNlAL9us7L1TlLVFVzL3SEfa2BQ/47z0XvaEw\n"
|
|
||||||
"+FvKXPnX4NAudu9ZrixmQfBxHJ7LEXAy0U+E3B/Lx+gyjqZLpLk1sJu+lVJyqB9W\n"
|
|
||||||
"whevoE/Ixtkv7BbOv+ijH+ECgYAb0WQnzpRzUZenkZDCJYxK3WajhM06wD/MtmfD\n"
|
|
||||||
"gPn1iR/R7WyYlU5KYIsoybTxiVztBlcYvehRoMev3baeNHaF4R1mgFJHE1d1aUfg\n"
|
|
||||||
"joWDkZ3m5ykEPjgejBWvJpwbXhf/cHN10S3pd0Ktp30b8IELh8S4G111ADYp4WrE\n"
|
|
||||||
"tDiXeQKBgQCROYcVuUEfkOiKeGHkBGbbsgj77KzZ1x7wUBzueKAND9+e2kX8kcc2\n"
|
|
||||||
"lX9DDkShUvZau0EJtQsFTehsZZeeBwtSvWu1A+2Wn9D19Hxe0qJCNZ6bqYQM9i2S\n"
|
|
||||||
"JjI6wG7YYl/foT3B3Zf3A3G9gUOc+P5/dnUi+6r+l7GUvQ5WnVQjDw==\n"
|
|
||||||
"-----END RSA PRIVATE KEY-----\n";
|
|
||||||
|
|
||||||
std::string const shortKey =
|
|
||||||
"-----BEGIN RSA PRIVATE KEY-----\n"
|
|
||||||
"MGMCAQACEQCtbMmYUOdPy+XwgP+xXzfrAgMBAAECEQCFPVJ5GpdMnxfbcKFUUb2\n"
|
|
||||||
"JAgkA2e+AQuY6Ns8CCQDLtxhLU8j0JQIJAKkphE9pUUp1AghYypxPMNy09QIISr\n"
|
|
||||||
"srXHy9nPk=\n"
|
|
||||||
"-----END RSA PRIVATE KEY-----\n";
|
|
||||||
|
|
||||||
std::string const longKey =
|
|
||||||
"-----BEGIN RSA PRIVATE KEY-----\n"
|
|
||||||
"MIIJYwIBAAKCAg4Aqx3vteNh7iinTC6EEVaYmCDAeQ2oxXcjYRlx5h1m0ddHplsr\n"
|
|
||||||
"/e2QbwqExsz8zK9Wlis3EiPBoVX/CI6JxJfCkrpUjLH22jP3J2KTjZ6BkZ7hahOW\n"
|
|
||||||
"iqttFYFCta9iGirDQk04Wfubbtc4JBHexNUBCyGClCN/Ovd8Yv3KpoL3YOBma6ct\n"
|
|
||||||
"40Gf2xvG2k6OlLiGg7zvsI2KyD/a0/xFoMrC/X5wWunRFvHZYeb4LM2hqGe79LeK\n"
|
|
||||||
"NrbdYN+p8S+jzS6jo91C9EoltmS9UNXaax51JT9G83sw1U6KMIWA1jK9+3C92mry\n"
|
|
||||||
"gkLkdqJzsCsHWLWUZFJfKrZE7KAbw1TBGPSjSakTY3KOgrMghP41k3XGDsmkLMgx\n"
|
|
||||||
"JGd/F46YqEOB5vfdiZs7y0MuYYZmKY1o6DBNu+cL+sKBzNdtkvTVEskhsrL/OzPA\n"
|
|
||||||
"sN8srZdQm/Kim+2yKR+lxWz2kamcV74KCQMn2ALlMflfbFG/6RyHGzbVbiGTlW/8\n"
|
|
||||||
"gJQY9acMIDaJF0cPeSAa7aEHcQE5o1zrBcORqkWYbhZpPZtuS7GZ3gXwwYHxXvzq\n"
|
|
||||||
"tg5rMTqvcVzS2o08O+q4BopqAkU0mTF64Yh7izJQ5WGgk+g058WohNm4QB5XPETi\n"
|
|
||||||
"WlGSsEJjuzpHECq19DNoDe88HhZCwrqJSOl07MN1LPete9YptE1J+zoRasNy5wxJ\n"
|
|
||||||
"NmZRdP2a61J5AgMBAAECggIOAIdoBQwVhqUDHn+2P2PI9q9LG4OvP2IiyKhJjkvd\n"
|
|
||||||
"8EMU6+nEM6eYmbaEyFTYWSNPjGEAiW+dQ9f7SPjocjRTMvEQ6V78ZK5+eJF9++0R\n"
|
|
||||||
"BM7Kvu1F2taYmJVv1+4VfrfeJu0MVg8+ftzTCeXhDjsLouu/9Khs/n0W4iMjWX0y\n"
|
|
||||||
"HbdXWzTM8g7nGywzasPNbh5ZdnhAxhsbpjqX7P3anu6CBJK7vwTyCTby4mYKc1Bg\n"
|
|
||||||
"2A9/JsibhI+PXNcPplbor+HpiixdJmJRWk5eoUCaOWCSlXiH/gkl7pqcr9V9j1nw\n"
|
|
||||||
"hU23BUUVZBmX/Vmza4B4TDPyXB6W4B/YY+orOEz1gGfTDnN3i5QiToshpnZ7BKJH\n"
|
|
||||||
"kI+NR/m47r+Dab7DFTpl0c9xEVDRtQj0vhKehzV3/FLJOVQtxMqXC+ZjW+rUfjuN\n"
|
|
||||||
"iNBWChGMMKOllJMvN6o+/lyA07RxSF1shgcfDNQQhnTCKnfz2SbKAxqnzLwVSrWZ\n"
|
|
||||||
"LldyoyTPKra5uYfldRSXCPM5Or0dSQYAaX8t9jxaYdHq7hT5w7C5lsJdlyeUFlO1\n"
|
|
||||||
"1+jl5VZ1MT7f6g7Poo+NMdOVsGT7N8D3ERUL/Kmspx1Gpdll5iRVWxtZDpg4ct3G\n"
|
|
||||||
"7NTxaJOe+gueNg49wo0I1k49gSQ+xnTOyKmzkOGaZ+Ncbapd4OIh+5Y/wuWA5FTi\n"
|
|
||||||
"msbBxaXyAg/snkOGaY8NEQKCAQcNatn6e2wuNDbvp0qtmG7ipU033acpGzpG0Zmc\n"
|
|
||||||
"l6mPO0uis8+7cSks0L3IL1Yh3qCR8CBd5gt9JyjVKL/USq7AO2v0Uhnbyn+qbh7f\n"
|
|
||||||
"476bifVq9iU31M001KccZ3B7Ev5wBsBCAT8GnP/SMxqdQHX6VxuDWc9/bdccidui\n"
|
|
||||||
"V3wBY1bDsxGNV80Gg5/n/p3gSlkFkdjv9g7Jl6ODTUP/1M8s7siF3Ah93846PBmI\n"
|
|
||||||
"CqfUgQhm42HEJQAi9dgA+Zhc1dyT1hwnhAhzPaNAaeWHQWCD8OM6WI+/24miAJMi\n"
|
|
||||||
"kNCDwIITr3H/tz8J5rA6yqXl30lDBKE7KSpUTqSegnSC2U2+29qMUtVlvwKCAQcM\n"
|
|
||||||
"wNzxi8PSFwLO/e9FBvcuhHCSYbAw3tHMgkNEItM+0wCUw9hpkIrq3XZLwh+GKopw\n"
|
|
||||||
"9Uqzo2xBq3LeZgiU0nokgnDoixvBTcawnXsR3Y7mQijJo0eG2Nukd+g5wJ7nRp7q\n"
|
|
||||||
"Rq0KHYzfER1UPcAPI2ZL4T1JU5sdmPqIZuZA0YGSIznQ5htBiQMB4zaJeNN7m4bK\n"
|
|
||||||
"7e/eEF8AbChzbKiNFzl4am1boPbIZK3xek5cS7pLv5G5vX4R4+t6UY1Na91XQG9l\n"
|
|
||||||
"YZzYb4cIxhmvy0/zVAjeJpZCJpAQjE67+IZdieEVe+xGNe7qC1TJN+pL1YNxJdi3\n"
|
|
||||||
"ZFAf9fCYH5Ir6Es+vXCRlyFhNBOFxwKCAQcBQehX30VONzqGz0jiaAzMVO2dtLo7\n"
|
|
||||||
"0f9uL6qT0Grlr4rxHqTzTjGrr4x5vGX4GqM1yileY3bkLc1X3M/Nl4o1HdyKMz+V\n"
|
|
||||||
"J687S8K8/N0aOp2zfooSZ3Er6FoZAWC7SBZsbVWLWg6MEh6vlnaCEk58PbmoX7xg\n"
|
|
||||||
"luy4EftxhX1rq+GvyZJ1iqr+V0ufNG+bW5xoNzj7lDXiksGSRqV+znT0IxTL5sks\n"
|
|
||||||
"8tKjBormAwmjksw0yE6bUVRn8l5iCQJMgQaBHGnbEjawhjBMkyAdwvTGqMbC6xXd\n"
|
|
||||||
"xzdo5WDktmm0T1Bhg+nNK2FPDj2p5OATYQ++pipuHveGmzA2YseEk9UDdBtRV1oE\n"
|
|
||||||
"hQKCAQcBZMpAc1+xA+bArCuLxZkZskuDE73neVJAITQsrAmd4f08RLLPxoYH6K/W\n"
|
|
||||||
"054SUW/TrFq/iup3ur7Q4yGo8d97Qe4I27rqww8lmfArIaVOMIi4kGluqSBHtvrf\n"
|
|
||||||
"5Nb4u1T+kT6zzkrozbwAysbEYL/7JuBFtSdMcr1eTrB3AO5CBCt7UspDvS9g822w\n"
|
|
||||||
"VE34QiTW5G3EPNHFAAzjoEpDMPiM2kSdMNgHSklgDFen6navdH3+aGDwn5HKSkNA\n"
|
|
||||||
"5LrJoDcMQ0CavoVpRgzkkzlnhBV8AYeGLySrSkoIbL5yVnEMogBOI/K6DQb0/nFS\n"
|
|
||||||
"XEEDCnnGgOXouD3Uwg59UeN3NcipgHSbZM+FXQKCAQcCswewWvkORgMxDYT68x6P\n"
|
|
||||||
"hZtkAuy7BxAQ2H7ToYxeiVy4SBELg3xFiSCLNwhdK8En5vmSo3WnjNuWOGZ4ywUe\n"
|
|
||||||
"KmbxNu7o+zMyOblNg/I6CQMSEuo6jHoLVc9QaODscGco3du8WjRwJ2DnA3HoBJ5F\n"
|
|
||||||
"L0XftzOCfSrBQfn0Fb2ej4nsaIw1z0wEaAnuDC18/VUHQ0rHl2K2QleX4FwBiyXK\n"
|
|
||||||
"qWzhAVuxskkfWe3Xgn58IT2MODSDnFhP8j6m0vq5lklwgfIi9c6+y0rmJbhSZI4N\n"
|
|
||||||
"b/o5HSpWAxfpaSnWzw5moN5JP6DmhGQzgnctW9YL2w4OfZ9jPHl+xWMlSGUd8TD2\n"
|
|
||||||
"QIpo2Qox/w==\n"
|
|
||||||
"-----END RSA PRIVATE KEY-----\n";
|
|
||||||
|
|
||||||
void check (
|
|
||||||
Fulfillment const& f,
|
|
||||||
Condition const& c,
|
|
||||||
Slice test,
|
|
||||||
Slice good)
|
|
||||||
{
|
|
||||||
BEAST_EXPECT (validate (f, c, test) ==
|
|
||||||
((test == good) && (f.condition() == c)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void testKnown ()
|
|
||||||
{
|
|
||||||
testcase ("Known");
|
|
||||||
|
|
||||||
Slice m = makeSlice (knownMessage);
|
|
||||||
std::string test = "aaabc";
|
|
||||||
|
|
||||||
// Load and test string and binary and text
|
|
||||||
// serialization & deserialization
|
|
||||||
auto const f = loadFulfillment(knownFulfillment);
|
|
||||||
BEAST_EXPECT (f);
|
|
||||||
BEAST_EXPECT (to_string (*f) == knownFulfillment);
|
|
||||||
|
|
||||||
{
|
|
||||||
auto const f2 = loadFulfillment(makeSlice(to_blob(*f)));
|
|
||||||
BEAST_EXPECT (f2);
|
|
||||||
BEAST_EXPECT (*f == *f2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the condition for this fulfillment and test
|
|
||||||
// binary and text serialization & deserialization
|
|
||||||
auto const c = f->condition();
|
|
||||||
BEAST_EXPECT (to_string(c) == knownCondition);
|
|
||||||
|
|
||||||
{
|
|
||||||
auto c1 = loadCondition (knownCondition);
|
|
||||||
BEAST_EXPECT (c1);
|
|
||||||
BEAST_EXPECT (c == *c1);
|
|
||||||
|
|
||||||
auto c2 = loadCondition (makeSlice(to_blob(c)));
|
|
||||||
BEAST_EXPECT (c2);
|
|
||||||
BEAST_EXPECT (c == *c2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// First check against incorrect conditions, using both
|
|
||||||
// correct, incorrect and empty buffers.
|
|
||||||
char const* const ccs[] =
|
|
||||||
{
|
|
||||||
"cc:0:3:PWh2oBRt6FdusjlahY3hIT0bksZbd53zozHP1aRYRUY:256",
|
|
||||||
"cc:1:25:XkflBmyISKuevH8-850LuMrzN-HT1Ds9zKUEzaZ2Wk0:103",
|
|
||||||
"cc:2:2b:d3O4epRCo_3rj17Bf3v8hp5ig7vq84ivPok07T9Rdl0:146",
|
|
||||||
"cc:3:11:Mjmrcm06fOo-3WOEZu9YDSNfqmn0lj4iOsTVEurtCdI:518",
|
|
||||||
"cc:4:20:O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik:96"
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto cc : ccs)
|
|
||||||
{
|
|
||||||
auto nc = loadCondition (cc);
|
|
||||||
|
|
||||||
if (BEAST_EXPECT (nc && nc != c))
|
|
||||||
{
|
|
||||||
check (*f, nc.get(), makeSlice(test), m);
|
|
||||||
check (*f, nc.get(), m, m);
|
|
||||||
check (*f, nc.get(), { }, m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now try against the correct condition with various
|
|
||||||
// buffers - most are incorrect, some are correct.
|
|
||||||
do
|
|
||||||
{
|
|
||||||
for (Slice t = makeSlice (test); !t.empty(); t += 1)
|
|
||||||
check (*f, c, t, m);
|
|
||||||
} while (std::next_permutation(test.begin(), test.end()));
|
|
||||||
|
|
||||||
// And with an empty buffer:
|
|
||||||
check (*f, c, Slice { }, m);
|
|
||||||
|
|
||||||
// Under the existing spec, multiple messages sharing
|
|
||||||
// the same key should generate the same fulfillment:
|
|
||||||
{
|
|
||||||
std::array<std::uint8_t, 3> aaa {{ 'a', 'a', 'a' }};
|
|
||||||
std::array<std::uint8_t, 3> bbb {{ 'b', 'b', 'b' }};
|
|
||||||
|
|
||||||
RsaSha256 f1;
|
|
||||||
BEAST_EXPECT (f1.sign (goodKey, makeSlice (aaa)));
|
|
||||||
|
|
||||||
RsaSha256 f2;
|
|
||||||
BEAST_EXPECT (f2.sign (goodKey, makeSlice (bbb)));
|
|
||||||
|
|
||||||
BEAST_EXPECT (f1.condition () == f2.condition ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void testDynamic ()
|
|
||||||
{
|
|
||||||
testcase ("Dynamic");
|
|
||||||
|
|
||||||
Slice m = makeSlice (knownMessage);
|
|
||||||
|
|
||||||
std::string test = "aaabc";
|
|
||||||
|
|
||||||
RsaSha256 f;
|
|
||||||
BEAST_EXPECT (f.sign (goodKey, m));
|
|
||||||
|
|
||||||
{
|
|
||||||
auto const f2 = loadFulfillment(makeSlice(to_blob(f)));
|
|
||||||
BEAST_EXPECT (f2);
|
|
||||||
BEAST_EXPECT (f == *f2);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate and verify the condition for this fulfillment:
|
|
||||||
auto const c = f.condition();
|
|
||||||
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// First check against incorrect conditions, using both
|
|
||||||
// correct, incorrect and empty buffers.
|
|
||||||
char const* const ccs[] =
|
|
||||||
{
|
|
||||||
"cc:0:3:PWh2oBRt6FdusjlahY3hIT0bksZbd53zozHP1aRYRUY:256",
|
|
||||||
"cc:1:25:XkflBmyISKuevH8-850LuMrzN-HT1Ds9zKUEzaZ2Wk0:103",
|
|
||||||
"cc:2:2b:d3O4epRCo_3rj17Bf3v8hp5ig7vq84ivPok07T9Rdl0:146",
|
|
||||||
"cc:3:11:Mjmrcm06fOo-3WOEZu9YDSNfqmn0lj4iOsTVEurtCdI:518",
|
|
||||||
"cc:4:20:O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik:96"
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto cc : ccs)
|
|
||||||
{
|
|
||||||
auto nc = loadCondition (cc);
|
|
||||||
|
|
||||||
if (BEAST_EXPECT (nc && nc != c))
|
|
||||||
{
|
|
||||||
check (f, nc.get(), makeSlice(test), m);
|
|
||||||
check (f, nc.get(), m, m);
|
|
||||||
check (f, nc.get(), { }, m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now try against the correct condition with various
|
|
||||||
// buffers - most are incorrect, some are correct.
|
|
||||||
do
|
|
||||||
{
|
|
||||||
for (Slice t = makeSlice (test); !t.empty(); t += 1)
|
|
||||||
check (f, c, t, m);
|
|
||||||
} while (std::next_permutation(test.begin(), test.end()));
|
|
||||||
|
|
||||||
// And with an empty buffer:
|
|
||||||
check (f, c, Slice { }, m);
|
|
||||||
}
|
|
||||||
|
|
||||||
void testKeySize ()
|
|
||||||
{
|
|
||||||
testcase ("Key Sizes");
|
|
||||||
|
|
||||||
RsaSha256 f1;
|
|
||||||
BEAST_EXPECT (!f1.sign (longKey, makeSlice (knownMessage)));
|
|
||||||
|
|
||||||
RsaSha256 f2;
|
|
||||||
BEAST_EXPECT (!f2.sign (shortKey, makeSlice (knownMessage)));
|
|
||||||
}
|
|
||||||
|
|
||||||
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:3:0:Mjmrcm06fOo-3WOEZu9YDSNfqmn0lj4iOsTVEurtCdI:518");
|
|
||||||
BEAST_EXPECT (!c1);
|
|
||||||
|
|
||||||
// The following will load but fail in different ways
|
|
||||||
auto c2 = loadCondition ( // only sha256
|
|
||||||
"cc:3:1:Mjmrcm06fOo-3WOEZu9YDSNfqmn0lj4iOsTVEurtCdI:518");
|
|
||||||
BEAST_EXPECT (c2 && !validate(*c2));
|
|
||||||
|
|
||||||
auto c3 = loadCondition ( // only preimage
|
|
||||||
"cc:3:2:Mjmrcm06fOo-3WOEZu9YDSNfqmn0lj4iOsTVEurtCdI:518");
|
|
||||||
BEAST_EXPECT (c3 && !validate(*c3));
|
|
||||||
|
|
||||||
auto c4 = loadCondition ( // sha256+preimage
|
|
||||||
"cc:4:3:RCmTBlAEqh5MSPTdAVgZTAI0m8xmTNluQA6iaZGKjVE:96");
|
|
||||||
BEAST_EXPECT (c4 && !validate(*c4));
|
|
||||||
|
|
||||||
auto c5 = loadCondition ( // Ed25519+sha256+preimage
|
|
||||||
"cc:1:23:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
|
||||||
BEAST_EXPECT (c5 && !validate(*c5));
|
|
||||||
|
|
||||||
auto c6 = loadCondition ( // rsa+sha256+threshold
|
|
||||||
"cc:1:19:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
|
||||||
BEAST_EXPECT (c6 && !validate(*c6));
|
|
||||||
|
|
||||||
auto c7 = loadCondition ( // rsa
|
|
||||||
"cc:1:10:Yja3qFj7NS_VwwE7aJjPJos-uFCzStJlJLD4VsNy2XM:1");
|
|
||||||
BEAST_EXPECT (c7 && !validate(*c7));
|
|
||||||
}
|
|
||||||
|
|
||||||
void run ()
|
|
||||||
{
|
|
||||||
testKnown();
|
|
||||||
testDynamic();
|
|
||||||
testKeySize();
|
|
||||||
testMalformedCondition();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE (RsaSha256, conditions, ripple);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
#include <test/app/SetAuth_test.cpp>
|
#include <test/app/SetAuth_test.cpp>
|
||||||
#include <test/app/SetRegularKey_test.cpp>
|
#include <test/app/SetRegularKey_test.cpp>
|
||||||
#include <test/app/SHAMapStore_test.cpp>
|
#include <test/app/SHAMapStore_test.cpp>
|
||||||
#include <test/app/SusPay_test.cpp>
|
#include <test/app/Escrow_test.cpp>
|
||||||
#include <test/app/Taker_test.cpp>
|
#include <test/app/Taker_test.cpp>
|
||||||
#include <test/app/Transaction_ordering_test.cpp>
|
#include <test/app/Transaction_ordering_test.cpp>
|
||||||
#include <test/app/TrustAndBalance_test.cpp>
|
#include <test/app/TrustAndBalance_test.cpp>
|
||||||
|
|||||||
@@ -18,6 +18,3 @@
|
|||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
||||||
#include <test/conditions/PreimageSha256_test.cpp>
|
#include <test/conditions/PreimageSha256_test.cpp>
|
||||||
#include <test/conditions/PrefixSha256_test.cpp>
|
|
||||||
#include <test/conditions/RsaSha256_test.cpp>
|
|
||||||
#include <test/conditions/Ed25519_test.cpp>
|
|
||||||
|
|||||||
Reference in New Issue
Block a user