ERC-7573 Decryption Oracle: Smart Contract for Generation/Verification/Decryption of Encrypted Keys
⚠️ Before you continue: Please read the Disclaimer.
By using this site, software, or contracts, you acknowledge that you have read and accepted it.
Introduction
The finmath keys decryption-oracle project provides open source implementations of the ERC-7573 decryption oracle (for secure stateless delivery-vs-payment).
Interfaces
The batch-enabled interfaces are included with this project and published as
@finmath.net/dvp@0.8.0.
The vendored interfaces have the same declarations, ABI, and NatSpec as that package. Their
declarations are ordered generate, verify, decrypt for readability.
Published Legacy Deployments (2.5.7)
These deployments predate batch key generation. They are incompatible with both the tagged 3.0.0 ABI and the 4.0.1 ABI in this source tree. No public deployment of the 4.0.1 ABI has been published yet.
Ethereum Mainnet
0xa116A2BDbef2BA379eD6eCED40504D4f28c755fc
Polygon Mainnet
0xB387746f1048645F142cAC13e762A3931f3114Ba
Sepolia (Ethereum Testnet)
0xda273EFE2F491903AB3DAf8Bee1A79A8F64e33E0
Amoy (Polygon Testnet)
0x86A6A4707526e230B66FE6E15A321b16000C076f
Use these only with the 2.5.7 interfaces.
Using the Decryption Oracle Contract
The interaction with the decryption oracle is asynchronous following a request*/fulfill* pattern.
Send your request to an instance (address) of the decryption oracle contract using one of the following three functions…
interface IKeyDecryptionOracle {
struct EncryptedKey {
bytes32 keyId;
bytes encryptedKey;
}
function requestGenerateEncryptedHashedKeys(uint256 id, IKeyDecryptionOracleCallback callback, address receiverContract, bytes calldata transaction, bytes32[] calldata keyIds) external payable returns (uint256 requestId);
function requestVerifyEncryptedKeys(uint256 id, EncryptedKey[] calldata keys, IKeyDecryptionOracleCallback callback) external payable returns (uint256 requestId);
function requestDecrypt(uint256 id, bytes calldata encryptedKey, IKeyDecryptionOracleCallback callback, bytes calldata transaction) external payable returns (uint256 requestId);
}
To obtain the result implement the IKeyDecryptionOracleCallback and pass the address of an
instance that should receive the results as callback. The results will then be passed to the corresponding method:
interface IKeyDecryptionOracleCallback {
struct EncryptedHashedKey {
bytes32 keyId;
bytes encryptedKey;
bytes hashedKey;
}
function onEncryptedHashedKeysGenerated(uint256 requestId, EncryptedHashedKey[] calldata keys, address receiverContract, bytes calldata transaction) external;
function onEncryptedKeysVerificationCompleted(uint256 requestId, bool verified, EncryptedHashedKey[] calldata keys, address receiverContract, bytes calldata transaction) external;
function onKeyReleased(uint256 requestId, bytes calldata key) external;
function onKeyDenied(uint256 requestId) external;
}
keyIds must be non-empty and contain distinct semantic identifiers. A one-element
array is the single-key form. The fulfillment must return exactly those identifiers
(in any order), and the proxy delivers the complete result in one callback after
validating the batch, receiverContract, and transaction.
Verification is also atomic and role-tagged. Its callback returns the complete requested
set and an explicit verified result; consumers must not infer rejection from empty data.
The reference proxy accepts at most 32 generation or verification keys and charges
feeGenerate() or feeVerify() per key.
The Java oracle remains protocol-neutral. Its encrypted release-key document contains only the
release secret, eligible receiver, and transaction. Semantic keyId values, consumer id,
requester, replay protection, and outcome meaning belong to the proxy and consuming contract.
Atomic verification covers the exact set named by that verification request. If an application
requires multiple outcome roles, its consumer must submit and validate all of them; verification
of a subset from an earlier generation batch remains a valid generic single-key request.
References may be constructed with the oracle public key. Therefore, applications relying on the
generation flow must authenticate its callback, pin the returned (keyId, encryptedKey, hashedKey)
material, and compare it during verification; reference verification alone is not generation proof.
Generic verification establishes the release-key hash, receiver, and transaction; it does not
establish generator provenance or the semantic meaning of keyId. The 0.8.0 interface's use of
“authenticate” refers to the outer role-tagged tuple together with proxy/consumer request state,
not extra fields inside the encrypted XML document.
Every request returns an oracle-assigned requestId, which is emitted in the request event,
used for fulfillment, and passed to the callback. The consumer-supplied id remains context
in the request event. Consumers must correlate pending callbacks by (oracle, requestId) and
validate the expected operation kind.
Migrating from 3.0.0 to 4.0.1
Version 3.0.0 introduced batch generation through
requestGenerateEncryptedHashedKeys and onEncryptedHashedKeysGenerated, but retained
scalar verification and passed the caller-supplied id to callbacks. Version 4.0.1
replaces scalar verification with requestVerifyEncryptedKeys and
onEncryptedKeysVerificationCompleted; all callbacks now receive the oracle-assigned
requestId instead of the caller's id.
These changes break the 3.0.0 ABI, but the encrypted release-key format is unchanged. Redeploy the
proxy and all callback consumers, and upgrade the off-chain service at the same time. Do not
combine a 4.0.1 contract or consumer with a tagged 3.0.0 service.
Custom proxies used with the reference service must also implement isRequestPending(requestId).
For production, use KeyDecryptionOracle_DefaultPermissioned (or construct the base contract with
requestsPermissionless == false) and allowlist only trusted consumer contracts. Plaintext keys
are visible in fulfillment transaction calldata; callback validation cannot undo disclosure from
an unauthorized request. The permissionless wrapper and DeployForDemo are for local demos only.
IMPORTANT: A compatible deployment may require a small fee to cover the gas cost and protect against
over-use (feeGenerate, feeVerify, feeDecrypt return the current fee in POL or ETH wei;
generation and verification fees are per key). For example, call decrypt via
oracle.requestDecrypt{value: KeyDecryptionOracle(payable(address(oracle))).feeDecrypt()}(
id, encryptedKey, callback, transaction
);
Literature
For a technical/mathematical description of related concepts see https://ssrn.com/abstract=4628811
Standards (Protocols)
IKeyDecryptionOracle and IKeyDecryptionOracleCallback
For the exact interface definition see the solidity page.
ERC-7573 Secure Delivery-versus-Payment
See ERC 7573.
License
The code is distributed under the Apache License version 2.0, unless otherwise explicitly stated.
