DEV Community

DC
DC

Posted on

Sapphire 101: A Technical Workshop For Blockchain Devs Part 3


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.

#5: What to do next?

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

  • Encrypted emitted events, stateless view calls
  • Encrypted coupons, proxies, authentication, compliance

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";
Enter fullscreen mode Exit fullscreen mode

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);
}
}
Enter fullscreen mode Exit fullscreen mode
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, "");
}
}
Enter fullscreen mode Exit fullscreen mode

Signing & Verification

  • Contracts can generate key-pairs (Ed25519, X25519, Bitcoin & NIST)
  • Signing with EcDSA and EdDSA

There are various utilities for this.

  • You can generate Ethereum addresses and sign transactions on-chain.
  • You can verify WebAuthN / TouchID, using Ed25519 & EdDSA
  • You can broadcast cross-chain without bridge dependency

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, "");
}
}
Enter fullscreen mode Exit fullscreen mode

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);
}
}
Enter fullscreen mode Exit fullscreen mode

On-chain Single Sign-On

  • Viewing Keys - submitting an access token to view your data.
  • Permits - providing access to specific functions (read/write).
  • Daily Login with EIP-712: a. it is similar to permits but is application-specific b. it lets you sign a transaction once on a daily or weekly basis

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:

  • EthereumUtils.sol - a, s = EthereumUtils.generateKeypair()
  • EIP155Signer.sol - struct EIP155Signer.EthTx - EIP155Signer.sign(address,secret,tx)

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);
}
}
Enter fullscreen mode Exit fullscreen mode

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
}));
}
Enter fullscreen mode Exit fullscreen mode

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

  • As a decentralized network, Oasis encourages developers to help with decentralization by becoming a validator and/or running a ParaTime compute node (it can be Sapphire as well as Cipher or Emerald).
  • Alternatively, devs can simply run consensus and/or ParaTime client node along with the web3 gateway to avoid public endpoints or possible malicious interactions.

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 from the online 101 workshop hosted by Matevz Jekovec, Oasis Software Engineer
The online video tutorial

Have a question or need help? Join our Discord and head over to the #dev-central channel.

Top comments (3)

Collapse
 
suvrajeet profile image
Suvrajeet Banerjee

Sapphire deep! 💎

Collapse
 
savvysid profile image
sid

This part of the Sapphire 101 workshop really shows why it’s more than just an EVM runtime, it’s a privacy-first developer toolkit. End-to-end encryption, on-chain signing/verification, autonomous contracts, and OPL all make it possible to build apps that are both Ethereum-compatible and confidentiality-native. Feels like a new baseline for Web3 devs who want security without sacrificing usability.

Collapse
 
caerlower profile image
Manav

This part of the workshop is 🔥. Seeing how Sapphire handles encryption/decryption and signing inside the contract itself makes the privacy tools feel way more tangible for EVM devs.