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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions