UNPKG

micro-stacks

Version:

Tiny libraries for building Stacks apps.

67 lines (62 loc) 16 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var ripemd160 = require('@noble/hashes/ripemd160'); var common = require('micro-stacks/common'); var cryptoSha = require('micro-stacks/crypto-sha'); var secp256k1 = require('@noble/secp256k1'); var cryptoAes = require('micro-stacks/crypto-aes'); var cryptoHmacSha = require('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.ripemd160(t):ripemd160.ripemd160.create().update(common.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=cryptoSha.hashSha512(t);return {encryptionKey:e.slice(0,32),hmacKey:e.slice(32)}}function $(t=32){return secp256k1.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=secp256k1.Point.fromHex(common.bytesToHex(t));return new secp256k1.Point(secp256k1.CURVE.Gx,secp256k1.CURVE.Gy).multiply(common.bytesToBigInt(e)).add(r).toRawBytes(Je(t))};function Le(t,e=secp256k1.CURVE.P){let r=t%e;return r>=0?r:e+r}var Rt=(t,e)=>common.intToBytes(Le(common.bytesToBigInt(e)+common.bytesToBigInt(t),secp256k1.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=cryptoSha.hashSha256(o),s=cryptoSha.hashSha256(i).slice(0,4);return n.set(r,0),n.set(t,1),n.set(s,t.length+1),common.encodeB58(n)}function q(t){let e=common.decodeB58(t),r=e.slice(-4),n=cryptoSha.hashSha256(e.slice(0,-4)),o=cryptoSha.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(common.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=common.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=cryptoSha.hashSha256(common.concatByteArrays([Uint8Array.of(t),e]));return cryptoSha.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 common.hexToBytes(s)}function Xt(t){try{return ee(t),!0}catch{return !1}}function cr(t,e=22,r){return qe(common.bytesToHex(secp256k1.getPublicKey(common.ensureHexBytes(t),r)),e)}function qe(t,e=22){return V(e,m(common.ensureHexBytes(t)))}function ar(t){let e=secp256k1.getPublicKey(t,!0),r=cryptoSha.hashSha256(e),n=P(r);return b(n,D.bitcoin.pubKeyHash)}function pr(t){let e=typeof t=="string"?t:common.bytesToHex(t),r=cryptoSha.hashSha256(common.hexToBytes(e)),n=P(r);return b(n,D.bitcoin.pubKeyHash)}function m(t){let e=cryptoSha.hashSha256(t);return P(e)}var fr=t=>common.bytesToHex(m(t)),gr=t=>{let e=m(t),r=new common.BufferArray;r.appendByte(0),r.appendByte(e.length),r.push(e);let n=r.concatBuffer(),o=m(n);return common.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 common.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=cryptoSha.hashSha256(n),i=new common.BufferArray;i.appendByte(0),i.appendByte(o.length),i.push(o);let c=i.concatBuffer(),s=m(c);return common.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 common.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 common.bytesToHex(o)};async function ce(t){let{contents:e,privateKey:r}=t,n=e instanceof ArrayBuffer?common.arrayBufferToUint8(e):typeof e=="string"?common.utf8ToBytes(e):e,o=common.bytesToHex(secp256k1.getPublicKey(r,!0)),i=cryptoSha.hashSha256(n),c=await secp256k1.sign(i,r,{canonical:!1});return {signature:common.bytesToHex(c),publicKey:o}}function xr(t,e=!1){let{contents:r,publicKey:n,signature:o}=t,i=r instanceof ArrayBuffer?common.arrayBufferToUint8(r):typeof r=="string"?common.utf8ToBytes(r):r,c=cryptoSha.hashSha256(i);return secp256k1.verify(o,c,n,{strict:e})}async function ae(t){let{publicKey:e,content:r,cipherTextEncoding:n="hex",wasString:o}=t,i=secp256k1.utils.randomPrivateKey(),c=secp256k1.getPublicKey(i,!0),s=secp256k1.getSharedSecret(i,e,!0);s=s.slice(1);let p=w(s),a=$(16),f=await cryptoAes.aes256CbcEncrypt(a,p.encryptionKey,r),d=common.concatByteArrays([a,c,f]),u=cryptoHmacSha.hmacSha256(p.hmacKey,d),h;if(!n||n==="hex")h=common.bytesToHex(f);else if(n==="base64")h=common.bytesToBase64(f);else throw new Error(`Unexpected cipherTextEncoding "${n}"`);let T={iv:common.bytesToHex(a),ephemeralPK:common.bytesToHex(c),cipherText:h,mac:common.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=secp256k1.getSharedSecret(e,n,!0);o=o.slice(1);let i=w(o),c=common.hexToBytes(r.iv),s;if(!r.cipherTextEncoding||r.cipherTextEncoding==="hex")s=common.hexToBytes(r.cipherText);else if(r.cipherTextEncoding==="base64")s=common.base64ToBytes(r.cipherText);else throw new Error(`Unexpected cipherTextEncoding "${r.cipherText}"`);let p=common.concatByteArrays([c,common.hexToBytes(n),s]),a=cryptoHmacSha.hmacSha256(i.hmacKey,p),f=common.hexToBytes(r.mac);if(!pt(f,a))throw new Error("Decryption failed: failure in MAC check");let d=await cryptoAes.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=common.bytesToHex(secp256k1.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"?common.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(common.bytesToBase64(t)):ge(common.bytesToBase64(new TextEncoder().encode(t)))}function yt(t){let e=common.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"?common.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),common.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+=common.copy(e,a,f,0,r)):f+=common.copy(e,a,f,n,r),a[f++]=I,a[f++]=c,o<0?(a[f++]=0,common.copy(e,a,f,r)):common.copy(e,a,f,r+o),common.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 common.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=cryptoSha.hashSha256(common.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=cryptoSha.hashSha256(common.utf8ToBytes(i));return this.createWithSignedHashSync(e,r,o,i,c)}async createWithSignedHash(e,r,n,o,i){let c=await secp256k1.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=secp256k1.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 secp256k1.verify(common.bytesToHex(common.base64ToBytes(a)),common.bytesToHex(s),this.rawPublicKey,{strict:r})},c=cryptoSha.hashSha256(common.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);secp256k1.verify(common.bytesToHex(common.base64ToBytes(a)),common.bytesToHex(s),this.rawPublicKey,{strict:r})||(o=!1);}),o),c=cryptoSha.hashSha256(common.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"})+"."} Object.defineProperty(exports, 'getPublicKey', { enumerable: true, get: function () { return secp256k1.getPublicKey; } }); exports.BITCOIN_TO_STACKS_NETWORK_VERSION = z; exports.Ripemd160PolyfillDigest = L; exports.STACKS_TO_BITCOIN_NETWORK_VERSION = F; exports.StacksNetworkVersion = X; exports.TokenSigner = Se; exports.TokenVerifier = we; exports.b58ToC32 = Ft; exports.base58checkDecode = q; exports.base58checkEncode = b; exports.c32ToB58 = Qt; exports.c32address = V; exports.c32addressDecode = ee; exports.c32checkDecode = We; exports.c32decode = $e; exports.c32normalize = te; exports.createHashRipemd160 = Ce; exports.createSigningInput = x; exports.createUnsecuredToken = At; exports.decodeToken = wt; exports.decryptContent = Ir; exports.decryptECIES = pe; exports.derivePrivateKey = Rt; exports.derivePublicKey = jt; exports.eciesGetJsonStringLength = Kt; exports.encryptContent = Rr; exports.encryptECIES = ae; exports.equalConstTime = pt; exports.getAesCbcOutputLength = Ae; exports.getBase64OutputLength = Ke; exports.getCipherObjectWrapper = He; exports.getRandomBytes = $; exports.getSignedCipherObjectWrapper = ke; exports.hashP2PKH = fr; exports.hashP2SH = hr; exports.hashP2WPKH = gr; exports.hashP2WSH = dr; exports.hashRipemd160 = P; exports.isCompressedPublicKey = Je; exports.privateKeyToBase58Address = ar; exports.privateKeyToStxAddress = cr; exports.publicKeyToBase58Address = pr; exports.publicKeyToStxAddress = qe; exports.ripemd160 = E; exports.sharedSecretToKeys = w; exports.signECDSA = ce; exports.validateStacksAddress = Xt; exports.verifyECDSA = xr;