Sapphire Contracts Lib

NPM npm

A library for privacy focused smart contract development.

  • Implementations of OPL smart contracts
  • Sapphire library precompiles and cryptographic primitives
  • Wrapped Rose example

Overview

Installation

$ pnpm install @oasisprotocol/sapphire-contracts

Usage

Once installed, you can import and use the Sapphire contracts as follows:

pragma solidity ^0.8.13;

import "@oasisprotocol/sapphire-contracts/contracts/Sapphire.sol";

contract RandomNumber {
  function generateNumber() public view returns (uint) {
    return uint(bytes32(Sapphire.randomBytes(32, "")));
  }
}

Documentation

See the user's guide for Sapphire and OPL.

The generated API reference is hosted at api.docs.oasis.io.

Generating API docs locally requires Foundry and mdbook-pagetoc. To install them and generate the docs execute:

curl -L https://foundry.paradigm.xyz | bash
cargo install mdbook-pagetoc
pnpm doc

The API docs index will be located in sol/sapphire-contracts/book/index.html.

Contribute

There are many ways you can participate and help build high quality software. Check out the contribution guide!

Contents

Enclave

Git Source

Inherits: Endpoint

The Sapphire-side of an OPL dApp.

Functions

constructor

constructor(address _host, bytes32 _hostChain) Endpoint(_host, _hostChain);

AutoConfigUnavailable

Git Source

Unable to automatically configure OPL. Please use the manual version of the base contract.

error AutoConfigUnavailable();

MissingRemoteAddr

Git Source

The remote endpoint's contract address was missing.

error MissingRemoteAddr();

MissingRemoteChainId

Git Source

The remote endpoint's chain ID was missing.

error MissingRemoteChainId();

SelfCallDisallowed

Git Source

Calls to contracts on the same chain are not allowed unless on a local testnet.

error SelfCallDisallowed();

UnknownEndpoint

Git Source

The requested endpoint does not exist.

error UnknownEndpoint();

Result

Git Source

The outcome of the message call.

enum Result {
    PermanentFailure,
    TransientFailure,
    Success
}

ICelerMessageBus

Git Source

Functions

feeBase

function feeBase() external view returns (uint256);

feePerByte

function feePerByte() external view returns (uint256);

sendMessage

function sendMessage(address _host, uint256 _hostChainId, bytes calldata _message) external payable;

BaseEndpoint

Git Source

State Variables

messageBus

address internal immutable messageBus;

inOrder

bool private immutable inOrder;

remote

address private remote;

remoteChainId

uint256 private remoteChainId;

endpoints

mapping(bytes32 => function(bytes calldata) returns (Result)) private endpoints;

txSeq

uint256 private txSeq;

rxSeq

uint256 private rxSeq;

Functions

constructor

constructor(address _remote, uint256 _remoteChainId, address _messageBus, bool _inOrder);

registerEndpoint

function registerEndpoint(bytes memory _method, function(bytes calldata) returns (Result) _cb) internal;

postMessage

function postMessage(bytes memory _method) internal returns (uint256);

postMessage

Calls the remote endpoint, returning the amount of native token charged for the operation.

function postMessage(bytes memory _method, bytes memory _message) internal returns (uint256);

executeMessage

Celer message bus callback function.

function executeMessage(address _sender, uint64 _senderChainId, bytes calldata _message, address)
    external
    payable
    returns (uint256);

estimateFee

function estimateFee(uint256 _msgLen) internal view returns (uint256);

_isLocalNetwork

function _isLocalNetwork() internal view returns (bool);

Endpoint

Git Source

Inherits: BaseEndpoint

An app that sends or receives using OPL.

Functions

constructor

constructor(address _remote, bytes32 _remoteChainName)
    BaseEndpoint(_remote, _getRemoteChainId(_remoteChainName), _getBus(_remote, _remoteChainName), false);

autoswitch

Git Source

Autoswitch automatically picks the remote network based on the network the contract on which the contract has already been deployed. When on testnet, the remote chain will be the testnet version of the provided chain. When running locally, the remote chain will be this one and the contracts will call each other without going through a message bus. This is helpful for debugging logic but does not test gas fee payment and other moving parts.

function autoswitch(bytes32 protocol) view returns (bytes32 networkName);

_chainName2ChainId

Git Source

function _chainName2ChainId(bytes32 name) pure returns (uint256);

_getRemoteChainId

Git Source

function _getRemoteChainId(bytes32 _remoteChainName) view returns (uint256);

_getChainConfig

Git Source

Configs from https://im-docs.celer.network/developer/contract-addresses-and-rpc-info.

function _getChainConfig(uint256 _chainId) pure returns (address _messageBus, bool _isTestnet);

_getBus

Git Source

function _getBus(address _remote, bytes32 _remoteChainName) view returns (address);

Host

Git Source

Inherits: Endpoint

The L1-side of an OPL dApp.

Functions

constructor

