Secret Network
WebsiteDiscordGithub
  • ๐Ÿ‘‹INTRODUCTION
    • Secret Network Introduction
    • Secret Network Techstack
      • Private transactions - A quick summary
      • Blockchain Technology
        • Cosmos Basics
        • Tendermint
        • Cosmos SDK
        • IBC
        • CosmWasm
      • Privacy Technology
        • Encryption - Key Management
          • Overview
          • Key Derivation & Encryption Techniques
          • The Initialization Of Secret Network
          • Full Node Boostrap
          • Contract State Encryption
          • Transaction Encryption
          • Consensus seed rotation
        • Trusted Execution Environmentsโ€Š (TEE) โ€”โ€Š Intel SGX
          • How Secret Network Uses SGX
          • SGX-SPS Security & Reliabillity
          • Remote Attestation
          • Trusted & Untrusted Core
          • Sealing
        • Private smart contracts - overview
  • ๐Ÿ’ปDevelopment
    • ๐Ÿ Getting Started
      • Setting Up Your Environment
        • Cargo.toml Best Practices (Crates vs Dependencies)
      • Compile and Deploy
      • Running the Application
      • Compile and Deploy on Secret testnet (best for Javascript devs)
      • Fullstack dApp Integration
    • ๐Ÿค“Secret Contracts
      • Secret Contracts & CosmWasm
        • Framework overview
        • Secret Contract Components
          • Instantiation Message
          • Execution Message
          • Query Message
          • Deps/DepsMut
          • Storage
            • Prefixed Storage
            • Singleton
            • Keymap
            • Append Store
            • Best practices
        • CosmWasm vs Secret CosmWasm
      • Secret Tokens (SNIP-20)
      • Contract - module call
      • Secret contract - Design Space/Features
        • Secret Contracts introduction
        • Gas/Fee usage
        • TPS and scalability
        • Privacy Essentials
        • Access Control
          • Viewing Keys
          • Permits
        • Trusted and untrusted data
        • Secret-VRF - on-chain Randomness
        • Privacy design
          • Mitigate privacy risks - full guide
          • Gas Evaporation & Tracking
        • Confidential Computing Layer
        • Fiat/Crypto Onboarding
        • Account abstraction
        • Fee abstraction
        • Wallet support
        • Bridge (messaging/tokens)
        • IBC (Hooks, PFM, Wasm)
        • Price Oracles
        • Auto Restaking
      • Permissioned Viewing
        • Viewing Keys
        • Permits
      • Cross Contract Communication
      • Submessages
        • get_contract_code_hash
      • Randomness API - Secret VRF
        • Native On-chain randomness
        • Randomness over IBC
      • Execution Finalization
      • Factory Contracts
      • Contract Migration
        • Manual - < v1.11
        • Native - from v1.11
      • Cross-deploy Vanilla CW and Secret Contracts
      • Testing Secret Contracts
        • Unit Tests
        • Continuous Integration
        • Datatype Handling - Uint, floats etc.
    • ๐Ÿ‘€Secret Contract - Reference, Guides, Examples
      • Starter guide - Millionaire's Problem
      • Reference Contracts
      • Open source dApps
      • Tools & Libraries
        • Network interaction SDKs
          • Secret.js (JavaScript)
          • SecretPy (Python)
          • SecretK (Kotlin)
          • Secret.NET
            • Snippets
              • Deploying a Contract
              • Send Native Coin
              • Query a Contract
              • Create a new Wallet
              • Permits
              • SNIP20
              • SNIP721
          • Shade.Js
        • LocalSecret - Devnet docker
        • Smart contract - Tools/Utils
          • Secret Toolkit
          • CW-Plus
          • Fadroma - SC framework
          • Hidden Gems
          • Other
            • Secret IDE
            • Polar
    • ๐Ÿ–ผ๏ธFrontend Development
      • Getting Started with SecretJS
        • Usage Examples
          • Sending Queries
          • Sending Messages
          • Contract Migration
          • Wallet Integrations
          • Query Permits
          • SNIP20 (SCRT Tokens)
          • SNIP721 (Secret NFTs)
      • Feegrant
        • Understanding Feegrant allowances
        • Grant allowances
        • Using grant allowances to execute transactions
        • Using the Fee Grant Faucet
    • ๐Ÿ“ฌDeployment Addresses/ API Endpoints
      • Secret (SNIP 20) token contracts list
        • SNIP Asset naming guidelines
      • Connecting to the Network
        • API Endpoints Mainnet (Secret-4)
        • API Endpoints Testnet (Pulsar-3)
        • Usage examples
        • Comparison of endpoint types
      • Create your own SNIP-25 IBC Token
  • Secret AI
    • ๐ŸคIntroduction
    • ๐Ÿ—๏ธArchitecture
    • ๐Ÿ‘ฉโ€๐Ÿ’ปSecret AI SDK
      • Setting Up Your Environment
      • Running the Application
    • ๐Ÿช™Economics
    • Smart Contract Reference
      • SubscriptionManager
      • WorkerManager
      • RewardsManager
  • ๐ŸŒSecretVM - Confidential Virtual Machines
    • ๐ŸคIntroduction
    • ๐Ÿ—๏ธArchitecture
    • โ˜‘๏ธAttestation
      • What is Attestation
      • Obtaining Attestation Data
      • Attestation Report - Key Fields
      • Chain of Trust
    • ๐ŸLaunching a SecretVM
    • ๐Ÿ› ๏ธManaging SecretVM Lifecycle
    • โœ…Verifying a SecretVM
      • ๐ŸขFull Verification
      • ๐ŸฐQuick Verification
    • ๐Ÿ‘จโ€๐Ÿ’ปSecretVM CLI
      • Getting started
      • Authentication Commands
      • Virtual Machine Commands
    • ๐Ÿ’กBest Practices for Developers
    • ๐Ÿ”Verifiable Message Signing
    • ๐Ÿ“–Glossary
  • ๐Ÿ”“Confidential Computing Layer
    • ๐Ÿง‘โ€๐Ÿš€IBC Developer Toolkit
      • Basics
        • Overview
        • Cross-chain Messaging with IBC Hooks
          • Functions, Methods, and Data Structures
          • Typescript SDK
          • IBC-Hooks
        • IBC Relaying with Go Relayer
      • Usecases
        • Storing Encrypted Data on Secret Network
          • Key-Value store Developer Tutorial
        • Secret VRF for IBC with IBC-Hooks
        • Confidential Voting
        • Sealed Bid Auctions
      • Supported Networks
        • Mainnet
        • Testnet
    • ๐ŸคEthereum (EVM) Developer Toolkit
      • Basics
        • Overview
        • Connecting Metamask to Secret Network
        • SecretPath + Reown integration
        • Cross-chain Messaging
          • SecretPath
            • Architecture Overview
            • Detailed Architecture
            • SecretPath Developer Tutorials
            • Public EVM Gateway Architecture
            • How to deploy SecretPath on your chain
          • Axelar GMP
            • Architecture Overview
            • Axelar GMP Developer Tutorial
      • Usecases
        • Storing Encrypted Data on Secret Network
          • Key-Value store Developer Tutorial
        • Sealed Bid Auction
          • Sealed Bid Auction Developer Tutorial
        • Confidential Voting
          • Confidential Voting Developer Tutorial with SecretPath
        • VRF
          • Implementing VRF into any EVM Contract
          • VRF Developer Tutorial
          • Performance figures of SecretVRF vs competitors
          • Using encrypted payloads for VRF
          • Converting from Chainlink VRF to Secret VRF in four steps
        • Confidential Document Sharing
        • Tokens
          • From EVM to Secret
      • Supported Networks
        • EVM
          • EVM Mainnet
          • EVM Testnet
          • Gateway Contract ABI
        • Secret Gateway
          • SecretPath mainnet (secret-4) contracts
          • SecretPath testnet (pulsar-3) contracts
    • ๐Ÿ™ŒSolana Developer Toolkit
      • Usecases
        • Storing Encrypted Data on Secret Network
          • Key-value Store Developer Tutorial
        • VRF
          • VRF Developer Tutorial
      • Program IDs
        • Solana Mainnet & Testnet
        • Gateway Contract IDL
  • ๐ŸคซOverview, Ecosystem and Technology
    • ๐Ÿš€Secret Network Overview
      • The SCRT coin
      • Private Tokens
      • Use Cases
        • Decentralized Finance (DeFi)
        • Art And Digital Media
        • Gaming
        • Data Privacy
        • Payments And Transactions
        • Communication
      • The technology
      • History
      • Roadmap (Core development)
        • Secret 2.0
      • Where To Buy SCRT?
      • Using the Testnet
    • ๐ŸธEcosystem Overview
      • Wallets
      • Applications
      • Explorers & tools
      • Funding
        • SCRT Labs Grants
        • Dilutive funding/VC raise
        • Community Pool
        • Developer bounties
          • SCRT Labs bounties [on-hold]
          • CCBL [on-hold]
          • CCR [On-hold]
        • Application specific
          • Shade Grants
      • Contributors & Entities
        • Validators
        • SCRT Labs
        • Secret Foundation
        • Secret Committees
          • Support
          • Governance
      • Secret Network Dictionary
  • ๐Ÿ”งInfrastructure
    • ๐Ÿ”“Use SecretCLI
      • Secretcli vs. Secretd
      • Install
      • Configuration
      • Address Types
      • Key Types
      • Generating Keys
      • Viewing Keys
      • Query Transactions
      • Send Tokens
      • Multisig Keys
      • Multisig Transactions
      • Transaction Broadcasting
      • Fees & Gas
      • Fee Distribution
      • Secret Contracts
      • Slashing
      • Minting
      • Delegating
      • Restake
      • Nodes
      • Governance
        • Creating Governance Proposals
        • Query Proposals
        • Deposits
        • Voting
    • ๐Ÿ”Use Ledger hardware wallet
      • ๐Ÿ”Ledger with SecretCLI
    • ๐Ÿ–ฅ๏ธRunning a node/validator
      • Setting up a node/validator
        • Hardware setup
          • Hardware Compliance
          • VPS/Bare-Metal Compliance
            • Leaseweb Setup
            • PhoenixNAP Setup
            • Psychz Setup
            • nForce Setup
            • Vultr Setup
            • OVHCloud Setup
            • Microsoft Azure Setup
          • Patching your Node
          • Enclave verification
          • Registration troubleshooting
        • Testnet Setup
          • Install SGX
          • Install secretd
          • Setup Full Node
          • Testnet State Sync
          • Becoming a Testnet Validator
          • Installing CLI & Creating A New Address
        • Mainnet Setup
          • Install SGX
          • Install secretd
          • Setup Full Node
          • Quicksync / Snapshot
          • Statesync
          • Becoming A Validator
          • Installing CLI & Creating A New Address
      • Maintaining a node/validator
        • Slashing information
        • Migrating a Validator
        • Troubleshooting
        • Validator Backup
        • Server security
          • SSH authentication
          • Server configuration
          • Uncomplicated-Firewall (UFW)
          • Local CLI
        • Node Monitoring
          • Prometheus
            • Environment Preperation
            • Install Node Exporter
            • Install Prometheus
            • Configuring Prometheus
          • Grafana
            • Install Grafana
            • Grafana Dashboard
            • Next Steps
          • Docker
            • Install Docker
            • Configuration
            • Start Containers
            • Grafana Dashboard
            • Application Ports
            • Stop Containers
          • Goaccess
            • Install Goaccess
            • Setup Goaccess
        • Helpful commands
          • Query Validators
          • Bond Tokens
          • Withdraw Rewards
          • Query Delegations
          • Unbond Tokens
          • Query Unbonding-Delegations
          • Redelegate Tokens
          • Query Redelegations
          • Query Parameters
          • Query Pool
          • Query Delegations To Validator
      • API Noderunning
        • Running Multiple Nodes on the Same Server
        • Node Loadbalancing using Nginx
          • Setup Nginx
          • Example Nginx config
        • Using Auto heal to improve cluster uptime for Nginx
      • Sentry and Archive nodes
        • Mantlemint
        • Sentry Nodes
        • Archive Nodes
    • โ›“๏ธIBC Relayers
      • Hermes
      • RLY
      • IBC channel database
    • ๐Ÿ†™Upgrade Instructions
      • v1.13
      • v1.12
      • v1.11
      • v1.10
      • v1.9
      • v1.8
      • v1.7
      • Shockwave Omega v1.6
      • v1.5
      • Shockwave Delta v1.4
      • Shockwave Delta v1.4 (Testnet)
      • Shockwave Alpha v1.3
      • Cosmovisor
      • Vulcan Network Upgrade (OLD)
    • โ˜ ๏ธPostmortems
      • SNIP-20 leaks
      • xApic
      • Secpk-Verifications Bloat
      • Earn Contract Exploit
      • Testnet Halt 95
    • โœ๏ธContribute to the documentation
      • Report Bugs
      • Suggest Enhancements
      • First Contribution Guide
      • Pull Request Templates
        • Update Documentation
        • Bug Fix
        • Improve Performance
        • Change Functionality
      • Style Guide
    • ๐ŸŒŠVersioning & Changelog
      • Secret Network v1.13
      • Secret Network v1.12
      • Secret Network v1.11
      • Secret Network v1.10
      • Secret network v1.9
      • Secret Network v1.7/1.8
      • Secret Network v1.6
      • Secret Network v1.5
      • Secret Network v1.4 (CosmWasm 1.0)
