From f35f0f5a4ebfae82b1d9d341d697659bf1796088 Mon Sep 17 00:00:00 2001 From: HashMapsData2Value <83883690+HashMapsData2Value@users.noreply.github.com> Date: Sat, 2 Aug 2025 17:11:08 +0200 Subject: [PATCH 1/8] fix: clean up monero folder --- monero/monero_setup.sh | 17 +++++--- monero/monero_utils.py | 95 ------------------------------------------ 2 files changed, 12 insertions(+), 100 deletions(-) delete mode 100644 monero/monero_utils.py diff --git a/monero/monero_setup.sh b/monero/monero_setup.sh index f2e051f..4794792 100644 --- a/monero/monero_setup.sh +++ b/monero/monero_setup.sh @@ -1,9 +1,16 @@ mkdir leakswap_testnet # Setup the two Monero Daemon Nodes -monerod --testnet --data-dir leakswap_testnet/node_01 --p2p-bind-ip 127.0.0.1 --p2p-bind-port 28080 --rpc-bind-port 28081 --zmq-rpc-bind-port 28082 --add-exclusive-node 127.0.0.1:38080 --no-igd --hide-my-port --log-level 0 --fixed-difficulty 100 --disable-rpc-ban -monerod --testnet --data-dir leakswap_testnet/node_02 --p2p-bind-ip 127.0.0.1 --p2p-bind-port 38080 --rpc-bind-port 38081 --zmq-rpc-bind-port 38082 --add-exclusive-node 127.0.0.1:28080 --no-igd --hide-my-port --log-level 0 --fixed-difficulty 100 --disable-rpc-ban +monerod --testnet --data-dir leakswap_testnet/node_01 \ + --p2p-bind-ip 127.0.0.1 --p2p-bind-port 28080 \ + --rpc-bind-port 28081 \ + --rpc-access-control-origins '*' \ + --zmq-rpc-bind-port 28082 --add-exclusive-node 127.0.0.1:38080 \ + --no-igd --hide-my-port --log-level 0 --fixed-difficulty 100 --disable-rpc-ban -# Start up the Monero Wallet RPC -monero-wallet-rpc --testnet --rpc-bind-port 28088 --wallet-dir leakswap_testnet --disable-rpc-login -monero-wallet-rpc --testnet --rpc-bind-port 38088 --wallet-dir leakswap_testnet --disable-rpc-login \ No newline at end of file +monerod --testnet --data-dir leakswap_testnet/node_02 \ + --p2p-bind-ip 127.0.0.1 --p2p-bind-port 38080 \ + --rpc-bind-port 38081 \ + --rpc-access-control-origins '*' \ + --zmq-rpc-bind-port 38082 --add-exclusive-node 127.0.0.1:28080 \ + --no-igd --hide-my-port --log-level 0 --fixed-difficulty 100 --disable-rpc-ban \ No newline at end of file diff --git a/monero/monero_utils.py b/monero/monero_utils.py deleted file mode 100644 index b29b761..0000000 --- a/monero/monero_utils.py +++ /dev/null @@ -1,95 +0,0 @@ -from binascii import unhexlify -from monero.backends.jsonrpc import JSONRPCWallet -from monero.base58 import encode -import secrets - -import utils as u - -def generate_monero_keys(seed_hex=None, env="main"): - l = 2 ** 252 + 27742317777372353535851937790883648493 - # l prime order of the elliptic curve basepoint - - if seed_hex: - seed_dec = int(seed_hex, 16) - spend_sk = u.little_to_big(u.itb(seed_dec)) - else: - spend_sk = u.itb(secrets.randbits(256) % l) - - view_sk = u.itb(u.bti(u.hash256(spend_sk)) % l) - # generate view_sk from spend_sk so we only need to store one key. - - spend_pk = u.get_public_from_secret(spend_sk) - view_pk = u.get_public_from_secret(view_sk) - - - # 18 main chain, 53 test chain, 24 stage chain - if env == "main": - prefix = "12" # hex(18) - elif env == "stage": - prefix = "18" # hex(24) - elif env == "test": - prefix = "35" # hex(53) - - data = prefix + spend_pk.hex() + view_pk.hex() - checksum = u.hash256(bytearray(unhexlify(data)))[:4] - address = data + checksum.hex() - - return [[spend_sk, spend_pk], [view_sk, view_pk]], encode(address) - -def generate_from_keys(wallet_filename, address, spendkey, viewkey, pw): - # Example from https://www.getmonero.org/resources/developer-guides/wallet-rpc.html#generate_from_keys - rpc_server = JSONRPCWallet(port=28088) - result = rpc_server.raw_request(method="generate_from_keys", params={ - "restore_height": 0, - "filename":wallet_filename, - "address":address, - "spendkey":spendkey.hex(), - "viewkey":viewkey.hex(), - "password":pw, - }) - return result - -def get_combined_private_key(partial_private_spend_a, partial_private_spend_b): - return u.scalar_add(partial_private_spend_a, partial_private_spend_b) - -""" -Tests just to check that things work -""" - -def test_monero_address(): - private_spend_key = "39c4b3cc4fa2ccad647990f67e8d84b611d5a15d53225213cc42783f227c4909" - private_view_key = "a86be8c70784ec97a8c8d45212b1ea356759ef1ff1a0983190351c62b14b3500" - public_spend_key = "ca5f63d230d44e6b3420edd2e797e2a18d5fb98e59dc594c02c4fac6441519f8" - public_view_key = "f070076aa7ccf42db141bbf6dfe6131409e34a99766dc5f3db407028efeca65c" - correct_address = "49HupRMMmXsJw1YshMsNJ5U2G2fSCdpu6DiQD7KE9NwSie2HZjD7hBZ8eGsQw2rvQr4MQBngHjNRrhniMht6xzkVBVFTY3M" - - keys, address = generate_monero_keys(seed_hex=private_spend_key) - - assert keys[0][0].hex() == private_spend_key - assert keys[0][1].hex() == public_spend_key - assert keys[1][0].hex() == private_view_key - assert keys[1][1].hex() == public_view_key - assert address == correct_address - - -def test_keys_addition(): - """ - Test that the generated keys can actually be added with each other. - """ - - alice, _ = generate_monero_keys() - bob, _ = generate_monero_keys() - - assert u.points_add(alice[0][1], bob[0][1]) == u.get_public_from_secret(u.scalar_add(alice[0][0], bob[0][0])) - assert u.points_add(alice[1][1], bob[1][1]) == u.get_public_from_secret(u.scalar_add(alice[1][0], bob[1][0])) - - -def test_monero_rpc_generate_from_keys(): - xavier = generate_monero_keys(env="test") - result = generate_from_keys("xavier_wallet", xavier[1], xavier[0][0][0], xavier[0][1][0], "") - assert "Wallet has been generated successfully." in result["info"] - -if __name__ == '__main__': - test_keys_addition() - test_monero_address() - #test_monero_rpc_generate_from_keys() \ No newline at end of file From ceeafeb40a15b2ae6944afcb3555f79214b5864a Mon Sep 17 00:00:00 2001 From: HashMapsData2Value <83883690+HashMapsData2Value@users.noreply.github.com> Date: Sat, 2 Aug 2025 17:15:01 +0200 Subject: [PATCH 2/8] fix: licensing --- LICENSE => algorand/LICENSE | 2 +- algorand/README.md | 23 ++--------------------- requirements.txt | 25 ------------------------- 3 files changed, 3 insertions(+), 47 deletions(-) rename LICENSE => algorand/LICENSE (96%) delete mode 100644 requirements.txt diff --git a/LICENSE b/algorand/LICENSE similarity index 96% rename from LICENSE rename to algorand/LICENSE index 9b14cda..dfb8f21 100644 --- a/LICENSE +++ b/algorand/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 HashMapsData2Value +Copyright (c) 2025 HashMapsData2Value Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/algorand/README.md b/algorand/README.md index c1afc52..9e299f6 100644 --- a/algorand/README.md +++ b/algorand/README.md @@ -1,22 +1,3 @@ -# algorand +# Algorand-part of LeakSwap -Welcome to your new AlgoKit project! - -This is your workspace root. A `workspace` in AlgoKit is an orchestrated collection of standalone projects (backends, smart contracts, frontend apps and etc). - -By default, `projects_root_path` parameter is set to `projects`. Which instructs AlgoKit CLI to create a new directory under `projects` directory when new project is instantiated via `algokit init` at the root of the workspace. - -## Getting Started - -To get started refer to `README.md` files in respective sub-projects in the `projects` directory. - -To learn more about algokit, visit [documentation](https://github.com/algorandfoundation/algokit-cli/blob/main/docs/algokit.md). - -### GitHub Codespaces - -To get started execute: - -1. `algokit generate devcontainer` - invoking this command from the root of this repository will create a `devcontainer.json` file with all the configuration needed to run this project in a GitHub codespace. [Run the repository inside a codespace](https://docs.github.com/en/codespaces/getting-started/quickstart) to get started. -2. `algokit init` - invoke this command inside a github codespace to launch an interactive wizard to guide you through the process of creating a new AlgoKit project - -Powered by [Copier templates](https://copier.readthedocs.io/en/stable/). +Note that everything in this folder is licensed under MIT license. diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 2cbde88..0000000 --- a/requirements.txt +++ /dev/null @@ -1,25 +0,0 @@ -black==22.3.0 -certifi==2022.5.18.1 -cffi==1.15.0 -charset-normalizer==2.0.12 -click==8.1.3 -idna==3.3 -ipaddress==1.0.23 -monero==1.0.2 -msgpack==1.0.3 -mypy-extensions==0.4.3 -pathspec==0.9.0 -platformdirs==2.5.2 -py-algorand-sdk==1.13.1 -pycparser==2.21 -pycryptodome==3.14.1 -pycryptodomex==3.14.1 -PyNaCl==1.5.0 -PySocks==1.7.1 -pyteal==0.10.1 -requests==2.27.1 -six==1.16.0 -tomli==2.0.1 -typing-extensions==4.2.0 -urllib3==1.26.9 -varint==1.0.2 From d14991ce0b39c74398bc90544d9ec2b4f08fda25 Mon Sep 17 00:00:00 2001 From: HashMapsData2Value <83883690+HashMapsData2Value@users.noreply.github.com> Date: Sat, 2 Aug 2025 17:20:40 +0200 Subject: [PATCH 3/8] feat: swap page --- swap-page/.gitignore | 21 + swap-page/README.md | 50 + swap-page/eslint.config.js | 28 + swap-page/index.html | 13 + swap-page/package-lock.json | 4316 +++++++++++++++++++++++ swap-page/package.json | 34 + swap-page/public/monero.worker.js | 3 + swap-page/src/Algorand/AlgorandSide.tsx | 14 + swap-page/src/Algorand/Connect.tsx | 165 + swap-page/src/App.tsx | 16 + swap-page/src/Monero/MoneroSide.tsx | 372 ++ swap-page/src/Monero/base58.ts | 129 + swap-page/src/Monero/toChocoBox2.ts | 101 + swap-page/src/index.css | 0 swap-page/src/main.tsx | 19 + swap-page/src/vite-env.d.ts | 1 + swap-page/tsconfig.app.json | 26 + swap-page/tsconfig.json | 7 + swap-page/tsconfig.node.json | 24 + swap-page/vite.config.ts | 47 + 20 files changed, 5386 insertions(+) create mode 100644 swap-page/.gitignore create mode 100644 swap-page/README.md create mode 100644 swap-page/eslint.config.js create mode 100644 swap-page/index.html create mode 100644 swap-page/package-lock.json create mode 100644 swap-page/package.json create mode 100644 swap-page/public/monero.worker.js create mode 100644 swap-page/src/Algorand/AlgorandSide.tsx create mode 100644 swap-page/src/Algorand/Connect.tsx create mode 100644 swap-page/src/App.tsx create mode 100644 swap-page/src/Monero/MoneroSide.tsx create mode 100644 swap-page/src/Monero/base58.ts create mode 100644 swap-page/src/Monero/toChocoBox2.ts create mode 100644 swap-page/src/index.css create mode 100644 swap-page/src/main.tsx create mode 100644 swap-page/src/vite-env.d.ts create mode 100644 swap-page/tsconfig.app.json create mode 100644 swap-page/tsconfig.json create mode 100644 swap-page/tsconfig.node.json create mode 100644 swap-page/vite.config.ts diff --git a/swap-page/.gitignore b/swap-page/.gitignore new file mode 100644 index 0000000..9c3c215 --- /dev/null +++ b/swap-page/.gitignore @@ -0,0 +1,21 @@ +.vite/ +node_modules/ +dist/ +build/ +.env +.env.* +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +coverage/ +.DS_Store +.parcel-cache/ +.turbo/ +.next/ +out/ +.vercel/ +.cache/ +*.local +*.sublime-workspace +*.sublime-project diff --git a/swap-page/README.md b/swap-page/README.md new file mode 100644 index 0000000..74872fd --- /dev/null +++ b/swap-page/README.md @@ -0,0 +1,50 @@ +# React + TypeScript + Vite + +This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. + +Currently, two official plugins are available: + +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh +- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh + +## Expanding the ESLint configuration + +If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: + +- Configure the top-level `parserOptions` property like this: + +```js +export default tseslint.config({ + languageOptions: { + // other options... + parserOptions: { + project: ['./tsconfig.node.json', './tsconfig.app.json'], + tsconfigRootDir: import.meta.dirname, + }, + }, +}) +``` + +- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` +- Optionally add `...tseslint.configs.stylisticTypeChecked` +- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: + +```js +// eslint.config.js +import react from 'eslint-plugin-react' + +export default tseslint.config({ + // Set the react version + settings: { react: { version: '18.3' } }, + plugins: { + // Add the react plugin + react, + }, + rules: { + // other rules... + // Enable its recommended rules + ...react.configs.recommended.rules, + ...react.configs['jsx-runtime'].rules, + }, +}) +``` diff --git a/swap-page/eslint.config.js b/swap-page/eslint.config.js new file mode 100644 index 0000000..092408a --- /dev/null +++ b/swap-page/eslint.config.js @@ -0,0 +1,28 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true }, + ], + }, + }, +) diff --git a/swap-page/index.html b/swap-page/index.html new file mode 100644 index 0000000..e4b78ea --- /dev/null +++ b/swap-page/index.html @@ -0,0 +1,13 @@ + + +
+ + + +=0;i--){for(var c=e.words[i],u=h-1;u>=0;u--){var l=c>>u&1;n!==r[0]&&(n=this.sqr(n)),0!==l||0!==o?(o<<=1,o|=l,(4==++a||0===i&&0===u)&&(n=this.mul(n,r[o]),a=0,o=0)):a=0}h=26}return n},N.prototype.convertTo=function(t){var e=t.umod(this.m);return e===t?e.clone():e},N.prototype.convertFrom=function(t){var e=t.clone();return e.red=null,e},s.mont=function(t){return new M(t)},n(M,N),M.prototype.convertTo=function(t){return this.imod(t.ushln(this.shift))},M.prototype.convertFrom=function(t){var e=this.imod(t.mul(this.rinv));return e.red=null,e},M.prototype.imul=function(t,e){if(t.isZero()||e.isZero())return t.words[0]=0,t.length=1,t;var r=t.imul(e),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),s=n;return n.cmp(this.m)>=0?s=n.isub(this.m):n.cmpn(0)<0&&(s=n.iadd(this.m)),s._forceRed(this)},M.prototype.mul=function(t,e){if(t.isZero()||e.isZero())return new s(0)._forceRed(this);var r=t.mul(e),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),o=n;return n.cmp(this.m)>=0?o=n.isub(this.m):n.cmpn(0)<0&&(o=n.iadd(this.m)),o._forceRed(this)},M.prototype.invm=function(t){return this.imod(t._invmp(this.m).mul(this.r2))._forceRed(this)}}(t=r.nmd(t),this)},9282:(t,e,r)=>{"use strict";var i=r(4155);function n(t){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},n(t)}function s(t,e){for(var r=0;r =0;i--){for(var c=e.words[i],u=h-1;u>=0;u--){var l=c>>u&1;n!==r[0]&&(n=this.sqr(n)),0!==l||0!==o?(o<<=1,o|=l,(4==++a||0===i&&0===u)&&(n=this.mul(n,r[o]),a=0,o=0)):a=0}h=26}return n},P.prototype.convertTo=function(t){var e=t.umod(this.m);return e===t?e.clone():e},P.prototype.convertFrom=function(t){var e=t.clone();return e.red=null,e},s.mont=function(t){return new T(t)},n(T,P),T.prototype.convertTo=function(t){return this.imod(t.ushln(this.shift))},T.prototype.convertFrom=function(t){var e=this.imod(t.mul(this.rinv));return e.red=null,e},T.prototype.imul=function(t,e){if(t.isZero()||e.isZero())return t.words[0]=0,t.length=1,t;var r=t.imul(e),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),s=n;return n.cmp(this.m)>=0?s=n.isub(this.m):n.cmpn(0)<0&&(s=n.iadd(this.m)),s._forceRed(this)},T.prototype.mul=function(t,e){if(t.isZero()||e.isZero())return new s(0)._forceRed(this);var r=t.mul(e),i=r.maskn(this.shift).mul(this.minv).imaskn(this.shift).mul(this.m),n=r.isub(i).iushrn(this.shift),o=n;return n.cmp(this.m)>=0?o=n.isub(this.m):n.cmpn(0)<0&&(o=n.iadd(this.m)),o._forceRed(this)},T.prototype.invm=function(t){return this.imod(t._invmp(this.m).mul(this.r2))._forceRed(this)}}(t=r.nmd(t),this)},9931:(t,e,r)=>{var i;function n(t){this.rand=t}if(t.exports=function(t){return i||(i=new n(null)),i.generate(t)},t.exports.Rand=n,n.prototype.generate=function(t){return this._rand(t)},n.prototype._rand=function(t){if(this.rand.getBytes)return this.rand.getBytes(t);for(var e=new Uint8Array(t),r=0;r-1&&t%1==0&&t<=z}function D(t){return null!=t&&W(t.length)&&!function(t){if(!a(t))return!1;var e=R(t);return e==A||e==H||e==B||e==L}(t)}var F={};function X(){}function q(t){return function(){if(null!==t){var e=t;t=null,e.apply(this,arguments)}}}var K="function"==typeof Symbol&&Symbol.iterator,C=function(t){return K&&t[K]&&t[K]()};function Z(t){return null!=t&&"object"==typeof t}function U(t){return Z(t)&&"[object Arguments]"==R(t)}var V=Object.prototype,J=V.hasOwnProperty,G=V.propertyIsEnumerable,Y=U(function(){return arguments}())?U:function(t){return Z(t)&&J.call(t,"callee")&&!G.call(t,"callee")},Q=Array.isArray;var _="object"==typeof e&&e&&!e.nodeType&&e,$=_&&t&&!t.nodeType&&t,tt=$&&$.exports===_?S.Buffer:void 0,et=(tt?tt.isBuffer:void 0)||function(){return!1},rt=9007199254740991,it=/^(?:0|[1-9]\d*)$/;function nt(t,e){var r=typeof t;return!!(e=null==e?rt:e)&&("number"==r||"symbol"!=r&&it.test(t))&&t>-1&&t%1==0&&t{for(var e=0,r=0;r=18?(s-=18,o+=1,this.words[o]|=n>>>26):s+=8;else for(i=(t.length-e)%2==0?e+1:e;i>>=1)n++;return 1<o)for(this.length-=o,c=0;c{var i=r(9509).Buffer;function n(t,e,r){var n=t._cipher.encryptBlock(t._prev)[0]^e;return t._prev=i.concat([t._prev.slice(1),i.from([r?e:n])]),n}e.encrypt=function(t,e,r){for(var s=e.length,o=i.allocUnsafe(s),a=-1;++a{var i=r(7295),n=r(9509).Buffer,s=r(685);function o(t){var e=t._cipher.encryptBlockRaw(t._prev);return s(t._prev),e}e.encrypt=function(t,e){var r=Math.ceil(e.length/16),s=t._cache.length;t._cache=n.concat([t._cache,n.allocUnsafe(16*r)]);for(var a=0;at.length)throw new RangeError("Index out of range")}function A(t,e,r,i,n){q(e,i,n,t,r,7);let s=Number(e&BigInt(4294967295));t[r++]=s,s>>=8,t[r++]=s,s>>=8,t[r++]=s,s>>=8,t[r++]=s;let o=Number(e>>BigInt(32)&BigInt(4294967295));return t[r++]=o,o>>=8,t[r++]=o,o>>=8,t[r++]=o,o>>=8,t[r++]=o,r}function H(t,e,r,i,n){q(e,i,n,t,r,7);let s=Number(e&BigInt(4294967295));t[r+7]=s,s>>=8,t[r+6]=s,s>>=8,t[r+5]=s,s>>=8,t[r+4]=s;let o=Number(e>>BigInt(32)&BigInt(4294967295));return t[r+3]=o,o>>=8,t[r+2]=o,o>>=8,t[r+1]=o,o>>=8,t[r]=o,r+8}function L(t,e,r,i,n,s){if(r+i>t.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function z(t,e,r,i,s){return e=+e,r>>>=0,s||L(t,0,r,4),n.write(t,e,r,i,23,4),r+4}function W(t,e,r,i,s){return e=+e,r>>>=0,s||L(t,0,r,8),n.write(t,e,r,i,52,8),r+8}h.prototype.slice=function(t,e){const r=this.length;(t=~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),(e=void 0===e?r:~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),e=49?a-49+10:a>=17?a-17+10:a}return n}s.isBN=function(t){return t instanceof s||null!==t&&"object"==typeof t&&t.constructor.wordSize===s.wordSize&&Array.isArray(t.words)},s.max=function(t,e){return t.cmp(e)>0?t:e},s.min=function(t,e){return t.cmp(e)<0?t:e},s.prototype._init=function(t,e,r){if("number"==typeof t)return this._initNumber(t,e,r);if("object"==typeof t)return this._initArray(t,e,r);"hex"===e&&(e=16),i(e===(0|e)&&e>=2&&e<=36);var n=0;"-"===(t=t.toString().replace(/\s+/g,""))[0]&&(n++,this.negative=1),n=18?(s-=18,o+=1,this.words[o]|=n>>>26):s+=8;else for(i=(t.length-e)%2==0?e+1:e;i=4096&&(r+=13,e>>>=13),e>=64&&(r+=7,e>>>=7),e>=8&&(r+=4,e>>>=4),e>=2&&(r+=2,e>>>=2),r+e},s.prototype._zeroBits=function(t){if(0===t)return 26;var e=t,r=0;return 0==(8191&e)&&(r+=13,e>>>=13),0==(127&e)&&(r+=7,e>>>=7),0==(15&e)&&(r+=4,e>>>=4),0==(3&e)&&(r+=2,e>>>=2),0==(1&e)&&r++,r},s.prototype.bitLength=function(){var t=this.words[this.length-1],e=this._countBits(t);return 26*(this.length-1)+e},s.prototype.zeroBits=function(){if(this.isZero())return 0;for(var t=0,e=0;e>>=1)n++;return 1<o)for(this.length-=o,c=0;c