constructor(address _enclave) Endpoint(_enclave, autoswitch("sapphire"));

StakingAddress

Git Source

21 byte version-prefixed address (1 byte version, 20 bytes truncated digest).

type StakingAddress is bytes21;

StakingSecretKey

Git Source

32 byte secret key.

type StakingSecretKey is bytes32;

ConsensusUtils

Git Source

Generate Oasis wallets for use with staking at the consensus level.

State Variables

ADDRESS_V0_CONTEXT_IDENTIFIER

The unique context for v0 staking account addresses.

string private constant ADDRESS_V0_CONTEXT_IDENTIFIER = "oasis-core/address: staking";

ADDRESS_V0_CONTEXT_VERSION

uint8 private constant ADDRESS_V0_CONTEXT_VERSION = 0;

Functions

generateStakingAddress

Generate a random Ed25519 wallet for Oasis consensus-layer staking.

function generateStakingAddress(bytes memory personalization)
    internal
    view
    returns (StakingAddress publicAddress, StakingSecretKey secretKey);

Parameters

NameTypeDescription
personalizationbytesOptional user-specified entropy.

Returns

NameTypeDescription
publicAddressStakingAddressPublic address of the keypair.
secretKeyStakingSecretKeySecret key for the keypair.

_stakingAddressFromPublicKey

Derive the staking address from the public key.

function _stakingAddressFromPublicKey(bytes32 ed25519publicKey) internal view returns (bytes21);

Parameters

NameTypeDescription
ed25519publicKeybytes32Ed25519 public key.

_addressFromData

Derive an Oasis-style address.

function _addressFromData(string memory contextIdentifier, uint8 contextVersion, bytes memory data)
    internal
    view
    returns (bytes21);

Parameters

NameTypeDescription
contextIdentifierstringDomain separator.
contextVersionuint8Domain version.
databytesPublic point of the keypair.

EIP155Signer

Git Source

Functions

encodeSignedTx

Encode a signed EIP-155 transaction.

function encodeSignedTx(EthTx memory rawTx, SignatureRSV memory rsv) internal pure returns (bytes memory);

Parameters

NameTypeDescription
rawTxEthTxTransaction which was signed.
rsvSignatureRSVR, S & V parameters of signature.

signRawTx

Sign a raw transaction, which will then need to be encoded to include the signature.

function signRawTx(EthTx memory rawTx, address pubkeyAddr, bytes32 secretKey)
    internal
    view
    returns (SignatureRSV memory ret);

Parameters

NameTypeDescription
rawTxEthTxTransaction to sign.
pubkeyAddraddressEthereum address of secret key.
secretKeybytes32Secret key used to sign.

sign

Sign a transaction, returning it in EIP-155 encoded form.

function sign(address publicAddress, bytes32 secretKey, EthTx memory transaction)
    internal
    view
    returns (bytes memory);

Parameters

NameTypeDescription
publicAddressaddressEthereum address of secret key.
secretKeybytes32Secret key used to sign.
transactionEthTxTransaction to sign.

Structs

EthTx

struct EthTx {
    uint64 nonce;
    uint256 gasPrice;
    uint64 gasLimit;
    address to;
    uint256 value;
    bytes data;
    uint256 chainId;
}

SignatureRSV

Git Source

struct SignatureRSV {
    bytes32 r;
    bytes32 s;
    uint256 v;
}

EthereumUtils

Git Source

State Variables

K256_P

uint256 internal constant K256_P = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f;

K256_P_PLUS_1_OVER_4

uint256 internal constant K256_P_PLUS_1_OVER_4 = 0x3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffff0c;

PRECOMPILE_BIGMODEXP

address internal constant PRECOMPILE_BIGMODEXP = address(0x5);

Functions

expmod

function expmod(uint256 base, uint256 exponent, uint256 modulus) internal view returns (uint256 out);

k256DeriveY

Recover Y coordinate from X coordinate and sign bit.

function k256DeriveY(uint8 prefix, uint256 x) internal view returns (uint256 y);

Parameters

NameTypeDescription
prefixuint80x02 or 0x03 indicates sign bit of compressed point.
xuint256X coordinate.

k256Decompress

Decompress SEC P256 k1 point.

function k256Decompress(bytes memory pk) internal view returns (uint256 x, uint256 y);

Parameters

NameTypeDescription
pkbytes33 byte compressed public key.

Returns

NameTypeDescription
xuint256X coordinate.
yuint256Y coordinate.

k256PubkeyToEthereumAddress

function k256PubkeyToEthereumAddress(bytes memory pubkey) internal view returns (address);

toEthereumAddress

Convert SEC P256 k1 curve point to Ethereum address.

function toEthereumAddress(uint256 x, uint256 y) internal pure returns (address);

Parameters

NameTypeDescription
xuint256X coordinate.
yuint256Y coordinate.

splitDERSignature

