npm.io
0.20.19 • Published 3 months ago

cojson-core-napi

Licence
MIT
Version
0.20.19
Deps
0
Size
54 kB
Vulns
0
Weekly
0

cojson-core-napi

A high-performance Node.js native addon for cryptographic operations, built with Rust and NAPI. This package provides essential cryptographic primitives for the Jazz framework, including hashing, encryption, digital signatures, and key management.

Features

  • BLAKE3 Hashing: Fast, secure cryptographic hashing with incremental support
  • Ed25519 Digital Signatures: High-performance elliptic curve digital signatures
  • X25519 Key Exchange: Secure key exchange for encrypted communications
  • XSalsa20 Encryption: Stream cipher encryption with optional authentication
  • Session Management: Transaction logging and cryptographic session handling
  • Cross-Platform: Pre-built binaries for multiple platforms and architectures

Jazz Framework Integration

This package is a core component of the Jazz framework, providing the cryptographic foundation for:

  • CoJSON: Collaborative JSON documents with cryptographic integrity
  • Real-time Collaboration: Secure peer-to-peer synchronization
  • Authentication: Cryptographic identity and session management
  • End-to-End Encryption: Secure data transmission and storage

The package is used throughout the Jazz ecosystem by other packages like cojson, jazz-tools, and various examples in the monorepo.

Installation

In the Jazz Monorepo

If you're working within the Jazz monorepo, the package is already available as a workspace dependency:

# From the monorepo root
pnpm install

# Build the NAPI package specifically
pnpm run build:napi

# Run tests for the NAPI package
pnpm test:napi
As a Standalone Package
pnpm install cojson-core-napi

The package includes pre-built binaries for the following platforms:

  • macOS (x64, ARM64)
  • Linux (x64, ARM64, ARM, musl)

API Reference

Hashing Functions
blake3HashOnce(data: Uint8Array): Uint8Array

Hash data once using BLAKE3. Returns 32 bytes of hash output.

import { blake3HashOnce } from 'cojson-core-napi';

const data = new TextEncoder().encode("Hello, World!");
const hash = blake3HashOnce(data);
console.log(hash.length); // 32
blake3HashOnceWithContext(data: Uint8Array, context: Uint8Array): Uint8Array

Hash data with a context prefix for domain separation.

import { blake3HashOnceWithContext } from 'cojson-core-napi';

const data = new TextEncoder().encode("message");
const context = new TextEncoder().encode("domain");
const hash = blake3HashOnceWithContext(data, context);
Blake3Hasher

Incremental hashing for large datasets.

import { Blake3Hasher } from 'cojson-core-napi';

const hasher = new Blake3Hasher();
hasher.update(new TextEncoder().encode("part1"));
hasher.update(new TextEncoder().encode("part2"));
const hash = hasher.finalize();
Digital Signatures (Ed25519)
newEd25519SigningKey(): Uint8Array

Generate a new Ed25519 signing key.

import { newEd25519SigningKey, ed25519VerifyingKey, ed25519Sign, ed25519Verify } from 'cojson-core-napi';

const signingKey = newEd25519SigningKey();
const verifyingKey = ed25519VerifyingKey(signingKey);

const message = new TextEncoder().encode("Hello, World!");
const signature = ed25519Sign(signingKey, message);
const isValid = ed25519Verify(verifyingKey, message, signature);
Key Management Functions
  • ed25519SigningKeyFromBytes(bytes: Uint8Array): Uint8Array - Validate and copy signing key bytes
  • ed25519VerifyingKeyFromBytes(bytes: Uint8Array): Uint8Array - Validate and copy verifying key bytes
  • ed25519SignatureFromBytes(bytes: Uint8Array): Uint8Array - Validate and copy signature bytes
  • ed25519SigningKeyToPublic(signingKey: Uint8Array): Uint8Array - Derive public key from signing key
  • ed25519SigningKeySign(signingKey: Uint8Array, message: Uint8Array): Uint8Array - Sign with signing key
Key Exchange (X25519)
newX25519PrivateKey(): Uint8Array

Generate a new X25519 private key.

import { newX25519PrivateKey, x25519PublicKey, x25519DiffieHellman } from 'cojson-core-napi';

const alicePrivate = newX25519PrivateKey();
const alicePublic = x25519PublicKey(alicePrivate);

const bobPrivate = newX25519PrivateKey();
const bobPublic = x25519PublicKey(bobPrivate);

// Perform key exchange
const aliceShared = x25519DiffieHellman(alicePrivate, bobPublic);
const bobShared = x25519DiffieHellman(bobPrivate, alicePublic);
// aliceShared and bobShared are identical
Encryption Functions
encrypt(value: Uint8Array, keySecret: string, nonceMaterial: Uint8Array): Uint8Array
decrypt(ciphertext: Uint8Array, keySecret: string, nonceMaterial: Uint8Array): Uint8Array

Encrypt/decrypt data with a key secret and nonce material.

import { encrypt, decrypt } from 'cojson-core-napi';

const keySecret = "keySecret_z11111111111111111111111111111111"; // Base58-encoded key
const nonceMaterial = new TextEncoder().encode("nonce");
const plaintext = new TextEncoder().encode("Secret message");

