Skip to content

Latest commit

 

History

History
246 lines (178 loc) · 6.76 KB

File metadata and controls

246 lines (178 loc) · 6.76 KB

dstack SDK for Rust

Access TEE features from your Rust application running inside dstack. Derive deterministic keys, generate attestation quotes, create TLS certificates, and sign data—all backed by hardware security.

Installation

[dependencies]
dstack-sdk = { git = "https://github.com/Dstack-TEE/dstack.git" }

Quick Start

use dstack_sdk::dstack_client::DstackClient;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = DstackClient::new(None);

    // Derive a deterministic key for your wallet
    let key = client.get_key(Some("wallet/eth".to_string()), None).await?;
    println!("{}", key.key);  // Same path always returns the same key

    // Generate an attestation quote
    let resp = client.attest(b"my-app-state".to_vec()).await?;
    println!("{}", resp.attestation);

    Ok(())
}

The client automatically connects to /var/run/dstack.sock. For local development with the simulator:

let client = DstackClient::new(Some("http://localhost:8090".to_string()));

Core API

Derive Keys

get_key() derives deterministic keys bound to your application's identity (app_id). The same path always produces the same key for your app, but different apps get different keys even with the same path.

// Derive keys by path
let eth_key = client.get_key(Some("wallet/ethereum".to_string()), None).await?;
let btc_key = client.get_key(Some("wallet/bitcoin".to_string()), None).await?;

// Use path to separate keys
let mainnet_key = client.get_key(Some("wallet/eth/mainnet".to_string()), None).await?;
let testnet_key = client.get_key(Some("wallet/eth/testnet".to_string()), None).await?;

Parameters:

  • path: Key derivation path (determines the key)
  • purpose (optional): Included in signature chain message, does not affect the derived key

Returns: GetKeyResponse

  • key: Hex-encoded private key
  • signature_chain: Signatures proving the key was derived in a genuine TEE

Generate Attestation Quotes

get_quote() creates a TDX quote proving your code runs in a genuine TEE.

let quote = client.get_quote(b"user:alice:nonce123".to_vec()).await?;

// Replay RTMRs from the event log
let rtmrs = quote.replay_rtmrs()?;
println!("{:?}", rtmrs);

Parameters:

  • report_data: Exactly 64 bytes recommended. If shorter, pad with zeros. If longer, hash it first (e.g., SHA-256).

Returns: GetQuoteResponse

  • quote: Hex-encoded TDX quote
  • event_log: JSON string of measured events
  • replay_rtmrs(): Method to compute RTMR values from event log

Get Instance Info

let info = client.info().await?;
println!("{}", info.app_id);
println!("{}", info.instance_id);
println!("{}", info.tcb_info);

Returns: InfoResponse

  • app_id: Application identifier
  • instance_id: Instance identifier
  • app_name: Application name
  • tcb_info: TCB measurements (JSON string)
  • compose_hash: Hash of the app configuration
  • app_cert: Application certificate (PEM)

attest(report_data: Vec<u8>) -> AttestResponse

Generates a versioned attestation with a custom 64-byte payload.

  • attestation: Hex-encoded attestation

emit_event(event: String, payload: Vec<u8>)

Sends an event log with associated binary payload to the runtime.

Generate TLS Certificates

get_tls_key() creates fresh TLS certificates. Unlike get_key(), each call generates a new random key.

use dstack_sdk_types::dstack::TlsKeyConfig;

let tls_config = TlsKeyConfig::builder()
    .subject("api.example.com")
    .alt_names(vec!["localhost".to_string()])
    .usage_ra_tls(true)  // Embed attestation in certificate
    .usage_server_auth(true)
    .build();

let tls = client.get_tls_key(tls_config).await?;

println!("{}", tls.key);                // PEM private key
println!("{:?}", tls.certificate_chain);  // Certificate chain

TlsKeyConfig Options:

  • .subject(name): Certificate common name (e.g., domain name)
  • .alt_names(names): List of subject alternative names
  • .usage_ra_tls(bool): Embed TDX quote in certificate extension
  • .usage_server_auth(bool): Enable for server authentication
  • .usage_client_auth(bool): Enable for client authentication

Returns: GetTlsKeyResponse

  • key: PEM-encoded private key
  • certificate_chain: List of PEM certificates

Sign and Verify

Sign data using TEE-derived keys (not yet released):

let result = client.sign("ed25519", b"message to sign".to_vec()).await?;
println!("{:?}", result.signature);
println!("{:?}", result.public_key);

// Verify the signature
let valid = client.verify(
    "ed25519",
    b"message to sign".to_vec(),
    result.signature.clone(),
    result.public_key.clone()
).await?;
println!("{}", valid.valid);  // true

sign() Parameters:

  • algorithm: "ed25519", "secp256k1", or "secp256k1_prehashed"
  • data: Data to sign

sign() Returns: SignResponse

  • signature: Signature bytes
  • public_key: Public key bytes
  • signature_chain: Signatures proving TEE origin

verify() Parameters:

  • algorithm: Algorithm used for signing
  • data: Original data
  • signature: Signature to verify
  • public_key: Public key to verify against

verify() Returns: VerifyResponse

  • valid: Boolean indicating if signature is valid

Emit Events

Extend RTMR3 with custom measurements for your application's boot sequence (requires dstack OS 0.5.0+). These measurements are append-only and become part of the attestation record.

client.emit_event("config_loaded".to_string(), b"production".to_vec()).await?;
client.emit_event("plugin_initialized".to_string(), b"auth-v2".to_vec()).await?;

Parameters:

  • event: Event name (string identifier)
  • payload: Event value (bytes)

Blockchain Integration

Ethereum with Alloy

use dstack_sdk::dstack_client::DstackClient;
use dstack_sdk::ethereum::to_account;

let key = client.get_key(Some("wallet/ethereum".to_string()), None).await?;
let signer = to_account(&key)?;
println!("Ethereum address: {}", signer.address());

Development

For local development without TDX hardware, use the simulator:

git clone https://github.com/Dstack-TEE/dstack.git
cd dstack/sdk/simulator
./build.sh
./dstack-simulator

Then set the endpoint:

export DSTACK_SIMULATOR_ENDPOINT=http://localhost:8090

Run examples:

cargo run --example dstack_client_usage

Migration from TappdClient

Replace TappdClient with DstackClient:

// Before
use dstack_sdk::tappd_client::TappdClient;
let client = TappdClient::new(None);

// After
use dstack_sdk::dstack_client::DstackClient;
let client = DstackClient::new(None);

Method changes:

  • derive_key()get_tls_key() for TLS certificates
  • Socket path: /var/run/tappd.sock/var/run/dstack.sock

License

Apache License 2.0