Extracts the r and s parameters from a DER encoded ECDSA signature. The signature is an ASN1 encoded SEQUENCE of the variable length r and s INTEGERs.

| 0x30 | len(z) | 0x02 | len(r) |  r   | 0x02 | len(s) |  s   | = hex value
|  1   |   1    |   1  |   1    | 1-33 |  1   |   1    | 1-33 | = byte length

If the highest bit of either r or s is set, it will be prefix padded with a zero byte. There is exponentially decreasing probability that either r or s will be below 32 bytes. There is a very high probability that either r or s will be 33 bytes. This function only works if either r or s are 256bits or lower.

function splitDERSignature(bytes memory der) internal pure returns (SignatureRSV memory rsv);

Parameters

NameTypeDescription
derbytesDER encoded ECDSA signature

Returns

NameTypeDescription
rsvSignatureRSVECDSA R point X coordinate, and S scalar

recoverV

function recoverV(address pubkeyAddr, bytes32 digest, SignatureRSV memory rsv) internal pure;

toEthereumSignature

Convert a Secp256k1PrehashedKeccak256 signature to one accepted by ecrecover.

function toEthereumSignature(bytes memory pubkey, bytes32 digest, bytes memory signature)
    internal
    view
    returns (address pubkeyAddr, SignatureRSV memory rsv);

Parameters

NameTypeDescription
pubkeybytes33 byte compressed public key.
digestbytes3232 byte pre-hashed message digest.
signaturebytesASN.1 DER encoded signature, as returned from Sapphire.sign.

Returns

NameTypeDescription
pubkeyAddraddress20 byte Ethereum address.
rsvSignatureRSVEthereum EcDSA RSV signature values.

sign

function sign(address pubkeyAddr, bytes32 secretKey, bytes32 digest) internal view returns (SignatureRSV memory rsv);

generateKeypair

Generate an Ethereum compatible SEC P256 k1 keypair and corresponding public address.

function generateKeypair() internal view returns (address pubkeyAddr, bytes32 secretKey);

Returns

NameTypeDescription
pubkeyAddraddressEthereum address.
secretKeybytes32Secret key used for signing.

Errors

expmod_Error

error expmod_Error();

k256DeriveY_Invalid_Prefix_Error

error k256DeriveY_Invalid_Prefix_Error();

k256Decompress_Invalid_Length_Error

error k256Decompress_Invalid_Length_Error();

DER_Split_Error

error DER_Split_Error();

recoverV_Error

error recoverV_Error();

RLPWriter

Git Source

Author: RLPWriter is a library for encoding Solidity types to RLP bytes. Adapted from Bakaoh's RLPEncode library (https://github.com/bakaoh/solidity-rlp-encode) with minor modifications to improve legibility.

Functions

writeBytes

RLP encodes a byte string.

function writeBytes(bytes memory _in) internal pure returns (bytes memory);

Parameters

NameTypeDescription
_inbytesThe byte string to encode.

Returns

NameTypeDescription
<none>bytesThe RLP encoded string in bytes.

writeList

RLP encodes a list of RLP encoded byte byte strings.

function writeList(bytes memory _in) internal pure returns (bytes memory);

Parameters

NameTypeDescription
_inbytesThe RLP encoded byte strings.

Returns

NameTypeDescription
<none>bytesThe RLP encoded list of items in bytes.

writeList

RLP encodes a list of RLP encoded byte byte strings.

function writeList(bytes[] memory _in) internal pure returns (bytes memory);

Parameters

NameTypeDescription
_inbytes[]The list of RLP encoded byte strings.

Returns

NameTypeDescription
<none>bytesThe RLP encoded list of items in bytes.

writeString

RLP encodes a string.

function writeString(string memory _in) internal pure returns (bytes memory);

Parameters

NameTypeDescription
_instringThe string to encode.

Returns

NameTypeDescription
<none>bytesThe RLP encoded string in bytes.

writeAddress

RLP encodes an address.

function writeAddress(address _in) internal pure returns (bytes memory);

Parameters

NameTypeDescription
_inaddressThe address to encode.

Returns

NameTypeDescription
<none>bytesThe RLP encoded address in bytes.

writeUint

RLP encodes a uint.

function writeUint(uint256 _in) internal pure returns (bytes memory);

Parameters

NameTypeDescription
_inuint256The uint256 to encode.

Returns

NameTypeDescription
<none>bytesThe RLP encoded uint256 in bytes.

writeBool

RLP encodes a bool.

function writeBool(bool _in) internal pure returns (bytes memory);

Parameters

NameTypeDescription
_inboolThe bool to encode.

Returns

NameTypeDescription
<none>bytesThe RLP encoded bool in bytes.

_writeLength

Encode the first byte and then the len in binary form if length is more than 55.

function _writeLength(uint256 _len, uint256 _offset) private pure returns (bytes memory);

Parameters

NameTypeDescription
_lenuint256The length of the string or the payload.
_offsetuint256128 if item is string, 192 if item is list.

