Skip to content

Commit bca3311

Browse files
committed
docs(sdk): keep v1 documentation free of chain flavor in go, python and js
1 parent e25fd5c commit bca3311

4 files changed

Lines changed: 33 additions & 34 deletions

File tree

sdk/go/README.md

Lines changed: 18 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ dstack applications consist of:
2121

2222
### SDK Capabilities
2323

24-
- **Key Derivation**: Deterministic key derivation for wallets, signing, encryption, and other application-specific secrets
24+
- **Key Derivation**: Deterministic key derivation for signing, encryption, and other application-specific secrets
2525
- **Remote Attestation**: Versioned attestations providing cryptographic proof of execution environment, including GPU evidence
2626
- **TLS Certificate Management**: Fresh certificate issuance with optional RA-TLS support for secure connections
2727
- **Deployment Security**: Client-side encryption of sensitive environment variables ensuring secrets are only accessible to target TEE applications
28-
- **Blockchain Integration**: v0-era adapters for Ethereum and Solana, see [Blockchain adapters](#blockchain-adapters)
28+
- **Blockchain Integration (legacy)**: v0-era adapters for Ethereum and Solana, not part of v1 — see [Blockchain adapters](#blockchain-adapters)
2929

3030
### Two API versions
3131

@@ -54,13 +54,13 @@ What v1 changes:
5454
- `Attest` subsumes `GetQuote`; `Info` is flat, with no `tcb_info` blob and no `app_cert`.
5555
- `Sign`, `Verify` and `EmitEvent` are gone. Sign and verify locally with a standard library, using the key `GetKey` returns; `EmitEvent` is gone because runtime RTMR3 events became system-owned.
5656

57-
> **⚠️ v1 derives different key material than v0.** `client.GetKey(ctx, "wallet", "secp256k1")`
58-
> and `v0.GetKey(ctx, "wallet", "", "secp256k1")` return **unrelated** keys. v1 derives
57+
> **⚠️ v1 derives different key material than v0.** `client.GetKey(ctx, "storage-encryption", "secp256k1")`
58+
> and `v0.GetKey(ctx, "storage-encryption", "", "secp256k1")` return **unrelated** keys. v1 derives
5959
> under its own HKDF salt and binds the algorithm and a versioned context tag alongside
6060
> the domain, so secp256k1 and ed25519 no longer share one 32-byte secret either. There is
6161
> no compatibility mode and no way to reach a v0 key through v1. An application holding
62-
> funds or data under a v0 key must migrate them deliberately: derive the v1 key, then
63-
> move the assets. See `docs/guest-api-v1.md` for the byte-level construction.
62+
> anything under a v0 key must migrate it deliberately: derive the v1 key, then re-key
63+
> whatever the old one protected. See `docs/guest-api-v1.md` for the byte-level construction.
6464
>
6565
> Code that used the unsuffixed client for v0 calls fails **loudly** on upgrade rather
6666
> than silently deriving different keys, because the v1 method signatures differ and
@@ -140,14 +140,14 @@ func main() {
140140
fmt.Println("App Compose:", info.AppCompose)
141141

142142
// Derive deterministic keys for application-specific secrets
143-
walletKey, err := client.GetKey(ctx, "wallet/ethereum", "secp256k1")
143+
storageKey, err := client.GetKey(ctx, "storage-encryption", "secp256k1")
144144
if err != nil {
145145
log.Fatal(err)
146146
}
147147

148-
fmt.Println("Derived key (32 bytes):", hex.EncodeToString(walletKey.Key)) // secp256k1 private key
149-
fmt.Println("Public key:", hex.EncodeToString(walletKey.PublicKey))
150-
fmt.Println("Signature chain links:", len(walletKey.SignatureChain)) // Authenticity proof
148+
fmt.Println("Derived key (32 bytes):", hex.EncodeToString(storageKey.Key)) // secp256k1 private key
149+
fmt.Println("Public key:", hex.EncodeToString(storageKey.PublicKey))
150+
fmt.Println("Signature chain links:", len(storageKey.SignatureChain)) // Authenticity proof
151151

152152
// Generate a remote attestation, bound to your own data
153153
applicationData := map[string]interface{}{
@@ -256,7 +256,7 @@ envVars := []dstack.EnvVar{
256256
{Key: "DATABASE_URL", Value: "postgresql://user:pass@host:5432/db"},
257257
{Key: "API_SECRET_KEY", Value: "your-secret-key"},
258258
{Key: "JWT_PRIVATE_KEY", Value: "-----BEGIN PRIVATE KEY-----\n..."},
259-
{Key: "WALLET_MNEMONIC", Value: "abandon abandon abandon..."},
259+
{Key: "BACKUP_SIGNING_SEED", Value: "hex-encoded seed..."},
260260
}
261261

262262
// 2. Obtain encryption public key from KMS API (dstack-vmm or Phala Cloud).
@@ -320,16 +320,16 @@ The SDK implements secure key derivation using:
320320

321321
```go
322322
// Each domain generates a unique, deterministic key
323-
wallet1, _ := client.GetKey(ctx, "app1/wallet", "secp256k1")
324-
wallet2, _ := client.GetKey(ctx, "app2/wallet", "secp256k1")
325-
// wallet1.Key != wallet2.Key (guaranteed different)
323+
storageKey, _ := client.GetKey(ctx, "storage-encryption", "secp256k1")
324+
authKey, _ := client.GetKey(ctx, "api-auth", "secp256k1")
325+
// storageKey.Key != authKey.Key (guaranteed different)
326326

327-
sameWallet, _ := client.GetKey(ctx, "app1/wallet", "secp256k1")
328-
// wallet1.Key == sameWallet.Key (guaranteed identical)
327+
sameStorageKey, _ := client.GetKey(ctx, "storage-encryption", "secp256k1")
328+
// storageKey.Key == sameStorageKey.Key (guaranteed identical)
329329

330330
// The algorithm is bound into the derivation, so the two curves never share a
331331
// secret — this is a second, unrelated key, not a reinterpretation of the first.
332-
solWallet, _ := client.GetKey(ctx, "app1/wallet", "ed25519")
332+
storageKeyEd25519, _ := client.GetKey(ctx, "storage-encryption", "ed25519")
333333
```
334334

335335
Derivation is **flat**: `a/b` is not a child of `a`. The `/` is a naming convention, nothing more, and two domains that share a prefix yield unrelated keys.
@@ -473,14 +473,13 @@ Derives an application key from `(domain, algorithm)`.
473473
secp256k1, 32 raw bytes for ed25519), and a two-element `SignatureChain`.
474474

475475
```go
476-
key, err := client.GetKey(ctx, "wallet/ethereum", "secp256k1")
476+
key, err := client.GetKey(ctx, "backup-signing", "secp256k1")
477477
```
478478

479479
**Use Cases:**
480480
- Stable service identity keys
481481
- Application signing keys
482482
- Encryption key seeds
483-
- Cryptocurrency wallets and transaction signing
484483
- Any scenario requiring consistent, reproducible keys
485484

486485
#### `Attest(ctx context.Context, reportData []byte, includeBoottimeGpuEvidence bool) (*AttestV1Response, error)`

sdk/js/README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ JavaScript / TypeScript client for the dstack guest agent. Derive deterministic
88
npm install @phala/dstack-sdk
99
```
1010

11-
`@noble/hashes` and `@noble/curves` ship as regular dependencies — the core needs them for hashing and for verifying the KMS env-encryption key. Install the matching peer when you import a blockchain submodule:
11+
`@noble/hashes` and `@noble/curves` ship as regular dependencies — the core needs them for hashing and for verifying the KMS env-encryption key. Install the matching peer when you import one of the v0-era chain submodules:
1212

1313
| Import path | Extra peer dependency |
1414
| --- | --- |
@@ -26,7 +26,7 @@ import { DstackClient } from '@phala/dstack-sdk'
2626

2727
const client = new DstackClient()
2828

29-
const key = await client.getKey('wallet/eth', 'secp256k1')
29+
const key = await client.getKey('storage-encryption', 'secp256k1')
3030
console.log(Buffer.from(key.key).toString('hex'))
3131

3232
const { attestation } = await client.attest('app-state-snapshot')
@@ -55,7 +55,7 @@ dstack 0.6.0 splits the guest agent API into two surfaces on the same socket, se
5555

5656
The unsuffixed `DstackClient` names v1. `DstackClientV1` is the same class under an explicit name — use whichever reads better; new code should not need `DstackClientV0` at all.
5757

58-
> **v1 keys are not v0 keys.** `getKey` on v1 derives under its own HKDF salt and binds the algorithm and a versioned context tag into the derivation. The same name yields **different key material** on the two surfaces, and under v1 secp256k1 and ed25519 no longer share one 32-byte secret. There is no compatibility mode and no migration path back — an app that has published a v0-derived address must keep deriving it with `DstackClientV0`. `docs/guest-api-v1.md` pins the byte-level construction.
58+
> **v1 keys are not v0 keys.** `getKey` on v1 derives under its own HKDF salt and binds the algorithm and a versioned context tag into the derivation. The same name yields **different key material** on the two surfaces, and under v1 secp256k1 and ed25519 no longer share one 32-byte secret. There is no compatibility mode and no migration path back — an app that has published v0-derived material must keep deriving it with `DstackClientV0`. `docs/guest-api-v1.md` pins the byte-level construction.
5959
6060
Code that used the unsuffixed client for v0 calls fails **loudly** on upgrade rather than silently deriving different keys, because the v1 method signatures differ and `getKey` requires `algorithm` explicitly. To stay on the frozen surface, switch to `DstackClientV0`.
6161

@@ -87,12 +87,12 @@ The key is freshly generated on every call and is not derived from the app ident
8787
Derive a deterministic application key.
8888

8989
```typescript
90-
const eth = await client.getKey('wallet/ethereum', 'secp256k1')
91-
const sol = await client.getKey('wallet/solana', 'ed25519')
90+
const enc = await client.getKey('storage-encryption', 'secp256k1')
91+
const sig = await client.getKey('backup-signing', 'ed25519') // unrelated key material
9292

93-
eth.key // Uint8Array, 32 bytes
94-
eth.public_key // Uint8Array — SEC1 compressed (33) for secp256k1, raw (32) for ed25519
95-
eth.signature_chain // Uint8Array[], exactly 2 links
93+
enc.key // Uint8Array, 32 bytes
94+
enc.public_key // Uint8Array — SEC1 compressed (33) for secp256k1, raw (32) for ed25519
95+
enc.signature_chain // Uint8Array[], exactly 2 links
9696
```
9797

9898
Both arguments are required. `algorithm` is exactly `'secp256k1'` or `'ed25519'` — there is no default and no `k256` alias, because v0's defaulting meant a typo silently produced a key of the wrong type under a name the caller thought meant something else.

sdk/js/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ export interface VersionResponseV1 {
720720
* `emitEvent` are absent by design, not by oversight; see `docs/guest-api-v1.md`.
721721
*
722722
* A v1 key is NOT the v0 key of the same name. v1 derives under its own HKDF
723-
* salt and binds the algorithm into the derivation, so `getKey('wallet',
723+
* salt and binds the algorithm into the derivation, so `getKey('storage-encryption',
724724
* 'secp256k1')` here returns different material than `DstackClientV0.getKey`
725725
* ever did, and secp256k1 and ed25519 no longer share one secret. There is no
726726
* compatibility mode.

sdk/python/README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ out for code that wants the surface visible at a glance.
2222
> the algorithm and its own context tag alongside the domain, which is the point of
2323
> the new derivation, not a defect: v0 ignored the algorithm, so one secret served
2424
> two curves. There is no compatibility mode and no flag that brings the old bytes
25-
> back. An application holding assets under a v0 key must migrate them deliberately —
26-
> derive the v1 key, move the asset with a transaction signed by the v0 key, and only
27-
> then cut over.
25+
> back. An application that has published or committed to material derived from a v0
26+
> key must migrate deliberately — derive the v1 key, re-establish whatever depends on
27+
> the old one under it, and only then cut over.
2828
>
2929
> Code that used the unsuffixed client for v0 calls fails **loudly** on upgrade
3030
> rather than silently deriving different keys, because the v1 method signatures
@@ -60,7 +60,7 @@ from dstack_sdk import DstackClient
6060

6161
client = DstackClient()
6262

63-
key = client.get_key('wallet/eth', 'secp256k1') # algorithm is required
63+
key = client.get_key('storage-encryption', 'secp256k1') # algorithm is required
6464
attestation = client.attest(b'my-app-state')
6565
info = client.info()
6666
```
@@ -89,7 +89,7 @@ same domain always produces the same key for your app, and different apps get
8989
different keys for the same domain.
9090

9191
```python
92-
key = client.get_key('wallet/eth', 'secp256k1')
92+
key = client.get_key('storage-encryption', 'secp256k1')
9393
print(key.decode_key()) # 32 raw bytes
9494
print(key.decode_public_key()) # SEC1 compressed (33 B), or 32 B for ed25519
9595
print(key.decode_signature_chain()) # two links: app root, then KMS root
@@ -212,7 +212,7 @@ async def main():
212212
client = AsyncDstackClient()
213213

214214
info = await client.info()
215-
key = await client.get_key('wallet/eth', 'ed25519')
215+
key = await client.get_key('backup-signing', 'ed25519')
216216

217217
# Run requests concurrently
218218
keys = await asyncio.gather(

0 commit comments

Comments
 (0)