Powered by GitBook
On this page
  • Install and import dependencies
  • Defining variables
  • Initializing the Ethereum client
  • Generating the encryption key using ECDH
  • Define the Calldata for the secret contract & Callback information
  • Encrypting the Payload
  • Signing the Payload with Metamask
  • Estimate the Callback Gas
  • Packing the Transaction & Send

Was this helpful?

Edit on GitHub
Export as PDF
  1. Confidential Computing Layer
  2. Ethereum (EVM) Developer Toolkit
  3. Usecases
  4. VRF

Using encrypted payloads for VRF

PreviousPerformance figures of SecretVRF vs competitorsNextConverting from Chainlink VRF to Secret VRF in four steps

Last updated 10 months ago

Was this helpful?

Need help with using encrypted payloads with Secretpath or want to discuss use cases for your dApp? Please ask in the Secret Network or Discord.

Install and import dependencies

First, install all of the the dependencies via NPM:

npm install @solar-republic/cosmos-grpc @solar-republic/neutrino ethers secure-random

Next, import the following into your code:

import { ethers } from "ethers"; 
import { arrayify, hexlify, SigningKey, keccak256, recoverPublicKey, computeAddress } from "ethers/lib/utils"; 
import {ecdh, chacha20_poly1305_seal} from "@solar-republic/neutrino"; 
import {bytes, bytes_to_base64, json_to_bytes, sha256, concat, text_to_bytes, base64_to_bytes} from '@blake.regalia/belt';

