Continuing with Sapphire tutorial, we learnt in part 1 about Oasis architecture and confidential transaction, and in part 2 about signed view calls, frontend, and precompiles.
This section will touch upon encryption & decryption, signing & verification, autonomous contracts, Oasis Privacy Layer (OPL), running nodes, etc.
Encryption & Decryption
We know now that end-to-end encryption is possible between user and smart contract where storage is on the public ledger in encrypted form. But, it is also possible to use X25519 key pairs inside a smart contract and derive shared secret on-chain.
ECDH states that two people with their own key pairs, when they have each others public keys they can both derive the point, and nobody else can, unless one of the secrets gets leaked.
Use cases
Encryption (TypeScript)
import * as sapphire from '@oasisprotocol/sapphire-paratime'
const e2ePubKey = await e2e.getPublicKey();
const box = sapphire.cipher.X25519DeoxysII.ephemeral(e2ePubKey);
let {nonce, cipherText} = await box.encrypt(plaintextBytes);
const nonceBytes32Hex = ethers.utils.hexlify(nonce) +
"0000000000000000000000000000000000";
Decryption (Solidity)
import "@oasisprotocol/sapphire-contracts/contracts/Sapphire.sol";
contract E2EProxy {
Sapphire.Curve25519PublicKey internal immutable publicKey;
Sapphire.Curve25519SecretKey internal immutable privateKey;
constructor (bytes memory extraEntropy) {
(publicKey, privateKey) = Sapphire.generateCurve25519KeyPair(extraEntropy);
}
function getPublicKey() external view returns (bytes32) {
return Sapphire.Curve25519PublicKey.unwrap(publicKey);
}
}
import "@oasisprotocol/sapphire-contracts/contracts/Sapphire.sol";
contract E2EProxy {
function decrypt(bytes32 peerPublicKey, bytes32 nonce, bytes memory data)
external
{
bytes32 sk = Sapphire.deriveSymmetricKey(
Sapphire.Curve25519PublicKey.wrap(peerPublicKey),
privateKey);
bytes memory plaintext = Sapphire.decrypt(sk, nonce, data, "");
}
}
Signing & Verification
There are various utilities for this.
Signing (Solidity)
import "@oasisprotocol/sapphire-contracts/contracts/Sapphire.sol";
contract SigningExample {
function sign(bytes32 hashed_message)
external returns (bytes)
{
Sapphire.SigningAlg alg =
Sapphire.SigningAlg.Secp256k1PrehashedKeccak256;
bytes memory pk;
bytes memory sk;
bytes memory digest = abi.encodePacked(hashed_message);
Bytes memory entropy = Sapphire.randomBytes(32, "");
(pk, sk) = Sapphire.generateSigningKeyPair(alg, entropy);
return Sapphire.sign(alg, sk, digest, "");
}
}
Verification (Solidity)
import "@oasisprotocol/sapphire-contracts/contracts/Sapphire.sol";
contract VerifyExample {
function verify(bytes32 hashed_message, bytes memory signature)
external returns (bool)
{
Sapphire.SigningAlg alg =
Sapphire.SigningAlg.Secp256k1PrehashedKeccak256;
bytes memory digest = abi.encodePacked(hashed_message);
return Sapphire.verify(alg, pk, digest, "", signature);
}
}
On-chain Single Sign-On
Explore this more with Oasis docs on Sapphire.
Autonomous Contracts
Using the key generation precompiles, Sapphire can generate Ethereum compatible accounts to pay their own gas — either on Sapphire or on other EVM compatible chains.
Ethereum compatible key-generation & signing is included in
the@oasisprotocol/sapphire-contracts package:
Ethereum Keypair Generation and Signing (Solidity)
import '@oasisprotocol/sapphire-contracts/contracts/EthereumUtils.sol';
contract KeypairExample {
address pubkey;
bytes32 secret;
constructor () {
(pubkey, secret) = EthereumUtils.generateKeypair();
}
function sign(bytes memory data)
external view returns (SignatureRSV memory rsv)
{
bytes32 digest = keccak256(data);
rsv = EthereumUtils.sign(pubkey, secret, digest);
}
}
Transaction Signing (Solidity)
function signTx(uint64 nonce, uint256 gasPrice, uint256 value)
external view returns (bytes memory txdata)
{
return EIP155Signer.sign(pubkey, secret, EIP155Signer.EthTx({
nonce: nonce,
gasPrice: gasPrice,
gasLimit: 250000,
to: msg.sender,
value: value,
data: "",
chainId: block.chainid
}));
}
Explore this more with Oasis docs on Sapphire
Oasis Privacy Layer (OPL)
This workflow demonstrates connecting Sapphire with Ethereum, BNB chain and other EVM networks to be able to add encrypted transactions and
confidential state without moving the whole build away from the home network.
Explore this more with Oasis docs on OPL
Running a node
Explore this more with Oasis docs on running a node
Key resources used for this tutorial which is must-check:
Sapphire docs
Sapphire repository
Oasis playground for demo dApps
Sapphire workshop in Oasis Academy
Have a question or need help? Join our Discord and head over to the #dev-central channel.
Originally published at https://dev.to on August 27, 2025.
Sapphire 101: A Technical Workshop For Blockchain Devs Part 3 was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.


