Skip to content

Commit c1f957e

Browse files
committed
tutorial renvision
1 parent 95a7979 commit c1f957e

23 files changed

Lines changed: 408 additions & 132 deletions

File tree

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ cat response.json | jq -r '.statement.tlsFingerprint'
161161

162162
## Next Steps
163163

164-
- [02-persistence-and-kms](../02-persistence-and-kms): Derive persistent keys across restarts
165-
- [03-gateway-and-ingress](../03-gateway-and-ingress): Custom domains and TLS
164+
- [02-kms-and-signing](../02-kms-and-signing): Derive persistent keys and sign messages
165+
- [03-gateway-and-tls](../03-gateway-and-tls): Custom domains and TLS
166166

167167
## SDK Reference
168168

@@ -172,7 +172,7 @@ cat response.json | jq -r '.statement.tlsFingerprint'
172172
## Files
173173

174174
```
175-
01-attestation-oracle/
175+
01-attestation/
176176
├── docker-compose.yaml # Oracle app (self-contained)
177177
├── verify_full.py # Python verification script
178178
└── README.md # This file
File renamed without changes.
File renamed without changes.
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Tutorial 02: KMS and Signing
2+
3+
Derive persistent keys that survive restarts and produce on-chain verifiable signatures.
4+
5+
## The Problem
6+
7+
TEE memory is wiped on restart. If your app generates a private key at startup, it gets a new key every time — breaking wallets, signatures, and any persistent identity.
8+
9+
## The Solution: `getKey()`
10+
11+
The dstack SDK's `getKey()` derives deterministic keys from KMS:
12+
13+
```javascript
14+
import { DstackClient } from '@phala/dstack-sdk'
15+
16+
const client = new DstackClient()
17+
const result = await client.getKey('/oracle', 'ethereum')
18+
19+
// Derive an Ethereum wallet
20+
const privateKey = '0x' + Buffer.from(result.key).toString('hex').slice(0, 64)
21+
```
22+
23+
The derived key is:
24+
- **Deterministic**: Same path → same key, every restart
25+
- **Unique to your app**: Different apps (compose hashes) get different keys
26+
- **Verifiable**: Signature chain proves the key came from KMS
27+
28+
## How It Works
29+
30+
```
31+
┌─────────────────────────────────────────────────────────────┐
32+
│ KMS │
33+
│ (runs in its own TEE, holds root keys) │
34+
│ │
35+
│ Root Key ──derives──▶ App Key ──derives──▶ Your Key │
36+
│ │ │ │ │
37+
│ │ │ └─ getKey('/oracle')
38+
│ │ └─ tied to appId (compose hash)
39+
│ └─ KMS root, known on-chain
40+
└─────────────────────────────────────────────────────────────┘
41+
```
42+
43+
The KMS returns a **signature chain** proving derivation:
44+
45+
```javascript
46+
const result = await client.getKey('/oracle', 'ethereum')
47+
48+
result.key // Your derived key bytes
49+
result.signature_chain[0] // App signature: appKey signs derivedPubkey
50+
result.signature_chain[1] // KMS signature: kmsRoot signs appPubkey
51+
```
52+
53+
## On-Chain Verification
54+
55+
The signature chain lets smart contracts verify a signature came from a TEE:
56+
57+
```
58+
KMS Root (known on-chain: 0x2f83172A...)
59+
60+
│ signs: "dstack-kms-issued:" + appId + appPubkey
61+
62+
App Key (recovered from kmsSignature)
63+
64+
│ signs: "ethereum:" + derivedPubkeyHex
65+
66+
Derived Key → signs your messages
67+
```
68+
69+
A contract can:
70+
1. Recover `appPubkey` from `kmsSignature` and verify it matches KMS root
71+
2. Recover `derivedPubkey` from `appSignature`
72+
3. Verify the message signature against `derivedPubkey`
73+
74+
## Minimal Example
75+
76+
```javascript
77+
import { DstackClient } from '@phala/dstack-sdk'
78+
import { privateKeyToAccount } from 'viem/accounts'
79+
80+
const client = new DstackClient()
81+
82+
// Derive a persistent wallet
83+
const result = await client.getKey('/wallet', 'ethereum')
84+
const privateKey = '0x' + Buffer.from(result.key).toString('hex').slice(0, 64)
85+
const account = privateKeyToAccount(privateKey)
86+
87+
console.log('Address:', account.address) // Same every restart
88+
89+
// Sign a message
90+
const signature = await account.signMessage({ message: 'hello' })
91+
```
92+
93+
## Key Paths
94+
95+
Use paths to organize multiple keys:
96+
97+
```javascript
98+
await client.getKey('/wallet/main') // Main wallet
99+
await client.getKey('/wallet/fees') // Fee payer
100+
await client.getKey('/signing/oracle') // Oracle signatures
101+
```
102+
103+
## Try It
104+
105+
```bash
106+
phala simulator start
107+
108+
docker compose run --rm \
109+
-v ~/.phala-cloud/simulator/0.5.3/dstack.sock:/var/run/dstack.sock \
110+
app
111+
```
112+
113+
## Next Steps
114+
115+
- [01-attestation](../01-attestation): Understand TDX quotes and verification
116+
- [04-onchain-oracle](../04-onchain-oracle): Full oracle with signature chain verification contract
117+
118+
## References
119+
120+
- [Key Management Protocol](https://docs.phala.network/dstack/design-documents/key-management-protocol)
121+
- [DstackKms contract](https://github.com/dstack-tee/dstack/blob/main/kms/auth-eth/contracts/DstackKms.sol)

tutorial/02-persistence-and-kms/README.md

Lines changed: 0 additions & 117 deletions
This file was deleted.
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ This creates a verification chain: TDX quote → file hashes → certificate.
8787

8888
## Next Steps
8989

90-
- [01-attestation-oracle](../01-attestation-oracle): Build verifiable apps
91-
- [02-persistence-and-kms](../02-persistence-and-kms): Persistent keys
90+
- [04-onchain-oracle](../04-onchain-oracle): Full oracle with on-chain verification
91+
- [05-hardening-https](../05-hardening-https): OCSP, CRL, and CT verification
9292

9393
## References
9494

File renamed without changes.
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Tutorial 05: On-Chain Verifiable Oracle
1+
# Tutorial 04: On-Chain Verifiable Oracle
22

33
Build an oracle that signs price data with TEE-derived keys, verifiable on-chain. This tutorial demonstrates the **AppAuth contract** architecture that controls which TEEs can get keys from KMS.
44

@@ -164,7 +164,7 @@ python3 test_local.py
164164
## Files
165165

166166
```
167-
05-onchain-oracle/
167+
04-onchain-oracle/
168168
├── docker-compose.yaml # Oracle app
169169
├── TeeOracle.sol # On-chain signature verification
170170
├── test_local.py # Test with simulator
@@ -178,6 +178,11 @@ python3 test_local.py
178178
└── README.md
179179
```
180180

181+
## Next Steps
182+
183+
- [05-hardening-https](../05-hardening-https): Strengthen TLS verification
184+
- [07-lightclient](../07-lightclient): Read verified blockchain state
185+
181186
## Contract Addresses
182187

183188
| Contract | Address |
File renamed without changes.

0 commit comments

Comments
 (0)