Returns

NameTypeDescription
<none>bytesRLP encoded bytes.

_toBinary

Encode integer in big endian binary form with no leading zeroes.

function _toBinary(uint256 _x) private pure returns (bytes memory);

Parameters

NameTypeDescription
_xuint256The integer to encode.

Returns

NameTypeDescription
<none>bytesRLP encoded bytes.

_memcpy

Copies a piece of memory to another location.

function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure;

Parameters

NameTypeDescription
_destuint256Destination location.
_srcuint256Source location.
_lenuint256Length of memory to copy.

_flatten

Flattens a list of byte strings into one byte string.

function _flatten(bytes[] memory _list) private pure returns (bytes memory);

Parameters

NameTypeDescription
_listbytes[]List of byte strings to flatten.

Returns

NameTypeDescription
<none>bytesThe flattened byte string.

Sapphire

Git Source

This library provides a number of convenient wrappers for cryptographic operations such as the x25519 key derivation, Deoxys-II-based encryption and decryption, signing key generation, message digest signing and verification, gas padding and hashing. Most of the mentioned functions are implemented as Sapphire's precompiles and are cheap to call.

Calling Precompiles Manually

You can override the wrappers and call Sapphire precompiles by dispatching calls to specific well-known contract addresses, as described below. The Precompile address section of each function will show you the address of the corresponding precompile. Input parameters should be packed into a contiguous memory region with each chunk of data padded to 32 bytes as usual. The recommended way to construct parameter byte sequences in Solidity is with abi.encode and abi.decode, which will transparently handle things like putting bytes lengths in the correct position.

State Variables

RANDOM_BYTES

address internal constant RANDOM_BYTES = 0x0100000000000000000000000000000000000001;

DERIVE_KEY

address internal constant DERIVE_KEY = 0x0100000000000000000000000000000000000002;

ENCRYPT

address internal constant ENCRYPT = 0x0100000000000000000000000000000000000003;

DECRYPT

address internal constant DECRYPT = 0x0100000000000000000000000000000000000004;

GENERATE_SIGNING_KEYPAIR

address internal constant GENERATE_SIGNING_KEYPAIR = 0x0100000000000000000000000000000000000005;

SIGN_DIGEST

address internal constant SIGN_DIGEST = 0x0100000000000000000000000000000000000006;

VERIFY_DIGEST

address internal constant VERIFY_DIGEST = 0x0100000000000000000000000000000000000007;

CURVE25519_PUBLIC_KEY

address internal constant CURVE25519_PUBLIC_KEY = 0x0100000000000000000000000000000000000008;

GAS_USED

address internal constant GAS_USED = 0x0100000000000000000000000000000000000009;

PAD_GAS

address internal constant PAD_GAS = 0x010000000000000000000000000000000000000a;

SHA512_256

address internal constant SHA512_256 = 0x0100000000000000000000000000000000000101;

SHA512

address internal constant SHA512 = 0x0100000000000000000000000000000000000102;

SHA384

address internal constant SHA384 = 0x0100000000000000000000000000000000000104;

Functions

randomBytes

Generate num_bytes pseudo-random bytes, with an optional personalization string (pers) added into the hashing algorithm to increase domain separation when needed.

Precompile address

0x0100000000000000000000000000000000000001

Gas cost

10,000 minimum plus 240 per output word plus 60 per word of the personalization string.

Implementation details

The mode (e.g. simulation or "view call" vs transaction execution) is fed to TupleHash (among other block-dependent components) to derive the "key id", which is then used to derive a per-block VRF key from epoch-ephemeral entropy (using KMAC256 and cSHAKE) so a different key id will result in a unique per-block VRF key. This per-block VRF key is then used to create the per-block root RNG which is then used to derive domain-separated (using Merlin transcripts) per-transaction random RNGs which are then exposed via this precompile. The KMAC, cSHAKE and TupleHash algorithms are SHA-3 derived functions defined in NIST Special Publication 800-185.

DANGER: Prior to Sapphire ParaTime 0.6.0

All view queries and simulated transactions (via eth_call) would receive the same entropy in-between blocks if they use the same num_bytes and pers parameters. If your contract requires confidentiality you should generate a secret in the constructor to be used with view calls:

Sapphire.randomBytes(64, abi.encodePacked(msg.sender, this.perContactSecret));

Example

bytes memory randomPad = Sapphire.randomBytes(64, "");
function randomBytes(uint256 numBytes, bytes memory pers) internal view returns (bytes memory);

Parameters

NameTypeDescription
numBytesuint256The number of bytes to return.
persbytesAn optional personalization string to increase domain separation.

Returns

NameTypeDescription
<none>bytesThe random bytes. If the number of bytes requested is too large (over 1024), a smaller amount (1024) will be returned.

generateCurve25519KeyPair

Generates a Curve25519 keypair.

function generateCurve25519KeyPair(bytes memory pers)
    internal
    view
    returns (Curve25519PublicKey pk, Curve25519SecretKey sk);

Parameters

NameTypeDescription
persbytesAn optional personalization string used to add domain separation.

Returns

NameTypeDescription
pkCurve25519PublicKeyThe Curve25519 public key. Useful for key exchange.
skCurve25519SecretKeyThe Curve25519 secret key. Pairs well with deriveSymmetricKey.

deriveSymmetricKey

Derive a symmetric key from a pair of keys using x25519.

Precompile address

0x0100000000000000000000000000000000000002

Gas cost

100,000

Example

bytes32 publicKey = ... ;
bytes32 privateKey = ... ;
bytes32 symmetric = Sapphire.deriveSymmetricKey(publicKey, privateKey);
function deriveSymmetricKey(Curve25519PublicKey peerPublicKey, Curve25519SecretKey secretKey)
    internal
    view
    returns (bytes32);

Parameters

NameTypeDescription
peerPublicKeyCurve25519PublicKeyThe peer's public key.
secretKeyCurve25519SecretKeyYour secret key.

Returns

NameTypeDescription
<none>bytes32A derived symmetric key.

encrypt

Encrypt and authenticate the plaintext and additional data using DeoxysII.

Precompile address

0x0100000000000000000000000000000000000003

Gas cost

50,000 minimum plus 100 per word of input

Example

bytes32 key = ... ;
bytes32 nonce = ... ;
bytes memory text = "plain text";
bytes memory ad = "additional data";
bytes memory encrypted = Sapphire.encrypt(key, nonce, text, ad);
bytes memory decrypted = Sapphire.decrypt(key, nonce, encrypted, ad);
function encrypt(bytes32 key, bytes32 nonce, bytes memory plaintext, bytes memory additionalData)
    internal
    view
    returns (bytes memory);

Parameters

NameTypeDescription
keybytes32The key to use for encryption.
noncebytes32The nonce. Note that only the first 15 bytes of this parameter are used.
plaintextbytesThe plaintext to encrypt and authenticate.
additionalDatabytesThe additional data to authenticate.

Returns

NameTypeDescription
<none>bytesThe ciphertext with appended auth tag.

decrypt

Decrypt and authenticate the ciphertext and additional data using DeoxysII. Reverts if the auth tag is incorrect.

Precompile address

0x0100000000000000000000000000000000000004

Gas cost

50,000 minimum plus 100 per word of input

Example

bytes32 key = ... ;
bytes32 nonce = ... ;
bytes memory text = "plain text";
bytes memory ad = "additional data";
bytes memory encrypted = Sapphire.encrypt(key, nonce, text, ad);
bytes memory decrypted = Sapphire.decrypt(key, nonce, encrypted, ad);
function decrypt(bytes32 key, bytes32 nonce, bytes memory ciphertext, bytes memory additionalData)
    internal
    view
    returns (bytes memory);

Parameters

NameTypeDescription
keybytes32The key to use for decryption.
noncebytes32The nonce. Note that only the first 15 bytes of this parameter are used.
ciphertextbytesThe ciphertext with tag to decrypt and authenticate.
additionalDatabytesThe additional data to authenticate against the ciphertext.

Returns

NameTypeDescription
<none>bytesThe original plaintext.

generateSigningKeyPair

Generate a public/private key pair using the specified method and seed. The available methods are items in the Sapphire.SigningAlg enum. Note, however, that the generation method ignores subvariants, so all three Ed25519-based are equivalent, and all Secp256k1 & Secp256r1 based methods are equivalent. Sr25519 is not available and will return an error.

Precompile address

0x0100000000000000000000000000000000000005

Gas Cost

Ed25519: 1,000 gas
  • 0 (Ed25519Oasis)
  • 1 (Ed25519Pure)
  • 2 (Ed25519PrehashedSha512)
Secp256k1: 1,500 gas.
  • 3 (Secp256k1Oasis)
  • 4 (Secp256k1PrehashedKeccak256)
  • 5 (Secp256k1PrehashedSha256)
Secp256r1: 4,000 gas
  • 7 (Secp256r1PrehashedSha256)

Public Key Format

Ed25519

32 bytes

Secp256k1 & Secp256r1

33 bytes, compressed format (0x02 or 0x03 prefix, then 32 byte X coordinate).

Example

bytes memory seed = hex"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef";
bytes memory publicKey;
bytes memory privateKey;
(publicKey, privateKey) = Sapphire.generateSigningKeyPair(Sapphire.SigningAlg.Ed25519Pure, seed);
function generateSigningKeyPair(SigningAlg alg, bytes memory seed)
    internal
    view
    returns (bytes memory publicKey, bytes memory secretKey);

Parameters

NameTypeDescription
algSigningAlgThe signing alg for which to generate a keypair.
seedbytesThe seed to use for generating the key pair. You can use the randomBytes method if you don't already have a seed.

Returns

