/** * Cross-runtime crypto provider interface. * * The vaults package needs to run on Node (server, via WASM) and React Native * Hermes (mobile, via @noble + react-native-argon2). Both runtimes implement * this interface; the active one is picked at bundle time by package.json * conditional exports. * * All byte-formats here are spec-§ compliant — see * encrypted_vaults_arweave/rust/wasm/vault-crypto/src/{aead,kdf,utils}.rs for * the reference implementation. */ export interface AeadResult { /** ciphertext WITH appended 16-byte GCM tag (or 16-byte Poly1305 tag) */ ciphertext: Uint8Array; } export interface AeadProvider { /** AES-256-GCM. key=32, nonce=12. Ciphertext output includes 16-byte tag. */ aesGcmEncrypt(key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, aad: Uint8Array): AeadResult; aesGcmDecrypt(key: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array, aad: Uint8Array): Uint8Array; /** XChaCha20-Poly1305. key=32, nonce=24. Ciphertext output includes 16-byte tag. */ xchachaEncrypt(key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, aad: Uint8Array): AeadResult; xchachaDecrypt(key: Uint8Array, nonce: Uint8Array, ciphertext: Uint8Array, aad: Uint8Array): Uint8Array; } /** * hash-wasm compatible signature. Mirrors what VaultEncryptionService passes today. * memorySize is in KiB, hashLength in bytes. */ export interface Argon2idOptions { password: string; salt: Uint8Array; parallelism: number; iterations: number; memorySize: number; hashLength: number; outputType: 'binary'; } export interface Argon2Provider { argon2id(opts: Argon2idOptions): Promise; } export interface KeyInput { kid: string; key: Uint8Array; } export interface KdfProvider { /** HKDF-SHA256 expand. empty salt → no salt (RFC 5869). */ hkdfExpand(ikm: Uint8Array, salt: Uint8Array, info: string, length: number): Uint8Array; /** Order-independent multi-key fold. info = `wrap:{context}`. */ hkdfJoin(keys: KeyInput[], context: string): Uint8Array; /** HKDF-Expand(seed, "", `cek:{context}`, 32). */ deriveCek(seed: Uint8Array, context: string): Uint8Array; /** base64url(SHA-256(publicKey)). */ deriveKid(publicKey: Uint8Array): string; /** base64url(HKDF-Expand(key, "", "kid:v1", 16)). */ deriveSymmetricKid(key: Uint8Array): string; } export interface KemKeypair { publicKey: Uint8Array; secretKey: Uint8Array; } export interface KemEncapResult { ciphertext: Uint8Array; sharedSecret: Uint8Array; } export interface KemProvider { /** ML-KEM-768 keygen. */ kemGenerateKeypair(): KemKeypair; /** ML-KEM-768 encapsulate; returns (ct, ss). */ kemEncapsulate(recipientPublicKey: Uint8Array): KemEncapResult; /** ML-KEM-768 decapsulate. */ kemDecapsulate(ciphertext: Uint8Array, secretKey: Uint8Array): Uint8Array; /** Wrap a CEK to a recipient's public key (KEM encap + AES-256-GCM wrap). */ kemWrapCek(cek: Uint8Array, recipientPublicKey: Uint8Array): Uint8Array; /** Unwrap a CEK with our secret key. */ kemUnwrapCek(wrappedCek: Uint8Array, secretKey: Uint8Array): Uint8Array; } export type SecretShareLike = any; export type SecretShareCtor = any; export interface ShamirProvider { shamirSplit(secret: Uint8Array, threshold: number, totalShares: number): SecretShareLike[]; shamirReconstruct(shares: SecretShareLike[]): Uint8Array; shamirSplitAndWrap(secret: Uint8Array, threshold: number, recipientPublicKeys: unknown): unknown; shamirUnwrapAndReconstruct(wrappedShares: unknown, secretKeys: unknown): Uint8Array; /** WASM-generated SecretShare class (fromJson/fromBase64/etc.). */ SecretShare: SecretShareCtor; } export interface UtilProvider { randomBytes(length: number): Uint8Array; generateCek(): Uint8Array; generateNonceAesGcm(): Uint8Array; generateNonceXchacha(): Uint8Array; /** HMAC-SHA256(cek, "kcmp:v1") → 32 bytes. */ keyCommitment(cek: Uint8Array): Uint8Array; verifyKeyCommitment(cek: Uint8Array, expectedKcmp: Uint8Array): boolean; sha256(data: Uint8Array): Uint8Array; blake2s256(data: Uint8Array): Uint8Array; computeSummary(digest: Uint8Array): Uint8Array; constantTimeEq(a: Uint8Array, b: Uint8Array): boolean; toBase64Url(data: Uint8Array): string; fromBase64Url(encoded: string): Uint8Array; toHex(data: Uint8Array): string; fromHex(encoded: string): Uint8Array; generateUuid(): string; zeroize(data: Uint8Array): void; /** * Build the canonical AAD bytes for envelope encryption (§5.3). * Reference Rust uses serde_json::json!() which (without preserve_order) * produces alphabetically-sorted-key JSON. Mirror exactly. */ canonicalAad(headerFields: { v: number; suite: string; aead: string; docId: string; vaultId?: string | null; epoch: number; policy: { mode: string; t?: number; n?: number; } | undefined; }): Uint8Array; /** `doc:{docId}:epoch:{epoch}` */ buildContext(docId: string, epoch: number): string; } export interface CryptoProvider extends AeadProvider, Argon2Provider, KdfProvider, KemProvider, ShamirProvider, UtilProvider { /** Identifies which backend is active. Useful for tests + error messages. */ readonly backend: 'wasm' | 'react-native'; }