walletkit-core 0.11.1

Reference implementation for the World ID Protocol. Core functionality to use a World ID.
docs.rs failed to build walletkit-core-0.11.1
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: walletkit-core-0.6.5

WalletKit enables mobile applications to use World ID.

Part of the World ID SDK.

WalletKit can be used as a Rust crate, or directly as a Swift or Android package. WalletKit includes foreign bindings for direct usage in Swift/Kotlin through UniFFI.

Installation

To use WalletKit in another Rust project:

cargo install walletkit

To use WalletKit in an iOS app:

WalletKit is distributed through a separate repo specifically for Swift bindings. This repo contains all the binaries required and is a mirror of @worldcoin/walletkit.

  1. Navigate to File > Swift Packages > Add Package Dependency in Xcode.
  2. Enter the WalletKit repo URL (note this is not the same repo): https://github.com/worldcoin/walletkit-swift

To use WalletKit in an Android app:

WalletKit's bindings for Kotlin are distributed through GitHub packages.

  1. Update build.gradle (App Level)
dependencies {
    /// ...
    implementation "org.world:walletkit:VERSION"
}

Replace VERSION with the desired WalletKit version.

  1. Sync Gradle.

Local development (Android/Kotlin)

Prerequisites

  1. Docker Desktop: Required for cross-compilation

    • The build uses cross which runs builds in Docker containers with all necessary toolchains
    • Install via Homebrew:
      brew install --cask docker
      
    • Launch Docker Desktop and ensure it's running before building
  2. Android SDK + NDK: Required for Gradle Android tasks

    • Install via Android Studio > Settings > Android SDK (ensure the NDK is installed)
    • Set sdk.dir (and ndk.dir if needed) in kotlin/local.properties
  3. Protocol Buffers compiler:

    brew install protobuf
    

Building and publishing

To test local changes before publishing a release, use the build script to compile the Rust library, generate UniFFI bindings, and publish a SNAPSHOT to Maven Local:

./kotlin/build_android_local.sh 0.3.1

Example with custom Rust locations:

RUSTUP_HOME=~/.rustup CARGO_HOME=~/.cargo ./kotlin/build_android_local.sh 0.1.0-SNAPSHOT

Note: The script can be run from any working directory (it resolves its own location). It sets RUSTUP_HOME and CARGO_HOME to /tmp by default to avoid Docker permission issues when using cross. You can override them by exporting your own values.

This will:

  1. Build the Rust library for all Android architectures (arm64-v8a, armeabi-v7a, x86_64, x86)
  2. Generate Kotlin UniFFI bindings
  3. Publish to ~/.m2/repository/org/world/walletkit/

In your consuming project, ensure mavenLocal() is included in your repositories and update your dependency version to the SNAPSHOT version (e.g., 0.3.1).

Development

Linting

WalletKit uses feature flags (e.g. semaphore, storage) that gate code paths with #[cfg]. To catch warnings across all configurations, run clippy three ways:

cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo clippy --workspace --all-targets -- -D warnings
cargo clippy --workspace --all-targets --no-default-features -- -D warnings

CI runs all three checks. Formatting:

cargo fmt -- --check

Overview

WalletKit is broken down into separate crates, offering the following functionality.

  • walletkit-core - Enables basic usage of a World ID to generate ZKPs using different credentials.

World ID Secret

  • Each World ID requires a secret. The secret is used in ZKPs to prove ownership over a World ID.
  • Each host app is responsible for generating, storing and backing up a World ID secret.
  • A World ID secret is a 32-byte secret generated with a cryptographically secure random function.
  • The World ID secret must never be exposed to third-parties and must not leave the holder's device. //TODO: Additional guidelines for secret generation and storage.

Getting Started

WalletKit is generally centered around a World ID. The most basic usage requires initializing a WorldId.

A World ID can then be used to generate Zero-Knowledge Proofs.

A ZKP is analogous to presenting a credential.

use walletkit::{proof::ProofContext, CredentialType, Environment, world_id::WorldId};

async fn example() {
    let world_id = WorldId::new(b"not_a_real_secret", &Environment::Staging);
    let context = ProofContext::new("app_ce4cb73cb75fc3b73b71ffb4de178410", Some("my_action".to_string()), None, CredentialType::Orb);
    let proof = world_id.generate_proof(&context).await.unwrap();

    println!(proof.to_json()); // the JSON output can be passed to the Developer Portal, World ID contracts, etc. for verification
}

🛠️ Logging

WalletKit uses tracing internally for all first-party logging and instrumentation. To integrate with iOS/Android logging systems, initialize WalletKit logging with a foreign Logger bridge.

Logger is intentionally minimal and level-aware:

  • log(level, message) receives all log messages.
  • level is one of: Trace, Debug, Info, Warn, Error.

This preserves severity semantics for native apps while still allowing forwarding to Datadog, Crashlytics, os_log, Android Log, or any custom sink.

Basic Usage

Implement the Logger trait and initialize logging once at app startup:

use walletkit_core::logger::{init_logging, LogLevel, Logger};
use std::sync::Arc;

struct MyLogger;

impl Logger for MyLogger {
    fn log(&self, level: LogLevel, message: String) {
        println!("[{level:?}] {message}");
    }
}

init_logging(Arc::new(MyLogger), Some(LogLevel::Debug));

Swift Integration

class WalletKitLoggerBridge: WalletKit.Logger {
    static let shared = WalletKitLoggerBridge()

    func log(level: WalletKit.LogLevel, message: String) {
        switch level {
        case .trace, .debug:
            Log.debug(message)
        case .info:
            Log.info(message)
        case .warn:
            Log.warn(message)
        case .error:
            Log.error(message)
        @unknown default:
            Log.error(message)
        }
    }
}

public func setupWalletKitLogging() {
    WalletKit.initLogging(logger: WalletKitLoggerBridge.shared, level: .debug)
}

Kotlin Integration

class WalletKitLoggerBridge : WalletKit.Logger {
    companion object {
        val shared = WalletKitLoggerBridge()
    }

    override fun log(level: WalletKit.LogLevel, message: String) {
        when (level) {
            WalletKit.LogLevel.TRACE, WalletKit.LogLevel.DEBUG ->
                Log.d("WalletKit", message)
            WalletKit.LogLevel.INFO ->
                Log.i("WalletKit", message)
            WalletKit.LogLevel.WARN ->
                Log.w("WalletKit", message)
            WalletKit.LogLevel.ERROR ->
                Log.e("WalletKit", message)
        }
    }
}

fun setupWalletKitLogging() {
    WalletKit.initLogging(WalletKitLoggerBridge.shared, WalletKit.LogLevel.DEBUG)
}