Sapphire Contracts Lib
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
- AutoConfigUnavailable
- MissingRemoteAddr
- MissingRemoteChainId
- SelfCallDisallowed
- UnknownEndpoint
- Result
- ICelerMessageBus
- BaseEndpoint
- Endpoint
- autoswitch
- _chainName2ChainId
- _getRemoteChainId
- _getChainConfig
- _getBus
- Host
Enclave
Inherits: Endpoint
The Sapphire-side of an OPL dApp.
Functions
constructor
constructor(address _host, bytes32 _hostChain) Endpoint(_host, _hostChain);
AutoConfigUnavailable
Unable to automatically configure OPL. Please use the manual version of the base contract.
error AutoConfigUnavailable();
MissingRemoteAddr
The remote endpoint's contract address was missing.
error MissingRemoteAddr();
MissingRemoteChainId
The remote endpoint's chain ID was missing.
error MissingRemoteChainId();
SelfCallDisallowed
Calls to contracts on the same chain are not allowed unless on a local testnet.
error SelfCallDisallowed();
UnknownEndpoint
The requested endpoint does not exist.
error UnknownEndpoint();
Result
The outcome of the message call.
enum Result {
PermanentFailure,
TransientFailure,
Success
}
ICelerMessageBus
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
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
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
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
function _chainName2ChainId(bytes32 name) pure returns (uint256);
_getRemoteChainId
function _getRemoteChainId(bytes32 _remoteChainName) view returns (uint256);
_getChainConfig
Configs from https://im-docs.celer.network/developer/contract-addresses-and-rpc-info.
function _getChainConfig(uint256 _chainId) pure returns (address _messageBus, bool _isTestnet);
_getBus
function _getBus(address _remote, bytes32 _remoteChainName) view returns (address);
Host
Inherits: Endpoint
The L1-side of an OPL dApp.
Functions
constructor
constructor(address _enclave) Endpoint(_enclave, autoswitch("sapphire"));
StakingAddress
21 byte version-prefixed address (1 byte version, 20 bytes truncated digest).
type StakingAddress is bytes21;
StakingSecretKey
32 byte secret key.
type StakingSecretKey is bytes32;
ConsensusUtils
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
Name | Type | Description |
---|---|---|
personalization | bytes | Optional user-specified entropy. |
Returns
Name | Type | Description |
---|---|---|
publicAddress | StakingAddress | Public address of the keypair. |
secretKey | StakingSecretKey | Secret key for the keypair. |
_stakingAddressFromPublicKey
Derive the staking address from the public key.
function _stakingAddressFromPublicKey(bytes32 ed25519publicKey) internal view returns (bytes21);
Parameters
Name | Type | Description |
---|---|---|
ed25519publicKey | bytes32 | Ed25519 public key. |
_addressFromData
Derive an Oasis-style address.
function _addressFromData(string memory contextIdentifier, uint8 contextVersion, bytes memory data)
internal
view
returns (bytes21);
Parameters
Name | Type | Description |
---|---|---|
contextIdentifier | string | Domain separator. |
contextVersion | uint8 | Domain version. |
data | bytes | Public point of the keypair. |
EIP155Signer
Functions
encodeSignedTx
Encode a signed EIP-155 transaction.
function encodeSignedTx(EthTx memory rawTx, SignatureRSV memory rsv) internal pure returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
rawTx | EthTx | Transaction which was signed. |
rsv | SignatureRSV | R, 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
Name | Type | Description |
---|---|---|
rawTx | EthTx | Transaction to sign. |
pubkeyAddr | address | Ethereum address of secret key. |
secretKey | bytes32 | Secret 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
Name | Type | Description |
---|---|---|
publicAddress | address | Ethereum address of secret key. |
secretKey | bytes32 | Secret key used to sign. |
transaction | EthTx | Transaction to sign. |
Structs
EthTx
struct EthTx {
uint64 nonce;
uint256 gasPrice;
uint64 gasLimit;
address to;
uint256 value;
bytes data;
uint256 chainId;
}
SignatureRSV
struct SignatureRSV {
bytes32 r;
bytes32 s;
uint256 v;
}
EthereumUtils
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
Name | Type | Description |
---|---|---|
prefix | uint8 | 0x02 or 0x03 indicates sign bit of compressed point. |
x | uint256 | X coordinate. |
k256Decompress
Decompress SEC P256 k1 point.
function k256Decompress(bytes memory pk) internal view returns (uint256 x, uint256 y);
Parameters
Name | Type | Description |
---|---|---|
pk | bytes | 33 byte compressed public key. |
Returns
Name | Type | Description |
---|---|---|
x | uint256 | X coordinate. |
y | uint256 | Y 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
Name | Type | Description |
---|---|---|
x | uint256 | X coordinate. |
y | uint256 | Y 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
Name | Type | Description |
---|---|---|
der | bytes | DER encoded ECDSA signature |
Returns
Name | Type | Description |
---|---|---|
rsv | SignatureRSV | ECDSA 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
Name | Type | Description |
---|---|---|
pubkey | bytes | 33 byte compressed public key. |
digest | bytes32 | 32 byte pre-hashed message digest. |
signature | bytes | ASN.1 DER encoded signature, as returned from Sapphire.sign . |
Returns
Name | Type | Description |
---|---|---|
pubkeyAddr | address | 20 byte Ethereum address. |
rsv | SignatureRSV | Ethereum 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
Name | Type | Description |
---|---|---|
pubkeyAddr | address | Ethereum address. |
secretKey | bytes32 | Secret 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
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
Name | Type | Description |
---|---|---|
_in | bytes | The byte string to encode. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The 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
Name | Type | Description |
---|---|---|
_in | bytes | The RLP encoded byte strings. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The 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
Name | Type | Description |
---|---|---|
_in | bytes[] | The list of RLP encoded byte strings. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The RLP encoded list of items in bytes. |
writeString
RLP encodes a string.
function writeString(string memory _in) internal pure returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
_in | string | The string to encode. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The RLP encoded string in bytes. |
writeAddress
RLP encodes an address.
function writeAddress(address _in) internal pure returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
_in | address | The address to encode. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The RLP encoded address in bytes. |
writeUint
RLP encodes a uint.
function writeUint(uint256 _in) internal pure returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
_in | uint256 | The uint256 to encode. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The RLP encoded uint256 in bytes. |
writeBool
RLP encodes a bool.
function writeBool(bool _in) internal pure returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
_in | bool | The bool to encode. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The 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
Name | Type | Description |
---|---|---|
_len | uint256 | The length of the string or the payload. |
_offset | uint256 | 128 if item is string, 192 if item is list. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | RLP encoded bytes. |
_toBinary
Encode integer in big endian binary form with no leading zeroes.
function _toBinary(uint256 _x) private pure returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
_x | uint256 | The integer to encode. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | RLP encoded bytes. |
_memcpy
Copies a piece of memory to another location.
function _memcpy(uint256 _dest, uint256 _src, uint256 _len) private pure;
Parameters
Name | Type | Description |
---|---|---|
_dest | uint256 | Destination location. |
_src | uint256 | Source location. |
_len | uint256 | Length 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
Name | Type | Description |
---|---|---|
_list | bytes[] | List of byte strings to flatten. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The flattened byte string. |
Sapphire
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
Name | Type | Description |
---|---|---|
numBytes | uint256 | The number of bytes to return. |
pers | bytes | An optional personalization string to increase domain separation. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The 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
Name | Type | Description |
---|---|---|
pers | bytes | An optional personalization string used to add domain separation. |
Returns
Name | Type | Description |
---|---|---|
pk | Curve25519PublicKey | The Curve25519 public key. Useful for key exchange. |
sk | Curve25519SecretKey | The 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
Name | Type | Description |
---|---|---|
peerPublicKey | Curve25519PublicKey | The peer's public key. |
secretKey | Curve25519SecretKey | Your secret key. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes32 | A 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
Name | Type | Description |
---|---|---|
key | bytes32 | The key to use for encryption. |
nonce | bytes32 | The nonce. Note that only the first 15 bytes of this parameter are used. |
plaintext | bytes | The plaintext to encrypt and authenticate. |
additionalData | bytes | The additional data to authenticate. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The 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
Name | Type | Description |
---|---|---|
key | bytes32 | The key to use for decryption. |
nonce | bytes32 | The nonce. Note that only the first 15 bytes of this parameter are used. |
ciphertext | bytes | The ciphertext with tag to decrypt and authenticate. |
additionalData | bytes | The additional data to authenticate against the ciphertext. |
Returns
Name | Type | Description |
---|---|---|
<none> | bytes | The 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
Name | Type | Description |
---|---|---|
alg | SigningAlg | The signing alg for which to generate a keypair. |
seed | bytes | The seed to use for generating the key pair. You can use the randomBytes method if you don't already have a seed. |
Returns
Name | Type | Description |
---|---|---|
publicKey | bytes | The public half of the keypair. |
secretKey | bytes | The 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 message4
(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
Name | Type | Description |
---|---|---|
alg | SigningAlg | The signing algorithm to use. |
secretKey | bytes | The secret key to use for signing. The key must be valid for use with the requested algorithm. |
contextOrHash | bytes | Domain-Separator Context, or precomputed hash bytes. |
message | bytes | Message to sign, should be zero-length if precomputed hash given. |
Returns
Name | Type | Description |
---|---|---|
signature | bytes | The 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 gas1
(Ed25519Pure
): 2,000 gas2
(Ed25519PrehashedSha512
): 2,000 gas3
(Secp256k1Oasis
): 3,000 gas4
(Secp256k1PrehashedKeccak256
): 3,000 gas5
(Secp256k1PrehashedSha256
): 3,000 gas7
(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
Name | Type | Description |
---|---|---|
alg | SigningAlg | The signing algorithm by which the signature was generated. |
publicKey | bytes | The public key against which to check the signature. |
contextOrHash | bytes | Domain-Separator Context, or precomputed hash bytes |
message | bytes | The hash of the message that was signed, should be zero-length if precomputed hash was given. |
signature | bytes | The signature to check. |
Returns
Name | Type | Description |
---|---|---|
verified | bool | Whether 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
Name | Type | Description |
---|---|---|
toAmount | uint128 | Gas 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
Hash the input data with SHA-384.
function sha384(bytes memory input) view returns (bytes memory output);
Parameters
Name | Type | Description |
---|---|---|
input | bytes | Bytes to hash. |
Returns
Name | Type | Description |
---|---|---|
output | bytes | 48 byte digest. |
sha512_256
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
Name | Type | Description |
---|---|---|
input | bytes | Bytes to hash. |
Returns
Name | Type | Description |
---|---|---|
result | bytes32 | 32 byte digest. |
sha512
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
Name | Type | Description |
---|---|---|
input | bytes | Bytes to hash. |
Returns
Name | Type | Description |
---|---|---|
output | bytes | 64 byte digest. |
SubcallReceiptKind
enum SubcallReceiptKind {
Invalid,
Delegate,
UndelegateStart,
UndelegateDone
}
Subcall
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
Name | Type | Description |
---|---|---|
method | string | Native message type. |
body | bytes | CBOR encoded body. |
Returns
Name | Type | Description |
---|---|---|
status | uint64 | Result of call. |
data | bytes | CBOR 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
Name | Type | Description |
---|---|---|
method | string | Runtime SDK method name ('module.Action'). |
to | StakingAddress | Destination address. |
value | uint128 | Amount specified. |
token | bytes |
Returns
Name | Type | Description |
---|---|---|
status | uint64 | Non-zero on error. |
data | bytes | Module 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 theerror
orshares
keys.UndelegateStart
will have theepoch
andreceipt
keys.UndelegateDone
will have theamount
key.
function consensusTakeReceipt(SubcallReceiptKind kind, uint64 receiptId) internal returns (bytes memory);
Parameters
Name | Type | Description |
---|---|---|
kind | SubcallReceiptKind | 1 (Delegate ), 2 (UndelegateStart ) or 3 (UndelegateDone ) |
receiptId | uint64 | ID 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
Name | Type | Description |
---|---|---|
receiptId | uint64 | Previously unretrieved receipt. |
result | bytes | CBOR 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
Name | Type | Description |
---|---|---|
from | StakingAddress | Consensus address which shares were delegated to. |
shares | uint128 | Number 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
Name | Type | Description |
---|---|---|
to | StakingAddress | Consensus address shares are delegated to. |
amount | uint128 | Native 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
Name | Type | Description |
---|---|---|
to | StakingAddress | Consensus address shares are delegated to. |
amount | uint128 | Native token amount (in wei). |
receiptId | uint64 | contract-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
Name | Type | Description |
---|---|---|
to | StakingAddress | Consensus address which gets the tokens. |
value | uint128 | Token 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
Name | Type | Description |
---|---|---|
to | address | Destination account. |
value | uint128 | native 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
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);