SDK Reference

@encra/core

Pure cryptographic primitives — zero framework dependencies. Works in Node.js 18+, all modern browsers, and React Native. All operations are built on libsodium via libsodium-wrappers.

Installation

bash
npm install @encra/core
libsodium loads asynchronously. Call await sodiumReady() once before using any function — or it will be called automatically on first use.
typescript
import { sodiumReady } from '@encra/core'

// In your app entry point or server startup:
await sodiumReady()

Key pairs

Encra uses X25519 key pairs for all asymmetric operations — key exchange, shared secret derivation, and Double Ratchet initialisation.

typescript
import { generateKeyPair, exportKey, importKey, deriveSharedSecret } from '@encra/core'

// Generate an X25519 key pair
const keyPair = await generateKeyPair()
// keyPair.publicKey  — Uint8Array (32 bytes)
// keyPair.privateKey — Uint8Array (32 bytes)

// Serialize to URL-safe base64 (for storage / transmission)
const pubB64  = exportKey(keyPair.publicKey)   // string
const privB64 = exportKey(keyPair.privateKey)  // string

// Deserialize back to Uint8Array
const pubKey  = importKey(pubB64)
const privKey = importKey(privB64)

// Derive a shared secret (ECDH — both sides get the same 32-byte key)
const shared = await deriveSharedSecret(myPrivateKey, theirPublicKey)
PropTypeDefaultDescription
generateKeyPair()Promise<KeyPair>Generate a new random X25519 key pair.
exportKey(key)stringEncode a Uint8Array key to URL-safe base64 (no padding).
importKey(b64)Uint8ArrayDecode a URL-safe base64 string back to a Uint8Array.
deriveSharedSecret(privateKey, publicKey)Promise<Uint8Array>Perform X25519 ECDH. Returns the 32-byte shared secret.
sodiumReady()Promise<void>Wait for libsodium WASM to finish loading. Safe to call multiple times.

encrypt / decrypt

Symmetric encryption using XSalsa20-Poly1305. Requires a 32-byte key (typically a shared secret from deriveSharedSecret). A fresh random nonce is generated on every encrypt call.

typescript
import { encrypt, decrypt, deriveSharedSecret } from '@encra/core'

const shared = await deriveSharedSecret(alicePrivKey, bobPubKey)

// Encrypt
const { ciphertext, nonce } = await encrypt('Hello, Bob!', shared)
// ciphertext — Uint8Array
// nonce      — Uint8Array (24 bytes, random, unique per call)

// Decrypt
const plaintext = await decrypt({ ciphertext, nonce }, shared)
// plaintext — string

encryptField / decryptField

Standalone field-level encryption — no server, no React, no key pair required. Provide a 32-byte symmetric key and encrypt individual string values for storage in a database. Each call generates a fresh random nonce.

Ideal for HIPAA / GDPR compliance: store encrypted columns in your database and decrypt only when needed, client-side.

typescript
import { encryptField, decryptField, generateFieldKey } from '@encra/core'

// Generate a 32-byte symmetric key (store this securely)
const key = await generateFieldKey()

// Encrypt a field value
const encrypted = await encryptField('123-45-6789', key)
// encrypted.ciphertext — URL-safe base64 string
// encrypted.nonce      — URL-safe base64 string

// Store both in your database:
// INSERT INTO patients (ssn_ciphertext, ssn_nonce) VALUES (?, ?)

// Decrypt when reading back
const ssn = await decryptField(encrypted, key)
// ssn === '123-45-6789'
PropTypeDefaultDescription
generateFieldKey()Promise<Uint8Array>Generate a cryptographically random 32-byte symmetric key.
encryptField(value, key)Promise<EncryptedField>Encrypt a string value with a 32-byte key. Returns { ciphertext, nonce } as URL-safe base64 strings.
decryptField(encrypted, key)Promise<string>Decrypt an EncryptedField. Throws DecryptionFailedError if the key is wrong or the ciphertext is tampered.
typescript
interface EncryptedField {
  ciphertext: string  // URL-safe base64, XSalsa20-Poly1305
  nonce:      string  // URL-safe base64, 24 random bytes
}

💡 Key management is your responsibility

generateFieldKey returns a raw key — store it in a secrets manager (AWS Secrets Manager, Vault, etc.) or derive it from a user-controlled passphrase. Never store the key in the same database as the ciphertext.

generateFingerprint

Generate Signal-style safety numbers — a human-readable fingerprint of two public keys that both parties can compare out-of-band to verify they're talking to each other (not an impostor).

typescript
import { generateFingerprint } from '@encra/core'

const fingerprint = await generateFingerprint(alicePubKey, bobPubKey)
// e.g. "12345 67890 12345 67890 12345 67890 12345 67890 12345 67890 12345 67890"

// Display to both users — if they match, the channel is authentic

Typed errors

All errors thrown by @encra/core extend a common base so you can handle them specifically.

typescript
import {
  DecryptionFailedError,
  InvalidKeyError,
  KeyNotFoundError,
} from '@encra/core'

try {
  const text = await decrypt({ ciphertext, nonce }, wrongKey)
} catch (err) {
  if (err instanceof DecryptionFailedError) {
    // Ciphertext tampered or wrong key
  }
  if (err instanceof InvalidKeyError) {
    // Key is wrong length or format
  }
}

TypeScript types

typescript
import type {
  KeyPair,          // { publicKey: Uint8Array, privateKey: Uint8Array }
  EncryptedField,   // { ciphertext: string, nonce: string }
  MessageHeader,    // Double Ratchet wire header
} from '@encra/core'

DoubleRatchet

The DoubleRatchet class is exported from @encra/corefor advanced use cases, but most apps should use the higher-level hooks in @encra/react or @encra/client instead.

Encra AI

Ask me anything · docs, code, troubleshooting

Hi, I'm Encra AI

I can explain concepts, generate starter code, troubleshoot errors, and guide your setup.

May make mistakes · verify critical crypto details