Testnet: Base Sepolia. Not real money.

Client SDK

The Djinn SDK handles client-side cryptography so your plaintext pick never leaves your device. The API only ever sees encrypted data.

Available now. The SDK source is at sdk/ in the repository. Install with pnpm add @djinn/sdk or reference the source directly. 35 unit tests cover all cryptographic operations.

What the SDK does

1. Encryption

Generates a random AES-256-GCM key, encrypts the 10-line signal blob (1 real pick + 9 decoys), and produces a commitment hash for on-chain submission. The plaintext pick exists only in the Genius's browser memory during signal creation.

2. Decoy generation

Generates 9 plausible decoy lines matching the sport and market type. Decoys are indistinguishable from the real pick to anyone without the Shamir secret. The API can suggest decoys via POST /api/genius/signal/prepare, or the SDK can generate them locally.

3. Shamir splitting

Splits the real pick index (which of the 10 lines is real) into n shares using Shamir's Secret Sharing over a prime field. Reconstruction requires k-of-n shares. Each share is encrypted with the corresponding validator's public key before distribution.

4. Key share encryption

The AES encryption key is also Shamir-split and each key share is encrypted for its target validator. This ensures no single validator can decrypt the signal content. Only the buyer (after purchasing) receives enough shares to reconstruct the key and decrypt.

5. On-chain commitment

Constructs the commitSignal() transaction for the SignalCommitment contract: encrypted blob, commitment hash, sport, pricing parameters, and expiry. The SDK prepares the calldata; the wallet signs and submits.

Signal creation flow

import { encryptSignal, generateDecoys } from "@djinn/sdk";

// 1. Fetch network config (cached, do once)
const config = await fetch("https://djinn.gg/api/network/config")
  .then(r => r.json());

// 2. Fetch odds data for decoy generation
const odds = await fetch("https://djinn.gg/api/odds?sport=basketball_nba")
  .then(r => r.json());

// 3. Generate decoys locally (NEVER use server suggestions)
const realPick = {
  event_id: "abc123",
  market: "spreads",
  pick: "Celtics -4.5",
  odds: -110,
  bookmaker: "DraftKings",
};
const decoys = generateDecoys({
  realPick,
  availableLines: odds,  // from The Odds API
});

// 4. Encrypt signal locally (plaintext never leaves this device)
const encrypted = await encryptSignal({
  pick: realPick,
  decoys,
  validators: config.validators,
  shamirK: config.shamir.k,
});

// 5. Commit on-chain (your wallet signs this)
// const tx = await signalCommitment.commit(...)

// 6. Distribute shares via API (only ciphertext sent)
await fetch("https://djinn.gg/api/genius/signal/commit", {
  method: "POST",
  headers: { "Authorization": "Bearer ...", "Content-Type": "application/json" },
  body: JSON.stringify({
    encrypted_blob: encrypted.blob,
    commit_hash: encrypted.hash,
    shares: encrypted.shares,
    commit_tx_hash: "0x...",
    event_id: realPick.event_id,
  }),
});

Security properties

Plaintext never leaves client

The real pick is encrypted in-browser. The API, validators, and Djinn servers never see it.

Threshold decryption

k-of-n Shamir sharing means no single validator can reconstruct the key or the real index. Collusion of k-1 validators reveals nothing.

Commitment binding

The on-chain commit hash binds the encrypted blob. The Genius cannot change the pick after committing.

Verifiable open-source

All encryption code is open-source. Anyone can audit the client to verify that plaintext picks are handled correctly.