In your vite.config.ts in the project, you need to add the support for bigInt into the esbuildOptions:

optimizeDeps: { 
    esbuildOptions: { 
        target: "esnext", 
        supported: { 
        bigint: true 
        }, 
    } 
}

Defining variables

To start, we first define all of our variables that we need for the encryption, as well as the gateway information:

const publicClientAddress = '0x3879E146140b627a5C858a08e507B171D9E43139' //EVM gateway contract address
const routing_contract = "secret1fxs74g8tltrngq3utldtxu9yys5tje8dzdvghr" //the contract you want to call in secret
const routing_code_hash = "49ffed0df451622ac1865710380c14d4af98dca2d32342bb20f2b22faca3d00d" //its codehash

First, we define the Gateway address that is specific to each chain, which can you can look up here Supported Networks.

Initializing the Ethereum client

Next, init the Ethereum client that you are using to call the contract with. Here, we init the chainId to use the Ethereum sepolia testnet and use ethers.js to retrieve the address.

 await (window as any).ethereum.request({
    method: 'wallet_switchEthereumChain',
    params: [{ chainId: '0xAA36A7' }], // chainId must be in hexadecimal numbers
});

// @ts-ignore
const provider = new ethers.providers.Web3Provider(window.ethereum);
const [myAddress] = await provider.send("eth_requestAccounts", []);

Generating the encryption key using ECDH

Next, you generate ephermal keys and load in the public encryption key for the Secret Gateway that you can look up in Supported Networks. Then, use ECDH to create the encryption key:

//Generating ephemeral keys
const wallet = ethers.Wallet.createRandom();
const userPrivateKeyBytes = arrayify(wallet.privateKey);
const userPublicKey: string = new SigningKey(wallet.privateKey).compressedPublicKey;
const userPublicKeyBytes = arrayify(userPublicKey)

//Gateway Encryption key for ChaCha20-Poly1305 Payload encryption
const gatewayPublicKey = "A20KrD7xDmkFXpNMqJn1CLpRaDLcdKpO1NdBBS7VpWh3";
const gatewayPublicKeyBytes = base64_to_bytes(gatewayPublicKey);

//create the sharedKey via ECDH
const sharedKey = await sha256(ecdh(userPrivateKeyBytes, gatewayPublicKeyBytes));

Define the Calldata for the secret contract & Callback information

Next, you define all of the information that you need for calling the private contract on Secret + add the callback information for the message on its way back.

We begin by defining the function that we are going to call on the private secret contract, here it's request_random . Next, we add the parameters/calldata for this function, which is ("{ numWords: Number(numWords) }"and convert it into a JSON string.

Next, we define the callback Information. In this case, we are using the gateway contract as an example callback. Here, you would typically put in your own custom callback address and callback selector in.

