@opaquecash/stellar 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.
@@ -0,0 +1,345 @@
1
+ import { Keypair } from '@stellar/stellar-sdk';
2
+ export { B as BN254_R, D as DerivedDeposit, a as POOL_TREE_DEPTH, P as PoolNote, d as deriveDeposit, g as getPoseidon, h as hashFields, n as newNoteSecrets, r as randomFieldElement, u as unspentTotal } from '../notes-CTR_oi8Y.js';
3
+
4
+ /**
5
+ * Byte and hex helpers shared across the crypto layer.
6
+ *
7
+ * These are intentionally dependency-free and isomorphic (Node + browser).
8
+ */
9
+ /** Parse a hex string (with or without `0x`) into bytes. */
10
+ declare function hexToBytes(hex: string): Uint8Array;
11
+ /** Encode bytes as a lowercase hex string (no `0x` prefix). */
12
+ declare function bytesToHex(b: Uint8Array): string;
13
+ /** Interpret bytes as a big-endian unsigned integer. */
14
+ declare function bytesToBigInt(b: Uint8Array): bigint;
15
+ /** Encode a bigint as a fixed 32-byte big-endian array. */
16
+ declare function bigIntToBytes32(value: bigint): Uint8Array;
17
+ /** bigint -> 0x-prefixed 32-byte big-endian hex. */
18
+ declare function toHex32(v: bigint): string;
19
+ /** Concatenate byte arrays into one. */
20
+ declare function concatBytes(...arrays: Uint8Array[]): Uint8Array;
21
+
22
+ /**
23
+ * String-based decimal parsing for XLM amounts to avoid floating-point precision
24
+ * issues. XLM uses 7 decimal places (1 XLM = 10^7 stroops).
25
+ */
26
+ /**
27
+ * Parse an XLM string into stroops. Enforces at most 7 decimal places and
28
+ * rejects malformed input.
29
+ *
30
+ * @throws if the input is empty, non-numeric, or has more than 7 decimals.
31
+ */
32
+ declare function parseXlmToStroops(xlmString: string): bigint;
33
+ /**
34
+ * Parse a Horizon balance string into stroops. Returns 0 for empty or malformed
35
+ * input (defensive against unexpected API responses).
36
+ */
37
+ declare function parseHorizonBalanceToStroops(balanceString: string | undefined): bigint;
38
+ /** Format stroops as an XLM string with trailing zeros removed. */
39
+ declare function formatStroopsToXlm(stroops: bigint): string;
40
+ /** Alias for {@link formatStroopsToXlm}. */
41
+ declare const formatXlm: typeof formatStroopsToXlm;
42
+
43
+ /**
44
+ * Dual-Key Stealth Address Protocol (DKSAP) — client-side crypto.
45
+ *
46
+ * Senders derive a one-time stealth address from a recipient's meta-address
47
+ * (viewing + spending public keys). Recipients use their viewing key to detect
48
+ * incoming transfers (view-tag prefilter) and their spending key to reconstruct
49
+ * the one-time private key and sweep.
50
+ *
51
+ * Uses @noble/curves secp256k1 and is byte-compatible with the Rust WASM scanner.
52
+ *
53
+ * Stellar adaptation: scanning matches on the 20-byte Keccak "stealth id"; funds
54
+ * are held on a deterministic Ed25519 Stellar account derived from the stealth
55
+ * secp256k1 point.
56
+ */
57
+
58
+ /** 0x-prefixed hex string. */
59
+ type Hex = `0x${string}`;
60
+ type DomainSeparationOpts = {
61
+ origin: string;
62
+ networkPassphrase: string;
63
+ walletPublicKey: string;
64
+ purpose: string;
65
+ };
66
+ /**
67
+ * Build the human-readable, domain-separated message a wallet signs to derive
68
+ * its Opaque stealth keys. Signing it is not a transaction and moves no funds.
69
+ */
70
+ declare function buildDomainSeparatedMessage(opts: DomainSeparationOpts): string;
71
+ declare const LEGACY_SETUP_MESSAGE = "Sign this message to derive your Opaque Cash stealth keys on Stellar. This is not a transaction and does not move funds.";
72
+ /**
73
+ * Derive viewing key (v) and spending key (s) from a wallet signature used as
74
+ * entropy. Expands the signature into 64 bytes via HKDF-SHA256, then splits into
75
+ * two 32-byte private keys. Domain string is "opaque-cash-v1".
76
+ */
77
+ declare function deriveKeysFromSignature(signatureHex: Hex | string): {
78
+ viewingKey: Uint8Array;
79
+ spendingKey: Uint8Array;
80
+ };
81
+ /**
82
+ * Build the stealth meta-address from viewing and spending private keys.
83
+ * Meta-address = compressed(V) || compressed(S) (66 bytes).
84
+ */
85
+ declare function keysToStealthMetaAddress(viewingKey: Uint8Array, spendingKey: Uint8Array): {
86
+ V: Uint8Array;
87
+ S: Uint8Array;
88
+ metaAddress: Uint8Array;
89
+ };
90
+ /** Encode the 66-byte stealth meta-address as 0x-prefixed hex. */
91
+ declare function stealthMetaAddressToHex(metaAddress: Uint8Array): Hex;
92
+ /**
93
+ * Parse a recipient stealth meta-address into viewing and spending public keys.
94
+ * Format: first 33 bytes = compressed viewing key V, next 33 = compressed S.
95
+ */
96
+ declare function parseStealthMetaAddress(metaHex: Hex | string): {
97
+ viewPubKey: Uint8Array;
98
+ spendPubKey: Uint8Array;
99
+ };
100
+ /**
101
+ * Sender-side: compute a one-time stealth address and view tag for a recipient
102
+ * meta-address. Generates a fresh ephemeral key per call.
103
+ */
104
+ declare function computeStealthAddressAndViewTag(recipientMetaAddressHex: Hex | string): {
105
+ ephemeralPriv: Uint8Array;
106
+ ephemeralPubKey: Uint8Array;
107
+ stealthAddress: string;
108
+ stealthStellarAddress: string;
109
+ viewTag: number;
110
+ metadata: Uint8Array;
111
+ };
112
+ /**
113
+ * Rebuild announce() parameters for a manual ghost receive using a stored
114
+ * ephemeral private key (deterministic re-derivation of a prior send).
115
+ */
116
+ declare function buildGhostAnnouncementPayload(recipientMetaAddressHex: Hex | string, ephemeralPrivKeyHex: Hex | string): {
117
+ stealthAddress: string;
118
+ ephemeralPubKey: Uint8Array;
119
+ metadata: Uint8Array;
120
+ viewTag: number;
121
+ };
122
+ /**
123
+ * Recipient-side: recompute the DKSAP shared-secret hash and view tag from the
124
+ * sender's ephemeral public key and the recipient's viewing key. Mirrors the
125
+ * sender computation via ECDH symmetry (viewPriv·EphPub == ephPriv·ViewPub).
126
+ */
127
+ declare function recipientSharedSecretHash(viewingKey: Uint8Array, ephemeralPubKey: Uint8Array): {
128
+ sH: Uint8Array;
129
+ viewTag: number;
130
+ };
131
+ /**
132
+ * Cheap recipient-side prefilter: does this announcement's view tag match?
133
+ * Lets a recipient skip the expensive point math for non-matching transfers.
134
+ */
135
+ declare function checkViewTagMatch(opts: {
136
+ viewingKey: Uint8Array;
137
+ ephemeralPubKey: Uint8Array;
138
+ viewTag: number;
139
+ }): boolean;
140
+ /**
141
+ * Recipient-side: reconstruct the one-time stealth private key for a transfer.
142
+ * stealthPriv = (spendingKey + sH) mod n, where sH = keccak(viewPriv·EphPub).
143
+ * The returned key controls the same secp256k1 point the sender derived, hence
144
+ * the same deterministic Stellar account.
145
+ */
146
+ declare function reconstructStealthPrivateKey(opts: {
147
+ viewingKey: Uint8Array;
148
+ spendingKey: Uint8Array;
149
+ ephemeralPubKey: Uint8Array;
150
+ }): Uint8Array;
151
+ /** Deterministic ephemeral scalar for the "Announcer" stealth signer. */
152
+ declare function deriveAnnouncerEphemeralKey(metaAddressHex: Hex | string): Uint8Array;
153
+ /** Derive the deterministic Ed25519 Stellar keypair from a stealth secp256k1 point. */
154
+ declare function deriveStealthStellarKeypair(stealthPubKeyUncompressed: Uint8Array): Keypair;
155
+ /** Derive the deterministic Stellar G-address from a stealth secp256k1 point. */
156
+ declare function deriveStealthStellarAddress(stealthPubKeyUncompressed: Uint8Array): string;
157
+ /**
158
+ * Recompute the 20-byte EVM-style stealth id (`0x` + 40 hex) from a stealth
159
+ * private key. Used to confirm a view-tag match against an announcement.
160
+ */
161
+ declare function stealthIdFromPrivateKey(stealthPrivKey: Uint8Array): string;
162
+ /** Derive the deterministic Stellar G-address from a stealth private key. */
163
+ declare function deriveStealthStellarAddressFromStealthPrivKey(stealthPrivKey: Uint8Array): string;
164
+ /** Derive the deterministic Stellar keypair from a stealth private key. */
165
+ declare function deriveStealthStellarKeypairFromStealthPrivKey(stealthPrivKey: Uint8Array): Keypair;
166
+
167
+ interface StealthAnnouncement {
168
+ /** 20-byte EVM-style stealth id (`0x` + 40 hex). */
169
+ stealthAddress: string;
170
+ /** Sender's compressed ephemeral public key (33 bytes). */
171
+ ephemeralPubKey: Uint8Array;
172
+ /** View tag byte from the announcement metadata. */
173
+ viewTag: number;
174
+ }
175
+ interface ScanMatch {
176
+ announcement: StealthAnnouncement;
177
+ /** Reconstructed one-time stealth private key (32 bytes). */
178
+ stealthPrivKey: Uint8Array;
179
+ /** Deterministic Stellar account holding the funds. */
180
+ stealthStellarAddress: string;
181
+ }
182
+ /**
183
+ * Scan announcements for transfers to the recipient. Each candidate is
184
+ * view-tag prefiltered, then confirmed by reconstructing the one-time key and
185
+ * checking its stealth id equals the announced one (so a coincidental tag match
186
+ * is rejected).
187
+ */
188
+ declare function scanAnnouncements(opts: {
189
+ announcements: StealthAnnouncement[];
190
+ viewingKey: Uint8Array;
191
+ spendingKey: Uint8Array;
192
+ }): ScanMatch[];
193
+
194
+ /**
195
+ * Schema field primitives shared by the schema codec and the schema service.
196
+ */
197
+ type FieldType = "bool" | "u8" | "u16" | "u32" | "u64" | "string" | "pubkey";
198
+ interface FieldDef {
199
+ /** Stable ordinal id (index in declaration order). */
200
+ id: string;
201
+ name: string;
202
+ type: FieldType;
203
+ }
204
+
205
+ /**
206
+ * Canonical schema / attestation encoding. Mirrors the `opaque-schema-core`
207
+ * crate and the Soroban schema/attestation contracts byte-for-byte.
208
+ */
209
+
210
+ declare const MAX_FIELDS = 16;
211
+ declare const MAX_FIELD_NAME_LEN = 32;
212
+ declare const MAX_STRING_VALUE_LEN = 128;
213
+ declare const MAX_ATTESTATION_DATA_LEN = 512;
214
+ declare class SchemaParseError extends Error {
215
+ constructor(message: string);
216
+ }
217
+ declare class AttestationDataError extends Error {
218
+ constructor(message: string);
219
+ }
220
+ /** Parse and validate `"type name"` comma-separated field definitions. */
221
+ declare function parseFieldDefinitions(fieldDefs: string): FieldDef[];
222
+ declare function fieldDefsToCanonicalString(fields: FieldDef[]): string;
223
+ declare function encodeCanonicalFieldDefs(fields: FieldDef[]): Uint8Array;
224
+ declare function addressToAuthorityBytes(address: string): Uint8Array;
225
+ /** Compute a schema id (SHA-256 of authority || name || version || canonical defs). */
226
+ declare function computeSchemaIdFromBytes(authorityBytes: Uint8Array, name: string, fieldDefinitions: string, version?: number): Promise<Uint8Array>;
227
+ declare function computeSchemaId(authority: string, name: string, fieldDefinitions: string, version?: number): Promise<Uint8Array>;
228
+ /** Encode attestation payload bytes in schema field order. */
229
+ declare function encodeAttestationData(fieldValues: Record<string, string>, fieldDefs: FieldDef[]): Uint8Array;
230
+ /** Decode canonical attestation bytes into a field-value map. */
231
+ declare function decodeAttestationData(data: Uint8Array, fieldDefs: FieldDef[]): Record<string, string>;
232
+
233
+ /**
234
+ * Encrypted backup of stealth ephemeral private keys ("ghost entries").
235
+ * PBKDF2-SHA256 key derivation + AES-256-GCM, using the Web Crypto API
236
+ * (available in browsers and Node 18+).
237
+ *
238
+ * Threat model: protects key material at rest against read-only exfiltration of
239
+ * stored backups. It does NOT protect against capture of the password at entry
240
+ * time, runtime memory inspection while decrypted, or a fully compromised host.
241
+ */
242
+ type GhostEntryLike = {
243
+ cluster: string;
244
+ stealthAddress: string;
245
+ ephemeralPrivKeyHex?: string;
246
+ createdAt: number;
247
+ };
248
+ type EncryptedGhostPayload = {
249
+ version: 1;
250
+ salt: string;
251
+ entries: Array<{
252
+ cluster: string;
253
+ stealthAddress: string;
254
+ ephemeralPrivKeyEncrypted?: string;
255
+ createdAt: number;
256
+ }>;
257
+ };
258
+ /**
259
+ * Encrypt ghost entries. Only `ephemeralPrivKeyHex` is encrypted; metadata
260
+ * (cluster, stealth address, timestamp) stays readable.
261
+ */
262
+ declare function encryptGhostEntries(entries: GhostEntryLike[], password: string): Promise<EncryptedGhostPayload>;
263
+ /** Decrypt ghost entries produced by {@link encryptGhostEntries}. */
264
+ declare function decryptGhostEntries(payload: EncryptedGhostPayload, password: string): Promise<GhostEntryLike[]>;
265
+ /** Export ghost entries as an encrypted JSON string. */
266
+ declare function exportEncryptedBackup(entries: GhostEntryLike[], password: string): Promise<string>;
267
+ /** Import ghost entries from an encrypted backup string. */
268
+ declare function importEncryptedBackup(backupJson: string, password: string): Promise<GhostEntryLike[]>;
269
+
270
+ /**
271
+ * Opaque payment-link format: `opaque://v{version}/{network}/{metaAddress}?{params}`
272
+ * with versioning, network binding, and optional SEP-compatible parameters.
273
+ */
274
+ type Network = "testnet" | "mainnet" | "futurenet" | "local";
275
+ interface PaymentLinkParams {
276
+ amount?: string;
277
+ asset?: string;
278
+ issuer?: string;
279
+ memo?: string;
280
+ sep?: string;
281
+ callback?: string;
282
+ label?: string;
283
+ expires?: string;
284
+ }
285
+ interface PaymentLink {
286
+ version: number;
287
+ network: Network;
288
+ metaAddress: string;
289
+ params: PaymentLinkParams;
290
+ }
291
+ interface PaymentLinkError {
292
+ type: "INVALID_FORMAT" | "UNSUPPORTED_VERSION" | "NETWORK_MISMATCH" | "INVALID_META_ADDRESS" | "INVALID_PARAMETER";
293
+ message: string;
294
+ details?: unknown;
295
+ }
296
+ /** Validate a DKSAP meta-address: `0x` + 132 hex chars (66 bytes). */
297
+ declare function isValidMetaAddress(metaAddress: string): boolean;
298
+ declare function isValidNetwork(network: string): network is Network;
299
+ /** Validate a Stellar public key (G..., 56 chars, base32). */
300
+ declare function isValidStellarPublicKey(publicKey: string): boolean;
301
+ declare function isValidAssetCode(assetCode: string): boolean;
302
+ declare function isValidAmount(amount: string): boolean;
303
+ declare function isValidIso8601(timestamp: string): boolean;
304
+ declare function isValidUrl(url: string): boolean;
305
+ /** Encode a payment link from components. Throws on invalid input. */
306
+ declare function encodePaymentLink(link: PaymentLink): string;
307
+ /** Decode a payment-link string into components, or a structured error. */
308
+ declare function decodePaymentLink(linkString: string, configuredNetwork?: Network): {
309
+ link: PaymentLink;
310
+ } | {
311
+ error: PaymentLinkError;
312
+ };
313
+ /** Create a v1 payment link from a meta-address and network. */
314
+ declare function createPaymentLink(metaAddress: string, network: Network, params?: PaymentLinkParams): string;
315
+ /** True when the string parses as a valid opaque payment link. */
316
+ declare function isOpaquePaymentLink(linkString: string): boolean;
317
+ /** Convert a legacy `https://host/pay/{metaAddress}` link into opaque format. */
318
+ declare function convertLegacyLink(legacyLink: string, network: Network, params?: PaymentLinkParams): string | null;
319
+
320
+ /**
321
+ * Destination memo risk + validation.
322
+ *
323
+ * Many Stellar custodians share one deposit address across users and rely on the
324
+ * transaction memo to disambiguate. Sending to such an address without a memo can
325
+ * lose funds. This module exposes a small allowlist of well-known custodial
326
+ * addresses and validators that match the Stellar memo spec.
327
+ */
328
+ type MemoType = "none" | "text" | "id" | "hash" | "return";
329
+ interface MemoRisk {
330
+ isKnownCustodian: boolean;
331
+ custodianName?: string;
332
+ recommendedMemoType?: MemoType;
333
+ }
334
+ /** Look up the memo risk for a destination. Safe for any input. */
335
+ declare function memoRiskFor(destination: string | undefined | null): MemoRisk;
336
+ interface MemoValidationResult {
337
+ ok: boolean;
338
+ error?: string;
339
+ }
340
+ /** Validate a memo value against the Stellar memo spec for the given type. */
341
+ declare function validateMemo(memoType: MemoType, memo: string | undefined): MemoValidationResult;
342
+ /** Warning copy for the inline banner, or null when no warning is needed. */
343
+ declare function memoWarningCopy(risk: MemoRisk, memo: string | undefined): string | null;
344
+
345
+ export { AttestationDataError, type DomainSeparationOpts, type EncryptedGhostPayload, type FieldDef, type FieldType, type GhostEntryLike, type Hex, LEGACY_SETUP_MESSAGE, MAX_ATTESTATION_DATA_LEN, MAX_FIELDS, MAX_FIELD_NAME_LEN, MAX_STRING_VALUE_LEN, type MemoRisk, type MemoType, type MemoValidationResult, type Network, type PaymentLink, type PaymentLinkError, type PaymentLinkParams, type ScanMatch, SchemaParseError, type StealthAnnouncement, addressToAuthorityBytes, bigIntToBytes32, buildDomainSeparatedMessage, buildGhostAnnouncementPayload, bytesToBigInt, bytesToHex, checkViewTagMatch, computeSchemaId, computeSchemaIdFromBytes, computeStealthAddressAndViewTag, concatBytes, convertLegacyLink, createPaymentLink, decodeAttestationData, decodePaymentLink, decryptGhostEntries, deriveAnnouncerEphemeralKey, deriveKeysFromSignature, deriveStealthStellarAddress, deriveStealthStellarAddressFromStealthPrivKey, deriveStealthStellarKeypair, deriveStealthStellarKeypairFromStealthPrivKey, encodeAttestationData, encodeCanonicalFieldDefs, encodePaymentLink, encryptGhostEntries, exportEncryptedBackup, fieldDefsToCanonicalString, formatStroopsToXlm, formatXlm, hexToBytes, importEncryptedBackup, isOpaquePaymentLink, isValidAmount, isValidAssetCode, isValidIso8601, isValidMetaAddress, isValidNetwork, isValidStellarPublicKey, isValidUrl, keysToStealthMetaAddress, memoRiskFor, memoWarningCopy, parseFieldDefinitions, parseHorizonBalanceToStroops, parseStealthMetaAddress, parseXlmToStroops, recipientSharedSecretHash, reconstructStealthPrivateKey, scanAnnouncements, stealthIdFromPrivateKey, stealthMetaAddressToHex, toHex32, validateMemo };