Using a custom identity contract
When to use identity contracts on Hylé
On Hylé, any smart contract can serve as proof of identity. This flexibility allows you to register your preferred identity source as a smart contract for account identification. Hylé also ships a native hydentity
contract for simplicity.
This guide walks you through creating and deploying your first simple identity contract using Hylé and RISC Zero. We'll use our simple identity example, which mirrors our simple token transfer example.
For a deeper understanding of smart contracts, explore our identity management documentation.
Run the example
Info
Jump to Code snippets to see the contract code in action.
Prerequisites
- Install Rust (you'll need
rustup
and Cargo). - Install OpenSSL crate.
- For our example, install RISC Zero.
- Start a single-node devnet. We recommend using dev-mode with
-e RISC0_DEV_MODE=1
for faster iterations during development.
Build and register the identity contract
To build all methods and register the smart contract on the local node from the source, from the cloned Examples folder, run:
The expected output is 📝 Registering new contract simple_identity
.
Register an account / Sign up
To register an account with a username (alice
) and password (abc123
), execute:
The node's logs will display:
INFO hyle::data_availability::node_state::verifiers: ✅ Risc0 proof verified.
INFO hyle::data_availability::node_state::verifiers: 🔎 Program outputs: Successfully registered identity for account: alice.simple_identity
Verify identity / Login
To verify alice
's identity:
This command will:
- Send a blob transaction to verify
alice
's identity. - Generate a ZK proof of that identity. It will only be valid once, thus the inclusion of a nonce.
- Send the proof to the devnet.
Upon reception of the proof, the node will:
- Verify the proof.
- Settle the blob transaction.
- Update the contract's state.
The node's logs will display:
INFO hyle::data_availability::node_state::verifiers: ✅ Risc0 proof verified.
INFO hyle::data_availability::node_state::verifiers: 🔎 Program outputs: Identity verified for account: alice.simple_identity
See your contract's state digest at: https://hyleou.hyle.eu/contract/$CONTRACT_NAME
.
See your transaction on Hylé's explorer: https://hyleou.hyle.eu/tx/$TX_HASH
.
Development mode
We recommend activating dev-mode during your early development phase for faster iteration upon code changes with -e RISC0_DEV_MODE=1
.
You may also want to get insights into the execution statistics of your project: add the environment variable RUST_LOG="[executor]=info"
before running your project.
The full command to run your project in development mode while getting execution statistics is:
Code snippets
Find the full annotated code in our examples repository.
Info
Read more about Transactions on hyle.
Registering the contract
This part is the same as for the the simple transfer token example described in Your first smart contract
Register an identity
Build the blob transaction
Here is a simplified code snippet:
let action = RegisterIdentity {
account: identity,
};
let blob = sdk::Blob {
contract_name: contract_name,
data: action.as_blob_data(), // Note: This function does not exist. Used here for clarity
};
let blob_tx = BlobTransaction {
identity: identity,
blobs: vec![blob],
};
You can compare this section to the fields described in the Transactions on Hylé page.
Prove the registration
On the backend side
The backend is called "host" in Risc0.
Hylé transactions are settled in two steps, following pipelined proving principles. After sending the blob, your transaction is sequenced, but not settled.
For the transaction to be settled, it needs to be proven. You'll start with building the contract input, specifying:
- the initial state
- the identity of the transaction initiator
- the transaction hash, which can be found in the explorer after sequencing
- information about the blobs.
- the password as a private input for proof generation in
private_blob
blobs
: full list of blobs in the transaction (must match the blob transaction)index
: each blob of a transaction must be proven separately for now, so you need to specify the index of the blob you're proving.
// Build the contract input
let inputs = ContractInput {
initial_state: initial_state.as_digest(),
identity: blob_tx.identity,
tx_hash: blob_tx_hash,
private_blob: sdk::BlobData(password),
blobs: blobs,
index: sdk::BlobIndex(0),
};
On the contract side
The contract is called "guest" in Risc0
These inputs are then used by the sdk to initialize the contract :
- The input variable is the above constructed ContractInput
- The action contains the
let action RegisterIdentity { account: identity };
defined in the blob.
The password is retrieved by the guest:
The action is then handled by the contract:
// We clone the inital state to be updated
let mut next_state: Identity = input.initial_state.clone();
// Execute the given action
let res = sdk::identity_provider::execute_action(&mut next_state, action, password);
And the contract then commits the new state:
If you look at the implementation of this guest::commit
function, you will find the HyleOutput
mentionned in Transaction on Hyle.
Verify an identity
The process is the same as for registering a new identity, but the action is different:
Check the full annotated code in our GitHub example.