//the function name of the function that is called on the private contract
const handle = "request_random"

//data are the calldata/parameters that are passed into the contract 
const data = JSON.stringify({ numWords: Number(numWords) })
    
const callbackAddress = publicClientAddress.toLowerCase();
//This is an empty callback for the sake of having a callback in the sample code.
//Here, you would put your callback selector for you contract in. 
const callbackSelector = iface.getSighash(iface.getFunction("upgradeHandler"))
const callbackGasLimit = Number(callback_gas_limit)

After defining the contract call and callback, we now construct the payload:

//payload data that are going to be encrypted
const payload = {
      data: data,
      routing_info: routing_contract,
      routing_code_hash: routing_code_hash,
      user_address: myAddress,
      user_key: bytes_to_base64(userPublicKeyBytes),
      callback_address: bytes_to_base64(arrayify(callbackAddress)),
      callback_selector: bytes_to_base64(arrayify(callbackSelector)),
      callback_gas_limit: callbackGasLimit,
}

Encrypting the Payload

Next, we encrypt the payload using ChaCha20-Poly1305. Then, we hash the encrypted payload into a ciphertextHash using Keccak256.

//build a Json of the payload 
const payloadJson = JSON.stringify(payload); 
const plaintext = json_to_bytes(payload);
//generate a nonce for ChaCha20-Poly1305 encryption 
//DO NOT skip this, stream cipher encryptions are only secure with a random nonce!
const nonce = crypto.getRandomValues(bytes(12));

//Encrypt the payload using ChachaPoly1305 and concat the ciphertext+tag to fit the Rust ChaChaPoly1305 requirements
const [ciphertextClient, tagClient] = chacha20_poly1305_seal(sharedKey, nonce, plaintext);
const ciphertext = concat([ciphertextClient, tagClient]);

