Skip to content

Findings from building a vetkeys datalake project #98

@jorgenbuilder

Description

@jorgenbuilder

Report from building a production application using ic-vetkeys (EncryptedMaps, KeyManager) with a React frontend. Covers skills used, issues encountered, and suggestions for new skills.

Issues already reported in #96 (Illegal invocation fetch fix, SDK version/import issues, local II deployment, ic_env cookie issues) are excluded here — this report focuses on new findings only.


1. vetkd skill: Rust API mismatches

The skill's Rust code shows types imported from ic_vetkeys::types that actually live in ic_cdk::management_canister:

// Skill shows:
use ic_vetkeys::types::{VetKDCurve, VetKDKeyId};

// Actual:
use ic_cdk::management_canister::{VetKDCurve, VetKDKeyId};

The enum variant name is also wrong:

// Skill shows:
VetKDCurve::Bls12381G2

// Actual (ic-cdk 0.19):
VetKDCurve::Bls12_381_G2

These cause immediate compilation failures.


2. vetkd skill: TypeScript API doesn't match @dfinity/vetkeys v0.4.0

The skill's frontend examples use an API that doesn't exist in the current npm package:

Skill shows Actual @dfinity/vetkeys v0.4.0 API
TransportSecretKey.fromSeed(seed) TransportSecretKey.random()
tsk.publicKey() tsk.publicKeyBytes()
vetKey.toDerivedKeyMaterial() vetKey.asDerivedKeyMaterial() (returns Promise)
Manual crypto.subtle.importKey("raw", material.data.slice(0,32), ...) keyMaterial.deriveAesGcmCryptoKey(domainSep)

The DerivedKeyMaterial class has a much richer API than documented — encryptMessage(), decryptMessage(), and deriveAesGcmCryptoKey() handle IV generation and key derivation internally. The skill's manual crypto.subtle approach works but is unnecessary and error-prone.


3. vetkd skill: EncryptedMaps not documented

The ic-vetkeys crate's EncryptedMaps<T: AccessControl> is the primary abstraction most developers will want — it wraps KeyManager + StableBTreeMap into a single struct with integrated encrypted storage and access control. It's not mentioned in the skill at all.

Key API details discovered by reading crate source:

  • EncryptedMaps::init() takes 4 memory regions (not 3 like KeyManager): config, ACL, shared keys, and data storage
  • KeyId = (Principal, Blob<32>) — owner principal + 32-byte map name
  • MapKey = Blob<32> — entries within a map use 32-byte keys
  • EncryptedMapValue = ByteBuf — the crate's own ByteBuf type (not Vec<u8>; has From/Into conversions)
  • Owner automatically gets ReadWriteManage rights
  • set_user_rights() / remove_user() for granting/revoking access
  • get_encrypted_values_for_map() checks ACL before returning ciphertext
  • get_encrypted_vetkey() also checks ACL — access control and encryption are coupled (two independent locks)
  • get_accessible_shared_map_names() for discovering what's been shared with you
  • get_all_accessible_encrypted_maps() for bulk retrieval

Example init (not in any skill):

use ic_vetkeys::encrypted_maps::EncryptedMaps;
use ic_vetkeys::types::AccessRights;

ENCRYPTED_MAPS.with(|em| {
    *em.borrow_mut() = Some(EncryptedMaps::init(
        "my_app_v1",          // domain separator
        key_id,               // VetKDKeyId
        mm.get(MemoryId::new(0)),  // config memory
        mm.get(MemoryId::new(1)),  // ACL memory
        mm.get(MemoryId::new(2)),  // shared keys memory
        mm.get(MemoryId::new(3)),  // encrypted data memory
    ));
});

4. vetkd skill: Missing getrandom dependency for WASM

Building ic-vetkeys for wasm32-unknown-unknown fails without:

getrandom = { version = "0.2", features = ["custom"] }

The error is:

error: the wasm*-unknown-unknown targets are not supported by default,
you may need to enable the "js" feature.

This is a hard build failure that every Rust vetKeys project will hit. Should be in the skill's Cargo.toml example.


5. stable-memory skill: Missing into_bytes in Storable example

The Rust Storable trait in ic-stable-structures v0.7 requires into_bytes(self) -> Vec<u8> in addition to to_bytes(&self) -> Cow<[u8]>. The skill's example omits into_bytes, causing a compilation error:

error[E0046]: not all trait items implemented, missing: `into_bytes`

6. icp-cli skill: No documentation for custom gateway port

When running multiple ICP projects simultaneously, they all default to port 8000 and conflict. The gateway.port configuration option exists (confirmed via icp-yaml-schema.json) but is not documented in any skill:

networks:
  - name: local
    mode: managed
    gateway:
      port: 8001

7. icp-cli skill: candid-extractor workflow not documented

The workflow for generating .did files from Rust canisters using export_candid!() is not covered by any skill. The process:

  1. Add ic_cdk::export_candid!(); to lib.rs
  2. Build: cargo build --target wasm32-unknown-unknown --release
  3. Extract: candid-extractor target/wasm32-unknown-unknown/release/<name>.wasm > <name>.did
  4. Use with @icp-sdk/bindgen for TypeScript bindings

candid-extractor must be installed separately (cargo install candid-extractor). Without this workflow documented, developers have no clear path from export_candid!() to TypeScript bindings.


Suggested new skills

encrypted-maps

A skill covering ic-vetkeys's EncryptedMaps — the primary abstraction for building encrypted storage applications. Should cover:

  • Init with 4 memory regions
  • Type system: KeyId, MapKey, EncryptedMapValue, ByteBuf
  • CRUD operations on encrypted values
  • Access control: grant, revoke, list shared users
  • Frontend pattern: deriving key material for another user's map (shared data decryption)
  • Complete working example

candid-generation

A skill covering .did file generation and TypeScript binding creation:

  • export_candid!() macro usage
  • candid-extractor tool
  • @icp-sdk/bindgen Vite plugin configuration
  • The full pipeline: Rust → WASM → .did → TypeScript bindings → frontend actor

Version matrix

All working together as of March 2026:

Dependency Version
ic-cdk 0.19
ic-stable-structures 0.7
ic-vetkeys 0.6
candid 0.10
getrandom 0.2 (features = ["custom"])
@icp-sdk/core 5.1.0
@icp-sdk/bindgen 0.2.3
@dfinity/vetkeys 0.4.0
Rust 1.93.0
Node.js 24.8.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions