bsv-bap 0.2.0-alpha.1 → 0.2.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/README.md CHANGED
@@ -22,7 +22,7 @@ Current digital identity systems suffer from three critical failures:
22
22
  BAP resolves these failures by recognizing a simple axiom: **a cryptographic keypair IS an identity**. This principle, combined with Bitcoin's immutable ledger, creates a system where:
23
23
 
24
24
  - Identity ownership is cryptographically provable
25
- - Attestations form an auditable chain of trust
25
+ - Attestations form an auditable chain of trust
26
26
  - Data persistence requires no institutional faith
27
27
  - Interoperability emerges from shared protocols, not corporate agreements
28
28
 
@@ -36,7 +36,7 @@ In BAP, identity is not assigned but derived. Your identity emerges from the mat
36
36
  IdentityKey = base58(ripemd160(sha256(rootAddress)))
37
37
  ```
38
38
 
39
- This deterministic derivation means identity recovery requires only the original key material - no database lookups, no account recovery flows, no customer service.
39
+ This deterministic derivation means identity recovery requires only the original key material no database lookups, no account recovery flows, no customer service.
40
40
 
41
41
  ### Attestations as Proofs
42
42
 
@@ -102,56 +102,62 @@ Member Key (identity root at path)
102
102
  Signing Key (used for on-chain operations)
103
103
  ```
104
104
 
105
- This structure ensures compatibility with BRC-100 wallet tooling while maintaining BAP's identity management features. The member key serves as the BRC-100 identity root, and the signing key is deterministically derived for on-chain operations.
105
+ The member key serves as the stable identity root. The signing key is deterministically derived from it for on-chain operations. This structure is compatible with BRC-100 wallet tooling, though BAP is not coupled to any specific wallet implementation.
106
106
 
107
107
  ## Implementation
108
108
 
109
109
  ### Installation
110
110
 
111
111
  ```bash
112
+ bun add bsv-bap
113
+ # or
112
114
  npm install bsv-bap
113
115
  ```
114
116
 
117
+ Peer dependency: `@bsv/sdk@^2.0.1`
118
+
115
119
  ### Basic Usage
116
120
 
117
- ```javascript
121
+ ```typescript
118
122
  import { BAP } from 'bsv-bap';
119
123
  import { PrivateKey } from '@bsv/sdk';
120
124
 
121
125
  // Initialize with Type 42 derivation (recommended)
122
126
  const rootKey = PrivateKey.fromRandom();
123
- const bap = new BAP({
124
- rootPk: rootKey.toWif()
125
- });
127
+ const bap = new BAP({ rootPk: rootKey.toWif() });
128
+
129
+ // Create an identity
130
+ const identity = bap.newId();
126
131
 
127
- // Create identity with meaningful name
128
- const identity = bap.newId('Professional Identity');
129
- identity.setAttribute('name', 'Satoshi Nakamoto');
132
+ console.log(identity.bapId); // Deterministic BAP ID
133
+ console.log(identity.rootAddress); // Root Bitcoin address
134
+ console.log(identity.rootPath); // "bap:0" (counter-based)
130
135
 
131
- // Generate ID transaction for blockchain
132
- const idTransaction = identity.getInitialIdTransaction();
136
+ // Create a second identity
137
+ const second = bap.newId();
138
+ console.log(second.rootPath); // "bap:1"
133
139
 
134
- // Create attestation hash for verification
135
- const attestationHash = identity.getAttestationHash('name');
140
+ // Export master backup
141
+ const backup = bap.exportForBackup('My Identities');
136
142
  ```
137
143
 
138
144
  ### Identity Discovery
139
145
 
140
- Type 42 identities use sequential counters (`bap:0`, `bap:1`, etc.) for deterministic recovery. This enables identity discovery when restoring from partial backups:
146
+ Type 42 identities use sequential counters (`bap:0`, `bap:1`, etc.) for deterministic recovery. This enables identity discovery when restoring from a backup:
141
147
 
142
- ```javascript
148
+ ```typescript
143
149
  // Discover identities by checking sequential counters
144
- async function discoverIdentities(bap, checkExistsOnChain) {
150
+ async function discoverIdentities(bap, existsOnChain) {
145
151
  const found = [];
146
-
147
- for (let i = 0; i < 100; i++) { // Check first 100 slots
148
- const identity = bap.newIdWithCounter(i, `Discovered Identity ${i}`);
149
-
150
- if (await checkExistsOnChain(identity.getIdentityKey())) {
152
+
153
+ for (let i = 0; i < 100; i++) {
154
+ const identity = bap.newIdWithCounter(i);
155
+
156
+ if (await existsOnChain(identity.bapId)) {
151
157
  found.push(identity);
152
158
  }
153
159
  }
154
-
160
+
155
161
  return found;
156
162
  }
157
163
  ```