//get Metamask to sign the payloadhash with personal_sign
const ciphertextHash = keccak256(ciphertext)

Signing the Payload with Metamask

Next, we use Metamask to sign the ciphertextHash using personal_sign. Then, we recover the user_pubkey from this signed message, which will be also passed into the Public Gateway.

Internally, Metamask takes the ciphertextHash, preprends the "\x19Ethereum Signed Message:\n32" string and then hashes it using Keccak256, which results the payloadHash. Metamask actually signs the payloadHash to get the signature. Keep this in mind when verifying the signature against the payloadHash and NOT the ciphertextHash.

//this is what metamask really signs with personal_sign, it prepends the ethereum signed message here
const payloadHash = keccak256(concat([
      text_to_bytes("\x19Ethereum Signed Message:\n32"),
      arrayify(ciphertextHash),
]))
//this is what we provide to metamask
const msgParams = ciphertextHash;
const from = myAddress;
const params = [from, msgParams];
const method = 'personal_sign';

const payloadSignature = await provider.send(method, params)
console.log(`Payload Signature: ${payloadSignature}`)

const user_pubkey = recoverPublicKey(payloadHash, payloadSignature)
console.log(`Recovered public key: ${user_pubkey}`)

Estimate the Callback Gas

The callback gas is the amount of gas that you have to pay for the message coming on the way back. If you do pay less than the amount specified below, your Gateway TX will fail:

/// @notice Increase the task_id to check for problems 
/// @param _callbackGasLimit the Callback Gas Limit

function estimateRequestPrice(uint32 _callbackGasLimit) private view returns (uint256) {
    uint256 baseFee = _callbackGasLimit*block.basefee;
    return baseFee;
}
//Then calculate how much gas you have to pay for the callback
//Forumla: callbackGasLimit*block.basefee.
//Use an appropriate overhead for the transaction, 1,5x = 3/2 is recommended since gasPrice fluctuates.

const gasFee = await provider.getGasPrice();
const amountOfGas = gasFee.mul(callbackGasLimit).mul(3).div(2);

Packing the Transaction & Send

Lastly, we pack all the information we collected during previous steps into an info struct that we send into the Gateway contract. We the encode the function data. Finally, we set the tx_params. Please make sure to set an approiate gas amount for your contract call, here we used 150k gas. For the value of the TX, we send over the estimated callback gas that we calculated above.

// function data to be abi encoded
const _userAddress = myAddress
const _routingInfo = routing_contract
const _payloadHash = payloadHash
const _info = {
        user_key: hexlify(userPublicKeyBytes),
        user_pubkey: user_pubkey, 
        routing_code_hash: routing_code_hash,
        task_destination_network: "pulsar-3",  //Destination for the task, here: pulsar-3 testnet
        handle: handle,
        nonce: hexlify(nonce),
        payload: hexlify(ciphertext),
        payload_signature: payloadSignature,
        callback_gas_limit: Number(callbackGasLimit)
}

const functionData = iface.encodeFunctionData("send",
        [
            _payloadHash,
            _userAddress,
            _routingInfo,
            _info,
        ]
    )
    
const tx_params = [
    {
            gas: hexlify(150000),
            to: publicClientAddress,
            from: myAddress,
            value: hexlify(amountOfGas), // send that extra amount of gas in to pay for the Callback Gas Limit that you set
            data: functionData, 
        },
      ];

const txHash = await provider.send("eth_sendTransaction", tx_params);

Second, you need to input the private contract that you are going to call, in our case the Secret VRF RNG contact on Secret Network. The code for this example contract can be found in case you want to deploy it yourself.

Since this check is dependent on the current block.basefee of the block it is included in, it is recommended that you estimate the gas fee beforehand and add some extra overhead to it. An example of how this can be implemented in your frontend can be found in this and here:

๐Ÿ”“
๐Ÿค
Telegram
here
example