├── .github └── workflows │ ├── release-publish.yml │ ├── rust-format.yml │ └── test-pr.yml ├── .gitignore ├── .vscode ├── launch.json └── settings.json ├── Cargo.toml ├── LICENSE_MIT ├── README.md ├── examples ├── node-test │ ├── package-lock.json │ ├── package.json │ ├── tests │ │ ├── aes.test.js │ │ ├── bsm.test.js │ │ ├── ecies.test.js │ │ ├── hash.test.js │ │ ├── interpreter.test.js │ │ ├── p2pkh.test.js │ │ ├── scripts.test.js │ │ ├── sighash.test.js │ │ ├── signatures.test.js │ │ ├── tx.test.js │ │ ├── xpriv.test.js │ │ └── xpub.test.js │ ├── yarn-error.log │ └── yarn.lock ├── web-test │ ├── express.js │ ├── index.html │ ├── package.json │ └── yarn.lock └── webpack-test │ ├── index.html │ ├── package.json │ ├── sdk │ ├── README.md │ ├── package.json │ ├── twetch_sdk_wasm.d.ts │ ├── twetch_sdk_wasm.js │ ├── twetch_sdk_wasm_bg.js │ ├── twetch_sdk_wasm_bg.wasm │ └── twetch_sdk_wasm_bg.wasm.d.ts │ ├── src │ └── index.js │ ├── webpack.config.js │ └── yarn.lock ├── index.html ├── packages └── bsv-wasm │ ├── Cargo.toml │ ├── Makefile │ ├── pkg │ └── deno │ │ ├── bsv_wasm.d.ts │ │ ├── bsv_wasm.js │ │ ├── bsv_wasm_bg.wasm │ │ └── bsv_wasm_bg.wasm.d.ts │ └── src │ ├── address.rs │ ├── bsm.rs │ ├── chainparams.rs │ ├── ecdh.rs │ ├── ecdsa.rs │ ├── ecies.rs │ ├── encryption.rs │ ├── hash.rs │ ├── interpreter.rs │ ├── kdf.rs │ ├── keypair │ ├── extended_private_key.rs │ ├── extended_public_key.rs │ ├── mod.rs │ ├── private_key.rs │ └── public_key.rs │ ├── lib.rs │ ├── opcodes.rs │ ├── script.rs │ ├── sighash.rs │ ├── signature.rs │ └── transaction │ ├── mod.rs │ ├── txin.rs │ └── txout.rs ├── rustfmt.toml ├── src ├── address │ └── mod.rs ├── bsm │ └── mod.rs ├── chainparams │ └── mod.rs ├── ecdsa │ ├── ecdh.rs │ ├── mod.rs │ ├── recover.rs │ ├── sign.rs │ └── verify.rs ├── ecies │ ├── ecies_ciphertext.rs │ └── mod.rs ├── encryption │ └── mod.rs ├── errors │ └── mod.rs ├── hash │ ├── digest_utils.rs │ ├── hash160_digest.rs │ ├── mod.rs │ ├── reverse_digest.rs │ ├── sha256d_digest.rs │ └── sha256r_digest.rs ├── interpreter │ ├── errors.rs │ ├── mod.rs │ ├── script_matching.rs │ ├── stack_trait.rs │ └── state.rs ├── kdf │ ├── mod.rs │ └── pbkdf2_kdf.rs ├── keypair │ ├── extended_private_key.rs │ ├── extended_public_key.rs │ ├── mod.rs │ ├── private_key.rs │ └── public_key.rs ├── lib.rs ├── script │ ├── mod.rs │ ├── op_codes.rs │ ├── script_bit.rs │ └── script_template.rs ├── signature │ └── mod.rs ├── traits │ ├── mod.rs │ ├── to_hex.rs │ └── varint.rs ├── transaction │ ├── match_criteria.rs │ ├── mod.rs │ ├── outpoint.rs │ ├── sighash.rs │ ├── txin.rs │ └── txout.rs └── utils │ └── mod.rs └── tests ├── address.rs ├── aes.rs ├── bsm.rs ├── ecies.rs ├── extended_private_key.rs ├── extended_public_key.rs ├── hash.rs ├── interpreter_arithmetic.rs ├── interpreter_signatures.rs ├── interpreter_utilities.rs ├── kdf.rs ├── private_key.rs ├── public_key.rs ├── script.rs ├── script_template.rs ├── sighash.rs ├── signature.rs ├── transaction.rs └── tx_match_criteria.rs /.github/workflows/release-publish.yml: -------------------------------------------------------------------------------- 1 | name: Test & Publish 2 | 3 | on: 4 | release: 5 | types: # This configuration does not affect the page_build event above 6 | - prereleased 7 | - released 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: actions-rs/toolchain@v1 19 | with: 20 | toolchain: stable 21 | override: true 22 | 23 | - uses: Swatinem/rust-cache@v1 24 | with: 25 | cache-on-failure: true 26 | 27 | - name: Run tests 28 | run: cargo test --verbose 29 | 30 | node-test: 31 | runs-on: ubuntu-latest 32 | 33 | strategy: 34 | matrix: 35 | node-version: [15.x, 16.x] 36 | 37 | steps: 38 | - uses: actions/checkout@v2 39 | - uses: actions-rs/toolchain@v1 40 | with: 41 | toolchain: stable 42 | override: true 43 | 44 | - uses: Swatinem/rust-cache@v1 45 | with: 46 | cache-on-failure: true 47 | 48 | - name: Install wasm-opt 49 | run: sudo apt-get install -y binaryen 50 | 51 | - name: Install wasm-pack 52 | run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 53 | 54 | - name: Install wasm-bindgen-cli Custom 55 | run: cargo install -f wasm-bindgen-cli 56 | - run: make build-nodejs 57 | working-directory: packages/bsv-wasm 58 | 59 | - name: Use Node.js ${{ matrix.node-version }} 60 | uses: actions/setup-node@v1 61 | with: 62 | node-version: ${{ matrix.node-version }} 63 | 64 | - run: yarn 65 | working-directory: examples/node-test 66 | - run: yarn test 67 | working-directory: examples/node-test 68 | 69 | publish: 70 | runs-on: ubuntu-latest 71 | needs: [test, node-test] 72 | 73 | steps: 74 | - uses: actions/checkout@v2 75 | 76 | - name: Install wasm-opt 77 | run: sudo apt-get install -y binaryen 78 | 79 | - name: Install wasm-pack 80 | run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 81 | 82 | - name: Install wasm-bindgen-cli Custom 83 | run: cargo install -f wasm-bindgen-cli 84 | - uses: actions-rs/toolchain@v1 85 | with: 86 | toolchain: stable 87 | override: true 88 | 89 | - uses: Swatinem/rust-cache@v1 90 | with: 91 | cache-on-failure: true 92 | 93 | - uses: katyo/publish-crates@v1 94 | with: 95 | registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} 96 | 97 | - run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc 98 | 99 | - name: Publish Node Package 100 | run: make publish-node 101 | working-directory: packages/bsv-wasm 102 | 103 | - name: Publish Web Package 104 | run: make publish-web 105 | working-directory: packages/bsv-wasm 106 | 107 | - name: Publish Bundler Package 108 | run: make publish-bundler 109 | working-directory: packages/bsv-wasm 110 | -------------------------------------------------------------------------------- /.github/workflows/rust-format.yml: -------------------------------------------------------------------------------- 1 | name: Rust format 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - uses: actions/checkout@v1 11 | - uses: actions-rs/toolchain@v1 12 | with: 13 | toolchain: stable 14 | override: true 15 | - run: rustup component add clippy 16 | - run: rustup component add rustfmt 17 | - run: cargo fmt -- --check && cargo clippy -- -Dwarnings 18 | -------------------------------------------------------------------------------- /.github/workflows/test-pr.yml: -------------------------------------------------------------------------------- 1 | name: Run Tests 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | test: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: actions-rs/toolchain@v1 19 | with: 20 | toolchain: stable 21 | override: true 22 | - uses: Swatinem/rust-cache@v1 23 | with: 24 | cache-on-failure: true 25 | 26 | - name: Run tests 27 | run: cargo test --verbose 28 | 29 | node-test: 30 | runs-on: ubuntu-latest 31 | 32 | strategy: 33 | matrix: 34 | node-version: [15.x, 16.x] 35 | 36 | steps: 37 | - uses: actions/checkout@v2 38 | 39 | - name: Install wasm-opt 40 | run: sudo apt-get install -y binaryen 41 | 42 | - name: Install wasm-pack 43 | run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh 44 | 45 | - name: Install wasm-bindgen-cli Custom 46 | run: cargo install -f wasm-bindgen-cli 47 | - uses: actions-rs/toolchain@v1 48 | with: 49 | toolchain: stable 50 | override: true 51 | 52 | - uses: Swatinem/rust-cache@v1 53 | with: 54 | cache-on-failure: true 55 | 56 | - run: make build-nodejs 57 | working-directory: packages/bsv-wasm 58 | 59 | - name: Use Node.js ${{ matrix.node-version }} 60 | uses: actions/setup-node@v1 61 | with: 62 | node-version: ${{ matrix.node-version }} 63 | 64 | - run: yarn 65 | working-directory: examples/node-test 66 | - run: yarn test 67 | working-directory: examples/node-test 68 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | bin/ 5 | wasm-pack.log 6 | .DS_Store 7 | 8 | # Generated by Cargo 9 | # will have compiled files and executables 10 | debug/ 11 | target/ 12 | 13 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 14 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 15 | Cargo.lock 16 | 17 | # These are backup files generated by rustfmt 18 | **/*.rs.bk 19 | 20 | node_modules 21 | 22 | examples/node-test/node.mjs 23 | 24 | examples/**/dist 25 | 26 | !pkg/ 27 | pkg/* 28 | !pkg/web/ 29 | !pkg/web/.gitignore 30 | !pkg/deno/ 31 | !pkg/deno/.gitignore -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | 8 | { 9 | "type": "lldb", 10 | "request": "launch", 11 | "name": "Debug unit tests in library 'bsv-wasm'", 12 | "cargo": { 13 | "args": [ 14 | "test", 15 | "--no-run", 16 | "--lib", 17 | "--package=bsv-wasm" 18 | ], 19 | "filter": { 20 | "name": "bsv-wasm", 21 | "kind": "lib" 22 | } 23 | }, 24 | "args": [], 25 | "cwd": "${workspaceFolder}" 26 | }, 27 | { 28 | "type": "lldb", 29 | "request": "launch", 30 | "name": "Debug integration test 'transaction'", 31 | "cargo": { 32 | "args": [ 33 | "test", 34 | "--no-run", 35 | "--test=transaction", 36 | "--package=bsv-wasm" 37 | ], 38 | "filter": { 39 | "name": "transaction", 40 | "kind": "test" 41 | } 42 | }, 43 | "args": [], 44 | "cwd": "${workspaceFolder}" 45 | }, 46 | { 47 | "type": "lldb", 48 | "request": "launch", 49 | "name": "Debug integration test 'private_key'", 50 | "cargo": { 51 | "args": [ 52 | "test", 53 | "--no-run", 54 | "--test=private_key", 55 | "--package=bsv-wasm" 56 | ], 57 | "filter": { 58 | "name": "private_key", 59 | "kind": "test" 60 | } 61 | }, 62 | "args": [], 63 | "cwd": "${workspaceFolder}" 64 | }, 65 | { 66 | "type": "lldb", 67 | "request": "launch", 68 | "name": "Debug integration test 'address'", 69 | "cargo": { 70 | "args": [ 71 | "test", 72 | "--no-run", 73 | "--test=address", 74 | "--package=bsv-wasm" 75 | ], 76 | "filter": { 77 | "name": "address", 78 | "kind": "test" 79 | } 80 | }, 81 | "args": [], 82 | "cwd": "${workspaceFolder}" 83 | }, 84 | { 85 | "type": "lldb", 86 | "request": "launch", 87 | "name": "Debug integration test 'signature'", 88 | "cargo": { 89 | "args": [ 90 | "test", 91 | "--no-run", 92 | "--test=signature", 93 | "--package=bsv-wasm" 94 | ], 95 | "filter": { 96 | "name": "signature", 97 | "kind": "test" 98 | } 99 | }, 100 | "args": [], 101 | "cwd": "${workspaceFolder}" 102 | }, 103 | { 104 | "type": "lldb", 105 | "request": "launch", 106 | "name": "Debug integration test 'public_key'", 107 | "cargo": { 108 | "args": [ 109 | "test", 110 | "--no-run", 111 | "--test=public_key", 112 | "--package=bsv-wasm" 113 | ], 114 | "filter": { 115 | "name": "public_key", 116 | "kind": "test" 117 | } 118 | }, 119 | "args": [], 120 | "cwd": "${workspaceFolder}" 121 | }, 122 | { 123 | "type": "lldb", 124 | "request": "launch", 125 | "name": "Debug integration test 'kdf'", 126 | "cargo": { 127 | "args": [ 128 | "test", 129 | "--no-run", 130 | "--test=kdf", 131 | "--package=bsv-wasm" 132 | ], 133 | "filter": { 134 | "name": "kdf", 135 | "kind": "test" 136 | } 137 | }, 138 | "args": [], 139 | "cwd": "${workspaceFolder}" 140 | }, 141 | { 142 | "type": "lldb", 143 | "request": "launch", 144 | "name": "Debug integration test 'sighash'", 145 | "cargo": { 146 | "args": [ 147 | "test", 148 | "--no-run", 149 | "--test=sighash", 150 | "--package=bsv-wasm" 151 | ], 152 | "filter": { 153 | "name": "sighash", 154 | "kind": "test" 155 | } 156 | }, 157 | "args": [], 158 | "cwd": "${workspaceFolder}" 159 | } 160 | ] 161 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "matklad.rust-analyzer", 3 | "editor.formatOnSave": true, 4 | // "rust-targets.targets": [ 5 | // // "system", 6 | // // "x86_64-pc-windows-gnu", 7 | // // "x86_64-apple-darwin", 8 | // "wasm32-unknown-unknown", 9 | // // "x86_64-unknown-linux-gnu" 10 | // ], 11 | // "rust-analyzer.cargo.target": "wasm32-unknown-unknown" 12 | } -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bsv" 3 | version = "2.1.1" 4 | authors = ["Firaenix "] 5 | edition = "2021" 6 | description = "A Bitcoin stdlib" 7 | repository = "https://github.com/Firaenix/bsv-wasm" 8 | license = "MIT" 9 | categories = ["api-bindings", "cryptography::cryptocurrencies", "network-programming", "wasm"] 10 | keywords = ["bitcoin", "bsv", "blockchain", "bitcoin-cash"] 11 | 12 | [lib] 13 | crate-type = ["cdylib", "rlib"] 14 | 15 | [dependencies] 16 | k256 = { version = "0.10.2", features = [ 17 | "ecdsa", 18 | "ecdh", 19 | "digest", 20 | "arithmetic", 21 | "sha256", 22 | ] } 23 | ecdsa = { version = "0.13.4", features = ["sign"] } 24 | elliptic-curve = { version = "0.11.12", features = ["dev", "ecdh"] } 25 | hex = "^0.4" 26 | bs58 = "^0.4.0" 27 | thiserror = "^1.0" 28 | byteorder = "^1.4.3" 29 | serde = { version = "^1.0", default-features = false, features = [ 30 | "alloc", 31 | "derive", 32 | ] } 33 | serde_json = "^1.0" 34 | ciborium = "0.2.0" 35 | strum = "0.23.0" 36 | strum_macros = "^0.23.1" 37 | num-traits = "^0.2" 38 | num-derive = "^0.3" 39 | aes = { version = "^0.7.4", features = ["ctr"] } 40 | block-modes = "^0.8.1" 41 | pbkdf2 = "^0.8.0" 42 | sha-1 = "^0.9.6" 43 | sha2 = "^0.9.5" 44 | hmac = "^0.11.0" 45 | ripemd160 = "^0.9.1" 46 | digest = "^0.9.0" 47 | num-bigint = "0.4" 48 | 49 | [dependencies.rand_core] 50 | version = "^0.6" 51 | features = ["getrandom"] 52 | 53 | [dependencies.getrandom] 54 | version = "^0.2" 55 | # features = ["js"] 56 | 57 | [dev-dependencies] 58 | # wasm-bindgen-test = "^0.3" 59 | rayon = "1.5" 60 | 61 | [build] 62 | rustflags = ["-C", "target-feature=+simd128"] 63 | 64 | [profile.release] 65 | opt-level = 3 66 | lto = true 67 | 68 | [profile.test] 69 | opt-level = 3 70 | debug = false 71 | -------------------------------------------------------------------------------- /LICENSE_MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Firaenix 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BSV.WASM/BSV-RS 2 | 3 | A Rust/WASM Library to interact with Bitcoin SV 4 | 5 | ## Installation 6 | NodeJS 14.6+: 7 | `npm i bsv-wasm --save` 8 | 9 | Web: 10 | `npm i bsv-wasm-web --save` 11 | 12 | Webpack: 13 | `npm i bsv-wasm-bundler --save` 14 | 15 | Rust: 16 | https://crates.io/crates/bsv 17 | 18 | Deno: 19 | ```js 20 | import init, { Transaction } from "https://deno.land/x/bsv_wasm@{VERSION}/bsv_wasm.js" 21 | await init(); 22 | ``` 23 | 24 | 25 | ## Usage 26 | ### Note: Rust and JS/TS method names and structs are the same 27 | 28 | - Eg. Derive private key from XPriv and log out P2PKH String 29 | `ExtendedPrivateKey.fromWIF('LMyWif...').toPrivateKey().toPublicKey().toAddress().toString()` 30 | 31 | ## Features 32 | - Hash (SHA256, SHA256d, SHA1, RIPEMD160, Hash160, SHA512) 33 | - KDF (PBKDF2) 34 | - Encryption (AES-CBC, AES-CTR) 35 | - ECDSA (Private Key, Public Key, Signatures) 36 | - Transaction (Building, Serialising, Deserialising) 37 | - Script (Serialising, Deserialising) 38 | - Script Matching (ScriptTemplate) 39 | - Addresses (P2PKH) 40 | - Sighash Support 41 | - Extended Private Keys and Child Derivation (BIP32, BIP42) 42 | - Testnet support 43 | 44 | ## TODO: 45 | - [ ] Split WASM modules from Rust - Release standalone bsv-rs 46 | - [ ] Break WASM packages up to be more modular 47 | - [ ] Allow Interop between WASM Packages 48 | - [ ] Write documentation (Inline on functions and structs) 49 | 50 | ### Thanks 51 | - Brenton Gunning [(rust-sv)](https://github.com/brentongunning/rust-sv) 52 | - Moneybutton Team [(bsv.js)](https://github.com/moneybutton/bsv) 53 | - [Bitping Team](https://bitping.com) 54 | - [learnmeabitcoin.com](https://learnmeabitcoin.com) 55 | - [Bitcoin SV Wiki](https://wiki.bitcoinsv.io) 56 | -------------------------------------------------------------------------------- /examples/node-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha -r esm tests/*.test.js --timeout 10000" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "@types/benchmark": "^2.1.0", 13 | "axios": "^0.21.1", 14 | "benchmark": "^2.1.4", 15 | "bsv": "^2.0.10", 16 | "ts-node": "^9.1.1", 17 | "typescript": "^4.2.3" 18 | }, 19 | "devDependencies": { 20 | "@types/mocha": "^8.2.2", 21 | "chai": "^4.3.4", 22 | "esm": "^3.2.25", 23 | "mocha": "^8.3.2" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/node-test/tests/aes.test.js: -------------------------------------------------------------------------------- 1 | import { AES, AESAlgorithms } from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 2 | import { assert, util } from 'chai'; 3 | import { Aescbc } from "bsv"; 4 | import crypto from 'crypto'; 5 | 6 | describe("AES Tests", function() { 7 | it('AES256-CBC Encrypted Message matches BSV.JS', () => { 8 | const cipherKeyBuf = crypto.randomBytes(32) 9 | cipherKeyBuf.fill(0x10) 10 | const ivBuf = crypto.randomBytes(16) 11 | ivBuf.fill(0) 12 | const messageBuf = Buffer.from("Hello world"); 13 | const encBuf = Aescbc.encrypt(messageBuf, cipherKeyBuf, ivBuf, false); 14 | 15 | let encrypted = AES.encrypt(cipherKeyBuf, ivBuf, messageBuf, AESAlgorithms.AES256_CBC); 16 | assert.equal(Buffer.from(encrypted).toString('hex'), encBuf.toString('hex')) 17 | }); 18 | 19 | it('AES128-CBC Encrypted Message matches BSV.JS', () => { 20 | const cipherKeyBuf = crypto.randomBytes(16) 21 | cipherKeyBuf.fill(0x10) 22 | const ivBuf = crypto.randomBytes(16) 23 | 24 | ivBuf.fill(0) 25 | const messageBuf = Buffer.from("Hello world"); 26 | const encBuf = Aescbc.encrypt(messageBuf, cipherKeyBuf, ivBuf, false); 27 | 28 | let encrypted = AES.encrypt(cipherKeyBuf, ivBuf, messageBuf, AESAlgorithms.AES128_CBC); 29 | assert.equal(Buffer.from(encrypted).toString('hex'), encBuf.toString('hex')) 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /examples/node-test/tests/bsm.test.js: -------------------------------------------------------------------------------- 1 | import { Bsm, PrivKey, PubKey, KeyPair, Address } from 'bsv' 2 | import { PrivateKey, PublicKey, P2PKHAddress, SigningHash, BSM, Signature } from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 3 | 4 | import { assert, util } from 'chai'; 5 | 6 | describe("Bitcoin Signed Messages", function() { 7 | this.timeout(30000); 8 | 9 | it('signed message matches BSV.JS', () => { 10 | for (let index = 0; index < 100; index++) { 11 | let wif = PrivateKey.from_random().to_wif(); 12 | 13 | const priv_wasm = PrivateKey.from_wif(wif); 14 | const pub_wasm = PublicKey.from_private_key(priv_wasm) 15 | const address_wasm = P2PKHAddress.from_pubkey(pub_wasm) 16 | 17 | const priv_js = PrivKey.fromWif(wif); 18 | const pub_js = new PubKey().fromPrivKey(priv_js); 19 | const address_js = new Address().fromPubKey(pub_js); 20 | 21 | 22 | const message = Buffer.from(`Hello, Bitcoin - ${Date.now().toString()}`, 'utf8'); 23 | 24 | const signature_js = Bsm.sign(message, new KeyPair().fromPrivKey(priv_js)) 25 | assert.equal(Bsm.verify(message, signature_js, address_js), true); 26 | 27 | // const buf = Buffer.from('18426974636f696e205369676e6564204d6573736167653a0a0e48656c6c6f2c20426974636f696e', 'hex') // calculated by logging the buf inside Bsv.magicHash(message) before sha256d 28 | 29 | let signature_wasm = BSM.sign_message(priv_wasm, message); 30 | 31 | const signature_wasm_b64 = Buffer.from(signature_wasm.to_compact_bytes()).toString('base64') 32 | const verification_wasm = Bsm.verify(message, signature_wasm_b64, address_js) 33 | assert.equal(verification_wasm, true); 34 | 35 | 36 | const wasm_reconstruct_sig = Signature.from_compact_bytes(Buffer.from(signature_wasm.to_compact_bytes(), 'base64')); 37 | 38 | assert.equal(address_wasm.verify_bitcoin_message(message, wasm_reconstruct_sig), true); 39 | assert.equal(BSM.verify_message(message, wasm_reconstruct_sig, address_wasm), true); 40 | assert.equal(BSM.is_valid_message(message, wasm_reconstruct_sig, address_wasm), true); 41 | 42 | assert.equal(address_js.toString(), address_wasm.to_string()); 43 | 44 | assert.equal(signature_wasm_b64, signature_js.toString(), "JS and WASM signatures did not match") 45 | 46 | } 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /examples/node-test/tests/hash.test.js: -------------------------------------------------------------------------------- 1 | import { Hash } from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 2 | import { assert, util } from 'chai'; 3 | import { Hash as JSHash } from "bsv"; 4 | 5 | describe("Hash Tests", function() { 6 | it('PBKDF2 hash matches BSV.JS', () => { 7 | 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /examples/node-test/tests/interpreter.test.js: -------------------------------------------------------------------------------- 1 | import { Interpreter, Script } from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 2 | import { assert, util } from 'chai'; 3 | import { PrivateKey } from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 4 | import { Transaction } from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 5 | import { Hash } from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 6 | import { TxIn } from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 7 | import { SigHash } from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 8 | 9 | describe("Interpreter Tests", function() { 10 | it('Executes 1 + 1 = 2', () => { 11 | let interpreter = Interpreter.from_script(Script.from_asm_string("OP_1 OP_1 OP_ADD")); 12 | interpreter.run(); 13 | let state = interpreter.get_state(); 14 | assert.equal(Number(state.get_stack()[0][0]), 2) 15 | }); 16 | 17 | /* 18 | #[test] 19 | fn simple_p2pkh_signature_test() { 20 | let private_key = PrivateKey::from_wif("L2WAdy8C19GHNtZDSkbsVBJrBaF9XHpPLTgmnc2N5aGyguhJf7zh").unwrap(); 21 | let pubkey = private_key.to_public_key().unwrap(); 22 | let mut tx = Transaction::new(2, 0); 23 | 24 | let locking_script = Script::from_asm_string(&format!("OP_DUP OP_HASH160 {} OP_EQUALVERIFY OP_CHECKSIG", Hash::hash_160(&pubkey.to_bytes().unwrap()).to_hex())).unwrap(); 25 | 26 | 27 | let mut txin = TxIn::default(); 28 | txin.set_satoshis(0); 29 | txin.set_locking_script(&locking_script); 30 | tx.add_input(&txin); 31 | 32 | 33 | let signature = tx.sign(&private_key, SigHash::ALL, 0, &locking_script, 0).unwrap(); 34 | let script = Script::from_asm_string(&format!(" 35 | {} {}", 36 | signature.to_hex().unwrap(), pubkey.to_hex().unwrap() 37 | )).unwrap(); 38 | 39 | txin.set_unlocking_script(&script); 40 | tx.set_input(0, &txin); 41 | 42 | let mut interpreter = Interpreter::from_transaction(&tx, 0).unwrap(); 43 | 44 | println!("Loaded P2PKH script {:?}", interpreter.script_bits()); 45 | interpreter.run().unwrap(); 46 | 47 | 48 | assert_eq!(interpreter.state().stack().last().unwrap(), &vec![1_u8]); 49 | } 50 | */ 51 | it('Executes Signature unlock', () => { 52 | const private_key = PrivateKey.from_wif("L2WAdy8C19GHNtZDSkbsVBJrBaF9XHpPLTgmnc2N5aGyguhJf7zh"); 53 | const pub_key = private_key.to_public_key(); 54 | let tx = new Transaction(2, 0); 55 | 56 | let locking_script = Script.from_asm_string(`OP_DUP OP_HASH160 ${Hash.hash_160(pub_key.to_bytes()).to_hex()} OP_EQUALVERIFY OP_CHECKSIG`) 57 | let txin = TxIn.empty(); 58 | txin.set_satoshis(0n); 59 | txin.set_locking_script(locking_script); 60 | tx.add_input(txin); 61 | 62 | let sig = tx.sign(private_key, SigHash.ALL, 0, locking_script, 0n); 63 | let script = Script.from_asm_string(`${sig.to_hex()} ${pub_key.to_hex()}`); 64 | 65 | txin.set_unlocking_script(script); 66 | tx.set_input(0, txin) 67 | 68 | let interpreter = Interpreter.from_transaction(tx, 0); 69 | interpreter.run(); 70 | let state = interpreter.get_state(); 71 | assert.equal(Number(state.get_stack()[0][0]), 1) 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /examples/node-test/tests/p2pkh.test.js: -------------------------------------------------------------------------------- 1 | import { ChainParams, P2PKHAddress } from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 2 | import { assert, util } from 'chai'; 3 | 4 | describe("P2PKH Address Tests", function() { 5 | it('Decodes a testnet address', () => { 6 | const address = P2PKHAddress.from_string("moEoqh2ZfYU8jN5EG6ERw6E3DmwnkuTdBC") 7 | assert.equal(address.to_string(), 'moEoqh2ZfYU8jN5EG6ERw6E3DmwnkuTdBC') 8 | }); 9 | 10 | it('Transforms a testnet address to a mainnet address', () => { 11 | const address = P2PKHAddress.from_string("moEoqh2ZfYU8jN5EG6ERw6E3DmwnkuTdBC").set_chain_params(new ChainParams()); 12 | assert.equal(address.to_string(), '18irYdwarX2sxFbcYXG47B1iMnM5rWxsem') 13 | }); 14 | 15 | it('Transforms a mainnet address to a testnet address', () => { 16 | const address = P2PKHAddress.from_string("18irYdwarX2sxFbcYXG47B1iMnM5rWxsem").set_chain_params(ChainParams.testnet()); 17 | assert.equal(address.to_string(), 'moEoqh2ZfYU8jN5EG6ERw6E3DmwnkuTdBC') 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /examples/node-test/tests/scripts.test.js: -------------------------------------------------------------------------------- 1 | import { assert, util } from 'chai'; 2 | import {describe} from 'mocha'; 3 | import {Script} from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 4 | import {Hash, Tx, Script as JSScript} from "bsv"; 5 | 6 | describe('Script Tests', function () { 7 | it('21e8 script matches BSV.JS', () => { 8 | let script = Script.from_hex("200a40eda5ff94de646c3928e4a8eff097feeb283d124b0e871b24962e758461440221e8825479a87c7f758875ac"); 9 | let jsScript = JSScript.fromHex("200a40eda5ff94de646c3928e4a8eff097feeb283d124b0e871b24962e758461440221e8825479a87c7f758875ac"); 10 | 11 | // assert.equal(script.toASMString(), "0a40eda5ff94de646c3928e4a8eff097feeb283d124b0e871b24962e75846144 21e8 OP_SIZE 4 OP_PICK OP_SHA256 OP_SWAP OP_SPLIT OP_DROP OP_EQUALVERIFY OP_DROP OP_CHECKSIG"); 12 | assert.equal(script.to_asm_string(), jsScript.toAsmString()); 13 | }); 14 | 15 | 16 | it('OP RETURN script matches BSV.JS', () => { 17 | let script = Script.from_hex("006a4cb47b227573657248616e646c65223a226c75636b787878222c226368616e6e656c223a226d61746368222c226368616e6e656c4964223a2264757374222c2277696e6e65724964223a2239383333323836362d636435372d343166332d393537632d636433376231666237643738222c2275736572496d616765223a2268747470733a2f2f636c6f75642e68616e64636173682e696f2f75736572732f70726f66696c65506963747572652f6c75636b787878227d"); 18 | let jsScript = JSScript.fromHex("006a4cb47b227573657248616e646c65223a226c75636b787878222c226368616e6e656c223a226d61746368222c226368616e6e656c4964223a2264757374222c2277696e6e65724964223a2239383333323836362d636435372d343166332d393537632d636433376231666237643738222c2275736572496d616765223a2268747470733a2f2f636c6f75642e68616e64636173682e696f2f75736572732f70726f66696c65506963747572652f6c75636b787878227d"); 19 | 20 | assert.equal(script.to_asm_string(), "0 OP_RETURN 7b227573657248616e646c65223a226c75636b787878222c226368616e6e656c223a226d61746368222c226368616e6e656c4964223a2264757374222c2277696e6e65724964223a2239383333323836362d636435372d343166332d393537632d636433376231666237643738222c2275736572496d616765223a2268747470733a2f2f636c6f75642e68616e64636173682e696f2f75736572732f70726f66696c65506963747572652f6c75636b787878227d"); 21 | assert.equal(script.to_asm_string(), jsScript.toAsmString()); 22 | }); 23 | 24 | it('Scrypt script matches BSV.JS', () => { 25 | let script = Script.from_asm_string("OP_NOP OP_0 ff OP_0 OP_PICK OP_2 OP_ROLL OP_DROP OP_1 OP_ROLL OP_DROP OP_NOP OP_1 OP_PICK OP_0 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_NUMEQUAL OP_NIP OP_NIP OP_NIP OP_ELSE OP_1 OP_PICK OP_1 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_LESSTHAN OP_NIP OP_NIP OP_NIP OP_ELSE OP_1 OP_PICK OP_2 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_GREATERTHAN OP_NIP OP_NIP OP_NIP OP_ELSE OP_0 OP_ENDIF OP_ENDIF OP_ENDIF"); 26 | let jsScript = JSScript.fromAsmString("OP_NOP OP_0 ff OP_0 OP_PICK OP_2 OP_ROLL OP_DROP OP_1 OP_ROLL OP_DROP OP_NOP OP_1 OP_PICK OP_0 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_NUMEQUAL OP_NIP OP_NIP OP_NIP OP_ELSE OP_1 OP_PICK OP_1 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_LESSTHAN OP_NIP OP_NIP OP_NIP OP_ELSE OP_1 OP_PICK OP_2 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_GREATERTHAN OP_NIP OP_NIP OP_NIP OP_ELSE OP_0 OP_ENDIF OP_ENDIF OP_ENDIF"); 27 | 28 | assert.equal(script.to_asm_string(), "OP_NOP 0 ff 0 OP_PICK OP_2 OP_ROLL OP_DROP OP_1 OP_ROLL OP_DROP OP_NOP OP_1 OP_PICK 0 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_NUMEQUAL OP_NIP OP_NIP OP_NIP OP_ELSE OP_1 OP_PICK OP_1 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_LESSTHAN OP_NIP OP_NIP OP_NIP OP_ELSE OP_1 OP_PICK OP_2 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_GREATERTHAN OP_NIP OP_NIP OP_NIP OP_ELSE 0 OP_ENDIF OP_ENDIF OP_ENDIF"); 29 | // assert.equal(jsScript.toAsmString(), "OP_NOP OP_0 ff OP_0 OP_PICK OP_2 OP_ROLL OP_DROP OP_1 OP_ROLL OP_DROP OP_NOP OP_1 OP_PICK OP_0 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_NUMEQUAL OP_NIP OP_NIP OP_NIP OP_ELSE OP_1 OP_PICK OP_1 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_LESSTHAN OP_NIP OP_NIP OP_NIP OP_ELSE OP_1 OP_PICK OP_2 OP_EQUAL OP_IF OP_2 OP_PICK OP_1 OP_PICK OP_GREATERTHAN OP_NIP OP_NIP OP_NIP OP_ELSE OP_0 OP_ENDIF OP_ENDIF OP_ENDIF"); 30 | assert.equal(script.to_asm_string(), jsScript.toAsmString()); 31 | }); 32 | }) 33 | -------------------------------------------------------------------------------- /examples/node-test/tests/signatures.test.js: -------------------------------------------------------------------------------- 1 | import {PrivateKey, Hash as WASMHash} from '../../../packages/bsv-wasm/pkg/node/bsv_wasm'; 2 | import { assert, util } from 'chai'; 3 | import {PrivKey, Ecdsa, KeyPair, Hash } from "bsv"; 4 | 5 | describe("Signature Tests", function() { 6 | it('Raw Signature Matches Signature from BSV.JS', () => { 7 | let wif = "L17y3TE8AgM6fiWFP4HsbaLnvuBJsQcFKYRoJoZULpTzeTCr2nEC" 8 | let jswifPrivateKey = PrivKey.fromWif(wif); 9 | let jsKeyPair = KeyPair.fromPrivKey(jswifPrivateKey); 10 | 11 | let signatureMessage = Buffer.from("Hello, Bitcoin."); 12 | 13 | let signature = Ecdsa.sign(Buffer.from(WASMHash.sha_256(signatureMessage).to_bytes()), jsKeyPair); 14 | 15 | assert.equal("3044022032c4ac1fe69db038e55e5848ddf99865167a4f5172d5acf910c7ac5d66729cb8022049821966a892afc494777f6445d4757e5662b60d9acb1b2c810a5001892774ac", signature.toHex()); 16 | 17 | let wasmPrivKey = PrivateKey.from_wif(wif); 18 | let wasmSignature = wasmPrivKey.sign_message(signatureMessage) 19 | 20 | assert.equal("3044022032c4ac1fe69db038e55e5848ddf99865167a4f5172d5acf910c7ac5d66729cb8022049821966a892afc494777f6445d4757e5662b60d9acb1b2c810a5001892774ac", wasmSignature.to_der_hex()) 21 | 22 | assert.equal(signature.toHex(), wasmSignature.to_der_hex()) 23 | }); 24 | 25 | 26 | it('Raw Signature Matches Signature from BSV.JS', () => { 27 | let wif = "L17y3TE8AgM6fiWFP4HsbaLnvuBJsQcFKYRoJoZULpTzeTCr2nEC" 28 | let jswifPrivateKey = PrivKey.fromWif(wif); 29 | let jsKeyPair = KeyPair.fromPrivKey(jswifPrivateKey); 30 | 31 | let signatureMessage = Buffer.from("01000000c0379c566167eef7a8bc0a14d15f77f84e0b094b81637626d68eb2c40f3d253f00000000000000000000000000000000000000000000000000000000000000003f36d1e82cd2f327970c84cbf0d4e4d116f9a15dd02259329ac40d7b6a018d9e0000000002006a0000000000000000ffffffffc7732d98e887792b43e5dae92a159010d22e47d60ed48b88ba7b6c12a3c9e7560000000043000000", "hex"); 32 | 33 | let signature = Ecdsa.sign(Buffer.from(WASMHash.sha_256d(signatureMessage).to_bytes()), jsKeyPair); 34 | 35 | assert.equal(signature.toHex(), "30440220210e4c7968daf9e023e0d813419a8f1be9fd49bd98446205a26a97b5b7b216cd02201d8fea7429c0b94238d94dc910e21c4f6a749bdc28057ba9f7462f214f425e68", "1."); 36 | 37 | let wasmPrivKey = PrivateKey.from_wif(wif); 38 | let wasmSignature = wasmPrivKey.sign_message(WASMHash.sha_256(signatureMessage).to_bytes()) 39 | 40 | assert.equal(wasmSignature.to_der_hex(), "30440220210e4c7968daf9e023e0d813419a8f1be9fd49bd98446205a26a97b5b7b216cd02201d8fea7429c0b94238d94dc910e21c4f6a749bdc28057ba9f7462f214f425e68", "2.") 41 | 42 | assert.equal(signature.toHex(), wasmSignature.to_der_hex(), "3.") 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /examples/node-test/tests/tx.test.js: -------------------------------------------------------------------------------- 1 | import { assert, util } from "chai"; 2 | import { Script, Transaction, TxIn } from "../../../packages/bsv-wasm/pkg/node/bsv_wasm"; 3 | 4 | describe("Transaction Tests", function () { 5 | it("Get Outpoints", () => { 6 | let tx = new Transaction(1, 0); 7 | let txin_1 = new TxIn( 8 | Buffer.from( 9 | "4fe512f97769bc2fe47b0dadb1767404ebe2be50b3ea39a9b93d6325ee287e9a", 10 | "hex" 11 | ), 12 | 0, 13 | Script.from_asm_string("OP_0 OP_RETURN"), 14 | 0 15 | ); 16 | tx.add_input(txin_1); 17 | let txin_2 = new TxIn( 18 | Buffer.from( 19 | "4fe512f97769bc2fe47b0dadb1767404ebe2be50b3ea39a9b93d6325ee287e9a", 20 | "hex" 21 | ), 22 | 1, 23 | Script.from_asm_string("OP_0 OP_RETURN"), 24 | 0 25 | ); 26 | tx.add_input(txin_2); 27 | let txin_3 = new TxIn( 28 | Buffer.from( 29 | "4fe512f97769bc2fe47b0dadb1767404ebe2be50b3ea39a9b93d6325ee287e9a", 30 | "hex" 31 | ), 32 | 2, 33 | Script.from_asm_string("OP_0 OP_RETURN"), 34 | 0 35 | ); 36 | tx.add_input(txin_3); 37 | 38 | let outpoints = tx.get_outpoints(); 39 | 40 | assert.deepEqual(Uint8Array.from(outpoints[0]), Uint8Array.from(Buffer.from( 41 | "9a7e28ee25633db9a939eab350bee2eb047476b1ad0d7be42fbc6977f912e54f00000000", 'hex' 42 | ))); 43 | assert.deepEqual(Uint8Array.from(outpoints[1]), Uint8Array.from(Buffer.from( 44 | "9a7e28ee25633db9a939eab350bee2eb047476b1ad0d7be42fbc6977f912e54f01000000", 'hex' 45 | ))); 46 | assert.deepEqual(Uint8Array.from(outpoints[2]), Uint8Array.from(Buffer.from( 47 | "9a7e28ee25633db9a939eab350bee2eb047476b1ad0d7be42fbc6977f912e54f02000000", 'hex' 48 | ))); 49 | }); 50 | 51 | it("Deserialise Coinbase hex", () => { 52 | let tx = Transaction.from_hex("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff63038d361604747a77610840000000230000004e2f686f77206c6f6e672063616e207468697320626520746573742074657374206170706172656e746c7920707265747479206c6f6e67206f6b20776f772031323334353637383930313220f09fa68d2f0000000001c817a804000000001976a91454b34b1ba228ba1d75dca5a40a114dc0f13a268788ac00000000"); 53 | assert.isTrue(tx.is_coinbase()); 54 | assert.equal(tx.to_hex(), "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff63038d361604747a77610840000000230000004e2f686f77206c6f6e672063616e207468697320626520746573742074657374206170706172656e746c7920707265747479206c6f6e67206f6b20776f772031323334353637383930313220f09fa68d2f0000000001c817a804000000001976a91454b34b1ba228ba1d75dca5a40a114dc0f13a268788ac00000000"); 55 | }) 56 | 57 | it("Get CBOR Buffer - to_compact_bytes", () => { 58 | let tx = new Transaction(1, 0); 59 | let txin_1 = new TxIn( 60 | Buffer.from( 61 | "4fe512f97769bc2fe47b0dadb1767404ebe2be50b3ea39a9b93d6325ee287e9a", 62 | "hex" 63 | ), 64 | 0, 65 | Script.from_asm_string("OP_0 OP_RETURN"), 66 | 0 67 | ); 68 | txin_1.set_satoshis(60000n); 69 | tx.add_input(txin_1); 70 | 71 | 72 | let txin_2 = new TxIn( 73 | Buffer.from( 74 | "4fe512f97769bc2fe47b0dadb1767404ebe2be50b3ea39a9b93d6325ee287e9a", 75 | "hex" 76 | ), 77 | 1, 78 | Script.from_asm_string("OP_0 OP_RETURN"), 79 | 0 80 | ); 81 | txin_2.set_satoshis(620000n); 82 | tx.add_input(txin_2); 83 | 84 | 85 | let txin_3 = new TxIn( 86 | Buffer.from( 87 | "4fe512f97769bc2fe47b0dadb1767404ebe2be50b3ea39a9b93d6325ee287e9a", 88 | "hex" 89 | ), 90 | 2, 91 | Script.from_asm_string("OP_1 OP_2 OP_ADD"), 92 | 0 93 | ); 94 | txin_3.set_satoshis(12n); 95 | txin_3.set_locking_script(Script.from_asm_string("OP_3 OP_EQUAL")) 96 | tx.add_input(txin_3); 97 | 98 | let CBORBuffer = tx.to_compact_bytes(); 99 | 100 | assert.deepEqual(Buffer.from(CBORBuffer).toString('hex'), "a46776657273696f6e0166696e7075747383a56a707265765f74785f696478403961376532386565323536333364623961393339656162333530626565326562303437343736623161643064376265343266626336393737663931326535346664766f7574006a7363726970745f73696782644f505f30694f505f52455455524e6873657175656e636500687361746f7368697319ea60a56a707265765f74785f696478403961376532386565323536333364623961393339656162333530626565326562303437343736623161643064376265343266626336393737663931326535346664766f7574016a7363726970745f73696782644f505f30694f505f52455455524e6873657175656e636500687361746f736869731a000975e0a66a707265765f74785f696478403961376532386565323536333364623961393339656162333530626565326562303437343736623161643064376265343266626336393737663931326535346664766f7574026a7363726970745f73696783644f505f31644f505f32664f505f4144446873657175656e63650070756e6c6f636b696e675f73637269707482644f505f33684f505f455155414c687361746f736869730c676f757470757473806a6e5f6c6f636b74696d6500"); 101 | 102 | let reconstructed_tx = Transaction.from_compact_bytes(CBORBuffer); 103 | 104 | assert.equal(reconstructed_tx.get_input(0).get_satoshis(), 60000n); 105 | 106 | let reconstructed_txin_3 = reconstructed_tx.get_input(2); 107 | 108 | assert.equal(reconstructed_txin_3.get_satoshis(), 12n); 109 | assert.equal(reconstructed_txin_3.get_locking_script().to_asm_string(),"OP_3 OP_EQUAL"); 110 | assert.equal(reconstructed_txin_3.get_unlocking_script().to_asm_string(), "OP_1 OP_2 OP_ADD"); 111 | }); 112 | }); 113 | -------------------------------------------------------------------------------- /examples/node-test/tests/xpriv.test.js: -------------------------------------------------------------------------------- 1 | import { ExtendedPrivateKey } from "../../../packages/bsv-wasm/pkg/node/bsv_wasm"; 2 | import { Bip32, Bip39 } from 'bsv'; 3 | import { assert } from "chai"; 4 | import crypto from 'crypto'; 5 | 6 | 7 | 8 | describe('XPriv Tests', function () { 9 | it('XPrivs match BSV.JS', () => { 10 | let xpriv_wif = "xprv9s21ZrQH143K2rdSf96bvxvYtHYjf2899A7M7S3Ka2jASLK6P3hs7Bg9snGVsArqAA2awhc26e5kqKDquKSkpZ6hXymjpCcUj1tRi17L4Bg"; 11 | 12 | let xpriv_wasm = ExtendedPrivateKey.from_string(xpriv_wif); 13 | let xpriv_js = Bip32.fromString(xpriv_wif); 14 | 15 | assert.equal(xpriv_wasm.to_string(), xpriv_js.toString()); 16 | }) 17 | 18 | it('Short seed match BSV.JS', () => { 19 | let small_bytes = crypto.randomBytes(32); 20 | let xpriv_wasm = ExtendedPrivateKey.from_seed(small_bytes); 21 | let xpriv_js = Bip32.fromSeed(small_bytes); 22 | 23 | assert.equal(xpriv_wasm.to_string(), xpriv_js.toString()); 24 | }) 25 | 26 | it('Long seed match BSV.JS', () => { 27 | let large_bytes = crypto.randomBytes(64); 28 | let xpriv_wasm = ExtendedPrivateKey.from_seed(large_bytes); 29 | let xpriv_js = Bip32.fromSeed(large_bytes); 30 | 31 | assert.equal(xpriv_wasm.to_string(), xpriv_js.toString()); 32 | }) 33 | 34 | it('Mnemonic -> XPriv derivations match BSV.JS', () => { 35 | let mnemonic = 'vapor cabbage jacket unveil permit web live pyramid husband final plug metal' 36 | 37 | let xpriv_wasm = ExtendedPrivateKey.from_mnemonic(Buffer.from(mnemonic, 'utf8')).to_string(); 38 | let xpriv_js = Bip32.fromSeed(new Bip39().fromString(mnemonic).toSeed()); 39 | 40 | assert.equal(xpriv_wasm, xpriv_js.toString()); 41 | assert.equal(xpriv_wasm, "xprv9s21ZrQH143K3kV5ByEVyeoaC6TbWS9T3UrQamHwMgpbTghuLXUfiSgeK1TRr1K9xWVcJKdtQawEM1RGwAfCzwPHJXSCEzTSze7ZnduyQaU"); 42 | }) 43 | 44 | it('XPriv derivations match BSV.JS', () => { 45 | let xpriv_wif = "xprv9s21ZrQH143K2rdSf96bvxvYtHYjf2899A7M7S3Ka2jASLK6P3hs7Bg9snGVsArqAA2awhc26e5kqKDquKSkpZ6hXymjpCcUj1tRi17L4Bg"; 46 | let path = "m/0/0/0/0" 47 | 48 | let xpriv_wasm = ExtendedPrivateKey.from_string(xpriv_wif); 49 | let xpriv_js = Bip32.fromString(xpriv_wif); 50 | 51 | assert.equal(xpriv_wasm.derive_from_path(path).to_string(), xpriv_js.derive(path).toString()); 52 | }) 53 | 54 | it('XPriv hardened derivations match BSV.JS', () => { 55 | let xpriv_wif = "xprv9s21ZrQH143K2rdSf96bvxvYtHYjf2899A7M7S3Ka2jASLK6P3hs7Bg9snGVsArqAA2awhc26e5kqKDquKSkpZ6hXymjpCcUj1tRi17L4Bg"; 56 | let path = "m/0'/0'/0'/0'" 57 | 58 | let xpriv_wasm = ExtendedPrivateKey.from_string(xpriv_wif); 59 | let xpriv_js = Bip32.fromString(xpriv_wif); 60 | 61 | assert.equal(xpriv_wasm.derive_from_path(path).to_string(), xpriv_js.derive(path).toString()); 62 | }) 63 | 64 | it('XPriv loop hardened derivations match BSV.JS', () => { 65 | let xpriv_wasm = ExtendedPrivateKey.from_random(); 66 | let xpriv_wif = xpriv_wasm.to_string() 67 | let path = "m/0'/0'/0'/0'" 68 | 69 | let xpriv_js = Bip32.fromString(xpriv_wif); 70 | 71 | assert.equal(xpriv_wasm.to_string(), xpriv_js.toString()); 72 | assert.equal(xpriv_wasm.derive_from_path(path).to_string(), xpriv_js.derive(path).toString()); 73 | 74 | for (let index = 0; index < 100; index++) { 75 | const element = path + '/' + index; 76 | assert.equal(xpriv_wasm.derive_from_path(element).to_string(), xpriv_js.derive(element).toString()); 77 | } 78 | }) 79 | }); 80 | -------------------------------------------------------------------------------- /examples/node-test/tests/xpub.test.js: -------------------------------------------------------------------------------- 1 | import { ExtendedPublicKey } from "../../../packages/bsv-wasm/pkg/node/bsv_wasm"; 2 | import { Bip32 } from 'bsv'; 3 | import { assert } from "chai"; 4 | 5 | 6 | 7 | describe('XPub Tests', function () { 8 | it('XPubs match BSV.JS', () => { 9 | let xpub_wif = "xpub67uA5wAUuv1ypp7rEY7jUZBZmwFSULFUArLBJrHr3amnymkUEYWzQJz13zLacZv33sSuxKVmerpZeFExapBNt8HpAqtTtWqDQRAgyqSKUHu"; 10 | 11 | let xpub_wasm = ExtendedPublicKey.from_string(xpub_wif); 12 | let xpub_js = Bip32.fromString(xpub_wif); 13 | 14 | assert.equal(xpub_wasm.to_string(), xpub_js.toString()); 15 | }) 16 | 17 | it('XPub derivations match BSV.JS', () => { 18 | let xpub_wif = "xpub67uA5wAUuv1ypp7rEY7jUZBZmwFSULFUArLBJrHr3amnymkUEYWzQJz13zLacZv33sSuxKVmerpZeFExapBNt8HpAqtTtWqDQRAgyqSKUHu"; 19 | let path = "m/0/0/0/0" 20 | 21 | let xpub_wasm = ExtendedPublicKey.from_string(xpub_wif); 22 | let xpub_js = Bip32.fromString(xpub_wif); 23 | 24 | assert.equal(xpub_wasm.derive_from_path(path).to_string(), xpub_js.derive(path).toString()); 25 | }) 26 | 27 | it('XPub hardened derivations match BSV.JS - Throws Error', () => { 28 | let xpub_wif = "xpub67uA5wAUuv1ypp7rEY7jUZBZmwFSULFUArLBJrHr3amnymkUEYWzQJz13zLacZv33sSuxKVmerpZeFExapBNt8HpAqtTtWqDQRAgyqSKUHu"; 29 | let path = "m/0'/0'/0'/0'" 30 | 31 | let xpub_wasm = ExtendedPublicKey.from_string(xpub_wif); 32 | let xpub_js = Bip32.fromString(xpub_wif); 33 | 34 | assert.throws(() => xpub_wasm.derive_from_path(path).to_string()); 35 | assert.throws(() => xpub_js.derive(path).toString()); 36 | }) 37 | 38 | it('XPub loop derivations match BSV.JS', () => { 39 | let xpub_wasm = ExtendedPublicKey.from_random(); 40 | let xpub_wif = xpub_wasm.to_string() 41 | let path = "m/0/0/0/0" 42 | 43 | let xpub_js = Bip32.fromString(xpub_wif); 44 | 45 | assert.equal(xpub_wasm.to_string(), xpub_js.toString()); 46 | assert.equal(xpub_wasm.derive_from_path(path).to_string(), xpub_js.derive(path).toString()); 47 | 48 | for (let index = 0; index < 100; index++) { 49 | const element = path + '/' + index; 50 | assert.equal(xpub_wasm.derive_from_path(element).to_string(), xpub_js.derive(element).toString()); 51 | } 52 | }) 53 | }); 54 | -------------------------------------------------------------------------------- /examples/web-test/express.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express() 3 | const port = 3000 4 | const path = require('path') 5 | 6 | app.get('*', (req, res) => { 7 | console.log("Request path", req.path) 8 | if (req.path === '/') { 9 | return res.sendFile(__dirname + '/index.html') 10 | } 11 | 12 | return res.sendFile(path.join(__dirname, '../../pkg/web/' + req.path)) 13 | }) 14 | 15 | app.listen(port, () => { 16 | console.log(`Example app listening at http://localhost:${port}`) 17 | }) -------------------------------------------------------------------------------- /examples/web-test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Getting Started 6 | 7 | 35 | 36 | 37 | 38 | Loading... 39 | 40 | -------------------------------------------------------------------------------- /examples/web-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "node ./express.js" 8 | }, 9 | "dependencies": { 10 | "express": "^4.17.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/webpack-test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Getting Started 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/webpack-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-test", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "start": "webpack serve --open", 8 | "build": "webpack build" 9 | }, 10 | "dependencies": { 11 | "twetch-sdk": "./sdk", 12 | "html-webpack-plugin": "^5.3.2" 13 | }, 14 | "devDependencies": { 15 | "webpack": "^5.72.1", 16 | "webpack-cli": "^4.9.2", 17 | "webpack-dev-server": "^4.9.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/webpack-test/sdk/README.md: -------------------------------------------------------------------------------- 1 | # sdk.wasm 2 | -------------------------------------------------------------------------------- /examples/webpack-test/sdk/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "twetch-sdk-wasm", 3 | "collaborators": [ 4 | "utxo detective" 5 | ], 6 | "version": "0.0.1", 7 | "files": [ 8 | "twetch_sdk_wasm_bg.wasm", 9 | "twetch_sdk_wasm_bg.js", 10 | "twetch_sdk_wasm_bg.js", 11 | "twetch_sdk_wasm.d.ts" 12 | ], 13 | "module": "twetch_sdk_wasm_bg.js", 14 | "types": "twetch_sdk_wasm.d.ts", 15 | "sideEffects": false 16 | } -------------------------------------------------------------------------------- /examples/webpack-test/sdk/twetch_sdk_wasm.js: -------------------------------------------------------------------------------- 1 | import * as wasm from "./twetch_sdk_wasm_bg.wasm"; 2 | export * from "./twetch_sdk_wasm_bg.js"; -------------------------------------------------------------------------------- /examples/webpack-test/sdk/twetch_sdk_wasm_bg.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Firaenix/bsv-wasm/5aac52e9a09c60e72fa8c7fdce10cff44657cc9f/examples/webpack-test/sdk/twetch_sdk_wasm_bg.wasm -------------------------------------------------------------------------------- /examples/webpack-test/src/index.js: -------------------------------------------------------------------------------- 1 | // import { PrivateKey, PublicKey, Signature, Script, Transaction, TxOut } from "bsv-wasm"; 2 | 3 | // let key = PrivateKey.fromRandom(); 4 | // document.body.innerText = key.toWIF(); 5 | 6 | 7 | // let message = "Hello"; 8 | // let signature = key.signMessage(new TextEncoder().encode(message)); 9 | // document.body.innerText = document.body.innerText + '\n' + `Message: ${message}` + '\n' + `Signed text: ${signature.toHex()}` 10 | 11 | // let pub_key = PublicKey.fromPrivateKey(key); 12 | // document.body.innerText = document.body.innerText + '\n' + `Pub Key: ${pub_key.toHex()}` 13 | 14 | // let verify_sig = Signature.fromHexDER(signature.toHex(), false); 15 | // document.body.innerText = document.body.innerText + '\n' + `Verfied?: ${verify_sig.verifyMessage(new TextEncoder().encode(message), pub_key)}` 16 | 17 | // let tx = new Transaction(1, 0); 18 | // tx.addOutput(new TxOut(BigInt(400000000000), Script.fromASMString("OP_0 OP_RETURN"))) 19 | // tx.addOutput(new TxOut(BigInt(4000), Script.fromASMString("OP_0 OP_RETURN"))) 20 | 21 | // // let totalOutSats = tx.getOutput(0).getValue() + tx.getOutput(1).getValue(); 22 | 23 | // document.body.innerText = document.body.innerText + '\n' + `Tx ${tx} Tx Sats out?: ${tx.satoshisOut()} Type?: ${typeof(tx.satoshisOut())}` 24 | 25 | import { Hash, TwetchPay, Wallet } from "twetch-sdk"; 26 | let result = await Wallet.from_seed_and_token("derive theory horse dash deny awkward interest human child hybrid awesome final", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoiMTYifSwiaWF0IjoxNjU5MTcxNTAzfQ.tqa8r77wfFurYT3IC9F_h4cpsTXXmqsRl837RcoGQro"); 27 | 28 | document.body.innerText = document.body.innerText + '\n' + `Hash: ${result.account_public_key().to_hex()}` -------------------------------------------------------------------------------- /examples/webpack-test/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | 4 | module.exports = { 5 | entry: './src/index.js', 6 | output: { 7 | filename: 'main.js', 8 | path: path.resolve(__dirname, 'dist'), 9 | hashFunction: "sha256" 10 | }, 11 | resolve: { 12 | extensions: ['.tsx', '.ts', '.js'], 13 | }, 14 | experiments: { 15 | asyncWebAssembly: true, 16 | topLevelAwait: true 17 | }, 18 | plugins: [new HtmlWebpackPlugin()], 19 | }; -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /packages/bsv-wasm/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bsv-wasm" 3 | version = "2.1.1" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | 10 | [dependencies] 11 | wasm-bindgen = { version = "0.2.87" } 12 | bsv = { path = "../.." } 13 | serde-wasm-bindgen = "0.6.0" 14 | console_error_panic_hook = { version = "0.1.7", optional = true } 15 | 16 | [package.metadata.wasm-pack.profile.release] 17 | wasm-opt = false 18 | 19 | [dependencies.getrandom] 20 | version = "0.2.10" 21 | features = ["js"] 22 | -------------------------------------------------------------------------------- /packages/bsv-wasm/Makefile: -------------------------------------------------------------------------------- 1 | check-format: 2 | cargo fmt -- --check && cargo clippy -- -Dwarnings 3 | 4 | build-web: 5 | wasm-pack build --release --out-dir ./pkg/web --target web 6 | 7 | build-bundler: 8 | wasm-pack build --release --out-dir ./pkg/bundler --target bundler 9 | 10 | build-nodejs: 11 | wasm-pack build --release --out-dir ./pkg/node --target nodejs 12 | cargo build --target wasm32-unknown-unknown --release 13 | wasm-bindgen ./target/wasm32-unknown-unknown/release/bsv_wasm.wasm --out-dir pkg/node --target nodejs --weak-refs 14 | wasm-opt -O4 --dce ./pkg/node/bsv_wasm_bg.wasm -o ./pkg/node/bsv_wasm_bg.wasm 15 | 16 | build-deno: 17 | cargo build --target wasm32-unknown-unknown --release 18 | wasm-bindgen ./target/wasm32-unknown-unknown/release/bsv_wasm.wasm --out-dir pkg/deno --target web --weak-refs 19 | wasm-opt -O4 --dce ./pkg/deno/bsv_wasm_bg.wasm -o ./pkg/deno/bsv_wasm_bg.wasm 20 | 21 | build-wasm: 22 | make build-web ; make build-bundler ; make build-nodejs 23 | 24 | test-node: 25 | make build-nodejs && pushd ../../examples/node-test && yarn test ; popd 26 | 27 | wasm-tests: 28 | wasm-pack test --node -- --features wasm-bindgen-exports 29 | 30 | publish-node: 31 | # make sure not to call make build-* because wasm-pack doesnt allow you to specify subdirectories. 32 | wasm-pack build --release --out-dir ./pkg --target nodejs 33 | cargo build --target wasm32-unknown-unknown --release 34 | wasm-bindgen ./target/wasm32-unknown-unknown/release/bsv_wasm.wasm --out-dir pkg/ --target nodejs --weak-refs 35 | wasm-opt -O4 --dce ./pkg/bsv_wasm_bg.wasm -o ./pkg/bsv_wasm_bg.wasm 36 | wasm-pack publish ./pkg/ 37 | 38 | publish-web: 39 | wasm-pack build --release --target web 40 | sed -i "s/bsv-wasm/bsv-wasm-web/" ./pkg/package.json 41 | wasm-pack publish ./pkg 42 | 43 | publish-bundler: 44 | wasm-pack build --release --target bundler 45 | sed -i "s/bsv-wasm/bsv-wasm-bundler/" ./pkg/package.json 46 | wasm-pack publish ./pkg 47 | 48 | create-isomorphic: 49 | rollup pkg/node/bsv_wasm.js --format umd --name bsv_wasm_iso --file pkg/node/bsv_wasm_iso.js 50 | -------------------------------------------------------------------------------- /packages/bsv-wasm/pkg/deno/bsv_wasm_bg.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Firaenix/bsv-wasm/5aac52e9a09c60e72fa8c7fdce10cff44657cc9f/packages/bsv-wasm/pkg/deno/bsv_wasm_bg.wasm -------------------------------------------------------------------------------- /packages/bsv-wasm/src/address.rs: -------------------------------------------------------------------------------- 1 | use crate::{chainparams::ChainParams, keypair::public_key::PublicKey, script::Script, sighash::SighashSignature, signature::Signature}; 2 | use bsv::P2PKHAddress as BSVP2PKHAddress; 3 | use wasm_bindgen::prelude::*; 4 | 5 | #[derive(Clone)] 6 | #[wasm_bindgen] 7 | pub struct P2PKHAddress(pub(crate) BSVP2PKHAddress); 8 | 9 | impl From for P2PKHAddress { 10 | fn from(v: BSVP2PKHAddress) -> P2PKHAddress { 11 | P2PKHAddress(v) 12 | } 13 | } 14 | 15 | impl From for BSVP2PKHAddress { 16 | fn from(v: P2PKHAddress) -> BSVP2PKHAddress { 17 | v.0 18 | } 19 | } 20 | 21 | #[wasm_bindgen] 22 | impl P2PKHAddress { 23 | pub fn from_pubkey_hash(hash_bytes: &[u8]) -> Result { 24 | Ok(P2PKHAddress(BSVP2PKHAddress::from_pubkey_hash(hash_bytes)?)) 25 | } 26 | 27 | pub fn from_pubkey(pub_key: &PublicKey) -> Result { 28 | Ok(P2PKHAddress(BSVP2PKHAddress::from_pubkey(&pub_key.0)?)) 29 | } 30 | 31 | pub fn set_chain_params(&self, chain_params: &ChainParams) -> Result { 32 | Ok(P2PKHAddress(BSVP2PKHAddress::set_chain_params(&self.0, &chain_params.0)?)) 33 | } 34 | 35 | pub fn to_string(&self) -> Result { 36 | Ok(BSVP2PKHAddress::to_string(&self.0)?) 37 | } 38 | 39 | pub fn from_string(address_string: &str) -> Result { 40 | Ok(P2PKHAddress(BSVP2PKHAddress::from_string(address_string)?)) 41 | } 42 | 43 | pub fn get_locking_script(&self) -> Result { 44 | Ok(Script(BSVP2PKHAddress::get_locking_script(&self.0)?)) 45 | } 46 | 47 | pub fn get_unlocking_script(&self, pub_key: &PublicKey, sig: &SighashSignature) -> Result { 48 | Ok(Script(BSVP2PKHAddress::get_unlocking_script(&self.0, &pub_key.0, &sig.0)?)) 49 | } 50 | 51 | pub fn verify_bitcoin_message(&self, message: &[u8], signature: &Signature) -> Result { 52 | Ok(BSVP2PKHAddress::verify_bitcoin_message(&self.0, message, &signature.0)?) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/bsm.rs: -------------------------------------------------------------------------------- 1 | use bsv::BSM as BSVBSM; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{address::P2PKHAddress, keypair::private_key::PrivateKey, signature::Signature}; 5 | 6 | #[wasm_bindgen] 7 | pub struct BSM; 8 | 9 | #[wasm_bindgen] 10 | impl BSM { 11 | /** 12 | * Sign a message with the intention of verifying with this same Address. 13 | * Used when using Bitcoin Signed Messages 14 | * 15 | * Returns boolean 16 | */ 17 | pub fn is_valid_message(message: &[u8], signature: &Signature, address: &P2PKHAddress) -> bool { 18 | BSVBSM::verify_message(message, &signature.0, &address.0).is_ok() 19 | } 20 | 21 | pub fn verify_message(message: &[u8], signature: &Signature, address: &P2PKHAddress) -> Result { 22 | Ok(BSVBSM::verify_message(message, &signature.0, &address.0)?) 23 | } 24 | 25 | pub fn sign_message(priv_key: &PrivateKey, message: &[u8]) -> Result { 26 | Ok(Signature(BSVBSM::sign_message(&priv_key.0, message)?)) 27 | } 28 | 29 | pub fn sign_message_with_k(priv_key: &PrivateKey, ephemeral_key: &PrivateKey, message: &[u8]) -> Result { 30 | Ok(Signature(BSVBSM::sign_message_with_k(&priv_key.0, &ephemeral_key.0, message)?)) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/chainparams.rs: -------------------------------------------------------------------------------- 1 | use bsv::chainparams::ChainParams as BSVChainParams; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | #[derive(Default)] 6 | pub struct ChainParams(pub(crate) BSVChainParams); 7 | 8 | impl From for ChainParams { 9 | fn from(v: BSVChainParams) -> ChainParams { 10 | ChainParams(v) 11 | } 12 | } 13 | 14 | impl From for BSVChainParams { 15 | fn from(v: ChainParams) -> BSVChainParams { 16 | v.0 17 | } 18 | } 19 | 20 | #[wasm_bindgen] 21 | impl ChainParams { 22 | #[wasm_bindgen(constructor)] 23 | pub fn new() -> ChainParams { 24 | ChainParams(BSVChainParams::default()) 25 | } 26 | 27 | pub fn mainnet() -> ChainParams { 28 | ChainParams(BSVChainParams::default()) 29 | } 30 | 31 | pub fn testnet() -> ChainParams { 32 | ChainParams(BSVChainParams::testnet()) 33 | } 34 | 35 | pub fn regtest() -> ChainParams { 36 | ChainParams(BSVChainParams::regtest()) 37 | } 38 | 39 | pub fn stn() -> ChainParams { 40 | ChainParams(BSVChainParams::stn()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/ecdh.rs: -------------------------------------------------------------------------------- 1 | use bsv::ECDH as BSVECDH; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::keypair::{private_key::PrivateKey, public_key::PublicKey}; 5 | 6 | #[wasm_bindgen] 7 | pub struct ECDH; 8 | 9 | #[wasm_bindgen] 10 | impl ECDH { 11 | pub fn derive_shared_key(priv_key: &PrivateKey, pub_key: &PublicKey) -> Result, wasm_bindgen::JsError> { 12 | Ok(BSVECDH::derive_shared_key(&priv_key.0, &pub_key.0)?) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/ecdsa.rs: -------------------------------------------------------------------------------- 1 | use bsv::ECDSA as BSVECDSA; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ 5 | keypair::{private_key::PrivateKey, public_key::PublicKey}, 6 | signature::Signature, 7 | }; 8 | 9 | #[wasm_bindgen] 10 | #[derive(PartialEq, Eq, Clone, Copy)] 11 | pub enum SigningHash { 12 | Sha256, 13 | Sha256d, 14 | } 15 | 16 | impl From for bsv::SigningHash { 17 | fn from(item: SigningHash) -> Self { 18 | match item { 19 | SigningHash::Sha256 => bsv::SigningHash::Sha256, 20 | SigningHash::Sha256d => bsv::SigningHash::Sha256d, 21 | } 22 | } 23 | } 24 | 25 | #[wasm_bindgen] 26 | pub struct ECDSA; 27 | 28 | #[wasm_bindgen] 29 | impl ECDSA { 30 | pub fn private_key_from_signature_k( 31 | signature: &Signature, 32 | public_key: &PublicKey, 33 | ephemeral_key: &PrivateKey, 34 | preimage: &[u8], 35 | hash_algo: SigningHash, 36 | ) -> Result { 37 | Ok(PrivateKey(BSVECDSA::private_key_from_signature_k( 38 | &signature.0, 39 | &public_key.0, 40 | &ephemeral_key.0, 41 | preimage, 42 | hash_algo.into(), 43 | )?)) 44 | } 45 | 46 | pub fn sign_with_random_k(private_key: &PrivateKey, preimage: &[u8], hash_algo: SigningHash, reverse_k: bool) -> Result { 47 | Ok(Signature(BSVECDSA::sign_with_random_k(&private_key.0, preimage, hash_algo.into(), reverse_k)?)) 48 | } 49 | 50 | pub fn sign_with_deterministic_k(private_key: &PrivateKey, preimage: &[u8], hash_algo: SigningHash, reverse_k: bool) -> Result { 51 | Ok(Signature(BSVECDSA::sign_with_deterministic_k(&private_key.0, preimage, hash_algo.into(), reverse_k)?)) 52 | } 53 | 54 | pub fn sign_digest_with_deterministic_k(private_key: &PrivateKey, digest: &[u8]) -> Result { 55 | Ok(Signature(BSVECDSA::sign_digest_with_deterministic_k(&private_key.0, digest)?)) 56 | } 57 | 58 | pub fn sign_with_k(private_key: &PrivateKey, ephemeral_key: &PrivateKey, preimage: &[u8], hash_algo: SigningHash) -> Result { 59 | Ok(Signature(BSVECDSA::sign_with_k(&private_key.0, &ephemeral_key.0, preimage, hash_algo.into())?)) 60 | } 61 | 62 | pub fn verify_digest(message: &[u8], pub_key: &PublicKey, signature: &Signature, hash_algo: SigningHash) -> Result { 63 | Ok(BSVECDSA::verify_digest(message, &pub_key.0, &signature.0, hash_algo.into())?) 64 | } 65 | 66 | pub fn verify_hashbuf(digest: &[u8], pub_key: &PublicKey, signature: &Signature) -> Result { 67 | Ok(BSVECDSA::verify_hashbuf(digest, &pub_key.0, &signature.0)?) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/ecies.rs: -------------------------------------------------------------------------------- 1 | use bsv::CipherKeys as BSVCipherKeys; 2 | use bsv::ECIESCiphertext as BSVECIESCiphertext; 3 | use bsv::ECIES as BSVECIES; 4 | use wasm_bindgen::prelude::*; 5 | 6 | use crate::keypair::private_key::PrivateKey; 7 | use crate::keypair::public_key::PublicKey; 8 | 9 | #[wasm_bindgen] 10 | pub struct ECIES; 11 | 12 | #[wasm_bindgen] 13 | impl ECIES { 14 | pub fn encrypt(message: &[u8], sender_priv_key: &PrivateKey, recipient_pub_key: &PublicKey, exclude_pub_key: bool) -> Result { 15 | Ok(ECIESCiphertext(BSVECIES::encrypt(message, &sender_priv_key.0, &recipient_pub_key.0, exclude_pub_key)?)) 16 | } 17 | 18 | /** 19 | * Encrypt with a randomly generate private key. 20 | * This is intended to be used if you want to anonymously send a party an encrypted message. 21 | */ 22 | pub fn encrypt_with_ephemeral_private_key(message: &[u8], recipient_pub_key: &PublicKey) -> Result { 23 | Ok(ECIESCiphertext(BSVECIES::encrypt_with_ephemeral_private_key(message, &recipient_pub_key.0)?)) 24 | } 25 | 26 | pub fn decrypt(ciphertext: &ECIESCiphertext, recipient_priv_key: &PrivateKey, sender_pub_key: &PublicKey) -> Result, wasm_bindgen::JsError> { 27 | Ok(BSVECIES::decrypt(&ciphertext.0, &recipient_priv_key.0, &sender_pub_key.0)?) 28 | } 29 | 30 | pub fn derive_cipher_keys(priv_key: &PrivateKey, pub_key: &PublicKey) -> Result { 31 | Ok(CipherKeys(BSVECIES::derive_cipher_keys(&priv_key.0, &pub_key.0)?)) 32 | } 33 | } 34 | 35 | #[wasm_bindgen] 36 | pub struct CipherKeys(pub(crate) BSVCipherKeys); 37 | 38 | #[wasm_bindgen] 39 | impl CipherKeys { 40 | pub fn get_iv(&self) -> Vec { 41 | self.0.get_iv() 42 | } 43 | 44 | pub fn get_ke(&self) -> Vec { 45 | self.0.get_ke() 46 | } 47 | 48 | pub fn get_km(&self) -> Vec { 49 | self.0.get_km() 50 | } 51 | } 52 | 53 | #[wasm_bindgen] 54 | pub struct ECIESCiphertext(pub(crate) BSVECIESCiphertext); 55 | 56 | #[wasm_bindgen] 57 | impl ECIESCiphertext { 58 | pub fn get_ciphertext(&self) -> Vec { 59 | self.0.get_ciphertext() 60 | } 61 | 62 | pub fn get_hmac(&self) -> Vec { 63 | self.0.get_hmac() 64 | } 65 | 66 | pub fn get_cipher_keys(&self) -> Option { 67 | self.0.get_cipher_keys().map(CipherKeys) 68 | } 69 | 70 | pub fn to_bytes(&self) -> Vec { 71 | self.0.to_bytes() 72 | } 73 | 74 | pub fn extract_public_key(&self) -> Result { 75 | Ok(PublicKey(self.0.extract_public_key()?)) 76 | } 77 | 78 | pub fn from_bytes(buffer: &[u8], has_pub_key: bool) -> Result { 79 | Ok(ECIESCiphertext(BSVECIESCiphertext::from_bytes(buffer, has_pub_key)?)) 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/encryption.rs: -------------------------------------------------------------------------------- 1 | use bsv::AESAlgorithms as BSVAESAlgorithms; 2 | use bsv::AES as BSVAES; 3 | use wasm_bindgen::prelude::*; 4 | 5 | #[wasm_bindgen] 6 | #[allow(non_camel_case_types)] 7 | #[derive(Debug, Clone, Copy)] 8 | pub enum AESAlgorithms { 9 | AES128_CBC, 10 | AES256_CBC, 11 | AES128_CTR, 12 | AES256_CTR, 13 | } 14 | 15 | impl From for BSVAESAlgorithms { 16 | fn from(item: AESAlgorithms) -> Self { 17 | match item { 18 | AESAlgorithms::AES128_CBC => BSVAESAlgorithms::AES128_CBC, 19 | AESAlgorithms::AES256_CBC => BSVAESAlgorithms::AES256_CBC, 20 | AESAlgorithms::AES128_CTR => BSVAESAlgorithms::AES128_CTR, 21 | AESAlgorithms::AES256_CTR => BSVAESAlgorithms::AES256_CTR, 22 | } 23 | } 24 | } 25 | 26 | #[wasm_bindgen] 27 | pub struct AES; 28 | 29 | #[wasm_bindgen] 30 | impl AES { 31 | pub fn encrypt(key: &[u8], iv: &[u8], message: &[u8], algo: AESAlgorithms) -> Result, wasm_bindgen::JsError> { 32 | Ok(BSVAES::encrypt(key, iv, message, algo.into())?) 33 | } 34 | 35 | pub fn decrypt(key: &[u8], iv: &[u8], message: &[u8], algo: AESAlgorithms) -> Result, wasm_bindgen::JsError> { 36 | Ok(BSVAES::decrypt(key, iv, message, algo.into())?) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/hash.rs: -------------------------------------------------------------------------------- 1 | use bsv::Hash as BSVHash; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | pub struct Hash(pub(crate) BSVHash); 6 | 7 | impl From for Hash { 8 | fn from(v: BSVHash) -> Hash { 9 | Hash(v) 10 | } 11 | } 12 | 13 | impl From for BSVHash { 14 | fn from(v: Hash) -> BSVHash { 15 | v.0 16 | } 17 | } 18 | 19 | /** 20 | * Serialisation Functions 21 | */ 22 | #[wasm_bindgen] 23 | impl Hash { 24 | pub fn to_bytes(&self) -> Vec { 25 | self.0.to_bytes() 26 | } 27 | 28 | pub fn to_hex(&self) -> String { 29 | self.0.to_hex() 30 | } 31 | pub fn sha_256d(input: &[u8]) -> Self { 32 | Hash(BSVHash::sha_256d(input)) 33 | } 34 | 35 | pub fn sha_256(input: &[u8]) -> Self { 36 | Hash(BSVHash::sha_256(input)) 37 | } 38 | 39 | pub fn sha_1(input: &[u8]) -> Self { 40 | Hash(BSVHash::sha_1(input)) 41 | } 42 | 43 | pub fn ripemd_160(input: &[u8]) -> Self { 44 | Hash(BSVHash::ripemd_160(input)) 45 | } 46 | 47 | pub fn hash_160(input: &[u8]) -> Self { 48 | Hash(BSVHash::hash_160(input)) 49 | } 50 | 51 | pub fn sha_512(input: &[u8]) -> Self { 52 | Hash(BSVHash::sha_512(input)) 53 | } 54 | 55 | pub fn sha_512_hmac(input: &[u8], key: &[u8]) -> Self { 56 | Self(BSVHash::sha_256d_hmac(input, key)) 57 | } 58 | 59 | pub fn sha_256_hmac(input: &[u8], key: &[u8]) -> Self { 60 | Self(BSVHash::sha_256d_hmac(input, key)) 61 | } 62 | 63 | pub fn sha_256d_hmac(input: &[u8], key: &[u8]) -> Self { 64 | Self(BSVHash::sha_256d_hmac(input, key)) 65 | } 66 | 67 | pub fn sha_1_hmac(input: &[u8], key: &[u8]) -> Self { 68 | Self(BSVHash::sha_1_hmac(input, key)) 69 | } 70 | 71 | pub fn ripemd_160_hmac(input: &[u8], key: &[u8]) -> Self { 72 | Self(BSVHash::ripemd_160_hmac(input, key)) 73 | } 74 | 75 | pub fn hash_160_hmac(input: &[u8], key: &[u8]) -> Self { 76 | Self(BSVHash::hash_160_hmac(input, key)) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/interpreter.rs: -------------------------------------------------------------------------------- 1 | use crate::{script::Script, transaction::Transaction}; 2 | use bsv::{Interpreter as BSVInterpreter, State as BSVState}; 3 | use wasm_bindgen::{prelude::*, JsError}; 4 | 5 | #[wasm_bindgen] 6 | pub struct Interpreter(pub(crate) BSVInterpreter); 7 | 8 | impl From for Interpreter { 9 | fn from(v: BSVInterpreter) -> Interpreter { 10 | Interpreter(v) 11 | } 12 | } 13 | 14 | impl From for BSVInterpreter { 15 | fn from(v: Interpreter) -> BSVInterpreter { 16 | v.0 17 | } 18 | } 19 | 20 | #[wasm_bindgen] 21 | impl Interpreter { 22 | pub fn from_transaction(tx: Transaction, txin_idx: usize) -> Result { 23 | Ok(Interpreter(BSVInterpreter::from_transaction(&tx.0, txin_idx)?)) 24 | } 25 | 26 | pub fn from_script(script: Script) -> Interpreter { 27 | Interpreter(BSVInterpreter::from_script(&script.0)) 28 | } 29 | 30 | pub fn run(&mut self) -> Result<(), JsError> { 31 | Ok(self.0.run()?) 32 | } 33 | 34 | #[wasm_bindgen(js_name = "next")] 35 | pub fn step(&mut self) -> Result, JsError> { 36 | let state = match self.0.next() { 37 | Some(v) => v?, 38 | None => return Ok(None), 39 | }; 40 | 41 | let js_state = State(state); 42 | Ok(Some(js_state)) 43 | } 44 | 45 | pub fn get_state(&self) -> State { 46 | State(self.0.state()) 47 | } 48 | } 49 | 50 | #[wasm_bindgen] 51 | pub struct State(pub(crate) BSVState); 52 | 53 | impl From for State { 54 | fn from(v: BSVState) -> State { 55 | State(v) 56 | } 57 | } 58 | 59 | #[wasm_bindgen(js_name = Status)] 60 | pub enum JsStatus { 61 | Running, 62 | Finished, 63 | } 64 | 65 | impl From for JsStatus { 66 | fn from(s: bsv::Status) -> Self { 67 | match s { 68 | bsv::Status::Running => JsStatus::Running, 69 | bsv::Status::Finished => JsStatus::Finished, 70 | } 71 | } 72 | } 73 | 74 | #[wasm_bindgen] 75 | impl State { 76 | pub fn get_executed_script(&self) -> Result { 77 | let asm_string: String = self.0.executed_opcodes.iter().map(|x| x.to_string()).fold(String::new(), |acc, x| format!("{} {}", acc, x)); 78 | Script::from_asm_string(&asm_string) 79 | } 80 | 81 | pub fn get_stack(&self) -> Result { 82 | let stack = self.0.stack(); 83 | 84 | Ok(serde_wasm_bindgen::to_value(stack)?) 85 | } 86 | 87 | pub fn get_alt_stack(&self) -> Result { 88 | let stack = &self.0.alt_stack; 89 | 90 | Ok(serde_wasm_bindgen::to_value(&stack)?) 91 | } 92 | 93 | pub fn get_status(&self) -> JsStatus { 94 | self.0.status.clone().into() 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/kdf.rs: -------------------------------------------------------------------------------- 1 | use crate::hash::Hash; 2 | use bsv::KDF as BSVKDF; 3 | use wasm_bindgen::prelude::*; 4 | 5 | #[wasm_bindgen] 6 | #[derive(Debug, Clone, Copy)] 7 | pub enum PBKDF2Hashes { 8 | SHA1, 9 | SHA256, 10 | SHA512, 11 | } 12 | 13 | impl From for bsv::PBKDF2Hashes { 14 | fn from(item: PBKDF2Hashes) -> Self { 15 | match item { 16 | PBKDF2Hashes::SHA1 => bsv::PBKDF2Hashes::SHA1, 17 | PBKDF2Hashes::SHA256 => bsv::PBKDF2Hashes::SHA256, 18 | PBKDF2Hashes::SHA512 => bsv::PBKDF2Hashes::SHA512, 19 | } 20 | } 21 | } 22 | 23 | #[wasm_bindgen] 24 | pub struct KDF(BSVKDF); 25 | 26 | impl From for KDF { 27 | fn from(v: BSVKDF) -> KDF { 28 | KDF(v) 29 | } 30 | } 31 | 32 | #[wasm_bindgen] 33 | impl KDF { 34 | pub fn get_hash(&self) -> Hash { 35 | Hash(self.0.get_hash()) 36 | } 37 | 38 | pub fn get_salt(&self) -> Vec { 39 | self.0.get_salt() 40 | } 41 | 42 | /** 43 | * Implementation of PBKDF2 - when None is specified for salt, a random salt will be generated 44 | */ 45 | pub fn pbkdf2(password: &[u8], salt: Option>, hash_algo: PBKDF2Hashes, rounds: u32, output_length: usize) -> KDF { 46 | KDF(BSVKDF::pbkdf2(password, salt, hash_algo.into(), rounds, output_length)) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/keypair/extended_private_key.rs: -------------------------------------------------------------------------------- 1 | use bsv::ExtendedPrivateKey as BSVExtendedPrivateKey; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use super::{private_key::PrivateKey, public_key::PublicKey}; 5 | 6 | #[wasm_bindgen] 7 | pub struct ExtendedPrivateKey(pub(crate) BSVExtendedPrivateKey); 8 | 9 | impl From for ExtendedPrivateKey { 10 | fn from(v: BSVExtendedPrivateKey) -> ExtendedPrivateKey { 11 | ExtendedPrivateKey(v) 12 | } 13 | } 14 | 15 | impl From for BSVExtendedPrivateKey { 16 | fn from(v: ExtendedPrivateKey) -> BSVExtendedPrivateKey { 17 | v.0 18 | } 19 | } 20 | 21 | #[wasm_bindgen] 22 | impl ExtendedPrivateKey { 23 | // #[cfg_attr(all(feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = getPrivateKey))] 24 | pub fn get_private_key(&self) -> PrivateKey { 25 | PrivateKey(self.0.get_private_key()) 26 | } 27 | 28 | // #[cfg_attr(all(feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = getPublicKey))] 29 | pub fn get_public_key(&self) -> PublicKey { 30 | PublicKey(self.0.get_public_key()) 31 | } 32 | 33 | // #[cfg_attr(all(feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = getChainCode))] 34 | pub fn get_chain_code(&self) -> Vec { 35 | self.0.get_chain_code() 36 | } 37 | 38 | // #[cfg_attr(all(feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = getDepth))] 39 | pub fn get_depth(&self) -> u8 { 40 | self.0.get_depth() 41 | } 42 | 43 | // #[cfg_attr(all(feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = getParentFingerprint))] 44 | pub fn get_parent_fingerprint(&self) -> Vec { 45 | self.0.get_parent_fingerprint() 46 | } 47 | 48 | // #[cfg_attr(all(feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = getIndex))] 49 | pub fn get_index(&self) -> u32 { 50 | self.0.get_index() 51 | } 52 | 53 | pub fn derive(&self, index: u32) -> Result { 54 | Ok(ExtendedPrivateKey(self.0.derive(index)?)) 55 | } 56 | 57 | pub fn derive_from_path(&self, path: &str) -> Result { 58 | Ok(ExtendedPrivateKey(self.0.derive_from_path(path)?)) 59 | } 60 | 61 | pub fn from_seed(seed: &[u8]) -> Result { 62 | Ok(ExtendedPrivateKey(BSVExtendedPrivateKey::from_seed_impl(seed)?)) 63 | } 64 | 65 | pub fn from_random() -> Result { 66 | Ok(ExtendedPrivateKey(BSVExtendedPrivateKey::from_random()?)) 67 | } 68 | 69 | pub fn from_string(xprv_string: &str) -> Result { 70 | Ok(ExtendedPrivateKey(BSVExtendedPrivateKey::from_string(xprv_string)?)) 71 | } 72 | 73 | pub fn to_string(&self) -> Result { 74 | Ok(self.0.to_string()?) 75 | } 76 | 77 | pub fn from_mnemonic(mnemonic: &[u8], passphrase: Option>) -> Result { 78 | Ok(ExtendedPrivateKey(BSVExtendedPrivateKey::from_mnemonic(mnemonic, passphrase)?)) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/keypair/extended_public_key.rs: -------------------------------------------------------------------------------- 1 | use bsv::ExtendedPublicKey as BSVExtendedPublicKey; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::keypair::{extended_private_key::ExtendedPrivateKey, public_key::PublicKey}; 5 | 6 | #[wasm_bindgen] 7 | pub struct ExtendedPublicKey(pub(crate) BSVExtendedPublicKey); 8 | 9 | impl From for ExtendedPublicKey { 10 | fn from(v: BSVExtendedPublicKey) -> ExtendedPublicKey { 11 | ExtendedPublicKey(v) 12 | } 13 | } 14 | 15 | impl From for BSVExtendedPublicKey { 16 | fn from(v: ExtendedPublicKey) -> BSVExtendedPublicKey { 17 | v.0 18 | } 19 | } 20 | 21 | #[wasm_bindgen] 22 | impl ExtendedPublicKey { 23 | pub fn get_public_key(&self) -> PublicKey { 24 | PublicKey(self.0.get_public_key()) 25 | } 26 | 27 | pub fn from_xpriv(xpriv: &ExtendedPrivateKey) -> Self { 28 | ExtendedPublicKey(BSVExtendedPublicKey::from_xpriv(&xpriv.0)) 29 | } 30 | 31 | pub fn get_chain_code(&self) -> Vec { 32 | self.0.get_chain_code() 33 | } 34 | 35 | // #[cfg_attr(all(feature = "wasm-bindgen-keypair"), wasm_bindgen(js_name = getDepth))] 36 | pub fn get_depth(&self) -> u8 { 37 | self.0.get_depth() 38 | } 39 | 40 | pub fn get_parent_fingerprint(&self) -> Vec { 41 | self.0.get_parent_fingerprint() 42 | } 43 | 44 | pub fn get_index(&self) -> u32 { 45 | self.0.get_index() 46 | } 47 | 48 | pub fn derive(&self, index: u32) -> Result { 49 | Ok(Self(self.0.derive(index)?)) 50 | } 51 | 52 | pub fn derive_from_path(&self, path: &str) -> Result { 53 | Ok(Self(self.0.derive_from_path(path)?)) 54 | } 55 | 56 | pub fn from_seed(seed: &[u8]) -> Result { 57 | Ok(ExtendedPublicKey(BSVExtendedPublicKey::from_seed(seed)?)) 58 | } 59 | 60 | pub fn from_random() -> Result { 61 | Ok(ExtendedPublicKey(BSVExtendedPublicKey::from_random()?)) 62 | } 63 | 64 | pub fn from_string(xpub_string: &str) -> Result { 65 | Ok(ExtendedPublicKey(BSVExtendedPublicKey::from_string(xpub_string)?)) 66 | } 67 | 68 | pub fn to_string(&self) -> Result { 69 | Ok(self.0.to_string()?) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/keypair/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod private_key; 2 | pub use private_key::*; 3 | 4 | pub mod extended_private_key; 5 | pub use extended_private_key::*; 6 | 7 | pub mod extended_public_key; 8 | pub use extended_public_key::*; 9 | 10 | pub mod public_key; 11 | pub use public_key::*; 12 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/keypair/private_key.rs: -------------------------------------------------------------------------------- 1 | use bsv::PrivateKey as BSVPrivateKey; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{ecies::ECIESCiphertext, keypair::public_key::PublicKey, signature::Signature}; 5 | 6 | #[wasm_bindgen] 7 | pub struct PrivateKey(pub(crate) BSVPrivateKey); 8 | 9 | impl From for PrivateKey { 10 | fn from(v: BSVPrivateKey) -> PrivateKey { 11 | PrivateKey(v) 12 | } 13 | } 14 | 15 | impl From for BSVPrivateKey { 16 | fn from(v: PrivateKey) -> BSVPrivateKey { 17 | v.0 18 | } 19 | } 20 | 21 | #[wasm_bindgen] 22 | impl PrivateKey { 23 | pub fn to_bytes(&self) -> Vec { 24 | self.0.to_bytes() 25 | } 26 | 27 | pub fn to_hex(&self) -> String { 28 | self.0.to_hex() 29 | } 30 | 31 | pub fn from_random() -> PrivateKey { 32 | PrivateKey(BSVPrivateKey::from_random()) 33 | } 34 | 35 | pub fn get_point(&self) -> Vec { 36 | self.0.get_point() 37 | } 38 | 39 | pub fn compress_public_key(&self, should_compress: bool) -> PrivateKey { 40 | PrivateKey(self.0.compress_public_key(should_compress)) 41 | } 42 | 43 | pub fn from_wif(wif_string: &str) -> Result { 44 | Ok(PrivateKey(BSVPrivateKey::from_wif(wif_string)?)) 45 | } 46 | 47 | pub fn from_hex(hex_str: &str) -> Result { 48 | Ok(PrivateKey(BSVPrivateKey::from_hex(hex_str)?)) 49 | } 50 | 51 | /** 52 | * Standard ECDSA Message Signing using SHA256 as the digestg 53 | */ 54 | pub fn sign_message(&self, msg: &[u8]) -> Result { 55 | Ok(Signature(self.0.sign_message(msg)?)) 56 | } 57 | 58 | pub fn to_wif(&self) -> Result { 59 | Ok(BSVPrivateKey::to_wif(&self.0)?) 60 | } 61 | 62 | pub fn from_bytes(bytes: &[u8]) -> Result { 63 | Ok(PrivateKey(BSVPrivateKey::from_bytes(bytes)?)) 64 | } 65 | 66 | pub fn to_public_key(&self) -> Result { 67 | Ok(PublicKey(self.0.to_public_key()?)) 68 | } 69 | 70 | /** 71 | * Encrypt a message to the public key of this private key. 72 | */ 73 | pub fn encrypt_message(&self, message: &[u8]) -> Result { 74 | Ok(ECIESCiphertext(self.0.encrypt_message(message)?)) 75 | } 76 | 77 | /** 78 | * Decrypt a message that was sent to the public key corresponding to this private key. 79 | */ 80 | pub fn decrypt_message(&self, ciphertext: &ECIESCiphertext, sender_pub_key: &PublicKey) -> Result, wasm_bindgen::JsError> { 81 | Ok(self.0.decrypt_message(&ciphertext.0, &sender_pub_key.0)?) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/keypair/public_key.rs: -------------------------------------------------------------------------------- 1 | use bsv::PublicKey as BSVPublicKey; 2 | use wasm_bindgen::prelude::*; 3 | 4 | use crate::{address::P2PKHAddress, ecies::ECIESCiphertext, keypair::private_key::PrivateKey, signature::Signature}; 5 | 6 | #[derive(Clone)] 7 | #[wasm_bindgen] 8 | pub struct PublicKey(pub(crate) BSVPublicKey); 9 | 10 | impl From for PublicKey { 11 | fn from(v: BSVPublicKey) -> PublicKey { 12 | PublicKey(v) 13 | } 14 | } 15 | 16 | impl From for BSVPublicKey { 17 | fn from(v: PublicKey) -> BSVPublicKey { 18 | v.0 19 | } 20 | } 21 | 22 | #[wasm_bindgen] 23 | impl PublicKey { 24 | pub fn to_address(&self) -> Result { 25 | Ok(P2PKHAddress(self.0.to_p2pkh_address()?)) 26 | } 27 | 28 | pub fn from_hex(hex_str: &str) -> Result { 29 | Ok(PublicKey(BSVPublicKey::from_hex(hex_str)?)) 30 | } 31 | 32 | pub fn from_bytes(bytes: &[u8]) -> Result { 33 | Ok(PublicKey(BSVPublicKey::from_bytes(bytes)?)) 34 | } 35 | 36 | pub fn to_bytes(&self) -> Result, wasm_bindgen::JsError> { 37 | Ok(self.0.to_bytes()?) 38 | } 39 | 40 | pub fn to_hex(&self) -> Result { 41 | Ok(self.0.to_hex()?) 42 | } 43 | 44 | pub fn from_private_key(priv_key: &PrivateKey) -> PublicKey { 45 | PublicKey(BSVPublicKey::from_private_key(&priv_key.0)) 46 | } 47 | 48 | pub fn verify_message(&self, message: &[u8], signature: &Signature) -> Result { 49 | Ok(self.0.verify_message(message, &signature.0)?) 50 | } 51 | 52 | pub fn to_p2pkh_address(&self) -> Result { 53 | Ok(P2PKHAddress(self.0.to_p2pkh_address()?)) 54 | } 55 | 56 | pub fn to_compressed(&self) -> Result { 57 | Ok(PublicKey(self.0.to_compressed()?)) 58 | } 59 | 60 | pub fn to_decompressed(&self) -> Result { 61 | Ok(PublicKey(self.0.to_decompressed()?)) 62 | } 63 | 64 | pub fn encrypt_message(&self, message: &[u8], sender_private_key: &PrivateKey) -> Result { 65 | Ok(ECIESCiphertext(self.0.encrypt_message(message, &sender_private_key.0)?)) 66 | } 67 | 68 | pub fn is_valid_message(&self, message: &[u8], signature: &Signature) -> bool { 69 | self.0.verify_message(message, &signature.0).is_ok() 70 | } 71 | 72 | pub fn is_compressed(&self) -> bool { 73 | self.0.is_compressed() 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod address; 2 | pub use address::*; 3 | 4 | mod bsm; 5 | pub use bsm::*; 6 | 7 | mod chainparams; 8 | pub use chainparams::*; 9 | 10 | mod ecdh; 11 | pub use ecdh::*; 12 | 13 | mod ecdsa; 14 | pub use ecdsa::*; 15 | 16 | mod ecies; 17 | pub use ecies::*; 18 | 19 | mod encryption; 20 | pub use encryption::*; 21 | 22 | mod hash; 23 | pub use hash::*; 24 | 25 | mod interpreter; 26 | pub use interpreter::*; 27 | 28 | mod kdf; 29 | pub use kdf::*; 30 | 31 | mod keypair; 32 | pub use keypair::*; 33 | 34 | mod opcodes; 35 | pub use opcodes::*; 36 | 37 | mod script; 38 | pub use script::*; 39 | 40 | mod sighash; 41 | pub use sighash::*; 42 | 43 | mod signature; 44 | pub use signature::*; 45 | 46 | mod transaction; 47 | pub use transaction::*; 48 | -------------------------------------------------------------------------------- /packages/bsv-wasm/src/script.rs: -------------------------------------------------------------------------------- 1 | use bsv::Script as BSVScript; 2 | use wasm_bindgen::prelude::*; 3 | 4 | #[wasm_bindgen] 5 | pub struct Script(pub(crate) BSVScript); 6 | 7 | impl From for Script { 8 | fn from(v: BSVScript) -> Script { 9 | Script(v) 10 | } 11 | } 12 | 13 | impl From