NameTypeDescription
publicKeybytesThe public half of the keypair.
secretKeybytesThe secret half of the keypair.

sign

Sign a message within the provided context using the specified algorithm, and return the signature. The context_or_digest and messages parameters change in meaning slightly depending on the method requested. For methods that take a context in addition to the message you must pass the context in the context_or_digest parameter and use message as expected. For methods that take a pre-existing hash of the message, pass that in context_or_digest and leave message empty. Specifically the Ed25519Oasis and Secp256k1Oasis variants take both a context and a message (each are variable length bytes), the context serves as a domain separator.

Precompile address

0x0100000000000000000000000000000000000006

Gas cost

See below for the method-dependent base cost, plus 8 gas per 32 bytes of context and message except digest.

Signing algorithms

  • 0 (Ed25519Oasis): 1,500 gas, variable length context and message.
  • 1 (Ed25519Pure): 1,500 gas, empty context, variable length message.
  • 2 (Ed25519PrehashedSha512): 1,500 gas, pre-existing SHA-512 hash (64 bytes) as context, empty message.
  • 3 (Secp256k1Oasis): 3,000 gas, variable length context and message
  • 4 (Secp256k1PrehashedKeccak256): 3,000 gas, pre-existing hash (32 bytes) as context, empty message.
  • 5 (Secp256k1PrehashedSha256): 3,000 gas, pre-existing hash (32 bytes) as context, empty message.
  • 7 (Secp256r1PrehashedSha256): 9,000 gas, pre-existing hash (32 bytes) as context, empty message.

Example

Sapphire.SigningAlg alg = Sapphire.SigningAlg.Ed25519Pure;
bytes memory pk;
bytes memory sk;
(pk, sk) = Sapphire.generateSigningKeyPair(alg, Sapphire.randomBytes(32, ""));
bytes memory signature = Sapphire.sign(alg, sk, "", "signed message");
function sign(SigningAlg alg, bytes memory secretKey, bytes memory contextOrHash, bytes memory message)
    internal
    view
    returns (bytes memory signature);

Parameters

NameTypeDescription
algSigningAlgThe signing algorithm to use.
secretKeybytesThe secret key to use for signing. The key must be valid for use with the requested algorithm.
contextOrHashbytesDomain-Separator Context, or precomputed hash bytes.
messagebytesMessage to sign, should be zero-length if precomputed hash given.

Returns

NameTypeDescription
signaturebytesThe resulting signature.

verify

Verifies that the provided digest was signed with using the secret key corresponding to the provided private key and the specified signing algorithm. The method, context_or_digest and message parameters have the same meaning as described above in the sign() function.

Precompile address

0x0100000000000000000000000000000000000007

Gas cost

The algorithm-specific base cost below, with an additional 8 gas per 32 bytes of context and message for the Ed25519Oasis, Ed25519Pure and Secp256k1Oasis algorithms.

  • 0 (Ed25519Oasis): 2,000 gas
  • 1 (Ed25519Pure): 2,000 gas
  • 2 (Ed25519PrehashedSha512): 2,000 gas
  • 3 (Secp256k1Oasis): 3,000 gas
  • 4 (Secp256k1PrehashedKeccak256): 3,000 gas
  • 5 (Secp256k1PrehashedSha256): 3,000 gas
  • 7 (Secp256r1PrehashedSha256): 7,900 gas

Example

Sapphire.SigningAlg alg = Sapphire.SigningAlg.Secp256k1PrehashedKeccak256;
bytes memory pk;
bytes memory sk;
bytes memory digest = abi.encodePacked(keccak256("signed message"));
(pk, sk) = Sapphire.generateSigningKeyPair(alg, Sapphire.randomBytes(32, ""));
bytes memory signature = Sapphire.sign(alg, sk, digest, "");
require( Sapphire.verify(alg, pk, digest, "", signature) );
function verify(
    SigningAlg alg,
    bytes memory publicKey,
    bytes memory contextOrHash,
    bytes memory message,
    bytes memory signature
) internal view returns (bool verified);

Parameters

NameTypeDescription
algSigningAlgThe signing algorithm by which the signature was generated.
publicKeybytesThe public key against which to check the signature.
contextOrHashbytesDomain-Separator Context, or precomputed hash bytes
messagebytesThe hash of the message that was signed, should be zero-length if precomputed hash was given.
signaturebytesThe signature to check.

Returns

NameTypeDescription
verifiedboolWhether the signature is valid for the given parameters.

padGas

Set the current transactions gas usage to a specific amount

Will cause a reversion if the current usage is more than the amount.

function padGas(uint128 toAmount) internal view;

Parameters

NameTypeDescription
toAmountuint128Gas usage will be set to this amount

gasUsed

Returns the amount of gas currently used by the transaction

function gasUsed() internal view returns (uint64);

Enums

SigningAlg

