UNPKG

micro-stacks

Version:

Tiny libraries for building Stacks apps.

14 lines (11 loc) 14.9 kB
import { ripemd160 } from '@noble/hashes/ripemd160'; import { ensureUint8Array, bytesToHex, bytesToBigInt, intToBytes, encodeB58, decodeB58, concatByteArrays, hexToBytes, ensureHexBytes, BufferArray, arrayBufferToUint8, utf8ToBytes, bytesToBase64, base64ToBytes, MissingParametersError, bytesToBase64Url, copy } from 'micro-stacks/common'; import { hashSha512, hashSha256 } from 'micro-stacks/crypto-sha'; import { utils, Point, CURVE, getPublicKey, sign, verify, getSharedSecret, signSync } from '@noble/secp256k1'; export { getPublicKey } from '@noble/secp256k1'; import { aes256CbcEncrypt, aes256CbcDecrypt } from 'micro-stacks/crypto-aes'; import { hmacSha256 } from 'micro-stacks/crypto-hmac-sha'; function Ae(t){return (Math.floor(t/16)+1)*16}function Ke(t){return Math.ceil(t/3)*4}function He(t){let e={iv:"",ephemeralPK:"",mac:"",cipherText:"",wasString:!!t.wasString};t.cipherTextEncoding==="base64"&&(e.cipherTextEncoding="base64");let r=32,n=66,o=64;return {payloadValuesLength:r+n+o,payloadShell:JSON.stringify(e)}}function ke(t){let e={signature:"",publicKey:"",cipherText:t};return {signedPayloadValuesLength:144+66,signedPayloadShell:JSON.stringify(e)}}function Kt(t){let{payloadShell:e,payloadValuesLength:r}=He(t),n=Ae(t.contentLength),o;if(!t.cipherTextEncoding||t.cipherTextEncoding==="hex")o=n*2;else if(t.cipherTextEncoding==="base64")o=Ke(n);else throw new Error(`Unexpected cipherTextEncoding "${t.cipherTextEncoding}"`);if(t.sign){let{signedPayloadShell:i,signedPayloadValuesLength:c}=ke(e);return i.length+c+r+o}else return e.length+r+o}function E(t){return typeof t=="string"?ripemd160(t):ripemd160.create().update(ensureUint8Array(t)).digest()}var L=class{digest(e){return E(e)}};function Ce(){return new L}function P(t){return Ce().digest(t)}function w(t){let e=hashSha512(t);return {encryptionKey:e.slice(0,32),hmacKey:e.slice(32)}}function $(t=32){return utils.randomBytes(t)}var Je=t=>{let e=t[0];return t.length===32||t.length===33&&(e===2||e===3)},jt=(t,e)=>{let r=Point.fromHex(bytesToHex(t));return new Point(CURVE.Gx,CURVE.Gy).multiply(bytesToBigInt(e)).add(r).toRawBytes(Je(t))};function Le(t,e=CURVE.P){let r=t%e;return r>=0?r:e+r}var Rt=(t,e)=>intToBytes(Le(bytesToBigInt(e)+bytesToBigInt(t),CURVE.n),!1,32);function b(t,e){let r=new Uint8Array([e]),n=new Uint8Array(25),o=new Uint8Array(21);o[0]=e,o.set(t,1);let i=hashSha256(o),s=hashSha256(i).slice(0,4);return n.set(r,0),n.set(t,1),n.set(s,t.length+1),encodeB58(n)}function q(t){let e=decodeB58(t),r=e.slice(-4),n=hashSha256(e.slice(0,-4)),o=hashSha256(n);for(let s=0;s<4;s++)if(o[s]!==r[s])throw new Error("base58 address has invalid checksum");let i=e[0];return {hash:e.slice(1,-4),version:i}}var je={messagePrefix:`Bitcoin Signed Message: `,bech32:"bc",bip32:{public:76067358,private:76066276},pubKeyHash:0,scriptHash:5,wif:128},Re={messagePrefix:`Bitcoin Signed Message: `,bech32:"tb",bip32:{public:70617039,private:70615956},pubKeyHash:111,scriptHash:196,wif:239},D={bitcoin:je,testnet:Re};var X=(o=>(o[o.mainnetP2PKH=22]="mainnetP2PKH",o[o.mainnetP2SH=20]="mainnetP2SH",o[o.testnetP2PKH=26]="testnetP2PKH",o[o.testnetP2SH=21]="testnetP2SH",o))(X||{}),z={[0]:22,[5]:20,[111]:26,[196]:21},F={[22]:0,[20]:5,[26]:111,[21]:196},y="0123456789ABCDEFGHJKMNPQRSTVWXYZ",R=new Map;[...y].forEach((t,e)=>R.set(t,e));var H="0123456789abcdef",j=new Map;[...H].forEach((t,e)=>j.set(t,e));function V(t,e){let r=Y(t,e),n=Me(concatByteArrays([e,r]));return `S${y[t]}${n}`}function Ft(t){let e=q(t),r=e.hash,n=e.version,o=n;return z[n]!==void 0&&(o=z[n]),V(o,r)}function Qt(t){let e=ee(t),r=e[0],n=e[1],o=r;return F[r]!==void 0&&(o=F[r]),b(n,o)}function Me(t){let e=bytesToHex(t),r=[],n=0;for(let s=e.length-1;s>=0;s--)if(n<4){let p=j.get(e[s])>>n,a=0;s!==0&&(a=j.get(e[s-1]));let f=1+n,d=a%(1<<f)<<5-f,u=y[p+d];n=f,r.unshift(u);}else n=0;let o=0;for(let s=0;s<r.length&&r[s]==="0";s++)o++;r=r.slice(o);let i=/^\u0000*/.exec(new TextDecoder().decode(t)),c=i?i[0].length:0;for(let s=0;s<c;s++)r.unshift(y[0]);return r.join("")}function Y(t,e){let r=hashSha256(concatByteArrays([Uint8Array.of(t),e]));return hashSha256(r).slice(0,4)}function ee(t){if(t.length<=5)throw new Error("Invalid c32 address: invalid length");if(t[0]!=="S")throw new Error('Invalid c32 address: must start with "S"');return We(t.slice(1))}function We(t){t=te(t);let e=$e(t.slice(1)),r=t[0],n=R.get(r),o=e.slice(-4),i=Y(n,e.slice(0,-4));for(let c=0;c<o.length;c++)if(o[c]!==i[c])throw new Error("Invalid c32check string: checksum mismatch");return [n,e.slice(0,-4)]}function te(t){return t.toUpperCase().replace(/O/g,"0").replace(/L|I/g,"1")}function $e(t){if(t=te(t),!RegExp(`^[${y}]*$`).exec(t))throw new Error("Not a c32-encoded string");let e=RegExp(`^${y[0]}*`).exec(t),r=e?e[0].length:0,n=[],o=0,i=0;for(let p=t.length-1;p>=0;p--){i===4&&(n.unshift(H[o]),i=0,o=0);let f=(R.get(t[p])<<i)+o,d=H[f%16];if(i+=1,o=f>>4,o>1<<i)throw new Error("Panic error in decoding.");n.unshift(d);}n.unshift(H[o]),n.length%2===1&&n.unshift("0");let c=0;for(let p=0;p<n.length&&n[p]==="0";p++)c++;n=n.slice(c-c%2);let s=n.join("");for(let p=0;p<r;p++)s=`00${s}`;return hexToBytes(s)}function Xt(t){try{return ee(t),!0}catch{return !1}}function cr(t,e=22,r){return qe(bytesToHex(getPublicKey(ensureHexBytes(t),r)),e)}function qe(t,e=22){return V(e,m(ensureHexBytes(t)))}function ar(t){let e=getPublicKey(t,!0),r=hashSha256(e),n=P(r);return b(n,D.bitcoin.pubKeyHash)}function pr(t){let e=typeof t=="string"?t:bytesToHex(t),r=hashSha256(hexToBytes(e)),n=P(r);return b(n,D.bitcoin.pubKeyHash)}function m(t){let e=hashSha256(t);return P(e)}var fr=t=>bytesToHex(m(t)),gr=t=>{let e=m(t),r=new BufferArray;r.appendByte(0),r.appendByte(e.length),r.push(e);let n=r.concatBuffer(),o=m(n);return bytesToHex(o)},dr=(t,e)=>{if(t>15||e.length>15)throw Error("P2WSH multisig address can only contain up to 15 public keys");let r=new BufferArray;r.appendByte(80+t),e.forEach(p=>{r.appendByte(p.length),r.push(p);}),r.appendByte(80+e.length),r.appendByte(174);let n=r.concatBuffer(),o=hashSha256(n),i=new BufferArray;i.appendByte(0),i.appendByte(o.length),i.push(o);let c=i.concatBuffer(),s=m(c);return bytesToHex(s)},hr=(t,e)=>{if(t>15||e.length>15)throw Error("P2SH multisig address can only contain up to 15 public keys");let r=new BufferArray;r.appendByte(80+t),e.forEach(i=>{r.appendByte(i.length),r.push(i);}),r.appendByte(80+e.length),r.appendByte(174);let n=r.concatBuffer(),o=m(n);return bytesToHex(o)};async function ce(t){let{contents:e,privateKey:r}=t,n=e instanceof ArrayBuffer?arrayBufferToUint8(e):typeof e=="string"?utf8ToBytes(e):e,o=bytesToHex(getPublicKey(r,!0)),i=hashSha256(n),c=await sign(i,r,{canonical:!1});return {signature:bytesToHex(c),publicKey:o}}function xr(t,e=!1){let{contents:r,publicKey:n,signature:o}=t,i=r instanceof ArrayBuffer?arrayBufferToUint8(r):typeof r=="string"?utf8ToBytes(r):r,c=hashSha256(i);return verify(o,c,n,{strict:e})}async function ae(t){let{publicKey:e,content:r,cipherTextEncoding:n="hex",wasString:o}=t,i=utils.randomPrivateKey(),c=getPublicKey(i,!0),s=getSharedSecret(i,e,!0);s=s.slice(1);let p=w(s),a=$(16),f=await aes256CbcEncrypt(a,p.encryptionKey,r),d=concatByteArrays([a,c,f]),u=hmacSha256(p.hmacKey,d),h;if(!n||n==="hex")h=bytesToHex(f);else if(n==="base64")h=bytesToBase64(f);else throw new Error(`Unexpected cipherTextEncoding "${n}"`);let T={iv:bytesToHex(a),ephemeralPK:bytesToHex(c),cipherText:h,mac:bytesToHex(u),wasString:o};return n&&n!=="hex"&&(T.cipherTextEncoding=n),T}function pt(t,e){if(t.length!==e.length)return !1;let r=0;for(let n=0;n<t.length;n++)r|=t[n]^e[n];return r===0}async function pe(t){let{privateKey:e,cipherObject:r}=t;if(!r.ephemeralPK)throw Error("No ephemeralPK found in cipher object");let n=r.ephemeralPK,o=getSharedSecret(e,n,!0);o=o.slice(1);let i=w(o),c=hexToBytes(r.iv),s;if(!r.cipherTextEncoding||r.cipherTextEncoding==="hex")s=hexToBytes(r.cipherText);else if(r.cipherTextEncoding==="base64")s=base64ToBytes(r.cipherText);else throw new Error(`Unexpected cipherTextEncoding "${r.cipherText}"`);let p=concatByteArrays([c,hexToBytes(n),s]),a=hmacSha256(i.hmacKey,p),f=hexToBytes(r.mac);if(!pt(f,a))throw new Error("Decryption failed: failure in MAC check");let d=await aes256CbcDecrypt(c,i.encryptionKey,s);return r.wasString?new TextDecoder().decode(d):d}function Ir(t,e){if(!e.privateKey)throw new Error("Private key is required for decryption.");try{let r=JSON.parse(t);return pe({privateKey:e.privateKey,cipherObject:r})}catch(r){throw r instanceof SyntaxError?new Error("Failed to parse encrypted content JSON. The content may not be encrypted. If using getFile, try passing { decrypt: false }."):r}}async function Rr(t,e){let{publicKey:r,privateKey:n,wasString:o}=e,{cipherTextEncoding:i,sign:c}=e;if(!n&&!r)throw new Error("Either public key or private key must be supplied for encryption.");if(!r&&n&&(r=bytesToHex(getPublicKey(n,!0))),typeof o!="boolean"&&(o=typeof t=="string"),!r)throw new Error("micro-stacks/crypto - no public key found to encrypt content");let s=typeof t=="string"?utf8ToBytes(t):t,p=await ae({publicKey:r,content:s,wasString:o,cipherTextEncoding:i});if(!c)return JSON.stringify(p);if(typeof c=="string"&&(n=c),!n)throw new Error("micro-stacks/crypto - need private key to sign contents");let a=await ce({contents:JSON.stringify(p),privateKey:n});return JSON.stringify({...a,cipherText:JSON.stringify(p)})}function ht(t){let r=t.length,n=r%4;if(!n)return t;let o=4-n,i=r+o;return t.padEnd(i,"=")}function ut(t){return t instanceof Uint8Array?ge(bytesToBase64(t)):ge(bytesToBase64(new TextEncoder().encode(t)))}function yt(t){let e=base64ToBytes(mt(t));return new TextDecoder().decode(e)}function mt(t){let e;return t instanceof Uint8Array?e=new TextDecoder().decode(t):e=t,ht(e).replace(/\-/g,"+").replace(/_/g,"/")}function ge(t){return t.replace(/=/g,"").replace(/\+/g,"-").replace(/\//g,"_")}var g={encode:ut,decode:yt};var v=128,ue=0,xt=32,St=16,bt=2,ye=St|xt|ue<<6,I=bt|ue<<6;function me(t){return typeof t=="string"?base64ToBytes(t):t}function _(t){let e=me(t),r=32,n=r+1,o=e.length,i=0;if(e[i++]!==ye)throw new Error('Could not find expected "seq"');let c=e[i++];if(c===(v|1)&&(c=e[i++]),o-i<c)throw new Error('"seq" specified length of "'+c+'", only "'+(o-i)+'" remaining');if(e[i++]!==I)throw new Error('Could not find expected "int" for "r"');let s=e[i++];if(o-i-2<s)throw new Error('"r" specified length of "'+s+'", only "'+(o-i-2)+'" available');if(n<s)throw new Error('"r" specified length of "'+s+'", max of "'+n+'" is acceptable');let p=i;if(i+=s,e[i++]!==I)throw new Error('Could not find expected "int" for "s"');let a=e[i++];if(o-i!==a)throw new Error('"s" specified length of "'+a+'", expected "'+(o-i)+'"');if(n<a)throw new Error('"s" specified length of "'+a+'", max of "'+n+'" is acceptable');let f=i;if(i+=a,i!==o)throw new Error('Expected to consume entire buffer, but "'+(o-i)+'" bytes remain');let d=r-s,u=r-a,h=new Uint8Array(d+s+u+a);for(i=0;i<d;++i)h[i]=0;h.set(e.slice(p+Math.max(-d,0),p+s),i),i=r;for(let T=i;i<T+u;++i)h[i]=0;return h.set(e.slice(f+Math.max(-u,0),f+a),i),bytesToBase64Url(h).replace(/=/g,"")}function de(t,e,r){let n=0;for(;e+n<r&&t[e+n]===0;)++n;return t[e+n]>=v&&--n,n}function M(t){let e=me(t),r=32,n=de(e,0,r),o=de(e,r,e.length),i=r-n,c=r-o,s=1+1+i+1+1+c,p=s<v,a=new Uint8Array((p?2:3)+s),f=0;return a[f++]=ye,p?a[f++]=s:(a[f++]=v|1,a[f++]=s&255),a[f++]=I,a[f++]=i,n<0?(a[f++]=0,f+=copy(e,a,f,0,r)):f+=copy(e,a,f,n,r),a[f++]=I,a[f++]=c,o<0?(a[f++]=0,copy(e,a,f,r)):copy(e,a,f,r+o),bytesToBase64Url(a).replace(/=/g,"")}function x(t,e){let r=[],n=g.encode(JSON.stringify(e));r.push(n);let o=g.encode(JSON.stringify(t));return r.push(o),r.join(".")}var Se=class{tokenType;rawPrivateKey;constructor(e="ES256K",r){if(!r)throw new MissingParametersError("TokenSigner: rawPrivateKey is required to sign a token");this.tokenType="JWT",this.rawPrivateKey=r;}header(e={}){return {...{typ:this.tokenType,alg:"ES256K"},...e}}async sign(e,r=!1,n={}){let o=this.header(n),i=x(e,o),c=hashSha256(utf8ToBytes(i));return this.createWithSignedHash(e,r,o,i,c)}signSync(e,r=!1,n={}){let o=this.header(n),i=x(e,o),c=hashSha256(utf8ToBytes(i));return this.createWithSignedHashSync(e,r,o,i,c)}async createWithSignedHash(e,r,n,o,i){let c=await sign(i,this.rawPrivateKey,{canonical:!1}),s=_(c);return r?{header:[g.encode(JSON.stringify(n))],payload:JSON.stringify(e),signature:[s]}:[o,s].join(".")}createWithSignedHashSync(e,r,n,o,i){let c=signSync(i,this.rawPrivateKey,{canonical:!1}),s=_(c);return r?{header:[g.encode(JSON.stringify(n))],payload:JSON.stringify(e),signature:[s]}:[o,s].join(".")}};var we=class{tokenType;rawPublicKey;constructor(e,r){this.tokenType="JWT",this.rawPublicKey=r;}verify(e,r=!1){return typeof e=="string"?this.verifyCompact(e,r):typeof e=="object"?this.verifyExpanded(e,r):!1}verifyCompact(e,r){let n=e.split("."),o=n[0]+"."+n[1],i=s=>{let p=n[2],a=M(p);return verify(bytesToHex(base64ToBytes(a)),bytesToHex(s),this.rawPublicKey,{strict:r})},c=hashSha256(utf8ToBytes(o));return i(c)}verifyExpanded(e,r){let n=[e.header.join("."),g.encode(e.payload)].join("."),o=!0,i=s=>(e.signature.map(p=>{let a=M(p);verify(bytesToHex(base64ToBytes(a)),bytesToHex(s),this.rawPublicKey,{strict:r})||(o=!1);}),o),c=hashSha256(utf8ToBytes(n));return i(c)}};function wt(t){if(typeof t=="string"){let e=t.split("."),r=JSON.parse(g.decode(e[0])),n=JSON.parse(g.decode(e[1])),o=e[2];return {header:r,payload:n,signature:o}}else if(typeof t=="object"){if(typeof t.payload!="string")throw new Error("Expected token payload to be a base64 or json string");let e=t.payload;t.payload[0]!=="{"&&(e=g.decode(e));let r=[];return t.header.map(n=>{let o=JSON.parse(g.decode(n));r.push(o);}),{header:r,payload:JSON.parse(e),signature:t.signature}}}function At(t){return x(t,{typ:"JWT",alg:"none"})+"."} export { z as BITCOIN_TO_STACKS_NETWORK_VERSION, L as Ripemd160PolyfillDigest, F as STACKS_TO_BITCOIN_NETWORK_VERSION, X as StacksNetworkVersion, Se as TokenSigner, we as TokenVerifier, Ft as b58ToC32, q as base58checkDecode, b as base58checkEncode, Qt as c32ToB58, V as c32address, ee as c32addressDecode, We as c32checkDecode, $e as c32decode, te as c32normalize, Ce as createHashRipemd160, x as createSigningInput, At as createUnsecuredToken, wt as decodeToken, Ir as decryptContent, pe as decryptECIES, Rt as derivePrivateKey, jt as derivePublicKey, Kt as eciesGetJsonStringLength, Rr as encryptContent, ae as encryptECIES, pt as equalConstTime, Ae as getAesCbcOutputLength, Ke as getBase64OutputLength, He as getCipherObjectWrapper, $ as getRandomBytes, ke as getSignedCipherObjectWrapper, fr as hashP2PKH, hr as hashP2SH, gr as hashP2WPKH, dr as hashP2WSH, P as hashRipemd160, Je as isCompressedPublicKey, ar as privateKeyToBase58Address, cr as privateKeyToStxAddress, pr as publicKeyToBase58Address, qe as publicKeyToStxAddress, E as ripemd160, w as sharedSecretToKeys, ce as signECDSA, Xt as validateStacksAddress, xr as verifyECDSA };