@cardanowall/crypto-core 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cbor.d.cts +6 -2
- package/dist/cbor.d.ts +6 -2
- package/dist/hash.cjs +10 -1
- package/dist/hash.cjs.map +1 -1
- package/dist/hash.d.cts +8 -1
- package/dist/hash.d.ts +8 -1
- package/dist/hash.js +10 -2
- package/dist/hash.js.map +1 -1
- package/dist/index.cjs +2123 -409
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.js +2098 -400
- package/dist/index.js.map +1 -1
- package/dist/sealed-poe.cjs +1959 -332
- package/dist/sealed-poe.cjs.map +1 -1
- package/dist/sealed-poe.d.cts +141 -62
- package/dist/sealed-poe.d.ts +141 -62
- package/dist/sealed-poe.js +1940 -324
- package/dist/sealed-poe.js.map +1 -1
- package/dist/seed-derive.cjs +195 -0
- package/dist/seed-derive.cjs.map +1 -1
- package/dist/seed-derive.d.cts +12 -1
- package/dist/seed-derive.d.ts +12 -1
- package/dist/seed-derive.js +192 -1
- package/dist/seed-derive.js.map +1 -1
- package/package.json +1 -1
- package/dist/canonical-DHeJLYDR.d.cts +0 -7
- package/dist/canonical-DHeJLYDR.d.ts +0 -7
package/dist/seed-derive.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/kdf/hkdf.ts","../src/kem/mlkem768x25519.ts","../src/kem/x25519.ts","../src/sig/ed25519.ts","../src/seed-derive/errors.ts","../src/seed-derive/derive.ts"],"names":[],"mappings":"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","file":"seed-derive.js","sourcesContent":["import { hkdf } from '@noble/hashes/hkdf.js';\nimport { sha256 } from '@noble/hashes/sha2.js';\n\nexport interface HkdfSha256Opts {\n readonly ikm: Uint8Array;\n readonly salt: Uint8Array;\n readonly info: Uint8Array;\n readonly length: number;\n}\n\nexport function hkdfSha256(opts: HkdfSha256Opts): Uint8Array {\n return hkdf(sha256, opts.ikm, opts.salt, opts.info, opts.length);\n}\n","import { XWing } from '@noble/post-quantum/hybrid.js';\n\n// X-Wing (ML-KEM-768 + X25519) hybrid KEM per draft-connolly-cfrg-xwing-kem-10.\n// `XWing` is @noble/post-quantum's alias for `ml_kem768_x25519`. We expose it\n// through opts-object wrappers that pin the wire lengths and map noble's field\n// names onto the project's vocabulary.\n//\n// Unlike the bare X25519 KEM, there is no contributory-behaviour rejection to\n// translate: X-Wing combines the ML-KEM and X25519 shared secrets through a\n// SHA3-256 combiner that also binds the X25519 ephemeral and recipient public\n// keys, and ML-KEM's implicit rejection already yields a constant-work\n// pseudorandom secret on a malformed ciphertext. Decapsulation therefore never\n// throws on attacker-supplied wire data — a wrong shared secret is the correct,\n// indistinguishable failure mode, and callers MUST treat it as a non-match\n// rather than expecting an exception.\n\nexport const MLKEM768X25519_PUBLIC_KEY_LENGTH = 1216 as const;\nexport const MLKEM768X25519_ENC_LENGTH = 1120 as const;\nexport const MLKEM768X25519_SHARED_SECRET_LENGTH = 32 as const;\nexport const MLKEM768X25519_SEED_LENGTH = 32 as const;\nexport const MLKEM768X25519_ESEED_LENGTH = 64 as const;\n\nexport interface Mlkem768X25519KeyPair {\n // The 32-byte root seed IS the secret key: the ML-KEM coins and the X25519\n // scalar are re-expanded from it via SHAKE-256 at decapsulation. (Later X-Wing\n // drafts also define an optional expanded decapsulation-key form; we keep the\n // seed-only key, which the draft-10 Appendix C vectors still pin.)\n readonly secretSeed: Uint8Array;\n readonly publicKey: Uint8Array;\n}\n\nexport interface Mlkem768X25519EncapsulateOpts {\n readonly publicKey: Uint8Array;\n // Optional 64-byte encapsulation randomness (msgRand). When supplied the\n // ciphertext and shared secret are fully deterministic; a 32-byte value is\n // rejected by noble, so we pin the length here too.\n readonly eseed?: Uint8Array;\n}\n\nexport interface Mlkem768X25519Encapsulation {\n readonly enc: Uint8Array;\n readonly ss: Uint8Array;\n}\n\nexport interface Mlkem768X25519DecapsulateOpts {\n readonly secretSeed: Uint8Array;\n readonly enc: Uint8Array;\n}\n\nexport function mlkem768x25519Keygen(seed: Uint8Array): Mlkem768X25519KeyPair {\n if (seed.length !== MLKEM768X25519_SEED_LENGTH) {\n throw new Error(\n `mlkem768x25519 seed must be ${MLKEM768X25519_SEED_LENGTH} bytes, got ${seed.length}`,\n );\n }\n const { secretKey, publicKey } = XWing.keygen(seed);\n return { secretSeed: secretKey, publicKey };\n}\n\nexport function mlkem768x25519Encapsulate(\n opts: Mlkem768X25519EncapsulateOpts,\n): Mlkem768X25519Encapsulation {\n if (opts.publicKey.length !== MLKEM768X25519_PUBLIC_KEY_LENGTH) {\n throw new Error(\n `mlkem768x25519 public key must be ${MLKEM768X25519_PUBLIC_KEY_LENGTH} bytes, got ${opts.publicKey.length}`,\n );\n }\n if (opts.eseed !== undefined && opts.eseed.length !== MLKEM768X25519_ESEED_LENGTH) {\n throw new Error(\n `mlkem768x25519 eseed must be ${MLKEM768X25519_ESEED_LENGTH} bytes, got ${opts.eseed.length}`,\n );\n }\n const { cipherText, sharedSecret } = XWing.encapsulate(opts.publicKey, opts.eseed);\n return { enc: cipherText, ss: sharedSecret };\n}\n\nexport function mlkem768x25519Decapsulate(opts: Mlkem768X25519DecapsulateOpts): Uint8Array {\n // Pre-check both lengths before calling noble: decapsulation must perform a\n // constant amount of work for any caller-supplied ciphertext (implicit\n // rejection), which requires the inputs to be the exact expected sizes.\n if (opts.secretSeed.length !== MLKEM768X25519_SEED_LENGTH) {\n throw new Error(\n `mlkem768x25519 secret seed must be ${MLKEM768X25519_SEED_LENGTH} bytes, got ${opts.secretSeed.length}`,\n );\n }\n if (opts.enc.length !== MLKEM768X25519_ENC_LENGTH) {\n throw new Error(\n `mlkem768x25519 enc must be ${MLKEM768X25519_ENC_LENGTH} bytes, got ${opts.enc.length}`,\n );\n }\n // noble's signature is decapsulate(cipherText, secretKey) — ciphertext first.\n return XWing.decapsulate(opts.enc, opts.secretSeed);\n}\n","import { x25519 } from '@noble/curves/ed25519.js';\n\n// RFC 7748 §6.1 contributory-behaviour rejection: a small-order (low-order)\n// Montgomery `u` coordinate makes the X25519 shared secret all-zero, which\n// @noble/curves refuses with `Error: invalid private or public key received`.\n// We rethrow that as a *typed* error so callers can distinguish a structurally\n// valid-but-malicious peer public key (a property of attacker-supplied wire\n// data — trial-decrypt MUST treat the slot as a non-match, not crash) from\n// genuine caller misuse such as a wrong-length key (which @noble raises as a\n// RangeError and which we deliberately let propagate untouched).\nexport class X25519LowOrderPointError extends Error {\n readonly code = 'X25519_LOW_ORDER_POINT' as const;\n constructor(options?: { cause?: unknown }) {\n super('x25519 ECDH rejected: peer public key is a small-order point', options);\n this.name = 'X25519LowOrderPointError';\n }\n}\n\n// @noble/curves v2 signals a small-order/all-zero shared secret with this exact\n// message. Matching on it (rather than the broad Error class) keeps unrelated\n// failures — e.g. a future internal assertion — surfacing as themselves.\nconst NOBLE_LOW_ORDER_MESSAGE = 'invalid private or public key received';\n\nexport interface X25519KeyPair {\n readonly secretKey: Uint8Array;\n readonly publicKey: Uint8Array;\n}\n\nexport interface X25519PublicKeyOpts {\n readonly secretKey: Uint8Array;\n}\n\nexport interface X25519EcdhOpts {\n readonly secretKey: Uint8Array;\n readonly theirPublicKey: Uint8Array;\n}\n\nexport function x25519Keygen(): X25519KeyPair {\n return x25519.keygen();\n}\n\nexport function x25519PublicKey(opts: X25519PublicKeyOpts): Uint8Array {\n return x25519.getPublicKey(opts.secretKey);\n}\n\nexport function x25519Ecdh(opts: X25519EcdhOpts): Uint8Array {\n try {\n return x25519.getSharedSecret(opts.secretKey, opts.theirPublicKey);\n } catch (e) {\n // Translate ONLY the contributory-check rejection into our typed error.\n // A wrong-length key throws a RangeError from @noble's length assertion;\n // that is caller misuse, not malicious wire data, so it must propagate.\n if (e instanceof Error && e.message === NOBLE_LOW_ORDER_MESSAGE) {\n throw new X25519LowOrderPointError({ cause: e });\n }\n throw e;\n }\n}\n","import * as ed from '@noble/ed25519';\nimport { sha512 } from '@noble/hashes/sha2.js';\n\ned.hashes.sha512 = sha512;\n\n// Ed25519 group order L (= 2^252 + 27742317777372353535851937790883648493).\nconst L = ed.Point.CURVE().n;\n\nexport interface SignEd25519Opts {\n readonly seed: Uint8Array;\n readonly message: Uint8Array;\n}\n\nexport interface VerifyEd25519Opts {\n readonly publicKey: Uint8Array;\n readonly message: Uint8Array;\n readonly signature: Uint8Array;\n}\n\nexport interface GetPublicKeyEd25519Opts {\n readonly seed: Uint8Array;\n}\n\nexport function signEd25519(opts: SignEd25519Opts): Uint8Array {\n return ed.sign(opts.message, opts.seed);\n}\n\n// Little-endian 32-byte scalar → bigint.\nfunction leBytesToBigInt(bytes: Uint8Array): bigint {\n let value = 0n;\n for (let i = bytes.length - 1; i >= 0; i--) {\n value = (value << 8n) | BigInt(bytes[i]!);\n }\n return value;\n}\n\n// Strict (non-cofactored) Ed25519 verification per RFC 8032 §5.1.7, matching\n// libsodium/PyNaCl `crypto_sign_verify_detached` and ed25519-dalek\n// `verify_strict`. The cofactor-less check rejects every small-order /\n// torsion-component edge case in the C2SP/CCTV corpus, which noble's\n// `{ zip215: false }` mode does NOT (it remains cofactored: it checks\n// `[8]([S]B - [k]A - R) == 0`, accepting torsion components).\n//\n// The verification equation is the unscaled `[S]B == R + [k]A`, rewritten as\n// `[S]B - [k]A - R == identity`. We reject S >= L (non-canonical scalar) and\n// any small-order A or R up front, so a torsion component can never be smuggled\n// through the cofactor multiplication the cofactored variant performs.\nexport function verifyEd25519(opts: VerifyEd25519Opts): boolean {\n const { signature, message, publicKey } = opts;\n if (signature.length !== 64 || publicKey.length !== 32) return false;\n\n // S = LE(sig[32..64]); reject if not a canonical scalar (S >= L).\n const S = leBytesToBigInt(signature.subarray(32, 64));\n if (S >= L) return false;\n\n // Decode A (public key) and R (sig[0..32]) with the canonical (non-zip215)\n // point encoding; a non-canonical encoding throws and rejects.\n let A: ed.Point;\n let R: ed.Point;\n try {\n A = ed.Point.fromBytes(publicKey);\n R = ed.Point.fromBytes(signature.subarray(0, 32));\n } catch {\n return false;\n }\n\n // Reject small-order (cofactor-torsion) A or R: this is exactly the strictness\n // that distinguishes verify_strict from the cofactored check.\n if (A.isSmallOrder() || R.isSmallOrder()) return false;\n\n // k = SHA-512(R || A || M) reduced mod L.\n const k =\n leBytesToBigInt(ed.hash(concatBytes(signature.subarray(0, 32), publicKey, message))) % L;\n\n // Accept iff [S]B - [k]A - R == identity. `multiplyUnsafe` returns the\n // identity for a 0 scalar, but guard explicitly to avoid relying on that.\n const sB = S === 0n ? ed.Point.ZERO : ed.Point.BASE.multiplyUnsafe(S);\n const kA = k === 0n ? ed.Point.ZERO : A.multiplyUnsafe(k);\n return sB.subtract(kA).subtract(R).is0();\n}\n\nfunction concatBytes(...parts: Uint8Array[]): Uint8Array {\n let total = 0;\n for (const p of parts) total += p.length;\n const out = new Uint8Array(total);\n let offset = 0;\n for (const p of parts) {\n out.set(p, offset);\n offset += p.length;\n }\n return out;\n}\n\nexport function getPublicKeyEd25519(opts: GetPublicKeyEd25519Opts): Uint8Array {\n return ed.getPublicKey(opts.seed);\n}\n","export type SeedDeriveErrorCode = 'INVALID_SEED_LENGTH';\n\nexport class SeedDeriveError extends Error {\n readonly code: SeedDeriveErrorCode;\n\n constructor(code: SeedDeriveErrorCode, message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'SeedDeriveError';\n this.code = code;\n }\n}\n","import { hkdfSha256 } from '../kdf/hkdf';\nimport { mlkem768x25519Keygen } from '../kem/mlkem768x25519';\nimport { x25519PublicKey } from '../kem/x25519';\nimport { getPublicKeyEd25519 } from '../sig/ed25519';\n\nimport { SeedDeriveError } from './errors';\n\n// HKDF info constants for the long-term identity keypairs.\n// These literal byte sequences are part of the on-wire protocol; every\n// conformant implementation MUST hash against these exact ASCII bytes (the\n// Python parity twin pins the identical labels).\nexport const INFO_ED25519: Uint8Array = new TextEncoder().encode('cardano-poe-ed25519-v1');\nexport const INFO_X25519: Uint8Array = new TextEncoder().encode('cardano-poe-x25519-v1');\nexport const INFO_MLKEM768X25519: Uint8Array = new TextEncoder().encode(\n 'cardano-poe-mlkem768x25519-v1',\n);\n\nif (INFO_ED25519.length !== 22) {\n throw new Error('INFO_ED25519 byte-length invariant violated (expected 22)');\n}\nif (INFO_X25519.length !== 21) {\n throw new Error('INFO_X25519 byte-length invariant violated (expected 21)');\n}\nif (INFO_MLKEM768X25519.length !== 29) {\n throw new Error('INFO_MLKEM768X25519 byte-length invariant violated (expected 29)');\n}\n\nconst EMPTY_SALT: Uint8Array = new Uint8Array(0);\nconst SEED_LENGTH = 32;\nconst DERIVED_LENGTH = 32;\n\nexport interface DerivedEd25519KeyPair {\n readonly secretKey: Uint8Array;\n readonly publicKey: Uint8Array;\n}\n\nexport interface DerivedX25519KeyPair {\n readonly secretKey: Uint8Array;\n readonly publicKey: Uint8Array;\n}\n\nexport interface DerivedMlKem768X25519KeyPair {\n readonly secretSeed: Uint8Array;\n readonly publicKey: Uint8Array;\n}\n\nfunction assertSeedLength(seed: Uint8Array): void {\n if (seed.length !== SEED_LENGTH) {\n throw new SeedDeriveError(\n 'INVALID_SEED_LENGTH',\n `seed must be exactly 32 bytes, got ${seed.length}`,\n );\n }\n}\n\nexport function deriveEd25519KeypairFromSeed(seed: Uint8Array): DerivedEd25519KeyPair {\n assertSeedLength(seed);\n const secretKey = hkdfSha256({\n ikm: seed,\n salt: EMPTY_SALT,\n info: INFO_ED25519,\n length: DERIVED_LENGTH,\n });\n const publicKey = getPublicKeyEd25519({ seed: secretKey });\n return { secretKey, publicKey };\n}\n\nexport function deriveX25519KeypairFromSeed(seed: Uint8Array): DerivedX25519KeyPair {\n assertSeedLength(seed);\n const secretKey = hkdfSha256({\n ikm: seed,\n salt: EMPTY_SALT,\n info: INFO_X25519,\n length: DERIVED_LENGTH,\n });\n const publicKey = x25519PublicKey({ secretKey });\n return { secretKey, publicKey };\n}\n\nexport function deriveMlKem768X25519KeypairFromSeed(\n seed: Uint8Array,\n): DerivedMlKem768X25519KeyPair {\n assertSeedLength(seed);\n // The 32-byte HKDF output IS the X-Wing root seed: keygen re-expands the\n // ML-KEM coins and the X25519 scalar from it, so the derived keypair's\n // secretSeed equals this value.\n const xwingSeed = hkdfSha256({\n ikm: seed,\n salt: EMPTY_SALT,\n info: INFO_MLKEM768X25519,\n length: DERIVED_LENGTH,\n });\n return mlkem768x25519Keygen(xwingSeed);\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/kdf/hkdf.ts","../src/kem/mlkem768x25519.ts","../src/kem/x25519.ts","../src/sig/ed25519.ts","../src/seed-derive/errors.ts","../src/seed-derive/derive.ts","../src/recipient/bech32.ts","../src/util/hex.ts","../src/seed-derive/encoding.ts"],"names":["SEED_LENGTH"],"mappings":"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","file":"seed-derive.js","sourcesContent":["import { hkdf } from '@noble/hashes/hkdf.js';\nimport { sha256 } from '@noble/hashes/sha2.js';\n\nexport interface HkdfSha256Opts {\n readonly ikm: Uint8Array;\n readonly salt: Uint8Array;\n readonly info: Uint8Array;\n readonly length: number;\n}\n\nexport function hkdfSha256(opts: HkdfSha256Opts): Uint8Array {\n return hkdf(sha256, opts.ikm, opts.salt, opts.info, opts.length);\n}\n","import { XWing } from '@noble/post-quantum/hybrid.js';\n\n// X-Wing (ML-KEM-768 + X25519) hybrid KEM per draft-connolly-cfrg-xwing-kem-10.\n// `XWing` is @noble/post-quantum's alias for `ml_kem768_x25519`. We expose it\n// through opts-object wrappers that pin the wire lengths and map noble's field\n// names onto the project's vocabulary.\n//\n// Unlike the bare X25519 KEM, there is no contributory-behaviour rejection to\n// translate: X-Wing combines the ML-KEM and X25519 shared secrets through a\n// SHA3-256 combiner that also binds the X25519 ephemeral and recipient public\n// keys, and ML-KEM's implicit rejection already yields a constant-work\n// pseudorandom secret on a malformed ciphertext. Decapsulation therefore never\n// throws on attacker-supplied wire data — a wrong shared secret is the correct,\n// indistinguishable failure mode, and callers MUST treat it as a non-match\n// rather than expecting an exception.\n\nexport const MLKEM768X25519_PUBLIC_KEY_LENGTH = 1216 as const;\nexport const MLKEM768X25519_ENC_LENGTH = 1120 as const;\nexport const MLKEM768X25519_SHARED_SECRET_LENGTH = 32 as const;\nexport const MLKEM768X25519_SEED_LENGTH = 32 as const;\nexport const MLKEM768X25519_ESEED_LENGTH = 64 as const;\n\nexport interface Mlkem768X25519KeyPair {\n // The 32-byte root seed IS the secret key: the ML-KEM coins and the X25519\n // scalar are re-expanded from it via SHAKE-256 at decapsulation. (Later X-Wing\n // drafts also define an optional expanded decapsulation-key form; we keep the\n // seed-only key, which the draft-10 Appendix C vectors still pin.)\n readonly secretSeed: Uint8Array;\n readonly publicKey: Uint8Array;\n}\n\nexport interface Mlkem768X25519EncapsulateOpts {\n readonly publicKey: Uint8Array;\n // Optional 64-byte encapsulation randomness (msgRand). When supplied the\n // ciphertext and shared secret are fully deterministic; a 32-byte value is\n // rejected by noble, so we pin the length here too.\n readonly eseed?: Uint8Array;\n}\n\nexport interface Mlkem768X25519Encapsulation {\n readonly enc: Uint8Array;\n readonly ss: Uint8Array;\n}\n\nexport interface Mlkem768X25519DecapsulateOpts {\n readonly secretSeed: Uint8Array;\n readonly enc: Uint8Array;\n}\n\nexport function mlkem768x25519Keygen(seed: Uint8Array): Mlkem768X25519KeyPair {\n if (seed.length !== MLKEM768X25519_SEED_LENGTH) {\n throw new Error(\n `mlkem768x25519 seed must be ${MLKEM768X25519_SEED_LENGTH} bytes, got ${seed.length}`,\n );\n }\n const { secretKey, publicKey } = XWing.keygen(seed);\n return { secretSeed: secretKey, publicKey };\n}\n\nexport function mlkem768x25519Encapsulate(\n opts: Mlkem768X25519EncapsulateOpts,\n): Mlkem768X25519Encapsulation {\n if (opts.publicKey.length !== MLKEM768X25519_PUBLIC_KEY_LENGTH) {\n throw new Error(\n `mlkem768x25519 public key must be ${MLKEM768X25519_PUBLIC_KEY_LENGTH} bytes, got ${opts.publicKey.length}`,\n );\n }\n if (opts.eseed !== undefined && opts.eseed.length !== MLKEM768X25519_ESEED_LENGTH) {\n throw new Error(\n `mlkem768x25519 eseed must be ${MLKEM768X25519_ESEED_LENGTH} bytes, got ${opts.eseed.length}`,\n );\n }\n const { cipherText, sharedSecret } = XWing.encapsulate(opts.publicKey, opts.eseed);\n return { enc: cipherText, ss: sharedSecret };\n}\n\nexport function mlkem768x25519Decapsulate(opts: Mlkem768X25519DecapsulateOpts): Uint8Array {\n // Pre-check both lengths before calling noble: decapsulation must perform a\n // constant amount of work for any caller-supplied ciphertext (implicit\n // rejection), which requires the inputs to be the exact expected sizes.\n if (opts.secretSeed.length !== MLKEM768X25519_SEED_LENGTH) {\n throw new Error(\n `mlkem768x25519 secret seed must be ${MLKEM768X25519_SEED_LENGTH} bytes, got ${opts.secretSeed.length}`,\n );\n }\n if (opts.enc.length !== MLKEM768X25519_ENC_LENGTH) {\n throw new Error(\n `mlkem768x25519 enc must be ${MLKEM768X25519_ENC_LENGTH} bytes, got ${opts.enc.length}`,\n );\n }\n // noble's signature is decapsulate(cipherText, secretKey) — ciphertext first.\n return XWing.decapsulate(opts.enc, opts.secretSeed);\n}\n","import { x25519 } from '@noble/curves/ed25519.js';\n\n// RFC 7748 §6.1 contributory-behaviour rejection: a small-order (low-order)\n// Montgomery `u` coordinate makes the X25519 shared secret all-zero, which\n// @noble/curves refuses with `Error: invalid private or public key received`.\n// We rethrow that as a *typed* error so callers can distinguish a structurally\n// valid-but-malicious peer public key (a property of attacker-supplied wire\n// data — trial-decrypt MUST treat the slot as a non-match, not crash) from\n// genuine caller misuse such as a wrong-length key (which @noble raises as a\n// RangeError and which we deliberately let propagate untouched).\nexport class X25519LowOrderPointError extends Error {\n readonly code = 'X25519_LOW_ORDER_POINT' as const;\n constructor(options?: { cause?: unknown }) {\n super('x25519 ECDH rejected: peer public key is a small-order point', options);\n this.name = 'X25519LowOrderPointError';\n }\n}\n\n// @noble/curves v2 signals a small-order/all-zero shared secret with this exact\n// message. Matching on it (rather than the broad Error class) keeps unrelated\n// failures — e.g. a future internal assertion — surfacing as themselves.\nconst NOBLE_LOW_ORDER_MESSAGE = 'invalid private or public key received';\n\nexport interface X25519KeyPair {\n readonly secretKey: Uint8Array;\n readonly publicKey: Uint8Array;\n}\n\nexport interface X25519PublicKeyOpts {\n readonly secretKey: Uint8Array;\n}\n\nexport interface X25519EcdhOpts {\n readonly secretKey: Uint8Array;\n readonly theirPublicKey: Uint8Array;\n}\n\nexport function x25519Keygen(): X25519KeyPair {\n return x25519.keygen();\n}\n\nexport function x25519PublicKey(opts: X25519PublicKeyOpts): Uint8Array {\n return x25519.getPublicKey(opts.secretKey);\n}\n\nexport function x25519Ecdh(opts: X25519EcdhOpts): Uint8Array {\n try {\n return x25519.getSharedSecret(opts.secretKey, opts.theirPublicKey);\n } catch (e) {\n // Translate ONLY the contributory-check rejection into our typed error.\n // A wrong-length key throws a RangeError from @noble's length assertion;\n // that is caller misuse, not malicious wire data, so it must propagate.\n if (e instanceof Error && e.message === NOBLE_LOW_ORDER_MESSAGE) {\n throw new X25519LowOrderPointError({ cause: e });\n }\n throw e;\n }\n}\n","import * as ed from '@noble/ed25519';\nimport { sha512 } from '@noble/hashes/sha2.js';\n\ned.hashes.sha512 = sha512;\n\n// Ed25519 group order L (= 2^252 + 27742317777372353535851937790883648493).\nconst L = ed.Point.CURVE().n;\n\nexport interface SignEd25519Opts {\n readonly seed: Uint8Array;\n readonly message: Uint8Array;\n}\n\nexport interface VerifyEd25519Opts {\n readonly publicKey: Uint8Array;\n readonly message: Uint8Array;\n readonly signature: Uint8Array;\n}\n\nexport interface GetPublicKeyEd25519Opts {\n readonly seed: Uint8Array;\n}\n\nexport function signEd25519(opts: SignEd25519Opts): Uint8Array {\n return ed.sign(opts.message, opts.seed);\n}\n\n// Little-endian 32-byte scalar → bigint.\nfunction leBytesToBigInt(bytes: Uint8Array): bigint {\n let value = 0n;\n for (let i = bytes.length - 1; i >= 0; i--) {\n value = (value << 8n) | BigInt(bytes[i]!);\n }\n return value;\n}\n\n// Strict (non-cofactored) Ed25519 verification per RFC 8032 §5.1.7, matching\n// libsodium/PyNaCl `crypto_sign_verify_detached` and ed25519-dalek\n// `verify_strict`. The cofactor-less check rejects every small-order /\n// torsion-component edge case in the C2SP/CCTV corpus, which noble's\n// `{ zip215: false }` mode does NOT (it remains cofactored: it checks\n// `[8]([S]B - [k]A - R) == 0`, accepting torsion components).\n//\n// The verification equation is the unscaled `[S]B == R + [k]A`, rewritten as\n// `[S]B - [k]A - R == identity`. We reject S >= L (non-canonical scalar) and\n// any small-order A or R up front, so a torsion component can never be smuggled\n// through the cofactor multiplication the cofactored variant performs.\nexport function verifyEd25519(opts: VerifyEd25519Opts): boolean {\n const { signature, message, publicKey } = opts;\n if (signature.length !== 64 || publicKey.length !== 32) return false;\n\n // S = LE(sig[32..64]); reject if not a canonical scalar (S >= L).\n const S = leBytesToBigInt(signature.subarray(32, 64));\n if (S >= L) return false;\n\n // Decode A (public key) and R (sig[0..32]) with the canonical (non-zip215)\n // point encoding; a non-canonical encoding throws and rejects.\n let A: ed.Point;\n let R: ed.Point;\n try {\n A = ed.Point.fromBytes(publicKey);\n R = ed.Point.fromBytes(signature.subarray(0, 32));\n } catch {\n return false;\n }\n\n // Reject small-order (cofactor-torsion) A or R: this is exactly the strictness\n // that distinguishes verify_strict from the cofactored check.\n if (A.isSmallOrder() || R.isSmallOrder()) return false;\n\n // k = SHA-512(R || A || M) reduced mod L.\n const k =\n leBytesToBigInt(ed.hash(concatBytes(signature.subarray(0, 32), publicKey, message))) % L;\n\n // Accept iff [S]B - [k]A - R == identity. `multiplyUnsafe` returns the\n // identity for a 0 scalar, but guard explicitly to avoid relying on that.\n const sB = S === 0n ? ed.Point.ZERO : ed.Point.BASE.multiplyUnsafe(S);\n const kA = k === 0n ? ed.Point.ZERO : A.multiplyUnsafe(k);\n return sB.subtract(kA).subtract(R).is0();\n}\n\nfunction concatBytes(...parts: Uint8Array[]): Uint8Array {\n let total = 0;\n for (const p of parts) total += p.length;\n const out = new Uint8Array(total);\n let offset = 0;\n for (const p of parts) {\n out.set(p, offset);\n offset += p.length;\n }\n return out;\n}\n\nexport function getPublicKeyEd25519(opts: GetPublicKeyEd25519Opts): Uint8Array {\n return ed.getPublicKey(opts.seed);\n}\n","export type SeedDeriveErrorCode = 'INVALID_SEED_LENGTH';\n\nexport class SeedDeriveError extends Error {\n readonly code: SeedDeriveErrorCode;\n\n constructor(code: SeedDeriveErrorCode, message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'SeedDeriveError';\n this.code = code;\n }\n}\n\nexport type SeedEncodingErrorCode =\n | 'INVALID_SEED_LENGTH'\n | 'SEED_STRING_MIXED_CASE'\n | 'SEED_STRING_BAD_CHECKSUM'\n | 'SEED_STRING_WRONG_HRP'\n | 'SEED_STRING_WRONG_LENGTH'\n | 'SEED_STRING_UNRECOGNIZED';\n\n// Raised by the identity-seed string codec (`encodeIdentitySeed` /\n// `parseIdentitySeed`). The codes are the cross-implementation contract: every\n// conforming implementation rejects the same malformed input with the same code.\nexport class SeedEncodingError extends Error {\n readonly code: SeedEncodingErrorCode;\n\n constructor(code: SeedEncodingErrorCode, message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'SeedEncodingError';\n this.code = code;\n }\n}\n","import { hkdfSha256 } from '../kdf/hkdf';\nimport { mlkem768x25519Keygen } from '../kem/mlkem768x25519';\nimport { x25519PublicKey } from '../kem/x25519';\nimport { getPublicKeyEd25519 } from '../sig/ed25519';\n\nimport { SeedDeriveError } from './errors';\n\n// HKDF info constants for the long-term identity keypairs.\n// These literal byte sequences are part of the on-wire protocol; every\n// conformant implementation MUST hash against these exact ASCII bytes (the\n// Python parity twin pins the identical labels).\nexport const INFO_ED25519: Uint8Array = new TextEncoder().encode('cardano-poe-ed25519-v1');\nexport const INFO_X25519: Uint8Array = new TextEncoder().encode('cardano-poe-x25519-v1');\nexport const INFO_MLKEM768X25519: Uint8Array = new TextEncoder().encode(\n 'cardano-poe-mlkem768x25519-v1',\n);\n\nif (INFO_ED25519.length !== 22) {\n throw new Error('INFO_ED25519 byte-length invariant violated (expected 22)');\n}\nif (INFO_X25519.length !== 21) {\n throw new Error('INFO_X25519 byte-length invariant violated (expected 21)');\n}\nif (INFO_MLKEM768X25519.length !== 29) {\n throw new Error('INFO_MLKEM768X25519 byte-length invariant violated (expected 29)');\n}\n\nconst EMPTY_SALT: Uint8Array = new Uint8Array(0);\nconst SEED_LENGTH = 32;\nconst DERIVED_LENGTH = 32;\n\nexport interface DerivedEd25519KeyPair {\n readonly secretKey: Uint8Array;\n readonly publicKey: Uint8Array;\n}\n\nexport interface DerivedX25519KeyPair {\n readonly secretKey: Uint8Array;\n readonly publicKey: Uint8Array;\n}\n\nexport interface DerivedMlKem768X25519KeyPair {\n readonly secretSeed: Uint8Array;\n readonly publicKey: Uint8Array;\n}\n\nfunction assertSeedLength(seed: Uint8Array): void {\n if (seed.length !== SEED_LENGTH) {\n throw new SeedDeriveError(\n 'INVALID_SEED_LENGTH',\n `seed must be exactly 32 bytes, got ${seed.length}`,\n );\n }\n}\n\nexport function deriveEd25519KeypairFromSeed(seed: Uint8Array): DerivedEd25519KeyPair {\n assertSeedLength(seed);\n const secretKey = hkdfSha256({\n ikm: seed,\n salt: EMPTY_SALT,\n info: INFO_ED25519,\n length: DERIVED_LENGTH,\n });\n const publicKey = getPublicKeyEd25519({ seed: secretKey });\n return { secretKey, publicKey };\n}\n\nexport function deriveX25519KeypairFromSeed(seed: Uint8Array): DerivedX25519KeyPair {\n assertSeedLength(seed);\n const secretKey = hkdfSha256({\n ikm: seed,\n salt: EMPTY_SALT,\n info: INFO_X25519,\n length: DERIVED_LENGTH,\n });\n const publicKey = x25519PublicKey({ secretKey });\n return { secretKey, publicKey };\n}\n\nexport function deriveMlKem768X25519KeypairFromSeed(\n seed: Uint8Array,\n): DerivedMlKem768X25519KeyPair {\n assertSeedLength(seed);\n // The 32-byte HKDF output IS the X-Wing root seed: keygen re-expands the\n // ML-KEM coins and the X25519 scalar from it, so the derived keypair's\n // secretSeed equals this value.\n const xwingSeed = hkdfSha256({\n ikm: seed,\n salt: EMPTY_SALT,\n info: INFO_MLKEM768X25519,\n length: DERIVED_LENGTH,\n });\n return mlkem768x25519Keygen(xwingSeed);\n}\n","// Minimal BIP-173 bech32 encoder used to format age-style recipient strings.\n//\n// This package's dependency policy keeps the runtime import graph to a small,\n// audited set of cryptographic libraries, so we inline the exact bech32\n// algorithm here rather than pull in a general-purpose base-encoding library.\n// Output is byte-identical to the no-length-limit form of a standard bech32\n// encoder (`encode(hrp, toWords(bytes))` with the 90-char BIP-173 cap\n// disabled): age recipients exceed that cap — an X-Wing recipient is ~1960\n// characters — so the limit must be off.\n\nconst BECH32_ALPHABET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';\nconst POLYMOD_GENERATORS = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];\nconst ENCODING_CONST = 1; // BIP-173 bech32 (not bech32m).\n\nfunction polymodStep(pre: number): number {\n const b = pre >> 25;\n let chk = (pre & 0x1ffffff) << 5;\n for (let i = 0; i < POLYMOD_GENERATORS.length; i++) {\n if (((b >> i) & 1) === 1) chk ^= POLYMOD_GENERATORS[i]!;\n }\n return chk;\n}\n\n// 8-bit bytes → 5-bit words, padding the final partial group with zero bits.\nfunction bytesToWords(bytes: Uint8Array): number[] {\n const words: number[] = [];\n let carry = 0;\n let pos = 0;\n const mask = (1 << 5) - 1;\n for (const n of bytes) {\n carry = (carry << 8) | n;\n pos += 8;\n for (; pos >= 5; pos -= 5) words.push((carry >> (pos - 5)) & mask);\n carry &= (1 << pos) - 1;\n }\n if (pos > 0) words.push((carry << (5 - pos)) & mask);\n return words;\n}\n\nfunction checksum(prefix: string, words: number[]): string {\n let chk = 1;\n for (let i = 0; i < prefix.length; i++) {\n const c = prefix.charCodeAt(i);\n if (c < 33 || c > 126) throw new Error(`bech32: invalid prefix (${prefix})`);\n chk = polymodStep(chk) ^ (c >> 5);\n }\n chk = polymodStep(chk);\n for (let i = 0; i < prefix.length; i++) chk = polymodStep(chk) ^ (prefix.charCodeAt(i) & 0x1f);\n for (const v of words) chk = polymodStep(chk) ^ v;\n for (let i = 0; i < 6; i++) chk = polymodStep(chk);\n chk ^= ENCODING_CONST;\n let out = '';\n for (let i = 0; i < 6; i++) out += BECH32_ALPHABET[(chk >> (5 * (5 - i))) & 31];\n return out;\n}\n\n// Encode raw bytes to a bech32 string with NO length limit. `prefix` is the HRP.\nexport function bech32EncodeNoLimit(prefix: string, bytes: Uint8Array): string {\n if (prefix.length === 0) throw new Error('bech32: empty prefix');\n const words = bytesToWords(bytes);\n let payload = '';\n for (const w of words) payload += BECH32_ALPHABET[w];\n const lowered = prefix.toLowerCase();\n return `${lowered}1${payload}${checksum(lowered, words)}`;\n}\n\n// Recompute the polymod over the HRP + every data word (the trailing six being\n// the checksum) and test it against the encoding constant. True iff the string\n// carries a valid bech32 checksum.\nfunction checksumValid(prefix: string, words: number[]): boolean {\n let chk = 1;\n for (let i = 0; i < prefix.length; i++) chk = polymodStep(chk) ^ (prefix.charCodeAt(i) >> 5);\n chk = polymodStep(chk);\n for (let i = 0; i < prefix.length; i++) chk = polymodStep(chk) ^ (prefix.charCodeAt(i) & 0x1f);\n for (const v of words) chk = polymodStep(chk) ^ v;\n return chk === ENCODING_CONST;\n}\n\n// 5-bit words → 8-bit bytes (the inverse of `bytesToWords`). Rejects\n// non-canonical padding: any leftover must be fewer than 5 bits and all zero,\n// matching the zero-fill `bytesToWords` applies to a final partial group.\nfunction wordsToBytes(words: number[]): Uint8Array {\n const out: number[] = [];\n let carry = 0;\n let pos = 0;\n for (const w of words) {\n carry = (carry << 5) | w;\n pos += 5;\n for (; pos >= 8; pos -= 8) out.push((carry >> (pos - 8)) & 0xff);\n carry &= (1 << pos) - 1;\n }\n if (pos >= 5 || carry !== 0) throw new Error('bech32: non-canonical padding');\n return Uint8Array.from(out);\n}\n\n// Decode a bech32 string with NO length limit, verifying the checksum. Returns\n// the lower-cased HRP and the decoded data bytes. The inverse of\n// `bech32EncodeNoLimit`. The separator is the last `1` in the string, so HRPs\n// that themselves contain a `1` (e.g. the `age1pqc` recipient prefix) round-trip\n// correctly.\nexport function bech32DecodeNoLimit(input: string): { hrp: string; bytes: Uint8Array } {\n if (input.length === 0) throw new Error('bech32: empty string');\n const hasLower = input !== input.toUpperCase();\n const hasUpper = input !== input.toLowerCase();\n if (hasLower && hasUpper) throw new Error('bech32: mixed-case string');\n const s = input.toLowerCase();\n const sep = s.lastIndexOf('1');\n if (sep < 1) throw new Error('bech32: missing human-readable prefix');\n if (s.length - sep - 1 < 6) throw new Error('bech32: data too short for checksum');\n const hrp = s.slice(0, sep);\n for (let i = 0; i < hrp.length; i++) {\n const c = hrp.charCodeAt(i);\n if (c < 33 || c > 126) throw new Error('bech32: invalid prefix character');\n }\n const words: number[] = [];\n for (let i = sep + 1; i < s.length; i++) {\n const v = BECH32_ALPHABET.indexOf(s[i]!);\n if (v === -1) throw new Error('bech32: invalid data character');\n words.push(v);\n }\n if (!checksumValid(hrp, words)) throw new Error('bech32: bad checksum');\n return { hrp, bytes: wordsToBytes(words.slice(0, words.length - 6)) };\n}\n","// Lower-case hex → bytes decoder. Caller is responsible for normalising\n// case + stripping any 0x prefix; the input must match /^[0-9a-f]*$/ with\n// even length. The decoder allocates exactly one fresh Uint8Array and\n// returns it as-is so callers downstream can rely on reference identity\n// (e.g. caller-owns-zeroize discipline for raw-seed import: the caller can\n// wipe the exact buffer this function returned).\nexport function hexToBytes(hex: string): Uint8Array {\n if ((hex.length & 1) !== 0) {\n throw new Error(`hexToBytes: input length ${hex.length} is not even`);\n }\n const out = new Uint8Array(hex.length >>> 1);\n for (let i = 0; i < out.length; i++) {\n const hi = charToNibble(hex.charCodeAt(i * 2));\n const lo = charToNibble(hex.charCodeAt(i * 2 + 1));\n if (hi < 0 || lo < 0) {\n throw new Error(`hexToBytes: non-hex character at offset ${i * 2}`);\n }\n out[i] = (hi << 4) | lo;\n }\n return out;\n}\n\nfunction charToNibble(code: number): number {\n if (code >= 48 && code <= 57) return code - 48;\n if (code >= 97 && code <= 102) return code - 87;\n return -1;\n}\n","// Checksummed string encoding for the 32-byte identity seed.\n//\n// The display/generation form is classic BIP-173 bech32 (no length limit — the\n// same primitive the age-style recipient codec uses) under the HRP\n// `l309-seed-`, returned UPPERCASE: `L309-SEED-1…`. Secrets are loud: the\n// uppercase form is visually unmistakable next to lowercase recipient\n// addresses (`age1…`, `age1pqc…`), mirroring age's `AGE-SECRET-KEY-1…`\n// convention, and the checksum deterministically catches typos and truncation.\n//\n// Parsing accepts two representations:\n// • the bech32 form in all-lowercase or all-uppercase (mixed case is\n// rejected per BIP-173), checksum verified, HRP exactly `l309-seed-`,\n// payload exactly 32 bytes;\n// • raw hex — 64 hex digits, case-insensitive, tolerating a `0x` prefix and\n// surrounding/internal whitespace — the lowest-common-denominator\n// interchange form, so a seed generated by any external tool imports.\n\nimport { bech32DecodeNoLimit, bech32EncodeNoLimit } from '../recipient/bech32';\nimport { hexToBytes } from '../util/hex';\n\nimport { SeedEncodingError } from './errors';\n\n// The bech32 human-readable part. The trailing hyphen is part of the HRP, so\n// with the bech32 separator `1` the rendered prefix reads `l309-seed-1…`.\nexport const IDENTITY_SEED_HRP = 'l309-seed-';\n\nconst SEED_LENGTH = 32;\nconst SEED_HEX_DIGITS = 64;\n\n// ASCII-case-insensitive probe: does the input claim to be the bech32 form?\n// Decides whether a decode failure is reported as a corrupted seed string\n// (`SEED_STRING_BAD_CHECKSUM`) or as unrecognized input. A non-`u` RegExp `i`\n// flag never case-matches a non-ASCII character to an ASCII one, so the probe\n// cannot be spoofed by Unicode case folding.\nconst CLAIMS_SEED_PREFIX = /^l309-seed-1/i;\n\n// Encode a 32-byte identity seed to its checksummed display form\n// (`L309-SEED-1…`, ~69 characters).\n//\n// Throws `SeedEncodingError` (`INVALID_SEED_LENGTH`) unless the seed is\n// exactly 32 bytes.\nexport function encodeIdentitySeed(seed: Uint8Array): string {\n if (seed.length !== SEED_LENGTH) {\n throw new SeedEncodingError(\n 'INVALID_SEED_LENGTH',\n `seed must be exactly 32 bytes, got ${seed.length}`,\n );\n }\n return bech32EncodeNoLimit(IDENTITY_SEED_HRP, seed).toUpperCase();\n}\n\n// Parse an identity seed from either accepted representation (the checksummed\n// bech32 form in a single case, or 64-digit raw hex) back to its 32 raw bytes.\n// The inverse of `encodeIdentitySeed` for the bech32 form.\n//\n// Throws `SeedEncodingError` with the code naming what was wrong: a mixed-case\n// bech32 string, a failed checksum, a foreign HRP (e.g. an age recipient\n// pasted by mistake), a wrong payload or hex-digit length, or input that is\n// neither representation.\nexport function parseIdentitySeed(input: string): Uint8Array {\n // Hex path: strip ALL whitespace and an optional 0x prefix; if what remains\n // is pure hex it can only be meant as a hex seed (the bech32 form always\n // carries non-hex characters: the HRP's `l`, `s`, and `-`).\n const compact = input.replace(/\\s+/g, '');\n const hexBody = compact.startsWith('0x') || compact.startsWith('0X') ? compact.slice(2) : compact;\n if (hexBody.length > 0 && /^[0-9a-fA-F]+$/.test(hexBody)) {\n if (hexBody.length !== SEED_HEX_DIGITS) {\n throw new SeedEncodingError(\n 'SEED_STRING_WRONG_LENGTH',\n `hex seed must be exactly 64 hex digits, got ${hexBody.length}`,\n );\n }\n return hexToBytes(hexBody.toLowerCase());\n }\n\n // Bech32 path: a single token, so only surrounding whitespace is tolerated.\n const candidate = input.trim();\n const claimed = CLAIMS_SEED_PREFIX.test(candidate);\n if (claimed && /[a-z]/.test(candidate) && /[A-Z]/.test(candidate)) {\n throw new SeedEncodingError(\n 'SEED_STRING_MIXED_CASE',\n 'identity-seed string mixes upper and lower case; use one case only',\n );\n }\n let decoded: { hrp: string; bytes: Uint8Array };\n try {\n decoded = bech32DecodeNoLimit(candidate);\n } catch (cause) {\n if (claimed) {\n throw new SeedEncodingError(\n 'SEED_STRING_BAD_CHECKSUM',\n 'identity-seed string failed bech32 decoding (checksum, character set, or structure)',\n { cause },\n );\n }\n throw new SeedEncodingError(\n 'SEED_STRING_UNRECOGNIZED',\n 'expected a 64-hex-digit seed or an L309-SEED-1… string',\n { cause },\n );\n }\n if (decoded.hrp !== IDENTITY_SEED_HRP) {\n throw new SeedEncodingError(\n 'SEED_STRING_WRONG_HRP',\n `expected the bech32 prefix \"${IDENTITY_SEED_HRP}\", got \"${decoded.hrp}\"`,\n );\n }\n if (decoded.bytes.length !== SEED_LENGTH) {\n throw new SeedEncodingError(\n 'SEED_STRING_WRONG_LENGTH',\n `identity-seed payload must be exactly 32 bytes, got ${decoded.bytes.length}`,\n );\n }\n return decoded.bytes;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cardanowall/crypto-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Closed-catalogue cryptographic primitives for Label 309 Proof-of-Existence (TypeScript reference implementation; byte-identical Python parity twin).",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
type CanonicalCborValue = null | boolean | number | bigint | string | Uint8Array | readonly CanonicalCborValue[] | {
|
|
2
|
-
readonly [key: string]: CanonicalCborValue;
|
|
3
|
-
} | ReadonlyMap<string | number, CanonicalCborValue>;
|
|
4
|
-
declare function encodeCanonicalCbor(value: CanonicalCborValue): Uint8Array;
|
|
5
|
-
declare function decodeCanonicalCbor(bytes: Uint8Array): unknown;
|
|
6
|
-
|
|
7
|
-
export { type CanonicalCborValue as C, decodeCanonicalCbor as d, encodeCanonicalCbor as e };
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
type CanonicalCborValue = null | boolean | number | bigint | string | Uint8Array | readonly CanonicalCborValue[] | {
|
|
2
|
-
readonly [key: string]: CanonicalCborValue;
|
|
3
|
-
} | ReadonlyMap<string | number, CanonicalCborValue>;
|
|
4
|
-
declare function encodeCanonicalCbor(value: CanonicalCborValue): Uint8Array;
|
|
5
|
-
declare function decodeCanonicalCbor(bytes: Uint8Array): unknown;
|
|
6
|
-
|
|
7
|
-
export { type CanonicalCborValue as C, decodeCanonicalCbor as d, encodeCanonicalCbor as e };
|