enum SigningAlg {
    Ed25519Oasis,
    Ed25519Pure,
    Ed25519PrehashedSha512,
    Secp256k1Oasis,
    Secp256k1PrehashedKeccak256,
    Secp256k1PrehashedSha256,
    Sr25519,
    Secp256r1PrehashedSha256,
    Secp384r1PrehashedSha384
}

sha384

Git Source

Hash the input data with SHA-384.

function sha384(bytes memory input) view returns (bytes memory output);

Parameters

NameTypeDescription
inputbytesBytes to hash.

Returns

NameTypeDescription
outputbytes48 byte digest.

sha512_256

Git Source

Hash the input data with SHA-512/256, according to NIST.FIPS.180-4.

Precompile address

0x0100000000000000000000000000000000000102

Gas cost

115 gas, then 13 gas per word

Example

bytes32 result = sha512_256(abi.encodePacked("input data"));

Warning: SHA-512 vs SHA-512/256 Length-Extension Attacks

SHA-512 is vulnerable to length-extension attacks, which are relevant if you are computing the hash of a secret message. The SHA-512/256 variant is not vulnerable to length-extension attacks.

function sha512_256(bytes memory input) view returns (bytes32 result);

Parameters

NameTypeDescription
inputbytesBytes to hash.

Returns

NameTypeDescription
resultbytes3232 byte digest.

sha512

Git Source

Hash the input data with SHA-512, according to NIST.FIPS.180-4

Precompile address

0x0100000000000000000000000000000000000101

Warning: SHA-512 vs SHA-512/256 Length-Extension Attacks

SHA-512 is vulnerable to length-extension attacks, which are relevant if you are computing the hash of a secret message. The SHA-512/256 variant is not vulnerable to length-extension attacks.

Gas Cost

115 gas, then 13 gas per word

Example

bytes memory result = sha512(abi.encodePacked("input data"));
function sha512(bytes memory input) view returns (bytes memory output);

Parameters

NameTypeDescription
inputbytesBytes to hash.

Returns

NameTypeDescription
outputbytes64 byte digest.

SubcallReceiptKind

Git Source

enum SubcallReceiptKind {
    Invalid,
    Delegate,
    UndelegateStart,
    UndelegateDone
}

Subcall

Git Source

Interact with Oasis Runtime SDK modules from Sapphire.

State Variables

CONSENSUS_DELEGATE

string private constant CONSENSUS_DELEGATE = "consensus.Delegate";

CONSENSUS_UNDELEGATE

string private constant CONSENSUS_UNDELEGATE = "consensus.Undelegate";

CONSENSUS_WITHDRAW

string private constant CONSENSUS_WITHDRAW = "consensus.Withdraw";

CONSENSUS_TAKE_RECEIPT

string private constant CONSENSUS_TAKE_RECEIPT = "consensus.TakeReceipt";

ACCOUNTS_TRANSFER

string private constant ACCOUNTS_TRANSFER = "accounts.Transfer";

SUBCALL

Address of the SUBCALL precompile

address internal constant SUBCALL = 0x0100000000000000000000000000000000000103;

Functions

subcall

Submit a native message to the Oasis runtime layer. Messages which re-enter the EVM module are forbidden: evm.*.

function subcall(string memory method, bytes memory body) internal returns (uint64 status, bytes memory data);

Parameters

NameTypeDescription
methodstringNative message type.
bodybytesCBOR encoded body.

Returns

NameTypeDescription
statusuint64Result of call.
databytesCBOR encoded result.

_subcallWithToAndAmount

Generic method to call {to:address, amount:uint128}.

function _subcallWithToAndAmount(string memory method, StakingAddress to, uint128 value, bytes memory token)
    internal
    returns (uint64 status, bytes memory data);

Parameters

NameTypeDescription
methodstringRuntime SDK method name ('module.Action').
toStakingAddressDestination address.
valueuint128Amount specified.
tokenbytes

Returns

NameTypeDescription
statusuint64Non-zero on error.
databytesModule name on error.

consensusTakeReceipt

Returns a CBOR encoded structure, containing the following possible keys. All keys are optional:

  • shares: u128
  • epoch: EpochTime
  • receipt: u64
  • amount: u128
  • error: {module: string, code: u32}

Keys returned by specific subcalls

  • Delegate will have the error or shares keys.
  • UndelegateStart will have the epoch and receipt keys.
  • UndelegateDone will have the amount key.
function consensusTakeReceipt(SubcallReceiptKind kind, uint64 receiptId) internal returns (bytes memory);

Parameters

NameTypeDescription
kindSubcallReceiptKind1 (Delegate), 2 (UndelegateStart) or 3 (UndelegateDone)
receiptIduint64ID of receipt

_parseCBORUint

function _parseCBORUint(bytes memory result, uint256 offset) public pure returns (uint256 newOffset, uint256 value);

_parseCBORUint64

function _parseCBORUint64(bytes memory result, uint256 offset) public pure returns (uint256 newOffset, uint64 value);

