{"_id":"arkiv-encryption","name":"arkiv-encryption","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"arkiv-encryption","version":"0.1.0","description":"AES-256-GCM payload encryption for Arkiv entities, using the same WebCrypto envelope in Node and browsers.","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"engines":{"node":">=22"},"scripts":{"build":"tsc","typecheck":"tsc --noEmit","test":"npm run build && node --test test/*.test.mjs","prepack":"npm run build"},"devDependencies":{"typescript":"5.9.3"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/SantiagoDevRel/arkiv-encrypted-entities.git"},"homepage":"https://github.com/SantiagoDevRel/arkiv-encrypted-entities#readme","_id":"arkiv-encryption@0.1.0","bugs":{"url":"https://github.com/SantiagoDevRel/arkiv-encrypted-entities/issues"},"_integrity":"sha512-xa1iGwaoXMbj1dAbxhJ/7+T9QYRbuCF100YRuAtJDplsFv31eqU830qAesYYXRWCUE+tnUriQr1hOvSYI39sPQ==","_resolved":"C:\\Users\\STZTR\\Downloads\\arkiv-encryption-release-20260909\\arkiv-encryption-0.1.0.tgz","_from":"file:C:/Users/STZTR/Downloads/arkiv-encryption-release-20260909/arkiv-encryption-0.1.0.tgz","_nodeVersion":"22.22.3","_npmVersion":"10.9.8","dist":{"integrity":"sha512-xa1iGwaoXMbj1dAbxhJ/7+T9QYRbuCF100YRuAtJDplsFv31eqU830qAesYYXRWCUE+tnUriQr1hOvSYI39sPQ==","shasum":"885af2f2b8518c078ff19eac2b44d69901842f55","tarball":"https://registry.npmjs.org/arkiv-encryption/-/arkiv-encryption-0.1.0.tgz","fileCount":7,"unpackedSize":21886,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCLDC3Hu3LiU7bf2IuW9kAsj6fnBr5b+5lIJknX0B123gIgDXNMoDVkjC05jI6FJSNUG9Y5+ZCCVjkX2YkXxwO0DBU="}]},"_npmUser":{"name":"santiagodevrel","email":"santiagotrujillozuluaga@gmail.com"},"directories":{},"maintainers":[{"name":"santiagodevrel","email":"santiagotrujillozuluaga@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/arkiv-encryption_0.1.0_1788956564375_0.3601607559234479"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-09T12:22:44.187Z","0.1.0":"2026-09-09T12:22:44.509Z","modified":"2026-09-09T12:22:44.738Z"},"maintainers":[{"name":"santiagodevrel","email":"santiagotrujillozuluaga@gmail.com"}],"description":"AES-256-GCM payload encryption for Arkiv entities, using the same WebCrypto envelope in Node and browsers.","homepage":"https://github.com/SantiagoDevRel/arkiv-encrypted-entities#readme","repository":{"type":"git","url":"git+https://github.com/SantiagoDevRel/arkiv-encrypted-entities.git"},"bugs":{"url":"https://github.com/SantiagoDevRel/arkiv-encrypted-entities/issues"},"license":"MIT","readme":"# arkiv-encryption\n\nEncrypt an Arkiv entity's payload before storing it, then authenticate and decrypt the retrieved bytes locally. Public attributes can still be queried. This small ESM package extracts the AES-GCM envelope already used by the Arkiv cookbook; it does not replace the Arkiv SDK.\n\n**These packages are intended for testnet use.**\n\nVersion: **0.1.0**. Release status and actually executed checks are recorded in [verification](https://github.com/SantiagoDevRel/arkiv-encrypted-entities/blob/arkiv-encryption-v0.1.0/docs/verification.md). A local build or tarball is not an npm release.\n\n- [npm](https://www.npmjs.com/package/arkiv-encryption)\n- [Source](https://github.com/SantiagoDevRel/arkiv-encrypted-entities)\n- [Runnable wallet sample](https://github.com/SantiagoDevRel/arkiv-encrypted-entities/blob/arkiv-encryption-v0.1.0/sample/README.md)\n- [Consumer agent guide](AGENTS.md) and [sample agent guide](https://github.com/SantiagoDevRel/arkiv-encrypted-entities/blob/arkiv-encryption-v0.1.0/sample/AGENTS.md)\n\nAgents integrating the installed package should explicitly open `node_modules/arkiv-encryption/AGENTS.md` and this README. Package managers do not automatically load them.\n\n## Install and run a minimal example\n\nRequires Node.js 22+ with WebCrypto. The library itself needs no wallet, funds, RPC, access key or SDK.\n\nActually tested: Node **22.22.3** and TypeScript **5.9.3**; use that TypeScript version for the examples and generated typed-array declarations. Older TypeScript versions are not verified. The browser sample is tested in Chrome **152** with SDK **0.8.0**, viem **2.56.3** and **Tiramisu testnet (7738577)**. Other browsers, runtimes and networks are not claimed as tested.\n\n```sh\nmkdir encrypted-demo\ncd encrypted-demo\nnpm init -y\nnpm install --save-exact arkiv-encryption@0.1.0\n```\n\nCreate `demo.mjs`:\n\n```js\nimport { generateKey, importKey, encryptPayload, decryptPayload } from 'arkiv-encryption';\n\nconst secret = generateKey(); // Keep a private backup; never log this or put it on-chain.\nconst key = await importKey(secret);\nconst ciphertext = await encryptPayload(key, 'Hello Arkiv');\nconst recovered = await decryptPayload(key, ciphertext);\nconsole.log(new TextDecoder().decode(recovered));\nconsole.log('Envelope bytes:', ciphertext.length);\n```\n\n```sh\nnode demo.mjs\n```\n\nExpected output:\n\n```text\nHello Arkiv\nEnvelope bytes: 39\n```\n\nEach encryption produces different ciphertext. Empty plaintext and binary `Uint8Array` input are supported.\n\n\n### TypeScript and typed failures\n\nTo check the minimal example with TypeScript, save the same code as `demo.mts` (instead of `demo.mjs`) and run:\n\n```sh\nnpm install --save-dev --save-exact typescript@5.9.3\nnpx tsc demo.mts --module nodenext --target es2022 --lib es2022,dom --strict --outDir build\nnode build/demo.mjs\n```\n\nHandle authentication failures without logging key or payload data:\n\n```ts\nimport { EncryptionError } from 'arkiv-encryption';\ntry {\n  await decryptPayload(key, ciphertext);\n} catch (error) {\n  if (error instanceof EncryptionError) console.error(error.code); // e.g. DECRYPTION_FAILED\n  else throw error;\n}\n```\n## Public API\n\n| Export | Contract |\n| --- | --- |\n| `generateKey(): string` | Cryptographically random 32-byte secret encoded as 64 hex characters. |\n| `importKey(raw: string \\| Uint8Array): Promise<CryptoKey>` | Exactly 64 hex characters without `0x`, or 32 bytes. Returns a non-extractable AES-256-GCM handle. This is **not** password derivation. |\n| `encryptPayload(key, plaintext: string \\| Uint8Array): Promise<Uint8Array>` | UTF-8 for strings. At most `MAX_PLAINTEXT_BYTES` (100,000 bytes). Fresh random IV per call. |\n| `decryptPayload(key, envelope: Uint8Array): Promise<Uint8Array>` | Returns bytes only after successful authentication; rejects wrong keys and tampering. |\n| `CONTENT_TYPE` | `application/vnd.arkiv.encrypted.v1`; store with the envelope to identify its format. |\n| `ENVELOPE` | Frozen algorithm, IV length, tag length and wire layout. |\n| `VERSION`, `MAX_PLAINTEXT_BYTES` | Package version and conservative single-entity input policy. |\n| `EncryptionError`, `EncryptionErrorCode` | Safe, stable error codes listed below; messages contain no secret data. |\n\nTypeScript declarations ship with the ESM export. CommonJS `require()` is not an advertised entry point; use `await import('arkiv-encryption')` from CommonJS. Browser use requires HTTPS or localhost and WebCrypto. No Node built-ins or runtime dependencies are bundled.\n\n## Store and retrieve on Arkiv\n\nThe [sample](https://github.com/SantiagoDevRel/arkiv-encrypted-entities/blob/arkiv-encryption-v0.1.0/sample/README.md) is the complete implementation: wallet connection, network validation, local encryption, one signed entity creation, ciphertext retrieval and local decryption. It imports this npm package rather than duplicating encryption.\n\nFor an existing SDK integration, install the tested dependencies:\n\n```sh\nnpm install --save-exact @arkiv-network/sdk@0.8.0 viem@2.56.3\n```\n\nGiven your SDK `walletClient` and `publicClient`, both configured for Tiramisu, and the key from the minimal example:\n\n```ts\nimport { CONTENT_TYPE, encryptPayload, decryptPayload } from 'arkiv-encryption';\nimport { ExpirationTime } from '@arkiv-network/sdk';\nimport { str } from '@arkiv-network/sdk/attr';\n\nconst payload = await encryptPayload(key, 'Non-sensitive integration test');\nconst created = await walletClient.createEntity({\n  payload,\n  contentType: CONTENT_TYPE,\n  attributes: { app: str('encrypted-entities-sample') }, // Public and queryable.\n  expires: ExpirationTime.fromSeconds(86400),\n});\nconst entity = await publicClient.getEntity(created.entityKey);\nif (entity.contentType !== CONTENT_TYPE || !entity.payload) throw new Error('Unexpected entity format');\nconst result = await decryptPayload(key, entity.payload);\nconsole.log(new TextDecoder().decode(result));\n```\n\nExpected recovered text: `Non-sensitive integration test`. Entity and transaction keys vary. Check your RPC's chain ID before writing, recheck the wallet's account/network before signing, and wait for the SDK's confirmed result. Do not automatically retry an uncertain write: it may already be on-chain. See the sample for these guards and gas estimation.\n\nTiramisu chain ID is **7738577**. The SDK's `tiramisu` export supplies the network configuration. Writes need a wallet with test GLM from the [Hub faucet](https://hub.arkiv.network/faucet). Reads and local crypto do not need a wallet. The public RPC can be used without an access key; provider limits can apply. If your integration requires a higher allowance, obtain an [access key](https://hub.arkiv.network/access-keys) and follow the provider's restrictions. Never embed a server-only key in browser code. No credentials are shipped.\n\n## Privacy and key custody\n\n- **Only the payload is encrypted.** Attributes, owner/creator addresses, entity key, content type, expiration, transactions and payload length remain public. In this unpadded format the exact plaintext byte length is envelope length minus 28. Query public attributes, not encrypted plaintext.\n- Format: **12-byte random IV || ciphertext || 16-byte authentication tag**, AES-256-GCM with a 128-bit tag. There is no compression and no extra authenticated data. Format version is identified by `CONTENT_TYPE`, not an embedded header. Existing cookbook envelopes use the same byte order; compressed cookbook content still needs its separate decompression step.\n- Authentication detects modified encrypted bytes or a wrong key. It **does not bind the payload to an entity key, wallet, network or public attributes**, and does not establish authorship. A valid envelope can be copied to another entity. If the application needs trusted authorship, verify an independently trusted entity/owner in its read policy.\n- Connecting or signing with MetaMask/Rabby does **not** derive or recover the encryption key. Generate an independent key and keep it in a password manager or another approved secret store. Do not use a wallet private key, seed phrase, password, transaction signature or login signature as this key.\n- Prefer a fresh key per note. If you reuse a key, track usage across all applications/devices and rotate well before 2^32 encryptions: the random-IV construction has a per-key invocation bound ([NIST SP 800-38D, section 8.3](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf)). The package is stateless and does not enforce a global counter or rotate keys. Preserve old keys privately while their ciphertext is still needed.\n- The sample holds keys and plaintext in page memory only; a reload loses them unless you made a private backup. The non-extractable CryptoKey does not erase the original hex string from application memory. JavaScript cannot guarantee memory erasure.\n- Anyone with the encryption key and ciphertext can decrypt. There is no key escrow, account recovery, sharing protocol, access revocation or automatic rotation. Losing the key loses access. A compromised key exposes previously published ciphertext.\n- Entity Expiration removes active availability; it is **not erasure** of transaction history or other copies. Do not test with personal or production secrets. This package is not an independently audited privacy system, and does not protect against an XSS-compromised application, malicious extensions, devices or recipients.\n\n## Errors and recovery\n\nValidation and authentication failures use `EncryptionError`. Unexpected WebCrypto/platform errors during key import or encryption can propagate; show a generic failure for unknown errors rather than rendering or logging arbitrary error objects.\n\n| Code / condition | Resolution |\n| --- | --- |\n| `INVALID_KEY` | Supply the original 64-character hex encryption key, without `0x`, whitespace or password text; or generate a key for new data. A new key cannot open old data. |\n| `DECRYPTION_FAILED` | Verify the original key and ciphertext source. Wrong key and modified ciphertext intentionally have the same failure; no plaintext is returned. |\n| `INVALID_ENVELOPE` | Retrieve the complete v1 binary payload, not its JSON/hex representation. Verify the content type. |\n| `INVALID_INPUT` | Use text or Uint8Array, within 100,000 UTF-8 bytes. Large-file chunking is outside this package. |\n| `CRYPTO_UNAVAILABLE` | Use Node 22+ or a modern browser on HTTPS/localhost. |\n| Wallet absent/rejected | Install/unlock MetaMask or Rabby and approve the intended testnet request, or read without a wallet. |\n| Wrong network / insufficient funds | Use Tiramisu in both wallet and RPC; obtain test GLM from the faucet. |\n| Missing/expired entity | Check entity key and network. An expired entity may no longer be retrievable through the active API. |\n| RPC failure/rate limit | Retry a **read** later or use an authorized provider endpoint. Never infer write failure from a timeout or automatically resubmit. |\n\n## Source development\n\n```sh\ngit clone https://github.com/SantiagoDevRel/arkiv-encrypted-entities.git\ncd arkiv-encrypted-entities\nnpm ci\nnpm test\nnpm run typecheck\nnpm pack --dry-run\n```\n\nThe sample has its own install and lockfile; see its README. Crypto interoperability tests use Node's independent `createCipheriv`/`createDecipheriv` implementation against the package's WebCrypto output in both directions. Exact release evidence, browser widths and network outcomes belong in [docs/verification.md](https://github.com/SantiagoDevRel/arkiv-encrypted-entities/blob/arkiv-encryption-v0.1.0/docs/verification.md), not in implied support claims.\n","readmeFilename":"README.md","_rev":"1-2f5e6b0400a345d28d617e13c62791e2"}