├── .github ├── FUNDING.yml └── workflows │ ├── main.yml │ └── release.yml ├── .gitignore ├── .gitmodules ├── App.org ├── App.pdf ├── App.txt ├── COPYING ├── GNUmakefile ├── LICENSE ├── MANIFEST.in ├── README.org ├── README.pdf ├── README.txt ├── SLIP-39-macOS.spec ├── SLIP-39-win32.spec ├── SLIP-39.metadata ├── check-signature └── entitlements.plist ├── SLIP-39.py ├── default.nix ├── dkim-setup ├── fonts_list.py ├── images ├── 1x1-ffffff3f.png ├── 1x1-ffffff7f.png ├── 1x1-ffffffbf.png ├── BIP-39-backup-entropy.png ├── BSC.png ├── BSC.svg ├── BTC.png ├── BTC.svg ├── CRO.png ├── CRO.svg ├── DOGE.png ├── DOGE.svg ├── ETH.png ├── ETH.svg ├── LTC.png ├── LTC.svg ├── SLIP-39.icns ├── SLIP-39.ico ├── SLIP-39.png ├── SLIP-39.svg ├── SLIP39 - Screen Shot 1.png ├── SLIP39 - Screen Shot 1.xcf ├── SLIP39-Example.pdf ├── SLIP39-backup-BIP39.png ├── SLIP39-recover-BIP39-entropy.png ├── SLIP39-recover-BIP39-mnemonic.png ├── XRP.png ├── XRP.svg ├── boo.svg ├── boo2.svg ├── guilloche-center.png ├── guilloche-center.svg ├── paper-wallet-background.svg ├── slip39-cards.png ├── slip39-overview-youtube.png ├── slip39-wallets.png └── slip39.png ├── nixpkgs.nix ├── pyproject.toml ├── pytest.ini ├── requirements-dev.txt ├── requirements-gui.txt ├── requirements-invoice.txt ├── requirements-serial.txt ├── requirements-tests.txt ├── requirements-wallet.txt ├── requirements.txt ├── setup.py ├── shell.nix └── slip39 ├── __init__.py ├── __main__.py ├── api.py ├── api_passphrase_test.py ├── api_test.py ├── cli ├── __init__.py └── __main__.py ├── communications.py ├── communications_test.py ├── defaults.py ├── dependency_test.py ├── generator ├── __init__.py ├── __main__.py └── main.py ├── generator_test.py ├── gui ├── SLIP-39-AS-BIP.org ├── SLIP-39-AS-BIP.txt ├── SLIP-39-CRYPTO.org ├── SLIP-39-CRYPTO.txt ├── SLIP-39-CS.org ├── SLIP-39-CS.txt ├── SLIP-39-EXTENDABLE.org ├── SLIP-39-EXTENDABLE.txt ├── SLIP-39-G-NAME.org ├── SLIP-39-G-NAME.txt ├── SLIP-39-G.org ├── SLIP-39-G.txt ├── SLIP-39-LO.org ├── SLIP-39-LO.txt ├── SLIP-39-PASSPHRASE.org ├── SLIP-39-PASSPHRASE.txt ├── SLIP-39-PF.org ├── SLIP-39-PF.txt ├── SLIP-39-SD.org ├── SLIP-39-SD.txt ├── SLIP-39-SE-SIGS.org ├── SLIP-39-SE-SIGS.txt ├── SLIP-39-SE.org ├── SLIP-39-SE.txt ├── SLIP-39-THRESHOLD.org ├── SLIP-39-THRESHOLD.txt ├── SLIP-39-WALLET.org ├── SLIP-39-WALLET.txt ├── SLIP-39.txt ├── __init__.py ├── __main__.py └── main.py ├── invoice ├── Cryptos │ ├── BNB_32.png │ ├── BTC_32.png │ ├── CRO_32.png │ ├── DOGE_32.png │ ├── ETH_32.png │ ├── LTC_32.png │ └── XRP_32.png ├── MultiSend-solc-v0-4-11.sol ├── MultiSend-solc-v0-5-15.sol ├── MultiTransferEther-solc-v0-5-16.sol ├── Tokens-Ethereum.json ├── Tokens-Goerli.json ├── Tokens.py ├── Tokens │ ├── 1INCH_32.webp │ ├── AGIX_28.webp │ ├── AMB_28.webp │ ├── AMP_32.webp │ ├── ANY_32.webp │ ├── AOA_28.webp │ ├── APE_32.webp │ ├── BAL_32.webp │ ├── BAND_32.webp │ ├── BAT.webp │ ├── BDG.webp │ ├── BIT_32.webp │ ├── BNB_2.webp │ ├── BNT_32.webp │ ├── BTT_32.webp │ ├── BUSD_32.webp │ ├── CEL_28.webp │ ├── CHSB_3.png │ ├── CHZ_28.webp │ ├── CNN_28.webp │ ├── COFI_28.webp │ ├── COMP_32.webp │ ├── CRO_32.webp │ ├── CVX_32.webp │ ├── DACC.png │ ├── DAI_32.webp │ ├── DATx_28.webp │ ├── DENT.webp │ ├── DFI_32.png │ ├── DYDX_32.webp │ ├── ELEC_28.webp │ ├── ELON_32.webp │ ├── ENJ_2.webp │ ├── ENS_32.webp │ ├── EURT_32.webp │ ├── FAIR_28.webp │ ├── FEG_32.webp │ ├── FET_32.webp │ ├── FLOKI_32.webp │ ├── FRAX_32.webp │ ├── FTI_28.png │ ├── FTM_32.webp │ ├── FUEL_28.webp │ ├── FUN_32.webp │ ├── FXS_32.webp │ ├── GALA_32.webp │ ├── GLM_32.webp │ ├── GMT_32.webp │ ├── GNO_32.webp │ ├── GRT_32.webp │ ├── GSE_28.webp │ ├── GTO.webp │ ├── GUSD_28.webp │ ├── HAND_28.png │ ├── HBTC_32.png │ ├── HEX_32.webp │ ├── HOGE_32.webp │ ├── HOT_28.webp │ ├── HT_28.webp │ ├── IHT_28.webp │ ├── IIC_28.png │ ├── IMT_28.png │ ├── IND_28.webp │ ├── IONC_28.png │ ├── IOST_28.webp │ ├── IOTX_28.webp │ ├── IOV_28.webp │ ├── KAN.webp │ ├── KCS_32.webp │ ├── KNC_32.webp │ ├── KUB_28.png │ ├── LDO_32.webp │ ├── LEND_28.webp │ ├── LEO_2.webp │ ├── LINK_32.webp │ ├── LPT_28.webp │ ├── LRC_32.webp │ ├── LXT_28.webp │ ├── LYM_28.webp │ ├── MASK_32.webp │ ├── MATIC_32.webp │ ├── MCO_28.webp │ ├── MITx_32.webp │ ├── MKR.webp │ ├── MWAT_28.webp │ ├── NEAR_32.webp │ ├── NEXO_32.webp │ ├── NXM_32.webp │ ├── OCN_28.webp │ ├── OHM_32.webp │ ├── OKB_28.webp │ ├── OMG_32.webp │ ├── ONE_32.png │ ├── PAI_28.png │ ├── PAXG_32.webp │ ├── PAY_28.webp │ ├── POLY_28.webp │ ├── POWR_2.webp │ ├── PTT_32.png │ ├── QNT_2.webp │ ├── REV_32.webp │ ├── RFR.png │ ├── RNDR_32.webp │ ├── RNT_28.png │ ├── RPL_32.webp │ ├── RSR_32.webp │ ├── SAITAMA_32.webp │ ├── SALT_28.webp │ ├── SAND_32.webp │ ├── SAT_28.png │ ├── SHIB_32.webp │ ├── SLP_32.webp │ ├── SNT.webp │ ├── SNX_32.webp │ ├── SRM_32.webp │ ├── STORJ_32.webp │ ├── STQ_28.webp │ ├── SUSHI_32.webp │ ├── SYN_32.webp │ ├── TEL_28.webp │ ├── THETA_28.webp │ ├── TOS_28.webp │ ├── TUSD_32.webp │ ├── UCASH_28.png │ ├── UNI_32.webp │ ├── USDC_28.webp │ ├── USDD_32.webp │ ├── USDP_32.webp │ ├── USDT_32.webp │ ├── VEN_28.webp │ ├── VIN_28.webp │ ├── WBTC_28.webp │ ├── WETH_28.webp │ ├── WOO_32.webp │ ├── WQTUM_28.png │ ├── XAUt_32.webp │ ├── XCN_32.webp │ ├── XDCE_28.webp │ ├── XEN_32.webp │ ├── XMX_28.webp │ ├── XNN_28.webp │ ├── XYO_2.webp │ ├── YEE_28.png │ ├── YFI_2.webp │ ├── ZIL_2.webp │ ├── ZRX_28.webp │ ├── ZSC_28.png │ ├── aAAVE_32.webp │ ├── anyLTC_32.webp │ ├── cDAI_32.webp │ ├── cETH_28.webp │ ├── cUSDC_28.webp │ ├── cUSDT_32.webp │ ├── nCash_28.webp │ ├── rETH_32.webp │ ├── stETH_32.webp │ ├── stkAAVE_32.webp │ ├── wCELO_32.png │ └── wMANA_32.webp ├── __init__.py ├── artifact.py ├── artifact_test.py ├── artifact_test │ ├── dominionrnd-invoice.png │ ├── dominionrnd-invoice.svg │ ├── dominionrnd-logo.png │ └── dominionrnd-logo.svg ├── bitquery_test.py ├── contracts │ ├── ForwarderERC20.sol │ ├── MultiPayoutERC20.sol │ ├── MultiPayoutERC20.sol-B52FD4-v0.8.17-o100 │ ├── MultiPayoutERC20Base.sol │ └── MultiPayoutERC20Forwarder.sol ├── ethereum.py ├── ethereum_test.py ├── multipayout.py ├── multipayout_test.crypto-keypair-plaintext ├── multipayout_test.machine-id ├── multipayout_test.py ├── payments.py ├── payments_test.py └── payments_test │ └── payments_test.machine-id ├── layout ├── 1x1-ffffff3f.png ├── 1x1-ffffff54.png ├── 1x1-ffffffbf.png ├── BNB.png ├── BTC.png ├── COVER-BIP-39.org ├── COVER-BIP-39.txt ├── COVER-SLIP-39.org ├── COVER-SLIP-39.txt ├── COVER.txt ├── CRO.png ├── DOGE.png ├── ETH.png ├── LTC.png ├── SLIP-39.png ├── XRP.png ├── __init__.py ├── components.py ├── font │ ├── DejaVuSansMono-Bold.ttf │ ├── DejaVuSansMono-BoldOblique.ttf │ ├── DejaVuSansMono-Oblique.ttf │ ├── DejaVuSansMono.ttf │ ├── Inconsolata-Bold.ttf │ ├── Inconsolata-Regular.ttf │ ├── NotoSansMono-Bold.ttf │ ├── NotoSansMono-Regular.ttf │ ├── OFL.txt │ ├── OverpassMono-Bold.ttf │ ├── OverpassMono-Regular.ttf │ ├── SourceCodePro-Bold.ttf │ ├── SourceCodePro-BoldItalic.ttf │ ├── SourceCodePro-Italic.ttf │ └── SourceCodePro-Regular.ttf ├── paper-wallet-background.png ├── pdf.py └── printer.py ├── main.py ├── output_test.py ├── recovery ├── __init__.py ├── __main__.py ├── entropy.py └── main.py ├── recovery_test.csv ├── recovery_test.py ├── util.py ├── util_test.py └── version.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [pjkundert] 2 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Python package 5 | 6 | on: 7 | push: 8 | branches: 9 | - master 10 | - feature-** 11 | - fix-** 12 | pull_request: 13 | branches: 14 | - master 15 | 16 | jobs: 17 | build: 18 | 19 | runs-on: ubuntu-24.04 20 | strategy: 21 | matrix: 22 | # Requires Python3 w/ Type Annotations 23 | python-version: ['3.9', '3.10', '3.11', '3.12'] 24 | 25 | steps: 26 | - name: Checkout repository code 27 | uses: actions/checkout@master 28 | - name: Update openssl 29 | run: | 30 | #sudo apt-get update 31 | #sudo apt-get -y install openssl 32 | openssl version 33 | openssl 34 | - name: Set up Python ${{ matrix.python-version }} 35 | uses: actions/setup-python@master 36 | with: 37 | python-version: ${{ matrix.python-version }} 38 | - name: Install dependencies 39 | run: | 40 | python3 -m pip install .[all,tests] 41 | - name: Lint with flake8 42 | run: | 43 | make analyze 44 | - name: Test with pytest 45 | run: | 46 | make test 47 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | pypi-publish: 10 | if: startsWith(github.ref, 'refs/tags') 11 | name: Upload release to PyPI 12 | runs-on: ubuntu-latest 13 | environment: 14 | name: pypi 15 | url: https://pypi.org/p/python-slip39 16 | permissions: 17 | id-token: write # IMPORTANT: this permission is mandatory for trusted publishing 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v3 21 | - name: Set up Python 22 | uses: actions/setup-python@v4 23 | - name: Build 24 | run: | 25 | python -m pip install -r requirements-dev.txt 26 | python -m build . 27 | - name: Publish package distributions to PyPI 28 | uses: pypa/gh-action-pypi-publish@release/v1 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.log.* 3 | *.log 4 | 5 | # Archive files 6 | *.tgz 7 | *.tar 8 | 9 | # Editor temporaries 10 | *~ 11 | .#* 12 | 13 | # System generated files 14 | .DS_Store 15 | 16 | *.tex 17 | *.aux 18 | *.toc 19 | auto/ 20 | *.out 21 | build/ 22 | MANIFEST 23 | dist/ 24 | *.egg-info/ 25 | .vagrant 26 | .pytest_cache/ 27 | .cache/ 28 | .eggs 29 | private_keys 30 | images/SLIP-39.iconset 31 | .coverage* 32 | /SLIP39-20*.pdf 33 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "slip39/invoice/openzeppelin-contracts"] 2 | path = slip39/invoice/openzeppelin-contracts 3 | url = https://github.com/OpenZeppelin/openzeppelin-contracts.git 4 | -------------------------------------------------------------------------------- /App.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/App.pdf -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Slip39 is distributed under the GNU General Public License version 3 (or later) 2 | and is also available under alternative licenses negotiated directly with 3 | Dominion Research & Development Corp. If you obtained slip39 under the GPL, 4 | then the GPL applies to all slip39 modules used on your system as well, except 5 | as defined below. The GPL (version 3) is included in this source tree in the 6 | file COPYING. 7 | 8 | Dominion Research & Development Corp. holds copyright and/or sufficient 9 | licenses to all components of the slip39 package, and therefore can grant, at 10 | its sole discretion, the ability for companies, individuals, or organizations 11 | to create proprietary or Open Source (even if not GPL) modules which may use at 12 | runtime the portions of slip39 which fall under our copyright/license umbrella, 13 | or are distributed under more flexible licenses than GPL. 14 | 15 | If you wish to use our code in other GPL programs, don't worry -- there is no 16 | requirement that you provide the same exception in your GPL'd products. 17 | 18 | If you have any questions regarding our licensing policy, please contact us: 19 | 20 | +1.780.970.8148 21 | perry@dominionrnd.com 22 | Dominion Research & Development Corp. 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # Both sdist and bdist include these files 2 | include LICENSE 3 | include COPYING 4 | include README.org 5 | include README.pdf 6 | include README.txt 7 | include requirements*.txt 8 | global-exclude *~ 9 | -------------------------------------------------------------------------------- /README.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/README.pdf -------------------------------------------------------------------------------- /SLIP-39-macOS.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | from PyInstaller.utils.hooks import collect_data_files 3 | 4 | datas = [] 5 | datas += collect_data_files('shamir_mnemonic') 6 | datas += collect_data_files('slip39') 7 | 8 | block_cipher = None 9 | 10 | a = Analysis( 11 | ['SLIP-39.py'], 12 | pathex=[], 13 | binaries=[], 14 | datas=datas, 15 | hiddenimports=['slip39'], 16 | hookspath=[], 17 | hooksconfig={}, 18 | runtime_hooks=[], 19 | excludes=[], 20 | win_no_prefer_redirects=False, 21 | win_private_assemblies=False, 22 | cipher=block_cipher, 23 | noarchive=False, 24 | ) 25 | 26 | pyz = PYZ( 27 | a.pure, 28 | a.zipped_data, 29 | cipher=block_cipher, 30 | ) 31 | 32 | exe = EXE( 33 | pyz, 34 | a.scripts, 35 | a.binaries, 36 | a.datas, 37 | [], 38 | name='SLIP-39', 39 | debug=False, 40 | bootloader_ignore_signals=False, 41 | strip=False, 42 | upx=True, 43 | upx_exclude=[], 44 | runtime_tmpdir=None, 45 | console=False, 46 | disable_windowed_traceback=False, 47 | argv_emulation=False, 48 | target_arch=None, 49 | codesign_identity='EAA134BE299C43D27E33E2B8645FF4CF55DE8A92', 50 | entitlements_file=None, 51 | icon='images/SLIP-39.icns', 52 | ) 53 | 54 | app = BUNDLE( 55 | exe, 56 | name='SLIP-39.app', 57 | icon='images/SLIP-39.icns', 58 | version='11.2.1', 59 | info_plist={ 60 | 'NSPrincipalClass': 'NSApplication', 61 | 'NSAppleScriptEnabled': False, 62 | 'LSBackgroundOnly': False, 63 | 'NSRequiresAquaSystemAppearance': 'No', 64 | 'CFBundleSupportedPlatforms': ['MacOSX'], 65 | 'CFBundleIdentifier': 'ca.kundert.perry.SLIP39', 66 | 'CFBundleVersion':'11.2.1', 67 | 'CFBundlePackageType':'APPL', 68 | 'LSApplicationCategoryType':'public.app-category.utilities', 69 | 'LSMinimumSystemVersion':'10.15', 70 | 'NSHumanReadableCopyright':"Copyright © 2023 Perry Kundert.", 71 | 'ITSAppUsesNonExemptEncryption': False, 72 | }, 73 | bundle_identifier='ca.kundert.perry.SLIP39', 74 | ) 75 | -------------------------------------------------------------------------------- /SLIP-39-win32.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | from PyInstaller.utils.hooks import collect_data_files 3 | 4 | datas = [] 5 | datas += collect_data_files('shamir_mnemonic') 6 | datas += collect_data_files('slip39') 7 | 8 | block_cipher = None 9 | 10 | a = Analysis( 11 | ['SLIP-39.py'], 12 | pathex=[], 13 | binaries=[], 14 | datas=datas, 15 | hiddenimports=['slip39'], 16 | hookspath=[], 17 | hooksconfig={}, 18 | runtime_hooks=[], 19 | excludes=[], 20 | win_no_prefer_redirects=False, 21 | win_private_assemblies=False, 22 | cipher=block_cipher, 23 | noarchive=False, 24 | ) 25 | 26 | pyz = PYZ( 27 | a.pure, 28 | a.zipped_data, 29 | cipher=block_cipher, 30 | ) 31 | 32 | exe = EXE( 33 | pyz, 34 | a.scripts, 35 | a.binaries, 36 | a.zipfiles, 37 | a.datas, 38 | [], 39 | name='SLIP-39', 40 | debug=False, 41 | bootloader_ignore_signals=False, 42 | strip=False, 43 | upx=True, 44 | upx_exclude=[], 45 | runtime_tmpdir=None, 46 | console=False, 47 | disable_windowed_traceback=False, 48 | argv_emulation=False, 49 | target_arch=None, 50 | codesign_identity=None, 51 | entitlements_file=None, 52 | ) 53 | -------------------------------------------------------------------------------- /SLIP-39.metadata/check-signature: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2011-2014 Apple Inc. All Rights Reserved. 4 | 5 | # IMPORTANT NOTE: This file is licensed only for use on Apple-branded 6 | # computers and is subject to the terms and conditions of the Apple Software 7 | # License Agreement accompanying the package this file is a part of. 8 | # You may not port this file to another platform without Apple's written consent. 9 | 10 | >&2 echo "(c) 2014 Apple Inc. All rights reserved." 11 | 12 | bundle_installer_requirements='(anchor apple generic and 13 | certificate 1[subject.CN] = "Apple Software Update Certification Authority") or 14 | (anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.10] exists) or 15 | (anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists and 16 | (certificate leaf[field.1.2.840.113635.100.6.1.14] or 17 | certificate leaf[field.1.2.840.113635.100.6.1.13]))' 18 | 19 | app_requirements='(anchor apple) or 20 | (anchor apple generic and certificate leaf[field.1.2.840.113635.100.6.1.9] exists) or 21 | (anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] exists 22 | and certificate leaf[field.1.2.840.113635.100.6.1.13] exists)' 23 | 24 | codesign=/usr/bin/codesign 25 | 26 | build_version=$(sw_vers -buildVersion) 27 | v1=$(sed 's/^\([0-9]*\).*/\1/' <<< $build_version) 28 | v2=$(sed 's/^[0-9]*\([A-Z]\).*/\1/' <<< $build_version) 29 | 30 | if [[ "$v1" -lt 13 || ( "$v1" -eq 13 && "$v2" < "F" ) ]]; then 31 | >&2 echo "This tool requires OS X Version 10.9.5 or higher." 32 | exit 3 33 | fi 34 | 35 | ok=1 36 | for target; do 37 | use_codesign=1 38 | 39 | if [[ $target == *.pkg || $target == *.mpkg ]]; then 40 | if [[ -d $target ]]; then 41 | >&2 echo "${target}: Warning: bundle installers are deprecated, please use regular installer packages." 42 | requirements=$bundle_installer_requirements 43 | else 44 | use_codesign=0 45 | 46 | pkgutil_output=$(pkgutil --check-signature "$target" 2>&1) 47 | result=$? 48 | 49 | [ $result -ne 0 ] && >&2 echo $pkgutil_output 50 | fi 51 | else 52 | requirements=$app_requirements 53 | fi 54 | 55 | if [[ $use_codesign -eq 1 ]]; then 56 | $codesign -v --deep -R="${requirements}" "$target" 57 | result=$? 58 | 59 | if [[ $result -eq 3 ]]; then 60 | >&2 echo "${target}: The target is not signed with Developer ID or by the Mac App Store." 61 | fi 62 | fi 63 | 64 | [ $# -ne 1 ] && echo -n "${target}: " 65 | if [[ $result -eq 0 ]]; then 66 | echo YES 67 | else 68 | echo NO 69 | ok=0 70 | fi 71 | done 72 | 73 | [ $ok -eq 1 ] && exit 0 || exit 2 74 | -------------------------------------------------------------------------------- /SLIP-39.metadata/entitlements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.files.user-selected.read-write 6 | 7 | 10 | com.apple.security.cs.allow-jit 11 | com.apple.security.cs.allow-unsigned-executable-memory 12 | com.apple.security.cs.disable-library-validation 13 | 14 | 15 | -------------------------------------------------------------------------------- /SLIP-39.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python3 2 | 3 | import sys 4 | 5 | from slip39.gui.main import main 6 | 7 | sys.exit( main() ) 8 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import ./nixpkgs.nix {} }: 2 | 3 | with pkgs; 4 | 5 | let 6 | in 7 | { 8 | py313 = stdenv.mkDerivation rec { 9 | name = "python313-with-pytest"; 10 | 11 | buildInputs = [ 12 | cacert 13 | git 14 | gnumake 15 | openssh 16 | python313Full 17 | python313Packages.pytest 18 | python313Packages.tkinter 19 | ]; 20 | }; 21 | 22 | py312 = stdenv.mkDerivation rec { 23 | name = "python312-with-pytest"; 24 | 25 | buildInputs = [ 26 | cacert 27 | git 28 | gnumake 29 | openssh 30 | python312Full 31 | python312Packages.pytest 32 | python312Packages.tkinter 33 | ]; 34 | }; 35 | 36 | py311 = stdenv.mkDerivation rec { 37 | name = "python311-with-pytest"; 38 | 39 | buildInputs = [ 40 | cacert 41 | git 42 | gnumake 43 | openssh 44 | python311Full 45 | python311Packages.pytest 46 | python311Packages.tkinter 47 | ]; 48 | }; 49 | 50 | py310 = stdenv.mkDerivation rec { 51 | name = "python310-with-pytest"; 52 | 53 | buildInputs = [ 54 | cacert 55 | git 56 | gnumake 57 | openssh 58 | python310Full 59 | python310Packages.pytest 60 | python310Packages.tkinter 61 | ]; 62 | }; 63 | 64 | py39 = stdenv.mkDerivation rec { 65 | name = "python39-with-pytest"; 66 | 67 | buildInputs = [ 68 | cacert 69 | git 70 | gnumake 71 | openssh 72 | python39Full 73 | python39Packages.pytest 74 | python39Packages.tkinter 75 | ]; 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /dkim-setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # 4 | # dkim-setup 5 | # 6 | # See: https://russell.ballestrini.net/quickstart-to-dkim-sign-email-with-python/ 7 | # 8 | # Create a new Email DKIM key for your company's licensing... subdomin, eg. 9 | # 10 | # licensing.awesome-inc.com 11 | # 12 | 13 | # This sub-domain exists solely to host a DKIM key to validate emails 14 | # generated by the company's product's Licensing verification code. 15 | 16 | # Signs an Email envelope for the singular purpose of sending Licensing 17 | # messages. This allows your software to send an SMTP email claiming to be from 18 | # the domain licensing.awesome-inc.com; DKIM-signed fields are indicated 19 | # by >: 20 | 21 | # 22 | # > From: no-reply@licensing.awesome-inc.com 23 | # > To: licensing@awesome-inc.com 24 | # Reply-To: some.client@example.com 25 | # > Subject: "Something Awesome" License: 123456 26 | # 27 | # > Dear Something Awesome Client; 28 | # > 29 | # > Your unique Client ID the Subject: line of this email. 30 | # > 31 | # > Please enter this Client ID when prompted, to complete your Licensing 32 | # > procedure for Example Inc's Awesome Product. Once you've entered 33 | # > the Client ID above, you will be authorized to use Something Awesome. 34 | # > 35 | # > Thanks, 36 | # > -- 37 | # > Something Awesome 38 | # > Product Support 39 | # > support@awesome-inc.com 40 | # 41 | 42 | # The From/To and body are signed, the the Subject: is not, because we must 43 | # send a different Client ID in each email's Subject: line. An auto-responder 44 | # must be set up on your Company's (eg. awesome-inc.com) email server, for the 45 | # new "licensing" recipient email address: 46 | 47 | # 48 | # licensing@awesome-inc.com 49 | # 50 | 51 | 52 | 53 | # Each email arriving at licensing@awesome-inc.com must simply be bounced 54 | # back to the Reply-To: address indicated. This accomplishes: 55 | 56 | # 1) Informs licensing@awesome-inc.com of the potential new client's email 57 | # address + Client ID, which are used to generate the MultiPayoutERC20 58 | # contract's .forwarder_address(), generating the unique Cryptocurrency 59 | # account address into which the client will deposit their payment. 60 | 61 | # 2) Ensures that the client has personal control over the indicated email 62 | # address, preventing the generation of "Spam" installations and allow 63 | # communications with the client. Even though your product itself generates 64 | # the unique ID, it demands that the client receive it via email to complete 65 | # the verification, because the email address is used as part of the hash, 66 | # and we do not want people using the same email address, or other people's 67 | # email addresses. 68 | 69 | KTYPE="rsa" # "ed25519" # but not well supported yet; even by Cloudflare 70 | 71 | COMPANY="" 72 | while [ "${COMPANY}" == "" ]; do 73 | echo -n "What is your company's name: " 74 | read COMPANY 75 | done 76 | 77 | DOMAIN="" 78 | while [ "${DOMAIN}" == "" ]; do 79 | echo -n "What is your domain name: " 80 | read DOMAIN 81 | done 82 | 83 | SUB="licensing" 84 | 85 | # See if we've already got a DKIM .dns/.key pair w/ a certain "selector"; 86 | # If not, create one with the present date 87 | SELECTOR="" 88 | for f in $( ls -1 ${SUB}.${DOMAIN}.*.dns | sort | tail -1 ); do 89 | f=${f%.dns} 90 | SELECTOR=${f#${SUB}.${DOMAIN}.} 91 | done 92 | if [ -z "${SELECTOR}" ]; then 93 | SELECTOR=$( date +%Y%m%d ) 94 | fi 95 | TXTFILE="${SUB}.${DOMAIN}.${SELECTOR}.dns" 96 | if [ ! -r "${TXTFILE}" ]; then 97 | dknewkey --ktype ${KTYPE} ${SUB}.${DOMAIN}.${SELECTOR} 98 | fi 99 | ls -l ${TXTFILE} 100 | 101 | echo "Found DKIM key: $( cat ${TXTFILE} )" 102 | 103 | # See if it's installed in DNS. Dig always returns TXT as string literals: "..." 104 | TXTREC="${SELECTOR}._domainkey.${SUB}.${DOMAIN}" 105 | echo -n "Checking DNS at ${TXTREC} ..." 106 | TXT=$( python3 -m crypto_licensing.licensing.doh --no-json dig ${TXTREC} TXT ) 107 | echo ${TXT} 108 | 109 | if (( $? )); then 110 | echo "Failed attempting to query DNS for ${TXTREC}"; 111 | exit 1 112 | elif [ -z "${TXT}" ]; then 113 | echo "No TXT record found at ${TXTREC}" 114 | exit 1 115 | elif ! echo -n ${TXT//\"} | diff ${TXTFILE} -; then 116 | echo "${TXTFILE} doesn't match ${TXTREC} TXT record" 117 | exit 1 118 | fi 119 | 120 | echo "DKIM properly set up for ${TXTREC}: ${TXT}" 121 | -------------------------------------------------------------------------------- /fonts_list.py: -------------------------------------------------------------------------------- 1 | from tkinter import Tk, font 2 | import PySimpleGUI as sg 3 | root = Tk() 4 | font_tuple = font.families() 5 | #Creates a Empty list to hold font names 6 | FontList=[] 7 | fonts = [font.Font(family=f) for f in font.families()] 8 | monospace = (f for f in fonts if f.metrics("fixed")) 9 | # for font in font_tuple: 10 | # FontList.append(font) 11 | for font in monospace: 12 | FontList.append(font.actual('family')) 13 | root.destroy() 14 | print( '\n'.join( FontList )) 15 | 16 | #size 28, 28 is optimized for my Android phone please tweak as per your screen 17 | #Scrolled popup to accommodate big list 18 | sg.popup_scrolled(FontList, title='All fonts installed using PySimpleGUI', size=(28,28), grab_anywhere=True) 19 | 20 | -------------------------------------------------------------------------------- /images/1x1-ffffff3f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/1x1-ffffff3f.png -------------------------------------------------------------------------------- /images/1x1-ffffff7f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/1x1-ffffff7f.png -------------------------------------------------------------------------------- /images/1x1-ffffffbf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/1x1-ffffffbf.png -------------------------------------------------------------------------------- /images/BIP-39-backup-entropy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/BIP-39-backup-entropy.png -------------------------------------------------------------------------------- /images/BSC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/BSC.png -------------------------------------------------------------------------------- /images/BSC.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 35 | 37 | 40 | 43 | 44 | 45 | 50 | 54 | 57 | 61 | 62 | 65 | 69 | 70 | 73 | 77 | 78 | 81 | 85 | 86 | 89 | 93 | 94 | 97 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /images/BTC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/BTC.png -------------------------------------------------------------------------------- /images/BTC.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 17 | 37 | 43 | 47 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /images/CRO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/CRO.png -------------------------------------------------------------------------------- /images/CRO.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /images/DOGE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/DOGE.png -------------------------------------------------------------------------------- /images/DOGE.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 39 | 46 | 49 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /images/ETH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/ETH.png -------------------------------------------------------------------------------- /images/ETH.svg: -------------------------------------------------------------------------------- 1 | 2 | 17 | 19 | 39 | 47 | 53 | 57 | 61 | 64 | 68 | 71 | 75 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /images/LTC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/LTC.png -------------------------------------------------------------------------------- /images/LTC.svg: -------------------------------------------------------------------------------- 1 | 2 | 21 | 23 | 47 | litecoin-ltc-logo 49 | 55 | 62 | 64 | 65 | 67 | litecoin-ltc-logo 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /images/SLIP-39.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/SLIP-39.icns -------------------------------------------------------------------------------- /images/SLIP-39.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/SLIP-39.ico -------------------------------------------------------------------------------- /images/SLIP-39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/SLIP-39.png -------------------------------------------------------------------------------- /images/SLIP39 - Screen Shot 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/SLIP39 - Screen Shot 1.png -------------------------------------------------------------------------------- /images/SLIP39 - Screen Shot 1.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/SLIP39 - Screen Shot 1.xcf -------------------------------------------------------------------------------- /images/SLIP39-Example.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/SLIP39-Example.pdf -------------------------------------------------------------------------------- /images/SLIP39-backup-BIP39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/SLIP39-backup-BIP39.png -------------------------------------------------------------------------------- /images/SLIP39-recover-BIP39-entropy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/SLIP39-recover-BIP39-entropy.png -------------------------------------------------------------------------------- /images/SLIP39-recover-BIP39-mnemonic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/SLIP39-recover-BIP39-mnemonic.png -------------------------------------------------------------------------------- /images/XRP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/XRP.png -------------------------------------------------------------------------------- /images/XRP.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16 | 35 | 37 | 40 | 43 | 44 | 45 | 50 | 54 | 57 | 61 | 62 | 65 | 69 | 70 | 73 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /images/boo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /images/boo2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /images/guilloche-center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/guilloche-center.png -------------------------------------------------------------------------------- /images/slip39-cards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/slip39-cards.png -------------------------------------------------------------------------------- /images/slip39-overview-youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/slip39-overview-youtube.png -------------------------------------------------------------------------------- /images/slip39-wallets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/slip39-wallets.png -------------------------------------------------------------------------------- /images/slip39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/images/slip39.png -------------------------------------------------------------------------------- /nixpkgs.nix: -------------------------------------------------------------------------------- 1 | import (fetchTarball { 2 | url = "https://github.com/NixOS/nixpkgs/archive/refs/tags/23.11.tar.gz"; 3 | sha256 = "1ndiv385w1qyb3b18vw13991fzb9wg4cl21wglk89grsfsnra41k"; 4 | }) 5 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools >= 40.9.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | -------------------------------------------------------------------------------- /pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | testpaths = slip39 3 | addopts = -v --ignore-glob=**/__main__.py --ignore-glob=**/main.py --ignore-glob=**/ethereum.py --cov=slip39 --cov-config=.coveragerc 4 | -------------------------------------------------------------------------------- /requirements-dev.txt: -------------------------------------------------------------------------------- 1 | build 2 | cx_Freeze >=6.12 3 | setuptools 4 | wheel 5 | -------------------------------------------------------------------------------- /requirements-gui.txt: -------------------------------------------------------------------------------- 1 | pysimplegui >=5.0.7,<5.1 2 | -------------------------------------------------------------------------------- /requirements-invoice.txt: -------------------------------------------------------------------------------- 1 | eth-account >=0.8.0,<0.9 2 | py-solc-x >=1.1.1,<1.2 3 | pycryptodome >=3.16, <4 4 | requests >=2.20, <3 5 | 6 | dkimpy[ed25519] >=1.0.5,<2 7 | 8 | # These versions are very brittle; must be upgraded in lock-step (see web3.py/setup.py) 9 | # 6.0.0b9 10 | #web3[tester] ==6.0.0b9 11 | #eth-tester[py-evm] ==v0.8.0-b.3 12 | # Until ethpm upgrade to avoid dependency 13 | #ipfshttpclient ; python_version >= "3.11" 14 | 15 | # 6.6.1 16 | web3[tester] ==6.8.0 17 | eth-tester[py-evm] ==v0.9.1-b.1 18 | # Until ethpm upgrade to avoid dependency 19 | #ipfshttpclient = 0.8.0a2 20 | -------------------------------------------------------------------------------- /requirements-serial.txt: -------------------------------------------------------------------------------- 1 | pyserial >=3.5 2 | -------------------------------------------------------------------------------- /requirements-tests.txt: -------------------------------------------------------------------------------- 1 | aiosmtpd >=1.4, <2 2 | build 3 | cx_Freeze >=6.12 4 | flake8 5 | pyinstaller >=6.1 6 | pytest >=7.4.2,<8 7 | pytest-cov >=4.1.0,<5 8 | setuptools 9 | wheel 10 | -------------------------------------------------------------------------------- /requirements-wallet.txt: -------------------------------------------------------------------------------- 1 | eth-account >=0.8.0,<0.9 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | base58 >=2.0.1,<3 2 | chacha20poly1305 >=0.0.3 3 | click >=8.1.3,<9 4 | crypto-licensing >=3.3.2,<4 5 | cx_Freeze >=6.12 ; sys_platform == "win32" 6 | fpdf2 >=2.7.6,<3 7 | #hdwallet >=2.3.0,<3 8 | hdwallet-slip39 >=2.3.0,<3 9 | #tabulate >=0.10.0 10 | tabulate-slip39 >=0.10.0 11 | mnemonic >=0.21, <1 12 | qrcode >=7.3 13 | #shamir-mnemonic >=0.3.0,<0.4 14 | shamir-mnemonic-slip39 >=0.4.0,<0.5 15 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import ./nixpkgs.nix {} }: 2 | 3 | let 4 | targets = import ./default.nix { 5 | inherit pkgs; 6 | }; 7 | targeted = builtins.getEnv "TARGET"; 8 | selected = targeted + pkgs.lib.optionalString (targeted == "") "py312"; 9 | in 10 | 11 | with pkgs; 12 | 13 | mkShell { 14 | buildInputs = lib.getAttrFromPath [ selected "buildInputs" ] targets; 15 | 16 | shellHook = '' 17 | echo "Welcome to the Python ${selected} environment!" 18 | ''; 19 | } 20 | -------------------------------------------------------------------------------- /slip39/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Python-slip39 -- Ethereum SLIP-39 Account Generation and Recovery 4 | # 5 | # Copyright (c) 2022, Dominion Research & Development Corp. 6 | # 7 | # Python-slip39 is free software: you can redistribute it and/or modify it under 8 | # the terms of the GNU General Public License as published by the Free Software 9 | # Foundation, either version 3 of the License, or (at your option) any later 10 | # version. It is also available under alternative (eg. Commercial) licenses, at 11 | # your option. See the LICENSE file at the top of the source tree. 12 | # 13 | # Python-slip39 is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 16 | # 17 | 18 | from __future__ import annotations 19 | 20 | __author__ = "Perry Kundert" 21 | __email__ = "perry@dominionrnd.com" 22 | __copyright__ = "Copyright (c) 2022 Dominion Research & Development Corp." 23 | __license__ = "Dual License: GPLv3 (or later) and Commercial (see LICENSE)" 24 | 25 | from .version import __version__, __version_info__ # noqa F401 26 | from .api import * # noqa F403 27 | from .layout import * # noqa F403 28 | from .recovery import * # noqa F403 29 | -------------------------------------------------------------------------------- /slip39/__main__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from .main import main 4 | 5 | sys.exit( main() ) 6 | -------------------------------------------------------------------------------- /slip39/cli/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Python-slip39 -- Ethereum SLIP-39 Account Generation and Recovery 4 | # 5 | # Copyright (c) 2022, Dominion Research & Development Corp. 6 | # 7 | # Python-slip39 is free software: you can redistribute it and/or modify it under 8 | # the terms of the GNU General Public License as published by the Free Software 9 | # Foundation, either version 3 of the License, or (at your option) any later 10 | # version. It is also available under alternative (eg. Commercial) licenses, at 11 | # your option. See the LICENSE file at the top of the source tree. 12 | # 13 | # Python-slip39 is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 16 | # 17 | 18 | from __future__ import annotations 19 | 20 | import click 21 | import json 22 | import logging 23 | import string 24 | 25 | from .. import addresses as slip39_addresses 26 | from ..util import commas, log_cfg, log_level, input_secure 27 | from ..defaults import BITS 28 | 29 | __author__ = "Perry Kundert" 30 | __email__ = "perry@dominionrnd.com" 31 | __copyright__ = "Copyright (c) 2022 Dominion Research & Development Corp." 32 | __license__ = "Dual License: GPLv3 (or later) and Commercial (see LICENSE)" 33 | 34 | """ 35 | Provide basic CLI access to the slip39 API. 36 | 37 | Output generally defaults to JSON. Use -v for more details, and --no-json to emit standard text output instead. 38 | """ 39 | 40 | log = logging.getLogger( __package__ ) 41 | 42 | 43 | @click.group() 44 | @click.option('-v', '--verbose', count=True) 45 | @click.option('-q', '--quiet', count=True) 46 | @click.option( '--json/--no-json', default=True, help="Output JSON (the default)") 47 | def cli( verbose, quiet, json ): 48 | cli.verbosity = verbose - quiet 49 | log_cfg['level'] = log_level( cli.verbosity ) 50 | logging.basicConfig( **log_cfg ) 51 | if verbose or quiet: 52 | logging.getLogger().setLevel( log_cfg['level'] ) 53 | cli.json = json 54 | cli.verbosity = 0 # noqa: E305 55 | cli.json = False 56 | 57 | 58 | @click.command() 59 | @click.option( "--crypto", help="The cryptocurrency address to generate (default: BTC)" ) 60 | @click.option( "--paths", help="The HD wallet derivation path (default: the standard path for the cryptocurrency; if xpub, omits leading hardened segments by default)" ) 61 | @click.option( "--secret", required=True, help="A hex seed or '{x,y,z}{pub,prv}...' x-public/private key to derive HD wallet addresses from; '-' reads it from stdin" ) 62 | @click.option( "--format", help="legacy, segwit, bech32 (default: standard for cryptocurrency or '{x,y,z}{pub/prv}...' key)" ) 63 | @click.option( '--unbounded/--no-unbounded', default=False, help="Allow unbounded sequences of addresses") 64 | def addresses( crypto, paths, secret, format, unbounded ): 65 | if secret == '-': 66 | secret = input_secure( 'Master secret hex: ', secret=True ) 67 | elif secret and ( secret.lower().startswith( '0x' ) 68 | or all( c in string.hexdigits for c in secret )): 69 | log.warning( "It is recommended to not use '-s|--secret '; specify '-' to read from input" ) 70 | if secret and secret.lower().startswith('0x'): 71 | secret = secret[2:] 72 | if not secret: 73 | log.error( f"Provide a random {commas( BITS, final='or' )}-bit Seed via --secret" ) 74 | if cli.json: 75 | click.echo( "[" ) 76 | for i,(cry,pth,adr) in enumerate( slip39_addresses( 77 | master_secret = secret, 78 | crypto = crypto, 79 | paths = paths, 80 | format = format, 81 | allow_unbounded = unbounded 82 | )): 83 | if cli.json: 84 | if i: 85 | click.echo( "," ) 86 | if cli.verbosity > 0: 87 | click.echo( f" [{json.dumps( cry )+',':6} {json.dumps( pth )+',':21} {json.dumps( adr )}]", nl=False ) 88 | else: 89 | click.echo( f" {json.dumps( adr )}", nl=False ) 90 | else: 91 | if cli.verbosity > 0: 92 | click.echo( f"{cry:5} {pth:20} {adr}" ) 93 | else: 94 | click.echo( f"{adr}" ) 95 | if cli.json: 96 | click.echo( "\n]" ) 97 | 98 | 99 | cli.add_command( addresses ) 100 | -------------------------------------------------------------------------------- /slip39/cli/__main__.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Python-slip39 -- Ethereum SLIP-39 Account Generation and Recovery 4 | # 5 | # Copyright (c) 2022, Dominion Research & Development Corp. 6 | # 7 | # Python-slip39 is free software: you can redistribute it and/or modify it under 8 | # the terms of the GNU General Public License as published by the Free Software 9 | # Foundation, either version 3 of the License, or (at your option) any later 10 | # version. It is also available under alternative (eg. Commercial) licenses, at 11 | # your option. See the LICENSE file at the top of the source tree. 12 | # 13 | # Python-slip39 is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 16 | # 17 | 18 | from __future__ import annotations 19 | 20 | from . import cli 21 | 22 | __author__ = "Perry Kundert" 23 | __email__ = "perry@dominionrnd.com" 24 | __copyright__ = "Copyright (c) 2022 Dominion Research & Development Corp." 25 | __license__ = "Dual License: GPLv3 (or later) and Commercial (see LICENSE)" 26 | 27 | cli() 28 | -------------------------------------------------------------------------------- /slip39/generator/__main__.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Python-slip39 -- Ethereum SLIP-39 Account Generation and Recovery 4 | # 5 | # Copyright (c) 2022, Dominion Research & Development Corp. 6 | # 7 | # Python-slip39 is free software: you can redistribute it and/or modify it under 8 | # the terms of the GNU General Public License as published by the Free Software 9 | # Foundation, either version 3 of the License, or (at your option) any later 10 | # version. It is also available under alternative (eg. Commercial) licenses, at 11 | # your option. See the LICENSE file at the top of the source tree. 12 | # 13 | # Python-slip39 is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 16 | # 17 | 18 | from __future__ import annotations 19 | 20 | import sys 21 | 22 | from .main import main 23 | 24 | __author__ = "Perry Kundert" 25 | __email__ = "perry@dominionrnd.com" 26 | __copyright__ = "Copyright (c) 2022 Dominion Research & Development Corp." 27 | __license__ = "Dual License: GPLv3 (or later) and Commercial (see LICENSE)" 28 | 29 | sys.exit( main() ) 30 | -------------------------------------------------------------------------------- /slip39/generator_test.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | import threading 4 | 5 | import pytest 6 | 7 | try: 8 | import pty 9 | from serial import Serial 10 | except ImportError: 11 | Serial = None 12 | 13 | from .api import random_secret, accountgroups 14 | from .generator import chacha20poly1305, accountgroups_output, accountgroups_input 15 | 16 | log = logging.getLogger( __package__ ) 17 | 18 | 19 | def listener(port): 20 | # continuously listen to commands on the master device 21 | while True: 22 | res = b"" 23 | while not res.endswith(b"\r\n"): 24 | # keep reading one byte at a time until we have a full line 25 | res += os.read(port, 1) 26 | #print("command: %s" % res) 27 | 28 | # write back the response 29 | if res == b'QPGS\r\n': 30 | os.write(port, b"correct result\r\n") 31 | else: 32 | os.write(port, b"I don't understand\r\n") 33 | 34 | 35 | @pytest.mark.skipif( not Serial, 36 | reason="Serial testing needs pyserial" ) 37 | def test_serial(): 38 | """Start the testing""" 39 | master,slave = pty.openpty() # open the pseudoterminal 40 | s_name = os.ttyname(slave) # translate the slave fd to a filename 41 | 42 | log.info( f"Pty name: {s_name}" ) 43 | 44 | # create a separate thread that listens on the master device for commands 45 | thread = threading.Thread(target=listener, args=[master]) 46 | thread.daemon = True 47 | thread.start() 48 | 49 | # open a pySerial connection to the slave. Receiver can signal sender to stop/start 50 | ser = Serial(s_name, 2400, timeout=1) 51 | 52 | ser.write(b'test2\r\n') # write the first command 53 | res = b"" 54 | while not res.endswith(b'\r\n'): 55 | # read the response 56 | res += ser.read() 57 | log.info("result: %s" % res) 58 | assert res.startswith( b"I don't understand" ) 59 | 60 | ser.write(b'QPGS\r\n') # write a second command 61 | res = b"" 62 | while not res.endswith(b'\r\n'): 63 | # read the response 64 | res += ser.read() 65 | log.info("result: %s" % res) 66 | assert res.startswith( b"correct result" ) 67 | 68 | 69 | def generator( password, cryptopaths, fd ): 70 | """Generate a sequence of Accounts to the given file descriptor.""" 71 | fdout = os.fdopen( fd, "w" ) 72 | nonce = random_secret( 12 ) 73 | cipher = chacha20poly1305( password=password ) 74 | for index,group in enumerate( accountgroups( 75 | master_secret = b'\xff' * 16, 76 | cryptopaths = cryptopaths, 77 | )): 78 | log.info( f"Sending: {group}" ) 79 | accountgroups_output( 80 | group = group, 81 | index = index, 82 | cipher = cipher, 83 | nonce = nonce, 84 | corrupt = .01, 85 | file = fdout, 86 | ) 87 | 88 | 89 | @pytest.mark.skipif( not Serial, 90 | reason="Serial testing needs pyserial" ) 91 | def test_groups_pty(): 92 | password = "password" 93 | master,slave = pty.openpty() 94 | slave_name = os.ttyname( slave ) 95 | 96 | cryptopaths = [ 97 | ("ETH", "m/44'/60'/0'/0/-10"), 98 | ("ETH", "m/44'/ 0'/0'/0/-10"), 99 | ] 100 | 101 | gen = threading.Thread( 102 | target = generator, 103 | args = [password, cryptopaths, master] ) 104 | gen.daemon = True 105 | gen.start() 106 | 107 | class SerialEOF( Serial ): 108 | """Convert any SerialException to an EOFError, for compatibility with PTY. In real serial 109 | ports, we'll handle detection of counterparty readiness with DTR/DSR, and flow control with 110 | RTS/CTS. 111 | 112 | """ 113 | def read( self, size=1 ): 114 | while True: 115 | try: 116 | return super( SerialEOF, self ).read( size=size ) 117 | except Exception as exc: # SerialError as exc: 118 | # if "readiness" in str(exc): 119 | # time.sleep( .1 ) 120 | # continue 121 | raise EOFError( str( exc )) 122 | 123 | ser = SerialEOF( slave_name, timeout=1) 124 | for group in accountgroups_input( 125 | cipher = chacha20poly1305( password=password ), 126 | encoding = 'UTF-8', 127 | file = ser 128 | ): 129 | log.info( f"Receive: {group}" ) 130 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-AS-BIP.org: -------------------------------------------------------------------------------- 1 | #+title: Using BIP-39 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | SLIP-39 Mnemonics can be used directly on a Trezor to backup/restore the Seed. 6 | 7 | Also supports other Hardware Wallets that require a BIP-39 Mnemonic for Seed recovery, such as to 8 | your Ledger Nano. Recover your BIP-39 Seed Phrase from these SLIP-39 cards using the GUI (or 9 | command-line, or [[https://iancoleman.io/slip39/]]) whenever you need it, to restore your Crypto 10 | accounts to your hardware wallet. 11 | 12 | | Controls | Description | 13 | |----------+---------------------------------------------------------------------| 14 | | Backup | Already using a BIP-39 Seed Phrase? Back it up using SLIP-39 Cards | 15 | | Create | Generate SLIP-39 Cards, even if using a BIP-39 hardware wallet | 16 | | Recover | Use SLIP-39/BIP-39 to recover Seed, supports using BIP-39 on wallet | 17 | | Pro | Convert existing BIP-39 Seed to SLIP-39 for "Paper Wallet" backup | 18 | #+END_ABSTRACT 19 | 20 | * Using BIP-39 21 | 22 | To support older or less expensive existing hardware wallets that *only* support BIP-39 recovery, 23 | *or* to backup existing BIP-39 Mnemonic phrases to SLIP-39 (to avoid moving all of your old 24 | BIP-39 Seed derived wallets to new SLIP-39 Seed derived wallets), click the "Using BIP-39" 25 | checkbox (this is the default). This will do two things: 26 | 27 | ** Output BIP-39 Mnemonics 28 | 29 | You will see your BIP-39 Mnemonic, which encodes the Seed Source (and optionally any Seed Extra 30 | Randomness) you've specified. 31 | 32 | We'll even include one BIP-39 card in the output PDF. You can store this card (very safely and 33 | securely), but we recommend you destroy it, and instead use the SLIP-39 App with your SLIP-39 34 | Mnemonic Cards to recover the BIP-39 Mnemonic phrase when needed. 35 | 36 | ** Use BIP-39 Seed Generation 37 | 38 | Any Cryptocurrency wallet QR codes and Paper Wallets will be derived using standard BIP-39 Seed generation. 39 | 40 | Since BIP-39 uses the Seed Entropy *differently* than SLIP-39 does, this produces *different* 41 | wallets in the hardware wallet device! In other words, exactly the same 128- or 256-bit entropy 42 | produces different wallets in a [[https://affil.trezor.io/SHdv][Trezor Safe 3]] recovered directly from SLIP-39 Mnemonics, compared 43 | to the same Trezor or [[https://shop.ledger.com/pages/ledger-nano-x?r=2cd1cb6ae51f][Ledger Nano X]] recovered from BIP-39. 44 | 45 | This is usually not a problem: just ensure that if you're intending to use a hardware wallet that 46 | natively supports SLIP-39 (like the Trezor), *do not select* "Using BIP-39". Then, the QR codes 47 | and Paper Wallets printed will match those produced in the hardware wallet after SLIP-39 48 | recovery. 49 | 50 | If your hardware wallet only supports BIP-39 (or you're just backing up the Seed Entropy of an 51 | existing BIP-39 Mnemonic using SLIP-39, and you want to continue using the original BIP-39 52 | wallets), then *do select* "Using BIP-39". Then, when you recover your Trezor or Ledger from 53 | BIP-39, the printed QR codes and Paper Wallets will use the BIP-39 Seed generation standard, and 54 | will match those produced in the hardware after BIP-39 recovery. 55 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-AS-BIP.txt: -------------------------------------------------------------------------------- 1 | SLIP-39 Mnemonics can be used directly on a Trezor to backup/restore the 2 | Seed. 3 | 4 | Also supports other Hardware Wallets that require a BIP-39 Mnemonic for 5 | Seed recovery, such as to your Ledger Nano. Recover your BIP-39 Seed 6 | Phrase from these SLIP-39 cards using the GUI (or command-line, or 7 | ) whenever you need it, to restore your 8 | Crypto accounts to your hardware wallet. 9 | 10 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11 | Controls Description 12 | ─────────────────────────────────────────────────────────────────────────────── 13 | Backup Already using a BIP-39 Seed Phrase? Back it up using SLIP-39 Cards 14 | Create Generate SLIP-39 Cards, even if using a BIP-39 hardware wallet 15 | Recover Use SLIP-39/BIP-39 to recover Seed, supports using BIP-39 on wallet 16 | Pro Convert existing BIP-39 Seed to SLIP-39 for "Paper Wallet" backup 17 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 18 | 19 | 20 | 1 Using BIP-39 21 | ══════════════ 22 | 23 | To support older or less expensive existing hardware wallets that 24 | *only* support BIP-39 recovery, *or* to backup existing BIP-39 25 | Mnemonic phrases to SLIP-39 (to avoid moving all of your old BIP-39 26 | Seed derived wallets to new SLIP-39 Seed derived wallets), click the 27 | "Using BIP-39" checkbox (this is the default). This will do two 28 | things: 29 | 30 | 31 | 1.1 Output BIP-39 Mnemonics 32 | ─────────────────────────── 33 | 34 | You will see your BIP-39 Mnemonic, which encodes the Seed Source (and 35 | optionally any Seed Extra Randomness) you've specified. 36 | 37 | We'll even include one BIP-39 card in the output PDF. You can store 38 | this card (very safely and securely), but we recommend you destroy it, 39 | and instead use the SLIP-39 App with your SLIP-39 Mnemonic Cards to 40 | recover the BIP-39 Mnemonic phrase when needed. 41 | 42 | 43 | 1.2 Use BIP-39 Seed Generation 44 | ────────────────────────────── 45 | 46 | Any Cryptocurrency wallet QR codes and Paper Wallets will be derived 47 | using standard BIP-39 Seed generation. 48 | 49 | Since BIP-39 uses the Seed Entropy *differently* than SLIP-39 does, 50 | this produces *different* wallets in the hardware wallet device! In 51 | other words, exactly the same 128- or 256-bit entropy produces 52 | different wallets in a [Trezor Safe 3] recovered directly from SLIP-39 53 | Mnemonics, compared to the same Trezor or [Ledger Nano X] recovered 54 | from BIP-39. 55 | 56 | This is usually not a problem: just ensure that if you're intending to 57 | use a hardware wallet that natively supports SLIP-39 (like the 58 | Trezor), *do not select* "Using BIP-39". Then, the QR codes and Paper 59 | Wallets printed will match those produced in the hardware wallet after 60 | SLIP-39 recovery. 61 | 62 | If your hardware wallet only supports BIP-39 (or you're just backing 63 | up the Seed Entropy of an existing BIP-39 Mnemonic using SLIP-39, and 64 | you want to continue using the original BIP-39 wallets), then *do 65 | select* "Using BIP-39". Then, when you recover your Trezor or Ledger 66 | from BIP-39, the printed QR codes and Paper Wallets will use the 67 | BIP-39 Seed generation standard, and will match those produced in the 68 | hardware after BIP-39 recovery. 69 | 70 | 71 | [Trezor Safe 3] 72 | 73 | [Ledger Nano X] 74 | 75 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-CRYPTO.org: -------------------------------------------------------------------------------- 1 | #+title: Cryptocurrencies 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | Cryptocurrencies Wallet addresses to display, and the Paper Wallets to produce (if a password is 6 | supplied). The cryptocurrencies supported, and the standard BIP-44 derivation paths (Trezor, 7 | Ledger, etc. compatible) displayed are: 8 | 9 | | Controls | Crypto | Semantic | Path | Address | Support | 10 | |-----------+--------+----------+-------------------+---------+---------| 11 | | (default) | ETH | Legacy | m/44'/ 60'/0'/0/0 | 0x... | | 12 | | (default) | BTC | Bech32 | m/84'/ 0'/0'/0/0 | bc1... | | 13 | | | | SegWit | m/49'/ 0'/0'/0/0 | 3... | | 14 | | | | Legacy | m/44'/ 0'/0'/0/0 | 1... | | 15 | | Recover | LTC | Bech32 | m/84'/ 2'/0'/0/0 | ltc1... | | 16 | | | | SegWit | m/49'/ 2'/0'/0/0 | M... | | 17 | | | | Legacy | m/44'/ 2'/0'/0/0 | L... | | 18 | | Recover | DOGE | Legacy | m/44'/ 3'/0'/0/0 | D... | | 19 | | Pro | BSC | Legacy | m/44'/ 60'/0'/0/0 | 0x... | Beta | 20 | | Pro | XRP | Legacy | m/44'/144'/0'/0/0 | r... | | 21 | 22 | On each SLIP-39 card, up to 2 Wallet addresses and QR codes will be displayed, for information 23 | purposes only, to illustrate *which* Wallets are derived from this Seed. 24 | #+END_ABSTRACT 25 | 26 | * Semantics 27 | 28 | By default, we produce address semantics compatible with what the Trezor hardware wallet produces 29 | (ie. Bech32, for =BTC= and =LTC=). The underlying =slip39= library is capable of producing the 30 | Legacy and SegWit forms of these addresses, if necessary. 31 | 32 | * Cryptocurrencies In Beta Testing 33 | 34 | XRP and BSC wallet addresses are also supported, if desired (currently in Beta testing quality). 35 | Generated Paper Wallets should be /tested/ to ensure that generated and recovered private keys are 36 | valid. 37 | 38 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-CRYPTO.txt: -------------------------------------------------------------------------------- 1 | Cryptocurrencies Wallet addresses to display, and the Paper Wallets to 2 | produce (if a password is supplied). The cryptocurrencies supported, 3 | and the standard BIP-44 derivation paths (Trezor, Ledger, etc. 4 | compatible) displayed are: 5 | 6 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 7 | Controls Crypto Semantic Path Address Support 8 | ────────────────────────────────────────────────────────────────── 9 | (default) ETH Legacy m/44'/ 60'/0'/0/0 0x… 10 | (default) BTC Bech32 m/84'/ 0'/0'/0/0 bc1… 11 | SegWit m/49'/ 0'/0'/0/0 3… 12 | Legacy m/44'/ 0'/0'/0/0 1… 13 | Recover LTC Bech32 m/84'/ 2'/0'/0/0 ltc1… 14 | SegWit m/49'/ 2'/0'/0/0 M… 15 | Legacy m/44'/ 2'/0'/0/0 L… 16 | Recover DOGE Legacy m/44'/ 3'/0'/0/0 D… 17 | Pro BSC Legacy m/44'/ 60'/0'/0/0 0x… Beta 18 | Pro XRP Legacy m/44'/144'/0'/0/0 r… 19 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 20 | 21 | On each SLIP-39 card, up to 2 Wallet addresses and QR codes will be 22 | displayed, for information purposes only, to illustrate *which* Wallets 23 | are derived from this Seed. 24 | 25 | 26 | 1 Semantics 27 | ═══════════ 28 | 29 | By default, we produce address semantics compatible with what the 30 | Trezor hardware wallet produces (ie. Bech32, for `BTC' and `LTC'). 31 | The underlying `slip39' library is capable of producing the Legacy and 32 | SegWit forms of these addresses, if necessary. 33 | 34 | 35 | 2 Cryptocurrencies In Beta Testing 36 | ══════════════════════════════════ 37 | 38 | XRP and BSC wallet addresses are also supported, if desired (currently 39 | in Beta testing quality). Generated Paper Wallets should be /tested/ 40 | to ensure that generated and recovered private keys are valid. 41 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-CS.org: -------------------------------------------------------------------------------- 1 | #+title: SLIP-39 Card Sizes 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | Select the desired SLIP-39 card size. 6 | 7 | | Controls | Card Size | Width | Height | 8 | |-----------+-----------+--------+--------| 9 | | (default) | Business | 3-1/2" | 2" | 10 | | All | Credit | 3-3/8" | 2-1/4" | 11 | | All | Index | 5" | 3" | 12 | | Recover | Half | 8" | 4.5" | 13 | | Recover | Third | 8" | 3-3/8" | 14 | | Recover | Quarter | 8" | 2-5/8" | 15 | | Pro | Photo | 5-1/2" | 3-1/5" | 16 | 17 | #+END_ABSTRACT 18 | 19 | * Orientation 20 | 21 | SLIP-39 Cards will be laid out on the desired paper size in the most optimal 22 | orientation, to fit the most Cards on the selected paper. 23 | 24 | ** Paper Wallets 25 | 26 | If Cryptocurrency "Paper Wallet" are printed, the selected Paper will always be printed in Portrait 27 | orientation. 28 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-CS.txt: -------------------------------------------------------------------------------- 1 | Select the desired SLIP-39 card size. 2 | 3 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4 | Controls Card Size Width Height 5 | ────────────────────────────────────── 6 | (default) Business 3-1/2" 2" 7 | All Credit 3-3/8" 2-1/4" 8 | All Index 5" 3" 9 | Recover Half 8" 4.5" 10 | Recover Third 8" 3-3/8" 11 | Recover Quarter 8" 2-5/8" 12 | Pro Photo 5-1/2" 3-1/5" 13 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 14 | 15 | 16 | 1 Orientation 17 | ═════════════ 18 | 19 | SLIP-39 Cards will be laid out on the desired paper size in the most 20 | optimal orientation, to fit the most Cards on the selected paper. 21 | 22 | 23 | 1.1 Paper Wallets 24 | ───────────────── 25 | 26 | If Cryptocurrency "Paper Wallet" are printed, the selected Paper will 27 | always be printed in Portrait orientation. 28 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-EXTENDABLE.org: -------------------------------------------------------------------------------- 1 | #+title: Extendable 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | SLIP-39 Mnemonics recover a unique (but "valid") Seed and derived wallets, no matter what 6 | /alternative/ passphrase you use! Your /original/ Seed can only be recovered with the originally 7 | specified "correct" passphrase. 8 | 9 | Extendable SLIP-39 Mnemonics ensures that all SLIP-39 Mnemonic sets generated from the /original/ 10 | Seed and original "correct" passphrase will /always/ result in the same unique Seed for each 11 | /alternative/ passphrase. 12 | 13 | Non-Extendable SLIP-39 Mnemonics recover the /original/ Seed with the "correct" passphrase, but 14 | *different* unique Seeds for all /alternative/ passphrases. 15 | #+END_ABSTRACT 16 | 17 | * Extendable 18 | 19 | The default is now /Extendable/ -- does /not/ use the Identifier to salt the encryption passphrase. 20 | 21 | ** The Purpose for Multiple Passphrases 22 | 23 | Recovering different Seeds for different passphrases is a valuable feature, because you may use 24 | the same SLIP-39 Mnemonic cards, and supply different passphrases to recover different (but valid) 25 | Seeds and sets of derived HD wallets! 26 | 27 | - You could have a "distress" passphrase that recovers a decoy wallet containing a 28 | small amount of sacrificial funds, while your real savings are under a different passphrase. 29 | - One password for your personal accounts and another for business accounts. 30 | 31 | ** Non-Extendable Encoding 32 | 33 | Historically, the SLIP-39 encoding used the randomly assigned Identifier to both 1) associate groups 34 | of Mnemonics belonging to the same set, but /also/ 2) to salt the Seed encryption. 35 | 36 | This meant that: if you created 2 sets of SLIP-39 Mnemonics for the same Seed -- each set would 37 | lead to */same/* Seed with the "correct" original passphrase, but to */different/* Seeds with 38 | each "distress" passphrase! 39 | 40 | Unless all sets of SLIP-39 Mnemonics lead to the same Seeds for each passphrase, you are 41 | restricted to ever issue /only one/ set of SLIP-39 Mnemonics for each Seed! You lose the ability 42 | to recover other "distress" passphrase Seeds from the new sets of Mnemonics! 43 | 44 | ** Issuing Multiple SLIP-39 Mnemonic Sets 45 | 46 | You may want to issue a simple set of SLIP-39 Mnemonics for your Seed to begin with, and then 47 | (later) decide to issue a more elaborate set of SLIP-39 Mnenmonic cards. 48 | 49 | Only with Extendable SLIP-39 Mnemonics, will the /alternative/ passphrase Seeds and derived 50 | wallets be consistent. 51 | 52 | * Recovery 53 | 54 | The SLIP-39 App supports recovery from both Extendable and (historic) non-Extendable SLIP-39 55 | Mnemonics. 56 | 57 | ** Using [[https://iancoleman.io/slip39]] 58 | 59 | Until the website is updated, you cannot (as of Dec 2024) use it to recover your Seed from 60 | Extendable SLIP-39 Mnemonics. 61 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-EXTENDABLE.txt: -------------------------------------------------------------------------------- 1 | SLIP-39 Mnemonics recover a unique (but "valid") Seed and derived 2 | wallets, no matter what /alternative/ passphrase you use! Your 3 | /original/ Seed can only be recovered with the originally specified 4 | "correct" passphrase. 5 | 6 | Extendable SLIP-39 Mnemonics ensures that all SLIP-39 Mnemonic sets 7 | generated from the /original/ Seed and original "correct" passphrase 8 | will /always/ result in the same unique Seed for each /alternative/ 9 | passphrase. 10 | 11 | Non-Extendable SLIP-39 Mnemonics recover the /original/ Seed with the 12 | "correct" passphrase, but *different* unique Seeds for all /alternative/ 13 | passphrases. 14 | 15 | 16 | 1 Extendable 17 | ════════════ 18 | 19 | The default is now /Extendable/ – does /not/ use the Identifier to 20 | salt the encryption passphrase. 21 | 22 | 23 | 1.1 The Purpose for Multiple Passphrases 24 | ──────────────────────────────────────── 25 | 26 | Recovering different Seeds for different passphrases is a valuable 27 | feature, because you may use the same SLIP-39 Mnemonic cards, and 28 | supply different passphrases to recover different (but valid) Seeds 29 | and sets of derived HD wallets! 30 | 31 | • You could have a "distress" passphrase that recovers a decoy wallet 32 | containing a small amount of sacrificial funds, while your real 33 | savings are under a different passphrase. 34 | • One password for your personal accounts and another for business 35 | accounts. 36 | 37 | 38 | 1.2 Non-Extendable Encoding 39 | ─────────────────────────── 40 | 41 | Historically, the SLIP-39 encoding used the randomly assigned 42 | Identifier to both 1) associate groups of Mnemonics belonging to the 43 | same set, but /also/ 2) to salt the Seed encryption. 44 | 45 | This meant that: if you created 2 sets of SLIP-39 Mnemonics for the 46 | same Seed – each set would lead to */same/* Seed with the "correct" 47 | original passphrase, but to */different/* Seeds with each "distress" 48 | passphrase! 49 | 50 | Unless all sets of SLIP-39 Mnemonics lead to the same Seeds for each 51 | passphrase, you are restricted to ever issue /only one/ set of SLIP-39 52 | Mnemonics for each Seed! You lose the ability to recover other 53 | "distress" passphrase Seeds from the new sets of Mnemonics! 54 | 55 | 56 | 1.3 Issuing Multiple SLIP-39 Mnemonic Sets 57 | ────────────────────────────────────────── 58 | 59 | You may want to issue a simple set of SLIP-39 Mnemonics for your Seed 60 | to begin with, and then (later) decide to issue a more elaborate set 61 | of SLIP-39 Mnenmonic cards. 62 | 63 | Only with Extendable SLIP-39 Mnemonics, will the /alternative/ 64 | passphrase Seeds and derived wallets be consistent. 65 | 66 | 67 | 2 Recovery 68 | ══════════ 69 | 70 | The SLIP-39 App supports recovery from both Extendable and (historic) 71 | non-Extendable SLIP-39 Mnemonics. 72 | 73 | 74 | 2.1 Using 75 | ──────────────────────────────────────── 76 | 77 | Until the website is updated, you cannot (as of Dec 2024) use it to 78 | recover your Seed from Extendable SLIP-39 Mnemonics. 79 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-G-NAME.org: -------------------------------------------------------------------------------- 1 | #+title: SLIP-39 Group Names 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | Name each Group according to "who" or "where" you plan to distribute it. 6 | 7 | The default Group names and their intended usages are: 8 | 9 | | First | A 1-card group stored in the First safe place | 10 | | Second | A 1-card group stored in the First safe place | 11 | | Fam | A smaller group of Family members | 12 | | Fren | A larger group of Friends; increase Needed | 13 | #+END_ABSTRACT 14 | 15 | * 1-Card Groups 16 | 17 | Useful for the direct owners of the Seed. Just one Card for these groups must be collected; 18 | ensure that 2+ of these Groups are created, and a "Requires recovery" threshold of least 2 is 19 | specified. 20 | 21 | If /less than/ the threshold amount of these cards is found by an attacker, the Seed /cannot/ be 22 | recovered (unless other Groups are also recovered). 23 | 24 | * Multi-Card Groups 25 | 26 | If you have a group of people (or places) that may be lost or destroyed, or where some Mnemonics 27 | (cards) may be found and fall into hostile hands, use a multi-card group. 28 | 29 | ** Hostile Groups 30 | 31 | The more /hostile/ (untrustworthy) the group (ie. the more likely that any card(s) may be stolen 32 | by an attacker) -- make the Group's Needed/#-in-Group ratio larger. Then, the attacker must 33 | collect more cards to defeat the Group. 34 | 35 | ** Fragile Groups 36 | 37 | The more /fragile/ (unreliable) the group (ie. the more likely that any card(s) may be lost or 38 | destroyed) -- make the Group's Needed/#-in-Group ratio smaller. Thus, more cards may be 39 | lost/destroyed before the Group can no longer be recovered (an *other* Group(s) must be 40 | colledted, instead, to recover the Seed). 41 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-G-NAME.txt: -------------------------------------------------------------------------------- 1 | Name each Group according to "who" or "where" you plan to distribute it. 2 | 3 | The default Group names and their intended usages are: 4 | 5 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6 | First A 1-card group stored in the First safe place 7 | Second A 1-card group stored in the First safe place 8 | Fam A smaller group of Family members 9 | Fren A larger group of Friends; increase Needed 10 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11 | 12 | 13 | 1 1-Card Groups 14 | ═══════════════ 15 | 16 | Useful for the direct owners of the Seed. Just one Card for these 17 | groups must be collected; ensure that 2+ of these Groups are created, 18 | and a "Requires recovery" threshold of least 2 is specified. 19 | 20 | If /less than/ the threshold amount of these cards is found by an 21 | attacker, the Seed /cannot/ be recovered (unless other Groups are also 22 | recovered). 23 | 24 | 25 | 2 Multi-Card Groups 26 | ═══════════════════ 27 | 28 | If you have a group of people (or places) that may be lost or 29 | destroyed, or where some Mnemonics (cards) may be found and fall into 30 | hostile hands, use a multi-card group. 31 | 32 | 33 | 2.1 Hostile Groups 34 | ────────────────── 35 | 36 | The more /hostile/ (untrustworthy) the group (ie. the more likely that 37 | any card(s) may be stolen by an attacker) – make the Group's 38 | Needed/#-in-Group ratio larger. Then, the attacker must collect more 39 | cards to defeat the Group. 40 | 41 | 42 | 2.2 Fragile Groups 43 | ────────────────── 44 | 45 | The more /fragile/ (unreliable) the group (ie. the more likely that 46 | any card(s) may be lost or destroyed) – make the Group's 47 | Needed/#-in-Group ratio smaller. Thus, more cards may be 48 | lost/destroyed before the Group can no longer be recovered (an *other* 49 | Group(s) must be colledted, instead, to recover the Seed). 50 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-G.org: -------------------------------------------------------------------------------- 1 | #+title: SLIP-39 Group Needed/#-in-Group 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | Increase "# in Group" as your target group locations or members grows. 6 | 7 | Increase "# Needed", the more Hostile/Untrustorthy the Group is. 8 | 9 | Decrease "# Needed", the less Fragile/Unreliable the Group is. 10 | 11 | #+END_ABSTRACT 12 | 13 | * 1-Card Groups 14 | 15 | Useful for the direct owners of the Seed. Just one Card for these groups must be collected; 16 | ensure that 2+ of these Groups are created, and a "Requires recovery" threshold of least 2 is 17 | specified. 18 | 19 | If /less than/ the threshold amount of these cards is found by an attacker, the Seed /cannot/ be 20 | recovered (unless other Groups are also recovered). 21 | 22 | * Multi-Card Groups 23 | 24 | If you have a group of people (or places) that may be lost or destroyed, or where some Mnemonics 25 | (cards) may be found and fall into hostile hands, use a multi-card group. 26 | 27 | ** Hostile Groups 28 | 29 | The more /hostile/ (untrustworthy) the group (ie. the more likely that any card(s) may be stolen 30 | by an attacker) -- make the Group's Needed/#-in-Group ratio larger. Then, the attacker must 31 | collect more cards to defeat the Group. 32 | 33 | ** Fragile Groups 34 | 35 | The more /fragile/ (unreliable) the group (ie. the more likely that any card(s) may be lost or 36 | destroyed) -- make the Group's Needed/#-in-Group ratio smaller. Thus, more cards may be 37 | lost/destroyed before the Group can no longer be recovered (an *other* Group(s) must be 38 | colledted, instead, to recover the Seed). 39 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-G.txt: -------------------------------------------------------------------------------- 1 | Increase "# in Group" as your target group locations or members grows. 2 | 3 | Increase "# Needed", the more Hostile/Untrustorthy the Group is. 4 | 5 | Decrease "# Needed", the less Fragile/Unreliable the Group is. 6 | 7 | 8 | 1 1-Card Groups 9 | ═══════════════ 10 | 11 | Useful for the direct owners of the Seed. Just one Card for these 12 | groups must be collected; ensure that 2+ of these Groups are created, 13 | and a "Requires recovery" threshold of least 2 is specified. 14 | 15 | If /less than/ the threshold amount of these cards is found by an 16 | attacker, the Seed /cannot/ be recovered (unless other Groups are also 17 | recovered). 18 | 19 | 20 | 2 Multi-Card Groups 21 | ═══════════════════ 22 | 23 | If you have a group of people (or places) that may be lost or 24 | destroyed, or where some Mnemonics (cards) may be found and fall into 25 | hostile hands, use a multi-card group. 26 | 27 | 28 | 2.1 Hostile Groups 29 | ────────────────── 30 | 31 | The more /hostile/ (untrustworthy) the group (ie. the more likely that 32 | any card(s) may be stolen by an attacker) – make the Group's 33 | Needed/#-in-Group ratio larger. Then, the attacker must collect more 34 | cards to defeat the Group. 35 | 36 | 37 | 2.2 Fragile Groups 38 | ────────────────── 39 | 40 | The more /fragile/ (unreliable) the group (ie. the more likely that 41 | any card(s) may be lost or destroyed) – make the Group's 42 | Needed/#-in-Group ratio smaller. Thus, more cards may be 43 | lost/destroyed before the Group can no longer be recovered (an *other* 44 | Group(s) must be colledted, instead, to recover the Seed). 45 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-LO.org: -------------------------------------------------------------------------------- 1 | #+title: Controls 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | Select an appropriate level of Controls detail. 6 | 7 | | Backup | Create SLIP-39 Mnemonics from existing BIP-39 Seed Phrase | 8 | | Create | SLIP-39 Mnemonic creation, "Using BIP-39" wallet support | 9 | | Recover | Enhanced SLIP-39 creation and SLIP-39/BIP-39 recovery | 10 | | Pro | Advanced Seeds, conversion of BIP-39 Phrase + passphrase to SLIP-39 | 11 | #+END_ABSTRACT 12 | 13 | * Backup 14 | 15 | The simplest mode, to "back up" a BIP-39 Seed Phrase Mnemonic to SLIP-39 Mnemonic Card Groups. 16 | 17 | Once you print, test recovery and distribute the SLIP-39 Mnemonic Cards, you can safely destroy 18 | your unreliable and insecure BIP-39 Seed Phrase Mnemonic backups; you can securely and reliably 19 | recover your BIP-39 Seed Phrase whenever you need it, by collecting a sufficient number of the 20 | SLIP-39 Cards. 21 | 22 | * Create 23 | 24 | A basic SLIP-39 Mnemonic creation interface. Default support for [[https://affil.trezor.io/SHdv][Trezor Safe 3]] with native 25 | SLIP-39 Mnemonics recovery. 26 | 27 | Select "Using BIP-39" for a traditional BIP-39 Seed Phrase Mnemonic, to use any other hardware 28 | wallets such as the [[https://shop.ledger.com/pages/ledger-nano-x?r=2cd1cb6ae51f][Ledger Nano]] (or even the Trezor, in BIP-39 Recovery mode). 29 | 30 | * Recovery 31 | 32 | Greater control over the Mnemonic creation process. Recovery of Seed Entropy from SLIP-39 33 | Mnemonics. 34 | 35 | Recover Seed Entropy from existing BIP-39 Mnemonic phrases by selecting "BIP-39 Entropy" in Seed 36 | Source. 37 | 38 | ** Extra Seed Randomness 39 | 40 | Probably most importantly, Extra Seed Entropy can be supplied. Any data supplied (Dice rolls, 41 | for example, add about 2.5 bits of entropy per roll) is hashed with a standard SHA-512 hash 42 | function, which can be independently confirmed. 43 | 44 | Finally, you can visually confirm that the Entropy is correctly applied via XOR to the Seed Data 45 | Source, to produce the Master Secret Seed. 46 | 47 | At no point do you need to "Trust" that the SLIP-39 program is producing a Master Secret Seed 48 | from known data! 49 | 50 | ** SLIP-39 51 | 52 | Supports input of existing SLIP-39 mnemonics to recover the original Seed Entropy. 53 | 54 | *** Recover From Lost SLIP-39 Mnemonic Cards 55 | 56 | If you know that some of your original SLIP-39 Mnemonic cards have been lost, you can 57 | re-issue /another/ set of SLIP-39 cards containing the same, original Seed Entropy. 58 | 59 | * Pro 60 | 61 | Advanced SLIP-39 creation and recovery, and recovery (and conversion) of BIP-39 Mnemonics to 62 | SLIP-39. 63 | 64 | Requires licensing. 65 | 66 | ** BIP-39 67 | 68 | Conversion of existing, fragile BIP-39 12- or 24-word Mnemonic phrases into SLIP-39 is supported. 69 | 70 | Enter the BIP-39 recover phrase to recover the original 128- or 256-bit Seed Entropy, and 71 | generate SLIP-39 Mnemonics which will recover the same Seed Entropy as the original 12- or 72 | 24-word BIP-39 Mnemonic. 73 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-LO.txt: -------------------------------------------------------------------------------- 1 | Select an appropriate level of Controls detail. 2 | 3 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4 | Backup Create SLIP-39 Mnemonics from existing BIP-39 Seed Phrase 5 | Create SLIP-39 Mnemonic creation, "Using BIP-39" wallet support 6 | Recover Enhanced SLIP-39 creation and SLIP-39/BIP-39 recovery 7 | Pro Advanced Seeds, conversion of BIP-39 Phrase + passphrase to SLIP-39 8 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9 | 10 | 11 | 1 Backup 12 | ════════ 13 | 14 | The simplest mode, to "back up" a BIP-39 Seed Phrase Mnemonic to 15 | SLIP-39 Mnemonic Card Groups. 16 | 17 | Once you print, test recovery and distribute the SLIP-39 Mnemonic 18 | Cards, you can safely destroy your unreliable and insecure BIP-39 Seed 19 | Phrase Mnemonic backups; you can securely and reliably recover your 20 | BIP-39 Seed Phrase whenever you need it, by collecting a sufficient 21 | number of the SLIP-39 Cards. 22 | 23 | 24 | 2 Create 25 | ════════ 26 | 27 | A basic SLIP-39 Mnemonic creation interface. Default support for 28 | [Trezor Safe 3] with native SLIP-39 Mnemonics recovery. 29 | 30 | Select "Using BIP-39" for a traditional BIP-39 Seed Phrase Mnemonic, 31 | to use any other hardware wallets such as the [Ledger Nano] (or even 32 | the Trezor, in BIP-39 Recovery mode). 33 | 34 | 35 | [Trezor Safe 3] 36 | 37 | [Ledger Nano] 38 | 39 | 40 | 41 | 3 Recovery 42 | ══════════ 43 | 44 | Greater control over the Mnemonic creation process. Recovery of Seed 45 | Entropy from SLIP-39 Mnemonics. 46 | 47 | Recover Seed Entropy from existing BIP-39 Mnemonic phrases by 48 | selecting "BIP-39 Entropy" in Seed Source. 49 | 50 | 51 | 3.1 Extra Seed Randomness 52 | ───────────────────────── 53 | 54 | Probably most importantly, Extra Seed Entropy can be supplied. Any 55 | data supplied (Dice rolls, for example, add about 2.5 bits of entropy 56 | per roll) is hashed with a standard SHA-512 hash function, which can 57 | be independently confirmed. 58 | 59 | Finally, you can visually confirm that the Entropy is correctly 60 | applied via XOR to the Seed Data Source, to produce the Master Secret 61 | Seed. 62 | 63 | At no point do you need to "Trust" that the SLIP-39 program is 64 | producing a Master Secret Seed from known data! 65 | 66 | 67 | 3.2 SLIP-39 68 | ─────────── 69 | 70 | Supports input of existing SLIP-39 mnemonics to recover the original 71 | Seed Entropy. 72 | 73 | 74 | 3.2.1 Recover From Lost SLIP-39 Mnemonic Cards 75 | ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ 76 | 77 | If you know that some of your original SLIP-39 Mnemonic cards have 78 | been lost, you can re-issue /another/ set of SLIP-39 cards containing 79 | the same, original Seed Entropy. 80 | 81 | 82 | 4 Pro 83 | ═════ 84 | 85 | Advanced SLIP-39 creation and recovery, and recovery (and conversion) 86 | of BIP-39 Mnemonics to SLIP-39. 87 | 88 | Requires licensing. 89 | 90 | 91 | 4.1 BIP-39 92 | ────────── 93 | 94 | Conversion of existing, fragile BIP-39 12- or 24-word Mnemonic phrases 95 | into SLIP-39 is supported. 96 | 97 | Enter the BIP-39 recover phrase to recover the original 128- or 98 | 256-bit Seed Entropy, and generate SLIP-39 Mnemonics which will 99 | recover the same Seed Entropy as the original 12- or 24-word BIP-39 100 | Mnemonic. 101 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-PASSPHRASE.org: -------------------------------------------------------------------------------- 1 | #+title: SLIP-39/BIP-39 Passphrase 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | BIP-39 Seed Phrases are often protected by a Passphrase, to partially offset their insecurity. This 6 | often makes the Seed unrecoverable, because the Passphrase can be so easily lost or forgotten. 7 | 8 | SLIP-39 Mnemonic Card Groups are *much* more reliable (to recover) and secure (against accidental 9 | disclosure); a Passphrase is *not* recommended. Leave it empty! 10 | 11 | #+END_ABSTRACT 12 | 13 | * BIP-39 Passphrase 14 | 15 | Since anyone who sees a BIP-39 phrase can immediately attempt to recover the Seed, it is often 16 | considered necessary to use a Passphrase. 17 | 18 | It is estimated that 20%+ of all Cryptocurrency has been lost, often because the BIP-39 Mnemonic is 19 | available but the Passphrase has been lost. 20 | 21 | ** Safely Using BIP-39 Passphrases 22 | 23 | Once you Backup your BIP-39 Seed Phrase to a set of SLIP-39 Mnemonic Card Groups, you *must* also 24 | arrange to secure and recover any BIP-39 Passphrase(s). Remember; you can have multiple 25 | Passphrases, to produce several sets of Cryptocurrency HD wallet accounts from the same BIP-39 26 | Seed Phrase. 27 | 28 | Make certain that each Passphrase is made available to each intended recipient, and also in at 29 | least one additional location (eg. with someone else who will be at your funeral). 30 | 31 | *** Backup Full 512-bit BIP-39 Seed *including* Passphrase! 32 | 33 | If you've *already* produced a BIP-39 Seed Phrase and a complex Passphrase, and have already 34 | funded or distributed the derived HD Wallet accounts, you can *still* back it up, securely and 35 | reliably with SLIP-39 -- without requiring the Passphrase to be remembered by the recipient! 36 | 37 | Use the Pro controls and select "BIP-39 Seed" + "Passphrase" to fully decrypt your BIP-39 Seed 38 | Phrase. Then, produce 59-word SLIP-39 recovery cards encoding the full, decrypted 512-bit Seed. 39 | 40 | These will *not* be compatible with standard BIP-39 nor SLIP-39 Hardware Wallets! (Don't blame 41 | me -- you elected to create an insecure and unreliable BIP-39 Seed Phrase + Passphrase, instead 42 | of SLIP-39 Mnemonic Cards! ;) 43 | 44 | Your heirs or business partners will need to use a fully standards compliant SLIP-39 recovery 45 | program (like this SLIP-39 App, or [[https://github.com/trezor/python-shamir-mnemonic][python-shamir-mnemonic on Github]] ) to enter the large (but 46 | standards-compliant!) 59 word Mnemonics, and then generate Paper Wallets for each derived HD 47 | Wallet account they want to access. But, they *will* be able to recover your cryptocurrency 48 | accounts, *without* needing to recover the original BIP-39 Seed Phrase or Passphrase! 49 | 50 | * SLIP-39 Passphrase 51 | 52 | If you use SLIP-39 Mnemonic Card Groups, it is usually not necessary to use a Passphrase. 53 | 54 | Since SLIP-39's security is so much greater (chance of accidentally disclosing your Seed is so low 55 | compared to BIP-39), no hardware wallet vendor has implemented SLIP-39 recovery Passphrase. 56 | 57 | ** Hardware Wallet Doesn't Support Passphrase 58 | 59 | The Trezor doesn't presently support using a Passphrase on SLIP-39 recovery. So, if you supply 60 | one here, you will not be able to use it when recovering your SLIP-39 Mnemonics on your Trezor. 61 | 62 | *** Use Trezor's "Hidden Wallets" Instead 63 | 64 | You can provide as many "Hidden Wallets" on your Trezor device as you wish, by entering a 65 | passphrase to switch between them. 66 | 67 | This works regardless of whether you recovered your Hardware Wallet from BIP-39 or SLIP-39. 68 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-PASSPHRASE.txt: -------------------------------------------------------------------------------- 1 | BIP-39 Seed Phrases are often protected by a Passphrase, to partially 2 | offset their insecurity. This often makes the Seed unrecoverable, 3 | because the Passphrase can be so easily lost or forgotten. 4 | 5 | SLIP-39 Mnemonic Card Groups are *much* more reliable (to recover) and 6 | secure (against accidental disclosure); a Passphrase is *not* 7 | recommended. Leave it empty! 8 | 9 | 10 | 1 BIP-39 Passphrase 11 | ═══════════════════ 12 | 13 | Since anyone who sees a BIP-39 phrase can immediately attempt to 14 | recover the Seed, it is often considered necessary to use a 15 | Passphrase. 16 | 17 | It is estimated that 20%+ of all Cryptocurrency has been lost, often 18 | because the BIP-39 Mnemonic is available but the Passphrase has been 19 | lost. 20 | 21 | 22 | 1.1 Safely Using BIP-39 Passphrases 23 | ─────────────────────────────────── 24 | 25 | Once you Backup your BIP-39 Seed Phrase to a set of SLIP-39 Mnemonic 26 | Card Groups, you *must* also arrange to secure and recover any BIP-39 27 | Passphrase(s). Remember; you can have multiple Passphrases, to 28 | produce several sets of Cryptocurrency HD wallet accounts from the 29 | same BIP-39 Seed Phrase. 30 | 31 | Make certain that each Passphrase is made available to each intended 32 | recipient, and also in at least one additional location (eg. with 33 | someone else who will be at your funeral). 34 | 35 | 36 | 1.1.1 Backup Full 512-bit BIP-39 Seed *including* Passphrase! 37 | ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ 38 | 39 | If you've *already* produced a BIP-39 Seed Phrase and a complex 40 | Passphrase, and have already funded or distributed the derived HD 41 | Wallet accounts, you can *still* back it up, securely and reliably 42 | with SLIP-39 – without requiring the Passphrase to be remembered by 43 | the recipient! 44 | 45 | Use the Pro controls and select "BIP-39 Seed" + "Passphrase" to fully 46 | decrypt your BIP-39 Seed Phrase. Then, produce 59-word SLIP-39 47 | recovery cards encoding the full, decrypted 512-bit Seed. 48 | 49 | These will *not* be compatible with standard BIP-39 nor SLIP-39 50 | Hardware Wallets! (Don't blame me – you elected to create an insecure 51 | and unreliable BIP-39 Seed Phrase + Passphrase, instead of SLIP-39 52 | Mnemonic Cards! ;) 53 | 54 | Your heirs or business partners will need to use a fully standards 55 | compliant SLIP-39 recovery program (like this SLIP-39 App, or 56 | [python-shamir-mnemonic on Github] ) to enter the large (but 57 | standards-compliant!) 59 word Mnemonics, and then generate Paper 58 | Wallets for each derived HD Wallet account they want to access. But, 59 | they *will* be able to recover your cryptocurrency accounts, *without* 60 | needing to recover the original BIP-39 Seed Phrase or Passphrase! 61 | 62 | 63 | [python-shamir-mnemonic on Github] 64 | 65 | 66 | 67 | 2 SLIP-39 Passphrase 68 | ════════════════════ 69 | 70 | If you use SLIP-39 Mnemonic Card Groups, it is usually not necessary 71 | to use a Passphrase. 72 | 73 | Since SLIP-39's security is so much greater (chance of accidentally 74 | disclosing your Seed is so low compared to BIP-39), no hardware wallet 75 | vendor has implemented SLIP-39 recovery Passphrase. 76 | 77 | 78 | 2.1 Hardware Wallet Doesn't Support Passphrase 79 | ────────────────────────────────────────────── 80 | 81 | The Trezor doesn't presently support using a Passphrase on SLIP-39 82 | recovery. So, if you supply one here, you will not be able to use it 83 | when recovering your SLIP-39 Mnemonics on your Trezor. 84 | 85 | 86 | 2.1.1 Use Trezor's "Hidden Wallets" Instead 87 | ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ 88 | 89 | You can provide as many "Hidden Wallets" on your Trezor device as you 90 | wish, by entering a passphrase to switch between them. 91 | 92 | This works regardless of whether you recovered your Hardware Wallet 93 | from BIP-39 or SLIP-39. 94 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-PF.org: -------------------------------------------------------------------------------- 1 | #+title: Paper Sizes 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | Select the desired PDF paper size. 6 | 7 | | Controls | Paper Size | Width | Height | 8 | |-----------+------------+--------+--------| 9 | | (default) | Letter | 8-1/2" | 11" | 10 | | All | Legal | 8-1/2" | 14" | 11 | | Recover | A4 | 210mm | 297mm | 12 | | Pro | Photo | 4" | 6" | 13 | #+END_ABSTRACT 14 | 15 | * Orientation 16 | 17 | SLIP-39 Cards will be laid out on the desired paper size in the most optimal 18 | orientation, to fit the most Cards on the selected paper. 19 | 20 | ** Paper Wallets 21 | 22 | However, if Cryptocurrency "Paper Wallet" are printed, the selected Paper will always 23 | be printed in Portrait orientation. 24 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-PF.txt: -------------------------------------------------------------------------------- 1 | Select the desired PDF paper size. 2 | 3 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4 | Controls Paper Size Width Height 5 | ─────────────────────────────────────── 6 | (default) Letter 8-1/2" 11" 7 | All Legal 8-1/2" 14" 8 | Recover A4 210mm 297mm 9 | Pro Photo 4" 6" 10 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11 | 12 | 13 | 1 Orientation 14 | ═════════════ 15 | 16 | SLIP-39 Cards will be laid out on the desired paper size in the most 17 | optimal orientation, to fit the most Cards on the selected paper. 18 | 19 | 20 | 1.1 Paper Wallets 21 | ───────────────── 22 | 23 | However, if Cryptocurrency "Paper Wallet" are printed, the selected 24 | Paper will always be printed in Portrait orientation. 25 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-SD.org: -------------------------------------------------------------------------------- 1 | #+title: Seed Data Source 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | Create (or recover) Seed Data for your SLIP-39 Mnemonic. Or, backup your insecure/unreliable 6 | BIP-39 Mnemonic using SLIP-39. 7 | 8 | | Controls | Source | Description | 9 | |----------+-------------+--------------------------------------------------------| 10 | | Backup | BIP-39 | Create SLIP-39 Mnemonics to recover BIP-39 Seed Phrase | 11 | | Create | Random | Create SLIP-39 Mnemonics from secure randomnes | 12 | | Recover | SLIP-39 | Recover Seed from SLIP-39 Mnemonics | 13 | | Pro | BIP-39 Seed | Backup 512-bit BIP-39 Seed from Mnemonics + passphrase | 14 | #+END_ABSTRACT 15 | 16 | * BIP-39 17 | 18 | Backup an existing 12- or 24-word BIP-39 Seed Phrase Mnemonic. Or, select Create to produce a new 19 | BIP-39 Mnemonic. Save your BIP-39 Seed Phrase as a set of SLIP-39 Mnemonic Card Groups. 20 | 21 | Later, select Recover to input your SLIP-39 Mnemonics, and recover your BIP-39 Seed Phrase. Use 22 | this BIP-39 Seed Phrase (plus your passphrase, if any) to initialize a BIP-39 Hardware Wallet. 23 | 24 | You can then securely destroy your BIP-39 Mnemonic card(s) (or, keep a copy in some *extremely* 25 | secure location), and use the SLIP-39 Mnemonic cards as your distributed backup in case of its 26 | loss. 27 | 28 | ** SLIP-39 vs. BIP-39 Seed 29 | 30 | The Seed is computed *differently* on the hardware wallet (eg. a Ledger or Trezor), when 31 | importing using BIP-39 vs. SLIP-39! 32 | 33 | So, in order for us to compute and show you the correct Cryptocurrency wallet(s), you must 34 | indicate whether you're importing using the SLIP-39 Mnemonics directly (ie. on a Trezor), *or* if 35 | you're recovering the BIP-39 Mnemonic, and using that on the hardware wallet (ie. on a Ledger, or 36 | some other non-SLIP-39 hardware wallet). 37 | 38 | If you recover your Seed Entropy from a BIP-39 Mnemonic, we'll /assume/ you intend to *use* the 39 | BIP-39 Mnemonic on your hardware wallet, and we'll check "Recovering from BIP-39 on my Hardware 40 | Wallet". 41 | 42 | * SLIP-39 43 | 44 | Here's where you can restore a lost Seed using recovered SLIP-39 Mnemonics. 45 | 46 | You don't have to worry about sorting the Mnemonics into Groups or anything; we'll be able to 47 | recover the Seed, if you provide us with a sufficient threshold of SLIP-39 Mnemonic cards from the 48 | required number of separate Mnemonic Card Groups. 49 | 50 | ** Fixing Partially Lost Groups 51 | 52 | If you know you've lost access to some cards, and want to repair your SLIP-39 backup, you can 53 | recover the Seed from the current SLIP-39 Mnemonic cards, here -- and generate a *new* set of 54 | SLIP-39 Mnemonic cards for the *same* Seed. 55 | 56 | Distribute the cards as you wish, again; either the old (partially degraded) SLIP-39 Groups, *or* 57 | the new SLIP-39 Groups can be used to recover your Seed. Obviously, cards from the old and new 58 | SLIP-39 Mnemonics can't be "mixed" together to recover the Seed. 59 | 60 | * Random 61 | 62 | A high-quality 128-bit random seed value is probably adequate, and the 20-word SLIP-39 (and 63 | 12-word BIP-39) Mnemonics are much more practical than those produced for 256-bit seeds. 64 | 65 | 2^128 is aproximately 10^38. There are about 10^57 atoms in our solar system, and about 10^19 66 | atoms in a particle of dust. 67 | 68 | Therefore, the odds of 2 people picking the *same* high-quality random 128-bit Seed (1 in 10^38), 69 | is about the same as 2 people randomly selecting the same particle of *dust* out of the mass of 70 | our entire solar system! 71 | 72 | So, 128-bit seeds are probably fine for most practical levels of account security... 73 | 74 | * BIP-39 Seed 75 | 76 | If you wish, you can backup a /complete/ BIP-39 Seed Phrase *including its passphrase*, as a raw 77 | 512-bit BIP-39 Seed! This ensures that whoever uses the SLIP-39 Mnemonics to recover the wallets 78 | does not need to know the original BIP-39 Mnemonic + passphrase. 79 | 80 | There are a couple of drawbacks with this approach, though: 81 | 82 | - Large 59-word SLIP-39 Mnemonics are produced, to store the 512-bit seed 83 | - The Seed cannot be re-imported into a standard BIP-39 Hardware Wallet 84 | - Produce "Paper Wallets" for whichever derived HD wallets you need to access 85 | 86 | ** The Birthday Paradox 87 | 88 | However, due to the [[https://en.wikipedia.org/wiki/Birthday_attack][Birthday Attack]], the probability of two parties out of /a large number 89 | creating Seeds/ having a Seed *collision* (accidentally selecting the same Seed value) is 90 | somewhat greater. 91 | 92 | If every human and all their devices created a few billion Seeds (about 10^13), the probability 93 | of an /accidental/ collision falls to about 1 in 10^12 -- about 1 in a trillion. Unlikely, but 94 | something like this has happened for IPv4 addresses, so who knows. 95 | 96 | So, if a 1 in a trillion chance of someone eventually stumbling upon your wallet is too great a 97 | risk, choose a 256-bit random Seed where this Birthday Paradox probability falls to 1 in 10^32 -- 98 | approximately the chance of 2 people on earth picking the same virus-sized particle in our solar 99 | system. 100 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-SE-SIGS.org: -------------------------------------------------------------------------------- 1 | #+title: Seed Extra Randomness - Ignore Bad Entropy 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | Bad Entropy is a risk to Cryptocurrency HD Wallet Seed Secrets! 6 | 7 | Avoid Harmonic and Shannon Entropy Deficiencies: 8 | - Use strong cryptographically secure randomness for your Seed Data 9 | - Use Extra Randomness from good sources, eg. rolling 20 or so dice 10 | #+END_ABSTRACT 11 | 12 | * Seed Entropy Deficit: {entropy_rating} 13 | #+BEGIN_EXAMPLE 14 | {update_seed_data.analysis} 15 | #+END_EXAMPLE 16 | 17 | #+BEGIN_EXAMPLE 18 | {update_seed_entropy.analysis} 19 | #+END_EXAMPLE 20 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-SE-SIGS.txt: -------------------------------------------------------------------------------- 1 | Bad Entropy is a risk to Cryptocurrency HD Wallet Seed Secrets! 2 | 3 | Avoid Harmonic and Shannon Entropy Deficiencies: 4 | • Use strong cryptographically secure randomness for your Seed Data 5 | • Use Extra Randomness from good sources, eg. rolling 20 or so dice 6 | 7 | 8 | 1 Seed Entropy Deficit: {entropy_rating} 9 | ════════════════════════════════════════ 10 | 11 | ┌──── 12 | │ {update_seed_data.analysis} 13 | └──── 14 | 15 | ┌──── 16 | │ {update_seed_entropy.analysis} 17 | └──── 18 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-SE.org: -------------------------------------------------------------------------------- 1 | #+title: Seed Extra Randomness 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | Provide extra Entropy, to improve the randomness of your Seed. 6 | 7 | | Controls | Extra Entropy | Description | 8 | |----------+----------------+--------------------------------------------------| 9 | | Create | None | No extra randness; you trust ours completely. :) | 10 | | Recover | Die Rolls, ... | Provide any data; we'll SHA-512 hash it | 11 | | Pro | Hex | Provide raw hex data from an external source | 12 | 13 | It is wise not to trust *anyone* (including this program) to provide randomness for your Seed! Many 14 | wallet tools have been made that produce a "predictable" Seed (mostly pre-defined, with a small 15 | amount of randomness added to make them seem legitimate.) Then, after you derive your addresses and 16 | fund your wallets, the attacker who created the tool can also easily derive your private keys, and 17 | steal your Cryptocurrency. 18 | 19 | All Seed Source and Extra Randomness are combined using XOR, which you can confirm visually (if you 20 | understand hexadecimal representation). 21 | #+END_ABSTRACT 22 | * None 23 | 24 | We are using Python's =secrets.token_bytes=, which is designed to provide cryptographically [[https://docs.python.org/3/library/secrets.html][strong 25 | random]] numbers, to produce entropy for your Seed. 26 | 27 | So, using the default Random Seed source should be fine for most purposes. 28 | 29 | * Die Rolls, ... 30 | 31 | For higher security, provide yourself with a source of high-quality randomness. 32 | 33 | A couple hand-fulls of high-quality dice is a good option. Roll 'em, and enter them here. 34 | 35 | We will SHA-512 hash them; you can confirm our [[https://emn178.github.io/online-tools/sha512.html][SHA-512]] results here, to prove we aren't lying. 36 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-SE.txt: -------------------------------------------------------------------------------- 1 | Provide extra Entropy, to improve the randomness of your Seed. 2 | 3 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4 | Controls Extra Entropy Description 5 | ─────────────────────────────────────────────────────────────────────────── 6 | Create None No extra randness; you trust ours completely. :) 7 | Recover Die Rolls, … Provide any data; we'll SHA-512 hash it 8 | Pro Hex Provide raw hex data from an external source 9 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 10 | 11 | It is wise not to trust *anyone* (including this program) to provide 12 | randomness for your Seed! Many wallet tools have been made that produce 13 | a "predictable" Seed (mostly pre-defined, with a small amount of 14 | randomness added to make them seem legitimate.) Then, after you derive 15 | your addresses and fund your wallets, the attacker who created the tool 16 | can also easily derive your private keys, and steal your Cryptocurrency. 17 | 18 | All Seed Source and Extra Randomness are combined using XOR, which you 19 | can confirm visually (if you understand hexadecimal representation). 20 | 21 | 22 | 1 None 23 | ══════ 24 | 25 | We are using Python's `secrets.token_bytes', which is designed to 26 | provide cryptographically [strong random] numbers, to produce entropy 27 | for your Seed. 28 | 29 | So, using the default Random Seed source should be fine for most 30 | purposes. 31 | 32 | 33 | [strong random] 34 | 35 | 36 | 2 Die Rolls, … 37 | ══════════════ 38 | 39 | For higher security, provide yourself with a source of high-quality 40 | randomness. 41 | 42 | A couple hand-fulls of high-quality dice is a good option. Roll 'em, 43 | and enter them here. 44 | 45 | We will SHA-512 hash them; you can confirm our [SHA-512] results here, 46 | to prove we aren't lying. 47 | 48 | 49 | [SHA-512] 50 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-THRESHOLD.org: -------------------------------------------------------------------------------- 1 | #+title: SLIP-39 Recovery Threshold 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | How many SLIP-39 Mnemonics Groups must be collected to recover the Seed. 6 | 7 | For each Group required, you must collect each group's "Needed" amount of Mnemonics (cards), out of 8 | the total number of cards in that Group. 9 | #+END_ABSTRACT 10 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-THRESHOLD.txt: -------------------------------------------------------------------------------- 1 | How many SLIP-39 Mnemonics Groups must be collected to recover the Seed. 2 | 3 | For each Group required, you must collect each group's "Needed" amount 4 | of Mnemonics (cards), out of the total number of cards in that Group. 5 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-WALLET.org: -------------------------------------------------------------------------------- 1 | #+title: Paper Wallets 2 | #+OPTIONS: toc:nil title:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | Supply a password to produce an encrypted Ethereum JSON wallet or Bitcoin, ... BIP-38 Paper Wallet. 6 | 7 | If you import these SLIP-39 Mnemonics directly into your Trezor hardware wallet -- you do 8 | /not/ need Paper Wallets: you have access to /all/ of the wallets, in every cryptocurrency supported 9 | by the Trezor. 10 | 11 | These are intended to support the importing of /individual/, single wallets into standard software 12 | wallets (eg. Brave browser, Metamask plugins, other software wallets on PCs or mobile devices). If 13 | you need some cryptocurrency "walking around" money, use them to create recoverable "Safe Portable 14 | Crypto Accounts" (below). 15 | #+END_ABSTRACT 16 | 17 | * Password 18 | 19 | If you lose or forget this Paper Wallet password -- you cannot import these wallets into 20 | compatible software Cryptocurrency wallets! Remember; the Seed can still be recovered by 21 | collecting sufficient numbers of Mnemonics (cards), and then new Paper Wallets can be issued. 22 | 23 | ** Hint 24 | 25 | A small (<10 character) hint about what (or where) the Paper Wallet Password is. 26 | 27 | * Safe Portable Crypto Accounts 28 | 29 | If you want to issue temporary Paper Wallets (to carry cryptocurrency with you to give to someone 30 | or buy something), then Paper Wallets derived from your account are a good idea. 31 | 32 | ** Custom Derivation Path 33 | 34 | Use the =SLIP-39= App to recover your Seed, select the desired Cryptocurrency (eg. =BTC=), and 35 | then enter a Paper Wallet Password, and a derivation path "suffix" into the "# to Derive" field, 36 | eg. "/1'/0/0-2". 37 | 38 | For example, if you use the BIP-39 recovery "test" Mnemonic "zoo zoo zoo zoo zoo zoo zoo zoo zoo 39 | zoo zoo wrong", with the above "# to Derive", this would result in 3 paper wallets being 40 | produced, at the following standard BTC Bech32 derivation paths: 41 | 42 | | m/84'/0'/1'/0/0 | bc1q8pqnqs573vx3qdp0xp6qdqzvnvy8px24rxh9lp | 43 | | m/84'/0'/1'/0/0 | bc1qwtc58u4mmnxa29u8j07e6lmqpnrs38vefy3y24 | 44 | | m/84'/0'/1'/0/0 | bc1qg9s8qzm0lcetfv6umhlm3evtca5zsqv7elqd5s | 45 | 46 | You could load these wallets with funds, write the amount on the front, and fold them over twice 47 | (to hide the PRIVATE KEY, while leaving the PUBLIC ADDRESS exposed), and even laminate them to 48 | avoid accidental discovery or exposure to moisture. 49 | 50 | Then, once loaded, they can always be *recovered* by you (if they are lost or accidentally 51 | destroyed). Otherwise, the intended recipient can unfold the Paper Wallet, and move the funds 52 | to their own wallet. 53 | 54 | 55 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39-WALLET.txt: -------------------------------------------------------------------------------- 1 | Supply a password to produce an encrypted Ethereum JSON wallet or 2 | Bitcoin, … BIP-38 Paper Wallet. 3 | 4 | If you import these SLIP-39 Mnemonics directly into your Trezor hardware 5 | wallet – you do /not/ need Paper Wallets: you have access to /all/ of 6 | the wallets, in every cryptocurrency supported by the Trezor. 7 | 8 | These are intended to support the importing of /individual/, single 9 | wallets into standard software wallets (eg. Brave browser, Metamask 10 | plugins, other software wallets on PCs or mobile devices). If you need 11 | some cryptocurrency "walking around" money, use them to create 12 | recoverable "Safe Portable Crypto Accounts" (below). 13 | 14 | 15 | 1 Password 16 | ══════════ 17 | 18 | If you lose or forget this Paper Wallet password – you cannot import 19 | these wallets into compatible software Cryptocurrency wallets! 20 | Remember; the Seed can still be recovered by collecting sufficient 21 | numbers of Mnemonics (cards), and then new Paper Wallets can be 22 | issued. 23 | 24 | 25 | 1.1 Hint 26 | ──────── 27 | 28 | A small (<10 character) hint about what (or where) the Paper Wallet 29 | Password is. 30 | 31 | 32 | 2 Safe Portable Crypto Accounts 33 | ═══════════════════════════════ 34 | 35 | If you want to issue temporary Paper Wallets (to carry cryptocurrency 36 | with you to give to someone or buy something), then Paper Wallets 37 | derived from your account are a good idea. 38 | 39 | 40 | 2.1 Custom Derivation Path 41 | ────────────────────────── 42 | 43 | Use the `SLIP-39' App to recover your Seed, select the desired 44 | Cryptocurrency (eg. `BTC'), and then enter a Paper Wallet Password, 45 | and a derivation path "suffix" into the "# to Derive" field, 46 | eg. "/1'/0/0-2". 47 | 48 | For example, if you use the BIP-39 recovery "test" Mnemonic "zoo zoo 49 | zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong", with the above "# to 50 | Derive", this would result in 3 paper wallets being produced, at the 51 | following standard BTC Bech32 derivation paths: 52 | 53 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 54 | m/84'/0'/1'/0/0 bc1q8pqnqs573vx3qdp0xp6qdqzvnvy8px24rxh9lp 55 | m/84'/0'/1'/0/0 bc1qwtc58u4mmnxa29u8j07e6lmqpnrs38vefy3y24 56 | m/84'/0'/1'/0/0 bc1qg9s8qzm0lcetfv6umhlm3evtca5zsqv7elqd5s 57 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 58 | 59 | You could load these wallets with funds, write the amount on the 60 | front, and fold them over twice (to hide the PRIVATE KEY, while 61 | leaving the PUBLIC ADDRESS exposed), and even laminate them to avoid 62 | accidental discovery or exposure to moisture. 63 | 64 | Then, once loaded, they can always be *recovered* by you (if they are 65 | lost or accidentally destroyed). Otherwise, the intended recipient 66 | can unfold the Paper Wallet, and move the funds to their own wallet. 67 | -------------------------------------------------------------------------------- /slip39/gui/SLIP-39.txt: -------------------------------------------------------------------------------- 1 | 2 | mmmm mm mmmmmm mmmmmm mmmmm mmmm 3 | m#""""# ## ""##"" ##""""#m #""""##m m##""##m 4 | ##m ## ## ## ## m## ## ## 5 | "####m ## ## ######" ##### "##mm### 6 | "## ## ## ## ##### "## """ ## 7 | #mmmmm#" ##mmmmmm mm##mm ## #mmmm##" #mmm## 8 | """"" """""""" """""" "" """"" """" 9 | 10 | 11 | Safe & Effective (tm) Crypto Wallet Backup and Recovery 12 | (explanations and instructions will appear here) 13 | -------------------------------------------------------------------------------- /slip39/gui/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/gui/__init__.py -------------------------------------------------------------------------------- /slip39/gui/__main__.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Python-slip39 -- Ethereum SLIP-39 Account Generation and Recovery 4 | # 5 | # Copyright (c) 2022, Dominion Research & Development Corp. 6 | # 7 | # Python-slip39 is free software: you can redistribute it and/or modify it under 8 | # the terms of the GNU General Public License as published by the Free Software 9 | # Foundation, either version 3 of the License, or (at your option) any later 10 | # version. It is also available under alternative (eg. Commercial) licenses, at 11 | # your option. See the LICENSE file at the top of the source tree. 12 | # 13 | # Python-slip39 is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 16 | # 17 | 18 | import sys 19 | 20 | from .main import main 21 | 22 | sys.exit( main() ) 23 | -------------------------------------------------------------------------------- /slip39/invoice/Cryptos/BNB_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Cryptos/BNB_32.png -------------------------------------------------------------------------------- /slip39/invoice/Cryptos/BTC_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Cryptos/BTC_32.png -------------------------------------------------------------------------------- /slip39/invoice/Cryptos/CRO_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Cryptos/CRO_32.png -------------------------------------------------------------------------------- /slip39/invoice/Cryptos/DOGE_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Cryptos/DOGE_32.png -------------------------------------------------------------------------------- /slip39/invoice/Cryptos/ETH_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Cryptos/ETH_32.png -------------------------------------------------------------------------------- /slip39/invoice/Cryptos/LTC_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Cryptos/LTC_32.png -------------------------------------------------------------------------------- /slip39/invoice/Cryptos/XRP_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Cryptos/XRP_32.png -------------------------------------------------------------------------------- /slip39/invoice/MultiSend-solc-v0-4-11.sol: -------------------------------------------------------------------------------- 1 | contract MultiSend { 2 | function MultiSend(address[] recipients, uint[] amounts, address remainder) { 3 | if(recipients.length != amounts.length) 4 | throw; 5 | 6 | for(uint i = 0; i < recipients.length; i++) { 7 | recipients[i].send(amounts[i]); 8 | } 9 | 10 | selfdestruct(remainder); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /slip39/invoice/MultiSend-solc-v0-5-15.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.15; 2 | 3 | contract MultiSend { 4 | constructor(address payable[] memory recipients, uint256[] memory amounts, address payable remainder) public payable { 5 | // require(recipients.length == amounts.length); 6 | 7 | for(uint256 i = 0; i < recipients.length; i++) { 8 | recipients[i].send(amounts[i]); 9 | } 10 | 11 | selfdestruct(remainder); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /slip39/invoice/MultiTransferEther-solc-v0-5-16.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.15; 2 | 3 | contract MultiSend { 4 | constructor(address payable[] memory recipients, uint256[] memory amounts, address payable remainder) public payable { 5 | // require(recipients.length == amounts.length); 6 | 7 | for(uint256 i = 0; i < recipients.length; i++) { 8 | recipients[i].send(amounts[i]); 9 | } 10 | 11 | selfdestruct(remainder); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /slip39/invoice/Tokens-Goerli.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "contract": "0xaFF4481D10270F50f203E0763e2597776068CBc5", 4 | "name": "Weenus \ud83d\udcaa", 5 | "symbol": "WEENUS", 6 | "decimals": 18, 7 | "icon": null 8 | }, 9 | { 10 | "contract": "0x022E292b44B5a146F2e8ee36Ff44D3dd863C915c", 11 | "name": "Xeenus \ud83d\udcaa", 12 | "symbol": "XEENUS", 13 | "decimals": 18, 14 | "icon": null 15 | }, 16 | { 17 | "contract": "0xc6fDe3FD2Cc2b173aEC24cc3f267cb3Cd78a26B7", 18 | "name": "Yeenus \ud83d\udcaa", 19 | "symbol": "YEENUS", 20 | "decimals": 8, 21 | "icon": null 22 | }, 23 | { 24 | "contract": "0x1f9061B953bBa0E36BF50F21876132DcF276fC6e", 25 | "name": "Zeenus \ud83d\udcaa", 26 | "symbol": "ZEENUS", 27 | "decimals": 0, 28 | "icon": null 29 | } 30 | ] 31 | -------------------------------------------------------------------------------- /slip39/invoice/Tokens/1INCH_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/1INCH_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/AGIX_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/AGIX_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/AMB_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/AMB_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/AMP_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/AMP_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/ANY_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/ANY_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/AOA_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/AOA_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/APE_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/APE_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/BAL_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/BAL_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/BAND_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/BAND_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/BAT.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/BAT.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/BDG.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/BDG.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/BIT_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/BIT_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/BNB_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/BNB_2.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/BNT_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/BNT_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/BTT_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/BTT_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/BUSD_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/BUSD_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/CEL_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/CEL_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/CHSB_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/CHSB_3.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/CHZ_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/CHZ_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/CNN_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/CNN_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/COFI_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/COFI_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/COMP_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/COMP_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/CRO_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/CRO_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/CVX_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/CVX_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/DACC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/DACC.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/DAI_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/DAI_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/DATx_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/DATx_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/DENT.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/DENT.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/DFI_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/DFI_32.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/DYDX_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/DYDX_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/ELEC_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/ELEC_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/ELON_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/ELON_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/ENJ_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/ENJ_2.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/ENS_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/ENS_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/EURT_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/EURT_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/FAIR_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/FAIR_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/FEG_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/FEG_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/FET_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/FET_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/FLOKI_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/FLOKI_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/FRAX_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/FRAX_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/FTI_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/FTI_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/FTM_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/FTM_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/FUEL_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/FUEL_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/FUN_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/FUN_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/FXS_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/FXS_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/GALA_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/GALA_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/GLM_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/GLM_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/GMT_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/GMT_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/GNO_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/GNO_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/GRT_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/GRT_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/GSE_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/GSE_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/GTO.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/GTO.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/GUSD_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/GUSD_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/HAND_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/HAND_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/HBTC_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/HBTC_32.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/HEX_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/HEX_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/HOGE_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/HOGE_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/HOT_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/HOT_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/HT_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/HT_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/IHT_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/IHT_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/IIC_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/IIC_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/IMT_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/IMT_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/IND_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/IND_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/IONC_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/IONC_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/IOST_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/IOST_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/IOTX_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/IOTX_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/IOV_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/IOV_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/KAN.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/KAN.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/KCS_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/KCS_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/KNC_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/KNC_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/KUB_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/KUB_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/LDO_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/LDO_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/LEND_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/LEND_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/LEO_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/LEO_2.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/LINK_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/LINK_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/LPT_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/LPT_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/LRC_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/LRC_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/LXT_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/LXT_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/LYM_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/LYM_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/MASK_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/MASK_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/MATIC_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/MATIC_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/MCO_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/MCO_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/MITx_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/MITx_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/MKR.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/MKR.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/MWAT_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/MWAT_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/NEAR_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/NEAR_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/NEXO_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/NEXO_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/NXM_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/NXM_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/OCN_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/OCN_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/OHM_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/OHM_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/OKB_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/OKB_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/OMG_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/OMG_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/ONE_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/ONE_32.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/PAI_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/PAI_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/PAXG_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/PAXG_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/PAY_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/PAY_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/POLY_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/POLY_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/POWR_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/POWR_2.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/PTT_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/PTT_32.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/QNT_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/QNT_2.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/REV_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/REV_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/RFR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/RFR.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/RNDR_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/RNDR_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/RNT_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/RNT_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/RPL_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/RPL_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/RSR_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/RSR_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SAITAMA_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SAITAMA_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SALT_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SALT_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SAND_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SAND_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SAT_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SAT_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SHIB_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SHIB_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SLP_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SLP_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SNT.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SNT.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SNX_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SNX_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SRM_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SRM_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/STORJ_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/STORJ_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/STQ_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/STQ_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SUSHI_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SUSHI_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/SYN_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/SYN_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/TEL_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/TEL_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/THETA_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/THETA_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/TOS_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/TOS_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/TUSD_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/TUSD_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/UCASH_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/UCASH_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/UNI_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/UNI_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/USDC_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/USDC_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/USDD_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/USDD_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/USDP_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/USDP_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/USDT_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/USDT_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/VEN_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/VEN_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/VIN_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/VIN_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/WBTC_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/WBTC_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/WETH_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/WETH_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/WOO_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/WOO_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/WQTUM_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/WQTUM_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/XAUt_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/XAUt_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/XCN_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/XCN_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/XDCE_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/XDCE_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/XEN_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/XEN_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/XMX_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/XMX_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/XNN_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/XNN_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/XYO_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/XYO_2.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/YEE_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/YEE_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/YFI_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/YFI_2.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/ZIL_2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/ZIL_2.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/ZRX_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/ZRX_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/ZSC_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/ZSC_28.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/aAAVE_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/aAAVE_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/anyLTC_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/anyLTC_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/cDAI_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/cDAI_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/cETH_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/cETH_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/cUSDC_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/cUSDC_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/cUSDT_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/cUSDT_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/nCash_28.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/nCash_28.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/rETH_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/rETH_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/stETH_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/stETH_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/stkAAVE_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/stkAAVE_32.webp -------------------------------------------------------------------------------- /slip39/invoice/Tokens/wCELO_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/wCELO_32.png -------------------------------------------------------------------------------- /slip39/invoice/Tokens/wMANA_32.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/Tokens/wMANA_32.webp -------------------------------------------------------------------------------- /slip39/invoice/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Python-slip39 -- Ethereum SLIP-39 Account Generation and Recovery 4 | # 5 | # Copyright (c) 2022, Dominion Research & Development Corp. 6 | # 7 | # Python-slip39 is free software: you can redistribute it and/or modify it under 8 | # the terms of the GNU General Public License as published by the Free Software 9 | # Foundation, either version 3 of the License, or (at your option) any later 10 | # version. It is also available under alternative (eg. Commercial) licenses, at 11 | # your option. See the LICENSE file at the top of the source tree. 12 | # 13 | # Python-slip39 is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 16 | # 17 | 18 | from __future__ import annotations 19 | 20 | from .ethereum import ( # noqa F401 21 | contract_address, 22 | etherscan_urls, 23 | etherscan, gasoracle, ethprice, 24 | etherbalance, ethertx, erc20tx, 25 | Direction, etherio, erc20io, 26 | GasOracle, Chain, Speed, Etherscan, 27 | Contract, 28 | ) 29 | from .multipayout import ( # noqa F401 30 | MultiPayoutERC20, 31 | ) 32 | 33 | __author__ = "Perry Kundert" 34 | __email__ = "perry@dominionrnd.com" 35 | __copyright__ = "Copyright (c) 2022 Dominion Research & Development Corp." 36 | __license__ = "Dual License: GPLv3 (or later) and Commercial (see LICENSE)" 37 | -------------------------------------------------------------------------------- /slip39/invoice/artifact_test/dominionrnd-invoice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/artifact_test/dominionrnd-invoice.png -------------------------------------------------------------------------------- /slip39/invoice/artifact_test/dominionrnd-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/invoice/artifact_test/dominionrnd-logo.png -------------------------------------------------------------------------------- /slip39/invoice/bitquery_test.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | import http.client 3 | import json 4 | import os 5 | 6 | 7 | # We don't want to run this test unless we provide our bitquery API 8 | # key in X-API-KEY 9 | @pytest.mark.skipif( not os.getenv( "BITQUERY_API_KEY" ), reason="Missing BITQUERY_API_KEY environment variable" ) 10 | def test_bitquery_smoke(): 11 | 12 | queries = [ 13 | { 14 | "query": """\ 15 | query ($network: EthereumNetwork!, $addresses: [String!]) { 16 | ethereum(network: $network) { 17 | address(address: {in: $addresses}) { 18 | address 19 | annotation 20 | balances { 21 | value 22 | currency { 23 | address 24 | symbol 25 | tokenType 26 | } 27 | } 28 | } 29 | } 30 | } 31 | """, 32 | "variables": { 33 | "network": "ethereum", 34 | "addresses": [ 35 | "0x22615C3A31d8f9d47bdB84502780A8D2C136fCF5" 36 | ] 37 | } 38 | }, 39 | { 40 | "query": """\ 41 | query ($network: BitcoinNetwork!, $addresses: [String!]) { 42 | bitcoin(network: $network) { 43 | inbound: coinpath(receiver: {in: $addresses}) { 44 | receiver { 45 | address 46 | } 47 | amount 48 | } 49 | } 50 | } 51 | """, 52 | "variables": { 53 | "network": "bitcoin", 54 | "addresses": [ 55 | "bc1qcj9ujyvrf94wu0902g2lnklzlyn5j5nrr44hwp", 56 | "18cBEMRxXHqzWWCxZNtU91F5sbUNKhL5PX", 57 | "bc1qygm3dlynmjxuflghr0hmq6r7wmff2jd5gtgz0q" 58 | ] 59 | } 60 | } 61 | ] 62 | 63 | headers = { 64 | 'Content-Type': 'application/json', 65 | 'X-API-KEY': os.getenv( "BITQUERY_API_KEY" ), 66 | } 67 | 68 | conn = http.client.HTTPSConnection("graphql.bitquery.io") 69 | 70 | for query in queries: 71 | payload = json.dumps( query ) 72 | print( payload ) 73 | 74 | conn.request("POST", "/", payload, headers) 75 | rx = conn.getresponse() 76 | rxstr = rx.read().decode("UTF-8") 77 | print(rxstr) 78 | response = json.loads( rxstr ) 79 | print( json.dumps( response, indent=4 )) 80 | -------------------------------------------------------------------------------- /slip39/invoice/contracts/ForwarderERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | // A minimal Forwarder that can be deployed using the EVM CREATE2 opcode at a 5 | // deterministic address. Thus, we do not need to actually deploy the contract 6 | // until funds appear at the address. 7 | // 8 | // This process takes the initiating source address (the address of the Contract initiating the 9 | // CREATE2), a salt and the contract creation code (which includes the constructor arguments). Of 10 | // course, this includes the destination address. But importantly, in order to support a number of 11 | // ERC-20 token Contract addresses, the Forward must know all the possible tokens *in advance* -- 12 | // support for additional tokens cannot be made *after* address creation! For example, if you wish to 13 | // allow the client to pay in ETH, or ERC-20 USDC or USDT, only these tokens can *ever* be supported by 14 | // this address! 15 | // 16 | // Some examples of this concept: 17 | // 18 | // https://github.com/gabrieladeniji/forwarder_factory/blob/main/contracts/ForwarderFactory.sol 19 | // 20 | // Our forwarder is a one-shot, where the constructore executes all ERC-20 transfers and finally uses 21 | // selfdestruct to clear out the account's ETH and destroy the contract, reducing its Gas cost. 22 | // Since this is a "push" payment, we must carefully wrap any ERC-20 calls ignoring errors, in 23 | // case one or more of the supported ERC-20 contracts is selfdestructed or is otherwise faulty. 24 | // Since all operations occur during Forwarder construction, no reentrancy is possible. 25 | // 26 | // Coinbase uses/used(?) something like this to manage their merchant payment wallets: 27 | // 28 | // https://web.archive.org/web/20190814233503/https://blog.coinbase.com/usdc-payment-processing-in-coinbase-commerce-b1af1c82fb0?gi=f79ac81c04f1 29 | // 30 | // Note that we can re-deploy the same contract multiple times, if desired (for example, if a client re-uses 31 | // the same payment address multiple times): 32 | // 33 | // https://forum.openzeppelin.com/t/selfdestruct-and-redeploy-in-the-same-transaction-using-create2-fails/8797 34 | // 35 | // This fact makes it possible to deploy 2 functionally *differing* contracts at the same address: 36 | // 37 | // https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2 38 | // 39 | // Deploymenet via the CREATE2 opcode is available in Solidity >=0.8 using: 40 | // 41 | // function deploy( uint256 _salt, uint256 _arg1, address _arg2 ) returns ( address ) { 42 | // return address( new ContractName{ salt: _salt }( _arg1, _arg2 )); 43 | // } 44 | // 45 | // The Contract address can be precomputed: (from https://solidity-by-example.org/app/create2/) 46 | // 47 | // function deploy_address( uint256 _salt, uint256 _arg1, address _arg2 ) 48 | // public 49 | // view 50 | // returns ( address ) 51 | // { 52 | // bytes memory contract = type(ContractName).creationCode; 53 | // bytes memory creation = abi.encodePacked( contract, abi.encode( _arg1, _arg2 )); 54 | // bytes32 creation_hash = keccak256( 55 | // abi.encodePacked( bytes1( 0xff ), address( this ), _salt, keccak256( creation )) 56 | // ); 57 | // return address( uint160( uint256( creation_hash ))); 58 | // } 59 | // 60 | // In Python using Web3, we could call this (view) contract function, or we can Contract creation encoded using the ABI: 61 | // 62 | // creation_code = ContractName.constructor( arg1, arg2 ).data_in_transaction; 63 | // 64 | // 65 | import "openzeppelin-contracts/contracts/interfaces/IERC20.sol"; 66 | 67 | contract ForwarderERC20 { 68 | constructor( address payable _recipient, IERC20[] memory _tokens ) public payable { 69 | for (uint256 tok = 0; tok < _tokens.length; tok++) { 70 | uint256 tok_balance; 71 | // Get the balance of the contract for the current token 72 | try _tokens[tok].balanceOf( address( this )) returns ( uint256 value ) { 73 | tok_balance = value; 74 | } catch { 75 | continue; 76 | } 77 | if ( tok_balance > 0 ) { 78 | // Forward the balance to the recipient 79 | try _tokens[tok].transfer( _recipient, tok_balance ) returns ( bool ) { 80 | // ignore failing ERC-20 transfer 81 | } catch { 82 | continue; // ignore exception on ERC-20 transfer 83 | } 84 | } 85 | } 86 | selfdestruct( _recipient ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /slip39/invoice/contracts/MultiPayoutERC20Base.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | import "../openzeppelin-contracts/contracts/security/ReentrancyGuard.sol"; 5 | import "../openzeppelin-contracts/contracts/access/Ownable.sol"; 6 | import { 7 | IERC20Metadata as IERC20 // w/ decimals() 8 | } from "../openzeppelin-contracts/contracts/token/ERC20/extensions/IERC20Metadata.sol"; 9 | 10 | // 11 | // Implements all the ERC-20 handling for MultiPayoutERC20 12 | // 13 | // Allows other contracts that know about MultiPayoutERC20 (such as MultiPayoutERC20Forwarder) to 14 | // access data about the supported ERC-20s. 15 | // 16 | abstract contract MultiPayoutERC20Base is ReentrancyGuard, Ownable { 17 | 18 | 19 | // 20 | // __SELF -- specific at construction, and used to support ...Forwarder collection 21 | // 22 | // NOTE: immutable variables are assigned once at construction, and the construction code is 23 | // modified to contain the value in-place, so "access" to these immutable values in code 24 | // does NOT actually interrogate the contract's data! Thus, in "delegatecall"-ed code, 25 | // we can safely use these values. 26 | // 27 | address internal immutable __SELF = address( this ); 28 | 29 | modifier isDelegated() { 30 | require( address( this ) != __SELF ); 31 | _; 32 | } 33 | modifier notDelegated() { 34 | require( address( this ) == __SELF ); 35 | _; 36 | } 37 | 38 | // 39 | // erc20s (and ..._len(), _add( IERC20 ), _del( IERC20 ) 40 | // 41 | IERC20[] public erc20s; 42 | 43 | // Construct w/ 0 or more ERC-20 tokens. Don't duplicate (just a waste, not checked) 44 | constructor( 45 | IERC20[] memory _erc20s 46 | ) 47 | payable 48 | { 49 | for ( uint256 t = 0; t < _erc20s.length; t++ ) { 50 | erc20s.push( _erc20s[t] ); 51 | } 52 | } 53 | 54 | function erc20s_len() 55 | public 56 | view 57 | returns ( uint256 ) 58 | { 59 | return erc20s.length; 60 | } 61 | 62 | function erc20s_add( 63 | IERC20 _token 64 | ) 65 | external 66 | onlyOwner 67 | { 68 | for ( uint256 i = 0; i < erc20s.length; ++i ) { 69 | if ( erc20s[i] == _token ) { 70 | return; 71 | } 72 | } 73 | erc20s.push( _token ); 74 | } 75 | 76 | function erc20s_del( 77 | IERC20 _token 78 | ) 79 | external 80 | onlyOwner 81 | { 82 | for ( uint256 i = 0; i < erc20s.length; i++ ) { 83 | if ( erc20s[i] == _token ) { 84 | unchecked { 85 | erc20s[i] = erc20s[erc20s.length - 1]; 86 | } 87 | erc20s.pop(); 88 | return; 89 | } 90 | } 91 | } 92 | 93 | // 94 | // Anyone can delegatecall this function, to forward all of their ERC-20 tokens into this contract 95 | // 96 | // Used by MultiPayoutERC20Forwarder to collect its ERC-20 tokens. 97 | // 98 | // Not recommended for general public use, but you can call it if you want! ;) 99 | // 100 | // REENTRANCY ATTACK 101 | // 102 | // It is not necessary to protect this from reentrancy, if only reputable ERC-20 tokens 103 | // are included. A disreputable ERC-20 token's transfer function could re-enter this 104 | // call, resulting in the same token transfers being re-attempted, and subsequent transfers 105 | // delayed. But, only its own failure to implement check-effects-interactions can be exploited, 106 | // since the full .balanceOf each token is being transferred out. 107 | // 108 | // A failing ERC-20 will result in an exception (reverting the ...Forwarder), but this can be solved 109 | // by removing the offending ERC-20 token via MultiPayoutERC20.erc20s_del(). 110 | // 111 | function erc20_collect( 112 | IERC20 _token 113 | ) 114 | private 115 | { 116 | uint256 balance = _token.balanceOf( address( this )); 117 | if ( balance > 0 ) { 118 | // Forward the caller's balance to the recipient (this contract!) 119 | _token.transfer( __SELF, balance ); 120 | } 121 | } 122 | 123 | function erc20s_collector() 124 | external 125 | isDelegated // Only delegatecall allowed! We'll be transferring from the caller's address( this ) 126 | { 127 | MultiPayoutERC20Base self = MultiPayoutERC20Base( __SELF ); 128 | uint256 t = self.erc20s_len(); 129 | while ( t > 0 ) { 130 | erc20_collect( self.erc20s( --t )); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /slip39/invoice/contracts/MultiPayoutERC20Forwarder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity ^0.8.0; 3 | 4 | // A minimal Forwarder that can be deployed using the EVM CREATE2 opcode at a 5 | // deterministic address. Thus, we do not need to actually deploy the contract 6 | // until funds appear at the address. 7 | // 8 | // This process takes the initiating source address (the address of the Contract initiating the 9 | // CREATE2), a salt and the contract creation code (which includes the constructor arguments). Of 10 | // course, this includes the destination address. But importantly, in order to support a number of 11 | // ERC-20 token Contract addresses, the Forward must know all the possible tokens *in advance* -- 12 | // support for additional tokens cannot be made *after* address creation! For example, if you wish to 13 | // allow the client to pay in ETH, or ERC-20 USDC or USDT, only these tokens can *ever* be supported by 14 | // this address! 15 | // 16 | // Some examples of this concept: 17 | // 18 | // https://github.com/gabrieladeniji/forwarder_factory/blob/main/contracts/ForwarderFactory.sol 19 | // 20 | // Our forwarder is a one-shot, where the constructore executes all ERC-20 transfers and finally uses 21 | // selfdestruct to clear out the account's ETH and destroy the contract, reducing its Gas cost. 22 | // Since this is a "push" payment, we must carefully wrap any ERC-20 calls ignoring errors, in 23 | // case one or more of the supported ERC-20 contracts is selfdestructed or is otherwise faulty. 24 | // Since all operations occur during Forwarder construction, no reentrancy is possible. 25 | // 26 | // Coinbase uses/used(?) something like this to manage their merchant payment wallets: 27 | // 28 | // https://web.archive.org/web/20190814233503/https://blog.coinbase.com/usdc-payment-processing-in-coinbase-commerce-b1af1c82fb0?gi=f79ac81c04f1 29 | // 30 | // Note that we can re-deploy the same contract multiple times, if desired (for example, if a client re-uses 31 | // the same payment address multiple times): 32 | // 33 | // https://forum.openzeppelin.com/t/selfdestruct-and-redeploy-in-the-same-transaction-using-create2-fails/8797 34 | // 35 | // This fact makes it possible to deploy 2 functionally *differing* contracts at the same address: 36 | // 37 | // https://docs.soliditylang.org/en/latest/control-structures.html#salted-contract-creations-create2 38 | // 39 | // Deploymenet via the CREATE2 opcode is available in Solidity >=0.8 using: 40 | // 41 | // function deploy( uint256 _salt, uint256 _arg1, address _arg2 ) returns ( address ) { 42 | // return address( new ContractName{ salt: _salt }( _arg1, _arg2 )); 43 | // } 44 | // 45 | // The Contract address can be precomputed: (from https://solidity-by-example.org/app/create2/) 46 | // 47 | // function deploy_address( uint256 _salt, uint256 _arg1, address _arg2 ) 48 | // public 49 | // view 50 | // returns ( address ) 51 | // { 52 | // bytes memory contract = type(ContractName).creationCode; 53 | // bytes memory creation = abi.encodePacked( contract, abi.encode( _arg1, _arg2 )); 54 | // bytes32 creation_hash = keccak256( 55 | // abi.encodePacked( bytes1( 0xff ), address( this ), _salt, keccak256( creation )) 56 | // ); 57 | // return address( uint160( uint256( creation_hash ))); 58 | // } 59 | // 60 | // In Python using Web3, we could call this (view) contract function, or we can Contract creation encoded using the ABI: 61 | // 62 | // creation_code = ContractName.constructor( arg1, arg2 ).data_in_transaction; 63 | // 64 | // 65 | import { 66 | MultiPayoutERC20Base 67 | } from "contracts/MultiPayoutERC20Base.sol"; 68 | 69 | contract MultiPayoutERC20Forwarder { 70 | constructor( 71 | address payable _multipayout 72 | ) 73 | payable 74 | { 75 | _multipayout.delegatecall( abi.encodeWithSignature( "erc20s_collector()" )); 76 | selfdestruct( _multipayout ); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /slip39/invoice/multipayout_test.crypto-keypair-plaintext: -------------------------------------------------------------------------------- 1 | { 2 | "sk":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7aie8zrakLWKjqNAqbw1zZTIVdx3iQ6Y6wEihi1naKQ==", 3 | "vk":"O2onvM62pC1io6jQKm8Nc2UyFXcd4kOmOsBIoYtZ2ik=" 4 | } 5 | -------------------------------------------------------------------------------- /slip39/invoice/multipayout_test.machine-id: -------------------------------------------------------------------------------- 1 | 000102030405060708090A0B0C0D0E0F 2 | -------------------------------------------------------------------------------- /slip39/invoice/payments_test/payments_test.machine-id: -------------------------------------------------------------------------------- 1 | 000102030405060708090A0B0C0D0E0F 2 | -------------------------------------------------------------------------------- /slip39/layout/1x1-ffffff3f.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/1x1-ffffff3f.png -------------------------------------------------------------------------------- /slip39/layout/1x1-ffffff54.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/1x1-ffffff54.png -------------------------------------------------------------------------------- /slip39/layout/1x1-ffffffbf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/1x1-ffffffbf.png -------------------------------------------------------------------------------- /slip39/layout/BNB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/BNB.png -------------------------------------------------------------------------------- /slip39/layout/BTC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/BTC.png -------------------------------------------------------------------------------- /slip39/layout/COVER-BIP-39.org: -------------------------------------------------------------------------------- 1 | #+title: Seed Recovery Using BIP-39 2 | #+OPTIONS: toc:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | SLIP-39 supports Hardware Wallets that require BIP-39 Mnemonics for Seed recovery, such as your 6 | Ledger Nano, etc. Recover your BIP-39 Mnemonic phrase from these cards using the SLIP-39 App 7 | whenever you need it, to restore your Cryptocurrency accounts to your hardware wallet. 8 | #+END_ABSTRACT 9 | 10 | - Open the SLIP-39 App, and set Controls to "Recover" 11 | - In "Seed Source", use "SLIP-39" and input Mnemonics, with sufficient: 12 | - Different Groups to satisfy Recovery Card Groups threshold 13 | - Cards in each Group to meet each groups' recovery minimums 14 | - In "Seed & SLIP-39 Recover Groups", click "Using BIP-39" 15 | - The BIP-39 Mnemonic will be recovered and displayed 16 | - Restore your Cryptocurrency accounts to your hardware wallet by entering the BIP-39 Mnemonic phrase. 17 | - Cut off and *destroy* this BIP-39 Mnemonic backup, once you are confident you can recover it at will! 18 | 19 | #+BEGIN_QUOTE 20 | NOTE: You cannot enter these SLIP-39 Mnemonics directly on a BIP-39 Hardware Wallet to recover the 21 | Seed. Use the SLIP-39 App to recover the BIP-39 Seed Phrase. 22 | #+END_QUOTE 23 | -------------------------------------------------------------------------------- /slip39/layout/COVER-BIP-39.txt: -------------------------------------------------------------------------------- 1 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2 | SEED RECOVERY USING BIP-39 3 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4 | 5 | 6 | SLIP-39 supports Hardware Wallets that require BIP-39 Mnemonics for Seed 7 | recovery, such as your Ledger Nano, etc. Recover your BIP-39 Mnemonic 8 | phrase from these cards using the SLIP-39 App whenever you need it, to 9 | restore your Cryptocurrency accounts to your hardware wallet. 10 | 11 | • Open the SLIP-39 App, and set Controls to "Recover" 12 | • In "Seed Source", use "SLIP-39" and input Mnemonics, with sufficient: 13 | • Different Groups to satisfy Recovery Card Groups threshold 14 | • Cards in each Group to meet each groups' recovery minimums 15 | • In "Seed & SLIP-39 Recover Groups", click "Using BIP-39" 16 | • The BIP-39 Mnemonic will be recovered and displayed 17 | • Restore your Cryptocurrency accounts to your hardware wallet by 18 | entering the BIP-39 Mnemonic phrase. 19 | • Cut off and *destroy* this BIP-39 Mnemonic backup, once you are 20 | confident you can recover it at will! 21 | 22 | NOTE: You cannot enter these SLIP-39 Mnemonics directly on a 23 | BIP-39 Hardware Wallet to recover the Seed. Use the SLIP-39 24 | App to recover the BIP-39 Seed Phrase. 25 | -------------------------------------------------------------------------------- /slip39/layout/COVER-SLIP-39.org: -------------------------------------------------------------------------------- 1 | #+title: Seed Recovery Using SLIP-39 2 | #+OPTIONS: toc:nil author:nil 3 | 4 | #+BEGIN_ABSTRACT 5 | SLIP-39 Mnemonic Cards for Hardware Wallets that natively support it, such as your Trezor. Recover 6 | your Cryptocurrency accounts to your hardware wallet directly from these SLIP-39 cards, by entering 7 | them on the screen of the device. 8 | #+END_ABSTRACT 9 | 10 | - Collect these "SLIP-39" Card Mnemonics, with sufficient: 11 | - Different Groups to satisfy Recovery Card Groups threshold 12 | - Cards in each Group to meet each groups' recovery minimums 13 | - Enter SLIP-39 recovery mode on your hardware wallet 14 | - Restore your Cryptocurrency accounts to your hardware wallet by entering the SLIP-39 Mnemonic phrases. 15 | 16 | #+BEGIN_QUOTE 17 | NOTE: There is no BIP-39 Seed Phrase for this cryptocurrency Seed! It must be recovered directly 18 | from the SLIP-39 Mnemonic Card phrases. You cannot use these phrases to recover the Seed to a 19 | BIP-39 compatible Hardware Wallet; only to one supporting native SLIP-39. 20 | #+END_QUOTE 21 | -------------------------------------------------------------------------------- /slip39/layout/COVER-SLIP-39.txt: -------------------------------------------------------------------------------- 1 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2 | SEED RECOVERY USING SLIP-39 3 | ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4 | 5 | 6 | SLIP-39 Mnemonic Cards for Hardware Wallets that natively support it, 7 | such as your Trezor. Recover your Cryptocurrency accounts to your 8 | hardware wallet directly from these SLIP-39 cards, by entering them on 9 | the screen of the device. 10 | 11 | • Collect these "SLIP-39" Card Mnemonics, with sufficient: 12 | • Different Groups to satisfy Recovery Card Groups threshold 13 | • Cards in each Group to meet each groups' recovery minimums 14 | • Enter SLIP-39 recovery mode on your hardware wallet 15 | • Restore your Cryptocurrency accounts to your hardware wallet by 16 | entering the SLIP-39 Mnemonic phrases. 17 | 18 | NOTE: There is no BIP-39 Seed Phrase for this cryptocurrency 19 | Seed! It must be recovered directly from the SLIP-39 20 | Mnemonic Card phrases. You cannot use these phrases to 21 | recover the Seed to a BIP-39 compatible Hardware Wallet; 22 | only to one supporting native SLIP-39. 23 | -------------------------------------------------------------------------------- /slip39/layout/COVER.txt: -------------------------------------------------------------------------------- 1 | 2 | # m m m m ""# " mmmm mmmm 3 | # mm mm#mm mm#mm mmmm mmm # # mmm # mmm mmmm " "# #" "m mmm mmm mmmmm 4 | #" # # # #" "# # " # # # # " # # #" "# mmm" #m m# #" " #" "# # # # 5 | # # # # # # """m # # """m # # # # "# """ # # # # # # # 6 | # # "mm "mm ##m#" "mmm" # # # "mmm" "mm mm#mm ##m#" "mmm#" "mmm" # "#mm" "#m#" # # # 7 | # " " # 8 | " " 9 | Safe & Effective (tm) Crypto Wallet Backup and Recovery 10 | (explanations and instructions will appear here) 11 | -------------------------------------------------------------------------------- /slip39/layout/CRO.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/CRO.png -------------------------------------------------------------------------------- /slip39/layout/DOGE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/DOGE.png -------------------------------------------------------------------------------- /slip39/layout/ETH.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/ETH.png -------------------------------------------------------------------------------- /slip39/layout/LTC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/LTC.png -------------------------------------------------------------------------------- /slip39/layout/SLIP-39.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/SLIP-39.png -------------------------------------------------------------------------------- /slip39/layout/XRP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/XRP.png -------------------------------------------------------------------------------- /slip39/layout/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Python-slip39 -- Ethereum SLIP-39 Account Generation and Recovery 4 | # 5 | # Copyright (c) 2022, Dominion Research & Development Corp. 6 | # 7 | # Python-slip39 is free software: you can redistribute it and/or modify it under 8 | # the terms of the GNU General Public License as published by the Free Software 9 | # Foundation, either version 3 of the License, or (at your option) any later 10 | # version. It is also available under alternative (eg. Commercial) licenses, at 11 | # your option. See the LICENSE file at the top of the source tree. 12 | # 13 | # Python-slip39 is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 16 | # 17 | from __future__ import annotations 18 | 19 | __author__ = "Perry Kundert" 20 | __email__ = "perry@dominionrnd.com" 21 | __copyright__ = "Copyright (c) 2022 Dominion Research & Development Corp." 22 | __license__ = "Dual License: GPLv3 (or later) and Commercial (see LICENSE)" 23 | 24 | from .components import * # noqa F403 25 | from .printer import * # noqa F403 26 | from .pdf import * # noqa F403 27 | -------------------------------------------------------------------------------- /slip39/layout/font/DejaVuSansMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/DejaVuSansMono-Bold.ttf -------------------------------------------------------------------------------- /slip39/layout/font/DejaVuSansMono-BoldOblique.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/DejaVuSansMono-BoldOblique.ttf -------------------------------------------------------------------------------- /slip39/layout/font/DejaVuSansMono-Oblique.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/DejaVuSansMono-Oblique.ttf -------------------------------------------------------------------------------- /slip39/layout/font/DejaVuSansMono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/DejaVuSansMono.ttf -------------------------------------------------------------------------------- /slip39/layout/font/Inconsolata-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/Inconsolata-Bold.ttf -------------------------------------------------------------------------------- /slip39/layout/font/Inconsolata-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/Inconsolata-Regular.ttf -------------------------------------------------------------------------------- /slip39/layout/font/NotoSansMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/NotoSansMono-Bold.ttf -------------------------------------------------------------------------------- /slip39/layout/font/NotoSansMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/NotoSansMono-Regular.ttf -------------------------------------------------------------------------------- /slip39/layout/font/OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright 2006 The Inconsolata Project Authors 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /slip39/layout/font/OverpassMono-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/OverpassMono-Bold.ttf -------------------------------------------------------------------------------- /slip39/layout/font/OverpassMono-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/OverpassMono-Regular.ttf -------------------------------------------------------------------------------- /slip39/layout/font/SourceCodePro-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/SourceCodePro-Bold.ttf -------------------------------------------------------------------------------- /slip39/layout/font/SourceCodePro-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/SourceCodePro-BoldItalic.ttf -------------------------------------------------------------------------------- /slip39/layout/font/SourceCodePro-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/SourceCodePro-Italic.ttf -------------------------------------------------------------------------------- /slip39/layout/font/SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/font/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /slip39/layout/paper-wallet-background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjkundert/python-slip39/fa02f5fc03ce123394afe5dd0d9d2132689f671d/slip39/layout/paper-wallet-background.png -------------------------------------------------------------------------------- /slip39/output_test.py: -------------------------------------------------------------------------------- 1 | import qrcode 2 | 3 | from pytest import approx 4 | from fpdf import FPDF, FlexTemplate 5 | 6 | from .layout import Region, Text, Image, Box, Coordinate 7 | from .defaults import MM_IN 8 | 9 | 10 | def test_Region(): 11 | card_size = Coordinate( y=2+1/4, x=3+3/8 ) 12 | card_margin = 1/8 13 | card = Box( 'card', 0, 0, card_size.x, card_size.y ) 14 | #print( card ) 15 | card_interior = card.add_region_relative( 16 | Region( 'card-interior', x1=+card_margin, y1=+card_margin, x2=-card_margin, y2=-card_margin ) 17 | ) 18 | #print( card_interior ) 19 | assert card_interior.x1 == card_margin 20 | assert card_interior.x2 == card_size.x - card_margin 21 | assert card_interior.y2 == card_size.y - card_margin 22 | assert card_interior.x2 - card_interior.x1 == card_size.x - card_margin * 2 23 | 24 | card_qr = card_interior.add_region_proportional( 25 | Image( 'card-qr', x1=1/2, y1=1/4, x2=1, y2=1 ) 26 | ).square( maximum=1, justify='BR' ) 27 | card_interior.add_region_proportional( 28 | Box( 'card-box-ul', x1=1/2, y1=1/4, x2=1, y2=1 ) 29 | ).square( maximum=.5, justify='TL' ) 30 | card_interior.add_region_proportional( 31 | Box( 'card-box-cm', x1=1/2, y1=1/4, x2=1, y2=1 ) 32 | ).square( maximum=.5 ) 33 | card_interior.add_region_proportional( 34 | Box( 'card-box-br', x1=1/2, y1=1/4, x2=1, y2=1 ) 35 | ).square( maximum=.5, justify='BR' ) 36 | 37 | #card_qr.x1 = card_qr.x2 - 1.0 38 | #card_qr.y1 = card_qr.y2 - 1.0 39 | #print( card_qr ) 40 | assert card_qr.x1 == 2.25 41 | assert card_qr.y1 == 1.125 42 | 43 | elements = list( card.elements() )[1:] 44 | #print( json.dumps( elements, indent=4 )) 45 | assert len( elements ) == 4 46 | assert elements[0]['type'] == 'I' 47 | 48 | card_top = card_interior.add_region_proportional( 49 | Region( 'card-top', x1=0, y1=0, x2=1, y2=1/3 ) 50 | ) 51 | card_top.add_region_proportional( 52 | Text( 'card-title', x1=0, y1=0, x2=1, y2=40/100 ) 53 | ) 54 | 55 | elements = list( card.elements() )[1:] 56 | #print( json.dumps( elements, indent=4 )) 57 | assert elements[-1]['type'] == 'T' 58 | assert elements[-1]['font'] == 'helvetica' 59 | assert elements[-1]['size'] == approx( 14.4 ) 60 | 61 | pdf = FPDF() 62 | pdf.add_page() 63 | 64 | tpl = FlexTemplate( pdf, list( card.elements() ) ) 65 | tpl['card-qr'] = qrcode.make( 'abc' ).get_image() 66 | tpl['card-title'] = 'Abc' 67 | # Abc in upper-left 68 | tpl.render() 69 | 70 | tpl['card-qr'] = qrcode.make( 'abc' ).get_image() 71 | tpl['card-title'] = 'Xyz' 72 | # Xyz in lower-right 73 | tpl.render( offsetx = card_size.x * MM_IN, offsety = card_size.y * MM_IN ) 74 | 75 | #pdf.output( "test.pdf" ) # To view results in test.pdf, uncomment 76 | -------------------------------------------------------------------------------- /slip39/recovery/__main__.py: -------------------------------------------------------------------------------- 1 | 2 | # 3 | # Python-slip39 -- Ethereum SLIP-39 Account Generation and Recovery 4 | # 5 | # Copyright (c) 2022, Dominion Research & Development Corp. 6 | # 7 | # Python-slip39 is free software: you can redistribute it and/or modify it under 8 | # the terms of the GNU General Public License as published by the Free Software 9 | # Foundation, either version 3 of the License, or (at your option) any later 10 | # version. It is also available under alternative (eg. Commercial) licenses, at 11 | # your option. See the LICENSE file at the top of the source tree. 12 | # 13 | # Python-slip39 is distributed in the hope that it will be useful, but WITHOUT 14 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 16 | # 17 | 18 | from __future__ import annotations 19 | 20 | import sys 21 | 22 | from .main import main 23 | 24 | __author__ = "Perry Kundert" 25 | __email__ = "perry@dominionrnd.com" 26 | __copyright__ = "Copyright (c) 2022 Dominion Research & Development Corp." 27 | __license__ = "Dual License: GPLv3 (or later) and Commercial (see LICENSE)" 28 | 29 | sys.exit( main() ) 30 | -------------------------------------------------------------------------------- /slip39/recovery_test.csv: -------------------------------------------------------------------------------- 1 | entropy, passphrase, using_bip39, path, address 2 | zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong,,true,,bc1qk0a9hr7wjfxeenz9nwenw9flhq0tmsf6vsgnn2 3 | zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong,,,,bc1q9yscq3l2yfxlvnlk3cszpqefparrv7tk24u6pl 4 | fruit wave dwarf banana earth journey tattoo true farm silk olive fence,banana,true,,17rxURoF96VhmkcEGCj5LNQkmN9HVhWb7F 5 | 000102030405060708090a0b0c0d0e0f,,,m/0'/1,xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ 6 | fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542,,,m/0,xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH 7 | fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542,,,m/0/2147483647'/1,xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon 8 | -------------------------------------------------------------------------------- /slip39/version.py: -------------------------------------------------------------------------------- 1 | __version_info__ = ( 13, 1, 0 ) 2 | __version__ = '.'.join( map( str, __version_info__ )) 3 | --------------------------------------------------------------------------------