Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Every SKILL.md has YAML frontmatter followed by a markdown body. See `skills/ski
`name`, `description`, plus `title`, `category` under `metadata:`

### Recommended frontmatter fields
`license`, `compatibility` (environment requirements — tools, system packages, network access; library deps go in `## Prerequisites`) — validator warns if missing but does not block
`license`, `compatibility` (environment requirements — tools, system packages, network access; document library deps in the body, either as a `## Prerequisites` section or a versions table — whichever reads better for the skill) — validator warns if missing but does not block

### Body sections
No rigid structure — organize content to best serve agents.
Expand Down
3 changes: 2 additions & 1 deletion .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
/skills/https-outcalls/ @derlerd-dfinity
/skills/multi-canister/ @derlerd-dfinity
/skills/stable-memory/ @derlerd-dfinity
/skills/vetkd/ @andreacerulli
/skills/vetkeys/ @dfinity/core-protocol
Comment thread
marc0olo marked this conversation as resolved.
/skills/encrypted-maps/ @dfinity/core-protocol
/skills/wallet-integration/ @dfinity/oisy
/skills/ic-dashboard/ @jp-dfinity

Expand Down
54 changes: 54 additions & 0 deletions evaluations/encrypted-maps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"output_evals": [
{
"name": "scaffold_backend_with_macro",
"prompt": "Scaffold just the Rust `lib.rs` for an encrypted password-manager canister on the IC using the vetKeys EncryptedMaps library. No frontend, no Cargo.toml, no explanation.",
"expected_behaviors": [
"Uses the `ic_vetkeys::export_encrypted_maps_canister!(...)` macro with a domain-separator string and four `Memory` instances",
"Sets up a `MemoryManager` and a `memory(id)` helper",
"Calls `ic_cdk::export_candid!();`",
"Does NOT hand-write `vetkd_derive_key` calls or the individual EncryptedMaps endpoints"
]
},
{
"name": "share_map_access_rights_variant",
"prompt": "Using @icp-sdk/vetkeys in the frontend, give me just the call that shares an encrypted map with another principal at read-write access. No setup, no explanation.",
"expected_behaviors": [
"Calls `setUserRights(owner, mapName, user, rights)` (map owner, map name, target principal, and rights)",
"Passes access rights as a Candid variant `{ ReadWrite: null }` — NOT the string \"ReadWrite\""
]
},
{
"name": "scaffold_motoko_backend_mixin",
"prompt": "Scaffold just the Motoko main.mo for an encrypted password-manager backend canister using the vetKeys EncryptedMaps library. No frontend, no explanation.",
"expected_behaviors": [
"Uses `include EncryptedMapsCanister(encryptedMapsState)` from `mo:ic-vetkeys/encrypted_maps/Canister`",
"Builds state with `EncryptedMaps.newEncryptedMapsState<Types.AccessRights>({ curve = #bls12_381_g2; name = keyName }, \"<domain separator>\")`",
"Reads the key name from the `VETKD_KEY_NAME` env var via `Runtime.envVar`",
"Declares the canister as `persistent actor` (so state persists without relying on a compiler flag)",
"Does NOT hand-write the individual EncryptedMaps endpoints (vetKD key, value, or access-control methods)"
]
},
{
"name": "derived_key_material_caching",
"prompt": "In my encrypted notes app the users re-derive their vetKey on every page reload. Should I just save the derived key material in localStorage to avoid that? Answer in a short paragraph.",
"expected_behaviors": [
"Warns against persisting raw key material in localStorage",
"Explains that since @icp-sdk/vetkeys 0.5.0 derived key material is cached in memory only by default (no longer persisted automatically)",
"Recommends `IndexedDbDerivedKeyMaterialCache` to persist across reloads and calling `clearCache()` on logout / identity change"
]
}
],
"trigger_evals": {
"description": "Queries testing whether the encrypted-maps skill activates. should_trigger should load it; should_not_trigger should route elsewhere (bidirectional routing with the sibling skill).",
"should_trigger": [
"Build a password manager on the IC with encrypted vaults users can share with each other",
"Store encrypted key-value data on-chain with per-user read/write access rights",
"Encrypt notes client-side and store them in my canister, shareable between users"
],
"should_not_trigger": [
"I need my canister to produce threshold BLS signatures verifiable by anyone",
"Encrypt a message to a specific principal using identity-based encryption"
]
}
}
64 changes: 64 additions & 0 deletions evaluations/vetkeys.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"output_evals": [
{
"name": "ibe_encrypt_to_principal",
"prompt": "Using the IC vetKeys frontend library, write just the TypeScript function that encrypts a string message to a recipient's principal with identity-based encryption (IBE). Assume you already have the canister's derived IBE public key bytes. No canister/backend code, no explanation.",
"expected_behaviors": [
"Imports from `@icp-sdk/vetkeys` (NOT `@dfinity/vetkeys`)",
"Uses `IbeCiphertext.encrypt(...)` with `IbeIdentity.fromPrincipal(recipient)` and `IbeSeed.random()`",
"Deserializes the public key via `DerivedPublicKey.deserialize(...)` and serializes the ciphertext with `.serialize()`",
"Does not invent a static per-user key pair — encrypts to the identity using the derived public key"
]
},
{
"name": "symmetric_key_material_api",
"prompt": "In a frontend, I already decrypted and verified a vetKey into a `VetKey` object. Give me just the snippet that derives an AES key from it and encrypts a string. No backend, no explanation.",
"expected_behaviors": [
"Calls `await vetKey.asDerivedKeyMaterial()` (async) — does NOT call a non-existent `toDerivedKeyMaterial()`",
"Encrypts via `await keyMaterial.encryptMessage(message, domainSep, associatedData)` (the correct 3-argument signature)",
"Does NOT use the raw decrypted vetKey bytes directly as an AES key"
]
},
{
"name": "motoko_has_no_low_level_primitives",
"prompt": "I'm writing a Motoko canister that uses vetKeys for IBE. Show me the Motoko code that generates the transport key pair, calls vetkd_derive_key, and then decrypts the encrypted vetKey with the transport secret key inside the canister. Just the Motoko.",
"expected_behaviors": [
"States that the Motoko `ic-vetkeys` library has no low-level primitives (no transport keys, no IBE, no vetKey decryption)",
"Explains the canister returns the ENCRYPTED vetKey and the frontend (`@icp-sdk/vetkeys`) does transport-key generation, `decryptAndVerify`, and IBE decryption",
"Shows the backend deriving via `mo:ic-vetkeys/ManagementCanister` (`vetKdDeriveKey`) rather than hand-rolling `actor \"aaaaa-aa\"`",
"Does not fabricate a Motoko `TransportSecretKey` / `decryptAndVerify` API"
]
},
{
"name": "cycle_cost_and_helpers",
"prompt": "How many cycles does a vetkd_derive_key call with test_key_1 cost on the local replica versus mainnet, and do I attach them manually? One short paragraph.",
"expected_behaviors": [
"States test_key_1 and key_1 cost the same locally and on mainnet — does NOT claim the local replica charges a different or higher amount",
"Gives the amounts: test_key_1 = 10_000_000_000, key_1 = 26_153_846_153, and notes vetkd_public_key is free",
"Notes the library helpers attach the cycles automatically (the Rust `ic-cdk-management-canister` binding or the Motoko `ManagementCanister`), so you just keep the canister funded"
]
},
{
"name": "bls_verify_uses_derived_public_key",
"prompt": "Frontend: verify a threshold BLS signature returned by my canister using the vetKeys library. Just the verification snippet, no setup.",
"expected_behaviors": [
"Calls `verifyBlsSignature(...)` imported from `@icp-sdk/vetkeys`",
"Passes a DerivedPublicKey object as the first argument via `DerivedPublicKey.deserialize(publicKeyBytes)` — NOT raw public-key bytes",
"Passes the message and signature as the remaining arguments"
]
}
],
"trigger_evals": {
"description": "Queries testing whether the vetkeys skill activates. should_trigger should load it; should_not_trigger should route elsewhere (bidirectional routing with the sibling skill).",
"should_trigger": [
"Implement identity-based encryption on the IC so a user can send an encrypted message to another user's principal",
"Add threshold BLS signing to my canister so anyone can verify signatures it produces",
"Build a sealed-bid auction where bids stay encrypted until the deadline passes",
"Derive a per-user symmetric AES key on my canister so each user can encrypt their own data"
],
"should_not_trigger": [
"Add an encrypted password manager with shareable vaults to my dapp",
"Set up Internet Identity login for my web app"
]
}
}
10 changes: 10 additions & 0 deletions public/_redirects
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,13 @@
/.well-known/skills/migrating-motoko-enhanced/SKILL.md /.well-known/skills/migrating-motoko-actors/SKILL.md 301
/.well-known/skills/migrating-motoko-enhanced/SKILL.zip /.well-known/skills/migrating-motoko-actors/SKILL.zip 301
/api/skills/migrating-motoko-enhanced.json /api/skills/migrating-motoko-actors.json 301

# Permanent redirects for the vetkd → vetkeys skill rename.
# (encrypted-maps is a new sibling skill, not a rename, so it needs no redirect.)
# from to status
/skills/vetkd /skills/vetkeys/ 301
/skills/vetkd/ /skills/vetkeys/ 301
/skills/vetkd/SKILL.md /skills/vetkeys/SKILL.md 301
/.well-known/skills/vetkd/SKILL.md /.well-known/skills/vetkeys/SKILL.md 301
/.well-known/skills/vetkd/SKILL.zip /.well-known/skills/vetkeys/SKILL.zip 301
/api/skills/vetkd.json /api/skills/vetkeys.json 301
Loading
Loading