_parseCBORUint128

function _parseCBORUint128(bytes memory result, uint256 offset)
    public
    pure
    returns (uint256 newOffset, uint128 value);

_parseCBORKey

function _parseCBORKey(bytes memory result, uint256 offset)
    internal
    pure
    returns (uint256 newOffset, bytes32 keyDigest);

_decodeReceiptUndelegateStart

function _decodeReceiptUndelegateStart(bytes memory result) internal pure returns (uint64 epoch, uint64 endReceipt);

_decodeReceiptUndelegateDone

function _decodeReceiptUndelegateDone(bytes memory result) internal pure returns (uint128 amount);

_decodeReceiptDelegate

Decodes a 'Delegate' receipt.

function _decodeReceiptDelegate(uint64 receiptId, bytes memory result) internal pure returns (uint128 shares);

Parameters

NameTypeDescription
receiptIduint64Previously unretrieved receipt.
resultbytesCBOR encoded {shares: u128}.

consensusTakeReceiptDelegate

function consensusTakeReceiptDelegate(uint64 receiptId) internal returns (uint128 shares);

consensusTakeReceiptUndelegateStart

function consensusTakeReceiptUndelegateStart(uint64 receiptId) internal returns (uint64 epoch, uint64 endReceipt);

consensusTakeReceiptUndelegateDone

function consensusTakeReceiptUndelegateDone(uint64 receiptId) internal returns (uint128 amount);

consensusUndelegate

Start the undelegation process of the given number of shares from consensus staking account to runtime account.

function consensusUndelegate(StakingAddress from, uint128 shares) internal;

Parameters

NameTypeDescription
fromStakingAddressConsensus address which shares were delegated to.
sharesuint128Number of shares to withdraw back to us.

consensusUndelegate

function consensusUndelegate(StakingAddress from, uint128 shares, uint64 receiptId) internal;

consensusDelegate

Delegate native token to consensus level.

function consensusDelegate(StakingAddress to, uint128 amount) internal returns (bytes memory data);

Parameters

NameTypeDescription
toStakingAddressConsensus address shares are delegated to.
amountuint128Native token amount (in wei).

consensusDelegate

Delegate native token to consensus level. Requests that the number of shares allocated can be retrieved with a receipt. The receipt will be of ReceiptKind.DelegateDone and can be decoded using decodeReceiptDelegateDone.

function consensusDelegate(StakingAddress to, uint128 amount, uint64 receiptId) internal returns (bytes memory data);

Parameters

NameTypeDescription
toStakingAddressConsensus address shares are delegated to.
amountuint128Native token amount (in wei).
receiptIduint64contract-specific receipt to retrieve result.

consensusWithdraw

Transfer from an account in this runtime to a consensus staking account.

function consensusWithdraw(StakingAddress to, uint128 value) internal;

Parameters

NameTypeDescription
toStakingAddressConsensus address which gets the tokens.
valueuint128Token amount (in wei).

accountsTransfer

Perform a transfer to another account. This is equivalent of payable(to).transfer(value);.

function accountsTransfer(address to, uint128 value) internal;

Parameters

NameTypeDescription
toaddressDestination account.
valueuint128native token amount (in wei).

Errors

SubcallError

Raised if the underlying subcall precompile does not succeed

error SubcallError();

ParseReceiptError

There was an error parsing the receipt

error ParseReceiptError(uint64 receiptId);

ConsensusUndelegateError

error ConsensusUndelegateError(uint64 status, string data);

ConsensusDelegateError

error ConsensusDelegateError(uint64 status, string data);

ConsensusTakeReceiptError

error ConsensusTakeReceiptError(uint64 status, string data);

ConsensusWithdrawError

error ConsensusWithdrawError(uint64 status, string data);

AccountsTransferError

error AccountsTransferError(uint64 status, string data);

TokenNameTooLong

Name of token cannot be CBOR encoded with current functions

error TokenNameTooLong();

InvalidKey

While parsing CBOR map, unexpected key

error InvalidKey();

InvalidMap

While parsing CBOR map, length is invalid, or other parse error

error InvalidMap();

InvalidLength

While parsing CBOR structure, data length was unexpected

error InvalidLength();

InvalidReceiptId

Invalid receipt ID

error InvalidReceiptId();

ValueOutOfRange

CBOR parsed valid is out of expected range

error ValueOutOfRange();

MissingKey

CBOR parser expected a key, but it was not found in the map!

error MissingKey();

WrappedROSE

Git Source

Inherits: ERC20, ERC20Burnable

Functions

constructor

constructor() ERC20("Wrapped ROSE", "wROSE");

deposit

function deposit() external payable;

withdraw

function withdraw(uint256 amount) external;

receive

receive() external payable;

_deposit

function _deposit() internal;

Events

Deposit

event Deposit(address indexed dst, uint256 wad);

Withdrawal

event Withdrawal(address indexed src, uint256 wad);