@shroud-fi/core 0.1.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.
Files changed (87) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +54 -0
  3. package/dist/cjs/compute-key.d.ts +24 -0
  4. package/dist/cjs/compute-key.d.ts.map +1 -0
  5. package/dist/cjs/compute-key.js +72 -0
  6. package/dist/cjs/compute-key.js.map +1 -0
  7. package/dist/cjs/constants.d.ts +20 -0
  8. package/dist/cjs/constants.d.ts.map +1 -0
  9. package/dist/cjs/constants.js +23 -0
  10. package/dist/cjs/constants.js.map +1 -0
  11. package/dist/cjs/errors.d.ts +35 -0
  12. package/dist/cjs/errors.d.ts.map +1 -0
  13. package/dist/cjs/errors.js +48 -0
  14. package/dist/cjs/errors.js.map +1 -0
  15. package/dist/cjs/identity.d.ts +20 -0
  16. package/dist/cjs/identity.d.ts.map +1 -0
  17. package/dist/cjs/identity.js +38 -0
  18. package/dist/cjs/identity.js.map +1 -0
  19. package/dist/cjs/index.d.ts +12 -0
  20. package/dist/cjs/index.d.ts.map +1 -0
  21. package/dist/cjs/index.js +36 -0
  22. package/dist/cjs/index.js.map +1 -0
  23. package/dist/cjs/keys.d.ts +17 -0
  24. package/dist/cjs/keys.d.ts.map +1 -0
  25. package/dist/cjs/keys.js +51 -0
  26. package/dist/cjs/keys.js.map +1 -0
  27. package/dist/cjs/meta-address.d.ts +26 -0
  28. package/dist/cjs/meta-address.d.ts.map +1 -0
  29. package/dist/cjs/meta-address.js +86 -0
  30. package/dist/cjs/meta-address.js.map +1 -0
  31. package/dist/cjs/package.json +1 -0
  32. package/dist/cjs/stealth.d.ts +22 -0
  33. package/dist/cjs/stealth.d.ts.map +1 -0
  34. package/dist/cjs/stealth.js +100 -0
  35. package/dist/cjs/stealth.js.map +1 -0
  36. package/dist/cjs/types.d.ts +46 -0
  37. package/dist/cjs/types.d.ts.map +1 -0
  38. package/dist/cjs/types.js +9 -0
  39. package/dist/cjs/types.js.map +1 -0
  40. package/dist/cjs/view-tag.d.ts +29 -0
  41. package/dist/cjs/view-tag.d.ts.map +1 -0
  42. package/dist/cjs/view-tag.js +62 -0
  43. package/dist/cjs/view-tag.js.map +1 -0
  44. package/dist/esm/compute-key.d.ts +24 -0
  45. package/dist/esm/compute-key.d.ts.map +1 -0
  46. package/dist/esm/compute-key.js +69 -0
  47. package/dist/esm/compute-key.js.map +1 -0
  48. package/dist/esm/constants.d.ts +20 -0
  49. package/dist/esm/constants.d.ts.map +1 -0
  50. package/dist/esm/constants.js +20 -0
  51. package/dist/esm/constants.js.map +1 -0
  52. package/dist/esm/errors.d.ts +35 -0
  53. package/dist/esm/errors.d.ts.map +1 -0
  54. package/dist/esm/errors.js +41 -0
  55. package/dist/esm/errors.js.map +1 -0
  56. package/dist/esm/identity.d.ts +20 -0
  57. package/dist/esm/identity.d.ts.map +1 -0
  58. package/dist/esm/identity.js +35 -0
  59. package/dist/esm/identity.js.map +1 -0
  60. package/dist/esm/index.d.ts +12 -0
  61. package/dist/esm/index.d.ts.map +1 -0
  62. package/dist/esm/index.js +17 -0
  63. package/dist/esm/index.js.map +1 -0
  64. package/dist/esm/keys.d.ts +17 -0
  65. package/dist/esm/keys.d.ts.map +1 -0
  66. package/dist/esm/keys.js +48 -0
  67. package/dist/esm/keys.js.map +1 -0
  68. package/dist/esm/meta-address.d.ts +26 -0
  69. package/dist/esm/meta-address.d.ts.map +1 -0
  70. package/dist/esm/meta-address.js +82 -0
  71. package/dist/esm/meta-address.js.map +1 -0
  72. package/dist/esm/stealth.d.ts +22 -0
  73. package/dist/esm/stealth.d.ts.map +1 -0
  74. package/dist/esm/stealth.js +97 -0
  75. package/dist/esm/stealth.js.map +1 -0
  76. package/dist/esm/types.d.ts +46 -0
  77. package/dist/esm/types.d.ts.map +1 -0
  78. package/dist/esm/types.js +8 -0
  79. package/dist/esm/types.js.map +1 -0
  80. package/dist/esm/view-tag.d.ts +29 -0
  81. package/dist/esm/view-tag.d.ts.map +1 -0
  82. package/dist/esm/view-tag.js +58 -0
  83. package/dist/esm/view-tag.js.map +1 -0
  84. package/dist/tsconfig.cjs.tsbuildinfo +1 -0
  85. package/dist/tsconfig.esm.tsbuildinfo +1 -0
  86. package/dist/tsconfig.tsbuildinfo +1 -0
  87. package/package.json +63 -0
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ /**
3
+ * ERC-6538 Stealth Meta-Address Encode/Decode
4
+ *
5
+ * Format: st:base:0x<spendingPubKey 33 bytes hex><viewingPubKey 33 bytes hex>
6
+ *
7
+ * Both keys are SEC1 compressed secp256k1 public keys (prefix 0x02 or 0x03).
8
+ * Total raw payload: 66 bytes = 132 hex characters.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.encodeMetaAddress = encodeMetaAddress;
12
+ exports.decodeMetaAddress = decodeMetaAddress;
13
+ const secp256k1_1 = require("@noble/curves/secp256k1");
14
+ const utils_1 = require("@noble/hashes/utils");
15
+ const errors_js_1 = require("./errors.js");
16
+ const constants_js_1 = require("./constants.js");
17
+ const META_ADDRESS_PREFIX = 'st:base:0x';
18
+ const COMPRESSED_KEY_LENGTH = 33; // bytes
19
+ const TOTAL_PAYLOAD_LENGTH = COMPRESSED_KEY_LENGTH * 2; // 66 bytes
20
+ /**
21
+ * Validate that a byte array is a valid compressed secp256k1 public key.
22
+ * Must be 33 bytes with 0x02 or 0x03 prefix.
23
+ */
24
+ function assertValidCompressedKey(key, label) {
25
+ if (key.length !== COMPRESSED_KEY_LENGTH) {
26
+ throw new errors_js_1.InvalidMetaAddressError(`${label} must be ${COMPRESSED_KEY_LENGTH} bytes, got ${key.length}`);
27
+ }
28
+ const prefix = key[0];
29
+ if (prefix !== 0x02 && prefix !== 0x03) {
30
+ throw new errors_js_1.InvalidMetaAddressError(`${label} must have 0x02 or 0x03 prefix`);
31
+ }
32
+ // Validate it's actually on the curve
33
+ try {
34
+ secp256k1_1.secp256k1.ProjectivePoint.fromHex(key);
35
+ }
36
+ catch {
37
+ throw new errors_js_1.InvalidMetaAddressError(`${label} is not a valid secp256k1 point`);
38
+ }
39
+ }
40
+ /**
41
+ * Encode a StealthMetaAddress into the ERC-6538 URI format.
42
+ *
43
+ * @param meta - Stealth meta-address containing spending and viewing public keys
44
+ * @returns Encoded string: "st:base:0x<spendHex><viewHex>"
45
+ * @throws InvalidMetaAddressError if keys are invalid
46
+ */
47
+ function encodeMetaAddress(meta) {
48
+ assertValidCompressedKey(meta.spendingPubKey, 'Spending public key');
49
+ assertValidCompressedKey(meta.viewingPubKey, 'Viewing public key');
50
+ const spendHex = (0, utils_1.bytesToHex)(meta.spendingPubKey);
51
+ const viewHex = (0, utils_1.bytesToHex)(meta.viewingPubKey);
52
+ return `${META_ADDRESS_PREFIX}${spendHex}${viewHex}`;
53
+ }
54
+ /**
55
+ * Decode an ERC-6538 URI string into a StealthMetaAddress.
56
+ *
57
+ * @param encoded - String in format "st:base:0x<66 bytes hex>"
58
+ * @returns Parsed StealthMetaAddress
59
+ * @throws InvalidMetaAddressError if format is invalid
60
+ */
61
+ function decodeMetaAddress(encoded) {
62
+ if (!encoded.startsWith(META_ADDRESS_PREFIX)) {
63
+ throw new errors_js_1.InvalidMetaAddressError(`Meta-address must start with "${META_ADDRESS_PREFIX}"`);
64
+ }
65
+ const hexPayload = encoded.slice(META_ADDRESS_PREFIX.length);
66
+ if (hexPayload.length !== TOTAL_PAYLOAD_LENGTH * 2) {
67
+ throw new errors_js_1.InvalidMetaAddressError(`Meta-address hex payload must be ${TOTAL_PAYLOAD_LENGTH * 2} characters, got ${hexPayload.length}`);
68
+ }
69
+ let payloadBytes;
70
+ try {
71
+ payloadBytes = (0, utils_1.hexToBytes)(hexPayload);
72
+ }
73
+ catch {
74
+ throw new errors_js_1.InvalidMetaAddressError('Meta-address contains invalid hex characters');
75
+ }
76
+ const spendingPubKey = payloadBytes.slice(0, COMPRESSED_KEY_LENGTH);
77
+ const viewingPubKey = payloadBytes.slice(COMPRESSED_KEY_LENGTH);
78
+ assertValidCompressedKey(spendingPubKey, 'Spending public key');
79
+ assertValidCompressedKey(viewingPubKey, 'Viewing public key');
80
+ return {
81
+ spendingPubKey,
82
+ viewingPubKey,
83
+ schemeId: constants_js_1.SCHEME_ID,
84
+ };
85
+ }
86
+ //# sourceMappingURL=meta-address.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-address.js","sourceRoot":"","sources":["../../src/meta-address.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;AA2CH,8CAQC;AASD,8CAiCC;AA3FD,uDAAoD;AACpD,+CAA6D;AAE7D,2CAAsD;AACtD,iDAA2C;AAE3C,MAAM,mBAAmB,GAAG,YAAY,CAAC;AACzC,MAAM,qBAAqB,GAAG,EAAE,CAAC,CAAC,QAAQ;AAC1C,MAAM,oBAAoB,GAAG,qBAAqB,GAAG,CAAC,CAAC,CAAC,WAAW;AAEnE;;;GAGG;AACH,SAAS,wBAAwB,CAAC,GAAe,EAAE,KAAa;IAC9D,IAAI,GAAG,CAAC,MAAM,KAAK,qBAAqB,EAAE,CAAC;QACzC,MAAM,IAAI,mCAAuB,CAC/B,GAAG,KAAK,YAAY,qBAAqB,eAAe,GAAG,CAAC,MAAM,EAAE,CACrE,CAAC;IACJ,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;QACvC,MAAM,IAAI,mCAAuB,CAC/B,GAAG,KAAK,gCAAgC,CACzC,CAAC;IACJ,CAAC;IACD,sCAAsC;IACtC,IAAI,CAAC;QACH,qBAAS,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,mCAAuB,CAAC,GAAG,KAAK,iCAAiC,CAAC,CAAC;IAC/E,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,IAAwB;IACxD,wBAAwB,CAAC,IAAI,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IACrE,wBAAwB,CAAC,IAAI,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAC;IAEnE,MAAM,QAAQ,GAAG,IAAA,kBAAU,EAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,IAAA,kBAAU,EAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAE/C,OAAO,GAAG,mBAAmB,GAAG,QAAQ,GAAG,OAAO,EAAE,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,iBAAiB,CAAC,OAAe;IAC/C,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,mBAAmB,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,mCAAuB,CAC/B,iCAAiC,mBAAmB,GAAG,CACxD,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAE7D,IAAI,UAAU,CAAC,MAAM,KAAK,oBAAoB,GAAG,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,mCAAuB,CAC/B,oCAAoC,oBAAoB,GAAG,CAAC,oBAAoB,UAAU,CAAC,MAAM,EAAE,CACpG,CAAC;IACJ,CAAC;IAED,IAAI,YAAwB,CAAC;IAC7B,IAAI,CAAC;QACH,YAAY,GAAG,IAAA,kBAAU,EAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,mCAAuB,CAAC,8CAA8C,CAAC,CAAC;IACpF,CAAC;IAED,MAAM,cAAc,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC;IACpE,MAAM,aAAa,GAAG,YAAY,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAEhE,wBAAwB,CAAC,cAAc,EAAE,qBAAqB,CAAC,CAAC;IAChE,wBAAwB,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAC;IAE9D,OAAO;QACL,cAAc;QACd,aAAa;QACb,QAAQ,EAAE,wBAAS;KACpB,CAAC;AACJ,CAAC"}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Stealth Address Generation (Sender Side)
3
+ *
4
+ * Implements EIP-5564 scheme 1 (secp256k1):
5
+ * 1. Generate random ephemeral key r, compute R = r*G
6
+ * 2. ECDH: sharedSecret = r * viewingPubKey
7
+ * 3. Hash: hashedSecret = keccak256(compress(sharedSecret))
8
+ * 4. View tag: viewTag = hashedSecret[0]
9
+ * 5. Stealth pubkey: P_stealth = spendingPubKey + hashedSecret * G
10
+ * 6. Stealth address: keccak256(uncompressed64(P_stealth))[12:] -> 20-byte address
11
+ */
12
+ import type { StealthMetaAddress, StealthAddressResult } from './types.js';
13
+ /**
14
+ * Generate a one-time stealth address for a recipient.
15
+ *
16
+ * @param meta - Recipient's stealth meta-address (two compressed public keys)
17
+ * @returns StealthAddressResult with stealth address, ephemeral pubkey, and view tag
18
+ * @throws InvalidKeyError if meta-address public keys are invalid
19
+ * @throws StealthAddressError if the derived stealth point is at infinity
20
+ */
21
+ export declare function generateStealthAddress(meta: StealthMetaAddress): StealthAddressResult;
22
+ //# sourceMappingURL=stealth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stealth.d.ts","sourceRoot":"","sources":["../../src/stealth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAa3E;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,kBAAkB,GACvB,oBAAoB,CA2DtB"}
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ /**
3
+ * Stealth Address Generation (Sender Side)
4
+ *
5
+ * Implements EIP-5564 scheme 1 (secp256k1):
6
+ * 1. Generate random ephemeral key r, compute R = r*G
7
+ * 2. ECDH: sharedSecret = r * viewingPubKey
8
+ * 3. Hash: hashedSecret = keccak256(compress(sharedSecret))
9
+ * 4. View tag: viewTag = hashedSecret[0]
10
+ * 5. Stealth pubkey: P_stealth = spendingPubKey + hashedSecret * G
11
+ * 6. Stealth address: keccak256(uncompressed64(P_stealth))[12:] -> 20-byte address
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.generateStealthAddress = generateStealthAddress;
15
+ const secp256k1_1 = require("@noble/curves/secp256k1");
16
+ const sha3_1 = require("@noble/hashes/sha3");
17
+ const utils_1 = require("@noble/hashes/utils");
18
+ const errors_js_1 = require("./errors.js");
19
+ /**
20
+ * Convert a 64-byte uncompressed public key (no 0x04 prefix) to an EVM address.
21
+ * address = last 20 bytes of keccak256(pubkey64)
22
+ */
23
+ function pubKeyToAddress(uncompressed64) {
24
+ const hash = (0, sha3_1.keccak_256)(uncompressed64);
25
+ const addrBytes = hash.slice(12);
26
+ return `0x${(0, utils_1.bytesToHex)(addrBytes)}`;
27
+ }
28
+ /**
29
+ * Generate a one-time stealth address for a recipient.
30
+ *
31
+ * @param meta - Recipient's stealth meta-address (two compressed public keys)
32
+ * @returns StealthAddressResult with stealth address, ephemeral pubkey, and view tag
33
+ * @throws InvalidKeyError if meta-address public keys are invalid
34
+ * @throws StealthAddressError if the derived stealth point is at infinity
35
+ */
36
+ function generateStealthAddress(meta) {
37
+ // Validate input public keys by parsing them (fromHex validates on-curve)
38
+ let viewingPoint;
39
+ let spendingPoint;
40
+ try {
41
+ viewingPoint = secp256k1_1.secp256k1.ProjectivePoint.fromHex(meta.viewingPubKey);
42
+ }
43
+ catch {
44
+ throw new errors_js_1.InvalidKeyError('Invalid viewing public key in meta-address');
45
+ }
46
+ try {
47
+ spendingPoint = secp256k1_1.secp256k1.ProjectivePoint.fromHex(meta.spendingPubKey);
48
+ }
49
+ catch {
50
+ throw new errors_js_1.InvalidKeyError('Invalid spending public key in meta-address');
51
+ }
52
+ // Step 1: Generate ephemeral keypair
53
+ const ephemeralPriv = secp256k1_1.secp256k1.utils.randomPrivateKey();
54
+ const ephemeralPub = secp256k1_1.secp256k1.getPublicKey(ephemeralPriv, true); // compressed
55
+ try {
56
+ // Step 2: ECDH shared secret S = r * P_view
57
+ const ephemeralScalar = bytesToBigInt(ephemeralPriv);
58
+ const sharedSecretPoint = viewingPoint.multiply(ephemeralScalar);
59
+ // Step 3: Hash the compressed shared secret
60
+ const sharedSecretCompressed = sharedSecretPoint.toRawBytes(true); // 33 bytes
61
+ const hashedSecret = (0, sha3_1.keccak_256)(sharedSecretCompressed); // 32 bytes
62
+ // Step 4: View tag = first byte
63
+ const viewTag = hashedSecret[0];
64
+ // Step 5: Stealth public key = P_spend + hashedSecret * G
65
+ const hashedScalar = bytesToBigInt(hashedSecret) % secp256k1_1.secp256k1.CURVE.n;
66
+ if (hashedScalar === 0n) {
67
+ throw new errors_js_1.StealthAddressError('Hashed secret reduced to zero');
68
+ }
69
+ const hashedPoint = secp256k1_1.secp256k1.ProjectivePoint.BASE.multiply(hashedScalar);
70
+ const stealthPubPoint = spendingPoint.add(hashedPoint);
71
+ // Verify not point at infinity
72
+ try {
73
+ stealthPubPoint.assertValidity();
74
+ }
75
+ catch {
76
+ throw new errors_js_1.StealthAddressError('Stealth public key is the point at infinity');
77
+ }
78
+ // Step 6: Derive EVM address from uncompressed stealth public key
79
+ const stealthPubUncompressed = stealthPubPoint.toRawBytes(false); // 65 bytes (04 || x || y)
80
+ const stealthAddress = pubKeyToAddress(stealthPubUncompressed.slice(1)); // strip 0x04 prefix
81
+ return {
82
+ stealthAddress,
83
+ ephemeralPubKey: ephemeralPub,
84
+ viewTag,
85
+ };
86
+ }
87
+ finally {
88
+ // Zero ephemeral private key
89
+ ephemeralPriv.fill(0);
90
+ }
91
+ }
92
+ /** Convert a Uint8Array to a BigInt (big-endian). */
93
+ function bytesToBigInt(bytes) {
94
+ let result = 0n;
95
+ for (const byte of bytes) {
96
+ result = (result << 8n) | BigInt(byte);
97
+ }
98
+ return result;
99
+ }
100
+ //# sourceMappingURL=stealth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stealth.js","sourceRoot":"","sources":["../../src/stealth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * ShroudFi Core Types
3
+ *
4
+ * Branded key types for compile-time safety -- prevents accidentally
5
+ * passing a scanning key where a spending key is expected.
6
+ */
7
+ /** secp256k1 spending private key (32 bytes). Controls funds. */
8
+ export type SpendingKey = {
9
+ readonly __brand: 'SpendingKey';
10
+ readonly bytes: Uint8Array;
11
+ };
12
+ /** secp256k1 scanning private key (32 bytes). Detects incoming payments. */
13
+ export type ScanningKey = {
14
+ readonly __brand: 'ScanningKey';
15
+ readonly bytes: Uint8Array;
16
+ };
17
+ /** secp256k1 viewing key (32 bytes). Enables selective disclosure. */
18
+ export type ViewingKey = {
19
+ readonly __brand: 'ViewingKey';
20
+ readonly bytes: Uint8Array;
21
+ };
22
+ /**
23
+ * ERC-6538 stealth meta-address: two compressed secp256k1 public keys.
24
+ * Shareable -- contains NO private material.
25
+ */
26
+ export interface StealthMetaAddress {
27
+ readonly spendingPubKey: Uint8Array;
28
+ readonly viewingPubKey: Uint8Array;
29
+ readonly schemeId: number;
30
+ }
31
+ /** Result of generating a one-time stealth address for a recipient. */
32
+ export interface StealthAddressResult {
33
+ /** The derived stealth EVM address. */
34
+ readonly stealthAddress: `0x${string}`;
35
+ /** Compressed ephemeral public key (33 bytes) -- must be announced. */
36
+ readonly ephemeralPubKey: Uint8Array;
37
+ /** View tag (0-255) -- first byte of hashed shared secret. */
38
+ readonly viewTag: number;
39
+ }
40
+ /** Full key hierarchy derived from a master seed. */
41
+ export interface KeyHierarchy {
42
+ readonly spendingKey: SpendingKey;
43
+ readonly scanningKey: ScanningKey;
44
+ readonly viewingKey: ViewingKey;
45
+ }
46
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,iEAAiE;AACjE,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B,CAAC;AAEF,sEAAsE;AACtE,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B,CAAC;AAEF;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,UAAU,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,uEAAuE;AACvE,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,QAAQ,CAAC,cAAc,EAAE,KAAK,MAAM,EAAE,CAAC;IACvC,uEAAuE;IACvE,QAAQ,CAAC,eAAe,EAAE,UAAU,CAAC;IACrC,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC"}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ /**
3
+ * ShroudFi Core Types
4
+ *
5
+ * Branded key types for compile-time safety -- prevents accidentally
6
+ * passing a scanning key where a spending key is expected.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":";AAAA;;;;;GAKG"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * View Tag Utilities
3
+ *
4
+ * View tags enable fast filtering of stealth address announcements.
5
+ * The view tag is the first byte of keccak256(compress(ECDH_shared_secret)).
6
+ * This filters ~99.6% of non-matching announcements with a single byte check.
7
+ */
8
+ import type { ScanningKey } from './types.js';
9
+ /**
10
+ * Extract the view tag from a compressed shared secret point.
11
+ * The view tag is byte 0 of keccak256(compressedPoint).
12
+ *
13
+ * @param sharedSecretCompressed - 33-byte compressed secp256k1 point
14
+ * @returns View tag value (0-255)
15
+ */
16
+ export declare function extractViewTag(sharedSecretCompressed: Uint8Array): number;
17
+ /**
18
+ * Check whether a view tag matches for a given scanning key and ephemeral public key.
19
+ *
20
+ * Performs the ECDH step and view tag extraction, then compares against
21
+ * the expected tag. This is the fast-path filter for scanning.
22
+ *
23
+ * @param scanningKey - Recipient's scanning private key
24
+ * @param ephemeralPubKey - Ephemeral public key from the announcement (33 bytes)
25
+ * @param expectedTag - The view tag from the announcement metadata
26
+ * @returns true if the view tag matches (candidate for full verification)
27
+ */
28
+ export declare function checkViewTag(scanningKey: ScanningKey, ephemeralPubKey: Uint8Array, expectedTag: number): boolean;
29
+ //# sourceMappingURL=view-tag.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-tag.d.ts","sourceRoot":"","sources":["../../src/view-tag.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,sBAAsB,EAAE,UAAU,GAAG,MAAM,CAGzE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,WAAW,EACxB,eAAe,EAAE,UAAU,EAC3B,WAAW,EAAE,MAAM,GAClB,OAAO,CAkBT"}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ /**
3
+ * View Tag Utilities
4
+ *
5
+ * View tags enable fast filtering of stealth address announcements.
6
+ * The view tag is the first byte of keccak256(compress(ECDH_shared_secret)).
7
+ * This filters ~99.6% of non-matching announcements with a single byte check.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.extractViewTag = extractViewTag;
11
+ exports.checkViewTag = checkViewTag;
12
+ const secp256k1_1 = require("@noble/curves/secp256k1");
13
+ const sha3_1 = require("@noble/hashes/sha3");
14
+ const errors_js_1 = require("./errors.js");
15
+ /**
16
+ * Extract the view tag from a compressed shared secret point.
17
+ * The view tag is byte 0 of keccak256(compressedPoint).
18
+ *
19
+ * @param sharedSecretCompressed - 33-byte compressed secp256k1 point
20
+ * @returns View tag value (0-255)
21
+ */
22
+ function extractViewTag(sharedSecretCompressed) {
23
+ const hash = (0, sha3_1.keccak_256)(sharedSecretCompressed);
24
+ return hash[0];
25
+ }
26
+ /**
27
+ * Check whether a view tag matches for a given scanning key and ephemeral public key.
28
+ *
29
+ * Performs the ECDH step and view tag extraction, then compares against
30
+ * the expected tag. This is the fast-path filter for scanning.
31
+ *
32
+ * @param scanningKey - Recipient's scanning private key
33
+ * @param ephemeralPubKey - Ephemeral public key from the announcement (33 bytes)
34
+ * @param expectedTag - The view tag from the announcement metadata
35
+ * @returns true if the view tag matches (candidate for full verification)
36
+ */
37
+ function checkViewTag(scanningKey, ephemeralPubKey, expectedTag) {
38
+ // Validate ephemeral public key
39
+ let ephemeralPoint;
40
+ try {
41
+ ephemeralPoint = secp256k1_1.secp256k1.ProjectivePoint.fromHex(ephemeralPubKey);
42
+ }
43
+ catch {
44
+ throw new errors_js_1.InvalidKeyError('Invalid ephemeral public key');
45
+ }
46
+ // ECDH: sharedSecret = scanningPriv * P_ephemeral
47
+ const scanScalar = bytesToBigInt(scanningKey.bytes);
48
+ const sharedSecretPoint = ephemeralPoint.multiply(scanScalar);
49
+ // Hash compressed shared secret and extract view tag
50
+ const sharedSecretCompressed = sharedSecretPoint.toRawBytes(true);
51
+ const tag = extractViewTag(sharedSecretCompressed);
52
+ return tag === expectedTag;
53
+ }
54
+ /** Convert a Uint8Array to a BigInt (big-endian). */
55
+ function bytesToBigInt(bytes) {
56
+ let result = 0n;
57
+ for (const byte of bytes) {
58
+ result = (result << 8n) | BigInt(byte);
59
+ }
60
+ return result;
61
+ }
62
+ //# sourceMappingURL=view-tag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-tag.js","sourceRoot":"","sources":["../../src/view-tag.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAcH,wCAGC;AAaD,oCAsBC;AAlDD,uDAAoD;AACpD,6CAAgD;AAEhD,2CAA8C;AAE9C;;;;;;GAMG;AACH,SAAgB,cAAc,CAAC,sBAAkC;IAC/D,MAAM,IAAI,GAAG,IAAA,iBAAU,EAAC,sBAAsB,CAAC,CAAC;IAChD,OAAO,IAAI,CAAC,CAAC,CAAE,CAAC;AAClB,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,YAAY,CAC1B,WAAwB,EACxB,eAA2B,EAC3B,WAAmB;IAEnB,gCAAgC;IAChC,IAAI,cAA8D,CAAC;IACnE,IAAI,CAAC;QACH,cAAc,GAAG,qBAAS,CAAC,eAAe,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,2BAAe,CAAC,8BAA8B,CAAC,CAAC;IAC5D,CAAC;IAED,kDAAkD;IAClD,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,iBAAiB,GAAG,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAE9D,qDAAqD;IACrD,MAAM,sBAAsB,GAAG,iBAAiB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAClE,MAAM,GAAG,GAAG,cAAc,CAAC,sBAAsB,CAAC,CAAC;IAEnD,OAAO,GAAG,KAAK,WAAW,CAAC;AAC7B,CAAC;AAED,qDAAqD;AACrD,SAAS,aAAa,CAAC,KAAiB;IACtC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Stealth Key Computation (Recipient Side)
3
+ *
4
+ * Given the scanning private key, spending private key, and the
5
+ * ephemeral public key from an announcement, derive the stealth
6
+ * private key that controls the stealth address.
7
+ *
8
+ * 1. ECDH: sharedSecret = scanningPrivKey * ephemeralPubKey
9
+ * 2. Hash: hashedSecret = keccak256(compress(sharedSecret))
10
+ * 3. Stealth private key: p_stealth = (spendingPrivKey + hashedSecret) mod n
11
+ */
12
+ import type { ScanningKey, SpendingKey } from './types.js';
13
+ /**
14
+ * Compute the stealth private key for a detected payment.
15
+ *
16
+ * @param scanningKey - Recipient's scanning private key
17
+ * @param spendingKey - Recipient's spending private key
18
+ * @param ephemeralPubKey - Ephemeral public key from the announcement (33 bytes compressed)
19
+ * @returns 32-byte stealth private key
20
+ * @throws InvalidKeyError if ephemeral public key is invalid
21
+ * @throws StealthAddressError if the derived stealth key is invalid
22
+ */
23
+ export declare function computeStealthKey(scanningKey: ScanningKey, spendingKey: SpendingKey, ephemeralPubKey: Uint8Array): Uint8Array;
24
+ //# sourceMappingURL=compute-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-key.d.ts","sourceRoot":"","sources":["../../src/compute-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG3D;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,WAAW,EACxB,WAAW,EAAE,WAAW,EACxB,eAAe,EAAE,UAAU,GAC1B,UAAU,CA6BZ"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Stealth Key Computation (Recipient Side)
3
+ *
4
+ * Given the scanning private key, spending private key, and the
5
+ * ephemeral public key from an announcement, derive the stealth
6
+ * private key that controls the stealth address.
7
+ *
8
+ * 1. ECDH: sharedSecret = scanningPrivKey * ephemeralPubKey
9
+ * 2. Hash: hashedSecret = keccak256(compress(sharedSecret))
10
+ * 3. Stealth private key: p_stealth = (spendingPrivKey + hashedSecret) mod n
11
+ */
12
+ import { secp256k1 } from '@noble/curves/secp256k1';
13
+ import { keccak_256 } from '@noble/hashes/sha3';
14
+ import { InvalidKeyError, StealthAddressError } from './errors.js';
15
+ /**
16
+ * Compute the stealth private key for a detected payment.
17
+ *
18
+ * @param scanningKey - Recipient's scanning private key
19
+ * @param spendingKey - Recipient's spending private key
20
+ * @param ephemeralPubKey - Ephemeral public key from the announcement (33 bytes compressed)
21
+ * @returns 32-byte stealth private key
22
+ * @throws InvalidKeyError if ephemeral public key is invalid
23
+ * @throws StealthAddressError if the derived stealth key is invalid
24
+ */
25
+ export function computeStealthKey(scanningKey, spendingKey, ephemeralPubKey) {
26
+ // Validate ephemeral public key
27
+ let ephemeralPoint;
28
+ try {
29
+ ephemeralPoint = secp256k1.ProjectivePoint.fromHex(ephemeralPubKey);
30
+ }
31
+ catch {
32
+ throw new InvalidKeyError('Invalid ephemeral public key');
33
+ }
34
+ // Step 1: ECDH shared secret S = scanningPriv * P_ephemeral
35
+ const scanScalar = bytesToBigInt(scanningKey.bytes);
36
+ const sharedSecretPoint = ephemeralPoint.multiply(scanScalar);
37
+ // Step 2: Hash the compressed shared secret
38
+ const sharedSecretCompressed = sharedSecretPoint.toRawBytes(true); // 33 bytes
39
+ const hashedSecret = keccak_256(sharedSecretCompressed); // 32 bytes
40
+ // Step 3: Stealth private key = (spendingPriv + hashedSecret) mod n
41
+ const n = secp256k1.CURVE.n;
42
+ const spendScalar = bytesToBigInt(spendingKey.bytes);
43
+ const hashedScalar = bytesToBigInt(hashedSecret) % n;
44
+ const stealthScalar = (spendScalar + hashedScalar) % n;
45
+ if (stealthScalar === 0n) {
46
+ throw new StealthAddressError('Derived stealth key is zero');
47
+ }
48
+ // Convert BigInt back to 32-byte Uint8Array (big-endian)
49
+ return bigIntToBytes(stealthScalar, 32);
50
+ }
51
+ /** Convert a Uint8Array to a BigInt (big-endian). */
52
+ function bytesToBigInt(bytes) {
53
+ let result = 0n;
54
+ for (const byte of bytes) {
55
+ result = (result << 8n) | BigInt(byte);
56
+ }
57
+ return result;
58
+ }
59
+ /** Convert a BigInt to a fixed-length Uint8Array (big-endian). */
60
+ function bigIntToBytes(value, length) {
61
+ const result = new Uint8Array(length);
62
+ let remaining = value;
63
+ for (let i = length - 1; i >= 0; i--) {
64
+ result[i] = Number(remaining & 0xffn);
65
+ remaining >>= 8n;
66
+ }
67
+ return result;
68
+ }
69
+ //# sourceMappingURL=compute-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-key.js","sourceRoot":"","sources":["../../src/compute-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAEnE;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,WAAwB,EACxB,WAAwB,EACxB,eAA2B;IAE3B,gCAAgC;IAChC,IAAI,cAA8D,CAAC;IACnE,IAAI,CAAC;QACH,cAAc,GAAG,SAAS,CAAC,eAAe,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,eAAe,CAAC,8BAA8B,CAAC,CAAC;IAC5D,CAAC;IAED,6DAA6D;IAC7D,MAAM,UAAU,GAAG,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,iBAAiB,GAAG,cAAc,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAE9D,4CAA4C;IAC5C,MAAM,sBAAsB,GAAG,iBAAiB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW;IAC9E,MAAM,YAAY,GAAG,UAAU,CAAC,sBAAsB,CAAC,CAAC,CAAC,WAAW;IAEpE,oEAAoE;IACpE,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5B,MAAM,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IACrD,MAAM,aAAa,GAAG,CAAC,WAAW,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAEvD,IAAI,aAAa,KAAK,EAAE,EAAE,CAAC;QACzB,MAAM,IAAI,mBAAmB,CAAC,6BAA6B,CAAC,CAAC;IAC/D,CAAC;IAED,yDAAyD;IACzD,OAAO,aAAa,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;AAC1C,CAAC;AAED,qDAAqD;AACrD,SAAS,aAAa,CAAC,KAAiB;IACtC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,kEAAkE;AAClE,SAAS,aAAa,CAAC,KAAa,EAAE,MAAc;IAClD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IACtC,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC,CAAC;QACtC,SAAS,KAAK,EAAE,CAAC;IACnB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * ShroudFi Core Constants
3
+ *
4
+ * EIP-5564 / ERC-6538 scheme configuration for Base (EVM).
5
+ */
6
+ /** EIP-5564 scheme ID for secp256k1 + view tags. */
7
+ export declare const SCHEME_ID = 1;
8
+ /** HKDF salt used for all key derivation from master seed. */
9
+ export declare const HKDF_SALT = "ShroudFi-EVM-v1";
10
+ /**
11
+ * ERC-5564 Announcer singleton address.
12
+ * Deterministic CREATE2 deployment -- same address on every EVM chain including Base.
13
+ */
14
+ export declare const ERC5564_ANNOUNCER_ADDRESS: "0x55649E01B5Df198D18D95b5cc5051630cfD45564";
15
+ /**
16
+ * ERC-6538 Stealth Meta-Address Registry singleton address.
17
+ * Deterministic CREATE2 deployment -- same address on every EVM chain including Base.
18
+ */
19
+ export declare const ERC6538_REGISTRY_ADDRESS: "0x6538E6bf4B0eBd30A8Ea093027Ac2422ce5d6538";
20
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,oDAAoD;AACpD,eAAO,MAAM,SAAS,IAAI,CAAC;AAE3B,8DAA8D;AAC9D,eAAO,MAAM,SAAS,oBAAoB,CAAC;AAE3C;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EACpC,4CAAqD,CAAC;AAExD;;;GAGG;AACH,eAAO,MAAM,wBAAwB,EACnC,4CAAqD,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * ShroudFi Core Constants
3
+ *
4
+ * EIP-5564 / ERC-6538 scheme configuration for Base (EVM).
5
+ */
6
+ /** EIP-5564 scheme ID for secp256k1 + view tags. */
7
+ export const SCHEME_ID = 1;
8
+ /** HKDF salt used for all key derivation from master seed. */
9
+ export const HKDF_SALT = 'ShroudFi-EVM-v1';
10
+ /**
11
+ * ERC-5564 Announcer singleton address.
12
+ * Deterministic CREATE2 deployment -- same address on every EVM chain including Base.
13
+ */
14
+ export const ERC5564_ANNOUNCER_ADDRESS = '0x55649E01B5Df198D18D95b5cc5051630cfD45564';
15
+ /**
16
+ * ERC-6538 Stealth Meta-Address Registry singleton address.
17
+ * Deterministic CREATE2 deployment -- same address on every EVM chain including Base.
18
+ */
19
+ export const ERC6538_REGISTRY_ADDRESS = '0x6538E6bf4B0eBd30A8Ea093027Ac2422ce5d6538';
20
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,oDAAoD;AACpD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC;AAE3B,8DAA8D;AAC9D,MAAM,CAAC,MAAM,SAAS,GAAG,iBAAiB,CAAC;AAE3C;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GACpC,4CAAqD,CAAC;AAExD;;;GAGG;AACH,MAAM,CAAC,MAAM,wBAAwB,GACnC,4CAAqD,CAAC"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * ShroudFi Privacy-Safe Error Hierarchy
3
+ *
4
+ * Rules:
5
+ * - NEVER include private keys, seeds, or scalars in error messages.
6
+ * - NEVER include amounts or balances.
7
+ * - NEVER include stealth addresses or ephemeral keys.
8
+ * - Safe to include: error codes, generic descriptions.
9
+ */
10
+ /** Base error for all ShroudFi operations. */
11
+ export declare class ShroudFiError extends Error {
12
+ readonly code: string;
13
+ constructor(code: string, message: string);
14
+ }
15
+ /** Thrown when a private or public key fails validation. */
16
+ export declare class InvalidKeyError extends ShroudFiError {
17
+ constructor(message?: string);
18
+ }
19
+ /** Thrown when a stealth meta-address cannot be parsed or is malformed. */
20
+ export declare class InvalidMetaAddressError extends ShroudFiError {
21
+ constructor(message?: string);
22
+ }
23
+ /** Thrown when stealth address generation or verification fails. */
24
+ export declare class StealthAddressError extends ShroudFiError {
25
+ constructor(message?: string);
26
+ }
27
+ /** Discriminated union result type -- avoids throwing for sensitive operations. */
28
+ export type Result<T> = {
29
+ readonly ok: true;
30
+ readonly value: T;
31
+ } | {
32
+ readonly ok: false;
33
+ readonly error: ShroudFiError;
34
+ };
35
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,8CAA8C;AAC9C,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAM1C;AAED,4DAA4D;AAC5D,qBAAa,eAAgB,SAAQ,aAAa;gBACpC,OAAO,GAAE,MAA+B;CAIrD;AAED,2EAA2E;AAC3E,qBAAa,uBAAwB,SAAQ,aAAa;gBAC5C,OAAO,GAAE,MAAuC;CAI7D;AAED,oEAAoE;AACpE,qBAAa,mBAAoB,SAAQ,aAAa;gBACxC,OAAO,GAAE,MAA2C;CAIjE;AAED,mFAAmF;AACnF,MAAM,MAAM,MAAM,CAAC,CAAC,IAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GACxC;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;CAAE,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * ShroudFi Privacy-Safe Error Hierarchy
3
+ *
4
+ * Rules:
5
+ * - NEVER include private keys, seeds, or scalars in error messages.
6
+ * - NEVER include amounts or balances.
7
+ * - NEVER include stealth addresses or ephemeral keys.
8
+ * - Safe to include: error codes, generic descriptions.
9
+ */
10
+ /** Base error for all ShroudFi operations. */
11
+ export class ShroudFiError extends Error {
12
+ code;
13
+ constructor(code, message) {
14
+ super(message);
15
+ this.code = code;
16
+ this.name = 'ShroudFiError';
17
+ Object.setPrototypeOf(this, new.target.prototype);
18
+ }
19
+ }
20
+ /** Thrown when a private or public key fails validation. */
21
+ export class InvalidKeyError extends ShroudFiError {
22
+ constructor(message = 'Invalid key material') {
23
+ super('INVALID_KEY', message);
24
+ this.name = 'InvalidKeyError';
25
+ }
26
+ }
27
+ /** Thrown when a stealth meta-address cannot be parsed or is malformed. */
28
+ export class InvalidMetaAddressError extends ShroudFiError {
29
+ constructor(message = 'Invalid stealth meta-address') {
30
+ super('INVALID_META_ADDRESS', message);
31
+ this.name = 'InvalidMetaAddressError';
32
+ }
33
+ }
34
+ /** Thrown when stealth address generation or verification fails. */
35
+ export class StealthAddressError extends ShroudFiError {
36
+ constructor(message = 'Stealth address operation failed') {
37
+ super('STEALTH_ADDRESS_ERROR', message);
38
+ this.name = 'StealthAddressError';
39
+ }
40
+ }
41
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,8CAA8C;AAC9C,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,IAAI,CAAS;IAEtB,YAAY,IAAY,EAAE,OAAe;QACvC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED,4DAA4D;AAC5D,MAAM,OAAO,eAAgB,SAAQ,aAAa;IAChD,YAAY,UAAkB,sBAAsB;QAClD,KAAK,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF;AAED,2EAA2E;AAC3E,MAAM,OAAO,uBAAwB,SAAQ,aAAa;IACxD,YAAY,UAAkB,8BAA8B;QAC1D,KAAK,CAAC,sBAAsB,EAAE,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AAED,oEAAoE;AACpE,MAAM,OAAO,mBAAoB,SAAQ,aAAa;IACpD,YAAY,UAAkB,kCAAkC;QAC9D,KAAK,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF"}