Node.js N-API bindings for the cojson-core Rust library, providing high-performance.
npm install cojson-core-napiA 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.
- 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
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.
If you're working within the Jazz monorepo, the package is already available as a workspace dependency:
``bashFrom the monorepo root
pnpm install
$3
`bash
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
$3
####
blake3HashOnce(data: Uint8Array): Uint8ArrayHash data once using BLAKE3. Returns 32 bytes of hash output.
`typescript
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): Uint8ArrayHash data with a context prefix for domain separation.
`typescript
import { blake3HashOnceWithContext } from 'cojson-core-napi';const data = new TextEncoder().encode("message");
const context = new TextEncoder().encode("domain");
const hash = blake3HashOnceWithContext(data, context);
`####
Blake3HasherIncremental hashing for large datasets.
`typescript
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();
`$3
####
newEd25519SigningKey(): Uint8ArrayGenerate a new Ed25519 signing key.
`typescript
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$3
####
newX25519PrivateKey(): Uint8ArrayGenerate a new X25519 private key.
`typescript
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
`$3
####
encrypt(value: Uint8Array, keySecret: string, nonceMaterial: Uint8Array): Uint8Array
#### decrypt(ciphertext: Uint8Array, keySecret: string, nonceMaterial: Uint8Array): Uint8ArrayEncrypt/decrypt data with a key secret and nonce material.
`typescript
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): Uint8ArrayXSalsa20 stream cipher encryption (without authentication).
`typescript
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);
`$3
####
seal(message: Uint8Array, senderSecret: string, recipientId: string, nonceMaterial: Uint8Array): Uint8Array
#### unseal(sealedMessage: Uint8Array, recipientSecret: string, senderId: string, nonceMaterial: Uint8Array): Uint8ArrayAuthenticated encryption with perfect forward secrecy using X25519 + XSalsa20-Poly1305.
`typescript
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);
`$3
####
sign(message: Uint8Array, secret: Uint8Array): string
#### verify(signature: Uint8Array, message: Uint8Array, id: Uint8Array): booleanSign and verify messages with base58-encoded signatures and IDs.
`typescript
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..."));
`$3
####
generateNonce(nonceMaterial: Uint8Array): Uint8ArrayGenerate a 24-byte nonce from input material using BLAKE3.
`typescript
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): stringDerive sealer/signer IDs from secrets.
`typescript
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..."
`$3
####
SessionLogManage cryptographic sessions and transactions.
`typescript
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.`typescript
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
$3
`bash
From the monorepo root - install all dependencies
pnpm installBuild only the NAPI package
pnpm run build:napiBuild all packages including NAPI
pnpm run build:packagesRun tests for the NAPI package
pnpm test:napiRun all tests (excluding NAPI tests)
pnpm test`$3
`typescript
// 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
``MIT License - see LICENSE file for details.
Contributions are welcome! Please see the main Jazz repository for contribution guidelines.