@@ -160,55 +166,273 @@ async function discoverIdentities(bap, checkExistsOnChain) {
160
166
 
161
167
  The BAP ID is defined by the member key at `rootPath`, while the active wallet/signing root follows `currentPath`.
162
168
 
163
- - `rootPath`: stable member key, used to derive the BAP ID
169
+ - `rootPath`: stable member key path, defines the BAP ID
164
170
  - `currentPath`: active wallet root, used for signing and wallet operations
165
171
  - `incrementPath()`: rotates the wallet/signing root without changing the BAP ID
166
172
 
167
- For Type 42 identities the first rotation now moves from `bap:0` to `bap:0:1`, then `bap:0:2`, and so on.
168
-
169
- For backward compatibility, malformed numeric rotation paths created by older buggy Type 42 builds continue rotating numerically (`1` -> `2`). New identities always use the namespaced `bap:<identity>:<rotation>` format.
173
+ For Type 42 identities the first rotation moves from `bap:0` to `bap:0:1`, then `bap:0:2`, and so on.
170
174
 
171
- ```javascript
172
- const identity = bap.newId('Professional Identity');
175
+ ```typescript
176
+ const identity = bap.newId();
173
177
 
174
- const stableMemberKey = identity.getMemberKey();
175
- const activeWalletKey = identity.getWalletPubkey();
178
+ const stableBapId = identity.bapId;
176
179
 
177
180
  identity.incrementPath();
178
181
 
179
- // Stable identity linkage
180
- console.log(identity.getMemberKey() === stableMemberKey); // true
182
+ // BAP ID is unchanged
183
+ console.log(identity.bapId === stableBapId); // true
184
+
185
+ // currentPath has advanced
186
+ console.log(identity.currentPath); // "bap:0:1"
187
+ ```
188
+
189
+ ## CLI
190
+
191
+ The `bap` CLI manages identities from the terminal. Config is stored at `~/.bap/`.
192
+
193
+ ### Identity Management
194
+
195
+ ```bash
196
+ bap create [--name <label>] [--wif <wif>] # Create new identity
197
+ bap list # List all identities (* = active)
198
+ bap use <bapId> # Set active identity
199
+ bap info # Show active identity details
200
+ bap remove <bapId> # Remove identity
201
+ ```
202
+
203
+ ### Backup
204
+
205
+ ```bash
206
+ bap export # Export master backup (JSON to stdout)
207
+ bap export-account [--id <bapId>] # Export account backup (WIF + bapId)
208
+ bap import <file> # Import from backup file
209
+ ```
210
+
211
+ ### Crypto
212
+
213
+ ```bash
214
+ bap encrypt <data> # Encrypt with master key (ECIES)
215
+ bap decrypt <ciphertext> # Decrypt with master key
216
+ bap verify <message> <signature> <address> # Verify BSM signature
217
+ ```
218
+
219
+ ### API Lookups
220
+
221
+ ```bash
222
+ bap lookup <bapId> # Lookup identity on overlay
223
+ bap lookup-address <address> # Lookup identity by address
224
+ bap attestations <hash> # Get attestations for attribute hash
225
+ ```
226
+
227
+ ### Utilities
228
+
229
+ ```bash
230
+ bap id-from-address <address> # Derive BAP ID from address
231
+ bap id-from-pubkey <pubkey> # Derive BAP ID from pubkey
232
+ ```
233
+
234
+ ### Examples
235
+
236
+ ```bash
237
+ # Create your first identity
238
+ bap create --name "Personal"
239
+
240
+ # Create a second identity
241
+ bap create --name "Work"
242
+
243
+ # List and switch
244
+ bap list
245
+ bap use <work-bap-id>
246
+
247
+ # Export account key for use in a wallet
248
+ bap export-account > account.json
249
+
250
+ # Lookup someone on the network
251
+ bap lookup <their-bap-id>
252
+
253
+ # Encrypt a note to yourself
254
+ bap encrypt "remember: office safe combo is 1234" > note.enc
255
+ cat note.enc | xargs bap decrypt
256
+ ```
257
+
258
+ ## Migration from 0.1.x
259
+
260
+ ### Breaking Changes
261
+
262
+ | 0.1.x | 0.2.0 | Notes |
263
+ |-------|-------|-------|
264
+ | `identity.identityKey` | `identity.bapId` | Renamed for clarity |
265
+ | `identity.getIdentityKey()` | `identity.bapId` | Now a property |
266
+ | `identity.idName` | Removed | Use external labels |
267
+ | `identity.setAttribute()` | Removed | Attributes removed from core |
268
+ | `identity.signMessage()` | Removed | Use your wallet |
269
+ | `identity.encrypt/decrypt()` | Removed from MasterID | Use `bap.encrypt/decrypt()` for master-level |
270
+ | `identity.getEncryptionPublicKey()` | Removed | Use your wallet |
271
+ | `identity.getCurrentAddress()` | Removed | Use `identity.getAccountKey()` |
272
+ | `MemberID` class | Removed | Use `identity.exportAccountBackup()` |
273
+ | `exportMemberBackup()` | `exportAccountBackup()` | Returns `{ wif, id }` |
274
+
275
+ ### Migration Path
276
+
277
+ ```typescript
278
+ // 0.1.x
279
+ const identity = bap.newId('My Identity');
280
+ const key = identity.getIdentityKey();
281
+ const addr = identity.getCurrentAddress();
282
+ const { address, signature } = identity.signMessage(msg);
283
+
284
+ // 0.2.0
285
+ const identity = bap.newId();
286
+ const key = identity.bapId;
287
+ const accountKey = identity.getAccountKey(); // Account-level PrivateKey
288
+ const backup = identity.exportAccountBackup(); // { wif, id }
289
+ ```
290
+
291
+ ## Backup Format
292
+
293
+ ### Master Backup (Type 42)
181
294
 
182
- // Rotated wallet/signing root
183
- console.log(identity.getWalletPubkey() === activeWalletKey); // false
295
+ ```json
296
+ {
297
+ "rootPk": "L...",
298
+ "ids": "<encrypted blob>",
299
+ "label": "My Identities",
300
+ "createdAt": "2024-01-01T00:00:00.000Z"
301
+ }
184
302
  ```
185
303
 
186
- ### Migration from Legacy Derivation
304
+ ### Master Backup (BIP32, legacy)
187
305
 
188
- Existing identities using the previous (pre-signing-key-derivation) format can be migrated:
306
+ ```json
307
+ {
308
+ "xprv": "xprv...",
309
+ "ids": "<encrypted blob>",
310
+ "mnemonic": "word1 word2 ...",
311
+ "createdAt": "2024-01-01T00:00:00.000Z"
312
+ }
313
+ ```
189
314
 
190
- ```javascript
191
- // Check if identity needs migration
192
- if (identity.needsRotation(registeredOnChainAddress)) {
193
- // Get the rotation transaction OP_RETURN
194
- const opReturn = identity.getLegacyRotationTransaction();
315
+ ### Account Backup
195
316
 
196
- // App handles funding and broadcasting the transaction
197
- // This rotates from legacy address to new derived signing address
317
+ ```json
318
+ {
319
+ "wif": "L...",
320
+ "id": "<bapId>"
198
321
  }
322
+ ```
323
+
324
+ Compatible with [bitcoin-backup](https://github.com/rohenaz/bitcoin-backup).
325
+
326
+ ## API Reference
327
+
328
+ ### BAP Class
329
+
330
+ The main class for managing identities.
331
+
332
+ #### Constructor
333
+
334
+ ```typescript
335
+ // Type 42 mode (recommended)
336
+ const bap = new BAP({ rootPk: wifKey });
337
+
338
+ // BIP32 mode (legacy)
339
+ const bap = new BAP(xprvKey);
340
+
341
+ // With API token and custom server
342
+ const bap = new BAP({ rootPk: wifKey }, token, server);
343
+ ```
344
+
345
+ #### Identity Management
346
+
347
+ ```typescript
348
+ bap.newId(customPath?: string, idSeed?: string): MasterID
349
+ bap.newIdWithCounter(counter: number): MasterID
350
+ bap.getId(bapId: string): MasterID | null
351
+ bap.listIds(): string[]
352
+ bap.removeId(bapId: string): void
353
+ bap.checkIdBelongs(id: MasterID): boolean
354
+ ```
355
+
356
+ #### Import / Export
357
+
358
+ ```typescript
359
+ // Encrypted identity blob (default)
360
+ const encrypted: string = bap.exportIds();
361
+ bap.importIds(encrypted);
362
+
363
+ // Unencrypted identity data
364
+ const plain = bap.exportIds(undefined, false);
365
+ bap.importIds(plain, false);
199
366
 
200
- // Utility methods for migration
201
- const legacyAddress = identity.getLegacyAddress(); // Pre-derivation address
202
- const newAddress = identity.getCurrentAddress(); // New derived address
367
+ // Master backup (for bitcoin-backup compatibility)
368
+ const backup = bap.exportForBackup(label?, xprv?, mnemonic?);
203
369
  ```
204
370
 
205
- ### Deprecation Notice
371
+ #### Master-Level Crypto
206
372
 
207
- The BIP32 initialization format using extended private keys (xprv) is deprecated. For new implementations, use Type 42 initialization with `{ rootPk: wifKey }`. The legacy BIP32 format remains supported for backward compatibility but should not be used in new projects.
373
+ ```typescript
374
+ // ECIES encryption with the master key
375
+ const ciphertext = bap.encrypt('secret');
376
+ const plaintext = bap.decrypt(ciphertext);
208
377
 
209
- ### Advanced Operations
378
+ // BSM signature verification
379
+ const valid = bap.verifySignature(message, address, signature);
210
380
 
211
- For detailed API documentation, see the [Library Documentation](src/README.md).
381
+ // Challenge verification via API
382
+ const valid = await bap.verifyChallengeSignature(idKey, address, challenge, signature);
383
+ ```
384
+
385
+ #### API Lookups
386
+
387
+ ```typescript
388
+ // Query the BAP overlay network
389
+ const identity = await bap.getIdentity(bapId);
390
+ const identity = await bap.getIdentityFromAddress(address);
391
+ const attestations = await bap.getAttestationsForHash(hash);
392
+ ```
393
+
394
+ ### MasterID Class
395
+
396
+ Represents a single identity. Managed through the `BAP` class.
397
+
398
+ #### Properties
399
+
400
+ ```typescript
401
+ identity.bapId: string // Deterministic BAP ID
402
+ identity.rootAddress: string // Root Bitcoin address
403
+ identity.rootPath: string // Derivation path (e.g., "bap:0")
404
+ identity.currentPath: string // Active path (advances on key rotation)
405
+ identity.previousPath: string
406
+ identity.idSeed: string // Seed used for sub-derivation
407
+ ```
408
+
409
+ #### Methods
410
+
411
+ ```typescript
412
+ // Get the account-level private key
413
+ identity.getAccountKey(): PrivateKey
414
+
415
+ // Export identity state
416
+ identity.export(): Identity
417
+
418
+ // Export account backup (WIF + BAP ID)
419
+ identity.exportAccountBackup(): BapAccountBackup
420
+
421
+ // Import identity state
422
+ identity.import(data: Identity | OldIdentity): void
423
+ ```
424
+
425
+ ### Utility Functions
426
+
427
+ ```typescript
428
+ import { bapIdFromAddress, bapIdFromPubkey } from 'bsv-bap';
429
+
430
+ // Derive BAP ID from a root address
431
+ const bapId = bapIdFromAddress(rootAddress);
432
+
433
+ // Derive BAP ID from a member public key (e.g., BRC-31 identity key)
434
+ const bapId = bapIdFromPubkey(pubkeyHex);
435
+ ```
212
436
 
213
437
  ## Applications
214
438
 
@@ -230,7 +454,7 @@ npm install bigblocks
230
454
  ```jsx
231
455
  import { BitcoinAuth } from 'bigblocks';
232
456
 
233
- <BitcoinAuth
457
+ <BitcoinAuth
234
458
  onAuthenticated={(identity) => {
235
459
  console.log('Authenticated:', identity);
236
460
  }}
@@ -1,5 +1,5 @@
1
1
  import { type PrivateKey, HD } from "@bsv/sdk";
2
- import type { Identity, OldIdentity } from "./interface";
2
+ import type { BapAccountBackup, Identity, OldIdentity } from "./interface";
3
3
  interface Type42KeySource {
4
4
  rootPk: PrivateKey;
5
5
  }
@@ -14,8 +14,10 @@ declare class MasterID {
14
14
  get currentPath(): string;
15
15
  get previousPath(): string;
16
16
  get idSeed(): string;
17
+ getAccountKey(): PrivateKey;
17
18
  validatePath(path: string): boolean;
18
19
  import(identity: Identity | OldIdentity): void;
19
20
  export(): Identity;
21
+ exportAccountBackup(): BapAccountBackup;
20
22
  }
21
23
  export { MasterID };
@@ -2,7 +2,7 @@ export declare const BAP_BITCOM_ADDRESS = "1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT";
2
2
  export declare const BAP_BITCOM_ADDRESS_HEX: string;
3
3
  export declare const AIP_BITCOM_ADDRESS = "15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva";
4
4
  export declare const AIP_BITCOM_ADDRESS_HEX: string;
5
- export declare const BAP_SERVER = "https://api.sigmaidentity.com/v1";
5
+ export declare const BAP_SERVER = "https://api.1sat.app/1sat/bap";
6
6
  export declare const MAX_INT: number;
7
7
  export declare const SIGNING_PATH_PREFIX = "m/424150'/0'/0'";
8
8
  export declare const ENCRYPTION_PATH = "m/424150'/2147483647'/2147483647'";
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { type APIFetcher } from "./api";
2
2
  import type { AttestationValidResponse, GetAttestationResponse, GetIdentityByAddressResponse, GetIdentityResponse } from "./apiTypes";
3
3
  import { MasterID } from "./MasterID";
4
- import type { Attestation, Identity, OldIdentity, PathPrefix } from "./interface";
4
+ import type { Attestation, BapAccountBackup, Identity, OldIdentity, PathPrefix } from "./interface";
5
5
  type Identities = {
6
6
  lastIdPath: string;
7
7
  ids: Identity[];
@@ -64,5 +64,5 @@ export declare class BAP {
64
64
  }
65
65
  export { MasterID };
66
66
  export { bapIdFromAddress, bapIdFromPubkey } from "./utils";
67
- export type { Attestation, Identity, PathPrefix, Type42Params, };
67
+ export type { Attestation, BapAccountBackup, Identity, PathPrefix, Type42Params, };
68
68
  export * from "./apiTypes";
@@ -1,4 +1,4 @@
1
1
  // @bun
2
- import{BSM as R,BigNumber as K,ECIES as D,HD as i,OP as r,Signature as x,PrivateKey as I}from"@bsv/sdk";import{Utils as m}from"@bsv/sdk";var u=async(f,o,$,w)=>{let z=`${$}${f}`;return(await fetch(z,{method:"post",headers:{"Content-type":"application/json; charset=utf-8",token:w,format:"json"},body:JSON.stringify(o)})).json()},h=(f,o)=>async($,w)=>{return u($,w,f,o)};import{Utils as n}from"@bsv/sdk";var{toHex:A,toArray:M}=n,b="1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT",O=A(M(b)),k="15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva",y=A(M(k)),U="https://api.sigmaidentity.com/v1",J=2147483647,Q="m/424150'/0'/0'",X=`m/424150'/${J}'/${J}'`;import{Hash as V,HD as T,Utils as l}from"@bsv/sdk";import{Hash as g,PublicKey as B,Utils as H}from"@bsv/sdk";var{toHex:S,toBase58:c}=H;function F(f){let o=S(g.sha256(f,"utf8"));return c(g.ripemd160(o,"hex"))}function v(f){let o=B.fromString(f);return F(o.toAddress())}var Y={getRandomBytes(f=32){if(typeof globalThis!=="undefined"&&globalThis.crypto&&globalThis.crypto.getRandomValues){let o=new Uint8Array(f);return globalThis.crypto.getRandomValues(o),o}throw new Error("Secure random number generation not available. crypto.getRandomValues() is required for cryptographic operations. This environment may not be suitable for secure key generation.")},getRandomString(f=32){let o=this.getRandomBytes(f);return Array.from(o,($)=>$.toString(16).padStart(2,"0")).join("")},getSigningPathFromHex(f,o=!0){let $="m",w=f.match(/.{1,8}/g);if(!w)throw new Error("Invalid hex string");let z=2147483647;for(let j of w){let G=Number(`0x${j}`);if(G>z)G-=z;$+=`/${G}${o?"'":""}`}return $},getNextIdentityPath(f){let o=f.split("/"),$=o[o.length-2],w=!1;if($.match("'"))w=!0;let z=(Number($.replace(/[^0-9]/g,""))+1).toString();return o[o.length-2]=z+(w?"'":""),o[o.length-1]=`0${w?"'":""}`,o.join("/")},getNextPath(f){let o=f.match(/^bap:(\d+)(?::(\d+))?$/);if(o){let G=o[1],Z=o[2];if(Z===void 0)return`bap:${G}:1`;return`bap:${G}:${Number(Z)+1}`}if(/^\d+$/.test(f))return(Number(f)+1).toString();if(!f.includes("/"))throw new Error(`Unsupported non-BIP32 path: ${f}`);let $=f.split("/"),w=$[$.length-1],z=!1;if(w.match("'"))z=!0;let j=(Number(w.replace(/[^0-9]/g,""))+1).toString();return $[$.length-1]=j+(z?"'":""),$.join("/")}};class q{#o;#f;#w;#$;#z;#j;#G;rootAddress;bapId;constructor(f,o=""){if(f instanceof T)if(this.#w=!1,o){let $=l.toHex(V.sha256(o,"utf8")),w=Y.getSigningPathFromHex($);this.#o=f.derive(w)}else this.#o=f;else if(this.#w=!0,this.#f=f.rootPk,o){let $=l.toHex(V.sha256(o,"utf8"));this.#f=this.#f.deriveChild(this.#f.toPublicKey(),$)}if(this.#G=o,this.#$=`${Q}/0/0/0`,this.#j=`${Q}/0/0/0`,this.#z=`${Q}/0/0/1`,this.#w){if(!this.#f)throw new Error("Master private key not initialized");let $=this.#f.deriveChild(this.#f.toPublicKey(),this.#$);this.rootAddress=$.toPublicKey().toAddress()}else{if(!this.#o)throw new Error("HD private key not initialized");let $=this.#o.derive(this.#$);this.rootAddress=$.privKey.toPublicKey().toAddress()}this.bapId=F(this.rootAddress)}set rootPath(f){if(this.#w){if(this.#$=f,!this.#f)throw new Error("Master private key not initialized");let o=this.#f.deriveChild(this.#f.toPublicKey(),f);this.rootAddress=o.toPublicKey().toAddress(),this.#j=f,this.#z=f}else{let o=f;if(f.split("/").length<5)o=`${Q}${f}`;if(!this.validatePath(o))throw new Error(`invalid signing path given ${o}`);if(this.#$=o,!this.#o)throw new Error("HD private key not initialized");let $=this.#o.derive(o);this.rootAddress=$.pubKey.toAddress(),this.#j=o,this.#z=o}this.bapId=F(this.rootAddress)}get rootPath(){return this.#$}set currentPath(f){if(this.#w)this.#j=this.#z,this.#z=f;else{let o=f;if(f.split("/").length<5)o=`${Q}${f}`;if(!this.validatePath(o))throw new Error("invalid signing path given");this.#j=this.#z,this.#z=o}}get currentPath(){return this.#z}get previousPath(){return this.#j}get idSeed(){return this.#G}validatePath(f){if(f.match(/\/[0-9]{1,10}'?\/[0-9]{1,10}'?\/[0-9]{1,10}'?\/[0-9]{1,10}'?\/[0-9]{1,10}'?\/[0-9]{1,10}'?/)){let o=f.split("/");if(o.length===7&&Number(o[1].replace("'",""))<=J&&Number(o[2].replace("'",""))<=J&&Number(o[3].replace("'",""))<=J&&Number(o[4].replace("'",""))<=J&&Number(o[5].replace("'",""))<=J&&Number(o[6].replace("'",""))<=J)return!0}return!1}import(f){this.bapId="bapId"in f?f.bapId:f.identityKey,this.#$=f.rootPath,this.rootAddress=f.rootAddress,this.#j=f.previousPath,this.#z=f.currentPath,this.#G=("idSeed"in f?f.idSeed:"")||""}export(){return{bapId:this.bapId,rootPath:this.#$,rootAddress:this.rootAddress,previousPath:this.#j,currentPath:this.#z,idSeed:this.#G,lastIdPath:""}}}var{toArray:L,toUTF8:W,toBase64:N,toHex:C}=m,{electrumEncrypt:_,electrumDecrypt:E}=D;class s{#o;#f;#w;#$={};#z=U;#j="";#G="";#J=0;getApiData;constructor(f,o="",$=""){if(!f)throw new Error("No key source given");if(typeof f==="string")this.#o=i.fromString(f),this.#w=!1;else this.#f=I.fromWif(f.rootPk),this.#w=!0;if(o)this.#j=o;if($)this.#z=$;this.getApiData=h(this.#z,this.#j)}get lastIdPath(){return this.#G}getPublicKey(f=""){if(this.#w){if(!this.#f)throw new Error("Master private key not initialized");if(f)return this.#f.deriveChild(this.#f.toPublicKey(),f).toPublicKey().toString();return this.#f.toPublicKey().toString()}if(!this.#o)throw new Error("HD private key not initialized");if(f)return this.#o.derive(f).pubKey.toString();return this.#o.pubKey.toString()}getHdPublicKey(f=""){if(this.#w)throw new Error("HD public keys are not available in Type 42 mode");if(!this.#o)throw new Error("HD private key not initialized");if(f)return this.#o.derive(f).toPublic().toString();return this.#o.toPublic().toString()}set BAP_SERVER(f){this.#z=f}get BAP_SERVER(){return this.#z}set BAP_TOKEN(f){this.#j=f}get BAP_TOKEN(){return this.#j}checkIdBelongs(f){let o;if(this.#w){if(!this.#f)throw new Error("Master private key not initialized");o=this.#f.deriveChild(this.#f.toPublicKey(),f.rootPath).toPublicKey().toAddress()}else{if(!this.#o)throw new Error("HD private key not initialized");o=this.#o.derive(f.rootPath).pubKey.toAddress()}if(o!==f.rootAddress)throw new Error("ID does not belong to this private key");return!0}listIds(){return Object.keys(this.#$)}newId(f,o=""){let $;if(f)$=f;else if(this.#w)$=`bap:${this.#J}`,this.#J++;else $=this.getNextValidPath();let w;if(this.#w){if(!this.#f)throw new Error("Type 42 parameters not initialized");w=new q({rootPk:this.#f},o)}else{if(!this.#o)throw new Error("HD private key not initialized");w=new q(this.#o,o)}if(w.rootPath=$,this.#w)w.currentPath=$;else w.currentPath=Y.getNextPath($);return this.#$[w.bapId]=w,this.#G=$,this.#$[w.bapId]}removeId(f){delete this.#$[f]}getNextValidPath(){if(this.#G)return Y.getNextIdentityPath(this.#G);return`/0'/${Object.keys(this.#$).length}'/0'`}newIdWithCounter(f){if(!this.#w)throw new Error("newIdWithCounter only works in Type 42 mode");return this.newId(`bap:${f}`)}getId(f){return this.#$[f]||null}setId(f){this.checkIdBelongs(f),this.#$[f.bapId]=f}importIds(f,o=!0){if(o&&typeof f==="string"){this.importEncryptedIds(f);return}let $=f;if(!$.lastIdPath)throw new Error("ID cannot be imported as it is not complete");if(!$.ids)throw new Error(`ID data is not in the correct format: ${f}`);let w=$.lastIdPath;for(let z of $.ids){if(!z.rootAddress)throw new Error("ID cannot be imported as it is not complete");let j;if(this.#w){if(!this.#f)throw new Error("Type 42 parameters not initialized");j=new q({rootPk:this.#f},z.idSeed)}else{if(!this.#o)throw new Error("HD private key not initialized");j=new q(this.#o,z.idSeed)}if(j.import(z),w==="")w=j.currentPath;if(this.checkIdBelongs(j),this.#$[j.bapId]=j,this.#w&&j.rootPath.startsWith("bap:")){let G=j.rootPath.split(":");if(G.length>=2){let Z=Number.parseInt(G[1],10);if(!Number.isNaN(Z))this.#J=Math.max(this.#J,Z+1)}}}this.#G=w}importEncryptedIds(f){let o=this.decrypt(f),$=JSON.parse(o);if(Array.isArray($)){this.importOldIds($);return}if(typeof $!=="object")throw new Error("decrypted, but found unrecognized identities format");this.importIds($,!1)}importOldIds(f){for(let o of f){let $;if(this.#w){if(!this.#f)throw new Error("Type 42 parameters not initialized");$=new q({rootPk:this.#f},o.idSeed??"")}else{if(!this.#o)throw new Error("HD private key not initialized");$=new q(this.#o,o.idSeed??"")}$.import(o),this.checkIdBelongs($),this.#$[$.bapId]=$,this.#G=$.currentPath}}exportIds(f,o=!0){let $={lastIdPath:this.#G,ids:[]},w=f||Object.keys(this.#$);for(let z of w){if(!this.#$[z])throw new Error(`Identity ${z} not found`);$.ids.push(this.#$[z].export())}if(o)return this.encrypt(JSON.stringify($));return $}exportId(f,o=!0){let $={lastIdPath:this.#G,ids:[]};if($.ids.push(this.#$[f].export()),o)return this.encrypt(JSON.stringify($));return $}encrypt(f){if(this.#w){if(!this.#f)throw new Error("Master private key not initialized");let $=this.#f.deriveChild(this.#f.toPublicKey(),X);return N(_(L(f),$.toPublicKey()))}if(!this.#o)throw new Error("HD private key not initialized");let o=this.#o.derive(X);return N(_(L(f),o.pubKey))}decrypt(f){if(this.#w){if(!this.#f)throw new Error("Master private key not initialized");let $=this.#f.deriveChild(this.#f.toPublicKey(),X);return W(E(L(f,"base64"),$))}if(!this.#o)throw new Error("HD private key not initialized");let o=this.#o.derive(X);return W(E(L(f,"base64"),o.privKey))}verifyAttestationWithAIP(f){if(!f.every((w)=>Array.isArray(w))||f[0][0]!==r.OP_RETURN||C(f[1])!==O)throw new Error("Not a valid BAP transaction");let o=C(f[7])==="44415441"?5:0,$={type:W(f[2]),hash:C(f[3]),sequence:W(f[4]),signingProtocol:W(f[7+o]),signingAddress:W(f[8+o]),signature:N(f[9+o])};if(o&&f[3]===f[8])$.data=C(f[9]);try{let w=[];for(let z=0;z<6+o;z++)w.push(f[z]);$.verified=this.verifySignature(w.flat(),$.signingAddress,$.signature)}catch{$.verified=!1}return $}verifySignature(f,o,$){let w;if(Array.isArray(f))w=f;else if(Buffer.isBuffer(f))w=[...f];else w=L(f,"utf8");let z=x.fromCompact($,"base64");for(let j=0;j<4;j++)try{let G=z.RecoverPublicKey(j,new K(R.magicHash(w)));if(R.verify(w,z,G)&&G.toAddress()===o)return!0}catch{}return!1}async verifyChallengeSignature(f,o,$,w){if(!this.verifySignature($,o,w))return!1;try{let j=await this.getApiData("/attestation/valid",{idKey:f,address:o,challenge:$,signature:w});return j?.status==="success"&&j?.result?.valid===!0}catch{return!1}}async isValidAttestationTransaction(f){if(this.verifyAttestationWithAIP(f))return this.getApiData("/attestation/valid",{tx:f});return!1}async getIdentityFromAddress(f){return this.getApiData("/identity/validByAddress",{address:f})}async getIdentity(f){return this.getApiData("/identity/get",{idKey:f})}async getAttestationsForHash(f){return this.getApiData("/attestations",{hash:f})}exportForBackup(f,o,$){let z={ids:this.exportIds(),...f&&{label:f},createdAt:new Date().toISOString()};if(this.#w){if(!this.#f)throw new Error("Type 42 parameters not initialized");return{...z,rootPk:this.#f.toWif()}}if(!this.#o)throw new Error("HD private key not initialized");return{...z,xprv:o||this.#o.toString(),mnemonic:$||""}}}export{v as bapIdFromPubkey,F as bapIdFromAddress,q as MasterID,s as BAP};
2
+ import{BSM as l,BigNumber as S,ECIES as T,HD as K,OP as D,Signature as x,PrivateKey as s}from"@bsv/sdk";import{Utils as I}from"@bsv/sdk";var R=async(o,f,w,$)=>{let z=`${w}${o}`;return(await fetch(z,{method:"post",headers:{"Content-type":"application/json; charset=utf-8",token:$,format:"json"},body:JSON.stringify(f)})).json()},n=(o,f)=>async(w,$)=>{return R(w,$,o,f)};import{Utils as _}from"@bsv/sdk";var{toHex:C,toArray:N}=_,c="1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT",u=C(N(c)),k="15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva",y=C(N(k)),M="https://api.1sat.app/1sat/bap",J=2147483647,h="m/424150'/0'/0'",Z=`m/424150'/${J}'/${J}'`;import{Hash as U,HD as v,Utils as g}from"@bsv/sdk";import{Hash as O,PublicKey as B,Utils as i}from"@bsv/sdk";var{toHex:b,toBase58:H}=i;function X(o){let f=b(O.sha256(o,"utf8"));return H(O.ripemd160(f,"hex"))}function r(o){let f=B.fromString(o);return X(f.toAddress())}var F={getRandomBytes(o=32){if(typeof globalThis<"u"&&globalThis.crypto&&globalThis.crypto.getRandomValues){let f=new Uint8Array(o);return globalThis.crypto.getRandomValues(f),f}throw Error("Secure random number generation not available. crypto.getRandomValues() is required for cryptographic operations. This environment may not be suitable for secure key generation.")},getRandomString(o=32){let f=this.getRandomBytes(o);return Array.from(f,(w)=>w.toString(16).padStart(2,"0")).join("")},getSigningPathFromHex(o,f=!0){let w="m",$=o.match(/.{1,8}/g);if(!$)throw Error("Invalid hex string");let z=2147483647;for(let j of $){let G=Number(`0x${j}`);if(G>z)G-=z;w+=`/${G}${f?"'":""}`}return w},getNextIdentityPath(o){let f=o.split("/"),w=f[f.length-2],$=!1;if(w.match("'"))$=!0;let z=(Number(w.replace(/[^0-9]/g,""))+1).toString();return f[f.length-2]=z+($?"'":""),f[f.length-1]=`0${$?"'":""}`,f.join("/")},getNextPath(o){let f=o.match(/^bap:(\d+)(?::(\d+))?$/);if(f){let G=f[1],Q=f[2];if(Q===void 0)return`bap:${G}:1`;return`bap:${G}:${Number(Q)+1}`}if(/^\d+$/.test(o))return(Number(o)+1).toString();if(!o.includes("/"))throw Error(`Unsupported non-BIP32 path: ${o}`);let w=o.split("/"),$=w[w.length-1],z=!1;if($.match("'"))z=!0;let j=(Number($.replace(/[^0-9]/g,""))+1).toString();return w[w.length-1]=j+(z?"'":""),w.join("/")}};class W{#f;#o;#w;#$;#z;#j;#G;rootAddress;bapId;constructor(o,f=""){if(o instanceof v)if(this.#w=!1,f){let w=g.toHex(U.sha256(f,"utf8")),$=F.getSigningPathFromHex(w);this.#f=o.derive($)}else this.#f=o;else if(this.#w=!0,this.#o=o.rootPk,f){let w=g.toHex(U.sha256(f,"utf8"));this.#o=this.#o.deriveChild(this.#o.toPublicKey(),w)}if(this.#G=f,this.#$=`${h}/0/0/0`,this.#j=`${h}/0/0/0`,this.#z=`${h}/0/0/1`,this.#w){if(!this.#o)throw Error("Master private key not initialized");let w=this.#o.deriveChild(this.#o.toPublicKey(),this.#$);this.rootAddress=w.toPublicKey().toAddress()}else{if(!this.#f)throw Error("HD private key not initialized");let w=this.#f.derive(this.#$);this.rootAddress=w.privKey.toPublicKey().toAddress()}this.bapId=X(this.rootAddress)}set rootPath(o){if(this.#w){if(this.#$=o,!this.#o)throw Error("Master private key not initialized");let f=this.#o.deriveChild(this.#o.toPublicKey(),o);this.rootAddress=f.toPublicKey().toAddress(),this.#j=o,this.#z=o}else{let f=o;if(o.split("/").length<5)f=`${h}${o}`;if(!this.validatePath(f))throw Error(`invalid signing path given ${f}`);if(this.#$=f,!this.#f)throw Error("HD private key not initialized");let w=this.#f.derive(f);this.rootAddress=w.pubKey.toAddress(),this.#j=f,this.#z=f}this.bapId=X(this.rootAddress)}get rootPath(){return this.#$}set currentPath(o){if(this.#w)this.#j=this.#z,this.#z=o;else{let f=o;if(o.split("/").length<5)f=`${h}${o}`;if(!this.validatePath(f))throw Error("invalid signing path given");this.#j=this.#z,this.#z=f}}get currentPath(){return this.#z}get previousPath(){return this.#j}get idSeed(){return this.#G}getAccountKey(){if(this.#w){if(!this.#o)throw Error("Master private key not initialized");return this.#o}if(!this.#f)throw Error("HD private key not initialized");return this.#f.privKey}validatePath(o){if(o.match(/\/[0-9]{1,10}'?\/[0-9]{1,10}'?\/[0-9]{1,10}'?\/[0-9]{1,10}'?\/[0-9]{1,10}'?\/[0-9]{1,10}'?/)){let f=o.split("/");if(f.length===7&&Number(f[1].replace("'",""))<=J&&Number(f[2].replace("'",""))<=J&&Number(f[3].replace("'",""))<=J&&Number(f[4].replace("'",""))<=J&&Number(f[5].replace("'",""))<=J&&Number(f[6].replace("'",""))<=J)return!0}return!1}import(o){this.bapId="bapId"in o?o.bapId:o.identityKey,this.#$=o.rootPath,this.rootAddress=o.rootAddress,this.#j=o.previousPath,this.#z=o.currentPath,this.#G=("idSeed"in o?o.idSeed:"")||""}export(){return{bapId:this.bapId,rootPath:this.#$,rootAddress:this.rootAddress,previousPath:this.#j,currentPath:this.#z,idSeed:this.#G,lastIdPath:""}}exportAccountBackup(){return{wif:this.getAccountKey().toWif(),id:this.bapId}}}var{toArray:Y,toUTF8:q,toBase64:L,toHex:A}=I,{electrumEncrypt:V,electrumDecrypt:E}=T;class m{#f;#o;#w;#$={};#z=M;#j="";#G="";#J=0;getApiData;constructor(o,f="",w=""){if(!o)throw Error("No key source given");if(typeof o==="string")this.#f=K.fromString(o),this.#w=!1;else this.#o=s.fromWif(o.rootPk),this.#w=!0;if(f)this.#j=f;if(w)this.#z=w;this.getApiData=n(this.#z,this.#j)}get lastIdPath(){return this.#G}getPublicKey(o=""){if(this.#w){if(!this.#o)throw Error("Master private key not initialized");if(o)return this.#o.deriveChild(this.#o.toPublicKey(),o).toPublicKey().toString();return this.#o.toPublicKey().toString()}if(!this.#f)throw Error("HD private key not initialized");if(o)return this.#f.derive(o).pubKey.toString();return this.#f.pubKey.toString()}getHdPublicKey(o=""){if(this.#w)throw Error("HD public keys are not available in Type 42 mode");if(!this.#f)throw Error("HD private key not initialized");if(o)return this.#f.derive(o).toPublic().toString();return this.#f.toPublic().toString()}set BAP_SERVER(o){this.#z=o}get BAP_SERVER(){return this.#z}set BAP_TOKEN(o){this.#j=o}get BAP_TOKEN(){return this.#j}checkIdBelongs(o){let f;if(this.#w){if(!this.#o)throw Error("Master private key not initialized");f=this.#o.deriveChild(this.#o.toPublicKey(),o.rootPath).toPublicKey().toAddress()}else{if(!this.#f)throw Error("HD private key not initialized");f=this.#f.derive(o.rootPath).pubKey.toAddress()}if(f!==o.rootAddress)throw Error("ID does not belong to this private key");return!0}listIds(){return Object.keys(this.#$)}newId(o,f=""){let w;if(o)w=o;else if(this.#w)w=`bap:${this.#J}`,this.#J++;else w=this.getNextValidPath();let $;if(this.#w){if(!this.#o)throw Error("Type 42 parameters not initialized");$=new W({rootPk:this.#o},f)}else{if(!this.#f)throw Error("HD private key not initialized");$=new W(this.#f,f)}if($.rootPath=w,this.#w)$.currentPath=w;else $.currentPath=F.getNextPath(w);return this.#$[$.bapId]=$,this.#G=w,this.#$[$.bapId]}removeId(o){delete this.#$[o]}getNextValidPath(){if(this.#G)return F.getNextIdentityPath(this.#G);return`/0'/${Object.keys(this.#$).length}'/0'`}newIdWithCounter(o){if(!this.#w)throw Error("newIdWithCounter only works in Type 42 mode");return this.newId(`bap:${o}`)}getId(o){return this.#$[o]||null}setId(o){this.checkIdBelongs(o),this.#$[o.bapId]=o}importIds(o,f=!0){if(f&&typeof o==="string"){this.importEncryptedIds(o);return}let w=o;if(!w.lastIdPath)throw Error("ID cannot be imported as it is not complete");if(!w.ids)throw Error(`ID data is not in the correct format: ${o}`);let $=w.lastIdPath;for(let z of w.ids){if(!z.rootAddress)throw Error("ID cannot be imported as it is not complete");let j;if(this.#w){if(!this.#o)throw Error("Type 42 parameters not initialized");j=new W({rootPk:this.#o},z.idSeed)}else{if(!this.#f)throw Error("HD private key not initialized");j=new W(this.#f,z.idSeed)}if(j.import(z),$==="")$=j.currentPath;if(this.checkIdBelongs(j),this.#$[j.bapId]=j,this.#w&&j.rootPath.startsWith("bap:")){let G=j.rootPath.split(":");if(G.length>=2){let Q=Number.parseInt(G[1],10);if(!Number.isNaN(Q))this.#J=Math.max(this.#J,Q+1)}}}this.#G=$}importEncryptedIds(o){let f=this.decrypt(o),w=JSON.parse(f);if(Array.isArray(w)){this.importOldIds(w);return}if(typeof w!=="object")throw Error("decrypted, but found unrecognized identities format");this.importIds(w,!1)}importOldIds(o){for(let f of o){let w;if(this.#w){if(!this.#o)throw Error("Type 42 parameters not initialized");w=new W({rootPk:this.#o},f.idSeed??"")}else{if(!this.#f)throw Error("HD private key not initialized");w=new W(this.#f,f.idSeed??"")}w.import(f),this.checkIdBelongs(w),this.#$[w.bapId]=w,this.#G=w.currentPath}}exportIds(o,f=!0){let w={lastIdPath:this.#G,ids:[]},$=o||Object.keys(this.#$);for(let z of $){if(!this.#$[z])throw Error(`Identity ${z} not found`);w.ids.push(this.#$[z].export())}if(f)return this.encrypt(JSON.stringify(w));return w}exportId(o,f=!0){let w={lastIdPath:this.#G,ids:[]};if(w.ids.push(this.#$[o].export()),f)return this.encrypt(JSON.stringify(w));return w}encrypt(o){if(this.#w){if(!this.#o)throw Error("Master private key not initialized");let w=this.#o.deriveChild(this.#o.toPublicKey(),Z);return L(V(Y(o),w.toPublicKey()))}if(!this.#f)throw Error("HD private key not initialized");let f=this.#f.derive(Z);return L(V(Y(o),f.pubKey))}decrypt(o){if(this.#w){if(!this.#o)throw Error("Master private key not initialized");let w=this.#o.deriveChild(this.#o.toPublicKey(),Z);return q(E(Y(o,"base64"),w))}if(!this.#f)throw Error("HD private key not initialized");let f=this.#f.derive(Z);return q(E(Y(o,"base64"),f.privKey))}verifyAttestationWithAIP(o){if(!o.every(($)=>Array.isArray($))||o[0][0]!==D.OP_RETURN||A(o[1])!==u)throw Error("Not a valid BAP transaction");let f=A(o[7])==="44415441"?5:0,w={type:q(o[2]),hash:A(o[3]),sequence:q(o[4]),signingProtocol:q(o[7+f]),signingAddress:q(o[8+f]),signature:L(o[9+f])};if(f&&o[3]===o[8])w.data=A(o[9]);try{let $=[];for(let z=0;z<6+f;z++)$.push(o[z]);w.verified=this.verifySignature($.flat(),w.signingAddress,w.signature)}catch{w.verified=!1}return w}verifySignature(o,f,w){let $;if(Array.isArray(o))$=o;else if(Buffer.isBuffer(o))$=[...o];else $=Y(o,"utf8");let z=x.fromCompact(w,"base64");for(let j=0;j<4;j++)try{let G=z.RecoverPublicKey(j,new S(l.magicHash($)));if(l.verify($,z,G)&&G.toAddress()===f)return!0}catch{}return!1}async verifyChallengeSignature(o,f,w,$){if(!this.verifySignature(w,f,$))return!1;try{let j=await this.getApiData("/attestation/valid",{idKey:o,address:f,challenge:w,signature:$});return j?.status==="success"&&j?.result?.valid===!0}catch{return!1}}async isValidAttestationTransaction(o){if(this.verifyAttestationWithAIP(o))return this.getApiData("/attestation/valid",{tx:o});return!1}async getIdentityFromAddress(o){return this.getApiData("/identity/validByAddress",{address:o})}async getIdentity(o){return this.getApiData("/identity/get",{idKey:o})}async getAttestationsForHash(o){return this.getApiData("/attestations",{hash:o})}exportForBackup(o,f,w){let z={ids:this.exportIds(),...o&&{label:o},createdAt:new Date().toISOString()};if(this.#w){if(!this.#o)throw Error("Type 42 parameters not initialized");return{...z,rootPk:this.#o.toWif()}}if(!this.#f)throw Error("HD private key not initialized");return{...z,xprv:f||this.#f.toString(),mnemonic:w||""}}}export{r as bapIdFromPubkey,X as bapIdFromAddress,W as MasterID,m as BAP};
3
3
 
4
- //# debugId=C18906DC4AA2D3B664756E2164756E21
4
+ //# debugId=72AB6104FF4A54F364756E2164756E21