bsv-bap 0.1.7 → 0.1.9

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
@@ -31,6 +31,7 @@ NOTE: All examples in this document use fake identity keys, addresses and signat
31
31
  - [Revoking an attestation](#revoking-an-attestation)
32
32
  - [BAP on the BSV Metanet - PROVISIONAL](#bap-on-the-bsv-metanet---provisional)
33
33
  - [BAP w3c DID - PROVISIONAL](#bap-w3c-did---provisional)
34
+ - [Bitcoin Backup Compatible Export Methods](#bitcoin-backup-compatible-export-methods)
34
35
  - [Extending the protocol](#extending-the-protocol)
35
36
 
36
37
  # TODO
@@ -46,6 +47,15 @@ The design goals:
46
47
  3. Allow for rotation of signing keys without having to change the existing attestations
47
48
  4. Allow for creation of an infinite amount of identities, but still allow for proving of attested attributes between the identities
48
49
 
50
+ ## Library Features
51
+
52
+ This JavaScript/TypeScript implementation of BAP includes:
53
+ - Full protocol implementation for creating and managing identities
54
+ - Hierarchical Deterministic (HD) key derivation
55
+ - ECIES encryption/decryption for secure data transmission
56
+ - Bitcoin-backup compatible export methods for secure identity storage
57
+ - Comprehensive API for attestations, delegations, and identity management
58
+
49
59
  # Protocol
50
60
 
51
61
  The protocol is defined using the [Bitcom](https://bitcom.bitdb.network/) convention. The signing is done using the [AUTHOR IDENTITY Protocol](https://github.com/BitcoinFiles/AUTHOR_IDENTITY_PROTOCOL).
@@ -814,6 +824,136 @@ When keys are rotated to a new signing key the new key can be added to the DID a
814
824
  }
815
825
  ```
816
826
 
827
+ # Bitcoin Backup Compatible Export Methods
828
+
829
+ The BAP library provides export methods that are compatible with the [bitcoin-backup](https://github.com/yourusername/bitcoin-backup) package format. These methods allow you to export master and member identities in a format that can be directly used with bitcoin-backup for secure storage.
830
+
831
+ ## Exporting Master Identity for Backup
832
+
833
+ To export a master identity (BAP instance) in bitcoin-backup compatible format:
834
+
835
+ ```javascript
836
+ const bap = new BAP('xprv...');
837
+
838
+ // Export for backup with optional parameters
839
+ const masterBackup = bap.exportForBackup(
840
+ 'My Identity', // optional label
841
+ undefined, // optional xprv override
842
+ 'word list...' // optional mnemonic
843
+ );
844
+
845
+ console.log(masterBackup);
846
+ // {
847
+ // ids: '...encrypted string...',
848
+ // xprv: 'xprv...',
849
+ // mnemonic: 'word list...',
850
+ // label: 'My Identity',
851
+ // createdAt: '2024-01-20T10:30:00.000Z'
852
+ // }
853
+ ```
854
+
855
+ The exported object contains:
856
+ - `ids`: Encrypted string containing all identity information
857
+ - `xprv`: The HD private key (extended private key)
858
+ - `mnemonic`: BIP39 mnemonic phrase (if provided)
859
+ - `label`: Optional descriptive label
860
+ - `createdAt`: ISO timestamp of when the export was created
861
+
862
+ ## Exporting Member Identity for Backup
863
+
864
+ To export a member identity in bitcoin-backup compatible format:
865
+
866
+ ```javascript
867
+ // Export member from BAP instance
868
+ const memberBackup = bap.exportMemberForBackup(
869
+ 'alice@example.com' // optional label
870
+ );
871
+
872
+ console.log(memberBackup);
873
+ // {
874
+ // wif: 'L1...',
875
+ // id: '...encrypted data...',
876
+ // label: 'alice@example.com',
877
+ // createdAt: '2024-01-20T10:30:00.000Z'
878
+ // }
879
+
880
+ // Or export directly from MemberID instance
881
+ const memberID = new MemberID('L1...');
882
+ const memberBackup = memberID.exportForBackup('Member Label');
883
+ ```
884
+
885
+ The exported object contains:
886
+ - `wif`: Wallet Import Format private key
887
+ - `id`: Encrypted member identity data
888
+ - `label`: Optional descriptive label
889
+ - `createdAt`: ISO timestamp of when the export was created
890
+
891
+ ## Integration with bitcoin-backup
892
+
893
+ These export methods are designed to work seamlessly with the bitcoin-backup package:
894
+
895
+ ```javascript
896
+ import { BAP } from 'bsv-bap';
897
+ import { BackupService } from 'bitcoin-backup';
898
+
899
+ // Initialize services
900
+ const bap = new BAP('xprv...');
901
+ const backupService = new BackupService();
902
+
903
+ // Export and encrypt master backup
904
+ const masterBackup = bap.exportForBackup('Primary Identity');
905
+ const encryptedMaster = await backupService.encryptBapMaster(
906
+ masterBackup,
907
+ 'password123'
908
+ );
909
+
910
+ // Export and encrypt member backup
911
+ const memberBackup = bap.exportMemberForBackup('Work Identity');
912
+ const encryptedMember = await backupService.encryptBapMember(
913
+ memberBackup,
914
+ 'password123'
915
+ );
916
+
917
+ // Store encrypted backups securely
918
+ await storage.save('master-backup.json', encryptedMaster);
919
+ await storage.save('member-backup.json', encryptedMember);
920
+ ```
921
+
922
+ ## Restoring from Backup
923
+
924
+ To restore identities from bitcoin-backup format:
925
+
926
+ ```javascript
927
+ import { BAP, MemberID } from 'bsv-bap';
928
+ import { BackupService } from 'bitcoin-backup';
929
+
930
+ const backupService = new BackupService();
931
+
932
+ // Restore master identity
933
+ const encryptedMaster = await storage.load('master-backup.json');
934
+ const masterData = await backupService.decryptBapMaster(
935
+ encryptedMaster,
936
+ 'password123'
937
+ );
938
+ const bap = BAP.import(masterData.xprv, masterData.ids);
939
+
940
+ // Restore member identity
941
+ const encryptedMember = await storage.load('member-backup.json');
942
+ const memberData = await backupService.decryptBapMember(
943
+ encryptedMember,
944
+ 'password123'
945
+ );
946
+ const memberID = new MemberID(memberData.wif);
947
+ ```
948
+
949
+ ## Security Considerations
950
+
951
+ - Always encrypt backups before storing them
952
+ - Use strong passwords for encryption
953
+ - Store encrypted backups in secure locations
954
+ - Never share unencrypted private keys or mnemonics
955
+ - Consider using hardware security modules for production systems
956
+
817
957
  # Extending the protocol
818
958
 
819
959
  The protocol could be extended for other use cases, by introducing new keywords (next to ATTEST, REVOKE, ID AND ALIAS) or introducing other `urn:bap:...` schemes.
@@ -3,7 +3,7 @@ import type { HD } from "@bsv/sdk";
3
3
  import { type APIFetcher } from "./api";
4
4
  import type { GetAttestationResponse, GetSigningKeysResponse } from "./apiTypes";
5
5
  import type { Identity, IdentityAttributes, OldIdentity, MemberIdentity } from "./interface";
6
- import { MemberID } from './MemberID';
6
+ import { MemberID } from "./MemberID";
7
7
  import { BaseClass } from "./BaseClass";
8
8
  /**
9
9
  * MasterID class
@@ -233,5 +233,13 @@ declare class MasterID extends BaseClass {
233
233
  export(): Identity;
234
234
  exportMemberBackup(): MemberIdentity;
235
235
  newId(): MemberID;
236
+ /**
237
+ * Export member data in bitcoin-backup compatible format
238
+ * @returns Object with wif and encrypted member data
239
+ */
240
+ exportMember(): {
241
+ wif: string;
242
+ encryptedData: string;
243
+ };
236
244
  }
237
245
  export { MasterID };
@@ -12,7 +12,7 @@ export declare class MemberID extends BaseClass {
12
12
  address: string;
13
13
  signature: string;
14
14
  };
15
- signOpReturnWithAIP(opReturn: number[][], _signingPath?: string): number[][];
15
+ signOpReturnWithAIP(opReturn: number[][]): number[][];
16
16
  getPublicKey(): string;
17
17
  import(identity: MemberIdentity): void;
18
18
  static fromMemberIdentity(identity: MemberIdentity): MemberID;
@@ -33,4 +33,15 @@ export declare class MemberID extends BaseClass {
33
33
  * Get the public key for encrypting data for this identity
34
34
  */
35
35
  getEncryptionPublicKey(): string;
36
+ /**
37
+ * Export member data in bitcoin-backup compatible format
38
+ * @param label Optional user-defined label
39
+ * @returns BapMemberBackup compatible object
40
+ */
41
+ exportForBackup(label?: string): {
42
+ wif: string;
43
+ id: string;
44
+ label?: string;
45
+ createdAt: string;
46
+ };
36
47
  }
package/dist/api.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  /**
2
- * Helper function to get attestation from a BAP API server
3
- *
4
- * @param apiUrl
5
- * @param apiData
6
- * @returns {Promise<any>}
7
- */
2
+ * Helper function to get attestation from a BAP API server
3
+ *
4
+ * @param apiUrl
5
+ * @param apiData
6
+ * @returns {Promise<any>}
7
+ */
8
8
  export declare const getApiData: <T>(apiUrl: string, apiData: unknown, server: string, token: string) => Promise<T>;
9
9
  export type APIFetcher = <T>(url: string, data: unknown) => Promise<T>;
10
10
  export declare const apiFetcher: (host: string, token: string) => APIFetcher;
@@ -1,6 +1,6 @@
1
- import type { Organization, Person, WithContext } from 'schema-dts';
1
+ import type { Organization, Person, WithContext } from "schema-dts";
2
2
  export interface APIResponse<T> {
3
- status: 'success' | 'error';
3
+ status: "success" | "error";
4
4
  result?: T;
5
5
  message?: string;
6
6
  }
package/dist/index.d.ts CHANGED
@@ -238,6 +238,32 @@ export declare class BAP {
238
238
  * @param attestationHash
239
239
  */
240
240
  getAttestationsForHash(attestationHash: string): Promise<GetAttestationResponse>;
241
+ /**
242
+ * Export master BAP data in bitcoin-backup compatible format
243
+ * @param label Optional user-defined label
244
+ * @param xprv Extended private key (if not provided, the HDPrivateKey will be used)
245
+ * @param mnemonic BIP39 mnemonic phrase (optional)
246
+ * @returns BapMasterBackup compatible object
247
+ */
248
+ exportForBackup(label?: string, xprv?: string, mnemonic?: string): {
249
+ ids: string;
250
+ xprv: string;
251
+ mnemonic: string;
252
+ label?: string;
253
+ createdAt: string;
254
+ };
255
+ /**
256
+ * Export a specific member ID in bitcoin-backup compatible format
257
+ * @param idKey The key of the identity to export
258
+ * @param label Optional user-defined label
259
+ * @returns BapMemberBackup compatible object
260
+ */
261
+ exportMemberForBackup(idKey: string, label?: string): {
262
+ wif: string;
263
+ id: string;
264
+ label?: string;
265
+ createdAt: string;
266
+ };
241
267
  }
242
268
  export { MasterID, MemberID };
243
- export type { Attestation, Identity, MemberIdentity, IdentityAttributes, PathPrefix };
269
+ export type { Attestation, Identity, MemberIdentity, IdentityAttributes, PathPrefix, };
@@ -1,8 +1,8 @@
1
1
  // @bun
2
- import{BSM as D,BigNumber as Lj,ECIES as wj,HD as Yj,OP as I,Signature as Gj}from"@bsv/sdk";import{Utils as Fj}from"@bsv/sdk";var s=async(j,$,J,q)=>{let z=`${J}${j}`;return(await fetch(z,{method:"post",headers:{"Content-type":"application/json; charset=utf-8",token:q,format:"json"},body:JSON.stringify($)})).json()},R=(j,$)=>async(J,q)=>{return s(J,q,j,$)};import{Utils as r}from"@bsv/sdk";var{toHex:K,toArray:g}=r,X="1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT",m=K(g(X)),M="15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva",fj=K(g(M)),T="https://api.sigmaidentity.com/v1",G=2147483647,O="m/424150'/0'/0'",w=`m/424150'/${G}'/${G}'`;import{BSM as x,Utils as Qj,ECIES as Wj,Hash as U,PublicKey as N,BigNumber as l}from"@bsv/sdk";import{randomBytes as i}from"crypto";var Y={getRandomString(j=32){return i(j).toString("hex")},getSigningPathFromHex(j,$=!0){let J="m",q=j.match(/.{1,8}/g);if(!q)throw new Error("Invalid hex string");let z=2147483647;for(let Q of q){let Z=Number(`0x${Q}`);if(Z>z)Z-=z;J+=`/${Z}${$?"'":""}`}return J},getNextIdentityPath(j){let $=j.split("/"),J=$[$.length-2],q=!1;if(J.match("'"))q=!0;let z=(Number(J.replace(/[^0-9]/g,""))+1).toString();return $[$.length-2]=z+(q?"'":""),$[$.length-1]=`0${q?"'":""}`,$.join("/")},getNextPath(j){let $=j.split("/"),J=$[$.length-1],q=!1;if(J.match("'"))q=!0;let z=(Number(J.replace(/[^0-9]/g,""))+1).toString();return $[$.length-1]=z+(q?"'":""),$.join("/")}};import{BSM as H,Utils as vj,PrivateKey as S,BigNumber as qj}from"@bsv/sdk";import{ECIES as a,Utils as e,OP as A,PublicKey as c}from"@bsv/sdk";var{toArray:C,toUTF8:t,toBase64:jj}=e,{electrumDecrypt:$j,electrumEncrypt:Jj}=a;class V{identityAttributes={};encrypt(j,$){let{privKey:J,pubKey:q}=this.getEncryptionKey(),z=$?c.fromString($):q;return jj(Jj(C(j),z,J))}decrypt(j,$){let{privKey:J}=this.getEncryptionKey(),q=void 0;if($)q=c.fromString($);return t($j(C(j,"base64"),J,q))}signOpReturnWithAIP(j,$){let J=this.getAIPMessageBuffer(j),{address:q,signature:z}=this.signMessage(J.flat(),$);return this.formatAIPOutput(J,q,z)}getAttributes(){return this.identityAttributes}getAttribute(j){if(this.identityAttributes[j])return this.identityAttributes[j];return null}setAttribute(j,$){if(!$)return;if(this.identityAttributes[j])this.updateExistingAttribute(j,$);else this.createNewAttribute(j,$)}unsetAttribute(j){delete this.identityAttributes[j]}addAttribute(j,$,J=""){let q=J;if(!J)q=Y.getRandomString();this.identityAttributes[j]={value:$,nonce:q}}getAttributeUrns(){let j="";for(let $ in this.identityAttributes){let J=this.getAttributeUrn($);if(J)j+=`${J}
2
+ import{BSM as g,BigNumber as Lj,ECIES as wj,HD as Yj,OP as K,Signature as Gj}from"@bsv/sdk";import{Utils as Fj}from"@bsv/sdk";var s=async(j,$,J,q)=>{let z=`${J}${j}`;return(await fetch(z,{method:"post",headers:{"Content-type":"application/json; charset=utf-8",token:q,format:"json"},body:JSON.stringify($)})).json()},x=(j,$)=>async(J,q)=>{return s(J,q,j,$)};import{Utils as r}from"@bsv/sdk";var{toHex:A,toArray:m}=r,X="1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT",c=A(m(X)),M="15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva",kj=A(m(M)),N="https://api.sigmaidentity.com/v1",F=2147483647,f="m/424150'/0'/0'",w=`m/424150'/${F}'/${F}'`;import{BSM as _,Utils as Qj,ECIES as Zj,Hash as U,PublicKey as E,BigNumber as h}from"@bsv/sdk";import{randomBytes as i}from"crypto";var Y={getRandomString(j=32){return i(j).toString("hex")},getSigningPathFromHex(j,$=!0){let J="m",q=j.match(/.{1,8}/g);if(!q)throw new Error("Invalid hex string");let z=2147483647;for(let Q of q){let W=Number(`0x${Q}`);if(W>z)W-=z;J+=`/${W}${$?"'":""}`}return J},getNextIdentityPath(j){let $=j.split("/"),J=$[$.length-2],q=!1;if(J.match("'"))q=!0;let z=(Number(J.replace(/[^0-9]/g,""))+1).toString();return $[$.length-2]=z+(q?"'":""),$[$.length-1]=`0${q?"'":""}`,$.join("/")},getNextPath(j){let $=j.split("/"),J=$[$.length-1],q=!1;if(J.match("'"))q=!0;let z=(Number(J.replace(/[^0-9]/g,""))+1).toString();return $[$.length-1]=z+(q?"'":""),$.join("/")}};import{BSM as H,Utils as Bj,PrivateKey as S,BigNumber as qj}from"@bsv/sdk";import{ECIES as a,Utils as e,OP as l,PublicKey as p}from"@bsv/sdk";var{toArray:C,toUTF8:t,toBase64:jj}=e,{electrumDecrypt:$j,electrumEncrypt:Jj}=a;class V{identityAttributes={};encrypt(j,$){let{privKey:J,pubKey:q}=this.getEncryptionKey(),z=$?p.fromString($):q;return jj(Jj(C(j),z,J))}decrypt(j,$){let{privKey:J}=this.getEncryptionKey(),q=void 0;if($)q=p.fromString($);return t($j(C(j,"base64"),J,q))}signOpReturnWithAIP(j,$){let J=this.getAIPMessageBuffer(j),{address:q,signature:z}=this.signMessage(J.flat(),$);return this.formatAIPOutput(J,q,z)}getAttributes(){return this.identityAttributes}getAttribute(j){if(this.identityAttributes[j])return this.identityAttributes[j];return null}setAttribute(j,$){if(!$)return;if(this.identityAttributes[j])this.updateExistingAttribute(j,$);else this.createNewAttribute(j,$)}unsetAttribute(j){delete this.identityAttributes[j]}addAttribute(j,$,J=""){let q=J;if(!J)q=Y.getRandomString();this.identityAttributes[j]={value:$,nonce:q}}getAttributeUrns(){let j="";for(let $ in this.identityAttributes){let J=this.getAttributeUrn($);if(J)j+=`${J}
3
3
  `}return j}getAttributeUrn(j){let $=this.identityAttributes[j];if($)return`urn:bap:id:${j}:${$.value}:${$.nonce}`;return null}parseStringUrns(j){let $={},J=j.replace(/^\s+/g,"").replace(/\r/gm,"").split(`
4
- `);for(let q of J){let Q=q.replace(/^\s+/g,"").replace(/\s+$/g,"").split(":");if(Q[0]==="urn"&&Q[1]==="bap"&&Q[2]==="id"&&Q[3]&&Q[4]&&Q[5])$[Q[3]]={value:Q[4],nonce:Q[5]}}return $}parseAttributes(j){if(typeof j==="string")return this.parseStringUrns(j);for(let $ in j)if(!j[$].value||!j[$].nonce)throw new Error("Invalid identity attribute");return j||{}}updateExistingAttribute(j,$){if(typeof $==="string"){this.identityAttributes[j].value=$;return}if(this.identityAttributes[j].value=$.value||"",$.nonce)this.identityAttributes[j].nonce=$.nonce}createNewAttribute(j,$){if(typeof $==="string"){this.addAttribute(j,$);return}this.addAttribute(j,$.value||"",$.nonce)}getAIPMessageBuffer(j,$){let J=j.findIndex((z)=>z[0]===A.OP_RETURN),q=[];if(J===-1)q.push([A.OP_RETURN]),J=0;if($)for(let z of $)q.push(j[J+z]);else for(let z of j)q.push(z);if(j.length>0)q.push(C("|"));return q}formatAIPOutput(j,$,J){let q=[C("|"),C(M),C("BITCOIN_ECDSA"),C($),C(J,"base64")];return[...j,...q]}}var{magicHash:zj}=H;class k extends V{key;idName;description;address;identityKey;constructor(j,$={}){super();this.key=j,this.address=j.toAddress(),this.idName="Member ID 1",this.description="",this.identityKey="",this.identityAttributes=this.parseAttributes($)}signMessage(j,$){let J=this.key,q=J.toAddress(),z=H.sign(j,J,"raw"),Q=new qj(zj(j)),Z=z.CalculateRecoveryFactor(J.toPublicKey(),Q),L=H.sign(j,J,"raw").toCompact(Z,!0,"base64");return{address:q,signature:L}}signOpReturnWithAIP(j,$){let J=this.getAIPMessageBuffer(j),{address:q,signature:z}=this.signMessage(J.flat());return this.formatAIPOutput(J,q,z)}getPublicKey(){return this.key.toPublicKey().toString()}import(j){this.idName=j.name,this.description=j.description,this.key=S.fromWif(j.derivedPrivateKey),this.address=this.key.toAddress(),this.identityAttributes=j.identityAttributes||{},this.identityKey=j.identityKey}static fromMemberIdentity(j){let $=new k(S.fromWif(j.derivedPrivateKey));return $.import(j),$}static fromBackup(j){let $=new k(S.fromWif(j.wif)),J=JSON.parse($.decrypt(j.id));return $.import(J),$}export(){return{name:this.idName,description:this.description,derivedPrivateKey:this.key.toWif(),address:this.address,identityAttributes:this.getAttributes(),identityKey:this.identityKey}}getEncryptionKey(){return{privKey:this.key.deriveChild(this.key.toPublicKey(),w),pubKey:this.key.deriveChild(this.key.toPublicKey(),w).toPublicKey()}}getEncryptionPublicKey(){let{pubKey:j}=this.getEncryptionKey();return j.toString()}}var{toArray:F,toHex:f,toBase58:Zj,toUTF8:p,toBase64:b}=Qj,{electrumDecrypt:h,electrumEncrypt:P}=Wj,{magicHash:o}=x;class _ extends V{#j;#J=T;#Q="";#$;#q;#z;#W;idName;description;rootAddress;identityKey;identityAttributes;getApiData;constructor(j,$={},J=""){super();if(J){let Q=f(U.sha256(J,"utf8")),Z=Y.getSigningPathFromHex(Q);this.#j=j.derive(Z)}else this.#j=j;this.#W=J,this.idName="ID 1",this.description="",this.#$=`${O}/0/0/0`,this.#q=`${O}/0/0/0`,this.#z=`${O}/0/0/1`;let q=this.#j.derive(this.#$);this.rootAddress=q.privKey.toPublicKey().toAddress(),this.identityKey=this.deriveIdentityKey(this.rootAddress);let z={...$};this.identityAttributes=this.parseAttributes(z),this.getApiData=R(this.#J,this.#Q)}set BAP_SERVER(j){this.#J=j}get BAP_SERVER(){return this.#J}set BAP_TOKEN(j){this.#Q=j}get BAP_TOKEN(){return this.#Q}deriveIdentityKey(j){let $=f(U.sha256(j,"utf8"));return Zj(U.ripemd160($,"hex"))}parseAttributes(j){if(typeof j==="string")return this.parseStringUrns(j);for(let $ in j)if(!j[$].value||!j[$].nonce)throw new Error("Invalid identity attribute");return j||{}}parseStringUrns(j){let $={},J=j.replace(/^\s+/g,"").replace(/\r/gm,"").split(`
5
- `);for(let q of J){let Q=q.replace(/^\s+/g,"").replace(/\s+$/g,"").split(":");if(Q[0]==="urn"&&Q[1]==="bap"&&Q[2]==="id"&&Q[3]&&Q[4]&&Q[5])$[Q[3]]={value:Q[4],nonce:Q[5]}}return $}getIdentityKey(){return this.identityKey}set rootPath(j){if(this.#j){let $=j;if(j.split("/").length<5)$=`${O}${j}`;if(!this.validatePath($))throw new Error(`invalid signing path given ${$}`);this.#$=$;let J=this.#j.derive($);this.rootAddress=J.pubKey.toAddress(),this.identityKey=this.deriveIdentityKey(this.rootAddress),this.#q=$,this.#z=$}}get rootPath(){return this.#$}getRootPath(){return this.#$}set currentPath(j){let $=j;if(j.split("/").length<5)$=`${O}${j}`;if(!this.validatePath($))throw new Error("invalid signing path given");this.#q=this.#z,this.#z=$}get currentPath(){return this.#z}get previousPath(){return this.#q}get idSeed(){return this.#W}incrementPath(){this.currentPath=Y.getNextPath(this.currentPath)}validatePath(j){if(j.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 $=j.split("/");if($.length===7&&Number($[1].replace("'",""))<=G&&Number($[2].replace("'",""))<=G&&Number($[3].replace("'",""))<=G&&Number($[4].replace("'",""))<=G&&Number($[5].replace("'",""))<=G&&Number($[6].replace("'",""))<=G)return!0}return!1}getInitialIdTransaction(){return this.getIdTransaction(this.#$)}getIdTransaction(j=""){if(this.#z===this.#$)throw new Error("Current path equals rootPath. ID was probably not initialized properly");let $=[F(X),F("ID"),F(this.identityKey),F(this.getCurrentAddress())];return this.signOpReturnWithAIP($,j||this.#q)}getAddress(j){return this.#j.derive(j).privKey.toPublicKey().toAddress()}getCurrentAddress(){return this.getAddress(this.#z)}getEncryptionKey(){let $=this.#j.derive(this.#$).derive(w).privKey;return{privKey:$,pubKey:$.toPublicKey()}}getEncryptionKeyType42(){let j=this.#j.derive(this.#$),$=j.privKey.deriveChild(j.toPublic().pubKey,w);return{privKey:$,pubKey:$.toPublicKey()}}getEncryptionPublicKey(){let{pubKey:j}=this.getEncryptionKey();return j.toString()}getEncryptionPublicKeyWithSeed(j){return this.getEncryptionPrivateKeyWithSeed(j).toPublicKey().toString()}encrypt(j,$){let z=this.#j.derive(this.#$).derive(w).privKey.toPublicKey(),Q=$?N.fromString($):z;return b(P(F(j),Q,null))}decrypt(j,$){let q=this.#j.derive(this.#$).derive(w).privKey,z=void 0;if($)z=N.fromString($);return p(h(F(j,"base64"),q,z))}encryptWithSeed(j,$,J){let q=this.getEncryptionPrivateKeyWithSeed($),z=q.toPublicKey(),Q=J?N.fromString(J):z;return b(P(F(j),Q,q))}decryptWithSeed(j,$,J){let q=this.getEncryptionPrivateKeyWithSeed($),z=void 0;if(J)z=N.fromString(J);return p(h(F(j,"base64"),q,z))}getEncryptionPrivateKeyWithSeed(j){let $=f(U.sha256(j,"utf8")),J=Y.getSigningPathFromHex($);return this.#j.derive(this.#$).derive(J).privKey}getAttestation(j){let $=U.sha256(j,"utf8");return`bap:attest:${f($)}:${this.getIdentityKey()}`}getAttestationHash(j){let $=this.getAttributeUrn(j);if(!$)return null;let J=this.getAttestation($),q=U.sha256(J,"utf8");return f(q)}signMessage(j,$){let J=$||this.#z,q=this.#j.derive(J).privKey,z=q.toAddress(),Q=x.sign(j,q,"raw"),Z=new l(o(j)),L=Q.CalculateRecoveryFactor(q.toPublicKey(),Z),B=x.sign(j,q,"raw").toCompact(L,!0,"base64");return{address:z,signature:B}}signMessageWithSeed(j,$){let J=f(U.sha256($,"utf8")),q=Y.getSigningPathFromHex(J),Q=this.#j.derive(this.#$).derive(q),Z=Q.privKey.toPublicKey().toAddress(),L=F(j,"utf8"),B=x.sign(L,Q.privKey,"raw"),u=new l(o(L)),d=B.CalculateRecoveryFactor(Q.privKey.toPublicKey(),u),n=x.sign(L,Q.privKey,"raw").toCompact(d,!0,"base64");return{address:Z,signature:n}}signOpReturnWithAIP(j,$=""){let J=this.getAIPMessageBuffer(j),{address:q,signature:z}=this.signMessage(J.flat(),$);return this.formatAIPOutput(j,q,z)}async getIdSigningKeys(){let j=await this.getApiData("/signing-keys",{idKey:this.identityKey});return console.log("getIdSigningKeys",j),j}async getAttributeAttestations(j){let $=this.getAttestationHash(j),J=await this.getApiData("/attestation/get",{hash:$});return console.log("getAttestations",j,$,J),J}import(j){this.idName=j.name,this.description=j.description||"",this.identityKey=j.identityKey,this.#$=j.rootPath,this.rootAddress=j.rootAddress,this.#q=j.previousPath,this.#z=j.currentPath,this.#W=("idSeed"in j?j.idSeed:"")||"",this.identityAttributes=this.parseAttributes(j.identityAttributes)}export(){return{name:this.idName,description:this.description,identityKey:this.identityKey,rootPath:this.#$,rootAddress:this.rootAddress,previousPath:this.#q,currentPath:this.#z,idSeed:this.#W,identityAttributes:this.getAttributes(),lastIdPath:""}}exportMemberBackup(){let j=this.#j.derive(this.#z).privKey;return{name:this.idName,description:this.description,derivedPrivateKey:j.toWif(),address:j.toPublicKey().toAddress(),identityAttributes:this.getAttributes(),identityKey:this.identityKey}}newId(){this.incrementPath();let j=this.#j.derive(this.#z).privKey;return new k(j)}}var{toArray:W,toUTF8:E,toBase64:y,toHex:v}=Fj,{electrumEncrypt:Xj,electrumDecrypt:Cj}=wj;class Uj{#j;#J={};#Q=T;#$="";#q="";getApiData;constructor(j,$="",J=""){if(!j)throw new Error("No HDPrivateKey given");if(this.#j=Yj.fromString(j),$)this.#$=$;if(J)this.#Q=J;this.getApiData=R(this.#Q,this.#$)}get lastIdPath(){return this.#q}getPublicKey(j=""){if(j)return this.#j.derive(j).pubKey.toString();return this.#j.pubKey.toString()}getHdPublicKey(j=""){if(j)return this.#j.derive(j).toPublic().toString();return this.#j.toPublic().toString()}set BAP_SERVER(j){this.#Q=j;for(let $ in this.#J)this.#J[$].BAP_SERVER=j}get BAP_SERVER(){return this.#Q}set BAP_TOKEN(j){this.#$=j;for(let $ in this.#J)this.#J[$].BAP_TOKEN=j}get BAP_TOKEN(){return this.#$}checkIdBelongs(j){if(this.#j.derive(j.rootPath).pubKey.toAddress()!==j.rootAddress)throw new Error("ID does not belong to this private key");return!0}listIds(){return Object.keys(this.#J)}newId(j,$={},J=""){let q;if(!j)q=this.getNextValidPath();else q=j;let z=new _(this.#j,$,J);z.BAP_SERVER=this.#Q,z.BAP_TOKEN=this.#$,z.rootPath=q,z.currentPath=Y.getNextPath(q);let Q=z.getIdentityKey();return this.#J[Q]=z,this.#q=q,this.#J[Q]}removeId(j){delete this.#J[j]}getNextValidPath(){if(this.#q)return Y.getNextIdentityPath(this.#q);return`/0'/${Object.keys(this.#J).length}'/0'`}getId(j){return this.#J[j]||null}setId(j){this.checkIdBelongs(j),this.#J[j.getIdentityKey()]=j}importIds(j,$=!0){if($&&typeof j==="string"){this.importEncryptedIds(j);return}let J=j;if(!J.lastIdPath)throw new Error("ID cannot be imported as it is not complete");if(!J.ids)throw new Error(`ID data is not in the correct format: ${j}`);let q=j.lastIdPath;for(let z of J.ids){if(!z.identityKey||!z.identityAttributes||!z.rootAddress)throw new Error("ID cannot be imported as it is not complete");let Q=new _(this.#j,{},z.idSeed);if(Q.BAP_SERVER=this.#Q,Q.BAP_TOKEN=this.#$,Q.import(z),q==="")q=Q.currentPath;this.checkIdBelongs(Q),this.#J[Q.getIdentityKey()]=Q}this.#q=q}importEncryptedIds(j){let $=this.decrypt(j),J=JSON.parse($);if(Array.isArray(J)){console.log(`Importing old format:
6
- `,J),this.importOldIds(J);return}if(typeof J!=="object")throw new Error("decrypted, but found unrecognized identities format");this.importIds(J,!1)}importOldIds(j){for(let $ of j){let J=new _(this.#j,{},$.idSeed??"");J.BAP_SERVER=this.#Q,J.BAP_TOKEN=this.#$,J.import($),this.checkIdBelongs(J),this.#J[J.getIdentityKey()]=J,this.#q=J.currentPath}}exportIds(j,$=!0){let J={lastIdPath:this.#q,ids:[]},q=j||Object.keys(this.#J);for(let z of q){if(!this.#J[z])throw new Error(`Identity ${z} not found`);J.ids.push(this.#J[z].export())}if($)return this.encrypt(JSON.stringify(J));return J}exportId(j,$=!0){let J={lastIdPath:this.#q,ids:[]};if(J.ids.push(this.#J[j].export()),$)return this.encrypt(JSON.stringify(J));return J}encrypt(j){let $=this.#j.derive(w);return y(Xj(W(j),$.pubKey,null))}decrypt(j){let $=this.#j.derive(w);return E(Cj(W(j,"base64"),$.privKey))}signAttestationWithAIP(j,$,J=0,q=""){let z=this.getId($);if(!z)throw new Error("Could not find identity to attest with");let Q=this.getAttestationBuffer(j,J,q),{address:Z,signature:L}=z.signMessage(Q);return this.createAttestationTransaction(j,J,Z,L,q)}verifyAttestationWithAIP(j){if(!j.every((q)=>Array.isArray(q))||j[0][0]!==I.OP_RETURN||v(j[1])!==m)throw new Error("Not a valid BAP transaction");let $=v(j[7])==="44415441"?5:0,J={type:E(j[2]),hash:v(j[3]),sequence:E(j[4]),signingProtocol:E(j[7+$]),signingAddress:E(j[8+$]),signature:y(j[9+$])};if($&&j[3]===j[8])J.data=v(j[9]);console.log({attestation:J});try{let q=[];for(let z=0;z<6+$;z++)q.push(j[z]);J.verified=this.verifySignature(q.flat(),J.signingAddress,J.signature)}catch(q){J.verified=!1}return J}createAttestationTransaction(j,$,J,q,z=""){let Q=[[I.OP_RETURN],W(X),W("ATTEST"),W(j),W(`${$}`),W("|")];if(z)Q.push(W(X),W("DATA"),W(j),W(z),W("|"));return Q.push(W(M),W("BITCOIN_ECDSA"),W(J),W(q,"base64")),console.log({elements:Q}),Q}getAttestationBuffer(j,$=0,J=""){let q=[[I.OP_RETURN],W(X),W("ATTEST"),W(j),W(`${$}`),W("|")];if(J)q.push(W(X),W("DATA"),W(j),W(J),W("|"));return q.flat()}verifySignature(j,$,J){let q;if(Array.isArray(j))q=j;else if(Buffer.isBuffer(j))q=[...j];else q=W(j,"utf8");let z=Gj.fromCompact(J,"base64"),Q;for(let Z=0;Z<4;Z++)try{if(Q=z.RecoverPublicKey(Z,new Lj(D.magicHash(q))),D.verify(q,z,Q)&&Q.toAddress()===$)return!0}catch(L){}return!1}async verifyChallengeSignature(j,$,J,q){if(!this.verifySignature(J,$,q))return!1;try{let Q=await this.getApiData("/attestation/valid",{idKey:j,address:$,challenge:J,signature:q});if(Q?.status==="success"&&Q?.result?.valid===!0)return!0;return!1}catch(Q){return console.error("API call failed:",Q),!1}}async isValidAttestationTransaction(j){if(this.verifyAttestationWithAIP(j))return this.getApiData("/attestation/valid",{tx:j});return!1}async getIdentityFromAddress(j){return this.getApiData("/identity/from-address",{address:j})}async getIdentity(j){return this.getApiData("/identity/get",{idKey:j})}async getAttestationsForHash(j){return this.getApiData("/attestations",{hash:j})}}export{k as MemberID,_ as MasterID,Uj as BAP};
4
+ `);for(let q of J){let Q=q.replace(/^\s+/g,"").replace(/\s+$/g,"").split(":");if(Q[0]==="urn"&&Q[1]==="bap"&&Q[2]==="id"&&Q[3]&&Q[4]&&Q[5])$[Q[3]]={value:Q[4],nonce:Q[5]}}return $}parseAttributes(j){if(typeof j==="string")return this.parseStringUrns(j);for(let $ in j)if(!j[$].value||!j[$].nonce)throw new Error("Invalid identity attribute");return j||{}}updateExistingAttribute(j,$){if(typeof $==="string"){this.identityAttributes[j].value=$;return}if(this.identityAttributes[j].value=$.value||"",$.nonce)this.identityAttributes[j].nonce=$.nonce}createNewAttribute(j,$){if(typeof $==="string"){this.addAttribute(j,$);return}this.addAttribute(j,$.value||"",$.nonce)}getAIPMessageBuffer(j,$){let J=j.findIndex((z)=>z[0]===l.OP_RETURN),q=[];if(J===-1)q.push([l.OP_RETURN]),J=0;if($)for(let z of $)q.push(j[J+z]);else for(let z of j)q.push(z);return q}formatAIPOutput(j,$,J){let q=[C("|"),C(M),C("BITCOIN_ECDSA"),C($),C(J,"base64")];return[...j,...q]}}var{magicHash:zj}=H;class O extends V{key;idName;description;address;identityKey;constructor(j,$={}){super();this.key=j,this.address=j.toAddress(),this.idName="Member ID 1",this.description="",this.identityKey="",this.identityAttributes=this.parseAttributes($)}signMessage(j,$){let J=this.key,q=J.toAddress(),z=H.sign(j,J,"raw"),Q=new qj(zj(j)),W=z.CalculateRecoveryFactor(J.toPublicKey(),Q),L=H.sign(j,J,"raw").toCompact(W,!0,"base64");return{address:q,signature:L}}signOpReturnWithAIP(j){let $=this.getAIPMessageBuffer(j),{address:J,signature:q}=this.signMessage($.flat());return this.formatAIPOutput($,J,q)}getPublicKey(){return this.key.toPublicKey().toString()}import(j){this.idName=j.name,this.description=j.description,this.key=S.fromWif(j.derivedPrivateKey),this.address=this.key.toAddress(),this.identityAttributes=j.identityAttributes||{},this.identityKey=j.identityKey}static fromMemberIdentity(j){let $=new O(S.fromWif(j.derivedPrivateKey));return $.import(j),$}static fromBackup(j){let $=new O(S.fromWif(j.wif)),J=JSON.parse($.decrypt(j.id));return $.import(J),$}export(){return{name:this.idName,description:this.description,derivedPrivateKey:this.key.toWif(),address:this.address,identityAttributes:this.getAttributes(),identityKey:this.identityKey}}getEncryptionKey(){return{privKey:this.key.deriveChild(this.key.toPublicKey(),w),pubKey:this.key.deriveChild(this.key.toPublicKey(),w).toPublicKey()}}getEncryptionPublicKey(){let{pubKey:j}=this.getEncryptionKey();return j.toString()}exportForBackup(j){let $=this.export(),J=this.encrypt(JSON.stringify($));return{wif:this.key.toWif(),id:J,...j&&{label:j},createdAt:new Date().toISOString()}}}var{toArray:G,toHex:k,toBase58:Wj,toUTF8:b,toBase64:D}=Qj,{electrumDecrypt:P,electrumEncrypt:I}=Zj,{magicHash:o}=_;class R extends V{#j;#J=N;#Q="";#$;#q;#z;#Z;idName;description;rootAddress;identityKey;identityAttributes;getApiData;constructor(j,$={},J=""){super();if(J){let Q=k(U.sha256(J,"utf8")),W=Y.getSigningPathFromHex(Q);this.#j=j.derive(W)}else this.#j=j;this.#Z=J,this.idName="ID 1",this.description="",this.#$=`${f}/0/0/0`,this.#q=`${f}/0/0/0`,this.#z=`${f}/0/0/1`;let q=this.#j.derive(this.#$);this.rootAddress=q.privKey.toPublicKey().toAddress(),this.identityKey=this.deriveIdentityKey(this.rootAddress);let z={...$};this.identityAttributes=this.parseAttributes(z),this.getApiData=x(this.#J,this.#Q)}set BAP_SERVER(j){this.#J=j}get BAP_SERVER(){return this.#J}set BAP_TOKEN(j){this.#Q=j}get BAP_TOKEN(){return this.#Q}deriveIdentityKey(j){let $=k(U.sha256(j,"utf8"));return Wj(U.ripemd160($,"hex"))}parseAttributes(j){if(typeof j==="string")return this.parseStringUrns(j);for(let $ in j)if(!j[$].value||!j[$].nonce)throw new Error("Invalid identity attribute");return j||{}}parseStringUrns(j){let $={},J=j.replace(/^\s+/g,"").replace(/\r/gm,"").split(`
5
+ `);for(let q of J){let Q=q.replace(/^\s+/g,"").replace(/\s+$/g,"").split(":");if(Q[0]==="urn"&&Q[1]==="bap"&&Q[2]==="id"&&Q[3]&&Q[4]&&Q[5])$[Q[3]]={value:Q[4],nonce:Q[5]}}return $}getIdentityKey(){return this.identityKey}set rootPath(j){if(this.#j){let $=j;if(j.split("/").length<5)$=`${f}${j}`;if(!this.validatePath($))throw new Error(`invalid signing path given ${$}`);this.#$=$;let J=this.#j.derive($);this.rootAddress=J.pubKey.toAddress(),this.identityKey=this.deriveIdentityKey(this.rootAddress),this.#q=$,this.#z=$}}get rootPath(){return this.#$}getRootPath(){return this.#$}set currentPath(j){let $=j;if(j.split("/").length<5)$=`${f}${j}`;if(!this.validatePath($))throw new Error("invalid signing path given");this.#q=this.#z,this.#z=$}get currentPath(){return this.#z}get previousPath(){return this.#q}get idSeed(){return this.#Z}incrementPath(){this.currentPath=Y.getNextPath(this.currentPath)}validatePath(j){if(j.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 $=j.split("/");if($.length===7&&Number($[1].replace("'",""))<=F&&Number($[2].replace("'",""))<=F&&Number($[3].replace("'",""))<=F&&Number($[4].replace("'",""))<=F&&Number($[5].replace("'",""))<=F&&Number($[6].replace("'",""))<=F)return!0}return!1}getInitialIdTransaction(){return this.getIdTransaction(this.#$)}getIdTransaction(j=""){if(this.#z===this.#$)throw new Error("Current path equals rootPath. ID was probably not initialized properly");let $=[G(X),G("ID"),G(this.identityKey),G(this.getCurrentAddress())];return this.signOpReturnWithAIP($,j||this.#q)}getAddress(j){return this.#j.derive(j).privKey.toPublicKey().toAddress()}getCurrentAddress(){return this.getAddress(this.#z)}getEncryptionKey(){let $=this.#j.derive(this.#$).derive(w).privKey;return{privKey:$,pubKey:$.toPublicKey()}}getEncryptionKeyType42(){let j=this.#j.derive(this.#$),$=j.privKey.deriveChild(j.toPublic().pubKey,w);return{privKey:$,pubKey:$.toPublicKey()}}getEncryptionPublicKey(){let{pubKey:j}=this.getEncryptionKey();return j.toString()}getEncryptionPublicKeyWithSeed(j){return this.getEncryptionPrivateKeyWithSeed(j).toPublicKey().toString()}encrypt(j,$){let z=this.#j.derive(this.#$).derive(w).privKey.toPublicKey(),Q=$?E.fromString($):z;return D(I(G(j),Q,null))}decrypt(j,$){let q=this.#j.derive(this.#$).derive(w).privKey,z=void 0;if($)z=E.fromString($);return b(P(G(j,"base64"),q,z))}encryptWithSeed(j,$,J){let q=this.getEncryptionPrivateKeyWithSeed($),z=q.toPublicKey(),Q=J?E.fromString(J):z;return D(I(G(j),Q,q))}decryptWithSeed(j,$,J){let q=this.getEncryptionPrivateKeyWithSeed($),z=void 0;if(J)z=E.fromString(J);return b(P(G(j,"base64"),q,z))}getEncryptionPrivateKeyWithSeed(j){let $=k(U.sha256(j,"utf8")),J=Y.getSigningPathFromHex($);return this.#j.derive(this.#$).derive(J).privKey}getAttestation(j){let $=U.sha256(j,"utf8");return`bap:attest:${k($)}:${this.getIdentityKey()}`}getAttestationHash(j){let $=this.getAttributeUrn(j);if(!$)return null;let J=this.getAttestation($),q=U.sha256(J,"utf8");return k(q)}signMessage(j,$){let J=$||this.#z,q=this.#j.derive(J).privKey,z=q.toAddress(),Q=_.sign(j,q,"raw"),W=new h(o(j)),L=Q.CalculateRecoveryFactor(q.toPublicKey(),W),v=_.sign(j,q,"raw").toCompact(L,!0,"base64");return{address:z,signature:v}}signMessageWithSeed(j,$){let J=k(U.sha256($,"utf8")),q=Y.getSigningPathFromHex(J),Q=this.#j.derive(this.#$).derive(q),W=Q.privKey.toPublicKey().toAddress(),L=G(j,"utf8"),v=_.sign(L,Q.privKey,"raw"),u=new h(o(L)),n=v.CalculateRecoveryFactor(Q.privKey.toPublicKey(),u),d=_.sign(L,Q.privKey,"raw").toCompact(n,!0,"base64");return{address:W,signature:d}}signOpReturnWithAIP(j,$=""){let J=this.getAIPMessageBuffer(j),{address:q,signature:z}=this.signMessage(J.flat(),$);return this.formatAIPOutput(j,q,z)}async getIdSigningKeys(){let j=await this.getApiData("/signing-keys",{idKey:this.identityKey});return console.log("getIdSigningKeys",j),j}async getAttributeAttestations(j){let $=this.getAttestationHash(j),J=await this.getApiData("/attestation/get",{hash:$});return console.log("getAttestations",j,$,J),J}import(j){this.idName=j.name,this.description=j.description||"",this.identityKey=j.identityKey,this.#$=j.rootPath,this.rootAddress=j.rootAddress,this.#q=j.previousPath,this.#z=j.currentPath,this.#Z=("idSeed"in j?j.idSeed:"")||"",this.identityAttributes=this.parseAttributes(j.identityAttributes)}export(){return{name:this.idName,description:this.description,identityKey:this.identityKey,rootPath:this.#$,rootAddress:this.rootAddress,previousPath:this.#q,currentPath:this.#z,idSeed:this.#Z,identityAttributes:this.getAttributes(),lastIdPath:""}}exportMemberBackup(){let j=this.#j.derive(this.#z).privKey;return{name:this.idName,description:this.description,derivedPrivateKey:j.toWif(),address:j.toPublicKey().toAddress(),identityAttributes:this.getAttributes(),identityKey:this.identityKey}}newId(){this.incrementPath();let j=this.#j.derive(this.#z).privKey;return new O(j)}exportMember(){let j=this.exportMemberBackup(),$=this.#j.derive(this.#z).privKey,J=D(I(G(JSON.stringify(j)),$.toPublicKey()));return{wif:j.derivedPrivateKey,encryptedData:J}}}var{toArray:Z,toUTF8:T,toBase64:y,toHex:B}=Fj,{electrumEncrypt:Xj,electrumDecrypt:Cj}=wj;class Uj{#j;#J={};#Q=N;#$="";#q="";getApiData;constructor(j,$="",J=""){if(!j)throw new Error("No HDPrivateKey given");if(this.#j=Yj.fromString(j),$)this.#$=$;if(J)this.#Q=J;this.getApiData=x(this.#Q,this.#$)}get lastIdPath(){return this.#q}getPublicKey(j=""){if(j)return this.#j.derive(j).pubKey.toString();return this.#j.pubKey.toString()}getHdPublicKey(j=""){if(j)return this.#j.derive(j).toPublic().toString();return this.#j.toPublic().toString()}set BAP_SERVER(j){this.#Q=j;for(let $ in this.#J)this.#J[$].BAP_SERVER=j}get BAP_SERVER(){return this.#Q}set BAP_TOKEN(j){this.#$=j;for(let $ in this.#J)this.#J[$].BAP_TOKEN=j}get BAP_TOKEN(){return this.#$}checkIdBelongs(j){if(this.#j.derive(j.rootPath).pubKey.toAddress()!==j.rootAddress)throw new Error("ID does not belong to this private key");return!0}listIds(){return Object.keys(this.#J)}newId(j,$={},J=""){let q;if(!j)q=this.getNextValidPath();else q=j;let z=new R(this.#j,$,J);z.BAP_SERVER=this.#Q,z.BAP_TOKEN=this.#$,z.rootPath=q,z.currentPath=Y.getNextPath(q);let Q=z.getIdentityKey();return this.#J[Q]=z,this.#q=q,this.#J[Q]}removeId(j){delete this.#J[j]}getNextValidPath(){if(this.#q)return Y.getNextIdentityPath(this.#q);return`/0'/${Object.keys(this.#J).length}'/0'`}getId(j){return this.#J[j]||null}setId(j){this.checkIdBelongs(j),this.#J[j.getIdentityKey()]=j}importIds(j,$=!0){if($&&typeof j==="string"){this.importEncryptedIds(j);return}let J=j;if(!J.lastIdPath)throw new Error("ID cannot be imported as it is not complete");if(!J.ids)throw new Error(`ID data is not in the correct format: ${j}`);let q=j.lastIdPath;for(let z of J.ids){if(!z.identityKey||!z.identityAttributes||!z.rootAddress)throw new Error("ID cannot be imported as it is not complete");let Q=new R(this.#j,{},z.idSeed);if(Q.BAP_SERVER=this.#Q,Q.BAP_TOKEN=this.#$,Q.import(z),q==="")q=Q.currentPath;this.checkIdBelongs(Q),this.#J[Q.getIdentityKey()]=Q}this.#q=q}importEncryptedIds(j){let $=this.decrypt(j),J=JSON.parse($);if(Array.isArray(J)){console.log(`Importing old format:
6
+ `,J),this.importOldIds(J);return}if(typeof J!=="object")throw new Error("decrypted, but found unrecognized identities format");this.importIds(J,!1)}importOldIds(j){for(let $ of j){let J=new R(this.#j,{},$.idSeed??"");J.BAP_SERVER=this.#Q,J.BAP_TOKEN=this.#$,J.import($),this.checkIdBelongs(J),this.#J[J.getIdentityKey()]=J,this.#q=J.currentPath}}exportIds(j,$=!0){let J={lastIdPath:this.#q,ids:[]},q=j||Object.keys(this.#J);for(let z of q){if(!this.#J[z])throw new Error(`Identity ${z} not found`);J.ids.push(this.#J[z].export())}if($)return this.encrypt(JSON.stringify(J));return J}exportId(j,$=!0){let J={lastIdPath:this.#q,ids:[]};if(J.ids.push(this.#J[j].export()),$)return this.encrypt(JSON.stringify(J));return J}encrypt(j){let $=this.#j.derive(w);return y(Xj(Z(j),$.pubKey,null))}decrypt(j){let $=this.#j.derive(w);return T(Cj(Z(j,"base64"),$.privKey))}signAttestationWithAIP(j,$,J=0,q=""){let z=this.getId($);if(!z)throw new Error("Could not find identity to attest with");let Q=this.getAttestationBuffer(j,J,q),{address:W,signature:L}=z.signMessage(Q);return this.createAttestationTransaction(j,J,W,L,q)}verifyAttestationWithAIP(j){if(!j.every((q)=>Array.isArray(q))||j[0][0]!==K.OP_RETURN||B(j[1])!==c)throw new Error("Not a valid BAP transaction");let $=B(j[7])==="44415441"?5:0,J={type:T(j[2]),hash:B(j[3]),sequence:T(j[4]),signingProtocol:T(j[7+$]),signingAddress:T(j[8+$]),signature:y(j[9+$])};if($&&j[3]===j[8])J.data=B(j[9]);console.log({attestation:J});try{let q=[];for(let z=0;z<6+$;z++)q.push(j[z]);J.verified=this.verifySignature(q.flat(),J.signingAddress,J.signature)}catch(q){J.verified=!1}return J}createAttestationTransaction(j,$,J,q,z=""){let Q=[[K.OP_RETURN],Z(X),Z("ATTEST"),Z(j),Z(`${$}`),Z("|")];if(z)Q.push(Z(X),Z("DATA"),Z(j),Z(z),Z("|"));return Q.push(Z(M),Z("BITCOIN_ECDSA"),Z(J),Z(q,"base64")),console.log({elements:Q}),Q}getAttestationBuffer(j,$=0,J=""){let q=[[K.OP_RETURN],Z(X),Z("ATTEST"),Z(j),Z(`${$}`),Z("|")];if(J)q.push(Z(X),Z("DATA"),Z(j),Z(J),Z("|"));return q.flat()}verifySignature(j,$,J){let q;if(Array.isArray(j))q=j;else if(Buffer.isBuffer(j))q=[...j];else q=Z(j,"utf8");let z=Gj.fromCompact(J,"base64"),Q;for(let W=0;W<4;W++)try{if(Q=z.RecoverPublicKey(W,new Lj(g.magicHash(q))),g.verify(q,z,Q)&&Q.toAddress()===$)return!0}catch(L){}return!1}async verifyChallengeSignature(j,$,J,q){if(!this.verifySignature(J,$,q))return!1;try{let Q=await this.getApiData("/attestation/valid",{idKey:j,address:$,challenge:J,signature:q});if(Q?.status==="success"&&Q?.result?.valid===!0)return!0;return!1}catch(Q){return console.error("API call failed:",Q),!1}}async isValidAttestationTransaction(j){if(this.verifyAttestationWithAIP(j))return this.getApiData("/attestation/valid",{tx:j});return!1}async getIdentityFromAddress(j){return this.getApiData("/identity/from-address",{address:j})}async getIdentity(j){return this.getApiData("/identity/get",{idKey:j})}async getAttestationsForHash(j){return this.getApiData("/attestations",{hash:j})}exportForBackup(j,$,J){return{ids:this.exportIds(),xprv:$||this.#j.toString(),mnemonic:J||"",...j&&{label:j},createdAt:new Date().toISOString()}}exportMemberForBackup(j,$){let J=this.#J[j];if(!J)throw new Error(`Identity ${j} not found`);let q=J.exportMember();return{wif:q.wif,id:q.encryptedData,...$&&{label:$},createdAt:new Date().toISOString()}}}export{O as MemberID,R as MasterID,Uj as BAP};
7
7
 
8
- //# debugId=ED087CE3E921C45564756E2164756E21
8
+ //# debugId=1F3C2BE0F86889F964756E2164756E21