const ciphertext = encrypt(plaintext, keySecret, nonceMaterial);
const decrypted = decrypt(ciphertext, keySecret, nonceMaterial);
encryptXsalsa20(key: Uint8Array, nonceMaterial: Uint8Array, plaintext: Uint8Array): Uint8Array
decryptXsalsa20(key: Uint8Array, nonceMaterial: Uint8Array, ciphertext: Uint8Array): Uint8Array

XSalsa20 stream cipher encryption (without authentication).

import { encryptXsalsa20, decryptXsalsa20 } from 'cojson-core-napi';

const key = new Uint8Array(32); // 32-byte key
const nonceMaterial = new TextEncoder().encode("nonce");
const plaintext = new TextEncoder().encode("Message");

const ciphertext = encryptXsalsa20(key, nonceMaterial, plaintext);
const decrypted = decryptXsalsa20(key, nonceMaterial, ciphertext);
Sealing/Unsealing (Authenticated Encryption)
seal(message: Uint8Array, senderSecret: string, recipientId: string, nonceMaterial: Uint8Array): Uint8Array
unseal(sealedMessage: Uint8Array, recipientSecret: string, senderId: string, nonceMaterial: Uint8Array): Uint8Array

Authenticated encryption with perfect forward secrecy using X25519 + XSalsa20-Poly1305.

import { seal, unseal, getSealerId } from 'cojson-core-napi';

const senderSecret = "sealerSecret_z..."; // Base58-encoded private key
const recipientId = "sealer_z..."; // Base58-encoded public key
const nonceMaterial = new TextEncoder().encode("nonce");
const message = new TextEncoder().encode("Secret message");

const sealed = seal(message, senderSecret, recipientId, nonceMaterial);
const unsealed = unseal(sealed, senderSecret, recipientId, nonceMaterial);
Signing/Verification (Base58-wrapped)
sign(message: Uint8Array, secret: Uint8Array): string
verify(signature: Uint8Array, message: Uint8Array, id: Uint8Array): boolean

Sign and verify messages with base58-encoded signatures and IDs.

import { sign, verify, getSignerId } from 'cojson-core-napi';

const secret = new TextEncoder().encode("signerSecret_z...");
const message = new TextEncoder().encode("Hello, World!");

const signature = sign(message, secret);
const isValid = verify(new TextEncoder().encode(signature), message, new TextEncoder().encode("signer_z..."));
Utility Functions
generateNonce(nonceMaterial: Uint8Array): Uint8Array

Generate a 24-byte nonce from input material using BLAKE3.

import { generateNonce } from 'cojson-core-napi';

const nonceMaterial = new TextEncoder().encode("input");
const nonce = generateNonce(nonceMaterial);
console.log(nonce.length); // 24
getSealerId(secret: Uint8Array): string
getSignerId(secret: Uint8Array): string

Derive sealer/signer IDs from secrets.

import { getSealerId, getSignerId } from 'cojson-core-napi';

const sealerSecret = new TextEncoder().encode("sealerSecret_z...");
const sealerId = getSealerId(sealerSecret);
console.log(sealerId); // "sealer_z..."

const signerSecret = new TextEncoder().encode("signerSecret_z...");
const signerId = getSignerId(signerSecret);
console.log(signerId); // "signer_z..."
Session Management
SessionLog

Manage cryptographic sessions and transactions.

import { SessionLog } from 'cojson-core-napi';

const session = new SessionLog("coId", "sessionId", "signerId");

// Add a new private transaction
const result = session.addNewPrivateTransaction(
  '{"changes": "..."}',
  "signerSecret_z...",
  "keySecret_z...",
  "keyId",
  Date.now(),
  "metadata"
);

// Add a new trusting transaction
const signature = session.addNewTrustingTransaction(
  '{"changes": "..."}',
  "signerSecret_z...",
  Date.now(),
  "metadata"
);

// Decrypt transaction data
const changes = session.decryptNextTransactionChangesJson(0, "keySecret_z...");
const meta = session.decryptNextTransactionMetaJson(0, "keySecret_z...");

Error Handling

All functions throw Error objects with descriptive messages for invalid inputs or cryptographic failures.

try {
  const hash = blake3HashOnce(invalidData);
} catch (error) {
  console.error('Hashing failed:', error.message);
}

Performance

This package is built with Rust for maximum performance:

  • BLAKE3 hashing is significantly faster than SHA-256
  • Ed25519 signatures are faster than RSA
  • X25519 key exchange is faster than RSA key exchange
  • Native code execution avoids JavaScript overhead

Platform Support

The package includes pre-built binaries for:

  • Windows: x64, x86, ARM64
  • macOS: x64, ARM64 (Apple Silicon)
  • Linux: x64, ARM64, ARM, musl
  • FreeBSD: x64
  • Android: ARM64, ARM

Development

Within the Jazz Monorepo
# From the monorepo root - install all dependencies
pnpm install

# Build only the NAPI package
pnpm run build:napi

# Build all packages including NAPI
pnpm run build:packages

# Run tests for the NAPI package
pnpm test:napi

# Run all tests (excluding NAPI tests)
pnpm test
Using in Other Jazz Packages
// In any Jazz package, import directly
import { 
  blake3HashOnce, 
  newEd25519SigningKey, 
  encrypt, 
  decrypt 
} from 'cojson-core-napi';

// The package is available as a workspace dependency
// No additional installation needed

License

MIT License - see LICENSE file for details.

Contributing

Contributions are welcome! Please see the main Jazz repository for contribution guidelines.

Keywords