Abstract

The interfaces in this proposal model a functional transaction scheme to establish a secure delivery-versus-payment across two blockchains, where a) no intermediary is required and b) one of the two chains can securely interact with a stateless “decryption oracle”. Here, delivery-versus-payment refers to the exchange of, e.g., an asset against a payment; however, the concept is generic to make a transfer of one token on one chain (e.g., the payment) conditional to the successful transfer of another token on another chain (e.g., the asset).

The scheme is realized by two smart contracts, one on each chain. One smart contract implements the ILockingContract interface on one chain (e.g. the “asset chain”), and another smart contract implements the IDecryptionContract interface on the other chain (e.g., the “payment chain”). The smart contract implementing ILockingContract locks a token (e.g., the asset) on its chain until a key is presented to encrypt to one of two given values. The smart contract implementing IDecryptionContract, decrypts one of two keys (via the decryption oracle) conditional to the success or failure of the token transfer (e.g., the payment). A stateless decryption oracle is attached to the chain running IDecryptionContract for the decryption.

Motivation

Within the domain of financial transactions and distributed ledger technology (DLT), the Hash-Linked Contract (HLC) concept has been recognized as valuable and has been thoroughly investigated. The concept may help to solve the challenge of delivery-versus-payment (DvP), especially in cases where the asset chain and payment system (which may be a chain, too) are separated. A prominent application of smart contracts realizing a secure DvP is that of buying an asset, where the asset is managed on one chain (the asset chain), but the payments are executed on another chain (the payment chain). Proposed solutions are based on an API-based interaction mechanism which bridges the communication between a so-called asset chain and a corresponding payment system or requires complex and problematic time locks.1

Here, we propose a protocol that facilitates secure delivery-versus-payment with less overhead, especially with a stateless oracle.2

Specification

Methods

Smart Contract on the chain that performs the locking (e.g. the asset chain)

The following methods specify the functionality of the smart contract implementing the locking. For further information, please also look at the interface documentation ILockingContract.sol.

Initiation of Transfer: inceptTransfer
function inceptTransfer(uint256 id, int amount, address from, string keyHashedSeller, string memory keyEncryptedSeller) external;

Called from the buyer of the token to initiate token transfer. Emits a TransferIncepted event. The parameter id is an identifier of the trade. The parameter from is the address of the seller (the address of the buyer is msg.sender). The parameter keyHashedSeller is a hash of the key that can be used by the seller to (re-)claim the token. The parameter keyEncryptedSeller is an encryption of the key that can be used by the buyer to claim the token. It is possible to implement the protocol in a way where the hashing method agrees with the encryption method. See below on “encryption”.

Initiation of Transfer: confirmTransfer
function confirmTransfer(uint256 id, int amount, address to, string keyHashedBuyer, string memory keyEncryptedBuyer) external;

Called from the seller of the token to confirm token transfer. Emits a TransferConfirmed event. The parameter id is an identifier of the trade. The parameter to is the address of the buyer (the address of the seller is msg.sender). The parameter keyHashedBuyer is a hash of the key that can be used by the buyer to (re-)claim the token. The parameter keyEncryptedBuyer is an encryption of the key that can be used by the buyer to (re-)claim the token. It is possibly to implement the protocol in a way where the hashing method agrees with the encryption method. See below on “encryption”.

If the trade specification, that is, the quadruple (id, amount, from, to), in a call to confirmTransfer matches that of a previous call to inceptTransfer, and the balance is sufficient, the corresponding amount of tokens is locked (transferred from from to the smart contract) and TransferConfirmed is emitted.

Transfer: transferWithKey
function transferWithKey(uint256 id, string memory key) external;

Called from either the buyer or the seller of the token of the trade with id id.

If the method is called from the buyer (to) and the hashing of key matches keyHashedBuyer, then the locked tokens are transferred to the buyer (to). This emits TokenClaimed.

If the method is called from the seller (from) and the hashing of key matches keyHashedSeller, then the locked tokens are transferred (back) to the seller (to). This emits TokenReclaimed.

Summary

The interface ILockingContract:

interface ILockingContract {
    event TransferIncepted(uint256 id, int amount, address from, address to, string keyHashedSeller, string keyEncryptedSeller);
    event TransferConfirmed(uint256 id, int amount, address from, address to, string keyHashedBuyer, string keyEncryptedBuyer);
    event TokenClaimed(uint256 id, string key);
    event TokenReclaimed(uint256 id, string key);

