bsv-bap 0.1.17 → 0.1.18
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/package.json +1 -1
- package/src/cli.ts +0 -0
- package/dist/index.cjs +0 -8
- package/src/README.md +0 -583
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
File without changes
|
package/dist/index.cjs
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// @bun @bun-cjs
|
|
2
|
-
(function(exports, require, module, __filename, __dirname) {var{defineProperty:v,getOwnPropertyNames:r,getOwnPropertyDescriptor:a}=Object,e=Object.prototype.hasOwnProperty;var K=new WeakMap,t=(j)=>{var J=K.get(j),$;if(J)return J;if(J=v({},"__esModule",{value:!0}),j&&typeof j==="object"||typeof j==="function")r(j).map((q)=>!e.call(J,q)&&v(J,q,{get:()=>j[q],enumerable:!($=a(j,q))||$.enumerable}));return K.set(j,J),J};var jj=(j,J)=>{for(var $ in J)v(j,$,{get:J[$],enumerable:!0,configurable:!0,set:(q)=>J[$]=()=>q})};var Fj={};jj(Fj,{MemberID:()=>x,MasterID:()=>V,BAP:()=>i});module.exports=t(Fj);var L=require("@bsv/sdk"),s=require("@bsv/sdk");var Jj=async(j,J,$,q)=>{let z=`${$}${j}`;return(await fetch(z,{method:"post",headers:{"Content-type":"application/json; charset=utf-8",token:q,format:"json"},body:JSON.stringify(J)})).json()},N=(j,J)=>async($,q)=>{return Jj($,q,j,J)};var m=require("@bsv/sdk"),{toHex:c,toArray:b}=m.Utils,k="1BAPSuaPnfGnSBM3GLV9yhxUdYe4vGbdMT",p=c(b(k)),E="15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva",Uj=c(b(E)),S="https://api.sigmaidentity.com/v1",M=2147483647,R="m/424150'/0'/0'",F=`m/424150'/${M}'/${M}'`;var H="1-bap-identity",h=2,P="friend";var w=require("@bsv/sdk");var U={getRandomBytes(j=32){if(typeof globalThis<"u"&&globalThis.crypto&&globalThis.crypto.getRandomValues){let J=new Uint8Array(j);return globalThis.crypto.getRandomValues(J),J}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(j=32){let J=this.getRandomBytes(j);return Array.from(J,($)=>$.toString(16).padStart(2,"0")).join("")},getSigningPathFromHex(j,J=!0){let $="m",q=j.match(/.{1,8}/g);if(!q)throw Error("Invalid hex string");let z=2147483647;for(let Q of q){let W=Number(`0x${Q}`);if(W>z)W-=z;$+=`/${W}${J?"'":""}`}return $},getNextIdentityPath(j){let J=j.split("/"),$=J[J.length-2],q=!1;if($.match("'"))q=!0;let z=(Number($.replace(/[^0-9]/g,""))+1).toString();return J[J.length-2]=z+(q?"'":""),J[J.length-1]=`0${q?"'":""}`,J.join("/")},getNextPath(j){let J=j.split("/"),$=J[J.length-1],q=!1;if($.match("'"))q=!0;let z=(Number($.replace(/[^0-9]/g,""))+1).toString();return J[J.length-1]=z+(q?"'":""),J.join("/")}};var f=require("@bsv/sdk");var Y=require("@bsv/sdk");var{toArray:O,toUTF8:$j,toBase64:qj}=Y.Utils,{magicHash:zj}=Y.BSM,{electrumDecrypt:Qj,electrumEncrypt:Zj}=Y.ECIES;class T{identityAttributes={};signWithBSM(j,J){let $=J.toPublicKey().toAddress(),q=Y.BSM.sign(j,J,"raw"),z=new Y.BigNumber(zj(j)),Q=q.CalculateRecoveryFactor(J.toPublicKey(),z),W=Y.BSM.sign(j,J,"raw").toCompact(Q,!0,"base64");return{address:$,signature:W}}encrypt(j,J){let{privKey:$,pubKey:q}=this.getEncryptionKey(),z=J?Y.PublicKey.fromString(J):q;return qj(Zj(O(j),z,$))}decrypt(j,J){let{privKey:$}=this.getEncryptionKey(),q;if(J)q=Y.PublicKey.fromString(J);return $j(Qj(O(j,"base64"),$,q))}signOpReturnWithAIP(j,J){let $=this.getAIPMessageBuffer(j),{address:q,signature:z}=this.signMessage($.flat(),J);return this.formatAIPOutput($,q,z)}getAttributes(){return this.identityAttributes}getAttribute(j){if(this.identityAttributes[j])return this.identityAttributes[j];return null}setAttribute(j,J){if(!J)return;if(this.identityAttributes[j])this.updateExistingAttribute(j,J);else this.createNewAttribute(j,J)}unsetAttribute(j){delete this.identityAttributes[j]}addAttribute(j,J,$=""){let q=$;if(!$)q=U.getRandomString();this.identityAttributes[j]={value:J,nonce:q}}getAttributeUrns(){let j="";for(let J in this.identityAttributes){let $=this.getAttributeUrn(J);if($)j+=`${$}
|
|
3
|
-
`}return j}getAttributeUrn(j){let J=this.identityAttributes[j];if(J)return`urn:bap:id:${j}:${J.value}:${J.nonce}`;return null}parseStringUrns(j){let J={},$=j.replace(/^\s+/g,"").replace(/\r/gm,"").split(`
|
|
4
|
-
`);for(let q of $){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])J[Q[3]]={value:Q[4],nonce:Q[5]}}return J}parseAttributes(j){if(typeof j==="string")return this.parseStringUrns(j);for(let J in j)if(!j[J].value||!j[J].nonce)throw Error("Invalid identity attribute");return j||{}}updateExistingAttribute(j,J){if(typeof J==="string"){this.identityAttributes[j].value=J;return}if(this.identityAttributes[j].value=J.value||"",J.nonce)this.identityAttributes[j].nonce=J.nonce}createNewAttribute(j,J){if(typeof J==="string"){this.addAttribute(j,J);return}this.addAttribute(j,J.value||"",J.nonce)}getAIPMessageBuffer(j,J){let $=j.findIndex((z)=>z[0]===Y.OP.OP_RETURN),q=[];if($===-1)q.push([Y.OP.OP_RETURN]),$=0;if(J)for(let z of J)q.push(j[$+z]);else for(let z of j)q.push(z);return q}formatAIPOutput(j,J,$){let q=[O("|"),O(E),O("BITCOIN_ECDSA"),O(J),O($,"base64")];return[...j,...q]}}var{toArray:o,toUTF8:Wj,toBase64:wj,toHex:Lj}=f.Utils,{electrumDecrypt:Yj,electrumEncrypt:Gj}=f.ECIES;class x extends T{key;idName;description;address;identityKey;constructor(j,J={}){super();this.key=j,this.address=this.getIdentitySigningKey().toPublicKey().toAddress(),this.idName="Member ID 1",this.description="",this.identityKey="",this.identityAttributes=this.parseAttributes(J)}getIdentitySigningKey(){return this.key.deriveChild(this.key.toPublicKey(),H)}getMemberKey(){return this.key.toPublicKey().toString()}getLegacyAddress(){return this.key.toPublicKey().toAddress()}signMessage(j,J){let $=this.getIdentitySigningKey();return this.signWithBSM(j,$)}signOpReturnWithAIP(j){let J=this.getAIPMessageBuffer(j),{address:$,signature:q}=this.signMessage(J.flat());return this.formatAIPOutput(J,$,q)}getPublicKey(){return this.getIdentitySigningKey().toPublicKey().toString()}import(j){this.idName=j.name,this.description=j.description,this.key=f.PrivateKey.fromWif(j.derivedPrivateKey),this.address=this.getIdentitySigningKey().toPublicKey().toAddress(),this.identityAttributes=j.identityAttributes||{},this.identityKey=j.identityKey}static fromMemberIdentity(j){let J=new x(f.PrivateKey.fromWif(j.derivedPrivateKey));return J.import(j),J}static fromBackup(j){let J=new x(f.PrivateKey.fromWif(j.wif)),$=JSON.parse(J.decrypt(j.id));return J.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(),F),pubKey:this.key.deriveChild(this.key.toPublicKey(),F).toPublicKey()}}getEncryptionPublicKey(){let{pubKey:j}=this.getEncryptionKey();return j.toString()}getEncryptionPrivateKeyWithSeed(j){let J=Lj(f.Hash.sha256(j,"utf8")),$=`${h}-${P}-${J}`;return this.key.deriveChild(this.key.toPublicKey(),$)}getEncryptionKeyWithSeed(j){let J=this.getEncryptionPrivateKeyWithSeed(j);return{privKey:J,pubKey:J.toPublicKey()}}getEncryptionPublicKeyWithSeed(j){return this.getEncryptionPrivateKeyWithSeed(j).toPublicKey().toString()}encryptWithSeed(j,J,$){let q=this.getEncryptionPrivateKeyWithSeed(J),z=q.toPublicKey(),Q=this.key.toPublicKey().constructor,W=$?Q.fromString($):z;return wj(Gj(o(j),W,q))}decryptWithSeed(j,J,$){let q=this.getEncryptionPrivateKeyWithSeed(J),z;if($)z=f.PublicKey.fromString($);return Wj(Yj(o(j,"base64"),q,z))}exportForBackup(j){let J=this.export(),$=this.encrypt(JSON.stringify(J));return{wif:this.key.toWif(),id:$,...j&&{label:j},createdAt:new Date().toISOString()}}}var{toArray:X,toHex:_,toBase58:Xj,toUTF8:u,toBase64:I}=w.Utils,{electrumDecrypt:d,electrumEncrypt:g}=w.ECIES;class V extends T{#J;#j;#q;#Q=S;#W="";#$;#Z;#z;#w;idName;description;rootAddress;identityKey;identityAttributes;getApiData;constructor(j,J={},$=""){super();if(j instanceof w.HD)if(this.#q=!1,$){let z=_(w.Hash.sha256($,"utf8")),Q=U.getSigningPathFromHex(z);this.#J=j.derive(Q)}else this.#J=j;else if(this.#q=!0,this.#j=j.rootPk,$){let z=_(w.Hash.sha256($,"utf8"));this.#j=this.#j.deriveChild(this.#j.toPublicKey(),z)}if(this.#w=$,this.idName="ID 1",this.description="",this.#$=`${R}/0/0/0`,this.#Z=`${R}/0/0/0`,this.#z=`${R}/0/0/1`,this.#q){if(!this.#j)throw Error("Master private key not initialized");let z=this.#j.deriveChild(this.#j.toPublicKey(),this.#$);this.rootAddress=z.toPublicKey().toAddress()}else{if(!this.#J)throw Error("HD private key not initialized");let z=this.#J.derive(this.#$);this.rootAddress=z.privKey.toPublicKey().toAddress()}this.identityKey=this.deriveIdentityKey(this.rootAddress);let q={...J};this.identityAttributes=this.parseAttributes(q),this.getApiData=N(this.#Q,this.#W)}set BAP_SERVER(j){this.#Q=j}get BAP_SERVER(){return this.#Q}set BAP_TOKEN(j){this.#W=j}get BAP_TOKEN(){return this.#W}deriveIdentityKey(j){let J=_(w.Hash.sha256(j,"utf8"));return Xj(w.Hash.ripemd160(J,"hex"))}parseAttributes(j){if(typeof j==="string")return this.parseStringUrns(j);for(let J in j)if(!j[J].value||!j[J].nonce)throw Error("Invalid identity attribute");return j||{}}parseStringUrns(j){let J={},$=j.replace(/^\s+/g,"").replace(/\r/gm,"").split(`
|
|
5
|
-
`);for(let q of $){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])J[Q[3]]={value:Q[4],nonce:Q[5]}}return J}getIdentityKey(){return this.identityKey}set rootPath(j){if(this.#q){if(this.#$=j,!this.#j)throw Error("Master private key not initialized");let J=this.#j.deriveChild(this.#j.toPublicKey(),j);this.rootAddress=J.toPublicKey().toAddress(),this.#Z=j,this.#z=j}else{let J=j;if(j.split("/").length<5)J=`${R}${j}`;if(!this.validatePath(J))throw Error(`invalid signing path given ${J}`);if(this.#$=J,!this.#J)throw Error("HD private key not initialized");let $=this.#J.derive(J);this.rootAddress=$.pubKey.toAddress(),this.#Z=J,this.#z=J}this.identityKey=this.deriveIdentityKey(this.rootAddress)}get rootPath(){return this.#$}getRootPath(){return this.#$}set currentPath(j){if(this.#q)this.#Z=this.#z,this.#z=j;else{let J=j;if(j.split("/").length<5)J=`${R}${j}`;if(!this.validatePath(J))throw Error("invalid signing path given");this.#Z=this.#z,this.#z=J}}get currentPath(){return this.#z}get previousPath(){return this.#Z}get idSeed(){return this.#w}incrementPath(){this.currentPath=U.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=j.split("/");if(J.length===7&&Number(J[1].replace("'",""))<=M&&Number(J[2].replace("'",""))<=M&&Number(J[3].replace("'",""))<=M&&Number(J[4].replace("'",""))<=M&&Number(J[5].replace("'",""))<=M&&Number(J[6].replace("'",""))<=M)return!0}return!1}getInitialIdTransaction(){return this.getIdTransaction(this.#$)}getIdTransaction(j=""){if(this.#z===this.#$)throw Error("Current path equals rootPath. ID was probably not initialized properly");let J=[X(k),X("ID"),X(this.identityKey),X(this.getCurrentAddress())];return this.signOpReturnWithAIP(J,j||this.#Z)}getPathDerivedKey(j){if(this.#q){if(!this.#j)throw Error("Master private key not initialized");return this.#j.deriveChild(this.#j.toPublicKey(),j)}if(!this.#J)throw Error("HD private key not initialized");return this.#J.derive(j).privKey}getIdentitySigningKeyForPath(j){let J=this.getPathDerivedKey(j);return J.deriveChild(J.toPublicKey(),H)}getMemberKey(j){let J=j||this.#z;return this.getPathDerivedKey(J).toPublicKey().toString()}getLegacyAddress(j){let J=j||this.#z;return this.getPathDerivedKey(J).toPublicKey().toAddress()}needsRotation(j){let J=j||this.rootAddress,$=this.getLegacyAddress(this.#$);return J===$}getLegacyRotationTransaction(){let j=this.getAddress(this.#$),J=[X(k),X("ID"),X(this.identityKey),X(j)],$=this.getAIPMessageBuffer(J),q=this.getPathDerivedKey(this.#$),{address:z,signature:Q}=this.signWithBSM($.flat(),q);return this.formatAIPOutput(J,z,Q)}getAddress(j){return this.getIdentitySigningKeyForPath(j).toPublicKey().toAddress()}getCurrentAddress(){return this.getAddress(this.#z)}getEncryptionKey(){if(this.#q){if(!this.#j)throw Error("Master private key not initialized");let $=this.#j.deriveChild(this.#j.toPublicKey(),this.#$),q=$.deriveChild($.toPublicKey(),F);return{privKey:q,pubKey:q.toPublicKey()}}if(!this.#J)throw Error("HD private key not initialized");let J=this.#J.derive(this.#$).derive(F).privKey;return{privKey:J,pubKey:J.toPublicKey()}}getEncryptionKeyType42(){if(this.#q)return this.getEncryptionKey();if(!this.#J)throw Error("HD private key not initialized");let j=this.#J.derive(this.#$),J=j.privKey.deriveChild(j.toPublic().pubKey,F);return{privKey:J,pubKey:J.toPublicKey()}}getEncryptionPublicKey(){let{pubKey:j}=this.getEncryptionKey();return j.toString()}getEncryptionPublicKeyWithSeed(j){return this.getEncryptionPrivateKeyWithSeed(j).toPublicKey().toString()}encrypt(j,J){let{privKey:$,pubKey:q}=this.getEncryptionKey(),z=J?w.PublicKey.fromString(J):q;return I(g(X(j),z,$))}decrypt(j,J){let{privKey:$}=this.getEncryptionKey(),q;if(J)q=w.PublicKey.fromString(J);return u(d(X(j,"base64"),$,q))}encryptWithSeed(j,J,$){let q=this.getEncryptionPrivateKeyWithSeed(J),z=q.toPublicKey(),Q=$?w.PublicKey.fromString($):z;return I(g(X(j),Q,q))}decryptWithSeed(j,J,$){let q=this.getEncryptionPrivateKeyWithSeed(J),z;if($)z=w.PublicKey.fromString($);return u(d(X(j,"base64"),q,z))}getEncryptionPrivateKeyWithSeed(j){let J=_(w.Hash.sha256(j,"utf8"));if(this.#q){if(!this.#j)throw Error("Master private key not initialized");let z=this.#j.deriveChild(this.#j.toPublicKey(),this.#$);return z.deriveChild(z.toPublicKey(),J)}if(!this.#J)throw Error("HD private key not initialized");let $=U.getSigningPathFromHex(J);return this.#J.derive(this.#$).derive($).privKey}getAttestation(j){let J=w.Hash.sha256(j,"utf8");return`bap:attest:${_(J)}:${this.getIdentityKey()}`}getAttestationHash(j){let J=this.getAttributeUrn(j);if(!J)return null;let $=this.getAttestation(J),q=w.Hash.sha256($,"utf8");return _(q)}signMessage(j,J){let $=J||this.#z,q=this.getIdentitySigningKeyForPath($);return this.signWithBSM(j,q)}signMessageWithSeed(j,J){let $=_(w.Hash.sha256(J,"utf8")),q;if(this.#q){if(!this.#j)throw Error("Master private key not initialized");let Q=this.#j.deriveChild(this.#j.toPublicKey(),this.#$);q=Q.deriveChild(Q.toPublicKey(),$)}else{if(!this.#J)throw Error("HD private key not initialized");let Q=U.getSigningPathFromHex($);q=this.#J.derive(this.#$).derive(Q).privKey}let z=q.deriveChild(q.toPublicKey(),H);return this.signWithBSM(X(j,"utf8"),z)}signOpReturnWithAIP(j,J=""){let $=this.getAIPMessageBuffer(j),{address:q,signature:z}=this.signMessage($.flat(),J);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 J=this.getAttestationHash(j),$=await this.getApiData("/attestation/get",{hash:J});return console.log("getAttestations",j,J,$),$}import(j){this.idName=j.name,this.description=j.description||"",this.identityKey=j.identityKey,this.#$=j.rootPath,this.rootAddress=j.rootAddress,this.#Z=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.#Z,currentPath:this.#z,idSeed:this.#w,identityAttributes:this.getAttributes(),lastIdPath:""}}exportMemberBackup(){let j=this.getPathDerivedKey(this.#z),J=this.getIdentitySigningKeyForPath(this.#z);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.getPathDerivedKey(this.#z);return new x(j)}exportMember(){let j=this.exportMemberBackup(),J=this.getPathDerivedKey(this.#z),$=I(g(X(JSON.stringify(j)),J.toPublicKey()));return{wif:j.derivedPrivateKey,encryptedData:$}}}var{toArray:Z,toUTF8:B,toBase64:A,toHex:D}=s.Utils,{electrumEncrypt:n,electrumDecrypt:y}=L.ECIES;class i{#J;#j;#q;#Q={};#W=S;#$="";#Z="";#z=0;getApiData;constructor(j,J="",$=""){if(!j)throw Error("No key source given");if(typeof j==="string")this.#J=L.HD.fromString(j),this.#q=!1;else this.#j=L.PrivateKey.fromWif(j.rootPk),this.#q=!0;if(J)this.#$=J;if($)this.#W=$;this.getApiData=N(this.#W,this.#$)}get lastIdPath(){return this.#Z}getPublicKey(j=""){if(this.#q){if(!this.#j)throw Error("Master private key not initialized");if(j)return this.#j.deriveChild(this.#j.toPublicKey(),j).toPublicKey().toString();return this.#j.toPublicKey().toString()}if(!this.#J)throw Error("HD private key not initialized");if(j)return this.#J.derive(j).pubKey.toString();return this.#J.pubKey.toString()}getHdPublicKey(j=""){if(this.#q)throw Error("HD public keys are not available in Type 42 mode");if(!this.#J)throw Error("HD private key not initialized");if(j)return this.#J.derive(j).toPublic().toString();return this.#J.toPublic().toString()}set BAP_SERVER(j){this.#W=j;for(let J in this.#Q)this.#Q[J].BAP_SERVER=j}get BAP_SERVER(){return this.#W}set BAP_TOKEN(j){this.#$=j;for(let J in this.#Q)this.#Q[J].BAP_TOKEN=j}get BAP_TOKEN(){return this.#$}checkIdBelongs(j){let J;if(this.#q){if(!this.#j)throw Error("Master private key not initialized");J=this.#j.deriveChild(this.#j.toPublicKey(),j.rootPath).toPublicKey().toAddress()}else{if(!this.#J)throw Error("HD private key not initialized");J=this.#J.derive(j.rootPath).pubKey.toAddress()}if(J!==j.rootAddress)throw Error("ID does not belong to this private key");return!0}listIds(){return Object.keys(this.#Q)}newId(j,J,$={},q=""){let z,Q,W;if(typeof j==="object"||j===void 0||typeof j==="string"&&j.startsWith("/"))Q=typeof j==="string"?j:void 0,W=typeof j==="object"?j:typeof J==="object"?J:{},z="Default Identity";else z=j,Q=typeof J==="string"?J:void 0,W=typeof J==="object"?J:$;let G;if(Q)G=Q;else if(this.#q)G=`bap:${this.#z}`,this.#z++;else G=this.getNextValidPath();let C;if(this.#q){if(!this.#j)throw Error("Type 42 parameters not initialized");C=new V({rootPk:this.#j},W,q)}else{if(!this.#J)throw Error("HD private key not initialized");C=new V(this.#J,W,q)}if(C.BAP_SERVER=this.#W,C.BAP_TOKEN=this.#$,C.idName=z,C.rootPath=G,this.#q)C.currentPath=G;else C.currentPath=U.getNextPath(G);let l=C.getIdentityKey();return this.#Q[l]=C,this.#Z=G,this.#Q[l]}removeId(j){delete this.#Q[j]}getNextValidPath(){if(this.#Z)return U.getNextIdentityPath(this.#Z);return`/0'/${Object.keys(this.#Q).length}'/0'`}newIdWithCounter(j,J=`Identity ${j}`){if(!this.#q)throw Error("newIdWithCounter only works in Type 42 mode");let $=`bap:${j}`;return this.newId(J,$)}getId(j){return this.#Q[j]||null}setId(j){this.checkIdBelongs(j),this.#Q[j.getIdentityKey()]=j}importIds(j,J=!0){if(J&&typeof j==="string"){this.importEncryptedIds(j);return}let $=j;if(!$.lastIdPath)throw Error("ID cannot be imported as it is not complete");if(!$.ids)throw Error(`ID data is not in the correct format: ${j}`);let q=j.lastIdPath;for(let z of $.ids){if(!z.identityKey||!z.identityAttributes||!z.rootAddress)throw Error("ID cannot be imported as it is not complete");let Q;if(this.#q){if(!this.#j)throw Error("Type 42 parameters not initialized");Q=new V({rootPk:this.#j},{},z.idSeed)}else{if(!this.#J)throw Error("HD private key not initialized");Q=new V(this.#J,{},z.idSeed)}if(Q.BAP_SERVER=this.#W,Q.BAP_TOKEN=this.#$,Q.import(z),q==="")q=Q.currentPath;if(this.checkIdBelongs(Q),this.#Q[Q.getIdentityKey()]=Q,this.#q&&Q.rootPath.startsWith("bap:")){let W=Q.rootPath.split(":");if(W.length>=2){let G=Number.parseInt(W[1],10);if(!Number.isNaN(G))this.#z=Math.max(this.#z,G+1)}}}this.#Z=q}importEncryptedIds(j){let J=this.decrypt(j),$=JSON.parse(J);if(Array.isArray($)){console.log(`Importing old format:
|
|
6
|
-
`,$),this.importOldIds($);return}if(typeof $!=="object")throw Error("decrypted, but found unrecognized identities format");this.importIds($,!1)}importOldIds(j){for(let J of j){let $;if(this.#q){if(!this.#j)throw Error("Type 42 parameters not initialized");$=new V({rootPk:this.#j},{},J.idSeed??"")}else{if(!this.#J)throw Error("HD private key not initialized");$=new V(this.#J,{},J.idSeed??"")}$.BAP_SERVER=this.#W,$.BAP_TOKEN=this.#$,$.import(J),this.checkIdBelongs($),this.#Q[$.getIdentityKey()]=$,this.#Z=$.currentPath}}exportIds(j,J=!0){let $={lastIdPath:this.#Z,ids:[]},q=j||Object.keys(this.#Q);for(let z of q){if(!this.#Q[z])throw Error(`Identity ${z} not found`);$.ids.push(this.#Q[z].export())}if(J)return this.encrypt(JSON.stringify($));return $}exportId(j,J=!0){let $={lastIdPath:this.#Z,ids:[]};if($.ids.push(this.#Q[j].export()),J)return this.encrypt(JSON.stringify($));return $}encrypt(j){if(this.#q){if(!this.#j)throw Error("Master private key not initialized");let $=this.#j.deriveChild(this.#j.toPublicKey(),F);return A(n(Z(j),$.toPublicKey(),null))}if(!this.#J)throw Error("HD private key not initialized");let J=this.#J.derive(F);return A(n(Z(j),J.pubKey,null))}decrypt(j){if(this.#q){if(!this.#j)throw Error("Master private key not initialized");let $=this.#j.deriveChild(this.#j.toPublicKey(),F);return B(y(Z(j,"base64"),$))}if(!this.#J)throw Error("HD private key not initialized");let J=this.#J.derive(F);return B(y(Z(j,"base64"),J.privKey))}signAttestationWithAIP(j,J,$=0,q=""){let z=this.getId(J);if(!z)throw Error("Could not find identity to attest with");let Q=this.getAttestationBuffer(j,$,q),{address:W,signature:G}=z.signMessage(Q);return this.createAttestationTransaction(j,$,W,G,q)}verifyAttestationWithAIP(j){if(!j.every((q)=>Array.isArray(q))||j[0][0]!==L.OP.OP_RETURN||D(j[1])!==p)throw Error("Not a valid BAP transaction");let J=D(j[7])==="44415441"?5:0,$={type:B(j[2]),hash:D(j[3]),sequence:B(j[4]),signingProtocol:B(j[7+J]),signingAddress:B(j[8+J]),signature:A(j[9+J])};if(J&&j[3]===j[8])$.data=D(j[9]);console.log({attestation:$});try{let q=[];for(let z=0;z<6+J;z++)q.push(j[z]);$.verified=this.verifySignature(q.flat(),$.signingAddress,$.signature)}catch{$.verified=!1}return $}createAttestationTransaction(j,J,$,q,z=""){let Q=[[L.OP.OP_RETURN],Z(k),Z("ATTEST"),Z(j),Z(`${J}`),Z("|")];if(z)Q.push(Z(k),Z("DATA"),Z(j),Z(z),Z("|"));return Q.push(Z(E),Z("BITCOIN_ECDSA"),Z($),Z(q,"base64")),console.log({elements:Q}),Q}getAttestationBuffer(j,J=0,$=""){let q=[[L.OP.OP_RETURN],Z(k),Z("ATTEST"),Z(j),Z(`${J}`),Z("|")];if($)q.push(Z(k),Z("DATA"),Z(j),Z($),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=L.Signature.fromCompact($,"base64"),Q;for(let W=0;W<4;W++)try{if(Q=z.RecoverPublicKey(W,new L.BigNumber(L.BSM.magicHash(q))),L.BSM.verify(q,z,Q)&&Q.toAddress()===J)return!0}catch{}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:J,challenge:$,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,$){let z={ids:this.exportIds(),...j&&{label:j},createdAt:new Date().toISOString()};if(this.#q){if(!this.#j)throw Error("Type 42 parameters not initialized");return{...z,rootPk:this.#j.toWif()}}if(!this.#J)throw Error("HD private key not initialized");return{...z,xprv:J||this.#J.toString(),mnemonic:$||""}}exportMemberForBackup(j,J){let $=this.#Q[j];if(!$)throw Error(`Identity ${j} not found`);let q=$.exportMember();return{wif:q.wif,id:q.encryptedData,...J&&{label:J},createdAt:new Date().toISOString()}}}})
|
|
7
|
-
|
|
8
|
-
//# debugId=E05864240FBDCD8664756E2164756E21
|
package/src/README.md
DELETED
|
@@ -1,583 +0,0 @@
|
|
|
1
|
-
# BAP Library Documentation
|
|
2
|
-
|
|
3
|
-
> Complete API reference for the bsv-bap JavaScript/TypeScript library
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install bsv-bap
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
```bash
|
|
12
|
-
yarn add bsv-bap
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
bun add bsv-bap
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Core Classes
|
|
20
|
-
|
|
21
|
-
### BAP
|
|
22
|
-
|
|
23
|
-
The main class for managing Bitcoin Attestation Protocol identities.
|
|
24
|
-
|
|
25
|
-
#### Constructor
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
// BIP32 mode (legacy)
|
|
29
|
-
const bap = new BAP(xprvKey: string);
|
|
30
|
-
|
|
31
|
-
// Type 42 mode (recommended)
|
|
32
|
-
const bap = new BAP({
|
|
33
|
-
rootPk: string // WIF format private key
|
|
34
|
-
});
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
#### Methods
|
|
38
|
-
|
|
39
|
-
##### Identity Management
|
|
40
|
-
|
|
41
|
-
```typescript
|
|
42
|
-
// Create a new identity (new signature - Type 42 optimized)
|
|
43
|
-
newId(idName?: string, customPath?: string, identityAttributes?: IdentityAttributes, idSeed?: string): MasterID
|
|
44
|
-
|
|
45
|
-
// Create identity with specific counter (useful for discovery)
|
|
46
|
-
newIdWithCounter(counter: number, idName?: string): MasterID
|
|
47
|
-
|
|
48
|
-
// Get an identity by key
|
|
49
|
-
getId(idKey: string): MasterID | null
|
|
50
|
-
|
|
51
|
-
// List all identity keys
|
|
52
|
-
listIds(): string[]
|
|
53
|
-
|
|
54
|
-
// Remove an identity
|
|
55
|
-
removeId(idKey: string): void
|
|
56
|
-
|
|
57
|
-
// Check if identity belongs to this BAP instance
|
|
58
|
-
checkIdBelongs(id: MasterID): boolean
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
##### Import/Export
|
|
62
|
-
|
|
63
|
-
```typescript
|
|
64
|
-
// Export identities (encrypted by default)
|
|
65
|
-
exportIds(idKeys?: string[], encrypted?: boolean): string | Identities
|
|
66
|
-
|
|
67
|
-
// Export specific identity
|
|
68
|
-
exportId(idKey: string, encrypted?: boolean): string | Identities
|
|
69
|
-
|
|
70
|
-
// Import identities
|
|
71
|
-
importIds(identities: string | Identities, encrypted?: boolean): void
|
|
72
|
-
|
|
73
|
-
// Bitcoin-backup compatible export
|
|
74
|
-
exportForBackup(label?: string, xprv?: string, mnemonic?: string): BapMasterBackup
|
|
75
|
-
|
|
76
|
-
// Export member backup
|
|
77
|
-
exportMemberForBackup(idKey: string, label?: string): BapMemberBackup
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
##### Cryptographic Operations
|
|
81
|
-
|
|
82
|
-
```typescript
|
|
83
|
-
// Create attestation transaction
|
|
84
|
-
signAttestationWithAIP(
|
|
85
|
-
attestationHash: string,
|
|
86
|
-
identityKey: string,
|
|
87
|
-
counter?: number,
|
|
88
|
-
dataString?: string
|
|
89
|
-
): number[][]
|
|
90
|
-
|
|
91
|
-
// Verify attestation
|
|
92
|
-
verifyAttestationWithAIP(txData: number[][]): AttestationResult
|
|
93
|
-
|
|
94
|
-
// Verify signature
|
|
95
|
-
verifySignature(
|
|
96
|
-
message: string | number[],
|
|
97
|
-
address: string,
|
|
98
|
-
signature: string
|
|
99
|
-
): boolean
|
|
100
|
-
|
|
101
|
-
// Verify challenge signature (with API validation)
|
|
102
|
-
async verifyChallengeSignature(
|
|
103
|
-
idKey: string,
|
|
104
|
-
address: string,
|
|
105
|
-
challenge: string,
|
|
106
|
-
signature: string
|
|
107
|
-
): Promise<boolean>
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
##### Encryption
|
|
111
|
-
|
|
112
|
-
```typescript
|
|
113
|
-
// Encrypt data using BAP master key
|
|
114
|
-
encrypt(data: string): string
|
|
115
|
-
|
|
116
|
-
// Decrypt data using BAP master key
|
|
117
|
-
decrypt(encryptedData: string): string
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
##### Configuration
|
|
121
|
-
|
|
122
|
-
```typescript
|
|
123
|
-
// Set/get API server
|
|
124
|
-
BAP_SERVER: string // Default: https://api.sigmaidentity.com/v1
|
|
125
|
-
|
|
126
|
-
// Set/get API token
|
|
127
|
-
BAP_TOKEN: string
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### MasterID
|
|
131
|
-
|
|
132
|
-
Represents an individual identity with HD key derivation support.
|
|
133
|
-
|
|
134
|
-
#### Properties
|
|
135
|
-
|
|
136
|
-
```typescript
|
|
137
|
-
idName: string // Identity name
|
|
138
|
-
description: string // Identity description
|
|
139
|
-
identityKey: string // Unique identity key
|
|
140
|
-
rootAddress: string // Root Bitcoin address
|
|
141
|
-
identityAttributes: IdentityAttributes
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
#### Methods
|
|
145
|
-
|
|
146
|
-
##### Attribute Management
|
|
147
|
-
|
|
148
|
-
```typescript
|
|
149
|
-
// Set attribute
|
|
150
|
-
setAttribute(name: string, value: string | IdentityAttribute): void
|
|
151
|
-
|
|
152
|
-
// Get attribute
|
|
153
|
-
getAttribute(name: string): IdentityAttribute | null
|
|
154
|
-
|
|
155
|
-
// Get all attributes
|
|
156
|
-
getAttributes(): IdentityAttributes
|
|
157
|
-
|
|
158
|
-
// Remove attribute
|
|
159
|
-
unsetAttribute(name: string): void
|
|
160
|
-
|
|
161
|
-
// Get attribute URN
|
|
162
|
-
getAttributeUrn(name: string): string | null
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
##### Key Management
|
|
166
|
-
|
|
167
|
-
```typescript
|
|
168
|
-
// Get current signing address
|
|
169
|
-
getCurrentAddress(): string
|
|
170
|
-
|
|
171
|
-
// Get address for specific path
|
|
172
|
-
getAddress(path: string): string
|
|
173
|
-
|
|
174
|
-
// Increment to next path
|
|
175
|
-
incrementPath(): void
|
|
176
|
-
|
|
177
|
-
// Get encryption public key
|
|
178
|
-
getEncryptionPublicKey(): string
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
##### Signing
|
|
182
|
-
|
|
183
|
-
```typescript
|
|
184
|
-
// Sign message
|
|
185
|
-
signMessage(
|
|
186
|
-
message: number[],
|
|
187
|
-
signingPath?: string
|
|
188
|
-
): { address: string; signature: string }
|
|
189
|
-
|
|
190
|
-
// Sign message with seed
|
|
191
|
-
signMessageWithSeed(
|
|
192
|
-
message: string,
|
|
193
|
-
seed: string
|
|
194
|
-
): { address: string; signature: string }
|
|
195
|
-
|
|
196
|
-
// Sign OP_RETURN with AIP
|
|
197
|
-
signOpReturnWithAIP(
|
|
198
|
-
opReturn: number[][],
|
|
199
|
-
signingPath?: string
|
|
200
|
-
): number[][]
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
##### Encryption
|
|
204
|
-
|
|
205
|
-
```typescript
|
|
206
|
-
// Encrypt data
|
|
207
|
-
encrypt(data: string, counterPartyPublicKey?: string): string
|
|
208
|
-
|
|
209
|
-
// Decrypt data
|
|
210
|
-
decrypt(ciphertext: string, counterPartyPublicKey?: string): string
|
|
211
|
-
|
|
212
|
-
// Encrypt with seed
|
|
213
|
-
encryptWithSeed(
|
|
214
|
-
data: string,
|
|
215
|
-
seed: string,
|
|
216
|
-
counterPartyPublicKey?: string
|
|
217
|
-
): string
|
|
218
|
-
|
|
219
|
-
// Decrypt with seed
|
|
220
|
-
decryptWithSeed(
|
|
221
|
-
ciphertext: string,
|
|
222
|
-
seed: string,
|
|
223
|
-
counterPartyPublicKey?: string
|
|
224
|
-
): string
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
##### Attestations
|
|
228
|
-
|
|
229
|
-
```typescript
|
|
230
|
-
// Get attestation hash for attribute
|
|
231
|
-
getAttestationHash(attribute: string): string | null
|
|
232
|
-
|
|
233
|
-
// Get attestation URN
|
|
234
|
-
getAttestation(urn: string): string
|
|
235
|
-
|
|
236
|
-
// Get all attestations for attribute (API call)
|
|
237
|
-
async getAttributeAttestations(attribute: string): Promise<GetAttestationResponse>
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
##### Transactions
|
|
241
|
-
|
|
242
|
-
```typescript
|
|
243
|
-
// Get initial ID transaction
|
|
244
|
-
getInitialIdTransaction(): number[][]
|
|
245
|
-
|
|
246
|
-
// Get ID transaction for rotation
|
|
247
|
-
getIdTransaction(previousPath?: string): number[][]
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### MemberID
|
|
251
|
-
|
|
252
|
-
Represents a standalone member identity (non-HD).
|
|
253
|
-
|
|
254
|
-
#### Constructor
|
|
255
|
-
|
|
256
|
-
```typescript
|
|
257
|
-
const member = new MemberID(privateKey: PrivateKey, attributes?: IdentityAttributes);
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
#### Methods
|
|
261
|
-
|
|
262
|
-
##### Core Operations
|
|
263
|
-
|
|
264
|
-
```typescript
|
|
265
|
-
// Get public key
|
|
266
|
-
getPublicKey(): string
|
|
267
|
-
|
|
268
|
-
// Sign message
|
|
269
|
-
signMessage(message: number[]): { address: string; signature: string }
|
|
270
|
-
|
|
271
|
-
// Sign OP_RETURN with AIP
|
|
272
|
-
signOpReturnWithAIP(opReturn: number[][]): number[][]
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
##### Import/Export
|
|
276
|
-
|
|
277
|
-
```typescript
|
|
278
|
-
// Export member data
|
|
279
|
-
export(): MemberIdentity
|
|
280
|
-
|
|
281
|
-
// Import member data
|
|
282
|
-
import(memberData: MemberIdentity): void
|
|
283
|
-
|
|
284
|
-
// Export for backup
|
|
285
|
-
exportForBackup(label?: string): BapMemberBackup
|
|
286
|
-
|
|
287
|
-
// Create from backup
|
|
288
|
-
static fromBackup(backup: BapMemberBackup): MemberID
|
|
289
|
-
|
|
290
|
-
// Create from member identity
|
|
291
|
-
static fromMemberIdentity(identity: MemberIdentity): MemberID
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
## Type System
|
|
295
|
-
|
|
296
|
-
### Core Types
|
|
297
|
-
|
|
298
|
-
```typescript
|
|
299
|
-
interface IdentityAttribute {
|
|
300
|
-
value: string;
|
|
301
|
-
nonce: string;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
interface IdentityAttributes {
|
|
305
|
-
[key: string]: IdentityAttribute;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
interface Identity {
|
|
309
|
-
name: string;
|
|
310
|
-
description: string;
|
|
311
|
-
identityKey: string;
|
|
312
|
-
rootPath: string;
|
|
313
|
-
rootAddress: string;
|
|
314
|
-
previousPath: string;
|
|
315
|
-
currentPath: string;
|
|
316
|
-
idSeed: string;
|
|
317
|
-
identityAttributes: IdentityAttributes;
|
|
318
|
-
lastIdPath: string;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
interface MemberIdentity {
|
|
322
|
-
name: string;
|
|
323
|
-
description: string;
|
|
324
|
-
derivedPrivateKey: string;
|
|
325
|
-
address: string;
|
|
326
|
-
identityAttributes: IdentityAttributes;
|
|
327
|
-
identityKey: string;
|
|
328
|
-
}
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
### Backup Types
|
|
332
|
-
|
|
333
|
-
```typescript
|
|
334
|
-
// Type 42 format
|
|
335
|
-
interface BapMasterBackup {
|
|
336
|
-
ids: string; // Encrypted identity data
|
|
337
|
-
rootPk: string; // WIF format private key
|
|
338
|
-
label?: string; // Optional label
|
|
339
|
-
createdAt: string; // ISO timestamp
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
// Legacy BIP32 format
|
|
343
|
-
interface BapMasterBackup {
|
|
344
|
-
ids: string; // Encrypted identity data
|
|
345
|
-
xprv: string; // Extended private key
|
|
346
|
-
mnemonic: string; // BIP39 mnemonic
|
|
347
|
-
label?: string; // Optional label
|
|
348
|
-
createdAt: string; // ISO timestamp
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
interface BapMemberBackup {
|
|
352
|
-
wif: string; // WIF private key
|
|
353
|
-
id: string; // Encrypted member data
|
|
354
|
-
label?: string; // Optional label
|
|
355
|
-
createdAt: string; // ISO timestamp
|
|
356
|
-
}
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
### API Types
|
|
360
|
-
|
|
361
|
-
```typescript
|
|
362
|
-
interface AttestationResult {
|
|
363
|
-
type: string;
|
|
364
|
-
hash: string;
|
|
365
|
-
sequence: string;
|
|
366
|
-
signingProtocol: string;
|
|
367
|
-
signingAddress: string;
|
|
368
|
-
signature: string;
|
|
369
|
-
data?: string;
|
|
370
|
-
verified?: boolean;
|
|
371
|
-
}
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
## Key Derivation
|
|
375
|
-
|
|
376
|
-
### BIP32 Mode (Legacy)
|
|
377
|
-
|
|
378
|
-
Uses hierarchical deterministic key derivation:
|
|
379
|
-
|
|
380
|
-
```
|
|
381
|
-
m/424150'/0'/0'/[identity]/[key]/[index]
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
### Type 42 Mode (Recommended)
|
|
385
|
-
|
|
386
|
-
Uses simple counter-based derivation with meaningful names:
|
|
387
|
-
|
|
388
|
-
```typescript
|
|
389
|
-
// Invoice numbers: "bap:0", "bap:1", "bap:2", etc.
|
|
390
|
-
const work = bap.newId("Work Identity"); // Uses bap:0
|
|
391
|
-
const personal = bap.newId("Personal"); // Uses bap:1
|
|
392
|
-
|
|
393
|
-
// Derivation uses counter as invoice number
|
|
394
|
-
derivedKey = masterKey.deriveChild(
|
|
395
|
-
masterKey.toPublicKey(),
|
|
396
|
-
"bap:0" // Simple counter format
|
|
397
|
-
);
|
|
398
|
-
|
|
399
|
-
// Names are stored separately for UX
|
|
400
|
-
identity.idName = "Work Identity"; // Human-readable name
|
|
401
|
-
identity.rootPath = "bap:0"; // Cryptographic derivation path
|
|
402
|
-
```
|
|
403
|
-
|
|
404
|
-
**Discovery**: Sequential counters enable systematic identity recovery:
|
|
405
|
-
|
|
406
|
-
```typescript
|
|
407
|
-
// Find all identities by checking counters
|
|
408
|
-
for (let i = 0; i < 100; i++) {
|
|
409
|
-
const identity = bap.newIdWithCounter(i);
|
|
410
|
-
if (await blockchainHasActivity(identity.getIdentityKey())) {
|
|
411
|
-
console.log(`Found identity: ${identity.idName}`);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
### Encryption Keys
|
|
417
|
-
|
|
418
|
-
Each identity has a unique encryption key:
|
|
419
|
-
|
|
420
|
-
```
|
|
421
|
-
BIP32: rootPath → m/424150'/2147483647'/2147483647'
|
|
422
|
-
Type 42: rootKey → deriveChild(rootPk.pubKey, path)
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
## Usage Examples
|
|
426
|
-
|
|
427
|
-
### Complete Identity Creation Flow
|
|
428
|
-
|
|
429
|
-
```typescript
|
|
430
|
-
import { BAP } from 'bsv-bap';
|
|
431
|
-
import { PrivateKey } from '@bsv/sdk';
|
|
432
|
-
|
|
433
|
-
// Create BAP instance (Type 42)
|
|
434
|
-
const rootKey = PrivateKey.fromRandom();
|
|
435
|
-
const bap = new BAP({
|
|
436
|
-
rootPk: rootKey.toWif()
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
// Create identity
|
|
440
|
-
const identity = bap.newId();
|
|
441
|
-
identity.idName = "Professional Identity";
|
|
442
|
-
identity.description = "My verified professional identity";
|
|
443
|
-
|
|
444
|
-
// Set attributes
|
|
445
|
-
identity.setAttribute('name', 'John Smith');
|
|
446
|
-
identity.setAttribute('title', 'Software Engineer');
|
|
447
|
-
identity.setAttribute('company', 'Bitcoin Corp');
|
|
448
|
-
|
|
449
|
-
// Get attestation for verification
|
|
450
|
-
const nameHash = identity.getAttestationHash('name');
|
|
451
|
-
console.log('Name attestation hash:', nameHash);
|
|
452
|
-
|
|
453
|
-
// Create ID transaction
|
|
454
|
-
const idTx = identity.getInitialIdTransaction();
|
|
455
|
-
// Broadcast idTx to Bitcoin network...
|
|
456
|
-
|
|
457
|
-
// Export for backup
|
|
458
|
-
const backup = bap.exportForBackup('Main Identity');
|
|
459
|
-
// Save backup securely...
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
### Attestation Workflow
|
|
463
|
-
|
|
464
|
-
```typescript
|
|
465
|
-
// Company attests to employee identity
|
|
466
|
-
const companyBap = new BAP(companyXprv);
|
|
467
|
-
const companyId = companyBap.getId(companyIdKey);
|
|
468
|
-
|
|
469
|
-
// Create attestation
|
|
470
|
-
const attestation = companyBap.signAttestationWithAIP(
|
|
471
|
-
employeeNameHash,
|
|
472
|
-
companyIdKey,
|
|
473
|
-
0, // sequence
|
|
474
|
-
JSON.stringify({
|
|
475
|
-
verified: true,
|
|
476
|
-
role: 'Senior Engineer',
|
|
477
|
-
date: new Date().toISOString()
|
|
478
|
-
})
|
|
479
|
-
);
|
|
480
|
-
|
|
481
|
-
// Verify attestation
|
|
482
|
-
const result = await companyBap.verifyAttestationWithAIP(attestation);
|
|
483
|
-
console.log('Attestation valid:', result.verified);
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
### Encrypted Communication
|
|
487
|
-
|
|
488
|
-
```typescript
|
|
489
|
-
// Alice encrypts message for Bob
|
|
490
|
-
const alice = bap.getId(aliceIdKey);
|
|
491
|
-
const bobPublicKey = await getBobsPublicKey();
|
|
492
|
-
|
|
493
|
-
const encrypted = alice.encrypt(
|
|
494
|
-
'Secret message for Bob',
|
|
495
|
-
bobPublicKey
|
|
496
|
-
);
|
|
497
|
-
|
|
498
|
-
// Bob decrypts message
|
|
499
|
-
const bob = bobBap.getId(bobIdKey);
|
|
500
|
-
const alicePublicKey = await getAlicesPublicKey();
|
|
501
|
-
|
|
502
|
-
const decrypted = bob.decrypt(
|
|
503
|
-
encrypted,
|
|
504
|
-
alicePublicKey
|
|
505
|
-
);
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
### Member Identity
|
|
509
|
-
|
|
510
|
-
```typescript
|
|
511
|
-
// Create standalone member identity
|
|
512
|
-
const memberKey = PrivateKey.fromRandom();
|
|
513
|
-
const member = new MemberID(memberKey);
|
|
514
|
-
|
|
515
|
-
member.idName = "Forum Member";
|
|
516
|
-
member.setAttribute('username', 'satoshi2024');
|
|
517
|
-
|
|
518
|
-
// Sign a message
|
|
519
|
-
const { address, signature } = member.signMessage(
|
|
520
|
-
Buffer.from('I approve this message')
|
|
521
|
-
);
|
|
522
|
-
|
|
523
|
-
// Export for sharing
|
|
524
|
-
const memberBackup = member.exportForBackup('Forum Identity');
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
## Migration Guide
|
|
528
|
-
|
|
529
|
-
### From BIP32 to Type 42
|
|
530
|
-
|
|
531
|
-
```typescript
|
|
532
|
-
// Export from BIP32
|
|
533
|
-
const oldBap = new BAP(xprv);
|
|
534
|
-
const backup = oldBap.exportForBackup();
|
|
535
|
-
|
|
536
|
-
// Extract root key
|
|
537
|
-
const hdKey = HD.fromString(xprv);
|
|
538
|
-
const rootWif = hdKey.privKey.toWif();
|
|
539
|
-
|
|
540
|
-
// Create Type 42 instance
|
|
541
|
-
const newBap = new BAP({
|
|
542
|
-
rootPk: rootWif
|
|
543
|
-
});
|
|
544
|
-
|
|
545
|
-
// Create new identity and link to old
|
|
546
|
-
const newId = newBap.newId();
|
|
547
|
-
// Create ID transaction pointing from last old address to new...
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
See [Type 42 Migration Guide](../docs/TYPE42_MIGRATION.md) for complete details.
|
|
551
|
-
|
|
552
|
-
## Best Practices
|
|
553
|
-
|
|
554
|
-
1. **Key Security**: Never expose private keys. Use encryption for all exports.
|
|
555
|
-
2. **Attribute Nonces**: Always use random nonces for attributes to prevent dictionary attacks.
|
|
556
|
-
3. **Path Management**: Let the library manage paths unless you have specific requirements.
|
|
557
|
-
4. **Backup Regularly**: Export and securely store identity backups.
|
|
558
|
-
5. **Verify Attestations**: Always verify attestations before trusting identity claims.
|
|
559
|
-
|
|
560
|
-
## Error Handling
|
|
561
|
-
|
|
562
|
-
```typescript
|
|
563
|
-
try {
|
|
564
|
-
const identity = bap.getId(idKey);
|
|
565
|
-
if (!identity) {
|
|
566
|
-
throw new Error('Identity not found');
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
const encrypted = identity.encrypt(data);
|
|
570
|
-
} catch (error) {
|
|
571
|
-
if (error.message.includes('not initialized')) {
|
|
572
|
-
// Handle key initialization errors
|
|
573
|
-
} else if (error.message.includes('not found')) {
|
|
574
|
-
// Handle missing identity
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
## API Reference
|
|
580
|
-
|
|
581
|
-
For protocol-level documentation, see [PROTOCOL.md](../PROTOCOL.md).
|
|
582
|
-
|
|
583
|
-
For blockchain API endpoints, see the [BAP API Documentation](https://api.sigmaidentity.com/docs).
|