    function inceptTransfer(uint256 id, int amount, address from, string memory keyHashedSeller, string memory keyEncryptedSeller) external;
    function confirmTransfer(uint256 id, int amount, address to, string memory keyHashedBuyer, string memory keyEncryptedBuyer) external;
    function transferWithKey(uint256 id, string memory key) external;
}

Smart Contract on the other chain that performs the conditional decryption (e.g. the payment chain)

The following methods specify the functionality of the smart contract implementing the conditional decryption. For further information, please also look at the interface documentation IDecryptionContract.sol.

Initiation of Transfer: inceptTransfer
function inceptTransfer(uint256 id, int amount, address from, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;

Called from the receiver of the amount to initiate payment transfer. Emits a TransferIncepted. The parameter id is an identifier of the trade. The parameter from is the address of the sender of the payment (the address of the receiver is msg.sender). The parameter keyEncryptedSuccess is an encryption of a key and will be decrypted if the transfer is successful in a call to transferAndDecrypt. The parameter keyEncryptedFailure is an encryption of a key and will be decrypted if the transfer fails in a call to transferAndDecrypt or if cancelAndDecrypt is successful.

Transfer: transferAndDecrypt
function transferAndDecrypt(uint256 id, int amount, address to, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;

Called from the sender of the amount to initiate completion of the payment transfer. Emits a TransferKeyRequested with keys depending on completion success. The parameter id is an identifier of the trade. The parameter to is the address of the receiver of the payment (the sender of the payment (from) is implicitly the msg.sender). The parameter keyEncryptedSuccess is an encryption of the key and will be decrypted if the transfer is successful. The parameter keyEncryptedFailure is an encryption of the key and will be decrypted if the transfer fails.

The method will not decrypt any key and not perform a transfer of a payment if the values (id, amount, from to, keyEncryptedSuccess, keyEncryptedFailure) do not match a previous call to inceptTransfer.

Cancelation of Transfer: cancelAndDecrypt
function cancelAndDecrypt(uint256 id, address from, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;

Called from the receiver of the amount to cancel payment transfer (cancels the incept transfer).

The method must be called from the caller of a previous call to inceptTransfer with the exact same arguments and cancels this specific transfer. If these preconditions are met and a valid call to transferAndDecrypt has not been issued before, i.e. if keyEncryptedSuccess has not been issued in a TransferKeyRequested event, then this method emits a TransferKeyRequested with the key keyEncryptedFailure.

Release of ILockingContract Access Key: releaseKey
function releaseKey(uint256 id, string memory key) external;

Called from the (possibly external) decryption oracle.

Emits the event TransferKeyReleased with the value of key if the call was eligible.

Summary

The interface IDecryptionContract:

interface IDecryptionContract {
    event TransferIncepted(uint256 id, int amount, address from, address to, string keyEncryptedSuccess, string keyEncryptedFailure);
    event TransferKeyRequested(address sender, uint256 id, string encryptedKey);
    event TransferKeyReleased(address sender, uint256 id, bool success, string key);

    function inceptTransfer(uint256 id, int amount, address from, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;
    function transferAndDecrypt(uint256 id, int amount, address to, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;
    function cancelAndDecrypt(uint256 id, address from, string memory keyEncryptedSuccess, string memory keyEncryptedFailure) external;
    function releaseKey(uint256 id, string memory key) external;
}

Encryption and Decryption

The linkage of the two smart contracts relies on use of a key, encryptedKey and hashedKey. The implementation is free to support several encryption methods for as long as the decryption oracle supports it.

The encryption is performed with the public key of the decryption oracle. Either the encryption oracle offers a method performing encryption, in which case the encryption method isn’t even required to be known, or both parties know the public key of the decryption oracle and can perform the generation of the key and its encryption.

It is implicitly assumed that the two parties may check that the strings keyEncryptedBuyer and keyEncryptedSeller are in a valid format.

To avoid on-chain encryption in the ILockingContract, it is possible to use a simpler hashing algorithm on the ILockingContract. In that case, the decryption oracle has to provide a method that allows to obtain the hash H(K) (keyHashed) for an encrypted key E(K) (keyEncrypted) without exposing the key K (``key`), cf. 2.

Sequence diagram of delivery versus payment

The interplay of the two smart contracts is summarized in the following sequence diagram:

sequence diagram dvp

Rationale

The protocol tries to be parsimonious. The transfer is associated with a (preferably unique) id possibly generated by some additional interaction of the trading parties.

The key and the encryptedKey arguments are strings to allow the flexible use of different encryption schemes. The decryption/encryption scheme should be inferable from the contents of the encryptedKey.

Ensuring Secure Key Decryption - Key Format

It has to be ensured that the decryption oracle decrypts a key only for the eligible contract.

It seems as if this would require us to introduce a concept of eligibility to the description oracle, which would imply a kind of state.

A fully stateless decryption can be realized by introducing a document format for the key and a corresponding eligibility verification protocol. We propose the following elements:

  • The (unencrypted) key documents contain the address of the payment contract implementing IDecryptionContract.
  • The decryption oracle offers a stateless function verify that receives an encrypted key and returns the callback address (that will be used for the releaseKey call) that is stored inside the decrypted key without returning the decrypted key.
  • When an encrypted key is presented to the decryption oracle, the oracle decrypts the document and passes the decrypted key to releaseKey of the callback contract address found within the document decrypted key.

We propose the following XML schema for the document of the decrypted key:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" targetNamespace="http://finnmath.net/erc/ILockingContract" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <xs:element name="releaseKey">
        <xs:complexType>
            <xs:simpleContent>
                <xs:extension base="xs:string">
                    <xs:attribute name="contract" type="xs:string" use="required" />
                    <xs:attribute name="transaction" type="xs:unsignedShort" use="required" />
                </xs:extension>
            </xs:simpleContent>
        </xs:complexType>
    </xs:element>
</xs:schema>

A corresponding XML sample is shown below.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<releaseKey contract="eip155:1:0x1234567890abcdef1234567890abcdef12345678" transaction="3141" xmlns="http://finnmath.net/erc/ILockingContract">
    <!-- random data -->
    zZsnePj9ZLPkelpSKUUcg93VGNOPC2oBwX1oCcVwa+U=
</releaseKey>

Security Considerations

The decryption oracle does not need to be a single trusted entity. Instead, a threshold decryption scheme can be employed, where multiple oracles perform partial decryption, requiring a quorum of them to reconstruct the secret key. This enhances security by mitigating the risk associated with a single point of failure or trust.

In such cases, each participating decryption oracle will observe the decryption request from an emitted TransferKeyRequested event, and subsequently call the releaseKey method with a partial decryption result. The following sequence diagram illustrates this.

sequence diagram distributed oracle

See 2 for details.

Copyright and related rights waived via CC0.

    {
      "type": "article",
      "id": 1,
      "author": [
        {
          "family": "La Rocca",
          "given": "Rosario"
        },
        {
          "family": "Mancini",
          "given": "Riccardo"
        },
        {
          "family": "Benedetti",
          "given": "Marco"
        },
        {
          "family": "Caruso",
          "given": "Matteo"
        },
        {
          "family": "Cossu",
          "given": "Stefano"
        },
        {
          "family": "Galano",
          "given": "Giuseppe"
        },
        {
          "family": "Mancini",
          "given": "Simone"
        },
        {
          "family": "Marcelli",
          "given": "Gabriele"
        },
        {
          "family": "Martella",
          "given": "Piero"
        },
        {
          "family": "Nardelli",
          "given": "Matteo"
        },
        {
          "family": "Oliviero",
          "given": "Ciro"
        }
      ],
      "DOI": "10.2139/ssrn.4386904",
      "title": "Integrating DLTs with Market Infrastructures: Analysis and Proof-of-Concept for Secure DvP between TIPS and DLT Platforms",
      "original-date": {
        "date-parts": [
          [2022, 7, 19]
        ]
      },
      "URL": "http://dx.doi.org/10.2139/ssrn.4386904"
    }
    {
      "type": "article",
      "id": 2,
      "author": [
        {
          "family": "Fries",
          "given": "Christian"
        },
        {
          "family": "Kohl-Landgraf",
          "given": "Peter"
        }
      ],
      "DOI": "10.2139/ssrn.4628811",
      "title": "A Proposal for a Lean and Functional Delivery versus Payment across two Blockchains",
      "original-date": {
        "date-parts": [
          [2023, 11, 9]
        ]
      },
      "URL": "http://dx.doi.org/10.2139/ssrn.4628811"
    }