diff --git a/.actrc b/.actrc new file mode 100644 index 00000000..a078f640 --- /dev/null +++ b/.actrc @@ -0,0 +1 @@ +-e contrib/act/event.json diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..453228e1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,8 @@ +# Set update schedule for GitHub Actions +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "weekly" diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml new file mode 100644 index 00000000..fbc9c32d --- /dev/null +++ b/.github/workflows/fuzz.yml @@ -0,0 +1,77 @@ +# Automatically generated by fuzz/generate-files.sh +name: Fuzz + +on: + push: + branches: + - update_on_bitcoin_0.31.x + - master + - 'test-ci/**' + pull_request: + +jobs: + fuzz: + if: ${{ !github.event.act }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + fuzz_target: [ + tapyrus_deserialize_address, + tapyrus_deserialize_amount, + tapyrus_deserialize_block, + tapyrus_deserialize_prefilled_transaction, + tapyrus_deserialize_psbt, + tapyrus_deserialize_script, + tapyrus_deserialize_transaction, + tapyrus_deserialize_witness, + tapyrus_deser_net_msg, + tapyrus_outpoint_string, + tapyrus_script_bytes_to_asm_fmt, + hashes_cbor, + hashes_json, + hashes_ripemd160, + hashes_sha1, + hashes_sha256, + hashes_sha512_256, + hashes_sha512, + ] + steps: + - name: Install test dependencies + run: sudo apt-get update -y && sudo apt-get install -y binutils-dev libunwind8-dev libcurl4-openssl-dev libelf-dev libdw-dev cmake gcc libiberty-dev + - uses: actions/checkout@v4 + - uses: actions/cache@v3 + id: cache-fuzz + with: + path: | + ~/.cargo/bin + fuzz/target + target + key: cache-${{ matrix.target }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }} + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: '1.65.0' + - name: fuzz + run: | + if [[ "${{ matrix.fuzz_target }}" =~ ^bitcoin ]]; then + export RUSTFLAGS='--cfg=hashes_fuzz --cfg=secp256k1_fuzz' + fi + echo "Using RUSTFLAGS $RUSTFLAGS" + cd fuzz && ./fuzz.sh "${{ matrix.fuzz_target }}" + - run: echo "${{ matrix.fuzz_target }}" >executed_${{ matrix.fuzz_target }} + - uses: actions/upload-artifact@v3 + with: + name: executed_${{ matrix.fuzz_target }} + path: executed_${{ matrix.fuzz_target }} + + verify-execution: + if: ${{ !github.event.act }} + needs: fuzz + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v3 + - name: Display structure of downloaded files + run: ls -R + - run: find executed_* -type f -exec cat {} + | sort > executed + - run: source ./fuzz/fuzz-util.sh && listTargetNames | sort | diff - executed diff --git a/.github/workflows/gh-release.yml b/.github/workflows/gh-release.yml new file mode 100644 index 00000000..69ea930c --- /dev/null +++ b/.github/workflows/gh-release.yml @@ -0,0 +1,15 @@ +name: GitHub Release + +on: + push: + tags: + - '*' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ncipollo/release-action@v1 + with: + generateReleaseNotes: true diff --git a/.github/workflows/kani.yml b/.github/workflows/kani.yml new file mode 100644 index 00000000..520ad176 --- /dev/null +++ b/.github/workflows/kani.yml @@ -0,0 +1,14 @@ +# From https://model-checking.github.io/kani/install-github-ci.html +name: Kani CI +on: + schedule: + - cron: '59 23 * * *' # midnight every day. +jobs: + run-kani: + runs-on: ubuntu-20.04 + steps: + - name: 'Checkout your code.' + uses: actions/checkout@v4 + + - name: 'Run Kani on your code.' + uses: model-checking/kani-github-action@v1.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..cd2a8725 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,22 @@ +on: + push: + branches: + - master + - 0.28.x + - 0.29.x + - 'test-ci/**' + pull_request: + +name: Release + +jobs: + release: + name: Release - dry-run + runs-on: ubuntu-latest + steps: + - name: Checkout Crate + uses: actions/checkout@v4 + - name: Checkout Toolchain + uses: dtolnay/rust-toolchain@stable + - name: run cargo + run: contrib/release.sh diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml new file mode 100644 index 00000000..aba635f0 --- /dev/null +++ b/.github/workflows/rust.yml @@ -0,0 +1,172 @@ +on: + push: + branches: + - master + - update_on_bitcoin_0.31.x + - 'test-ci/**' + pull_request: + +name: Continuous integration + +jobs: + Stable: + name: Test - stable toolchain + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - name: Checkout Crate + uses: actions/checkout@v4 + - name: Checkout Toolchain + # https://github.com/dtolnay/rust-toolchain + uses: dtolnay/rust-toolchain@stable + - name: Running test script + env: + DO_COV: true + AS_DEPENDENCY: false + DO_NO_STD: true + DO_DOCS: true + DO_FEATURE_MATRIX: true + DO_SCHEMARS_TESTS: true # Currently only used in hashes crate. + run: ./contrib/test.sh + + Beta: + name: Test - beta toolchain + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - name: Checkout Crate + uses: actions/checkout@v4 + - name: Checkout Toolchain + uses: dtolnay/rust-toolchain@beta + - name: Running test script + env: + AS_DEPENDENCY: false + DO_NO_STD: true + run: ./contrib/test.sh + + Nightly: + name: Test - nightly toolchain + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - name: Checkout Crate + uses: actions/checkout@v4 + - name: Checkout Toolchain + uses: dtolnay/rust-toolchain@nightly + - name: Install clippy + run: rustup component add clippy + - name: Running test script + env: + DO_LINT: true + DO_FMT: false + DO_BENCH: true + AS_DEPENDENCY: false + DO_NO_STD: true + DO_DOCSRS: true + run: ./contrib/test.sh + + MSRV: + name: Test - 1.56.1 toolchain + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - name: Checkout Crate + uses: actions/checkout@v4 + - name: Checkout Toolchain + uses: dtolnay/rust-toolchain@stable + with: + toolchain: "1.56.1" + - name: Running test script + env: + DO_FEATURE_MATRIX: true + DO_NO_STD: true + run: ./contrib/test.sh + + Arch32bit: + name: Test 32-bit version + runs-on: ubuntu-latest + steps: + - name: Checkout Crate + uses: actions/checkout@v4 + - name: Checkout Toolchain + uses: dtolnay/rust-toolchain@stable + - name: Add architecture i386 + run: sudo dpkg --add-architecture i386 + - name: Install i686 gcc + run: sudo apt-get update -y && sudo apt-get install -y gcc-multilib + - name: Install target + run: rustup target add i686-unknown-linux-gnu + - name: Run test on i686 + run: cargo test --target i686-unknown-linux-gnu + + Cross: + name: Cross test + if: ${{ !github.event.act }} + runs-on: ubuntu-latest + steps: + - name: Checkout Crate + uses: actions/checkout@v4 + - name: Checkout Toolchain + uses: dtolnay/rust-toolchain@stable + - name: Install target + run: rustup target add s390x-unknown-linux-gnu + - name: install cross + run: cargo install cross --locked + - name: run cross test + run: cross test --target s390x-unknown-linux-gnu + + Embedded: + name: Embedded test + runs-on: ubuntu-latest + env: + RUSTFLAGS: "-C link-arg=-Tlink.x" + CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER: "qemu-system-arm -cpu cortex-m3 -machine mps2-an385 -nographic -semihosting-config enable=on,target=native -kernel" + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Set up QEMU + run: sudo apt update && sudo apt install -y qemu-system-arm gcc-arm-none-eabi + - name: Checkout Toolchain + uses: dtolnay/rust-toolchain@nightly + with: + targets: thumbv7m-none-eabi + - name: Install src + run: rustup component add rust-src + - name: Run tapyrus/embedded + run: cd tapyrus/embedded && cargo run --target thumbv7m-none-eabi + - name: Run hashes/embedded no alloc + run: cd hashes/embedded && cargo run --target thumbv7m-none-eabi + - name: Run hashes/embedded with alloc + run: cd hashes/embedded && cargo run --target thumbv7m-none-eabi --features=alloc + + ASAN: + name: Address sanitizer # hashes crate only. + runs-on: ubuntu-latest + steps: + - name: Checkout Crate + uses: actions/checkout@v4 + - name: Checkout Toolchain + uses: dtolnay/rust-toolchain@nightly + - name: Install src + run: rustup component add rust-src + - name: Running address sanitizer + env: + DO_ASAN: true + run: cd hashes && ./contrib/test.sh + + WASM: + name: WebAssembly Build # hashes crate only. + runs-on: ubuntu-latest + steps: + - name: Checkout Crate + uses: actions/checkout@v4 + - name: Checkout Toolchain + uses: dtolnay/rust-toolchain@stable + - name: Running WASM build + env: + DO_WASM: true + run: cd hashes && ./contrib/test.sh diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml new file mode 100644 index 00000000..4fb721e0 --- /dev/null +++ b/.github/workflows/rustfmt.yml @@ -0,0 +1,26 @@ +name: Nightly rustfmt +on: + schedule: + - cron: "0 0 * * 0" # runs weekly on Sunday at 00:00 + workflow_dispatch: # allows manual triggering +jobs: + format: + name: Nightly rustfmt + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@nightly + with: + components: rustfmt + - name: Run Nightly rustfmt + run: cargo +nightly fmt + - name: Get the current date + run: echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + title: Automated nightly rustfmt (${{ env.date }}) + body: | + Automated nightly `rustfmt` changes by [create-pull-request](https://github.com/peter-evans/create-pull-request) GitHub action + commit-message: ${{ env.date }} automated rustfmt nightly + labels: rustfmt diff --git a/.gitignore b/.gitignore index 93426a2c..76ab8e9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,20 @@ -target +# .gitignore for rust-tapyrus repository workspace. + +# Lock files Cargo.lock +internals/Cargo.lock +tapyrus/Cargo.lock +hashes/Cargo.lock + +# Build artifacts +target +internals/target +tapyrus/target +hashes/target -#fuzz -fuzz/hfuzz_target -fuzz/hfuzz_workspace +# Test artifacts +tapyrus/dep_test -#IntelliJ project files -.idea -*.iml +# Fuzz artifacts +hfuzz_target +hfuzz_workspace diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9bfabdeb..00000000 --- a/.travis.yml +++ /dev/null @@ -1,46 +0,0 @@ -language: rust -cache: cargo - -addons: - apt: - update: true - packages: - - binutils-dev - - libunwind8-dev - - libcurl4-openssl-dev - - libelf-dev - - libdw-dev - - cmake - - gcc - - libiberty-dev - - -matrix: - include: - - rust: stable - env: DO_FUZZ=true DO_COV=true AS_DEPENDENCY=true - - rust: beta - env: AS_DEPENDENCY=true - - rust: nightly - env: DO_BENCH=true AS_DEPENDENCY=true - - rust: 1.22.0 - env: AS_DEPENDENCY=true - -script: - - ./contrib/test.sh - -after_success: | - if [ "$DO_COV" = true ]; then - wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz && - tar xzf master.tar.gz && - cd kcov-master && - mkdir build && - cd build && - cmake .. && - make && - make install DESTDIR=../../kcov-build && - cd ../.. && - rm -rf kcov-master && - for file in target/debug/bitcoin-*; do [ -x "${file}" ] || continue; mkdir -p "target/cov/$(basename $file)"; ./kcov-build/usr/local/bin/kcov --exclude-pattern=/.cargo,/usr/lib --verify "target/cov/$(basename $file)" "$file"; done && - bash <(curl -s https://codecov.io/bash) && - echo "Uploaded code coverage"; fi diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 6a4475e8..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,192 +0,0 @@ - -# 0.23.0 - 2020-01-07 - -- Update `secp256k1` dependency to `0.17.1`. -- Update `bitcoinconsensus` dependency to `0.19.0-1`. -- Update `bech32` dependency to `0.7.2`. - -# 0.22.0 - 2020-01-07 - -- Add `ServiceFlags` type. -- Add `NetworkMessage::command`. -- Add `key::Error`. -- Add newtypes for specific hashes: - - `Txid` - - `Wtxid` - - `BlockHash` - - `SigHash` - - `PubkeyHash` - - `ScriptHash` - - `WPubkeyHash` - - `WScriptHash` - - `TxMerkleNode` - - `WitnessMerkleNode` - - `WitnessCommitment` - - `XpubIdentifier` - - `FilterHash` -- Refactor `CommandString`. -- Refactor `Reject` message. -- Rename `RejectReason` enum variants. -- Refactor `encode::Error`. -- Implement `Default` for `TxIn`. -- Implement `std::hash::Hash` for `Inventory`. -- Implement `Copy` for `InvType` enum. -- Use `psbt::Error` in `PartiallySignedTransaction::from_unsigned_tx`. -- Drop message decode max length to 4_000_000. -- Drop `hex` and `byteorder` dependencies. - -# 0.21.0 - 2019-10-02 - -* Add [serde to `BlockHeader` and `Block`](https://github.com/rust-bitcoin/rust-bitcoin/pull/321) -* [Clean up `StreamReader` API](https://github.com/rust-bitcoin/rust-bitcoin/pull/318) (breaking change) -* Add [reject message](https://github.com/rust-bitcoin/rust-bitcoin/pull/323) to p2p messages - -# 0.20.0 - 2019-08-23 - -* Update `secp256k1` 0.15 and `bitcoinconsensus` 0.17 - -# 0.19.0 - 2019-08-16 - -* Add `Amount` and `SignedAmount` types. -* Add BIP-158 support with `BlockFilter` and related types. -* Add `util::misc::signed_msg_hash()` for signing messages. -* Add `MerkleBlock` and `PartialMerkleTree` types. -* bip32: Support serde serializaton for types and add some utility methods: - * `ChildNumber::increment` - * `DerivationPath::children_from` - * `DerivationPath::normal_children` - * `DerivationPath::hardened_children` -* Add `blockdata::script::Builder::push_verify` to verify-ify an opcode. -* Add `sendheaders` network message. -* Add `OutPoint::new()` method and JSON-serialize as `:`. -* Refactor `Address` type: - * Now supports segwit addresses with version >0. - * Add `Address::from_script` constructor. - * Add `Address::address_type` inspector. - * Parsing now returns an `address::Error` instead of `encode::Error`. - * Removed `bitcoin_bech32` dependency for bech32 payloads. -* bip143: Rename `witness_script` to `script_code` -* Rename `BlockHeader::spv_validate` to `validate_pow` -* Rename `OP_NOP2` and `OP_NOP3` to `OP_CLTV` and `OP_CSV` -* psbt: Use `BTreeMap` instead of `HashMap` to ensure serialization roundtrips. -* Drop `Decimal` type. -* Drop `LoneHeaders` type. -* Replace `strason` dependency with (optional) `serde_json`. -* Export the `bitcoin_hashes` and `secp256k1` dependent crates. -* Updated `bitcoin_hashes` dependency to v0.7. -* Removed `rand` and `serde_test` dependencies. -* Internal improvements to consensus encoding logic. - -# 0.18.0 - 2019-03-21 - -* Update `bitcoin-bech32` version to 0.9 -* add `to_bytes` method for `util::key` types -* add serde impls for `util::key` types -* contracthash: minor cleanups, use `util::key` types instead of `secp256k1` types - -# 0.17.1 - 2019-03-04 - -* Add some trait impls to `PublicKey` for miniscript interoperability - -# 0.17.0 - 2019-02-28 - ``The PSBT Release'' - -* **Update minimum rustc version to 1.22**. -* [Replace `rust-crypto` with `bitcoin_hashes`; refactor hash types](https://github.com/rust-bitcoin/rust-bitcoin/pull/215) -* [Remove `Address::p2pk`](https://github.com/rust-bitcoin/rust-bitcoin/pull/222/) -* Remove misleading blanket `MerkleRoot` implementation; [it is now only defined for `Block`](https://github.com/rust-bitcoin/rust-bitcoin/pull/218) -* [Add BIP157](https://github.com/rust-bitcoin/rust-bitcoin/pull/215) (client-side block filtering messages) -* Allow network messages [to be deserialized even across multiple packets](https://github.com/rust-bitcoin/rust-bitcoin/pull/231) -* [Replace all key types](https://github.com/rust-bitcoin/rust-bitcoin/pull/183) to better match abstractions needed for PSBT -* [Clean up BIP32](https://github.com/rust-bitcoin/rust-bitcoin/pull/233) in preparation for PSBT; [use new native key types rather than `secp256k1` ones](https://github.com/rust-bitcoin/rust-bitcoin/pull/238/) -* Remove [apparently-used `Option` serialization](https://github.com/rust-bitcoin/rust-bitcoin/pull/236#event-2158116421) code -* Finally merge [PSBT](https://github.com/rust-bitcoin/rust-bitcoin/pull/103) after nearly nine months - -# 0.16.0 - 2019-01-15 - -* Reorganize opcode types to eliminate unsafe code -* Un-expose some macros that were unintentionally exported -* Update rust-secp256k1 dependency to 0.12 -* Remove `util::iter::Pair` type which does not belong in this library -* Minor bugfixes and optimizations - -# 0.15.1 - 2018-11-08 - -* [Detect p2pk addresses with compressed keys](https://github.com/rust-bitcoin/rust-bitcoin/pull/189) - -# 0.15.0 - 2018-11-03 - -* [Significant API overhaul](https://github.com/rust-bitcoin/rust-bitcoin/pull/156): - * Remove `nu_select` macro and low-level networking support - * Move `network::consensus_params` to `consensus::params` - * Move many other things into `consensus::params` - * Move `BitcoinHash` from `network::serialize` to `util::hash`; remove impl for `Vec` - * Rename/restructure error types - * Rename `Consensus{De,En}coder` to `consensus::{De,En}coder` - * Replace `Raw{De,En}coder` with blanket impls of `consensus::{De,En}coder` on `io::Read` and `io::Write` - * make `serialize` and `serialize_hex` infallible -* Make 0-input transaction de/serialization [always use segwit](https://github.com/rust-bitcoin/rust-bitcoin/pull/153) -* Implement `FromStr` and `Display` for many more types - -# 0.14.2 - 2018-09-11 - -* Add serde support for `Address` - -# 0.14.1 - 2018-08-28 - -* Reject non-compact `VarInt`s on various types -* Expose many types at the top level of the crate -* Add `Ord`, `PartialOrd` impls for `Script` - -# 0.14.0 - 2018-08-22 - -* Add [regtest network](https://github.com/rust-bitcoin/rust-bitcoin/pull/84) to `Network` enum -* Add [`Script::is_op_return()`](https://github.com/rust-bitcoin/rust-bitcoin/pull/101/) which is more specific than - `Script::is_provably_unspendable()` -* Update to bech32 0.8.0; [add Regtest bech32 address support](https://github.com/rust-bitcoin/rust-bitcoin/pull/110) -* [Replace rustc-serialize dependency with hex](https://github.com/rust-bitcoin/rust-bitcoin/pull/107) as a stopgap - toward eliminating any extra dependencies for this; clean up the many independent hex encoders and decoders - throughout the codebase. -* [Add conversions between `ChildNumber` and `u32`](https://github.com/rust-bitcoin/rust-bitcoin/pull/126); make - representation non-public; fix documentation -* [Add several derivation convenience](https://github.com/rust-bitcoin/rust-bitcoin/pull/129) to `bip32` extended keys -* Make `deserialize::deserialize()` [enforce no trailing bytes](https://github.com/rust-bitcoin/rust-bitcoin/pull/129) -* Replace `TxOutRef` with `OutPoint`; use it in `TxIn` struct. -* Use modern `as_` `to_` `into_` conventions for array-wrapping types; impl `Display` rather than `ToString` for most types -* Change `script::Instructions` iterator [to allow rejecting non-minimal pushes](https://github.com/rust-bitcoin/rust-bitcoin/pull/136); - fix bug where errors would iterate forever. -* Overhaul `util::Error`; introduce `serialize::Error` [and use it for `SimpleDecoder` and `SimpleDecoder` rather - than parameterizing these over their error type](https://github.com/rust-bitcoin/rust-bitcoin/pull/137). -* Overhaul `UDecimal` and `Decimal` serialization and parsing [and fix many lingering parsing bugs](https://github.com/rust-bitcoin/rust-bitcoin/pull/142) -* [Update to serde 1.0 and strason 0.4](https://github.com/rust-bitcoin/rust-bitcoin/pull/125) -* Update to secp256k1 0.11.0 -* Many, many documentation and test improvements. - -# 0.13.1 - -* Add `Display` trait to uints, `FromStr` trait to `Network` enum -* Add witness inv types to inv enum, constants for Bitcoin regtest network, `is_coin_base` accessor for tx inputs -* Expose `merkleroot(Vec)` - -# 0.13 - -* Move witnesses inside the `TxIn` structure -* Add `Transaction::get_weight()` -* Update bip143 `sighash_all` API to be more ergonomic - -# 0.12 - -* The in-memory blockchain was moved into a dedicated project rust-bitcoin-chain. -* Removed old script interpreter -* A new optional feature "bitcoinconsensus" lets this library use Bitcoin Core's native -script verifier, wrappend into Rust by the rust-bitcoinconsenus project. -See `Transaction::verify` and `Script::verify` methods. -* Replaced Base58 traits with `encode_slice`, `check_encode_slice`, from and `from_check` functions in the base58 module. -* Un-reversed the Debug output for Sha256dHash -* Add bech32 support -* Support segwit address types - -### 0.11 - -* Remove `num` dependency at Matt's request; agree this is obnoxious to require all -downstream users to also have a `num` dependency just so they can use `Uint256::from_u64`. - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..813c57e7 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,255 @@ +# Contributing to rust-bitcoin + +:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: + +The following is a set of guidelines for contributing to Rust Bitcoin +implementation and other Rust Bitcoin-related projects, which are hosted in the +[Rust Bitcoin Community](https://github.com/rust-bitcoin) on GitHub. These are +mostly guidelines, not rules. Use your best judgment, and feel free to propose +changes to this document in a pull request. + +#### Table Of Contents + +- [General](#general) +- [Communication channels](#communication-channels) +- [Asking questions](#asking-questions) +- [Contribution workflow](#contribution-workflow) + * [Preparing PRs](#preparing-prs) + * [Peer review](#peer-review) + * [Repository maintainers](#repository-maintainers) +- [Coding conventions](#coding-conventions) + * [Formatting](#formatting) + * [MSRV](#msrv) + * [Naming conventions](#naming-conventions) + * [Upgrading dependencies](#upgrading-dependencies) + * [Unsafe code](#unsafe-code) +- [Security](#security) +- [Testing](#testing) +- [Going further](#going-further) + + +## General + +The Rust Bitcoin project operates an open contributor model where anyone is +welcome to contribute towards development in the form of peer review, +documentation, testing and patches. + +Anyone is invited to contribute without regard to technical experience, +"expertise", OSS experience, age, or other concern. However, the development of +standards & reference implementations demands a high-level of rigor, adversarial +thinking, thorough testing and risk-minimization. Any bug may cost users real +money. That being said, we deeply welcome people contributing for the first time +to an open source project or pick up Rust while contributing. Don't be shy, +you'll learn. + + +## Communication channels + +Communication about Rust Bitcoin happens primarily in +[#bitcoin-rust](https://web.libera.chat/?channel=#bitcoin-rust) IRC chat on +[Libera](https://libera.chat/) with the logs available at + (starting from Jun 2021 and now on) and + (historical archive before Jun 2021). + +Discussion about code base improvements happens in GitHub issues and on pull +requests. + +Major projects are tracked [here](https://github.com/orgs/rust-bitcoin/projects). +Major milestones are tracked [here](https://github.com/rust-bitcoin/rust-bitcoin/milestones). + + +## Asking questions + +> **Note:** Please don't file an issue to ask a question. You'll get faster +> results by using the resources below. + +We have a dedicated developer channel on IRC, #bitcoin-rust@libera.chat where +you may get helpful advice if you have questions. + + +## Contribution workflow + +The codebase is maintained using the "contributor workflow" where everyone +without exception contributes patch proposals using "pull requests". This +facilitates social contribution, easy testing and peer review. + +To contribute a patch, the workflow is a as follows: + +1. Fork Repository +2. Create topic branch +3. Commit patches + +Please keep commits should atomic and diffs easy to read. For this reason +do not mix any formatting fixes or code moves with actual code changes. +Further, each commit, individually, should compile and pass tests, in order to +ensure git bisect and other automated tools function properly. + +Please cover every new feature with unit tests. + +When refactoring, structure your PR to make it easy to review and don't hesitate +to split it into multiple small, focused PRs. + +Commits should cover both the issue fixed and the solution's rationale. +Please keep these [guidelines](https://chris.beams.io/posts/git-commit/) in mind. + +To facilitate communication with other contributors, the project is making use +of GitHub's "assignee" field. First check that no one is assigned and then +comment suggesting that you're working on it. If someone is already assigned, +don't hesitate to ask if the assigned party or previous commenters are still +working on it if it has been awhile. + + +## Preparing PRs + +The main library development happens in the `master` branch. This branch must +always compile without errors (using GitHub CI). All external contributions are +made within PRs into this branch. + +Prerequisites that a PR must satisfy for merging into the `master` branch: +* each commit within a PR must compile and pass unit tests with no errors, with + every feature combination (including compiling the fuzztests) on some + reasonably recent compiler (this is partially automated with CI, so the rule + is that we will not accept commits which do not pass GitHub CI); +* the tip of any PR branch must also compile and pass tests with no errors on + MSRV (check [README.md] on current MSRV requirements) and pass fuzz tests on + nightly rust; +* contain all necessary tests for the introduced functional (either as a part of + commits, or, more preferably, as separate commits, so that it's easy to + reorder them during review and check that the new tests fail without the new + code); +* contain all inline docs for newly introduced API and pass doc tests; +* be based on the recent `master` tip from the original repository at + . + +NB: reviewers may run more complex test/CI scripts, thus, satisfying all the +requirements above is just a preliminary, but not necessary sufficient step for +getting the PR accepted as a valid candidate PR for the `master` branch. + +PR authors may also find it useful to run the following script locally in order +to check that each of the commits within the PR satisfies the requirements +above, before submitting the PR to review: +```shell script +RUSTUP_TOOLCHAIN=1.41.1 ./contrib/test.sh +``` +Please replace the value in `RUSTUP_TOOLCHAIN=1.41.1` with the current MSRV from +[README.md]. + +NB: Please keep in mind that the script above replaces `Cargo.lock` file, which +is necessary to support current MSRV, incompatible with `stable` and newer cargo +versions. + +### Peer review + +Anyone may participate in peer review which is expressed by comments in the pull +request. Typically, reviewers will review the code for obvious errors, as well as +test out the patch set and opine on the technical merits of the patch. Please, +first review PR on the conceptual level before focusing on code style or +grammar fixes. + +### Repository maintainers + +Pull request merge requirements: +- all CI test should pass, +- at least two "accepts"/ACKs from the repository maintainers (see "refactor carve-out"). +- no reasonable "rejects"/NACKs from anybody who reviewed the code. + +Current list of the project maintainers: + +- [Andrew Poelstra](https://github.com/apoelstra) +- [Steven Roose](https://github.com/stevenroose) +- [Matt Corallo](https://github.com/TheBlueMatt) +- [Elichai Turkel](https://github.com/elichai) +- [Sanket Kanjalkar](https://github.com/sanket1729) +- [Martin Habovštiak](https://github.com/Kixunil) +- [Riccardo Casatta](https://github.com/RCasatta) +- [Tobin Harding](https://github.com/tcharding) + +#### Refactor carve-out + +The repository is going through heavy refactoring and "trivial" API redesign +(eg, rename `Foo::empty` to `Foo::new`) as we push towards API stabilization. As +such reviewers are either bored or overloaded with notifications, hence we have +created a carve out to the 2-ACK rule. + +A PR may be considered for merge if it has a single ACK and has sat open for at +least two weeks with no comments, questions, or NACKs. + +#### One ACK carve-out + +We reserve the right to merge PRs with a single ACK [0], at any time, if they match +any of the following conditions: + +1. PR only touches CI i.e, only changes any of the `test.sh` scripts and/or + stuff in `.github/workflows`. +2. Non-content changing documentation fixes i.e., grammar/typos, spelling, full + stops, capital letters. Any change with more substance must still get two + ACKs. +3. Code moves that do not change the API e.g., moving error types to a private + submodule and re-exporting them from the original module. Must not include + any code changes except to import paths. This rule is more restrictive than + the refactor carve-out. It requires absolutely no change to the public API. + +[0] - Obviously author and ACK'er must not be the same person. + +## Coding conventions + +Library reflects Bitcoin Core approach whenever possible. + +### Naming conventions + +Naming of data structures/enums and their fields/variants must follow names used +in Bitcoin Core, with the following exceptions: +- the case should follow Rust standards (i.e. PascalCase for types and + snake_case for fields and variants); +- omit `C`-prefixes. + +### Upgrading dependencies + +If your change requires a dependency to be upgraded you must do the following: + +1. Modify `Cargo.toml` +2. Copy `Cargo-minimal.lock` to `Cargo.lock` +3. Trigger cargo to update the required entries in the lock file - use `--precise` using the minimum version number that works +4. Test your change +5. Copy `Cargo.lock` to `Cargo-minimal.lock` +6. Update `Cargo-recent.lock` if it is also behind +7. Commit both lock files together with `Cargo.toml` and your code changes + +### Unsafe code + +Use of `unsafe` code is prohibited unless there is a unanimous decision among +library maintainers on the exclusion from this rule. In such cases there is a +requirement to test unsafe code with sanitizers including Miri. + + +## Security + +Security is the primary focus for this library; disclosure of security +vulnerabilities helps prevent user loss of funds. If you believe a vulnerability +may affect other implementations, please disclose this information according to +the [security guidelines](./SECURITY.md), work on which is currently in progress. +Before it is completed, feel free to send disclosure to Andrew Poelstra, +apoelstra@wpsoftware.net, encrypted with his public key from +. + + +## Testing + +Related to the security aspect, rust bitcoin developers take testing very +seriously. Due to the modular nature of the project, writing new test cases is +easy and good test coverage of the codebase is an important goal. Refactoring +the project to enable fine-grained unit testing is also an ongoing effort. + +Various methods of testing are in use (e.g. fuzzing, mutation), please see +the [readme](./REAME.md) for more information. + + +## Going further + +You may be interested in the guide by Jon Atack on +[How to review Bitcoin Core PRs](https://github.com/jonatack/bitcoin-development/blob/master/how-to-review-bitcoin-core-prs.md) +and [How to make Bitcoin Core PRs](https://github.com/jonatack/bitcoin-development/blob/master/how-to-make-bitcoin-core-prs.md). +While there are differences between the projects in terms of context and +maturity, many of the suggestions offered apply to this project. + +Overall, have fun :) diff --git a/Cargo-minimal.lock b/Cargo-minimal.lock new file mode 100644 index 00000000..319a62df --- /dev/null +++ b/Cargo-minimal.lock @@ -0,0 +1,510 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "base64" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" + +[[package]] +name = "bech32" +version = "0.10.0-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" + +[[package]] +name = "bincode" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f30d3a39baa26f9651f17b375061f3233dde33424a8b72b0dbe93a68a0bc896d" +dependencies = [ + "byteorder", + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + +[[package]] +name = "bitcoinconsensus" +version = "0.20.2-0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54505558b77e0aa21b2491a7b39cbae9db22ac8b1bc543ef4600edb762306f9c" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "byteorder" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60f0b0d4c0a382d2734228fd12b5a6b5dac185c60e938026fd31b265b94f9bd2" + +[[package]] +name = "cc" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" + +[[package]] +name = "cfg-if" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" + +[[package]] +name = "core2" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cf12d2dad3ed124aa116f59561428478993d69ab81ae4d30e5349c9c5b5a5f6" +dependencies = [ + "memchr", +] + +[[package]] +name = "dyn-clone" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0da518043f6481364cd454be81dfe096cfd3f82daa1466f4946d24ea325b0941" + +[[package]] +name = "getrandom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" + +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +dependencies = [ + "core2", +] + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "honggfuzz" +version = "0.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848e9c511092e0daa0a35a63e8e6e475a3e8f870741448b9f6028d69b142f18e" +dependencies = [ + "lazy_static", + "memmap2", + "rustc_version", +] + +[[package]] +name = "itoa" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" + +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dfca3d9957906e8d1e6a0b641dc9a59848e793f1da2165889fd4f62d10d79c" + +[[package]] +name = "memchr" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01e64d9017d18e7fc09d8e4fe0e28ff6931019e979fb8019319db7ca827f8a6" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "mutagen" +version = "0.2.0" +source = "git+https://github.com/llogiq/mutagen#a6377c4c3f360afeb7a287c1c17e4b69456d5f53" +dependencies = [ + "mutagen-core", + "mutagen-transform", +] + +[[package]] +name = "mutagen-core" +version = "0.2.0" +source = "git+https://github.com/llogiq/mutagen#a6377c4c3f360afeb7a287c1c17e4b69456d5f53" +dependencies = [ + "anyhow", + "json", + "lazy_static", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", +] + +[[package]] +name = "mutagen-transform" +version = "0.2.0" +source = "git+https://github.com/llogiq/mutagen#a6377c4c3f360afeb7a287c1c17e4b69456d5f53" +dependencies = [ + "mutagen-core", + "proc-macro2", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" + +[[package]] +name = "proc-macro2" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76330fb486679b4ace3670f117bbc9e16204005c4bde9c4bd372f45bed34f12" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" + +[[package]] +name = "schemars" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6ab463ae35acccb5cba66c0084c985257b797d288b6050cc2f6ac1b266cb78" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "902fdfbcf871ae8f653bddf4b2c05905ddaabc08f69d32a915787e3be0d31356" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "secp256k1" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" +dependencies = [ + "bitcoin_hashes", + "rand", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e67c467c38fd24bd5499dc9a18183b31575c12ee549197e3e20d57aa4fe3b7" +dependencies = [ + "cc", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.156" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45cd6d95391b16cd57e88b68be41d504183b7faae22030c0cc3b3f73dd57b2fd" +dependencies = [ + "byteorder", + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.156" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dbab34ca63057a1f15280bdf3c39f2b1eb1b54c17e98360e511637aef7418c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_test" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "482765e11e55174e2d74a611674d09ed96712c00e0777e305a0c416dfef5fa40" +dependencies = [ + "serde", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tapyrus" +version = "0.5.0" +dependencies = [ + "base64", + "bech32", + "bincode", + "bitcoinconsensus", + "core2", + "hex-conservative", + "hex_lit", + "mutagen", + "num-bigint", + "num-integer", + "num-traits", + "secp256k1", + "serde", + "serde_derive", + "serde_json", + "serde_test", + "tapyrus-internals", + "tapyrus_hashes", +] + +[[package]] +name = "tapyrus-fuzz" +version = "0.0.1" +dependencies = [ + "honggfuzz", + "serde", + "serde_cbor", + "serde_json", + "tapyrus", +] + +[[package]] +name = "tapyrus-internals" +version = "0.2.0" +dependencies = [ + "serde", +] + +[[package]] +name = "tapyrus_hashes" +version = "0.13.0" +dependencies = [ + "core2", + "hex-conservative", + "schemars", + "serde", + "serde_json", + "serde_test", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" diff --git a/Cargo-recent.lock b/Cargo-recent.lock new file mode 100644 index 00000000..5d38625b --- /dev/null +++ b/Cargo-recent.lock @@ -0,0 +1,499 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "base64" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53" + +[[package]] +name = "bech32" +version = "0.10.0-beta" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98f7eed2b2781a6f0b5c903471d48e15f56fb4e1165df8a9a2337fd1a59d45ea" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals", + "hex-conservative", +] + +[[package]] +name = "bitcoinconsensus" +version = "0.20.2-0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54505558b77e0aa21b2491a7b39cbae9db22ac8b1bc543ef4600edb762306f9c" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "core2" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239fa3ae9b63c2dc74bd3fa852d4792b8b305ae64eeede946265b6af62f1fff3" +dependencies = [ + "memchr", +] + +[[package]] +name = "dyn-clone" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b0cf012f1230e43cd00ebb729c6bb58707ecfa8ad08b52ef3a4ccd2697fc30" + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "half" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" + +[[package]] +name = "hex-conservative" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30ed443af458ccb6d81c1e7e661545f94d3176752fb1df2f543b902a1e0f51e2" +dependencies = [ + "core2", +] + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "honggfuzz" +version = "0.5.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848e9c511092e0daa0a35a63e8e6e475a3e8f870741448b9f6028d69b142f18e" +dependencies = [ + "lazy_static", + "memmap2", + "rustc_version", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "json" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.142" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "mutagen" +version = "0.2.0" +source = "git+https://github.com/llogiq/mutagen#a6377c4c3f360afeb7a287c1c17e4b69456d5f53" +dependencies = [ + "mutagen-core", + "mutagen-transform", +] + +[[package]] +name = "mutagen-core" +version = "0.2.0" +source = "git+https://github.com/llogiq/mutagen#a6377c4c3f360afeb7a287c1c17e4b69456d5f53" +dependencies = [ + "anyhow", + "json", + "lazy_static", + "proc-macro2", + "quote", + "serde", + "serde_json", + "syn", +] + +[[package]] +name = "mutagen-transform" +version = "0.2.0" +source = "git+https://github.com/llogiq/mutagen#a6377c4c3f360afeb7a287c1c17e4b69456d5f53" +dependencies = [ + "mutagen-core", + "proc-macro2", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "proc-macro2" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "schemars" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02c613288622e5f0c3fdc5dbd4db1c5fbe752746b1d1a56a0630b78fd00de44f" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109da1e6b197438deb6db99952990c7f959572794b80ff93707d55a232545e7c" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn", +] + +[[package]] +name = "secp256k1" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acea373acb8c21ecb5a23741452acd2593ed44ee3d343e72baaa143bc89d0d5" +dependencies = [ + "bitcoin_hashes", + "rand", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09e67c467c38fd24bd5499dc9a18183b31575c12ee549197e3e20d57aa4fe3b7" +dependencies = [ + "cc", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.156" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "314b5b092c0ade17c00142951e50ced110ec27cea304b1037c6969246c2469a4" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45cd6d95391b16cd57e88b68be41d504183b7faae22030c0cc3b3f73dd57b2fd" +dependencies = [ + "byteorder", + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.156" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7e29c4601e36bcec74a223228dce795f4cd3616341a4af93520ca1a837c087d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_test" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c95a500e3923258f7fc3a16bf29934e403aef5ca1096e184d85e3b1926675e8" +dependencies = [ + "serde", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tapyrus" +version = "0.5.0" +dependencies = [ + "base64", + "bech32", + "bincode", + "bitcoinconsensus", + "core2", + "hex-conservative", + "hex_lit", + "mutagen", + "num-bigint", + "num-integer", + "num-traits", + "secp256k1", + "serde", + "serde_derive", + "serde_json", + "serde_test", + "tapyrus-internals", + "tapyrus_hashes", +] + +[[package]] +name = "tapyrus-fuzz" +version = "0.0.1" +dependencies = [ + "honggfuzz", + "serde", + "serde_cbor", + "serde_json", + "tapyrus", +] + +[[package]] +name = "tapyrus-internals" +version = "0.2.0" +dependencies = [ + "serde", +] + +[[package]] +name = "tapyrus_hashes" +version = "0.13.0" +dependencies = [ + "core2", + "hex-conservative", + "schemars", + "serde", + "serde_json", + "serde_test", +] + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/Cargo.toml b/Cargo.toml index 0409be7a..763f5be7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,37 +1,11 @@ -[package] -name = "bitcoin" -version = "0.23.0" -authors = ["Andrew Poelstra "] -license = "CC0-1.0" -homepage = "https://github.com/rust-bitcoin/rust-bitcoin/" -repository = "https://github.com/rust-bitcoin/rust-bitcoin/" -documentation = "https://docs.rs/bitcoin/" -description = "General purpose library for using and interoperating with Bitcoin and other cryptocurrencies." -keywords = [ "crypto", "bitcoin" ] -readme = "README.md" +[workspace] +members = ["tapyrus", "hashes", "internals", "fuzz"] -[lib] -name = "bitcoin" -path = "src/lib.rs" +[patch.crates-io.tapyrus] +path = "tapyrus" -[features] -fuzztarget = ["secp256k1/fuzztarget", "bitcoin_hashes/fuzztarget"] -unstable = [] -rand = ["secp256k1/rand"] -use-serde = ["hex", "serde", "bitcoin_hashes/serde", "secp256k1/serde"] +[patch.crates-io.tapyrus_hashes] +path = "hashes" -[dependencies] -bech32 = "0.7.2" -bitcoin_hashes = "0.7.3" -secp256k1 = "0.17.1" - -bitcoinconsensus = { version = "0.19.0-1", optional = true } -serde = { version = "1", optional = true } -hex = { version = "=0.3.2", optional = true } - -[dev-dependencies] -hex = "=0.3.2" -serde_derive = "<1.0.99" -serde_json = "1" -serde_test = "1" -secp256k1 = { version = "0.17.1", features = ["rand"] } +[patch.crates-io.tapyrus-internals] +path = "internals" diff --git a/README.md b/README.md index d0b4d8eb..29cfd8af 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,22 @@ -[![Status](https://travis-ci.org/rust-bitcoin/rust-bitcoin.png?branch=master)](https://travis-ci.org/rust-bitcoin/rust-bitcoin) -[![Safety Dance](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/) - -# Rust Bitcoin Library - -Library with support for de/serialization, parsing and executing on data -structures and network messages related to Bitcoin. +
+

Rust Bitcoin

+ + Rust Bitcoin logo by Hunter Trujillo, see license and source files under /logo + +

Library with support for de/serialization, parsing and executing on data-structures + and network messages related to Bitcoin. +

+ +

+ Crate Info + CC0 1.0 Universal Licensed + CI Status + API Docs + Rustc Version 1.56.1+ + Chat on IRC + +

+
[Documentation](https://docs.rs/bitcoin/) @@ -14,54 +26,84 @@ Supports (or should support) * De/serialization of blocks and transactions * Script de/serialization * Private keys and address creation, de/serialization and validation (including full BIP32 support) -* PSBT creation, manipulation, merging and finalization -* Pay-to-contract support as in Appendix A of the [Blockstream sidechains whitepaper](https://www.blockstream.com/sidechains.pdf) +* PSBT v0 de/serialization and all but the Input Finalizer role. Use [rust-miniscript](https://docs.rs/miniscript/latest/miniscript/psbt/index.html) to finalize. For JSONRPC interaction with Bitcoin Core, it is recommended to use [rust-bitcoincore-rpc](https://github.com/rust-bitcoin/rust-bitcoincore-rpc). -# Known limitations +It is recommended to always use [cargo-crev](https://github.com/crev-dev/cargo-crev) to verify the +trustworthiness of each of your dependencies, including this one. + +## Known limitations -## Consensus +### Consensus -This library **must not** be used for consensus code (i.e. fully validating -blockchain data). It technically supports doing this, but doing so is very -ill-advised because there are many deviations, known and unknown, between -this library and the Bitcoin Core reference implementation. In a consensus -based cryptocurrency such as Bitcoin it is critical that all parties are -using the same rules to validate data, and this library is simply unable -to implement the same rules as Core. +This library **must not** be used for consensus code (i.e. fully validating blockchain data). It +technically supports doing this, but doing so is very ill-advised because there are many deviations, +known and unknown, between this library and the Bitcoin Core reference implementation. In a +consensus based cryptocurrency such as Bitcoin it is critical that all parties are using the same +rules to validate data, and this library is simply unable to implement the same rules as Core. -Given the complexity of both C++ and Rust, it is unlikely that this will -ever be fixed, and there are no plans to do so. Of course, patches to -fix specific consensus incompatibilities are welcome. +Given the complexity of both C++ and Rust, it is unlikely that this will ever be fixed, and there +are no plans to do so. Of course, patches to fix specific consensus incompatibilities are welcome. + +### Support for 16-bit pointer sizes + +16-bit pointer sizes are not supported and we can't promise they will be. If you care about them +please let us know, so we can know how large the interest is and possibly decide to support them. ## Documentation -Currently can be found on [docs.rs/bitcoin](https://docs.rs/bitcoin/). -Patches to add usage examples and to expand on existing docs would be extremely -appreciated. +Currently can be found on [docs.rs/bitcoin](https://docs.rs/bitcoin/). Patches to add usage examples +and to expand on existing docs would be extremely appreciated. + +## Contributing -# Contributing -Contributions are generally welcome. If you intend to make larger changes please -discuss them in an issue before PRing them to avoid duplicate work and -architectural mismatches. If you have any questions or ideas you want to discuss -please join us in -[#rust-bitcoin](http://webchat.freenode.net/?channels=%23rust-bitcoin) on -freenode. +Contributions are generally welcome. If you intend to make larger changes please discuss them in an +issue before PRing them to avoid duplicate work and architectural mismatches. If you have any +questions or ideas you want to discuss please join us in +[#bitcoin-rust](https://web.libera.chat/?channel=#bitcoin-rust) on +[libera.chat](https://libera.chat). + +For more information please see `./CONTRIBUTING.md`. ## Minimum Supported Rust Version (MSRV) -This library should always compile with any combination of features on **Rust 1.22**. + +This library should always compile with any combination of features on **Rust 1.56.1**. + +To build with the MSRV you will likely need to pin a bunch of dependencies, see `./contrib/test.sh` +for the current list. + +## External dependencies + +We integrate with a few external libraries, most notably `serde`. These +are available via feature flags. To ensure compatibility and MSRV stability we +provide two lock files as a means of inspecting compatible versions: +`Cargo-minimal.lock` containing minimal versions of dependencies and +`Cargo-recent.lock` containing recent versions of dependencies tested in our CI. + +We do not provide any guarantees about the content of these lock files outside +of "our CI didn't fail with these versions". Specifically, we do not guarantee +that the committed hashes are free from malware. It is your responsibility to +review them. ## Installing Rust -Rust can be installed using your package manager of choice or -[rustup.rs](https://rustup.rs). The former way is considered more secure since -it typically doesn't involve trust in the CA system. But you should be aware -that the version of Rust shipped by your distribution might be out of date. -Generally this isn't a problem for `rust-bitcoin` since we support much older -versions (>=1.22) than the current stable one. + +Rust can be installed using your package manager of choice or [rustup.rs](https://rustup.rs). The +former way is considered more secure since it typically doesn't involve trust in the CA system. But +you should be aware that the version of Rust shipped by your distribution might be out of date. +Generally this isn't a problem for `rust-bitcoin` since we support much older versions than the +current stable one (see MSRV section). ## Building + +The cargo feature `std` is enabled by default. At least one of the features `std` or `no-std` or +both must be enabled. + +Enabling the `no-std` feature does not disable `std`. To disable the `std` feature you must disable +default features. The `no-std` feature only enables additional features required for this crate to +be usable without `std`. Both can be enabled without conflict. + The library can be built and tested using [`cargo`](https://github.com/rust-lang/cargo/): ``` @@ -76,35 +118,103 @@ You can run tests with: cargo test ``` -Please refer to the [`cargo` documentation](https://doc.rust-lang.org/stable/cargo/) for more detailed instructions. +Please refer to the [`cargo` documentation](https://doc.rust-lang.org/stable/cargo/) for more +detailed instructions. + +### Just + +We support [`just`](https://just.systems/man/en/) for running dev workflow commands. Run `just` from +your shell to see list available sub-commands. + +### Building the docs + +We build docs with the nightly toolchain, you may wish to use the following shell alias to check +your documentation changes build correctly. + +``` +alias build-docs='RUSTDOCFLAGS="--cfg docsrs" cargo +nightly rustdoc --features="$FEATURES" -- -D rustdoc::broken-intra-doc-links' +``` + +## Testing + +Unit and integration tests are available for those interested, along with benchmarks. For project +developers, especially new contributors looking for something to work on, we do: + +- Fuzz testing with [`Hongfuzz`](https://github.com/rust-fuzz/honggfuzz-rs) +- Mutation testing with [`Mutagen`](https://github.com/llogiq/mutagen) +- Code verification with [`Kani`](https://github.com/model-checking/kani) + +There are always more tests to write and more bugs to find, contributions to our testing efforts +extremely welcomed. Please consider testing code a first class citizen, we definitely do take PRs +improving and cleaning up test code. + +### Unit/Integration tests + +Run as for any other Rust project `cargo test --all-features`. + +### Benchmarks + +We use a custom Rust compiler configuration conditional to guard the bench mark code. To run the +bench marks use: `RUSTFLAGS='--cfg=bench' cargo +nightly bench`. + +### Mutation tests + +We have started doing mutation testing with [mutagen](https://github.com/llogiq/mutagen). To run +these tests first install the latest dev version with `cargo +nightly install --git https://github.com/llogiq/mutagen` +then run with `RUSTFLAGS='--cfg=mutate' cargo +nightly mutagen`. + +### Code verification + +We have started using [kani](https://github.com/model-checking/kani), install with `cargo install --locked kani-verifier` + (no need to run `cargo kani setup`). Run the tests with `cargo kani`. ## Pull Requests -Every PR needs at least two reviews to get merged. During the review phase -maintainers and contributors are likely to leave comments and request changes. -Please try to address them, otherwise your PR might get closed without merging -after a longer time of inactivity. If your PR isn't ready for review yet please -mark it by prefixing the title with `WIP: `. + +Every PR needs at least two reviews to get merged. During the review phase maintainers and +contributors are likely to leave comments and request changes. Please try to address them, otherwise +your PR might get closed without merging after a longer time of inactivity. If your PR isn't ready +for review yet please mark it by prefixing the title with `WIP: `. + +### CI Pipeline + +The CI pipeline requires approval before being run on each MR. + +In order to speed up the review process the CI pipeline can be run locally using +[act](https://github.com/nektos/act). The `fuzz` and `Cross` jobs will be skipped when using `act` +due to caching being unsupported at this time. We do not *actively* support `act` but will merge PRs +fixing `act` issues. + +### Githooks + +To assist devs in catching errors _before_ running CI we provide some githooks. If you do not +already have locally configured githooks you can use the ones in this repository by running, in the +root directory of the repository: +``` +git config --local core.hooksPath githooks/ +``` + +Alternatively add symlinks in your `.git/hooks` directory to any of the githooks we provide. ## Policy on Altcoins/Altchains -Patches which add support for non-Bitcoin cryptocurrencies by adding constants -to existing enums (e.g. to set the network message magic-byte sequence) are -welcome. Anything more involved will be considered on a case-by-case basis, -as the altcoin landscape includes projects which [frequently appear and -disappear, and are poorly designed anyway](https://download.wpsoftware.net/bitcoin/alts.pdf) -and keeping the codebase maintainable is a large priority. +Since the altcoin landscape includes projects which [frequently appear and disappear, and are poorly +designed anyway](https://download.wpsoftware.net/bitcoin/alts.pdf) we do not support any altcoins. +Supporting Bitcoin properly is already difficult enough and we do not want to increase the +maintenance burden and decrease API stability by adding support for other coins. + +Our code is public domain so by all means fork it and go wild :) -In general, things that improve cross-chain compatibility (e.g. support for -cross-chain atomic swaps) are more likely to be accepted than things which -support only a single blockchain. +## Release Notes -# Release Notes +Release notes are done per crate, see: -See CHANGELOG.md +- [bitcoin CHANGELOG](tapyrus/CHANGELOG.md) +- [hashes CHANGELOG](hashes/CHANGELOG.md) +- [internals CHANGELOG](internals/CHANGELOG.md) -# Licensing +## Licensing -The code in this project is licensed under the Creative Commons CC0 1.0 -Universal license. +The code in this project is licensed under the [Creative Commons CC0 1.0 Universal license](LICENSE). +We use the [SPDX license list](https://spdx.org/licenses/) and [SPDX IDs](https://spdx.dev/ids/). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..2e161330 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,540 @@ +# Security Policy + +This security policy applies to the "core" crates in the rust-bitcoin ecosystem, which are +`bitcoin`, `secp256k1`, `bitcoin_hashes` and `bitcoin-internals`. These crates deal with +cryptography and cryptographic algorithms, and as such, are likely locations for security +vulnerabilities to crop up. + +As a general rule, an issue is a security vulnerability if it could lead to: + +* Loss of funds +* Loss of privacy +* Censorship (including e.g. by attaching an incorrectly low fee to a transaction) +* Any "ordinary" security problem, such as remote code execution or invalid memory acccess + +In general, use your best judgement in determining whether an issue is a security issue. If not, +go ahead and post it to the public issue tracker. + +**If you believe you are aware of a security issue**, please contact Andrew Poelstra at +`rust-bitcoin-security@wpsoftware.net`. You may GPG-encrypt this email to his public key, which +[can be downloaded from his website here](https://wpsoftware.net/andrew/andrew.gpg) or which is +listed in full below. + +# Andrew Poelstra's GPG Key + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBFASGPEBCACwQgoZpLKmYtTFXQ+YAXIn8LtoLqom/eyJP6UbKQJoWPs9P79o +CQpYy3Y6xx8JYKK556htGbi0OXIfqmDakBMG+yxs5fj6z2bTfLMJz6ej4AORC/aV +JrlopIGE8/mhiQ+C1wX/3S3ueSFUmDOju4pucjzQTb3pL8ONob3kwWJAAXMP0SWy +aNQY/ZZQ8k2Q6joI0gd80LbM3tWUdX8ryLArfbE58CITiEgKPA1ghNGHCB78elrh +oMcmhoes+wTHN7Q7wSkoJdPFzAgIXIff/UpsDhm8EUjVAdgi0fo04vxxjdTF86M1 +KaoAYbxtSR5Rb+U101xd9Xsca+Gofm2KsAGLABEBAAG0NUFuZHJldyBQb2Vsc3Ry +YSAoYW5keXRvc2hpKSA8YW5keXRvc2hpQGJpdGNvaW4ubmluamE+iQFWBBMBCABA +AhsDBwsJCAcDAgEGFQgCCQoLBBYCAwECHgECF4AWIQRpmmPvwXrTqaNM/8B60Kkc +QL0AkQUCYQMqwAUJGlcTTQAKCRB60KkcQL0AkQZ2B/9j9UhklerAYJBehQqKJixb +JL6DPdEufL4+PnR51bXV3YRn2OH6Orhq/XXadjdbAcSz0nlGXyFBoPfzZfzZAeqy +jLbKsHCjPNST/K8whZMvUVgUk2kze8DOY2R6miNmQwEf1stMh5ZrTcsj4F1GHeS+ +x022NPvnT+V0A4t3I+/BqaKnQ92eu+l6RWQjde40Ti6COwozaaNjYuxUYiYUyHnJ +3oC4UlVp0AnV/iUo4qVlhfDlrAEgQq+5wPKtvmYmgW8SmiCWDAdBn4r0VeFAPcB2 +ogzM+UT6DWcf0z0upT1QtvcOBU9/DjwCLv1+HcYwRwMkYwFd3dG+XkgQ2uj5H4ZW +iQEcBBMBCAAGBQJV+wjiAAoJEE90TaH18VOBuSQIANeu+vh+7SCzhR1lRtiPlO9c +oDsQ/VXf1V0nLSEOIFphPy5exOeeb/1ReJLzLFEllVblmLm42wnWjrQVPVnRfBkQ +xj8vt7SGlYH9QnvEDF/ewli1BKOZcaBlCDrYCa/MX3kwPl4H9K+JnwujgSQInYgG +ploXiimYqFlzxiGFCqfB02q2QvGDXxXxDkqeGIj/Ari9JYAPwtubUPnoWGPz/Mnb +XBzGaesCFPo21us75cBHOdDQVFdbQy0ppBMK4PEdeN0JYksRex3hLbMSnHBdu0He +NfgTPqqnD1TufBebz8pvNqP6EkvHud614bzTpvY2AYDjnQZIEjqr2bwJQJgJW7eJ +ASAEEAEIAAoFAlX7ED4DBQF4AAoJEHfoBoKoPbQOEQsH/jtK6ipNhgS9e0x2xwia +/+refQMsbLdA/MEQzb6GRr67rXXu8btMWsXorL7/P82WB3OE2nZD0EpRGc5Gcvjj +nMPSGvKMM0yhdELZm3uwAteR3bM0lCRApOcWMwtPjiJds3kZjCIDH0OEzr/fpRHR +4jw9yWJi5mLdHrpC3ATssV1bumfOyQHUrZweZAiI9VkU3wO33epHD6m/uryttlqQ +9nCsPnskEtle8NSbLTzNjNd16roXyQuZbHwxFBC5sDZHUi7LzJbfDwCBjmRLVRa9 +QHvOtCcb8sVXhqg0EdHORlc5wj+6TBjFJ57ISU0YUo/07AiUWyKwFrKHWaY0NyRF +r9qJAhwEEAEIAAYFAlX9oZYACgkQibu4Zj4uZc6OZg/9F+iMKDjW1sSIS/mrU7M3 +UWerLdGRd0JVTuGluUpvyi4UPQwXbtPLi1r+yW1X+YuzvSEOZEQQgqpElFoixvzw +dcdsbfIn40rn3vGW2dOOEMm3lemK3Y2eQSn+4sErW6gzu8uf2EgLHWrbrhOJbS9i +lM22xyksmr3NnlY9Jemauhf7xX2S1xg6KsLCqGOqEn6jhRmLM+OYdYuSZ75t1MAk +dheo08GbL1Jdu1RXw3DwS4soY/ujgbAFoGkVzNv5cEgZ1HnBMIVT7bFwbAWCP64L +B8UToCoEWCB1eNKxDI44NHMbwIBu0JdhCM7iW0GwPOVaFjTlAXDIsgrqqWhr+GaI +vgPnwi1xv45HpB/a+zh9neFqL7uZDocU3KXEUwVCkaP0t3h8/vN4J+QgfCVwWDRP +gQtj9n2oDkM+DqbOSA73/O0O68oBAU2Sd1yJkRutJv5PjKUf6gcKeedtMrwWo7Vo +QrPfEmgWvCoYXs38yLJu7xeKr0h5pAjUx5RhUngeHdkOwxPPOoC2Q8BON+xT0ZoI +l+OO3imgIz0Bz7U4UUPADgCFw+GFc5tqPMj1OVDn9ysQYP7PfUUAwmHxJ6gvjUI9 +ttHQH3ZK11RTLCCN/YQCwlSjUFbzeR1MvaSelrTnSypG/P3C76eDUT3J8FT7UKZw +c9gsvZ633NTfRRIKh7FInMS0K0FuZHJldyBQb2Vsc3RyYSA8YXBvZWxzdHJhQGJs +b2Nrc3RyZWFtLmNvbT6JAVYEEwEIAEACGwMHCwkIBwMCAQYVCAIJCgsEFgIDAQIe +AQIXgBYhBGmaY+/BetOpo0z/wHrQqRxAvQCRBQJhAyq+BQkaVxNNAAoJEHrQqRxA +vQCRYzEIAJNMMqFKAHCWi0npDNjaRypWT+zvfbXfnYEctdladHbrs0lGEHzMACeC +JyBX9JOZbkp9AFNmLL7UvFlzLC1MOQ/tp3V8fip0S10lBUkWG1vtsgeM3N9ERFAz +3brFtM+h3l9wohfVWwpY9sLzCWJ43QlBN22pjLcpVJGyv136M4dcfkXWA/csQsuq +XjBt7P4QwmacISnL1KUIJMgWBl9CM1nxiANMQx8EyCINylEu/A9qNy5OApkRy33v ++ww3kJ9PR4hzUDkd/s+R0PevlzYaw+rgdmKET4lh9J8EarSYu7RUG2NimKhzqweH +aLo0OYgwfNfpKiFKNNaZ07NN2MAo3ReJAhwEEAEIAAYFAlX9oiYACgkQibu4Zj4u +Zc4M2Q/7BvWr+ugC/ZJONikubDkn+nJ/TVxl1CBciMWsyJRI/RKLQQcEvY00xIdu +CF2iPvaqlIifDo6suMTrAO0L6wIWlovICWYak9n2RrsN6w693ccj39MzAd3EwaC0 +Va0YlcNFz9pIyqQtRzyzEEXQeBti88RJvwlMOa+3hganU2NOFerFkpIJHBNYBKQR +lnbqWo6fc9fWKCmQI3Chtkl9UtEslBziaEPILPsphfdW82iSgCEsKTN2zoliXZtl +/P10J+2yS5dO7AjMHyVktS7+idR3Qdde3l0W/5uw9Af+DbBTQpsvwZPRhakWa98m +nEiAdSWRwmtBSDxHQDqSdhtMq3NrwmD9qBpQphFfaGM+267wmkM2zEcM+Xc9EKEO +6CnR+RBYEnmvSqZBiRPB8cN9UfhwGRXzXh+KoDyZCK3i245LBmA2du9SvLPlD5zs +3WlYsYX4XsCDT/DPRGMkQmA1P582Ygw4s+GCJt59Ti1ELzGXiQbaN0C5hgkxk5Cy +IXs9mv2YO9r9scw4zO9lgeTC4Y19C1h+XOTqvUHOfsjVjWr7KuSjtYhKk2PAkJCg +1BO7vFqxTWF34X3h+CjPIYIyMVTQk71x7anLFQdqq1qekGCCJqPQ3XZKNH8nCo5M +KxmHbWzXs+5GEuk9DAUIE8EMVY9dzdGD25gi9Oc3b8NqKgJOrhKJARwEEwEIAAYF +AlX7CTAACgkQT3RNofXxU4FaWAgAiPzsB/nInalQQ2p3FrReO/AUELbjomoJoBIV +QDcv5w7C5RtWvzgy1uJ+NLWlVO5zJKyRcDCllhaBWVpZjqRH6w+zjbTc6BXAMUe4 +da5T7Q2TJvun6oIDmobnySx1MBgvXrlAcxJV+kDWaIgUcdODhdg3ScI14BRoBsX7 +TccuTC3dJ/4DXO6cwE7476Nzt99m37AwV5/z9CvpKiHHzulpDSnvarPSXi/w4fun +7YtzND85qfv1i/U+J4ueYRmPQVeuiAjHc3y+09SCWymwFz08o5qcMoZLdoPlFHCl +oTtxJqrY0PLWFikJlmukIRzmqbV3mt2vpTHGYCO92ty8qCzy0IkBIAQQAQgACgUC +VfsQSwMFAXgACgkQd+gGgqg9tA5x1wf/RlDqaZIRlEIj46ZDPgQ4lGB6l3ycu1jl +W8og2vkoSIuncZhzEasOhleqvngaF2zf5UD6FzTFci4pgNP/oCiuLE9x4yBKnawW +ghJTXsIZ/Jd2ZZkVzsjaI+qQ1XFJv+oL+0GVgJlqfZkunszIcx0uIuqKQVjVzK9b +t4B48u/8Mc11xllDe0EuOoe5c5t++8NtFh3CumU52YfwJYCptaBfUY52yWj0syml +HME8TDYClgMeJQia/6XB+t6XRWLrhY6ZsLHdk7rJHNCNZKUEW8GTv+MhaWh3DVXu +K4DT3ApDtHKkRRFBrAnYrhCikRX5Uwz8hpODc2lPcT/az06MCVvaPLQeQW5kcmV3 +IFBvZWxzdHJhIDxhc3AxMUBzZnUuY2E+iQFVBBMBCAA/AhsDBgsJCAcDAgYVCAIJ +CgsEFgIDAQIeAQIXgBYhBGmaY+/BetOpo0z/wHrQqRxAvQCRBQJhAyrABQkaVxNN +AAoJEHrQqRxAvQCRjgQIAJad9AeZK4LcrUwlhFaWMDJ5UHVGkQQhwqN6X74vmRe9 +u4038wiWbhYiii352A0s2Pc3i1dqvclx4BZP4CPRJ22p+MnTY/jkiLUoO0+B6RlR +ABqGpDJBO9EL7hFCl+uIAXMC+8ydxgRj5Mf2TvH2ZEHIj6bdIC3qwFqoFe/aJcHf +Euy3IDZf/oT+n7JLb6+FK5UTP8fNQVXlYPmuGejRFth/i7kq7IVCJioJ6nDbZBLL +ZxAkG2080MLcXqfci28miM6laIrTbMp/lvmmxAf58XRFVTXlPOfaI+LjW99KbR+4 +PuIvcQd5GdExwl86bARLAlgUjXhLEqelRtno3mtKj+KIRgQQEQIABgUCUPDl0wAK +CRArUtddZVtI3frFAJwJT+mDI95JV97R+cBA9HtBtfxByQCffgr0OgSG46R6UbAi +oMWbYzYkMyuJARwEEAECAAYFAlDzG8gACgkQna7c7cP6Lei5vwgApA/2Eak5eXw2 +w1gj+iiPgviiJL9o+BbS110MR1cn/wEHdkMBjAPX59myWKlPWC64wIvt+MsMrCIN +vT7QJUUBKzOcMH1xoRQ3tY0X+M7bLaD2M8+Kgw00D4eyC8aGtcFKauqWHsbxABc5 +18n8J3dP8oaf7UOqgsETfRJgnD3GZA1lhs8INwsuGVqp4+WoWlt5JTGsrMlDnm0r +dWekcozSKzDZkxTkbcC8M5HEvZypmXRa5hVQ/TIICy1YMqULb7GVweZK7Ma7ZXK8 +AQm2OZ4Jjs6byQX3A9Z3PLJzmNQGdwJ/BSh3pET0YSPPcAPYM2E84PJhP6GqaRTN +3yKcsn9pJYkBHAQQAQIABgUCUSPNYgAKCRBy2PuGax8742PBB/49Gfquv8xjz91x +YPNMbXzWjxhkFaF9JEwnSiGq8AQAfotH0bYYHt4Y/vdukY9B4fnqj/U34aOLr5qK +SkymKII3npVCV9bP5eXSAPbYoCy92jHW5RpnTeR4H3O4gn5ICTWfrdOYq/GH2I0E +Eei2nlW9SdgJRTq8AuN5bwtzaeS1gvAQqQeABq9yKUOImggHViigiL5K/55xDms/ +ybgNIHgFA2yMuCTZztiyuVi8AiJHWreeoJW3Cyo4QYx67BOCIEgHYRnF+elbKbF5 +BBViG8tPwDo/QzASBeTwO3TbkMeZsBdw3QJ8jGgW2S5vbWyJcW/nFIdOVxr4I5B6 +98br0XQTiQE+BBMBAgAoBQJQ71MZAhsDBQkB4TOABgsJCAcDAgYVCAIJCgsEFgID +AQIeAQIXgAAKCRB60KkcQL0AkadHB/9V9LW4i55Lu/GSeBiZjdOnkD2HKJSGbvFG +mqT7UEPupBB07v8q9JOLyrDLrxZl/QvpDCTmrmi3NAPXnneILgzoiBJCCXdxM0n2 +WyJmRNl7pHIvGmjl4CDbZe0LnhIe66vam4v394CNsbl2M0I5TLzVmP9Pb+bGJ6cL +M2zhTdCLwfG8IqqjaCf19S79DJwwfaKnnjkv4Sj9vCxKanOZKt9NsR74UIxTS3M7 +FLOK24IUW7uqkzZWsEyU37lVEWZw8i6ov/VbYphTsSwGZvrX5EhPhalQK306esJY +ucTQ+cuQ165QxZRISk1M/teoyhGJP5f+A3Ec0ctF0PO8fbBx1A7TiQF7BBIBCABl +BQJS+Yo3XhSAAAAAABUAQGJsb2NraGFzaEBiaXRjb2luLm9yZzAwMDAwMDAwMDAw +MDAwMDBjODRhMDRhNzAyMzI1Y2YzY2RmNGEzNDQzNjJlZDBjMTllYzgxN2E5MDE0 +ZWVlYzcACgkQf6sRQmfk+gTeWAf+I/v9anL0GzK/MQ1v80qysizrbbfrab8vojLK +n/vVqoX7B85uVE+B/Mp9FDAQ0mMnD1Yn1PsWwX3fr4du4Jr+jRXRqupF5GLU5LlW +NfP1VwY/49zUpUx2ka+aGgOCNhsr0VZrqZPt8qjDSVlvX1twrc7P1bWk0Y/e4Y4z +whBDNZ3luge2fakVuxdk1eoLwrgHARCt2MnFkcNm4pZiNyeTnWlDgcKDFatRkXSE +czC3jTC6cLBaOjR1p7lzXthAAlUPbOUcztNCOhjhoEQu05pQQB8yN9lChCachsc/ +oKGEWkFgl4UsuYtBx8iJB8lYw3Yvl2gEOTA0oIyXzKnRLt6iiokCHAQQAQIABgUC +VA9iQAAKCRBQfh+DfBT/qeW9EACWx2O20PEGQA3QpJfXR4ocJD4iXfYNYwu9Du26 +2RKwLLDpVxCgXDUIlH2EfVaQNQF/jatz78UnukPAbCmQz7n85lvlU64R1P1Mv1/W +80f+211mb+K3V6mAE4vQtJTMis7vW+c4lv30QNwkQ9n4YFz9fqfRm3qacy1ydAdM +wnigV/L+M10IRnYMB6A2Z2lYLmvvCtKWkBSXvl9r8LVJRsVT2DSzw4O762YcuVXN +quLV1aGp5pe/8w0DKd+OYJrEyYi1Qj+Svod2J6OEobDTISqBdi0KGujelaDaCDwB +teTZBdjBgWh+YG+cRBoq6jNPF4tiyU34kcVHsZflyNyCgUmJsSSgJW7D4KqXZoEy +WpsIALAf9xCAh16Uj5zyci3Dyk61Gj9C9ykhdEHfONGVhNF9G8lmGc9SGz8lNoJd +SMQ63TsWqxo62D1Ap+BIzr6EImets16gbRs5J4w1bV1g5Vb22SlpuFScE6wRO+S3 +W+onsr3xfj2Q1faUxmFjkcjAgBPMz2Q2RuV3+m3FusI8RgcpyNpCLr6cJD2JaKTR +udiAafV0a2TEh8olN9f496+/XCw+ZJn9zON+1GVzm5cmr0B/aRqSi7nn9sP3P8Va +EDRV1rkcLVWIDov42/st8hR4JNZ6lapfxn2kzMdgQwoT/g9wF4C56kB3600h1HsE +YnQJ/IhGBBIRCAAGBQJUHfafAAoJEKyFk2KwQTv6kugAoI3lvAuQCG2oqDO2/eoW +diHP7pogAJ9xRwHrbsZX4owUHT5frkXhzAkNDYkBPgQTAQIAKAIbAwYLCQgHAwIG +FQgCCQoLBBYCAwECHgECF4AFAlHz+0sFCQWkSVoACgkQetCpHEC9AJGNtggAoh2B +mpLMurIgXlB4ueaMu3tkskVsh8qWxE7gwOnUCK4SV8jPA1+mfymyBZZbl6BStHD5 +PEw3Ls0TiMFyIML2uAD3vS1vB7HVZTwwJy62FwNMy1Ghrg8JesBlwnbTWA2Bk4kD +G4QVzN9/EGLW7xgHiQUaZieiT5XR8YhfAtmH1ZSJ5xmaRfFrc2fu3uJw6qhs4mI7 +tpSL6mVYET7pY3TaMflSXXqUB3dITBKzXDBaKIdosKfMW+BmCC0Cxy97AF3qqW1c +E/d4bnXSNf4k5Sq5WKTAFQbpDJCQPIWz2cMatKblzvfh0iDBPQinbeAx52D/7rnr +DwakV83cmoxNaD7saokBHAQTAQgABgUCVfsJAgAKCRBPdE2h9fFTgcEOB/9q4au8 +n/tY/jCLo8BLxYVRstSdOBunU2M1lwSZXQHeI955a90gxd59EBageWu1HisuUW51 +mUF2uZA3Eo/xvTt5MzuofP0WQj+PofTr1BHws7Zx5lr83XtnlS8H7cpwI6SmH/dp +30HwwiKnvW2amBATlBawtP3md8UGtNk2vHRjV9qtnpzgPFKIl/zKlLaJZFdQs0Bo +OFyHLADVuphgdQNQBsg+wGK7Qhz5jpW2dJrEpNg+U+Q1VCGGIeew/tCcFJrLaqY+ +2HQAkb9RhkqChpOsGCgcTloDjq06qtBVNo8J+qp3XSsDl5wNPwk5AQvc0wG1gmJQ +QR+dGScOM39Zt5D7iQEgBBABCAAKBQJV+xBCAwUBeAAKCRB36AaCqD20DhjeB/45 +Tt3rljXIIKWhkTsRz6fmEdGV7ShL2BvRBv9R3hA6C7vAxn43sVMXYc+hpNIdYZQ9 +kPiuOjGXk39ZfYUeQZCq7R1E1AuPdoMDPFFKC8s9mkNcn/iq46gWSzQ6LQ3F+2tu +7MWPErvcRv7EaFC8J2bgXh/JaOw5bB9Rvh4Zy9ndHwmsPhwaWZ2Cnx4yEU7cFGDk +IOy++PXZx/fmB8knGrgTbYpihZGOp4w7I12wQGrG/noyklyHvikmJvCoWw/k+L1p +2SEOO/OMG2kGz9/oVbQQ0lQEIp21Pxx97vGNpEp9MTGklCLRjA59IE/lAYUeweCH +ticIjJveWHelks918K8siQIcBBABAgAGBQJV+wPWAAoJEGviztFKmRe8pyMP/3PD +Ra5dQO6kK7gxyEzRV/Wq0wnhdSMx2hhsdmDko1cN0A1s3Id/y7kfjLROW/hp7Thx +nQq5iq+qG4qEjnAqtXeskQ0c0Vif66Q9w+v+PtOAFal157jgw/Szdf9JCe/psBP5 +BMHZT/YXxkA6TODSsVEo7XXgJgvzxwTdviM+j3ZTggFhDVI9zCr2akAniDFsCRRK +8YBp+LPqXXeBSpiCy4nufiaMNiGZBHnj4qpY9D8AsbnqmNYF2FXdOKEKu0WfOCRl +IWepjCICzWHYpbU+tUKUY3b6wGB8wIlw8SJ+Vi73gduXeBLP9CCYzXrIOayamYOF +TgVMOCBtxAPGK8/ZjUCboSpOh71FLvaAZYXzmyt8tBBhT6JIUPu40QFOPXk833+3 +3QNbl5Zmn4pG/NohHP6jhAIBNo6d5Nndf7HTE8/afNUvVtZJLtqPSX2Na9h6C6N5 +efILyg5rfD+U2D9Aa21rbzIyxB+pqrj4XIoKuVgPLA/BVDK2yP9WB0frzN7Lv8Nq +0msfSzuUi9Rbb1cACv4GVKO8qdODktyxfbI73lq/3tbAtetbGbvmiox7cJLxV4Tl +Y8F2CgN9FAyzbjH6oGm1pb/1O4v7Wl1BwGeuyKU+7v5V8iWUEOUR0ryaezehewdo +sqv+dc48vMFKqRU+U8R0WPiizlPqMr6f7oqH1k9uiQIcBBABCAAGBQJV/aHKAAoJ +EIm7uGY+LmXO4FQP/2NSN+RwCrZJLa/3BGeOGfrWaScWLIZK2uDkA0F2IBSzxpAq +bAIrbAq/YtxZ0r8mA9/eKjHATUGzn66ZIyi6ctJCbyZ936mDdks02y4+yGd0o2ME +DNO5vh3HqBjkZX5wHS53VRCWhA3cjG6A9Yy7DB4fY3G7cSAez5TtNOq8YJSpUqEj +/iDs1yXL6R7qOtZ1+s6o+yy7ZujuGsnjCSyvQo0lTD97croT7EwJhVGAcVDADcWS +SZVrQQFlHegCpVjgQepPzUJxYUSW/zeZszQ/Xi8XeaeGjxdZlnoR2nuubnkL25Ok +qbOnBx9sEQ/A4BnSeq2ZmaMLayCTCctfytlhrA0PWaf+KmqPLLsDJ0pQxSr4xJHu +leUhq6k3aeTXODxSH60/rQRgGuP5oBZHepymhJ4al7kUJ5Cu3m4EQ5HOA7xD1Nzm +jho1+0QnIyde0X/ZCKHudNnMwyn+EBpVE4iskVyXVF5PFcBGZtbgMf2aIzMFiDqf +7E3sK1SvuVmG3i5qDc5DihPcxdsN0UTzH0ycuFXiYgfFBQw1KV8l15QBN2JsN7iu +Cup2QbRdctbRzCoYqTWhBAPSP4GA94X1rKEGQuoiB6w7pHc7VdQyVUOHh2KrKBVF +t7Vjcv1Zuf7/Dzz6cdydihaXtOUS1zrZm+T0NzV6oSvW+pq5Appaj3K4xGW7tCpB +bmRyZXcgUG9lbHN0cmEgPGFwb2Vsc3RyYUB3cHNvZnR3YXJlLm5ldD6JAVUEEwEI +AD8CGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAFiEEaZpj78F606mjTP/AetCp +HEC9AJEFAmEDKsAFCRpXE00ACgkQetCpHEC9AJENMAgApv94rvW2PKh6EpdU3AZi +V7urV/l7l1hz0dZfNArzo9mn0Sqh9VxCa8EUytUmRzc3s9zFBHV4Q85i1iqLS7um +9QR/boBRZzsOd3WBxFYKW2mGybf9hxBlBqILPikiw+7wZv1WdDE82x3qBQE4HiiP +QQ0QKXtHf0gE8Q7IBneWQGfIP1YE32AUUWH4FK0akH8wT4XSbSo8qggcHxTJrsI1 +c3jnh/MXJtBm1O1JOfJvfCSO1GBx5Lw7cGmOnPElm1y53kZ0cc97+sk27F//D2Rt +30oRI62VXcysOENWIxBWgI5jMgMQeLG1A/cOcs+qXmZ4n7rRCM3SVM71MNgh5UFj +W4hGBBARAgAGBQJQ8OXYAAoJECtS111lW0jd4ioAoKzv0zQN2vCltURI+WsjPT4p +OuWkAJ9SsVndSL8jQ+Dd5CzPMkNy99wPU4kBHAQQAQIABgUCUPMb0QAKCRCdrtzt +w/ot6DYvB/9cCjJIQTkBc7GxX8nOpQPnu0/QpK+zbJTPLuYPi/XV4XSq72Xtm6ug +Ygv5hwTHMkBSP/4sshFGykx/1055bl12+MQvMYZpnTrHYG7hsF3ob25tcU/bixXO +fDwhvNrY7lM5mHwd7S7+NCHBDdbh/G6ZRRuzdUUgVvxvAM26VsKOS5aikHSaqk9T +Or6edk2wPKl/49glspRwMebppCPVQcwvieK5e8v6WO5L+/5mm5h8Zrpk0fOjaCyK +PPO754p1GNHSKrFfVNDNfMMTY8rp4XjBHHRQw24Ob87kwrctvnkr0Gatih9kbJUW +oPwxIeN1TnU3xTqdag/WNPzjWThkFEEbiQEcBBABAgAGBQJRI81jAAoJEHLY+4Zr +HzvjFBAH/RnY2TRoVfoTF1yjZYYVgIh9iuqVKAolK7oM7TGiNRRjR4UzhzGRTabJ +NlCuKnp/u1Cmng2Gt7Sl4GdIIW5TY+RSBcqepTOz59YyvCZA0pGrAghQDJi3imSw +gc5s53NQtgB2IUbB2mt4p9sc3WROfYiBBYEZWXXCN6r49xDqgs9NmLyc/l2nrG8n +GVESgZVnLtmYi2GWjelqwZwn/a+Lbk1hveABN/QjP+0eehxvPdxdxCpovSrDHRrQ +W1EkH/JA02/ziZ0cLqqLMCpR46QIS7Xkh0cWuP3VXJVR6bT/YqZw0dgKN7M/C1p3 +t52BAeox8gXSkOKS/3svonOpKFdLKbmJAT4EEwECACgFAlASGPECGwMFCQHhM4AG +CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEHrQqRxAvQCR2LwH/j11HbaHIlQV ++D7hK67nMpTdl5ZRcK1flNJFHU3jcqxDeaXkHWMMoZqvWx+sbXCOVA8+WIn3l+Cy +clSvGN4M0qEu4hOSbCRdbuSOFUV1sYTxUHdTtocCL/oSGAYtdtwTKMYCZZSMEwiL +fJkrojZ8ceQ5LggqoMK1s9uki+U2fO9FOJXWa1SJB0dq+lNMpGVRxRHGgqavhL7B +3l45sKXM13ynrIaa1d1J9Z5+skbU+d4jbAv+wYAqaDkBsUgXxrdo00UZWKcQEgON +2hcemz0NLI5acFvH2tzoNynWsMgPVVzQ6v0HIMEk+hA4bNh84sUq3gW5snzNN+yi +VIogALfOjGKJAXsEEgEIAGUFAlL5ilpeFIAAAAAAFQBAYmxvY2toYXNoQGJpdGNv +aW4ub3JnMDAwMDAwMDAwMDAwMDAwMGM4NGEwNGE3MDIzMjVjZjNjZGY0YTM0NDM2 +MmVkMGMxOWVjODE3YTkwMTRlZWVjNwAKCRB/qxFCZ+T6BMMOB/9xyr3H+x314Aiw +y0fl3eYFhX35L1+EehCgYMpf11gTzRIxiosbEGxjGXqaoWhNu37J4cpfApsPwOXM +v9GMjLQE80hHwuAfh1jYO/gJk9dutrVd1OMpv6Ltk7c7dfK48LfKAystWpTf8d3c +KaIRlucvQLEmyhT/aYkTb0u3N9DHNKBvbBeHRqufjnKAIYShYrMH1UtWpFzf3IiH +5ctDHk/6Jsv53JunvL13sUKJ9pyqa1wnYfZML7QhR7eVr6f0mn9L+75QfJZznXaF +DEn8yt96yZZNt7WQAp78HUu6XcbnRIeiFHF+XhcsJCrSfYGLmg0dkUaofVFHh7mr +n4WXfv/ViQIcBBABAgAGBQJUD2JAAAoJEFB+H4N8FP+py5wP/1/Yy4DnFr3IsgRq +noTuEcFI8EpXkeycORoZi52EOV1KIY2Eff38ahAv35O6xtSKiYeL8vycBZJLWqZM +w8HyYZa+lyUu/gmO5fUyQipxLCtgXt3umoaYSIWoefnOZxmyUA2Ky7xsmMeFZD/Z +Si/wc2cwVfo5/xSTF1Z6E7uYQTdI5kV/E4xIJGxYVqAlnuK/Z6fVJhjaJSRN1bOJ +yV6fDzqZDw5L/qe94bIRRhThoapHVe1ogSfuUSBjHq/R0hG370UsnOIRVhO3hCSm +qpNVm9AeYWKtn3j8XXgIr1UfIduKVo45u/v/eBTRYeZ5bptEDFyBYDGHKv10xkap +Ma85ggtzOU32Vio/9XqCSPGumUQe/Js07/9bROWP09if/fsyGpyfCO0m81gLN2zV +au39rKI9jPRcApawa4H2stUBFMkFFm2cw3UwVJfE216L4r77X0tj2um96agCy4wV +BIcpHjVK9Q9Wx5bjRjTP/WbVBFg42X7K5VU97u//xCuCYWFH9JRkFdalwJhBAQbD +6vUKyTJMOh3Q1kIJgZW4BFFqBxe0CL/QQfRmo0UHxe5XrsMeERKo0XmAncInCgYd +kUK4xfMEWl1SNzBUSPFHMDpWKft8bczcfhXdX7DRQMxKIYBYFUZHnKPM7STVGDa5 +k300Ew/f9io46wOU/YAMjHl6r0BViEYEEhEIAAYFAlQd9p8ACgkQrIWTYrBBO/qn +vwCgxgz0DNQN/kZXpcosUwzMui4DBZ8AoLa9dpon/9lYtyVsj4YYepkSsKS0iQQc +BBABAgAGBQJUKM0DAAoJEL0ClCQh9IifNkIgAJn9Kk7FURHWg1TSiXXbINBl1AQA +5QKUPp4qKiAT5ObGhAPJ6zcWza3Kq4D2XYodETKGR7YM3CcYJlV9s0/JxW/KdAC2 +WnnSjmWhL+1wrw+E7hJFF7Rm+nhZR8eRjLGFryJxu7UQ3cE9EzJq+s9WH12rPXAj +clME2g4Idf/BYlIVdhROK7qI+j0f6ez1JpTi0rK1emXd2LOjYsf+ZvGEeaZua+3R +FPVGvIdAxCHkYaYAmmRQDUnZm29IYFakEfMHRIPNfFJ6vYNGGypSPozGhO0cen3A +a6lcTJ7Yq83TaF7+vDaPMhWjheImeu3Ku7FQGNKMfm06N5l6LFMjDnZRPfnsDfWs +5atpxPtBDBm7d5v2uVOuKXcNdelTLgIoLLHLU58nQf3HocPJecdWFN4PPcbUwbzX +LodU/TH6hG1a5U5Ph0TO8Ibhp+ui0qJB0StX47k2DK6tnU/c+qBtdZ7BBynnTscD +KfTVyMu9GnNkRZZX9XCq2m/f43UVktS0G6Tbh2G3lr9rm0NQHQn7UFhv4V5EI3V2 +3Jm6TTKtuKaUmqKTXr2FE2lKaWAfcKU55EnIzA71ixRQAYTvkFUvONsOY0vV0HfP +4VBnMYhPffTmcdaMsOqR1W2hYKAh/RSgqal+6GKgVqmWoICIWmg5FpUVmlE5UIU4 +T9Rb96MDfl4eM6jj2ED6eq8BcXnKB8XTQcFzNaAGtf9m8KA8Y2UC/enD5BWuwHLU +Cn03fJo4ouyiBwnEqd92cyfi0oCGspl+NFeLDmDujWKXdmg9zklroH9FsaFNKbpm +FhhghA1D/ALd1GxT9u4WV1DOg9i7gXM9aK4Gnmk8xbdPg5LZfmUNP8z24fRwtw5t +cprp8GKGYNj0euVFCp03X37HIy4RZkCMEQvfDDJsaE8HG89w1bfQpZ9+44aZZ0N3 +S4j5gexBOFGquXm1KcPsuQQxw4B0dSp7aSswsZnWsl5lP2Sul8TAxZBLb5GhzJli +z51X+uKQkGUMQZlDD38k+UAZHnA1DBlDmvwzgVqB7N7pCjifaqw8+jsHL6QqivSF +8TsEFwOQ1komff5EojMJjim+JThUovJzYaLu2U95acGWhqaoEkJzXKCPkGY7M/Fr +TFyyclZEymkDQcTWQIy2j5ZBEfywXwzCFnm4Lf/MxZ28R5nLv54dUwYoYlGmWpUw +rc2r6r86pTrvVFnhFrC4DsJR2/kr8joDR9ifXVeS2CYU241Y357xT7yskb4SMrXL +N9WBkcm5XxrgdAWOvLfOXiocjjLQDp87rL67DdQIlMFAjsbnn+fY/HWv4w/M6COY +OT47WQVcXEGO+G5+vBEgg7ztJGwXXv6thcZp8TTpDhvhnKYQIZe1hvMUh4eJAT4E +EwECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheABQJR8/tNBQkFpElaAAoJ +EHrQqRxAvQCR8dgH/3C4aYaG3376KD/fEpIYAZk1eK6iejhlR8TTpbNZAtDQVn5d +pU/8xjiNCsFa7oGWibPkIyJuhyu1BQdGEazH2x4fKjbQsQlfG9hMVDM4pNs45bzY +f1bqzrIVEhxcJF6zSU6nhTpbQGn5cTj6h3rOvx70bX2BLxtHkzfkAhBEbyNptHzw +TH5X/f1LeSzu2r6al5/wqxL0/MVerRuGmRnkqHNvfjiG9Tx5RJK4dGX2oh2YtDTX +UAfQoYb5jIE6nNWxKT1mUidO1Sa8t1KOnSwjHgZxZszFkpXCsYC5hBicUiWUtatv +jNRUeWiMLiYV7NEvOVfnkhODCaXFgarHP8wnlziJARwEEwEIAAYFAlX7CRgACgkQ +T3RNofXxU4G2Ogf+KQ4Sg36PGVmLbRj4lIMdvI5MM3NCLkcEdG9KKzS9fKmfuFco +H4xPfhdrGWghuTS2WWojKvKh7Lz34D02z0Y8IevVrFjdXhMv+1KmIYqVjS7dvtqd +szVVJEH3FnwyGb5qNDKB/bKgR5GnaIMqUeiFxeYjHOcUCWoka549CSWCEfQ1U1hV +dz3g/Yul83qbtRmt6bVU9UBUh5XntbuMpC/g4cMK/Oa/o7dcta36tEkIx/hg/PHu +J/hW4hlIG7fFHlBQhHZzHnCgsw5xazeMzSZRP0eClxq1bjw9ZVVLg6ysIjHRW0aq +W17LYUwJ96MMR4KUO77zANOHweDsb7Mebgs1D4kBIAQQAQgACgUCVfsQRQMFAXgA +CgkQd+gGgqg9tA79Swf+Iz1P/OCk4MmrEX6pbYVkJWSfSa+7PMfucdUqF769yB3y +3aEdiVKZ+/hDvAGT+d72kRrnGNGTMn2dn+BpuFFhRTKHQdt7TWkVV2CXsitZNGF9 +iE3fGJOuwm/GMOLsE4p1qweVAxHIfKqh9ta7EywATLx4gTDzKKzJF0fXwW4BQZQ2 +d63KpPwqRlgK5QH0HDDxHNCcF7s/kEUtoGsFJZVUJeHmKdX44Caldnhm4qcKU25X +WIr1MzymfRLNh4GnsnY1Hf9pOy7QYrRHIzsqtKyywD8uaAOIeQlaT9W0F9dKWDyB +V4PSaO4HriXVSwkE38Vk8Kle7Gf5J22zDamNY36AeokCHAQQAQIABgUCVfsD1gAK +CRBr4s7RSpkXvDKsD/9QJuq6mVxtdhx6AWLx77P5O3klZjxube/jegLpKSp5BT46 +WsoDtxwcI4qCEpas3HTYyRZLDl2rRQGHA+pB82xQNzjWuyDiog6Qhz8lRd6hZgzD +bCm0ZsXZ1WweNp9IFxJsNTm+kCruIcz8rr5P0eZAn6ogCA2U7k4pykmwtj9WzD7l +3tf2R1nVpfl254eIFUD6SqgVLW3IbWZIG3LxANAbUFP+NgQMw5wQB1iZRV3azk7H +Jxp66d+Mtqpn2+m/SIjYAU8L4Kbu4y27aUuWJ6iS73BOSQRM7+aAP5NZLCl9OeYz +ZqlpZHzlKJuTrU57mMANdmu/La8mPMwZxTDUCE88r1yfEduqqq+61kIod/BqXaYJ +VycrXcRC9vTxFKG0gq1D33jziig0m68tEnnK6g2iV0oGhC5ORWO04XywFqkwAPwM +3uNDWMNF1FnPD9z3mHw1FtJM0T0WNxXrOVkzXaIQG9lu9g6yh4+UneFrn+kmnthl +ieKvMv/D5mDk5x4ipKbgTQjiVdRu+CFYsIT01oi2JI4AsdpFSzWCUVDvy3ORMOZc +OLnTE2Sj1MY5BngeTlmNCSzchnbsTNcVkKxvSIK7pPpmg9A91RcZOhGran/P7t6m +iWsH1nxuUZLhz3vvFjqFFKO0mBcWEGF4OAQviJPt8xNzpRJXYwfXVcHHr9naq4kC +HAQQAQgABgUCVf2iAwAKCRCJu7hmPi5lzjWEEADDf+kXBgFdQITZEVWcPjtS/mlN +OH+mu5Zeny7UUu5KPrqSy3MBDz/V+k4KN/y6FnT0mkCJVIOENysGF2jUbuZe7Le8 +/Lvpgn8wJ0BpbqkvgC1pxy4eZooZSKmO+xjomA6ng6pi/CDC47TCouCm9hhhuyDO +lsm7hCVLILTNH7TVrAKtBJacHYQmAdeT5reseRJUCOaE1Crc0Y1yqasUoByPN+ja +NoC6spOsRDugrNrXCzV2pWAlO8PidDYbhgYWJN/vaaAqJxqky80e9l9RdZl0SbZu +bta1g1trkzbGRxNNhRSdXiLxfeEbFkKrsW2VbiyWKxgKqxkb0k1b25AFOaL4QKRc +phpfVPK3mthha1GaE5j3cYyuFGNViBAaEkPpBS0JOmt66+LIjx+tZ0t4rVHG/oIP +GdD9QMvToWzxGqTI1zjQtcJpud84q0zTokdzKhfZMdc3fC8SJWKhrpUYHlC311Jj +if5IU2TDfPWIQ1Oesz/OcfAxjf/WXBijYj0obbXNkYHqtXKmBg4NQn4yVF0OBpUk +3MdbWAVsUH6mNiVTA16tLPekSr522u+pCo24zQF9RhNOvtrxRuyVjduzzYjFK+kG +47UgZBqjg8gOZdFh2tdjeuevE4yuxAmzcNYhCYLE7czMz+7br3qozHKR7/PGfcqg +WHy8x72OCoutpA1PMtHVydXHARAAAQEAAAAAAAAAAAAAAAD/2P/gABBKRklGAAEB +AQBIAEgAAP/+ADtDUkVBVE9SOiBnZC1qcGVnIHYxLjAgKHVzaW5nIElKRyBKUEVH +IHY2MiksIHF1YWxpdHkgPSA5MAr/2wBDABcQERQRDhcUEhQaGBcbIjklIh8fIkYy +NSk5UkhXVVFIUE5bZoNvW2F8Yk5QcptzfIeLkpSSWG2grJ+OqoOPko3/2wBDARga +GiIeIkMlJUONXlBejY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2N +jY2NjY2NjY2NjY2NjY3/wgARCAEYARgDAREAAhEBAxEB/8QAGQABAQEBAQEAAAAA +AAAAAAAAAAECAwQF/8QAFwEBAQEBAAAAAAAAAAAAAAAAAAECA//aAAwDAQACEAMQ +AAAB92NAAAAACFBBUiigAACFEKIlBGgAAACFAIQyQ80uztZDoWkKAEKCACLFoSLQ +gKQGI5r41zAzbzTRQdz23PSgJACghSBqBBVliKARzXzZvmt50M2CWalhDR1j6Vzo +tABCgECwAUECkeaXzzXIxoOdhFZSqKQ6S+mTsemyigAQoFzQQoIBlfJm+deenOwE +ErKaC0RpbHoPoXNoQpBCkDUoICkgMS/OmuOksynWahiyWalENEBo3H0LnrQQoIAV +rNAAiAcpfnNYoUKklZs0qFAEyU9UnvuVoAQoI1KBCkBmPLLxWLo2QhDNQVUQqHCw +dY+lc6oCgAGs0ACA4xwzeN13jsaMmQZrFQAEThXG52v02elICwJQNywFBAco8udc +rfbHUVkzEJWahAkBivLYPoM96SBbQBG5QECCuceGai++NCsmYzUIQlQIIeWs2eyT +1ayhRRYA6SgSLUEczwTVX3RohCGKyASoEA81c7O8nt1kVSAqB1lCIADkeCa0vtjZ +AQxWSUBEEBwrz2dD6NzZFosADpLYgAIcDxzVX25dKErBDNQGUwUpTjXCyJ9OyyKs +FAp1lRAKQrzy+FdS+6Olco41zOhslZTkvOrHU0mDz6nRPdYktItoQO0okACJwXwt +al+hGU4Lw1Odu5fXmWuOp51xcxPRNdIh5dTZ7mdJQVVIHbNEABDmfNa6y++ORyrz +6zlbNezM1XnrjRLXSNwPFqeg9bNKEqqQO0sikAIczxNJfoRgycq5LT0ySuFc6sU0 +mgePT2s9GatoiWgHaWRakQoMnGa8i/QgczFZOsdKweeoQGypDz2+y86lUWiJaDtK +iWJRAQk145v2M05rirHRBi3hUQDRUhxt9V51KFtIFB2lggCAGZrjNdkpk52yOiBb +wrCCmgkFdbigqFBKF7SiCBACS5m0mqhzXBoydE4acymjSEVqzSVBbUAikveAWQIA +QzLF3BeZAZqHGoaLGrInTWdWIAqgLAl7xBKBACEJFmkuTFCVzJUCI3UTrrNQAUAA +L3lgEQAgIBnQyvAlZusGSWak6yKtne5IIUUgADvLFRACAEBJbLlcVTN1wXNlTciR +WrntcgAAAFHaEogBAQERLZqRm2GDlUqlSRK6WdbmoAAAUg7Z0BAQAiRRC50jKysG +KyUhmym07ayQAUAAV2zqQIEgBCKIXNjWYtYMVgGSWbWp2uLVQAKQBTrnQEQQgIuT +CeLc9GN+vGuBmhismKhs2DV59KqUFAAB2zqECQHM8+nmshisy/S579MsPMcazWRX +STa2IeXpjNz6oho9EUtIFXrLJIeauFcrOVRFWKrO/q89dCmUwcreVVC2JUTxdOeb +BSGo7r646AsYXyWcKgSVIUNFlZ39LnrvComTlXOgVErzaxw3gAADUepeZzIRFACA +GhCb9vPfryqKyc651ASPPueffMQoABSAH//EACUQAAICAAYCAwEBAQAAAAAAAAAB +AhEDECAwMUASIRMyQVAiQv/aAAgBAQABBQL+jZ5DkfJ7+RHmq+SJfZsliJDxWzzZ +5DkWXmpEZWus2SkPZsjNoi76uIyTy/XtQlQp/wCukx/aby/WVrrPC+3Slw5F50Pa +iyDtdGXDyrRRWzhP30G6G8kjxPE8TxPEooooooazi6adrfmPKK9UVnRRRWmSyRD6 +7+Jwz9jxuSGIh0J8Mjyt1kssPoT4fEBb08sPnfn9XxAW9LKLp78+GR5js2eR5Zyy +j7lv4vB+x4HIcmeTE9DZeSykMwud/EX+RcjGOZdiZH2MkMfoV5IlwR5W/PhmHySE +jEVtISIEiWVWKNZIlwQXQlGyWHRDkeTKEhIkMrS+P2PRmf8AS4zoSylrfEeeiyvK +S4HpY9TK9rosUfHQ9DH/AAODyybL00V1K1vWv4a7LdHky2eRZbPea57NFDWuPPbe +uPdepc9da77TmkTxneBJvJ+iyy9CzU+i5JEsY+STPOWVGCqiNWOLWV5paJ/aMnEW +Mj5hYyE72G0h4yQ8ZjnJ6kR4zocUVqbt6LoWMyMlLRLGSJYsmXsog/Wh6py2E6Fj +enjSPJvdw3pemU93/8QAHBEBAAICAwEAAAAAAAAAAAAAARFAAFAgMGBw/9oACAED +AQE/AfJx87fhr7k1M81ybcYHKMjUNE0ZjRaJjRaJQnJpzk+2dG6NsGjOxrR2ujax +2LXOte3/xAAeEQACAgICAwAAAAAAAAAAAAABEQAwQGAQIAJwgP/aAAgBAgEBPwHU +ns49WHaztqi7rLdDxz9TKeWcoouTYOFFWoouxtFaiqNgGQagLf/EACAQAAEDAwUB +AAAAAAAAAAAAACEAAREwMUAQIGBwgFH/2gAIAQEABj8C42OOz063go9Ez48ugE81 +IfBLoK6vhBkUKBX1BXyTtBx4oltL44q//8QAIhAAAgICAgMBAQEBAAAAAAAAAAEQ +ESExIEEwQGFRcVCh/9oACAEBAAE/IfRv/AoUbFpXZlhhC/YWRYmOkxI9eozudIxE +B2Rg2J0McNaRYvhS79dVlSLx7Ki50NlsuOsFJMvyd83opwhiw2XY3oYIbmxM/spw +rh15/nA1sxYy6QnsNbk9CVn8Ev2ENCY3YXm6jUNTFTHZjErEUKhTVH8Mmih+n24W +2UMJUUyhwJFFFGZRR4jnrhQHPI9lkrnPngtU4pGVD8nXDRGnGDRUGHBRRRUXfkKv ++jlSNijohKk5Y+SWhYPivQyDGZ1lj8OgmYe0vnoNUbfiY+NS4IevJ64bh7Q242Pw +rFSJ+JnXB3Y/BiNODcOcIUL4EaBa87UbyJjQdFULJKxyU4LBpCnobhWRLQSpDWOk +VdCcNRVBBqULh2ezWxrFDi08/wCoxksWrBlvIfgHLaGNiVI1kdBcsavcjstyxeej +ku4MVhDQljOUqk2KEihI3CCYx4X4EyLFoGhjYrSaxRUKN0aXn6jSxXDGShCjQ25L +aozstGniXPNUPbKWoITjTgUuFrw7OvBZeRDGdlhPehvBQK7KFNmKm/TrAqCGMqhl +DYGJcdPTehDhnQ3DQyioUpj0e+b0dZHwGVi8CsKMvSfRwuDhQwDUJemOXvg5csNF +cOzb2FwfAy/RvkbPkXxN0JljY3Jsu3CfoPZ2OPg3lGKaDNMQpssass+YaDDY2WJ3 +KrsqhO9PyPWDuOjTgla39Y/zP4Kh5iFZmU/YRsawbaLFm9FO+DhphlDKdjI5pQlM +ky+e0I1wb0SN442MR0dGxitSxo9oQ6KfhXBuslw+KZsMV/QkxwdB2tL4Nnt8WKOj +cuWWPlZ1PA1rTPoBjWB7zDfjRXgTlwcs6vK//9oADAMBAAIAAwAAABAkkkltLJaZ +SQQAgQKTEkkknlv2G4nRAAQCSbksm029R2fvggDbSaZN+r01xjaola46STSRL/7f +l1eTMsAQHbAAEAbNZtyuQdrMH2jAQTTaAlP3aXraL4fEmTSbaQKC07PWf0eRFQsA +RSZCQSbPI3KaXlfLSQAACACS8YDZKTJXccLW7aSAQFaKRYAR9lSh+ABQBJA1DCeJ +aT/64uyJIAYRVpbdlLQFuH2gmbQLbI+STss1d9DwORJKLbLVjBCKpfrKHz1rZBbB +AFQIUoVDLY6e8TYDJb2qPOTYrs9EbvoLZbZY3QDLapMF7hZdBYZZLVQBXb3B55Sf +C5LDDZKGzc3j9arpfrS5IK7ZY4DBPyT1dX94bJCbLZJxeJ8DMralJrdoCZZJRi7T +OqCsHPhb3UhLZTQg30hhX0t9LW43JZIT3IIaA8OP/tv/AAgWwwwVi4Cjcib7Lf8A +zFtllBSJQjExW2223tUtllJdGJmYWZG2y3n0llknJM0NMlaw7+22yNt/35J4hjkq +Jo//AH/vJN/uTlJAH1YBivtt/rb18f3uRY6OLQEl8/qd9eM95QXrOKG2msU3kze8 +0pbTm0hDkmk12Lc0ymnxb1+m8E0A2my//8QAHREAAwADAQEBAQAAAAAAAAAAAAER +ECBAMFAxIf/aAAgBAwEBPxD6MIJEIQhOqCEIQuJhoa6Et0NlKMa5UhLLZcUpdENE +5FmjINDIQWJl8aFlISw8JExNWuWEzCCXgnEkLgY+BC93l8C4WhD4ELgfEQuJ8C9r +q+BfFLWbzKGPgWFo4E7h6iCHh8K1Y2ZDZ1h+DwxvgTFqi+D+MwfFSeL1fKtfF6sQ ++Ix+j2ezx/A+MoFWt3eHyr1Y+VCzCCRCDWHh86elEyjY31kLWl7S+cNc9H9P4fDS +lLhBKen7KUpfKlLqhejGutLq2UvguVUpS+a9Q3fT/8QAHREAAwADAQADAAAAAAAA +AAAAAAERECBAMCExUP/aAAgBAgEBPxD9GlGylKUvTdEIQmaJ87KLCJtCQT5WxYSE +JZhNHi8bHhCCLhbsXGyUSghsbE8vdifExFKN5TL4QXDRsRSlKUpS5pSi43wLDF0l +4IYuBiQ/dMYuBiH7oYuBi2LyXExD87ouJkHutJquFlHogw1hZSGHo+BiQ8oQbGMQ +sJzBvlT3N4SF4LifCuF8S4WMu0wvBcL8lskTjg14LZcr9lysmUhIhCEHleM9mPFL +q8roelzdF0PzQud7LVcyQiiW0JqvrhSFnQbg90hMvRfgmSMj8IILFNj0omUukE1h +NUEJ4PB6r2IQhPRiaLjP/8QAJxAAAgICAwACAwEAAgMAAAAAAAERITFBEFFhIHGB +obGRweEw8PH/2gAIAQEAAT8Q+jLke+0xLPph8aF28C36drjX5NM0zZviMpCcjdVn +nVcLv4a50fXGjDaQjb6HuD/jh4bH/wBnUizOicsZJND7FQmDTUIYmRVga2gWcNmO +yKl22IabYptfLO+JPrns6jiRZhaJ2K2hbjnRLBnwIWhuRvA1k3gY3Mx/Rw3T6JMs +DS3JkW2h3MKLnJNqG66GSh5D1IhLNiZtmVz3PH0YRowa4TF+yIX0TsdL88aFZq+z +C/BRy6X8FZaKCThLQ57dEYtjaSjQ5CTazRHTE0kLO2WKCLwSKRaFbFvIlrQlbrIv +vPE8v9/DY8mZM0i7keHAqS7E7Hr9Fg9lmYvTEikbHtEGVzslZixzFihgyThCmZHr +E5ZGhaQ3+BdTp6E5R8bhXxte8b+Fz3od7wPSfRpbNN9jz6O/0ejQp2JtCWBfoKey +WQYSpLY1Bdh4aahBkhW2SEQHWKiLc6MfYvTCbfwVOiNrJNLc7IMBVfgqS2Okt0MY +8cEknY6aIkeo8HtCFK2MeIHDI/RajREKdsh4QoC0E2dihC2IW7Xx2TPP0O16K75V +0yZhLsdpzcD0MrHFUNdUMnLFOGPStjc7Z0yMgYgV5FI+o22xJMDmLpjc4KEiv0J0 +e/D6+DQ4X+juD/gTo3o0OnI/0xTWxzL8Dti00ib0JIUngJl4O1niPgXga9ESjAy4 +XY5IRJtcr47HVdGFL/JMRtscKXQ8jpT7Jlp60PCO2PLPSJy+yeWhKtEIFRgaDR5E +fAZ8HJEDkbgWaFjugm+J4niSRVnbMnP4EE53hGUvTssibElX0xrdDKBGIXC2MfBB +rlogSFv0PDUj0r4alEkiZJJJJI/s14be/TLFaYnLMP8AYsvhk6QtxRTA3yNwNjvh +q+NEWJIYjmGhqPb4zxJJl+DdqXAqbHhzg14TtIeFIhm8lH9YlDHhj4IPjQ1wjjAS +x1aIRcSL5OoXZhIStjiU4N1geEP9CrueSpYkeg1DMj5GuLHw+GXMdOhjS7GNJsn5 +q21Nofh0k2RqCFN5Q3d4SIlpiJ00NAnw6NDYqYklDDY2NEtjXoQJXsalSYsaUtvB +EHZVF8c8vb2KWkOIH28IfbF7s3exFCG8Iyyh2SxaJSkzGQ1ikbDYx5E5U8HhEWWQ +mk2K3KINUxnkZhqaQyReYoXC4n4oUT9mcG2PoeZPxBCTI2uyJXRIfRPy7IuaTw2N +abQ6zI3TZEysWWNLvBUhxJ96RDIbxR9ogXwNiCV4Y8rxJPxVZG7SNj7NSN4HkdJ3 ++xe4Z+AIogZZH8wJZZfwvdEJElSJa+uCS5eCaSZBJi05NYkyrMWKEv8AQwuBKklG +OF4b4xze7P0PzJiDXh3oVKRUbMa1vKZSPMiwTGB1Bk2P+hE9FaElWMEn0egpURC/ +4CzCNioQiuNC+KGdpDyqxxn/AKGpf0aEpUaJuCRHDjwZzqvY0o/CiShMSBayKhJk +MYoJCCVFPqIK+xUKhcr4vMcLrjCN9iTlL/IvqkJMmiKTArSnlDEGKY4MvYSODEIR +1KcsToo0MPwXxi1BBJxjs10MeDQ8GEJKjIYl4JzrI74KJjdkihCTmxAljTkmeCwS +Wpi6gWE4QuPvlDQdDI0Tdjbl0PFZI7sakbNxoSt0tDSLQo02EySMxuuyW4qQxiSo +kVFwrKaROlpfxXFcv/EPJcekzvA6lkX6zUtmc0hbLWp+CHpW+GBJuBIINWQV4MJC +t5ZAxMTkToboWv8A4oInIzPiFd8Psf7LdbMiTh9kK6WRm5eF0Jzng6ZlgpYwnPg0 +a4Nei3InQ7ZAq+UfD7ELMt0TnpGh4H/6h0O3/TQ8dIdaENVwOax+CcqibiY0jf2J +uhXS3CEhEiQL4RXxXGhzDSMXkeWYiB24R7o7apMP+CojLGuWxX59iy4xxgJG5Y3Y +VigohMliRKFWOJMzZo/vEEcV8cuWyZGNS7eENx6xukJk/wD4TDe30JNO3JnOhsYS +jIsCwIPwkmTRIxBUSTZDcpyPHOTZPEfF5Y8GvTMd8b8yTeKzJhvRN92TI8P+smoR +RKR2MaFE4RBDsJjQhMk9fOfg/wBIdE3AxeEhtpVJovDrInMEGnD/ACNtpJUv6O/p +E70NM1EjhYNZ45iYY4DYFBFSImmJyp1xJ9koniDXFGvP6PPaKSvYs+saEWycNf0Z +uUvy2TVYG1OzdwLcF0SUgsrLHxkFVkn/AINRJAgaBh3xafbgjXC50R23xMIZdR9m +6YlJkXZPZPbJJJJJ4RN9wKYSG/0g2Xg3EuLikhPJuIyXiT6m/wDBa0YnXR1Q7Uej +OG9lg9iq2XCCEJjJeGSlDQNm7ZDaEkzLPoXDNTokro60x+u6Ky/T6xukz2rRJknn +CRE2SYTQ3Lb/AMSE7aS9ZJJW3lIn7HLyIYcXjhE9Kxqji2EVlUQTwSFjkroZfQHL +gJFhC4bEI2wj2R8J2a4njk/GO0oL6rJ097TyhMTJ7I2kv0TS+tQayxv1kjfQzD5X +gWQ0KfVBMnkm0RHCQxiXp3wxfBCO8mhWZHrDHOK+KR1Lz+xg2SSSZQ8jEZQsFGZz +ZIiRuuFihliQ0KzM77Y3fySIPobF6Sf/2YkBVQQTAQgAPwIbAwYLCQgHAwIGFQgC +CQoLBBYCAwECHgECF4AWIQRpmmPvwXrTqaNM/8B60KkcQL0AkQUCYQMqwAUJGlcT +TQAKCRB60KkcQL0AkWgqB/4x0rSeA8SrfwBuzd7q+MGpqaIK3egP3lb3zLhBgOYw +U+/Bf9iH35a5rWuNzpnRDVQLNN/LltKKzaUhyBYf1TbReMcObjousA0LRK0uGQFa +ELIOHDhAjx938tNu/iM+aRh0Xt1KP2X4sWH+Lf4pLhK00ndK3FzRM0xWkO+saHoE +3ouOgQxrKRLSZ3pHjVYNa1vwWJRJYB5N/FPL8hH7ufqDm52EWg/jpgQGaqSoVoq1 +CR8qoIV3wlrO/R8OMVI64IWeLW2oRRK9xQZp4q25p6yiJvM9e1EmD1bUf+7qi4zA +X6BRBTO5SQG0hOJjmf3XrZNEoF8zt0+bp20UJ9CWaNkuiQGBBBIBCABrBQJS/AGa +BYMSzAMAXhSAAAAAABUAQGJsb2NraGFzaEBiaXRjb2luLm9yZzAwMDAwMDAwMDAw +MDAwMDBlYTdkOTk4ZjIzYTJiODM1MjMyNjMwNjY5ZDZlYTA5MDVhMWIwZTAyZThh +YmQ2YmMACgkQf6sRQmfk+gR56ggAqN5hVBXG+DTBjplyUKR3WoYf2m3HSDwSDBaN +9H4ohSzm3GeIzXu866AQI9G+3mFCzMgYgzGh5OVcHCF7Bznt8K8hYjd9OCgWxAyz +cjsA1A8zjgaDg8HskUNU5b53NpCqHoNpqT5u1ckuBIRPwNMxEGj31D4pU7o256L5 +iBPPsJxSa4ouF5YAT023Iy3GqZDwqpQdvjHNf6wjAXx2BZ9xBFR0MtOgA097brKw +13A+T9QZkJlv3XT2WSTBE4jvPDjzg1KttpG+Mg/4juI/JiNsHiRxlbmU7bqtfdYX +patbscGg0bf3S+lQCUB45lWr4hsaHcVK3FX3ALeau9GUsMsOKIkCHAQQAQIABgUC +VA9iQAAKCRBQfh+DfBT/qYBvEACY+T+wpBtLLyOZf1ZW3H1qGKomOxAm7jUrPNq/ +O6nxS6QODUapcSZU8lmOEhE6LXttwMPcR0Nm6Ehnr4+RrZ7ev+7YqHOYhbQwx2Po +YrwlSSBRMSeHrZKGcIvbnyPyffTv7VMicT5dH7UnrrabycyvcRnDa3SIf77u3XqM +5HpLrAO0aHCXtJu6aeLtfs6qtjPpRzN8HpciYk8chgbp/5glPjJWHtkxClVeydUB +EQeMkKXBhE5pib4HPh+BvfKiwsmG6IdHVIPBFo3BpCnh6teUEcoWcH8jIo9M8Fty +6Y8raDH3rnTMUC5LnaVPk65EU/jEXDkSX9Yw7UcuT4schgcICrFZfEVdJQmhSePs +18S6EXoJPhWpW5Z0yfpQkl+vVEQ49FeBtTMXf5ukR/52c7FrGfhSubV07XSkx87j +r2CsmVZofS4LuC5HlISKUZXbpLkUT7Gdg3xB4gs6Iq0Fc82P0JTc0z9K/+ButRb9 +X1rv1PvemKTacgzWkWIEzQdiJj7faythoUaN6SBXqgLZaLk5ArywvTLM8WPl6qq4 +gikO030bgGFsLTlYZLOP/GL/CKKIsiRngk1VqY3w7KVWAWEuMkyvk0nhi8XA6b4W +of1KzMJxvqcb8m+EP4nKMOiE7w5wp/BsIDziQk7vSXnUKt8tsNlYLzy8d35lV+d4 +VJZVKYhGBBIRCAAGBQJUHfafAAoJEKyFk2KwQTv6E4UAn1yhDV5IztOAtP2fYydi +8/2cqhmYAJ94FUEgSeuXyjti4NZ5aueyICXjwokBPgQTAQIAKAUCUvmV3QIbAwUJ +BaRJWgYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQetCpHEC9AJGRXgf9HWkm +R3v6Qbz6UJgRb4AWpfdYTSRQ3qre3zoNKHv7lE5zHgiW9upGBDTyD1Att6Nr8sAo +dS+W8LIcNwJaXWlyZ9FqqEbDfnu7jfDU/mPsDMl70TdgzMaYz8vZY1qEnxJIQCNp +WJ/0iFxcuvTrFzb/OLPpT0u9qQNW6JC1wFzgUZBwz/gkfdGZIawtAc0xk5RUcHDO +RyQ8NgcGZS7/d8sx9agjLnj1bUnoHkY/8VROnHqi2aqsDgvGugBFwx6TVngoZFPq +ecKn3lf9FLh/SM8Cn5SidkiBoMtl7Bye/mXYc3/lm00JdcXBeECXglN2OaCVcOIl +vqJeu2JN0V8aEhy5OYkBIgQTAQgADAUCVfsJUQWDB4YfgAAKCRBPdE2h9fFTgUmQ +CADYxnavHKeqKizht75trGycvUoilAfA87i76/ATkrGDuSz0twk6Zs/XVSMl9xTz +pGzrFCSzTpPSdEHegWxC1kBPgegBYSFUGQn4ZxJXUYkeTKnT07SQpeu8nBQbii2o +lQT2RIqkIwk7OyTz4lVMuFqQm4fkp/L5MvJqB613Ejn6S/eaJCF6Tobbot2pUfsS +gZZeceSVamb6TwHOyOZgYCUxycARg6AZnION5edv7X9lvecdKLrfgCwHEPzaBzK2 +ExR2ND2qGvHKUixUCO6Z3V4cfZ7BIhgSPHoiarjHqB32DjL0RQm2uFPgZln1LqBj +d2yje1iPS8l8z4GV9CrcnyhliQEgBBABCAAKBQJV+xBIAwUBeAAKCRB36AaCqD20 +DpjpB/9p6OJ06jnbdRF22aftOBKBPV2wHZw12Qlwoqc85KXpATAz5HuSIG8+XLHi +fxiKF6shPdJyfRyeAiwZGgA1d30WfiRi/w3zC4THek1Kwf84swPva0Kun3rTmt9+ +CNLSKO1Bg067ZzKJS8ejfv1KhzzHlAv14fvQ6EFJ5Uz8R9KQOc9m1kv+lkoSS6yU +jTfDNGSY7LCkq5EOEZ0WzsZgxhh8wZuxkPPZjd9FMQaCYX8z9GvA8sluEsvewbqW +EYJivcYnKItIrBbsN0/N1vUNV977PxXhhCwgGnpsIo2LQ1laTocgoV8WeWFIZT/H +xtVne4JqmcuJVBPszhTb5+a/EwroiQIcBBABAgAGBQJV+wPWAAoJEGviztFKmRe8 +ZHgP/3/YUdrm8WWzv6zPG2pqCgHK2UFiCq6ICBMG4Lr2NalbSSXJCNuHsnD3ocR7 +UssRgQchbMNIXf6ksNIuUzo1kJSghcLNpHF9K5SSitzwSdapV7PibGhdM9gk83DH +hvxEpNPolJ3oPktUkmelvNCH4kBVV4XbHOwMh6Rsr5mtr6G5DXCdnRXiAG3mEE5e +POefp3V1dDlBoGri5xTHHyZlN5Z1/qGtTenODI1IUsK3CZ6jdq8JUEaWiAHOCGqP +9YBix+PVXzJKxAyCgRk3LSwCWRUYUYB7wIm+Teww4nZHqp9WNON3v2KJ16G40toz +7R4txwFlmRuZ/h6weHrSrJ+PghKBMF+KZ3kAAfCD7vHBG1enQ8G1UkbuVtJDfM1Y +ivRkf5M5rvhgfvnUr5cNA1uXMPDUV0TgyORFoNVi91zEd9eSO2gdnVlzlfAVANmQ +9PKqaHRmGEUXKPuOqviG2Wk9sswnGodSnr1n7T4XZdA8cCxIaIGj96/9d2hTYQfW +1jBONK+wWQSOgmd2Hho+DRXuAd3nW6GHGqFJn484+8PHW/Ko4QpP6GfIrAk4zofz +7mc/NEEHLBRMNbhT9Mgcy1e5RTX2wjyxp4banGQITcx+l6lfCDdPdP7bPpZs4s5k +EAgrmwj40Ftv0jgDyqKRcOW+i3zVEOc0cRENd6vyUpzJJgS/uQENBFASGPEBCADO +lZuRdAJPbVFJgbN8j0vUv5wAlt7oXOo/yNDNeeLC/EvSKHstg3cOvssWorE7fEUr +Evcw+1YcNBJtMeCuSyKS2MZW/FX+IrEbGE0o4yOpPWHcszRgE8Lt06jQ9PKFstDw +3uZLI80MTiTWExN7LVPfZAWlbI+Qnqj2/2Yoy7p7S9SuLlbmVJ7F2PKUHVc5Pgma +lTG5mU37BGQKrdvytPHhDfcvoY8W4U/tRuGHMRq7aoCGoHQ5JKkJX1MbXtEYJqR/ +byI7f9nn9A62/Lfnx20TR6aoOg+uYPOwVqn/UH49c+d5//hEJNjcWLu3xGIcl0zC +gtOxGLR/Tge4JzC57ioTABEBAAGJATwEGAEIACYCGwwWIQRpmmPvwXrTqaNM/8B6 +0KkcQL0AkQUCYQMxXQUJGlcZ7AAKCRB60KkcQL0AkR54B/0c1ZmIjdTtpBCohRmj +kQuw7VuYtI27sx4QGzGLssDZU4VS1jVvLpDJQkOBppngXeALUkZSBiXJwrrqrcI4 +ZQJsD7uTw+21d+DrNqYOctgz+IlSEMNLvnc7/1tA+K9JYRyZZ8nbW7/NsZN6Ph3G +Rt8BaJBH6zh9HaTjx4g3Nij1rkwp9gV+rDS0Wk+WoPHicATJHRaf5jqpBRkGvy2C +YFpe2NoMRgDhlt9ckr99m3uVL3lY3HkrIMGDyMkHR8uW+tk9TcGs3gWDkJG4lNoK +ZS7/gZ79/9sOEG5feGJ7xP/jOfLjaeNdOW9zclm8+iz/Sq0lzvi23Dv4UXwue2Rz +urvOuQINBFKaS+cBEAD10Tq0yWHrCzzelYKtZ25DSl3oPtrg/qpGzXQiYLUkL40z +M9W3q7HuVvdHr9vqC/HYHAJnxOoIRY+M90felUTcphGtOPY8XGh0I4H0k52sRY71 +9RhIcied7AxdB8t1LIWjq2+DqS66CBtTz/N1fYR23A/hFas/3Q+fKYmsJD+gwNHm +HnIdszLK08NaVUDQiOvfJXvdPowFseiBaatu/TAukpttcvy6lnyHsdW89CwiB5BX +TbrkOKXyEjT8kAzO3Z2v8pJCa2fzGhFFO9xeGt2r4JIo4qgYSw+CIPXUIg+GlEJ1 +iedykt95Ir8xsaXou27DvUU0h2SKO3o8hIaL4rErmiHmYmpWRakfW9JWP2G7fRCp +TMoAru3/r23gUpdCqeAmfP9WyTOs3wfi3OmsK11jv5RoJCv2rCzK04zVpKBSuiND +3J9fsv4L9lRHeAfohjc81eNerHb/4vYeFLRCwLzjqaKnn0Svcp2CV4WBBpjuu8PL +IzZmNawylbktPEBFfKUUa3RE/R5DpHt9HP1JwM8DDLRNhPx5ZFIQPprs8+bCwSy6 +W9BNjzvHNjZnLIDhSg3emu+ylatGKV3ZmGL7f4G63qFI04zw/iuKmvL6Xy/+Ek9W +j/4vxRY+VKsWvBhQelnp0KiBedZZ9NBFnk5SfEETTvwPtHwlQVki0BjFA0mW+QAR +AQABiQE8BBgBCAAmAhsMFiEEaZpj78F606mjTP/AetCpHEC9AJEFAmEDMV0FCRfO +5vYACgkQetCpHEC9AJGA7Af9EwJrRiCsFxmiDKePcrsj9o0CV29Ksg2zDmUGrPVc +qjAI56YLorHWpoTbt5eemXCdpTYLYXLZb2Zh8cFB4GgsWriKWY9vMCI5L0Ax6oMI +Vo+aaqlFl7Q1++4HsxVp/b+mgpTsj+kRzvtJ3X7hLTtZ9ZTmPJViQHZF2yIZ7dSg +mWjlsRURUHwwUUs49UiLBPyJKBKHOb/KYSmjv0dolV8tsstm0+OmM45UorVkeUEk +eRm0O0CIl8md9T3l3TNTxdx8YNEB7VMWtW2avdSmA79NrKPs3tEufj+bVQSBMfNb +IuASrezmWSioD7YhMvKZtLTD7JuR5zE98kt0qkQG5PSqqrkBDQRUm2SaAQgArgVZ +BhfUgH4ANVz0VzHdvykwBvBprfVjrWATWZZlEN02s6/HvyRj5QKRAqrqzk8R1Xb2 +ekn+Q2Q8o5ZAQ/akrFxTDzXA0RNGUIoF/a2jN3pD6pkgV9kRHo/yJhe1jxuKesn5 +r1BOBkYES1G23gT2FMZUoeZU26m1N6dUr8Vdtp6fsOT5iejTaaD0FbXwgHCZtXyx +yA1TJevhOAFoJXo8B4sbZr/0+LaVibEurghh16jic9D824pfoNd4Fm0kqVRS60jg +86cf/35ktquY3UNV51QAf5xzmvLrUI3BQXgo6FiGZm2jHo3RPIeYtTXNK1gePjsX +g7R0kGjAMKoqEAWnawARAQABiQE8BBgBCAAmAhsMFiEEaZpj78F606mjTP/AetCp +HEC9AJEFAmEDMV0FCRXNzkMACgkQetCpHEC9AJFV9wf/WRHGp8jvxD1RAe2R78Dv +si54R1Zck7jy5gkT5FG9cDaKyAoVvx4noxDEPCK0G7jBM7iCnbpp3ewWVQg40E19 +v+pYy2ESwDvx72giotTieHdbUCD6kT+ZPlVbrG00K3e+unvyLubmskgukVvceo9V +CRSJ+trtLCqWvSrFSctzU8LokyF6e93CK2xirr1fLhTDE0SVDl0sWZrere73//Uw +7fLuUX/e/VbUi2iFw1AWSrvof0ybNmjMfvm+7cMvyWwO12763meOCnaytKTAtgSR +IEKYIHg3KxvaXs2BDkEyK84ZcdHI++WF/xea9uOJzO0iNqJU1fH5AWszOCTxkABU +3rkBDQRUm2YgAQgAnR2NmQHlMWu5SLBn6i1lkYE7kFuVeztPiP59ZxkOrXK25NEF +Fi3t/651P2Ey4BB/CH1e+EqfUuo2wQjH3nD0VRU2c5x4hfy5bUfl1wkG3p4yXxx3 +MkvzVLRGAZk06cPCKY4QNtXXJ391odqHa0VcaBZJZS0euZ7CsAEUhUm5zxpTH/4O +ZTO/GpmHn6brQD7cwLZu+gIOEl5RM5Q00QLU88aOvftU/D/au1ujxBUZbT8UICDx +IKagLqtEBXpXdaGZSRymoRjJpWccGusPI3DSGTWqcp+u1ocqyy+4ntkA5X4COzTl +Hmn+9OoFPui9wtDvlj1NvdSdTg7/tutscY2+4wARAQABiQJbBBgBCAAmAhsCFiEE +aZpj78F606mjTP/AetCpHEC9AJEFAmEDMV0FCRXNzL0BKcBdIAQZAQIABgUCVJtm +IAAKCRDFiNY85BuXwfX9B/9qXO+H5CVJidWIjwfY9+m1zmMNgTnsw4ZkI/ZIrnHs +YiNieOSy2q21omme37oylFRku0ol4Q1TbV0dpmIMl4TRG0XIr/B+fLWLhBC90AT0 +FYJJ9ROYBQA7T6LqZRTjE7cmZd6fXvTJYEuq3YCh+pFtVHJYR6yu6+5LWEZuXdhK +mWkz/qsZ2U2m9VxRUVRoPHsn2wZq2Kh+j3G8tVgwzU50ggS1IMq79IMU05/2AIqX +sToRYKNGou9fDV8fZRiOE32suJE/SlKCitc+h8YKfzzMLFGYzoCF5XBchbzZnyYA +tWppHoZzttzwfCwi78f/Xw1/GLZsSGdVeotYTyacfacKCRB60KkcQL0AkUvVB/4q +N2pKbx/+EQ89hxSy2dxYwUiRa58lvWSdekom23SUEILfo29ijDZ03w+ek1q12typ +kibymHg9RN9M2sammZji3tm11rqYZkSFEAVq2MBXx/rBXJw8srNENNpY1WEN4o4y +jHk25t/PNBu2KgBGTb6Dlz7zepUsToAN2oZU75mg/KV2vKXR9IjNzM/rdApjuYUN +kKx89cCI2mBa3ke844fy5ifD+NICXZvfOj4YlVfLdYFz48VXqeCRTyTRoDIL4E2E +pN7P/uK85nO2p0s2p1nANJYS9j1A97AyFQDpPCJynlC66IZxrKSULbD0+BOvE2yY +dpxrlOWOxI9jmzuQ75LO +=WxeH +-----END PGP PUBLIC KEY BLOCK----- + diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 00000000..173999bc --- /dev/null +++ b/clippy.toml @@ -0,0 +1,2 @@ +msrv = "1.56.1" +too-many-arguments-threshold = 13 diff --git a/contrib/release.sh b/contrib/release.sh new file mode 100755 index 00000000..9df34c9a --- /dev/null +++ b/contrib/release.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# +# Check that we can publish crates in their current form if there are changes on top of the tip of +# master that imply that we are about to do a release. + +set -ex + +main () { + for crate in "internals" "hashes" "tapyrus"; do + if release_changes $crate; then + echo "$crate has changes implying this is a release PR, checking if we can publish ..." + + # Check if there is any mention of NEXT_RELEASE which means the + # next version number should be filled in. + if grep -qr NEXT.RELEASE ./$crate; then + echo Version number needs to be filled in following places: + grep -r NEXT.RELEASE ./$crate + exit 1 + fi + + # Then try to dry-run cargo publish + publish_dry_run $crate + fi + done +} + +# Returns 0 if crate ($1) contains changes since tip of master that imply this patch set is done in +# preparation for releasing the crate. +release_changes() { + local crate=$1 + git log --patch --reverse master.. -- $crate/Cargo.toml | grep version +} + +# Do a dry run publish to crates.io using the correct package name for crate ($1). +# We use `set -e` so this will fail the script if the dry-run fails. +publish_dry_run() { + local crate=$1 + if [ "$crate" == "hashes" ]; then + cargo publish -p "tapyrus_hashes" --dry-run + elif [ "$crate" == "internals" ]; then + cargo publish -p "tapyrus-internals" --dry-run + elif [ "$crate" == "tapyrus" ]; then + cargo publish -p "tapyrus" --dry-run + fi +} + +# +# Main script. +# +main $@ diff --git a/contrib/test.sh b/contrib/test.sh index de1cb3ec..a7b1f536 100755 --- a/contrib/test.sh +++ b/contrib/test.sh @@ -1,49 +1,31 @@ -#!/bin/sh -ex +#!/bin/sh -FEATURES="bitcoinconsensus use-serde rand" +set -ex -if [ "$DO_COV" = true ] -then - export RUSTFLAGS="-C link-dead-code" -fi +CRATES="tapyrus hashes internals fuzz" +DEPS="recent minimal" - -# Use toolchain if explicitly specified -if [ -n "$TOOLCHAIN" ] -then - alias cargo="cargo +$TOOLCHAIN" -fi - -# Test without any features first -cargo test --verbose - -# Test each feature -for feature in ${FEATURES} +for dep in $DEPS do - cargo test --verbose --features="$feature" + cp "Cargo-$dep.lock" Cargo.lock + for crate in ${CRATES} + do + ( + cd "$crate" + ./contrib/test.sh + ) + done + if [ "$dep" = recent ]; + then + # We always test committed dependencies but we want to warn if they could've been updated + cargo update + if diff Cargo-recent.lock Cargo.lock; + then + echo Dependencies are up to date + else + echo "::warning file=Cargo-recent.lock::Dependencies could be updated" + fi + fi done -# Fuzz if told to -if [ "$DO_FUZZ" = true ] -then - ( - cd fuzz - cargo test --verbose - ./travis-fuzz.sh - ) -fi - -# Bench if told to -if [ "$DO_BENCH" = true ] -then - cargo bench --features unstable -fi - -# Use as dependency if told to -if [ -n "$AS_DEPENDENCY" ] -then - cargo new dep_test - cd dep_test - echo 'bitcoin = { path = "..", features = ["use-serde"] }' >> Cargo.toml - cargo test --verbose -fi +exit 0 diff --git a/contrib/update-lock-files.sh b/contrib/update-lock-files.sh new file mode 100755 index 00000000..02ba1f7c --- /dev/null +++ b/contrib/update-lock-files.sh @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# +# Update the minimal/recent lock file + +set -euo pipefail + +for file in Cargo-minimal.lock Cargo-recent.lock; do + cp --force "$file" Cargo.lock + cargo check + cp --force Cargo.lock "$file" +done diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index 4b3941da..7a9b521f 100644 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -1,53 +1,92 @@ [package] -name = "bitcoin-fuzz" +name = "tapyrus-fuzz" +edition = "2018" version = "0.0.1" -authors = ["Automatically generated"] +authors = ["Generated by fuzz/generate-files.sh"] publish = false [package.metadata] cargo-fuzz = true -[features] -afl_fuzz = ["afl"] -honggfuzz_fuzz = ["honggfuzz"] - [dependencies] -honggfuzz = { version = "0.5", optional = true } -afl = { version = "0.4", optional = true } -bitcoin = { path = "..", features = ["fuzztarget"] } +honggfuzz = { version = "0.5.55", default-features = false } +tapyrus = { path = "../tapyrus", features = [ "serde" ] } + +serde = { version = "1.0.103", features = [ "derive" ] } +serde_json = "1.0" +serde_cbor = "0.9" + +[[bin]] +name = "tapyrus_deserialize_address" +path = "fuzz_targets/tapyrus/deserialize_address.rs" + +[[bin]] +name = "tapyrus_deserialize_amount" +path = "fuzz_targets/tapyrus/deserialize_amount.rs" + +[[bin]] +name = "tapyrus_deserialize_block" +path = "fuzz_targets/tapyrus/deserialize_block.rs" + +[[bin]] +name = "tapyrus_deserialize_prefilled_transaction" +path = "fuzz_targets/tapyrus/deserialize_prefilled_transaction.rs" + +[[bin]] +name = "tapyrus_deserialize_psbt" +path = "fuzz_targets/tapyrus/deserialize_psbt.rs" + +[[bin]] +name = "tapyrus_deserialize_script" +path = "fuzz_targets/tapyrus/deserialize_script.rs" -# Prevent this from interfering with workspaces -[workspace] -members = ["."] +[[bin]] +name = "tapyrus_deserialize_transaction" +path = "fuzz_targets/tapyrus/deserialize_transaction.rs" + +[[bin]] +name = "tapyrus_deserialize_witness" +path = "fuzz_targets/tapyrus/deserialize_witness.rs" [[bin]] -name = "deserialize_block" -path = "fuzz_targets/deserialize_block.rs" +name = "tapyrus_deser_net_msg" +path = "fuzz_targets/tapyrus/deser_net_msg.rs" [[bin]] -name = "deserialize_script" -path = "fuzz_targets/deserialize_script.rs" +name = "tapyrus_outpoint_string" +path = "fuzz_targets/tapyrus/outpoint_string.rs" [[bin]] -name = "deserialize_transaction" -path = "fuzz_targets/deserialize_transaction.rs" +name = "tapyrus_script_bytes_to_asm_fmt" +path = "fuzz_targets/tapyrus/script_bytes_to_asm_fmt.rs" [[bin]] -name = "deserialize_address" -path = "fuzz_targets/deserialize_address.rs" +name = "hashes_cbor" +path = "fuzz_targets/hashes/cbor.rs" [[bin]] -name = "deserialize_amount" -path = "fuzz_targets/deserialize_amount.rs" +name = "hashes_json" +path = "fuzz_targets/hashes/json.rs" [[bin]] -name = "outpoint_string" -path = "fuzz_targets/outpoint_string.rs" +name = "hashes_ripemd160" +path = "fuzz_targets/hashes/ripemd160.rs" [[bin]] -name = "deserialize_psbt" -path = "fuzz_targets/deserialize_psbt.rs" +name = "hashes_sha1" +path = "fuzz_targets/hashes/sha1.rs" [[bin]] -name = "deser_net_msg" -path = "fuzz_targets/deser_net_msg.rs" +name = "hashes_sha256" +path = "fuzz_targets/hashes/sha256.rs" + +[[bin]] +name = "hashes_sha512_256" +path = "fuzz_targets/hashes/sha512_256.rs" + +[[bin]] +name = "hashes_sha512" +path = "fuzz_targets/hashes/sha512.rs" + +[lints.rust] +unexpected_cfgs = { level = "deny", check-cfg = ['cfg(fuzzing)'] } \ No newline at end of file diff --git a/fuzz/README.md b/fuzz/README.md new file mode 100644 index 00000000..f53a22e4 --- /dev/null +++ b/fuzz/README.md @@ -0,0 +1,115 @@ +# Fuzzing + +`bitcoin` and `bitcoin_hashes` have fuzzing harnesses setup for use with +honggfuzz. + +To run the fuzz-tests as in CI -- briefly fuzzing every target -- simply +run + + ./fuzz.sh + +in this directory. + +To build honggfuzz, you must have libunwind on your system, as well as +libopcodes and libbfd from binutils **2.38** on your system. The most +recently-released binutils 2.39 has changed their API in a breaking way. + +On Nix, you can obtain these libraries by running + + nix-shell -p libopcodes_2_38 -p libunwind + +and then run fuzz.sh as above. + +# Fuzzing with weak cryptography + +You may wish to replace the hashing and signing code with broken crypto, +which will be faster and enable the fuzzer to do otherwise impossible +things such as forging signatures or finding preimages to hashes. + +Doing so may result in spurious bug reports since the broken crypto does +not respect the encoding or algebraic invariants upheld by the real crypto. We +would like to improve this but it's a nontrivial problem -- though not +beyond the abilities of a motivated student with a few months of time. +Please let us know if you are interested in taking this on! + +Meanwhile, to use the broken crypto, simply compile (and run the fuzzing +scripts) with + + RUSTFLAGS="--cfg=hashes_fuzz --cfg=secp256k1_fuzz" + +which will replace the hashing library with broken hashes, and the +secp256k1 library with broken cryptography. + +Needless to say, NEVER COMPILE REAL CODE WITH THESE FLAGS because if a +fuzzer can break your crypto, so can anybody. + +# Long-term fuzzing + +To see the full list of targets, the most straightforward way is to run + + source ./fuzz-util.sh + listTargetNames + +To run each of them for an hour, run + + ./cycle.sh + +To run a single fuzztest indefinitely, run + + HFUZZ_BUILD_ARGS='--features honggfuzz_fuzz' cargo hfuzz run + +This script uses the `chrt` utility to try to reduce the priority of the +jobs. If you would like to run for longer, the most straightforward way +is to edit `cycle.sh` before starting. To run the fuzz-tests in parallel, +you will need to implement a custom harness. + +# Adding fuzz tests + +All fuzz tests can be found in the `fuzz_target/` directory. Adding a new +one is as simple as copying an existing one and editing the `do_test` +function to do what you want. + +If your test clearly belongs to a specific crate, please put it in that +crate's directory. Otherwise you can put it directly in `fuzz_target/`. + +If you need to add dependencies, edit the file `generate-files.sh` to add +it to the generated `Cargo.toml`. + +Once you've added a fuzztest, regenerate the `Cargo.toml` and CI job by +running + + ./generate-files.sh + +Then to test your fuzztest, run + + ./fuzz.sh + +If it is working, you will see a rapid stream of data for many seconds +(you can hit Ctrl+C to stop it early). If not, you should quickly see +an error. + +# Reproducing Failures + +If a fuzztest fails, it will exit with a summary which looks something like + +``` +... + fuzzTarget : hfuzz_target/x86_64-unknown-linux-gnu/release/hashes_sha256 +CRASH: +DESCRIPTION: +ORIG_FNAME: 00000000000000000000000000000000.00000000.honggfuzz.cov +FUZZ_FNAME: hfuzz_workspace/hashes_sha256/SIGABRT.PC.7ffff7c8abc7.STACK.18826d9b64.CODE.-6.ADDR.0.INSTR.mov____%eax,%ebp.fuzz +... +===================================================================== +fff400610004 +``` + +The final line is a hex-encoded version of the input that caused the crash. You +can test this directly by editing the `duplicate_crash` test to copy/paste the +hex output into the call to `extend_vec_from_hex`. Then run the test with + + cargo test + +Note that if you set your `RUSTFLAGS` while fuzzing (see above) you must make +sure they are set the same way when running `cargo test`. + diff --git a/fuzz/contrib/test.sh b/fuzz/contrib/test.sh new file mode 100755 index 00000000..fd34b23c --- /dev/null +++ b/fuzz/contrib/test.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +set -ex + +FEATURES="" + +cargo --version +rustc --version + +# Make all cargo invocations verbose +export CARGO_TERM_VERBOSE=true + +# Pin dependencies as required if we are using MSRV toolchain. +if cargo --version | grep "1\.41"; then + # 1.0.157 uses syn 2.0 which requires edition 2021 + cargo update -p serde --precise 1.0.156 + # 1.0.108 uses `matches!` macro so does not work with Rust 1.41.1, bad `syn` no biscuit. + cargo update -p syn --precise 1.0.107 + # Half 1.8 uses edition 2021 features + cargo update -p half --precise 1.7.1 +fi + +if [ "$DO_LINT" = true ] +then + cargo clippy --all-features --all-targets -- -D warnings +fi + +# Defaults / sanity checks +cargo build +cargo test + +# Address Sanitizer +if [ "$DO_ASAN" = true ]; then + cargo clean + CC='clang -fsanitize=address -fno-omit-frame-pointer' \ + RUSTFLAGS='-Zsanitizer=address -Clinker=clang -Cforce-frame-pointers=yes' \ + ASAN_OPTIONS='detect_leaks=1 detect_invalid_pointer_pairs=1 detect_stack_use_after_return=1' \ + cargo test --lib --no-default-features --features="$FEATURES" -Zbuild-std --target x86_64-unknown-linux-gnu + cargo clean + CC='clang -fsanitize=memory -fno-omit-frame-pointer' \ + RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins -Cforce-frame-pointers=yes' \ + cargo test --lib --no-default-features --features="$FEATURES" -Zbuild-std --target x86_64-unknown-linux-gnu +fi + diff --git a/fuzz/cycle.sh b/fuzz/cycle.sh new file mode 100755 index 00000000..0b59827a --- /dev/null +++ b/fuzz/cycle.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Continuosly cycle over fuzz targets running each for 1 hour. +# It uses chrt SCHED_IDLE so that other process takes priority. +# +# For hfuzz options see https://github.com/google/honggfuzz/blob/master/docs/USAGE.md + +set -e +REPO_DIR=$(git rev-parse --show-toplevel) +# shellcheck source=./fuzz-util.sh +source "$REPO_DIR/fuzz/fuzz-util.sh" + +while : +do + for targetFile in $(listTargetFiles); do + targetName=$(targetFileToName "$targetFile") + echo "Fuzzing target $targetName ($targetFile)" + + # fuzz for one hour + HFUZZ_RUN_ARGS='--run_time 3600' chrt -i 0 cargo hfuzz run "$targetName" + # minimize the corpus + HFUZZ_RUN_ARGS="-i hfuzz_workspace/$targetName/input/ -P -M" chrt -i 0 cargo hfuzz run "$targetName" + done +done + diff --git a/fuzz/fuzz-util.sh b/fuzz/fuzz-util.sh new file mode 100755 index 00000000..759d41c4 --- /dev/null +++ b/fuzz/fuzz-util.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +REPO_DIR=$(git rev-parse --show-toplevel) + +listTargetFiles() { + pushd "$REPO_DIR/fuzz" > /dev/null || exit 1 + find fuzz_targets/ -type f -name "*.rs" | sort + popd > /dev/null || exit 1 +} + +targetFileToName() { + echo "$1" \ + | sed 's/^fuzz_targets\///' \ + | sed 's/\.rs$//' \ + | sed 's/\//_/g' \ + | sed 's/^_//g' +} + +targetFileToHFuzzInputArg() { + baseName=$(basename "$1") + dirName="${baseName%.*}" + if [ -d "hfuzz_input/$dirName" ]; then + echo "HFUZZ_INPUT_ARGS=\"-f hfuzz_input/$FILE/input\"" + fi +} + +listTargetNames() { + for target in $(listTargetFiles); do + targetFileToName "$target" + done +} + +# Utility function to avoid CI failures on Windows +checkWindowsFiles() { + incorrectFilenames=$(find . -type f -name "*,*" -o -name "*:*" -o -name "*<*" -o -name "*>*" -o -name "*|*" -o -name "*\?*" -o -name "*\**" -o -name "*\"*" | wc -l) + if [ "$incorrectFilenames" -gt 0 ]; then + echo "Bailing early because there is a Windows-incompatible filename in the tree." + exit 2 + fi +} + +# Checks whether a fuzz case output some report, and dumps it in hex +checkReport() { + reportFile="hfuzz_workspace/$1/HONGGFUZZ.REPORT.TXT" + if [ -f "$reportFile" ]; then + cat "$reportFile" + for CASE in "hfuzz_workspace/$1/SIG"*; do + xxd -p -c10000 < "$CASE" + done + exit 1 + fi +} diff --git a/fuzz/fuzz.sh b/fuzz/fuzz.sh new file mode 100755 index 00000000..5fc65ae6 --- /dev/null +++ b/fuzz/fuzz.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -ex + +REPO_DIR=$(git rev-parse --show-toplevel) + +# shellcheck source=./fuzz-util.sh +source "$REPO_DIR/fuzz/fuzz-util.sh" + +# Check that input files are correct Windows file names +checkWindowsFiles + +if [ "$1" == "" ]; then + targetFiles="$(listTargetFiles)" +else + targetFiles=fuzz_targets/"$1".rs +fi + +cargo --version +rustc --version + +# Testing +cargo install --force honggfuzz --no-default-features +for targetFile in $targetFiles; do + targetName=$(targetFileToName "$targetFile") + echo "Fuzzing target $targetName ($targetFile)" + if [ -d "hfuzz_input/$targetName" ]; then + HFUZZ_INPUT_ARGS="-f hfuzz_input/$targetName/input\"" + else + HFUZZ_INPUT_ARGS="" + fi + HFUZZ_RUN_ARGS="--run_time 30 --exit_upon_crash -v $HFUZZ_INPUT_ARGS" cargo hfuzz run "$targetName" + + checkReport "$targetName" +done diff --git a/fuzz/fuzz_targets/deserialize_psbt.rs b/fuzz/fuzz_targets/deserialize_psbt.rs deleted file mode 100644 index d19563b1..00000000 --- a/fuzz/fuzz_targets/deserialize_psbt.rs +++ /dev/null @@ -1,61 +0,0 @@ -extern crate bitcoin; - -fn do_test(data: &[u8]) { - let psbt: Result = bitcoin::consensus::encode::deserialize(data); - match psbt { - Err(_) => {}, - Ok(psbt) => { - let ser = bitcoin::consensus::encode::serialize(&psbt); - let deser: bitcoin::util::psbt::PartiallySignedTransaction = bitcoin::consensus::encode::deserialize(&ser).unwrap(); - // Since the fuzz data could order psbt fields differently, we compare to our deser/ser instead of data - assert_eq!(ser, bitcoin::consensus::encode::serialize(&deser)); - } - } -} - -#[cfg(feature = "afl")] -#[macro_use] extern crate afl; -#[cfg(feature = "afl")] -fn main() { - fuzz!(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] -fn main() { - loop { - fuzz!(|data| { - do_test(data); - }); - } -} - -#[cfg(test)] -mod tests { - fn extend_vec_from_hex(hex: &str, out: &mut Vec) { - let mut b = 0; - for (idx, c) in hex.as_bytes().iter().enumerate() { - b <<= 4; - match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', - _ => panic!("Bad hex"), - } - if (idx & 1) == 1 { - out.push(b); - b = 0; - } - } - } - - #[test] - fn duplicate_crash() { - let mut a = Vec::new(); - extend_vec_from_hex("00", &mut a); - super::do_test(&a); - } -} diff --git a/fuzz/fuzz_targets/deserialize_transaction.rs b/fuzz/fuzz_targets/deserialize_transaction.rs deleted file mode 100644 index b0cd7ab5..00000000 --- a/fuzz/fuzz_targets/deserialize_transaction.rs +++ /dev/null @@ -1,73 +0,0 @@ -extern crate bitcoin; - -fn do_test(data: &[u8]) { - let tx_result: Result = bitcoin::consensus::encode::deserialize(data); - match tx_result { - Err(_) => {}, - Ok(mut tx) => { - let ser = bitcoin::consensus::encode::serialize(&tx); - assert_eq!(&ser[..], data); - let len = ser.len(); - let calculated_weight = tx.get_weight(); - for input in &mut tx.input { - input.witness = vec![]; - } - let no_witness_len = bitcoin::consensus::encode::serialize(&tx).len(); - // For 0-input transactions, `no_witness_len` will be incorrect because - // we serialize as segwit even after "stripping the witnesses". We need - // to drop two bytes (i.e. eight weight) - if tx.input.is_empty() { - assert_eq!(no_witness_len * 3 + len - 8, calculated_weight); - } else { - assert_eq!(no_witness_len * 3 + len, calculated_weight); - } - }, - } -} - -#[cfg(feature = "afl")] -#[macro_use] extern crate afl; -#[cfg(feature = "afl")] -fn main() { - fuzz!(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] -fn main() { - loop { - fuzz!(|data| { - do_test(data); - }); - } -} - -#[cfg(test)] -mod tests { - fn extend_vec_from_hex(hex: &str, out: &mut Vec) { - let mut b = 0; - for (idx, c) in hex.as_bytes().iter().enumerate() { - b <<= 4; - match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', - _ => panic!("Bad hex"), - } - if (idx & 1) == 1 { - out.push(b); - b = 0; - } - } - } - - #[test] - fn duplicate_crash() { - let mut a = Vec::new(); - extend_vec_from_hex("000700000001000000010000", &mut a); - super::do_test(&a); - } -} diff --git a/fuzz/fuzz_targets/hashes/cbor.rs b/fuzz/fuzz_targets/hashes/cbor.rs new file mode 100644 index 00000000..e680f96c --- /dev/null +++ b/fuzz/fuzz_targets/hashes/cbor.rs @@ -0,0 +1,56 @@ +use honggfuzz::fuzz; +use serde::{Deserialize, Serialize}; +use tapyrus::hashes::{ripemd160, sha1, sha256d, sha512, Hmac}; + +#[derive(Deserialize, Serialize)] +struct Hmacs { + sha1: Hmac, + sha512: Hmac, +} + +#[derive(Deserialize, Serialize)] +struct Main { + hmacs: Hmacs, + ripemd: ripemd160::Hash, + sha2d: sha256d::Hash, +} + +fn do_test(data: &[u8]) { + if let Ok(m) = serde_cbor::from_slice::
(data) { + let vec = serde_cbor::to_vec(&m).unwrap(); + assert_eq!(data, &vec[..]); + } +} + +fn main() { + loop { + fuzz!(|d| { do_test(d) }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00000", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/hashes/json.rs b/fuzz/fuzz_targets/hashes/json.rs new file mode 100644 index 00000000..9a153e06 --- /dev/null +++ b/fuzz/fuzz_targets/hashes/json.rs @@ -0,0 +1,56 @@ +use honggfuzz::fuzz; +use serde::{Deserialize, Serialize}; +use tapyrus::hashes::{ripemd160, sha1, sha256d, sha512, Hmac}; + +#[derive(Deserialize, Serialize)] +struct Hmacs { + sha1: Hmac, + sha512: Hmac, +} + +#[derive(Deserialize, Serialize)] +struct Main { + hmacs: Hmacs, + ripemd: ripemd160::Hash, + sha2d: sha256d::Hash, +} + +fn do_test(data: &[u8]) { + if let Ok(m) = serde_json::from_slice::
(data) { + let vec = serde_json::to_vec(&m).unwrap(); + assert_eq!(data, &vec[..]); + } +} + +fn main() { + loop { + fuzz!(|d| { do_test(d) }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00000", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/hashes/ripemd160.rs b/fuzz/fuzz_targets/hashes/ripemd160.rs new file mode 100644 index 00000000..2fb5a193 --- /dev/null +++ b/fuzz/fuzz_targets/hashes/ripemd160.rs @@ -0,0 +1,44 @@ +use honggfuzz::fuzz; +use tapyrus::hashes::{ripemd160, Hash, HashEngine}; + +fn do_test(data: &[u8]) { + let mut engine = ripemd160::Hash::engine(); + engine.input(data); + let eng_hash = ripemd160::Hash::from_engine(engine); + + let hash = ripemd160::Hash::hash(data); + assert_eq!(&hash[..], &eng_hash[..]); +} + +fn main() { + loop { + fuzz!(|d| { do_test(d) }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00000", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/hashes/sha1.rs b/fuzz/fuzz_targets/hashes/sha1.rs new file mode 100644 index 00000000..6db171e0 --- /dev/null +++ b/fuzz/fuzz_targets/hashes/sha1.rs @@ -0,0 +1,44 @@ +use honggfuzz::fuzz; +use tapyrus::hashes::{sha1, Hash, HashEngine}; + +fn do_test(data: &[u8]) { + let mut engine = sha1::Hash::engine(); + engine.input(data); + let eng_hash = sha1::Hash::from_engine(engine); + + let hash = sha1::Hash::hash(data); + assert_eq!(&hash[..], &eng_hash[..]); +} + +fn main() { + loop { + fuzz!(|d| { do_test(d) }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00000", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/hashes/sha256.rs b/fuzz/fuzz_targets/hashes/sha256.rs new file mode 100644 index 00000000..eb3002a6 --- /dev/null +++ b/fuzz/fuzz_targets/hashes/sha256.rs @@ -0,0 +1,44 @@ +use honggfuzz::fuzz; +use tapyrus::hashes::{sha256, Hash, HashEngine}; + +fn do_test(data: &[u8]) { + let mut engine = sha256::Hash::engine(); + engine.input(data); + let eng_hash = sha256::Hash::from_engine(engine); + + let hash = sha256::Hash::hash(data); + assert_eq!(&hash[..], &eng_hash[..]); +} + +fn main() { + loop { + fuzz!(|d| { do_test(d) }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("fff400610004", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/hashes/sha512.rs b/fuzz/fuzz_targets/hashes/sha512.rs new file mode 100644 index 00000000..6da43cbe --- /dev/null +++ b/fuzz/fuzz_targets/hashes/sha512.rs @@ -0,0 +1,44 @@ +use honggfuzz::fuzz; +use tapyrus::hashes::{sha512, Hash, HashEngine}; + +fn do_test(data: &[u8]) { + let mut engine = sha512::Hash::engine(); + engine.input(data); + let eng_hash = sha512::Hash::from_engine(engine); + + let hash = sha512::Hash::hash(data); + assert_eq!(&hash[..], &eng_hash[..]); +} + +fn main() { + loop { + fuzz!(|d| { do_test(d) }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00000", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/hashes/sha512_256.rs b/fuzz/fuzz_targets/hashes/sha512_256.rs new file mode 100644 index 00000000..3344da96 --- /dev/null +++ b/fuzz/fuzz_targets/hashes/sha512_256.rs @@ -0,0 +1,44 @@ +use honggfuzz::fuzz; +use tapyrus::hashes::{sha512_256, Hash, HashEngine}; + +fn do_test(data: &[u8]) { + let mut engine = sha512_256::Hash::engine(); + engine.input(data); + let eng_hash = sha512_256::Hash::from_engine(engine); + + let hash = sha512_256::Hash::hash(data); + assert_eq!(&hash[..], &eng_hash[..]); +} + +fn main() { + loop { + fuzz!(|d| { do_test(d) }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00000", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/deserialize_block.rs b/fuzz/fuzz_targets/tapyrus/deser_net_msg.rs similarity index 54% rename from fuzz/fuzz_targets/deserialize_block.rs rename to fuzz/fuzz_targets/tapyrus/deser_net_msg.rs index 3e2b7a1b..5f55167a 100644 --- a/fuzz/fuzz_targets/deserialize_block.rs +++ b/fuzz/fuzz_targets/tapyrus/deser_net_msg.rs @@ -1,21 +1,10 @@ -extern crate bitcoin; +use honggfuzz::fuzz; fn do_test(data: &[u8]) { - let _: Result= bitcoin::consensus::encode::deserialize(data); + let _: Result = + tapyrus::consensus::encode::deserialize(data); } -#[cfg(feature = "afl")] -#[macro_use] extern crate afl; -#[cfg(feature = "afl")] -fn main() { - fuzz!(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { @@ -24,16 +13,16 @@ fn main() { } } -#[cfg(test)] +#[cfg(all(test, fuzzing))] mod tests { fn extend_vec_from_hex(hex: &str, out: &mut Vec) { let mut b = 0; for (idx, c) in hex.as_bytes().iter().enumerate() { b <<= 4; match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', _ => panic!("Bad hex"), } if (idx & 1) == 1 { diff --git a/fuzz/fuzz_targets/deserialize_address.rs b/fuzz/fuzz_targets/tapyrus/deserialize_address.rs similarity index 60% rename from fuzz/fuzz_targets/deserialize_address.rs rename to fuzz/fuzz_targets/tapyrus/deserialize_address.rs index 4a26a20c..435b2b7b 100644 --- a/fuzz/fuzz_targets/deserialize_address.rs +++ b/fuzz/fuzz_targets/tapyrus/deserialize_address.rs @@ -1,26 +1,16 @@ -extern crate bitcoin; use std::str::FromStr; + +use honggfuzz::fuzz; + fn do_test(data: &[u8]) { let data_str = String::from_utf8_lossy(data); - let addr = match bitcoin::util::address::Address::from_str(&data_str) { - Ok(addr) => addr, + let addr = match tapyrus::address::Address::from_str(&data_str) { + Ok(addr) => addr.assume_checked(), Err(_) => return, }; assert_eq!(addr.to_string(), data_str); } -#[cfg(feature = "afl")] -#[macro_use] extern crate afl; -#[cfg(feature = "afl")] -fn main() { - fuzz!(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { @@ -29,16 +19,16 @@ fn main() { } } -#[cfg(test)] +#[cfg(all(test, fuzzing))] mod tests { fn extend_vec_from_hex(hex: &str, out: &mut Vec) { let mut b = 0; for (idx, c) in hex.as_bytes().iter().enumerate() { b <<= 4; match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', _ => panic!("Bad hex"), } if (idx & 1) == 1 { diff --git a/fuzz/fuzz_targets/deserialize_amount.rs b/fuzz/fuzz_targets/tapyrus/deserialize_amount.rs similarity index 57% rename from fuzz/fuzz_targets/deserialize_amount.rs rename to fuzz/fuzz_targets/tapyrus/deserialize_amount.rs index 6c396da4..8d28119c 100644 --- a/fuzz/fuzz_targets/deserialize_amount.rs +++ b/fuzz/fuzz_targets/tapyrus/deserialize_amount.rs @@ -1,43 +1,33 @@ -extern crate bitcoin; use std::str::FromStr; + +use honggfuzz::fuzz; + fn do_test(data: &[u8]) { let data_str = String::from_utf8_lossy(data); // signed - let samt = match bitcoin::util::amount::SignedAmount::from_str(&data_str) { + let samt = match tapyrus::amount::SignedAmount::from_str(&data_str) { Ok(amt) => amt, Err(_) => return, }; - let samt_roundtrip = match bitcoin::util::amount::SignedAmount::from_str(&samt.to_string()) { + let samt_roundtrip = match tapyrus::amount::SignedAmount::from_str(&samt.to_string()) { Ok(amt) => amt, Err(_) => return, }; assert_eq!(samt, samt_roundtrip); // unsigned - let amt = match bitcoin::util::amount::Amount::from_str(&data_str) { + let amt = match tapyrus::amount::Amount::from_str(&data_str) { Ok(amt) => amt, Err(_) => return, }; - let amt_roundtrip = match bitcoin::util::amount::Amount::from_str(&amt.to_string()) { + let amt_roundtrip = match tapyrus::amount::Amount::from_str(&amt.to_string()) { Ok(amt) => amt, Err(_) => return, }; assert_eq!(amt, amt_roundtrip); } -#[cfg(feature = "afl")] -#[macro_use] extern crate afl; -#[cfg(feature = "afl")] -fn main() { - fuzz!(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { @@ -46,16 +36,16 @@ fn main() { } } -#[cfg(test)] +#[cfg(all(test, fuzzing))] mod tests { fn extend_vec_from_hex(hex: &str, out: &mut Vec) { let mut b = 0; for (idx, c) in hex.as_bytes().iter().enumerate() { b <<= 4; match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', _ => panic!("Bad hex"), } if (idx & 1) == 1 { diff --git a/fuzz/fuzz_targets/deser_net_msg.rs b/fuzz/fuzz_targets/tapyrus/deserialize_block.rs similarity index 54% rename from fuzz/fuzz_targets/deser_net_msg.rs rename to fuzz/fuzz_targets/tapyrus/deserialize_block.rs index e2c1a0a7..313a4759 100644 --- a/fuzz/fuzz_targets/deser_net_msg.rs +++ b/fuzz/fuzz_targets/tapyrus/deserialize_block.rs @@ -1,21 +1,10 @@ -extern crate bitcoin; +use honggfuzz::fuzz; fn do_test(data: &[u8]) { - let _: Result = bitcoin::consensus::encode::deserialize(data); + let _: Result = + tapyrus::consensus::encode::deserialize(data); } -#[cfg(feature = "afl")] -#[macro_use] extern crate afl; -#[cfg(feature = "afl")] -fn main() { - fuzz!(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { @@ -24,16 +13,16 @@ fn main() { } } -#[cfg(test)] +#[cfg(all(test, fuzzing))] mod tests { fn extend_vec_from_hex(hex: &str, out: &mut Vec) { let mut b = 0; for (idx, c) in hex.as_bytes().iter().enumerate() { b <<= 4; match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', _ => panic!("Bad hex"), } if (idx & 1) == 1 { diff --git a/fuzz/fuzz_targets/tapyrus/deserialize_prefilled_transaction.rs b/fuzz/fuzz_targets/tapyrus/deserialize_prefilled_transaction.rs new file mode 100644 index 00000000..02c66243 --- /dev/null +++ b/fuzz/fuzz_targets/tapyrus/deserialize_prefilled_transaction.rs @@ -0,0 +1,50 @@ +use honggfuzz::fuzz; + +fn do_test(data: &[u8]) { + // We already fuzz Transactions in `./deserialize_transaction.rs`. + let tx_result: Result = + tapyrus::consensus::encode::deserialize(data); + + match tx_result { + Err(_) => {} + Ok(tx) => { + let ser = tapyrus::consensus::encode::serialize(&tx); + assert_eq!(&ser[..], data); + } + } +} + +fn main() { + loop { + fuzz!(|data| { + do_test(data); + }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00000000", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/tapyrus/deserialize_psbt.rs b/fuzz/fuzz_targets/tapyrus/deserialize_psbt.rs new file mode 100644 index 00000000..760191e0 --- /dev/null +++ b/fuzz/fuzz_targets/tapyrus/deserialize_psbt.rs @@ -0,0 +1,49 @@ +use honggfuzz::fuzz; + +fn do_test(data: &[u8]) { + let psbt: Result = tapyrus::psbt::Psbt::deserialize(data); + match psbt { + Err(_) => {} + Ok(psbt) => { + let ser = tapyrus::psbt::Psbt::serialize(&psbt); + let deser = tapyrus::psbt::Psbt::deserialize(&ser).unwrap(); + // Since the fuzz data could order psbt fields differently, we compare to our deser/ser instead of data + assert_eq!(ser, tapyrus::psbt::Psbt::serialize(&deser)); + } + } +} + +fn main() { + loop { + fuzz!(|data| { + do_test(data); + }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/deserialize_script.rs b/fuzz/fuzz_targets/tapyrus/deserialize_script.rs similarity index 61% rename from fuzz/fuzz_targets/deserialize_script.rs rename to fuzz/fuzz_targets/tapyrus/deserialize_script.rs index e7c36de0..973f1542 100644 --- a/fuzz/fuzz_targets/deserialize_script.rs +++ b/fuzz/fuzz_targets/tapyrus/deserialize_script.rs @@ -1,27 +1,29 @@ -extern crate bitcoin; - -use bitcoin::util::address::Address; -use bitcoin::network::constants::Network; -use bitcoin::blockdata::script; -use bitcoin::consensus::encode; +use honggfuzz::fuzz; +use tapyrus::address::Address; +use tapyrus::blockdata::script; +use tapyrus::consensus::encode; +use tapyrus::Network; fn do_test(data: &[u8]) { - let s: Result = encode::deserialize(data); + let s: Result = encode::deserialize(data); if let Ok(script) = s { - let _: Vec = script.iter(false).collect(); - let enforce_min: Vec = script.iter(true).collect(); + let _: Result, script::Error> = script.instructions().collect(); let mut b = script::Builder::new(); - for ins in enforce_min { - match ins { - script::Instruction::Error(_) => return, - script::Instruction::Op(op) => { b = b.push_opcode(op); } + for ins in script.instructions_minimal() { + if ins.is_err() { + return; + } + match ins.ok().unwrap() { + script::Instruction::Op(op) => { + b = b.push_opcode(op); + } script::Instruction::PushBytes(bytes) => { // Any one-byte pushes, except -0, which can be interpreted as numbers, should be // reserialized as numbers. (For -1 through 16, this will use special ops; for // others it'll just reserialize them as pushes.) if bytes.len() == 1 && bytes[0] != 0x80 && bytes[0] != 0x00 { - if let Ok(num) = script::read_scriptint(bytes) { + if let Ok(num) = script::read_scriptint(bytes.as_bytes()) { b = b.push_int(num); } else { b = b.push_slice(bytes); @@ -36,24 +38,12 @@ fn do_test(data: &[u8]) { assert_eq!(data, &encode::serialize(&script)[..]); // Check if valid address and if that address roundtrips. - if let Some(addr) = Address::from_script(&script, Network::Bitcoin) { + if let Ok(addr) = Address::from_script(&script, Network::Prod) { assert_eq!(addr.script_pubkey(), script); } } } -#[cfg(feature = "afl")] -#[macro_use] extern crate afl; -#[cfg(feature = "afl")] -fn main() { - fuzz!(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { @@ -62,16 +52,16 @@ fn main() { } } -#[cfg(test)] +#[cfg(all(test, fuzzing))] mod tests { fn extend_vec_from_hex(hex: &str, out: &mut Vec) { let mut b = 0; for (idx, c) in hex.as_bytes().iter().enumerate() { b <<= 4; match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', _ => panic!("Bad hex"), } if (idx & 1) == 1 { diff --git a/fuzz/fuzz_targets/tapyrus/deserialize_transaction.rs b/fuzz/fuzz_targets/tapyrus/deserialize_transaction.rs new file mode 100644 index 00000000..064fcc22 --- /dev/null +++ b/fuzz/fuzz_targets/tapyrus/deserialize_transaction.rs @@ -0,0 +1,55 @@ +use honggfuzz::fuzz; + +fn do_test(data: &[u8]) { + let tx_result: Result = + tapyrus::consensus::encode::deserialize(data); + match tx_result { + Err(_) => {} + Ok(mut tx) => { + let ser = tapyrus::consensus::encode::serialize(&tx); + assert_eq!(&ser[..], data); + let len = ser.len(); + let calculated_weight = tx.weight().to_wu() as usize; + for input in &mut tx.input { + input.witness = tapyrus::blockdata::witness::Witness::default(); + } + let no_witness_len = tapyrus::consensus::encode::serialize(&tx).len(); + assert_eq!(no_witness_len * 3 + len, calculated_weight); + } + } +} + +fn main() { + loop { + fuzz!(|data| { + do_test(data); + }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("000700000001000000010000", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/tapyrus/deserialize_witness.rs b/fuzz/fuzz_targets/tapyrus/deserialize_witness.rs new file mode 100644 index 00000000..92b975e7 --- /dev/null +++ b/fuzz/fuzz_targets/tapyrus/deserialize_witness.rs @@ -0,0 +1,46 @@ +use honggfuzz::fuzz; +use tapyrus::blockdata::witness::Witness; +use tapyrus::consensus::{deserialize, serialize}; + +fn do_test(data: &[u8]) { + let w: Result = deserialize(data); + if let Ok(witness) = w { + let serialized = serialize(&witness); + assert_eq!(data, &serialized[..]); + } +} + +fn main() { + loop { + fuzz!(|data| { + do_test(data); + }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/fuzz_targets/outpoint_string.rs b/fuzz/fuzz_targets/tapyrus/outpoint_string.rs similarity index 65% rename from fuzz/fuzz_targets/outpoint_string.rs rename to fuzz/fuzz_targets/tapyrus/outpoint_string.rs index ed2d3fee..64989354 100644 --- a/fuzz/fuzz_targets/outpoint_string.rs +++ b/fuzz/fuzz_targets/tapyrus/outpoint_string.rs @@ -1,21 +1,22 @@ - -extern crate bitcoin; - -use bitcoin::blockdata::transaction::OutPoint; -use bitcoin::consensus::encode; - use std::str::FromStr; +use honggfuzz::fuzz; +use tapyrus::blockdata::transaction::OutPoint; +use tapyrus::consensus::encode; + fn do_test(data: &[u8]) { - let lowercase: Vec = data.iter().map(|c| match *c { - b'A' => b'a', - b'B' => b'b', - b'C' => b'c', - b'D' => b'd', - b'E' => b'e', - b'F' => b'f', - x => x - }).collect(); + let lowercase: Vec = data + .iter() + .map(|c| match *c { + b'A' => b'a', + b'B' => b'b', + b'C' => b'c', + b'D' => b'd', + b'E' => b'e', + b'F' => b'f', + x => x, + }) + .collect(); let data_str = match String::from_utf8(lowercase) { Err(_) => return, Ok(s) => s, @@ -33,25 +34,13 @@ fn do_test(data: &[u8]) { let string = deser.to_string(); match OutPoint::from_str(&string) { Ok(destring) => assert_eq!(destring, deser), - Err(_) => panic!() + Err(_) => panic!(), } } } } } -#[cfg(feature = "afl")] -#[macro_use] extern crate afl; -#[cfg(feature = "afl")] -fn main() { - fuzz!(|data| { - do_test(&data); - }); -} - -#[cfg(feature = "honggfuzz")] -#[macro_use] extern crate honggfuzz; -#[cfg(feature = "honggfuzz")] fn main() { loop { fuzz!(|data| { @@ -60,16 +49,16 @@ fn main() { } } -#[cfg(test)] +#[cfg(all(test, fuzzing))] mod tests { fn extend_vec_from_hex(hex: &str, out: &mut Vec) { let mut b = 0; for (idx, c) in hex.as_bytes().iter().enumerate() { b <<= 4; match *c { - b'A'...b'F' => b |= c - b'A' + 10, - b'a'...b'f' => b |= c - b'a' + 10, - b'0'...b'9' => b |= c - b'0', + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', _ => panic!("Bad hex"), } if (idx & 1) == 1 { diff --git a/fuzz/fuzz_targets/tapyrus/script_bytes_to_asm_fmt.rs b/fuzz/fuzz_targets/tapyrus/script_bytes_to_asm_fmt.rs new file mode 100644 index 00000000..2a41b09e --- /dev/null +++ b/fuzz/fuzz_targets/tapyrus/script_bytes_to_asm_fmt.rs @@ -0,0 +1,52 @@ +use std::fmt; + +use honggfuzz::fuzz; + +// faster than String, we don't need to actually produce the value, just check absence of panics +struct NullWriter; + +impl fmt::Write for NullWriter { + fn write_str(&mut self, _s: &str) -> fmt::Result { Ok(()) } + + fn write_char(&mut self, _c: char) -> fmt::Result { Ok(()) } +} + +fn do_test(data: &[u8]) { + let mut writer = NullWriter; + tapyrus::Script::from_bytes(data).fmt_asm(&mut writer).unwrap(); +} + +fn main() { + loop { + fuzz!(|data| { + do_test(data); + }); + } +} + +#[cfg(all(test, fuzzing))] +mod tests { + fn extend_vec_from_hex(hex: &str, out: &mut Vec) { + let mut b = 0; + for (idx, c) in hex.as_bytes().iter().enumerate() { + b <<= 4; + match *c { + b'A'..=b'F' => b |= c - b'A' + 10, + b'a'..=b'f' => b |= c - b'a' + 10, + b'0'..=b'9' => b |= c - b'0', + _ => panic!("Bad hex"), + } + if (idx & 1) == 1 { + out.push(b); + b = 0; + } + } + } + + #[test] + fn duplicate_crash() { + let mut a = Vec::new(); + extend_vec_from_hex("00000", &mut a); + super::do_test(&a); + } +} diff --git a/fuzz/generate-files.sh b/fuzz/generate-files.sh new file mode 100755 index 00000000..c16770ce --- /dev/null +++ b/fuzz/generate-files.sh @@ -0,0 +1,103 @@ +#!/usr/bin/env bash + +set -e + +REPO_DIR=$(git rev-parse --show-toplevel) + +# shellcheck source=./fuzz-util.sh +source "$REPO_DIR/fuzz/fuzz-util.sh" + +# 1. Generate fuzz/Cargo.toml +cat > "$REPO_DIR/fuzz/Cargo.toml" <> "$REPO_DIR/fuzz/Cargo.toml" < "$REPO_DIR/.github/workflows/fuzz.yml" <executed_\${{ matrix.fuzz_target }} + - uses: actions/upload-artifact@v3 + with: + name: executed_\${{ matrix.fuzz_target }} + path: executed_\${{ matrix.fuzz_target }} + + verify-execution: + if: \${{ !github.event.act }} + needs: fuzz + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v3 + - name: Display structure of downloaded files + run: ls -R + - run: find executed_* -type f -exec cat {} + | sort > executed + - run: source ./fuzz/fuzz-util.sh && listTargetNames | sort | diff - executed +EOF + diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/132dec80e89477d962a7bd0d20947063.00000077.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/132dec80e89477d962a7bd0d20947063.00000077.honggfuzz.cov deleted file mode 100644 index e133fd44..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/132dec80e89477d962a7bd0d20947063.00000077.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/24fc2c1884453115fa0b1f2a758a8696.0000034c.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/24fc2c1884453115fa0b1f2a758a8696.0000034c.honggfuzz.cov deleted file mode 100644 index ca7f418c..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/24fc2c1884453115fa0b1f2a758a8696.0000034c.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/2d32100000000000323d000000000000.00000002.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/2d32100000000000323d000000000000.00000002.honggfuzz.cov deleted file mode 100644 index 852f75b9..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/2d32100000000000323d000000000000.00000002.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -'0 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/3096e01ac84d84540d122233010feba6.000004cf.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/3096e01ac84d84540d122233010feba6.000004cf.honggfuzz.cov deleted file mode 100644 index e80229f4..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/3096e01ac84d84540d122233010feba6.000004cf.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/36413cf2bc1e6cf57d77335d0f348928.00000047.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/36413cf2bc1e6cf57d77335d0f348928.00000047.honggfuzz.cov deleted file mode 100644 index c2538676..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/36413cf2bc1e6cf57d77335d0f348928.00000047.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/467ad0f85000000078708ab670000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/467ad0f85000000078708ab670000000.00000004.honggfuzz.cov deleted file mode 100644 index c0648a18..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/467ad0f85000000078708ab670000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[8 u \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/51110622200000005266211140000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/51110622200000005266211140000000.00000004.honggfuzz.cov deleted file mode 100644 index ec747fa4..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/51110622200000005266211140000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/57fd8d882850000078282d8da7800000.00000005.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/57fd8d882850000078282d8da7800000.00000005.honggfuzz.cov deleted file mode 100644 index e22e541d..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/57fd8d882850000078282d8da7800000.00000005.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[[]]h \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/70e4556ab8a8c7dcc2338dfa4891f4ae.000000a6.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/70e4556ab8a8c7dcc2338dfa4891f4ae.000000a6.honggfuzz.cov deleted file mode 100644 index e4dbc88c..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/70e4556ab8a8c7dcc2338dfa4891f4ae.000000a6.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{"v2-26518032317924925183̶*NkkkkkkkkkR05 뱝0d:PVPp":9 } 뱝0d:PVVPp":9 PVPp":9 u 뱝0d:PVVPp8:9 P \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/74606c62f539e4d5935525e03e92a40e.00000109.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/74606c62f539e4d5935525e03e92a40e.00000109.honggfuzz.cov deleted file mode 100644 index a0f1e52c..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/74606c62f539e4d5935525e03e92a40e.00000109.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/77ec8eda1dccae702efb36b0adf0e18f.00000165.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/77ec8eda1dccae702efb36b0adf0e18f.00000165.honggfuzz.cov deleted file mode 100644 index 47d68df6..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/77ec8eda1dccae702efb36b0adf0e18f.00000165.honggfuzz.cov +++ /dev/null @@ -1,2 +0,0 @@ -{"v0d:PVPp":9 ,"83622040NkkkkkkkkkRv5 뱝0d:PVPp":9 -7858362224003565858VPp":9 v3Zrۦ( -?*ef9i"*(r܇]1Y":9 u뱝0d:PVVPp3̶FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/7bea4e2285010eb3cf4acb9b1203841b.0000007b.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/7bea4e2285010eb3cf4acb9b1203841b.0000007b.honggfuzz.cov deleted file mode 100644 index 375c7326..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/7bea4e2285010eb3cf4acb9b1203841b.0000007b.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/7cd702cb9c81e396ff5433e1b716e343.0000056e.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/7cd702cb9c81e396ff5433e1b716e343.0000056e.honggfuzz.cov deleted file mode 100644 index dec57403..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/7cd702cb9c81e396ff5433e1b716e343.0000056e.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000002_orig-0ee00000000000000ee0000000000000.00000001.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000002_orig-0ee00000000000000ee0000000000000.00000001.honggfuzz.cov deleted file mode 100644 index 8b137891..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000002_orig-0ee00000000000000ee0000000000000.00000001.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ - diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000003_orig-108d4836be71e10731359b612fcb840b.000010b4.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000003_orig-108d4836be71e10731359b612fcb840b.000010b4.honggfuzz.cov deleted file mode 100644 index 92fbbcf0..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000003_orig-108d4836be71e10731359b612fcb840b.000010b4.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000004_orig-123fcb7f3b8bc4bc500d63157d0d25ff.00001d58.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000004_orig-123fcb7f3b8bc4bc500d63157d0d25ff.00001d58.honggfuzz.cov deleted file mode 100644 index d80ce6b1..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000004_orig-123fcb7f3b8bc4bc500d63157d0d25ff.00001d58.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000005_orig-12dfa93ad99f88fc4f2053d53480c3e5.00000d84.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000005_orig-12dfa93ad99f88fc4f2053d53480c3e5.00000d84.honggfuzz.cov deleted file mode 100644 index a3731f31..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000005_orig-12dfa93ad99f88fc4f2053d53480c3e5.00000d84.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000007_orig-1e82e6b16644739bc1095df2d0075c0b.00000097.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000007_orig-1e82e6b16644739bc1095df2d0075c0b.00000097.honggfuzz.cov deleted file mode 100644 index 0b1e19e6..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000007_orig-1e82e6b16644739bc1095df2d0075c0b.00000097.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000008_orig-1e9b9cbf5c7959604b0d1c83097d1345.00001520.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000008_orig-1e9b9cbf5c7959604b0d1c83097d1345.00001520.honggfuzz.cov deleted file mode 100644 index 74badb19..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000008_orig-1e9b9cbf5c7959604b0d1c83097d1345.00001520.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[""7-5 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000009_orig-20ae411d2fd000002ffd211e40800000.00000005.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000009_orig-20ae411d2fd000002ffd211e40800000.00000005.honggfuzz.cov deleted file mode 100644 index b6b3dc08..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000009_orig-20ae411d2fd000002ffd211e40800000.00000005.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -30928 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000012_orig-288e5e0e600000002e5e0e48a0000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000012_orig-288e5e0e600000002e5e0e48a0000000.00000004.honggfuzz.cov deleted file mode 100644 index 804f8bff..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000012_orig-288e5e0e600000002e5e0e48a0000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -2.26 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000013_orig-2a4d69685000000078792d6a70000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000013_orig-2a4d69685000000078792d6a70000000.00000004.honggfuzz.cov deleted file mode 100644 index 890011b0..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000013_orig-2a4d69685000000078792d6a70000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[7,5 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000017_orig-334c35e4651b52f2061d4fe13e60a281.00000214.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000017_orig-334c35e4651b52f2061d4fe13e60a281.00000214.honggfuzz.cov deleted file mode 100644 index bf291a94..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000017_orig-334c35e4651b52f2061d4fe13e60a281.00000214.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000018_orig-397e6000000000002e59500000000000.00000002.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000018_orig-397e6000000000002e59500000000000.00000002.honggfuzz.cov deleted file mode 100644 index a9bcb243..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000018_orig-397e6000000000002e59500000000000.00000002.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -2+ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000020_orig-3cde6000000000002e5cf00000000000.00000002.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000020_orig-3cde6000000000002e5cf00000000000.00000002.honggfuzz.cov deleted file mode 100644 index 998d1104..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000020_orig-3cde6000000000002e5cf00000000000.00000002.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -2- \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000021_orig-3cf00000000000003cf0000000000000.00000001.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000021_orig-3cf00000000000003cf0000000000000.00000001.honggfuzz.cov deleted file mode 100644 index 3cf20d57..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000021_orig-3cf00000000000003cf0000000000000.00000001.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -- \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000023_orig-47c000000000000047c0000000000000.00000001.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000023_orig-47c000000000000047c0000000000000.00000001.honggfuzz.cov deleted file mode 100644 index 32f64f4d..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000023_orig-47c000000000000047c0000000000000.00000001.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -t \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000024_orig-4e500000000000004e50000000000000.00000001.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000024_orig-4e500000000000004e50000000000000.00000001.honggfuzz.cov deleted file mode 100644 index 81750b96..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000024_orig-4e500000000000004e50000000000000.00000001.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000026_orig-53cfa000000000005ff3900000000000.00000002.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000026_orig-53cfa000000000005ff3900000000000.00000002.honggfuzz.cov deleted file mode 100644 index e0a6c666..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000026_orig-53cfa000000000005ff3900000000000.00000002.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -fo \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000027_orig-54c0ad00000000002d20d4e000000000.00000003.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000027_orig-54c0ad00000000002d20d4e000000000.00000003.honggfuzz.cov deleted file mode 100644 index 4fc953f0..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000027_orig-54c0ad00000000002d20d4e000000000.00000003.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -08j \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000028_orig-5631cf21cf4a9e2d44df21cf21f52d69.0000000e.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000028_orig-5631cf21cf4a9e2d44df21cf21f52d69.0000000e.honggfuzz.cov deleted file mode 100644 index 57608ac4..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000028_orig-5631cf21cf4a9e2d44df21cf21f52d69.0000000e.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000029_orig-57f82d882850000078282d8807800000.00000005.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000029_orig-57f82d882850000078282d8807800000.00000005.honggfuzz.cov deleted file mode 100644 index f3e2f82b..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000029_orig-57f82d882850000078282d8807800000.00000005.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[[][h \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000031_orig-57fddbb82850000078287bbda7800000.00000005.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000031_orig-57fddbb82850000078287bbda7800000.00000005.honggfuzz.cov deleted file mode 100644 index 57025ac5..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000031_orig-57fddbb82850000078287bbda7800000.00000005.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[[4]h \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000032_orig-5d2d2d5a700000002a2d2d2d70000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000032_orig-5d2d2d5a700000002a2d2d2d70000000.00000004.honggfuzz.cov deleted file mode 100644 index e969b4b3..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000032_orig-5d2d2d5a700000002a2d2d2d70000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -5eee \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000035_orig-6d59154edc9107406929538201922082.00000248.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000035_orig-6d59154edc9107406929538201922082.00000248.honggfuzz.cov deleted file mode 100644 index 774af0af..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000035_orig-6d59154edc9107406929538201922082.00000248.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000037_orig-705e4e493e4e5e0e6f5e0e4e493e4e4a.00000008.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000037_orig-705e4e493e4e5e0e6f5e0e4e493e4e4a.00000008.honggfuzz.cov deleted file mode 100644 index b38d997a..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000037_orig-705e4e493e4e5e0e6f5e0e4e493e4e4a.00000008.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -2.227225 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000040_orig-761f0bedebcfac240c2affec91115bfd.00000011.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000040_orig-761f0bedebcfac240c2affec91115bfd.00000011.honggfuzz.cov deleted file mode 100644 index 8c08ecf4..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000040_orig-761f0bedebcfac240c2affec91115bfd.00000011.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -2.322947127462735 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000041_orig-77c36463d3da4ba27232b488be74d652.00000443.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000041_orig-77c36463d3da4ba27232b488be74d652.00000443.honggfuzz.cov deleted file mode 100644 index 48b9a17c..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000041_orig-77c36463d3da4ba27232b488be74d652.00000443.honggfuzz.cov +++ /dev/null @@ -1,4 +0,0 @@ -{"v0d:PVh Pu_IBAƿX{?a0Glw#g:NҐI^YOn~Xjo Pp":9 ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ix*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":{"v0d:PVh Pu_IBAƿX{?a0Glw#g:NҐI^YOn~Xjo Pp":9 ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ix*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":{"v0d:PVh Pu_IBAƿX{?a0Glw#g:NҐI^YOn~Xjo Pp":9 ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ix*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":9 }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||, \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000042_orig-77d7557f54289c91e217b85d989facd8.00000018.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000042_orig-77d7557f54289c91e217b85d989facd8.00000018.honggfuzz.cov deleted file mode 100644 index a64e3821..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000042_orig-77d7557f54289c91e217b85d989facd8.00000018.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -0.3329481833294518658410 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000044_orig-78500000000000007850000000000000.00000001.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000044_orig-78500000000000007850000000000000.00000001.honggfuzz.cov deleted file mode 100644 index 8e2f0bef..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000044_orig-78500000000000007850000000000000.00000001.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000047_orig-7dc55518500000007865551df0000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000047_orig-7dc55518500000007865551df0000000.00000004.honggfuzz.cov deleted file mode 100644 index 93b6be2b..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000047_orig-7dc55518500000007865551df0000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[""] \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000048_orig-7eedadd9a00e3b31fcb0884b16349723.00000014.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000048_orig-7eedadd9a00e3b31fcb0884b16349723.00000014.honggfuzz.cov deleted file mode 100644 index 635e7b69..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000048_orig-7eedadd9a00e3b31fcb0884b16349723.00000014.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ --7010909841481319489 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000049_orig-8d5ec8a00000000028ae6d5000000000.00000003.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000049_orig-8d5ec8a00000000028ae6d5000000000.00000003.honggfuzz.cov deleted file mode 100644 index e664d1b5..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000049_orig-8d5ec8a00000000028ae6d5000000000.00000003.honggfuzz.cov +++ /dev/null @@ -1,2 +0,0 @@ -6 - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000052_orig-a3a3fd51b18fec92a2a7beeffed8cae3.00000018.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000052_orig-a3a3fd51b18fec92a2a7beeffed8cae3.00000018.honggfuzz.cov deleted file mode 100644 index e26fee6a..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000052_orig-a3a3fd51b18fec92a2a7beeffed8cae3.00000018.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000055_orig-a9f6021f1f65e0dc27de93336aabd27c.000018d9.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000055_orig-a9f6021f1f65e0dc27de93336aabd27c.000018d9.honggfuzz.cov deleted file mode 100644 index 789cd047..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000055_orig-a9f6021f1f65e0dc27de93336aabd27c.000018d9.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000056_orig-ada1751ee6257eb5e41676e7942f2cee.0000018c.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000056_orig-ada1751ee6257eb5e41676e7942f2cee.0000018c.honggfuzz.cov deleted file mode 100644 index ad41a6b0..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000056_orig-ada1751ee6257eb5e41676e7942f2cee.0000018c.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000057_orig-aebd22b8a4eaea84473de8f7af92b9e8.00000010.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000057_orig-aebd22b8a4eaea84473de8f7af92b9e8.00000010.honggfuzz.cov deleted file mode 100644 index 74515b63..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000057_orig-aebd22b8a4eaea84473de8f7af92b9e8.00000010.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -2.32294718384932 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000058_orig-bb2dbbbe28500000781e1b8d4b500000.00000005.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000058_orig-bb2dbbbe28500000781e1b8d4b500000.00000005.honggfuzz.cov deleted file mode 100644 index 75f66321..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000058_orig-bb2dbbbe28500000781e1b8d4b500000.00000005.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[{}] \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000059_orig-bfff1b9d411fec33960462c7c10fff37.00000015.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000059_orig-bfff1b9d411fec33960462c7c10fff37.00000015.honggfuzz.cov deleted file mode 100644 index fac0d071..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000059_orig-bfff1b9d411fec33960462c7c10fff37.00000015.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ --0.89846310859469617 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000061_orig-c10ddce82b9fbc814168922cd0a8c702.00000cd9.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000061_orig-c10ddce82b9fbc814168922cd0a8c702.00000cd9.honggfuzz.cov deleted file mode 100644 index c99f102b..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000061_orig-c10ddce82b9fbc814168922cd0a8c702.00000cd9.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[[4]]5 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000062_orig-cba6d94806f7b566cb25b3da0ef0c600.0000111f.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000062_orig-cba6d94806f7b566cb25b3da0ef0c600.0000111f.honggfuzz.cov deleted file mode 100644 index 91b7cf5b..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000062_orig-cba6d94806f7b566cb25b3da0ef0c600.0000111f.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000063_orig-d40f0232cbdf1d50812e29256f1fd27c.000002e7.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000063_orig-d40f0232cbdf1d50812e29256f1fd27c.000002e7.honggfuzz.cov deleted file mode 100644 index 40c54f91..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000063_orig-d40f0232cbdf1d50812e29256f1fd27c.000002e7.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000064_orig-d706a550b181d5068db96ee44a07c478.000000b7.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000064_orig-d706a550b181d5068db96ee44a07c478.000000b7.honggfuzz.cov deleted file mode 100644 index 115f5a52..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000064_orig-d706a550b181d5068db96ee44a07c478.000000b7.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000065_orig-d7b9d4f86a11cd25d4fef32dc4e27948.000001d6.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000065_orig-d7b9d4f86a11cd25d4fef32dc4e27948.000001d6.honggfuzz.cov deleted file mode 100644 index 5b4000e1..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000065_orig-d7b9d4f86a11cd25d4fef32dc4e27948.000001d6.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000067_orig-db66e14c0e5000004e2c61361b600000.00000005.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000067_orig-db66e14c0e5000004e2c61361b600000.00000005.honggfuzz.cov deleted file mode 100644 index a63c371b..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000067_orig-db66e14c0e5000004e2c61361b600000.00000005.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{\9 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000068_orig-e177cb82e1fdef491f2140a923efd3ed.000001d6.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_decimal/input/id-000068_orig-e177cb82e1fdef491f2140a923efd3ed.000001d6.honggfuzz.cov deleted file mode 100644 index 24f5f82e..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000068_orig-e177cb82e1fdef491f2140a923efd3ed.000001d6.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000080_src-000000_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000080_src-000000_op-havoc_rep-32 deleted file mode 100644 index d6ddb445..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000080_src-000000_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000083_src-000000_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000083_src-000000_op-havoc_rep-8 deleted file mode 100644 index 52420837..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000083_src-000000_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000084_src-000000_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000084_src-000000_op-havoc_rep-4 deleted file mode 100644 index fec3dfd2..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000084_src-000000_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000086_src-000000_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000086_src-000000_op-havoc_rep-16 deleted file mode 100644 index 5eb264df..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000086_src-000000_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000090_src-000000_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000090_src-000000_op-havoc_rep-8 deleted file mode 100644 index 14c37392..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000090_src-000000_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000093_src-000000_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000093_src-000000_op-havoc_rep-128 deleted file mode 100644 index b5f49a5b..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000093_src-000000_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000097_src-000000_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000097_src-000000_op-havoc_rep-64 deleted file mode 100644 index 0ce4cb24..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000097_src-000000_op-havoc_rep-64 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000098_src-000000_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000098_src-000000_op-havoc_rep-32 deleted file mode 100644 index 0c8f4c03..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000098_src-000000_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000099_src-000000_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000099_src-000000_op-havoc_rep-64 deleted file mode 100644 index 18194e57..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000099_src-000000_op-havoc_rep-64 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000100_src-000000_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000100_src-000000_op-havoc_rep-16 deleted file mode 100644 index 1da1c48e..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000100_src-000000_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000104_src-000000_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000104_src-000000_op-havoc_rep-64 deleted file mode 100644 index 2514619c..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000104_src-000000_op-havoc_rep-64 +++ /dev/null @@ -1 +0,0 @@ -"4#@>4\"" \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000105_src-000000_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000105_src-000000_op-havoc_rep-128 deleted file mode 100644 index a12847e4..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000105_src-000000_op-havoc_rep-128 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000107_src-000001_op-flip1_pos-77 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000107_src-000001_op-flip1_pos-77 deleted file mode 100644 index dbaa009d..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000107_src-000001_op-flip1_pos-77 +++ /dev/null @@ -1 +0,0 @@ -"4#-5!S57VgAظ7i<N\u1471\u471\u1471\u1471\u1471\u1471\u\u\ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000112_src-000001_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000112_src-000001_op-havoc_rep-4 deleted file mode 100644 index 09f08443..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000112_src-000001_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -"4#-5\u1471\u1471\u1471\u1471\u1471\u1471\u1471\u1471\u1471\u\u\ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000114_src-000001_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000114_src-000001_op-havoc_rep-8 deleted file mode 100644 index 36de43b2..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000114_src-000001_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ -"4#-5!S57VgAظ7i<N\u1471\u1471\\ZB471\u1471\d \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000115_src-000001_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000115_src-000001_op-havoc_rep-64 deleted file mode 100644 index e4da3fc9..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000115_src-000001_op-havoc_rep-64 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000116_src-000001_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000116_src-000001_op-havoc_rep-128 deleted file mode 100644 index 011a33b5..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000116_src-000001_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000118_src-000001_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000118_src-000001_op-havoc_rep-64 deleted file mode 100644 index 70ed709c..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000118_src-000001_op-havoc_rep-64 +++ /dev/null @@ -1 +0,0 @@ -[[[[HV \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000124_src-000001_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000124_src-000001_op-havoc_rep-128 deleted file mode 100644 index e8d6f4f5..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000124_src-000001_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000125_src-000006_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000125_src-000006_op-havoc_rep-128 deleted file mode 100644 index 8e39ac29..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000125_src-000006_op-havoc_rep-128 +++ /dev/null @@ -1 +0,0 @@ -1E \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000126_src-000008_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000126_src-000008_op-havoc_rep-8 deleted file mode 100644 index 5d77a2e2..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000126_src-000008_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ -[[[5d5 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000127_src-000008_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000127_src-000008_op-havoc_rep-8 deleted file mode 100644 index 70f8ae2b..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000127_src-000008_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000128_src-000008_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000128_src-000008_op-havoc_rep-4 deleted file mode 100644 index 20bfef46..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000128_src-000008_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -[["?- \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000129_src-000008_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000129_src-000008_op-havoc_rep-8 deleted file mode 100644 index 6df3c2c7..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000129_src-000008_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ -[ " \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000130_src-000008_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000130_src-000008_op-havoc_rep-128 deleted file mode 100644 index d0b81a19..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000130_src-000008_op-havoc_rep-128 +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  - - - - - - - diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000132_src-000008_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000132_src-000008_op-havoc_rep-8 deleted file mode 100644 index 16ec7290..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000132_src-000008_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ -[--------------------9"@ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000133_src-000008_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000133_src-000008_op-havoc_rep-32 deleted file mode 100644 index 16f741c5..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000133_src-000008_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000135_src-000008_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000135_src-000008_op-havoc_rep-16 deleted file mode 100644 index 8643d998..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000135_src-000008_op-havoc_rep-16 +++ /dev/null @@ -1 +0,0 @@ -nuu \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000137_src-000008_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000137_src-000008_op-havoc_rep-2 deleted file mode 100644 index 40c502d0..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000137_src-000008_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -----5 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000138_src-000008_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000138_src-000008_op-havoc_rep-2 deleted file mode 100644 index 5693cfda..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000138_src-000008_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ ---5 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000139_src-000008_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000139_src-000008_op-havoc_rep-128 deleted file mode 100644 index e2017f6c..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000139_src-000008_op-havoc_rep-128 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000141_src-000008_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000141_src-000008_op-havoc_rep-2 deleted file mode 100644 index 43bdfe7e..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000141_src-000008_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ ---------------------------------[""7-F \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000142_src-000010_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000142_src-000010_op-havoc_rep-32 deleted file mode 100644 index c7d525fc..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000142_src-000010_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000143_src-000010_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000143_src-000010_op-havoc_rep-128 deleted file mode 100644 index 3f3a1afb..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000143_src-000010_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000145_src-000011_op-flip4_pos-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000145_src-000011_op-flip4_pos-4 deleted file mode 100644 index 334c7a67..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000145_src-000011_op-flip4_pos-4 +++ /dev/null @@ -1 +0,0 @@ -2.7E,KF83 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000146_src-000011_op-int8_pos-5_val-+32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000146_src-000011_op-int8_pos-5_val-+32 deleted file mode 100644 index 58bc77c3..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000146_src-000011_op-int8_pos-5_val-+32 +++ /dev/null @@ -1 +0,0 @@ -2.7E+ F83 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000147_src-000013_op-arith8_pos-3_val--21 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000147_src-000013_op-arith8_pos-3_val--21 deleted file mode 100644 index 0b2f985d..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000147_src-000013_op-arith8_pos-3_val--21 +++ /dev/null @@ -1 +0,0 @@ -[7, \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000149_src-000016_op-flip1_pos-79 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000149_src-000016_op-flip1_pos-79 deleted file mode 100644 index f41001f2..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000149_src-000016_op-flip1_pos-79 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000150_src-000018_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000150_src-000018_op-havoc_rep-64 deleted file mode 100644 index 05ab0776..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000150_src-000018_op-havoc_rep-64 +++ /dev/null @@ -1 +0,0 @@ - 0  M \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000152_src-000028_op-flip1_pos-5 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000152_src-000028_op-flip1_pos-5 deleted file mode 100644 index f58a2661..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000152_src-000028_op-flip1_pos-5 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000153_src-000028_op-flip1_pos-7 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000153_src-000028_op-flip1_pos-7 deleted file mode 100644 index 002d6cbf..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000153_src-000028_op-flip1_pos-7 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000155_src-000028_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000155_src-000028_op-havoc_rep-4 deleted file mode 100644 index c7f042f6..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000155_src-000028_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000157_src-000028_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000157_src-000028_op-havoc_rep-2 deleted file mode 100644 index a14ea541..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000157_src-000028_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000158_src-000028_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000158_src-000028_op-havoc_rep-2 deleted file mode 100644 index 5e63c5a6..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000158_src-000028_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000160_src-000030_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000160_src-000030_op-havoc_rep-8 deleted file mode 100644 index 3b3c2479..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000160_src-000030_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ -[[[]] \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000161_src-000036_op-flip1_pos-12 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000161_src-000036_op-flip1_pos-12 deleted file mode 100644 index 60302fc7..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000161_src-000036_op-flip1_pos-12 +++ /dev/null @@ -1 +0,0 @@ --7010909849.01319480 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000163_src-000039_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000163_src-000039_op-havoc_rep-64 deleted file mode 100644 index 18732492..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000163_src-000039_op-havoc_rep-64 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000165_src-000043_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000165_src-000043_op-havoc_rep-8 deleted file mode 100644 index 0fb0e76e..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000165_src-000043_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ -{"v0dPp":9 ,"8362p":9 ,"22040Nkkk뱝0d:PVPp":9 -7 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000168_src-000060_op-arith8_pos-544_val-+18 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000168_src-000060_op-arith8_pos-544_val-+18 deleted file mode 100644 index 74519565..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000168_src-000060_op-arith8_pos-544_val-+18 +++ /dev/null @@ -1,2 +0,0 @@ -{"v0d:PVh Pu_IBAƿX{?a0Gnw#g:NҐI^YOn~Xjo Pp":9 ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ix*,DڢbY'Eč2b#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":9 ,"83622040NkikkkkkkkRn~Xjo Pp":9 ,"8362204040NkkkkkkkkkRv5 뱝08673586266809954039-Pp":9 ,"83622040NkikkkkkkkRn~Xjo Pp":9 ,"83622040NkkkkkkkkkRv5 뱝0d:PVPp":9 }kkk \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000171_src-000060_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000171_src-000060_op-havoc_rep-16 deleted file mode 100644 index 9d248a93..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000171_src-000060_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000172_src-000060_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000172_src-000060_op-havoc_rep-128 deleted file mode 100644 index 6cc03186..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000172_src-000060_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000175_src-000061_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000175_src-000061_op-havoc_rep-4 deleted file mode 100644 index e1eb3d2c..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000175_src-000061_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -[[[[4]]]54]<5 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000176_src-000061_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000176_src-000061_op-havoc_rep-2 deleted file mode 100644 index c8ce1e27..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000176_src-000061_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -[[[4]]#[4]]# \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000177_src-000062_op-arith8_pos-167_val--35 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000177_src-000062_op-arith8_pos-167_val--35 deleted file mode 100644 index 4fb7fddc..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000177_src-000062_op-arith8_pos-167_val--35 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000178_src-000062_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000178_src-000062_op-havoc_rep-32 deleted file mode 100644 index fc0c1970..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000178_src-000062_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000180_src-000065_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000180_src-000065_op-havoc_rep-4 deleted file mode 100644 index cbb1d4ce..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000180_src-000065_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000181_src-000070_op-flip1_pos-2 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000181_src-000070_op-flip1_pos-2 deleted file mode 100644 index 1b7b7133..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000181_src-000070_op-flip1_pos-2 +++ /dev/null @@ -1,4 +0,0 @@ -{"0d:PVh Pu_IBAƿX{?a0Glw#g:NҐI^YOn~Xjo Pp":9 ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ix*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":{"v0d:PVh Pu_IBAƿX{?a0Glw#g:NҐI^YOn~Xjo Pp":9 ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ix*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":{"v0d:PVh Pu_IBAƿX{?a0Glw#g:NҐI^YOn~Xjo Pp":9 ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ix*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":9 ,"83622040NkikkkkkkkRn~Xjo Pp":9}Zd# \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000187_src-000070_op-flip1_pos-686 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000187_src-000070_op-flip1_pos-686 deleted file mode 100644 index 7f8fc72d..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000187_src-000070_op-flip1_pos-686 +++ /dev/null @@ -1,4 +0,0 @@ -{"v0d:PVh Pu_IBAƿX{?a0Glw#g:NҐI^YOn~Xjo Pp":9 ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ix*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":{"v0d:PVh Pu_IBAƿX{?a0Glw#g:NҐI^YOn~Xjo Pp":9 ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ix*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":{"v0d:PVh Pu_IBAƿX{?a0Glw#g:NҐI^YOn~Xjo Pp": ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ix*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":9 ,"83622040NkikkkkkkkRn~Xjo Pp":9}Zd# \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000189_src-000070_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000189_src-000070_op-havoc_rep-32 deleted file mode 100644 index 92c974f8..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000189_src-000070_op-havoc_rep-32 +++ /dev/null @@ -1,3 +0,0 @@ -{"v0d:PVh Pu_IBAƿX{?YOn~Xjo Pp111111111111111111111111ѬTO'2EO dG@wYWZ$Y(1=y=#ix*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkRv5x 뱝08673586266809954039-Pp":{"v0d:PVh PWZ$Y(1=y=#ix*,Du_IBAƿX{?a0Glw#g:Rv5I^Y836220tQ -TO'2EO d@@wڢbY'Y(1=y#ix*,DڢbY'Eč2}#'JaL-qok.b~40NkkkkkkkkkRvTO'2EO d0d:PdVgPu_IBOn~XaL-;w#g:^ҐIqYOn~Xjo Pp"99 ,"836220tQ -TO'2EO d@@wYWZ$Y(1=y=#ex*,DڢbY'Eč2}#'JaL-;r]qok.b~40NkkkkkkkkkRv5 뱝08673586266809954039-Pp":9 G"83622040NkikkkkkkkRTmXjo Pp":9}Zd# \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000190_src-000070_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000190_src-000070_op-havoc_rep-64 deleted file mode 100644 index 788c2695..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000190_src-000070_op-havoc_rep-64 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000193_src-000070_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000193_src-000070_op-havoc_rep-32 deleted file mode 100644 index ccc22dad..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000193_src-000070_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000194_src-000070_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000194_src-000070_op-havoc_rep-32 deleted file mode 100644 index 6a2d83df..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000194_src-000070_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000195_src-000070_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000195_src-000070_op-havoc_rep-64 deleted file mode 100644 index a71635c2..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000195_src-000070_op-havoc_rep-64 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000196_src-000102_op-flip1_pos-52 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000196_src-000102_op-flip1_pos-52 deleted file mode 100644 index 2392a355..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000196_src-000102_op-flip1_pos-52 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000197_src-000102_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000197_src-000102_op-havoc_rep-16 deleted file mode 100644 index c1f389b7..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000197_src-000102_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000199_src-000104_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000199_src-000104_op-havoc_rep-4 deleted file mode 100644 index f22acca2..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000199_src-000104_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -"<#>4\"@>4\"\"" \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000200_src-000110_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000200_src-000110_op-havoc_rep-2 deleted file mode 100644 index 0e439e61..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000200_src-000110_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -"4U1\u1471\u1471\u1471\u1471\u1471\u1471\u1471#N\u1471\u1471?u1471\u1471\u1471\u1471\u\u\ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000203_src-000114_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000203_src-000114_op-havoc_rep-32 deleted file mode 100644 index d062943f..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000203_src-000114_op-havoc_rep-32 +++ /dev/null @@ -1 +0,0 @@ -"\u \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000204_src-000114_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000204_src-000114_op-havoc_rep-4 deleted file mode 100644 index 30a08576..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000204_src-000114_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -"i<N\u1471\u1471\\Z4#-5)S57VgAظ7i<N\u1471\u1471\\ZB47N\u1471\d \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000205_src-000149_op-arith8_pos-210_val--6 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000205_src-000149_op-arith8_pos-210_val--6 deleted file mode 100644 index a893376f..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000205_src-000149_op-arith8_pos-210_val--6 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000206_src-000149_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000206_src-000149_op-havoc_rep-32 deleted file mode 100644 index 8937e859..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000206_src-000149_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000207_src-000151_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000207_src-000151_op-havoc_rep-2 deleted file mode 100644 index e9c625b8..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000207_src-000151_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -[7.3,7.. \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000208_src-000172_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000208_src-000172_op-havoc_rep-8 deleted file mode 100644 index 3ad291c9..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000208_src-000172_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000209_src-000172_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000209_src-000172_op-havoc_rep-8 deleted file mode 100644 index 881c3d74..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000209_src-000172_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000210_src-000180_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000210_src-000180_op-havoc_rep-4 deleted file mode 100644 index 7f88af8d..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000210_src-000180_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000211_src-000180_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000211_src-000180_op-havoc_rep-16 deleted file mode 100644 index d49733e0..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000211_src-000180_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000212_src-000018_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000212_src-000018_op-havoc_rep-8 deleted file mode 100644 index 22123993..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000212_src-000018_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ -[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[w[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[+[+[ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000214_src-000025_op-arith8_pos-5_val--9 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000214_src-000025_op-arith8_pos-5_val--9 deleted file mode 100644 index 3f05825e..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000214_src-000025_op-arith8_pos-5_val--9 +++ /dev/null @@ -1 +0,0 @@ --10.0089898414813184 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000215_src-000067_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000215_src-000067_op-havoc_rep-4 deleted file mode 100644 index d817d8a2..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000215_src-000067_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -{ , \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000217_src-000095_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000217_src-000095_op-havoc_rep-16 deleted file mode 100644 index 9b3150c8..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000217_src-000095_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000223_src-000095_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000223_src-000095_op-havoc_rep-128 deleted file mode 100644 index e4bcfffa..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000223_src-000095_op-havoc_rep-128 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000224_src-000121_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000224_src-000121_op-havoc_rep-4 deleted file mode 100644 index 758198ce..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000224_src-000121_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000226_src-000121_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000226_src-000121_op-havoc_rep-64 deleted file mode 100644 index e5682522..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000226_src-000121_op-havoc_rep-64 +++ /dev/null @@ -1 +0,0 @@ - 7Y \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000227_src-000121_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000227_src-000121_op-havoc_rep-16 deleted file mode 100644 index e69de29b..00000000 diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000228_src-000227_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000228_src-000227_op-havoc_rep-4 deleted file mode 100644 index 3bd5e62a..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000228_src-000227_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -"4#-\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\1\u1471au41wu\u\ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000229_src-000227_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000229_src-000227_op-havoc_rep-8 deleted file mode 100644 index 4fc68d24..00000000 --- a/fuzz/hfuzz_input/deserialize_decimal/input/id-000229_src-000227_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ ---------------------------------------------------------------------------------------------------------------------------------"#--b\ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000230_src-000015_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000230_src-000015_op-havoc_rep-128 deleted file mode 100644 index 2a3a092c..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000230_src-000015_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_decimal/input/id-000231_src-000015_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_decimal/input/id-000231_src-000015_op-havoc_rep-16 deleted file mode 100644 index 49334343..00000000 Binary files a/fuzz/hfuzz_input/deserialize_decimal/input/id-000231_src-000015_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/091c677536b4cdd0e0933edcb2f53213.00001d71.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/091c677536b4cdd0e0933edcb2f53213.00001d71.honggfuzz.cov deleted file mode 100644 index e9dc8e0a..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/091c677536b4cdd0e0933edcb2f53213.00001d71.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/0ee00000000000000ee0000000000000.00000001.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/0ee00000000000000ee0000000000000.00000001.honggfuzz.cov deleted file mode 100644 index 8b137891..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/0ee00000000000000ee0000000000000.00000001.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ - diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/19d007141504156035041504277019d0.00000007.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/19d007141504156035041504277019d0.00000007.honggfuzz.cov deleted file mode 100644 index 5b75d83f..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/19d007141504156035041504277019d0.00000007.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/2d897328aaf93f1998dd6bca1836848d.00000441.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/2d897328aaf93f1998dd6bca1836848d.00000441.honggfuzz.cov deleted file mode 100644 index 385601a9..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/2d897328aaf93f1998dd6bca1836848d.00000441.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/3e1e013000000000210e1e2000000000.00000003.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/3e1e013000000000210e1e2000000000.00000003.honggfuzz.cov deleted file mode 100644 index 78d83348..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/3e1e013000000000210e1e2000000000.00000003.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -9.. \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/4da14ef30de3322fc98aef037a303e0d.00000018.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/4da14ef30de3322fc98aef037a303e0d.00000018.honggfuzz.cov deleted file mode 100644 index 6b2f926d..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/4da14ef30de3322fc98aef037a303e0d.00000018.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -0.6607817016591206817018 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/598a5e032ede3ed1662401c66f5611e0.0000049c.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/598a5e032ede3ed1662401c66f5611e0.0000049c.honggfuzz.cov deleted file mode 100644 index 228534aa..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/598a5e032ede3ed1662401c66f5611e0.0000049c.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/7c75552e500000004e65551c40000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/7c75552e500000004e65551c40000000.00000004.honggfuzz.cov deleted file mode 100644 index b20c53d8..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/7c75552e500000004e65551c40000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{""\ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/7d8828500000000078282df000000000.00000003.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/7d8828500000000078282df000000000.00000003.honggfuzz.cov deleted file mode 100644 index 8e493586..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/7d8828500000000078282df000000000.00000003.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[[] \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/8b3e1a5bccf16edc5fc472cc6a059ac8.00000b21.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/8b3e1a5bccf16edc5fc472cc6a059ac8.00000b21.honggfuzz.cov deleted file mode 100644 index 0f100ab9..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/8b3e1a5bccf16edc5fc472cc6a059ac8.00000b21.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/bfa25b5017821f0f58530174be1fff90.000001c9.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/bfa25b5017821f0f58530174be1fff90.000001c9.honggfuzz.cov deleted file mode 100644 index 0ff40951..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/bfa25b5017821f0f58530174be1fff90.000001c9.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/d6cfbe4b90ca21e2b1092f4ff8a52983.00000092.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/d6cfbe4b90ca21e2b1092f4ff8a52983.00000092.honggfuzz.cov deleted file mode 100644 index 2a5a74f8..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/d6cfbe4b90ca21e2b1092f4ff8a52983.00000092.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/ecfae34af81663d62f734894509973be.0000001e.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/ecfae34af81663d62f734894509973be.0000001e.honggfuzz.cov deleted file mode 100644 index b750fcbc..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/ecfae34af81663d62f734894509973be.0000001e.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{"":-3,"":-3,"":3,"":-3,"":3,S \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/ee6ca66fbfb43256b2b02562b261e566.00000473.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/ee6ca66fbfb43256b2b02562b261e566.00000473.honggfuzz.cov deleted file mode 100644 index 083654a5..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/ee6ca66fbfb43256b2b02562b261e566.00000473.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000001_orig-003cdbfcf00000003cdbfcf000000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000001_orig-003cdbfcf00000003cdbfcf000000000.00000004.honggfuzz.cov deleted file mode 100644 index 4a167fc3..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000001_orig-003cdbfcf00000003cdbfcf000000000.00000004.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000002_orig-004bbe1bbe5000004e1bbe1bf0000000.00000005.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000002_orig-004bbe1bbe5000004e1bbe1bf0000000.00000005.honggfuzz.cov deleted file mode 100644 index afcb0c48..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000002_orig-004bbe1bbe5000004e1bbe1bf0000000.00000005.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{}{} \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000003_orig-007d8dde1828500078287e1d8df00000.00000006.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000003_orig-007d8dde1828500078287e1d8df00000.00000006.honggfuzz.cov deleted file mode 100644 index b78de4c3..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000003_orig-007d8dde1828500078287e1d8df00000.00000006.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000005_orig-0ac5552e500000004e65556af0000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000005_orig-0ac5552e500000004e65556af0000000.00000004.honggfuzz.cov deleted file mode 100644 index 3550ddb7..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000005_orig-0ac5552e500000004e65556af0000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{"" \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000006_orig-0adbc000000000002bcaf00000000000.00000002.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000006_orig-0adbc000000000002bcaf00000000000.00000002.honggfuzz.cov deleted file mode 100644 index be162472..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000006_orig-0adbc000000000002bcaf00000000000.00000002.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -4 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000009_orig-134ec2407d3c5889df6cf9e04424cff3.000008d7.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000009_orig-134ec2407d3c5889df6cf9e04424cff3.000008d7.honggfuzz.cov deleted file mode 100644 index cbb65b8f..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000009_orig-134ec2407d3c5889df6cf9e04424cff3.000008d7.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[[]]326 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000011_orig-20a0be0130000000210e00a080000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000011_orig-20a0be0130000000210e00a080000000.00000004.honggfuzz.cov deleted file mode 100644 index d477568d..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000011_orig-20a0be0130000000210e00a080000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -9.88 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000012_orig-20be013000000000210e008000000000.00000003.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000012_orig-20be013000000000210e008000000000.00000003.honggfuzz.cov deleted file mode 100644 index 5a00ea9c..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000012_orig-20be013000000000210e008000000000.00000003.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -9.8 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000014_orig-23d5552e500000004e655543e0000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000014_orig-23d5552e500000004e655543e0000000.00000004.honggfuzz.cov deleted file mode 100644 index 17d04514..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000014_orig-23d5552e500000004e655543e0000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{"": \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000015_orig-2bb8500000000000787bc00000000000.00000002.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000015_orig-2bb8500000000000787bc00000000000.00000002.honggfuzz.cov deleted file mode 100644 index 57efe083..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000015_orig-2bb8500000000000787bc00000000000.00000002.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[4 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000016_orig-2bfd69685000000078792d6bc0000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000016_orig-2bfd69685000000078792d6bc0000000.00000004.honggfuzz.cov deleted file mode 100644 index 8703a157..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000016_orig-2bfd69685000000078792d6bc0000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[7,4 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000017_orig-2c9c9d2c8e013000210e0c9d2c9cb000.00000006.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000017_orig-2c9c9d2c8e013000210e0c9d2c9cb000.00000006.honggfuzz.cov deleted file mode 100644 index f20a46ab..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000017_orig-2c9c9d2c8e013000210e0c9d2c9cb000.00000006.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -9.1011 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000018_orig-2d2bebebc00000002bebebed00000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000018_orig-2d2bebebc00000002bebebed00000000.00000004.honggfuzz.cov deleted file mode 100644 index a569be7e..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000018_orig-2d2bebebc00000002bebebed00000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -4440 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000020_orig-2e4177c00000000047e11e6000000000.00000003.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000020_orig-2e4177c00000000047e11e6000000000.00000003.honggfuzz.cov deleted file mode 100644 index 3bf14bc8..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000020_orig-2e4177c00000000047e11e6000000000.00000003.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -t92 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000021_orig-2e494d4cf00000003cad593e60000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000021_orig-2e494d4cf00000003cad593e60000000.00000004.honggfuzz.cov deleted file mode 100644 index 206cc257..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000021_orig-2e494d4cf00000003cad593e60000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ --e72 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000022_orig-32100000000000003210000000000000.00000001.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000022_orig-32100000000000003210000000000000.00000001.honggfuzz.cov deleted file mode 100644 index ad2823b4..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000022_orig-32100000000000003210000000000000.00000001.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -' \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000023_orig-36000000000000003600000000000000.00000001.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000023_orig-36000000000000003600000000000000.00000001.honggfuzz.cov deleted file mode 100644 index 0519ecba..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000023_orig-36000000000000003600000000000000.00000001.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000025_orig-393b5bebc00000002bebab4950000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000025_orig-393b5bebc00000002bebab4950000000.00000004.honggfuzz.cov deleted file mode 100644 index 61ff7db5..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000025_orig-393b5bebc00000002bebab4950000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -44E+ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000027_orig-44772822d5bcd735bd3496d55c266f39.00001e09.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000027_orig-44772822d5bcd735bd3496d55c266f39.00001e09.honggfuzz.cov deleted file mode 100644 index 0a5c28ef..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000027_orig-44772822d5bcd735bd3496d55c266f39.00001e09.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000028_orig-4a301bea76c496cbe93fc11d316243a8.00000025.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000028_orig-4a301bea76c496cbe93fc11d316243a8.00000025.honggfuzz.cov deleted file mode 100644 index 924623b4..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000028_orig-4a301bea76c496cbe93fc11d316243a8.00000025.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{"":-3,"":{"":-3,"":{"":-3,"":-39}z \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000029_orig-4e500000000000004e50000000000000.00000001.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000029_orig-4e500000000000004e50000000000000.00000001.honggfuzz.cov deleted file mode 100644 index 81750b96..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000029_orig-4e500000000000004e50000000000000.00000001.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000031_orig-531aecc7a327406fbc818647b2747231.00000332.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000031_orig-531aecc7a327406fbc818647b2747231.00000332.honggfuzz.cov deleted file mode 100644 index 58200562..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000031_orig-531aecc7a327406fbc818647b2747231.00000332.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000033_orig-5fa00000000000005fa0000000000000.00000001.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000033_orig-5fa00000000000005fa0000000000000.00000001.honggfuzz.cov deleted file mode 100644 index 4d1ae35b..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000033_orig-5fa00000000000005fa0000000000000.00000001.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -f \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000034_orig-6618a9cb08e58ca994025c6b5884b728.000002a6.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000034_orig-6618a9cb08e58ca994025c6b5884b728.000002a6.honggfuzz.cov deleted file mode 100644 index dd38eefa..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000034_orig-6618a9cb08e58ca994025c6b5884b728.000002a6.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000035_orig-6b1f7658418934df57e359338f3d17b4.0000075c.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000035_orig-6b1f7658418934df57e359338f3d17b4.0000075c.honggfuzz.cov deleted file mode 100644 index f1759044..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000035_orig-6b1f7658418934df57e359338f3d17b4.0000075c.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{"":-3,"":{"":-3,"":{"":-3,"":-39}}}1L2 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000037_orig-6b6848a2730c22267bf9d90037a40bfe.00000441.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000037_orig-6b6848a2730c22267bf9d90037a40bfe.00000441.honggfuzz.cov deleted file mode 100644 index e8cdef7b..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000037_orig-6b6848a2730c22267bf9d90037a40bfe.00000441.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000042_orig-7c834de7a99556aff16ff256ddf39c78.0000009a.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000042_orig-7c834de7a99556aff16ff256ddf39c78.0000009a.honggfuzz.cov deleted file mode 100644 index 80ffdd2a..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000042_orig-7c834de7a99556aff16ff256ddf39c78.0000009a.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{"":""p \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000045_orig-7dde18285000000078287e1df0000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000045_orig-7dde18285000000078287e1df0000000.00000004.honggfuzz.cov deleted file mode 100644 index 7cd359c2..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000045_orig-7dde18285000000078287e1df0000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[[2] \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000049_orig-8d5edcf0000000003cfe6d5000000000.00000003.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000049_orig-8d5edcf0000000003cfe6d5000000000.00000003.honggfuzz.cov deleted file mode 100644 index 9c3a6bc1..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000049_orig-8d5edcf0000000003cfe6d5000000000.00000003.honggfuzz.cov +++ /dev/null @@ -1,2 +0,0 @@ -- - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000052_orig-93dbf628a000000028962b53f0000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000052_orig-93dbf628a000000028962b53f0000000.00000004.honggfuzz.cov deleted file mode 100644 index 5f6f4ce9..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000052_orig-93dbf628a000000028962b53f0000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -6 4 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000054_orig-9e2ff69a90c666a7063d85e22473fb79.00000012.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000054_orig-9e2ff69a90c666a7063d85e22473fb79.00000012.honggfuzz.cov deleted file mode 100644 index 25402ed0..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000054_orig-9e2ff69a90c666a7063d85e22473fb79.00000012.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{"":{}}:}} \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000056_orig-a8f294d39b025d6f3e7b21a5d442ed75.0000000d.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000056_orig-a8f294d39b025d6f3e7b21a5d442ed75.0000000d.honggfuzz.cov deleted file mode 100644 index 3de3f0ec..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000056_orig-a8f294d39b025d6f3e7b21a5d442ed75.0000000d.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{"":-3,"":-39 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000057_orig-a8f73f40773f1bb509a83cddc7672957.00000015.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000057_orig-a8f73f40773f1bb509a83cddc7672957.00000015.honggfuzz.cov deleted file mode 100644 index d0f7bbff..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000057_orig-a8f73f40773f1bb509a83cddc7672957.00000015.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ --3521667332658478285, \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000058_orig-b033c968500000007879335010000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000058_orig-b033c968500000007879335010000000.00000004.honggfuzz.cov deleted file mode 100644 index 1cb727e1..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000058_orig-b033c968500000007879335010000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -[7: \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000059_orig-b3644d6846422333e6651c8ae420b443.00000012.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000059_orig-b3644d6846422333e6651c8ae420b443.00000012.honggfuzz.cov deleted file mode 100644 index 37a05fa8..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000059_orig-b3644d6846422333e6651c8ae420b443.00000012.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000064_orig-c4cf70f203705977ad13bc992ac28e5e.0000159e.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000064_orig-c4cf70f203705977ad13bc992ac28e5e.0000159e.honggfuzz.cov deleted file mode 100644 index 996e6a9b..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000064_orig-c4cf70f203705977ad13bc992ac28e5e.0000159e.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -{"":-3,"":-39}z S[ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000065_orig-ced1987ddea38cce8a3955f7dc3f6600.00001895.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000065_orig-ced1987ddea38cce8a3955f7dc3f6600.00001895.honggfuzz.cov deleted file mode 100644 index 2aeac383..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000065_orig-ced1987ddea38cce8a3955f7dc3f6600.00001895.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -9.660739332658478285,\n \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000069_orig-e05663d17cebb565f03a6cbab766ff92.00000014.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000069_orig-e05663d17cebb565f03a6cbab766ff92.00000014.honggfuzz.cov deleted file mode 100644 index 6e97d15f..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000069_orig-e05663d17cebb565f03a6cbab766ff92.00000014.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000070_orig-e28c4e864c2dbaea77f8c3c28daaeedd.00000047.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000070_orig-e28c4e864c2dbaea77f8c3c28daaeedd.00000047.honggfuzz.cov deleted file mode 100644 index 4e165140..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000070_orig-e28c4e864c2dbaea77f8c3c28daaeedd.00000047.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000071_orig-ec2fb20e1a37aadffb3f2b5914bf3678.00000048.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000071_orig-ec2fb20e1a37aadffb3f2b5914bf3678.00000048.honggfuzz.cov deleted file mode 100644 index 1441ff5d..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000071_orig-ec2fb20e1a37aadffb3f2b5914bf3678.00000048.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000074_orig-f49e0b5a700000002a1b5e94b0000000.00000004.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000074_orig-f49e0b5a700000002a1b5e94b0000000.00000004.honggfuzz.cov deleted file mode 100644 index 7c81cee5..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000074_orig-f49e0b5a700000002a1b5e94b0000000.00000004.honggfuzz.cov +++ /dev/null @@ -1 +0,0 @@ -5E2 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000075_orig-f6546e628a7644857fe5143a8a438bb4.00000141.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000075_orig-f6546e628a7644857fe5143a8a438bb4.00000141.honggfuzz.cov deleted file mode 100644 index 842ef770..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000075_orig-f6546e628a7644857fe5143a8a438bb4.00000141.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000076_orig-fce0f4557885f35c7f2568ce9c36c826.00000dcc.honggfuzz.cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000076_orig-fce0f4557885f35c7f2568ce9c36c826.00000dcc.honggfuzz.cov deleted file mode 100644 index 87283e5a..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000076_orig-fce0f4557885f35c7f2568ce9c36c826.00000dcc.honggfuzz.cov and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000078_src-000000_op-arith8_pos-3_val-+34 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000078_src-000000_op-arith8_pos-3_val-+34 deleted file mode 100644 index 2d201497..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000078_src-000000_op-arith8_pos-3_val-+34 +++ /dev/null @@ -1 +0,0 @@ -"N" \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000079_src-000000_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000079_src-000000_op-havoc_rep-2 deleted file mode 100644 index a311f3a9..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000079_src-000000_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -"NN \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000080_src-000000_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000080_src-000000_op-havoc_rep-16 deleted file mode 100644 index 708a8853..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000080_src-000000_op-havoc_rep-16 +++ /dev/null @@ -1 +0,0 @@ -"P5@555%5 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000082_src-000000_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000082_src-000000_op-havoc_rep-64 deleted file mode 100644 index 991aa1a5..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000082_src-000000_op-havoc_rep-64 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000083_src-000000_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000083_src-000000_op-havoc_rep-32 deleted file mode 100644 index 0aff809b..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000083_src-000000_op-havoc_rep-32 +++ /dev/null @@ -1 +0,0 @@ -9. \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000086_src-000000_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000086_src-000000_op-havoc_rep-16 deleted file mode 100644 index 5ed6c9d1..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000086_src-000000_op-havoc_rep-16 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000088_src-000000_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000088_src-000000_op-havoc_rep-128 deleted file mode 100644 index 0597d13d..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000088_src-000000_op-havoc_rep-128 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000090_src-000000_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000090_src-000000_op-havoc_rep-8 deleted file mode 100644 index 34cefe37..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000090_src-000000_op-havoc_rep-8 +++ /dev/null @@ -1,6 +0,0 @@ - - - - - -" \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000091_src-000000_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000091_src-000000_op-havoc_rep-4 deleted file mode 100644 index ecdaac08..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000091_src-000000_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000094_src-000000_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000094_src-000000_op-havoc_rep-2 deleted file mode 100644 index 8e35157e..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000094_src-000000_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000095_src-000000_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000095_src-000000_op-havoc_rep-8 deleted file mode 100644 index 8e6472d5..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000095_src-000000_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ -[[[[[[[[[[[ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000096_src-000000_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000096_src-000000_op-havoc_rep-128 deleted file mode 100644 index b0fcb7b4..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000096_src-000000_op-havoc_rep-128 +++ /dev/null @@ -1 +0,0 @@ -  \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000097_src-000000_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000097_src-000000_op-havoc_rep-128 deleted file mode 100644 index af756f67..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000097_src-000000_op-havoc_rep-128 +++ /dev/null @@ -1 +0,0 @@ -66666666666666666666666666666666 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000098_src-000000_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000098_src-000000_op-havoc_rep-32 deleted file mode 100644 index b28b04f6..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000098_src-000000_op-havoc_rep-32 +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000099_src-000000_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000099_src-000000_op-havoc_rep-16 deleted file mode 100644 index 16b8c2c7..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000099_src-000000_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000100_src-000000_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000100_src-000000_op-havoc_rep-128 deleted file mode 100644 index 1aa5bb46..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000100_src-000000_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000101_src-000000_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000101_src-000000_op-havoc_rep-64 deleted file mode 100644 index 1f240327..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000101_src-000000_op-havoc_rep-64 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000103_src-000000_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000103_src-000000_op-havoc_rep-16 deleted file mode 100644 index 92971a2f..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000103_src-000000_op-havoc_rep-16 +++ /dev/null @@ -1 +0,0 @@ -[[[[[[[ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000105_src-000000_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000105_src-000000_op-havoc_rep-128 deleted file mode 100644 index 7141e096..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000105_src-000000_op-havoc_rep-128 +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000106_src-000000_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000106_src-000000_op-havoc_rep-16 deleted file mode 100644 index ef939988..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000106_src-000000_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000112_src-000003_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000112_src-000003_op-havoc_rep-4 deleted file mode 100644 index d8555012..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000112_src-000003_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000113_src-000003_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000113_src-000003_op-havoc_rep-2 deleted file mode 100644 index ab475a04..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000113_src-000003_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000116_src-000003_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000116_src-000003_op-havoc_rep-8 deleted file mode 100644 index e976d76f..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000116_src-000003_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000117_src-000003_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000117_src-000003_op-havoc_rep-128 deleted file mode 100644 index a6cd9e56..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000117_src-000003_op-havoc_rep-128 +++ /dev/null @@ -1 +0,0 @@ -nuu \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000121_src-000007_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000121_src-000007_op-havoc_rep-2 deleted file mode 100644 index 3747b796..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000121_src-000007_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -9.4660739 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000122_src-000007_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000122_src-000007_op-havoc_rep-2 deleted file mode 100644 index cafa222b..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000122_src-000007_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -9.663333333333307,9 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000123_src-000007_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000123_src-000007_op-havoc_rep-8 deleted file mode 100644 index 0952686a..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000123_src-000007_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ -9eee \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000124_src-000011_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000124_src-000011_op-havoc_rep-16 deleted file mode 100644 index e8f4dd31..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000124_src-000011_op-havoc_rep-16 +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000125_src-000013_op-flip1_pos-1 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000125_src-000013_op-flip1_pos-1 deleted file mode 100644 index 34411686..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000125_src-000013_op-flip1_pos-1 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000130_src-000013_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000130_src-000013_op-havoc_rep-32 deleted file mode 100644 index bb262726..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000130_src-000013_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000131_src-000013_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000131_src-000013_op-havoc_rep-8 deleted file mode 100644 index 72938110..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000131_src-000013_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000134_src-000013_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000134_src-000013_op-havoc_rep-2 deleted file mode 100644 index 3f69021b..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000134_src-000013_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000135_src-000014_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000135_src-000014_op-havoc_rep-2 deleted file mode 100644 index ec3a7ee7..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000135_src-000014_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -{"":{1": \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000136_src-000016_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000136_src-000016_op-havoc_rep-2 deleted file mode 100644 index 75d1370d..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000136_src-000016_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -[777,7,4 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000137_src-000019_op-arith8_pos-249_val--14 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000137_src-000019_op-arith8_pos-249_val--14 deleted file mode 100644 index 7c8880bc..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000137_src-000019_op-arith8_pos-249_val--14 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000138_src-000019_op-arith8_pos-697_val-+10 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000138_src-000019_op-arith8_pos-697_val-+10 deleted file mode 100644 index 4a66b7f2..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000138_src-000019_op-arith8_pos-697_val-+10 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000139_src-000025_op-arith8_pos-0_val--7 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000139_src-000025_op-arith8_pos-0_val--7 deleted file mode 100644 index 0f414922..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000139_src-000025_op-arith8_pos-0_val--7 +++ /dev/null @@ -1 +0,0 @@ --4E+ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000140_src-000025_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000140_src-000025_op-havoc_rep-4 deleted file mode 100644 index 0ec527f3..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000140_src-000025_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -44E++4H+ \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000143_src-000031_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000143_src-000031_op-havoc_rep-128 deleted file mode 100644 index 608a7b7a..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000143_src-000031_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000144_src-000031_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000144_src-000031_op-havoc_rep-128 deleted file mode 100644 index 994527c6..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000144_src-000031_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000153_src-000035_op-flip1_pos-35 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000153_src-000035_op-flip1_pos-35 deleted file mode 100644 index e3c5084a..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000153_src-000035_op-flip1_pos-35 +++ /dev/null @@ -1 +0,0 @@ -{"":-3,"":{"":-3,"":{"":-3,"":-39}} \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000156_src-000035_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000156_src-000035_op-havoc_rep-2 deleted file mode 100644 index c7e6b5bb..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000156_src-000035_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -{"":-3,"":-3,"":-39}1L2 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000158_src-000035_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000158_src-000035_op-havoc_rep-2 deleted file mode 100644 index 42242393..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000158_src-000035_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -{"":-3,"":{"":-3,"":{"":-3,"":{"":-B,"":"":{"":-B,"":-39}}}1L2 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000159_src-000035_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000159_src-000035_op-havoc_rep-32 deleted file mode 100644 index 3951e677..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000159_src-000035_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000160_src-000035_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000160_src-000035_op-havoc_rep-4 deleted file mode 100644 index f3dde8b5..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000160_src-000035_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ ---------2 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000161_src-000037_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000161_src-000037_op-havoc_rep-8 deleted file mode 100644 index b19064f3..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000161_src-000037_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000162_src-000037_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000162_src-000037_op-havoc_rep-64 deleted file mode 100644 index 860312b7..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000162_src-000037_op-havoc_rep-64 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000163_src-000037_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000163_src-000037_op-havoc_rep-128 deleted file mode 100644 index 118ea208..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000163_src-000037_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000164_src-000046_op-flip1_pos-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000164_src-000046_op-flip1_pos-2 deleted file mode 100644 index e8f68db6..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000164_src-000046_op-flip1_pos-2 +++ /dev/null @@ -1 +0,0 @@ -[7.4,7,4,6 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000167_src-000047_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000167_src-000047_op-havoc_rep-2 deleted file mode 100644 index 9e8d5b08..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000167_src-000047_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000168_src-000047_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000168_src-000047_op-havoc_rep-8 deleted file mode 100644 index dacbc3c1..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000168_src-000047_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000169_src-000047_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000169_src-000047_op-havoc_rep-8 deleted file mode 100644 index 99a2ce5d..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000169_src-000047_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000174_src-000053_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000174_src-000053_op-havoc_rep-2 deleted file mode 100644 index 9bc9dc68..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000174_src-000053_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000175_src-000057_op-arith8_pos-3_val--4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000175_src-000057_op-arith8_pos-3_val--4 deleted file mode 100644 index 84fa52ce..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000175_src-000057_op-arith8_pos-3_val--4 +++ /dev/null @@ -1 +0,0 @@ --35.1667332658478285, \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000177_src-000062_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000177_src-000062_op-havoc_rep-8 deleted file mode 100644 index f41972df..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000177_src-000062_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000178_src-000062_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000178_src-000062_op-havoc_rep-4 deleted file mode 100644 index fb709cfd..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000178_src-000062_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -"N317720572651764D\u4265\"N72651764D\u4265\e4e4 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000179_src-000118_op-flip2_pos-3 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000179_src-000118_op-flip2_pos-3 deleted file mode 100644 index a654abb7..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000179_src-000118_op-flip2_pos-3 +++ /dev/null @@ -1 +0,0 @@ -9.000739 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000180_src-000129_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000180_src-000129_op-havoc_rep-2 deleted file mode 100644 index 99d225d5..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000180_src-000129_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -"\t\t%\t\t \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000182_src-000130_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000182_src-000130_op-havoc_rep-2 deleted file mode 100644 index da8c9afb..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000182_src-000130_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000183_src-000130_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000183_src-000130_op-havoc_rep-16 deleted file mode 100644 index a3b5ab00..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000183_src-000130_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000185_src-000168_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000185_src-000168_op-havoc_rep-4 deleted file mode 100644 index c10dadc8..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000185_src-000168_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000186_src-000170_op-flip1_pos-64 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000186_src-000170_op-flip1_pos-64 deleted file mode 100644 index 30875ca1..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000186_src-000170_op-flip1_pos-64 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000188_src-000170_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000188_src-000170_op-havoc_rep-4 deleted file mode 100644 index f517cbb5..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000188_src-000170_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000189_src-000171_op-flip1_pos-95 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000189_src-000171_op-flip1_pos-95 deleted file mode 100644 index d515290a..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000189_src-000171_op-flip1_pos-95 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000190_src-000178_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000190_src-000178_op-havoc_rep-8 deleted file mode 100644 index 0f999b1f..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000190_src-000178_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000191_src-000178_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000191_src-000178_op-havoc_rep-8 deleted file mode 100644 index d9934821..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000191_src-000178_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ -"N305726\u4265\"N726\"N72665\"N7D\u454665\"N7D\u4565\e4 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000192_src-000178_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000192_src-000178_op-havoc_rep-16 deleted file mode 100644 index ae376f11..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000192_src-000178_op-havoc_rep-16 +++ /dev/null @@ -1 +0,0 @@ -"N'3131720&6>\"776>\"770<65\"N76DP6 \e \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000195_src-000021_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000195_src-000021_op-havoc_rep-8 deleted file mode 100644 index 336ce216..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000195_src-000021_op-havoc_rep-8 +++ /dev/null @@ -1 +0,0 @@ ------------------------------------------- \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000198_src-000111_op-flip2_pos-27 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000198_src-000111_op-flip2_pos-27 deleted file mode 100644 index 170f2036..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000198_src-000111_op-flip2_pos-27 +++ /dev/null @@ -1 +0,0 @@ ----------------------------0 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000200_src-000113_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000200_src-000113_op-havoc_rep-2 deleted file mode 100644 index 07e9d0a8..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000200_src-000113_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000201_src-000114_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000201_src-000114_op-havoc_rep-2 deleted file mode 100644 index a67ce703..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000201_src-000114_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -[[[]]]]] \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000202_src-000116_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000202_src-000116_op-havoc_rep-16 deleted file mode 100644 index 320c0d1c..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000202_src-000116_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000204_src-000143_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000204_src-000143_op-havoc_rep-128 deleted file mode 100644 index 61ea6f89..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000204_src-000143_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000205_src-000157_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000205_src-000157_op-havoc_rep-2 deleted file mode 100644 index 1d3030a5..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000205_src-000157_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -{"":-3,"":{"":-3,"":{"":-3,"": -3,"": 339}},"": 339}r}1L2}1L2 \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000206_src-000159_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000206_src-000159_op-havoc_rep-2 deleted file mode 100644 index a3f8ee24..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000206_src-000159_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000208_src-000163_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000208_src-000163_op-havoc_rep-16 deleted file mode 100644 index 5c4a5df7..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000208_src-000163_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000210_src-000171_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000210_src-000171_op-havoc_rep-4 deleted file mode 100644 index 54b60f6d..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000210_src-000171_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000211_src-000180_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000211_src-000180_op-havoc_rep-4 deleted file mode 100644 index 0217032c..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000211_src-000180_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000212_src-000193_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000212_src-000193_op-havoc_rep-4 deleted file mode 100644 index 31ef4408..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000212_src-000193_op-havoc_rep-4 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000216_src-000201_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000216_src-000201_op-havoc_rep-2 deleted file mode 100644 index 3b9f6dba..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000216_src-000201_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -[[[[]]]u \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000218_src-000201_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000218_src-000201_op-havoc_rep-2 deleted file mode 100644 index b1a91ca9..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000218_src-000201_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -[[[[[[]]]] \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000221_src-000211_op-havoc_rep-8 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000221_src-000211_op-havoc_rep-8 deleted file mode 100644 index cec86934..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000221_src-000211_op-havoc_rep-8 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000222_src-000212_op-havoc_rep-16 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000222_src-000212_op-havoc_rep-16 deleted file mode 100644 index 8e9624c2..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000222_src-000212_op-havoc_rep-16 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000224_src-000214_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000224_src-000214_op-havoc_rep-2 deleted file mode 100644 index f46de6da..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000224_src-000214_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000225_src-000219_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000225_src-000219_op-havoc_rep-128 deleted file mode 100644 index 83ff2376..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000225_src-000219_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000226_src-000220_op-flip1_pos-445 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000226_src-000220_op-flip1_pos-445 deleted file mode 100644 index bcc7a374..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000226_src-000220_op-flip1_pos-445 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000228_src-000005_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000228_src-000005_op-havoc_rep-4 deleted file mode 100644 index fa9d9adc..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000228_src-000005_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000231_src-000029_op-havoc_rep-64 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000231_src-000029_op-havoc_rep-64 deleted file mode 100644 index 5a1b771a..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000231_src-000029_op-havoc_rep-64 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000232_src-000055_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000232_src-000055_op-havoc_rep-128 deleted file mode 100644 index 2ab95678..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000232_src-000055_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000233_src-000144_op-havoc_rep-128 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000233_src-000144_op-havoc_rep-128 deleted file mode 100644 index ca8becaa..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000233_src-000144_op-havoc_rep-128 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000234_src-000144_op-havoc_rep-32 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000234_src-000144_op-havoc_rep-32 deleted file mode 100644 index 4a079f5c..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000234_src-000144_op-havoc_rep-32 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000236_src-000203_op-havoc_rep-2_+cov b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000236_src-000203_op-havoc_rep-2_+cov deleted file mode 100644 index 45171232..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000236_src-000203_op-havoc_rep-2_+cov +++ /dev/null @@ -1 +0,0 @@ -null \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000239_src-000154_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000239_src-000154_op-havoc_rep-4 deleted file mode 100644 index e69de29b..00000000 diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000240_src-000154_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000240_src-000154_op-havoc_rep-4 deleted file mode 100644 index d6e34ca2..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000240_src-000154_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -{"{":-3,"":{"":-3,"":{"{":-3,"":{"{":-3,"":{"":-3,"":{"{":-3,"":{"":-3,"":{"":-3,"":-3,"":{"":-3,#":{"":-3,"":-39}}}1L""{"":-3,"":-3,"":{"":-3,"":{"":-3,""<-39}}}1L"":-3,"":{"":-3,"":-3,"":{"":-3,#":{"":-3,"":-39}}}1L""{"":-3,"":-3,"":{"":-3,"":{"":-3,"":-39}}}1L"" \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000241_src-000165_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000241_src-000165_op-havoc_rep-2 deleted file mode 100644 index a43b63db..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000241_src-000165_op-havoc_rep-2 +++ /dev/null @@ -1 +0,0 @@ -[7,4,7,[7,4,77,4,7,[7,4,7@, \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000242_src-000165_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000242_src-000165_op-havoc_rep-4 deleted file mode 100644 index 9c3a1d52..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000242_src-000165_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -[7,4]7,[774,@, \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000243_src-000165_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000243_src-000165_op-havoc_rep-4 deleted file mode 100644 index 68a89c87..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000243_src-000165_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -[7,437,[7E47,437,[7E4,?,@,,7,@, \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000244_src-000165_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000244_src-000165_op-havoc_rep-4 deleted file mode 100644 index 1e3b2760..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000244_src-000165_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -[7,4,4,7,[7,4,74,4,7,[7,4,7,,4,7,@,[7,4 7,@, \ No newline at end of file diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000245_src-000173_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000245_src-000173_op-havoc_rep-2 deleted file mode 100644 index ff91b19b..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000245_src-000173_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000246_src-000185_op-havoc_rep-2 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000246_src-000185_op-havoc_rep-2 deleted file mode 100644 index 040d0100..00000000 Binary files a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000246_src-000185_op-havoc_rep-2 and /dev/null differ diff --git a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000247_src-000191_op-havoc_rep-4 b/fuzz/hfuzz_input/deserialize_udecimal/input/id-000247_src-000191_op-havoc_rep-4 deleted file mode 100644 index 98c1328a..00000000 --- a/fuzz/hfuzz_input/deserialize_udecimal/input/id-000247_src-000191_op-havoc_rep-4 +++ /dev/null @@ -1 +0,0 @@ -"305726\u4265\"N726\"N72665\"N7?\u4265\"N726\"N72665\"N7D\u454665\"N7D\\u45 665\"N7D\u4565\e4 \ No newline at end of file diff --git a/fuzz/travis-fuzz.sh b/fuzz/travis-fuzz.sh deleted file mode 100755 index 8f699815..00000000 --- a/fuzz/travis-fuzz.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -set -e - -# Check that input files are correct Windows file names -incorrectFilenames=$(find . -type f -name "*,*" -o -name "*:*" -o -name "*<*" -o -name "*>*" -o -name "*|*" -o -name "*\?*" -o -name "*\**" -o -name "*\"*" | wc -l) - -if [ ${incorrectFilenames} -gt 0 ]; then - exit 2 -fi - -# Testing -cargo install --force honggfuzz -for TARGET in fuzz_targets/*; do - FILENAME=$(basename $TARGET) - FILE="${FILENAME%.*}" - if [ -d hfuzz_input/$FILE ]; then - HFUZZ_INPUT_ARGS="-f hfuzz_input/$FILE/input" - fi - HFUZZ_BUILD_ARGS="--features honggfuzz_fuzz" HFUZZ_RUN_ARGS="--run_time 30 --exit_upon_crash -v $HFUZZ_INPUT_ARGS" cargo hfuzz run $FILE - - if [ -f hfuzz_workspace/$FILE/HONGGFUZZ.REPORT.TXT ]; then - cat hfuzz_workspace/$FILE/HONGGFUZZ.REPORT.TXT - for CASE in hfuzz_workspace/$FILE/SIG*; do - cat $CASE | xxd -p - done - exit 1 - fi -done diff --git a/githooks/pre-commit b/githooks/pre-commit new file mode 100755 index 00000000..5bb2c486 --- /dev/null +++ b/githooks/pre-commit @@ -0,0 +1,52 @@ +#!/bin/sh +# +# Verify what is about to be committed. Called by "git commit" with no +# arguments. The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=$(git hash-object -t tree /dev/null) +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +git diff-index --check --cached $against -- || exit 1 + +# Check that code lints cleanly. +cargo clippy --all-features -- -D warnings || exit 1 + +# Check that there are no formatting issues. +cargo +nightly fmt --check || exit 1 diff --git a/hashes/CHANGELOG.md b/hashes/CHANGELOG.md new file mode 100644 index 00000000..44d52f9c --- /dev/null +++ b/hashes/CHANGELOG.md @@ -0,0 +1,194 @@ +# 0.13.0 - 2023-06-29 + +The main improvement in this version is removal of the `hex` module in favour of the new +[`hex-conservative`](https://crates.io/crates/hex-conservative) crate (which we wrote). We also +bumped the Minimum Supported Rust Version across the `rust-bitcoin` ecosystem to v1.48 + +* Bump MSRV to 1.48.0 [#1729](https://github.com/rust-bitcoin/rust-bitcoin/pull/1729). +* Depend on new `hex-conservative` crate and remove `hex` module [#1883](https://github.com/rust-bitcoin/rust-bitcoin/pull/1833). +* Make `sha256t_hash_newtype!` evocative of the output [#1773](https://github.com/rust-bitcoin/rust-bitcoin/pull/1773). +* Implement computing SHA256 in const context [#1769](https://github.com/rust-bitcoin/rust-bitcoin/pull/1769). +* Add `from_bytes_ref` and `from_bytes_mut` to all hash types [#1761](https://github.com/rust-bitcoin/rust-bitcoin/pull/1761). +* Rename `crate::Error` to `crate::FromSliceError` [#1873](https://github.com/rust-bitcoin/rust-bitcoin/pull/1873). +* Add simd sha256 intrinsics for x86 machines [#1962](https://github.com/rust-bitcoin/rust-bitcoin/pull/1962). +* Introduce the "small-hash" feature for `bitcoin_hashes` [#1990](https://github.com/rust-bitcoin/rust-bitcoin/pull/1990). + +# 0.12.0 - 2023-03-05 + +0.12 is a significant release. We pulled the repository into the rust-bitcoin +repo to improve our integration testing and to get more eyes on this crate. We +began the process of replacing the hex functionality in this crate with a more +performant, dedicated crate, and otherwise cleaning up the API as we look forward +to 1.0. + +* [Remove `FromHex` implementation](https://github.com/rust-bitcoin/rust-bitcoin/pull/1565/commits/a308e1e2ea5c6ae419d961b8da71cc8a35a92715) +from all hashes and implement `FromStr` instead. +* Move crate from [original repo](https://github.com/rust-bitcoin/bitcoin_hashes) to the +`rust-bitcoin` repository. Commit history was lost during move, for commit history see the original +repository. Tip of bitcoin_hashes:master at time of import: 54c16249e06cc6b7870c7fc07d90f489d82647c7 +* [Remove `Deref` impls for all hashes](https://github.com/rust-bitcoin/rust-bitcoin/pull/1450) +* [Add `AsRef` impls for all hashes from fixed-size arrays](https://github.com/rust-bitcoin/rust-bitcoin/pull/1593) +* [Add the `sha512_256` hash](https://github.com/rust-bitcoin/rust-bitcoin/pull/1413) +* [Remove the `ToHex` trait in favor of `DisplayHex` and `fmt::Display`](https://github.com/rust-bitcoin/rust-bitcoin/pull/1531) +* [Remove the now-unused `HexWriter` object](https://github.com/rust-bitcoin/rust-bitcoin/pull/1572) +* [nostd: `alloc` feature no longer enables `core2`](https://github.com/rust-bitcoin/rust-bitcoin/pull/1612) +* [Rewrite `hash_newtype` macro with new syntax](https://github.com/rust-bitcoin/rust-bitcoin/pull/1659) +* [Rename `Hash::Inner` to `Hash::Bytes`, 'Hash::*_inner` and several related conversion methods](https://github.com/rust-bitcoin/rust-bitcoin/pull/1577) + + +# 0.11.0 - 2022-06-25 + +The major change in this version is the increase of the Minimum Supported Rust Version (MSRV) from +1.29 to 1.41.1. This is a big change because it introduces Rust Edition 2018 to the codebase along +with all the benefits that brings. We also did a bunch of optimisations to speed up encoding and +decoding hex strings. + +## Breaking changes + +* [Enable edition 2018 and bump MSRV to Rust 1.41.1](https://github.com/rust-bitcoin/bitcoin_hashes/pull/136) + +## New features/APIs + +* [Add `all_zeros` to `Hash` trait](https://github.com/rust-bitcoin/bitcoin_hashes/pull/148) +* [Implement `Write` on `HmacEngine`](https://github.com/rust-bitcoin/bitcoin_hashes/pull/133) +* [Introduce `HexWriter`](https://github.com/rust-bitcoin/bitcoin_hashes/pull/156), makes serialising hex faster +* [Implement `Read` on `HexIterator`](https://github.com/rust-bitcoin/bitcoin_hashes/pull/135), makes deserialising hex faster + +## Other improvements + +* Use `rotate_left` [instead of custom macro](https://github.com/rust-bitcoin/bitcoin_hashes/pull/162) +* [Enable clippy on CI](https://github.com/rust-bitcoin/bitcoin_hashes/pull/152) +* Various docs fixes +* [Improve feature test coverage](https://github.com/rust-bitcoin/bitcoin_hashes/pull/147) +* [Add a disabled `rustfmt.toml`](https://github.com/rust-bitcoin/bitcoin_hashes/pull/141) to improve interaction with auto-formatting in editors + + +# 0.10.0 - 2021-07-05 + +* Increase `core2` to released version of 0.3.0 + +# 0.9.7 - 2021-06-17 + +* Introduce `alloc` feature and `core2` dependency for nostd support (this feature has MSRV of 1.36 rather than 1.29) + +# 0.9.6 - 2021-05-03 + +* Re-export `core` as `_export::_core`. This resolves an issue when calling several exported macros with the `std` feature. + +# 0.9.5 - 2021-04-28 + +* Add [`#[repr(transparent)]` to all newtype wrappers](https://github.com/rust-bitcoin/bitcoin_hashes/pull/108/) +* Add [missing `#derive`s](https://github.com/rust-bitcoin/bitcoin_hashes/pull/110/) +* Replace `fuzztarget` feature with [use of `cfg(fuzzing)`](https://github.com/rust-bitcoin/bitcoin_hashes/pull/111/) +* Use [`core` rather than `std`](https://github.com/rust-bitcoin/bitcoin_hashes/pull/118/) and [fix `no_std` compilation](https://github.com/rust-bitcoin/bitcoin_hashes/pull/122/) + +Note that we have stopped re-exporting the `core` crate when compiling without `std`. This is technically a breaking change but it is hard to imagine what user might be affected. + +# 0.9.4 - 2020-10-23 + +* Add `Hmac::from_inner_engines` + +# 0.9.3 - 2020-10-19 + +* More serde macro fixes + +# 0.9.2 - 2020-10-18 + +* Fix rustc 1.29.0 downstream issues with serde macros + +# 0.9.2 - 2020-10-16 + +* Fix visibility issue with serde macros + +# 0.9.1 - 2020-10-07 + +* Add `FromStr` impl to `sha256t::Hash` +* Fix `Hash::engine()` implementation for hash newtypes +* Add `sha256t_hash_newtype!` macro for creating tagged hashes + +# 0.9.0 - 2020-08-27 + +* **Update MSRV to 1.29.0** + +# 0.8.0 - 2020-08-26 + +* Add `as_inner` method to `Hash` trait +* Add `n_bytes_hashed` to `HashEngine` trait + +# 0.7.6 - 2020-04-05 + +* Support hash newtypes with reversed hex serialization. + +# 0.7.5 - 2020-04-02 + +* Add `sha256t` module for SHA-256-based tagged hashes. +* Add `FromStr` for hash newtypes. +* Add `from_hash` for hash newtypes. + +# 0.7.3 - 2019-12-18 + +* Add `as_hash(&self) -> ` method to hash newtypes. + +# 0.7.2 - 2019-11-29 + +* Make the inner variable of `sha256::Midstat` public +* Drop the `byteorder` dependency in favor of manual endianness implementations +(later this will be in stdlib so we can drop even that) +* Fix the `hash_newtype` macro, which did not compile before + +# 0.7.1 - 2019-08-14 + +* Add hash_newtype macro that allows third parties to create newtype structs. + +# 0.7.0 - 2019-07-19 + +* Add `hex::Error` type for errors generated by the `hex` module. + +# 0.6.0 - 2019-07-10 + +* Add `no_std` support, rearrange traits to not depend on `io::Write` + +# 0.5.0 - 2019-06-28 + +* Fix panic when parsing hashes that contain multibyte characters +* Add `FromStr` to all hashes which hex-parses them + +# 0.4.0 - 2019-06-23 + +* [Add `from_inner` method](https://github.com/rust-bitcoin/bitcoin_hashes/pull/20) to all hashes +* [Update `FromHex` trait](https://github.com/rust-bitcoin/bitcoin_hashes/pull/40) to require `from_byte_iter` method rather than `from_hex` be implemented +* Make `Hmac` midstate [an actual HMAC midstate](https://github.com/rust-bitcoin/bitcoin_hashes/pull/43) +* Allow `Display` [of truncated hashes](https://github.com/rust-bitcoin/bitcoin_hashes/pull/9) +* Require [using a constructor for `HexIterator`](https://github.com/rust-bitcoin/bitcoin_hashes/pull/44) and then [clean up the internals](https://github.com/rust-bitcoin/bitcoin_hashes/pull/47) +* [Strongly type `sha256::Midstate`](https://github.com/rust-bitcoin/bitcoin_hashes/pull/39) to allow independent serialization +* Add [siphash24 module](https://github.com/rust-bitcoin/bitcoin_hashes/pull/46) + +# 0.3.2 - 2019-03-20 + +* Implement the `FromHex` trait on [many more types](https://github.com/rust-bitcoin/bitcoin_hashes/pull/38) + +# 0.3.1 - 2019-03-04 + +* [Fix serde serialization](https://github.com/rust-bitcoin/bitcoin_hashes/pull/36) + +# 0.3.0 - 2019-01-23 + +* Bump minimum required rustc version to 1.22.0 +* Fixed serde deserialization into owned string that previously caused panics + when doing round-trip (de)serialization +* `HashEngine::block_size()` and `Hash::len()` are now associated constants + `HashEngine::BLOCK_SIZE` and `Hash::LEN` +* Removed `block_size()` method from `Hash` trait. It is still available as + `::Engine::BLOCK_SIZE` + +# 0.2.0 - 2019-01-15 + +* Add a constant-time comparison function +* Simplify `io::Write::write` implementations by having them do only partial writes +* Add fuzzing support +* Allow `Hash`es to be borrowed as `[u8]` +* Replace public `Hash` inners with `into_inner` method + +# 0.1.0 - 2018-12-08 + +* Initial release diff --git a/hashes/Cargo.toml b/hashes/Cargo.toml new file mode 100644 index 00000000..8d026f80 --- /dev/null +++ b/hashes/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "tapyrus_hashes" +version = "0.13.0" +authors = ["Andrew Poelstra "] +license = "MIT" +homepage = "https://github.com/chaintope/rust-tapyrus/" +repository = "https://github.com/chaintope/rust-tapyrus/" +description = "Hash functions used by the rust-tapyrus eccosystem" +categories = ["algorithms"] +keywords = [ "crypto", "bitcoin", "hash", "digest" ] +readme = "README.md" +edition = "2018" +exclude = ["tests", "contrib"] + +[features] +default = ["std"] +std = ["alloc", "hex/std"] +alloc = ["hex/alloc"] +serde-std = ["serde/std"] +# If you want I/O you must enable either "std" or "core2". +core2 = ["actual-core2", "hex/core2"] +# Smaller (but slower) implementation of sha256, sha512 and ripemd160 +small-hash = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +hex = { package = "hex-conservative", version = "0.1.1", default-features = false } + +schemars = { version = "0.8.3", optional = true } +# Only enable this if you explicitly do not want to use "std", otherwise enable "serde-std". +serde = { version = "1.0", default-features = false, optional = true } + +# Do NOT use this feature! Use the "core2" feature instead. +actual-core2 = { package = "core2", version = "0.3.2", default-features = false, optional = true } + +[dev-dependencies] +serde_test = "1.0" +serde_json = "1.0" + +[lints.rust] +unexpected_cfgs = { level = "deny", check-cfg = ['cfg(bench)', 'cfg(hashes_fuzz)' ] } diff --git a/hashes/README.md b/hashes/README.md new file mode 100644 index 00000000..433a9593 --- /dev/null +++ b/hashes/README.md @@ -0,0 +1,44 @@ +# Bitcoin Hashes Library + +This is a simple, no-dependency library which implements the hash functions +needed by Bitcoin. These are SHA1, SHA256, SHA256d, SHA512, and RIPEMD160. As an +ancilliary thing, it exposes hexadecimal serialization and deserialization, +since these are needed to display hashes anway. + +[Documentation](https://docs.rs/bitcoin_hashes/) + +## Minimum Supported Rust Version (MSRV) + +This library should always compile with any combination of features on **Rust 1.56.1**. + + +To build with the MSRV you will need to pin `serde` (if you have either the `serde` or the +`schemars` feature enabled) + +``` +# serde 1.0.157 uses syn 2.0 which requires edition 2021 +cargo update -p serde --precise 1.0.156 +``` + +before building. (And if your code is a library, your downstream users will need to run these +commands, and so on.) + +## Contributions + +Contributions are welcome, including additional hash function implementations. + +### Githooks + +To assist devs in catching errors _before_ running CI we provide some githooks. If you do not +already have locally configured githooks you can use the ones in this repository by running, in the +root directory of the repository: +``` +git config --local core.hooksPath githooks/ +``` + +Alternatively add symlinks in your `.git/hooks` directory to any of the githooks we provide. + +### Running Benchmarks + +We use a custom Rust compiler configuration conditional to guard the bench mark code. To run the +bench marks use: `RUSTFLAGS='--cfg=bench' cargo +nightly bench`. diff --git a/hashes/contrib/test.sh b/hashes/contrib/test.sh new file mode 100755 index 00000000..37160d0e --- /dev/null +++ b/hashes/contrib/test.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash + +set -ex + +FEATURES="serde serde-std std core2 alloc" + +cargo --version +rustc --version + +# Work out if we are using a nightly toolchain. +NIGHTLY=false +if cargo --version | grep nightly >/dev/null; then + NIGHTLY=true +fi + +# Pin dependencies as required if we are using MSRV toolchain. +if cargo --version | grep "1\.48"; then + # 1.0.157 uses syn 2.0 which requires edition 2021 + cargo update -p serde_json --precise 1.0.99 + cargo update -p serde --precise 1.0.156 +fi + +# Make all cargo invocations verbose +export CARGO_TERM_VERBOSE=true + +# Defaults / sanity checks +cargo build +cargo test + +if [ "$DO_LINT" = true ] +then + cargo clippy --locked --all-features --all-targets -- -D warnings +fi + +if [ "$DO_FEATURE_MATRIX" = true ]; then + cargo build --locked --no-default-features + cargo test --locked --no-default-features + + # All features + cargo build --locked --no-default-features --features="$FEATURES" + cargo test --locked --no-default-features --features="$FEATURES" + # Single features + for feature in ${FEATURES} + do + cargo build --locked --no-default-features --features="$feature" + cargo test --locked --no-default-features --features="$feature" + # All combos of two features + for featuretwo in ${FEATURES}; do + cargo build --locked --no-default-features --features="$feature $featuretwo" + cargo test --locked --no-default-features --features="$feature $featuretwo" + done + done + + # Other combos + cargo test --locked --no-default-features --features="std,schemars" +fi + +REPO_DIR=$(git rev-parse --show-toplevel) + +if [ "$DO_SCHEMARS_TESTS" = true ]; then + pushd "$REPO_DIR/hashes/extended_tests/schemars" > /dev/null + cargo test + popd > /dev/null +fi + +# Build the docs if told to (this only works with the nightly toolchain) +if [ "$DO_DOCSRS" = true ]; then + RUSTDOCFLAGS="--cfg docsrs -D warnings -D rustdoc::broken-intra-doc-links" cargo +nightly doc --all-features +fi + +# Build the docs with a stable toolchain, in unison with the DO_DOCSRS command +# above this checks that we feature guarded docs imports correctly. +if [ "$DO_DOCS" = true ]; then + RUSTDOCFLAGS="-D warnings" cargo +stable doc --all-features +fi + +# Webassembly stuff +if [ "$DO_WASM" = true ]; then + clang --version && + CARGO_TARGET_DIR=wasm cargo install --force wasm-pack && + printf '\n[target.wasm32-unknown-unknown.dev-dependencies]\nwasm-bindgen-test = "0.3"\n' >> Cargo.toml && + printf '\n[lib]\ncrate-type = ["cdylib", "rlib"]\n' >> Cargo.toml && + CC=clang-9 wasm-pack build && + CC=clang-9 wasm-pack test --node; +fi + +# Address Sanitizer +if [ "$DO_ASAN" = true ]; then + cargo clean + CC='clang -fsanitize=address -fno-omit-frame-pointer' \ + RUSTFLAGS='-Zsanitizer=address -Clinker=clang -Cforce-frame-pointers=yes' \ + ASAN_OPTIONS='detect_leaks=1 detect_invalid_pointer_pairs=1 detect_stack_use_after_return=1' \ + cargo test --lib --no-default-features --features="$FEATURES" -Zbuild-std --target x86_64-unknown-linux-gnu + cargo clean + CC='clang -fsanitize=memory -fno-omit-frame-pointer' \ + RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins -Cforce-frame-pointers=yes' \ + cargo test --lib --no-default-features --features="$FEATURES" -Zbuild-std --target x86_64-unknown-linux-gnu +fi + +# Run formatter if told to. +if [ "$DO_FMT" = true ]; then + if [ "$NIGHTLY" = false ]; then + echo "DO_FMT requires a nightly toolchain (consider using RUSTUP_TOOLCHAIN)" + exit 1 + fi + rustup component add rustfmt + cargo fmt --check +fi + +# Bench if told to, only works with non-stable toolchain (nightly, beta). +if [ "$DO_BENCH" = true ] +then + if [ "$NIGHTLY" = false ] + then + if [ -n "$RUSTUP_TOOLCHAIN" ] + then + echo "RUSTUP_TOOLCHAIN is set to a non-nightly toolchain but DO_BENCH requires a nightly toolchain" + else + echo "DO_BENCH requires a nightly toolchain" + fi + exit 1 + fi + RUSTFLAGS='--cfg=bench' cargo bench +fi diff --git a/hashes/embedded/Cargo.toml b/hashes/embedded/Cargo.toml new file mode 100644 index 00000000..ea85dc99 --- /dev/null +++ b/hashes/embedded/Cargo.toml @@ -0,0 +1,35 @@ +[package] +authors = ["Riccardo Casatta "] +edition = "2018" +readme = "README.md" +name = "embedded" +version = "0.1.0" + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[features] +alloc = ["alloc-cortex-m", "tapyrus_hashes/alloc"] + +[dependencies] +cortex-m = "0.6.0" +cortex-m-rt = "0.6.10" +cortex-m-semihosting = "0.3.3" +panic-halt = "0.2.0" +alloc-cortex-m = { version = "0.4.1", optional = true } +tapyrus_hashes = { path="../", default-features = false, features = ["core2"] } +core2 = { version = "0.3.0", default_features = false } + +[[bin]] +name = "embedded" +test = false +bench = false + +[profile.release] +codegen-units = 1 # better optimizations +debug = true # symbols are nice and they don't increase the size on Flash +lto = true # better optimizations + +[patch.crates-io.tapyrus-internals] +path = "../../internals" diff --git a/hashes/embedded/README.md b/hashes/embedded/README.md new file mode 100644 index 00000000..60e4e1a1 --- /dev/null +++ b/hashes/embedded/README.md @@ -0,0 +1,30 @@ +# Running + +To run the embedded test, first prepare your environment: + +```shell +sudo ./scripts/install-deps +rustup +nightly target add thumbv7m-none-eabi +``` + +Then: + +```shell +source ./scripts/env.sh && cargo +nightly run --target thumbv7m-none-eabi +``` + +Output should be something like: + +```text +hash:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad hash_check:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad +hash:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad hash_check:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad +``` + +## Cleanup + +After sourcing `scripts/env.sh` and _before_ building again using another target +you'll want to unset `RUSTFLAGS` otherwise you'll get linker errors. + +```shell +unset RUSTFLAGS +``` diff --git a/hashes/embedded/memory.x b/hashes/embedded/memory.x new file mode 100644 index 00000000..95de161b --- /dev/null +++ b/hashes/embedded/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH : ORIGIN = 0x00000000, LENGTH = 256K + RAM : ORIGIN = 0x20000000, LENGTH = 64K +} diff --git a/hashes/embedded/scripts/env.sh b/hashes/embedded/scripts/env.sh new file mode 100644 index 00000000..125162b6 --- /dev/null +++ b/hashes/embedded/scripts/env.sh @@ -0,0 +1,2 @@ +export RUSTFLAGS="-C link-arg=-Tlink.x" +export CARGO_TARGET_THUMBV7M_NONE_EABI_RUNNER="qemu-system-arm -cpu cortex-m3 -machine mps2-an385 -nographic -semihosting-config enable=on,target=native -kernel" diff --git a/hashes/embedded/scripts/install-deps b/hashes/embedded/scripts/install-deps new file mode 100755 index 00000000..d22806dd --- /dev/null +++ b/hashes/embedded/scripts/install-deps @@ -0,0 +1,3 @@ +#!/bin/sh + +apt install gcc-arm-none-eabi qemu-system-arm gdb-multiarch diff --git a/hashes/embedded/src/main.rs b/hashes/embedded/src/main.rs new file mode 100644 index 00000000..7c58163d --- /dev/null +++ b/hashes/embedded/src/main.rs @@ -0,0 +1,63 @@ +#![cfg_attr(feature = "alloc", feature(alloc_error_handler))] +#![no_std] +#![no_main] + +#[macro_use] +extern crate tapyrus_hashes; + +#[cfg(feature = "alloc")] extern crate alloc; +#[cfg(feature = "alloc")] use alloc_cortex_m::CortexMHeap; +#[cfg(feature = "alloc")] use alloc::string::ToString; + +use tapyrus_hashes::{sha256, Hash, HashEngine}; +use core2::io::Write; +use core::str::FromStr; +use cortex_m_rt::entry; +use cortex_m_semihosting::{debug, hprintln}; +use panic_halt as _; + +hash_newtype! { + struct TestType(sha256::Hash); +} + +// this is the allocator the application will use +#[cfg(feature = "alloc")] +#[global_allocator] +static ALLOCATOR: CortexMHeap = CortexMHeap::empty(); + +#[cfg(feature = "alloc")] +const HEAP_SIZE: usize = 1024; // in bytes + +#[entry] +fn main() -> ! { + #[cfg(feature = "alloc")] + unsafe { ALLOCATOR.init(cortex_m_rt::heap_start() as usize, HEAP_SIZE) } + + let mut engine = TestType::engine(); + engine.write_all(b"abc").unwrap(); + check_result(engine); + + let mut engine = TestType::engine(); + engine.input(b"abc"); + check_result(engine); + + debug::exit(debug::EXIT_SUCCESS); + loop {} +} + +fn check_result(engine: sha256::HashEngine) { + let hash = TestType::from_engine(engine); + + let hash_check = + TestType::from_str("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad") + .unwrap(); + hprintln!("hash:{} hash_check:{}", hash, hash_check).unwrap(); + if hash != hash_check { + debug::exit(debug::EXIT_FAILURE); + } + + #[cfg(feature = "alloc")] + if hash.to_string() != hash_check.to_string() { + debug::exit(debug::EXIT_FAILURE); + } +} diff --git a/hashes/extended_tests/schemars/Cargo.toml b/hashes/extended_tests/schemars/Cargo.toml new file mode 100644 index 00000000..b784d016 --- /dev/null +++ b/hashes/extended_tests/schemars/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "schemars" +version = "0.1.0" +authors = ["Jeremy Rubin "] +edition = "2018" + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[dependencies.tapyrus_hashes] +path = "../.." +features = ['schemars', 'serde'] + +[dependencies] +jsonschema-valid = "0.4.0" +serde = { version = "1.0", default-features = false} +schemars = "0.8.3" +serde_test = "1.0" +serde_json = "1.0" + +[patch.crates-io.tapyrus-internals] +path = "../../../internals" diff --git a/hashes/extended_tests/schemars/README.md b/hashes/extended_tests/schemars/README.md new file mode 100644 index 00000000..9e0a5970 --- /dev/null +++ b/hashes/extended_tests/schemars/README.md @@ -0,0 +1,11 @@ +# Test crate for the schemars feature + +Run as usual with `cargo test`. + +## Minimum Supported Rust Version (MSRV) + +To run the tests with the MSRV you will need to pin `serde`: + +- `cargo update -p serde --precise 1.0.156` +- `cargo update -p regex --precise 1.7.3` +- `cargo update -p chrono --precise 0.4.24` diff --git a/hashes/extended_tests/schemars/src/main.rs b/hashes/extended_tests/schemars/src/main.rs new file mode 100644 index 00000000..b4e480ca --- /dev/null +++ b/hashes/extended_tests/schemars/src/main.rs @@ -0,0 +1,191 @@ +fn main() {} +#[cfg(test)] +mod tests { + use tapyrus_hashes::*; + + #[test] + fn hash160() { + static HASH_BYTES: [u8; 20] = [ + 0x13, 0x20, 0x72, 0xdf, 0x69, 0x09, 0x33, 0x83, 0x5e, 0xb8, 0xb6, 0xad, 0x0b, 0x77, + 0xe7, 0xb6, 0xf1, 0x4a, 0xca, 0xd7, + ]; + + let hash = hash160::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap(); + let s = schemars::schema_for!(hash160::Hash); + let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap(); + assert!(jsonschema_valid::Config::from_schema(&schema, None) + .unwrap() + .validate(&js) + .is_ok()); + } + + #[test] + fn hmac_sha512() { + static HASH_BYTES: [u8; 64] = [ + 0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21, 0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, + 0x1b, 0x8e, 0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd, 0x00, 0xa4, 0x11, 0x62, + 0x0b, 0x46, 0xf2, 0x0f, 0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97, 0x12, 0x1a, + 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8, 0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f, + 0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c, + ]; + + let hash = Hmac::::from_slice(&HASH_BYTES).expect("right number of bytes"); + let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap(); + let s = schemars::schema_for!(Hmac::); + let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap(); + assert!(jsonschema_valid::Config::from_schema(&schema, None) + .unwrap() + .validate(&js) + .is_ok()); + } + + #[test] + fn ripemd160() { + static HASH_BYTES: [u8; 20] = [ + 0x13, 0x20, 0x72, 0xdf, 0x69, 0x09, 0x33, 0x83, 0x5e, 0xb8, 0xb6, 0xad, 0x0b, 0x77, + 0xe7, 0xb6, 0xf1, 0x4a, 0xca, 0xd7, + ]; + + let hash = ripemd160::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap(); + let s = schemars::schema_for!(ripemd160::Hash); + let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap(); + assert!(jsonschema_valid::Config::from_schema(&schema, None) + .unwrap() + .validate(&js) + .is_ok()); + } + + #[test] + fn sha1() { + static HASH_BYTES: [u8; 20] = [ + 0x13, 0x20, 0x72, 0xdf, 0x69, 0x09, 0x33, 0x83, 0x5e, 0xb8, 0xb6, 0xad, 0x0b, 0x77, + 0xe7, 0xb6, 0xf1, 0x4a, 0xca, 0xd7, + ]; + + let hash = sha1::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap(); + let s = schemars::schema_for!(sha1::Hash); + let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap(); + assert!(jsonschema_valid::Config::from_schema(&schema, None) + .unwrap() + .validate(&js) + .is_ok()); + } + + #[test] + fn sha256d() { + static HASH_BYTES: [u8; 32] = [ + 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, + 0x3d, 0x97, 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, 0xb7, 0x65, 0x44, 0x8c, + 0x86, 0x35, 0xfb, 0x6c, + ]; + + let hash = sha256d::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap(); + let s = schemars::schema_for!(sha256d::Hash); + let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap(); + assert!(jsonschema_valid::Config::from_schema(&schema, None) + .unwrap() + .validate(&js) + .is_ok()); + } + + #[test] + fn sha256() { + static HASH_BYTES: [u8; 32] = [ + 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, + 0x3d, 0x97, 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, 0xb7, 0x65, 0x44, 0x8c, + 0x86, 0x35, 0xfb, 0x6c, + ]; + + let hash = sha256::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap(); + let s = schemars::schema_for!(sha256::Hash); + let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap(); + assert!(jsonschema_valid::Config::from_schema(&schema, None) + .unwrap() + .validate(&js) + .is_ok()); + } + + #[test] + fn test_hash() { + const TEST_MIDSTATE: [u8; 32] = [ + 156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, + 147, 108, 71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201, + ]; + + #[derive( + Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash, schemars::JsonSchema, + )] + pub struct TestHashTag; + + impl sha256t::Tag for TestHashTag { + fn engine() -> sha256::HashEngine { + // The TapRoot TapLeaf midstate. + let midstate = sha256::Midstate::from_byte_array(TEST_MIDSTATE); + sha256::HashEngine::from_midstate(midstate, 64) + } + } + + /// A hash tagged with `$name`. + pub type TestHash = sha256t::Hash; + + sha256t_hash_newtype! { + struct NewTypeTag = raw(TEST_MIDSTATE, 64); + + #[hash_newtype(backward)] + struct NewTypeHash(_); + } + static HASH_BYTES: [u8; 32] = [ + 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, + 0x3d, 0x97, 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, 0xb7, 0x65, 0x44, 0x8c, + 0x86, 0x35, 0xfb, 0x6c, + ]; + + let hash = TestHash::from_slice(&HASH_BYTES).expect("right number of bytes"); + let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap(); + let s = schemars::schema_for!(TestHash); + let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap(); + assert!(jsonschema_valid::Config::from_schema(&schema, None) + .unwrap() + .validate(&js) + .is_ok()); + } + + #[test] + fn sha512() { + static HASH_BYTES: [u8; 64] = [ + 0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21, 0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, + 0x1b, 0x8e, 0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd, 0x00, 0xa4, 0x11, 0x62, + 0x0b, 0x46, 0xf2, 0x0f, 0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97, 0x12, 0x1a, + 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8, 0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f, + 0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c, + ]; + + let hash = sha512::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap(); + let s = schemars::schema_for!(sha512::Hash); + let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap(); + assert!(jsonschema_valid::Config::from_schema(&schema, None) + .unwrap() + .validate(&js) + .is_ok()); + } + + #[test] + fn siphash24() { + static HASH_BYTES: [u8; 8] = [0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21]; + + let hash = siphash24::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + let js = serde_json::from_str(&serde_json::to_string(&hash).unwrap()).unwrap(); + let s = schemars::schema_for!(siphash24::Hash); + let schema = serde_json::from_str(&serde_json::to_string(&s).unwrap()).unwrap(); + assert!(jsonschema_valid::Config::from_schema(&schema, None) + .unwrap() + .validate(&js) + .is_ok()); + } +} diff --git a/hashes/src/cmp.rs b/hashes/src/cmp.rs new file mode 100644 index 00000000..d84b31c0 --- /dev/null +++ b/hashes/src/cmp.rs @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Useful comparison functions. + +/// Compare two slices for equality in fixed time. Panics if the slices are of non-equal length. +/// +/// This works by XOR'ing each byte of the two inputs together and keeping an OR counter of the +/// results. +/// +/// Instead of doing fancy bit twiddling to try to outsmart the compiler and prevent early exits, +/// which is not guaranteed to remain stable as compilers get ever smarter, we take the hit of +/// writing each intermediate value to memory with a volatile write and then re-reading it with a +/// volatile read. This should remain stable across compiler upgrades, but is much slower. +/// +/// As of rust 1.31.0 disassembly looks completely within reason for this, see +/// . +pub fn fixed_time_eq(a: &[u8], b: &[u8]) -> bool { + assert!(a.len() == b.len()); + let count = a.len(); + let lhs = &a[..count]; + let rhs = &b[..count]; + + let mut r: u8 = 0; + for i in 0..count { + let mut rs = unsafe { core::ptr::read_volatile(&r) }; + rs |= lhs[i] ^ rhs[i]; + unsafe { + core::ptr::write_volatile(&mut r, rs); + } + } + { + let mut t = unsafe { core::ptr::read_volatile(&r) }; + t |= t >> 4; + unsafe { + core::ptr::write_volatile(&mut r, t); + } + } + { + let mut t = unsafe { core::ptr::read_volatile(&r) }; + t |= t >> 2; + unsafe { + core::ptr::write_volatile(&mut r, t); + } + } + { + let mut t = unsafe { core::ptr::read_volatile(&r) }; + t |= t >> 1; + unsafe { + core::ptr::write_volatile(&mut r, t); + } + } + unsafe { (::core::ptr::read_volatile(&r) & 1) == 0 } +} + +#[test] +fn eq_test() { + assert!(fixed_time_eq(&[0b00000000], &[0b00000000])); + assert!(fixed_time_eq(&[0b00000001], &[0b00000001])); + assert!(fixed_time_eq(&[0b00000010], &[0b00000010])); + assert!(fixed_time_eq(&[0b00000100], &[0b00000100])); + assert!(fixed_time_eq(&[0b00001000], &[0b00001000])); + assert!(fixed_time_eq(&[0b00010000], &[0b00010000])); + assert!(fixed_time_eq(&[0b00100000], &[0b00100000])); + assert!(fixed_time_eq(&[0b01000000], &[0b01000000])); + assert!(fixed_time_eq(&[0b10000000], &[0b10000000])); + assert!(fixed_time_eq(&[0b11111111], &[0b11111111])); + + assert!(!fixed_time_eq(&[0b00000001], &[0b00000000])); + assert!(!fixed_time_eq(&[0b00000001], &[0b11111111])); + assert!(!fixed_time_eq(&[0b00000010], &[0b00000000])); + assert!(!fixed_time_eq(&[0b00000010], &[0b11111111])); + assert!(!fixed_time_eq(&[0b00000100], &[0b00000000])); + assert!(!fixed_time_eq(&[0b00000100], &[0b11111111])); + assert!(!fixed_time_eq(&[0b00001000], &[0b00000000])); + assert!(!fixed_time_eq(&[0b00001000], &[0b11111111])); + assert!(!fixed_time_eq(&[0b00010000], &[0b00000000])); + assert!(!fixed_time_eq(&[0b00010000], &[0b11111111])); + assert!(!fixed_time_eq(&[0b00100000], &[0b00000000])); + assert!(!fixed_time_eq(&[0b00100000], &[0b11111111])); + assert!(!fixed_time_eq(&[0b01000000], &[0b00000000])); + assert!(!fixed_time_eq(&[0b01000000], &[0b11111111])); + assert!(!fixed_time_eq(&[0b10000000], &[0b00000000])); + assert!(!fixed_time_eq(&[0b10000000], &[0b11111111])); + + assert!(fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000000, 0b00000000])); + assert!(!fixed_time_eq(&[0b00000001, 0b00000000], &[0b00000000, 0b00000000])); + assert!(!fixed_time_eq(&[0b00000000, 0b00000001], &[0b00000000, 0b00000000])); + assert!(!fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000001, 0b00000000])); + assert!(!fixed_time_eq(&[0b00000000, 0b00000000], &[0b00000001, 0b00000001])); +} + +#[cfg(bench)] +mod benches { + use test::Bencher; + + use crate::cmp::fixed_time_eq; + use crate::{sha256, sha512, Hash}; + + #[bench] + fn bench_32b_constant_time_cmp_ne(bh: &mut Bencher) { + let hash_a = sha256::Hash::hash(&[0; 1]); + let hash_b = sha256::Hash::hash(&[1; 1]); + bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..])) + } + + #[bench] + fn bench_32b_slice_cmp_ne(bh: &mut Bencher) { + let hash_a = sha256::Hash::hash(&[0; 1]); + let hash_b = sha256::Hash::hash(&[1; 1]); + bh.iter(|| &hash_a[..] == &hash_b[..]) + } + + #[bench] + fn bench_32b_constant_time_cmp_eq(bh: &mut Bencher) { + let hash_a = sha256::Hash::hash(&[0; 1]); + let hash_b = sha256::Hash::hash(&[0; 1]); + bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..])) + } + + #[bench] + fn bench_32b_slice_cmp_eq(bh: &mut Bencher) { + let hash_a = sha256::Hash::hash(&[0; 1]); + let hash_b = sha256::Hash::hash(&[0; 1]); + bh.iter(|| &hash_a[..] == &hash_b[..]) + } + + #[bench] + fn bench_64b_constant_time_cmp_ne(bh: &mut Bencher) { + let hash_a = sha512::Hash::hash(&[0; 1]); + let hash_b = sha512::Hash::hash(&[1; 1]); + bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..])) + } + + #[bench] + fn bench_64b_slice_cmp_ne(bh: &mut Bencher) { + let hash_a = sha512::Hash::hash(&[0; 1]); + let hash_b = sha512::Hash::hash(&[1; 1]); + bh.iter(|| &hash_a[..] == &hash_b[..]) + } + + #[bench] + fn bench_64b_constant_time_cmp_eq(bh: &mut Bencher) { + let hash_a = sha512::Hash::hash(&[0; 1]); + let hash_b = sha512::Hash::hash(&[0; 1]); + bh.iter(|| fixed_time_eq(&hash_a[..], &hash_b[..])) + } + + #[bench] + fn bench_64b_slice_cmp_eq(bh: &mut Bencher) { + let hash_a = sha512::Hash::hash(&[0; 1]); + let hash_b = sha512::Hash::hash(&[0; 1]); + bh.iter(|| &hash_a[..] == &hash_b[..]) + } +} diff --git a/hashes/src/hash160.rs b/hashes/src/hash160.rs new file mode 100644 index 00000000..af44f477 --- /dev/null +++ b/hashes/src/hash160.rs @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: CC0-1.0 +// +// This module is largely copied from the rust-crypto ripemd.rs file; +// while rust-crypto is licensed under Apache, that file specifically +// was written entirely by Andrew Poelstra, who is re-licensing its +// contents here as CC0. + +//! HASH160 (SHA256 then RIPEMD160) implementation. +//! + +use core::ops::Index; +use core::slice::SliceIndex; +use core::str; + +use crate::{ripemd160, sha256, FromSliceError}; + +crate::internal_macros::hash_type! { + 160, + false, + "Output of the Bitcoin HASH160 hash function. (RIPEMD160(SHA256))", + "crate::util::json_hex_string::len_20" +} + +type HashEngine = sha256::HashEngine; + +fn from_engine(e: HashEngine) -> Hash { + use crate::Hash as _; + + let sha2 = sha256::Hash::from_engine(e); + let rmd = ripemd160::Hash::hash(&sha2[..]); + + let mut ret = [0; 20]; + ret.copy_from_slice(&rmd[..]); + Hash(ret) +} + +#[cfg(test)] +mod tests { + #[test] + #[cfg(feature = "alloc")] + fn test() { + use crate::{hash160, Hash, HashEngine}; + + #[derive(Clone)] + #[cfg(feature = "alloc")] + struct Test { + input: Vec, + output: Vec, + output_str: &'static str, + } + + #[rustfmt::skip] + let tests = vec![ + // Uncompressed pubkey obtained from Bitcoin key; data from validateaddress + Test { + input: vec![ + 0x04, 0xa1, 0x49, 0xd7, 0x6c, 0x5d, 0xe2, 0x7a, 0x2d, + 0xdb, 0xfa, 0xa1, 0x24, 0x6c, 0x4a, 0xdc, 0xd2, 0xb6, + 0xf7, 0xaa, 0x29, 0x54, 0xc2, 0xe2, 0x53, 0x03, 0xf5, + 0x51, 0x54, 0xca, 0xad, 0x91, 0x52, 0xe4, 0xf7, 0xe4, + 0xb8, 0x5d, 0xf1, 0x69, 0xc1, 0x8a, 0x3c, 0x69, 0x7f, + 0xbb, 0x2d, 0xc4, 0xec, 0xef, 0x94, 0xac, 0x55, 0xfe, + 0x81, 0x64, 0xcc, 0xf9, 0x82, 0xa1, 0x38, 0x69, 0x1a, + 0x55, 0x19, + ], + output: vec![ + 0xda, 0x0b, 0x34, 0x52, 0xb0, 0x6f, 0xe3, 0x41, + 0x62, 0x6a, 0xd0, 0x94, 0x9c, 0x18, 0x3f, 0xbd, + 0xa5, 0x67, 0x68, 0x26, + ], + output_str: "da0b3452b06fe341626ad0949c183fbda5676826", + }, + ]; + + for test in tests { + // Hash through high-level API, check hex encoding/decoding + let hash = hash160::Hash::hash(&test.input[..]); + assert_eq!(hash, test.output_str.parse::().expect("parse hex")); + assert_eq!(&hash[..], &test.output[..]); + assert_eq!(&hash.to_string(), &test.output_str); + + // Hash through engine, checking that we can input byte by byte + let mut engine = hash160::Hash::engine(); + for ch in test.input { + engine.input(&[ch]); + } + let manual_hash = Hash::from_engine(engine); + assert_eq!(hash, manual_hash); + assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice()); + } + } + + #[cfg(feature = "serde")] + #[test] + fn ripemd_serde() { + use serde_test::{assert_tokens, Configure, Token}; + + use crate::{hash160, Hash}; + + #[rustfmt::skip] + static HASH_BYTES: [u8; 20] = [ + 0x13, 0x20, 0x72, 0xdf, + 0x69, 0x09, 0x33, 0x83, + 0x5e, 0xb8, 0xb6, 0xad, + 0x0b, 0x77, 0xe7, 0xb6, + 0xf1, 0x4a, 0xca, 0xd7, + ]; + + let hash = hash160::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]); + assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]); + } +} + +#[cfg(bench)] +mod benches { + use test::Bencher; + + use crate::{hash160, Hash, HashEngine}; + + #[bench] + pub fn hash160_10(bh: &mut Bencher) { + let mut engine = hash160::Hash::engine(); + let bytes = [1u8; 10]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn hash160_1k(bh: &mut Bencher) { + let mut engine = hash160::Hash::engine(); + let bytes = [1u8; 1024]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn hash160_64k(bh: &mut Bencher) { + let mut engine = hash160::Hash::engine(); + let bytes = [1u8; 65536]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } +} diff --git a/hashes/src/hmac.rs b/hashes/src/hmac.rs new file mode 100644 index 00000000..32ca96a1 --- /dev/null +++ b/hashes/src/hmac.rs @@ -0,0 +1,383 @@ +// SPDX-License-Identifier: CC0-1.0 + +// This module is largely copied from the rust-crypto ripemd.rs file; +// while rust-crypto is licensed under Apache, that file specifically +// was written entirely by Andrew Poelstra, who is re-licensing its +// contents here as CC0. + +//! Hash-based Message Authentication Code (HMAC). +//! + +use core::{borrow, fmt, ops, str}; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use crate::{FromSliceError, Hash, HashEngine}; + +/// A hash computed from a RFC 2104 HMAC. Parameterized by the underlying hash function. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[cfg_attr(feature = "schemars", schemars(transparent))] +#[repr(transparent)] +pub struct Hmac(T); + +impl str::FromStr for Hmac { + type Err = ::Err; + fn from_str(s: &str) -> Result { Ok(Hmac(str::FromStr::from_str(s)?)) } +} + +/// Pair of underlying hash midstates which represent the current state of an `HmacEngine`. +pub struct HmacMidState { + /// Midstate of the inner hash engine + pub inner: ::MidState, + /// Midstate of the outer hash engine + pub outer: ::MidState, +} + +/// Pair of underyling hash engines, used for the inner and outer hash of HMAC. +#[derive(Clone)] +pub struct HmacEngine { + iengine: T::Engine, + oengine: T::Engine, +} + +impl Default for HmacEngine { + fn default() -> Self { HmacEngine::new(&[]) } +} + +impl HmacEngine { + /// Constructs a new keyed HMAC from `key`. + /// + /// We only support underlying hashes whose block sizes are ≤ 128 bytes. + /// + /// # Panics + /// + /// Larger hashes will result in a panic. + pub fn new(key: &[u8]) -> HmacEngine { + debug_assert!(T::Engine::BLOCK_SIZE <= 128); + + let mut ipad = [0x36u8; 128]; + let mut opad = [0x5cu8; 128]; + let mut ret = HmacEngine { iengine: ::engine(), oengine: ::engine() }; + + if key.len() > T::Engine::BLOCK_SIZE { + let hash = ::hash(key); + for (b_i, b_h) in ipad.iter_mut().zip(&hash[..]) { + *b_i ^= *b_h; + } + for (b_o, b_h) in opad.iter_mut().zip(&hash[..]) { + *b_o ^= *b_h; + } + } else { + for (b_i, b_h) in ipad.iter_mut().zip(key) { + *b_i ^= *b_h; + } + for (b_o, b_h) in opad.iter_mut().zip(key) { + *b_o ^= *b_h; + } + }; + + HashEngine::input(&mut ret.iengine, &ipad[..T::Engine::BLOCK_SIZE]); + HashEngine::input(&mut ret.oengine, &opad[..T::Engine::BLOCK_SIZE]); + ret + } + + /// A special constructor giving direct access to the underlying "inner" and "outer" engines. + pub fn from_inner_engines(iengine: T::Engine, oengine: T::Engine) -> HmacEngine { + HmacEngine { iengine, oengine } + } +} + +impl HashEngine for HmacEngine { + type MidState = HmacMidState; + + fn midstate(&self) -> Self::MidState { + HmacMidState { inner: self.iengine.midstate(), outer: self.oengine.midstate() } + } + + const BLOCK_SIZE: usize = T::Engine::BLOCK_SIZE; + + fn n_bytes_hashed(&self) -> usize { self.iengine.n_bytes_hashed() } + + fn input(&mut self, buf: &[u8]) { self.iengine.input(buf) } +} + +impl fmt::Debug for Hmac { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&self.0, f) } +} + +impl fmt::Display for Hmac { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, f) } +} + +impl fmt::LowerHex for Hmac { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(&self.0, f) } +} + +impl ops::Index for Hmac { + type Output = u8; + fn index(&self, index: usize) -> &u8 { &self.0[index] } +} + +impl ops::Index> for Hmac { + type Output = [u8]; + fn index(&self, index: ops::Range) -> &[u8] { &self.0[index] } +} + +impl ops::Index> for Hmac { + type Output = [u8]; + fn index(&self, index: ops::RangeFrom) -> &[u8] { &self.0[index] } +} + +impl ops::Index> for Hmac { + type Output = [u8]; + fn index(&self, index: ops::RangeTo) -> &[u8] { &self.0[index] } +} + +impl ops::Index for Hmac { + type Output = [u8]; + fn index(&self, index: ops::RangeFull) -> &[u8] { &self.0[index] } +} + +impl borrow::Borrow<[u8]> for Hmac { + fn borrow(&self) -> &[u8] { &self[..] } +} + +impl Hash for Hmac { + type Engine = HmacEngine; + type Bytes = T::Bytes; + + fn from_engine(mut e: HmacEngine) -> Hmac { + let ihash = T::from_engine(e.iengine); + e.oengine.input(&ihash[..]); + let ohash = T::from_engine(e.oengine); + Hmac(ohash) + } + + const LEN: usize = T::LEN; + + fn from_slice(sl: &[u8]) -> Result, FromSliceError> { T::from_slice(sl).map(Hmac) } + + fn to_byte_array(self) -> Self::Bytes { self.0.to_byte_array() } + + fn as_byte_array(&self) -> &Self::Bytes { self.0.as_byte_array() } + + fn from_byte_array(bytes: T::Bytes) -> Self { Hmac(T::from_byte_array(bytes)) } + + fn all_zeros() -> Self { + let zeros = T::all_zeros(); + Hmac(zeros) + } +} + +#[cfg(feature = "serde")] +impl Serialize for Hmac { + fn serialize(&self, s: S) -> Result { + Serialize::serialize(&self.0, s) + } +} + +#[cfg(feature = "serde")] +impl<'de, T: Hash + Deserialize<'de>> Deserialize<'de> for Hmac { + fn deserialize>(d: D) -> Result, D::Error> { + let bytes = Deserialize::deserialize(d)?; + Ok(Hmac(bytes)) + } +} + +#[cfg(test)] +mod tests { + #[test] + #[cfg(feature = "alloc")] + fn test() { + use crate::{sha256, Hash, HashEngine, Hmac, HmacEngine}; + + #[derive(Clone)] + struct Test { + key: Vec, + input: Vec, + output: Vec, + } + + #[rustfmt::skip] + let tests = vec![ + // Test vectors copied from libsecp256k1 + // Sadly the RFC2104 test vectors all use MD5 as their underlying hash function, + // which of course this library does not support. + Test { + key: vec![ 0x0b; 20], + input: vec![0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65], + output: vec![ + 0xb0, 0x34, 0x4c, 0x61, 0xd8, 0xdb, 0x38, 0x53, + 0x5c, 0xa8, 0xaf, 0xce, 0xaf, 0x0b, 0xf1, 0x2b, + 0x88, 0x1d, 0xc2, 0x00, 0xc9, 0x83, 0x3d, 0xa7, + 0x26, 0xe9, 0x37, 0x6c, 0x2e, 0x32, 0xcf, 0xf7, + ], + }, + Test { + key: vec![ 0x4a, 0x65, 0x66, 0x65 ], + input: vec![ + 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, + 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, + 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, + 0x69, 0x6e, 0x67, 0x3f, + ], + output: vec![ + 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e, + 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7, + 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83, + 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43, + ], + }, + Test { + key: vec![ 0xaa; 20 ], + input: vec![ 0xdd; 50 ], + output: vec![ + 0x77, 0x3e, 0xa9, 0x1e, 0x36, 0x80, 0x0e, 0x46, + 0x85, 0x4d, 0xb8, 0xeb, 0xd0, 0x91, 0x81, 0xa7, + 0x29, 0x59, 0x09, 0x8b, 0x3e, 0xf8, 0xc1, 0x22, + 0xd9, 0x63, 0x55, 0x14, 0xce, 0xd5, 0x65, 0xfe, + ], + }, + Test { + key: vec![ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, + 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19 + ], + input: vec![ 0xcd; 50 ], + output: vec![ + 0x82, 0x55, 0x8a, 0x38, 0x9a, 0x44, 0x3c, 0x0e, + 0xa4, 0xcc, 0x81, 0x98, 0x99, 0xf2, 0x08, 0x3a, + 0x85, 0xf0, 0xfa, 0xa3, 0xe5, 0x78, 0xf8, 0x07, + 0x7a, 0x2e, 0x3f, 0xf4, 0x67, 0x29, 0x66, 0x5b, + ], + }, + Test { + key: vec! [ 0xaa; 131 ], + input: vec![ + 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, + 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, + 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, + 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, + 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, + 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, + 0x20, 0x46, 0x69, 0x72, 0x73, 0x74, + ], + output: vec![ + 0x60, 0xe4, 0x31, 0x59, 0x1e, 0xe0, 0xb6, 0x7f, + 0x0d, 0x8a, 0x26, 0xaa, 0xcb, 0xf5, 0xb7, 0x7f, + 0x8e, 0x0b, 0xc6, 0x21, 0x37, 0x28, 0xc5, 0x14, + 0x05, 0x46, 0x04, 0x0f, 0x0e, 0xe3, 0x7f, 0x54, + ], + }, + Test { + key: vec! [ 0xaa; 131 ], + input: vec![ + 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, + 0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x75, + 0x73, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x6c, + 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, 0x68, + 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, + 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x6b, 0x65, + 0x79, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, + 0x6c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x74, + 0x68, 0x61, 0x6e, 0x20, 0x62, 0x6c, 0x6f, 0x63, + 0x6b, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x20, 0x64, + 0x61, 0x74, 0x61, 0x2e, 0x20, 0x54, 0x68, 0x65, + 0x20, 0x6b, 0x65, 0x79, 0x20, 0x6e, 0x65, 0x65, + 0x64, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, + 0x20, 0x68, 0x61, 0x73, 0x68, 0x65, 0x64, 0x20, + 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x20, 0x62, + 0x65, 0x69, 0x6e, 0x67, 0x20, 0x75, 0x73, 0x65, + 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x48, 0x4d, 0x41, 0x43, 0x20, 0x61, 0x6c, + 0x67, 0x6f, 0x72, 0x69, 0x74, 0x68, 0x6d, 0x2e, + ], + output: vec![ + 0x9b, 0x09, 0xff, 0xa7, 0x1b, 0x94, 0x2f, 0xcb, + 0x27, 0x63, 0x5f, 0xbc, 0xd5, 0xb0, 0xe9, 0x44, + 0xbf, 0xdc, 0x63, 0x64, 0x4f, 0x07, 0x13, 0x93, + 0x8a, 0x7f, 0x51, 0x53, 0x5c, 0x3a, 0x35, 0xe2, + ], + }, + ]; + + for test in tests { + let mut engine = HmacEngine::::new(&test.key); + engine.input(&test.input); + let hash = Hmac::::from_engine(engine); + assert_eq!(&hash[..], &test.output[..]); + assert_eq!(hash.as_byte_array(), test.output.as_slice()); + } + } + + #[cfg(feature = "serde")] + #[test] + fn hmac_sha512_serde() { + use serde_test::{assert_tokens, Configure, Token}; + + use crate::{sha512, Hash, Hmac}; + + #[rustfmt::skip] + static HASH_BYTES: [u8; 64] = [ + 0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21, + 0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e, + 0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd, + 0x00, 0xa4, 0x11, 0x62, 0x0b, 0x46, 0xf2, 0x0f, + 0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97, + 0x12, 0x1a, 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8, + 0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f, + 0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c, + ]; + + let hash = Hmac::::from_slice(&HASH_BYTES).expect("right number of bytes"); + assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]); + assert_tokens( + &hash.readable(), + &[Token::Str( + "8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\ + fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c", + )], + ); + } +} + +#[cfg(bench)] +mod benches { + use test::Bencher; + + use crate::{sha256, Hash, HashEngine, Hmac}; + + #[bench] + pub fn hmac_sha256_10(bh: &mut Bencher) { + let mut engine = Hmac::::engine(); + let bytes = [1u8; 10]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn hmac_sha256_1k(bh: &mut Bencher) { + let mut engine = Hmac::::engine(); + let bytes = [1u8; 1024]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn hmac_sha256_64k(bh: &mut Bencher) { + let mut engine = Hmac::::engine(); + let bytes = [1u8; 65536]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } +} diff --git a/hashes/src/impls.rs b/hashes/src/impls.rs new file mode 100644 index 00000000..088a7f1f --- /dev/null +++ b/hashes/src/impls.rs @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! `std` / `core2` Impls. +//! +//! Implementations of traits defined in `std` / `core2` and not in `core`. +//! + +use crate::{hmac, io, ripemd160, sha1, sha256, sha512, siphash24, HashEngine}; + +impl io::Write for sha1::HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +impl io::Write for sha256::HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +impl io::Write for sha512::HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +impl io::Write for ripemd160::HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +impl io::Write for siphash24::HashEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +impl io::Write for hmac::HmacEngine { + fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn write(&mut self, buf: &[u8]) -> io::Result { + self.input(buf); + Ok(buf.len()) + } +} + +#[cfg(test)] +mod tests { + use super::io::Write; + use crate::{hash160, hmac, ripemd160, sha1, sha256, sha256d, sha512, siphash24, Hash}; + + macro_rules! write_test { + ($mod:ident, $exp_empty:expr, $exp_256:expr, $exp_64k:expr,) => { + #[test] + fn $mod() { + let mut engine = $mod::Hash::engine(); + engine.write_all(&[]).unwrap(); + assert_eq!(format!("{}", $mod::Hash::from_engine(engine)), $exp_empty); + + let mut engine = $mod::Hash::engine(); + engine.write_all(&[1; 256]).unwrap(); + assert_eq!(format!("{}", $mod::Hash::from_engine(engine)), $exp_256); + + let mut engine = $mod::Hash::engine(); + engine.write_all(&[99; 64000]).unwrap(); + assert_eq!(format!("{}", $mod::Hash::from_engine(engine)), $exp_64k); + } + }; + } + + write_test!( + sha1, + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "ac458b067c6b021c7e9358229b636e9d1e4cb154", + "e4b66838f9f7b6f91e5be32a02ae78094df402e7", + ); + + write_test!( + sha256, + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "2661920f2409dd6c8adeb0c44972959f232b6429afa913845d0fd95e7e768234", + "5c5e904f5d4fd587c7a906bf846e08a927286f388c54c39213a4884695271bbc", + ); + + write_test!( + sha256d, + "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d", + "374000d830c75d10d9417e493a7652920f30efbd300e3fb092f24c28c20baf64", + "0050d4148ad7a0437ca0643fad5bf4614cd95d9ba21fde52370b37dcc3f03307", + ); + + write_test!( + sha512, + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce\ + 47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", + "57ecf739d3a7ca647639adae80a05f4f361304bfcbfa1ceba93296b096e74287\ + 45fc10c142cecdd3bb587a3dba598c072f6f78b31cc0a06a3da0105ee51f75d6", + "dd28f78c53f3bc9bd0c2dca9642a1ad402a70412f985c1f6e54fadb98ce9c458\ + 4761df8d04ed04bb734ba48dd2106bb9ea54524f1394cdd18e6da3166e71c3ee", + ); + + write_test!( + ripemd160, + "9c1185a5c5e9fc54612808977ee8f548b2258d31", + "e571a1ca5b780aa52bafdb9ec852544ffca418ba", + "ddd2ecce739e823629c7d46ab18918e9c4a51c75", + ); + + write_test!( + hash160, + "b472a266d0bd89c13706a4132ccfb16f7c3b9fcb", + "671356a1a874695ad3bc20cae440f4360835bd5a", + "a9608c952c8dbcc20c53803d2ca5ad31d64d9313", + ); + + write_test!(siphash24, "d70077739d4b921e", "3a3ccefde9b5b1e3", "ce456e4e4ecbc5bf",); + + #[test] + fn hmac() { + let mut engine = hmac::HmacEngine::::new(&[0xde, 0xad, 0xbe, 0xef]); + engine.write_all(&[]).unwrap(); + assert_eq!( + format!("{}", hmac::Hmac::from_engine(engine)), + "bf5515149cf797955c4d3194cca42472883281951697c8375d9d9b107f384225" + ); + + let mut engine = hmac::HmacEngine::::new(&[0xde, 0xad, 0xbe, 0xef]); + engine.write_all(&[1; 256]).unwrap(); + assert_eq!( + format!("{}", hmac::Hmac::from_engine(engine)), + "59c9aca10c81c73cb4c196d94db741b6bf2050e0153d5a45f2526bff34675ac5" + ); + + let mut engine = hmac::HmacEngine::::new(&[0xde, 0xad, 0xbe, 0xef]); + engine.write_all(&[99; 64000]).unwrap(); + assert_eq!( + format!("{}", hmac::Hmac::from_engine(engine)), + "30df499717415a395379a1eaabe50038036e4abb5afc94aa55c952f4aa57be08" + ); + } +} diff --git a/hashes/src/internal_macros.rs b/hashes/src/internal_macros.rs new file mode 100644 index 00000000..32a52dbf --- /dev/null +++ b/hashes/src/internal_macros.rs @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Non-public macros + +macro_rules! arr_newtype_fmt_impl { + ($ty:ident, $bytes:expr $(, $gen:ident: $gent:ident)*) => { + impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> { + #[inline] + fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result { + #[allow(unused)] + use crate::Hash as _; + let case = $crate::hex::Case::Lower; + if <$ty<$($gen),*>>::DISPLAY_BACKWARD { + $crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case) + } else { + $crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter(), case) + } + } + } + + impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> { + #[inline] + fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result { + #[allow(unused)] + use crate::Hash as _; + let case = $crate::hex::Case::Upper; + if <$ty<$($gen),*>>::DISPLAY_BACKWARD { + $crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter().rev(), case) + } else { + $crate::hex::fmt_hex_exact!(f, $bytes, self.0.iter(), case) + } + } + } + + impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> { + #[inline] + fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result { + $crate::_export::_core::fmt::LowerHex::fmt(self, f) + } + } + + impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> { + #[inline] + fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result { + write!(f, "{:#}", self) + } + } + } +} +pub(crate) use arr_newtype_fmt_impl; + +/// Adds trait impls to the type called `Hash` in the current scope. +/// +/// Implpements various conversion traits as well as the [`crate::Hash`] trait. +/// Arguments: +/// +/// * `$bits` - number of bits this hash type has +/// * `$reverse` - `bool` - `true` if the hash type should be displayed backwards, `false` +/// otherwise. +/// * `$gen: $gent` - generic type(s) and trait bound(s) +/// +/// Restrictions on usage: +/// +/// * There must be a free-standing `fn from_engine(HashEngine) -> Hash` in the scope +/// * `fn internal_new([u8; $bits / 8]) -> Self` must exist on `Hash` +/// * `fn internal_engine() -> HashEngine` must exist on `Hash` +/// +/// `from_engine` obviously implements the finalization algorithm. +/// `internal_new` is required so that types with more than one field are constructible. +/// `internal_engine` is required to initialize the engine for given hash type. +macro_rules! hash_trait_impls { + ($bits:expr, $reverse:expr $(, $gen:ident: $gent:ident)*) => { + impl<$($gen: $gent),*> Hash<$($gen),*> { + /// Displays hex forwards, regardless of how this type would display it naturally. + /// + /// This is mainly intended as an internal method and you shouldn't need it unless + /// you're doing something special. + pub fn forward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex { + $crate::hex::DisplayHex::as_hex(&self.0) + } + + /// Displays hex backwards, regardless of how this type would display it naturally. + /// + /// This is mainly intended as an internal method and you shouldn't need it unless + /// you're doing something special. + pub fn backward_hex(&self) -> impl '_ + core::fmt::LowerHex + core::fmt::UpperHex { + $crate::hex::display::DisplayArray::<_, [u8; $bits / 8 * 2]>::new(self.0.iter().rev()) + } + + /// Zero cost conversion between a fixed length byte array shared reference and + /// a shared reference to this Hash type. + pub fn from_bytes_ref(bytes: &[u8; $bits / 8]) -> &Self { + // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8] + unsafe { &*(bytes as *const _ as *const Self) } + } + + /// Zero cost conversion between a fixed length byte array exclusive reference and + /// an exclusive reference to this Hash type. + pub fn from_bytes_mut(bytes: &mut [u8; $bits / 8]) -> &mut Self { + // Safety: Sound because Self is #[repr(transparent)] containing [u8; $bits / 8] + unsafe { &mut *(bytes as *mut _ as *mut Self) } + } + } + + impl<$($gen: $gent),*> str::FromStr for Hash<$($gen),*> { + type Err = $crate::hex::HexToArrayError; + fn from_str(s: &str) -> Result { + use $crate::hex::{FromHex, HexToBytesIter}; + use $crate::Hash; + + let inner: [u8; $bits / 8] = if $reverse { + FromHex::from_byte_iter(HexToBytesIter::new(s)?.rev())? + } else { + FromHex::from_byte_iter(HexToBytesIter::new(s)?)? + }; + Ok(Self::from_byte_array(inner)) + } + } + + $crate::internal_macros::arr_newtype_fmt_impl!(Hash, $bits / 8 $(, $gen: $gent)*); + serde_impl!(Hash, $bits / 8 $(, $gen: $gent)*); + borrow_slice_impl!(Hash $(, $gen: $gent)*); + + impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8; $bits / 8]> for Hash<$($gen),*> { + fn as_ref(&self) -> &[u8; $bits / 8] { + &self.0 + } + } + + impl $(, $gen: $gent)*> Index for Hash<$($gen),*> { + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + &self.0[index] + } + } + + impl<$($gen: $gent),*> crate::Hash for Hash<$($gen),*> { + type Engine = HashEngine; + type Bytes = [u8; $bits / 8]; + + const LEN: usize = $bits / 8; + const DISPLAY_BACKWARD: bool = $reverse; + + fn engine() -> Self::Engine { + Self::internal_engine() + } + + fn from_engine(e: HashEngine) -> Hash<$($gen),*> { + from_engine(e) + } + + fn from_slice(sl: &[u8]) -> Result, FromSliceError> { + if sl.len() != $bits / 8 { + Err(FromSliceError{expected: Self::LEN, got: sl.len()}) + } else { + let mut ret = [0; $bits / 8]; + ret.copy_from_slice(sl); + Ok(Self::internal_new(ret)) + } + } + + fn to_byte_array(self) -> Self::Bytes { + self.0 + } + + fn as_byte_array(&self) -> &Self::Bytes { + &self.0 + } + + fn from_byte_array(bytes: Self::Bytes) -> Self { + Self::internal_new(bytes) + } + + fn all_zeros() -> Self { + Hash::internal_new([0x00; $bits / 8]) + } + } + } +} +pub(crate) use hash_trait_impls; + +/// Creates a type called `Hash` and implements standard interface for it. +/// +/// The created type will have all standard derives, `Hash` impl and implementation of +/// `internal_engine` returning default. The created type has a single field. +/// +/// Arguments: +/// +/// * `$bits` - the number of bits of the hash type +/// * `$reverse` - `true` if the hash should be displayed backwards, `false` otherwise +/// * `$doc` - doc string to put on the type +/// * `$schemars` - a literal that goes into `schema_with`. +/// +/// The `from_engine` free-standing function is still required with this macro. See the doc of +/// [`hash_trait_impls`]. +macro_rules! hash_type { + ($bits:expr, $reverse:expr, $doc:literal, $schemars:literal) => { + #[doc = $doc] + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[cfg_attr(feature = "schemars", derive(crate::schemars::JsonSchema))] + #[repr(transparent)] + pub struct Hash( + #[cfg_attr(feature = "schemars", schemars(schema_with = $schemars))] [u8; $bits / 8], + ); + + impl Hash { + fn internal_new(arr: [u8; $bits / 8]) -> Self { Hash(arr) } + + fn internal_engine() -> HashEngine { Default::default() } + } + + crate::internal_macros::hash_trait_impls!($bits, $reverse); + }; +} +pub(crate) use hash_type; diff --git a/hashes/src/lib.rs b/hashes/src/lib.rs new file mode 100644 index 00000000..61361bb5 --- /dev/null +++ b/hashes/src/lib.rs @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Rust hashes library. +//! +//! This is a simple, no-dependency library which implements the hash functions +//! needed by Bitcoin. These are SHA256, SHA256d, and RIPEMD160. As an ancillary +//! thing, it exposes hexadecimal serialization and deserialization, since these +//! are needed to display hashes anway. +//! +//! ## Commonly used operations +//! +//! Hashing a single byte slice or a string: +//! +//! ```rust +//! use tapyrus_hashes::sha256; +//! use tapyrus_hashes::Hash; +//! +//! let bytes = [0u8; 5]; +//! let hash_of_bytes = sha256::Hash::hash(&bytes); +//! let hash_of_string = sha256::Hash::hash("some string".as_bytes()); +//! ``` +//! +//! +//! Hashing content from a reader: +//! +//! ```rust +//! use tapyrus_hashes::sha256; +//! use tapyrus_hashes::Hash; +//! +//! #[cfg(std)] +//! # fn main() -> std::io::Result<()> { +//! let mut reader: &[u8] = b"hello"; // in real code, this could be a `File` or `TcpStream` +//! let mut engine = sha256::HashEngine::default(); +//! std::io::copy(&mut reader, &mut engine)?; +//! let hash = sha256::Hash::from_engine(engine); +//! # Ok(()) +//! # } +//! +//! #[cfg(not(std))] +//! # fn main() {} +//! ``` +//! +//! +//! Hashing content by [`std::io::Write`] on HashEngine: +//! +//! ```rust +//! use tapyrus_hashes::sha256; +//! use tapyrus_hashes::Hash; +//! use std::io::Write; +//! +//! #[cfg(std)] +//! # fn main() -> std::io::Result<()> { +//! let mut part1: &[u8] = b"hello"; +//! let mut part2: &[u8] = b" "; +//! let mut part3: &[u8] = b"world"; +//! let mut engine = sha256::HashEngine::default(); +//! engine.write_all(part1)?; +//! engine.write_all(part2)?; +//! engine.write_all(part3)?; +//! let hash = sha256::Hash::from_engine(engine); +//! # Ok(()) +//! # } +//! +//! #[cfg(not(std))] +//! # fn main() {} +//! ``` + +// Coding conventions +#![warn(missing_docs)] +// Experimental features we need. +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(bench, feature(test))] +// In general, rust is absolutely horrid at supporting users doing things like, +// for example, compiling Rust code for real environments. Disable useless lints +// that don't do anything but annoy us and cant actually ever be resolved. +#![allow(bare_trait_objects)] +#![allow(ellipsis_inclusive_range_patterns)] +#![cfg_attr(all(not(test), not(feature = "std")), no_std)] +// Instead of littering the codebase for non-fuzzing code just globally allow. +#![cfg_attr(hashes_fuzz, allow(dead_code, unused_imports))] +// Exclude clippy lints we don't think are valuable +#![allow(clippy::needless_question_mark)] // https://github.com/rust-bitcoin/rust-bitcoin/pull/2134 + +#[cfg(all(not(test), not(feature = "std"), feature = "core2"))] +extern crate actual_core2 as core2; +#[cfg(all(feature = "alloc", not(feature = "std")))] +extern crate alloc; +#[cfg(any(test, feature = "std"))] +extern crate core; + +#[cfg(feature = "serde")] +/// A generic serialization/deserialization framework. +pub extern crate serde; + +#[cfg(all(test, feature = "serde"))] +extern crate serde_test; +#[cfg(bench)] +extern crate test; + +/// Re-export the `hex-conservative` crate. +pub extern crate hex; + +#[doc(hidden)] +pub mod _export { + /// A re-export of core::* + pub mod _core { + pub use core::*; + } +} + +#[cfg(feature = "schemars")] +extern crate schemars; + +mod internal_macros; +#[macro_use] +mod util; +#[macro_use] +pub mod serde_macros; +pub mod cmp; +pub mod hash160; +pub mod hmac; +#[cfg(any(test, feature = "std", feature = "core2"))] +mod impls; +pub mod ripemd160; +pub mod sha1; +pub mod sha256; +pub mod sha256d; +pub mod sha256t; +pub mod sha512; +pub mod sha512_256; +pub mod siphash24; + +use core::{borrow, fmt, hash, ops}; +// You get I/O if you enable "std" or "core2" (as well as during testing). +#[cfg(any(test, feature = "std"))] +use std::io; + +#[cfg(all(not(test), not(feature = "std"), feature = "core2"))] +use core2::io; +pub use hmac::{Hmac, HmacEngine}; + +/// A hashing engine which bytes can be serialized into. +pub trait HashEngine: Clone + Default { + /// Byte array representing the internal state of the hash engine. + type MidState; + + /// Outputs the midstate of the hash engine. This function should not be + /// used directly unless you really know what you're doing. + fn midstate(&self) -> Self::MidState; + + /// Length of the hash's internal block size, in bytes. + const BLOCK_SIZE: usize; + + /// Add data to the hash engine. + fn input(&mut self, data: &[u8]); + + /// Return the number of bytes already n_bytes_hashed(inputted). + fn n_bytes_hashed(&self) -> usize; +} + +/// Trait which applies to hashes of all types. +pub trait Hash: + Copy + + Clone + + PartialEq + + Eq + + PartialOrd + + Ord + + hash::Hash + + fmt::Debug + + fmt::Display + + fmt::LowerHex + + ops::Index + + ops::Index, Output = [u8]> + + ops::Index, Output = [u8]> + + ops::Index, Output = [u8]> + + ops::Index + + borrow::Borrow<[u8]> +{ + /// A hashing engine which bytes can be serialized into. It is expected + /// to implement the `io::Write` trait, and to never return errors under + /// any conditions. + type Engine: HashEngine; + + /// The byte array that represents the hash internally. + type Bytes: hex::FromHex + Copy; + + /// Constructs a new engine. + fn engine() -> Self::Engine { Self::Engine::default() } + + /// Produces a hash from the current state of a given engine. + fn from_engine(e: Self::Engine) -> Self; + + /// Length of the hash, in bytes. + const LEN: usize; + + /// Copies a byte slice into a hash object. + fn from_slice(sl: &[u8]) -> Result; + + /// Hashes some bytes. + fn hash(data: &[u8]) -> Self { + let mut engine = Self::engine(); + engine.input(data); + Self::from_engine(engine) + } + + /// Flag indicating whether user-visible serializations of this hash + /// should be backward. For some reason Satoshi decided this should be + /// true for `Sha256dHash`, so here we are. + const DISPLAY_BACKWARD: bool = false; + + /// Returns the underlying byte array. + fn to_byte_array(self) -> Self::Bytes; + + /// Returns a reference to the underlying byte array. + fn as_byte_array(&self) -> &Self::Bytes; + + /// Constructs a hash from the underlying byte array. + fn from_byte_array(bytes: Self::Bytes) -> Self; + + /// Returns an all zero hash. + /// + /// An all zeros hash is a made up construct because there is not a known input that can create + /// it, however it is used in various places in Bitcoin e.g., the Bitcoin genesis block's + /// previous blockhash and the coinbase transaction's outpoint txid. + fn all_zeros() -> Self; +} + +/// Attempted to create a hash from an invalid length slice. +#[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub struct FromSliceError { + expected: usize, + got: usize, +} + +impl fmt::Display for FromSliceError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "invalid slice length {} (expected {})", self.got, self.expected) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for FromSliceError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } +} + +#[cfg(test)] +mod tests { + use crate::{sha256d, Hash}; + + hash_newtype! { + /// A test newtype + struct TestNewtype(sha256d::Hash); + + /// A test newtype + struct TestNewtype2(sha256d::Hash); + } + + #[test] + fn convert_newtypes() { + let h1 = TestNewtype::hash(&[]); + let h2: TestNewtype2 = h1.to_raw_hash().into(); + assert_eq!(&h1[..], &h2[..]); + + let h = sha256d::Hash::hash(&[]); + let h2: TestNewtype = h.to_string().parse().unwrap(); + assert_eq!(h2.to_raw_hash(), h); + } +} diff --git a/hashes/src/ripemd160.rs b/hashes/src/ripemd160.rs new file mode 100644 index 00000000..d97b3bba --- /dev/null +++ b/hashes/src/ripemd160.rs @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! RIPEMD160 implementation. +//! + +use core::convert::TryInto; +use core::ops::Index; +use core::slice::SliceIndex; +use core::{cmp, str}; + +use crate::{FromSliceError, HashEngine as _}; + +crate::internal_macros::hash_type! { + 160, + false, + "Output of the RIPEMD160 hash function.", + "crate::util::json_hex_string::len_20" +} + +#[cfg(not(hashes_fuzz))] +fn from_engine(mut e: HashEngine) -> Hash { + // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining + let data_len = e.length as u64; + + let zeroes = [0; BLOCK_SIZE - 8]; + e.input(&[0x80]); + if e.length % BLOCK_SIZE > zeroes.len() { + e.input(&zeroes); + } + let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); + e.input(&zeroes[..pad_length]); + debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); + + e.input(&(8 * data_len).to_le_bytes()); + debug_assert_eq!(e.length % BLOCK_SIZE, 0); + + Hash(e.midstate()) +} + +#[cfg(hashes_fuzz)] +fn from_engine(e: HashEngine) -> Hash { + let mut res = e.midstate(); + res[0] ^= (e.length & 0xff) as u8; + Hash(res) +} + +const BLOCK_SIZE: usize = 64; + +/// Engine to compute RIPEMD160 hash function. +#[derive(Clone)] +pub struct HashEngine { + buffer: [u8; BLOCK_SIZE], + h: [u32; 5], + length: usize, +} + +impl Default for HashEngine { + fn default() -> Self { + HashEngine { + h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], + length: 0, + buffer: [0; BLOCK_SIZE], + } + } +} + +impl crate::HashEngine for HashEngine { + type MidState = [u8; 20]; + + #[cfg(not(hashes_fuzz))] + fn midstate(&self) -> [u8; 20] { + let mut ret = [0; 20]; + for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(4)) { + ret_bytes.copy_from_slice(&(*val).to_le_bytes()); + } + ret + } + + #[cfg(hashes_fuzz)] + fn midstate(&self) -> [u8; 20] { + let mut ret = [0; 20]; + ret.copy_from_slice(&self.buffer[..20]); + ret + } + + const BLOCK_SIZE: usize = 64; + + fn n_bytes_hashed(&self) -> usize { self.length } + + engine_input_impl!(); +} + +#[cfg(feature = "small-hash")] +#[macro_use] +mod small_hash { + #[rustfmt::skip] + pub(super) fn round(a: u32, _b: u32, c: u32, _d: u32, e: u32, + x: u32, bits: u32, add: u32, round: u32, + ) -> (u32, u32) { + let a = a.wrapping_add(round).wrapping_add(x).wrapping_add(add); + let a = a.rotate_left(bits).wrapping_add(e); + let c = c.rotate_left(10); + + (a, c) + } + + macro_rules! round( + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, + $x:expr, $bits:expr, $add:expr, $round:expr) => ({ + let updates = small_hash::round($a, $b, $c, $d, $e, $x, $bits, $add, $round); + $a = updates.0; + $c = updates.1; + }); + ); +} + +#[cfg(not(feature = "small-hash"))] +macro_rules! round( + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, + $x:expr, $bits:expr, $add:expr, $round:expr) => ({ + $a = $a.wrapping_add($round).wrapping_add($x).wrapping_add($add); + $a = $a.rotate_left($bits).wrapping_add($e); + $c = $c.rotate_left(10); + }); +); + +macro_rules! process_block( + ($h:expr, $data:expr, + $( round1: h_ordering $f0:expr, $f1:expr, $f2:expr, $f3:expr, $f4:expr; + data_index $data_index1:expr; roll_shift $bits1:expr; )* + $( round2: h_ordering $g0:expr, $g1:expr, $g2:expr, $g3:expr, $g4:expr; + data_index $data_index2:expr; roll_shift $bits2:expr; )* + $( round3: h_ordering $h0:expr, $h1:expr, $h2:expr, $h3:expr, $h4:expr; + data_index $data_index3:expr; roll_shift $bits3:expr; )* + $( round4: h_ordering $i0:expr, $i1:expr, $i2:expr, $i3:expr, $i4:expr; + data_index $data_index4:expr; roll_shift $bits4:expr; )* + $( round5: h_ordering $j0:expr, $j1:expr, $j2:expr, $j3:expr, $j4:expr; + data_index $data_index5:expr; roll_shift $bits5:expr; )* + $( par_round1: h_ordering $pj0:expr, $pj1:expr, $pj2:expr, $pj3:expr, $pj4:expr; + data_index $pdata_index1:expr; roll_shift $pbits1:expr; )* + $( par_round2: h_ordering $pi0:expr, $pi1:expr, $pi2:expr, $pi3:expr, $pi4:expr; + data_index $pdata_index2:expr; roll_shift $pbits2:expr; )* + $( par_round3: h_ordering $ph0:expr, $ph1:expr, $ph2:expr, $ph3:expr, $ph4:expr; + data_index $pdata_index3:expr; roll_shift $pbits3:expr; )* + $( par_round4: h_ordering $pg0:expr, $pg1:expr, $pg2:expr, $pg3:expr, $pg4:expr; + data_index $pdata_index4:expr; roll_shift $pbits4:expr; )* + $( par_round5: h_ordering $pf0:expr, $pf1:expr, $pf2:expr, $pf3:expr, $pf4:expr; + data_index $pdata_index5:expr; roll_shift $pbits5:expr; )* + ) => ({ + let mut bb = $h; + let mut bbb = $h; + + // Round 1 + $( round!(bb[$f0], bb[$f1], bb[$f2], bb[$f3], bb[$f4], + $data[$data_index1], $bits1, 0x00000000, + bb[$f1] ^ bb[$f2] ^ bb[$f3]); )* + + // Round 2 + $( round!(bb[$g0], bb[$g1], bb[$g2], bb[$g3], bb[$g4], + $data[$data_index2], $bits2, 0x5a827999, + (bb[$g1] & bb[$g2]) | (!bb[$g1] & bb[$g3])); )* + + // Round 3 + $( round!(bb[$h0], bb[$h1], bb[$h2], bb[$h3], bb[$h4], + $data[$data_index3], $bits3, 0x6ed9eba1, + (bb[$h1] | !bb[$h2]) ^ bb[$h3]); )* + + // Round 4 + $( round!(bb[$i0], bb[$i1], bb[$i2], bb[$i3], bb[$i4], + $data[$data_index4], $bits4, 0x8f1bbcdc, + (bb[$i1] & bb[$i3]) | (bb[$i2] & !bb[$i3])); )* + + // Round 5 + $( round!(bb[$j0], bb[$j1], bb[$j2], bb[$j3], bb[$j4], + $data[$data_index5], $bits5, 0xa953fd4e, + bb[$j1] ^ (bb[$j2] | !bb[$j3])); )* + + // Parallel rounds: these are the same as the previous five + // rounds except that the constants have changed, we work + // with the other buffer, and they are applied in reverse + // order. + + // Parallel Round 1 + $( round!(bbb[$pj0], bbb[$pj1], bbb[$pj2], bbb[$pj3], bbb[$pj4], + $data[$pdata_index1], $pbits1, 0x50a28be6, + bbb[$pj1] ^ (bbb[$pj2] | !bbb[$pj3])); )* + + // Porallel Round 2 + $( round!(bbb[$pi0], bbb[$pi1], bbb[$pi2], bbb[$pi3], bbb[$pi4], + $data[$pdata_index2], $pbits2, 0x5c4dd124, + (bbb[$pi1] & bbb[$pi3]) | (bbb[$pi2] & !bbb[$pi3])); )* + + // Parallel Round 3 + $( round!(bbb[$ph0], bbb[$ph1], bbb[$ph2], bbb[$ph3], bbb[$ph4], + $data[$pdata_index3], $pbits3, 0x6d703ef3, + (bbb[$ph1] | !bbb[$ph2]) ^ bbb[$ph3]); )* + + // Parallel Round 4 + $( round!(bbb[$pg0], bbb[$pg1], bbb[$pg2], bbb[$pg3], bbb[$pg4], + $data[$pdata_index4], $pbits4, 0x7a6d76e9, + (bbb[$pg1] & bbb[$pg2]) | (!bbb[$pg1] & bbb[$pg3])); )* + + // Parallel Round 5 + $( round!(bbb[$pf0], bbb[$pf1], bbb[$pf2], bbb[$pf3], bbb[$pf4], + $data[$pdata_index5], $pbits5, 0x00000000, + bbb[$pf1] ^ bbb[$pf2] ^ bbb[$pf3]); )* + + // Combine results + bbb[3] = bbb[3].wrapping_add($h[1]).wrapping_add(bb[2]); + $h[1] = $h[2].wrapping_add(bb[3]).wrapping_add(bbb[4]); + $h[2] = $h[3].wrapping_add(bb[4]).wrapping_add(bbb[0]); + $h[3] = $h[4].wrapping_add(bb[0]).wrapping_add(bbb[1]); + $h[4] = $h[0].wrapping_add(bb[1]).wrapping_add(bbb[2]); + $h[0] = bbb[3]; + }); +); + +impl HashEngine { + fn process_block(&mut self) { + debug_assert_eq!(self.buffer.len(), BLOCK_SIZE); + + let mut w = [0u32; 16]; + for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.chunks_exact(4)) { + *w_val = u32::from_le_bytes(buff_bytes.try_into().expect("4 byte slice")) + } + + process_block!(self.h, w, + // Round 1 + round1: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 11; + round1: h_ordering 4, 0, 1, 2, 3; data_index 1; roll_shift 14; + round1: h_ordering 3, 4, 0, 1, 2; data_index 2; roll_shift 15; + round1: h_ordering 2, 3, 4, 0, 1; data_index 3; roll_shift 12; + round1: h_ordering 1, 2, 3, 4, 0; data_index 4; roll_shift 5; + round1: h_ordering 0, 1, 2, 3, 4; data_index 5; roll_shift 8; + round1: h_ordering 4, 0, 1, 2, 3; data_index 6; roll_shift 7; + round1: h_ordering 3, 4, 0, 1, 2; data_index 7; roll_shift 9; + round1: h_ordering 2, 3, 4, 0, 1; data_index 8; roll_shift 11; + round1: h_ordering 1, 2, 3, 4, 0; data_index 9; roll_shift 13; + round1: h_ordering 0, 1, 2, 3, 4; data_index 10; roll_shift 14; + round1: h_ordering 4, 0, 1, 2, 3; data_index 11; roll_shift 15; + round1: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift 6; + round1: h_ordering 2, 3, 4, 0, 1; data_index 13; roll_shift 7; + round1: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift 9; + round1: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift 8; + + // Round 2 + round2: h_ordering 4, 0, 1, 2, 3; data_index 7; roll_shift 7; + round2: h_ordering 3, 4, 0, 1, 2; data_index 4; roll_shift 6; + round2: h_ordering 2, 3, 4, 0, 1; data_index 13; roll_shift 8; + round2: h_ordering 1, 2, 3, 4, 0; data_index 1; roll_shift 13; + round2: h_ordering 0, 1, 2, 3, 4; data_index 10; roll_shift 11; + round2: h_ordering 4, 0, 1, 2, 3; data_index 6; roll_shift 9; + round2: h_ordering 3, 4, 0, 1, 2; data_index 15; roll_shift 7; + round2: h_ordering 2, 3, 4, 0, 1; data_index 3; roll_shift 15; + round2: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift 7; + round2: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 12; + round2: h_ordering 4, 0, 1, 2, 3; data_index 9; roll_shift 15; + round2: h_ordering 3, 4, 0, 1, 2; data_index 5; roll_shift 9; + round2: h_ordering 2, 3, 4, 0, 1; data_index 2; roll_shift 11; + round2: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift 7; + round2: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 13; + round2: h_ordering 4, 0, 1, 2, 3; data_index 8; roll_shift 12; + + // Round 3 + round3: h_ordering 3, 4, 0, 1, 2; data_index 3; roll_shift 11; + round3: h_ordering 2, 3, 4, 0, 1; data_index 10; roll_shift 13; + round3: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift 6; + round3: h_ordering 0, 1, 2, 3, 4; data_index 4; roll_shift 7; + round3: h_ordering 4, 0, 1, 2, 3; data_index 9; roll_shift 14; + round3: h_ordering 3, 4, 0, 1, 2; data_index 15; roll_shift 9; + round3: h_ordering 2, 3, 4, 0, 1; data_index 8; roll_shift 13; + round3: h_ordering 1, 2, 3, 4, 0; data_index 1; roll_shift 15; + round3: h_ordering 0, 1, 2, 3, 4; data_index 2; roll_shift 14; + round3: h_ordering 4, 0, 1, 2, 3; data_index 7; roll_shift 8; + round3: h_ordering 3, 4, 0, 1, 2; data_index 0; roll_shift 13; + round3: h_ordering 2, 3, 4, 0, 1; data_index 6; roll_shift 6; + round3: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift 5; + round3: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 12; + round3: h_ordering 4, 0, 1, 2, 3; data_index 5; roll_shift 7; + round3: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift 5; + + // Round 4 + round4: h_ordering 2, 3, 4, 0, 1; data_index 1; roll_shift 11; + round4: h_ordering 1, 2, 3, 4, 0; data_index 9; roll_shift 12; + round4: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 14; + round4: h_ordering 4, 0, 1, 2, 3; data_index 10; roll_shift 15; + round4: h_ordering 3, 4, 0, 1, 2; data_index 0; roll_shift 14; + round4: h_ordering 2, 3, 4, 0, 1; data_index 8; roll_shift 15; + round4: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift 9; + round4: h_ordering 0, 1, 2, 3, 4; data_index 4; roll_shift 8; + round4: h_ordering 4, 0, 1, 2, 3; data_index 13; roll_shift 9; + round4: h_ordering 3, 4, 0, 1, 2; data_index 3; roll_shift 14; + round4: h_ordering 2, 3, 4, 0, 1; data_index 7; roll_shift 5; + round4: h_ordering 1, 2, 3, 4, 0; data_index 15; roll_shift 6; + round4: h_ordering 0, 1, 2, 3, 4; data_index 14; roll_shift 8; + round4: h_ordering 4, 0, 1, 2, 3; data_index 5; roll_shift 6; + round4: h_ordering 3, 4, 0, 1, 2; data_index 6; roll_shift 5; + round4: h_ordering 2, 3, 4, 0, 1; data_index 2; roll_shift 12; + + // Round 5 + round5: h_ordering 1, 2, 3, 4, 0; data_index 4; roll_shift 9; + round5: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 15; + round5: h_ordering 4, 0, 1, 2, 3; data_index 5; roll_shift 5; + round5: h_ordering 3, 4, 0, 1, 2; data_index 9; roll_shift 11; + round5: h_ordering 2, 3, 4, 0, 1; data_index 7; roll_shift 6; + round5: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift 8; + round5: h_ordering 0, 1, 2, 3, 4; data_index 2; roll_shift 13; + round5: h_ordering 4, 0, 1, 2, 3; data_index 10; roll_shift 12; + round5: h_ordering 3, 4, 0, 1, 2; data_index 14; roll_shift 5; + round5: h_ordering 2, 3, 4, 0, 1; data_index 1; roll_shift 12; + round5: h_ordering 1, 2, 3, 4, 0; data_index 3; roll_shift 13; + round5: h_ordering 0, 1, 2, 3, 4; data_index 8; roll_shift 14; + round5: h_ordering 4, 0, 1, 2, 3; data_index 11; roll_shift 11; + round5: h_ordering 3, 4, 0, 1, 2; data_index 6; roll_shift 8; + round5: h_ordering 2, 3, 4, 0, 1; data_index 15; roll_shift 5; + round5: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift 6; + + // Porallel Round 1; + par_round1: h_ordering 0, 1, 2, 3, 4; data_index 5; roll_shift 8; + par_round1: h_ordering 4, 0, 1, 2, 3; data_index 14; roll_shift 9; + par_round1: h_ordering 3, 4, 0, 1, 2; data_index 7; roll_shift 9; + par_round1: h_ordering 2, 3, 4, 0, 1; data_index 0; roll_shift 11; + par_round1: h_ordering 1, 2, 3, 4, 0; data_index 9; roll_shift 13; + par_round1: h_ordering 0, 1, 2, 3, 4; data_index 2; roll_shift 15; + par_round1: h_ordering 4, 0, 1, 2, 3; data_index 11; roll_shift 15; + par_round1: h_ordering 3, 4, 0, 1, 2; data_index 4; roll_shift 5; + par_round1: h_ordering 2, 3, 4, 0, 1; data_index 13; roll_shift 7; + par_round1: h_ordering 1, 2, 3, 4, 0; data_index 6; roll_shift 7; + par_round1: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift 8; + par_round1: h_ordering 4, 0, 1, 2, 3; data_index 8; roll_shift 11; + par_round1: h_ordering 3, 4, 0, 1, 2; data_index 1; roll_shift 14; + par_round1: h_ordering 2, 3, 4, 0, 1; data_index 10; roll_shift 14; + par_round1: h_ordering 1, 2, 3, 4, 0; data_index 3; roll_shift 12; + par_round1: h_ordering 0, 1, 2, 3, 4; data_index 12; roll_shift 6; + + // Parallel Round 2 + par_round2: h_ordering 4, 0, 1, 2, 3; data_index 6; roll_shift 9; + par_round2: h_ordering 3, 4, 0, 1, 2; data_index 11; roll_shift 13; + par_round2: h_ordering 2, 3, 4, 0, 1; data_index 3; roll_shift 15; + par_round2: h_ordering 1, 2, 3, 4, 0; data_index 7; roll_shift 7; + par_round2: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 12; + par_round2: h_ordering 4, 0, 1, 2, 3; data_index 13; roll_shift 8; + par_round2: h_ordering 3, 4, 0, 1, 2; data_index 5; roll_shift 9; + par_round2: h_ordering 2, 3, 4, 0, 1; data_index 10; roll_shift 11; + par_round2: h_ordering 1, 2, 3, 4, 0; data_index 14; roll_shift 7; + par_round2: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift 7; + par_round2: h_ordering 4, 0, 1, 2, 3; data_index 8; roll_shift 12; + par_round2: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift 7; + par_round2: h_ordering 2, 3, 4, 0, 1; data_index 4; roll_shift 6; + par_round2: h_ordering 1, 2, 3, 4, 0; data_index 9; roll_shift 15; + par_round2: h_ordering 0, 1, 2, 3, 4; data_index 1; roll_shift 13; + par_round2: h_ordering 4, 0, 1, 2, 3; data_index 2; roll_shift 11; + + // Parallel Round 3 + par_round3: h_ordering 3, 4, 0, 1, 2; data_index 15; roll_shift 9; + par_round3: h_ordering 2, 3, 4, 0, 1; data_index 5; roll_shift 7; + par_round3: h_ordering 1, 2, 3, 4, 0; data_index 1; roll_shift 15; + par_round3: h_ordering 0, 1, 2, 3, 4; data_index 3; roll_shift 11; + par_round3: h_ordering 4, 0, 1, 2, 3; data_index 7; roll_shift 8; + par_round3: h_ordering 3, 4, 0, 1, 2; data_index 14; roll_shift 6; + par_round3: h_ordering 2, 3, 4, 0, 1; data_index 6; roll_shift 6; + par_round3: h_ordering 1, 2, 3, 4, 0; data_index 9; roll_shift 14; + par_round3: h_ordering 0, 1, 2, 3, 4; data_index 11; roll_shift 12; + par_round3: h_ordering 4, 0, 1, 2, 3; data_index 8; roll_shift 13; + par_round3: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift 5; + par_round3: h_ordering 2, 3, 4, 0, 1; data_index 2; roll_shift 14; + par_round3: h_ordering 1, 2, 3, 4, 0; data_index 10; roll_shift 13; + par_round3: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 13; + par_round3: h_ordering 4, 0, 1, 2, 3; data_index 4; roll_shift 7; + par_round3: h_ordering 3, 4, 0, 1, 2; data_index 13; roll_shift 5; + + // Parallel Round 4 + par_round4: h_ordering 2, 3, 4, 0, 1; data_index 8; roll_shift 15; + par_round4: h_ordering 1, 2, 3, 4, 0; data_index 6; roll_shift 5; + par_round4: h_ordering 0, 1, 2, 3, 4; data_index 4; roll_shift 8; + par_round4: h_ordering 4, 0, 1, 2, 3; data_index 1; roll_shift 11; + par_round4: h_ordering 3, 4, 0, 1, 2; data_index 3; roll_shift 14; + par_round4: h_ordering 2, 3, 4, 0, 1; data_index 11; roll_shift 14; + par_round4: h_ordering 1, 2, 3, 4, 0; data_index 15; roll_shift 6; + par_round4: h_ordering 0, 1, 2, 3, 4; data_index 0; roll_shift 14; + par_round4: h_ordering 4, 0, 1, 2, 3; data_index 5; roll_shift 6; + par_round4: h_ordering 3, 4, 0, 1, 2; data_index 12; roll_shift 9; + par_round4: h_ordering 2, 3, 4, 0, 1; data_index 2; roll_shift 12; + par_round4: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift 9; + par_round4: h_ordering 0, 1, 2, 3, 4; data_index 9; roll_shift 12; + par_round4: h_ordering 4, 0, 1, 2, 3; data_index 7; roll_shift 5; + par_round4: h_ordering 3, 4, 0, 1, 2; data_index 10; roll_shift 15; + par_round4: h_ordering 2, 3, 4, 0, 1; data_index 14; roll_shift 8; + + // Parallel Round 5 + par_round5: h_ordering 1, 2, 3, 4, 0; data_index 12; roll_shift 8; + par_round5: h_ordering 0, 1, 2, 3, 4; data_index 15; roll_shift 5; + par_round5: h_ordering 4, 0, 1, 2, 3; data_index 10; roll_shift 12; + par_round5: h_ordering 3, 4, 0, 1, 2; data_index 4; roll_shift 9; + par_round5: h_ordering 2, 3, 4, 0, 1; data_index 1; roll_shift 12; + par_round5: h_ordering 1, 2, 3, 4, 0; data_index 5; roll_shift 5; + par_round5: h_ordering 0, 1, 2, 3, 4; data_index 8; roll_shift 14; + par_round5: h_ordering 4, 0, 1, 2, 3; data_index 7; roll_shift 6; + par_round5: h_ordering 3, 4, 0, 1, 2; data_index 6; roll_shift 8; + par_round5: h_ordering 2, 3, 4, 0, 1; data_index 2; roll_shift 13; + par_round5: h_ordering 1, 2, 3, 4, 0; data_index 13; roll_shift 6; + par_round5: h_ordering 0, 1, 2, 3, 4; data_index 14; roll_shift 5; + par_round5: h_ordering 4, 0, 1, 2, 3; data_index 0; roll_shift 15; + par_round5: h_ordering 3, 4, 0, 1, 2; data_index 3; roll_shift 13; + par_round5: h_ordering 2, 3, 4, 0, 1; data_index 9; roll_shift 11; + par_round5: h_ordering 1, 2, 3, 4, 0; data_index 11; roll_shift 11; + ); + } +} + +#[cfg(test)] +mod tests { + #[test] + #[cfg(feature = "alloc")] + fn test() { + use std::convert::TryFrom; + + use crate::{ripemd160, Hash, HashEngine}; + + #[derive(Clone)] + struct Test { + input: &'static str, + output: Vec, + output_str: &'static str, + } + + #[rustfmt::skip] + let tests = vec![ + // Test messages from FIPS 180-1 + Test { + input: "abc", + output: vec![ + 0x8e, 0xb2, 0x08, 0xf7, + 0xe0, 0x5d, 0x98, 0x7a, + 0x9b, 0x04, 0x4a, 0x8e, + 0x98, 0xc6, 0xb0, 0x87, + 0xf1, 0x5a, 0x0b, 0xfc, + ], + output_str: "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc" + }, + Test { + input: + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + output: vec![ + 0x12, 0xa0, 0x53, 0x38, + 0x4a, 0x9c, 0x0c, 0x88, + 0xe4, 0x05, 0xa0, 0x6c, + 0x27, 0xdc, 0xf4, 0x9a, + 0xda, 0x62, 0xeb, 0x2b, + ], + output_str: "12a053384a9c0c88e405a06c27dcf49ada62eb2b" + }, + // Examples from wikipedia + Test { + input: "The quick brown fox jumps over the lazy dog", + output: vec![ + 0x37, 0xf3, 0x32, 0xf6, + 0x8d, 0xb7, 0x7b, 0xd9, + 0xd7, 0xed, 0xd4, 0x96, + 0x95, 0x71, 0xad, 0x67, + 0x1c, 0xf9, 0xdd, 0x3b, + ], + output_str: "37f332f68db77bd9d7edd4969571ad671cf9dd3b", + }, + Test { + input: "The quick brown fox jumps over the lazy cog", + output: vec![ + 0x13, 0x20, 0x72, 0xdf, + 0x69, 0x09, 0x33, 0x83, + 0x5e, 0xb8, 0xb6, 0xad, + 0x0b, 0x77, 0xe7, 0xb6, + 0xf1, 0x4a, 0xca, 0xd7, + ], + output_str: "132072df690933835eb8b6ad0b77e7b6f14acad7", + }, + ]; + + for mut test in tests { + // Hash through high-level API, check hex encoding/decoding + let hash = ripemd160::Hash::hash(test.input.as_bytes()); + assert_eq!(hash, test.output_str.parse::().expect("parse hex")); + assert_eq!(&hash[..], &test.output[..]); + assert_eq!(&hash.to_string(), &test.output_str); + assert_eq!( + ripemd160::Hash::from_bytes_ref( + <&[u8; 20]>::try_from(&*test.output).expect("known length") + ), + &hash + ); + assert_eq!( + ripemd160::Hash::from_bytes_mut( + <&mut [u8; 20]>::try_from(&mut *test.output).expect("known length") + ), + &hash + ); + + // Hash through engine, checking that we can input byte by byte + let mut engine = ripemd160::Hash::engine(); + for ch in test.input.as_bytes() { + engine.input(&[*ch]); + } + let manual_hash = ripemd160::Hash::from_engine(engine); + assert_eq!(hash, manual_hash); + assert_eq!(hash.as_byte_array(), test.output.as_slice()); + } + } + + #[cfg(feature = "serde")] + #[test] + fn ripemd_serde() { + use serde_test::{assert_tokens, Configure, Token}; + + use crate::{ripemd160, Hash}; + + #[rustfmt::skip] + static HASH_BYTES: [u8; 20] = [ + 0x13, 0x20, 0x72, 0xdf, + 0x69, 0x09, 0x33, 0x83, + 0x5e, 0xb8, 0xb6, 0xad, + 0x0b, 0x77, 0xe7, 0xb6, + 0xf1, 0x4a, 0xca, 0xd7, + ]; + + let hash = ripemd160::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]); + assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]); + } +} + +#[cfg(bench)] +mod benches { + use test::Bencher; + + use crate::{ripemd160, Hash, HashEngine}; + + #[bench] + pub fn ripemd160_10(bh: &mut Bencher) { + let mut engine = ripemd160::Hash::engine(); + let bytes = [1u8; 10]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn ripemd160_1k(bh: &mut Bencher) { + let mut engine = ripemd160::Hash::engine(); + let bytes = [1u8; 1024]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn ripemd160_64k(bh: &mut Bencher) { + let mut engine = ripemd160::Hash::engine(); + let bytes = [1u8; 65536]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } +} diff --git a/hashes/src/serde_macros.rs b/hashes/src/serde_macros.rs new file mode 100644 index 00000000..ded28b2f --- /dev/null +++ b/hashes/src/serde_macros.rs @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Macros for serde trait implementations, and supporting code. +//! + +/// Functions used by serde impls of all hashes. +#[cfg(feature = "serde")] +pub mod serde_details { + use core::marker::PhantomData; + use core::str::FromStr; + use core::{fmt, ops, str}; + + use crate::FromSliceError; + struct HexVisitor(PhantomData); + use serde::{de, Deserializer, Serializer}; + + impl<'de, ValueT> de::Visitor<'de> for HexVisitor + where + ValueT: FromStr, + ::Err: fmt::Display, + { + type Value = ValueT; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("an ASCII hex string") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: de::Error, + { + if let Ok(hex) = str::from_utf8(v) { + Self::Value::from_str(hex).map_err(E::custom) + } else { + return Err(E::invalid_value(de::Unexpected::Bytes(v), &self)); + } + } + + fn visit_str(self, v: &str) -> Result + where + E: de::Error, + { + Self::Value::from_str(v).map_err(E::custom) + } + } + + struct BytesVisitor(PhantomData); + + impl<'de, ValueT> de::Visitor<'de> for BytesVisitor + where + ValueT: SerdeHash, + ::Err: fmt::Display, + { + type Value = ValueT; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a bytestring") + } + + fn visit_bytes(self, v: &[u8]) -> Result + where + E: de::Error, + { + SerdeHash::from_slice_delegated(v).map_err(|_| { + // from_slice only errors on incorrect length + E::invalid_length(v.len(), &stringify!(N)) + }) + } + } + + /// Default serialization/deserialization methods. + pub trait SerdeHash + where + Self: Sized + + FromStr + + fmt::Display + + ops::Index + + ops::Index, + ::Err: fmt::Display, + { + /// Size, in bits, of the hash. + const N: usize; + + /// Helper function to turn a deserialized slice into the correct hash type. + fn from_slice_delegated(sl: &[u8]) -> Result; + + /// Do serde serialization. + fn serialize(&self, s: S) -> Result { + if s.is_human_readable() { + s.collect_str(self) + } else { + s.serialize_bytes(&self[..]) + } + } + + /// Do serde deserialization. + fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result { + if d.is_human_readable() { + d.deserialize_str(HexVisitor::(PhantomData)) + } else { + d.deserialize_bytes(BytesVisitor::(PhantomData)) + } + } + } +} + +/// Implements `Serialize` and `Deserialize` for a type `$t` which +/// represents a newtype over a byte-slice over length `$len`. +#[macro_export] +#[cfg(feature = "serde")] +macro_rules! serde_impl( + ($t:ident, $len:expr $(, $gen:ident: $gent:ident)*) => ( + impl<$($gen: $gent),*> $crate::serde_macros::serde_details::SerdeHash for $t<$($gen),*> { + const N : usize = $len; + fn from_slice_delegated(sl: &[u8]) -> Result { + #[allow(unused_imports)] + use $crate::Hash as _; + $t::from_slice(sl) + } + } + + impl<$($gen: $gent),*> $crate::serde::Serialize for $t<$($gen),*> { + fn serialize(&self, s: S) -> Result { + $crate::serde_macros::serde_details::SerdeHash::serialize(self, s) + } + } + + impl<'de $(, $gen: $gent)*> $crate::serde::Deserialize<'de> for $t<$($gen),*> { + fn deserialize>(d: D) -> Result<$t<$($gen),*>, D::Error> { + $crate::serde_macros::serde_details::SerdeHash::deserialize(d) + } + } +)); + +/// Does an "empty" serde implementation for the configuration without serde feature. +#[macro_export] +#[cfg(not(feature = "serde"))] +macro_rules! serde_impl( + ($t:ident, $len:expr $(, $gen:ident: $gent:ident)*) => () +); diff --git a/hashes/src/sha1.rs b/hashes/src/sha1.rs new file mode 100644 index 00000000..a638ebc3 --- /dev/null +++ b/hashes/src/sha1.rs @@ -0,0 +1,257 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! SHA1 implementation. +//! + +use core::convert::TryInto; +use core::ops::Index; +use core::slice::SliceIndex; +use core::{cmp, str}; + +use crate::{FromSliceError, HashEngine as _}; + +crate::internal_macros::hash_type! { + 160, + false, + "Output of the SHA1 hash function.", + "crate::util::json_hex_string::len_20" +} + +fn from_engine(mut e: HashEngine) -> Hash { + // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining + let data_len = e.length as u64; + + let zeroes = [0; BLOCK_SIZE - 8]; + e.input(&[0x80]); + if e.length % BLOCK_SIZE > zeroes.len() { + e.input(&zeroes); + } + let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); + e.input(&zeroes[..pad_length]); + debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); + + e.input(&(8 * data_len).to_be_bytes()); + debug_assert_eq!(e.length % BLOCK_SIZE, 0); + + Hash(e.midstate()) +} + +const BLOCK_SIZE: usize = 64; + +/// Engine to compute SHA1 hash function. +#[derive(Clone)] +pub struct HashEngine { + buffer: [u8; BLOCK_SIZE], + h: [u32; 5], + length: usize, +} + +impl Default for HashEngine { + fn default() -> Self { + HashEngine { + h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0], + length: 0, + buffer: [0; BLOCK_SIZE], + } + } +} + +impl crate::HashEngine for HashEngine { + type MidState = [u8; 20]; + + #[cfg(not(hashes_fuzz))] + fn midstate(&self) -> [u8; 20] { + let mut ret = [0; 20]; + for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(4)) { + ret_bytes.copy_from_slice(&val.to_be_bytes()) + } + ret + } + + #[cfg(hashes_fuzz)] + fn midstate(&self) -> [u8; 20] { + let mut ret = [0; 20]; + ret.copy_from_slice(&self.buffer[..20]); + ret + } + + const BLOCK_SIZE: usize = 64; + + fn n_bytes_hashed(&self) -> usize { self.length } + + engine_input_impl!(); +} + +impl HashEngine { + // Basic unoptimized algorithm from Wikipedia + fn process_block(&mut self) { + debug_assert_eq!(self.buffer.len(), BLOCK_SIZE); + + let mut w = [0u32; 80]; + for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.chunks_exact(4)) { + *w_val = u32::from_be_bytes(buff_bytes.try_into().expect("4 bytes slice")) + } + for i in 16..80 { + w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1); + } + + let mut a = self.h[0]; + let mut b = self.h[1]; + let mut c = self.h[2]; + let mut d = self.h[3]; + let mut e = self.h[4]; + + for (i, &wi) in w.iter().enumerate() { + let (f, k) = match i { + 0...19 => ((b & c) | (!b & d), 0x5a827999), + 20...39 => (b ^ c ^ d, 0x6ed9eba1), + 40...59 => ((b & c) | (b & d) | (c & d), 0x8f1bbcdc), + 60...79 => (b ^ c ^ d, 0xca62c1d6), + _ => unreachable!(), + }; + + let new_a = + a.rotate_left(5).wrapping_add(f).wrapping_add(e).wrapping_add(k).wrapping_add(wi); + e = d; + d = c; + c = b.rotate_left(30); + b = a; + a = new_a; + } + + self.h[0] = self.h[0].wrapping_add(a); + self.h[1] = self.h[1].wrapping_add(b); + self.h[2] = self.h[2].wrapping_add(c); + self.h[3] = self.h[3].wrapping_add(d); + self.h[4] = self.h[4].wrapping_add(e); + } +} + +#[cfg(test)] +mod tests { + #[test] + #[cfg(feature = "alloc")] + fn test() { + use crate::{sha1, Hash, HashEngine}; + + #[derive(Clone)] + struct Test { + input: &'static str, + output: Vec, + output_str: &'static str, + } + + #[rustfmt::skip] + let tests = vec![ + // Examples from wikipedia + Test { + input: "", + output: vec![ + 0xda, 0x39, 0xa3, 0xee, + 0x5e, 0x6b, 0x4b, 0x0d, + 0x32, 0x55, 0xbf, 0xef, + 0x95, 0x60, 0x18, 0x90, + 0xaf, 0xd8, 0x07, 0x09, + ], + output_str: "da39a3ee5e6b4b0d3255bfef95601890afd80709" + }, + Test { + input: "The quick brown fox jumps over the lazy dog", + output: vec![ + 0x2f, 0xd4, 0xe1, 0xc6, + 0x7a, 0x2d, 0x28, 0xfc, + 0xed, 0x84, 0x9e, 0xe1, + 0xbb, 0x76, 0xe7, 0x39, + 0x1b, 0x93, 0xeb, 0x12, + ], + output_str: "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12", + }, + Test { + input: "The quick brown fox jumps over the lazy cog", + output: vec![ + 0xde, 0x9f, 0x2c, 0x7f, + 0xd2, 0x5e, 0x1b, 0x3a, + 0xfa, 0xd3, 0xe8, 0x5a, + 0x0b, 0xd1, 0x7d, 0x9b, + 0x10, 0x0d, 0xb4, 0xb3, + ], + output_str: "de9f2c7fd25e1b3afad3e85a0bd17d9b100db4b3", + }, + ]; + + for test in tests { + // Hash through high-level API, check hex encoding/decoding + let hash = sha1::Hash::hash(test.input.as_bytes()); + assert_eq!(hash, test.output_str.parse::().expect("parse hex")); + assert_eq!(&hash[..], &test.output[..]); + assert_eq!(&hash.to_string(), &test.output_str); + + // Hash through engine, checking that we can input byte by byte + let mut engine = sha1::Hash::engine(); + for ch in test.input.as_bytes() { + engine.input(&[*ch]); + } + let manual_hash = sha1::Hash::from_engine(engine); + assert_eq!(hash, manual_hash); + assert_eq!(hash.as_byte_array(), test.output.as_slice()); + } + } + + #[cfg(feature = "serde")] + #[test] + fn sha1_serde() { + use serde_test::{assert_tokens, Configure, Token}; + + use crate::{sha1, Hash}; + + #[rustfmt::skip] + static HASH_BYTES: [u8; 20] = [ + 0x13, 0x20, 0x72, 0xdf, + 0x69, 0x09, 0x33, 0x83, + 0x5e, 0xb8, 0xb6, 0xad, + 0x0b, 0x77, 0xe7, 0xb6, + 0xf1, 0x4a, 0xca, 0xd7, + ]; + + let hash = sha1::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]); + assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]); + } +} + +#[cfg(bench)] +mod benches { + use test::Bencher; + + use crate::{sha1, Hash, HashEngine}; + + #[bench] + pub fn sha1_10(bh: &mut Bencher) { + let mut engine = sha1::Hash::engine(); + let bytes = [1u8; 10]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn sha1_1k(bh: &mut Bencher) { + let mut engine = sha1::Hash::engine(); + let bytes = [1u8; 1024]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn sha1_64k(bh: &mut Bencher) { + let mut engine = sha1::Hash::engine(); + let bytes = [1u8; 65536]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } +} diff --git a/hashes/src/sha256.rs b/hashes/src/sha256.rs new file mode 100644 index 00000000..3a8718d5 --- /dev/null +++ b/hashes/src/sha256.rs @@ -0,0 +1,1066 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! SHA256 implementation. +//! + +#[cfg(target_arch = "x86")] +use core::arch::x86::*; +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; +use core::convert::TryInto; +use core::ops::Index; +use core::slice::SliceIndex; +use core::{cmp, str}; + +use crate::{hex, sha256d, FromSliceError, HashEngine as _}; + +crate::internal_macros::hash_type! { + 256, + false, + "Output of the SHA256 hash function.", + "crate::util::json_hex_string::len_32" +} + +#[cfg(not(hashes_fuzz))] +fn from_engine(mut e: HashEngine) -> Hash { + // pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining + let data_len = e.length as u64; + + let zeroes = [0; BLOCK_SIZE - 8]; + e.input(&[0x80]); + if e.length % BLOCK_SIZE > zeroes.len() { + e.input(&zeroes); + } + let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); + e.input(&zeroes[..pad_length]); + debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); + + e.input(&(8 * data_len).to_be_bytes()); + debug_assert_eq!(e.length % BLOCK_SIZE, 0); + + Hash(e.midstate().to_byte_array()) +} + +#[cfg(hashes_fuzz)] +fn from_engine(e: HashEngine) -> Hash { + let mut hash = e.midstate().to_byte_array(); + if hash == [0; 32] { + // Assume sha256 is secure and never generate 0-hashes (which represent invalid + // secp256k1 secret keys, causing downstream application breakage). + hash[0] = 1; + } + Hash(hash) +} + +const BLOCK_SIZE: usize = 64; + +/// Engine to compute SHA256 hash function. +#[derive(Clone)] +pub struct HashEngine { + buffer: [u8; BLOCK_SIZE], + h: [u32; 8], + length: usize, +} + +impl Default for HashEngine { + fn default() -> Self { + HashEngine { + h: [ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, + 0x5be0cd19, + ], + length: 0, + buffer: [0; BLOCK_SIZE], + } + } +} + +impl crate::HashEngine for HashEngine { + type MidState = Midstate; + + #[cfg(not(hashes_fuzz))] + fn midstate(&self) -> Midstate { + let mut ret = [0; 32]; + for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(4)) { + ret_bytes.copy_from_slice(&val.to_be_bytes()); + } + Midstate(ret) + } + + #[cfg(hashes_fuzz)] + fn midstate(&self) -> Midstate { + let mut ret = [0; 32]; + ret.copy_from_slice(&self.buffer[..32]); + Midstate(ret) + } + + const BLOCK_SIZE: usize = 64; + + fn n_bytes_hashed(&self) -> usize { self.length } + + engine_input_impl!(); +} + +impl Hash { + /// Iterate the sha256 algorithm to turn a sha256 hash into a sha256d hash + pub fn hash_again(&self) -> sha256d::Hash { + crate::Hash::from_byte_array(::hash(&self.0).0) + } + + /// Computes hash from `bytes` in `const` context. + /// + /// Warning: this function is inefficient. It should be only used in `const` context. + pub const fn const_hash(bytes: &[u8]) -> Self { Hash(Midstate::const_hash(bytes, true).0) } +} + +/// Output of the SHA256 hash function. +#[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] +pub struct Midstate(pub [u8; 32]); + +crate::internal_macros::arr_newtype_fmt_impl!(Midstate, 32); +serde_impl!(Midstate, 32); +borrow_slice_impl!(Midstate); + +impl> Index for Midstate { + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { &self.0[index] } +} + +impl str::FromStr for Midstate { + type Err = hex::HexToArrayError; + fn from_str(s: &str) -> Result { hex::FromHex::from_hex(s) } +} + +impl Midstate { + /// Length of the midstate, in bytes. + const LEN: usize = 32; + + /// Flag indicating whether user-visible serializations of this hash + /// should be backward. For some reason Satoshi decided this should be + /// true for `Sha256dHash`, so here we are. + const DISPLAY_BACKWARD: bool = true; + + /// Construct a new [`Midstate`] from the inner value. + pub const fn from_byte_array(inner: [u8; 32]) -> Self { Midstate(inner) } + + /// Copies a byte slice into the [`Midstate`] object. + pub fn from_slice(sl: &[u8]) -> Result { + if sl.len() != Self::LEN { + Err(FromSliceError { expected: Self::LEN, got: sl.len() }) + } else { + let mut ret = [0; 32]; + ret.copy_from_slice(sl); + Ok(Midstate(ret)) + } + } + + /// Unwraps the [`Midstate`] and returns the underlying byte array. + pub fn to_byte_array(self) -> [u8; 32] { self.0 } + + /// Creates midstate for tagged hashes. + /// + /// Warning: this function is inefficient. It should be only used in `const` context. + /// + /// Computes non-finalized hash of `sha256(tag) || sha256(tag)` for use in + /// [`sha256t`](super::sha256t). It's provided for use with [`sha256t`](crate::sha256t). + pub const fn hash_tag(tag: &[u8]) -> Self { + let hash = Hash::const_hash(tag); + let mut buf = [0u8; 64]; + let mut i = 0usize; + while i < buf.len() { + buf[i] = hash.0[i % hash.0.len()]; + i += 1; + } + Self::const_hash(&buf, false) + } +} + +impl hex::FromHex for Midstate { + type Err = hex::HexToArrayError; + fn from_byte_iter(iter: I) -> Result + where + I: Iterator> + + ExactSizeIterator + + DoubleEndedIterator, + { + // DISPLAY_BACKWARD is true + Ok(Midstate::from_byte_array(hex::FromHex::from_byte_iter(iter.rev())?)) + } +} + +#[allow(non_snake_case)] +const fn Ch(x: u32, y: u32, z: u32) -> u32 { z ^ (x & (y ^ z)) } +#[allow(non_snake_case)] +const fn Maj(x: u32, y: u32, z: u32) -> u32 { (x & y) | (z & (x | y)) } +#[allow(non_snake_case)] +const fn Sigma0(x: u32) -> u32 { x.rotate_left(30) ^ x.rotate_left(19) ^ x.rotate_left(10) } +#[allow(non_snake_case)] +const fn Sigma1(x: u32) -> u32 { x.rotate_left(26) ^ x.rotate_left(21) ^ x.rotate_left(7) } +const fn sigma0(x: u32) -> u32 { x.rotate_left(25) ^ x.rotate_left(14) ^ (x >> 3) } +const fn sigma1(x: u32) -> u32 { x.rotate_left(15) ^ x.rotate_left(13) ^ (x >> 10) } + +#[cfg(feature = "small-hash")] +#[macro_use] +mod small_hash { + use super::*; + + #[rustfmt::skip] + pub(super) const fn round(a: u32, b: u32, c: u32, d: u32, e: u32, + f: u32, g: u32, h: u32, k: u32, w: u32) -> (u32, u32) { + let t1 = + h.wrapping_add(Sigma1(e)).wrapping_add(Ch(e, f, g)).wrapping_add(k).wrapping_add(w); + let t2 = Sigma0(a).wrapping_add(Maj(a, b, c)); + (d.wrapping_add(t1), t1.wrapping_add(t2)) + } + #[rustfmt::skip] + pub(super) const fn later_round(a: u32, b: u32, c: u32, d: u32, e: u32, + f: u32, g: u32, h: u32, k: u32, w: u32, + w1: u32, w2: u32, w3: u32, + ) -> (u32, u32, u32) { + let w = w.wrapping_add(sigma1(w1)).wrapping_add(w2).wrapping_add(sigma0(w3)); + let (d, h) = round(a, b, c, d, e, f, g, h, k, w); + (d, h, w) + } + + macro_rules! round( + // first round + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => ( + let updates = small_hash::round($a, $b, $c, $d, $e, $f, $g, $h, $k, $w); + $d = updates.0; + $h = updates.1; + ); + // later rounds we reassign $w before doing the first-round computation + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => ( + let updates = small_hash::later_round($a, $b, $c, $d, $e, $f, $g, $h, $k, $w, $w1, $w2, $w3); + $d = updates.0; + $h = updates.1; + $w = updates.2; + ) + ); +} + +#[cfg(not(feature = "small-hash"))] +#[macro_use] +mod fast_hash { + macro_rules! round( + // first round + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => ( + let t1 = $h.wrapping_add(Sigma1($e)).wrapping_add(Ch($e, $f, $g)).wrapping_add($k).wrapping_add($w); + let t2 = Sigma0($a).wrapping_add(Maj($a, $b, $c)); + $d = $d.wrapping_add(t1); + $h = t1.wrapping_add(t2); + ); + // later rounds we reassign $w before doing the first-round computation + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => ( + $w = $w.wrapping_add(sigma1($w1)).wrapping_add($w2).wrapping_add(sigma0($w3)); + round!($a, $b, $c, $d, $e, $f, $g, $h, $k, $w); + ) + ); +} + +impl Midstate { + #[allow(clippy::identity_op)] // more readble + const fn read_u32(bytes: &[u8], index: usize) -> u32 { + ((bytes[index + 0] as u32) << 24) + | ((bytes[index + 1] as u32) << 16) + | ((bytes[index + 2] as u32) << 8) + | ((bytes[index + 3] as u32) << 0) + } + + const fn copy_w(bytes: &[u8], index: usize) -> [u32; 16] { + let mut w = [0u32; 16]; + let mut i = 0; + while i < 16 { + w[i] = Self::read_u32(bytes, index + i * 4); + i += 1; + } + w + } + + const fn const_hash(bytes: &[u8], finalize: bool) -> Self { + let mut state = [ + 0x6a09e667u32, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19, + ]; + + let num_chunks = (bytes.len() + 9 + 63) / 64; + let mut chunk = 0; + #[allow(clippy::precedence)] + while chunk < num_chunks { + if !finalize && chunk + 1 == num_chunks { + break; + } + let mut w = if chunk * 64 + 64 <= bytes.len() { + Self::copy_w(bytes, chunk * 64) + } else { + let mut buf = [0; 64]; + let mut i = 0; + let offset = chunk * 64; + while offset + i < bytes.len() { + buf[i] = bytes[offset + i]; + i += 1; + } + if (bytes.len() % 64 <= 64 - 9) || (chunk + 2 == num_chunks) { + buf[i] = 0x80; + } + #[allow(clippy::identity_op)] // more readble + #[allow(clippy::erasing_op)] + if chunk + 1 == num_chunks { + let bit_len = bytes.len() as u64 * 8; + buf[64 - 8] = ((bit_len >> 8 * 7) & 0xFF) as u8; + buf[64 - 7] = ((bit_len >> 8 * 6) & 0xFF) as u8; + buf[64 - 6] = ((bit_len >> 8 * 5) & 0xFF) as u8; + buf[64 - 5] = ((bit_len >> 8 * 4) & 0xFF) as u8; + buf[64 - 4] = ((bit_len >> 8 * 3) & 0xFF) as u8; + buf[64 - 3] = ((bit_len >> 8 * 2) & 0xFF) as u8; + buf[64 - 2] = ((bit_len >> 8 * 1) & 0xFF) as u8; + buf[64 - 1] = ((bit_len >> 8 * 0) & 0xFF) as u8; + } + Self::copy_w(&buf, 0) + }; + chunk += 1; + + let mut a = state[0]; + let mut b = state[1]; + let mut c = state[2]; + let mut d = state[3]; + let mut e = state[4]; + let mut f = state[5]; + let mut g = state[6]; + let mut h = state[7]; + + round!(a, b, c, d, e, f, g, h, 0x428a2f98, w[0]); + round!(h, a, b, c, d, e, f, g, 0x71374491, w[1]); + round!(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w[2]); + round!(f, g, h, a, b, c, d, e, 0xe9b5dba5, w[3]); + round!(e, f, g, h, a, b, c, d, 0x3956c25b, w[4]); + round!(d, e, f, g, h, a, b, c, 0x59f111f1, w[5]); + round!(c, d, e, f, g, h, a, b, 0x923f82a4, w[6]); + round!(b, c, d, e, f, g, h, a, 0xab1c5ed5, w[7]); + round!(a, b, c, d, e, f, g, h, 0xd807aa98, w[8]); + round!(h, a, b, c, d, e, f, g, 0x12835b01, w[9]); + round!(g, h, a, b, c, d, e, f, 0x243185be, w[10]); + round!(f, g, h, a, b, c, d, e, 0x550c7dc3, w[11]); + round!(e, f, g, h, a, b, c, d, 0x72be5d74, w[12]); + round!(d, e, f, g, h, a, b, c, 0x80deb1fe, w[13]); + round!(c, d, e, f, g, h, a, b, 0x9bdc06a7, w[14]); + round!(b, c, d, e, f, g, h, a, 0xc19bf174, w[15]); + + round!(a, b, c, d, e, f, g, h, 0xe49b69c1, w[0], w[14], w[9], w[1]); + round!(h, a, b, c, d, e, f, g, 0xefbe4786, w[1], w[15], w[10], w[2]); + round!(g, h, a, b, c, d, e, f, 0x0fc19dc6, w[2], w[0], w[11], w[3]); + round!(f, g, h, a, b, c, d, e, 0x240ca1cc, w[3], w[1], w[12], w[4]); + round!(e, f, g, h, a, b, c, d, 0x2de92c6f, w[4], w[2], w[13], w[5]); + round!(d, e, f, g, h, a, b, c, 0x4a7484aa, w[5], w[3], w[14], w[6]); + round!(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w[6], w[4], w[15], w[7]); + round!(b, c, d, e, f, g, h, a, 0x76f988da, w[7], w[5], w[0], w[8]); + round!(a, b, c, d, e, f, g, h, 0x983e5152, w[8], w[6], w[1], w[9]); + round!(h, a, b, c, d, e, f, g, 0xa831c66d, w[9], w[7], w[2], w[10]); + round!(g, h, a, b, c, d, e, f, 0xb00327c8, w[10], w[8], w[3], w[11]); + round!(f, g, h, a, b, c, d, e, 0xbf597fc7, w[11], w[9], w[4], w[12]); + round!(e, f, g, h, a, b, c, d, 0xc6e00bf3, w[12], w[10], w[5], w[13]); + round!(d, e, f, g, h, a, b, c, 0xd5a79147, w[13], w[11], w[6], w[14]); + round!(c, d, e, f, g, h, a, b, 0x06ca6351, w[14], w[12], w[7], w[15]); + round!(b, c, d, e, f, g, h, a, 0x14292967, w[15], w[13], w[8], w[0]); + + round!(a, b, c, d, e, f, g, h, 0x27b70a85, w[0], w[14], w[9], w[1]); + round!(h, a, b, c, d, e, f, g, 0x2e1b2138, w[1], w[15], w[10], w[2]); + round!(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w[2], w[0], w[11], w[3]); + round!(f, g, h, a, b, c, d, e, 0x53380d13, w[3], w[1], w[12], w[4]); + round!(e, f, g, h, a, b, c, d, 0x650a7354, w[4], w[2], w[13], w[5]); + round!(d, e, f, g, h, a, b, c, 0x766a0abb, w[5], w[3], w[14], w[6]); + round!(c, d, e, f, g, h, a, b, 0x81c2c92e, w[6], w[4], w[15], w[7]); + round!(b, c, d, e, f, g, h, a, 0x92722c85, w[7], w[5], w[0], w[8]); + round!(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w[8], w[6], w[1], w[9]); + round!(h, a, b, c, d, e, f, g, 0xa81a664b, w[9], w[7], w[2], w[10]); + round!(g, h, a, b, c, d, e, f, 0xc24b8b70, w[10], w[8], w[3], w[11]); + round!(f, g, h, a, b, c, d, e, 0xc76c51a3, w[11], w[9], w[4], w[12]); + round!(e, f, g, h, a, b, c, d, 0xd192e819, w[12], w[10], w[5], w[13]); + round!(d, e, f, g, h, a, b, c, 0xd6990624, w[13], w[11], w[6], w[14]); + round!(c, d, e, f, g, h, a, b, 0xf40e3585, w[14], w[12], w[7], w[15]); + round!(b, c, d, e, f, g, h, a, 0x106aa070, w[15], w[13], w[8], w[0]); + + round!(a, b, c, d, e, f, g, h, 0x19a4c116, w[0], w[14], w[9], w[1]); + round!(h, a, b, c, d, e, f, g, 0x1e376c08, w[1], w[15], w[10], w[2]); + round!(g, h, a, b, c, d, e, f, 0x2748774c, w[2], w[0], w[11], w[3]); + round!(f, g, h, a, b, c, d, e, 0x34b0bcb5, w[3], w[1], w[12], w[4]); + round!(e, f, g, h, a, b, c, d, 0x391c0cb3, w[4], w[2], w[13], w[5]); + round!(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w[5], w[3], w[14], w[6]); + round!(c, d, e, f, g, h, a, b, 0x5b9cca4f, w[6], w[4], w[15], w[7]); + round!(b, c, d, e, f, g, h, a, 0x682e6ff3, w[7], w[5], w[0], w[8]); + round!(a, b, c, d, e, f, g, h, 0x748f82ee, w[8], w[6], w[1], w[9]); + round!(h, a, b, c, d, e, f, g, 0x78a5636f, w[9], w[7], w[2], w[10]); + round!(g, h, a, b, c, d, e, f, 0x84c87814, w[10], w[8], w[3], w[11]); + round!(f, g, h, a, b, c, d, e, 0x8cc70208, w[11], w[9], w[4], w[12]); + round!(e, f, g, h, a, b, c, d, 0x90befffa, w[12], w[10], w[5], w[13]); + round!(d, e, f, g, h, a, b, c, 0xa4506ceb, w[13], w[11], w[6], w[14]); + round!(c, d, e, f, g, h, a, b, 0xbef9a3f7, w[14], w[12], w[7], w[15]); + round!(b, c, d, e, f, g, h, a, 0xc67178f2, w[15], w[13], w[8], w[0]); + + state[0] = state[0].wrapping_add(a); + state[1] = state[1].wrapping_add(b); + state[2] = state[2].wrapping_add(c); + state[3] = state[3].wrapping_add(d); + state[4] = state[4].wrapping_add(e); + state[5] = state[5].wrapping_add(f); + state[6] = state[6].wrapping_add(g); + state[7] = state[7].wrapping_add(h); + } + let mut output = [0u8; 32]; + let mut i = 0; + #[allow(clippy::identity_op)] // more readble + while i < 8 { + output[i * 4 + 0] = (state[i + 0] >> 24) as u8; + output[i * 4 + 1] = (state[i + 0] >> 16) as u8; + output[i * 4 + 2] = (state[i + 0] >> 8) as u8; + output[i * 4 + 3] = (state[i + 0] >> 0) as u8; + i += 1; + } + Midstate(output) + } +} + +impl HashEngine { + /// Create a new [`HashEngine`] from a [`Midstate`]. + /// + /// # Panics + /// + /// If `length` is not a multiple of the block size. + pub fn from_midstate(midstate: Midstate, length: usize) -> HashEngine { + assert!(length % BLOCK_SIZE == 0, "length is no multiple of the block size"); + + let mut ret = [0; 8]; + for (ret_val, midstate_bytes) in ret.iter_mut().zip(midstate[..].chunks_exact(4)) { + *ret_val = u32::from_be_bytes(midstate_bytes.try_into().expect("4 byte slice")); + } + + HashEngine { buffer: [0; BLOCK_SIZE], h: ret, length } + } + + fn process_block(&mut self) { + #[cfg(all(feature = "std", any(target_arch = "x86", target_arch = "x86_64")))] + { + if is_x86_feature_detected!("sse4.1") + && is_x86_feature_detected!("sha") + && is_x86_feature_detected!("sse2") + && is_x86_feature_detected!("ssse3") + { + return unsafe { self.process_block_simd_x86_intrinsics() }; + } + } + + // fallback implementation without using any intrinsics + self.software_process_block() + } + + #[cfg(all(feature = "std", any(target_arch = "x86", target_arch = "x86_64")))] + #[target_feature(enable = "sha,sse2,ssse3,sse4.1")] + unsafe fn process_block_simd_x86_intrinsics(&mut self) { + // Code translated and based on from + // https://github.com/noloader/SHA-Intrinsics/blob/4899efc81d1af159c1fd955936c673139f35aea9/sha256-x86.c + + /* sha256-x86.c - Intel SHA extensions using C intrinsics */ + /* Written and place in public domain by Jeffrey Walton */ + /* Based on code from Intel, and by Sean Gulley for */ + /* the miTLS project. */ + + // Variable names are also kept the same as in the original C code for easier comparison. + let (mut state0, mut state1); + let (mut msg, mut tmp); + + let (mut msg0, mut msg1, mut msg2, mut msg3); + + let (abef_save, cdgh_save); + + #[allow(non_snake_case)] + let MASK: __m128i = + _mm_set_epi64x(0x0c0d_0e0f_0809_0a0bu64 as i64, 0x0405_0607_0001_0203u64 as i64); + + let block_offset = 0; + + // Load initial values + // CAST SAFETY: loadu_si128 documentation states that mem_addr does not + // need to be aligned on any particular boundary. + tmp = _mm_loadu_si128(self.h.as_ptr().add(0) as *const __m128i); + state1 = _mm_loadu_si128(self.h.as_ptr().add(4) as *const __m128i); + + tmp = _mm_shuffle_epi32(tmp, 0xB1); // CDAB + state1 = _mm_shuffle_epi32(state1, 0x1B); // EFGH + state0 = _mm_alignr_epi8(tmp, state1, 8); // ABEF + state1 = _mm_blend_epi16(state1, tmp, 0xF0); // CDGH + + // Process a single block + { + // Save current state + abef_save = state0; + cdgh_save = state1; + + // Rounds 0-3 + msg = _mm_loadu_si128(self.buffer.as_ptr().add(block_offset) as *const __m128i); + msg0 = _mm_shuffle_epi8(msg, MASK); + msg = _mm_add_epi32( + msg0, + _mm_set_epi64x(0xE9B5DBA5B5C0FBCFu64 as i64, 0x71374491428A2F98u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + + // Rounds 4-7 + msg1 = _mm_loadu_si128(self.buffer.as_ptr().add(block_offset + 16) as *const __m128i); + msg1 = _mm_shuffle_epi8(msg1, MASK); + msg = _mm_add_epi32( + msg1, + _mm_set_epi64x(0xAB1C5ED5923F82A4u64 as i64, 0x59F111F13956C25Bu64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg0 = _mm_sha256msg1_epu32(msg0, msg1); + + // Rounds 8-11 + msg2 = _mm_loadu_si128(self.buffer.as_ptr().add(block_offset + 32) as *const __m128i); + msg2 = _mm_shuffle_epi8(msg2, MASK); + msg = _mm_add_epi32( + msg2, + _mm_set_epi64x(0x550C7DC3243185BEu64 as i64, 0x12835B01D807AA98u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg1 = _mm_sha256msg1_epu32(msg1, msg2); + + // Rounds 12-15 + msg3 = _mm_loadu_si128(self.buffer.as_ptr().add(block_offset + 48) as *const __m128i); + msg3 = _mm_shuffle_epi8(msg3, MASK); + msg = _mm_add_epi32( + msg3, + _mm_set_epi64x(0xC19BF1749BDC06A7u64 as i64, 0x80DEB1FE72BE5D74u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg3, msg2, 4); + msg0 = _mm_add_epi32(msg0, tmp); + msg0 = _mm_sha256msg2_epu32(msg0, msg3); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg2 = _mm_sha256msg1_epu32(msg2, msg3); + + // Rounds 16-19 + msg = _mm_add_epi32( + msg0, + _mm_set_epi64x(0x240CA1CC0FC19DC6u64 as i64, 0xEFBE4786E49B69C1u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg0, msg3, 4); + msg1 = _mm_add_epi32(msg1, tmp); + msg1 = _mm_sha256msg2_epu32(msg1, msg0); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg3 = _mm_sha256msg1_epu32(msg3, msg0); + + // Rounds 20-23 + msg = _mm_add_epi32( + msg1, + _mm_set_epi64x(0x76F988DA5CB0A9DCu64 as i64, 0x4A7484AA2DE92C6Fu64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg1, msg0, 4); + msg2 = _mm_add_epi32(msg2, tmp); + msg2 = _mm_sha256msg2_epu32(msg2, msg1); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg0 = _mm_sha256msg1_epu32(msg0, msg1); + + // Rounds 24-27 + msg = _mm_add_epi32( + msg2, + _mm_set_epi64x(0xBF597FC7B00327C8u64 as i64, 0xA831C66D983E5152u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg2, msg1, 4); + msg3 = _mm_add_epi32(msg3, tmp); + msg3 = _mm_sha256msg2_epu32(msg3, msg2); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg1 = _mm_sha256msg1_epu32(msg1, msg2); + + // Rounds 28-31 + msg = _mm_add_epi32( + msg3, + _mm_set_epi64x(0x1429296706CA6351u64 as i64, 0xD5A79147C6E00BF3u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg3, msg2, 4); + msg0 = _mm_add_epi32(msg0, tmp); + msg0 = _mm_sha256msg2_epu32(msg0, msg3); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg2 = _mm_sha256msg1_epu32(msg2, msg3); + + // Rounds 32-35 + msg = _mm_add_epi32( + msg0, + _mm_set_epi64x(0x53380D134D2C6DFCu64 as i64, 0x2E1B213827B70A85u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg0, msg3, 4); + msg1 = _mm_add_epi32(msg1, tmp); + msg1 = _mm_sha256msg2_epu32(msg1, msg0); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg3 = _mm_sha256msg1_epu32(msg3, msg0); + + // Rounds 36-39 + msg = _mm_add_epi32( + msg1, + _mm_set_epi64x(0x92722C8581C2C92Eu64 as i64, 0x766A0ABB650A7354u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg1, msg0, 4); + msg2 = _mm_add_epi32(msg2, tmp); + msg2 = _mm_sha256msg2_epu32(msg2, msg1); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg0 = _mm_sha256msg1_epu32(msg0, msg1); + + // Rounds 40-43 + msg = _mm_add_epi32( + msg2, + _mm_set_epi64x(0xC76C51A3C24B8B70u64 as i64, 0xA81A664BA2BFE8A1u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg2, msg1, 4); + msg3 = _mm_add_epi32(msg3, tmp); + msg3 = _mm_sha256msg2_epu32(msg3, msg2); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg1 = _mm_sha256msg1_epu32(msg1, msg2); + + // Rounds 44-47 + msg = _mm_add_epi32( + msg3, + _mm_set_epi64x(0x106AA070F40E3585u64 as i64, 0xD6990624D192E819u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg3, msg2, 4); + msg0 = _mm_add_epi32(msg0, tmp); + msg0 = _mm_sha256msg2_epu32(msg0, msg3); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg2 = _mm_sha256msg1_epu32(msg2, msg3); + + // Rounds 48-51 + msg = _mm_add_epi32( + msg0, + _mm_set_epi64x(0x34B0BCB52748774Cu64 as i64, 0x1E376C0819A4C116u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg0, msg3, 4); + msg1 = _mm_add_epi32(msg1, tmp); + msg1 = _mm_sha256msg2_epu32(msg1, msg0); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + msg3 = _mm_sha256msg1_epu32(msg3, msg0); + + // Rounds 52-55 + msg = _mm_add_epi32( + msg1, + _mm_set_epi64x(0x682E6FF35B9CCA4Fu64 as i64, 0x4ED8AA4A391C0CB3u64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg1, msg0, 4); + msg2 = _mm_add_epi32(msg2, tmp); + msg2 = _mm_sha256msg2_epu32(msg2, msg1); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + + // Rounds 56-59 + msg = _mm_add_epi32( + msg2, + _mm_set_epi64x(0x8CC7020884C87814u64 as i64, 0x78A5636F748F82EEu64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + tmp = _mm_alignr_epi8(msg2, msg1, 4); + msg3 = _mm_add_epi32(msg3, tmp); + msg3 = _mm_sha256msg2_epu32(msg3, msg2); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + + // Rounds 60-63 + msg = _mm_add_epi32( + msg3, + _mm_set_epi64x(0xC67178F2BEF9A3F7u64 as i64, 0xA4506CEB90BEFFFAu64 as i64), + ); + state1 = _mm_sha256rnds2_epu32(state1, state0, msg); + msg = _mm_shuffle_epi32(msg, 0x0E); + state0 = _mm_sha256rnds2_epu32(state0, state1, msg); + + // Combine state + state0 = _mm_add_epi32(state0, abef_save); + state1 = _mm_add_epi32(state1, cdgh_save); + } + + tmp = _mm_shuffle_epi32(state0, 0x1B); // FEBA + state1 = _mm_shuffle_epi32(state1, 0xB1); // DCHG + state0 = _mm_blend_epi16(tmp, state1, 0xF0); // DCBA + state1 = _mm_alignr_epi8(state1, tmp, 8); // ABEF + + // Save state + // CAST SAFETY: storeu_si128 documentation states that mem_addr does not + // need to be aligned on any particular boundary. + _mm_storeu_si128(self.h.as_mut_ptr().add(0) as *mut __m128i, state0); + _mm_storeu_si128(self.h.as_mut_ptr().add(4) as *mut __m128i, state1); + } + + // Algorithm copied from libsecp256k1 + fn software_process_block(&mut self) { + debug_assert_eq!(self.buffer.len(), BLOCK_SIZE); + + let mut w = [0u32; 16]; + for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.chunks_exact(4)) { + *w_val = u32::from_be_bytes(buff_bytes.try_into().expect("4 byte slice")); + } + + let mut a = self.h[0]; + let mut b = self.h[1]; + let mut c = self.h[2]; + let mut d = self.h[3]; + let mut e = self.h[4]; + let mut f = self.h[5]; + let mut g = self.h[6]; + let mut h = self.h[7]; + + round!(a, b, c, d, e, f, g, h, 0x428a2f98, w[0]); + round!(h, a, b, c, d, e, f, g, 0x71374491, w[1]); + round!(g, h, a, b, c, d, e, f, 0xb5c0fbcf, w[2]); + round!(f, g, h, a, b, c, d, e, 0xe9b5dba5, w[3]); + round!(e, f, g, h, a, b, c, d, 0x3956c25b, w[4]); + round!(d, e, f, g, h, a, b, c, 0x59f111f1, w[5]); + round!(c, d, e, f, g, h, a, b, 0x923f82a4, w[6]); + round!(b, c, d, e, f, g, h, a, 0xab1c5ed5, w[7]); + round!(a, b, c, d, e, f, g, h, 0xd807aa98, w[8]); + round!(h, a, b, c, d, e, f, g, 0x12835b01, w[9]); + round!(g, h, a, b, c, d, e, f, 0x243185be, w[10]); + round!(f, g, h, a, b, c, d, e, 0x550c7dc3, w[11]); + round!(e, f, g, h, a, b, c, d, 0x72be5d74, w[12]); + round!(d, e, f, g, h, a, b, c, 0x80deb1fe, w[13]); + round!(c, d, e, f, g, h, a, b, 0x9bdc06a7, w[14]); + round!(b, c, d, e, f, g, h, a, 0xc19bf174, w[15]); + + round!(a, b, c, d, e, f, g, h, 0xe49b69c1, w[0], w[14], w[9], w[1]); + round!(h, a, b, c, d, e, f, g, 0xefbe4786, w[1], w[15], w[10], w[2]); + round!(g, h, a, b, c, d, e, f, 0x0fc19dc6, w[2], w[0], w[11], w[3]); + round!(f, g, h, a, b, c, d, e, 0x240ca1cc, w[3], w[1], w[12], w[4]); + round!(e, f, g, h, a, b, c, d, 0x2de92c6f, w[4], w[2], w[13], w[5]); + round!(d, e, f, g, h, a, b, c, 0x4a7484aa, w[5], w[3], w[14], w[6]); + round!(c, d, e, f, g, h, a, b, 0x5cb0a9dc, w[6], w[4], w[15], w[7]); + round!(b, c, d, e, f, g, h, a, 0x76f988da, w[7], w[5], w[0], w[8]); + round!(a, b, c, d, e, f, g, h, 0x983e5152, w[8], w[6], w[1], w[9]); + round!(h, a, b, c, d, e, f, g, 0xa831c66d, w[9], w[7], w[2], w[10]); + round!(g, h, a, b, c, d, e, f, 0xb00327c8, w[10], w[8], w[3], w[11]); + round!(f, g, h, a, b, c, d, e, 0xbf597fc7, w[11], w[9], w[4], w[12]); + round!(e, f, g, h, a, b, c, d, 0xc6e00bf3, w[12], w[10], w[5], w[13]); + round!(d, e, f, g, h, a, b, c, 0xd5a79147, w[13], w[11], w[6], w[14]); + round!(c, d, e, f, g, h, a, b, 0x06ca6351, w[14], w[12], w[7], w[15]); + round!(b, c, d, e, f, g, h, a, 0x14292967, w[15], w[13], w[8], w[0]); + + round!(a, b, c, d, e, f, g, h, 0x27b70a85, w[0], w[14], w[9], w[1]); + round!(h, a, b, c, d, e, f, g, 0x2e1b2138, w[1], w[15], w[10], w[2]); + round!(g, h, a, b, c, d, e, f, 0x4d2c6dfc, w[2], w[0], w[11], w[3]); + round!(f, g, h, a, b, c, d, e, 0x53380d13, w[3], w[1], w[12], w[4]); + round!(e, f, g, h, a, b, c, d, 0x650a7354, w[4], w[2], w[13], w[5]); + round!(d, e, f, g, h, a, b, c, 0x766a0abb, w[5], w[3], w[14], w[6]); + round!(c, d, e, f, g, h, a, b, 0x81c2c92e, w[6], w[4], w[15], w[7]); + round!(b, c, d, e, f, g, h, a, 0x92722c85, w[7], w[5], w[0], w[8]); + round!(a, b, c, d, e, f, g, h, 0xa2bfe8a1, w[8], w[6], w[1], w[9]); + round!(h, a, b, c, d, e, f, g, 0xa81a664b, w[9], w[7], w[2], w[10]); + round!(g, h, a, b, c, d, e, f, 0xc24b8b70, w[10], w[8], w[3], w[11]); + round!(f, g, h, a, b, c, d, e, 0xc76c51a3, w[11], w[9], w[4], w[12]); + round!(e, f, g, h, a, b, c, d, 0xd192e819, w[12], w[10], w[5], w[13]); + round!(d, e, f, g, h, a, b, c, 0xd6990624, w[13], w[11], w[6], w[14]); + round!(c, d, e, f, g, h, a, b, 0xf40e3585, w[14], w[12], w[7], w[15]); + round!(b, c, d, e, f, g, h, a, 0x106aa070, w[15], w[13], w[8], w[0]); + + round!(a, b, c, d, e, f, g, h, 0x19a4c116, w[0], w[14], w[9], w[1]); + round!(h, a, b, c, d, e, f, g, 0x1e376c08, w[1], w[15], w[10], w[2]); + round!(g, h, a, b, c, d, e, f, 0x2748774c, w[2], w[0], w[11], w[3]); + round!(f, g, h, a, b, c, d, e, 0x34b0bcb5, w[3], w[1], w[12], w[4]); + round!(e, f, g, h, a, b, c, d, 0x391c0cb3, w[4], w[2], w[13], w[5]); + round!(d, e, f, g, h, a, b, c, 0x4ed8aa4a, w[5], w[3], w[14], w[6]); + round!(c, d, e, f, g, h, a, b, 0x5b9cca4f, w[6], w[4], w[15], w[7]); + round!(b, c, d, e, f, g, h, a, 0x682e6ff3, w[7], w[5], w[0], w[8]); + round!(a, b, c, d, e, f, g, h, 0x748f82ee, w[8], w[6], w[1], w[9]); + round!(h, a, b, c, d, e, f, g, 0x78a5636f, w[9], w[7], w[2], w[10]); + round!(g, h, a, b, c, d, e, f, 0x84c87814, w[10], w[8], w[3], w[11]); + round!(f, g, h, a, b, c, d, e, 0x8cc70208, w[11], w[9], w[4], w[12]); + round!(e, f, g, h, a, b, c, d, 0x90befffa, w[12], w[10], w[5], w[13]); + round!(d, e, f, g, h, a, b, c, 0xa4506ceb, w[13], w[11], w[6], w[14]); + round!(c, d, e, f, g, h, a, b, 0xbef9a3f7, w[14], w[12], w[7], w[15]); + round!(b, c, d, e, f, g, h, a, 0xc67178f2, w[15], w[13], w[8], w[0]); + + self.h[0] = self.h[0].wrapping_add(a); + self.h[1] = self.h[1].wrapping_add(b); + self.h[2] = self.h[2].wrapping_add(c); + self.h[3] = self.h[3].wrapping_add(d); + self.h[4] = self.h[4].wrapping_add(e); + self.h[5] = self.h[5].wrapping_add(f); + self.h[6] = self.h[6].wrapping_add(g); + self.h[7] = self.h[7].wrapping_add(h); + } +} + +#[cfg(test)] +mod tests { + use crate::{sha256, Hash, HashEngine}; + + #[test] + #[cfg(feature = "alloc")] + fn test() { + #[derive(Clone)] + struct Test { + input: &'static str, + output: Vec, + output_str: &'static str, + } + + #[rustfmt::skip] + let tests = vec![ + // Examples from wikipedia + Test { + input: "", + output: vec![ + 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, + 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, + 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, + 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55, + ], + output_str: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + }, + Test { + input: "The quick brown fox jumps over the lazy dog", + output: vec![ + 0xd7, 0xa8, 0xfb, 0xb3, 0x07, 0xd7, 0x80, 0x94, + 0x69, 0xca, 0x9a, 0xbc, 0xb0, 0x08, 0x2e, 0x4f, + 0x8d, 0x56, 0x51, 0xe4, 0x6d, 0x3c, 0xdb, 0x76, + 0x2d, 0x02, 0xd0, 0xbf, 0x37, 0xc9, 0xe5, 0x92, + ], + output_str: "d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592", + }, + Test { + input: "The quick brown fox jumps over the lazy dog.", + output: vec![ + 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, + 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97, + 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, + 0xb7, 0x65, 0x44, 0x8c, 0x86, 0x35, 0xfb, 0x6c, + ], + output_str: "ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c", + }, + ]; + + for test in tests { + // Hash through high-level API, check hex encoding/decoding + let hash = sha256::Hash::hash(test.input.as_bytes()); + assert_eq!(hash, test.output_str.parse::().expect("parse hex")); + assert_eq!(&hash[..], &test.output[..]); + assert_eq!(&hash.to_string(), &test.output_str); + + // Hash through engine, checking that we can input byte by byte + let mut engine = sha256::Hash::engine(); + for ch in test.input.as_bytes() { + engine.input(&[*ch]); + } + let manual_hash = sha256::Hash::from_engine(engine); + assert_eq!(hash, manual_hash); + assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice()); + } + } + + #[test] + #[rustfmt::skip] + fn midstate() { + // Test vector obtained by doing an asset issuance on Elements + let mut engine = sha256::Hash::engine(); + // sha256dhash of outpoint + // 73828cbc65fd68ab78dc86992b76ae50ae2bf8ceedbe8de0483172f0886219f7:0 + engine.input(&[ + 0x9d, 0xd0, 0x1b, 0x56, 0xb1, 0x56, 0x45, 0x14, + 0x3e, 0xad, 0x15, 0x8d, 0xec, 0x19, 0xf8, 0xce, + 0xa9, 0x0b, 0xd0, 0xa9, 0xb2, 0xf8, 0x1d, 0x21, + 0xff, 0xa3, 0xa4, 0xc6, 0x44, 0x81, 0xd4, 0x1c, + ]); + // 32 bytes of zeroes representing "new asset" + engine.input(&[0; 32]); + assert_eq!( + engine.midstate(), + // RPC output + sha256::Midstate::from_byte_array([ + 0x0b, 0xcf, 0xe0, 0xe5, 0x4e, 0x6c, 0xc7, 0xd3, + 0x4f, 0x4f, 0x7c, 0x1d, 0xf0, 0xb0, 0xf5, 0x03, + 0xf2, 0xf7, 0x12, 0x91, 0x2a, 0x06, 0x05, 0xb4, + 0x14, 0xed, 0x33, 0x7f, 0x7f, 0x03, 0x2e, 0x03, + ]) + ); + } + + #[test] + fn engine_with_state() { + let mut engine = sha256::Hash::engine(); + let midstate_engine = sha256::HashEngine::from_midstate(engine.midstate(), 0); + // Fresh engine and engine initialized with fresh state should have same state + assert_eq!(engine.h, midstate_engine.h); + + // Midstate changes after writing 64 bytes + engine.input(&[1; 63]); + assert_eq!(engine.h, midstate_engine.h); + engine.input(&[2; 1]); + assert_ne!(engine.h, midstate_engine.h); + + // Initializing an engine with midstate from another engine should result in + // both engines producing the same hashes + let data_vec = vec![vec![3; 1], vec![4; 63], vec![5; 65], vec![6; 66]]; + for data in data_vec { + let mut engine = engine.clone(); + let mut midstate_engine = + sha256::HashEngine::from_midstate(engine.midstate(), engine.length); + assert_eq!(engine.h, midstate_engine.h); + assert_eq!(engine.length, midstate_engine.length); + engine.input(&data); + midstate_engine.input(&data); + assert_eq!(engine.h, midstate_engine.h); + let hash1 = sha256::Hash::from_engine(engine); + let hash2 = sha256::Hash::from_engine(midstate_engine); + assert_eq!(hash1, hash2); + } + + // Test that a specific midstate results in a specific hash. Midstate was + // obtained by applying sha256 to sha256("MuSig coefficient")||sha256("MuSig + // coefficient"). + #[rustfmt::skip] + static MIDSTATE: [u8; 32] = [ + 0x0f, 0xd0, 0x69, 0x0c, 0xfe, 0xfe, 0xae, 0x97, + 0x99, 0x6e, 0xac, 0x7f, 0x5c, 0x30, 0xd8, 0x64, + 0x8c, 0x4a, 0x05, 0x73, 0xac, 0xa1, 0xa2, 0x2f, + 0x6f, 0x43, 0xb8, 0x01, 0x85, 0xce, 0x27, 0xcd, + ]; + #[rustfmt::skip] + static HASH_EXPECTED: [u8; 32] = [ + 0x18, 0x84, 0xe4, 0x72, 0x40, 0x4e, 0xf4, 0x5a, + 0xb4, 0x9c, 0x4e, 0xa4, 0x9a, 0xe6, 0x23, 0xa8, + 0x88, 0x52, 0x7f, 0x7d, 0x8a, 0x06, 0x94, 0x20, + 0x8f, 0xf1, 0xf7, 0xa9, 0xd5, 0x69, 0x09, 0x59, + ]; + let midstate_engine = + sha256::HashEngine::from_midstate(sha256::Midstate::from_byte_array(MIDSTATE), 64); + let hash = sha256::Hash::from_engine(midstate_engine); + assert_eq!(hash, sha256::Hash(HASH_EXPECTED)); + } + + #[test] + fn const_hash() { + assert_eq!(super::Hash::hash(&[]), super::Hash::const_hash(&[])); + + let mut bytes = Vec::new(); + for i in 0..256 { + bytes.push(i as u8); + assert_eq!( + super::Hash::hash(&bytes), + super::Hash::const_hash(&bytes), + "hashes don't match for length {}", + i + 1 + ); + } + } + + #[test] + fn const_midstate() { + use super::Midstate; + + assert_eq!( + Midstate::hash_tag(b"TapLeaf"), + Midstate([ + 156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, + 243, 147, 108, 71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201, + ]) + ) + } + + #[cfg(feature = "serde")] + #[test] + fn sha256_serde() { + use serde_test::{assert_tokens, Configure, Token}; + + #[rustfmt::skip] + static HASH_BYTES: [u8; 32] = [ + 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, + 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97, + 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, + 0xb7, 0x65, 0x44, 0x8c, 0x86, 0x35, 0xfb, 0x6c, + ]; + + let hash = sha256::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]); + assert_tokens( + &hash.readable(), + &[Token::Str("ef537f25c895bfa782526529a9b63d97aa631564d5d789c2b765448c8635fb6c")], + ); + } + + #[cfg(target_arch = "wasm32")] + mod wasm_tests { + extern crate wasm_bindgen_test; + use self::wasm_bindgen_test::*; + use super::*; + #[wasm_bindgen_test] + fn sha256_tests() { + test(); + midstate(); + engine_with_state(); + } + } +} + +#[cfg(bench)] +mod benches { + use test::Bencher; + + use crate::{sha256, Hash, HashEngine}; + + #[bench] + pub fn sha256_10(bh: &mut Bencher) { + let mut engine = sha256::Hash::engine(); + let bytes = [1u8; 10]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn sha256_1k(bh: &mut Bencher) { + let mut engine = sha256::Hash::engine(); + let bytes = [1u8; 1024]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn sha256_64k(bh: &mut Bencher) { + let mut engine = sha256::Hash::engine(); + let bytes = [1u8; 65536]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } +} diff --git a/hashes/src/sha256d.rs b/hashes/src/sha256d.rs new file mode 100644 index 00000000..e7f6990b --- /dev/null +++ b/hashes/src/sha256d.rs @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! SHA256d implementation (double SHA256). +//! + +use core::ops::Index; +use core::slice::SliceIndex; +use core::str; + +use crate::{sha256, FromSliceError}; + +crate::internal_macros::hash_type! { + 256, + true, + "Output of the SHA256d hash function.", + "crate::util::json_hex_string::len_32" +} + +type HashEngine = sha256::HashEngine; + +fn from_engine(e: sha256::HashEngine) -> Hash { + use crate::Hash as _; + + let sha2 = sha256::Hash::from_engine(e); + let sha2d = sha256::Hash::hash(&sha2[..]); + + let mut ret = [0; 32]; + ret.copy_from_slice(&sha2d[..]); + Hash(ret) +} + +#[cfg(test)] +mod tests { + #[test] + #[cfg(feature = "alloc")] + fn test() { + use crate::{sha256, sha256d, Hash, HashEngine}; + + #[derive(Clone)] + struct Test { + input: &'static str, + output: Vec, + output_str: &'static str, + } + + #[rustfmt::skip] + let tests = vec![ + // Test vector copied out of rust-tapyrus + Test { + input: "", + output: vec![ + 0x5d, 0xf6, 0xe0, 0xe2, 0x76, 0x13, 0x59, 0xd3, + 0x0a, 0x82, 0x75, 0x05, 0x8e, 0x29, 0x9f, 0xcc, + 0x03, 0x81, 0x53, 0x45, 0x45, 0xf5, 0x5c, 0xf4, + 0x3e, 0x41, 0x98, 0x3f, 0x5d, 0x4c, 0x94, 0x56, + ], + output_str: "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d", + }, + ]; + + for test in tests { + // Hash through high-level API, check hex encoding/decoding + let hash = sha256d::Hash::hash(test.input.as_bytes()); + assert_eq!(hash, test.output_str.parse::().expect("parse hex")); + assert_eq!(&hash[..], &test.output[..]); + assert_eq!(&hash.to_string(), &test.output_str); + + // Hash through engine, checking that we can input byte by byte + let mut engine = sha256d::Hash::engine(); + for ch in test.input.as_bytes() { + engine.input(&[*ch]); + } + let manual_hash = sha256d::Hash::from_engine(engine); + assert_eq!(hash, manual_hash); + + // Hash by computing a sha256 then `hash_again`ing it + let sha2_hash = sha256::Hash::hash(test.input.as_bytes()); + let sha2d_hash = sha2_hash.hash_again(); + assert_eq!(hash, sha2d_hash); + + assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice()); + } + } + + #[cfg(feature = "serde")] + #[test] + fn sha256_serde() { + use serde_test::{assert_tokens, Configure, Token}; + + use crate::{sha256d, Hash}; + + #[rustfmt::skip] + static HASH_BYTES: [u8; 32] = [ + 0xef, 0x53, 0x7f, 0x25, 0xc8, 0x95, 0xbf, 0xa7, + 0x82, 0x52, 0x65, 0x29, 0xa9, 0xb6, 0x3d, 0x97, + 0xaa, 0x63, 0x15, 0x64, 0xd5, 0xd7, 0x89, 0xc2, + 0xb7, 0x65, 0x44, 0x8c, 0x86, 0x35, 0xfb, 0x6c, + ]; + + let hash = sha256d::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]); + assert_tokens( + &hash.readable(), + &[Token::Str("6cfb35868c4465b7c289d7d5641563aa973db6a929655282a7bf95c8257f53ef")], + ); + } +} + +#[cfg(bench)] +mod benches { + use test::Bencher; + + use crate::{sha256d, Hash, HashEngine}; + + #[bench] + pub fn sha256d_10(bh: &mut Bencher) { + let mut engine = sha256d::Hash::engine(); + let bytes = [1u8; 10]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn sha256d_1k(bh: &mut Bencher) { + let mut engine = sha256d::Hash::engine(); + let bytes = [1u8; 1024]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn sha256d_64k(bh: &mut Bencher) { + let mut engine = sha256d::Hash::engine(); + let bytes = [1u8; 65536]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } +} diff --git a/hashes/src/sha256t.rs b/hashes/src/sha256t.rs new file mode 100644 index 00000000..e136455b --- /dev/null +++ b/hashes/src/sha256t.rs @@ -0,0 +1,208 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! SHA256t implementation (tagged SHA256). +//! + +use core::marker::PhantomData; +use core::ops::Index; +use core::slice::SliceIndex; +use core::{cmp, str}; + +use crate::{sha256, FromSliceError}; + +type HashEngine = sha256::HashEngine; + +/// Trait representing a tag that can be used as a context for SHA256t hashes. +pub trait Tag { + /// Returns a hash engine that is pre-tagged and is ready to be used for the data. + fn engine() -> sha256::HashEngine; +} + +/// Output of the SHA256t hash function. +#[repr(transparent)] +pub struct Hash([u8; 32], PhantomData); + +#[cfg(feature = "schemars")] +impl schemars::JsonSchema for Hash { + fn schema_name() -> String { "Hash".to_owned() } + + fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { + crate::util::json_hex_string::len_32(gen) + } +} + +impl Hash { + fn internal_new(arr: [u8; 32]) -> Self { Hash(arr, Default::default()) } + + fn internal_engine() -> HashEngine { T::engine() } +} + +impl Copy for Hash {} +impl Clone for Hash { + fn clone(&self) -> Self { *self } +} +impl PartialEq for Hash { + fn eq(&self, other: &Hash) -> bool { self.0 == other.0 } +} +impl Eq for Hash {} +impl Default for Hash { + fn default() -> Self { Hash([0; 32], PhantomData) } +} +impl PartialOrd for Hash { + fn partial_cmp(&self, other: &Hash) -> Option { + Some(cmp::Ord::cmp(self, other)) + } +} +impl Ord for Hash { + fn cmp(&self, other: &Hash) -> cmp::Ordering { cmp::Ord::cmp(&self.0, &other.0) } +} +impl core::hash::Hash for Hash { + fn hash(&self, h: &mut H) { self.0.hash(h) } +} + +crate::internal_macros::hash_trait_impls!(256, true, T: Tag); + +fn from_engine(e: sha256::HashEngine) -> Hash { + use crate::Hash as _; + + Hash::from_byte_array(sha256::Hash::from_engine(e).to_byte_array()) +} + +/// Macro used to define a newtype tagged hash. +/// +/// This macro creates two types: +/// +/// * a tag struct +/// * a hash wrapper +/// +/// The syntax is: +/// +/// ``` +/// # use tapyrus_hashes::sha256t_hash_newtype; +/// sha256t_hash_newtype! { +/// /// Optional documentation details here. +/// /// Summary is always generated. +/// pub struct FooTag = hash_str("foo"); +/// +/// /// A foo hash. +/// // Direction works just like in case of hash_newtype! macro. +/// #[hash_newtype(forward)] +/// pub struct FooHash(_); +/// } +/// ``` +/// +/// The structs must be defined in this order - tag first, then hash type. `hash_str` marker +/// says the midstate should be generated by hashing the supplied string in a way described in +/// BIP-341. Alternatively, you can supply `hash_bytes` to hash raw bytes. If you have the midstate +/// already pre-computed and prefer **compiler** performance to readability you may use +/// `raw(MIDSTATE_BYTES, HASHED_BYTES_LENGHT)` instead. +/// +/// Both visibility modifiers and attributes are optional and passed to inner structs (excluding +/// `#[hash_newtype(...)]`). The attributes suffer same compiler performance limitations as in +/// [`hash_newtype`] macro. +/// +/// The macro accepts multiple inputs so you can define multiple hash newtypes in one macro call. +/// Just make sure to enter the structs in order `Tag0`, `Hash0`, `Tag1`, `Hash1`... +/// +/// [`hash_newtype`]: crate::hash_newtype +#[macro_export] +macro_rules! sha256t_hash_newtype { + ($($(#[$($tag_attr:tt)*])* $tag_vis:vis struct $tag:ident = $constructor:tt($($tag_value:tt)+); $(#[$($hash_attr:tt)*])* $hash_vis:vis struct $hash_name:ident($(#[$($field_attr:tt)*])* _);)+) => { + $( + $crate::sha256t_hash_newtype_tag!($tag_vis, $tag, stringify!($hash_name), $(#[$($tag_attr)*])*); + + impl $crate::sha256t::Tag for $tag { + #[inline] + fn engine() -> $crate::sha256::HashEngine { + const MIDSTATE: ($crate::sha256::Midstate, usize) = $crate::sha256t_hash_newtype_tag_constructor!($constructor, $($tag_value)+); + #[allow(unused)] + const _LENGTH_CHECK: () = [(); 1][MIDSTATE.1 % 64]; + $crate::sha256::HashEngine::from_midstate(MIDSTATE.0, MIDSTATE.1) + } + } + + $crate::hash_newtype! { + $(#[$($hash_attr)*])* + $hash_vis struct $hash_name($(#[$($field_attr)*])* $crate::sha256t::Hash<$tag>); + } + )+ + } +} + +// Workaround macros being unavailable in attributes. +#[doc(hidden)] +#[macro_export] +macro_rules! sha256t_hash_newtype_tag { + ($vis:vis, $tag:ident, $name:expr, $(#[$($attr:meta)*])*) => { + #[doc = "The tag used for [`"] + #[doc = $name] + #[doc = "`]\n\n"] + $(#[$($attr)*])* + #[derive(Copy, Clone, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] + $vis struct $tag; + }; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! sha256t_hash_newtype_tag_constructor { + (hash_str, $value:expr) => { + ($crate::sha256::Midstate::hash_tag($value.as_bytes()), 64) + }; + (hash_bytes, $value:expr) => { + ($crate::sha256::Midstate::hash_tag($value), 64) + }; + (raw, $bytes:expr, $len:expr) => { + ($crate::sha256::Midstate::from_byte_array($bytes), $len) + }; +} + +#[cfg(test)] +mod tests { + #[cfg(feature = "alloc")] + use crate::Hash; + use crate::{sha256, sha256t}; + + const TEST_MIDSTATE: [u8; 32] = [ + 156, 224, 228, 230, 124, 17, 108, 57, 56, 179, 202, 242, 195, 15, 80, 137, 211, 243, 147, + 108, 71, 99, 110, 96, 125, 179, 62, 234, 221, 198, 240, 201, + ]; + + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)] + #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] + pub struct TestHashTag; + + impl sha256t::Tag for TestHashTag { + fn engine() -> sha256::HashEngine { + // The TapRoot TapLeaf midstate. + let midstate = sha256::Midstate::from_byte_array(TEST_MIDSTATE); + sha256::HashEngine::from_midstate(midstate, 64) + } + } + + /// A hash tagged with `$name`. + #[cfg(feature = "alloc")] + pub type TestHash = sha256t::Hash; + + sha256t_hash_newtype! { + /// Test detailed explanation. + struct NewTypeTag = raw(TEST_MIDSTATE, 64); + + /// A test hash. + #[hash_newtype(backward)] + struct NewTypeHash(_); + } + + #[test] + #[cfg(feature = "alloc")] + fn test_sha256t() { + assert_eq!( + TestHash::hash(&[0]).to_string(), + "29589d5122ec666ab5b4695070b6debc63881a4f85d88d93ddc90078038213ed" + ); + assert_eq!( + NewTypeHash::hash(&[0]).to_string(), + "29589d5122ec666ab5b4695070b6debc63881a4f85d88d93ddc90078038213ed" + ); + } +} diff --git a/hashes/src/sha512.rs b/hashes/src/sha512.rs new file mode 100644 index 00000000..85a8aa4c --- /dev/null +++ b/hashes/src/sha512.rs @@ -0,0 +1,453 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! SHA512 implementation. +//! + +use core::convert::TryInto; +use core::ops::Index; +use core::slice::SliceIndex; +use core::{cmp, str}; + +use crate::{FromSliceError, HashEngine as _}; + +crate::internal_macros::hash_trait_impls!(512, false); + +pub(crate) const BLOCK_SIZE: usize = 128; + +/// Engine to compute SHA512 hash function. +#[derive(Clone)] +pub struct HashEngine { + h: [u64; 8], + length: usize, + buffer: [u8; BLOCK_SIZE], +} + +impl Default for HashEngine { + #[rustfmt::skip] + fn default() -> Self { + HashEngine { + h: [ + 0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179, + ], + length: 0, + buffer: [0; BLOCK_SIZE], + } + } +} + +impl HashEngine { + /// Constructs a hash engine suitable for use inside the default `sha512_256::HashEngine`. + #[rustfmt::skip] + pub(crate) fn sha512_256() -> Self { + HashEngine { + h: [ + 0x22312194fc2bf72c, 0x9f555fa3c84c64c2, 0x2393b86b6f53b151, 0x963877195940eabd, + 0x96283ee2a88effe3, 0xbe5e1e2553863992, 0x2b0199fc2c85b8aa, 0x0eb72ddc81c52ca2, + ], + length: 0, + buffer: [0; BLOCK_SIZE], + } + } +} + +impl crate::HashEngine for HashEngine { + type MidState = [u8; 64]; + + #[cfg(not(hashes_fuzz))] + fn midstate(&self) -> [u8; 64] { + let mut ret = [0; 64]; + for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(8)) { + ret_bytes.copy_from_slice(&val.to_be_bytes()); + } + ret + } + + #[cfg(hashes_fuzz)] + fn midstate(&self) -> [u8; 64] { + let mut ret = [0; 64]; + ret.copy_from_slice(&self.buffer[..64]); + ret + } + + const BLOCK_SIZE: usize = 128; + + fn n_bytes_hashed(&self) -> usize { self.length } + + engine_input_impl!(); +} + +/// Output of the SHA512 hash function. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[repr(transparent)] +pub struct Hash( + #[cfg_attr( + feature = "schemars", + schemars(schema_with = "crate::util::json_hex_string::len_64") + )] + [u8; 64], +); + +impl Hash { + fn internal_new(arr: [u8; 64]) -> Self { Hash(arr) } + + fn internal_engine() -> HashEngine { Default::default() } +} + +#[cfg(not(hashes_fuzz))] +pub(crate) fn from_engine(mut e: HashEngine) -> Hash { + // pad buffer with a single 1-bit then all 0s, until there are exactly 16 bytes remaining + let data_len = e.length as u64; + + let zeroes = [0; BLOCK_SIZE - 16]; + e.input(&[0x80]); + if e.length % BLOCK_SIZE > zeroes.len() { + e.input(&zeroes); + } + let pad_length = zeroes.len() - (e.length % BLOCK_SIZE); + e.input(&zeroes[..pad_length]); + debug_assert_eq!(e.length % BLOCK_SIZE, zeroes.len()); + + e.input(&[0; 8]); + e.input(&(8 * data_len).to_be_bytes()); + debug_assert_eq!(e.length % BLOCK_SIZE, 0); + + Hash(e.midstate()) +} + +#[cfg(hashes_fuzz)] +pub(crate) fn from_engine(e: HashEngine) -> Hash { + let mut hash = e.midstate(); + hash[0] ^= 0xff; // Make this distinct from SHA-256 + Hash(hash) +} + +#[allow(non_snake_case)] +fn Ch(x: u64, y: u64, z: u64) -> u64 { z ^ (x & (y ^ z)) } +#[allow(non_snake_case)] +fn Maj(x: u64, y: u64, z: u64) -> u64 { (x & y) | (z & (x | y)) } +#[allow(non_snake_case)] +fn Sigma0(x: u64) -> u64 { x.rotate_left(36) ^ x.rotate_left(30) ^ x.rotate_left(25) } +#[allow(non_snake_case)] +fn Sigma1(x: u64) -> u64 { x.rotate_left(50) ^ x.rotate_left(46) ^ x.rotate_left(23) } +fn sigma0(x: u64) -> u64 { x.rotate_left(63) ^ x.rotate_left(56) ^ (x >> 7) } +fn sigma1(x: u64) -> u64 { x.rotate_left(45) ^ x.rotate_left(3) ^ (x >> 6) } + +#[cfg(feature = "small-hash")] +#[macro_use] +mod small_hash { + use super::*; + + #[rustfmt::skip] + pub(super) fn round(a: u64, b: u64, c: u64, d: &mut u64, e: u64, + f: u64, g: u64, h: &mut u64, k: u64, w: u64, + ) { + let t1 = + h.wrapping_add(Sigma1(e)).wrapping_add(Ch(e, f, g)).wrapping_add(k).wrapping_add(w); + let t2 = Sigma0(a).wrapping_add(Maj(a, b, c)); + *d = d.wrapping_add(t1); + *h = t1.wrapping_add(t2); + } + #[rustfmt::skip] + pub(super) fn later_round(a: u64, b: u64, c: u64, d: &mut u64, e: u64, + f: u64, g: u64, h: &mut u64, k: u64, w: u64, + w1: u64, w2: u64, w3: u64, + ) -> u64 { + let w = w.wrapping_add(sigma1(w1)).wrapping_add(w2).wrapping_add(sigma0(w3)); + round(a, b, c, d, e, f, g, h, k, w); + w + } + + macro_rules! round( + // first round + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => ( + small_hash::round($a, $b, $c, &mut $d, $e, $f, $g, &mut $h, $k, $w) + ); + // later rounds we reassign $w before doing the first-round computation + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => ( + $w = small_hash::later_round($a, $b, $c, &mut $d, $e, $f, $g, &mut $h, $k, $w, $w1, $w2, $w3) + ) + ); +} + +#[cfg(not(feature = "small-hash"))] +#[macro_use] +mod fast_hash { + macro_rules! round( + // first round + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => ( + let t1 = $h.wrapping_add(Sigma1($e)).wrapping_add(Ch($e, $f, $g)).wrapping_add($k).wrapping_add($w); + let t2 = Sigma0($a).wrapping_add(Maj($a, $b, $c)); + $d = $d.wrapping_add(t1); + $h = t1.wrapping_add(t2); + ); + // later rounds we reassign $w before doing the first-round computation + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => ( + $w = $w.wrapping_add(sigma1($w1)).wrapping_add($w2).wrapping_add(sigma0($w3)); + round!($a, $b, $c, $d, $e, $f, $g, $h, $k, $w); + ) + ); +} + +impl HashEngine { + // Algorithm copied from libsecp256k1 + pub(crate) fn process_block(&mut self) { + debug_assert_eq!(self.buffer.len(), BLOCK_SIZE); + + let mut w = [0u64; 16]; + for (w_val, buff_bytes) in w.iter_mut().zip(self.buffer.chunks_exact(8)) { + *w_val = u64::from_be_bytes(buff_bytes.try_into().expect("8 byte slice")); + } + + let mut a = self.h[0]; + let mut b = self.h[1]; + let mut c = self.h[2]; + let mut d = self.h[3]; + let mut e = self.h[4]; + let mut f = self.h[5]; + let mut g = self.h[6]; + let mut h = self.h[7]; + + round!(a, b, c, d, e, f, g, h, 0x428a2f98d728ae22, w[0]); + round!(h, a, b, c, d, e, f, g, 0x7137449123ef65cd, w[1]); + round!(g, h, a, b, c, d, e, f, 0xb5c0fbcfec4d3b2f, w[2]); + round!(f, g, h, a, b, c, d, e, 0xe9b5dba58189dbbc, w[3]); + round!(e, f, g, h, a, b, c, d, 0x3956c25bf348b538, w[4]); + round!(d, e, f, g, h, a, b, c, 0x59f111f1b605d019, w[5]); + round!(c, d, e, f, g, h, a, b, 0x923f82a4af194f9b, w[6]); + round!(b, c, d, e, f, g, h, a, 0xab1c5ed5da6d8118, w[7]); + round!(a, b, c, d, e, f, g, h, 0xd807aa98a3030242, w[8]); + round!(h, a, b, c, d, e, f, g, 0x12835b0145706fbe, w[9]); + round!(g, h, a, b, c, d, e, f, 0x243185be4ee4b28c, w[10]); + round!(f, g, h, a, b, c, d, e, 0x550c7dc3d5ffb4e2, w[11]); + round!(e, f, g, h, a, b, c, d, 0x72be5d74f27b896f, w[12]); + round!(d, e, f, g, h, a, b, c, 0x80deb1fe3b1696b1, w[13]); + round!(c, d, e, f, g, h, a, b, 0x9bdc06a725c71235, w[14]); + round!(b, c, d, e, f, g, h, a, 0xc19bf174cf692694, w[15]); + + round!(a, b, c, d, e, f, g, h, 0xe49b69c19ef14ad2, w[0], w[14], w[9], w[1]); + round!(h, a, b, c, d, e, f, g, 0xefbe4786384f25e3, w[1], w[15], w[10], w[2]); + round!(g, h, a, b, c, d, e, f, 0x0fc19dc68b8cd5b5, w[2], w[0], w[11], w[3]); + round!(f, g, h, a, b, c, d, e, 0x240ca1cc77ac9c65, w[3], w[1], w[12], w[4]); + round!(e, f, g, h, a, b, c, d, 0x2de92c6f592b0275, w[4], w[2], w[13], w[5]); + round!(d, e, f, g, h, a, b, c, 0x4a7484aa6ea6e483, w[5], w[3], w[14], w[6]); + round!(c, d, e, f, g, h, a, b, 0x5cb0a9dcbd41fbd4, w[6], w[4], w[15], w[7]); + round!(b, c, d, e, f, g, h, a, 0x76f988da831153b5, w[7], w[5], w[0], w[8]); + round!(a, b, c, d, e, f, g, h, 0x983e5152ee66dfab, w[8], w[6], w[1], w[9]); + round!(h, a, b, c, d, e, f, g, 0xa831c66d2db43210, w[9], w[7], w[2], w[10]); + round!(g, h, a, b, c, d, e, f, 0xb00327c898fb213f, w[10], w[8], w[3], w[11]); + round!(f, g, h, a, b, c, d, e, 0xbf597fc7beef0ee4, w[11], w[9], w[4], w[12]); + round!(e, f, g, h, a, b, c, d, 0xc6e00bf33da88fc2, w[12], w[10], w[5], w[13]); + round!(d, e, f, g, h, a, b, c, 0xd5a79147930aa725, w[13], w[11], w[6], w[14]); + round!(c, d, e, f, g, h, a, b, 0x06ca6351e003826f, w[14], w[12], w[7], w[15]); + round!(b, c, d, e, f, g, h, a, 0x142929670a0e6e70, w[15], w[13], w[8], w[0]); + + round!(a, b, c, d, e, f, g, h, 0x27b70a8546d22ffc, w[0], w[14], w[9], w[1]); + round!(h, a, b, c, d, e, f, g, 0x2e1b21385c26c926, w[1], w[15], w[10], w[2]); + round!(g, h, a, b, c, d, e, f, 0x4d2c6dfc5ac42aed, w[2], w[0], w[11], w[3]); + round!(f, g, h, a, b, c, d, e, 0x53380d139d95b3df, w[3], w[1], w[12], w[4]); + round!(e, f, g, h, a, b, c, d, 0x650a73548baf63de, w[4], w[2], w[13], w[5]); + round!(d, e, f, g, h, a, b, c, 0x766a0abb3c77b2a8, w[5], w[3], w[14], w[6]); + round!(c, d, e, f, g, h, a, b, 0x81c2c92e47edaee6, w[6], w[4], w[15], w[7]); + round!(b, c, d, e, f, g, h, a, 0x92722c851482353b, w[7], w[5], w[0], w[8]); + round!(a, b, c, d, e, f, g, h, 0xa2bfe8a14cf10364, w[8], w[6], w[1], w[9]); + round!(h, a, b, c, d, e, f, g, 0xa81a664bbc423001, w[9], w[7], w[2], w[10]); + round!(g, h, a, b, c, d, e, f, 0xc24b8b70d0f89791, w[10], w[8], w[3], w[11]); + round!(f, g, h, a, b, c, d, e, 0xc76c51a30654be30, w[11], w[9], w[4], w[12]); + round!(e, f, g, h, a, b, c, d, 0xd192e819d6ef5218, w[12], w[10], w[5], w[13]); + round!(d, e, f, g, h, a, b, c, 0xd69906245565a910, w[13], w[11], w[6], w[14]); + round!(c, d, e, f, g, h, a, b, 0xf40e35855771202a, w[14], w[12], w[7], w[15]); + round!(b, c, d, e, f, g, h, a, 0x106aa07032bbd1b8, w[15], w[13], w[8], w[0]); + + round!(a, b, c, d, e, f, g, h, 0x19a4c116b8d2d0c8, w[0], w[14], w[9], w[1]); + round!(h, a, b, c, d, e, f, g, 0x1e376c085141ab53, w[1], w[15], w[10], w[2]); + round!(g, h, a, b, c, d, e, f, 0x2748774cdf8eeb99, w[2], w[0], w[11], w[3]); + round!(f, g, h, a, b, c, d, e, 0x34b0bcb5e19b48a8, w[3], w[1], w[12], w[4]); + round!(e, f, g, h, a, b, c, d, 0x391c0cb3c5c95a63, w[4], w[2], w[13], w[5]); + round!(d, e, f, g, h, a, b, c, 0x4ed8aa4ae3418acb, w[5], w[3], w[14], w[6]); + round!(c, d, e, f, g, h, a, b, 0x5b9cca4f7763e373, w[6], w[4], w[15], w[7]); + round!(b, c, d, e, f, g, h, a, 0x682e6ff3d6b2b8a3, w[7], w[5], w[0], w[8]); + round!(a, b, c, d, e, f, g, h, 0x748f82ee5defb2fc, w[8], w[6], w[1], w[9]); + round!(h, a, b, c, d, e, f, g, 0x78a5636f43172f60, w[9], w[7], w[2], w[10]); + round!(g, h, a, b, c, d, e, f, 0x84c87814a1f0ab72, w[10], w[8], w[3], w[11]); + round!(f, g, h, a, b, c, d, e, 0x8cc702081a6439ec, w[11], w[9], w[4], w[12]); + round!(e, f, g, h, a, b, c, d, 0x90befffa23631e28, w[12], w[10], w[5], w[13]); + round!(d, e, f, g, h, a, b, c, 0xa4506cebde82bde9, w[13], w[11], w[6], w[14]); + round!(c, d, e, f, g, h, a, b, 0xbef9a3f7b2c67915, w[14], w[12], w[7], w[15]); + round!(b, c, d, e, f, g, h, a, 0xc67178f2e372532b, w[15], w[13], w[8], w[0]); + + round!(a, b, c, d, e, f, g, h, 0xca273eceea26619c, w[0], w[14], w[9], w[1]); + round!(h, a, b, c, d, e, f, g, 0xd186b8c721c0c207, w[1], w[15], w[10], w[2]); + round!(g, h, a, b, c, d, e, f, 0xeada7dd6cde0eb1e, w[2], w[0], w[11], w[3]); + round!(f, g, h, a, b, c, d, e, 0xf57d4f7fee6ed178, w[3], w[1], w[12], w[4]); + round!(e, f, g, h, a, b, c, d, 0x06f067aa72176fba, w[4], w[2], w[13], w[5]); + round!(d, e, f, g, h, a, b, c, 0x0a637dc5a2c898a6, w[5], w[3], w[14], w[6]); + round!(c, d, e, f, g, h, a, b, 0x113f9804bef90dae, w[6], w[4], w[15], w[7]); + round!(b, c, d, e, f, g, h, a, 0x1b710b35131c471b, w[7], w[5], w[0], w[8]); + round!(a, b, c, d, e, f, g, h, 0x28db77f523047d84, w[8], w[6], w[1], w[9]); + round!(h, a, b, c, d, e, f, g, 0x32caab7b40c72493, w[9], w[7], w[2], w[10]); + round!(g, h, a, b, c, d, e, f, 0x3c9ebe0a15c9bebc, w[10], w[8], w[3], w[11]); + round!(f, g, h, a, b, c, d, e, 0x431d67c49c100d4c, w[11], w[9], w[4], w[12]); + round!(e, f, g, h, a, b, c, d, 0x4cc5d4becb3e42b6, w[12], w[10], w[5], w[13]); + round!(d, e, f, g, h, a, b, c, 0x597f299cfc657e2a, w[13], w[11], w[6], w[14]); + round!(c, d, e, f, g, h, a, b, 0x5fcb6fab3ad6faec, w[14], w[12], w[7], w[15]); + round!(b, c, d, e, f, g, h, a, 0x6c44198c4a475817, w[15], w[13], w[8], w[0]); + + self.h[0] = self.h[0].wrapping_add(a); + self.h[1] = self.h[1].wrapping_add(b); + self.h[2] = self.h[2].wrapping_add(c); + self.h[3] = self.h[3].wrapping_add(d); + self.h[4] = self.h[4].wrapping_add(e); + self.h[5] = self.h[5].wrapping_add(f); + self.h[6] = self.h[6].wrapping_add(g); + self.h[7] = self.h[7].wrapping_add(h); + } +} + +#[cfg(test)] +mod tests { + #[test] + #[cfg(feature = "alloc")] + fn test() { + use crate::{sha512, Hash, HashEngine}; + + #[derive(Clone)] + struct Test { + input: &'static str, + output: Vec, + output_str: &'static str, + } + + #[rustfmt::skip] + let tests = vec![ + // Test vectors computed with `sha512sum` + Test { + input: "", + output: vec![ + 0xcf, 0x83, 0xe1, 0x35, 0x7e, 0xef, 0xb8, 0xbd, + 0xf1, 0x54, 0x28, 0x50, 0xd6, 0x6d, 0x80, 0x07, + 0xd6, 0x20, 0xe4, 0x05, 0x0b, 0x57, 0x15, 0xdc, + 0x83, 0xf4, 0xa9, 0x21, 0xd3, 0x6c, 0xe9, 0xce, + 0x47, 0xd0, 0xd1, 0x3c, 0x5d, 0x85, 0xf2, 0xb0, + 0xff, 0x83, 0x18, 0xd2, 0x87, 0x7e, 0xec, 0x2f, + 0x63, 0xb9, 0x31, 0xbd, 0x47, 0x41, 0x7a, 0x81, + 0xa5, 0x38, 0x32, 0x7a, 0xf9, 0x27, 0xda, 0x3e, + ], + output_str: "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e" + }, + Test { + input: "The quick brown fox jumps over the lazy dog", + output: vec![ + 0x07, 0xe5, 0x47, 0xd9, 0x58, 0x6f, 0x6a, 0x73, + 0xf7, 0x3f, 0xba, 0xc0, 0x43, 0x5e, 0xd7, 0x69, + 0x51, 0x21, 0x8f, 0xb7, 0xd0, 0xc8, 0xd7, 0x88, + 0xa3, 0x09, 0xd7, 0x85, 0x43, 0x6b, 0xbb, 0x64, + 0x2e, 0x93, 0xa2, 0x52, 0xa9, 0x54, 0xf2, 0x39, + 0x12, 0x54, 0x7d, 0x1e, 0x8a, 0x3b, 0x5e, 0xd6, + 0xe1, 0xbf, 0xd7, 0x09, 0x78, 0x21, 0x23, 0x3f, + 0xa0, 0x53, 0x8f, 0x3d, 0xb8, 0x54, 0xfe, 0xe6, + ], + output_str: "07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6", + }, + Test { + input: "The quick brown fox jumps over the lazy dog.", + output: vec![ + 0x91, 0xea, 0x12, 0x45, 0xf2, 0x0d, 0x46, 0xae, + 0x9a, 0x03, 0x7a, 0x98, 0x9f, 0x54, 0xf1, 0xf7, + 0x90, 0xf0, 0xa4, 0x76, 0x07, 0xee, 0xb8, 0xa1, + 0x4d, 0x12, 0x89, 0x0c, 0xea, 0x77, 0xa1, 0xbb, + 0xc6, 0xc7, 0xed, 0x9c, 0xf2, 0x05, 0xe6, 0x7b, + 0x7f, 0x2b, 0x8f, 0xd4, 0xc7, 0xdf, 0xd3, 0xa7, + 0xa8, 0x61, 0x7e, 0x45, 0xf3, 0xc4, 0x63, 0xd4, + 0x81, 0xc7, 0xe5, 0x86, 0xc3, 0x9a, 0xc1, 0xed, + ], + output_str: "91ea1245f20d46ae9a037a989f54f1f790f0a47607eeb8a14d12890cea77a1bbc6c7ed9cf205e67b7f2b8fd4c7dfd3a7a8617e45f3c463d481c7e586c39ac1ed", + }, + ]; + + for test in tests { + // Hash through high-level API, check hex encoding/decoding + let hash = sha512::Hash::hash(test.input.as_bytes()); + assert_eq!(hash, test.output_str.parse::().expect("parse hex")); + assert_eq!(&hash[..], &test.output[..]); + assert_eq!(&hash.to_string(), &test.output_str); + + // Hash through engine, checking that we can input byte by byte + let mut engine = sha512::Hash::engine(); + for ch in test.input.as_bytes() { + engine.input(&[*ch]); + } + let manual_hash = sha512::Hash::from_engine(engine); + assert_eq!(hash, manual_hash); + assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice()); + } + } + + #[cfg(feature = "serde")] + #[test] + fn sha512_serde() { + use serde_test::{assert_tokens, Configure, Token}; + + use crate::{sha512, Hash}; + + #[rustfmt::skip] + static HASH_BYTES: [u8; 64] = [ + 0x8b, 0x41, 0xe1, 0xb7, 0x8a, 0xd1, 0x15, 0x21, + 0x11, 0x3c, 0x52, 0xff, 0x18, 0x2a, 0x1b, 0x8e, + 0x0a, 0x19, 0x57, 0x54, 0xaa, 0x52, 0x7f, 0xcd, + 0x00, 0xa4, 0x11, 0x62, 0x0b, 0x46, 0xf2, 0x0f, + 0xff, 0xfb, 0x80, 0x88, 0xcc, 0xf8, 0x54, 0x97, + 0x12, 0x1a, 0xd4, 0x49, 0x9e, 0x08, 0x45, 0xb8, + 0x76, 0xf6, 0xdd, 0x66, 0x40, 0x08, 0x8a, 0x2f, + 0x0b, 0x2d, 0x8a, 0x60, 0x0b, 0xdf, 0x4c, 0x0c, + ]; + + let hash = sha512::Hash::from_slice(&HASH_BYTES).expect("right number of bytes"); + assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]); + assert_tokens( + &hash.readable(), + &[Token::Str( + "8b41e1b78ad11521113c52ff182a1b8e0a195754aa527fcd00a411620b46f20f\ + fffb8088ccf85497121ad4499e0845b876f6dd6640088a2f0b2d8a600bdf4c0c", + )], + ); + } +} + +#[cfg(bench)] +mod benches { + use test::Bencher; + + use crate::{sha512, Hash, HashEngine}; + + #[bench] + pub fn sha512_10(bh: &mut Bencher) { + let mut engine = sha512::Hash::engine(); + let bytes = [1u8; 10]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn sha512_1k(bh: &mut Bencher) { + let mut engine = sha512::Hash::engine(); + let bytes = [1u8; 1024]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn sha512_64k(bh: &mut Bencher) { + let mut engine = sha512::Hash::engine(); + let bytes = [1u8; 65536]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } +} diff --git a/hashes/src/sha512_256.rs b/hashes/src/sha512_256.rs new file mode 100644 index 00000000..27d90d68 --- /dev/null +++ b/hashes/src/sha512_256.rs @@ -0,0 +1,180 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! SHA512_256 implementation. +//! +//! SHA512/256 is a hash function that uses the sha512 alogrithm but it truncates +//! the output to 256 bits. It has different initial constants than sha512 so it +//! produces an entirely different hash compared to sha512. More information at +//! . + +use core::ops::Index; +use core::slice::SliceIndex; +use core::str; + +use crate::{sha512, FromSliceError}; + +/// Engine to compute SHA512/256 hash function. +/// +/// SHA512/256 is a hash function that uses the sha512 alogrithm but it truncates +/// the output to 256 bits. It has different initial constants than sha512 so it +/// produces an entirely different hash compared to sha512. More information at +/// . +#[derive(Clone)] +pub struct HashEngine(sha512::HashEngine); + +impl Default for HashEngine { + #[rustfmt::skip] + fn default() -> Self { + HashEngine(sha512::HashEngine::sha512_256()) + } +} + +impl crate::HashEngine for HashEngine { + type MidState = [u8; 64]; + + fn midstate(&self) -> [u8; 64] { self.0.midstate() } + + const BLOCK_SIZE: usize = sha512::BLOCK_SIZE; + + fn n_bytes_hashed(&self) -> usize { self.0.n_bytes_hashed() } + + fn input(&mut self, inp: &[u8]) { self.0.input(inp); } +} + +crate::internal_macros::hash_type! { + 256, + false, + "Output of the SHA512/256 hash function.\n\nSHA512/256 is a hash function that uses the sha512 alogrithm but it truncates the output to 256 bits. It has different initial constants than sha512 so it produces an entirely different hash compared to sha512. More information at . ", + "crate::util::json_hex_string::len_32" +} + +fn from_engine(e: HashEngine) -> Hash { + let mut ret = [0; 32]; + ret.copy_from_slice(&sha512::from_engine(e.0)[..32]); + Hash(ret) +} + +#[cfg(test)] +mod tests { + #[test] + #[cfg(feature = "alloc")] + fn test() { + use crate::{sha512_256, Hash, HashEngine}; + + #[derive(Clone)] + struct Test { + input: &'static str, + output: Vec, + output_str: &'static str, + } + + #[rustfmt::skip] + let tests = vec![ + // Examples from go sha512/256 tests. + Test { + input: "", + output: vec![ + 0xc6, 0x72, 0xb8, 0xd1, 0xef, 0x56, 0xed, 0x28, + 0xab, 0x87, 0xc3, 0x62, 0x2c, 0x51, 0x14, 0x06, + 0x9b, 0xdd, 0x3a, 0xd7, 0xb8, 0xf9, 0x73, 0x74, + 0x98, 0xd0, 0xc0, 0x1e, 0xce, 0xf0, 0x96, 0x7a, + ], + output_str: "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a" + }, + Test { + input: "abcdef", + output: vec![ + 0xe4, 0xfd, 0xcb, 0x11, 0xd1, 0xac, 0x14, 0xe6, + 0x98, 0x74, 0x3a, 0xcd, 0x88, 0x05, 0x17, 0x4c, + 0xea, 0x5d, 0xdc, 0x0d, 0x31, 0x2e, 0x3e, 0x47, + 0xf6, 0x37, 0x20, 0x32, 0x57, 0x1b, 0xad, 0x84, + ], + output_str: "e4fdcb11d1ac14e698743acd8805174cea5ddc0d312e3e47f6372032571bad84", + }, + Test { + input: "Discard medicine more than two years old.", + output: vec![ + 0x69, 0x0c, 0x8a, 0xd3, 0x91, 0x6c, 0xef, 0xd3, + 0xad, 0x29, 0x22, 0x6d, 0x98, 0x75, 0x96, 0x5e, + 0x3e, 0xe9, 0xec, 0x0d, 0x44, 0x82, 0xea, 0xcc, + 0x24, 0x8f, 0x2f, 0xf4, 0xaa, 0x0d, 0x8e, 0x5b, + ], + output_str: "690c8ad3916cefd3ad29226d9875965e3ee9ec0d4482eacc248f2ff4aa0d8e5b", + }, + Test { + input: "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", + output: vec![ + 0xb5, 0xba, 0xf7, 0x47, 0xc3, 0x07, 0xf9, 0x88, + 0x49, 0xec, 0x88, 0x1c, 0xf0, 0xd4, 0x86, 0x05, + 0xae, 0x4e, 0xdd, 0x38, 0x63, 0x72, 0xae, 0xa9, + 0xb2, 0x6e, 0x71, 0xdb, 0x51, 0x7e, 0x65, 0x0b, + ], + output_str: "b5baf747c307f98849ec881cf0d48605ae4edd386372aea9b26e71db517e650b", + }, + Test { + input: "The major problem is with sendmail. -Mark Horton", + output: vec![ + 0x53, 0xed, 0x5f, 0x9b, 0x5c, 0x0b, 0x67, 0x4a, + 0xc0, 0xf3, 0x42, 0x5d, 0x9f, 0x9a, 0x5d, 0x46, + 0x26, 0x55, 0xb0, 0x7c, 0xc9, 0x0f, 0x5d, 0x0f, + 0x69, 0x2e, 0xec, 0x09, 0x38, 0x84, 0xa6, 0x07, + ], + output_str: "53ed5f9b5c0b674ac0f3425d9f9a5d462655b07cc90f5d0f692eec093884a607", + }, + ]; + + for test in tests { + // Hash through high-level API, check hex encoding/decoding + let hash = sha512_256::Hash::hash(test.input.as_bytes()); + assert_eq!(hash, test.output_str.parse::().expect("parse hex")); + assert_eq!(&hash[..], &test.output[..]); + assert_eq!(&hash.to_string(), &test.output_str); + + // Hash through engine, checking that we can input byte by byte + let mut engine = sha512_256::Hash::engine(); + for ch in test.input.as_bytes() { + engine.0.input(&[*ch]); + } + let manual_hash = sha512_256::Hash::from_engine(engine); + assert_eq!(hash, manual_hash); + assert_eq!(hash.to_byte_array()[..].as_ref(), test.output.as_slice()); + } + } +} + +#[cfg(bench)] +mod benches { + use test::Bencher; + + use crate::{sha512_256, Hash, HashEngine}; + + #[bench] + pub fn sha512_256_10(bh: &mut Bencher) { + let mut engine = sha512_256::Hash::engine(); + let bytes = [1u8; 10]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn sha512_256_1k(bh: &mut Bencher) { + let mut engine = sha512_256::Hash::engine(); + let bytes = [1u8; 1024]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn sha512_256_64k(bh: &mut Bencher) { + let mut engine = sha512_256::Hash::engine(); + let bytes = [1u8; 65536]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } +} diff --git a/hashes/src/siphash24.rs b/hashes/src/siphash24.rs new file mode 100644 index 00000000..86981afe --- /dev/null +++ b/hashes/src/siphash24.rs @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! SipHash 2-4 implementation. +//! + +use core::ops::Index; +use core::slice::SliceIndex; +use core::{cmp, mem, ptr, str}; + +use crate::{FromSliceError, Hash as _, HashEngine as _}; + +crate::internal_macros::hash_type! { + 64, + false, + "Output of the SipHash24 hash function.", + "crate::util::json_hex_string::len_8" +} + +#[cfg(not(hashes_fuzz))] +fn from_engine(e: HashEngine) -> Hash { Hash::from_u64(Hash::from_engine_to_u64(e)) } + +#[cfg(hashes_fuzz)] +fn from_engine(e: HashEngine) -> Hash { + let state = e.midstate(); + Hash::from_u64(state.v0 ^ state.v1 ^ state.v2 ^ state.v3) +} + +macro_rules! compress { + ($state:expr) => {{ + compress!($state.v0, $state.v1, $state.v2, $state.v3) + }}; + ($v0:expr, $v1:expr, $v2:expr, $v3:expr) => {{ + $v0 = $v0.wrapping_add($v1); + $v1 = $v1.rotate_left(13); + $v1 ^= $v0; + $v0 = $v0.rotate_left(32); + $v2 = $v2.wrapping_add($v3); + $v3 = $v3.rotate_left(16); + $v3 ^= $v2; + $v0 = $v0.wrapping_add($v3); + $v3 = $v3.rotate_left(21); + $v3 ^= $v0; + $v2 = $v2.wrapping_add($v1); + $v1 = $v1.rotate_left(17); + $v1 ^= $v2; + $v2 = $v2.rotate_left(32); + }}; +} + +/// Load an integer of the desired type from a byte stream, in LE order. Uses +/// `copy_nonoverlapping` to let the compiler generate the most efficient way +/// to load it from a possibly unaligned address. +/// +/// Unsafe because: unchecked indexing at `i..i+size_of(int_ty)`. +macro_rules! load_int_le { + ($buf:expr, $i:expr, $int_ty:ident) => {{ + debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len()); + let mut data = 0 as $int_ty; + ptr::copy_nonoverlapping( + $buf.get_unchecked($i), + &mut data as *mut _ as *mut u8, + mem::size_of::<$int_ty>(), + ); + data.to_le() + }}; +} + +/// Internal state of the [`HashEngine`]. +#[derive(Debug, Clone)] +pub struct State { + // v0, v2 and v1, v3 show up in pairs in the algorithm, + // and simd implementations of SipHash will use vectors + // of v02 and v13. By placing them in this order in the struct, + // the compiler can pick up on just a few simd optimizations by itself. + v0: u64, + v2: u64, + v1: u64, + v3: u64, +} + +/// Engine to compute the SipHash24 hash function. +#[derive(Debug, Clone)] +pub struct HashEngine { + k0: u64, + k1: u64, + length: usize, // how many bytes we've processed + state: State, // hash State + tail: u64, // unprocessed bytes le + ntail: usize, // how many bytes in tail are valid +} + +impl HashEngine { + /// Creates a new SipHash24 engine with keys. + pub fn with_keys(k0: u64, k1: u64) -> HashEngine { + HashEngine { + k0, + k1, + length: 0, + state: State { + v0: k0 ^ 0x736f6d6570736575, + v1: k1 ^ 0x646f72616e646f6d, + v2: k0 ^ 0x6c7967656e657261, + v3: k1 ^ 0x7465646279746573, + }, + tail: 0, + ntail: 0, + } + } + + /// Creates a new SipHash24 engine. + pub fn new() -> HashEngine { HashEngine::with_keys(0, 0) } + + /// Retrieves the keys of this engine. + pub fn keys(&self) -> (u64, u64) { (self.k0, self.k1) } + + #[inline] + fn c_rounds(state: &mut State) { + compress!(state); + compress!(state); + } + + #[inline] + fn d_rounds(state: &mut State) { + compress!(state); + compress!(state); + compress!(state); + compress!(state); + } +} + +impl Default for HashEngine { + fn default() -> Self { HashEngine::new() } +} + +impl crate::HashEngine for HashEngine { + type MidState = State; + + fn midstate(&self) -> State { self.state.clone() } + + const BLOCK_SIZE: usize = 8; + + #[inline] + fn input(&mut self, msg: &[u8]) { + let length = msg.len(); + self.length += length; + + let mut needed = 0; + + if self.ntail != 0 { + needed = 8 - self.ntail; + self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << (8 * self.ntail); + if length < needed { + self.ntail += length; + return; + } else { + self.state.v3 ^= self.tail; + HashEngine::c_rounds(&mut self.state); + self.state.v0 ^= self.tail; + self.ntail = 0; + } + } + + // Buffered tail is now flushed, process new input. + let len = length - needed; + let left = len & 0x7; + + let mut i = needed; + while i < len - left { + let mi = unsafe { load_int_le!(msg, i, u64) }; + + self.state.v3 ^= mi; + HashEngine::c_rounds(&mut self.state); + self.state.v0 ^= mi; + + i += 8; + } + + self.tail = unsafe { u8to64_le(msg, i, left) }; + self.ntail = left; + } + + fn n_bytes_hashed(&self) -> usize { self.length } +} + +impl Hash { + /// Hashes the given data with an engine with the provided keys. + pub fn hash_with_keys(k0: u64, k1: u64, data: &[u8]) -> Hash { + let mut engine = HashEngine::with_keys(k0, k1); + engine.input(data); + Hash::from_engine(engine) + } + + /// Hashes the given data directly to u64 with an engine with the provided keys. + pub fn hash_to_u64_with_keys(k0: u64, k1: u64, data: &[u8]) -> u64 { + let mut engine = HashEngine::with_keys(k0, k1); + engine.input(data); + Hash::from_engine_to_u64(engine) + } + + /// Produces a hash as `u64` from the current state of a given engine. + #[inline] + pub fn from_engine_to_u64(e: HashEngine) -> u64 { + let mut state = e.state; + + let b: u64 = ((e.length as u64 & 0xff) << 56) | e.tail; + + state.v3 ^= b; + HashEngine::c_rounds(&mut state); + state.v0 ^= b; + + state.v2 ^= 0xff; + HashEngine::d_rounds(&mut state); + + state.v0 ^ state.v1 ^ state.v2 ^ state.v3 + } + + /// Returns the (little endian) 64-bit integer representation of the hash value. + pub fn as_u64(&self) -> u64 { u64::from_le_bytes(self.0) } + + /// Creates a hash from its (little endian) 64-bit integer representation. + pub fn from_u64(hash: u64) -> Hash { Hash(hash.to_le_bytes()) } +} + +/// Load an u64 using up to 7 bytes of a byte slice. +/// +/// Unsafe because: unchecked indexing at `start..start+len`. +#[inline] +unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 { + debug_assert!(len < 8); + let mut i = 0; // current byte index (from LSB) in the output u64 + let mut out = 0; + if i + 3 < len { + out = u64::from(load_int_le!(buf, start + i, u32)); + i += 4; + } + if i + 1 < len { + out |= u64::from(load_int_le!(buf, start + i, u16)) << (i * 8); + i += 2 + } + if i < len { + out |= u64::from(*buf.get_unchecked(start + i)) << (i * 8); + i += 1; + } + debug_assert_eq!(i, len); + out +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_siphash_2_4() { + #[rustfmt::skip] + let vecs: [[u8; 8]; 64] = [ + [0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72], + [0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74], + [0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d], + [0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85], + [0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf], + [0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18], + [0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb], + [0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab], + [0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93], + [0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e], + [0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a], + [0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4], + [0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75], + [0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14], + [0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7], + [0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1], + [0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f], + [0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69], + [0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b], + [0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb], + [0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe], + [0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0], + [0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93], + [0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8], + [0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8], + [0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc], + [0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17], + [0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f], + [0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde], + [0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6], + [0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad], + [0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32], + [0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71], + [0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7], + [0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12], + [0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15], + [0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31], + [0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02], + [0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca], + [0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a], + [0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e], + [0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad], + [0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18], + [0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4], + [0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9], + [0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9], + [0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb], + [0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0], + [0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6], + [0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7], + [0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee], + [0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1], + [0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a], + [0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81], + [0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f], + [0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24], + [0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7], + [0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea], + [0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60], + [0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66], + [0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c], + [0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f], + [0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5], + [0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95], + ]; + + let k0 = 0x_07_06_05_04_03_02_01_00; + let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; + let mut vin = [0u8; 64]; + let mut state_inc = HashEngine::with_keys(k0, k1); + + for i in 0..64 { + vin[i] = i as u8; + let vec = Hash::from_slice(&vecs[i][..]).unwrap(); + let out = Hash::hash_with_keys(k0, k1, &vin[0..i]); + assert_eq!(vec, out, "vec #{}", i); + + let inc = Hash::from_engine(state_inc.clone()); + assert_eq!(vec, inc, "vec #{}", i); + state_inc.input(&[i as u8]); + } + } +} + +#[cfg(bench)] +mod benches { + use test::Bencher; + + use crate::{siphash24, Hash, HashEngine}; + + #[bench] + pub fn siphash24_1ki(bh: &mut Bencher) { + let mut engine = siphash24::Hash::engine(); + let bytes = [1u8; 1024]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn siphash24_64ki(bh: &mut Bencher) { + let mut engine = siphash24::Hash::engine(); + let bytes = [1u8; 65536]; + bh.iter(|| { + engine.input(&bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn siphash24_1ki_hash(bh: &mut Bencher) { + let k0 = 0x_07_06_05_04_03_02_01_00; + let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; + let bytes = [1u8; 1024]; + bh.iter(|| { + let _ = siphash24::Hash::hash_with_keys(k0, k1, &bytes); + }); + bh.bytes = bytes.len() as u64; + } + + #[bench] + pub fn siphash24_1ki_hash_u64(bh: &mut Bencher) { + let k0 = 0x_07_06_05_04_03_02_01_00; + let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; + let bytes = [1u8; 1024]; + bh.iter(|| { + let _ = siphash24::Hash::hash_to_u64_with_keys(k0, k1, &bytes); + }); + bh.bytes = bytes.len() as u64; + } +} diff --git a/hashes/src/util.rs b/hashes/src/util.rs new file mode 100644 index 00000000..6282897d --- /dev/null +++ b/hashes/src/util.rs @@ -0,0 +1,486 @@ +// SPDX-License-Identifier: CC0-1.0 + +#[macro_export] +/// Adds hexadecimal formatting implementation of a trait `$imp` to a given type `$ty`. +macro_rules! hex_fmt_impl( + ($reverse:expr, $ty:ident) => ( + $crate::hex_fmt_impl!($reverse, $ty, ); + ); + ($reverse:expr, $ty:ident, $($gen:ident: $gent:ident),*) => ( + impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> { + #[inline] + fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result { + if $reverse { + $crate::_export::_core::fmt::LowerHex::fmt(&self.0.backward_hex(), f) + } else { + $crate::_export::_core::fmt::LowerHex::fmt(&self.0.forward_hex(), f) + } + } + } + + impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> { + #[inline] + fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result { + if $reverse { + $crate::_export::_core::fmt::UpperHex::fmt(&self.0.backward_hex(), f) + } else { + $crate::_export::_core::fmt::UpperHex::fmt(&self.0.forward_hex(), f) + } + } + } + + impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> { + #[inline] + fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result { + $crate::_export::_core::fmt::LowerHex::fmt(&self, f) + } + } + + impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> { + #[inline] + fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result { + write!(f, "{:#}", self) + } + } + ); +); + +/// Adds slicing traits implementations to a given type `$ty` +#[macro_export] +macro_rules! borrow_slice_impl( + ($ty:ident) => ( + $crate::borrow_slice_impl!($ty, ); + ); + ($ty:ident, $($gen:ident: $gent:ident),*) => ( + impl<$($gen: $gent),*> $crate::_export::_core::borrow::Borrow<[u8]> for $ty<$($gen),*> { + fn borrow(&self) -> &[u8] { + &self[..] + } + } + + impl<$($gen: $gent),*> $crate::_export::_core::convert::AsRef<[u8]> for $ty<$($gen),*> { + fn as_ref(&self) -> &[u8] { + &self[..] + } + } + ) +); + +macro_rules! engine_input_impl( + () => ( + #[cfg(not(hashes_fuzz))] + fn input(&mut self, mut inp: &[u8]) { + while !inp.is_empty() { + let buf_idx = self.length % ::BLOCK_SIZE; + let rem_len = ::BLOCK_SIZE - buf_idx; + let write_len = cmp::min(rem_len, inp.len()); + + self.buffer[buf_idx..buf_idx + write_len] + .copy_from_slice(&inp[..write_len]); + self.length += write_len; + if self.length % ::BLOCK_SIZE == 0 { + self.process_block(); + } + inp = &inp[write_len..]; + } + } + + #[cfg(hashes_fuzz)] + fn input(&mut self, inp: &[u8]) { + for c in inp { + self.buffer[0] ^= *c; + } + self.length += inp.len(); + } + ) +); + +/// Creates a new newtype around a [`Hash`] type. +/// +/// The syntax is similar to the usual tuple struct syntax: +/// +/// ``` +/// # use tapyrus_hashes::{hash_newtype, sha256}; +/// hash_newtype! { +/// /// Hash of `Foo`. +/// pub struct MyNewtype(pub sha256::Hash); +/// } +/// ``` +/// +/// You can use any valid visibility specifier in place of `pub` or you can omit either or both, if +/// you want the type or its field to be private. +/// +/// Whether the hash is reversed or not when displaying depends on the inner type. However you can +/// override it like this: +/// +/// ``` +/// # use tapyrus_hashes::{hash_newtype, sha256}; +/// hash_newtype! { +/// #[hash_newtype(backward)] +/// struct MyNewtype(sha256::Hash); +/// } +/// ``` +/// +/// This will display the hash backwards regardless of what the inner type does. Use `forward` +/// instead of `backward` to force displaying forward. +/// +/// You can add arbitrary doc comments or other attributes to the struct or it's field. Note that +/// the macro already derives [`Copy`], [`Clone`], [`Eq`], [`PartialEq`], +/// [`Hash`](core::hash::Hash), [`Ord`], [`PartialOrd`]. With the `serde` feature on, this also adds +/// `Serialize` and `Deserialize` implementations. +/// +/// You can also define multiple newtypes within one macro call: +/// +/// ``` +/// # use tapyrus_hashes::{hash_newtype, sha256, hash160}; +/// +/// hash_newtype! { +/// /// My custom type 1 +/// pub struct Newtype1(sha256::Hash); +/// +/// /// My custom type 2 +/// struct Newtype2(hash160::Hash); +/// } +/// ``` +/// +/// Note: the macro is internally recursive. If you use too many attributes (> 256 tokens) you may +/// hit recursion limit. If you have so many attributes for a good reason, just raising the limit +/// should be OK. Note however that attribute-processing part has to use [TT muncher] which has +/// quadratic complexity, so having many attributes may blow up compile time. This should be rare. +/// +/// [TT muncher]: https://danielkeep.github.io/tlborm/book/pat-incremental-tt-munchers.html +/// +// Ever heard of legendary comments warning developers to not touch the code? Yep, here's another +// one. The following code is written the way it is for some specific reasons. If you think you can +// simplify it, I suggest spending your time elsewhere. +// +// If you looks at the code carefully you might ask these questions: +// +// * Why are attributes using `tt` and not `meta`?! +// * Why are the macros split like that?! +// * Why use recursion instead of `$()*`? +// +// None of these are here by accident. For some reason unknown to me, if you accept an argument to +// macro with any fragment specifier other than `tt` it will **not** match any of the rules +// requiring a specific token. Yep, I tried it, I literally got error that `hash_newtype` doesn't +// match `hash_newtype`. So all input attributes must be `tt`. +// +// Originally I wanted to define a bunch of macros that would filter-out hash_type attributes. Then +// I remembered (by seeing compiler error) that calling macros is not allowed inside attributes. +// And no, you can't bypass it by calling a helper macro and passing "output of another macro" into +// it. The whole macro gets passed, not the resulting value. So we have to generate the entire +// attributes. And you can't just place an attribute-producing macro above struct - they are +// considered separate items. This is not C. +// +// Thus struct is generated in a separate macro together with attributes. And since the macro needs +// attributes as the input and I didn't want to create confusion by using `#[]` syntax *after* +// struct, I opted to use `{}` as a separator. Yes, a separator is required because an attribute +// may be composed of multiple token trees - that's the point of "double repetition". +#[macro_export] +macro_rules! hash_newtype { + ($($(#[$($type_attrs:tt)*])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:tt])* $field_vis:vis $hash:path);)+) => { + $( + $($crate::hash_newtype_known_attrs!(#[ $($type_attrs)* ]);)* + + $crate::hash_newtype_struct! { + $type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash); + + $({ $($type_attrs)* })* + } + + $crate::hex_fmt_impl!(<$newtype as $crate::Hash>::DISPLAY_BACKWARD, $newtype); + $crate::serde_impl!($newtype, <$newtype as $crate::Hash>::LEN); + $crate::borrow_slice_impl!($newtype); + + impl $newtype { + /// Creates this wrapper type from the inner hash type. + #[allow(unused)] // the user of macro may not need this + pub fn from_raw_hash(inner: $hash) -> $newtype { + $newtype(inner) + } + + /// Returns the inner hash (sha256, sh256d etc.). + #[allow(unused)] // the user of macro may not need this + pub fn to_raw_hash(self) -> $hash { + self.0 + } + + /// Returns a reference to the inner hash (sha256, sh256d etc.). + #[allow(unused)] // the user of macro may not need this + pub fn as_raw_hash(&self) -> &$hash { + &self.0 + } + } + + impl $crate::_export::_core::convert::From<$hash> for $newtype { + fn from(inner: $hash) -> $newtype { + // Due to rust 1.22 we have to use this instead of simple `Self(inner)` + Self { 0: inner } + } + } + + impl $crate::_export::_core::convert::From<$newtype> for $hash { + fn from(hashtype: $newtype) -> $hash { + hashtype.0 + } + } + + impl $crate::Hash for $newtype { + type Engine = <$hash as $crate::Hash>::Engine; + type Bytes = <$hash as $crate::Hash>::Bytes; + + const LEN: usize = <$hash as $crate::Hash>::LEN; + const DISPLAY_BACKWARD: bool = $crate::hash_newtype_get_direction!($hash, $(#[$($type_attrs)*])*); + + fn engine() -> Self::Engine { + <$hash as $crate::Hash>::engine() + } + + fn from_engine(e: Self::Engine) -> Self { + Self::from(<$hash as $crate::Hash>::from_engine(e)) + } + + #[inline] + fn from_slice(sl: &[u8]) -> Result<$newtype, $crate::FromSliceError> { + Ok($newtype(<$hash as $crate::Hash>::from_slice(sl)?)) + } + + #[inline] + fn from_byte_array(bytes: Self::Bytes) -> Self { + $newtype(<$hash as $crate::Hash>::from_byte_array(bytes)) + } + + #[inline] + fn to_byte_array(self) -> Self::Bytes { + self.0.to_byte_array() + } + + #[inline] + fn as_byte_array(&self) -> &Self::Bytes { + self.0.as_byte_array() + } + + #[inline] + fn all_zeros() -> Self { + let zeros = <$hash>::all_zeros(); + $newtype(zeros) + } + } + + impl $crate::_export::_core::str::FromStr for $newtype { + type Err = $crate::hex::HexToArrayError; + fn from_str(s: &str) -> $crate::_export::_core::result::Result<$newtype, Self::Err> { + use $crate::hex::{FromHex, HexToBytesIter}; + use $crate::Hash; + + let inner: <$hash as Hash>::Bytes = if ::DISPLAY_BACKWARD { + FromHex::from_byte_iter(HexToBytesIter::new(s)?.rev())? + } else { + FromHex::from_byte_iter(HexToBytesIter::new(s)?)? + }; + Ok($newtype(<$hash>::from_byte_array(inner))) + } + } + + impl $crate::_export::_core::convert::AsRef<[u8; <$hash as $crate::Hash>::LEN]> for $newtype { + fn as_ref(&self) -> &[u8; <$hash as $crate::Hash>::LEN] { + AsRef::<[u8; <$hash as $crate::Hash>::LEN]>::as_ref(&self.0) + } + } + + impl> $crate::_export::_core::ops::Index for $newtype { + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + &self.0[index] + } + } + )+ + }; +} + +// Generates the struct only (no impls) +// +// This is a separate macro to make it more readable and have a separate interface that allows for +// two groups of type attributes: processed and not-yet-processed ones (think about it like +// computation via recursion). The macro recursively matches unprocessed attributes, popping them +// one at a time and either ignoring them (`hash_newtype`) or appending them to the list of +// processed attributes to be added to the struct. +// +// Once the list of not-yet-processed attributes is empty the struct is generated with processed +// attributes added. +#[doc(hidden)] +#[macro_export] +macro_rules! hash_newtype_struct { + ($(#[$other_attrs:meta])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:meta])* $field_vis:vis $hash:path);) => { + $(#[$other_attrs])* + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] + $type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash); + }; + ($(#[$other_attrs:meta])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:meta])* $field_vis:vis $hash:path); { hash_newtype($($ignore:tt)*) } $($type_attrs:tt)*) => { + $crate::hash_newtype_struct! { + $(#[$other_attrs])* + $type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash); + + $($type_attrs)* + } + }; + ($(#[$other_attrs:meta])* $type_vis:vis struct $newtype:ident($(#[$field_attrs:meta])* $field_vis:vis $hash:path); { $other_attr:meta } $($type_attrs:tt)*) => { + $crate::hash_newtype_struct! { + $(#[$other_attrs])* + #[$other_attr] + $type_vis struct $newtype($(#[$field_attrs])* $field_vis $hash); + + $($type_attrs)* + } + }; +} + +// Extracts `hash_newtype(forward)` and `hash_newtype(backward)` attributes if any and turns them +// into bool, defaulting to `DISPLAY_BACKWARD` of the wrapped type if the attribute is omitted. +// +// Once an appropriate attribute is found we pass the remaining ones into another macro to detect +// duplicates/conflicts and report an error. +// +// FYI, no, we can't use a helper macro to first filter all `hash_newtype` attributes. We would be +// attempting to match on macros instead. So we must write `hashe_newtype` in each branch. +#[doc(hidden)] +#[macro_export] +macro_rules! hash_newtype_get_direction { + ($hash:ty, ) => { <$hash as $crate::Hash>::DISPLAY_BACKWARD }; + ($hash:ty, #[hash_newtype(forward)] $($others:tt)*) => { { $crate::hash_newtype_forbid_direction!(forward, $($others)*); false } }; + ($hash:ty, #[hash_newtype(backward)] $($others:tt)*) => { { $crate::hash_newtype_forbid_direction!(backward, $($others)*); true } }; + ($hash:ty, #[$($ignore:tt)*] $($others:tt)*) => { $crate::hash_newtype_get_direction!($hash, $($others)*) }; +} + +// Reports an error if any of the attributes is `hash_newtype($direction)`. +// +// This is used for detection of duplicates/conflicts, see the macro above. +#[doc(hidden)] +#[macro_export] +macro_rules! hash_newtype_forbid_direction { + ($direction:ident, ) => {}; + ($direction:ident, #[hash_newtype(forward)] $(others:tt)*) => { + compile_error!(concat!("Cannot set display direction to forward: ", stringify!($direction), " was already specified")); + }; + ($direction:ident, #[hash_newtype(backward)] $(others:tt)*) => { + compile_error!(concat!("Cannot set display direction to backward: ", stringify!($direction), " was already specified")); + }; + ($direction:ident, #[$($ignore:tt)*] $(#[$others:tt])*) => { + $crate::hash_newtype_forbid_direction!($direction, $(#[$others])*) + }; +} + +// Checks (at compile time) that all `hash_newtype` attributes are known. +// +// An unknown attribute could be a typo that could cause problems - e.g. wrong display direction if +// it's missing. To prevent this, we call this macro above. The macro produces nothing unless an +// unknown attribute is found in which case it produces `compile_error!`. +#[doc(hidden)] +#[macro_export] +macro_rules! hash_newtype_known_attrs { + (#[hash_newtype(forward)]) => {}; + (#[hash_newtype(backward)]) => {}; + (#[hash_newtype($($unknown:tt)*)]) => { compile_error!(concat!("Unrecognized attribute ", stringify!($($unknown)*))); }; + ($($ignore:tt)*) => {}; +} + +#[cfg(feature = "schemars")] +pub mod json_hex_string { + use schemars::gen::SchemaGenerator; + use schemars::schema::{Schema, SchemaObject}; + use schemars::JsonSchema; + macro_rules! define_custom_hex { + ($name:ident, $len:expr) => { + pub fn $name(gen: &mut SchemaGenerator) -> Schema { + let mut schema: SchemaObject = ::json_schema(gen).into(); + schema.string = Some(Box::new(schemars::schema::StringValidation { + max_length: Some($len * 2), + min_length: Some($len * 2), + pattern: Some("[0-9a-fA-F]+".to_owned()), + })); + schema.into() + } + }; + } + define_custom_hex!(len_8, 8); + define_custom_hex!(len_20, 20); + define_custom_hex!(len_32, 32); + define_custom_hex!(len_64, 64); +} + +#[cfg(test)] +mod test { + use crate::{sha256, Hash}; + + #[test] + fn hash_as_ref_array() { + let hash = sha256::Hash::hash(&[3, 50]); + let r = AsRef::<[u8; 32]>::as_ref(&hash); + assert_eq!(r, hash.as_byte_array()); + } + + #[test] + fn hash_as_ref_slice() { + let hash = sha256::Hash::hash(&[3, 50]); + let r = AsRef::<[u8]>::as_ref(&hash); + assert_eq!(r, hash.as_byte_array()); + } + + #[test] + fn hash_borrow() { + use core::borrow::Borrow; + + let hash = sha256::Hash::hash(&[3, 50]); + let borrowed: &[u8] = hash.borrow(); + assert_eq!(borrowed, hash.as_byte_array()); + } + + hash_newtype! { + /// Test hash. + struct TestHash(crate::sha256d::Hash); + } + + #[test] + fn display() { + let want = "0000000000000000000000000000000000000000000000000000000000000000"; + let got = format!("{}", TestHash::all_zeros()); + assert_eq!(got, want) + } + + #[test] + fn display_alternate() { + let want = "0x0000000000000000000000000000000000000000000000000000000000000000"; + let got = format!("{:#}", TestHash::all_zeros()); + assert_eq!(got, want) + } + + #[test] + fn lower_hex() { + let want = "0000000000000000000000000000000000000000000000000000000000000000"; + let got = format!("{:x}", TestHash::all_zeros()); + assert_eq!(got, want) + } + + #[test] + fn lower_hex_alternate() { + let want = "0x0000000000000000000000000000000000000000000000000000000000000000"; + let got = format!("{:#x}", TestHash::all_zeros()); + assert_eq!(got, want) + } + + #[test] + fn inner_hash_as_ref_array() { + let hash = TestHash::all_zeros(); + let r = AsRef::<[u8; 32]>::as_ref(&hash); + assert_eq!(r, hash.as_byte_array()); + } + + #[test] + fn inner_hash_as_ref_slice() { + let hash = TestHash::all_zeros(); + let r = AsRef::<[u8]>::as_ref(&hash); + assert_eq!(r, hash.as_byte_array()); + } +} diff --git a/internals/CHANGELOG.md b/internals/CHANGELOG.md new file mode 100644 index 00000000..1003c776 --- /dev/null +++ b/internals/CHANGELOG.md @@ -0,0 +1,11 @@ +# 0.2.0 - 2023-06-20 + +- [Rename crate](https://github.com/rust-bitcoin/rust-bitcoin/pull/1885) to `bitcoin-internals` +- Add module to assist [alloc-free parse error handling](https://github.com/rust-bitcoin/rust-bitcoin/pull/1297) +- Move various macros here. + +# 0.1.0 - 2023-03-08 + +Split this crate out from the [rust-bitcoin](https://github.com/rust-bitcoin/rust-bitcoin) crate. +For previous development history see the original +[CHANGELOG](https://github.com/rust-bitcoin/rust-bitcoin/blob/master/bitcoin/CHANGELOG.md) file. diff --git a/internals/Cargo.toml b/internals/Cargo.toml new file mode 100644 index 00000000..8de92516 --- /dev/null +++ b/internals/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "tapyrus-internals" +version = "0.2.0" +authors = ["Andrew Poelstra ", "The Rust Bitcoin developers"] +license = "MIT" +homepage = "https://github.com/chaintope/rust-tapyrus/" +repository = "https://github.com/chaintope/rust-tapyrus/" +description = "Internal types and macros used by rust-tapyrus ecosystem" +categories = ["cryptography::cryptocurrencies"] +keywords = ["internal"] +readme = "README.md" +edition = "2018" +exclude = ["tests", "contrib"] + +[features] +default = [] +std = ["alloc"] +alloc = [] + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +serde = { version = "1.0.103", default-features = false, optional = true } + +[dev-dependencies] diff --git a/internals/README.md b/internals/README.md new file mode 100644 index 00000000..79aa2980 --- /dev/null +++ b/internals/README.md @@ -0,0 +1,7 @@ +Rust Bitcoin Internals +====================== + +This crate is only meant to be used internally by crates in the +[rust-bitcoin](https://github.com/rust-bitcoin) ecosystem. + +This crate will never be stabilized, depend on it at your own risk. diff --git a/internals/build.rs b/internals/build.rs new file mode 100644 index 00000000..ab1f0411 --- /dev/null +++ b/internals/build.rs @@ -0,0 +1,35 @@ +fn main() { + let rustc = std::env::var_os("RUSTC"); + let rustc = rustc.as_ref().map(std::path::Path::new).unwrap_or_else(|| "rustc".as_ref()); + let output = std::process::Command::new(rustc) + .arg("--version") + .output() + .unwrap_or_else(|error| panic!("Failed to run `{:?} --version`: {:?}", rustc, error)); + assert!(output.status.success(), "{:?} -- version returned non-zero exit code", rustc); + let stdout = String::from_utf8(output.stdout).expect("rustc produced non-UTF-8 output"); + let version_prefix = "rustc "; + if !stdout.starts_with(version_prefix) { + panic!("unexpected rustc output: {}", stdout); + } + + let version = &stdout[version_prefix.len()..]; + let end = version.find(&[' ', '-'] as &[_]).unwrap_or(version.len()); + let version = &version[..end]; + let mut version_components = version.split('.'); + let major = version_components.next().unwrap(); + assert_eq!(major, "1", "Unexpected Rust major version"); + let minor = version_components + .next() + .unwrap_or("0") + .parse::() + .expect("invalid Rust minor version"); + + // print cfg for all interesting versions less than or equal to minor + // 46 adds `track_caller` + // 55 adds `kind()` to `ParseIntError` + for version in &[46, 55] { + if *version <= minor { + println!("cargo:rustc-cfg=rust_v_1_{}", version); + } + } +} diff --git a/internals/contrib/test.sh b/internals/contrib/test.sh new file mode 100755 index 00000000..d4243b51 --- /dev/null +++ b/internals/contrib/test.sh @@ -0,0 +1,64 @@ +#!/bin/sh + +set -ex + +FEATURES="std alloc" + +cargo --version +rustc --version + +# Work out if we are using a nightly toolchain. +NIGHTLY=false +if cargo --version | grep nightly >/dev/null; then + NIGHTLY=true +fi + +# Make all cargo invocations verbose +export CARGO_TERM_VERBOSE=true + +# Defaults / sanity checks +cargo --locked build +cargo --locked test + +if [ "$DO_LINT" = true ] +then + cargo clippy --locked --all-features --all-targets -- -D warnings +fi + +if [ "$DO_FEATURE_MATRIX" = true ]; then + # No features + cargo build --locked --no-default-features + cargo test --locked --no-default-features + + # All features + cargo build --locked --no-default-features --features="$FEATURES" + cargo test --locked --no-default-features --features="$FEATURES" + + # Single features + for feature in ${FEATURES} + do + cargo build --locked --no-default-features --features="$feature" + cargo test --locked --no-default-features --features="$feature" + done +fi + +# Build the docs if told to (this only works with the nightly toolchain) +if [ "$DO_DOCSRS" = true ]; then + RUSTDOCFLAGS="--cfg docsrs -D warnings -D rustdoc::broken-intra-doc-links" cargo +nightly doc --all-features +fi + +# Build the docs with a stable toolchain, in unison with the DO_DOCSRS command +# above this checks that we feature guarded docs imports correctly. +if [ "$DO_DOCS" = true ]; then + RUSTDOCFLAGS="-D warnings" cargo +stable doc --locked --all-features +fi + +# Run formatter if told to. +if [ "$DO_FMT" = true ]; then + if [ "$NIGHTLY" = false ]; then + echo "DO_FMT requires a nightly toolchain (consider using RUSTUP_TOOLCHAIN)" + exit 1 + fi + rustup component add rustfmt + cargo fmt --check +fi diff --git a/internals/src/error.rs b/internals/src/error.rs new file mode 100644 index 00000000..6731ae13 --- /dev/null +++ b/internals/src/error.rs @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! # Error +//! +//! Error handling macros and helpers. +//! + +pub mod input_string; +mod parse_error; + +pub use input_string::InputString; + +/// Formats error. +/// +/// If `std` feature is OFF appends error source (delimited by `: `). We do this because +/// `e.source()` is only available in std builds, without this macro the error source is lost for +/// no-std builds. +#[macro_export] +macro_rules! write_err { + ($writer:expr, $string:literal $(, $args:expr)*; $source:expr) => { + { + #[cfg(feature = "std")] + { + let _ = &$source; // Prevents clippy warnings. + write!($writer, $string $(, $args)*) + } + #[cfg(not(feature = "std"))] + { + write!($writer, concat!($string, ": {}") $(, $args)*, $source) + } + } + } +} diff --git a/internals/src/error/input_string.rs b/internals/src/error/input_string.rs new file mode 100644 index 00000000..b69751c0 --- /dev/null +++ b/internals/src/error/input_string.rs @@ -0,0 +1,126 @@ +//! Implements the [`InputString`] type storing the parsed input. + +use core::fmt; + +use storage::Storage; + +/// Conditionally stores the input string in parse errors. +/// +/// This type stores the input string of a parse function depending on whether `alloc` feature is +/// enabled. When it is enabled, the string is stored inside as `String`. When disabled this is a +/// zero-sized type and attempt to store a string does nothing. +/// +/// This provides two methods to format the error strings depending on the context. +#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] +pub struct InputString(Storage); + +impl InputString { + /// Displays a message saying `failed to parse as `. + /// + /// This is normally used whith the `write_err!` macro. + pub fn display_cannot_parse<'a, T>(&'a self, what: &'a T) -> CannotParse<'a, T> + where + T: fmt::Display + ?Sized, + { + CannotParse { input: self, what } + } + + /// Formats a message saying ` is not a known `. + /// + /// This is normally used in leaf parse errors (with no source) when parsing an enum. + pub fn unknown_variant(&self, what: &T, f: &mut fmt::Formatter) -> fmt::Result + where + T: fmt::Display + ?Sized, + { + storage::unknown_variant(&self.0, what, f) + } +} + +macro_rules! impl_from { + ($($type:ty),+ $(,)?) => { + $( + impl From<$type> for InputString { + fn from(input: $type) -> Self { + #[allow(clippy::useless_conversion)] + InputString(input.into()) + } + } + )+ + } +} + +impl_from!(&str); + +/// Displays message saying `failed to parse as `. +/// +/// This is created by `display_cannot_parse` method and should be used as +/// `write_err!("{}", self.input.display_cannot_parse("what is parsed"); self.source)` in parse +/// error [`Display`](fmt::Display) imlementation if the error has source. If the error doesn't +/// have a source just use regular `write!` with same formatting arguments. +pub struct CannotParse<'a, T: fmt::Display + ?Sized> { + input: &'a InputString, + what: &'a T, +} + +impl<'a, T: fmt::Display + ?Sized> fmt::Display for CannotParse<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + storage::cannot_parse(&self.input.0, &self.what, f) + } +} + +#[cfg(not(feature = "alloc"))] +mod storage { + use core::fmt; + + #[derive(Clone, Eq, PartialEq, Hash, Ord, PartialOrd)] + pub(super) struct Storage; + + impl fmt::Debug for Storage { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("") + } + } + + impl From<&str> for Storage { + fn from(_value: &str) -> Self { Storage } + } + + pub(super) fn cannot_parse(_: &Storage, what: &W, f: &mut fmt::Formatter) -> fmt::Result + where + W: fmt::Display + ?Sized, + { + write!(f, "failed to parse {}", what) + } + + pub(super) fn unknown_variant(_: &Storage, what: &W, f: &mut fmt::Formatter) -> fmt::Result + where + W: fmt::Display + ?Sized, + { + write!(f, "unknown {}", what) + } +} + +#[cfg(feature = "alloc")] +mod storage { + use core::fmt; + + use super::InputString; + + pub(super) type Storage = alloc::string::String; + + pub(super) fn cannot_parse(input: &Storage, what: &W, f: &mut fmt::Formatter) -> fmt::Result + where + W: fmt::Display + ?Sized, + { + write!(f, "failed to parse '{}' as {}", input, what) + } + + pub(super) fn unknown_variant(inp: &Storage, what: &W, f: &mut fmt::Formatter) -> fmt::Result + where + W: fmt::Display + ?Sized, + { + write!(f, "'{}' is not a known {}", inp, what) + } + + impl_from!(alloc::string::String, alloc::boxed::Box, alloc::borrow::Cow<'_, str>); +} diff --git a/internals/src/error/parse_error.rs b/internals/src/error/parse_error.rs new file mode 100644 index 00000000..ee501e03 --- /dev/null +++ b/internals/src/error/parse_error.rs @@ -0,0 +1,48 @@ +//! Contains helpers for parsing-related errors. + +/// Creates an error type intended for string parsing errors. +/// +/// The resulting error type has two fields: `input` and `source`. The type of `input` is +/// [`InputString`](super::InputString), the type of `source` is specified as the second argument +/// to the macro. +/// +/// The resulting type is public, conditionally implements [`std::error::Error`] and has a private +/// `new()` method for convenience. +/// +/// ## Parameters +/// +/// * `name` - the name of the error type +/// * `source` - the type of the source type +/// * `subject` - English description of the type being parsed (e.g. "a tapyrus amount") +/// * `derive` - list of derives to add +#[macro_export] +macro_rules! parse_error_type { + ($vis:vis $name:ident, $source:ty, $subject:expr $(, $derive:path)* $(,)?) => { + #[derive(Debug $(, $derive)*)] + $vis struct $name { + input: $crate::error::InputString, + source: $source, + } + + impl $name { + /// Creates `Self`. + fn new>(input: T, source: $source) -> Self { + $name { + input: input.into(), + source, + } + } + } + + impl core::fmt::Display for $name { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + $crate::error::write_err!("{}", self.input.display_cannot_parse($subject); self.source) + } + } + + #[cfg(feature = "std")] + impl std::error::Error for $name { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.source) } + } + } +} diff --git a/internals/src/lib.rs b/internals/src/lib.rs new file mode 100644 index 00000000..75192dbe --- /dev/null +++ b/internals/src/lib.rs @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! # Rust Bitcoin Internal +//! +//! This crate is only meant to be used internally by crates in the +//! [rust-tapyrus](https://github.com/rust-bitcoin) ecosystem. +//! + +#![no_std] +// Experimental features we need. +#![cfg_attr(docsrs, feature(doc_auto_cfg))] +// Coding conventions +#![warn(missing_docs)] +// Exclude clippy lints we don't think are valuable +#![allow(clippy::needless_question_mark)] // https://github.com/rust-bitcoin/rust-bitcoin/pull/2134 + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(feature = "std")] +extern crate std; + +pub mod error; +pub mod macros; +mod parse; +pub mod serde; diff --git a/internals/src/macros.rs b/internals/src/macros.rs new file mode 100644 index 00000000..799730f0 --- /dev/null +++ b/internals/src/macros.rs @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: CC0-1.0 + +//! Various macros used by the Rust Bitcoin ecosystem. +//! + +/// Implements standard array methods for a given wrapper type. +#[macro_export] +macro_rules! impl_array_newtype { + ($thing:ident, $ty:ty, $len:literal) => { + impl $thing { + /// Converts the object to a raw pointer. + #[inline] + pub fn as_ptr(&self) -> *const $ty { + let &$thing(ref dat) = self; + dat.as_ptr() + } + + /// Converts the object to a mutable raw pointer. + #[inline] + pub fn as_mut_ptr(&mut self) -> *mut $ty { + let &mut $thing(ref mut dat) = self; + dat.as_mut_ptr() + } + + /// Returns the length of the object as an array. + #[inline] + pub fn len(&self) -> usize { $len } + + /// Returns whether the object, as an array, is empty. Always false. + #[inline] + pub fn is_empty(&self) -> bool { false } + } + + impl<'a> core::convert::From<[$ty; $len]> for $thing { + fn from(data: [$ty; $len]) -> Self { $thing(data) } + } + + impl<'a> core::convert::From<&'a [$ty; $len]> for $thing { + fn from(data: &'a [$ty; $len]) -> Self { $thing(*data) } + } + + impl<'a> core::convert::TryFrom<&'a [$ty]> for $thing { + type Error = core::array::TryFromSliceError; + + fn try_from(data: &'a [$ty]) -> Result { + use core::convert::TryInto; + + Ok($thing(data.try_into()?)) + } + } + + impl AsRef<[$ty; $len]> for $thing { + fn as_ref(&self) -> &[$ty; $len] { &self.0 } + } + + impl AsMut<[$ty; $len]> for $thing { + fn as_mut(&mut self) -> &mut [$ty; $len] { &mut self.0 } + } + + impl AsRef<[$ty]> for $thing { + fn as_ref(&self) -> &[$ty] { &self.0 } + } + + impl AsMut<[$ty]> for $thing { + fn as_mut(&mut self) -> &mut [$ty] { &mut self.0 } + } + + impl core::borrow::Borrow<[$ty; $len]> for $thing { + fn borrow(&self) -> &[$ty; $len] { &self.0 } + } + + impl core::borrow::BorrowMut<[$ty; $len]> for $thing { + fn borrow_mut(&mut self) -> &mut [$ty; $len] { &mut self.0 } + } + + // The following two are valid because `[T; N]: Borrow<[T]>` + impl core::borrow::Borrow<[$ty]> for $thing { + fn borrow(&self) -> &[$ty] { &self.0 } + } + + impl core::borrow::BorrowMut<[$ty]> for $thing { + fn borrow_mut(&mut self) -> &mut [$ty] { &mut self.0 } + } + + impl core::ops::Index for $thing + where + [$ty]: core::ops::Index, + { + type Output = <[$ty] as core::ops::Index>::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { &self.0[index] } + } + }; +} + +/// Implements `Debug` by calling through to `Display`. +#[macro_export] +macro_rules! debug_from_display { + ($thing:ident) => { + impl core::fmt::Debug for $thing { + fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { + core::fmt::Display::fmt(self, f) + } + } + }; +} + +/// Asserts a boolean expression at compile time. +#[macro_export] +macro_rules! const_assert { + ($x:expr) => {{ + const _: [(); 0 - !$x as usize] = []; + }}; +} diff --git a/internals/src/parse.rs b/internals/src/parse.rs new file mode 100644 index 00000000..1aed7605 --- /dev/null +++ b/internals/src/parse.rs @@ -0,0 +1,107 @@ +/// Support for parsing strings. + +// Impls a single TryFrom conversion +#[doc(hidden)] +#[macro_export] +macro_rules! impl_try_from_stringly { + ($from:ty, $to:ty, $error:ty, $func:expr) => { + $(#[$attr])? + impl core::convert::TryFrom<$from> for $to { + type Error = $error; + + fn try_from(s: $from) -> Result { + $func(AsRef::::as_ref(s)).map_err(|source| <$error>::new(s, source)) + } + } + + } +} + +/// Implements conversions from various string types. +/// +/// This macro implements `FromStr` as well as `TryFrom<{stringly}` where `{stringly}` is one of +/// these types: +/// +/// * `&str` +/// * `String` +/// * `Box` +/// * `Cow<'_, str>` +/// +/// The last three are only available with `alloc` feature turned on. +#[macro_export] +macro_rules! impl_parse { + ($type:ty, $descr:expr, $func:expr, $vis:vis $error:ident, $error_source:ty $(, $error_derive:path)*) => { + $crate::parse_error_type!($vis $error, $error_source, $descr $(, $error_derive)*); + + impl core::str::FromStr for $type { + type Err = $error; + + fn from_str(s: &str) -> Result { + $func(s).map_err(|source| <$error>::new(s, source)) + } + } + + impl_try_from_stringly!(&str); + + #[cfg(feature = "alloc")] + impl_try_from_stringly!(alloc::string::String, $type, $error, $func); + #[cfg(feature = "alloc")] + impl_try_from_stringly!(alloc::borrow::Cow<'_, str>, $type, $error, $func); + #[cfg(feature = "alloc")] + impl_try_from_stringly!(alloc::boxed::Box, $type, $error, $func); + } +} + +/// Implements conversions from various string types as well as `serde` (de)serialization. +/// +/// This calls `impl_parse` macro and implements serde deserialization by expecting and parsing a +/// string and serialization by outputting a string. +#[macro_export] +macro_rules! impl_parse_and_serde { + ($type:ty, $descr:expr, $func:expr, $error:ident, $error_source:ty $(, $error_derive:path)*) => { + impl_parse!($type, $descr, $func, $error, $error_source $(, $error_derive)*); + + // We don't use `serde_string_impl` because we want to avoid allocating input. + #[cfg(feature = "serde")] + impl<'de> $crate::serde::Deserialize<'de> for $type { + fn deserialize(deserializer: D) -> Result<$name, D::Error> + where + D: $crate::serde::de::Deserializer<'de>, + { + use core::fmt::{self, Formatter}; + use core::str::FromStr; + + struct Visitor; + impl<'de> $crate::serde::de::Visitor<'de> for Visitor { + type Value = $name; + + fn expecting(&self, f: &mut Formatter) -> fmt::Result { + f.write_str($descr) + } + + fn visit_str(self, s: &str) -> Result + where + E: $crate::serde::de::Error, + { + s.parse().map_err(|error| { + $crate::serde::IntoDeError::try_into_de_error(error) + .unwrap_or_else(|_| E::invalid_value(Unexpected::Str(s), &self)) + }) + } + } + + deserializer.deserialize_str(Visitor) + } + } + + #[cfg(feature = "serde")] + impl $crate::serde::Serialize for $name { + fn serialize(&self, serializer: S) -> Result + where + S: $crate::serde::Serializer, + { + serializer.collect_str(&self) + } + } + } +} diff --git a/internals/src/serde.rs b/internals/src/serde.rs new file mode 100644 index 00000000..de79756a --- /dev/null +++ b/internals/src/serde.rs @@ -0,0 +1,64 @@ +//! Contains extensions of `serde` and internal reexports. + +#[cfg(feature = "serde")] +#[doc(hidden)] +pub use serde::{de, ser, Deserialize, Deserializer, Serialize, Serializer}; + +/// Converts given error type to a type implementing [`de::Error`]. +/// +/// This is used in [`Deserialize`] implementations to convert specialized errors into serde +/// errors. +#[cfg(feature = "serde")] +pub trait IntoDeError: Sized { + /// Converts to deserializer error possibly outputting vague message. + /// + /// This method is allowed to return a vague error message if the error type doesn't contain + /// enough information to explain the error precisely. + fn into_de_error(self, expected: Option<&dyn de::Expected>) -> E; + + /// Converts to deserializer error without outputting vague message. + /// + /// If the error type doesn't contain enough information to explain the error precisely this + /// should return `Err(self)` allowing the caller to use its information instead. + fn try_into_de_error(self, expected: Option<&dyn de::Expected>) -> Result + where + E: de::Error, + { + Ok(self.into_de_error(expected)) + } +} + +#[cfg(feature = "serde")] +mod impls { + use super::*; + + impl IntoDeError for core::convert::Infallible { + fn into_de_error(self, _expected: Option<&dyn de::Expected>) -> E { + match self {} + } + } + + impl IntoDeError for core::num::ParseIntError { + fn into_de_error(self, expected: Option<&dyn de::Expected>) -> E { + self.try_into_de_error(expected).unwrap_or_else(|_| { + let expected = expected.unwrap_or(&"an integer"); + + E::custom(format_args!("invalid string, expected {}", expected)) + }) + } + + fn try_into_de_error(self, expected: Option<&dyn de::Expected>) -> Result + where + E: de::Error, + { + use core::num::IntErrorKind::Empty; + + let expected = expected.unwrap_or(&"an integer"); + + match self.kind() { + Empty => Ok(E::invalid_value(de::Unexpected::Str(""), expected)), + _ => Err(self), + } + } + } +} diff --git a/justfile b/justfile new file mode 100644 index 00000000..b52728ca --- /dev/null +++ b/justfile @@ -0,0 +1,22 @@ +default: + @just --list + +# Cargo build everything. +build: + cargo build --workspace --all-targets --all-features + +# Cargo check everything. +check: + cargo check --workspace --all-targets --all-features + +# Lint everything. +lint: + cargo clippy --workspace --all-targets --all-features -- --deny warnings + +# Check the formatting +format: + cargo +nightly fmt --all --check + +# Update the recent and minimal lock files. +update-lock-files: + contrib/update-lock-files.sh diff --git a/logo/README.md b/logo/README.md new file mode 100644 index 00000000..71a563db --- /dev/null +++ b/logo/README.md @@ -0,0 +1,32 @@ +# Rust Bitcoin Logo + +## Files + +Included are: + +- [rust-bitcoin-inkscape.svg](./rust-bitcoin-inkscape.svg) - The Inkscape source file with the things used to make the logo in case adjustments are desired +- [rust-bitcoin-optimized.svg](./rust-bitcoin-optimized.svg) - An optimized SVG for embedding or rendering at any size desired +- [rust-bitcoin.png](./rust-bitcoin.png) - The PNG logo rendered at 300px used by this project +- [rust-bitcoin-large.png](./rust-bitcoin-large.png) - A larger size 1024px x 1024px for convenience for embedding in presentations + +## Author + +Hunter Trujillo, @cryptoquick on [Twitter](https://twitter.com/cryptoquick), [GitHub](https://github.com/cryptoquick), and Telegram. + +## License + +Licensed in the public domain under [CC0 1.0 Universal Public Domain Dedication](https://creativecommons.org/publicdomain/zero/1.0/), and the author of this work rescinds all claims to copyright or coercion or acts of force from any nation state over this work for any purpose + +Bitcoin Logo is licensed under the CC Public Domain Dedication: and + +Rust Logo is licensed under CC-BY, which allows reuse and modifications for any purpose, as long as distributors give appropriate credit and indicate changes have been made. See here: + +## Acknowledgements + +Acknowledgement for the runners up in this PR: https://github.com/rust-bitcoin/rust-bitcoin/pull/891#issuecomment-1074476858 + +In particular, the Rust Bitcoin Wizard gear was an incredibly inspired piece of art. Also, the meshed gears design was beloved by some but not all. + +Thank you to the Rust Bitcoin maintainers and community, your timely responses and guidance was appreciated. + +Also, thank you to the voters on the Rust in Bitcoin Telegram group: . diff --git a/logo/rust-bitcoin-inkscape.svg b/logo/rust-bitcoin-inkscape.svg new file mode 100644 index 00000000..9b504a34 --- /dev/null +++ b/logo/rust-bitcoin-inkscape.svg @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/logo/rust-bitcoin-large.png b/logo/rust-bitcoin-large.png new file mode 100644 index 00000000..f0cce340 Binary files /dev/null and b/logo/rust-bitcoin-large.png differ diff --git a/logo/rust-bitcoin-optimized.svg b/logo/rust-bitcoin-optimized.svg new file mode 100644 index 00000000..31cf374b --- /dev/null +++ b/logo/rust-bitcoin-optimized.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/logo/rust-bitcoin.png b/logo/rust-bitcoin.png new file mode 100644 index 00000000..0f59dd16 Binary files /dev/null and b/logo/rust-bitcoin.png differ diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..2c104735 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,77 @@ +ignore = [] +hard_tabs = false +tab_spaces = 4 +newline_style = "Auto" +indent_style = "Block" + +max_width = 100 # This is number of characters. +# `use_small_heuristics` is ignored if the granular width config values are explicitly set. +use_small_heuristics = "Max" # "Max" == All granular width settings same as `max_width`. +# # Granular width configuration settings. These are percentages of `max_width`. +# fn_call_width = 60 +# attr_fn_like_width = 70 +# struct_lit_width = 18 +# struct_variant_width = 35 +# array_width = 60 +# chain_width = 60 +# single_line_if_else_max_width = 50 + +wrap_comments = false +format_code_in_doc_comments = false +comment_width = 100 # Default 80 +normalize_comments = false +normalize_doc_attributes = false +format_strings = false +format_macro_matchers = false +format_macro_bodies = true +hex_literal_case = "Preserve" +empty_item_single_line = true +struct_lit_single_line = true +fn_single_line = true # Default false +where_single_line = false +imports_indent = "Block" +imports_layout = "Mixed" +imports_granularity = "Module" # Default "Preserve" +group_imports = "StdExternalCrate" # Default "Preserve" +reorder_imports = true +reorder_modules = true +reorder_impl_items = false +type_punctuation_density = "Wide" +space_before_colon = false +space_after_colon = true +spaces_around_ranges = false +binop_separator = "Front" +remove_nested_parens = true +combine_control_expr = true +overflow_delimited_expr = false +struct_field_align_threshold = 0 +enum_discrim_align_threshold = 0 +match_arm_blocks = false # Default true +match_arm_leading_pipes = "Never" +force_multiline_blocks = false +fn_params_layout = "Tall" +brace_style = "SameLineWhere" +control_brace_style = "AlwaysSameLine" +trailing_semicolon = true +trailing_comma = "Vertical" +match_block_trailing_comma = false +blank_lines_upper_bound = 1 +blank_lines_lower_bound = 0 +edition = "2018" +version = "One" +inline_attribute_width = 0 +format_generated_files = true +merge_derives = true +use_try_shorthand = false +use_field_init_shorthand = false +force_explicit_abi = true +condense_wildcard_suffixes = false +color = "Auto" +unstable_features = false +disable_all_formatting = false +skip_children = false +hide_parse_errors = false +error_on_line_overflow = false +error_on_unformatted = false +emit_mode = "Files" +make_backup = false diff --git a/src/blockdata/block.rs b/src/blockdata/block.rs deleted file mode 100644 index f67e8586..00000000 --- a/src/blockdata/block.rs +++ /dev/null @@ -1,285 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Bitcoin Block -//! -//! A block is a bundle of transactions with a proof-of-work attached, -//! which commits to an earlier block to form the blockchain. This -//! module describes structures and functions needed to describe -//! these blocks and the blockchain. -//! - -use util; -use util::Error::{BlockBadTarget, BlockBadProofOfWork}; -use util::hash::{BitcoinHash, bitcoin_merkle_root}; -use hashes::{Hash, HashEngine}; -use hash_types::{Wtxid, BlockHash, TxMerkleNode, WitnessMerkleNode, WitnessCommitment}; -use util::uint::Uint256; -use consensus::encode::Encodable; -use network::constants::Network; -use blockdata::transaction::Transaction; -use blockdata::constants::max_target; - -/// A block header, which contains all the block's information except -/// the actual transactions -#[derive(Copy, PartialEq, Eq, Clone, Debug)] -pub struct BlockHeader { - /// The protocol version. Should always be 1. - pub version: u32, - /// Reference to the previous block in the chain - pub prev_blockhash: BlockHash, - /// The root hash of the merkle tree of transactions in the block - pub merkle_root: TxMerkleNode, - /// The timestamp of the block, as claimed by the miner - pub time: u32, - /// The target value below which the blockhash must lie, encoded as a - /// a float (with well-defined rounding, of course) - pub bits: u32, - /// The nonce, selected to obtain a low enough blockhash - pub nonce: u32, -} - -/// A Bitcoin block, which is a collection of transactions with an attached -/// proof of work. -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct Block { - /// The block header - pub header: BlockHeader, - /// List of transactions contained in the block - pub txdata: Vec -} - -impl Block { - /// check if merkle root of header matches merkle root of the transaction list - pub fn check_merkle_root (&self) -> bool { - self.header.merkle_root == self.merkle_root() - } - - /// check if witness commitment in coinbase is matching the transaction list - pub fn check_witness_commitment(&self) -> bool { - - // witness commitment is optional if there are no transactions using SegWit in the block - if self.txdata.iter().all(|t| t.input.iter().all(|i| i.witness.is_empty())) { - return true; - } - if self.txdata.len() > 0 { - let coinbase = &self.txdata[0]; - if coinbase.is_coin_base() { - // commitment is in the last output that starts with below magic - if let Some(pos) = coinbase.output.iter() - .rposition(|o| { - o.script_pubkey.len () >= 38 && - o.script_pubkey[0..6] == [0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed] }) { - let commitment = WitnessCommitment::from_slice(&coinbase.output[pos].script_pubkey.as_bytes()[6..38]).unwrap(); - // witness reserved value is in coinbase input witness - if coinbase.input[0].witness.len() == 1 && coinbase.input[0].witness[0].len() == 32 { - let witness_root = self.witness_root(); - return commitment == Self::compute_witness_commitment(&witness_root, coinbase.input[0].witness[0].as_slice()) - } - } - } - } - false - } - - /// Calculate the transaction merkle root. - pub fn merkle_root(&self) -> TxMerkleNode { - let hashes = self.txdata.iter().map(|obj| obj.txid().as_hash()); - bitcoin_merkle_root(hashes).into() - } - - /// compute witness commitment for the transaction list - pub fn compute_witness_commitment (witness_root: &WitnessMerkleNode, witness_reserved_value: &[u8]) -> WitnessCommitment { - let mut encoder = WitnessCommitment::engine(); - witness_root.consensus_encode(&mut encoder).unwrap(); - encoder.input(witness_reserved_value); - WitnessCommitment::from_engine(encoder) - } - - /// Merkle root of transactions hashed for witness - pub fn witness_root(&self) -> WitnessMerkleNode { - let hashes = self.txdata.iter().enumerate().map(|(i, t)| - if i == 0 { - // Replace the first hash with zeroes. - Wtxid::default().as_hash() - } else { - t.wtxid().as_hash() - } - ); - bitcoin_merkle_root(hashes).into() - } -} - -impl BlockHeader { - /// Computes the target [0, T] that a blockhash must land in to be valid - pub fn target(&self) -> Uint256 { - // This is a floating-point "compact" encoding originally used by - // OpenSSL, which satoshi put into consensus code, so we're stuck - // with it. The exponent needs to have 3 subtracted from it, hence - // this goofy decoding code: - let (mant, expt) = { - let unshifted_expt = self.bits >> 24; - if unshifted_expt <= 3 { - ((self.bits & 0xFFFFFF) >> (8 * (3 - unshifted_expt as usize)), 0) - } else { - (self.bits & 0xFFFFFF, 8 * ((self.bits >> 24) - 3)) - } - }; - - // The mantissa is signed but may not be negative - if mant > 0x7FFFFF { - Default::default() - } else { - Uint256::from_u64(mant as u64).unwrap() << (expt as usize) - } - } - - /// Computes the target value in float format from Uint256 format. - pub fn compact_target_from_u256(value: &Uint256) -> u32 { - let mut size = (value.bits() + 7) / 8; - let mut compact = if size <= 3 { - (value.low_u64() << (8 * (3 - size))) as u32 - } else { - let bn = *value >> (8 * (size - 3)); - bn.low_u32() - }; - - if (compact & 0x00800000) != 0 { - compact >>= 8; - size += 1; - } - - compact | (size << 24) as u32 - } - - /// Compute the popular "difficulty" measure for mining - pub fn difficulty(&self, network: Network) -> u64 { - (max_target(network) / self.target()).low_u64() - } - - /// Checks that the proof-of-work for the block is valid. - pub fn validate_pow(&self, required_target: &Uint256) -> Result<(), util::Error> { - let target = &self.target(); - if target != required_target { - return Err(BlockBadTarget); - } - let data: [u8; 32] = self.bitcoin_hash().into_inner(); - let mut ret = [0u64; 4]; - util::endian::bytes_to_u64_slice_le(&data, &mut ret); - let hash = &Uint256(ret); - if hash <= target { Ok(()) } else { Err(BlockBadProofOfWork) } - } - - /// Returns the total work of the block - pub fn work(&self) -> Uint256 { - // 2**256 / (target + 1) == ~target / (target+1) + 1 (eqn shamelessly stolen from bitcoind) - let mut ret = !self.target(); - let mut ret1 = self.target(); - ret1.increment(); - ret = ret / ret1; - ret.increment(); - ret - } -} - -impl BitcoinHash for BlockHeader { - fn bitcoin_hash(&self) -> BlockHash { - use consensus::encode::serialize; - BlockHash::hash(&serialize(self)) - } -} - -impl BitcoinHash for Block { - fn bitcoin_hash(&self) -> BlockHash { - self.header.bitcoin_hash() - } -} - -impl_consensus_encoding!(BlockHeader, version, prev_blockhash, merkle_root, time, bits, nonce); -impl_consensus_encoding!(Block, header, txdata); -serde_struct_impl!(BlockHeader, version, prev_blockhash, merkle_root, time, bits, nonce); -serde_struct_impl!(Block, header, txdata); - -#[cfg(test)] -mod tests { - use hex::decode as hex_decode; - - use blockdata::block::{Block, BlockHeader}; - use consensus::encode::{deserialize, serialize}; - - #[test] - fn block_test() { - let some_block = hex_decode("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000").unwrap(); - let cutoff_block = hex_decode("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac").unwrap(); - - let prevhash = hex_decode("4ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000").unwrap(); - let merkle = hex_decode("bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914c").unwrap(); - - let decode: Result = deserialize(&some_block); - let bad_decode: Result = deserialize(&cutoff_block); - - assert!(decode.is_ok()); - assert!(bad_decode.is_err()); - let real_decode = decode.unwrap(); - assert_eq!(real_decode.header.version, 1); - assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash); - assert_eq!(real_decode.header.merkle_root, real_decode.merkle_root()); - assert_eq!(serialize(&real_decode.header.merkle_root), merkle); - assert_eq!(real_decode.header.time, 1231965655); - assert_eq!(real_decode.header.bits, 486604799); - assert_eq!(real_decode.header.nonce, 2067413810); - // [test] TODO: check the transaction data - - // should be also ok for a non-witness block as commitment is optional in that case - assert!(real_decode.check_witness_commitment()); - - assert_eq!(serialize(&real_decode), some_block); - } - - // Check testnet block 000000000000045e0b1660b6445b5e5c5ab63c9a4f956be7e1e69be04fa4497b - #[test] - fn segwit_block_test() { - let segwit_block = hex_decode("000000202aa2f2ca794ccbd40c16e2f3333f6b8b683f9e7179b2c4d7490600000000000010bc26e70a2f672ad420a6153dd0c28b40a6002c55531bfc99bf8994a8e8f67e5503bd5750d4061a4ed90a700f010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a3983704012000000000000000000000000000000000000000000000000000000000000000000000000001000000017e4f81175332a733e26d4ba4e29f53f67b7a5d7c2adebb276e447ca71d130b55000000006b483045022100cac809cd1a3d9ad5d5e31a84e2e1d8ec5542841e4d14c6b52e8b38cbe1ff1728022064470b7fb0c2efeccb2e84bfa36ec5f9e434c84b1101c00f7ee32f726371b7410121020e62280798b6b8c37f068df0915b0865b63fabc401c2457cbc3ef96887dd3647ffffffff02ca2f780c000000001976a914c6b5545b3592cb477d709896fa705592c9b6113a88ac663b2a06000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac0000000001000000011e99f5a785e677e017d36b50aa4fd10010ffd039f38f42f447ca8895250e121f01000000d90047304402200d3d296ad641a281dd5c0d68b9ab0d1ad5f7052bec148c1fb81fb1ba69181ec502201a372bb16fb8e054ee9bef41e300d292153830f841a4db0ab7f7407f6581b9bc01473044022002584f313ae990236b6bebb82fbbb006a2b02a448dd5c93434428991eae960d60220491d67d2660c4dde19025cf86e5164a559e2c79c3b98b40e146fab974acd24690147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9140ffdcf96700455074292a821c74922e8652993998788997bc60000000017a9148ce5408cfeaddb7ccb2545ded41ef478109454848700000000010000000113100b09e6a78d63ec4850654ab0f68806de29710b09172eddfef730652b155501000000da00473044022015389408e3446a3f36a05060e0e4a3c8b92ff3901ba2511aa944ec91a537a1cb022045a33b6ec47605b1718ed2e753263e54918edbf6126508ff039621fb928d28a001483045022100bb952fde81f216f7063575c0bb2bedc050ce08c96d9b437ea922f5eb98c882da02201b7cbf3a2f94ea4c5eb7f0df3af2ebcafa8705af7f410ab5d3d4bac13d6bc6120147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914d3db9a20312c3ab896a316eb108dbd01e47e17d687e0ba7ac60000000017a9148ce5408cfeaddb7ccb2545ded41ef47810945484870000000001000000016e3cca1599cde54878e2f27f434df69df0afd1f313cb6e38c08d3ffb57f97a6c01000000da0048304502210095623b70ec3194fa4037a1c1106c2580caedc390e25e5b330bbeb3111e8184bc02205ae973c4a4454be2a3a03beb66297143c1044a3c4743742c5cdd1d516a1ad3040147304402202f3d6d89996f5b42773dd6ebaf367f1af1f3a95c7c7b487ec040131c40f4a4a30220524ffbb0b563f37b3eb1341228f792e8f84111b7c4a9f49cdd998e052ee42efa0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9141ade6b95896dde8ec4dee9e59af8849d3797348e8728af7ac60000000017a9148ce5408cfeaddb7ccb2545ded41ef47810945484870000000001000000011d9dc3a5df9b5b2eeb2bd11a2db243be9e8cc23e2f180bf317d32a499904c15501000000db00483045022100ebbd1c9a8ce626edbb1a7881df81e872ef8c6424feda36faa8a5745157400c6a02206eb463bc8acd5ea06a289e86115e1daae0c2cf10d9cbbd199e1311170d5543ef01483045022100809411a917dc8cf4f3a777f0388fdea6de06243ef7691e500c60abd1c7f19ae602205255d2b1191d8adedb77b814ccb66471eb8486cb4ff8727824254ee5589f176b0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914759a49c772347be81c49517f9e1e6def6a88d4dd87800b85c60000000017a9148ce5408cfeaddb7ccb2545ded41ef47810945484870000000001000000018c51902affd8e5247dfcc2e5d0528a3815f53c8b6d2c200ff290b2b2b486d7704f0000006a47304402201be0d485f6a3ce871be80064c593c5327b3fd7e450f05ab7fae38385bc40cfbe02206e2a6c9970b5d1d10207892376733757486634fce4f352e772149c486857612101210350c33bc9a790c9495195761577b34912a949b73d5bc5ae5343f5ba08b33220ccffffffff0110270000000000001976a9142ab1c62710a7bdfdb4bb6394bbedc58b32b4d5a388ac0000000001000000018c51902affd8e5247dfcc2e5d0528a3815f53c8b6d2c200ff290b2b2b486d7704e0000006b483045022100ccc8c0ac90bdb0402842aec91830c765cdead7a728552a6a34de7d13a6dab28e02206c96f8640cf3444054e9632b197be30598a09c3d5defcd95750bdb922a60d64801210350c33bc9a790c9495195761577b34912a949b73d5bc5ae5343f5ba08b33220ccffffffff0110270000000000001976a9142ab1c62710a7bdfdb4bb6394bbedc58b32b4d5a388ac0000000001000000011b436669c06cbf3442e21a2fe3edc20cd3cf13c358c53234bc4d88bfd8c4bd2a000000006a47304402204a63410ee13db52c7609ab08e25b7fe3c608cc21cc1755ad13460685eb55193202204cd1ea80c06a81571119be0b8cccd96ef7cdd90f62c1fe2d538622feb08e22ba0121024baa8b67cc9ed8a97d90895e3716b25469b67cb26d3324d7aff213f507764765ffffffff010000000000000000306a2e516d64523365345261445653324d436a736e536171734a5753324465655446624238354541794a4d5843784c7934000000000100000001be4a95ed36316cada5118b1982e4cb4a07f93e7a4153e227466f1cb0776de995000000006b483045022100a22d5251deea0470806bab817013d675a63cd52218d6e477ab0c9d601d018b7f022042121b46afcdcd0c66f189398212b66085e88c6973ae560f1810c13e55e2bee40121024baa8b67cc9ed8a97d90895e3716b25469b67cb26d3324d7aff213f507764765ffffffff010000000000000000306a2e516d57484d57504e5248515872504c7338554c586b4d483746745356413675366b5a6b4a4e3851796e4e583751340000000001000000016c061a65b49edec21acdbc22f97dc853aa872302aeef13fabf0bf6807de1b8bd010000006b483045022100dd80381f2d158b4dad7f98d2d97317c533fb36e737542473feb05fa74d0b73bb02207097d4331196069167e525b61d132532292fd75cc039a5839c04c2545d427e2b0121035e9a597df8b417bef66811882a2844604fc591c427f642628f0fef46be19a4c9feffffff0280a4bf07000000001976a914573b9106e16ee0b5c143dc40f0724f77dd0e282088ac9533b22c000000001976a9149c4da607efb1d759d33da71778bc6cafa56acb5988acd31b0e0001000000017dae20994b69b28534e5b22f3d7c50f9d7541348cbf6f43fcc654263ebaf8f68000000006b483045022100a85300eb94b24b044877d0b0d61e08e16dbc82ec7d69c723a8a45519f95c35b002203d78376e6bee31b455c097557af7fe4d6b620bc74269e9a75e2aad2b545abddb012103b0d08aba2a5ac6cf2788fda941c386040e35e49d3a57d2aefb16c0438fb98acbfeffffff022222305f000000001976a914cfda30dd836b596db6a9c230c45ae2179107f04888ac80a4bf07000000001976a91442dfcf5823aacb185844e663873c35fb98bfd21b88acd31b0e000100000002ad3e85e4af30678a330f8941ed7a9ca17cd0236368d238cac4e9ff09c466fed1020000006b483045022100d1196c48a0392e09592f1b96b4aec32ab0cecb6fd17b1d0c85ab3250a2fe45d9022059217c82f684fcdecdbe660a2077ea956dfbbb964d2648bc1e8ae0f0fe565449012103b64e32e5f62e03701428fb1e3151e9a57f149c67708f6164a235c8199fe17cc2ffffffff34f0a71c1c2cd610522e9c18c67931cded5e9647d4419c49b99715e2a0795f3d020000006a4730440220316e81d8242abf3c5f885d200feca12c3adb63cf2cd4dc74602f7b8b0cba50340220210d525758df77ccdca6908311c1895275e07bbb29b45963a19252acde55873f012103b64e32e5f62e03701428fb1e3151e9a57f149c67708f6164a235c8199fe17cc2ffffffff0510270000000000001976a914449d2394dde057bc199f23fb8aa2e400f344611788ac10270000000000001976a914449d2394dde057bc199f23fb8aa2e400f344611788aca0860100000000001976a91413d35ad337dd80a055757e5ea0a45b59fee3060c88ac70110100000000001976a91413d35ad337dd80a055757e5ea0a45b59fee3060c88ac0000000000000000026a000000000001000000018e33fecc2ddbd86c5ea919f7bd5a5acf8a09f3e0cdaaaf4f08c5ef095161ef1100000000fdfe0000483045022100d2489b225d39b7d8b6767a6928c8029a2a1297c08fdf00d683ba0c1987e7d7000220176cb66c8a243806bb7421f658325a69a51c82c0c3314e37f2400f33626390210148304502210096cfa57662a545830d0e29610becd41ea031e256339913718ce18dbb1a27bdb00220482911c851d15adcd37097dff99a9ff1f97d953bcebc528835118f447412553e014c695221028d9889862b29430278c084b5c4090b7b807b31e047bcd212ebc2c4e43fc0e3c52103160949a7c8c81f2c25d7763f57eb1cb407d867c5b7c290331bd2dc4b1182c6d32103fbef3b60914bda9173765902013a251ec89450c75d0b5a96a143db1dabf98d9553aeffffffff0220e8891c0100000017a914d996715e081c50f8f6b1b4e7fb6ca214f9924fdf87809698000000000017a9145611d812263f32960228cb5f85329bce4770a218870000000001000000017720507dcbe6c69f652b0c0ce19406f482372d1a8abc05d45fb7acf97fb80eec00000000fdfe00004830450221009821d8e117de44b1202c829c0f5063997acf007cf9b561c6fb8d1212cddb6c40022010ff5067b0d9d4eca2da0ceb876e9a16f1a2142da866d3042a7bae8968813e8001483045022100dea759d14a8a1c5da5f3dcc5509871aaa2c1e3be03752c1b858d80fa4227163702205183d70cc28dcb6df9b037714c8b6442ef84e0ddce07711a30c731e9f0925090014c695221028d70ea66fe7a7def282df7b2b498007e5072933e42c18f63ce85975dcbcf1a8821037e8f842b1e47e21d88002c5aab2559212a4c2c9dbe5ef5347f2a29afd0510ec1210251259cb9fd4f6206488408286e4475c9c9fe887e57a3e32ae4da222778a2aedf53aeffffffff023380cb020000000017a9143b5a7e85b22656a34d43187ac8dd09acd7109d2487809698000000000017a914b9b4b555f594a34deec3ad61d5c5f3738b17ee158700000000").unwrap(); - - let decode: Result = deserialize(&segwit_block); - - let prevhash = hex_decode("2aa2f2ca794ccbd40c16e2f3333f6b8b683f9e7179b2c4d74906000000000000").unwrap(); - let merkle = hex_decode("10bc26e70a2f672ad420a6153dd0c28b40a6002c55531bfc99bf8994a8e8f67e").unwrap(); - - assert!(decode.is_ok()); - let real_decode = decode.unwrap(); - assert_eq!(real_decode.header.version, 0x20000000); // VERSIONBITS but no bits set - assert_eq!(serialize(&real_decode.header.prev_blockhash), prevhash); - assert_eq!(serialize(&real_decode.header.merkle_root), merkle); - assert_eq!(real_decode.header.merkle_root, real_decode.merkle_root()); - assert_eq!(real_decode.header.time, 1472004949); - assert_eq!(real_decode.header.bits, 0x1a06d450); - assert_eq!(real_decode.header.nonce, 1879759182); - // [test] TODO: check the transaction data - - assert!(real_decode.check_witness_commitment()); - - assert_eq!(serialize(&real_decode), segwit_block); - } - - #[test] - fn compact_roundrtip_test() { - let some_header = hex_decode("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b").unwrap(); - - let header: BlockHeader = deserialize(&some_header).expect("Can't deserialize correct block header"); - - assert_eq!(header.bits, BlockHeader::compact_target_from_u256(&header.target())); - } -} - diff --git a/src/blockdata/constants.rs b/src/blockdata/constants.rs deleted file mode 100644 index 23622918..00000000 --- a/src/blockdata/constants.rs +++ /dev/null @@ -1,207 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Blockdata constants -//! -//! This module provides various constants relating to the blockchain and -//! consensus code. In particular, it defines the genesis block and its -//! single transaction -//! - -use std::default::Default; - -use hashes::hex::FromHex; -use hashes::sha256d; -use blockdata::opcodes; -use blockdata::script; -use blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn}; -use blockdata::block::{Block, BlockHeader}; -use network::constants::Network; -use util::uint::Uint256; - -/// The maximum allowable sequence number -pub const MAX_SEQUENCE: u32 = 0xFFFFFFFF; -/// How many satoshis are in "one bitcoin" -pub const COIN_VALUE: u64 = 100_000_000; -/// How many seconds between blocks we expect on average -pub const TARGET_BLOCK_SPACING: u32 = 600; -/// How many blocks between diffchanges -pub const DIFFCHANGE_INTERVAL: u32 = 2016; -/// How much time on average should occur between diffchanges -pub const DIFFCHANGE_TIMESPAN: u32 = 14 * 24 * 3600; -/// The maximum allowed weight for a block, see BIP 141 (network rule) -pub const MAX_BLOCK_WEIGHT: u32 = 4_000_000; -/// The minimum transaction weight for a valid serialized transaction -pub const MIN_TRANSACTION_WEIGHT: u32 = 4 * 60; - - -/// In Bitcoind this is insanely described as ~((u256)0 >> 32) -pub fn max_target(_: Network) -> Uint256 { - Uint256::from_u64(0xFFFF).unwrap() << 208 -} - -/// The maximum value allowed in an output (useful for sanity checking, -/// since keeping everything below this value should prevent overflows -/// if you are doing anything remotely sane with monetary values). -pub fn max_money(_: Network) -> u64 { - 21_000_000 * COIN_VALUE -} - -/// Constructs and returns the coinbase (and only) transaction of the Bitcoin genesis block -fn bitcoin_genesis_tx() -> Transaction { - // Base - let mut ret = Transaction { - version: 1, - lock_time: 0, - input: vec![], - output: vec![], - }; - - // Inputs - let in_script = script::Builder::new().push_scriptint(486604799) - .push_scriptint(4) - .push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks") - .into_script(); - ret.input.push(TxIn { - previous_output: OutPoint::null(), - script_sig: in_script, - sequence: MAX_SEQUENCE, - witness: vec![], - }); - - // Outputs - let out_script = script::Builder::new() - .push_slice(&Vec::::from_hex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f").unwrap()) - .push_opcode(opcodes::all::OP_CHECKSIG) - .into_script(); - ret.output.push(TxOut { - value: 50 * COIN_VALUE, - script_pubkey: out_script - }); - - // end - ret -} - -/// Constructs and returns the genesis block -pub fn genesis_block(network: Network) -> Block { - let txdata = vec![bitcoin_genesis_tx()]; - let hash: sha256d::Hash = txdata[0].txid().into(); - let merkle_root = hash.into(); - match network { - Network::Bitcoin => { - Block { - header: BlockHeader { - version: 1, - prev_blockhash: Default::default(), - merkle_root, - time: 1231006505, - bits: 0x1d00ffff, - nonce: 2083236893 - }, - txdata: txdata - } - } - Network::Testnet => { - Block { - header: BlockHeader { - version: 1, - prev_blockhash: Default::default(), - merkle_root, - time: 1296688602, - bits: 0x1d00ffff, - nonce: 414098458 - }, - txdata: txdata - } - } - Network::Regtest => { - Block { - header: BlockHeader { - version: 1, - prev_blockhash: Default::default(), - merkle_root, - time: 1296688602, - bits: 0x207fffff, - nonce: 2 - }, - txdata: txdata - } - } - } -} - -#[cfg(test)] -mod test { - use std::default::Default; - use hex::decode as hex_decode; - - use network::constants::Network; - use consensus::encode::serialize; - use blockdata::constants::{genesis_block, bitcoin_genesis_tx}; - use blockdata::constants::{MAX_SEQUENCE, COIN_VALUE}; - use util::hash::BitcoinHash; - - #[test] - fn bitcoin_genesis_first_transaction() { - let gen = bitcoin_genesis_tx(); - - assert_eq!(gen.version, 1); - assert_eq!(gen.input.len(), 1); - assert_eq!(gen.input[0].previous_output.txid, Default::default()); - assert_eq!(gen.input[0].previous_output.vout, 0xFFFFFFFF); - assert_eq!(serialize(&gen.input[0].script_sig), - hex_decode("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73").unwrap()); - - assert_eq!(gen.input[0].sequence, MAX_SEQUENCE); - assert_eq!(gen.output.len(), 1); - assert_eq!(serialize(&gen.output[0].script_pubkey), - hex_decode("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac").unwrap()); - assert_eq!(gen.output[0].value, 50 * COIN_VALUE); - assert_eq!(gen.lock_time, 0); - - assert_eq!(format!("{:x}", gen.wtxid()), - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); - } - - #[test] - fn bitcoin_genesis_full_block() { - let gen = genesis_block(Network::Bitcoin); - - assert_eq!(gen.header.version, 1); - assert_eq!(gen.header.prev_blockhash, Default::default()); - assert_eq!(format!("{:x}", gen.header.merkle_root), - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); - assert_eq!(gen.header.time, 1231006505); - assert_eq!(gen.header.bits, 0x1d00ffff); - assert_eq!(gen.header.nonce, 2083236893); - assert_eq!(format!("{:x}", gen.header.bitcoin_hash()), - "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f".to_string()); - } - - #[test] - fn testnet_genesis_full_block() { - let gen = genesis_block(Network::Testnet); - assert_eq!(gen.header.version, 1); - assert_eq!(gen.header.prev_blockhash, Default::default()); - assert_eq!(format!("{:x}", gen.header.merkle_root), - "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b".to_string()); - assert_eq!(gen.header.time, 1296688602); - assert_eq!(gen.header.bits, 0x1d00ffff); - assert_eq!(gen.header.nonce, 414098458); - assert_eq!(format!("{:x}", gen.header.bitcoin_hash()), - "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943".to_string()); - } -} - diff --git a/src/blockdata/mod.rs b/src/blockdata/mod.rs deleted file mode 100644 index 4713b89c..00000000 --- a/src/blockdata/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Blockdata -//! -//! This module defines structures and functions for storing the blocks and -//! transactions which make up the Bitcoin system. -//! - -pub mod constants; -pub mod opcodes; -pub mod script; -pub mod transaction; -pub mod block; - diff --git a/src/blockdata/opcodes.rs b/src/blockdata/opcodes.rs deleted file mode 100644 index 724b16c2..00000000 --- a/src/blockdata/opcodes.rs +++ /dev/null @@ -1,1097 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Opcodes -//! -//! Bitcoin's script uses a stack-based assembly language. This module defines -//! all of the opcodes -//! - -#![allow(non_camel_case_types)] - -#[cfg(feature = "serde")] use serde; - -use std::fmt; - -// Note: I am deliberately not implementing PartialOrd or Ord on the -// opcode enum. If you want to check ranges of opcodes, etc., -// write an #[inline] helper function which casts to u8s. - -/// A script Opcode -#[derive(Copy, Clone, PartialEq, Eq)] -pub struct All { - code: u8, -} - -pub mod all { - //! Constants associated with All type - use super::All; - - /// Push an empty array onto the stack - pub const OP_PUSHBYTES_0: All = All {code: 0x00}; - /// Push the next byte as an array onto the stack - pub const OP_PUSHBYTES_1: All = All {code: 0x01}; - /// Push the next 2 bytes as an array onto the stack - pub const OP_PUSHBYTES_2: All = All {code: 0x02}; - /// Push the next 2 bytes as an array onto the stack - pub const OP_PUSHBYTES_3: All = All {code: 0x03}; - /// Push the next 4 bytes as an array onto the stack - pub const OP_PUSHBYTES_4: All = All {code: 0x04}; - /// Push the next 5 bytes as an array onto the stack - pub const OP_PUSHBYTES_5: All = All {code: 0x05}; - /// Push the next 6 bytes as an array onto the stack - pub const OP_PUSHBYTES_6: All = All {code: 0x06}; - /// Push the next 7 bytes as an array onto the stack - pub const OP_PUSHBYTES_7: All = All {code: 0x07}; - /// Push the next 8 bytes as an array onto the stack - pub const OP_PUSHBYTES_8: All = All {code: 0x08}; - /// Push the next 9 bytes as an array onto the stack - pub const OP_PUSHBYTES_9: All = All {code: 0x09}; - /// Push the next 10 bytes as an array onto the stack - pub const OP_PUSHBYTES_10: All = All {code: 0x0a}; - /// Push the next 11 bytes as an array onto the stack - pub const OP_PUSHBYTES_11: All = All {code: 0x0b}; - /// Push the next 12 bytes as an array onto the stack - pub const OP_PUSHBYTES_12: All = All {code: 0x0c}; - /// Push the next 13 bytes as an array onto the stack - pub const OP_PUSHBYTES_13: All = All {code: 0x0d}; - /// Push the next 14 bytes as an array onto the stack - pub const OP_PUSHBYTES_14: All = All {code: 0x0e}; - /// Push the next 15 bytes as an array onto the stack - pub const OP_PUSHBYTES_15: All = All {code: 0x0f}; - /// Push the next 16 bytes as an array onto the stack - pub const OP_PUSHBYTES_16: All = All {code: 0x10}; - /// Push the next 17 bytes as an array onto the stack - pub const OP_PUSHBYTES_17: All = All {code: 0x11}; - /// Push the next 18 bytes as an array onto the stack - pub const OP_PUSHBYTES_18: All = All {code: 0x12}; - /// Push the next 19 bytes as an array onto the stack - pub const OP_PUSHBYTES_19: All = All {code: 0x13}; - /// Push the next 20 bytes as an array onto the stack - pub const OP_PUSHBYTES_20: All = All {code: 0x14}; - /// Push the next 21 bytes as an array onto the stack - pub const OP_PUSHBYTES_21: All = All {code: 0x15}; - /// Push the next 22 bytes as an array onto the stack - pub const OP_PUSHBYTES_22: All = All {code: 0x16}; - /// Push the next 23 bytes as an array onto the stack - pub const OP_PUSHBYTES_23: All = All {code: 0x17}; - /// Push the next 24 bytes as an array onto the stack - pub const OP_PUSHBYTES_24: All = All {code: 0x18}; - /// Push the next 25 bytes as an array onto the stack - pub const OP_PUSHBYTES_25: All = All {code: 0x19}; - /// Push the next 26 bytes as an array onto the stack - pub const OP_PUSHBYTES_26: All = All {code: 0x1a}; - /// Push the next 27 bytes as an array onto the stack - pub const OP_PUSHBYTES_27: All = All {code: 0x1b}; - /// Push the next 28 bytes as an array onto the stack - pub const OP_PUSHBYTES_28: All = All {code: 0x1c}; - /// Push the next 29 bytes as an array onto the stack - pub const OP_PUSHBYTES_29: All = All {code: 0x1d}; - /// Push the next 30 bytes as an array onto the stack - pub const OP_PUSHBYTES_30: All = All {code: 0x1e}; - /// Push the next 31 bytes as an array onto the stack - pub const OP_PUSHBYTES_31: All = All {code: 0x1f}; - /// Push the next 32 bytes as an array onto the stack - pub const OP_PUSHBYTES_32: All = All {code: 0x20}; - /// Push the next 33 bytes as an array onto the stack - pub const OP_PUSHBYTES_33: All = All {code: 0x21}; - /// Push the next 34 bytes as an array onto the stack - pub const OP_PUSHBYTES_34: All = All {code: 0x22}; - /// Push the next 35 bytes as an array onto the stack - pub const OP_PUSHBYTES_35: All = All {code: 0x23}; - /// Push the next 36 bytes as an array onto the stack - pub const OP_PUSHBYTES_36: All = All {code: 0x24}; - /// Push the next 37 bytes as an array onto the stack - pub const OP_PUSHBYTES_37: All = All {code: 0x25}; - /// Push the next 38 bytes as an array onto the stack - pub const OP_PUSHBYTES_38: All = All {code: 0x26}; - /// Push the next 39 bytes as an array onto the stack - pub const OP_PUSHBYTES_39: All = All {code: 0x27}; - /// Push the next 40 bytes as an array onto the stack - pub const OP_PUSHBYTES_40: All = All {code: 0x28}; - /// Push the next 41 bytes as an array onto the stack - pub const OP_PUSHBYTES_41: All = All {code: 0x29}; - /// Push the next 42 bytes as an array onto the stack - pub const OP_PUSHBYTES_42: All = All {code: 0x2a}; - /// Push the next 43 bytes as an array onto the stack - pub const OP_PUSHBYTES_43: All = All {code: 0x2b}; - /// Push the next 44 bytes as an array onto the stack - pub const OP_PUSHBYTES_44: All = All {code: 0x2c}; - /// Push the next 45 bytes as an array onto the stack - pub const OP_PUSHBYTES_45: All = All {code: 0x2d}; - /// Push the next 46 bytes as an array onto the stack - pub const OP_PUSHBYTES_46: All = All {code: 0x2e}; - /// Push the next 47 bytes as an array onto the stack - pub const OP_PUSHBYTES_47: All = All {code: 0x2f}; - /// Push the next 48 bytes as an array onto the stack - pub const OP_PUSHBYTES_48: All = All {code: 0x30}; - /// Push the next 49 bytes as an array onto the stack - pub const OP_PUSHBYTES_49: All = All {code: 0x31}; - /// Push the next 50 bytes as an array onto the stack - pub const OP_PUSHBYTES_50: All = All {code: 0x32}; - /// Push the next 51 bytes as an array onto the stack - pub const OP_PUSHBYTES_51: All = All {code: 0x33}; - /// Push the next 52 bytes as an array onto the stack - pub const OP_PUSHBYTES_52: All = All {code: 0x34}; - /// Push the next 53 bytes as an array onto the stack - pub const OP_PUSHBYTES_53: All = All {code: 0x35}; - /// Push the next 54 bytes as an array onto the stack - pub const OP_PUSHBYTES_54: All = All {code: 0x36}; - /// Push the next 55 bytes as an array onto the stack - pub const OP_PUSHBYTES_55: All = All {code: 0x37}; - /// Push the next 56 bytes as an array onto the stack - pub const OP_PUSHBYTES_56: All = All {code: 0x38}; - /// Push the next 57 bytes as an array onto the stack - pub const OP_PUSHBYTES_57: All = All {code: 0x39}; - /// Push the next 58 bytes as an array onto the stack - pub const OP_PUSHBYTES_58: All = All {code: 0x3a}; - /// Push the next 59 bytes as an array onto the stack - pub const OP_PUSHBYTES_59: All = All {code: 0x3b}; - /// Push the next 60 bytes as an array onto the stack - pub const OP_PUSHBYTES_60: All = All {code: 0x3c}; - /// Push the next 61 bytes as an array onto the stack - pub const OP_PUSHBYTES_61: All = All {code: 0x3d}; - /// Push the next 62 bytes as an array onto the stack - pub const OP_PUSHBYTES_62: All = All {code: 0x3e}; - /// Push the next 63 bytes as an array onto the stack - pub const OP_PUSHBYTES_63: All = All {code: 0x3f}; - /// Push the next 64 bytes as an array onto the stack - pub const OP_PUSHBYTES_64: All = All {code: 0x40}; - /// Push the next 65 bytes as an array onto the stack - pub const OP_PUSHBYTES_65: All = All {code: 0x41}; - /// Push the next 66 bytes as an array onto the stack - pub const OP_PUSHBYTES_66: All = All {code: 0x42}; - /// Push the next 67 bytes as an array onto the stack - pub const OP_PUSHBYTES_67: All = All {code: 0x43}; - /// Push the next 68 bytes as an array onto the stack - pub const OP_PUSHBYTES_68: All = All {code: 0x44}; - /// Push the next 69 bytes as an array onto the stack - pub const OP_PUSHBYTES_69: All = All {code: 0x45}; - /// Push the next 70 bytes as an array onto the stack - pub const OP_PUSHBYTES_70: All = All {code: 0x46}; - /// Push the next 71 bytes as an array onto the stack - pub const OP_PUSHBYTES_71: All = All {code: 0x47}; - /// Push the next 72 bytes as an array onto the stack - pub const OP_PUSHBYTES_72: All = All {code: 0x48}; - /// Push the next 73 bytes as an array onto the stack - pub const OP_PUSHBYTES_73: All = All {code: 0x49}; - /// Push the next 74 bytes as an array onto the stack - pub const OP_PUSHBYTES_74: All = All {code: 0x4a}; - /// Push the next 75 bytes as an array onto the stack - pub const OP_PUSHBYTES_75: All = All {code: 0x4b}; - /// Read the next byte as N; push the next N bytes as an array onto the stack - pub const OP_PUSHDATA1: All = All {code: 0x4c}; - /// Read the next 2 bytes as N; push the next N bytes as an array onto the stack - pub const OP_PUSHDATA2: All = All {code: 0x4d}; - /// Read the next 4 bytes as N; push the next N bytes as an array onto the stack - pub const OP_PUSHDATA4: All = All {code: 0x4e}; - /// Push the array [0x81] onto the stack - pub const OP_PUSHNUM_NEG1: All = All {code: 0x4f}; - /// Synonym for OP_RETURN - pub const OP_RESERVED: All = All {code: 0x50}; - /// Push the array [0x01] onto the stack - pub const OP_PUSHNUM_1: All = All {code: 0x51}; - /// Push the array [0x02] onto the stack - pub const OP_PUSHNUM_2: All = All {code: 0x52}; - /// Push the array [0x03] onto the stack - pub const OP_PUSHNUM_3: All = All {code: 0x53}; - /// Push the array [0x04] onto the stack - pub const OP_PUSHNUM_4: All = All {code: 0x54}; - /// Push the array [0x05] onto the stack - pub const OP_PUSHNUM_5: All = All {code: 0x55}; - /// Push the array [0x06] onto the stack - pub const OP_PUSHNUM_6: All = All {code: 0x56}; - /// Push the array [0x07] onto the stack - pub const OP_PUSHNUM_7: All = All {code: 0x57}; - /// Push the array [0x08] onto the stack - pub const OP_PUSHNUM_8: All = All {code: 0x58}; - /// Push the array [0x09] onto the stack - pub const OP_PUSHNUM_9: All = All {code: 0x59}; - /// Push the array [0x0a] onto the stack - pub const OP_PUSHNUM_10: All = All {code: 0x5a}; - /// Push the array [0x0b] onto the stack - pub const OP_PUSHNUM_11: All = All {code: 0x5b}; - /// Push the array [0x0c] onto the stack - pub const OP_PUSHNUM_12: All = All {code: 0x5c}; - /// Push the array [0x0d] onto the stack - pub const OP_PUSHNUM_13: All = All {code: 0x5d}; - /// Push the array [0x0e] onto the stack - pub const OP_PUSHNUM_14: All = All {code: 0x5e}; - /// Push the array [0x0f] onto the stack - pub const OP_PUSHNUM_15: All = All {code: 0x5f}; - /// Push the array [0x10] onto the stack - pub const OP_PUSHNUM_16: All = All {code: 0x60}; - /// Does nothing - pub const OP_NOP: All = All {code: 0x61}; - /// Synonym for OP_RETURN - pub const OP_VER: All = All {code: 0x62}; - /// Pop and execute the next statements if a nonzero element was popped - pub const OP_IF: All = All {code: 0x63}; - /// Pop and execute the next statements if a zero element was popped - pub const OP_NOTIF: All = All {code: 0x64}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_VERIF: All = All {code: 0x65}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_VERNOTIF: All = All {code: 0x66}; - /// Execute statements if those after the previous OP_IF were not, and vice-versa. - /// If there is no previous OP_IF, this acts as a RETURN. - pub const OP_ELSE: All = All {code: 0x67}; - /// Pop and execute the next statements if a zero element was popped - pub const OP_ENDIF: All = All {code: 0x68}; - /// If the top value is zero or the stack is empty, fail; otherwise, pop the stack - pub const OP_VERIFY: All = All {code: 0x69}; - /// Fail the script immediately. (Must be executed.) - pub const OP_RETURN: All = All {code: 0x6a}; - /// Pop one element from the main stack onto the alt stack - pub const OP_TOALTSTACK: All = All {code: 0x6b}; - /// Pop one element from the alt stack onto the main stack - pub const OP_FROMALTSTACK: All = All {code: 0x6c}; - /// Drops the top two stack items - pub const OP_2DROP: All = All {code: 0x6d}; - /// Duplicates the top two stack items as AB -> ABAB - pub const OP_2DUP: All = All {code: 0x6e}; - /// Duplicates the two three stack items as ABC -> ABCABC - pub const OP_3DUP: All = All {code: 0x6f}; - /// Copies the two stack items of items two spaces back to - /// the front, as xxAB -> ABxxAB - pub const OP_2OVER: All = All {code: 0x70}; - /// Moves the two stack items four spaces back to the front, - /// as xxxxAB -> ABxxxx - pub const OP_2ROT: All = All {code: 0x71}; - /// Swaps the top two pairs, as ABCD -> CDAB - pub const OP_2SWAP: All = All {code: 0x72}; - /// Duplicate the top stack element unless it is zero - pub const OP_IFDUP: All = All {code: 0x73}; - /// Push the current number of stack items onto the stack - pub const OP_DEPTH: All = All {code: 0x74}; - /// Drops the top stack item - pub const OP_DROP: All = All {code: 0x75}; - /// Duplicates the top stack item - pub const OP_DUP: All = All {code: 0x76}; - /// Drops the second-to-top stack item - pub const OP_NIP: All = All {code: 0x77}; - /// Copies the second-to-top stack item, as xA -> AxA - pub const OP_OVER: All = All {code: 0x78}; - /// Pop the top stack element as N. Copy the Nth stack element to the top - pub const OP_PICK: All = All {code: 0x79}; - /// Pop the top stack element as N. Move the Nth stack element to the top - pub const OP_ROLL: All = All {code: 0x7a}; - /// Rotate the top three stack items, as [top next1 next2] -> [next2 top next1] - pub const OP_ROT: All = All {code: 0x7b}; - /// Swap the top two stack items - pub const OP_SWAP: All = All {code: 0x7c}; - /// Copy the top stack item to before the second item, as [top next] -> [top next top] - pub const OP_TUCK: All = All {code: 0x7d}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_CAT: All = All {code: 0x7e}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_SUBSTR: All = All {code: 0x7f}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_LEFT: All = All {code: 0x80}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_RIGHT: All = All {code: 0x81}; - /// Pushes the length of the top stack item onto the stack - pub const OP_SIZE: All = All {code: 0x82}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_INVERT: All = All {code: 0x83}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_AND: All = All {code: 0x84}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_OR: All = All {code: 0x85}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_XOR: All = All {code: 0x86}; - /// Pushes 1 if the inputs are exactly equal, 0 otherwise - pub const OP_EQUAL: All = All {code: 0x87}; - /// Returns success if the inputs are exactly equal, failure otherwise - pub const OP_EQUALVERIFY: All = All {code: 0x88}; - /// Synonym for OP_RETURN - pub const OP_RESERVED1: All = All {code: 0x89}; - /// Synonym for OP_RETURN - pub const OP_RESERVED2: All = All {code: 0x8a}; - /// Increment the top stack element in place - pub const OP_1ADD: All = All {code: 0x8b}; - /// Decrement the top stack element in place - pub const OP_1SUB: All = All {code: 0x8c}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_2MUL: All = All {code: 0x8d}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_2DIV: All = All {code: 0x8e}; - /// Multiply the top stack item by -1 in place - pub const OP_NEGATE: All = All {code: 0x8f}; - /// Absolute value the top stack item in place - pub const OP_ABS: All = All {code: 0x90}; - /// Map 0 to 1 and everything else to 0, in place - pub const OP_NOT: All = All {code: 0x91}; - /// Map 0 to 0 and everything else to 1, in place - pub const OP_0NOTEQUAL: All = All {code: 0x92}; - /// Pop two stack items and push their sum - pub const OP_ADD: All = All {code: 0x93}; - /// Pop two stack items and push the second minus the top - pub const OP_SUB: All = All {code: 0x94}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_MUL: All = All {code: 0x95}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_DIV: All = All {code: 0x96}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_MOD: All = All {code: 0x97}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_LSHIFT: All = All {code: 0x98}; - /// Fail the script unconditionally, does not even need to be executed - pub const OP_RSHIFT: All = All {code: 0x99}; - /// Pop the top two stack items and push 1 if both are nonzero, else push 0 - pub const OP_BOOLAND: All = All {code: 0x9a}; - /// Pop the top two stack items and push 1 if either is nonzero, else push 0 - pub const OP_BOOLOR: All = All {code: 0x9b}; - /// Pop the top two stack items and push 1 if both are numerically equal, else push 0 - pub const OP_NUMEQUAL: All = All {code: 0x9c}; - /// Pop the top two stack items and return success if both are numerically equal, else return failure - pub const OP_NUMEQUALVERIFY: All = All {code: 0x9d}; - /// Pop the top two stack items and push 0 if both are numerically equal, else push 1 - pub const OP_NUMNOTEQUAL: All = All {code: 0x9e}; - /// Pop the top two items; push 1 if the second is less than the top, 0 otherwise - pub const OP_LESSTHAN : All = All {code: 0x9f}; - /// Pop the top two items; push 1 if the second is greater than the top, 0 otherwise - pub const OP_GREATERTHAN : All = All {code: 0xa0}; - /// Pop the top two items; push 1 if the second is <= the top, 0 otherwise - pub const OP_LESSTHANOREQUAL : All = All {code: 0xa1}; - /// Pop the top two items; push 1 if the second is >= the top, 0 otherwise - pub const OP_GREATERTHANOREQUAL : All = All {code: 0xa2}; - /// Pop the top two items; push the smaller - pub const OP_MIN: All = All {code: 0xa3}; - /// Pop the top two items; push the larger - pub const OP_MAX: All = All {code: 0xa4}; - /// Pop the top three items; if the top is >= the second and < the third, push 1, otherwise push 0 - pub const OP_WITHIN: All = All {code: 0xa5}; - /// Pop the top stack item and push its RIPEMD160 hash - pub const OP_RIPEMD160: All = All {code: 0xa6}; - /// Pop the top stack item and push its SHA1 hash - pub const OP_SHA1: All = All {code: 0xa7}; - /// Pop the top stack item and push its SHA256 hash - pub const OP_SHA256: All = All {code: 0xa8}; - /// Pop the top stack item and push its RIPEMD(SHA256) hash - pub const OP_HASH160: All = All {code: 0xa9}; - /// Pop the top stack item and push its SHA256(SHA256) hash - pub const OP_HASH256: All = All {code: 0xaa}; - /// Ignore this and everything preceding when deciding what to sign when signature-checking - pub const OP_CODESEPARATOR: All = All {code: 0xab}; - /// https://en.bitcoin.it/wiki/OP_CHECKSIG pushing 1/0 for success/failure - pub const OP_CHECKSIG: All = All {code: 0xac}; - /// https://en.bitcoin.it/wiki/OP_CHECKSIG returning success/failure - pub const OP_CHECKSIGVERIFY: All = All {code: 0xad}; - /// Pop N, N pubkeys, M, M signatures, a dummy (due to bug in reference code), and verify that all M signatures are valid. - /// Push 1 for "all valid", 0 otherwise - pub const OP_CHECKMULTISIG: All = All {code: 0xae}; - /// Like the above but return success/failure - pub const OP_CHECKMULTISIGVERIFY: All = All {code: 0xaf}; - /// Does nothing - pub const OP_NOP1: All = All {code: 0xb0}; - /// https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki - pub const OP_CLTV: All = All {code: 0xb1}; - /// https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki - pub const OP_CSV: All = All {code: 0xb2}; - /// Does nothing - pub const OP_NOP4: All = All {code: 0xb3}; - /// Does nothing - pub const OP_NOP5: All = All {code: 0xb4}; - /// Does nothing - pub const OP_NOP6: All = All {code: 0xb5}; - /// Does nothing - pub const OP_NOP7: All = All {code: 0xb6}; - /// Does nothing - pub const OP_NOP8: All = All {code: 0xb7}; - /// Does nothing - pub const OP_NOP9: All = All {code: 0xb8}; - /// Does nothing - pub const OP_NOP10: All = All {code: 0xb9}; - // Every other opcode acts as OP_RETURN - /// Synonym for OP_RETURN - pub const OP_RETURN_186: All = All {code: 0xba}; - /// Synonym for OP_RETURN - pub const OP_RETURN_187: All = All {code: 0xbb}; - /// Synonym for OP_RETURN - pub const OP_RETURN_188: All = All {code: 0xbc}; - /// Synonym for OP_RETURN - pub const OP_RETURN_189: All = All {code: 0xbd}; - /// Synonym for OP_RETURN - pub const OP_RETURN_190: All = All {code: 0xbe}; - /// Synonym for OP_RETURN - pub const OP_RETURN_191: All = All {code: 0xbf}; - /// Synonym for OP_RETURN - pub const OP_RETURN_192: All = All {code: 0xc0}; - /// Synonym for OP_RETURN - pub const OP_RETURN_193: All = All {code: 0xc1}; - /// Synonym for OP_RETURN - pub const OP_RETURN_194: All = All {code: 0xc2}; - /// Synonym for OP_RETURN - pub const OP_RETURN_195: All = All {code: 0xc3}; - /// Synonym for OP_RETURN - pub const OP_RETURN_196: All = All {code: 0xc4}; - /// Synonym for OP_RETURN - pub const OP_RETURN_197: All = All {code: 0xc5}; - /// Synonym for OP_RETURN - pub const OP_RETURN_198: All = All {code: 0xc6}; - /// Synonym for OP_RETURN - pub const OP_RETURN_199: All = All {code: 0xc7}; - /// Synonym for OP_RETURN - pub const OP_RETURN_200: All = All {code: 0xc8}; - /// Synonym for OP_RETURN - pub const OP_RETURN_201: All = All {code: 0xc9}; - /// Synonym for OP_RETURN - pub const OP_RETURN_202: All = All {code: 0xca}; - /// Synonym for OP_RETURN - pub const OP_RETURN_203: All = All {code: 0xcb}; - /// Synonym for OP_RETURN - pub const OP_RETURN_204: All = All {code: 0xcc}; - /// Synonym for OP_RETURN - pub const OP_RETURN_205: All = All {code: 0xcd}; - /// Synonym for OP_RETURN - pub const OP_RETURN_206: All = All {code: 0xce}; - /// Synonym for OP_RETURN - pub const OP_RETURN_207: All = All {code: 0xcf}; - /// Synonym for OP_RETURN - pub const OP_RETURN_208: All = All {code: 0xd0}; - /// Synonym for OP_RETURN - pub const OP_RETURN_209: All = All {code: 0xd1}; - /// Synonym for OP_RETURN - pub const OP_RETURN_210: All = All {code: 0xd2}; - /// Synonym for OP_RETURN - pub const OP_RETURN_211: All = All {code: 0xd3}; - /// Synonym for OP_RETURN - pub const OP_RETURN_212: All = All {code: 0xd4}; - /// Synonym for OP_RETURN - pub const OP_RETURN_213: All = All {code: 0xd5}; - /// Synonym for OP_RETURN - pub const OP_RETURN_214: All = All {code: 0xd6}; - /// Synonym for OP_RETURN - pub const OP_RETURN_215: All = All {code: 0xd7}; - /// Synonym for OP_RETURN - pub const OP_RETURN_216: All = All {code: 0xd8}; - /// Synonym for OP_RETURN - pub const OP_RETURN_217: All = All {code: 0xd9}; - /// Synonym for OP_RETURN - pub const OP_RETURN_218: All = All {code: 0xda}; - /// Synonym for OP_RETURN - pub const OP_RETURN_219: All = All {code: 0xdb}; - /// Synonym for OP_RETURN - pub const OP_RETURN_220: All = All {code: 0xdc}; - /// Synonym for OP_RETURN - pub const OP_RETURN_221: All = All {code: 0xdd}; - /// Synonym for OP_RETURN - pub const OP_RETURN_222: All = All {code: 0xde}; - /// Synonym for OP_RETURN - pub const OP_RETURN_223: All = All {code: 0xdf}; - /// Synonym for OP_RETURN - pub const OP_RETURN_224: All = All {code: 0xe0}; - /// Synonym for OP_RETURN - pub const OP_RETURN_225: All = All {code: 0xe1}; - /// Synonym for OP_RETURN - pub const OP_RETURN_226: All = All {code: 0xe2}; - /// Synonym for OP_RETURN - pub const OP_RETURN_227: All = All {code: 0xe3}; - /// Synonym for OP_RETURN - pub const OP_RETURN_228: All = All {code: 0xe4}; - /// Synonym for OP_RETURN - pub const OP_RETURN_229: All = All {code: 0xe5}; - /// Synonym for OP_RETURN - pub const OP_RETURN_230: All = All {code: 0xe6}; - /// Synonym for OP_RETURN - pub const OP_RETURN_231: All = All {code: 0xe7}; - /// Synonym for OP_RETURN - pub const OP_RETURN_232: All = All {code: 0xe8}; - /// Synonym for OP_RETURN - pub const OP_RETURN_233: All = All {code: 0xe9}; - /// Synonym for OP_RETURN - pub const OP_RETURN_234: All = All {code: 0xea}; - /// Synonym for OP_RETURN - pub const OP_RETURN_235: All = All {code: 0xeb}; - /// Synonym for OP_RETURN - pub const OP_RETURN_236: All = All {code: 0xec}; - /// Synonym for OP_RETURN - pub const OP_RETURN_237: All = All {code: 0xed}; - /// Synonym for OP_RETURN - pub const OP_RETURN_238: All = All {code: 0xee}; - /// Synonym for OP_RETURN - pub const OP_RETURN_239: All = All {code: 0xef}; - /// Synonym for OP_RETURN - pub const OP_RETURN_240: All = All {code: 0xf0}; - /// Synonym for OP_RETURN - pub const OP_RETURN_241: All = All {code: 0xf1}; - /// Synonym for OP_RETURN - pub const OP_RETURN_242: All = All {code: 0xf2}; - /// Synonym for OP_RETURN - pub const OP_RETURN_243: All = All {code: 0xf3}; - /// Synonym for OP_RETURN - pub const OP_RETURN_244: All = All {code: 0xf4}; - /// Synonym for OP_RETURN - pub const OP_RETURN_245: All = All {code: 0xf5}; - /// Synonym for OP_RETURN - pub const OP_RETURN_246: All = All {code: 0xf6}; - /// Synonym for OP_RETURN - pub const OP_RETURN_247: All = All {code: 0xf7}; - /// Synonym for OP_RETURN - pub const OP_RETURN_248: All = All {code: 0xf8}; - /// Synonym for OP_RETURN - pub const OP_RETURN_249: All = All {code: 0xf9}; - /// Synonym for OP_RETURN - pub const OP_RETURN_250: All = All {code: 0xfa}; - /// Synonym for OP_RETURN - pub const OP_RETURN_251: All = All {code: 0xfb}; - /// Synonym for OP_RETURN - pub const OP_RETURN_252: All = All {code: 0xfc}; - /// Synonym for OP_RETURN - pub const OP_RETURN_253: All = All {code: 0xfd}; - /// Synonym for OP_RETURN - pub const OP_RETURN_254: All = All {code: 0xfe}; - /// Synonym for OP_RETURN - pub const OP_RETURN_255: All = All {code: 0xff}; -} - -impl fmt::Debug for All { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("OP_")?; - match *self { - All {code: x} if x <= 75 => write!(f, "PUSHBYTES_{}", self.code), - all::OP_PUSHDATA1 => write!(f, "PUSHDATA1"), - all::OP_PUSHDATA2 => write!(f, "PUSHDATA2"), - all::OP_PUSHDATA4 => write!(f, "PUSHDATA4"), - all::OP_PUSHNUM_NEG1 => write!(f, "PUSHNUM_NEG1"), - all::OP_RESERVED => write!(f, "RESERVED"), - All {code: x} if x >= all::OP_PUSHNUM_1.code && x <= all::OP_PUSHNUM_16.code => write!(f, "PUSHNUM_{}", x - all::OP_PUSHNUM_1.code + 1), - all::OP_NOP => write!(f, "NOP"), - all::OP_VER => write!(f, "VER"), - all::OP_IF => write!(f, "IF"), - all::OP_NOTIF => write!(f, "NOTIF"), - all::OP_VERIF => write!(f, "VERIF"), - all::OP_VERNOTIF => write!(f, "VERNOTIF"), - all::OP_ELSE => write!(f, "ELSE"), - all::OP_ENDIF => write!(f, "ENDIF"), - all::OP_VERIFY => write!(f, "VERIFY"), - all::OP_RETURN => write!(f, "RETURN"), - all::OP_TOALTSTACK => write!(f, "TOALTSTACK"), - all::OP_FROMALTSTACK => write!(f, "FROMALTSTACK"), - all::OP_2DROP => write!(f, "2DROP"), - all::OP_2DUP => write!(f, "2DUP"), - all::OP_3DUP => write!(f, "3DUP"), - all::OP_2OVER => write!(f, "2OVER"), - all::OP_2ROT => write!(f, "2ROT"), - all::OP_2SWAP => write!(f, "2SWAP"), - all::OP_IFDUP => write!(f, "IFDUP"), - all::OP_DEPTH => write!(f, "DEPTH"), - all::OP_DROP => write!(f, "DROP"), - all::OP_DUP => write!(f, "DUP"), - all::OP_NIP => write!(f, "NIP"), - all::OP_OVER => write!(f, "OVER"), - all::OP_PICK => write!(f, "PICK"), - all::OP_ROLL => write!(f, "ROLL"), - all::OP_ROT => write!(f, "ROT"), - all::OP_SWAP => write!(f, "SWAP"), - all::OP_TUCK => write!(f, "TUCK"), - all::OP_CAT => write!(f, "CAT"), - all::OP_SUBSTR => write!(f, "SUBSTR"), - all::OP_LEFT => write!(f, "LEFT"), - all::OP_RIGHT => write!(f, "RIGHT"), - all::OP_SIZE => write!(f, "SIZE"), - all::OP_INVERT => write!(f, "INVERT"), - all::OP_AND => write!(f, "AND"), - all::OP_OR => write!(f, "OR"), - all::OP_XOR => write!(f, "XOR"), - all::OP_EQUAL => write!(f, "EQUAL"), - all::OP_EQUALVERIFY => write!(f, "EQUALVERIFY"), - all::OP_RESERVED1 => write!(f, "RESERVED1"), - all::OP_RESERVED2 => write!(f, "RESERVED2"), - all::OP_1ADD => write!(f, "1ADD"), - all::OP_1SUB => write!(f, "1SUB"), - all::OP_2MUL => write!(f, "2MUL"), - all::OP_2DIV => write!(f, "2DIV"), - all::OP_NEGATE => write!(f, "NEGATE"), - all::OP_ABS => write!(f, "ABS"), - all::OP_NOT => write!(f, "NOT"), - all::OP_0NOTEQUAL => write!(f, "0NOTEQUAL"), - all::OP_ADD => write!(f, "ADD"), - all::OP_SUB => write!(f, "SUB"), - all::OP_MUL => write!(f, "MUL"), - all::OP_DIV => write!(f, "DIV"), - all::OP_MOD => write!(f, "MOD"), - all::OP_LSHIFT => write!(f, "LSHIFT"), - all::OP_RSHIFT => write!(f, "RSHIFT"), - all::OP_BOOLAND => write!(f, "BOOLAND"), - all::OP_BOOLOR => write!(f, "BOOLOR"), - all::OP_NUMEQUAL => write!(f, "NUMEQUAL"), - all::OP_NUMEQUALVERIFY => write!(f, "NUMEQUALVERIFY"), - all::OP_NUMNOTEQUAL => write!(f, "NUMNOTEQUAL"), - all::OP_LESSTHAN => write!(f, "LESSTHAN"), - all::OP_GREATERTHAN => write!(f, "GREATERTHAN"), - all::OP_LESSTHANOREQUAL => write!(f, "LESSTHANOREQUAL"), - all::OP_GREATERTHANOREQUAL => write!(f, "GREATERTHANOREQUAL"), - all::OP_MIN => write!(f, "MIN"), - all::OP_MAX => write!(f, "MAX"), - all::OP_WITHIN => write!(f, "WITHIN"), - all::OP_RIPEMD160 => write!(f, "RIPEMD160"), - all::OP_SHA1 => write!(f, "SHA1"), - all::OP_SHA256 => write!(f, "SHA256"), - all::OP_HASH160 => write!(f, "HASH160"), - all::OP_HASH256 => write!(f, "HASH256"), - all::OP_CODESEPARATOR => write!(f, "CODESEPARATOR"), - all::OP_CHECKSIG => write!(f, "CHECKSIG"), - all::OP_CHECKSIGVERIFY => write!(f, "CHECKSIGVERIFY"), - all::OP_CHECKMULTISIG => write!(f, "CHECKMULTISIG"), - all::OP_CHECKMULTISIGVERIFY => write!(f, "CHECKMULTISIGVERIFY"), - all::OP_CLTV => write!(f, "CLTV"), - all::OP_CSV => write!(f, "CSV"), - All {code: x} if x >= all::OP_NOP1.code && x <= all::OP_NOP10.code => write!(f, "NOP{}", x - all::OP_NOP1.code + 1), - All {code: x} => write!(f, "RETURN_{}", x), - } - } -} - -impl All { - /// Classifies an Opcode into a broad class - #[inline] - pub fn classify(&self) -> Class { - // 17 opcodes - if *self == all::OP_VERIF || *self == all::OP_VERNOTIF || - *self == all::OP_CAT || *self == all::OP_SUBSTR || - *self == all::OP_LEFT || *self == all::OP_RIGHT || - *self == all::OP_INVERT || *self == all::OP_AND || - *self == all::OP_OR || *self == all::OP_XOR || - *self == all::OP_2MUL || *self == all::OP_2DIV || - *self == all::OP_MUL || *self == all::OP_DIV || *self == all::OP_MOD || - *self == all::OP_LSHIFT || *self == all::OP_RSHIFT { - Class::IllegalOp - // 11 opcodes - } else if *self == all::OP_NOP || - (all::OP_NOP1.code <= self.code && - self.code <= all::OP_NOP10.code) { - Class::NoOp - // 75 opcodes - } else if *self == all::OP_RESERVED || *self == all::OP_VER || *self == all::OP_RETURN || - *self == all::OP_RESERVED1 || *self == all::OP_RESERVED2 || - self.code >= all::OP_RETURN_186.code { - Class::ReturnOp - // 1 opcode - } else if *self == all::OP_PUSHNUM_NEG1 { - Class::PushNum(-1) - // 16 opcodes - } else if all::OP_PUSHNUM_1.code <= self.code && - self.code <= all::OP_PUSHNUM_16.code { - Class::PushNum(1 + self.code as i32 - all::OP_PUSHNUM_1.code as i32) - // 76 opcodes - } else if self.code <= all::OP_PUSHBYTES_75.code { - Class::PushBytes(self.code as u32) - // 60 opcodes - } else { - Class::Ordinary(Ordinary::try_from_all(*self).unwrap()) - } - } - - /// Encode as a byte - #[inline] - pub fn into_u8(&self) -> u8 { - self.code - } -} - -impl From for All { - #[inline] - fn from(b: u8) -> All { - All {code: b} - } -} - - -display_from_debug!(All); - -#[cfg(feature = "serde")] -impl serde::Serialize for All { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -/// Empty stack is also FALSE -pub static OP_FALSE: All = all::OP_PUSHBYTES_0; -/// Number 1 is also TRUE -pub static OP_TRUE: All = all::OP_PUSHNUM_1; -/// previously called OP_NOP2 -pub static OP_NOP2: All = all::OP_CLTV; -/// previously called OP_NOP3 -pub static OP_NOP3: All = all::OP_CSV; - -/// Broad categories of opcodes with similar behavior -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum Class { - /// Pushes the given number onto the stack - PushNum(i32), - /// Pushes the given number of bytes onto the stack - PushBytes(u32), - /// Fails the script if executed - ReturnOp, - /// Fails the script even if not executed - IllegalOp, - /// Does nothing - NoOp, - /// Any opcode not covered above - Ordinary(Ordinary) -} - -display_from_debug!(Class); - -#[cfg(feature = "serde")] -impl serde::Serialize for Class { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&self.to_string()) - } -} - -macro_rules! ordinary_opcode { - ($($op:ident),*) => ( - #[repr(u8)] - #[doc(hidden)] - #[derive(Copy, Clone, PartialEq, Eq, Debug)] - pub enum Ordinary { - $( $op = all::$op.code ),* - } - - impl Ordinary { - /// Try to create from an All - pub fn try_from_all(b: All) -> Option { - match b { - $( all::$op => { Some(Ordinary::$op) } ),* - _ => None, - } - } - } - ); -} - -// "Ordinary" opcodes -- should be 60 of these -ordinary_opcode! { - // pushdata - OP_PUSHDATA1, OP_PUSHDATA2, OP_PUSHDATA4, - // control flow - OP_IF, OP_NOTIF, OP_ELSE, OP_ENDIF, OP_VERIFY, - // stack - OP_TOALTSTACK, OP_FROMALTSTACK, - OP_2DROP, OP_2DUP, OP_3DUP, OP_2OVER, OP_2ROT, OP_2SWAP, - OP_DROP, OP_DUP, OP_NIP, OP_OVER, OP_PICK, OP_ROLL, OP_ROT, OP_SWAP, OP_TUCK, - OP_IFDUP, OP_DEPTH, OP_SIZE, - // equality - OP_EQUAL, OP_EQUALVERIFY, - // arithmetic - OP_1ADD, OP_1SUB, OP_NEGATE, OP_ABS, OP_NOT, OP_0NOTEQUAL, - OP_ADD, OP_SUB, OP_BOOLAND, OP_BOOLOR, - OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_NUMNOTEQUAL, OP_LESSTHAN, - OP_GREATERTHAN, OP_LESSTHANOREQUAL, OP_GREATERTHANOREQUAL, - OP_MIN, OP_MAX, OP_WITHIN, - // crypto - OP_RIPEMD160, OP_SHA1, OP_SHA256, OP_HASH160, OP_HASH256, - OP_CODESEPARATOR, OP_CHECKSIG, OP_CHECKSIGVERIFY, - OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY -} - -impl Ordinary { - /// Encode as a byte - #[inline] - pub fn into_u8(&self) -> u8 { - *self as u8 - } -} - -#[cfg(test)] -mod tests { - use std::collections::HashSet; - - use super::*; - - macro_rules! roundtrip { - ($unique:expr, $op:ident) => { - assert_eq!(all::$op, All::from(all::$op.into_u8())); - - let s1 = format!("{}", all::$op); - let s2 = format!("{:?}", all::$op); - assert_eq!(s1, s2); - assert_eq!(s1, stringify!($op)); - assert!($unique.insert(s1)); - } - } - - #[test] - fn str_roundtrip() { - let mut unique = HashSet::new(); - roundtrip!(unique, OP_PUSHBYTES_0); - roundtrip!(unique, OP_PUSHBYTES_1); - roundtrip!(unique, OP_PUSHBYTES_2); - roundtrip!(unique, OP_PUSHBYTES_3); - roundtrip!(unique, OP_PUSHBYTES_4); - roundtrip!(unique, OP_PUSHBYTES_5); - roundtrip!(unique, OP_PUSHBYTES_6); - roundtrip!(unique, OP_PUSHBYTES_7); - roundtrip!(unique, OP_PUSHBYTES_8); - roundtrip!(unique, OP_PUSHBYTES_9); - roundtrip!(unique, OP_PUSHBYTES_10); - roundtrip!(unique, OP_PUSHBYTES_11); - roundtrip!(unique, OP_PUSHBYTES_12); - roundtrip!(unique, OP_PUSHBYTES_13); - roundtrip!(unique, OP_PUSHBYTES_14); - roundtrip!(unique, OP_PUSHBYTES_15); - roundtrip!(unique, OP_PUSHBYTES_16); - roundtrip!(unique, OP_PUSHBYTES_17); - roundtrip!(unique, OP_PUSHBYTES_18); - roundtrip!(unique, OP_PUSHBYTES_19); - roundtrip!(unique, OP_PUSHBYTES_20); - roundtrip!(unique, OP_PUSHBYTES_21); - roundtrip!(unique, OP_PUSHBYTES_22); - roundtrip!(unique, OP_PUSHBYTES_23); - roundtrip!(unique, OP_PUSHBYTES_24); - roundtrip!(unique, OP_PUSHBYTES_25); - roundtrip!(unique, OP_PUSHBYTES_26); - roundtrip!(unique, OP_PUSHBYTES_27); - roundtrip!(unique, OP_PUSHBYTES_28); - roundtrip!(unique, OP_PUSHBYTES_29); - roundtrip!(unique, OP_PUSHBYTES_30); - roundtrip!(unique, OP_PUSHBYTES_31); - roundtrip!(unique, OP_PUSHBYTES_32); - roundtrip!(unique, OP_PUSHBYTES_33); - roundtrip!(unique, OP_PUSHBYTES_34); - roundtrip!(unique, OP_PUSHBYTES_35); - roundtrip!(unique, OP_PUSHBYTES_36); - roundtrip!(unique, OP_PUSHBYTES_37); - roundtrip!(unique, OP_PUSHBYTES_38); - roundtrip!(unique, OP_PUSHBYTES_39); - roundtrip!(unique, OP_PUSHBYTES_40); - roundtrip!(unique, OP_PUSHBYTES_41); - roundtrip!(unique, OP_PUSHBYTES_42); - roundtrip!(unique, OP_PUSHBYTES_43); - roundtrip!(unique, OP_PUSHBYTES_44); - roundtrip!(unique, OP_PUSHBYTES_45); - roundtrip!(unique, OP_PUSHBYTES_46); - roundtrip!(unique, OP_PUSHBYTES_47); - roundtrip!(unique, OP_PUSHBYTES_48); - roundtrip!(unique, OP_PUSHBYTES_49); - roundtrip!(unique, OP_PUSHBYTES_50); - roundtrip!(unique, OP_PUSHBYTES_51); - roundtrip!(unique, OP_PUSHBYTES_52); - roundtrip!(unique, OP_PUSHBYTES_53); - roundtrip!(unique, OP_PUSHBYTES_54); - roundtrip!(unique, OP_PUSHBYTES_55); - roundtrip!(unique, OP_PUSHBYTES_56); - roundtrip!(unique, OP_PUSHBYTES_57); - roundtrip!(unique, OP_PUSHBYTES_58); - roundtrip!(unique, OP_PUSHBYTES_59); - roundtrip!(unique, OP_PUSHBYTES_60); - roundtrip!(unique, OP_PUSHBYTES_61); - roundtrip!(unique, OP_PUSHBYTES_62); - roundtrip!(unique, OP_PUSHBYTES_63); - roundtrip!(unique, OP_PUSHBYTES_64); - roundtrip!(unique, OP_PUSHBYTES_65); - roundtrip!(unique, OP_PUSHBYTES_66); - roundtrip!(unique, OP_PUSHBYTES_67); - roundtrip!(unique, OP_PUSHBYTES_68); - roundtrip!(unique, OP_PUSHBYTES_69); - roundtrip!(unique, OP_PUSHBYTES_70); - roundtrip!(unique, OP_PUSHBYTES_71); - roundtrip!(unique, OP_PUSHBYTES_72); - roundtrip!(unique, OP_PUSHBYTES_73); - roundtrip!(unique, OP_PUSHBYTES_74); - roundtrip!(unique, OP_PUSHBYTES_75); - roundtrip!(unique, OP_PUSHDATA1); - roundtrip!(unique, OP_PUSHDATA2); - roundtrip!(unique, OP_PUSHDATA4); - roundtrip!(unique, OP_PUSHNUM_NEG1); - roundtrip!(unique, OP_RESERVED); - roundtrip!(unique, OP_PUSHNUM_1); - roundtrip!(unique, OP_PUSHNUM_2); - roundtrip!(unique, OP_PUSHNUM_3); - roundtrip!(unique, OP_PUSHNUM_4); - roundtrip!(unique, OP_PUSHNUM_5); - roundtrip!(unique, OP_PUSHNUM_6); - roundtrip!(unique, OP_PUSHNUM_7); - roundtrip!(unique, OP_PUSHNUM_8); - roundtrip!(unique, OP_PUSHNUM_9); - roundtrip!(unique, OP_PUSHNUM_10); - roundtrip!(unique, OP_PUSHNUM_11); - roundtrip!(unique, OP_PUSHNUM_12); - roundtrip!(unique, OP_PUSHNUM_13); - roundtrip!(unique, OP_PUSHNUM_14); - roundtrip!(unique, OP_PUSHNUM_15); - roundtrip!(unique, OP_PUSHNUM_16); - roundtrip!(unique, OP_NOP); - roundtrip!(unique, OP_VER); - roundtrip!(unique, OP_IF); - roundtrip!(unique, OP_NOTIF); - roundtrip!(unique, OP_VERIF); - roundtrip!(unique, OP_VERNOTIF); - roundtrip!(unique, OP_ELSE); - roundtrip!(unique, OP_ENDIF); - roundtrip!(unique, OP_VERIFY); - roundtrip!(unique, OP_RETURN); - roundtrip!(unique, OP_TOALTSTACK); - roundtrip!(unique, OP_FROMALTSTACK); - roundtrip!(unique, OP_2DROP); - roundtrip!(unique, OP_2DUP); - roundtrip!(unique, OP_3DUP); - roundtrip!(unique, OP_2OVER); - roundtrip!(unique, OP_2ROT); - roundtrip!(unique, OP_2SWAP); - roundtrip!(unique, OP_IFDUP); - roundtrip!(unique, OP_DEPTH); - roundtrip!(unique, OP_DROP); - roundtrip!(unique, OP_DUP); - roundtrip!(unique, OP_NIP); - roundtrip!(unique, OP_OVER); - roundtrip!(unique, OP_PICK); - roundtrip!(unique, OP_ROLL); - roundtrip!(unique, OP_ROT); - roundtrip!(unique, OP_SWAP); - roundtrip!(unique, OP_TUCK); - roundtrip!(unique, OP_CAT); - roundtrip!(unique, OP_SUBSTR); - roundtrip!(unique, OP_LEFT); - roundtrip!(unique, OP_RIGHT); - roundtrip!(unique, OP_SIZE); - roundtrip!(unique, OP_INVERT); - roundtrip!(unique, OP_AND); - roundtrip!(unique, OP_OR); - roundtrip!(unique, OP_XOR); - roundtrip!(unique, OP_EQUAL); - roundtrip!(unique, OP_EQUALVERIFY); - roundtrip!(unique, OP_RESERVED1); - roundtrip!(unique, OP_RESERVED2); - roundtrip!(unique, OP_1ADD); - roundtrip!(unique, OP_1SUB); - roundtrip!(unique, OP_2MUL); - roundtrip!(unique, OP_2DIV); - roundtrip!(unique, OP_NEGATE); - roundtrip!(unique, OP_ABS); - roundtrip!(unique, OP_NOT); - roundtrip!(unique, OP_0NOTEQUAL); - roundtrip!(unique, OP_ADD); - roundtrip!(unique, OP_SUB); - roundtrip!(unique, OP_MUL); - roundtrip!(unique, OP_DIV); - roundtrip!(unique, OP_MOD); - roundtrip!(unique, OP_LSHIFT); - roundtrip!(unique, OP_RSHIFT); - roundtrip!(unique, OP_BOOLAND); - roundtrip!(unique, OP_BOOLOR); - roundtrip!(unique, OP_NUMEQUAL); - roundtrip!(unique, OP_NUMEQUALVERIFY); - roundtrip!(unique, OP_NUMNOTEQUAL); - roundtrip!(unique, OP_LESSTHAN ); - roundtrip!(unique, OP_GREATERTHAN ); - roundtrip!(unique, OP_LESSTHANOREQUAL ); - roundtrip!(unique, OP_GREATERTHANOREQUAL ); - roundtrip!(unique, OP_MIN); - roundtrip!(unique, OP_MAX); - roundtrip!(unique, OP_WITHIN); - roundtrip!(unique, OP_RIPEMD160); - roundtrip!(unique, OP_SHA1); - roundtrip!(unique, OP_SHA256); - roundtrip!(unique, OP_HASH160); - roundtrip!(unique, OP_HASH256); - roundtrip!(unique, OP_CODESEPARATOR); - roundtrip!(unique, OP_CHECKSIG); - roundtrip!(unique, OP_CHECKSIGVERIFY); - roundtrip!(unique, OP_CHECKMULTISIG); - roundtrip!(unique, OP_CHECKMULTISIGVERIFY); - roundtrip!(unique, OP_NOP1); - roundtrip!(unique, OP_CLTV); - roundtrip!(unique, OP_CSV); - roundtrip!(unique, OP_NOP4); - roundtrip!(unique, OP_NOP5); - roundtrip!(unique, OP_NOP6); - roundtrip!(unique, OP_NOP7); - roundtrip!(unique, OP_NOP8); - roundtrip!(unique, OP_NOP9); - roundtrip!(unique, OP_NOP10); - roundtrip!(unique, OP_RETURN_186); - roundtrip!(unique, OP_RETURN_187); - roundtrip!(unique, OP_RETURN_188); - roundtrip!(unique, OP_RETURN_189); - roundtrip!(unique, OP_RETURN_190); - roundtrip!(unique, OP_RETURN_191); - roundtrip!(unique, OP_RETURN_192); - roundtrip!(unique, OP_RETURN_193); - roundtrip!(unique, OP_RETURN_194); - roundtrip!(unique, OP_RETURN_195); - roundtrip!(unique, OP_RETURN_196); - roundtrip!(unique, OP_RETURN_197); - roundtrip!(unique, OP_RETURN_198); - roundtrip!(unique, OP_RETURN_199); - roundtrip!(unique, OP_RETURN_200); - roundtrip!(unique, OP_RETURN_201); - roundtrip!(unique, OP_RETURN_202); - roundtrip!(unique, OP_RETURN_203); - roundtrip!(unique, OP_RETURN_204); - roundtrip!(unique, OP_RETURN_205); - roundtrip!(unique, OP_RETURN_206); - roundtrip!(unique, OP_RETURN_207); - roundtrip!(unique, OP_RETURN_208); - roundtrip!(unique, OP_RETURN_209); - roundtrip!(unique, OP_RETURN_210); - roundtrip!(unique, OP_RETURN_211); - roundtrip!(unique, OP_RETURN_212); - roundtrip!(unique, OP_RETURN_213); - roundtrip!(unique, OP_RETURN_214); - roundtrip!(unique, OP_RETURN_215); - roundtrip!(unique, OP_RETURN_216); - roundtrip!(unique, OP_RETURN_217); - roundtrip!(unique, OP_RETURN_218); - roundtrip!(unique, OP_RETURN_219); - roundtrip!(unique, OP_RETURN_220); - roundtrip!(unique, OP_RETURN_221); - roundtrip!(unique, OP_RETURN_222); - roundtrip!(unique, OP_RETURN_223); - roundtrip!(unique, OP_RETURN_224); - roundtrip!(unique, OP_RETURN_225); - roundtrip!(unique, OP_RETURN_226); - roundtrip!(unique, OP_RETURN_227); - roundtrip!(unique, OP_RETURN_228); - roundtrip!(unique, OP_RETURN_229); - roundtrip!(unique, OP_RETURN_230); - roundtrip!(unique, OP_RETURN_231); - roundtrip!(unique, OP_RETURN_232); - roundtrip!(unique, OP_RETURN_233); - roundtrip!(unique, OP_RETURN_234); - roundtrip!(unique, OP_RETURN_235); - roundtrip!(unique, OP_RETURN_236); - roundtrip!(unique, OP_RETURN_237); - roundtrip!(unique, OP_RETURN_238); - roundtrip!(unique, OP_RETURN_239); - roundtrip!(unique, OP_RETURN_240); - roundtrip!(unique, OP_RETURN_241); - roundtrip!(unique, OP_RETURN_242); - roundtrip!(unique, OP_RETURN_243); - roundtrip!(unique, OP_RETURN_244); - roundtrip!(unique, OP_RETURN_245); - roundtrip!(unique, OP_RETURN_246); - roundtrip!(unique, OP_RETURN_247); - roundtrip!(unique, OP_RETURN_248); - roundtrip!(unique, OP_RETURN_249); - roundtrip!(unique, OP_RETURN_250); - roundtrip!(unique, OP_RETURN_251); - roundtrip!(unique, OP_RETURN_252); - roundtrip!(unique, OP_RETURN_253); - roundtrip!(unique, OP_RETURN_254); - roundtrip!(unique, OP_RETURN_255); - assert_eq!(unique.len(), 256); - } -} - diff --git a/src/blockdata/script.rs b/src/blockdata/script.rs deleted file mode 100644 index 508a91da..00000000 --- a/src/blockdata/script.rs +++ /dev/null @@ -1,1090 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Script -//! -//! Scripts define Bitcoin's digital signature scheme: a signature is formed -//! from a script (the second half of which is defined by a coin to be spent, -//! and the first half provided by the spending transaction), and is valid -//! iff the script leaves `TRUE` on the stack after being evaluated. -//! Bitcoin's script is a stack-based assembly language similar in spirit to -//! Forth. -//! -//! This module provides the structures and functions needed to support scripts. -//! - -use std::default::Default; -use std::{error, fmt, io}; - -#[cfg(feature = "serde")] use serde; - -use hash_types::{ScriptHash, WScriptHash}; -use blockdata::opcodes; -use consensus::{encode, Decodable, Encodable}; -use hashes::Hash; -#[cfg(feature="bitcoinconsensus")] use bitcoinconsensus; -#[cfg(feature="bitcoinconsensus")] use std::convert; -#[cfg(feature="bitcoinconsensus")] use OutPoint; - -use util::key::PublicKey; - -#[derive(Clone, Default, PartialOrd, Ord, PartialEq, Eq, Hash)] -/// A Bitcoin script -pub struct Script(Box<[u8]>); - -impl fmt::Debug for Script { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("Script(")?; - self.fmt_asm(f)?; - f.write_str(")") - } -} - -impl fmt::Display for Script { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(self, f) - } -} - -impl fmt::LowerHex for Script { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for &ch in self.0.iter() { - write!(f, "{:02x}", ch)?; - } - Ok(()) - } -} - -impl fmt::UpperHex for Script { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for &ch in self.0.iter() { - write!(f, "{:02X}", ch)?; - } - Ok(()) - } -} - -#[derive(PartialEq, Eq, Debug, Clone)] -/// An object which can be used to construct a script piece by piece -pub struct Builder(Vec, Option); -display_from_debug!(Builder); - -/// Ways that a script might fail. Not everything is split up as -/// much as it could be; patches welcome if more detailed errors -/// would help you. -#[derive(PartialEq, Eq, Debug, Clone)] -pub enum Error { - /// Something did a non-minimal push; for more information see - /// `https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#Push_operators` - NonMinimalPush, - /// Some opcode expected a parameter, but it was missing or truncated - EarlyEndOfScript, - /// Tried to read an array off the stack as a number when it was more than 4 bytes - NumericOverflow, - #[cfg(feature="bitcoinconsensus")] - /// Error validating the script with bitcoinconsensus library - BitcoinConsensus(bitcoinconsensus::Error), - #[cfg(feature="bitcoinconsensus")] - /// Can not find the spent output - UnknownSpentOutput(OutPoint), - #[cfg(feature="bitcoinconsensus")] - /// Can not serialize the spending transaction - SerializationError -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(error::Error::description(self)) - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { None } - - fn description(&self) -> &'static str { - match *self { - Error::NonMinimalPush => "non-minimal datapush", - Error::EarlyEndOfScript => "unexpected end of script", - Error::NumericOverflow => "numeric overflow (number on stack larger than 4 bytes)", - #[cfg(feature="bitcoinconsensus")] - Error::BitcoinConsensus(ref _n) => "bitcoinconsensus verification failed", - #[cfg(feature="bitcoinconsensus")] - Error::UnknownSpentOutput(ref _point) => "unknown spent output Transaction::verify()", - #[cfg(feature="bitcoinconsensus")] - Error::SerializationError => "can not serialize the spending transaction in Transaction::verify()", - } - } -} - -#[cfg(feature="bitcoinconsensus")] -#[doc(hidden)] -impl convert::From for Error { - fn from(err: bitcoinconsensus::Error) -> Error { - match err { - _ => Error::BitcoinConsensus(err) - } - } -} -/// Helper to encode an integer in script format -fn build_scriptint(n: i64) -> Vec { - if n == 0 { return vec![] } - - let neg = n < 0; - - let mut abs = if neg { -n } else { n } as usize; - let mut v = vec![]; - while abs > 0xFF { - v.push((abs & 0xFF) as u8); - abs >>= 8; - } - // If the number's value causes the sign bit to be set, we need an extra - // byte to get the correct value and correct sign bit - if abs & 0x80 != 0 { - v.push(abs as u8); - v.push(if neg { 0x80u8 } else { 0u8 }); - } - // Otherwise we just set the sign bit ourselves - else { - abs |= if neg { 0x80 } else { 0 }; - v.push(abs as u8); - } - v -} - -/// Helper to decode an integer in script format -/// Notice that this fails on overflow: the result is the same as in -/// bitcoind, that only 4-byte signed-magnitude values may be read as -/// numbers. They can be added or subtracted (and a long time ago, -/// multiplied and divided), and this may result in numbers which -/// can't be written out in 4 bytes or less. This is ok! The number -/// just can't be read as a number again. -/// This is a bit crazy and subtle, but it makes sense: you can load -/// 32-bit numbers and do anything with them, which back when mult/div -/// was allowed, could result in up to a 64-bit number. We don't want -/// overflow since that's surprising --- and we don't want numbers that -/// don't fit in 64 bits (for efficiency on modern processors) so we -/// simply say, anything in excess of 32 bits is no longer a number. -/// This is basically a ranged type implementation. -pub fn read_scriptint(v: &[u8]) -> Result { - let len = v.len(); - if len == 0 { return Ok(0); } - if len > 4 { return Err(Error::NumericOverflow); } - - let (mut ret, sh) = v.iter() - .fold((0, 0), |(acc, sh), n| (acc + ((*n as i64) << sh), sh + 8)); - if v[len - 1] & 0x80 != 0 { - ret &= (1 << (sh - 1)) - 1; - ret = -ret; - } - Ok(ret) -} - -/// This is like "`read_scriptint` then map 0 to false and everything -/// else as true", except that the overflow rules don't apply. -#[inline] -pub fn read_scriptbool(v: &[u8]) -> bool { - !(v.is_empty() || - ((v[v.len() - 1] == 0 || v[v.len() - 1] == 0x80) && - v.iter().rev().skip(1).all(|&w| w == 0))) -} - -/// Read a script-encoded unsigned integer -pub fn read_uint(data: &[u8], size: usize) -> Result { - if data.len() < size { - Err(Error::EarlyEndOfScript) - } else { - let mut ret = 0; - for (i, item) in data.iter().take(size).enumerate() { - ret += (*item as usize) << (i * 8); - } - Ok(ret) - } -} - -impl Script { - /// Creates a new empty script - pub fn new() -> Script { Script(vec![].into_boxed_slice()) } - - /// The length in bytes of the script - pub fn len(&self) -> usize { self.0.len() } - - /// Whether the script is the empty script - pub fn is_empty(&self) -> bool { self.0.is_empty() } - - /// Returns the script data - pub fn as_bytes(&self) -> &[u8] { &*self.0 } - - /// Returns a copy of the script data - pub fn to_bytes(&self) -> Vec { self.0.clone().into_vec() } - - /// Convert the script into a byte vector - pub fn into_bytes(self) -> Vec { self.0.into_vec() } - - /// Compute the P2SH output corresponding to this redeem script - pub fn to_p2sh(&self) -> Script { - Builder::new().push_opcode(opcodes::all::OP_HASH160) - .push_slice(&ScriptHash::hash(&self.0)[..]) - .push_opcode(opcodes::all::OP_EQUAL) - .into_script() - } - - /// Compute the P2WSH output corresponding to this witnessScript (aka the "witness redeem - /// script") - pub fn to_v0_p2wsh(&self) -> Script { - Builder::new().push_int(0) - .push_slice(&WScriptHash::hash(&self.0)[..]) - .into_script() - } - - /// Checks whether a script pubkey is a p2sh output - #[inline] - pub fn is_p2sh(&self) -> bool { - self.0.len() == 23 && - self.0[0] == opcodes::all::OP_HASH160.into_u8() && - self.0[1] == opcodes::all::OP_PUSHBYTES_20.into_u8() && - self.0[22] == opcodes::all::OP_EQUAL.into_u8() - } - - /// Checks whether a script pubkey is a p2pkh output - #[inline] - pub fn is_p2pkh(&self) -> bool { - self.0.len() == 25 && - self.0[0] == opcodes::all::OP_DUP.into_u8() && - self.0[1] == opcodes::all::OP_HASH160.into_u8() && - self.0[2] == opcodes::all::OP_PUSHBYTES_20.into_u8() && - self.0[23] == opcodes::all::OP_EQUALVERIFY.into_u8() && - self.0[24] == opcodes::all::OP_CHECKSIG.into_u8() - } - - /// Checks whether a script pubkey is a p2pk output - #[inline] - pub fn is_p2pk(&self) -> bool { - (self.0.len() == 67 && - self.0[0] == opcodes::all::OP_PUSHBYTES_65.into_u8() && - self.0[66] == opcodes::all::OP_CHECKSIG.into_u8()) - || (self.0.len() == 35 && - self.0[0] == opcodes::all::OP_PUSHBYTES_33.into_u8() && - self.0[34] == opcodes::all::OP_CHECKSIG.into_u8()) - } - - /// Checks whether a script pubkey is a Segregated Witness (segwit) program. - #[inline] - pub fn is_witness_program(&self) -> bool { - // A scriptPubKey (or redeemScript as defined in BIP16/P2SH) that consists of a 1-byte - // push opcode (for 0 to 16) followed by a data push between 2 and 40 bytes gets a new - // special meaning. The value of the first push is called the "version byte". The following - // byte vector pushed is called the "witness program". - let min_vernum: u8 = opcodes::all::OP_PUSHNUM_1.into_u8(); - let max_vernum: u8 = opcodes::all::OP_PUSHNUM_16.into_u8(); - self.0.len() >= 4 - && self.0.len() <= 42 - // Version 0 or PUSHNUM_1-PUSHNUM_16 - && (self.0[0] == 0 || self.0[0] >= min_vernum && self.0[0] <= max_vernum) - // Second byte push opcode 2-40 bytes - && self.0[1] >= opcodes::all::OP_PUSHBYTES_2.into_u8() - && self.0[1] <= opcodes::all::OP_PUSHBYTES_40.into_u8() - // Check that the rest of the script has the correct size - && self.0.len() - 2 == self.0[1] as usize - } - - /// Checks whether a script pubkey is a p2wsh output - #[inline] - pub fn is_v0_p2wsh(&self) -> bool { - self.0.len() == 34 && - self.0[0] == opcodes::all::OP_PUSHBYTES_0.into_u8() && - self.0[1] == opcodes::all::OP_PUSHBYTES_32.into_u8() - } - - /// Checks whether a script pubkey is a p2wpkh output - #[inline] - pub fn is_v0_p2wpkh(&self) -> bool { - self.0.len() == 22 && - self.0[0] == opcodes::all::OP_PUSHBYTES_0.into_u8() && - self.0[1] == opcodes::all::OP_PUSHBYTES_20.into_u8() - } - - /// Check if this is an OP_RETURN output - pub fn is_op_return (&self) -> bool { - !self.0.is_empty() && (opcodes::All::from(self.0[0]) == opcodes::all::OP_RETURN) - } - - /// Whether a script can be proven to have no satisfying input - pub fn is_provably_unspendable(&self) -> bool { - !self.0.is_empty() && (opcodes::All::from(self.0[0]).classify() == opcodes::Class::ReturnOp || - opcodes::All::from(self.0[0]).classify() == opcodes::Class::IllegalOp) - } - - /// Iterate over the script in the form of `Instruction`s, which are an enum covering - /// opcodes, datapushes and errors. At most one error will be returned and then the - /// iterator will end. To instead iterate over the script as sequence of bytes, treat - /// it as a slice using `script[..]` or convert it to a vector using `into_bytes()`. - pub fn iter(&self, enforce_minimal: bool) -> Instructions { - Instructions { - data: &self.0[..], - enforce_minimal: enforce_minimal, - } - } - - #[cfg(feature="bitcoinconsensus")] - /// verify spend of an input script - /// # Parameters - /// * index - the input index in spending which is spending this transaction - /// * amount - the amount this script guards - /// * spending - the transaction that attempts to spend the output holding this script - pub fn verify (&self, index: usize, amount: u64, spending: &[u8]) -> Result<(), Error> { - Ok(bitcoinconsensus::verify (&self.0[..], amount, spending, index)?) - } - - /// Write the assembly decoding of the script to the formatter. - pub fn fmt_asm(&self, f: &mut fmt::Write) -> fmt::Result { - let mut index = 0; - while index < self.0.len() { - let opcode = opcodes::All::from(self.0[index]); - index += 1; - - let data_len = if let opcodes::Class::PushBytes(n) = opcode.classify() { - n as usize - } else { - match opcode { - opcodes::all::OP_PUSHDATA1 => { - if self.0.len() < index + 1 { - f.write_str("")?; - break; - } - match read_uint(&self.0[index..], 1) { - Ok(n) => { index += 1; n as usize } - Err(_) => { f.write_str("")?; break; } - } - } - opcodes::all::OP_PUSHDATA2 => { - if self.0.len() < index + 2 { - f.write_str("")?; - break; - } - match read_uint(&self.0[index..], 2) { - Ok(n) => { index += 2; n as usize } - Err(_) => { f.write_str("")?; break; } - } - } - opcodes::all::OP_PUSHDATA4 => { - if self.0.len() < index + 4 { - f.write_str("")?; - break; - } - match read_uint(&self.0[index..], 4) { - Ok(n) => { index += 4; n as usize } - Err(_) => { f.write_str("")?; break; } - } - } - _ => 0 - } - }; - - if index > 1 { f.write_str(" ")?; } - // Write the opcode - if opcode == opcodes::all::OP_PUSHBYTES_0 { - f.write_str("OP_0")?; - } else { - write!(f, "{:?}", opcode)?; - } - // Write any pushdata - if data_len > 0 { - f.write_str(" ")?; - if index + data_len <= self.0.len() { - for ch in &self.0[index..index + data_len] { - write!(f, "{:02x}", ch)?; - } - index += data_len; - } else { - f.write_str("")?; - break; - } - } - } - Ok(()) - } - - /// Get the assembly decoding of the script. - pub fn asm(&self) -> String { - let mut buf = String::new(); - self.fmt_asm(&mut buf).unwrap(); - buf - } -} - -/// Creates a new script from an existing vector -impl From> for Script { - fn from(v: Vec) -> Script { Script(v.into_boxed_slice()) } -} - -impl_index_newtype!(Script, u8); - -/// A "parsed opcode" which allows iterating over a Script in a more sensible way -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Instruction<'a> { - /// Push a bunch of data - PushBytes(&'a [u8]), - /// Some non-push opcode - Op(opcodes::All), - /// An opcode we were unable to parse - Error(Error) -} - -/// Iterator over a script returning parsed opcodes -pub struct Instructions<'a> { - data: &'a [u8], - enforce_minimal: bool, -} - -impl<'a> Iterator for Instructions<'a> { - type Item = Instruction<'a>; - - fn next(&mut self) -> Option> { - if self.data.is_empty() { - return None; - } - - match opcodes::All::from(self.data[0]).classify() { - opcodes::Class::PushBytes(n) => { - let n = n as usize; - if self.data.len() < n + 1 { - self.data = &[]; // Kill iterator so that it does not return an infinite stream of errors - return Some(Instruction::Error(Error::EarlyEndOfScript)); - } - if self.enforce_minimal { - if n == 1 && (self.data[1] == 0x81 || (self.data[1] > 0 && self.data[1] <= 16)) { - self.data = &[]; - return Some(Instruction::Error(Error::NonMinimalPush)); - } - } - let ret = Some(Instruction::PushBytes(&self.data[1..n+1])); - self.data = &self.data[n + 1..]; - ret - } - opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) => { - if self.data.len() < 2 { - self.data = &[]; - return Some(Instruction::Error(Error::EarlyEndOfScript)); - } - let n = match read_uint(&self.data[1..], 1) { - Ok(n) => n, - Err(e) => { - self.data = &[]; - return Some(Instruction::Error(e)); - } - }; - if self.data.len() < n + 2 { - self.data = &[]; - return Some(Instruction::Error(Error::EarlyEndOfScript)); - } - if self.enforce_minimal && n < 76 { - self.data = &[]; - return Some(Instruction::Error(Error::NonMinimalPush)); - } - let ret = Some(Instruction::PushBytes(&self.data[2..n+2])); - self.data = &self.data[n + 2..]; - ret - } - opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) => { - if self.data.len() < 3 { - self.data = &[]; - return Some(Instruction::Error(Error::EarlyEndOfScript)); - } - let n = match read_uint(&self.data[1..], 2) { - Ok(n) => n, - Err(e) => { - self.data = &[]; - return Some(Instruction::Error(e)); - } - }; - if self.enforce_minimal && n < 0x100 { - self.data = &[]; - return Some(Instruction::Error(Error::NonMinimalPush)); - } - if self.data.len() < n + 3 { - self.data = &[]; - return Some(Instruction::Error(Error::EarlyEndOfScript)); - } - let ret = Some(Instruction::PushBytes(&self.data[3..n + 3])); - self.data = &self.data[n + 3..]; - ret - } - opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => { - if self.data.len() < 5 { - self.data = &[]; - return Some(Instruction::Error(Error::EarlyEndOfScript)); - } - let n = match read_uint(&self.data[1..], 4) { - Ok(n) => n, - Err(e) => { - self.data = &[]; - return Some(Instruction::Error(e)); - } - }; - if self.enforce_minimal && n < 0x10000 { - self.data = &[]; - return Some(Instruction::Error(Error::NonMinimalPush)); - } - if self.data.len() < n + 5 { - self.data = &[]; - return Some(Instruction::Error(Error::EarlyEndOfScript)); - } - let ret = Some(Instruction::PushBytes(&self.data[5..n + 5])); - self.data = &self.data[n + 5..]; - ret - } - // Everything else we can push right through - _ => { - let ret = Some(Instruction::Op(opcodes::All::from(self.data[0]))); - self.data = &self.data[1..]; - ret - } - } - } -} - -impl Builder { - /// Creates a new empty script - pub fn new() -> Builder { - Builder(vec![], None) - } - - /// The length in bytes of the script - pub fn len(&self) -> usize { self.0.len() } - - /// Whether the script is the empty script - pub fn is_empty(&self) -> bool { self.0.is_empty() } - - /// Adds instructions to push an integer onto the stack. Integers are - /// encoded as little-endian signed-magnitude numbers, but there are - /// dedicated opcodes to push some small integers. - pub fn push_int(self, data: i64) -> Builder { - // We can special-case -1, 1-16 - if data == -1 || (data >= 1 && data <= 16) { - let opcode = opcodes::All::from( - (data - 1 + opcodes::OP_TRUE.into_u8() as i64) as u8 - ); - self.push_opcode(opcode) - } - // We can also special-case zero - else if data == 0 { - self.push_opcode(opcodes::OP_FALSE) - } - // Otherwise encode it as data - else { self.push_scriptint(data) } - } - - /// Adds instructions to push an integer onto the stack, using the explicit - /// encoding regardless of the availability of dedicated opcodes. - pub fn push_scriptint(self, data: i64) -> Builder { - self.push_slice(&build_scriptint(data)) - } - - /// Adds instructions to push some arbitrary data onto the stack - pub fn push_slice(mut self, data: &[u8]) -> Builder { - // Start with a PUSH opcode - match data.len() as u64 { - n if n < opcodes::Ordinary::OP_PUSHDATA1 as u64 => { self.0.push(n as u8); }, - n if n < 0x100 => { - self.0.push(opcodes::Ordinary::OP_PUSHDATA1.into_u8()); - self.0.push(n as u8); - }, - n if n < 0x10000 => { - self.0.push(opcodes::Ordinary::OP_PUSHDATA2.into_u8()); - self.0.push((n % 0x100) as u8); - self.0.push((n / 0x100) as u8); - }, - n if n < 0x100000000 => { - self.0.push(opcodes::Ordinary::OP_PUSHDATA4.into_u8()); - self.0.push((n % 0x100) as u8); - self.0.push(((n / 0x100) % 0x100) as u8); - self.0.push(((n / 0x10000) % 0x100) as u8); - self.0.push((n / 0x1000000) as u8); - } - _ => panic!("tried to put a 4bn+ sized object into a script!") - } - // Then push the raw bytes - self.0.extend(data.iter().cloned()); - self.1 = None; - self - } - - /// Pushes a public key - pub fn push_key(self, key: &PublicKey) -> Builder { - if key.compressed { - self.push_slice(&key.key.serialize()[..]) - } else { - self.push_slice(&key.key.serialize_uncompressed()[..]) - } - } - - /// Adds a single opcode to the script - pub fn push_opcode(mut self, data: opcodes::All) -> Builder { - self.0.push(data.into_u8()); - self.1 = Some(data); - self - } - - /// Adds an `OP_VERIFY` to the script, unless the most-recently-added - /// opcode has an alternate `VERIFY` form, in which case that opcode - /// is replaced. e.g. `OP_CHECKSIG` will become `OP_CHECKSIGVERIFY`. - pub fn push_verify(mut self) -> Builder { - match self.1 { - Some(opcodes::all::OP_EQUAL) => { - self.0.pop(); - self.push_opcode(opcodes::all::OP_EQUALVERIFY) - }, - Some(opcodes::all::OP_NUMEQUAL) => { - self.0.pop(); - self.push_opcode(opcodes::all::OP_NUMEQUALVERIFY) - }, - Some(opcodes::all::OP_CHECKSIG) => { - self.0.pop(); - self.push_opcode(opcodes::all::OP_CHECKSIGVERIFY) - }, - Some(opcodes::all::OP_CHECKMULTISIG) => { - self.0.pop(); - self.push_opcode(opcodes::all::OP_CHECKMULTISIGVERIFY) - }, - _ => self.push_opcode(opcodes::all::OP_VERIFY), - } - } - - /// Converts the `Builder` into an unmodifiable `Script` - pub fn into_script(self) -> Script { - Script(self.0.into_boxed_slice()) - } -} - -/// Adds an individual opcode to the script -impl Default for Builder { - fn default() -> Builder { Builder::new() } -} - -/// Creates a new script from an existing vector -impl From> for Builder { - fn from(v: Vec) -> Builder { - let script = Script(v.into_boxed_slice()); - let last_op = match script.iter(false).last() { - Some(Instruction::Op(op)) => Some(op), - _ => None, - }; - Builder(script.into_bytes(), last_op) - } -} - -impl_index_newtype!(Builder, u8); - -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for Script { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use std::fmt::Formatter; - - struct Visitor; - impl<'de> serde::de::Visitor<'de> for Visitor { - type Value = Script; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a script") - } - - fn visit_str(self, v: &str) -> Result - where - E: serde::de::Error, - { - let v: Vec = ::hex::decode(v).map_err(E::custom)?; - Ok(Script::from(v)) - } - - fn visit_borrowed_str(self, v: &'de str) -> Result - where - E: serde::de::Error, - { - self.visit_str(v) - } - - fn visit_string(self, v: String) -> Result - where - E: serde::de::Error, - { - self.visit_str(&v) - } - } - - deserializer.deserialize_str(Visitor) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for Script { - /// User-facing serialization for `Script`. - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&format!("{:x}", self)) - } -} - -// Network serialization -impl Encodable for Script { - #[inline] - fn consensus_encode( - &self, - s: S, - ) -> Result { - self.0.consensus_encode(s) - } -} - -impl Decodable for Script { - #[inline] - fn consensus_decode(d: D) -> Result { - Ok(Script(Decodable::consensus_decode(d)?)) - } -} - -#[cfg(test)] -mod test { - use std::str::FromStr; - use hex::decode as hex_decode; - - use super::*; - use super::build_scriptint; - - use consensus::encode::{deserialize, serialize}; - use blockdata::opcodes; - use util::key::PublicKey; - - #[test] - fn script() { - let mut comp = vec![]; - let mut script = Builder::new(); - assert_eq!(&script[..], &comp[..]); - - // small ints - script = script.push_int(1); comp.push(81u8); assert_eq!(&script[..], &comp[..]); - script = script.push_int(0); comp.push(0u8); assert_eq!(&script[..], &comp[..]); - script = script.push_int(4); comp.push(84u8); assert_eq!(&script[..], &comp[..]); - script = script.push_int(-1); comp.push(79u8); assert_eq!(&script[..], &comp[..]); - // forced scriptint - script = script.push_scriptint(4); comp.extend([1u8, 4].iter().cloned()); assert_eq!(&script[..], &comp[..]); - // big ints - script = script.push_int(17); comp.extend([1u8, 17].iter().cloned()); assert_eq!(&script[..], &comp[..]); - script = script.push_int(10000); comp.extend([2u8, 16, 39].iter().cloned()); assert_eq!(&script[..], &comp[..]); - // notice the sign bit set here, hence the extra zero/128 at the end - script = script.push_int(10000000); comp.extend([4u8, 128, 150, 152, 0].iter().cloned()); assert_eq!(&script[..], &comp[..]); - script = script.push_int(-10000000); comp.extend([4u8, 128, 150, 152, 128].iter().cloned()); assert_eq!(&script[..], &comp[..]); - - // data - script = script.push_slice("NRA4VR".as_bytes()); comp.extend([6u8, 78, 82, 65, 52, 86, 82].iter().cloned()); assert_eq!(&script[..], &comp[..]); - - // keys - let keystr = "21032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af"; - let key = PublicKey::from_str(&keystr[2..]).unwrap(); - script = script.push_key(&key); comp.extend(hex_decode(keystr).unwrap().iter().cloned()); assert_eq!(&script[..], &comp[..]); - let keystr = "41042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133"; - let key = PublicKey::from_str(&keystr[2..]).unwrap(); - script = script.push_key(&key); comp.extend(hex_decode(keystr).unwrap().iter().cloned()); assert_eq!(&script[..], &comp[..]); - - // opcodes - script = script.push_opcode(opcodes::all::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(&script[..], &comp[..]); - script = script.push_opcode(opcodes::all::OP_CHECKSIG); comp.push(0xACu8); assert_eq!(&script[..], &comp[..]); - } - - #[test] - fn script_builder() { - // from txid 3bb5e6434c11fb93f64574af5d116736510717f2c595eb45b52c28e31622dfff which was in my mempool when I wrote the test - let script = Builder::new().push_opcode(opcodes::all::OP_DUP) - .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&hex_decode("16e1ae70ff0fa102905d4af297f6912bda6cce19").unwrap()) - .push_opcode(opcodes::all::OP_EQUALVERIFY) - .push_opcode(opcodes::all::OP_CHECKSIG) - .into_script(); - assert_eq!(&format!("{:x}", script), "76a91416e1ae70ff0fa102905d4af297f6912bda6cce1988ac"); - } - - #[test] - fn script_builder_verify() { - let simple = Builder::new() - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", simple), "69"); - let simple2 = Builder::from(vec![]) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", simple2), "69"); - - let nonverify = Builder::new() - .push_verify() - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", nonverify), "6969"); - let nonverify2 = Builder::from(vec![0x69]) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", nonverify2), "6969"); - - let equal = Builder::new() - .push_opcode(opcodes::all::OP_EQUAL) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", equal), "88"); - let equal2 = Builder::from(vec![0x87]) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", equal2), "88"); - - let numequal = Builder::new() - .push_opcode(opcodes::all::OP_NUMEQUAL) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", numequal), "9d"); - let numequal2 = Builder::from(vec![0x9c]) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", numequal2), "9d"); - - let checksig = Builder::new() - .push_opcode(opcodes::all::OP_CHECKSIG) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", checksig), "ad"); - let checksig2 = Builder::from(vec![0xac]) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", checksig2), "ad"); - - let checkmultisig = Builder::new() - .push_opcode(opcodes::all::OP_CHECKMULTISIG) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", checkmultisig), "af"); - let checkmultisig2 = Builder::from(vec![0xae]) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", checkmultisig2), "af"); - - let trick_slice = Builder::new() - .push_slice(&[0xae]) // OP_CHECKMULTISIG - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", trick_slice), "01ae69"); - let trick_slice2 = Builder::from(vec![0x01, 0xae]) - .push_verify() - .into_script(); - assert_eq!(format!("{:x}", trick_slice2), "01ae69"); - } - - #[test] - fn script_serialize() { - let hex_script = hex_decode("6c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52").unwrap(); - let script: Result = deserialize(&hex_script); - assert!(script.is_ok()); - assert_eq!(serialize(&script.unwrap()), hex_script); - } - - #[test] - fn scriptint_round_trip() { - assert_eq!(build_scriptint(-1), vec![0x81]); - assert_eq!(build_scriptint(255), vec![255, 0]); - assert_eq!(build_scriptint(256), vec![0, 1]); - assert_eq!(build_scriptint(257), vec![1, 1]); - assert_eq!(build_scriptint(511), vec![255, 1]); - for &i in [10, 100, 255, 256, 1000, 10000, 25000, 200000, 5000000, 1000000000, - (1 << 31) - 1, -((1 << 31) - 1)].iter() { - assert_eq!(Ok(i), read_scriptint(&build_scriptint(i))); - assert_eq!(Ok(-i), read_scriptint(&build_scriptint(-i))); - } - assert!(read_scriptint(&build_scriptint(1 << 31)).is_err()); - assert!(read_scriptint(&build_scriptint(-(1 << 31))).is_err()); - } - - #[test] - fn provably_unspendable_test() { - // p2pk - assert_eq!(hex_script!("410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac").is_provably_unspendable(), false); - assert_eq!(hex_script!("4104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac").is_provably_unspendable(), false); - // p2pkhash - assert_eq!(hex_script!("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac").is_provably_unspendable(), false); - assert_eq!(hex_script!("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87").is_provably_unspendable(), true); - } - - #[test] - fn op_return_test() { - assert_eq!(hex_script!("6aa9149eb21980dc9d413d8eac27314938b9da920ee53e87").is_op_return(), true); - assert_eq!(hex_script!("76a914ee61d57ab51b9d212335b1dba62794ac20d2bcf988ac").is_op_return(), false); - assert_eq!(hex_script!("").is_op_return(), false); - } - - #[test] - #[cfg(feature = "serde")] - fn script_json_serialize() { - use serde_json; - - let original = hex_script!("827651a0698faaa9a8a7a687"); - let json = serde_json::to_value(&original).unwrap(); - assert_eq!(json, serde_json::Value::String("827651a0698faaa9a8a7a687".to_owned())); - let des = serde_json::from_value(json).unwrap(); - assert_eq!(original, des); - } - - #[test] - fn script_asm() { - assert_eq!(hex_script!("6363636363686868686800").asm(), - "OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0"); - assert_eq!(hex_script!("6363636363686868686800").asm(), - "OP_IF OP_IF OP_IF OP_IF OP_IF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_ENDIF OP_0"); - assert_eq!(hex_script!("2102715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699ac").asm(), - "OP_PUSHBYTES_33 02715e91d37d239dea832f1460e91e368115d8ca6cc23a7da966795abad9e3b699 OP_CHECKSIG"); - // Elements Alpha peg-out transaction with some signatures removed for brevity. Mainly to test PUSHDATA1 - assert_eq!(hex_script!("0047304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401004cf1552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae").asm(), - "OP_0 OP_PUSHBYTES_71 304402202457e78cc1b7f50d0543863c27de75d07982bde8359b9e3316adec0aec165f2f02200203fd331c4e4a4a02f48cf1c291e2c0d6b2f7078a784b5b3649fca41f8794d401 OP_0 OP_PUSHDATA1 552103244e602b46755f24327142a0517288cebd159eccb6ccf41ea6edf1f601e9af952103bbbacc302d19d29dbfa62d23f37944ae19853cf260c745c2bea739c95328fcb721039227e83246bd51140fe93538b2301c9048be82ef2fb3c7fc5d78426ed6f609ad210229bf310c379b90033e2ecb07f77ecf9b8d59acb623ab7be25a0caed539e2e6472103703e2ed676936f10b3ce9149fa2d4a32060fb86fa9a70a4efe3f21d7ab90611921031e9b7c6022400a6bb0424bbcde14cff6c016b91ee3803926f3440abf5c146d05210334667f975f55a8455d515a2ef1c94fdfa3315f12319a14515d2a13d82831f62f57ae"); - } - - #[test] - fn script_p2sh_p2p2k_template() { - // random outputs I picked out of the mempool - assert!(hex_script!("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").is_p2pkh()); - assert!(!hex_script!("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ac").is_p2sh()); - assert!(!hex_script!("76a91402306a7c23f3e8010de41e9e591348bb83f11daa88ad").is_p2pkh()); - assert!(!hex_script!("").is_p2pkh()); - assert!(hex_script!("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87").is_p2sh()); - assert!(!hex_script!("a914acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87").is_p2pkh()); - assert!(!hex_script!("a314acc91e6fef5c7f24e5c8b3f11a664aa8f1352ffd87").is_p2sh()); - } - - #[test] - fn script_p2pk() { - assert!(hex_script!("21021aeaf2f8638a129a3156fbe7e5ef635226b0bafd495ff03afe2c843d7e3a4b51ac").is_p2pk()); - assert!(hex_script!("410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac").is_p2pk()); - } - - #[test] - fn p2sh_p2wsh_conversion() { - // Test vectors taken from Core tests/data/script_tests.json - // bare p2wsh - let redeem_script = hex_script!("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac"); - let expected_witout = hex_script!("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64"); - assert!(redeem_script.to_v0_p2wsh().is_v0_p2wsh()); - assert_eq!(redeem_script.to_v0_p2wsh(), expected_witout); - - // p2sh - let redeem_script = hex_script!("0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"); - let expected_p2shout = hex_script!("a91491b24bf9f5288532960ac687abb035127b1d28a587"); - assert!(redeem_script.to_p2sh().is_p2sh()); - assert_eq!(redeem_script.to_p2sh(), expected_p2shout); - - // p2sh-p2wsh - let redeem_script = hex_script!("410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8ac"); - let expected_witout = hex_script!("0020b95237b48faaa69eb078e1170be3b5cbb3fddf16d0a991e14ad274f7b33a4f64"); - let expected_out = hex_script!("a914f386c2ba255cc56d20cfa6ea8b062f8b5994551887"); - assert!(redeem_script.to_p2sh().is_p2sh()); - assert!(redeem_script.to_p2sh().to_v0_p2wsh().is_v0_p2wsh()); - assert_eq!(redeem_script.to_v0_p2wsh(), expected_witout); - assert_eq!(redeem_script.to_v0_p2wsh().to_p2sh(), expected_out); - } - - #[test] - fn test_iterator() { - let zero = hex_script!("00"); - let zeropush = hex_script!("0100"); - - let nonminimal = hex_script!("4c0169b2"); // PUSHDATA1 for no reason - let minimal = hex_script!("0169b2"); // minimal - let nonminimal_alt = hex_script!("026900b2"); // non-minimal number but minimal push (should be OK) - - let v_zero: Vec = zero.iter(true).collect(); - let v_zeropush: Vec = zeropush.iter(true).collect(); - - let v_min: Vec = minimal.iter(true).collect(); - let v_nonmin: Vec = nonminimal.iter(true).collect(); - let v_nonmin_alt: Vec = nonminimal_alt.iter(true).collect(); - let slop_v_min: Vec = minimal.iter(false).collect(); - let slop_v_nonmin: Vec = nonminimal.iter(false).collect(); - let slop_v_nonmin_alt: Vec = nonminimal_alt.iter(false).collect(); - - assert_eq!( - v_zero, - vec![ - Instruction::PushBytes(&[]), - ] - ); - assert_eq!( - v_zeropush, - vec![ - Instruction::PushBytes(&[0]), - ] - ); - - assert_eq!( - v_min, - vec![ - Instruction::PushBytes(&[105]), - Instruction::Op(opcodes::OP_NOP3), - ] - ); - - assert_eq!( - v_nonmin, - vec![ - Instruction::Error(Error::NonMinimalPush), - ] - ); - - assert_eq!( - v_nonmin_alt, - vec![ - Instruction::PushBytes(&[105, 0]), - Instruction::Op(opcodes::OP_NOP3), - ] - ); - - assert_eq!(v_min, slop_v_min); - assert_eq!(v_min, slop_v_nonmin); - assert_eq!(v_nonmin_alt, slop_v_nonmin_alt); - } - - #[test] - fn script_ord() { - let script_1 = Builder::new().push_slice(&[1,2,3,4]).into_script(); - let script_2 = Builder::new().push_int(10).into_script(); - let script_3 = Builder::new().push_int(15).into_script(); - let script_4 = Builder::new().push_opcode(opcodes::all::OP_RETURN).into_script(); - - assert!(script_1 < script_2); - assert!(script_2 < script_3); - assert!(script_3 < script_4); - - assert!(script_1 <= script_1); - assert!(script_1 >= script_1); - - assert!(script_4 > script_3); - assert!(script_3 > script_2); - assert!(script_2 > script_1); - } - - #[test] - #[cfg(feature="bitcoinconsensus")] - fn test_bitcoinconsensus () { - // a random segwit transaction from the blockchain using native segwit - let spent = Builder::from(hex_decode("0020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d").unwrap()).into_script(); - let spending = hex_decode("010000000001011f97548fbbe7a0db7588a66e18d803d0089315aa7d4cc28360b6ec50ef36718a0100000000ffffffff02df1776000000000017a9146c002a686959067f4866b8fb493ad7970290ab728757d29f0000000000220020701a8d401c84fb13e6baf169d59684e17abd9fa216c8cc5b9fc63d622ff8c58d04004730440220565d170eed95ff95027a69b313758450ba84a01224e1f7f130dda46e94d13f8602207bdd20e307f062594022f12ed5017bbf4a055a06aea91c10110a0e3bb23117fc014730440220647d2dc5b15f60bc37dc42618a370b2a1490293f9e5c8464f53ec4fe1dfe067302203598773895b4b16d37485cbe21b337f4e4b650739880098c592553add7dd4355016952210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae00000000").unwrap(); - spent.verify(0, 18393430, spending.as_slice()).unwrap(); - } -} - diff --git a/src/blockdata/transaction.rs b/src/blockdata/transaction.rs deleted file mode 100644 index 7beac7f5..00000000 --- a/src/blockdata/transaction.rs +++ /dev/null @@ -1,1220 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Bitcoin Transaction -//! -//! A transaction describes a transfer of money. It consumes previously-unspent -//! transaction outputs and produces new ones, satisfying the condition to spend -//! the old outputs (typically a digital signature with a specific key must be -//! provided) and defining the condition to spend the new ones. The use of digital -//! signatures ensures that coins cannot be spent by unauthorized parties. -//! -//! This module provides the structures and functions needed to support transactions. -//! - -use std::default::Default; -use std::{fmt, io}; - -use hashes::{self, Hash, sha256d}; -use hashes::hex::FromHex; - -use util::endian; -#[cfg(feature="bitcoinconsensus")] use blockdata::script; -use blockdata::script::Script; -use consensus::{encode, serialize, Decodable, Encodable}; -use hash_types::*; -use VarInt; - -/// A reference to a transaction output -#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] -pub struct OutPoint { - /// The referenced transaction's txid - pub txid: Txid, - /// The index of the referenced output in its transaction's vout - pub vout: u32, -} -serde_struct_human_string_impl!(OutPoint, "an OutPoint", txid, vout); - -impl OutPoint { - /// Create a new [OutPoint]. - #[inline] - pub fn new(txid: Txid, vout: u32) -> OutPoint { - OutPoint { - txid: txid, - vout: vout, - } - } - - /// Creates a "null" `OutPoint`. - /// - /// This value is used for coinbase transactions because they don't have - /// any previous outputs. - #[inline] - pub fn null() -> OutPoint { - OutPoint { - txid: Default::default(), - vout: u32::max_value(), - } - } - - /// Checks if an `OutPoint` is "null". - /// - /// # Examples - /// - /// ```rust - /// use bitcoin::blockdata::constants::genesis_block; - /// use bitcoin::network::constants::Network; - /// - /// let block = genesis_block(Network::Bitcoin); - /// let tx = &block.txdata[0]; - /// - /// // Coinbase transactions don't have any previous output. - /// assert_eq!(tx.input[0].previous_output.is_null(), true); - /// ``` - #[inline] - pub fn is_null(&self) -> bool { - *self == OutPoint::null() - } -} - -impl Default for OutPoint { - fn default() -> Self { - OutPoint::null() - } -} - -impl fmt::Display for OutPoint { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}:{}", self.txid, self.vout) - } -} - -/// An error in parsing an OutPoint. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum ParseOutPointError { - /// Error in TXID part. - Txid(hashes::hex::Error), - /// Error in vout part. - Vout(::std::num::ParseIntError), - /// Error in general format. - Format, - /// Size exceeds max. - TooLong, - /// Vout part is not strictly numeric without leading zeroes. - VoutNotCanonical, -} - -impl fmt::Display for ParseOutPointError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ParseOutPointError::Txid(ref e) => write!(f, "error parsing TXID: {}", e), - ParseOutPointError::Vout(ref e) => write!(f, "error parsing vout: {}", e), - ParseOutPointError::Format => write!(f, "OutPoint not in : format"), - ParseOutPointError::TooLong => write!(f, "vout should be at most 10 digits"), - ParseOutPointError::VoutNotCanonical => write!(f, "no leading zeroes or + allowed in vout part"), - } - } -} - -impl ::std::error::Error for ParseOutPointError { - fn description(&self) -> &str { - match *self { - ParseOutPointError::Txid(_) => "TXID parse error", - ParseOutPointError::Vout(_) => "vout parse error", - ParseOutPointError::Format => "outpoint format error", - ParseOutPointError::TooLong => "size error", - ParseOutPointError::VoutNotCanonical => "vout canonical error", - } - } - - fn cause(&self) -> Option<&::std::error::Error> { - match *self { - ParseOutPointError::Txid(ref e) => Some(e), - ParseOutPointError::Vout(ref e) => Some(e), - _ => None, - } - } -} - -/// Parses a string-encoded transaction index (vout). -/// It does not permit leading zeroes or non-digit characters. -fn parse_vout(s: &str) -> Result { - if s.len() > 1 { - let first = s.chars().nth(0).unwrap(); - if first == '0' || first == '+' { - return Err(ParseOutPointError::VoutNotCanonical); - } - } - Ok(s.parse().map_err(ParseOutPointError::Vout)?) -} - -impl ::std::str::FromStr for OutPoint { - type Err = ParseOutPointError; - - fn from_str(s: &str) -> Result { - if s.len() > 75 { // 64 + 1 + 10 - return Err(ParseOutPointError::TooLong); - } - let find = s.find(':'); - if find == None || find != s.rfind(':') { - return Err(ParseOutPointError::Format); - } - let colon = find.unwrap(); - if colon == 0 || colon == s.len() - 1 { - return Err(ParseOutPointError::Format); - } - Ok(OutPoint { - txid: Txid::from_hex(&s[..colon]).map_err(ParseOutPointError::Txid)?, - vout: parse_vout(&s[colon+1..])?, - }) - } -} - -/// A transaction input, which defines old coins to be consumed -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct TxIn { - /// The reference to the previous output that is being used an an input - pub previous_output: OutPoint, - /// The script which pushes values on the stack which will cause - /// the referenced output's script to accept - pub script_sig: Script, - /// The sequence number, which suggests to miners which of two - /// conflicting transactions should be preferred, or 0xFFFFFFFF - /// to ignore this feature. This is generally never used since - /// the miner behaviour cannot be enforced. - pub sequence: u32, - /// Witness data: an array of byte-arrays. - /// Note that this field is *not* (de)serialized with the rest of the TxIn in - /// Encodable/Decodable, as it is (de)serialized at the end of the full - /// Transaction. It *is* (de)serialized with the rest of the TxIn in other - /// (de)serialization routines. - pub witness: Vec> -} -serde_struct_impl!(TxIn, previous_output, script_sig, sequence, witness); - -impl Default for TxIn { - fn default() -> TxIn { - TxIn { - previous_output: OutPoint::default(), - script_sig: Script::new(), - sequence: u32::max_value(), - witness: Vec::new(), - } - } -} - -/// A transaction output, which defines new coins to be created from old ones. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct TxOut { - /// The value of the output, in satoshis - pub value: u64, - /// The script which must satisfy for the output to be spent - pub script_pubkey: Script -} -serde_struct_impl!(TxOut, value, script_pubkey); - -// This is used as a "null txout" in consensus signing code -impl Default for TxOut { - fn default() -> TxOut { - TxOut { value: 0xffffffffffffffff, script_pubkey: Script::new() } - } -} - -/// A Bitcoin transaction, which describes an authenticated movement of coins. -/// -/// If any inputs have nonempty witnesses, the entire transaction is serialized -/// in the post-BIP141 Segwit format which includes a list of witnesses. If all -/// inputs have empty witnesses, the transaction is serialized in the pre-BIP141 -/// format. -/// -/// There is one major exception to this: to avoid deserialization ambiguity, -/// if the transaction has no inputs, it is serialized in the BIP141 style. Be -/// aware that this differs from the transaction format in PSBT, which _never_ -/// uses BIP141. (Ordinarily there is no conflict, since in PSBT transactions -/// are always unsigned and therefore their inputs have empty witnesses.) -/// -/// The specific ambiguity is that Segwit uses the flag bytes `0001` where an old -/// serializer would read the number of transaction inputs. The old serializer -/// would interpret this as "no inputs, one output", which means the transaction -/// is invalid, and simply reject it. Segwit further specifies that this encoding -/// should *only* be used when some input has a nonempty witness; that is, -/// witness-less transactions should be encoded in the traditional format. -/// -/// However, in protocols where transactions may legitimately have 0 inputs, e.g. -/// when parties are cooperatively funding a transaction, the "00 means Segwit" -/// heuristic does not work. Since Segwit requires such a transaction be encoded -/// in the original transaction format (since it has no inputs and therefore -/// no input witnesses), a traditionally encoded transaction may have the `0001` -/// Segwit flag in it, which confuses most Segwit parsers including the one in -/// Bitcoin Core. -/// -/// We therefore deviate from the spec by always using the Segwit witness encoding -/// for 0-input transactions, which results in unambiguously parseable transactions. -#[derive(Clone, PartialEq, Eq, Debug, Hash)] -pub struct Transaction { - /// The protocol version, is currently expected to be 1 or 2 (BIP 68). - pub version: u32, - /// Block number before which this transaction is valid, or 0 for - /// valid immediately. - pub lock_time: u32, - /// List of inputs - pub input: Vec, - /// List of outputs - pub output: Vec, -} -serde_struct_impl!(Transaction, version, lock_time, input, output); - -impl Transaction { - /// Computes a "normalized TXID" which does not include any signatures. - /// This gives a way to identify a transaction that is ``the same'' as - /// another in the sense of having same inputs and outputs. - pub fn ntxid(&self) -> sha256d::Hash { - let cloned_tx = Transaction { - version: self.version, - lock_time: self.lock_time, - input: self.input.iter().map(|txin| TxIn { script_sig: Script::new(), witness: vec![], .. *txin }).collect(), - output: self.output.clone(), - }; - cloned_tx.txid().into() - } - - /// Computes the txid. For non-segwit transactions this will be identical - /// to the output of `wtxid()`, but for segwit transactions, - /// this will give the correct txid (not including witnesses) while `wtxid` - /// will also hash witnesses. - pub fn txid(&self) -> Txid { - let mut enc = Txid::engine(); - self.version.consensus_encode(&mut enc).unwrap(); - self.input.consensus_encode(&mut enc).unwrap(); - self.output.consensus_encode(&mut enc).unwrap(); - self.lock_time.consensus_encode(&mut enc).unwrap(); - Txid::from_engine(enc) - } - - /// Computes SegWit-version of the transaction id (wtxid). For transaction with the witness - /// data this hash includes witness, for pre-witness transaction it is equal to the normal - /// value returned by txid() function. - pub fn wtxid(&self) -> Wtxid { - let mut enc = Wtxid::engine(); - self.consensus_encode(&mut enc).unwrap(); - Wtxid::from_engine(enc) - } - - /// Computes a signature hash for a given input index with a given sighash flag. - /// To actually produce a scriptSig, this hash needs to be run through an - /// ECDSA signer, the SigHashType appended to the resulting sig, and a - /// script written around this, but this is the general (and hard) part. - /// - /// *Warning* This does NOT attempt to support OP_CODESEPARATOR. In general - /// this would require evaluating `script_pubkey` to determine which separators - /// get evaluated and which don't, which we don't have the information to - /// determine. - /// - /// # Panics - /// Panics if `input_index` is greater than or equal to `self.input.len()` - /// - pub fn signature_hash(&self, input_index: usize, script_pubkey: &Script, sighash_u32: u32) -> SigHash { - assert!(input_index < self.input.len()); // Panic on OOB - - let (sighash, anyone_can_pay) = SigHashType::from_u32(sighash_u32).split_anyonecanpay_flag(); - - // Special-case sighash_single bug because this is easy enough. - if sighash == SigHashType::Single && input_index >= self.output.len() { - return SigHash::from_slice(&[1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0]).unwrap(); - } - - // Build tx to sign - let mut tx = Transaction { - version: self.version, - lock_time: self.lock_time, - input: vec![], - output: vec![], - }; - // Add all inputs necessary.. - if anyone_can_pay { - tx.input = vec![TxIn { - previous_output: self.input[input_index].previous_output, - script_sig: script_pubkey.clone(), - sequence: self.input[input_index].sequence, - witness: vec![], - }]; - } else { - tx.input = Vec::with_capacity(self.input.len()); - for (n, input) in self.input.iter().enumerate() { - tx.input.push(TxIn { - previous_output: input.previous_output, - script_sig: if n == input_index { script_pubkey.clone() } else { Script::new() }, - sequence: if n != input_index && (sighash == SigHashType::Single || sighash == SigHashType::None) { 0 } else { input.sequence }, - witness: vec![], - }); - } - } - // ..then all outputs - tx.output = match sighash { - SigHashType::All => self.output.clone(), - SigHashType::Single => { - let output_iter = self.output.iter() - .take(input_index + 1) // sign all outputs up to and including this one, but erase - .enumerate() // all of them except for this one - .map(|(n, out)| if n == input_index { out.clone() } else { TxOut::default() }); - output_iter.collect() - } - SigHashType::None => vec![], - _ => unreachable!() - }; - // hash the result - let mut raw_vec = serialize(&tx); - raw_vec.extend_from_slice(&endian::u32_to_array_le(sighash_u32)); - SigHash::hash(&raw_vec) - } - - /// Gets the "weight" of this transaction, as defined by BIP141. For transactions with an empty - /// witness, this is simply the consensus-serialized size times 4. For transactions with a - /// witness, this is the non-witness consensus-serialized size multiplied by 3 plus the - /// with-witness consensus-serialized size. - #[inline] - pub fn get_weight(&self) -> usize { - let mut input_weight = 0; - let mut inputs_with_witnesses = 0; - for input in &self.input { - input_weight += 4*(32 + 4 + 4 + // outpoint (32+4) + nSequence - VarInt(input.script_sig.len() as u64).len() + - input.script_sig.len()); - if !input.witness.is_empty() { - inputs_with_witnesses += 1; - input_weight += VarInt(input.witness.len() as u64).len(); - for elem in &input.witness { - input_weight += VarInt(elem.len() as u64).len() + elem.len(); - } - } - } - let mut output_size = 0; - for output in &self.output { - output_size += 8 + // value - VarInt(output.script_pubkey.len() as u64).len() + - output.script_pubkey.len(); - } - let non_input_size = - // version: - 4 + - // count varints: - VarInt(self.input.len() as u64).len() + - VarInt(self.output.len() as u64).len() + - output_size + - // lock_time - 4; - if inputs_with_witnesses == 0 { - non_input_size * 4 + input_weight - } else { - non_input_size * 4 + input_weight + self.input.len() - inputs_with_witnesses + 2 - } - } - - #[cfg(feature="bitcoinconsensus")] - /// Verify that this transaction is able to spend its inputs - /// The lambda spent should not return the same TxOut twice! - pub fn verify(&self, mut spent: S) -> Result<(), script::Error> - where S: FnMut(&OutPoint) -> Option { - let tx = serialize(&*self); - for (idx, input) in self.input.iter().enumerate() { - if let Some(output) = spent(&input.previous_output) { - output.script_pubkey.verify(idx, output.value, tx.as_slice())?; - } else { - return Err(script::Error::UnknownSpentOutput(input.previous_output.clone())); - } - } - Ok(()) - } - - /// Is this a coin base transaction? - pub fn is_coin_base(&self) -> bool { - self.input.len() == 1 && self.input[0].previous_output.is_null() - } -} - -impl_consensus_encoding!(TxOut, value, script_pubkey); - -impl Encodable for OutPoint { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let len = self.txid.consensus_encode(&mut s)?; - Ok(len + self.vout.consensus_encode(s)?) - } -} -impl Decodable for OutPoint { - fn consensus_decode(mut d: D) -> Result { - Ok(OutPoint { - txid: Decodable::consensus_decode(&mut d)?, - vout: Decodable::consensus_decode(d)?, - }) - } -} - -impl Encodable for TxIn { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let mut len = 0; - len += self.previous_output.consensus_encode(&mut s)?; - len += self.script_sig.consensus_encode(&mut s)?; - len += self.sequence.consensus_encode(s)?; - Ok(len) - } -} -impl Decodable for TxIn { - fn consensus_decode(mut d: D) -> Result { - Ok(TxIn { - previous_output: Decodable::consensus_decode(&mut d)?, - script_sig: Decodable::consensus_decode(&mut d)?, - sequence: Decodable::consensus_decode(d)?, - witness: vec![], - }) - } -} - -impl Encodable for Transaction { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let mut len = 0; - len += self.version.consensus_encode(&mut s)?; - let mut have_witness = self.input.is_empty(); - for input in &self.input { - if !input.witness.is_empty() { - have_witness = true; - break; - } - } - if !have_witness { - len += self.input.consensus_encode(&mut s)?; - len += self.output.consensus_encode(&mut s)?; - } else { - len += 0u8.consensus_encode(&mut s)?; - len += 1u8.consensus_encode(&mut s)?; - len += self.input.consensus_encode(&mut s)?; - len += self.output.consensus_encode(&mut s)?; - for input in &self.input { - len += input.witness.consensus_encode(&mut s)?; - } - } - len += self.lock_time.consensus_encode(s)?; - Ok(len) - } -} - -impl Decodable for Transaction { - fn consensus_decode(mut d: D) -> Result { - let version = u32::consensus_decode(&mut d)?; - let input = Vec::::consensus_decode(&mut d)?; - // segwit - if input.is_empty() { - let segwit_flag = u8::consensus_decode(&mut d)?; - match segwit_flag { - // BIP144 input witnesses - 1 => { - let mut input = Vec::::consensus_decode(&mut d)?; - let output = Vec::::consensus_decode(&mut d)?; - for txin in input.iter_mut() { - txin.witness = Decodable::consensus_decode(&mut d)?; - } - if !input.is_empty() && input.iter().all(|input| input.witness.is_empty()) { - Err(encode::Error::ParseFailed("witness flag set but no witnesses present")) - } else { - Ok(Transaction { - version: version, - input: input, - output: output, - lock_time: Decodable::consensus_decode(d)?, - }) - } - } - // We don't support anything else - x => { - Err(encode::Error::UnsupportedSegwitFlag(x)) - } - } - // non-segwit - } else { - Ok(Transaction { - version: version, - input: input, - output: Decodable::consensus_decode(&mut d)?, - lock_time: Decodable::consensus_decode(d)?, - }) - } - } -} - -/// Hashtype of a transaction, encoded in the last byte of a signature -/// Fixed values so they can be casted as integer types for encoding -#[derive(PartialEq, Eq, Debug, Copy, Clone)] -pub enum SigHashType { - /// 0x1: Sign all outputs - All = 0x01, - /// 0x2: Sign no outputs --- anyone can choose the destination - None = 0x02, - /// 0x3: Sign the output whose index matches this input's index. If none exists, - /// sign the hash `0000000000000000000000000000000000000000000000000000000000000001`. - /// (This rule is probably an unintentional C++ism, but it's consensus so we have - /// to follow it.) - Single = 0x03, - /// 0x81: Sign all outputs but only this input - AllPlusAnyoneCanPay = 0x81, - /// 0x82: Sign no outputs and only this input - NonePlusAnyoneCanPay = 0x82, - /// 0x83: Sign one output and only this input (see `Single` for what "one output" means) - SinglePlusAnyoneCanPay = 0x83 -} - -impl SigHashType { - /// Break the sighash flag into the "real" sighash flag and the ANYONECANPAY boolean - fn split_anyonecanpay_flag(&self) -> (SigHashType, bool) { - match *self { - SigHashType::All => (SigHashType::All, false), - SigHashType::None => (SigHashType::None, false), - SigHashType::Single => (SigHashType::Single, false), - SigHashType::AllPlusAnyoneCanPay => (SigHashType::All, true), - SigHashType::NonePlusAnyoneCanPay => (SigHashType::None, true), - SigHashType::SinglePlusAnyoneCanPay => (SigHashType::Single, true) - } - } - - /// Reads a 4-byte uint32 as a sighash type - pub fn from_u32(n: u32) -> SigHashType { - match n & 0x9f { - // "real" sighashes - 0x01 => SigHashType::All, - 0x02 => SigHashType::None, - 0x03 => SigHashType::Single, - 0x81 => SigHashType::AllPlusAnyoneCanPay, - 0x82 => SigHashType::NonePlusAnyoneCanPay, - 0x83 => SigHashType::SinglePlusAnyoneCanPay, - // catchalls - x if x & 0x80 == 0x80 => SigHashType::AllPlusAnyoneCanPay, - _ => SigHashType::All - } - } - - /// Converts to a u32 - pub fn as_u32(&self) -> u32 { *self as u32 } -} - - -#[cfg(test)] -mod tests { - use super::{OutPoint, ParseOutPointError, Transaction, TxIn}; - - use std::str::FromStr; - use blockdata::script::Script; - use consensus::encode::serialize; - use consensus::encode::deserialize; - - use hashes::Hash; - use hashes::hex::FromHex; - - use hash_types::*; - - #[test] - fn test_outpoint() { - assert_eq!(OutPoint::from_str("i don't care"), - Err(ParseOutPointError::Format)); - assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:1:1"), - Err(ParseOutPointError::Format)); - assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:"), - Err(ParseOutPointError::Format)); - assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:11111111111"), - Err(ParseOutPointError::TooLong)); - assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:01"), - Err(ParseOutPointError::VoutNotCanonical)); - assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:+42"), - Err(ParseOutPointError::VoutNotCanonical)); - assert_eq!(OutPoint::from_str("i don't care:1"), - Err(ParseOutPointError::Txid(Txid::from_hex("i don't care").unwrap_err()))); - assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c945X:1"), - Err(ParseOutPointError::Txid(Txid::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c945X").unwrap_err()))); - assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:lol"), - Err(ParseOutPointError::Vout(u32::from_str("lol").unwrap_err()))); - - assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:42"), - Ok(OutPoint{ - txid: Txid::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap(), - vout: 42, - })); - assert_eq!(OutPoint::from_str("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:0"), - Ok(OutPoint{ - txid: Txid::from_hex("5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456").unwrap(), - vout: 0, - })); - } - - #[test] - fn test_txin() { - let txin: Result = deserialize(&Vec::::from_hex("a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff").unwrap()); - assert!(txin.is_ok()); - } - - #[test] - fn test_txin_default() { - let txin = TxIn::default(); - assert_eq!(txin.previous_output, OutPoint::default()); - assert_eq!(txin.script_sig, Script::new()); - assert_eq!(txin.sequence, 0xFFFFFFFF); - assert_eq!(txin.previous_output, OutPoint::default()); - assert_eq!(txin.witness.len(), 0 as usize); - } - - #[test] - fn test_is_coinbase () { - use network::constants::Network; - use blockdata::constants; - - let genesis = constants::genesis_block(Network::Bitcoin); - assert! (genesis.txdata[0].is_coin_base()); - let hex_tx = Vec::::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap(); - let tx: Transaction = deserialize(&hex_tx).unwrap(); - assert!(!tx.is_coin_base()); - } - - #[test] - fn test_nonsegwit_transaction() { - let hex_tx = Vec::::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap(); - let tx: Result = deserialize(&hex_tx); - assert!(tx.is_ok()); - let realtx = tx.unwrap(); - // All these tests aren't really needed because if they fail, the hash check at the end - // will also fail. But these will show you where the failure is so I'll leave them in. - assert_eq!(realtx.version, 1); - assert_eq!(realtx.input.len(), 1); - // In particular this one is easy to get backward -- in bitcoin hashes are encoded - // as little-endian 256-bit numbers rather than as data strings. - assert_eq!(format!("{:x}", realtx.input[0].previous_output.txid), - "ce9ea9f6f5e422c6a9dbcddb3b9a14d1c78fab9ab520cb281aa2a74a09575da1".to_string()); - assert_eq!(realtx.input[0].previous_output.vout, 1); - assert_eq!(realtx.output.len(), 1); - assert_eq!(realtx.lock_time, 0); - - assert_eq!(format!("{:x}", realtx.txid()), - "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()); - assert_eq!(format!("{:x}", realtx.wtxid()), - "a6eab3c14ab5272a58a5ba91505ba1a4b6d7a3a9fcbd187b6cd99a7b6d548cb7".to_string()); - assert_eq!(realtx.get_weight(), 193*4); - } - - #[test] - fn test_segwit_transaction() { - let hex_tx = Vec::::from_hex( - "02000000000101595895ea20179de87052b4046dfe6fd515860505d6511a9004cf12a1f93cac7c01000000\ - 00ffffffff01deb807000000000017a9140f3444e271620c736808aa7b33e370bd87cb5a078702483045022\ - 100fb60dad8df4af2841adc0346638c16d0b8035f5e3f3753b88db122e70c79f9370220756e6633b17fd271\ - 0e626347d28d60b0a2d6cbb41de51740644b9fb3ba7751040121028fa937ca8cba2197a37c007176ed89410\ - 55d3bcb8627d085e94553e62f057dcc00000000" - ).unwrap(); - let tx: Result = deserialize(&hex_tx); - assert!(tx.is_ok()); - let realtx = tx.unwrap(); - // All these tests aren't really needed because if they fail, the hash check at the end - // will also fail. But these will show you where the failure is so I'll leave them in. - assert_eq!(realtx.version, 2); - assert_eq!(realtx.input.len(), 1); - // In particular this one is easy to get backward -- in bitcoin hashes are encoded - // as little-endian 256-bit numbers rather than as data strings. - assert_eq!(format!("{:x}", realtx.input[0].previous_output.txid), - "7cac3cf9a112cf04901a51d605058615d56ffe6d04b45270e89d1720ea955859".to_string()); - assert_eq!(realtx.input[0].previous_output.vout, 1); - assert_eq!(realtx.output.len(), 1); - assert_eq!(realtx.lock_time, 0); - - assert_eq!(format!("{:x}", realtx.txid()), - "f5864806e3565c34d1b41e716f72609d00b55ea5eac5b924c9719a842ef42206".to_string()); - assert_eq!(format!("{:x}", realtx.wtxid()), - "80b7d8a82d5d5bf92905b06f2014dd699e03837ca172e3a59d51426ebbe3e7f5".to_string()); - assert_eq!(realtx.get_weight(), 442); - } - - #[test] - fn tx_no_input_deserialization() { - let hex_tx = Vec::::from_hex( - "010000000001000100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000" - ).unwrap(); - let tx: Transaction = deserialize(&hex_tx).expect("deserialize tx"); - - assert_eq!(tx.input.len(), 0); - assert_eq!(tx.output.len(), 1); - - let reser = serialize(&tx); - assert_eq!(hex_tx, reser); - } - - #[test] - fn test_ntxid() { - let hex_tx = Vec::::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap(); - let mut tx: Transaction = deserialize(&hex_tx).unwrap(); - - let old_ntxid = tx.ntxid(); - assert_eq!(format!("{:x}", old_ntxid), "c3573dbea28ce24425c59a189391937e00d255150fa973d59d61caf3a06b601d"); - // changing sigs does not affect it - tx.input[0].script_sig = Script::new(); - assert_eq!(old_ntxid, tx.ntxid()); - // changing pks does - tx.output[0].script_pubkey = Script::new(); - assert!(old_ntxid != tx.ntxid()); - } - - #[test] - fn test_txid() { - // segwit tx from Liquid integration tests, txid/hash from Core decoderawtransaction - let hex_tx = Vec::::from_hex( - "01000000000102ff34f95a672bb6a4f6ff4a7e90fa8c7b3be7e70ffc39bc99be3bda67942e836c00000000\ - 23220020cde476664d3fa347b8d54ef3aee33dcb686a65ced2b5207cbf4ec5eda6b9b46e4f414d4c934ad8\ - 1d330314e888888e3bd22c7dde8aac2ca9227b30d7c40093248af7812201000000232200200af6f6a071a6\ - 9d5417e592ed99d256ddfd8b3b2238ac73f5da1b06fc0b2e79d54f414d4c0ba0c8f505000000001976a914\ - dcb5898d9036afad9209e6ff0086772795b1441088ac033c0f000000000017a914889f8c10ff2bd4bb9dab\ - b68c5c0d700a46925e6c87033c0f000000000017a914889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c87\ - 033c0f000000000017a914889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c87033c0f000000000017a914\ - 889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c87033c0f000000000017a914889f8c10ff2bd4bb9dabb6\ - 8c5c0d700a46925e6c87033c0f000000000017a914889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c8703\ - 3c0f000000000017a914889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c87033c0f000000000017a91488\ - 9f8c10ff2bd4bb9dabb68c5c0d700a46925e6c87033c0f000000000017a914889f8c10ff2bd4bb9dabb68c\ - 5c0d700a46925e6c87033c0f000000000017a914889f8c10ff2bd4bb9dabb68c5c0d700a46925e6c870500\ - 47304402200380b8663e727d7e8d773530ef85d5f82c0b067c97ae927800a0876a1f01d8e2022021ee611e\ - f6507dfd217add2cd60a8aea3cbcfec034da0bebf3312d19577b8c290147304402207bd9943ce1c2c5547b\ - 120683fd05d78d23d73be1a5b5a2074ff586b9c853ed4202202881dcf435088d663c9af7b23efb3c03b9db\ - c0c899b247aa94a74d9b4b3c84f501483045022100ba12bba745af3f18f6e56be70f8382ca8e107d1ed5ce\ - aa3e8c360d5ecf78886f022069b38ebaac8fe6a6b97b497cbbb115f3176f7213540bef08f9292e5a72de52\ - de01695321023c9cd9c6950ffee24772be948a45dc5ef1986271e46b686cb52007bac214395a2102756e27\ - cb004af05a6e9faed81fd68ff69959e3c64ac8c9f6cd0e08fd0ad0e75d2103fa40da236bd82202a985a910\ - 4e851080b5940812685769202a3b43e4a8b13e6a53ae050048304502210098b9687b81d725a7970d1eee91\ - ff6b89bc9832c2e0e3fb0d10eec143930b006f02206f77ce19dc58ecbfef9221f81daad90bb4f468df3912\ - 12abc4f084fe2cc9bdef01483045022100e5479f81a3ad564103da5e2ec8e12f61f3ac8d312ab68763c1dd\ - d7bae94c20610220789b81b7220b27b681b1b2e87198897376ba9d033bc387f084c8b8310c8539c2014830\ - 45022100aa1cc48a2d256c0e556616444cc08ae4959d464e5ffff2ae09e3550bdab6ce9f02207192d5e332\ - 9a56ba7b1ead724634d104f1c3f8749fe6081e6233aee3e855817a016953210260de9cc68658c61af984e3\ - ab0281d17cfca1cc035966d335f474932d5e6c5422210355fbb768ce3ce39360277345dbb5f376e706459e\ - 5a2b5e0e09a535e61690647021023222ceec58b94bd25925dd9743dae6b928737491bd940fc5dd7c6f5d5f\ - 2adc1e53ae00000000" - ).unwrap(); - let tx: Transaction = deserialize(&hex_tx).unwrap(); - - assert_eq!(format!("{:x}", tx.wtxid()), "d6ac4a5e61657c4c604dcde855a1db74ec6b3e54f32695d72c5e11c7761ea1b4"); - assert_eq!(format!("{:x}", tx.txid()), "9652aa62b0e748caeec40c4cb7bc17c6792435cc3dfe447dd1ca24f912a1c6ec"); - assert_eq!(tx.get_weight(), 2718); - - // non-segwit tx from my mempool - let hex_tx = Vec::::from_hex( - "01000000010c7196428403d8b0c88fcb3ee8d64f56f55c8973c9ab7dd106bb4f3527f5888d000000006a47\ - 30440220503a696f55f2c00eee2ac5e65b17767cd88ed04866b5637d3c1d5d996a70656d02202c9aff698f\ - 343abb6d176704beda63fcdec503133ea4f6a5216b7f925fa9910c0121024d89b5a13d6521388969209df2\ - 7a8469bd565aff10e8d42cef931fad5121bfb8ffffffff02b825b404000000001976a914ef79e7ee9fff98\ - bcfd08473d2b76b02a48f8c69088ac0000000000000000296a273236303039343836393731373233313237\ - 3633313032313332353630353838373931323132373000000000" - ).unwrap(); - let tx: Transaction = deserialize(&hex_tx).unwrap(); - - assert_eq!(format!("{:x}", tx.wtxid()), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"); - assert_eq!(format!("{:x}", tx.txid()), "971ed48a62c143bbd9c87f4bafa2ef213cfa106c6e140f111931d0be307468dd"); - } - - #[test] - #[cfg(feature = "serde")] - fn test_txn_encode_decode() { - let hex_tx = Vec::::from_hex("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap(); - let tx: Transaction = deserialize(&hex_tx).unwrap(); - serde_round_trip!(tx); - } - - fn run_test_sighash(tx: &str, script: &str, input_index: usize, hash_type: i32, expected_result: &str) { - let tx: Transaction = deserialize(&Vec::::from_hex(tx).unwrap()[..]).unwrap(); - let script = Script::from(Vec::::from_hex(script).unwrap()); - let mut raw_expected = Vec::::from_hex(expected_result).unwrap(); - raw_expected.reverse(); - let expected_result = SigHash::from_slice(&raw_expected[..]).unwrap(); - - let actual_result = tx.signature_hash(input_index, &script, hash_type as u32); - assert_eq!(actual_result, expected_result); - } - - // Test decoding transaction `4be105f158ea44aec57bf12c5817d073a712ab131df6f37786872cfc70734188` - // from testnet, which is the first BIP144-encoded transaction I encountered. - #[test] - #[cfg(feature = "serde")] - fn test_segwit_tx_decode() { - let hex_tx = Vec::::from_hex("010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a39837040120000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); - let tx: Transaction = deserialize(&hex_tx).unwrap(); - assert_eq!(tx.get_weight(), 780); - serde_round_trip!(tx); - - let consensus_encoded = serialize(&tx); - assert_eq!(consensus_encoded, hex_tx); - } - - - // These test vectors were stolen from libbtc, which is Copyright 2014 Jonas Schnelli MIT - // They were transformed by replacing {...} with run_test_sighash(...), then the ones containing - // OP_CODESEPARATOR in their pubkeys were removed - #[test] - fn test_sighash() { - run_test_sighash("907c2bc503ade11cc3b04eb2918b6f547b0630ab569273824748c87ea14b0696526c66ba740200000004ab65ababfd1f9bdd4ef073c7afc4ae00da8a66f429c917a0081ad1e1dabce28d373eab81d8628de802000000096aab5253ab52000052ad042b5f25efb33beec9f3364e8a9139e8439d9d7e26529c3c30b6c3fd89f8684cfd68ea0200000009ab53526500636a52ab599ac2fe02a526ed040000000008535300516352515164370e010000000003006300ab2ec229", "", 2, 1864164639, "31af167a6cf3f9d5f6875caa4d31704ceb0eba078d132b78dab52c3b8997317e"); - run_test_sighash("a0aa3126041621a6dea5b800141aa696daf28408959dfb2df96095db9fa425ad3f427f2f6103000000015360290e9c6063fa26912c2e7fb6a0ad80f1c5fea1771d42f12976092e7a85a4229fdb6e890000000001abc109f6e47688ac0e4682988785744602b8c87228fcef0695085edf19088af1a9db126e93000000000665516aac536affffffff8fe53e0806e12dfd05d67ac68f4768fdbe23fc48ace22a5aa8ba04c96d58e2750300000009ac51abac63ab5153650524aa680455ce7b000000000000499e50030000000008636a00ac526563ac5051ee030000000003abacabd2b6fe000000000003516563910fb6b5", "65", 0, -1391424484, "48d6a1bd2cd9eec54eb866fc71209418a950402b5d7e52363bfb75c98e141175"); - run_test_sighash("73107cbd025c22ebc8c3e0a47b2a760739216a528de8d4dab5d45cbeb3051cebae73b01ca10200000007ab6353656a636affffffffe26816dffc670841e6a6c8c61c586da401df1261a330a6c6b3dd9f9a0789bc9e000000000800ac6552ac6aac51ffffffff0174a8f0010000000004ac52515100000000", "5163ac63635151ac", 1, 1190874345, "06e328de263a87b09beabe222a21627a6ea5c7f560030da31610c4611f4a46bc"); - run_test_sighash("50818f4c01b464538b1e7e7f5ae4ed96ad23c68c830e78da9a845bc19b5c3b0b20bb82e5e9030000000763526a63655352ffffffff023b3f9c040000000008630051516a6a5163a83caf01000000000553ab65510000000000", "6aac", 0, 946795545, "746306f322de2b4b58ffe7faae83f6a72433c22f88062cdde881d4dd8a5a4e2d"); - run_test_sighash("a93e93440250f97012d466a6cc24839f572def241c814fe6ae94442cf58ea33eb0fdd9bcc1030000000600636a0065acffffffff5dee3a6e7e5ad6310dea3e5b3ddda1a56bf8de7d3b75889fc024b5e233ec10f80300000007ac53635253ab53ffffffff0160468b04000000000800526a5300ac526a00000000", "ac00636a53", 1, 1773442520, "5c9d3a2ce9365bb72cfabbaa4579c843bb8abf200944612cf8ae4b56a908bcbd"); - run_test_sighash("d3b7421e011f4de0f1cea9ba7458bf3486bee722519efab711a963fa8c100970cf7488b7bb0200000003525352dcd61b300148be5d05000000000000000000", "535251536aac536a", 0, -1960128125, "29aa6d2d752d3310eba20442770ad345b7f6a35f96161ede5f07b33e92053e2a"); - run_test_sighash("04bac8c5033460235919a9c63c42b2db884c7c8f2ed8fcd69ff683a0a2cccd9796346a04050200000003655351fcad3a2c5a7cbadeb4ec7acc9836c3f5c3e776e5c566220f7f965cf194f8ef98efb5e3530200000007526a006552526526a2f55ba5f69699ece76692552b399ba908301907c5763d28a15b08581b23179cb01eac03000000075363ab6a516351073942c2025aa98a05000000000765006aabac65abd7ffa6030000000004516a655200000000", "53ac6365ac526a", 1, 764174870, "bf5fdc314ded2372a0ad078568d76c5064bf2affbde0764c335009e56634481b"); - run_test_sighash("c363a70c01ab174230bbe4afe0c3efa2d7f2feaf179431359adedccf30d1f69efe0c86ed390200000002ab51558648fe0231318b04000000000151662170000000000008ac5300006a63acac00000000", "", 0, 2146479410, "191ab180b0d753763671717d051f138d4866b7cb0d1d4811472e64de595d2c70"); - run_test_sighash("8d437a7304d8772210a923fd81187c425fc28c17a5052571501db05c7e89b11448b36618cd02000000026a6340fec14ad2c9298fde1477f1e8325e5747b61b7e2ff2a549f3d132689560ab6c45dd43c3010000000963ac00ac000051516a447ed907a7efffebeb103988bf5f947fc688aab2c6a7914f48238cf92c337fad4a79348102000000085352ac526a5152517436edf2d80e3ef06725227c970a816b25d0b58d2cd3c187a7af2cea66d6b27ba69bf33a0300000007000063ab526553f3f0d6140386815d030000000003ab6300de138f00000000000900525153515265abac1f87040300000000036aac6500000000", "51", 3, -315779667, "b6632ac53578a741ae8c36d8b69e79f39b89913a2c781cdf1bf47a8c29d997a5"); - run_test_sighash("fd878840031e82fdbe1ad1d745d1185622b0060ac56638290ec4f66b1beef4450817114a2c0000000009516a63ab53650051abffffffff37b7a10322b5418bfd64fb09cd8a27ddf57731aeb1f1f920ffde7cb2dfb6cdb70300000008536a5365ac53515369ecc034f1594690dbe189094dc816d6d57ea75917de764cbf8eccce4632cbabe7e116cd0100000003515352ffffffff035777fc000000000003515200abe9140300000000050063005165bed6d10200000000076300536363ab65195e9110", "635265", 0, 1729787658, "6e3735d37a4b28c45919543aabcb732e7a3e1874db5315abb7cc6b143d62ff10"); - run_test_sighash("a63bc673049c75211aa2c09ecc38e360eaa571435fedd2af1116b5c1fa3d0629c269ecccbf0000000008ac65ab516352ac52ffffffffbf1a76fdda7f451a5f0baff0f9ccd0fe9136444c094bb8c544b1af0fa2774b06010000000463535253ffffffff13d6b7c3ddceef255d680d87181e100864eeb11a5bb6a3528cb0d70d7ee2bbbc02000000056a0052abab951241809623313b198bb520645c15ec96bfcc74a2b0f3db7ad61d455cc32db04afc5cc702000000016309c9ae25014d9473020000000004abab6aac3bb1e803", "", 3, -232881718, "6e48f3da3a4ac07eb4043a232df9f84e110485d7c7669dd114f679c27d15b97e"); - run_test_sighash("4c565efe04e7d32bac03ae358d63140c1cfe95de15e30c5b84f31bb0b65bb542d637f49e0f010000000551abab536348ae32b31c7d3132030a510a1b1aacf7b7c3f19ce8dc49944ef93e5fa5fe2d356b4a73a00100000009abac635163ac00ab514c8bc57b6b844e04555c0a4f4fb426df139475cd2396ae418bc7015820e852f711519bc202000000086a00510000abac52488ff4aec72cbcfcc98759c58e20a8d2d9725aa4a80f83964e69bc4e793a4ff25cd75dc701000000086a52ac6aac5351532ec6b10802463e0200000000000553005265523e08680100000000002f39a6b0", "", 3, 70712784, "c6076b6a45e6fcfba14d3df47a34f6aadbacfba107e95621d8d7c9c0e40518ed"); - run_test_sighash("fd22692802db8ae6ab095aeae3867305a954278f7c076c542f0344b2591789e7e33e4d29f4020000000151ffffffffb9409129cfed9d3226f3b6bab7a2c83f99f48d039100eeb5796f00903b0e5e5e0100000006656552ac63abd226abac0403e649000000000007abab51ac5100ac8035f10000000000095165006a63526a52510d42db030000000007635365ac6a63ab24ef5901000000000453ab6a0000000000", "536a52516aac6a", 1, 309309168, "7ca0f75e6530ec9f80d031fc3513ca4ecd67f20cb38b4dacc6a1d825c3cdbfdb"); - run_test_sighash("a43f85f701ffa54a3cc57177510f3ea28ecb6db0d4431fc79171cad708a6054f6e5b4f89170000000008ac6a006a536551652bebeaa2013e779c05000000000665ac5363635100000000", "ac", 0, 2028978692, "58294f0d7f2e68fe1fd30c01764fe1619bcc7961d68968944a0e263af6550437"); - run_test_sighash("c2b0b99001acfecf7da736de0ffaef8134a9676811602a6299ba5a2563a23bb09e8cbedf9300000000026300ffffffff042997c50300000000045252536a272437030000000007655353ab6363ac663752030000000002ab6a6d5c900000000000066a6a5265abab00000000", "52ac525163515251", 0, -894181723, "8b300032a1915a4ac05cea2f7d44c26f2a08d109a71602636f15866563eaafdc"); - run_test_sighash("82f9f10304c17a9d954cf3380db817814a8c738d2c811f0412284b2c791ec75515f38c4f8c020000000265ab5729ca7db1b79abee66c8a757221f29280d0681355cb522149525f36da760548dbd7080a0100000001510b477bd9ce9ad5bb81c0306273a3a7d051e053f04ecf3a1dbeda543e20601a5755c0cfae030000000451ac656affffffff71141a04134f6c292c2e0d415e6705dfd8dcee892b0d0807828d5aeb7d11f5ef0300000001520b6c6dc802a6f3dd0000000000056aab515163bfb6800300000000015300000000", "", 3, -635779440, "d55ed1e6c53510f2608716c12132a11fb5e662ec67421a513c074537eeccc34b"); - run_test_sighash("2074bad5011847f14df5ea7b4afd80cd56b02b99634893c6e3d5aaad41ca7c8ee8e5098df003000000026a6affffffff018ad59700000000000900ac656a526551635300000000", "65635265", 0, -1804671183, "663c999a52288c9999bff36c9da2f8b78d5c61b8347538f76c164ccba9868d0a"); - run_test_sighash("7100b11302e554d4ef249ee416e7510a485e43b2ba4b8812d8fe5529fe33ea75f36d392c4403000000020000ffffffff3d01a37e075e9a7715a657ae1bdf1e44b46e236ad16fd2f4c74eb9bf370368810000000007636553ac536365ffffffff01db696a0400000000065200ac656aac00000000", "63005151", 0, -1210499507, "b9c3aee8515a4a3b439de1ffc9c156824bda12cb75bfe5bc863164e8fd31bd7a"); - run_test_sighash("02c1017802091d1cb08fec512db7b012fe4220d57a5f15f9e7676358b012786e1209bcff950100000004acab6352ffffffff799bc282724a970a6fea1828984d0aeb0f16b67776fa213cbdc4838a2f1961a3010000000951516a536552ab6aabffffffff016c7b4b03000000000865abac5253ac5352b70195ad", "65655200516a", 0, -241626954, "be567cb47170b34ff81c66c1142cb9d27f9b6898a384d6dfc4fce16b75b6cb14"); - run_test_sighash("4504cb1904c7a4acf375ddae431a74de72d5436efc73312cf8e9921f431267ea6852f9714a01000000066a656a656553a2fbd587c098b3a1c5bd1d6480f730a0d6d9b537966e20efc0e352d971576d0f87df0d6d01000000016321aeec3c4dcc819f1290edb463a737118f39ab5765800547522708c425306ebfca3f396603000000055300ac656a1d09281d05bfac57b5eb17eb3fa81ffcedfbcd3a917f1be0985c944d473d2c34d245eb350300000007656a51525152ac263078d9032f470f0500000000066aac00000052e12da60200000000003488410200000000076365006300ab539981e432", "52536a52526a", 1, -31909119, "f0a2deee7fd8a3a9fad6927e763ded11c940ee47e9e6d410f94fda5001f82e0c"); - run_test_sighash("14bc7c3e03322ec0f1311f4327e93059c996275302554473104f3f7b46ca179bfac9ef753503000000016affffffff9d405eaeffa1ca54d9a05441a296e5cc3a3e32bb8307afaf167f7b57190b07e00300000008abab51ab5263abab45533aa242c61bca90dd15d46079a0ab0841d85df67b29ba87f2393cd764a6997c372b55030000000452005263ffffffff0250f40e02000000000651516a0063630e95ab0000000000046a5151ac00000000", "6a65005151", 0, -1460947095, "aa418d096929394c9147be8818d8c9dafe6d105945ab9cd7ec682df537b5dd79"); - run_test_sighash("a08ff466049fb7619e25502ec22fedfb229eaa1fe275aa0b5a23154b318441bf547989d0510000000005ab5363636affffffff2b0e335cb5383886751cdbd993dc0720817745a6b1c9b8ab3d15547fc9aafd03000000000965656a536a52656a532b53d10584c290d3ac1ab74ab0a19201a4a039cb59dc58719821c024f6bf2eb26322b33f010000000965ac6aac0053ab6353ffffffff048decba6ebbd2db81e416e39dde1f821ba69329725e702bcdea20c5cc0ecc6402000000086363ab5351ac6551466e377b0468c0fa00000000000651ab53ac6a513461c6010000000008636a636365535100eeb3dc010000000006526a52ac516a43f362010000000005000063536500000000", "0063516a", 1, -1158911348, "f6a1ecb50bd7c2594ebecea5a1aa23c905087553e40486dade793c2f127fdfae"); - run_test_sighash("f10a0356031cd569d652dbca8e7a4d36c8da33cdff428d003338602b7764fe2c96c505175b010000000465ac516affffffffbb54563c71136fa944ee20452d78dc87073ac2365ba07e638dce29a5d179da600000000003635152ffffffff9a411d8e2d421b1e6085540ee2809901e590940bbb41532fa38bd7a16b68cc350100000007535251635365636195df1603b61c45010000000002ab65bf6a310400000000026352fcbba10200000000016aa30b7ff0", "5351", 0, 1552495929, "9eb8adf2caecb4bf9ac59d7f46bd20e83258472db2f569ee91aba4cf5ee78e29"); - run_test_sighash("c3325c9b012f659466626ca8f3c61dfd36f34670abc054476b7516a1839ec43cd0870aa0c0000000000753525265005351e7e3f04b0112650500000000000363ac6300000000", "acac", 0, -68961433, "5ca70e727d91b1a42b78488af2ed551642c32d3de4712a51679f60f1456a8647"); - run_test_sighash("b500ca48011ec57c2e5252e5da6432089130603245ffbafb0e4c5ffe6090feb629207eeb0e010000000652ab6a636aab8302c9d2042b44f40500000000015278c05a050000000004ac5251524be080020000000007636aac63ac5252c93a9a04000000000965ab6553636aab5352d91f9ddb", "52005100", 0, -2024394677, "49c8a6940a461cc7225637f1e512cdd174c99f96ec05935a59637ededc77124c"); - run_test_sighash("f52ff64b02ee91adb01f3936cc42e41e1672778962b68cf013293d649536b519bc3271dd2c00000000020065afee11313784849a7c15f44a61cd5fd51ccfcdae707e5896d131b082dc9322a19e12858501000000036aac654e8ca882022deb7c020000000006006a515352abd3defc0000000000016300000000", "63520063", 0, 1130989496, "7f208df9a5507e98c62cebc5c1e2445eb632e95527594929b9577b53363e96f6"); - run_test_sighash("ab7d6f36027a7adc36a5cf7528fe4fb5d94b2c96803a4b38a83a675d7806dda62b380df86a0000000003000000ffffffff5bc00131e29e22057c04be854794b4877dda42e416a7a24706b802ff9da521b20000000007ac6a0065ac52ac957cf45501b9f06501000000000500ac6363ab25f1110b", "00526500536a635253", 0, 911316637, "5fa09d43c8aef6f6fa01c383a69a5a61a609cd06e37dce35a39dc9eae3ddfe6c"); - run_test_sighash("f940888f023dce6360263c850372eb145b864228fdbbb4c1186174fa83aab890ff38f8c9a90300000000ffffffff01e80ccdb081e7bbae1c776531adcbfb77f2e5a7d0e5d0d0e2e6c8758470e85f00000000020053ffffffff03b49088050000000004656a52ab428bd604000000000951630065ab63ac636a0cbacf0400000000070063ac5265ac53d6e16604", "ac63", 0, 39900215, "713ddeeefcfe04929e7b6593c792a4efbae88d2b5280d1f0835d2214eddcbad6"); - run_test_sighash("530ecd0b01ec302d97ef6f1b5a6420b9a239714013e20d39aa3789d191ef623fc215aa8b940200000005ac5351ab6a3823ab8202572eaa04000000000752ab6a51526563fd8a270100000000036a006581a798f0", "525153656a0063", 0, 1784562684, "fe42f73a8742676e640698222b1bd6b9c338ff1ccd766d3d88d7d3c6c6ac987e"); - run_test_sighash("5d781d9303acfcce964f50865ddfddab527ea971aee91234c88e184979985c00b4de15204b0100000003ab6352a009c8ab01f93c8ef2447386c434b4498538f061845862c3f9d5751ad0fce52af442b3a902000000045165ababb909c66b5a3e7c81b3c45396b944be13b8aacfc0204f3f3c105a66fa8fa6402f1b5efddb01000000096a65ac636aacab656ac3c677c402b79fa4050000000004006aab5133e35802000000000751ab635163ab0078c2e025", "6aac51636a6a005265", 0, -882306874, "551ce975d58647f10adefb3e529d9bf9cda34751627ec45e690f135ef0034b95"); - run_test_sighash("a9c57b1a018551bcbc781b256642532bbc09967f1cbe30a227d352a19365d219d3f11649a3030000000451655352b140942203182894030000000006ab00ac6aab654add350400000000003d379505000000000553abacac00e1739d36", "5363", 0, -1069721025, "6da32416deb45a0d720a1dbe6d357886eabc44029dd5db74d50feaffbe763245"); - run_test_sighash("05c4fb94040f5119dc0b10aa9df054871ed23c98c890f1e931a98ffb0683dac45e98619fdc0200000007acab6a525263513e7495651c9794c4d60da835d303eb4ee6e871f8292f6ad0b32e85ef08c9dc7aa4e03c9c010000000500ab52acacfffffffffee953259cf14ced323fe8d567e4c57ba331021a1ef5ac2fa90f7789340d7c550100000007ac6aacac6a6a53ffffffff08d9dc820d00f18998af247319f9de5c0bbd52a475ea587f16101af3afab7c210100000003535363569bca7c0468e34f00000000000863536353ac51ac6584e319010000000006650052ab6a533debea030000000003ac0053ee7070020000000006ac52005253ac00000000", "6351005253", 2, 1386916157, "76c4013c40bfa1481badd9d342b6d4b8118de5ab497995fafbf73144469e5ff0"); - run_test_sighash("ca66ae10049533c2b39f1449791bd6d3f039efe0a121ab7339d39ef05d6dcb200ec3fb2b3b020000000465006a53ffffffff534b8f97f15cc7fb4f4cea9bf798472dc93135cd5b809e4ca7fe4617a61895980100000000ddd83c1dc96f640929dd5e6f1151dab1aa669128591f153310d3993e562cc7725b6ae3d903000000046a52536582f8ccddb8086d8550f09128029e1782c3f2624419abdeaf74ecb24889cc45ac1a64492a0100000002516a4867b41502ee6ccf03000000000752acacab52ab6a4b7ba80000000000075151ab0052536300000000", "6553", 2, -62969257, "8085e904164ab9a8c20f58f0d387f6adb3df85532e11662c03b53c3df8c943cb"); - run_test_sighash("ba646d0b0453999f0c70cb0430d4cab0e2120457bb9128ed002b6e9500e9c7f8d7baa20abe0200000001652a4e42935b21db02b56bf6f08ef4be5adb13c38bc6a0c3187ed7f6197607ba6a2c47bc8a03000000040052516affffffffa55c3cbfc19b1667594ac8681ba5d159514b623d08ed4697f56ce8fcd9ca5b0b00000000096a6a5263ac655263ab66728c2720fdeabdfdf8d9fb2bfe88b295d3b87590e26a1e456bad5991964165f888c03a0200000006630051ac00acffffffff0176fafe0100000000070063acac65515200000000", "63", 1, 2002322280, "9db4e320208185ee70edb4764ee195deca00ba46412d5527d9700c1cf1c3d057"); - run_test_sighash("2ddb8f84039f983b45f64a7a79b74ff939e3b598b38f436def7edd57282d0803c7ef34968d02000000026a537eb00c4187de96e6e397c05f11915270bcc383959877868ba93bac417d9f6ed9f627a7930300000004516551abffffffffacc12f1bb67be3ae9f1d43e55fda8b885340a0df1175392a8bbd9f959ad3605003000000025163ffffffff02ff0f4700000000000070bd99040000000003ac53abf8440b42", "", 2, -393923011, "0133f1a161363b71dfb3a90065c7128c56bd0028b558b610142df79e055ab5c7"); - run_test_sighash("b21fc15403b4bdaa994204444b59323a7b8714dd471bd7f975a4e4b7b48787e720cbd1f5f00000000000ffffffff311533001cb85c98c1d58de0a5fbf27684a69af850d52e22197b0dc941bc6ca9030000000765ab6363ab5351a8ae2c2c7141ece9a4ff75c43b7ea9d94ec79b7e28f63e015ac584d984a526a73fe1e04e0100000007526352536a5365ffffffff02a0a9ea030000000002ab52cfc4f300000000000465525253e8e0f342", "000000", 1, 1305253970, "d1df1f4bba2484cff8a816012bb6ec91c693e8ca69fe85255e0031711081c46a"); - run_test_sighash("f821a042036ad43634d29913b77c0fc87b4af593ac86e9a816a9d83fd18dfcfc84e1e1d57102000000076a63ac52006351ffffffffbcdaf490fc75086109e2f832c8985716b3a624a422cf9412fe6227c10585d21203000000095252abab5352ac526affffffff2efed01a4b73ad46c7f7bc7fa3bc480f8e32d741252f389eaca889a2e9d2007e000000000353ac53ffffffff032ac8b3020000000009636300000063516300d3d9f2040000000006510065ac656aafa5de0000000000066352ab5300ac9042b57d", "525365", 1, 667065611, "0d17a92c8d5041ba09b506ddf9fd48993be389d000aad54f9cc2a44fcc70426b"); - run_test_sighash("d62f183e037e0d52dcf73f9b31f70554bce4f693d36d17552d0e217041e01f15ad3840c838000000000963acac6a6a6a63ab63ffffffffabdfb395b6b4e63e02a763830f536fc09a35ff8a0cf604021c3c751fe4c88f4d0300000006ab63ab65ac53aa4d30de95a2327bccf9039fb1ad976f84e0b4a0936d82e67eafebc108993f1e57d8ae39000000000165ffffffff04364ad30500000000036a005179fd84010000000007ab636aac6363519b9023030000000008510065006563ac6acd2a4a02000000000000000000", "52", 1, 595020383, "da8405db28726dc4e0f82b61b2bfd82b1baa436b4e59300305cc3b090b157504"); - run_test_sighash("44c200a5021238de8de7d80e7cce905606001524e21c8d8627e279335554ca886454d692e6000000000500acac52abbb8d1dc876abb1f514e96b21c6e83f429c66accd961860dc3aed5071e153e556e6cf076d02000000056553526a51870a928d0360a580040000000004516a535290e1e302000000000851ab6a00510065acdd7fc5040000000007515363ab65636abb1ec182", "6363", 0, -785766894, "ed53cc766cf7cb8071cec9752460763b504b2183442328c5a9761eb005c69501"); - run_test_sighash("d682d52d034e9b062544e5f8c60f860c18f029df8b47716cabb6c1b4a4b310a0705e754556020000000400656a0016eeb88eef6924fed207fba7ddd321ff3d84f09902ff958c815a2bf2bb692eb52032c4d803000000076365ac516a520099788831f8c8eb2552389839cfb81a9dc55ecd25367acad4e03cfbb06530f8cccf82802701000000085253655300656a53ffffffff02d543200500000000056a510052ac03978b05000000000700ac51525363acfdc4f784", "", 2, -696035135, "e1a256854099907050cfee7778f2018082e735a1f1a3d91437584850a74c87bb"); - run_test_sighash("e8c0dec5026575ddf31343c20aeeca8770afb33d4e562aa8ee52eeda6b88806fdfd4fe0a97030000000953acabab65ab516552ffffffffdde122c2c3e9708874286465f8105f43019e837746686f442666629088a970e0010000000153ffffffff01f98eee0100000000025251fe87379a", "63", 1, 633826334, "abe441209165d25bc6d8368f2e7e7dc21019056719fef1ace45542aa2ef282e2"); - run_test_sighash("b288c331011c17569293c1e6448e33a64205fc9dc6e35bc756a1ac8b97d18e912ea88dc0770200000007635300ac6aacabfc3c890903a3ccf8040000000004656500ac9c65c9040000000009ab6a6aabab65abac63ac5f7702000000000365005200000000", "526a63", 0, 1574937329, "0dd1bd5c25533bf5f268aa316ce40f97452cca2061f0b126a59094ca5b65f7a0"); - run_test_sighash("6b68ba00023bb4f446365ea04d68d48539aae66f5b04e31e6b38b594d2723ab82d44512460000000000200acffffffff5dfc6febb484fff69c9eeb7c7eb972e91b6d949295571b8235b1da8955f3137b020000000851ac6352516a535325828c8a03365da801000000000800636aabac6551ab0f594d03000000000963ac536365ac63636a45329e010000000005abac53526a00000000", "005151", 0, 1317038910, "42f5ba6f5fe1e00e652a08c46715871dc4b40d89d9799fd7c0ea758f86eab6a7"); - run_test_sighash("046ac25e030a344116489cc48025659a363da60bc36b3a8784df137a93b9afeab91a04c1ed020000000951ab0000526a65ac51ffffffff6c094a03869fde55b9a8c4942a9906683f0a96e2d3e5a03c73614ea3223b2c29020000000500ab636a6affffffff3da7aa5ecef9071600866267674b54af1740c5aeb88a290c459caa257a2683cb0000000004ab6565ab7e2a1b900301b916030000000005abac63656308f4ed03000000000852ab53ac63ac51ac73d620020000000003ab00008deb1285", "6a", 2, 1299505108, "f79e6b776e2592bad45ca328c54abf14050c241d8f822d982c36ea890fd45757"); - run_test_sighash("ff5400dd02fec5beb9a396e1cbedc82bedae09ed44bae60ba9bef2ff375a6858212478844b03000000025253ffffffff01e46c203577a79d1172db715e9cc6316b9cfc59b5e5e4d9199fef201c6f9f0f000000000900ab6552656a5165acffffffff02e8ce62040000000002515312ce3e00000000000251513f119316", "", 0, 1541581667, "1e0da47eedbbb381b0e0debbb76e128d042e02e65b11125e17fd127305fc65cd"); - run_test_sighash("b54bf5ac043b62e97817abb892892269231b9b220ba08bc8dbc570937cd1ea7cdc13d9676c010000000451ab5365a10adb7b35189e1e8c00b86250f769319668189b7993d6bdac012800f1749150415b2deb0200000003655300ffffffff60b9f4fb9a7e17069fd00416d421f804e2ef2f2c67de4ca04e0241b9f9c1cc5d0200000003ab6aacfffffffff048168461cce1d40601b42fbc5c4f904ace0d35654b7cc1937ccf53fe78505a0100000008526563525265abacffffffff01dbf4e6040000000007acac656553636500000000", "63", 2, 882302077, "f5b38b0f06e246e47ce622e5ee27d5512c509f8ac0e39651b3389815eff2ab93"); - run_test_sighash("ebf628b30360bab3fa4f47ce9e0dcbe9ceaf6675350e638baff0c2c197b2419f8e4fb17e16000000000452516365ac4d909a79be207c6e5fb44fbe348acc42fc7fe7ef1d0baa0e4771a3c4a6efdd7e2c118b0100000003acacacffffffffa6166e9101f03975721a3067f1636cc390d72617be72e5c3c4f73057004ee0ee010000000863636a6a516a5252c1b1e82102d8d54500000000000153324c900400000000015308384913", "0063516a51", 1, -1658428367, "eb2d8dea38e9175d4d33df41f4087c6fea038a71572e3bad1ea166353bf22184"); - run_test_sighash("d6a8500303f1507b1221a91adb6462fb62d741b3052e5e7684ea7cd061a5fc0b0e93549fa50100000004acab65acfffffffffdec79bf7e139c428c7cfd4b35435ae94336367c7b5e1f8e9826fcb0ebaaaea30300000000ffffffffd115fdc00713d52c35ea92805414bd57d1e59d0e6d3b79a77ee18a3228278ada020000000453005151ffffffff040231510300000000085100ac6a6a000063c6041c0400000000080000536a6563acac138a0b04000000000263abd25fbe03000000000900656a00656aac510000000000", "ac526aac6a00", 1, -2007972591, "13d12a51598b34851e7066cd93ab8c5212d60c6ed2dae09d91672c10ccd7f87c"); - run_test_sighash("e92492cc01aec4e62df67ea3bc645e2e3f603645b3c5b353e4ae967b562d23d6e043badecd0100000003acab65ffffffff02c7e5ea040000000002ab52e1e584010000000005536365515195d16047", "6551", 0, -424930556, "93c34627f526d73f4bea044392d1a99776b4409f7d3d835f23b03c358f5a61c2"); - run_test_sighash("b28d5f5e015a7f24d5f9e7b04a83cd07277d452e898f78b50aae45393dfb87f94a26ef57720200000008ababac630053ac52ffffffff046475ed040000000008ab5100526363ac65c9834a04000000000251abae26b30100000000040000ac65ceefb900000000000000000000", "ac6551ac6a536553", 0, -1756558188, "5848d93491044d7f21884eef7a244fe7d38886f8ae60df49ce0dfb2a342cd51a"); - run_test_sighash("efb8b09801f647553b91922a5874f8e4bb2ed8ddb3536ed2d2ed0698fac5e0e3a298012391030000000952ac005263ac52006affffffff04cdfa0f050000000007ac53ab51abac65b68d1b02000000000553ab65ac00d057d50000000000016a9e1fda010000000007ac63ac536552ac00000000", "6aac", 0, 1947322973, "603a9b61cd30fcea43ef0a5c18b88ca372690b971b379ee9e01909c336280511"); - run_test_sighash("67761f2a014a16f3940dcb14a22ba5dc057fcffdcd2cf6150b01d516be00ef55ef7eb07a830100000004636a6a51ffffffff01af67bd050000000008526553526300510000000000", "6a00", 0, 1570943676, "079fa62e9d9d7654da8b74b065da3154f3e63c315f25751b4d896733a1d67807"); - run_test_sighash("ec02fbee03120d02fde12574649660c441b40d330439183430c6feb404064d4f507e704f3c0100000000ffffffffe108d99c7a4e5f75cc35c05debb615d52fac6e3240a6964a29c1704d98017fb60200000002ab63fffffffff726ec890038977adfc9dadbeaf5e486d5fcb65dc23acff0dd90b61b8e2773410000000002ac65e9dace55010f881b010000000005ac00ab650000000000", "51ac525152ac6552", 2, -1564046020, "3f988922d8cd11c7adff1a83ce9499019e5ab5f424752d8d361cf1762e04269b"); - run_test_sighash("33b03bf00222c7ca35c2f8870bbdef2a543b70677e413ce50494ac9b22ea673287b6aa55c50000000005ab00006a52ee4d97b527eb0b427e4514ea4a76c81e68c34900a23838d3e57d0edb5410e62eeb8c92b6000000000553ac6aacac42e59e170326245c000000000009656553536aab516aabb1a10603000000000852ab52ab6a516500cc89c802000000000763ac6a63ac516300000000", "", 0, 557416556, "41bead1b073e1e9fee065dd612a617ca0689e8f9d3fed9d0acfa97398ebb404c"); - run_test_sighash("813eda1103ac8159850b4524ef65e4644e0fc30efe57a5db0c0365a30446d518d9b9aa8fdd0000000003656565c2f1e89448b374b8f12055557927d5b33339c52228f7108228149920e0b77ef0bcd69da60000000006abac00ab63ab82cdb7978d28630c5e1dc630f332c4245581f787936f0b1e84d38d33892141974c75b4750300000004ac53ab65ffffffff0137edfb02000000000000000000", "0063", 1, -1948560575, "71dfcd2eb7f2e6473aed47b16a6d5fcbd0af22813d892e9765023151e07771ec"); - run_test_sighash("9e45d9aa0248c16dbd7f435e8c54ae1ad086de50c7b25795a704f3d8e45e1886386c653fbf01000000025352fb4a1acefdd27747b60d1fb79b96d14fb88770c75e0da941b7803a513e6d4c908c6445c7010000000163ffffffff014069a8010000000001520a794fb3", "51ac005363", 1, -719113284, "0d31a221c69bd322ef7193dd7359ddfefec9e0a1521d4a8740326d46e44a5d6a"); - run_test_sighash("c3efabba03cb656f154d1e159aa4a1a4bf9423a50454ebcef07bc3c42a35fb8ad84014864d0000000000d1cc73d260980775650caa272e9103dc6408bdacaddada6b9c67c88ceba6abaa9caa2f7d020000000553536a5265ffffffff9f946e8176d9b11ff854b76efcca0a4c236d29b69fb645ba29d406480427438e01000000066a0065005300ffffffff040419c0010000000003ab6a63cdb5b6010000000009006300ab5352656a63f9fe5e050000000004acac5352611b980100000000086a00acac00006a512d7f0c40", "0053", 0, -59089911, "c503001c16fbff82a99a18d88fe18720af63656fccd8511bca1c3d0d69bd7fc0"); - run_test_sighash("efb55c2e04b21a0c25e0e29f6586be9ef09f2008389e5257ebf2f5251051cdc6a79fce2dac020000000351006affffffffaba73e5b6e6c62048ba5676d18c33ccbcb59866470bb7911ccafb2238cfd493802000000026563ffffffffe62d7cb8658a6eca8a8babeb0f1f4fa535b62f5fc0ec70eb0111174e72bbec5e0300000009abababac516365526affffffffbf568789e681032d3e3be761642f25e46c20322fa80346c1146cb47ac999cf1b0300000000b3dbd55902528828010000000001ab0aac7b0100000000015300000000", "acac52", 3, 1638140535, "e84444d91580da41c8a7dcf6d32229bb106f1be0c811b2292967ead5a96ce9d4"); - run_test_sighash("91d3b21903629209b877b3e1aef09cd59aca6a5a0db9b83e6b3472aceec3bc2109e64ab85a0200000003530065ffffffffca5f92de2f1b7d8478b8261eaf32e5656b9eabbc58dcb2345912e9079a33c4cd010000000700ab65ab00536ad530611da41bbd51a389788c46678a265fe85737b8d317a83a8ff7a839debd18892ae5c80300000007ab6aac65ab51008b86c501038b8a9a05000000000263525b3f7a040000000007ab535353ab00abd4e3ff04000000000665ac51ab65630b7b656f", "6551525151516a00", 2, 499657927, "ef4bd7622eb7b2bbbbdc48663c1bc90e01d5bde90ff4cb946596f781eb420a0c"); - run_test_sighash("ceecfa6c02b7e3345445b82226b15b7a097563fa7d15f3b0c979232b138124b62c0be007890200000009abac51536a63525253ffffffffbae481ccb4f15d94db5ec0d8854c24c1cc8642bd0c6300ede98a91ca13a4539a0200000001ac50b0813d023110f5020000000006acabac526563e2b0d0040000000009656aac0063516a536300000000", "0063526500", 0, -1862053821, "e1600e6df8a6160a79ac32aa40bb4644daa88b5f76c0d7d13bf003327223f70c"); - run_test_sighash("f06f64af04fdcb830464b5efdb3d5ee25869b0744005375481d7b9d7136a0eb8828ad1f0240200000003516563fffffffffd3ba192dabe9c4eb634a1e3079fca4f072ee5ceb4b57deb6ade5527053a92c5000000000165ffffffff39f43401a36ba13a5c6dd7f1190e793933ae32ee3bf3e7bfb967be51e681af760300000009650000536552636a528e34f50b21183952cad945a83d4d56294b55258183e1627d6e8fb3beb8457ec36cadb0630000000005abab530052334a7128014bbfd10100000000085352ab006a63656afc424a7c", "53650051635253ac00", 2, 313255000, "d309da5afd91b7afa257cfd62df3ca9df036b6a9f4b38f5697d1daa1f587312b"); - run_test_sighash("6dfd2f98046b08e7e2ef5fff153e00545faf7076699012993c7a30cb1a50ec528281a9022f030000000152ffffffff1f535e4851920b968e6c437d84d6ecf586984ebddb7d5db6ae035bd02ba222a8010000000651006a53ab51605072acb3e17939fa0737bc3ee43bc393b4acd58451fc4ffeeedc06df9fc649828822d5010000000253525a4955221715f27788d302382112cf60719be9ae159c51f394519bd5f7e70a4f9816c7020200000009526a6a51636aab656a36d3a5ff0445548e0100000000086a6a00516a52655167030b050000000004ac6a63525cfda8030000000000e158200000000000010000000000", "535263ac6a65515153", 3, 585774166, "72b7da10704c3ca7d1deb60c31b718ee12c70dc9dfb9ae3461edce50789fe2ba"); - run_test_sighash("2a45cd1001bf642a2315d4a427eddcc1e2b0209b1c6abd2db81a800c5f1af32812de42032702000000050051525200ffffffff032177db050000000005530051abac49186f000000000004ab6aab00645c0000000000000765655263acabac00000000", "6a65", 0, -1774715722, "6a9ac3f7da4c7735fbc91f728b52ecbd602233208f96ac5592656074a5db118a"); - run_test_sighash("ca816e7802cd43d66b9374cd9bf99a8da09402d69c688d8dcc5283ace8f147e1672b757e020200000005516aabab5240fb06c95c922342279fcd88ba6cd915933e320d7becac03192e0941e0345b79223e89570300000004005151ac353ecb5d0264dfbd010000000005ac6aacababd5d70001000000000752ac53ac6a5151ec257f71", "63ac", 1, 774695685, "cc180c4f797c16a639962e7aec58ec4b209853d842010e4d090895b22e7a7863"); - run_test_sighash("b42b955303942fedd7dc77bbd9040aa0de858afa100f399d63c7f167b7986d6c2377f66a7403000000066aac00525100ffffffff0577d04b64880425a3174055f94191031ad6b4ca6f34f6da9be7c3411d8b51fc000000000300526a6391e1cf0f22e45ef1c44298523b516b3e1249df153590f592fcb5c5fc432dc66f3b57cb03000000046a6aac65ffffffff0393a6c9000000000004516a65aca674ac0400000000046a525352c82c370000000000030053538e577f89", "", 1, -1237094944, "566953eb806d40a9fb684d46c1bf8c69dea86273424d562bd407b9461c8509af"); - run_test_sighash("92c9fe210201e781b72554a0ed5e22507fb02434ddbaa69aff6e74ea8bad656071f1923f3f02000000056a63ac6a514470cef985ba83dcb8eee2044807bedbf0d983ae21286421506ae276142359c8c6a34d68020000000863ac63525265006aa796dd0102ca3f9d05000000000800abab52ab535353cd5c83010000000007ac00525252005322ac75ee", "5165", 0, 97879971, "6e6307cef4f3a9b386f751a6f40acebab12a0e7e17171d2989293cbec7fd45c2"); - run_test_sighash("ccca1d5b01e40fe2c6b3ee24c660252134601dab785b8f55bd6201ffaf2fddc7b3e2192325030000000365535100496d4703b4b66603000000000665535253ac633013240000000000015212d2a502000000000951abac636353636a5337b82426", "0052", 0, -1691630172, "577bf2b3520b40aef44899a20d37833f1cded6b167e4d648fc5abe203e43b649"); - run_test_sighash("bc1a7a3c01691e2d0c4266136f12e391422f93655c71831d90935fbda7e840e50770c61da20000000008635253abac516353ffffffff031f32aa020000000003636563786dbc0200000000003e950f00000000000563516a655184b8a1de", "51536a", 0, -1627072905, "730bc25699b46703d7718fd5f5c34c4b5f00f594a9968ddc247fa7d5175124ed"); - run_test_sighash("076d209e02d904a6c40713c7225d23e7c25d4133c3c3477828f98c7d6dbd68744023dbb66b030000000753ab00536565acffffffff10975f1b8db8861ca94c8cc7c7cff086ddcd83e10b5fffd4fc8f2bdb03f9463c0100000000ffffffff029dff76010000000006526365530051a3be6004000000000000000000", "515253ac65acacac", 1, -1207502445, "66c488603b2bc53f0d22994a1f0f66fb2958203102eba30fe1d37b27a55de7a5"); - run_test_sighash("cac6382d0462375e83b67c7a86c922b569a7473bfced67f17afd96c3cd2d896cf113febf9e0300000003006a53ffffffffaa4913b7eae6821487dd3ca43a514e94dcbbf350f8cc4cafff9c1a88720711b800000000096a6a525300acac6353ffffffff184fc4109c34ea27014cc2c1536ef7ed1821951797a7141ddacdd6e429fae6ff01000000055251655200ffffffff9e7b79b4e6836e290d7b489ead931cba65d1030ccc06f20bd4ca46a40195b33c030000000008f6bc8304a09a2704000000000563655353511dbc73050000000000cf34c500000000000091f76e0000000000085200ab00005100abd07208cb", "0063656a", 2, -1488731031, "bf078519fa87b79f40abc38f1831731422722c59f88d86775535f209cb41b9b1"); - run_test_sighash("1711146502c1a0b82eaa7893976fefe0fb758c3f0e560447cef6e1bde11e42de91a125f71c030000000015bd8c04703b4030496c7461482481f290c623be3e76ad23d57a955807c9e851aaaa20270300000000d04abaf20326dcb7030000000001632225350400000000075263ac00520063dddad9020000000000af23d148", "52520053510063", 0, 1852122830, "e33d5ee08c0f3c130a44d7ce29606450271b676f4a80c52ab9ffab00cecf67f8"); - run_test_sighash("22d81c740469695a6a83a9a4824f77ecff8804d020df23713990afce2b72591ed7de98500502000000065352526a6a6affffffff90dc85e118379b1005d7bbc7d2b8b0bab104dad7eaa49ff5bead892f17d8c3ba010000000665656300ab51ffffffff965193879e1d5628b52005d8560a35a2ba57a7f19201a4045b7cbab85133311d0200000003ac005348af21a13f9b4e0ad90ed20bf84e4740c8a9d7129632590349afc03799414b76fd6e826200000000025353ffffffff04a0d40d04000000000060702700000000000652655151516ad31f1502000000000365ac0069a1ac0500000000095100655300ab53525100000000", "51636a52ac", 0, -1644680765, "add7f5da27262f13da6a1e2cc2feafdc809bd66a67fb8ae2a6f5e6be95373b6f"); - run_test_sighash("a27dcbc801e3475174a183586082e0914c314bc9d79d1570f29b54591e5e0dff07fbb45a7f0000000004ac53ab51ffffffff027347f5020000000005535351ab63d0e5c9030000000009ac65ab6a63515200ab7cd632ed", "ac63636553", 0, -686435306, "883a6ea3b2cc53fe8a803c229106366ca14d25ffbab9fef8367340f65b201da6"); - run_test_sighash("0728c606014c1fd6005ccf878196ba71a54e86cc8c53d6db500c3cc0ac369a26fac6fcbc210000000005ab53ac5365ba9668290182d7870100000000066a000053655100000000", "65", 0, 1789961588, "ab6baa6da3b2bc853868d166f8996ad31d63ef981179f9104f49968fd61c8427"); - run_test_sighash("ed3bb93802ddbd08cb030ef60a2247f715a0226de390c9c1a81d52e83f8674879065b5f87d0300000003ab6552ffffffff04d2c5e60a21fb6da8de20bf206db43b720e2a24ce26779bca25584c3f765d1e0200000008ab656a6aacab00ab6e946ded025a811d04000000000951abac6352ac00ab5143cfa3030000000005635200636a00000000", "5352ac650065535300", 1, -668727133, "e9995065e1fddef72a796eef5274de62012249660dc9d233a4f24e02a2979c87"); - run_test_sighash("59f4629d030fa5d115c33e8d55a79ea3cba8c209821f979ed0e285299a9c72a73c5bba00150200000002636affffffffd8aca2176df3f7a96d0dc4ee3d24e6cecde1582323eec2ebef9a11f8162f17ac0000000007ab6565acab6553ffffffffeebc10af4f99c7a21cbc1d1074bd9f0ee032482a71800f44f26ee67491208e0403000000065352ac656351ffffffff0434e955040000000004ab515152caf2b305000000000365ac007b1473030000000003ab530033da970500000000060051536a5253bb08ab51", "", 2, 396340944, "0e9c47973ef2c292b2252c623f465bbb92046fe0b893eebf4e1c9e02cb01c397"); - run_test_sighash("33a98004029d262f951881b20a8d746c8c707ea802cd2c8b02a33b7e907c58699f97e42be80100000007ac53536552abacdee04cc01d205fd8a3687fdf265b064d42ab38046d76c736aad8865ca210824b7c622ecf02000000070065006a536a6affffffff01431c5d010000000000270d48ee", "", 1, 921554116, "ff9d7394002f3f196ea25472ea6c46f753bd879a7244795157bb7235c9322902"); - run_test_sighash("aac18f2b02b144ed481557c53f2146ae523f24fcde40f3445ab0193b6b276c315dc2894d2300000000075165650000636a233526947dbffc76aec7db1e1baa6868ad4799c76e14794dcbaaec9e713a83967f6a65170200000005abac6551ab27d518be01b652a30000000000015300000000", "52ac5353", 1, 1559377136, "59fc2959bb7bb24576cc8a237961ed95bbb900679d94da6567734c4390cb6ef5"); - run_test_sighash("5ab79881033555b65fe58c928883f70ce7057426fbdd5c67d7260da0fe8b1b9e6a2674cb850300000009ac516aac6aac006a6affffffffa5be9223b43c2b1a4d120b5c5b6ec0484f637952a3252181d0f8e813e76e11580200000000e4b5ceb8118cb77215bbeedc9a076a4d087bb9cd1473ea32368b71daeeeacc451ec209010000000005acac5153aced7dc34e02bc5d11030000000005ac5363006a54185803000000000552ab00636a00000000", "5100", 1, 1927062711, "e9f53d531c12cce1c50abed4ac521a372b4449b6a12f9327c80020df6bff66c0"); - run_test_sighash("6c2c8fac0124b0b7d4b610c3c5b91dee32b7c927ac71abdf2d008990ca1ac40de0dfd530660300000006ababac5253656bd7eada01d847ec000000000004ac52006af4232ec8", "6a6a6a0051", 0, -340809707, "fb51eb9d7e47d32ff2086205214f90c7c139e08c257a64829ae4d2b301071c6a"); - run_test_sighash("0e803682024f79337b25c98f276d412bc27e56a300aa422c42994004790cee213008ff1b8303000000080051ac65ac655165f421a331892b19a44c9f88413d057fea03c3c4a6c7de4911fe6fe79cf2e9b3b10184b1910200000005525163630096cb1c670398277204000000000253acf7d5d502000000000963536a6a636a5363ab381092020000000002ac6a911ccf32", "6565", 1, -1492094009, "f0672638a0e568a919e9d8a9cbd7c0189a3e132940beeb52f111a89dcc2daa2c"); - run_test_sighash("7d71669d03022f9dd90edac323cde9e56354c6804c6b8e687e9ae699f46805aafb8bcaa636000000000253abffffffff698a5fdd3d7f2b8b000c68333e4dd58fa8045b3e2f689b889beeb3156cecdb490300000009525353abab0051acabc53f0aa821cdd69b473ec6e6cf45cf9b38996e1c8f52c27878a01ec8bb02e8cb31ad24e500000000055353ab0052ffffffff0447a23401000000000565ab53ab5133aaa0030000000006515163656563057d110300000000056a6aacac52cf13b5000000000003526a5100000000", "6a6a51", 1, -1349253507, "722efdd69a7d51d3d77bed0ac5544502da67e475ea5857cd5af6bdf640a69945"); - run_test_sighash("9ff618e60136f8e6bb7eabaaac7d6e2535f5fba95854be6d2726f986eaa9537cb283c701ff02000000026a65ffffffff012d1c0905000000000865ab00ac6a516a652f9ad240", "51515253635351ac", 0, 1571304387, "659cd3203095d4a8672646add7d77831a1926fc5b66128801979939383695a79"); - run_test_sighash("09adb2e90175ca0e816326ae2dce7750c1b27941b16f6278023dbc294632ab97977852a09d030000000465ab006affffffff027739cf0100000000075151ab63ac65ab8a5bb601000000000653ac5151520011313cdc", "ac", 0, -76831756, "478ee06501b4965b40bdba6cbaad9b779b38555a970912bb791b86b7191c54bc"); - run_test_sighash("fd22ebaa03bd588ad16795bea7d4aa7f7d48df163d75ea3afebe7017ce2f350f6a0c1cb0bb00000000086aabac5153526363ffffffff488e0bb22e26a565d77ba07178d17d8f85702630ee665ec35d152fa05af3bda10200000004515163abffffffffeb21035849e85ad84b2805e1069a91bb36c425dc9c212d9bae50a95b6bfde1200300000001ab5df262fd02b69848040000000008ab6363636a6363ace23bf2010000000007655263635253534348c1da", "006353526563516a00", 0, -1491036196, "92364ba3c7a85d4e88885b8cb9b520dd81fc29e9d2b750d0790690e9c1246673"); - run_test_sighash("b04154610363fdade55ceb6942d5e5a723323863b48a0cb04fdcf56210717955763f56b08d0300000009ac526a525151635151ffffffff93a176e76151a9eabdd7af00ef2af72f9e7af5ecb0aa4d45d00618f394cdd03c030000000074d818b332ebe05dc24c44d776cf9d275c61f471cc01efce12fd5a16464157f1842c65cb00000000066a0000ac6352d3c4134f01d8a1c0030000000005520000005200000000", "5200656a656351", 2, -9757957, "6e3e5ba77f760b6b5b5557b13043f1262418f3dd2ce7f0298b012811fc8ad5bc"); - run_test_sighash("94533db7015e70e8df715066efa69dbb9c3a42ff733367c18c22ff070392f988f3b93920820000000006535363636300ce4dac3e03169af80300000000080065ac6a53ac65ac39c050020000000006abacab6aacac708a02050000000005ac5251520000000000", "6553", 0, -360458507, "5418cf059b5f15774836edd93571e0eed3855ba67b2b08c99dccab69dc87d3e9"); - run_test_sighash("c8597ada04f59836f06c224a2640b79f3a8a7b41ef3efa2602592ddda38e7597da6c639fee0300000009005251635351acabacffffffff4c518f347ee694884b9d4072c9e916b1a1f0a7fc74a1c90c63fdf8e5a185b6ae02000000007113af55afb41af7518ea6146786c7c726641c68c8829a52925e8d4afd07d8945f68e7230300000008ab00ab65ab650063ffffffffc28e46d7598312c420e11dfaae12add68b4d85adb182ae5b28f8340185394b63000000000165ffffffff04dbabb7010000000000ee2f6000000000000852ab6500ab6a51acb62a27000000000009ac53515300ac006a6345fb7505000000000752516a0051636a00000000", "", 3, 15199787, "0d66003aff5bf78cf492ecbc8fd40c92891acd58d0a271be9062e035897f317e"); - run_test_sighash("c33028b301d5093e1e8397270d75a0b009b2a6509a01861061ab022ca122a6ba935b8513320200000000ffffffff013bcf5a0500000000015200000000", "", 0, -513413204, "6b1459536f51482f5dbf42d7e561896557461e1e3b6bf67871e2b51faae2832c"); - run_test_sighash("43b2727901a7dd06dd2abf690a1ccedc0b0739cb551200796669d9a25f24f71d8d101379f50300000000ffffffff0418e031040000000000863d770000000000085352ac526563ac5174929e040000000004ac65ac00ec31ac0100000000066a51ababab5300000000", "65", 0, -492874289, "154ff7a9f0875edcfb9f8657a0b98dd9600fabee3c43eb88af37cf99286d516c"); - run_test_sighash("fe6ddf3a02657e42a7496ef170b4a8caf245b925b91c7840fd28e4a22c03cb459cb498b8d603000000065263656a650071ce6bf8d905106f9f1faf6488164f3decac65bf3c5afe1dcee20e6bc3cb6d052561985a030000000163295b117601343dbb0000000000026563dba521df", "", 1, -1696179931, "d9684685c99ce48f398fb467a91a1a59629a850c429046fb3071f1fa9a5fe816"); - run_test_sighash("c61523ef0129bb3952533cbf22ed797fa2088f307837dd0be1849f20decf709cf98c6f032f03000000026563c0f1d378044338310400000000066363516a5165a14fcb0400000000095163536a6a00ab53657271d60200000000001d953f0500000000010000000000", "53516353005153", 0, 1141615707, "7e975a72db5adaa3c48d525d9c28ac11cf116d0f8b16ce08f735ad75a80aec66"); - run_test_sighash("ba3dac6c0182562b0a26d475fe1e36315f0913b6869bdad0ecf21f1339a5fcbccd32056c840200000000ffffffff04300351050000000000220ed405000000000851abac636565ac53dbbd19020000000007636363ac6a52acbb005a0500000000016abd0c78a8", "63006a635151005352", 0, 1359658828, "47bc8ab070273e1f4a0789c37b45569a6e16f3f3092d1ce94dddc3c34a28f9f4"); - run_test_sighash("ac27e7f5025fc877d1d99f7fc18dd4cadbafa50e34e1676748cc89c202f93abf36ed46362101000000036300abffffffff958cd5381962b765e14d87fc9524d751e4752dd66471f973ed38b9d562e525620100000003006500ffffffff02b67120050000000004ac51516adc330c0300000000015200000000", "656352", 1, 15049991, "f3374253d64ac264055bdbcc32e27426416bd595b7c7915936c70f839e504010"); - run_test_sighash("7e50207303146d1f7ad62843ae8017737a698498d4b9118c7a89bb02e8370307fa4fada41d000000000753006300005152b7afefc85674b1104ba33ef2bf37c6ed26316badbc0b4aa6cb8b00722da4f82ff3555a6c020000000900ac656363ac51ac52ffffffff93fab89973bd322c5d7ad7e2b929315453e5f7ada3072a36d8e33ca8bebee6e0020000000300acab930da52b04384b04000000000004650052ac435e380200000000076a6a515263ab6aa9494705000000000600ab6a525252af8ba90100000000096565acab526353536a279b17ad", "acac005263536aac63", 1, -34754133, "4e6357da0057fb7ff79da2cc0f20c5df27ff8b2f8af4c1709e6530459f7972b0"); - run_test_sighash("5a59e0b9040654a3596d6dab8146462363cd6549898c26e2476b1f6ae42915f73fd9aedfda00000000036363abffffffff9ac9e9ca90be0187be2214251ff08ba118e6bf5e2fd1ba55229d24e50a510d53010000000165ffffffff41d42d799ac4104644969937522873c0834cc2fcdab7cdbecd84d213c0e96fd60000000000ffffffffd838db2c1a4f30e2eaa7876ef778470f8729fcf258ad228b388df2488709f8410300000000fdf2ace002ceb6d903000000000265654c1310040000000003ac00657e91c0ec", "536a63ac", 0, 82144555, "98ccde2dc14d14f5d8b1eeea5364bd18fc84560fec2fcea8de4d88b49c00695e"); - run_test_sighash("156ebc8202065d0b114984ee98c097600c75c859bfee13af75dc93f57c313a877efb09f230010000000463536a51ffffffff81114e8a697be3ead948b43b5005770dd87ffb1d5ccd4089fa6c8b33d3029e9c03000000066a5251656351ffffffff01a87f140000000000050000ac51ac00000000", "00", 0, -362221092, "a903c84d8c5e71134d1ab6dc1e21ac307c4c1a32c90c90f556f257b8a0ec1bf5"); - run_test_sighash("6d97a9a5029220e04f4ccc342d8394c751282c328bf1c132167fc05551d4ca4da4795f6d4e02000000076a0052ab525165ffffffff9516a205e555fa2a16b73e6db6c223a9e759a7e09c9a149a8f376c0a7233fa1b0100000007acab51ab63ac6affffffff04868aed04000000000652ac65ac536a396edf01000000000044386c0000000000076aab5363655200894d48010000000001ab8ebefc23", "6351526aac51", 1, 1943666485, "f0bd4ca8e97203b9b4e86bc24bdc8a1a726db5e99b91000a14519dc83fc55c29"); - run_test_sighash("05921d7c048cf26f76c1219d0237c226454c2a713c18bf152acc83c8b0647a94b13477c07f0300000003ac526afffffffff2f494453afa0cabffd1ba0a626c56f90681087a5c1bd81d6adeb89184b27b7402000000036a6352ffffffff0ad10e2d3ce355481d1b215030820da411d3f571c3f15e8daf22fe15342fed04000000000095f29f7b93ff814a9836f54dc6852ec414e9c4e16a506636715f569151559100ccfec1d100000000055263656a53ffffffff04f4ffef010000000008ac6a6aabacabab6a0e6689040000000006ab536a5352abe364d005000000000965536363655251ab53807e00010000000004526aab63f18003e3", "6363ac51", 3, -375891099, "001b0b176f0451dfe2d9787b42097ceb62c70d324e925ead4c58b09eebdf7f67"); - run_test_sighash("b9b44d9f04b9f15e787d7704e6797d51bc46382190c36d8845ec68dfd63ee64cf7a467b21e00000000096aac00530052ab636aba1bcb110a80c5cbe073f12c739e3b20836aa217a4507648d133a8eedd3f02cb55c132b203000000076a000063526352b1c288e3a9ff1f2da603f230b32ef7c0d402bdcf652545e2322ac01d725d75f5024048ad0100000000ffffffffffd882d963be559569c94febc0ef241801d09dc69527c9490210f098ed8203c700000000056a006300ab9109298d01719d9a0300000000066a52ab006365d7894c5b", "ac6351650063636a", 3, -622355349, "ac87b1b93a6baab6b2c6624f10e8ebf6849b0378ef9660a3329073e8f5553c8d"); - run_test_sighash("ff60473b02574f46d3e49814c484081d1adb9b15367ba8487291fc6714fd6e3383d5b335f001000000026a6ae0b82da3dc77e5030db23d77b58c3c20fa0b70aa7d341a0f95f3f72912165d751afd57230300000008ac536563516a6363ffffffff04f86c0200000000000553acab636ab13111000000000003510065f0d3f305000000000951ab516a65516aabab730a3a010000000002515200000000", "ac6a", 1, 1895032314, "0767e09bba8cd66d55915677a1c781acd5054f530d5cf6de2d34320d6c467d80"); - run_test_sighash("f218026204f4f4fc3d3bd0eada07c57b88570d544a0436ae9f8b753792c0c239810bb30fbc0200000002536affffffff8a468928d6ec4cc10aa0f73047697970e99fa64ae8a3b4dca7551deb0b639149010000000851ab520052650051ffffffffa98dc5df357289c9f6873d0f5afcb5b030d629e8f23aa082cf06ec9a95f3b0cf0000000000ffffffffea2c2850c5107705fd380d6f29b03f533482fd036db88739122aac9eff04e0aa010000000365536a03bd37db034ac4c4020000000007515152655200ac33b27705000000000151efb71e0000000000007b65425b", "515151", 3, -1772252043, "de35c84a58f2458c33f564b9e58bc57c3e028d629f961ad1b3c10ee020166e5a"); - run_test_sighash("48e7d42103b260b27577b70530d1ac2fed2551e9dd607cbcf66dca34bb8c03862cf8f5fd5401000000075151526aacab00ffffffff1e3d3b841552f7c6a83ee379d9d66636836673ce0b0eda95af8f2d2523c91813030000000665acac006365ffffffff388b3c386cd8c9ef67c83f3eaddc79f1ff910342602c9152ffe8003bce51b28b0100000008636363006a636a52ffffffff04b8f67703000000000852005353ac6552520cef720200000000085151ab6352ab00ab5096d6030000000005516a005100662582020000000001ac6c137280", "6a65", 1, 1513618429, "e2fa3e1976aed82c0987ab30d4542da2cb1cffc2f73be13480132da8c8558d5c"); - run_test_sighash("91ebc4cf01bc1e068d958d72ee6e954b196f1d85b3faf75a521b88a78021c543a06e056279000000000265ab7c12df0503832121030000000000cc41a6010000000005ab5263516540a951050000000006ab63ab65acac00000000", "526a0065636a6a6aac", 0, -614046478, "7de4ba875b2e584a7b658818c112e51ee5e86226f5a80e5f6b15528c86400573"); - run_test_sighash("3cd4474201be7a6c25403bf00ca62e2aa8f8f4f700154e1bb4d18c66f7bb7f9b975649f0dc0100000006535151535153ffffffff01febbeb000000000006005151006aac00000000", "", 0, -1674687131, "6b77ca70cc452cc89acb83b69857cda98efbfc221688fe816ef4cb4faf152f86"); - run_test_sighash("92fc95f00307a6b3e2572e228011b9c9ed41e58ddbaefe3b139343dbfb3b34182e9fcdc3f50200000002acab847bf1935fde8bcfe41c7dd99683289292770e7f163ad09deff0e0665ed473cd2b56b0f40300000006516551ab6351294dab312dd87b9327ce2e95eb44b712cfae0e50fda15b07816c8282e8365b643390eaab01000000026aacffffffff016e0b6b040000000001ac00000000", "650065acac005300", 2, -1885164012, "bd7d26bb3a98fc8c90c972500618bf894cb1b4fe37bf5481ff60eef439d3b970"); - run_test_sighash("4db591ab018adcef5f4f3f2060e41f7829ce3a07ea41d681e8cb70a0e37685561e4767ac3b0000000005000052acabd280e63601ae6ef20000000000036a636326c908f7", "ac6a51526300630052", 0, 862877446, "355ccaf30697c9c5b966e619a554d3323d7494c3ea280a9b0dfb73f953f5c1cb"); - run_test_sighash("c80abebd042cfec3f5c1958ee6970d2b4586e0abec8305e1d99eb9ee69ecc6c2cbd76374380000000007ac53006300ac510acee933b44817db79320df8094af039fd82111c7726da3b33269d3820123694d849ee5001000000056a65ab526562699bea8530dc916f5d61f0babea709dac578774e8a4dcd9c640ec3aceb6cb2443f24f302000000020063ea780e9e57d1e4245c1e5df19b4582f1bf704049c5654f426d783069bcc039f2d8fa659f030000000851ab53635200006a8d00de0b03654e8500000000000463ab635178ebbb0400000000055100636aab239f1d030000000006ab006300536500000000", "6565ac515100", 3, 1460851377, "b35bb1b72d02fab866ed6bbbea9726ab32d968d33a776686df3ac16aa445871e"); - run_test_sighash("0337b2d5043eb6949a76d6632b8bb393efc7fe26130d7409ef248576708e2d7f9d0ced9d3102000000075352636a5163007034384dfa200f52160690fea6ce6c82a475c0ef1caf5c9e5a39f8f9ddc1c8297a5aa0eb02000000026a51ffffffff38e536298799631550f793357795d432fb2d4231f4effa183c4e2f61a816bcf0030000000463ac5300706f1cd3454344e521fde05b59b96e875c8295294da5d81d6cc7efcfe8128f150aa54d6503000000008f4a98c704c1561600000000000072cfa6000000000000e43def01000000000100cf31cc0500000000066365526a6500cbaa8e2e", "", 3, 2029506437, "7615b4a7b3be865633a31e346bc3db0bcc410502c8358a65b8127089d81b01f8"); - run_test_sighash("cbc79b10020b15d605680a24ee11d8098ad94ae5203cb6b0589e432832e20c27b72a926af20300000006ab65516a53acbb854f3146e55c508ece25fa3d99dbfde641a58ed88c051a8a51f3dacdffb1afb827814b02000000026352c43e6ef30302410a020000000000ff4bd90100000000065100ab63000008aa8e0400000000095265526565ac5365abc52c8a77", "53526aac0051", 0, 202662340, "984efe0d8d12e43827b9e4b27e97b3777ece930fd1f589d616c6f9b71dab710e"); - run_test_sighash("4e8594d803b1d0a26911a2bcdd46d7cbc987b7095a763885b1a97ca9cbb747d32c5ab9aa91030000000353ac53a0cc4b215e07f1d648b6eeb5cdbe9fa32b07400aa773b9696f582cebfd9930ade067b2b200000000060065abab6500fc99833216b8e27a02defd9be47fafae4e4a97f52a9d2a210d08148d2a4e5d02730bcd460100000004516351ac37ce3ae1033baa55040000000006006a636a63acc63c990400000000025265eb1919030000000005656a6a516a00000000", "", 1, -75217178, "04c5ee48514cd033b82a28e336c4d051074f477ef2675ce0ce4bafe565ee9049"); - run_test_sighash("44e1a2b4010762af23d2027864c784e34ef322b6e24c70308a28c8f2157d90d17b99cd94a401000000085163656565006300ffffffff0198233d020000000002000000000000", "52525153656365", 0, 1119696980, "d9096de94d70c6337da6202e6e588166f31bff5d51bb5adc9468594559d65695"); - run_test_sighash("44ca65b901259245abd50a745037b17eb51d9ce1f41aa7056b4888285f48c6f26cb97b7a25020000000552636363abffffffff047820350400000000040053acab14f3e603000000000652635100ab630ce66c03000000000001bdc704000000000765650065ac51ac3e886381", "51", 0, -263340864, "ed5622ac642d11f90e68c0feea6a2fe36d880ecae6b8c0d89c4ea4b3d162bd90"); - run_test_sighash("cfa147d2017fe84122122b4dda2f0d6318e59e60a7207a2d00737b5d89694d480a2c26324b0000000006006351526552ffffffff0456b5b804000000000800516aab525363ab166633000000000004655363ab254c0e02000000000952ab6a6a00ab525151097c1b020000000009656a52ac6300530065ad0d6e50", "6a535165ac6a536500", 0, -574683184, "f926d4036eac7f019a2b0b65356c4ee2fe50e089dd7a70f1843a9f7bc6997b35"); - run_test_sighash("91c5d5f6022fea6f230cc4ae446ce040d8313071c5ac1749c82982cc1988c94cb1738aa48503000000016a19e204f30cb45dd29e68ff4ae160da037e5fc93538e21a11b92d9dd51cf0b5efacba4dd70000000005656a6aac51ffffffff03db126905000000000953006a53ab6563636a36a273030000000006656a52656552b03ede00000000000352516500000000", "530052526a00", 1, 1437328441, "255c125b60ee85f4718b2972174c83588ee214958c3627f51f13b5fb56c8c317"); - run_test_sighash("03f20dc202c886907b607e278731ebc5d7373c348c8c66cac167560f19b341b782dfb634cb03000000076a51ac6aab63abea3e8de7adb9f599c9caba95aa3fa852e947fc88ed97ee50e0a0ec0d14d164f44c0115c10100000004ab5153516fdd679e0414edbd000000000005ac636a53512021f2040000000007006a0051536a52c73db2050000000005525265ac5369046e000000000003ab006a1ef7bd1e", "52656a", 0, 1360223035, "5a0a05e32ce4cd0558aabd5d79cd5fcbffa95c07137506e875a9afcba4bef5a2"); - run_test_sighash("d9611140036881b61e01627078512bc3378386e1d4761f959d480fdb9d9710bebddba2079d020000000763536aab5153ab819271b41e228f5b04daa1d4e72c8e1955230accd790640b81783cfc165116a9f535a74c000000000163ffffffffa2e7bb9a28e810624c251ff5ba6b0f07a356ac082048cf9f39ec036bba3d431a02000000076a000000ac65acffffffff01678a820000000000085363515153ac635100000000", "535353", 2, -82213851, "52b9e0778206af68998cbc4ebdaad5a9469e04d0a0a6cef251abfdbb74e2f031"); - run_test_sighash("98b3a0bf034233afdcf0df9d46ac65be84ef839e58ee9fa59f32daaa7d684b6bdac30081c60200000007636351acabababffffffffc71cf82ded4d1593e5825618dc1d5752ae30560ecfaa07f192731d68ea768d0f0100000006650052636563f3a2888deb5ddd161430177ce298242c1a86844619bc60ca2590d98243b5385bc52a5b8f00000000095365acacab520052ac50d4722801c3b8a60300000000035165517e563b65", "51", 1, -168940690, "b6b684e2d2ecec8a8dce4ed3fc1147f8b2e45732444222aa8f52d860c2a27a9d"); - run_test_sighash("97be4f7702dc20b087a1fdd533c7de762a3f2867a8f439bddf0dcec9a374dfd0276f9c55cc0300000000cdfb1dbe6582499569127bda6ca4aaff02c132dc73e15dcd91d73da77e92a32a13d1a0ba0200000002ab51ffffffff048cfbe202000000000900516351515363ac535128ce0100000000076aac5365ab6aabc84e8302000000000863536a53ab6a6552f051230500000000066aac535153510848d813", "ac51", 0, 229541474, "e5da9a416ea883be1f8b8b2d178463633f19de3fa82ae25d44ffb531e35bdbc8"); - run_test_sighash("085b6e04040b5bff81e29b646f0ed4a45e05890a8d32780c49d09643e69cdccb5bd81357670100000001abffffffffa5c981fe758307648e783217e3b4349e31a557602225e237f62b636ec26df1a80300000004650052ab4792e1da2930cc90822a8d2a0a91ea343317bce5356b6aa8aae6c3956076aa33a5351a9c0300000004abac5265e27ddbcd472a2f13325cc6be40049d53f3e266ac082172f17f6df817db1936d9ff48c02b000000000152ffffffff021aa7670500000000085353635163ab51ac14d584000000000001aca4d136cc", "6a525300536352536a", 0, -1398925877, "41ecca1e8152ec55074f4c39f8f2a7204dda48e9ec1e7f99d5e7e4044d159d43"); - run_test_sighash("eec32fff03c6a18b12cd7b60b7bdc2dd74a08977e53fdd756000af221228fe736bd9c42d870100000007005353ac515265ffffffff037929791a188e9980e8b9cc154ad1b0d05fb322932501698195ab5b219488fc02000000070063510065ab6a0bfc176aa7e84f771ea3d45a6b9c24887ceea715a0ff10ede63db8f089e97d927075b4f1000000000551abab63abffffffff02eb933c000000000000262c420000000000036563632549c2b6", "6352", 2, 1480445874, "ff8a4016dfdd918f53a45d3a1f62b12c407cd147d68ca5c92b7520e12c353ff5"); - run_test_sighash("3ab70f4604e8fc7f9de395ec3e4c3de0d560212e84a63f8d75333b604237aa52a10da17196000000000763526a6553ac63a25de6fd66563d71471716fe59087be0dde98e969e2b359282cf11f82f14b00f1c0ac70f02000000050052516aacdffed6bb6889a13e46956f4b8af20752f10185838fd4654e3191bf49579c961f5597c36c0100000005ac636363abc3a1785bae5b8a1b4be5d0cbfadc240b4f7acaa7dfed6a66e852835df5eb9ac3c553766801000000036a65630733b7530218569602000000000952006a6a6a51acab52777f06030000000007ac0063530052abc08267c9", "000000536aac0000", 1, 1919096509, "df1c87cf3ba70e754d19618a39fdbd2970def0c1bfc4576260cba5f025b87532"); - run_test_sighash("bdb6b4d704af0b7234ced671c04ba57421aba7ead0a117d925d7ebd6ca078ec6e7b93eea6600000000026565ffffffff3270f5ad8f46495d69b9d71d4ab0238cbf86cc4908927fbb70a71fa3043108e6010000000700516a65655152ffffffff6085a0fdc03ae8567d0562c584e8bfe13a1bd1094c518690ebcb2b7c6ce5f04502000000095251530052536a53aba576a37f2c516aad9911f687fe83d0ae7983686b6269b4dd54701cb5ce9ec91f0e6828390300000000ffffffff04cc76cc020000000002656a01ffb702000000000253ab534610040000000009acab006565516a00521f55f5040000000000389dfee9", "6a525165", 0, 1336204763, "71c294523c48fd7747eebefbf3ca06e25db7b36bff6d95b41c522fecb264a919"); - run_test_sighash("54258edd017d22b274fbf0317555aaf11318affef5a5f0ae45a43d9ca4aa652c6e85f8a040010000000953ac65ab5251656500ffffffff03321d450000000000085265526a51526a529ede8b030000000003635151ce6065020000000001534c56ec1b", "acac", 0, 2094130012, "110d90fea9470dfe6c5048f45c3af5e8cc0cb77dd58fd13d338268e1c24b1ccc"); - run_test_sighash("ce0d322e04f0ffc7774218b251530a7b64ebefca55c90db3d0624c0ff4b3f03f918e8cf6f60300000003656500ffffffff9cce943872da8d8af29022d0b6321af5fefc004a281d07b598b95f6dcc07b1830200000007abab515351acab8d926410e69d76b7e584aad1470a97b14b9c879c8b43f9a9238e52a2c2fefc2001c56af8010000000400ab5253cd2cd1fe192ce3a93b5478af82fa250c27064df82ba416dfb0debf4f0eb307a746b6928901000000096500abacac6a0063514214524502947efc0200000000035251652c40340100000000096a6aab52000052656a5231c54c", "51", 2, -2090320538, "0322ca570446869ec7ec6ad66d9838cff95405002d474c0d3c17708c7ee039c6"); - run_test_sighash("233cd90b043916fc41eb870c64543f0111fb31f3c486dc72457689dea58f75c16ae59e9eb2000000000500536a6a6affffffff9ae30de76be7cd57fb81220fce78d74a13b2dbcad4d023f3cadb3c9a0e45a3ce000000000965ac6353ac5165515130834512dfb293f87cb1879d8d1b20ebad9d7d3d5c3e399a291ce86a3b4d30e4e32368a9020000000453005165ffffffff26d84ae93eb58c81158c9b3c3cbc24a84614d731094f38d0eea8686dec02824d0300000005636a65abacf02c784001a0bd5d03000000000900655351ab65ac516a416ef503", "", 1, -295106477, "b79f31c289e95d9dadec48ebf88e27c1d920661e50d090e422957f90ff94cb6e"); - run_test_sighash("9200e26b03ff36bc4bf908143de5f97d4d02358db642bd5a8541e6ff709c420d1482d471b70000000008abab65536a636553ffffffff61ba6d15f5453b5079fb494af4c48de713a0c3e7f6454d7450074a2a80cb6d880300000007ac6a00ab5165515dfb7574fbce822892c2acb5d978188b1d65f969e4fe874b08db4c791d176113272a5cc10100000000ffffffff0420958d000000000009ac63516a0063516353dd885505000000000465ac00007b79e901000000000066d8bf010000000005525252006a00000000", "ac5152", 0, 2089531339, "89ec7fab7cfe7d8d7d96956613c49dc48bf295269cfb4ea44f7333d88c170e62"); - run_test_sighash("45f335ba01ce2073a8b0273884eb5b48f56df474fc3dff310d9706a8ac7202cf5ac188272103000000025363ffffffff049d859502000000000365ab6a8e98b1030000000002ac51f3a80603000000000752535151ac00000306e30300000000020051b58b2b3a", "", 0, 1899564574, "78e01310a228f645c23a2ad0acbb8d91cedff4ecdf7ca997662c6031eb702b11"); - run_test_sighash("94083c840288d40a6983faca876d452f7c52a07de9268ad892e70a81e150d602a773c175ad03000000007ec3637d7e1103e2e7e0c61896cbbf8d7e205b2ecc93dd0d6d7527d39cdbf6d335789f660300000000ffffffff019e1f7b03000000000800ac0051acac0053539cb363", "", 1, -183614058, "a17b66d6bb427f42653d08207a22b02353dd19ccf2c7de6a9a3a2bdb7c49c9e7"); - run_test_sighash("30e0d4d20493d0cd0e640b757c9c47a823120e012b3b64c9c1890f9a087ae4f2001ca22a61010000000152f8f05468303b8fcfaad1fb60534a08fe90daa79bff51675472528ebe1438b6f60e7f60c10100000009526aab6551ac510053ffffffffaaab73957ea2133e32329795221ed44548a0d3a54d1cf9c96827e7cffd1706df0200000009ab00526a005265526affffffffd19a6fe54352015bf170119742821696f64083b5f14fb5c7d1b5a721a3d7786801000000085265abababac53abffffffff020f39bd030000000004ab6aac52049f6c050000000004ab52516aba5b4c60", "6a6365516a6a655253", 0, -624256405, "8e221a6c4bf81ca0d8a0464562674dcd14a76a32a4b7baf99450dd9195d411e6"); - run_test_sighash("5c0ac112032d6885b7a9071d3c5f493aa16c610a4a57228b2491258c38de8302014276e8be030000000300ab6a17468315215262ad5c7393bb5e0c5a6429fd1911f78f6f72dafbbbb78f3149a5073e24740300000003ac5100ffffffff33c7a14a062bdea1be3c9c8e973f54ade53fe4a69dcb5ab019df5f3345050be00100000008ac63655163526aab428defc0033ec36203000000000765516365536a00ae55b2000000000002ab53f4c0080400000000095265516a536563536a00000000", "6a005151006a", 2, 272749594, "91082410630337a5d89ff19145097090f25d4a20bdd657b4b953927b2f62c73b"); - run_test_sighash("e3683329026720010b08d4bec0faa244f159ae10aa582252dd0f3f80046a4e145207d54d31000000000852acac52656aacac3aaf2a5017438ad6adfa3f9d05f53ebed9ceb1b10d809d507bcf75e0604254a8259fc29c020000000653526552ab51f926e52c04b44918030000000000f7679c0100000000090000525152005365539e3f48050000000009516500ab635363ab008396c905000000000253650591024f", "6a6365", 0, 908746924, "458aec3b5089a585b6bad9f99fd37a2b443dc5a2eefac2b7e8c5b06705efc9db"); - run_test_sighash("00b20fd104dd59705b84d67441019fa26c4c3dec5fd3b50eca1aa549e750ef9ddb774dcabe000000000651ac656aac65ffffffff52d4246f2db568fc9eea143e4d260c698a319f0d0670f84c9c83341204fde48b0200000000ffffffffb8aeabb85d3bcbc67b132f1fd815b451ea12dcf7fc169c1bc2e2cf433eb6777a03000000086a51ac6aab6563acd510d209f413da2cf036a31b0def1e4dcd8115abf2e511afbcccb5ddf41d9702f28c52900100000006ac52ab6a0065ffffffff039c8276000000000008ab53655200656a52401561010000000003acab0082b7160100000000035100ab00000000", "535265", 1, -947367579, "3212c6d6dd8d9d3b2ac959dec11f4638ccde9be6ed5d36955769294e23343da0"); - run_test_sighash("624d28cb02c8747915e9af2b13c79b417eb34d2fa2a73547897770ace08c6dd9de528848d3030000000651ab63abab533c69d3f9b75b6ef8ed2df50c2210fd0bf4e889c42477d58682f711cbaece1a626194bb85030000000765acab53ac5353ffffffff018cc280040000000009abacabac52636352ac6859409e", "ac51ac", 1, 1005144875, "919144aada50db8675b7f9a6849c9d263b86450570293a03c245bd1e3095e292"); - run_test_sighash("8f28471d02f7d41b2e70e9b4c804f2d90d23fb24d53426fa746bcdcfffea864925bdeabe3e0200000001acffffffff76d1d35d04db0e64d65810c808fe40168f8d1f2143902a1cc551034fd193be0e0000000001acffffffff048a5565000000000005005151516afafb610400000000045263ac53648bb30500000000086363516a6a5165513245de01000000000000000000", "6a0053510053", 1, -1525137460, "305fc8ff5dc04ebd9b6448b03c9a3d945a11567206c8d5214666b30ec6d0d6cc"); - run_test_sighash("10ec50d7046b8b40e4222a3c6449490ebe41513aad2eca7848284a08f3069f3352c2a9954f0000000009526aac656352acac53ffffffff0d979f236155aa972472d43ee6f8ce22a2d052c740f10b59211454ff22cb7fd00200000007acacacab63ab53ffffffffbbf97ebde8969b35725b2e240092a986a2cbfd58de48c4475fe077bdd493a20c010000000663ab5365ababffffffff4600722d33b8dba300d3ad037bcfc6038b1db8abfe8008a15a1de2da2264007302000000035351ac6dbdafaf020d0ccf04000000000663ab6a51ab6ae06e5e0200000000036aabab00000000", "", 0, -1658960232, "2420dd722e229eccafae8508e7b8d75c6920bfdb3b5bac7cb8e23419480637c2"); - run_test_sighash("43559290038f32fda86580dd8a4bc4422db88dd22a626b8bd4f10f1c9dd325c8dc49bf479f01000000026351ffffffff401339530e1ed3ffe996578a17c3ec9d6fccb0723dd63e7b3f39e2c44b976b7b0300000006ab6a65656a51ffffffff6fb9ba041c96b886482009f56c09c22e7b0d33091f2ac5418d05708951816ce7000000000551ac525100ffffffff020921e40500000000035365533986f40500000000016a00000000", "52ac51", 0, 1769771809, "02040283ef2291d8e1f79bb71bdabe7c1546c40d7ed615c375643000a8b9600d"); - run_test_sighash("35b6fc06047ebad04783a5167ab5fc9878a00c4eb5e7d70ef297c33d5abd5137a2dea9912402000000036aacacffffffff21dc291763419a584bdb3ed4f6f8c60b218aaa5b99784e4ba8acfec04993e50c03000000046a00ac6affffffff69e04d77e4b662a82db71a68dd72ef0af48ca5bebdcb40f5edf0caf591bb41020200000000b5db78a16d93f5f24d7d932f93a29bb4b784febd0cbb1943f90216dc80bba15a0567684b000000000853ab52ab5100006a1be2208a02f6bdc103000000000265ab8550ea04000000000365636a00000000", "", 0, -1114114836, "1c8655969b241e717b841526f87e6bd68b2329905ba3fc9e9f72526c0b3ea20c"); - run_test_sighash("f35befbc03faf8c25cc4bc0b92f6239f477e663b44b83065c9cb7cf231243032cf367ce3130000000005ab65526a517c4c334149a9c9edc39e29276a4b3ffbbab337de7908ea6f88af331228bd90086a6900ba020000000151279d19950d2fe81979b72ce3a33c6d82ebb92f9a2e164b6471ac857f3bbd3c0ea213b542010000000953ab51635363520065052657c20300a9ba04000000000452636a6a0516ea020000000008535253656365ababcfdd3f01000000000865ac516aac00530000000000", "", 2, -99793521, "c834a5485e68dc13edb6c79948784712122440d7fa5bbaa5cd2fc3d4dac8185d"); - run_test_sighash("d3da18520216601acf885414538ce2fb4d910997eeb91582cac42eb6982c9381589587794f0300000000fffffffff1b1c9880356852e10cf41c02e928748dd8fae2e988be4e1c4cb32d0bfaea6f7000000000465ab6aabffffffff02fb0d69050000000002ababeda8580500000000085163526565ac52522b913c95", "ac", 1, -1247973017, "99b32b5679d91e0f9cdd6737afeb07459806e5acd7630c6a3b9ab5d550d0c003"); - run_test_sighash("8218eb740229c695c252e3630fc6257c42624f974bc856b7af8208df643a6c520ef681bfd00000000002510066f30f270a09b2b420e274c14d07430008e7886ec621ba45665057120afce58befca96010300000004525153ab84c380a9015d96100000000000076a5300acac526500000000", "ac005263", 0, -1855679695, "5071f8acf96aea41c7518bd1b5b6bbe16258b529df0c03f9e374b83c66b742c6"); - run_test_sighash("1123e7010240310013c74e5def60d8e14dd67aedff5a57d07a24abc84d933483431b8cf8ea0300000003530051fc6775ff1a23c627a2e605dd2560e84e27f4208300071e90f4589e762ad9c9fe8d0da95e020000000465655200ffffffff04251598030000000004ab65ab639d28d90400000000096563636aacac525153474df801000000000851525165ac51006a75e23b040000000000e5bd3a4a", "6363636565", 0, -467124448, "9cb0dd04e9fe287b112e94a1647590d27e8b164ca13c4fe70c610fd13f82c2fd"); - run_test_sighash("3b937e05032b8895d2f4945cb7e3679be2fbd15311e2414f4184706dbfc0558cf7de7b4d000000000001638b91a12668a3c3ce349788c961c26aa893c862f1e630f18d80e7843686b6e1e6fc396310000000000852635353ab65ac51eeb09dd1c9605391258ee6f74b9ae17b5e8c2ef010dc721c5433dcdc6e93a1593e3b6d1700000000085365ac6553526351ffffffff0308b18e04000000000253acb6dd00040000000008536aac5153ac516ab0a88201000000000500ac006500804e3ff2", "", 0, 416167343, "595a3c02254564634e8085283ec4ea7c23808da97ce9c5da7aecd7b553e7fd7f"); - run_test_sighash("a48f27ca047997470da74c8ee086ddad82f36d9c22e790bd6f8603ee6e27ad4d3174ea875403000000095153ac636aab6aacabffffffffefc936294e468d2c9a99e09909ba599978a8c0891ad47dc00ba424761627cef202000000056a51630053ffffffff304cae7ed2d3dbb4f2fbd679da442aed06221ffda9aee460a28ceec5a9399f4e0200000000f5bddf82c9c25fc29c5729274c1ff0b43934303e5f595ce86316fc66ad263b96ca46ab8d0100000003536500d7cf226b0146b00c04000000000200ac5c2014ce", "515100636563", 0, 1991799059, "9c051a7092fe17fa62b1720bc2c4cb2ffc1527d9fb0b006d2e142bb8fe07bf3c"); - run_test_sighash("180cd53101c5074cf0b7f089d139e837fe49932791f73fa2342bd823c6df6a2f72fe6dba1303000000076a6a63ac53acabffffffff03853bc1020000000007ac526a6a6a6a003c4a8903000000000453515163a0fbbd030000000005ab656a5253253d64cf", "ac65", 0, -1548453970, "4d8efb3b99b9064d2f6be33b194a903ffabb9d0e7baa97a48fcec038072aac06"); - run_test_sighash("c21ec8b60376c47e057f2c71caa90269888d0ffd5c46a471649144a920d0b409e56f190b700000000008acac6a526a536365ffffffff5d315d9da8bf643a9ba11299450b1f87272e6030fdb0c8adc04e6c1bfc87de9a0000000000ea43a9a142e5830c96b0ce827663af36b23b0277244658f8f606e95384574b91750b8e940000000007516a63ac0063acffffffff023c61be0400000000055165ab5263313cc8020000000006006a53526551ed8c3d56", "6a", 1, 1160627414, "a638cc17fd91f4b1e77877e8d82448c84b2a4e100df1373f779de7ad32695112"); - run_test_sighash("b8fd394001ed255f49ad491fecc990b7f38688e9c837ccbc7714ddbbf5404f42524e68c18f0000000007ab6353535363ab081e15ee02706f7d050000000008515200535351526364c7ec040000000005636a53acac9206cbe1", "655352ac", 0, -1251578838, "8e0697d8cd8a9ccea837fd798cc6c5ed29f6fbd1892ee9bcb6c944772778af19"); - run_test_sighash("e42a76740264677829e30ed610864160c7f97232c16528fe5610fc08814b21c34eefcea69d010000000653006a6a0052ffffffff647046cf44f217d040e6a8ff3f295312ab4dd5a0df231c66968ad1c6d8f4428000000000025352ffffffff0199a7f900000000000000000000", "655263006a005163", 1, 1122505713, "7cda43f1ff9191c646c56a4e29b1a8c6cb3f7b331da6883ef2f0480a515d0861"); - run_test_sighash("a2dfa4690214c1ab25331815a5128f143219de51a47abdc7ce2d367e683eeb93960a31af9f010000000363636affffffff8be0628abb1861b078fcc19c236bc4cc726fa49068b88ad170adb2a97862e7460200000004ac655363ffffffff0441f11103000000000153dbab0c000000000009ab53ac5365526aab63abbb95050000000004ab52516a29a029040000000003ac526a00000000", "6a52ac63", 1, -1302210567, "913060c7454e6c80f5ba3835454b54db2188e37dc4ce72a16b37d11a430b3d23"); - run_test_sighash("9dbc591f04521670af83fb3bb591c5d4da99206f5d38e020289f7db95414390dddbbeb56680100000004ac5100acffffffffb6a40b5e29d5e459f8e72d39f800089529f0889006cad3d734011991da8ef09d0100000009526a5100acab536a515fc427436df97cc51dc8497642ffc868857ee245314d28b356bd70adba671bd6071301fc0000000000ffffffff487efde2f620566a9b017b2e6e6d42525e4070f73a602f85c6dfd58304518db30000000005516353006a8d8090180244904a0200000000046a65656ab1e9c203000000000451ab63aba06a5449", "", 0, -1414953913, "bae189eb3d64aedbc28a6c28f6c0ccbd58472caaf0cf45a5aabae3e031dd1fea"); - run_test_sighash("1345fb2c04bb21a35ae33a3f9f295bece34650308a9d8984a989dfe4c977790b0c21ff9a7f0000000006ac52ac6a0053ffffffff7baee9e8717d81d375a43b691e91579be53875350dfe23ba0058ea950029fcb7020000000753ab53ab63ab52ffffffff684b6b3828dfb4c8a92043b49b8cb15dd3a7c98b978da1d314dce5b9570dadd202000000086353ab6a5200ac63d1a8647bf667ceb2eae7ec75569ca249fbfd5d1b582acfbd7e1fcf5886121fca699c011d0100000003ac006affffffff049b1eb00300000000001e46dc0100000000080065ab6a6a630065ca95b40300000000030051520c8499010000000006ab6aac526a6500000000", "53526aac636300", 2, 1809978100, "cfeaa36790bc398783d4ca45e6354e1ea52ee74e005df7f9ebd10a680e9607bf"); - run_test_sighash("7d75dc8f011e5f9f7313ba6aedef8dbe10d0a471aca88bbfc0c4a448ce424a2c5580cda1560300000003ab5152ffffffff01997f8e0200000000096552ac6a65656563530d93bbcc", "00656a6563", 0, 1414485913, "ec91eda1149f75bffb97612569a78855498c5d5386d473752a2c81454f297fa7"); - run_test_sighash("1459179504b69f01c066e8ade5e124c748ae5652566b34ed673eea38568c483a5a4c4836ca0100000008ac5352006563656affffffff5d4e037880ab1975ce95ea378d2874dcd49d5e01e1cdbfae3343a01f383fa35800000000095251ac52ac6aac6500ffffffff7de3ae7d97373b7f2aeb4c55137b5e947b2d5fb325e892530cb589bc4f92abd503000000086563ac53ab520052ffffffffb4db36a32d6e543ef49f4bafde46053cb85b2a6c4f0e19fa0860d9083901a1190300000003ab51531bbcfe5504a6dbda040000000008536a5365abac6500d660c80300000000096565abab6a53536a6a54e84e010000000003acac52df2ccf0500000000025351220c857e", "", 2, 1879181631, "3aad18a209fab8db44954eb55fd3cc7689b5ec9c77373a4d5f4dae8f7ae58d14"); - run_test_sighash("cabb1b06045a895e6dcfc0c1e971e94130c46feace286759f69a16d298c8b0f6fd0afef8f20300000004ac006352ffffffffa299f5edac903072bfb7d29b663c1dd1345c2a33546a508ba5cf17aab911234602000000056a65515365ffffffff89a20dc2ee0524b361231092a070ace03343b162e7162479c96b757739c8394a0300000002abab92ec524daf73fabee63f95c1b79fa8b84e92d0e8bac57295e1d0adc55dc7af5534ebea410200000001534d70e79b04674f6f00000000000600abacab53517d60cc0200000000035265ab96c51d040000000004ac6300ac62a787050000000008006a516563ab63639e2e7ff7", "6551ac6351ac", 3, 1942663262, "d0c4a780e4e0bc22e2f231e23f01c9d536b09f6e5be51c123d218e906ec518be"); - run_test_sighash("8b96d7a30132f6005b5bd33ea82aa325e2bcb441f46f63b5fca159ac7094499f380f6b7e2e00000000076aacabac6300acffffffff0158056700000000000465005100c319e6d0", "52006a", 0, -1100733473, "fb4bd26a91b5cf225dd3f170eb09bad0eac314bc1e74503cc2a3f376833f183e"); - run_test_sighash("112191b7013cfbe18a175eaf09af7a43cbac2c396f3695bbe050e1e5f4250603056d60910e02000000001c8a5bba03738a22010000000005525352656a77a149010000000002510003b52302000000000351ac52722be8e6", "65ac6565", 0, -1847972737, "8e795aeef18f510d117dfa2b9f4a2bd2e2847a343205276cedd2ba14548fd63f"); - run_test_sighash("ce6e1a9e04b4c746318424705ea69517e5e0343357d131ad55d071562d0b6ebfedafd6cb840100000003656553ffffffff67bd2fa78e2f52d9f8900c58b84c27ef9d7679f67a0a6f78645ce61b883fb8de000000000100d699a56b9861d99be2838e8504884af4d30b909b1911639dd0c5ad47c557a0773155d4d303000000046a5151abffffffff9fdb84b77c326921a8266854f7bbd5a71305b54385e747fe41af8a397e78b7fa010000000863acac6a51ab00ac0d2e9b9d049b8173010000000007ac53526a650063ba9b7e010000000008526a00525263acac0ab3fd030000000000ea8a0303000000000200aca61a97b9", "", 1, -1276952681, "b6ed4a3721be3c3c7305a5128c9d418efa58e419580cec0d83f133a93e3a22c5"); - run_test_sighash("2f7353dd02e395b0a4d16da0f7472db618857cd3de5b9e2789232952a9b154d249102245fd030000000151617fd88f103280b85b0a198198e438e7cab1a4c92ba58409709997cc7a65a619eb9eec3c0200000003636aabffffffff0397481c0200000000045300636a0dc97803000000000009d389030000000003ac6a53134007bb", "0000536552526a", 0, -1912746174, "30c4cd4bd6b291f7e9489cc4b4440a083f93a7664ea1f93e77a9597dab8ded9c"); - run_test_sighash("89e7928c04363cb520eff4465251fd8e41550cbd0d2cdf18c456a0be3d634382abcfd4a2130200000006ac516a6a656355042a796061ed72db52ae47d1607b1ceef6ca6aea3b7eea48e7e02429f382b378c4e51901000000085351ab6352ab5252ffffffff53631cbda79b40183000d6ede011c778f70147dc6fa1aed3395d4ce9f7a8e69701000000096a6553ab52516a52abad0de418d80afe059aab5da73237e0beb60af4ac490c3394c12d66665d1bac13bdf29aa8000000000153f2b59ab6027a33eb040000000007005351ac5100ac88b941030000000003ab0052e1e8a143", "63656a", 0, 1258533326, "b575a04b0bb56e38bbf26e1a396a76b99fb09db01527651673a073a75f0a7a34"); - run_test_sighash("ca356e2004bea08ec2dd2df203dc275765dc3f6073f55c46513a588a7abcc4cbde2ff011c7020000000553525100003aefec4860ef5d6c1c6be93e13bd2d2a40c6fb7361694136a7620b020ecbaca9413bcd2a030000000965ac00536352535100ace4289e00e97caaea741f2b89c1143060011a1f93090dc230bee3f05e34fbd8d8b6c399010000000365526affffffff48fc444238bda7a757cb6a98cb89fb44338829d3e24e46a60a36d4e24ba05d9002000000026a53ffffffff03d70b440200000000056a6a526aac853c97010000000002515335552202000000000351635300000000", "0052", 3, -528192467, "fc93cc056c70d5e033933d730965f36ad81ef64f1762e57f0bc5506c5b507e24"); - run_test_sighash("82d4fa65017958d53e562fac073df233ab154bd0cf6e5a18f57f4badea8200b217975e31030200000004636aab51ac0891a204227cc9050000000006635200655365bfef8802000000000865650051635252acfc2d09050000000006ab65ac51516380195e030000000007ac52525352510063d50572", "53", 0, -713567171, "e095003ca82af89738c1863f0f5488ec56a96fb81ea7df334f9344fcb1d0cf40"); - run_test_sighash("75f6949503e0e47dd70426ef32002d6cdb564a45abedc1575425a18a8828bf385fa8e808e600000000036aabab82f9fd14e9647d7a1b5284e6c55169c8bd228a7ea335987cef0195841e83da45ec28aa2e0300000002516350dc6fe239d150efdb1b51aa288fe85f9b9f741c72956c11d9dcd176889963d699abd63f0000000001ab429a63f502777d20010000000007abac52ac516a53d081d9020000000003acac630c3cc3a8", "535152516551510000", 1, 973814968, "c6ec1b7cb5c16a1bfd8a3790db227d2acc836300534564252b57bd66acf95092"); - run_test_sighash("e86a24bc03e4fae784cdf81b24d120348cb5e52d937cd9055402fdba7e43281e482e77a1c100000000046363006affffffffa5447e9bdcdab22bd20d88b19795d4c8fb263fbbf7ce8f4f9a85f865953a6325020000000663ac53535253ffffffff9f8b693bc84e0101fc73748e0513a8cecdc264270d8a4ee1a1b6717607ee1eaa00000000026a513417bf980158d82c020000000009005253005351acac5200000000", "6353516365536a6a", 2, -563792735, "508129278ef07b43112ac32faf00170ad38a500eed97615a860fd58baaad174b"); - run_test_sighash("536bc5e60232eb60954587667d6bcdd19a49048d67a027383cc0c2a29a48b960dc38c5a0370300000005ac636300abffffffff8f1cfc102f39b1c9348a2195d496e602c77d9f57e0769dabde7eaaedf9c69e250100000006acabab6a6351ffffffff0432f56f0400000000046a5365517fd54b0400000000035265539484e4050000000003536a5376dc25020000000008ac536aab6aab536ab978e686", "ac0051006a006a006a", 0, -273074082, "f151f1ec305f698d9fdce18ea292b145a58d931f1518cf2a4c83484d9a429638"); - run_test_sighash("fab796ee03f737f07669160d1f1c8bf0800041157e3ac7961fea33a293f976d79ce49c02ab0200000003ac5252eb097ea1a6d1a7ae9dace338505ba559e579a1ee98a2e9ad96f30696d6337adcda5a85f403000000096500abab656a6a656396d5d41a9b11f571d91e4242ddc0cf2420eca796ad4882ef1251e84e42b930398ec69dd80100000005526551ac6a8e5d0de804f763bb0400000000015288271a010000000001acf2bf2905000000000300ab51c9641500000000000952655363636365ac5100000000", "00ac536552", 0, -1854521113, "f3bbab70b759fe6cfae1bf349ce10716dbc64f6e9b32916904be4386eb461f1f"); - run_test_sighash("f2b539a401e4e8402869d5e1502dbc3156dbce93583f516a4947b333260d5af1a34810c6a00200000003525363ffffffff01d305e2000000000005acab535200a265fe77", "", 0, -1435650456, "41617b27321a830c712638dbb156dae23d4ef181c7a06728ccbf3153ec53d7dd"); - run_test_sighash("9f10b1d8033aee81ac04d84ceee0c03416a784d1017a2af8f8a34d2f56b767aea28ff88c8f02000000025352ffffffff748cb29843bea8e9c44ed5ff258df1faf55fbb9146870b8d76454786c4549de100000000016a5ba089417305424d05112c0ca445bc7107339083e7da15e430050d578f034ec0c589223b0200000007abac53ac6565abffffffff025a4ecd010000000006636563ab65ab40d2700000000000056a6553526333fa296c", "", 0, -395044364, "20fd0eee5b5716d6cbc0ddf852614b686e7a1534693570809f6719b6fcb0a626"); - run_test_sighash("ff2ecc09041b4cf5abb7b760e910b775268abee2792c7f21cc5301dd3fecc1b4233ee70a2c0200000009acac5300006a51526affffffffeb39c195a5426afff38379fc85369771e4933587218ef4968f3f05c51d6b7c92000000000165453a5f039b8dbef7c1ffdc70ac383b481f72f99f52b0b3a5903c825c45cfa5d2c0642cd50200000001654b5038e6c49daea8c0a9ac8611cfe904fc206dad03a41fb4e5b1d6d85b1ecad73ecd4c0102000000096a51000053ab656565bdb5548302cc719200000000000452655265214a3603000000000300ab6a00000000", "52516a006a63", 1, -2113289251, "37ed6fae36fcb3360c69cac8b359daa62230fc1419b2cf992a32d8f3e079dcff"); - run_test_sighash("70a8577804e553e462a859375957db68cfdf724d68caeacf08995e80d7fa93db7ebc04519d02000000045352ab53619f4f2a428109c5fcf9fee634a2ab92f4a09dc01a5015e8ecb3fc0d9279c4a77fb27e900000000006ab6a51006a6affffffff3ed1a0a0d03f25c5e8d279bb5d931b7eb7e99c8203306a6c310db113419a69ad010000000565516300abffffffff6bf668d4ff5005ef73a1b0c51f32e8235e67ab31fe019bf131e1382050b39a630000000004536a6563ffffffff02faf0bb00000000000163cf2b4b05000000000752ac635363acac15ab369f", "ac", 0, -1175809030, "1c9d6816c20865849078f9777544b5ddf37c8620fe7bd1618e4b72fb72dddca1"); - run_test_sighash("a3604e5304caa5a6ba3c257c20b45dcd468f2c732a8ca59016e77b6476ac741ce8b16ca8360200000004acac6553ffffffff695e7006495517e0b79bd4770f955040610e74d35f01e41c9932ab8ccfa3b55d0300000007ac5253515365acffffffff6153120efc5d73cd959d72566fc829a4eb00b3ef1a5bd3559677fb5aae116e38000000000400abab52c29e7abd06ff98372a3a06227386609adc7665a602e511cadcb06377cc6ac0b8f63d4fdb03000000055100acabacffffffff04209073050000000009ab5163ac525253ab6514462e05000000000952abacab636300656a20672c0400000000025153b276990000000000056565ab6a5300000000", "5351", 0, 1460890590, "249c4513a49076c6618aabf736dfd5ae2172be4311844a62cf313950b4ba94be"); - run_test_sighash("c6a72ed403313b7d027f6864e705ec6b5fa52eb99169f8ea7cd884f5cdb830a150cebade870100000009ac63ab516565ab6a51ffffffff398d5838735ff43c390ca418593dbe43f3445ba69394a6d665b5dc3b4769b5d700000000075265acab515365ffffffff7ee5616a1ee105fd18189806a477300e2a9cf836bf8035464e8192a0d785eea3030000000700ac6a51516a52ffffffff018075fd0000000000015100000000", "005251acac5252", 2, -656067295, "2cc1c7514fdc512fd45ca7ba4f7be8a9fe6d3318328bc1a61ae6e7675047e654"); - run_test_sighash("93c12cc30270fc4370c960665b8f774e07942a627c83e58e860e38bd6b0aa2cb7a2c1e060901000000036300abffffffff4d9b618035f9175f564837f733a2b108c0f462f28818093372eec070d9f0a5440300000001acffffffff039c2137020000000001525500990100000000055265ab636a07980e0300000000005ba0e9d1", "656a5100", 1, 18954182, "6beca0e0388f824ca33bf3589087a3c8ad0857f9fe7b7609ae3704bef0eb83e2"); - run_test_sighash("97bddc63015f1767619d56598ad0eb5c7e9f880b24a928fea1e040e95429c930c1dc653bdb0100000008ac53acac00005152aaa94eb90235ed10040000000000287bdd0400000000016a8077673a", "acac6a536352655252", 0, -813649781, "5990b139451847343c9bb89cdba0e6daee6850b60e5b7ea505b04efba15f5d92"); - run_test_sighash("cc3c9dd303637839fb727270261d8e9ddb8a21b7f6cbdcf07015ba1e5cf01dc3c3a327745d0300000000d2d7804fe20a9fca9659a0e49f258800304580499e8753046276062f69dbbde85d17cd2201000000096352536a520000acabffffffffbc75dfa9b5f81f3552e4143e08f485dfb97ae6187330e6cd6752de6c21bdfd21030000000600ab53650063ffffffff0313d0140400000000096565515253526aacac167f0a040000000008acab00535263536a9a52f8030000000006abab5151ab63f75b66f2", "6a635353636a65ac65", 1, 377286607, "dbc7935d718328d23d73f8a6dc4f53a267b8d4d9816d0091f33823bd1f0233e9"); - run_test_sighash("236f91b702b8ffea3b890700b6f91af713480769dda5a085ae219c8737ebae90ff25915a3203000000056300ac6300811a6a10230f12c9faa28dae5be2ebe93f37c06a79e76214feba49bb017fb25305ff84eb020000000100ffffffff041e351703000000000351ac004ff53e050000000003ab53636c1460010000000000cb55f701000000000651520051ab0000000000", "acac636a6aac5300", 0, 406448919, "793a3d3c37f6494fab79ff10c16702de002f63e34be25dd8561f424b0ea938c4"); - run_test_sighash("c47d5ad60485cb2f7a825587b95ea665a593769191382852f3514a486d7a7a11d220b62c54000000000663655253acab8c3cf32b0285b040e50dcf6987ddf7c385b3665048ad2f9317b9e0c5ba0405d8fde4129b00000000095251ab00ac65635300ffffffff549fe963ee410d6435bb2ed3042a7c294d0c7382a83edefba8582a2064af3265000000000152fffffffff7737a85e0e94c2d19cd1cde47328ece04b3e33cd60f24a8a345da7f2a96a6d0000000000865ab6a0051656aab28ff30d5049613ea020000000005ac51000063f06df1050000000008ac63516aabac5153afef5901000000000700656500655253688bc00000000000086aab5352526a53521ff1d5ff", "51ac52", 2, -1296011911, "0c1fd44476ff28bf603ad4f306e8b6c7f0135a441dc3194a6f227cb54598642a"); - run_test_sighash("0b43f122032f182366541e7ee18562eb5f39bc7a8e5e0d3c398f7e306e551cdef773941918030000000863006351ac51acabffffffffae586660c8ff43355b685dfa8676a370799865fbc4b641c5a962f0849a13d8250100000005abab63acabffffffff0b2b6b800d8e77807cf130de6286b237717957658443674df047a2ab18e413860100000008ab6aac655200ab63ffffffff04f1dbca03000000000800635253ab656a52a6eefd0300000000036365655d8ca90200000000005a0d530400000000015300000000", "65ac65acac", 0, 351448685, "86f26e23822afd1bdfc9fff92840fc1e60089f12f54439e3ab9e5167d0361dcf"); - run_test_sighash("af1c4ab301ec462f76ee69ba419b1b2557b7ded639f3442a3522d4f9170b2d6859765c3df402000000016affffffff01a5ca6c000000000008ab52536aab00005300000000", "6a6351", 0, 110304602, "e88ed2eea9143f2517b15c03db00767eb01a5ce12193b99b964a35700607e5f4"); - run_test_sighash("0bfd34210451c92cdfa02125a62ba365448e11ff1db3fb8bc84f1c7e5615da40233a8cd368010000000252ac9a070cd88dec5cf9aed1eab10d19529720e12c52d3a21b92c6fdb589d056908e43ea910e0200000009ac516a52656a6a5165ffffffffc3edcca8d2f61f34a5296c405c5f6bc58276416c720c956ff277f1fb81541ddd00000000030063abffffffff811247905cdfc973d179c03014c01e37d44e78f087233444dfdce1d1389d97c302000000065163000063ab1724a26e02ca37c902000000000851ab53525352ac529012a90100000000085200525253535353fa32575b", "5352ac6351", 1, -1087700448, "b8f1e1f35e3e1368bd17008c756e59cced216b3c699bcd7bebdb5b6c8eec4697"); - run_test_sighash("467a3e7602e6d1a7a531106791845ec3908a29b833598e41f610ef83d02a7da3a1900bf2960000000005ab6a636353ffffffff031db6dac6f0bafafe723b9199420217ad2c94221b6880654f2b35114f44b1df010000000965ab52636a63ac6352ffffffff02b3b95c0100000000026300703216030000000001ab3261c0aa", "6a", 0, 2110869267, "3078b1d1a7713c6d101c64afe35adfae0977a5ab4c7e07a0b170b041258adbf2"); - run_test_sighash("8713bc4f01b411149d575ebae575f5dd7e456198d61d238695df459dd9b86c4e3b2734b62e0300000004abac6363ffffffff03b58049050000000002ac653c714c04000000000953656a005151526a527b5a9e03000000000652ac5100525300000000", "52", 0, -647281251, "0e0bed1bf2ff255aef6e5c587f879ae0be6222ab33bd75ee365ec6fbb8acbe38"); - run_test_sighash("b5a7df6102107beded33ae7f1dec0531d4829dff7477260925aa2cba54119b7a07d92d5a1d02000000046a516a52803b625c334c1d2107a326538a3db92c6c6ae3f7c3516cd90a09b619ec6f58d10e77bd6703000000056563006a63ffffffff0117484b03000000000853acab52526a65abc1b548a1", "ac006a525100", 0, 2074359913, "680336db57347d8183b8898cd27a83f1ba5884155aeae5ce20b4840b75e12871"); - run_test_sighash("49eb2178020a04fca08612c34959fd41447319c190fb7ffed9f71c235aa77bec28703aa1820200000003ac6353abaff326071f07ec6b77fb651af06e8e8bd171068ec96b52ed584de1d71437fed186aecf0300000001acffffffff03da3dbe02000000000652ac63ac6aab8f3b680400000000096a536a65636a53516a5175470100000000016500000000", "6a536365", 0, 1283691249, "c670219a93234929f662ecb9aa148a85a2d281e83f4e53d10509461cdea47979"); - run_test_sighash("0f96cea9019b4b3233c0485d5b1bad770c246fe8d4a58fb24c3b7dfdb3b0fd90ea4e8e947f0300000006006a5163515303571e1e01906956030000000005ab635353abadc0fbbe", "acac", 0, -1491469027, "716a8180e417228f769dcb49e0491e3fda63badf3d5ea0ceeac7970d483dd7e2"); - run_test_sighash("148e68480196eb52529af8e83e14127cbfdbd4a174e60a86ac2d86eac9665f46f4447cf7aa01000000045200ac538f8f871401cf240c0300000000065252ab52656a5266cf61", "", 0, -344314825, "eacc47c5a53734d6ae3aedbc6a7c0a75a1565310851b29ef0342dc4745ceb607"); - run_test_sighash("6c7913f902aa3f5f939dd1615114ce961beda7c1e0dd195be36a2f0d9d047c28ac62738c3a020000000453abac00ffffffff477bf2c5b5c6733881447ac1ecaff3a6f80d7016eee3513f382ad7f554015b970100000007ab6563acab5152ffffffff04e58fe1040000000009ab00526aabab526553e59790010000000002ab525a834b03000000000035fdaf0200000000086551ac65515200ab00000000", "63ac53", 1, 1285478169, "1536da582a0b6de017862445e91ba14181bd6bf953f4de2f46b040d351a747c9"); - run_test_sighash("3320f6730132f830c4681d0cae542188e4177cad5d526fae84565c60ceb5c0118e844f90bd030000000163ffffffff0257ec5a040000000005525251ac6538344d000000000002515200000000", "5352656a53ac516a65", 0, 788050308, "3afacaca0ef6be9d39e71d7b1b118994f99e4ea5973c9107ca687d28d8eba485"); - run_test_sighash("c13aa4b702eedd7cde09d0416e649a890d40e675aa9b5b6d6912686e20e9b9e10dbd40abb1000000000863ab6353515351ac11d24dc4cc22ded7cdbc13edd3f87bd4b226eda3e4408853a57bcd1becf2df2a1671fd1600000000045165516affffffff01baea300100000000076aab52ab53005300000000", "0065", 0, -1195908377, "241a23e7b1982d5f78917ed97a8678087acbbffe7f624b81df78a5fe5e41e754"); - run_test_sighash("a2692fff03b2387f5bacd5640c86ba7df574a0ee9ed7f66f22c73cccaef3907eae791cbd230200000004536363abffffffff4d9fe7e5b375de88ba48925d9b2005447a69ea2e00495a96eafb2f144ad475b40000000008000053000052636537259bee3cedd3dcc07c8f423739690c590dc195274a7d398fa196af37f3e9b4a1413f810000000006ac63acac52abffffffff04c65fe60200000000075151536365ab657236fc020000000009005263ab00656a6a5195b8b6030000000007ac5165636aac6a7d7b66010000000002acab00000000", "51", 2, -826546582, "925037c7dc7625f3f12dc83904755a37016560de8e1cdd153c88270a7201cf15"); - run_test_sighash("2c5b003201b88654ac2d02ff6762446cb5a4af77586f05e65ee5d54680cea13291efcf930d0100000005ab536a006a37423d2504100367000000000004536a515335149800000000000152166aeb03000000000452510063226c8e03000000000000000000", "635251", 0, 1060344799, "7e058ca5dd07640e4aae7dea731cfb7d7fef1bfd0d6d7b6ce109d041f4ca2a31"); - run_test_sighash("f981b9e104acb93b9a7e2375080f3ea0e7a94ce54cd8fb25c57992fa8042bdf4378572859f0100000002630008604febba7e4837da77084d5d1b81965e0ea0deb6d61278b6be8627b0d9a2ecd7aeb06a0300000005ac5353536a42af3ef15ce7a2cd60482fc0d191c4236e66b4b48c9018d7dbe4db820f5925aad0e8b52a0300000008ab0063510052516301863715efc8608bf69c0343f18fb81a8b0c720898a3563eca8fe630736c0440a179129d03000000086aac6a52ac6a63ac44fec4c00408320a03000000000062c21c030000000007ac6a655263006553835f0100000000015303cd60000000000005535263536558b596e0", "00", 0, -2140385880, "49870a961263354c9baf108c6979b28261f99b374e97605baa532d9fa3848797"); - run_test_sighash("c4b702e502f1a54f235224f0e6de961d2e53b506ab45b9a40805d1dacd35148f0acf24ca5e00000000085200ac65ac53acabf34ba6099135658460de9d9b433b84a8562032723635baf21ca1db561dce1c13a06f4407000000000851ac006a63516aabffffffff02a853a603000000000163d17a67030000000005ab63006a5200000000", "ac5363515153", 1, 480734903, "5c46f7ac3d6460af0da28468fcc5b3c87f2b9093d0f837954b7c8174b4d7b6e7"); - run_test_sighash("9b83f78704f492b9b353a3faad8d93f688e885030c274856e4037818848b99e490afef27770200000000ffffffff36b60675a5888c0ef4d9e11744ecd90d9fe9e6d8abb4cff5666c898fdce98d9e00000000056aab656352596370fca7a7c139752971e169a1af3e67d7656fc4fc7fd3b98408e607c2f2c836c9f27c030000000653ac51ab6300a0761de7e158947f401b3595b7dc0fe7b75fa9c833d13f1af57b9206e4012de0c41b8124030000000953656a53ab53510052242e5f5601bf83b301000000000465516a6300000000", "63515200ac656365", 3, -150879312, "9cf05990421ea853782e4a2c67118e03434629e7d52ab3f1d55c37cf7d72cdc4"); - run_test_sighash("f492a9da04f80b679708c01224f68203d5ea2668b1f442ebba16b1aa4301d2fe5b4e2568f3010000000953005351525263ab65ffffffff93b34c3f37d4a66df255b514419105b56d7d60c24bf395415eda3d3d8aa5cd0101000000020065ffffffff9dba34dabdc4f1643b372b6b77fdf2b482b33ed425914bb4b1a61e4fad33cf390000000002ab52ffffffffbbf3dc82f397ef3ee902c5146c8a80d9a1344fa6e38b7abce0f157be7adaefae0000000009515351005365006a51ffffffff021359ba010000000000403fea0200000000095200ac6353abac635300000000", "00ac51acacac", 0, -2115078404, "fd44fc98639ca32c927929196fc3f3594578f4c4bd248156a25c04a65bf3a9f3"); - run_test_sighash("2f73e0b304f154d3a00fde2fdd40e791295e28d6cb76af9c0fd8547acf3771a02e3a92ba37030000000852ac6351ab6565639aa95467b065cec61b6e7dc4d6192b5536a7c569315fb43f470078b31ed22a55dab8265f02000000080065636a6aab6a53ffffffff9e3addbff52b2aaf9fe49c67017395198a9b71f0aa668c5cb354d06c295a691a0100000000ffffffff45c2b4019abaf05c5e484df982a4a07459204d1343a6ee5badade358141f8f990300000007ac516a6aacac6308655cd601f3bc2f0000000000015200000000", "", 0, -2082053939, "9a95e692e1f78efd3e46bb98f178a1e3a0ef60bd0301d9f064c0e5703dc879c2"); - run_test_sighash("5a60b9b503553f3c099f775db56af3456330f1e44e67355c4ab290d22764b9144a7b5f959003000000030052acbd63e0564decc8659aa53868be48c1bfcda0a8c9857b0db32a217bc8b46d9e7323fe9649020000000553ac6551abd0ecf806211db989bead96c09c7f3ec5f73c1411d3329d47d12f9e46678f09bac0dc383e0200000000ffffffff01494bb202000000000500516551ac00000000", "ac", 0, 1169947809, "62a36c6e8da037202fa8aeae03e533665376d5a4e0a854fc4624a75ec52e4eb1"); - run_test_sighash("e3649aa40405e6ffe377dbb1bbbb672a40d8424c430fa6512c6165273a2b9b6afa9949ec430200000007630052ab655153a365f62f2792fa90c784efe3f0981134d72aac0b1e1578097132c7f0406671457c332b84020000000353ab6ad780f40cf51be22bb4ff755434779c7f1def4999e4f289d2bd23d142f36b66fbe5cfbb4b01000000076a5252abac52ab1430ffdc67127c9c0fc97dcd4b578dab64f4fb9550d2b59d599773962077a563e8b6732c02000000016affffffff04cb2687000000000002ab636e320904000000000252acf70e9401000000000100dc3393050000000006ab0063536aacbc231765", "65520053", 3, -2016196547, "f64f805f0ff7f237359fa6b0e58085f3c766d1859003332223444fd29144112a"); - run_test_sighash("4c4be7540344050e3044f0f1d628039a334a7c1f7b4573469cfea46101d6888bb6161fe9710200000000ffffffffac85a4fdad641d8e28523f78cf5b0f4dc74e6c5d903c10b358dd13a5a1fd8a06000000000163e0ae75d05616b72467b691dc207fe2e65ea35e2eadb7e06ea442b2adb9715f212c0924f10200000000ffffffff0194ddfe02000000000265ac00000000", "00006500", 1, -479922562, "d66924d49f03a6960d3ca479f3415d638c45889ce9ab05e25b65ac260b51d634"); - run_test_sighash("202c18eb012bc0a987e69e205aea63f0f0c089f96dd8f0e9fcde199f2f37892b1d4e6da90302000000055352ac6565ffffffff0257e5450100000000025300ad257203000000000000000000", "520052ac6a005265", 0, 168054797, "502967a6f999f7ee25610a443caf8653dda288e6d644a77537bcc115a8a29894"); - run_test_sighash("32fa0b0804e6ea101e137665a041cc2350b794e59bf42d9b09088b01cde806ec1bbea077df0200000008515153650000006506a11c55904258fa418e57b88b12724b81153260d3f4c9f080439789a391ab147aabb0fa0000000007000052ac51ab510986f2a15c0d5e05d20dc876dd2dafa435276d53da7b47c393f20900e55f163b97ce0b800000000008ab526a520065636a8087df7d4d9c985fb42308fb09dce704650719140aa6050e8955fa5d2ea46b464a333f870000000009636300636a6565006affffffff01994a0d040000000002536500000000", "516563530065", 2, -163068286, "f58637277d2bc42e18358dc55f7e87e7043f5e33f4ce1fc974e715ef0d3d1c2a"); - run_test_sighash("ae23424d040cd884ebfb9a815d8f17176980ab8015285e03fdde899449f4ae71e04275e9a80100000007ab006553530053ffffffff018e06db6af519dadc5280c07791c0fd33251500955e43fe4ac747a4df5c54df020000000251ac330e977c0fec6149a1768e0d312fdb53ed9953a3737d7b5d06aad4d86e9970346a4feeb5030000000951ab51ac6563ab526a67cabc431ee3d8111224d5ecdbb7d717aa8fe82ce4a63842c9bd1aa848f111910e5ae1eb0100000004ac515300bfb7e0d7048acddc030000000009636a5253636a655363a3428e040000000001525b99c6050000000004655265ab717e6e020000000000d99011eb", "ac6a6a516565", 1, -716251549, "b098eb9aff1bbd375c70a0cbb9497882ab51f3abfebbf4e1f8d74c0739dc7717"); - run_test_sighash("030f44fc01b4a9267335a95677bd190c1c12655e64df74addc53b753641259af1a54146baa020000000152e004b56c04ba11780300000000026a53f125f001000000000251acd2cc7c03000000000763536563655363c9b9e50500000000015200000000", "ac", 0, -1351818298, "19dd32190ed2a37be22f0224a9b55b91e37290577c6c346d36d32774db0219a3"); - run_test_sighash("c05f448f02817740b30652c5681a3b128322f9dc97d166bd4402d39c37c0b14506d8adb5890300000003536353ffffffffa188b430357055ba291c648f951cd2f9b28a2e76353bef391b71a889ba68d5fc02000000056565526a6affffffff02745f73010000000001ab3ec34c0400000000036aac5200000000", "516551510053", 0, -267877178, "3a1c6742d4c374f061b1ebe330b1e169a113a19792a1fdde979b53e094cc4a3c"); - run_test_sighash("163ba45703dd8c2c5a1c1f8b806afdc710a2a8fc40c0138e2d83e329e0e02a9b6c837ff6b8000000000700655151ab6a522b48b8f134eb1a7e6f5a6fa319ce9d11b36327ba427b7d65ead3b4a6a69f85cda8bbcd22030000000563656552acffffffffdbcf4955232bd11eef0cc6954f3f6279675b2956b9bcc24f08c360894027a60201000000066500006500abffffffff04d0ce9d0200000000008380650000000000015233f360040000000003006aabedcf0801000000000000000000", "000065006500ac", 0, 216965323, "9afe3f4978df6a86e9a8ebd62ef6a9d48a2203f02629349f1864ef2b8b92fd55"); - run_test_sighash("fe647f950311bf8f3a4d90afd7517df306e04a344d2b2a2fea368935faf11fa6882505890d0000000005ab5100516affffffff43c140947d9778718919c49c0535667fc6cc727f5876851cb8f7b6460710c7f60100000000ffffffffce4aa5d90d7ab93cbec2e9626a435afcf2a68dd693c15b0e1ece81a9fcbe025e0300000000ffffffff02f34806020000000002515262e54403000000000965635151ac655363636de5ce24", "6a005100ac516351", 2, 989643518, "818a7ceaf963f52b5c48a7f01681ac6653c26b63a9f491856f090d9d60f2ffe3"); - run_test_sighash("cef7316804c3e77fe67fc6207a1ea6ae6eb06b3bf1b3a4010a45ae5c7ad677bb8a4ebd16d90200000009ac536a5152ac5263005301ab8a0da2b3e0654d31a30264f9356ba1851c820a403be2948d35cafc7f9fe67a06960300000006526a63636a53ffffffffbada0d85465199fa4232c6e4222df790470c5b7afd54704595a48eedd7a4916b030000000865ab63ac006a006ab28dba4ad55e58b5375053f78b8cdf4879f723ea4068aed3dd4138766cb4d80aab0aff3d0300000003ac6a00ffffffff010f5dd6010000000006ab006aab51ab00000000", "", 1, 889284257, "d0f32a6db43378af84b063a6706d614e2d647031cf066997c48c04de3b493a94"); - run_test_sighash("7b3ff28004ba3c7590ed6e36f45453ebb3f16636fe716acb2418bb2963df596a50ed954d2e03000000065251515265abffffffff706ee16e32e22179400c9841013971645dabf63a3a6d2d5feb42f83aa468983e030000000653ac51ac5152ffffffffa03a16e5e5de65dfa848b9a64ee8bf8656cc1f96b06a15d35bd5f3d32629876e020000000043c1a3965448b3b46f0f0689f1368f3b2981208a368ec5c30defb35595ef9cf95ffd10e902000000036aac65253a5bbe042e907204000000000800006565656352634203b4020000000002656336b3b7010000000001ab7a063f0100000000026500a233cb76", "006551636a53ac5251", 1, -1144216171, "68c7bd717b399b1ee33a6562a916825a2fed3019cdf4920418bb72ffd7403c8c"); - run_test_sighash("1be8ee5604a9937ebecffc832155d9ba7860d0ca451eaced58ca3688945a31d93420c27c460100000006abac5300535288b65458af2f17cbbf7c5fbcdcfb334ffd84c1510d5500dc7d25a43c36679b702e850f7c0200000003005300ffffffff7c237281cb859653eb5bb0a66dbb7aeb2ac11d99ba9ed0f12c766a8ae2a2157203000000086aabac526365acabfffffffff09d3d6639849f442a6a52ad10a5d0e4cb1f4a6b22a98a8f442f60280c9e5be80200000007ab00ab6565ab52ffffffff0398fe83030000000005526aababacbdd6ec010000000005535252ab6a82c1e6040000000001652b71c40c", "6563526353656351", 2, -853634888, "0d936cceda2f56c7bb87d90a7b508f6208577014ff280910a710580357df25f3"); - run_test_sighash("9e0f99c504fbca858c209c6d9371ddd78985be1ab52845db0720af9ae5e2664d352f5037d4010000000552ac53636affffffff0e0ce866bc3f5b0a49748f597c18fa47a2483b8a94cef1d7295d9a5d36d31ae7030000000663515263ac635bb5d1698325164cdd3f7f3f7831635a3588f26d47cc30bf0fefd56cd87dc4e84f162ab702000000036a6365ffffffff85c2b1a61de4bcbd1d5332d5f59f338dd5e8accbc466fd860f96eef1f54c28ec030000000165ffffffff04f5cabd010000000007000052ac526563c18f1502000000000465510051dc9157050000000008655363ac525253ac506bb600000000000865656a53ab63006a00000000", "006a6a0052", 0, 1186324483, "2f9b7348600336512686e7271c53015d1cb096ab1a5e0bce49acd35bceb42bc8"); - run_test_sighash("11ce51f90164b4b54b9278f0337d95c50d16f6828fcb641df9c7a041a2b274aa70b1250f2b0000000008ab6a6a65006551524c9fe7f604af44be050000000005525365006521f79a0300000000015306bb4e04000000000265ac99611a05000000000765acab656500006dc866d0", "", 0, -1710478768, "cfa4b7573559b3b199478880c8013fa713ca81ca8754a3fd68a6d7ee6147dc5a"); - run_test_sighash("86bc233e02ba3c647e356558e7252481a7769491fb46e883dd547a4ce9898fc9a1ca1b77790000000006ab5351abab51f0c1d09c37696d5c7c257788f5dff5583f4700687bcb7d4acfb48521dc953659e325fa390300000003acac5280f29523027225af03000000000963abac0065ab65acab7e59d90400000000016549dac846", "53006aac52acac", 0, 711159875, "880330ccde00991503ea598a6dfd81135c6cda9d317820352781417f89134d85"); - run_test_sighash("beac155d03a853bf18cd5c490bb2a245b3b2a501a3ce5967945b0bf388fec2ba9f04c03d68030000000012fe96283aec4d3aafed8f888b0f1534bd903f9cd1af86a7e64006a2fa0d2d30711af770010000000163ffffffffd963a19d19a292104b9021c535d3e302925543fb3b5ed39fb2124ee23a9db00302000000056500ac63acffffffff01ad67f503000000000300ac5189f78db2", "53536a636500", 2, 748992863, "bde3dd0575164d7ece3b5783ce0783ffddb7df98f178fe6468683230314f285a"); - run_test_sighash("489ebbf10478e260ba88c0168bd7509a651b36aaee983e400c7063da39c93bf28100011f280100000004abab63ab2fc856f05f59b257a4445253e0d91b6dffe32302d520ac8e7f6f2467f7f6b4b65f2f59e903000000096353abacab6351656affffffff0122d9480db6c45a2c6fd68b7bc57246edffbf6330c39ccd36aa3aa45ec108fc030000000265ab9a7e78a69aadd6b030b12602dff0739bbc346b466c7c0129b34f50ae1f61e634e11e9f3d0000000006516a53525100ffffffff011271070000000000086563ab6353536352c4dd0e2c", "", 0, -293358504, "4eba3055bc2b58765593ec6e11775cea4b6493d8f785e28d01e2d5470ea71575"); - run_test_sighash("6911195d04f449e8eade3bc49fd09b6fb4b7b7ec86529918b8593a9f6c34c2f2d301ec378b000000000263ab49162266af054643505b572c24ff6f8e4c920e601b23b3c42095881857d00caf56b28acd030000000565525200ac3ac4d24cb59ee8cfec0950312dcdcc14d1b360ab343e834004a5628d629642422f3c5acc02000000035100accf99b663e3c74787aba1272129a34130668a877cc6516bfb7574af9fa6d07f9b4197303400000000085351ab5152635252ffffffff042b3c95000000000000ff92330200000000046a5252ab884a2402000000000853530065520063000d78be03000000000953abab52ab53ac65aba72cb34b", "6a", 2, -637739405, "6b80d74eb0e7ee59d14f06f30ba7d72a48d3a8ff2d68d3b99e770dec23e9284f"); - run_test_sighash("746347cf03faa548f4c0b9d2bd96504d2e780292730f690bf0475b188493fb67ca58dcca4f0000000002005336e3521bfb94c254058e852a32fc4cf50d99f9cc7215f7c632b251922104f638aa0b9d080100000008656aac5351635251ffffffff4da22a678bb5bb3ad1a29f97f6f7e5b5de11bb80bcf2f7bb96b67b9f1ac44d09030000000365ababffffffff036f02b30000000000076353ab6aac63ac50b72a050000000002acaba8abf804000000000663006a6a6353797eb999", "acac5100", 1, -1484493812, "164c32a263f357e385bd744619b91c3f9e3ce6c256d6a827d6defcbdff38fa75"); - run_test_sighash("e17149010239dd33f847bf1f57896db60e955117d8cf013e7553fae6baa9acd3d0f1412ad90200000006516500516500cb7b32a8a67d58dddfb6ceb5897e75ef1c1ff812d8cd73875856487826dec4a4e2d2422a0100000004ac525365196dbb69039229270400000000070000535351636a8b7596020000000006ab51ac52655131e99d040000000003516551ee437f5c", "ac656a53", 1, 1102662601, "8858bb47a042243f369f27d9ab4a9cd6216adeac1c1ac413ed0890e46f23d3f3"); - run_test_sighash("144971940223597a2d1dec49c7d4ec557e4f4bd207428618bafa3c96c411752d494249e1fb0100000004526a5151ffffffff340a545b1080d4f7e2225ff1c9831f283a7d4ca4d3d0a29d12e07d86d6826f7f0200000003006553ffffffff03c36965000000000000dfa9af00000000000451636aac7f7d140300000000016300000000", "", 1, -108117779, "c84fcaf9d779df736a26cc3cabd04d0e61150d4d5472dd5358d6626e610be57f"); - run_test_sighash("2aee6b9a02172a8288e02fac654520c9dd9ab93cf514d73163701f4788b4caeeb9297d2e250300000004ab6363008fb36695528d7482710ea2926412f877a3b20acae31e9d3091406bfa6b62ebf9d9d2a6470100000009535165536a63520065ffffffff03f7b560050000000003acab6a9a8338050000000000206ce90000000000056552516a5100000000", "5252", 1, -1102319963, "fa4676c374ae3a417124b4c970d1ed3319dc3ac91fb36efca1aa9ed981a8aa1b"); - run_test_sighash("9554595203ad5d687f34474685425c1919e3d2cd05cf2dac89d5f33cd3963e5bb43f8706480100000000ffffffff9de2539c2fe3000d59afbd376cb46cefa8bd01dbc43938ff6089b63d68acdc2b02000000096553655251536a6500fffffffff9695e4016cd4dfeb5f7dadf00968e6a409ef048f81922cec231efed4ac78f5d010000000763abab6a5365006caaf0070162cc640200000000045163ab5100000000", "", 0, -1105256289, "e8e10ed162b1a43bfd23bd06b74a6c2f138b8dc1ab094ffb2fa11d5b22869bee"); - run_test_sighash("04f51f2a0484cba53d63de1cb0efdcb222999cdf2dd9d19b3542a896ca96e23a643dfc45f00200000007acac53510063002b091fd0bfc0cfb386edf7b9e694f1927d7a3cf4e1d2ce937c1e01610313729ef6419ae7030000000165a3372a913c59b8b3da458335dc1714805c0db98992fd0d93f16a7f28c55dc747fe66a5b503000000095351ab65ab52536351ffffffff5650b318b3e236802a4e41ed9bc0a19c32b7aa3f9b2cda1178f84499963a0cde000000000165ffffffff0383954f04000000000553ac536363a8fc90030000000000a2e315000000000005acab00ab5100000000", "0053", 2, -1424653648, "a5bc0356f56b2b41a2314ec05bee7b91ef57f1074bcd2efc4da442222269d1a3"); - run_test_sighash("53dc1a88046531c7b57a35f4d9adf101d068bf8d63fbbedaf4741dba8bc5e92c8725def571030000000453655251fcdf116a226b3ec240739c4c7493800e4edfe67275234e371a227721eac43d3d9ecaf1b50300000003ac0052ffffffff2c9279ffeea4718d167e9499bd067600715c14484e373ef93ae4a31d2f5671ab0000000009516553ac636a6a65001977752eeba95a8f16b88c571a459c2f2a204e23d48cc7090e4f4cc35846ca7fc0a455ce00000000055165ac0063188143f80205972902000000000765ac63ac516353c7b6a50000000000036a510000000000", "655351536a", 0, 103806788, "b276584d3514e5b4e058167c41dc02915b9d97f6795936a51f40e894ed8508bc"); - run_test_sighash("5a06cb4602dcfc85f49b8d14513f33c48f67146f2ee44959bbca092788e6823b2719f3160b0200000001ab3c013f2518035b9ea635f9a1c74ec1a3fb7496a160f46aae2e09bfc5cd5111a0f20969e003000000015158c89ab7049f20d6010000000008ac6a52abac53515349765e00000000000300ab638292630100000000045351ab0086da09010000000006656a6365525300000000", "526a63", 1, 1502936586, "bdfaff8a4e775379c5dc26e024968efa805f923de53fa8272dd53ec582afa0c5"); - run_test_sighash("ca9d84fa0129011e1bf27d7cb71819650b59fb292b053d625c6f02b0339249b498ff7fd4b601000000025352ffffffff032173a0040000000008525253abab5152639473bb030000000009005153526a53535151d085bd0000000000086a5365ab5165655300000000", "005152ac51", 0, 580353445, "c629d93b02037f40aa110e46d903edb34107f64806aa0c418d435926feef68b8"); - run_test_sighash("e3cdbfb4014d90ae6a4401e85f7ac717adc2c035858bf6ff48979dd399d155bce1f150daea0300000002ac51a67a0d39017f6c71040000000005535200535200000000", "", 0, -1899950911, "c1c7df8206e661d593f6455db1d61a364a249407f88e99ecad05346e495b38d7"); - run_test_sighash("b2b6b9ab0283d9d73eeae3d847f41439cd88279c166aa805e44f8243adeb3b09e584efb1df00000000026300ffffffff7dfe653bd67ca094f8dab51007c6adaced09de2af745e175b9714ca1f5c68d050000000003ac6500aa8e596903fd3f3204000000000553ac6a6a533a2e210500000000075253acabab526392d0ee020000000008520065635200ab5200000000", "65acacac65005365", 0, 28298553, "39c2aaa2496212b3ab120ab7d7f37c5e852bfe38d20f5226413a2268663eeae8"); - run_test_sighash("4314339e01de40faabcb1b970245a7f19eedbc17c507dac86cf986c2973715035cf95736ae0200000007abababababab65bde67b900151510b04000000000853ac00655200535300000000", "52", 0, 399070095, "47585dc25469d04ff3a60939d0a03779e3e81a411bf0ca18b91bb925ebd30718"); - run_test_sighash("f063171b03e1830fdc1d685a30a377537363ccafdc68b42bf2e3acb908dac61ee24b37595c020000000765ac5100ab6aacf447bc8e037b89d6cadd62d960cc442d5ced901d188867b5122b42a862929ce45e7b628d010000000253aba009a1ba42b00f1490b0b857052820976c675f335491cda838fb7934d5eea0257684a2a202000000001e83cf2401a7f777030000000008ab6553526a53526a00000000", "", 2, 1984790332, "c19caada8e71535e29a86fa29cfd9b74a0c7412003fc722a121005e461e01636"); - run_test_sighash("cf7bdc250249e22cbe23baf6b648328d31773ea0e771b3b76a48b4748d7fbd390e88a004d30000000003ac536a4ab8cce0e097136c90b2037f231b7fde2063017facd40ed4e5896da7ad00e9c71dd70ae600000000096a0063516352525365ffffffff01b71e3e00000000000300536a00000000", "", 1, 546970113, "6a815ba155270af102322c882f26d22da11c5330a751f520807936b320b9af5d"); - run_test_sighash("ac7a125a0269d35f5dbdab9948c48674616e7507413cd10e1acebeaf85b369cd8c88301b7c030000000963656aac6a530053abffffffffed94c39a582e1a46ce4c6bffda2ccdb16cda485f3a0d94b06206066da12aecfe010000000752abab63536363ef71dcfb02ee07fa0400000000016a6908c802000000000751656a6551abac688c2c2d", "6a6351526551", 0, 858400684, "552ff97d7924f51cda6d1b94be53483153ef725cc0a3a107adbef220c753f9a6"); - run_test_sighash("3a1f454a03a4591e46cf1f7605a3a130b631bf4dfd81bd2443dc4fac1e0a224e74112884fe0000000005516aac6a53a87e78b55548601ffc941f91d75eab263aa79cd498c88c37fdf275a64feff89fc1710efe03000000016a39d7ef6f2a52c00378b4f8f8301853b61c54792c0f1c4e2cd18a08cb97a7668caa008d970200000002656affffffff017642b20100000000096a63535253abac6a6528271998", "51", 2, 1459585400, "e9a7f21fc2d38be7be47095fbc8f1bf8923660aa4d71df6d797ae0ba5ca4d5b0"); - run_test_sighash("6269e0fa0173e76e89657ca495913f1b86af5b8f1c1586bcd6c960aede9bc759718dfd5044000000000352ac530e2c7bd90219849b000000000007ab00ab6a53006319f281000000000007ab00515165ac5200000000", "6a", 0, -2039568300, "62094f98234a05bf1b9c7078c5275ed085656856fb5bdfd1b48090e86b53dd85"); - run_test_sighash("eb2bc00604815b9ced1c604960d54beea4a3a74b5c0035d4a8b6bfec5d0c9108f143c0e99a0000000000ffffffff22645b6e8da5f11d90e5130fd0a0df8cf79829b2647957471d881c2372c527d8010000000263acffffffff1179dbaf17404109f706ae27ad7ba61e860346f63f0c81cb235d2b05d14f2c1003000000025300264cb23aaffdc4d6fa8ec0bb94eff3a2e50a83418a8e9473a16aaa4ef8b855625ed77ef40100000003ac51acf8414ad404dd328901000000000652526500006ab6261c000000000002526a72a4c9020000000006ac526500656586d2e7000000000006656aac00ac5279cd8908", "51", 1, -399279379, "d37532e7b2b8e7db5c7c534197600397ebcc15a750e3af07a3e2d2e4f84b024f"); - run_test_sighash("eba8b0de04ac276293c272d0d3636e81400b1aaa60db5f11561480592f99e6f6fa13ad387002000000070053acab536563bebb23d66fd17d98271b182019864a90e60a54f5a615e40b643a54f8408fa8512cfac927030000000963ac6a6aabac65ababffffffff890a72192bc01255058314f376bab1dc72b5fea104c154a15d6faee75dfa5dba020000000100592b3559b0085387ac7575c05b29b1f35d9a2c26a0c27903cc0f43e7e6e37d5a60d8305a030000000252abffffffff0126518f05000000000000000000", "005300635252635351", 1, 664344756, "26dc2cba4bd5334e5c0b3a520b44cc1640c6b923d10e576062f1197171724097"); - run_test_sighash("185cda1a01ecf7a8a8c28466725b60431545fc7a3367ab68e34d486e8ea85ee3128e0d8384000000000465ac63abec88b7bb031c56eb04000000000965636a51005252006a7c78d5040000000007acac63abac51ac3024a40500000000086300526a51abac51464c0e8c", "0065535265515352", 0, 1594558917, "b5280b9610c0625a65b36a8c2402a95019a7bbb9dd3de77f7c3cb1d82c3263ba"); - run_test_sighash("92c9fb780138abc472e589d5b59489303f234acc838ca66ffcdf0164517a8679bb622a4267020000000153468e373d04de03fa020000000009ac006a5265ab5163006af649050000000007515153006a00658ceb59030000000001ac36afa0020000000009ab53006351ab51000000000000", "6a", 0, 2059357502, "e2358dfb51831ee81d7b0bc602a65287d6cd2dbfacf55106e2bf597e22a4b573"); - run_test_sighash("6f62138301436f33a00b84a26a0457ccbfc0f82403288b9cbae39986b34357cb2ff9b889b302000000045253655335a7ff6701bac9960400000000086552ab656352635200000000", "6aac51", 0, 1444414211, "502a2435fd02898d2ff3ab08a3c19078414b32ec9b73d64a944834efc9dae10c"); - run_test_sighash("9981143a040a88c2484ac3abe053849e72d04862120f424f373753161997dd40505dcb4783030000000700536365536565a2e10da3f4b1c1ad049d97b33f0ae0ea48c5d7c30cc8810e144ad93be97789706a5ead180100000003636a00ffffffffbdcbac84c4bcc87f03d0ad83fbe13b369d7e42ddb3aecf40870a37e814ad8bb5010000000963536a5100636a53abffffffff883609905a80e34202101544f69b58a0b4576fb7391e12a769f890eef90ffb72020000000651656352526affffffff04243660000000000004ab5352534a9ce001000000000863656363ab6a53652df19d030000000003ac65acedc51700000000000000000000", "ac6300acac", 2, 293672388, "7ba99b289c04718a7283f150d831175ed6303081e191a0608ea81f78926c5bdf"); - run_test_sighash("49f7d0b6037bba276e910ad3cd74966c7b3bc197ffbcfefd6108d6587006947e97789835ea0300000008526a52006a650053ffffffff8d7b6c07cd10f4c4010eac7946f61aff7fb5f3920bdf3467e939e58a1d4100ab03000000076aac63ac535351ffffffff8f48c3ba2d52ad67fbcdc90d8778f3c8a3894e3c35b9730562d7176b81af23c80100000003ab5265ffffffff0301e3ef0300000000046a525353e899ac0500000000075153ab6a65abac259bea0400000000007b739972", "53516aacac6aac", 1, 955403557, "5d366a7f4346ae18aeb7c9fc4dab5af71173184aa20ed22fcb4ea8511ad25449"); - run_test_sighash("58a4fed801fbd8d92db9dfcb2e26b6ff10b120204243fee954d7dcb3b4b9b53380e7bb8fb60100000003006351ffffffff02a0795b050000000006536351ac6aac2718d00200000000075151acabac515354d21ba1", "005363515351", 0, -1322430665, "bbee941bbad950424bf40e3623457db47f60ed29deaa43c99dec702317cb3326"); - run_test_sighash("17fad0d303da0d764fedf9f2887a91ea625331b28704940f41e39adf3903d8e75683ef6d46020000000151ffffffffff376eea4e880bcf0f03d33999104aafed2b3daf4907950bb06496af6b51720a020000000900636a63525253525196521684f3b08497bad2c660b00b43a6a517edc58217876eb5e478aa3b5fda0f29ee1bea00000000046aacab6affffffff03dde8e2050000000007ac5365ac51516a14772e000000000005630000abacbbb360010000000006ab5251ab656a50f180f0", "0053", 0, -1043701251, "a3bdf8771c8990971bff9b4e7d59b7829b067ed0b8d3ac1ec203429811384668"); - run_test_sighash("5a2257df03554550b774e677f348939b37f8e765a212e566ce6b60b4ea8fed4c9504b7f7d1000000000653655265ab5258b67bb931df15b041177cf9599b0604160b79e30f3d7a594e7826bae2c29700f6d8f8f40300000005515300ac6a159cf8808a41f504eb5c2e0e8a9279f3801a5b5d7bc6a70515fbf1c5edc875bb4c9ffac500000000050063510052ffffffff0422a90105000000000965006a650000516a006417d2020000000006526363ab00524d969d0100000000035153acc4f077040000000005ac5200636500000000", "6a52", 1, -1482463464, "37b794b05d0687c9b93d5917ab068f6b2f0e38406ff04e7154d104fc1fb14cdc"); - run_test_sighash("e0032ad601269154b3fa72d3888a3151da0aed32fb2e1a15b3ae7bee57c3ddcffff76a1321010000000100110d93ae03f5bd080100000000075263516a6551002871e60100000000046a005252eaa753040000000004ab6aab526e325c71", "630052", 0, -1857873018, "ea117348e94de86381bb8ad1c7f93b8c623f0272104341701bb54e6cb433596c"); - run_test_sighash("014b2a5304d46764817aca180dca50f5ab25f2e0d5749f21bb74a2f8bf6b8b7b3fa8189cb7030000000965ac5165ab6a51ac6360ecd91e8abc7e700a4c36c1a708a494c94bb20cbe695c408543146566ab22be43beae9103000000045163ab00ffffffffffa48066012829629a9ec06ccd4905a05df0e2b745b966f6a269c9c8e13451fc00000000026565ffffffffc40ccadc21e65fe8a4b1e072f4994738ccaf4881ae6fede2a2844d7da4d199ab02000000065152ab536aabffffffff01b6e054030000000004515352ab3e063432", "", 0, 1056459916, "a7aff48f3b8aeb7a4bfe2e6017c80a84168487a69b69e46681e0d0d8e63a84b6"); - run_test_sighash("1201ab5d04f89f07c0077abd009762e59db4bb0d86048383ba9e1dad2c9c2ad96ef660e6d00200000007ab6a65ac5200652466fa5143ab13d55886b6cdc3d0f226f47ec1c3020c1c6e32602cd3428aceab544ef43e00000000086a6a6a526a6a5263ffffffffd5be0b0be13ab75001243749c839d779716f46687e2e9978bd6c9e2fe457ee48020000000365abab1e1bac0f72005cf638f71a3df2e3bbc0fa35bf00f32d9c7dc9c39a5e8909f7d53170c8ae0200000008ab6a51516363516affffffff02f0a6210500000000036300ac867356010000000009acab65ac6353536a659356d367", "ac53535252", 0, 917543338, "418acc156c2bc76a5d7baa58db29f1b4cf6c266c9222ed167ef5b4d47f0e0f41"); - run_test_sighash("344fa11e01c19c4dd232c77742f0dd0aeb3695f18f76da627628741d0ee362b0ea1fb3a2180200000007635151005100529bab25af01937c1f0500000000055153ab53656e7630af", "6351005163ac51", 0, -629732125, "228ca52a0a376fe0527a61cfa8da6d7baf87486bba92d49dfd3899cac8a1034f"); - run_test_sighash("b2fda1950191358a2b855f5626a0ebc830ab625bea7480f09f9cd3b388102e35c0f303124c030000000565ac65ab53ffffffff03f9c5ec04000000000765ab51516551650e2b9f0500000000045365525284e8f6040000000001ac00000000", "ac51655253", 0, 1433027632, "d2fa7e13c34cecda5105156bd2424c9b84ee0a07162642b0706f83243ff811a8"); - run_test_sighash("a4a6bbd201aa5d882957ac94f2c74d4747ae32d69fdc765add4acc2b68abd1bdb8ee333d6e0300000008516a6552515152abffffffff02c353cb040000000007ac6351ab51536588bd320500000000066552525253ac00000000", "", 0, 1702060459, "499da7d74032388f820645191ac3c8d20f9dba8e8ded7fa3a5401ea2942392a1"); - run_test_sighash("83a583d204d926f2ee587a83dd526cf1e25a44bb668e45370798f91a2907d184f7cddcbbc7030000000700ab6565536a539f71d3776300dffdfa0cdd1c3784c9a1f773e34041ca400193612341a9c42df64e3f550e01000000050052515251ffffffff52dab2034ab0648553a1bb8fc4e924b2c89ed97c18dfc8a63e248b454035564b01000000015139ab54708c7d4d2c2886290f08a5221cf69592a810fd1979d7b63d35c271961e710424fd0300000005ac65ac5251ffffffff01168f7c030000000000a85e5fb0", "6a536353656a00", 0, 179595345, "5350a31ac954a0b49931239d0ecafbf34d035a537fd0c545816b8fdc355e9961"); - run_test_sighash("ffd35d51042f290108fcb6ea49a560ba0a6560f9181da7453a55dfdbdfe672dc800b39e7320200000006630065516a65f2166db2e3827f44457e86dddfd27a8af3a19074e216348daa0204717d61825f198ec0030100000006ab51abab00abffffffffdf41807adb7dff7db9f14d95fd6dc4e65f8402c002d009a3f1ddedf6f4895fc8030000000500ab006a65a5a848345052f860620abd5fcd074195548ce3bd0839fa9ad8642ed80627bf43a0d47dbd010000000765ab006a656a53b38cdd6502a186da05000000000765ab00ab006a53527c0e0100000000085365ab51acacac52534bd1b1", "6a635253ac0000", 0, 1095082149, "3c05473a816621a3613f0e903faa1a1e44891dd40862b029e41fc520776350fa"); - run_test_sighash("6c9a4b98013c8f1cae1b1df9f0f2de518d0c50206a0ab871603ac682155504c0e0ce946f460100000000ffffffff04e9266305000000000753535100ac6aacded39e04000000000365ac6ab93ccd010000000002515397bf3d050000000003ab636300000000", "63520052ac656353", 0, -352633155, "936eff8cdfd771be24124da87c7b24feb48da7cbc2c25fb5ba13d1a23255d902"); - run_test_sighash("c4b80f850323022205b3e1582f1ed097911a81be593471a8dce93d5c3a7bded92ef6c7c1260100000002006affffffff70294d62f37c3da7c5eae5d67dce6e1b28fedd7316d03f4f48e1829f78a88ae801000000096a5200530000516351f6b7b544f7c39189d3a2106ca58ce4130605328ce7795204be592a90acd81bef517d6f170200000000ffffffff012ab8080000000000075100006365006335454c1e", "53ac6a536aacac", 0, -1124103895, "06277201504e6bf8b8c94136fad81b6e3dadacb9d4a2c21a8e10017bfa929e0e"); - run_test_sighash("8ab69ed50351b47b6e04ac05e12320984a63801716739ed7a940b3429c9c9fed44d3398ad40300000006536a516a52638171ef3a46a2adb8025a4884b453889bc457d63499971307a7e834b0e76eec69c943038a0300000000ffffffff566bb96f94904ed8d43d9d44a4a6301073cef2c011bf5a12a89bedbaa03e4724030000000265acb606affd01edea38050000000008515252516aacac6300000000", "65000000006365ac53", 0, -1338942849, "7912573937824058103cb921a59a7f910a854bf2682f4116a393a2045045a8c3"); - run_test_sighash("2484991e047f1cf3cfe38eab071f915fe86ebd45d111463b315217bf9481daf0e0d10902a402000000006e71a424eb1347ffa638363604c0d5eccbc90447ff371e000bf52fc743ec832851bb564a0100000001abffffffffef7d014fad3ae7927948edbbb3afe247c1bcbe7c4c8f5d6cf97c799696412612020000000851536a5353006a001dfee0d7a0dd46ada63b925709e141863f7338f34f7aebde85d39268ae21b77c3068c01d0000000008535151ab00636563ffffffff018478070200000000095200635365ac52ab5341b08cd3", "", 3, 265623923, "24cb420a53b4f8bb477f7cbb293caabfd2fc47cc400ce37dbbab07f92d3a9575"); - run_test_sighash("54839ef9026f65db30fc9cfcb71f5f84d7bb3c48731ab9d63351a1b3c7bc1e7da22bbd508e0300000000442ad138f170e446d427d1f64040016032f36d8325c3b2f7a4078766bdd8fb106e52e8d20000000003656500ffffffff02219aa101000000000851ababac52ab00659646bd02000000000552acacabac24c394a5", "ac", 0, 906807497, "69264faadcd1a581f7000570a239a0a26b82f2ad40374c5b9c1f58730514de96"); - run_test_sighash("5036d7080434eb4eef93efda86b9131b0b4c6a0c421e1e5feb099a28ff9dd8477728639f77030000000951516aab535152ab5391429be9cce85d9f3d358c5605cf8c3666f034af42740e94d495e28b9aaa1001ba0c87580300000008006552ab00ab006affffffffd838978e10c0c78f1cd0a0830d6815f38cdcc631408649c32a25170099669daa0000000002acab8984227e804ad268b5b367285edcdf102d382d027789250a2c0641892b480c21bf84e3fb0100000000b518041e023d8653010000000001004040fb0100000000080051ac5200636a6300000000", "52ac", 0, 366357656, "bd0e88829afa6bdc1e192bb8b2d9d14db69298a4d81d464cbd34df0302c634c6"); - run_test_sighash("9ad5ccf503fa4facf6a27b538bc910cce83c118d6dfd82f3fb1b8ae364a1aff4dcefabd38f03000000096365655263ac655300807c48130c5937190a996105a69a8eba585e0bd32fadfc57d24029cbed6446d30ebc1f100100000004000053650f0ccfca1356768df7f9210cbf078a53c72e0712736d9a7a238e0115faac0ca383f219d0010000000600ab536552002799982b0221b8280000000000000c41320000000000086552ac6365636a6595f233a3", "6a5152", 2, 553208588, "f99c29a79f1d73d2a69c59abbb5798e987639e36d4c44125d8dc78a94ddcfb13"); - run_test_sighash("669538a204047214ce058aed6a07ca5ad4866c821c41ac1642c7d63ed0054f84677077a84f030000000853abacab6a655353ffffffff70c2a071c115282924e3cb678b13800c1d29b6a028b3c989a598c491bc7c76c5030000000752ac52ac5163ac80420e8a6e43d39af0163271580df6b936237f15de998e9589ec39fe717553d415ac02a4030000000463635153184ad8a5a4e69a8969f71288c331aff3c2b7d1b677d2ebafad47234840454b624bf7ac1d03000000056a63abab63df38c24a02fbc63a040000000002ab535ec3dc050000000002536500000000", "635153", 3, -190399351, "9615541884dfb1feeb08073a6a6aa73ef694bc5076e52187fdf4138a369f94d9"); - run_test_sighash("972128b904e7b673517e96e98d80c0c8ceceae76e2f5c126d63da77ffd7893fb53308bb2da0300000006ac6552ab52acffffffff4cac767c797d297c079a93d06dc8569f016b4bf7a7d79b605c526e1d36a40e2202000000095365ab636aac6a6a6a69928d2eddc836133a690cfb72ec2d3115bf50fb3b0d10708fa5d2ebb09b4810c426a1db01000000060052526300001e8e89585da7e77b2dd2e30625887f0660accdf29e53a614d23cf698e6fc8ab03310e87700000000076a520051acac6555231ddb0330ec2d03000000000200abfaf457040000000004ab6a6352bdc42400000000000153d6dd2f04", "", 0, 209234698, "4a92fec1eb03f5bd754ee9bfd70707dc4420cc13737374f4675f48529be518e4"); - run_test_sighash("5374f0c603d727f63006078bd6c3dce48bd5d0a4b6ea00a47e5832292d86af258ea0825c260000000009655353636352526a6af2221067297d42a9f8933dfe07f61a574048ff9d3a44a3535cd8eb7de79fb7c45b6f47320200000003ac006affffffff153d917c447d367e75693c5591e0abf4c94bbdd88a98ab8ad7f75bfe69a08c470200000005ac65516365ffffffff037b5b7b000000000001515dc4d904000000000004bb26010000000004536a6aac00000000", "516552516352ac", 2, 328538756, "8bb7a0129eaf4b8fc23e911c531b9b7637a21ab11a246352c6c053ff6e93fcb6"); - run_test_sighash("c441132102cc82101b6f31c1025066ab089f28108c95f18fa67db179610247086350c163bd010000000651525263ab00ffffffff9b8d56b1f16746f075249b215bdb3516cbbe190fef6292c75b1ad8a8988897c3000000000751ab6553abab00ffffffff02f9078b000000000009ab0053ac51ac00ab51c0422105000000000651006563525200000000", "ac51", 0, -197051790, "55acd8293ed0be6792150a3d7ced6c5ccd153ca7daf09cee035c1b0dac92bb96"); - run_test_sighash("8bff9d170419fa6d556c65fa227a185fe066efc1decf8a1c490bc5cbb9f742d68da2ab7f320100000007ab000053525365a7a43a80ab9593b9e8b6130a7849603b14b5c9397a190008d89d362250c3a2257504eb810200000007acabacac00ab51ee141be418f003e75b127fd3883dbf4e8c3f6cd05ca4afcaac52edd25dd3027ae70a62a00000000008ac52526a5200536affffffffb8058f4e1d7f220a1d1fa17e96d81dfb9a304a2de4e004250c9a576963a586ae0300000005abacac5363b9bc856c039c01d804000000000951656aac53005365acb0724e00000000000565abab63acea7c7a0000000000036a00ac00000000", "6565", 1, -1349282084, "2b822737c2affeefae13451d7c9db22ff98e06490005aba57013f6b9bbc97250"); - run_test_sighash("0e1633b4041c50f656e882a53fde964e7f0c853b0ada0964fc89ae124a2b7ffc5bc97ea6230100000006ac6aacacabacffffffff2e35f4dfcad2d53ea1c8ada8041d13ea6c65880860d96a14835b025f76b1fbd9000000000351515121270867ef6bf63a91adbaf790a43465c61a096acc5a776b8e5215d4e5cd1492e611f761000000000600ac6aab5265ffffffff63b5fc39bcac83ca80ac36124abafc5caee608f9f63a12479b68473bd4bae769000000000965ac52acac5263acabffffffff0163153e020000000008ab005165ab65515300000000", "6a6aac00", 0, -968477862, "20732d5073805419f275c53784e78db45e53332ee618a9fcf60a3417a6e2ca69"); - run_test_sighash("2b052c24022369e956a8d318e38780ef73b487ba6a8f674a56bdb80a9a63634c6110fb5154010000000251acffffffff48fe138fb7fdaa014d67044bc05940f4127e70c113c6744fbd13f8d51d45143e01000000005710db3804e01aa9030000000008acac6a516a5152abfd55aa01000000000751ab510000ac636d6026010000000000b97da9000000000000fddf3b53", "006552", 0, 595461670, "685d67d84755906d67a007a7d4fa311519467b9bdc6a351913246a41e082a29f"); - run_test_sighash("7888b71403f6d522e414d4ca2e12786247acf3e78f1918f6d727d081a79813d129ee8befce0100000009ab516a6353ab6365abffffffff4a882791bf6400fda7a8209fb2c83c6eef51831bdf0f5dacde648859090797ec030000000153ffffffffbb08957d59fa15303b681bad19ccf670d7d913697a2f4f51584bf85fcf91f1f30200000008526565ac52ac63acffffffff0227c0e8050000000001ac361dc801000000000800515165ab00ab0000000000", "656a", 2, 1869281295, "f43378a0b7822ad672773944884e866d7a46579ee34f9afc17b20afc1f6cf197"); - run_test_sighash("cc4dda57047bd0ca6806243a6a4b108f7ced43d8042a1acaa28083c9160911cf47eab910c40200000007526a0000ab6a63e4154e581fcf52567836c9a455e8b41b162a78c85906ccc1c2b2b300b4c69caaaa2ba0230300000008ab5152ac5100ab65ffffffff69696b523ed4bd41ecd4d65b4af73c9cf77edf0e066138712a8e60a04614ea1c0300000004ab6a000016c9045c7df7836e05ac4b2e397e2dd72a5708f4a8bf6d2bc36adc5af3cacefcf074b8b403000000065352ac5252acffffffff01d7e380050000000000cf4e699a", "525163656351", 1, -776533694, "ff18c5bffd086e00917c2234f880034d24e7ea2d1e1933a28973d134ca9e35d2"); - run_test_sighash("b7877f82019c832707a60cf14fba44cfa254d787501fdd676bd58c744f6e951dbba0b3b77f0200000009ac515263ac53525300a5a36e500148f89c0500000000085265ac6a6a65acab00000000", "6563", 0, -1785108415, "cb6e4322955af12eb29613c70e1a00ddbb559c887ba844df0bcdebed736dffbd"); - run_test_sighash("aeb14046045a28cc59f244c2347134d3434faaf980961019a084f7547218785a2bd03916f3000000000165f852e6104304955bda5fa0b75826ee176211acc4a78209816bbb4419feff984377b2352200000000003a94a5032df1e0d60390715b4b188c330e4bb7b995f07cdef11ced9d17ee0f60bb7ffc8e0100000002516513e343a5c1dc1c80cd4561e9dddad22391a2dbf9c8d2b6048e519343ca1925a9c6f0800a020000000665516365ac513180144a0290db27000000000006ab655151ab5138b187010000000007ab5363abac516a9e5cd98a", "53ac", 0, 478591320, "e8d89a302ae626898d4775d103867a8d9e81f4fd387af07212adab99946311ef"); - run_test_sighash("57a5a04c0278c8c8e243d2df4bb716f81d41ac41e2df153e7096f5682380c4f441888d9d260300000004ab63ab6afdbe4203525dff42a7b1e628fe22bccaa5edbb34d8ab02faff198e085580ea5fcdb0c61b0000000002ac6affffffff03375e6c05000000000663ab516a6a513cb6260400000000007ca328020000000006516a636a52ab94701cc7", "0053ac5152", 0, -550925626, "b7ca991ab2e20d0158168df2d3dd842a57ab4a3b67cca8f45b07c4b7d1d11126"); - run_test_sighash("7e27c42d0279c1a05eeb9b9faedcc9be0cab6303bde351a19e5cbb26dd0d594b9d74f40d2b020000000200518c8689a08a01e862d5c4dcb294a2331912ff11c13785be7dce3092f154a005624970f84e0200000000500cf5a601e74c1f0000000000076aab52636a6a5200000000", "6500006a5351", 0, 449533391, "535ba819d74770d4d613ee19369001576f98837e18e1777b8246238ff2381dd0"); - run_test_sighash("2b3470dd028083910117f86614cdcfb459ee56d876572510be4df24c72e8f58c70d5f5948b03000000066aab65635265da2c3aac9d42c9baafd4b655c2f3efc181784d8cba5418e053482132ee798408ba43ccf90300000000ffffffff047dda4703000000000765516a52ac53009384a603000000000651636a63ab6a8cf57a03000000000352ab6a8cf6a405000000000952636a6a6565525100661e09cb", "ac520063ac6a6a52", 1, 1405647183, "9b360c3310d55c845ef537125662b9fe56840c72136891274e9fedfef56f9bb5"); - run_test_sighash("3a5644a9010f199f253f858d65782d3caec0ac64c3262b56893022b9796086275c9d4d097b02000000009d168f7603a67b30050000000007ac51536a0053acd9d88a050000000007655363535263ab3cf1f403000000000352ac6a00000000", "005363536565acac6a", 0, -1383947195, "6390ab0963cf611e0cea35a71dc958b494b084e6fd71d22217fdc5524787ade6"); - run_test_sighash("bda1ff6804a3c228b7a12799a4c20917301dd501c67847d35da497533a606701ad31bf9d5e0300000001ac16a6c5d03cf516cd7364e4cbbf5aeccd62f8fd03cb6675883a0636a7daeb650423cb1291010000000500656553ac4a63c30b6a835606909c9efbae1b2597e9db020c5ecfc0642da6dc583fba4e84167539a8020000000865525353515200acffffffff990807720a5803c305b7da08a9f24b92abe343c42ac9e917a84e1f335aad785d00000000026a52ffffffff04981f20030000000001ab8c762200000000000253ab690b9605000000000151ce88b301000000000753526a6a51006500000000", "000052ac52530000", 1, -1809193140, "5299b0fb7fc16f40a5d6b337e71fcd1eb04d2600aefd22c06fe9c71fe0b0ba54"); - run_test_sighash("db4904e6026b6dd8d898f278c6428a176410d1ffbde75a4fa37cda12263108ccd4ca6137440100000007656a0000515263ffffffff1db7d5005c1c40da0ed17b74cf6b2a6ee2c33c9e0bacda76c0da2017dcac2fc70200000004abab6a53ffffffff0454cf2103000000000153463aef000000000009ab6a630065ab52636387e0ed050000000000e8d16f05000000000352ac63e4521b22", "", 1, 1027042424, "48315a95e49277ab6a2d561ee4626820b7bab919eea372b6bf4e9931ab221d04"); - run_test_sighash("dca31ad10461ead74751e83d9a81dcee08db778d3d79ad9a6d079cfdb93919ac1b0b61871102000000086500525365ab51ac7f7e9aed78e1ef8d213d40a1c50145403d196019985c837ffe83836222fe3e5955e177e70100000006525152525300ffffffff5e98482883cc08a6fe946f674cca479822f0576a43bf4113de9cbf414ca628060100000006ac53516a5253ffffffff07490b0b898198ec16c23b75d606e14fa16aa3107ef9818594f72d5776805ec502000000036a0052ffffffff01932a2803000000000865ab6551ac6a516a2687aa06", "635300ac", 2, -1880362326, "74d6a2fa7866fd8b74b2e34693e2d6fd690410384b7afdcd6461b1ae71d265ce"); - run_test_sighash("e14e1a9f0442ab44dfc5f6d945ad1ff8a376bc966aad5515421e96ddbe49e529614995cafc03000000055165515165fffffffff97582b8290e5a5cfeb2b0f018882dbe1b43f60b7f45e4dd21dbd3a8b0cfca3b0200000000daa267726fe075db282d694b9fee7d6216d17a8c1f00b2229085495c5dc5b260c8f8cd5d000000000363ac6affffffffaab083d22d0465471c896a438c6ac3abf4d383ae79420617a8e0ba8b9baa872b010000000963526563ac5363ababd948b5ce022113440200000000076a636552006a53229017040000000000e6f62ac8", "526353636a65", 3, -485265025, "1bc8ad76f9b7c366c5d052dc479d6a8a2015566d3a42e93ab12f727692c89d65"); - run_test_sighash("69df842a04c1410bfca10896467ce664cfa31c681a5dac10106b34d4b9d4d6d0dc1eac01c1000000000551536a5165269835ca4ad7268667b16d0a2df154ec81e304290d5ed69e0069b43f8c89e673328005e200000000076a5153006aacabffffffffc9314bd80b176488f3d634360fcba90c3a659e74a52e100ac91d3897072e3509010000000765abac51636363ffffffff0e0768b13f10f0fbd2fa3f68e4b4841809b3b5ba0e53987c3aaffcf09eee12bf0300000008ac535263526a53ac514f4c2402da8fab0400000000001ef15201000000000451526a52d0ec9aca", "525365ac52", 1, 313967049, "a72a760b361af41832d2c667c7488dc9702091918d11e344afc234a4aea3ec44"); - run_test_sighash("e4fec9f10378a95199c1dd23c6228732c9de0d7997bf1c83918a5cfd36012476c0c3cba24002000000085165536500ac0000ad08ab93fb49d77d12a7ccdbb596bc5110876451b53a79fdce43104ff1c316ad63501de801000000046a6352ab76af9908463444aeecd32516a04dd5803e02680ed7f16307242a794024d93287595250f4000000000089807279041a82e603000000000200521429100200000000055253636a63f20b940400000000004049ed04000000000500ab5265ab43dfaf7d", "6563526aac", 2, -1923470368, "32f3c012eca9a823bebb9b282240aec40ca65df9f38da43b1dcfa0cac0c0df7e"); - run_test_sighash("4000d3600100b7a3ff5b41ec8d6ccdc8b2775ad034765bad505192f05d1f55d2bc39d0cbe10100000007ab5165ac6a5163ffffffff034949150100000000026a6a92c9f6000000000008ab6553ab6aab635200e697040000000007636a5353525365237ae7d2", "52000063", 0, -880046683, "c76146f68f43037289aaeb2bacf47408cddc0fb326b350eb4f5ef6f0f8564793"); - run_test_sighash("eabc0aa701fe489c0e4e6222d72b52f083166b49d63ad1410fb98caed027b6a71c02ab830c03000000075253ab63530065ffffffff01a5dc0b05000000000253533e820177", "", 0, 954499283, "1d849b92eedb9bf26bd4ced52ce9cb0595164295b0526842ab1096001fcd31b1"); - run_test_sighash("d48d55d304aad0139783b44789a771539d052db565379f668def5084daba0dfd348f7dcf6b00000000006826f59e5ffba0dd0ccbac89c1e2d69a346531d7f995dea2ca6d7e6d9225d81aec257c6003000000096a655200ac656552acffffffffa188ffbd5365cae844c8e0dea6213c4d1b2407274ae287b769ab0bf293e049eb0300000005ac6a6aab51ad1c407c5b116ca8f65ed496b476183f85f072c5f8a0193a4273e2015b1cc288bf03e9e2030000000252abffffffff04076f44040000000006655353abab53be6500050000000003ac65ac3c15040500000000095100ab536353516a52ed3aba04000000000900ac53ab53636aabac00000000", "5253526563acac", 2, -1506108646, "bbee17c8582514744bab5df50012c94b0db4aff5984d2e13a8d09421674404e2"); - run_test_sighash("9746f45b039bfe723258fdb6be77eb85917af808211eb9d43b15475ee0b01253d33fc3bfc502000000065163006a655312b12562dc9c54e11299210266428632a7d0ee31d04dfc7375dcad2da6e9c11947ced0e000000000009074095a5ac4df057554566dd04740c61490e1d3826000ad9d8f777a93373c8dddc4918a00000000025351ffffffff01287564030000000004636a00ab00000000", "52", 2, -1380411075, "84af1623366c4db68d81f452b86346832344734492b9c23fbb89015e516c60b2"); - run_test_sighash("df0a32ae01c4672fd1abd0b2623aae0a1a8256028df57e532f9a472d1a9ceb194267b6ee190200000009536a6a51516a525251b545f9e803469a2302000000000465526500810631040000000000441f5b050000000006530051006aaceb183c76", "536a635252ac6a", 0, 1601138113, "9a0435996cc58bdba09643927fe48c1fc908d491a050abbef8daec87f323c58f"); - run_test_sighash("b1c0b71804dff30812b92eefb533ac77c4b9fdb9ab2f77120a76128d7da43ad70c20bbfb990200000002536392693e6001bc59411aebf15a3dc62a6566ec71a302141b0c730a3ecc8de5d76538b30f55010000000665535252ac514b740c6271fb9fe69fdf82bf98b459a7faa8a3b62f3af34943ad55df4881e0d93d3ce0ac0200000000c4158866eb9fb73da252102d1e64a3ce611b52e873533be43e6883137d0aaa0f63966f060000000001abffffffff04a605b604000000000851006a656a630052f49a0300000000000252515a94e1050000000009abac65ab0052abab00fd8dd002000000000651535163526a2566852d", "ac5363", 0, -1718831517, "b0dc030661783dd9939e4bf1a6dfcba809da2017e1b315a6312e5942d714cf05"); - run_test_sighash("3657e4260304ccdc19936e47bdf058d36167ee3d4eb145c52b224eff04c9eb5d1b4e434dfc0000000001ab58aefe57707c66328d3cceef2e6f56ab6b7465e587410c5f73555a513ace2b232793a74400000000036a006522e69d3a785b61ad41a635d59b3a06b2780a92173f85f8ed428491d0aaa436619baa9c4501000000046351abab2609629902eb7793050000000000a1b967040000000003525353a34d6192", "516a", 0, -1761874713, "0a2ff41f6d155d8d0e37cd9438f3b270df9f9214cda8e95c76d5a239ca189df2"); - run_test_sighash("a0eb6dc402994e493c787b45d1f946d267b09c596c5edde043e620ce3d59e95b2b5b93d43002000000096a5252526aac63ab6555694287a279e29ee491c177a801cd685b8744a2eab83824255a3bcd08fc0e3ea13fb8820000000009abab6365ab52ab0063ffffffff029e424a040000000008acab53ab516a636a23830f0400000000016adf49c1f9", "ac0065ac6500005252", 1, 669294500, "e05e3d383631a7ed1b78210c13c2eb26564e5577db7ddfcea2583c7c014091d4"); - run_test_sighash("6e67c0d3027701ef71082204c85ed63c700ef1400c65efb62ce3580d187fb348376a23e9710200000001655b91369d3155ba916a0bc6fe4f5d94cad461d899bb8aaac3699a755838bfc229d6828920010000000765536353526a52ffffffff04c0c792000000000005650052535372f79e000000000001527fc0ee010000000005ac5300ab65d1b3e902000000000251aba942b278", "6a5151", 0, 1741407676, "e657e2c8ec4ebc769ddd3198a83267b47d4f2a419fc737e813812acefad92ff7"); - run_test_sighash("8f53639901f1d643e01fc631f632b7a16e831d846a0184cdcda289b8fa7767f0c292eb221a00000000046a53abacffffffff037a2daa01000000000553ac6a6a51eac349020000000005ac526552638421b3040000000007006a005100ac63048a1492", "ac65", 0, 1033685559, "da86c260d42a692358f46893d6f91563985d86eeb9ea9e21cd38c2d8ffcfcc4d"); - run_test_sighash("b3cad3a7041c2c17d90a2cd994f6c37307753fa3635e9ef05ab8b1ff121ca11239a0902e700300000009ab635300006aac5163ffffffffcec91722c7468156dce4664f3c783afef147f0e6f80739c83b5f09d5a09a57040200000004516a6552ffffffff969d1c6daf8ef53a70b7cdf1b4102fb3240055a8eaeaed2489617cd84cfd56cf020000000352ab53ffffffff46598b6579494a77b593681c33422a99559b9993d77ca2fa97833508b0c169f80200000009655300655365516351ffffffff04d7ddf800000000000853536a65ac6351ab09f3420300000000056aab65abac33589d04000000000952656a65655151acac944d6f0400000000006a8004ba", "005165", 1, 1035865506, "fe1dc9e8554deecf8f50c417c670b839cc9d650722ebaaf36572418756075d58"); - run_test_sighash("cf781855040a755f5ba85eef93837236b34a5d3daeb2dbbdcf58bb811828d806ed05754ab8010000000351ac53ffffffffda1e264727cf55c67f06ebcc56dfe7fa12ac2a994fecd0180ce09ee15c480f7d00000000096351516a51acac00ab53dd49ff9f334befd6d6f87f1a832cddfd826a90b78fd8cf19a52cb8287788af94e939d6020000000700525251ac526310d54a7e8900ed633f0f6f0841145aae7ee0cbbb1e2a0cae724ee4558dbabfdc58ba6855010000000552536a53abfd1b101102c51f910500000000096300656a525252656a300bee010000000009ac52005263635151abe19235c9", "53005365", 2, 1422854188, "d5981bd4467817c1330da72ddb8760d6c2556cd809264b2d85e6d274609fc3a3"); - } - - #[test] - #[cfg(feature="bitcoinconsensus")] - fn test_transaction_verify () { - use hex::decode as hex_decode; - use std::collections::HashMap; - use blockdata::script; - // a random recent segwit transaction from blockchain using both old and segwit inputs - let mut spending: Transaction = deserialize(hex_decode("020000000001031cfbc8f54fbfa4a33a30068841371f80dbfe166211242213188428f437445c91000000006a47304402206fbcec8d2d2e740d824d3d36cc345b37d9f65d665a99f5bd5c9e8d42270a03a8022013959632492332200c2908459547bf8dbf97c65ab1a28dec377d6f1d41d3d63e012103d7279dfb90ce17fe139ba60a7c41ddf605b25e1c07a4ddcb9dfef4e7d6710f48feffffff476222484f5e35b3f0e43f65fc76e21d8be7818dd6a989c160b1e5039b7835fc00000000171600140914414d3c94af70ac7e25407b0689e0baa10c77feffffffa83d954a62568bbc99cc644c62eb7383d7c2a2563041a0aeb891a6a4055895570000000017160014795d04cc2d4f31480d9a3710993fbd80d04301dffeffffff06fef72f000000000017a91476fd7035cd26f1a32a5ab979e056713aac25796887a5000f00000000001976a914b8332d502a529571c6af4be66399cd33379071c588ac3fda0500000000001976a914fc1d692f8de10ae33295f090bea5fe49527d975c88ac522e1b00000000001976a914808406b54d1044c429ac54c0e189b0d8061667e088ac6eb68501000000001976a914dfab6085f3a8fb3e6710206a5a959313c5618f4d88acbba20000000000001976a914eb3026552d7e3f3073457d0bee5d4757de48160d88ac0002483045022100bee24b63212939d33d513e767bc79300051f7a0d433c3fcf1e0e3bf03b9eb1d70220588dc45a9ce3a939103b4459ce47500b64e23ab118dfc03c9caa7d6bfc32b9c601210354fd80328da0f9ae6eef2b3a81f74f9a6f66761fadf96f1d1d22b1fd6845876402483045022100e29c7e3a5efc10da6269e5fc20b6a1cb8beb92130cc52c67e46ef40aaa5cac5f0220644dd1b049727d991aece98a105563416e10a5ac4221abac7d16931842d5c322012103960b87412d6e169f30e12106bdf70122aabb9eb61f455518322a18b920a4dfa887d30700") - .unwrap().as_slice()).unwrap(); - let spent1: Transaction = deserialize(hex_decode("020000000001040aacd2c49f5f3c0968cfa8caf9d5761436d95385252e3abb4de8f5dcf8a582f20000000017160014bcadb2baea98af0d9a902e53a7e9adff43b191e9feffffff96cd3c93cac3db114aafe753122bd7d1afa5aa4155ae04b3256344ecca69d72001000000171600141d9984579ceb5c67ebfbfb47124f056662fe7adbfeffffffc878dd74d3a44072eae6178bb94b9253177db1a5aaa6d068eb0e4db7631762e20000000017160014df2a48cdc53dae1aba7aa71cb1f9de089d75aac3feffffffe49f99275bc8363f5f593f4eec371c51f62c34ff11cc6d8d778787d340d6896c0100000017160014229b3b297a0587e03375ab4174ef56eeb0968735feffffff03360d0f00000000001976a9149f44b06f6ee92ddbc4686f71afe528c09727a5c788ac24281b00000000001976a9140277b4f68ff20307a2a9f9b4487a38b501eb955888ac227c0000000000001976a9148020cd422f55eef8747a9d418f5441030f7c9c7788ac0247304402204aa3bd9682f9a8e101505f6358aacd1749ecf53a62b8370b97d59243b3d6984f02200384ad449870b0e6e89c92505880411285ecd41cf11e7439b973f13bad97e53901210205b392ffcb83124b1c7ce6dd594688198ef600d34500a7f3552d67947bbe392802473044022033dfd8d190a4ae36b9f60999b217c775b96eb10dee3a1ff50fb6a75325719106022005872e4e36d194e49ced2ebcf8bb9d843d842e7b7e0eb042f4028396088d292f012103c9d7cbf369410b090480de2aa15c6c73d91b9ffa7d88b90724614b70be41e98e0247304402207d952de9e59e4684efed069797e3e2d993e9f98ec8a9ccd599de43005fe3f713022076d190cc93d9513fc061b1ba565afac574e02027c9efbfa1d7b71ab8dbb21e0501210313ad44bc030cc6cb111798c2bf3d2139418d751c1e79ec4e837ce360cc03b97a024730440220029e75edb5e9413eb98d684d62a077b17fa5b7cc19349c1e8cc6c4733b7b7452022048d4b9cae594f03741029ff841e35996ef233701c1ea9aa55c301362ea2e2f68012103590657108a72feb8dc1dec022cf6a230bb23dc7aaa52f4032384853b9f8388baf9d20700") - .unwrap().as_slice()).unwrap(); - let spent2: Transaction = deserialize(hex_decode("0200000000010166c3d39490dc827a2594c7b17b7d37445e1f4b372179649cd2ce4475e3641bbb0100000017160014e69aa750e9bff1aca1e32e57328b641b611fc817fdffffff01e87c5d010000000017a914f3890da1b99e44cd3d52f7bcea6a1351658ea7be87024830450221009eb97597953dc288de30060ba02d4e91b2bde1af2ecf679c7f5ab5989549aa8002202a98f8c3bd1a5a31c0d72950dd6e2e3870c6c5819a6c3db740e91ebbbc5ef4800121023f3d3b8e74b807e32217dea2c75c8d0bd46b8665b3a2d9b3cb310959de52a09bc9d20700") - .unwrap().as_slice()).unwrap(); - let spent3: Transaction = deserialize(hex_decode("01000000027a1120a30cef95422638e8dab9dedf720ec614b1b21e451a4957a5969afb869d000000006a47304402200ecc318a829a6cad4aa9db152adbf09b0cd2de36f47b53f5dade3bc7ef086ca702205722cda7404edd6012eedd79b2d6f24c0a0c657df1a442d0a2166614fb164a4701210372f4b97b34e9c408741cd1fc97bcc7ffdda6941213ccfde1cb4075c0f17aab06ffffffffc23b43e5a18e5a66087c0d5e64d58e8e21fcf83ce3f5e4f7ecb902b0e80a7fb6010000006b483045022100f10076a0ea4b4cf8816ed27a1065883efca230933bf2ff81d5db6258691ff75202206b001ef87624e76244377f57f0c84bc5127d0dd3f6e0ef28b276f176badb223a01210309a3a61776afd39de4ed29b622cd399d99ecd942909c36a8696cfd22fc5b5a1affffffff0200127a000000000017a914f895e1dd9b29cb228e9b06a15204e3b57feaf7cc8769311d09000000001976a9144d00da12aaa51849d2583ae64525d4a06cd70fde88ac00000000") - .unwrap().as_slice()).unwrap(); - - let mut spent = HashMap::new(); - spent.insert(spent1.txid(), spent1); - spent.insert(spent2.txid(), spent2); - spent.insert(spent3.txid(), spent3); - let mut spent2 = spent.clone(); - let mut spent3 = spent.clone(); - - spending.verify(|point: &OutPoint| { - if let Some(tx) = spent.remove(&point.txid) { - return tx.output.get(point.vout as usize).cloned(); - } - None - }).unwrap(); - - // test that we fail with repeated use of same input - let mut double_spending = spending.clone(); - let re_use = double_spending.input[0].clone(); - double_spending.input.push (re_use); - - assert!(double_spending.verify(|point: &OutPoint| { - if let Some(tx) = spent2.remove(&point.txid) { - return tx.output.get(point.vout as usize).cloned(); - } - None - }).is_err()); - - // test that we get a failure if we corrupt a signature - spending.input[1].witness[0][10] = 42; - match spending.verify(|point: &OutPoint| { - if let Some(tx) = spent3.remove(&point.txid) { - return tx.output.get(point.vout as usize).cloned(); - } - None - }).err().unwrap() { - script::Error::BitcoinConsensus(_) => {}, - _ => panic!("Wrong error type"), - } - } -} - diff --git a/src/consensus/encode.rs b/src/consensus/encode.rs deleted file mode 100644 index 402a4b51..00000000 --- a/src/consensus/encode.rs +++ /dev/null @@ -1,932 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Consensus-encodable types -//! -//! This is basically a replacement of the `Encodable` trait which does -//! normalization for endianness, etc., to ensure that the encoding -//! matches for endianness, etc., to ensure that the encoding matches -//! the network consensus encoding. -//! -//! Essentially, anything that must go on the -disk- or -network- must -//! be encoded using the `Encodable` trait, since this data -//! must be the same for all systems. Any data going to the -user-, e.g. -//! over JSONRPC, should use the ordinary `Encodable` trait. (This -//! should also be the same across systems, of course, but has some -//! critical differences from the network format, e.g. scripts come -//! with an opcode decode, hashes are big-endian, numbers are typically -//! big-endian decimals, etc.) -//! - -use std::{fmt, error, io, mem, u32}; -use std::borrow::Cow; -use std::io::{Cursor, Read, Write}; -use hashes::hex::ToHex; - -use hashes::{sha256d, Hash}; -use hash_types::{BlockHash, FilterHash, TxMerkleNode}; - -use util::endian; -use util::psbt; - -use blockdata::transaction::{TxOut, Transaction, TxIn}; -use network::message_blockdata::Inventory; -use network::address::Address; - -/// Encoding error -#[derive(Debug)] -pub enum Error { - /// And I/O error - Io(io::Error), - /// PSBT-related error - Psbt(psbt::Error), - /// Network magic was not expected - UnexpectedNetworkMagic { - /// The expected network magic - expected: u32, - /// The unexpected network magic - actual: u32, - }, - /// Tried to allocate an oversized vector - OversizedVectorAllocation{ - /// The capacity requested - requested: usize, - /// The maximum capacity - max: usize, - }, - /// Checksum was invalid - InvalidChecksum { - /// The expected checksum - expected: [u8; 4], - /// The invalid checksum - actual: [u8; 4], - }, - /// VarInt was encoded in a non-minimal way - NonMinimalVarInt, - /// Network magic was unknown - UnknownNetworkMagic(u32), - /// Parsing error - ParseFailed(&'static str), - /// Unsupported Segwit flag - UnsupportedSegwitFlag(u8), - /// Unrecognized network command - UnrecognizedNetworkCommand(String), - /// Invalid Inventory type - UnknownInventoryType(u32), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Io(ref e) => write!(f, "I/O error: {}", e), - Error::Psbt(ref e) => write!(f, "PSBT error: {}", e), - Error::UnexpectedNetworkMagic { expected: ref e, actual: ref a } => write!(f, - "unexpected network magic: expected {}, actual {}", e, a), - Error::OversizedVectorAllocation { requested: ref r, max: ref m } => write!(f, - "allocation of oversized vector: requested {}, maximum {}", r, m), - Error::InvalidChecksum { expected: ref e, actual: ref a } => write!(f, - "invalid checksum: expected {}, actual {}", e.to_hex(), a.to_hex()), - Error::NonMinimalVarInt => write!(f, "non-minimal varint"), - Error::UnknownNetworkMagic(ref m) => write!(f, "unknown network magic: {}", m), - Error::ParseFailed(ref e) => write!(f, "parse failed: {}", e), - Error::UnsupportedSegwitFlag(ref swflag) => write!(f, - "unsupported segwit version: {}", swflag), - Error::UnrecognizedNetworkCommand(ref nwcmd) => write!(f, - "unrecognized network command: {}", nwcmd), - Error::UnknownInventoryType(ref tp) => write!(f, "Unknown Inventory type: {}", tp), - } - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::Io(ref e) => Some(e), - Error::Psbt(ref e) => Some(e), - Error::UnexpectedNetworkMagic { .. } - | Error::OversizedVectorAllocation { .. } - | Error::InvalidChecksum { .. } - | Error::NonMinimalVarInt - | Error::UnknownNetworkMagic(..) - | Error::ParseFailed(..) - | Error::UnsupportedSegwitFlag(..) - | Error::UnrecognizedNetworkCommand(..) - | Error::UnknownInventoryType(..) => None, - } - } - - fn description(&self) -> &str { - "Bitcoin encoding error" - } -} - -#[doc(hidden)] - -#[doc(hidden)] -impl From for Error { - fn from(error: io::Error) -> Self { - Error::Io(error) - } -} - -#[doc(hidden)] -impl From for Error { - fn from(e: psbt::Error) -> Error { - Error::Psbt(e) - } -} - -/// Encode an object into a vector -pub fn serialize(data: &T) -> Vec { - let mut encoder = Cursor::new(vec![]); - data.consensus_encode(&mut encoder).unwrap(); - encoder.into_inner() -} - -/// Encode an object into a hex-encoded string -pub fn serialize_hex(data: &T) -> String { - serialize(data)[..].to_hex() -} - -/// Deserialize an object from a vector, will error if said deserialization -/// doesn't consume the entire vector. -pub fn deserialize<'a, T: Decodable>(data: &'a [u8]) -> Result { - let (rv, consumed) = deserialize_partial(data)?; - - // Fail if data are not consumed entirely. - if consumed == data.len() { - Ok(rv) - } else { - Err(Error::ParseFailed("data not consumed entirely when explicitly deserializing")) - } -} - -/// Deserialize an object from a vector, but will not report an error if said deserialization -/// doesn't consume the entire vector. -pub fn deserialize_partial<'a, T: Decodable>( - data: &'a [u8], -) -> Result<(T, usize), Error> { - let mut decoder = Cursor::new(data); - let rv = Decodable::consensus_decode(&mut decoder)?; - let consumed = decoder.position() as usize; - - Ok((rv, consumed)) -} - - -/// Extensions of `Write` to encode data as per Bitcoin consensus -pub trait WriteExt { - /// Output a 64-bit uint - fn emit_u64(&mut self, v: u64) -> Result<(), Error>; - /// Output a 32-bit uint - fn emit_u32(&mut self, v: u32) -> Result<(), Error>; - /// Output a 16-bit uint - fn emit_u16(&mut self, v: u16) -> Result<(), Error>; - /// Output a 8-bit uint - fn emit_u8(&mut self, v: u8) -> Result<(), Error>; - - /// Output a 64-bit int - fn emit_i64(&mut self, v: i64) -> Result<(), Error>; - /// Output a 32-bit int - fn emit_i32(&mut self, v: i32) -> Result<(), Error>; - /// Output a 16-bit int - fn emit_i16(&mut self, v: i16) -> Result<(), Error>; - /// Output a 8-bit int - fn emit_i8(&mut self, v: i8) -> Result<(), Error>; - - /// Output a boolean - fn emit_bool(&mut self, v: bool) -> Result<(), Error>; - - /// Output a byte slice - fn emit_slice(&mut self, v: &[u8]) -> Result<(), Error>; -} - -/// Extensions of `Read` to decode data as per Bitcoin consensus -pub trait ReadExt { - /// Read a 64-bit uint - fn read_u64(&mut self) -> Result; - /// Read a 32-bit uint - fn read_u32(&mut self) -> Result; - /// Read a 16-bit uint - fn read_u16(&mut self) -> Result; - /// Read a 8-bit uint - fn read_u8(&mut self) -> Result; - - /// Read a 64-bit int - fn read_i64(&mut self) -> Result; - /// Read a 32-bit int - fn read_i32(&mut self) -> Result; - /// Read a 16-bit int - fn read_i16(&mut self) -> Result; - /// Read a 8-bit int - fn read_i8(&mut self) -> Result; - - /// Read a boolean - fn read_bool(&mut self) -> Result; - - /// Read a byte slice - fn read_slice(&mut self, slice: &mut [u8]) -> Result<(), Error>; -} - -macro_rules! encoder_fn { - ($name:ident, $val_type:ty, $writefn:ident) => { - #[inline] - fn $name(&mut self, v: $val_type) -> Result<(), Error> { - self.write_all(&endian::$writefn(v)).map_err(Error::Io) - } - } -} - -macro_rules! decoder_fn { - ($name:ident, $val_type:ty, $readfn:ident, $byte_len: expr) => { - #[inline] - fn $name(&mut self) -> Result<$val_type, Error> { - assert_eq!(::std::mem::size_of::<$val_type>(), $byte_len); // size_of isn't a constfn in 1.22 - let mut val = [0; $byte_len]; - self.read_exact(&mut val[..]).map_err(Error::Io)?; - Ok(endian::$readfn(&val)) - } - } -} - -impl WriteExt for W { - encoder_fn!(emit_u64, u64, u64_to_array_le); - encoder_fn!(emit_u32, u32, u32_to_array_le); - encoder_fn!(emit_u16, u16, u16_to_array_le); - encoder_fn!(emit_i64, i64, i64_to_array_le); - encoder_fn!(emit_i32, i32, i32_to_array_le); - encoder_fn!(emit_i16, i16, i16_to_array_le); - - #[inline] - fn emit_i8(&mut self, v: i8) -> Result<(), Error> { - self.write_all(&[v as u8]).map_err(Error::Io) - } - #[inline] - fn emit_u8(&mut self, v: u8) -> Result<(), Error> { - self.write_all(&[v]).map_err(Error::Io) - } - #[inline] - fn emit_bool(&mut self, v: bool) -> Result<(), Error> { - self.write_all(&[if v {1} else {0}]).map_err(Error::Io) - } - #[inline] - fn emit_slice(&mut self, v: &[u8]) -> Result<(), Error> { - self.write_all(v).map_err(Error::Io) - } -} - -impl ReadExt for R { - decoder_fn!(read_u64, u64, slice_to_u64_le, 8); - decoder_fn!(read_u32, u32, slice_to_u32_le, 4); - decoder_fn!(read_u16, u16, slice_to_u16_le, 2); - decoder_fn!(read_i64, i64, slice_to_i64_le, 8); - decoder_fn!(read_i32, i32, slice_to_i32_le, 4); - decoder_fn!(read_i16, i16, slice_to_i16_le, 2); - - #[inline] - fn read_u8(&mut self) -> Result { - let mut slice = [0u8; 1]; - self.read_exact(&mut slice)?; - Ok(slice[0]) - } - #[inline] - fn read_i8(&mut self) -> Result { - let mut slice = [0u8; 1]; - self.read_exact(&mut slice)?; - Ok(slice[0] as i8) - } - #[inline] - fn read_bool(&mut self) -> Result { - ReadExt::read_i8(self).map(|bit| bit != 0) - } - #[inline] - fn read_slice(&mut self, slice: &mut [u8]) -> Result<(), Error> { - self.read_exact(slice).map_err(Error::Io) - } -} - -/// Maximum size, in bytes, of a vector we are allowed to decode -pub const MAX_VEC_SIZE: usize = 4_000_000; - -/// Data which can be encoded in a consensus-consistent way -pub trait Encodable { - /// Encode an object with a well-defined format, should only ever error if - /// the underlying `Write` errors. Returns the number of bytes written on - /// success - fn consensus_encode(&self, e: W) -> Result; -} - -/// Data which can be encoded in a consensus-consistent way -pub trait Decodable: Sized { - /// Decode an object with a well-defined format - fn consensus_decode(d: D) -> Result; -} - -/// A variable-length unsigned integer -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)] -pub struct VarInt(pub u64); - -/// Data which must be preceded by a 4-byte checksum -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct CheckedData(pub Vec); - -// Primitive types -macro_rules! impl_int_encodable{ - ($ty:ident, $meth_dec:ident, $meth_enc:ident) => ( - impl Decodable for $ty { - #[inline] - fn consensus_decode(mut d: D) -> Result { - ReadExt::$meth_dec(&mut d).map($ty::from_le) - } - } - - impl Encodable for $ty { - #[inline] - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - s.$meth_enc(self.to_le())?; - Ok(mem::size_of::<$ty>()) - } - } - ) -} - -impl_int_encodable!(u8, read_u8, emit_u8); -impl_int_encodable!(u16, read_u16, emit_u16); -impl_int_encodable!(u32, read_u32, emit_u32); -impl_int_encodable!(u64, read_u64, emit_u64); -impl_int_encodable!(i8, read_i8, emit_i8); -impl_int_encodable!(i16, read_i16, emit_i16); -impl_int_encodable!(i32, read_i32, emit_i32); -impl_int_encodable!(i64, read_i64, emit_i64); - -impl VarInt { - /// Gets the length of this VarInt when encoded. - /// Returns 1 for 0...0xFC, 3 for 0xFD...(2^16-1), 5 for 0x10000...(2^32-1), - /// and 9 otherwise. - #[inline] - pub fn len(&self) -> usize { - match self.0 { - 0...0xFC => { 1 } - 0xFD...0xFFFF => { 3 } - 0x10000...0xFFFFFFFF => { 5 } - _ => { 9 } - } - } -} - -impl Encodable for VarInt { - #[inline] - fn consensus_encode(&self, mut s: S) -> Result { - match self.0 { - 0...0xFC => { - (self.0 as u8).consensus_encode(s)?; - Ok(1) - }, - 0xFD...0xFFFF => { - s.emit_u8(0xFD)?; - (self.0 as u16).consensus_encode(s)?; - Ok(3) - }, - 0x10000...0xFFFFFFFF => { - s.emit_u8(0xFE)?; - (self.0 as u32).consensus_encode(s)?; - Ok(5) - }, - _ => { - s.emit_u8(0xFF)?; - (self.0 as u64).consensus_encode(s)?; - Ok(9) - }, - } - } -} - -impl Decodable for VarInt { - #[inline] - fn consensus_decode(mut d: D) -> Result { - let n = ReadExt::read_u8(&mut d)?; - match n { - 0xFF => { - let x = ReadExt::read_u64(&mut d)?; - if x < 0x100000000 { - Err(self::Error::NonMinimalVarInt) - } else { - Ok(VarInt(x)) - } - } - 0xFE => { - let x = ReadExt::read_u32(&mut d)?; - if x < 0x10000 { - Err(self::Error::NonMinimalVarInt) - } else { - Ok(VarInt(x as u64)) - } - } - 0xFD => { - let x = ReadExt::read_u16(&mut d)?; - if x < 0xFD { - Err(self::Error::NonMinimalVarInt) - } else { - Ok(VarInt(x as u64)) - } - } - n => Ok(VarInt(n as u64)) - } - } -} - - -// Booleans -impl Encodable for bool { - #[inline] - fn consensus_encode(&self, mut s: S) -> Result { - s.emit_u8(if *self {1} else {0})?; - Ok(1) - } -} - -impl Decodable for bool { - #[inline] - fn consensus_decode(mut d: D) -> Result { - ReadExt::read_u8(&mut d).map(|n| n != 0) - } -} - -// Strings -impl Encodable for String { - #[inline] - fn consensus_encode(&self, mut s: S) -> Result { - let b = self.as_bytes(); - let vi_len = VarInt(b.len() as u64).consensus_encode(&mut s)?; - s.emit_slice(&b)?; - Ok(vi_len + b.len()) - } -} - -impl Decodable for String { - #[inline] - fn consensus_decode(d: D) -> Result { - String::from_utf8(Decodable::consensus_decode(d)?) - .map_err(|_| self::Error::ParseFailed("String was not valid UTF8")) - } -} - -// Cow<'static, str> -impl Encodable for Cow<'static, str> { - #[inline] - fn consensus_encode(&self, mut s: S) -> Result { - let b = self.as_bytes(); - let vi_len = VarInt(b.len() as u64).consensus_encode(&mut s)?; - s.emit_slice(&b)?; - Ok(vi_len + b.len()) - } -} - -impl Decodable for Cow<'static, str> { - #[inline] - fn consensus_decode(d: D) -> Result, Error> { - String::from_utf8(Decodable::consensus_decode(d)?) - .map_err(|_| self::Error::ParseFailed("String was not valid UTF8")) - .map(Cow::Owned) - } -} - - -// Arrays -macro_rules! impl_array { - ( $size:expr ) => ( - impl Encodable for [u8; $size] { - #[inline] - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - s.emit_slice(&self[..])?; - Ok(self.len()) - } - } - - impl Decodable for [u8; $size] { - #[inline] - fn consensus_decode(mut d: D) -> Result { - let mut ret = [0; $size]; - d.read_slice(&mut ret)?; - Ok(ret) - } - } - ); -} - -impl_array!(2); -impl_array!(4); -impl_array!(8); -impl_array!(12); -impl_array!(16); -impl_array!(32); -impl_array!(33); - -impl Decodable for [u16; 8] { - #[inline] - fn consensus_decode(mut d: D) -> Result { - let mut res = [0; 8]; - for i in 0..8 { - res[i] = Decodable::consensus_decode(&mut d)?; - } - Ok(res) - } -} - -impl Encodable for [u16; 8] { - #[inline] - fn consensus_encode(&self, mut s: S) -> Result { - for c in self.iter() { c.consensus_encode(&mut s)?; } - Ok(16) - } -} - -// Vectors -macro_rules! impl_vec { - ($type: ty) => { - impl Encodable for Vec<$type> { - #[inline] - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let mut len = 0; - len += VarInt(self.len() as u64).consensus_encode(&mut s)?; - for c in self.iter() { - len += c.consensus_encode(&mut s)?; - } - Ok(len) - } - } - - impl Decodable for Vec<$type> { - #[inline] - fn consensus_decode(mut d: D) -> Result { - let len = VarInt::consensus_decode(&mut d)?.0; - let byte_size = (len as usize) - .checked_mul(mem::size_of::<$type>()) - .ok_or(self::Error::ParseFailed("Invalid length"))?; - if byte_size > MAX_VEC_SIZE { - return Err(self::Error::OversizedVectorAllocation { requested: byte_size, max: MAX_VEC_SIZE }) - } - let mut ret = Vec::with_capacity(len as usize); - for _ in 0..len { - ret.push(Decodable::consensus_decode(&mut d)?); - } - Ok(ret) - } - } - } -} -impl_vec!(BlockHash); -impl_vec!(FilterHash); -impl_vec!(TxMerkleNode); -impl_vec!(Transaction); -impl_vec!(TxOut); -impl_vec!(TxIn); -impl_vec!(Inventory); -impl_vec!(Vec); -impl_vec!((u32, Address)); -impl_vec!(u64); - -impl Encodable for Vec { - #[inline] - fn consensus_encode(&self, mut s: S) -> Result { - let vi_len = VarInt(self.len() as u64).consensus_encode(&mut s)?; - s.emit_slice(&self)?; - Ok(vi_len + self.len()) - } -} - -impl Decodable for Vec { - #[inline] - fn consensus_decode(mut d: D) -> Result { - let len = VarInt::consensus_decode(&mut d)?.0 as usize; - if len > MAX_VEC_SIZE { - return Err(self::Error::OversizedVectorAllocation { requested: len, max: MAX_VEC_SIZE }) - } - let mut ret = Vec::with_capacity(len); - ret.resize(len, 0); - d.read_slice(&mut ret)?; - Ok(ret) - } -} - -impl Encodable for Box<[u8]> { - #[inline] - fn consensus_encode(&self, mut s: S) -> Result { - let vi_len = VarInt(self.len() as u64).consensus_encode(&mut s)?; - s.emit_slice(&self)?; - Ok(vi_len + self.len()) - } -} - -impl Decodable for Box<[u8]> { - #[inline] - fn consensus_decode(mut d: D) -> Result { - let len = VarInt::consensus_decode(&mut d)?.0; - let len = len as usize; - if len > MAX_VEC_SIZE { - return Err(self::Error::OversizedVectorAllocation { requested: len, max: MAX_VEC_SIZE }) - } - let mut ret = Vec::with_capacity(len); - ret.resize(len, 0); - d.read_slice(&mut ret)?; - Ok(ret.into_boxed_slice()) - } -} - - -/// Do a double-SHA256 on some data and return the first 4 bytes -fn sha2_checksum(data: &[u8]) -> [u8; 4] { - let checksum = ::hash(data); - [checksum[0], checksum[1], checksum[2], checksum[3]] -} - -// Checked data -impl Encodable for CheckedData { - #[inline] - fn consensus_encode(&self, mut s: S) -> Result { - (self.0.len() as u32).consensus_encode(&mut s)?; - sha2_checksum(&self.0).consensus_encode(&mut s)?; - s.emit_slice(&self.0)?; - Ok(8 + self.0.len()) - } -} - -impl Decodable for CheckedData { - #[inline] - fn consensus_decode(mut d: D) -> Result { - let len = u32::consensus_decode(&mut d)?; - if len > MAX_VEC_SIZE as u32 { - return Err(self::Error::OversizedVectorAllocation { - requested: len as usize, - max: MAX_VEC_SIZE - }); - } - let checksum = <[u8; 4]>::consensus_decode(&mut d)?; - let mut ret = Vec::with_capacity(len as usize); - ret.resize(len as usize, 0); - d.read_slice(&mut ret)?; - let expected_checksum = sha2_checksum(&ret); - if expected_checksum != checksum { - Err(self::Error::InvalidChecksum { - expected: expected_checksum, - actual: checksum, - }) - } else { - Ok(CheckedData(ret)) - } - } -} - -// Tuples -macro_rules! tuple_encode { - ($($x:ident),*) => ( - impl <$($x: Encodable),*> Encodable for ($($x),*) { - #[inline] - #[allow(non_snake_case)] - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let &($(ref $x),*) = self; - let mut len = 0; - $(len += $x.consensus_encode(&mut s)?;)* - Ok(len) - } - } - - impl<$($x: Decodable),*> Decodable for ($($x),*) { - #[inline] - #[allow(non_snake_case)] - fn consensus_decode(mut d: D) -> Result { - Ok(($({let $x = Decodable::consensus_decode(&mut d)?; $x }),*)) - } - } - ); -} - -tuple_encode!(T0, T1); -tuple_encode!(T0, T1, T2, T3); -tuple_encode!(T0, T1, T2, T3, T4, T5); -tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); - -impl Encodable for sha256d::Hash { - fn consensus_encode(&self, s: S) -> Result { - self.into_inner().consensus_encode(s) - } -} - -impl Decodable for sha256d::Hash { - fn consensus_decode(d: D) -> Result { - Ok(Self::from_inner(<::Inner>::consensus_decode(d)?)) - } -} - -// Tests -#[cfg(test)] -mod tests { - use super::{CheckedData, VarInt}; - - use super::{deserialize, serialize, Error}; - - #[test] - fn serialize_int_test() { - // bool - assert_eq!(serialize(&false), vec![0u8]); - assert_eq!(serialize(&true), vec![1u8]); - // u8 - assert_eq!(serialize(&1u8), vec![1u8]); - assert_eq!(serialize(&0u8), vec![0u8]); - assert_eq!(serialize(&255u8), vec![255u8]); - // u16 - assert_eq!(serialize(&1u16), vec![1u8, 0]); - assert_eq!(serialize(&256u16), vec![0u8, 1]); - assert_eq!(serialize(&5000u16), vec![136u8, 19]); - // u32 - assert_eq!(serialize(&1u32), vec![1u8, 0, 0, 0]); - assert_eq!(serialize(&256u32), vec![0u8, 1, 0, 0]); - assert_eq!(serialize(&5000u32), vec![136u8, 19, 0, 0]); - assert_eq!(serialize(&500000u32), vec![32u8, 161, 7, 0]); - assert_eq!(serialize(&168430090u32), vec![10u8, 10, 10, 10]); - // i32 - assert_eq!(serialize(&-1i32), vec![255u8, 255, 255, 255]); - assert_eq!(serialize(&-256i32), vec![0u8, 255, 255, 255]); - assert_eq!(serialize(&-5000i32), vec![120u8, 236, 255, 255]); - assert_eq!(serialize(&-500000i32), vec![224u8, 94, 248, 255]); - assert_eq!(serialize(&-168430090i32), vec![246u8, 245, 245, 245]); - assert_eq!(serialize(&1i32), vec![1u8, 0, 0, 0]); - assert_eq!(serialize(&256i32), vec![0u8, 1, 0, 0]); - assert_eq!(serialize(&5000i32), vec![136u8, 19, 0, 0]); - assert_eq!(serialize(&500000i32), vec![32u8, 161, 7, 0]); - assert_eq!(serialize(&168430090i32), vec![10u8, 10, 10, 10]); - // u64 - assert_eq!(serialize(&1u64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&256u64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&5000u64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&500000u64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&723401728380766730u64), vec![10u8, 10, 10, 10, 10, 10, 10, 10]); - // i64 - assert_eq!(serialize(&-1i64), vec![255u8, 255, 255, 255, 255, 255, 255, 255]); - assert_eq!(serialize(&-256i64), vec![0u8, 255, 255, 255, 255, 255, 255, 255]); - assert_eq!(serialize(&-5000i64), vec![120u8, 236, 255, 255, 255, 255, 255, 255]); - assert_eq!(serialize(&-500000i64), vec![224u8, 94, 248, 255, 255, 255, 255, 255]); - assert_eq!(serialize(&-723401728380766730i64), vec![246u8, 245, 245, 245, 245, 245, 245, 245]); - assert_eq!(serialize(&1i64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&256i64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&5000i64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&500000i64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&723401728380766730i64), vec![10u8, 10, 10, 10, 10, 10, 10, 10]); - } - - #[test] - fn serialize_varint_test() { - assert_eq!(serialize(&VarInt(10)), vec![10u8]); - assert_eq!(serialize(&VarInt(0xFC)), vec![0xFCu8]); - assert_eq!(serialize(&VarInt(0xFD)), vec![0xFDu8, 0xFD, 0]); - assert_eq!(serialize(&VarInt(0xFFF)), vec![0xFDu8, 0xFF, 0xF]); - assert_eq!(serialize(&VarInt(0xF0F0F0F)), vec![0xFEu8, 0xF, 0xF, 0xF, 0xF]); - assert_eq!(serialize(&VarInt(0xF0F0F0F0F0E0)), vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0]); - } - - #[test] - fn deserialize_nonminimal_vec() { - match deserialize::>(&[0xfd, 0x00, 0x00]) { - Err(Error::NonMinimalVarInt) => {}, - x => panic!(x) - } - match deserialize::>(&[0xfd, 0xfc, 0x00]) { - Err(Error::NonMinimalVarInt) => {}, - x => panic!(x) - } - match deserialize::>(&[0xfe, 0xff, 0x00, 0x00, 0x00]) { - Err(Error::NonMinimalVarInt) => {}, - x => panic!(x) - } - match deserialize::>(&[0xfe, 0xff, 0xff, 0x00, 0x00]) { - Err(Error::NonMinimalVarInt) => {}, - x => panic!(x) - } - match deserialize::>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) { - Err(Error::NonMinimalVarInt) => {}, - x => panic!(x) - } - match deserialize::>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00]) { - Err(Error::NonMinimalVarInt) => {}, - x => panic!(x) - } - - let mut vec_256 = vec![0; 259]; - vec_256[0] = 0xfd; - vec_256[1] = 0x00; - vec_256[2] = 0x01; - assert!(deserialize::>(&vec_256).is_ok()); - - let mut vec_253 = vec![0; 256]; - vec_253[0] = 0xfd; - vec_253[1] = 0xfd; - vec_253[2] = 0x00; - assert!(deserialize::>(&vec_253).is_ok()); - } - - #[test] - fn serialize_checkeddata_test() { - let cd = CheckedData(vec![1u8, 2, 3, 4, 5]); - assert_eq!(serialize(&cd), vec![5, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]); - } - - #[test] - fn serialize_vector_test() { - assert_eq!(serialize(&vec![1u8, 2, 3]), vec![3u8, 1, 2, 3]); - // TODO: test vectors of more interesting objects - } - - #[test] - fn serialize_strbuf_test() { - assert_eq!(serialize(&"Andrew".to_string()), vec![6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]); - } - - #[test] - fn deserialize_int_test() { - // bool - assert!((deserialize(&[58u8, 0]) as Result).is_err()); - assert_eq!(deserialize(&[58u8]).ok(), Some(true)); - assert_eq!(deserialize(&[1u8]).ok(), Some(true)); - assert_eq!(deserialize(&[0u8]).ok(), Some(false)); - assert!((deserialize(&[0u8, 1]) as Result).is_err()); - - // u8 - assert_eq!(deserialize(&[58u8]).ok(), Some(58u8)); - - // u16 - assert_eq!(deserialize(&[0x01u8, 0x02]).ok(), Some(0x0201u16)); - assert_eq!(deserialize(&[0xABu8, 0xCD]).ok(), Some(0xCDABu16)); - assert_eq!(deserialize(&[0xA0u8, 0x0D]).ok(), Some(0xDA0u16)); - let failure16: Result = deserialize(&[1u8]); - assert!(failure16.is_err()); - - // u32 - assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABu32)); - assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD]).ok(), Some(0xCDAB0DA0u32)); - let failure32: Result = deserialize(&[1u8, 2, 3]); - assert!(failure32.is_err()); - // TODO: test negative numbers - assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABi32)); - assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0x2D]).ok(), Some(0x2DAB0DA0i32)); - let failurei32: Result = deserialize(&[1u8, 2, 3]); - assert!(failurei32.is_err()); - - // u64 - assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABu64)); - assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(0x99000099CDAB0DA0u64)); - let failure64: Result = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]); - assert!(failure64.is_err()); - // TODO: test negative numbers - assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), Some(0xCDABi64)); - assert_eq!(deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), Some(-0x66ffff663254f260i64)); - let failurei64: Result = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]); - assert!(failurei64.is_err()); - } - - #[test] - fn deserialize_vec_test() { - assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4])); - assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result, _>).is_err()); - // found by cargo fuzz - assert!(deserialize::>(&[0xff,0xff,0xff,0xff,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0x6b,0xa,0xa,0x3a]).is_err()); - } - - #[test] - fn deserialize_strbuf_test() { - assert_eq!(deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), Some("Andrew".to_string())); - assert_eq!( - deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), - Some(::std::borrow::Cow::Borrowed("Andrew")) - ); - } - - #[test] - fn deserialize_checkeddata_test() { - let cd: Result = deserialize(&[5u8, 0, 0, 0, 162, 107, 175, 90, 1, 2, 3, 4, 5]); - assert_eq!(cd.ok(), Some(CheckedData(vec![1u8, 2, 3, 4, 5]))); - } -} - diff --git a/src/consensus/mod.rs b/src/consensus/mod.rs deleted file mode 100644 index 1e302333..00000000 --- a/src/consensus/mod.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Rust Bitcoin Library -// Written by -// The Rust Bitcoin developers -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Consensus -//! -//! This module defines structures, functions, and traits which are needed to -//! conform to Bitcoin consensus. -//! - -pub mod encode; -pub mod params; - -pub use self::encode::{Encodable, Decodable, WriteExt, ReadExt}; -pub use self::encode::{serialize, deserialize, deserialize_partial}; -pub use self::params::Params; diff --git a/src/consensus/params.rs b/src/consensus/params.rs deleted file mode 100644 index a1311fa1..00000000 --- a/src/consensus/params.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Consensus parameters -//! -//! This module provides predefined set of parameters for different chains. -//! - -use network::constants::Network; -use util::uint::Uint256; - -/// Lowest possible difficulty for Mainnet. -const MAX_BITS_BITCOIN: Uint256 = Uint256([ - 0xffffffffffffffffu64, - 0xffffffffffffffffu64, - 0xffffffffffffffffu64, - 0x00000000ffffffffu64, -]); -/// Lowest possible difficulty for Testnet. -const MAX_BITS_TESTNET: Uint256 = Uint256([ - 0xffffffffffffffffu64, - 0xffffffffffffffffu64, - 0xffffffffffffffffu64, - 0x00000000ffffffffu64, -]); -/// Lowest possible difficulty for Regtest. -const MAX_BITS_REGTEST: Uint256 = Uint256([ - 0xffffffffffffffffu64, - 0xffffffffffffffffu64, - 0xffffffffffffffffu64, - 0x7fffffffffffffffu64, -]); - -#[derive(Debug, Clone)] -/// Parameters that influence chain consensus. -pub struct Params { - /// Network for which parameters are valid. - pub network: Network, - /// Time when BIP16 becomes active. - pub bip16_time: u32, - /// Block height at which BIP34 becomes active. - pub bip34_height: u32, - /// Block height at which BIP65 becomes active. - pub bip65_height: u32, - /// Block height at which BIP66 becomes active. - pub bip66_height: u32, - /// Minimum blocks including miner confirmation of the total of 2016 blocks in a retargeting period, - /// (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments. - /// Examples: 1916 for 95%, 1512 for testchains. - pub rule_change_activation_threshold: u32, - /// Number of blocks with the same set of rules. - pub miner_confirmation_window: u32, - /// Proof of work limit value. It contains the lowest possible difficulty. - pub pow_limit: Uint256, - /// Expected amount of time to mine one block. - pub pow_target_spacing: u64, - /// Difficulty recalculation interval. - pub pow_target_timespan: u64, - /// Determines whether minimal difficulty may be used for blocks or not. - pub allow_min_difficulty_blocks: bool, - /// Determines whether retargeting is disabled for this network or not. - pub no_pow_retargeting: bool, -} - -impl Params { - /// Creates parameters set for the given network. - pub fn new(network: Network) -> Self { - match network { - Network::Bitcoin => Params { - network: Network::Bitcoin, - bip16_time: 1333238400, // Apr 1 2012 - bip34_height: 227931, // 000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8 - bip65_height: 388381, // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0 - bip66_height: 363725, // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931 - rule_change_activation_threshold: 1916, // 95% - miner_confirmation_window: 2016, - pow_limit: MAX_BITS_BITCOIN, - pow_target_spacing: 10 * 60, // 10 minutes. - pow_target_timespan: 14 * 24 * 60 * 60, // 2 weeks. - allow_min_difficulty_blocks: false, - no_pow_retargeting: false, - }, - Network::Testnet => Params { - network: Network::Testnet, - bip16_time: 1333238400, // Apr 1 2012 - bip34_height: 21111, // 0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8 - bip65_height: 581885, // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6 - bip66_height: 330776, // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182 - rule_change_activation_threshold: 1512, // 75% - miner_confirmation_window: 2016, - pow_limit: MAX_BITS_TESTNET, - pow_target_spacing: 10 * 60, // 10 minutes. - pow_target_timespan: 14 * 24 * 60 * 60, // 2 weeks. - allow_min_difficulty_blocks: true, - no_pow_retargeting: false, - }, - Network::Regtest => Params { - network: Network::Regtest, - bip16_time: 1333238400, // Apr 1 2012 - bip34_height: 100000000, // not activated on regtest - bip65_height: 1351, - bip66_height: 1251, // used only in rpc tests - rule_change_activation_threshold: 108, // 75% - miner_confirmation_window: 144, - pow_limit: MAX_BITS_REGTEST, - pow_target_spacing: 10 * 60, // 10 minutes. - pow_target_timespan: 14 * 24 * 60 * 60, // 2 weeks. - allow_min_difficulty_blocks: true, - no_pow_retargeting: true, - }, - } - } - - /// Calculates the number of blocks between difficulty adjustments. - pub fn difficulty_adjustment_interval(&self) -> u64 { - self.pow_target_timespan / self.pow_target_spacing - } -} diff --git a/src/hash_types.rs b/src/hash_types.rs deleted file mode 100644 index 514c5309..00000000 --- a/src/hash_types.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! File defines types for hashes used throughout the library. These types are needed in order -//! to avoid mixing data of the same hash format (like SHA256d) but of different meaning -//! (transaction id, block hash etc). - -use std::io; - -use consensus::encode::{Encodable, Decodable, Error}; -use hashes::{sha256, sha256d, hash160, Hash}; -use hashes::hex::{ToHex, FromHex}; - -macro_rules! impl_hashencode { - ($hashtype:ident) => { - impl Encodable for $hashtype { - fn consensus_encode(&self, s: S) -> Result { - self.0.consensus_encode(s) - } - } - - impl Decodable for $hashtype { - fn consensus_decode(d: D) -> Result { - Ok(Self::from_inner(<<$hashtype as Hash>::Inner>::consensus_decode(d)?)) - } - } - } -} - -hash_newtype!(Txid, sha256d::Hash, 32, doc="A bitcoin transaction hash/transaction ID."); -hash_newtype!(Wtxid, sha256d::Hash, 32, doc="A bitcoin witness transaction ID."); -hash_newtype!(BlockHash, sha256d::Hash, 32, doc="A bitcoin block hash."); -hash_newtype!(SigHash, sha256d::Hash, 32, doc="Hash of the transaction according to the signature algorithm"); - -hash_newtype!(PubkeyHash, hash160::Hash, 20, doc="A hash of a public key."); -hash_newtype!(ScriptHash, hash160::Hash, 20, doc="A hash of Bitcoin Script bytecode."); -hash_newtype!(WPubkeyHash, hash160::Hash, 20, doc="SegWit version of a public key hash."); -hash_newtype!(WScriptHash, sha256::Hash, 32, doc="SegWit version of a Bitcoin Script bytecode hash."); - -hash_newtype!(TxMerkleNode, sha256d::Hash, 32, doc="A hash of the Merkle tree branch or root for transactions"); -hash_newtype!(WitnessMerkleNode, sha256d::Hash, 32, doc="A hash corresponding to the Merkle tree root for witness data"); -hash_newtype!(WitnessCommitment, sha256d::Hash, 32, doc="A hash corresponding to the witness structure commitment in the coinbase transaction"); -hash_newtype!(XpubIdentifier, hash160::Hash, 20, doc="XpubIdentifier as defined in BIP-32."); - -hash_newtype!(FilterHash, sha256d::Hash, 32, doc="Bloom filter souble-SHA256 locator hash, as defined in BIP-168"); - - -impl_hashencode!(Txid); -impl_hashencode!(Wtxid); -impl_hashencode!(SigHash); -impl_hashencode!(BlockHash); -impl_hashencode!(TxMerkleNode); -impl_hashencode!(WitnessMerkleNode); -impl_hashencode!(FilterHash); diff --git a/src/internal_macros.rs b/src/internal_macros.rs deleted file mode 100644 index 362a2290..00000000 --- a/src/internal_macros.rs +++ /dev/null @@ -1,799 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Internal Macros -//! -//! Macros meant to be used inside the Rust Bitcoin library - -macro_rules! impl_consensus_encoding { - ($thing:ident, $($field:ident),+) => ( - impl ::consensus::Encodable for $thing { - #[inline] - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let mut len = 0; - $(len += self.$field.consensus_encode(&mut s)?;)+ - Ok(len) - } - } - - impl ::consensus::Decodable for $thing { - #[inline] - fn consensus_decode( - mut d: D, - ) -> Result<$thing, ::consensus::encode::Error> { - Ok($thing { - $($field: ::consensus::Decodable::consensus_decode(&mut d)?),+ - }) - } - } - ); -} - -macro_rules! impl_array_newtype { - ($thing:ident, $ty:ty, $len:expr) => { - impl $thing { - #[inline] - /// Converts the object to a raw pointer - pub fn as_ptr(&self) -> *const $ty { - let &$thing(ref dat) = self; - dat.as_ptr() - } - - #[inline] - /// Converts the object to a mutable raw pointer - pub fn as_mut_ptr(&mut self) -> *mut $ty { - let &mut $thing(ref mut dat) = self; - dat.as_mut_ptr() - } - - #[inline] - /// Returns the length of the object as an array - pub fn len(&self) -> usize { $len } - - #[inline] - /// Returns whether the object, as an array, is empty. Always false. - pub fn is_empty(&self) -> bool { false } - - #[inline] - /// Returns the underlying bytes. - pub fn as_bytes(&self) -> &[$ty; $len] { &self.0 } - - #[inline] - /// Returns the underlying bytes. - pub fn to_bytes(&self) -> [$ty; $len] { self.0.clone() } - - #[inline] - /// Returns the underlying bytes. - pub fn into_bytes(self) -> [$ty; $len] { self.0 } - } - - impl<'a> From<&'a [$ty]> for $thing { - fn from(data: &'a [$ty]) -> $thing { - assert_eq!(data.len(), $len); - let mut ret = [0; $len]; - ret.copy_from_slice(&data[..]); - $thing(ret) - } - } - - impl ::std::ops::Index for $thing { - type Output = $ty; - - #[inline] - fn index(&self, index: usize) -> &$ty { - let &$thing(ref dat) = self; - &dat[index] - } - } - - impl_index_newtype!($thing, $ty); - - impl PartialEq for $thing { - #[inline] - fn eq(&self, other: &$thing) -> bool { - &self[..] == &other[..] - } - } - - impl Eq for $thing {} - - impl PartialOrd for $thing { - #[inline] - fn partial_cmp(&self, other: &$thing) -> Option<::std::cmp::Ordering> { - Some(self.cmp(&other)) - } - } - - impl Ord for $thing { - #[inline] - fn cmp(&self, other: &$thing) -> ::std::cmp::Ordering { - // manually implement comparison to get little-endian ordering - // (we need this for our numeric types; non-numeric ones shouldn't - // be ordered anyway except to put them in BTrees or whatever, and - // they don't care how we order as long as we're consistent). - for i in 0..$len { - if self[$len - 1 - i] < other[$len - 1 - i] { return ::std::cmp::Ordering::Less; } - if self[$len - 1 - i] > other[$len - 1 - i] { return ::std::cmp::Ordering::Greater; } - } - ::std::cmp::Ordering::Equal - } - } - - #[cfg_attr(feature = "clippy", allow(expl_impl_clone_on_copy))] // we don't define the `struct`, we have to explicitly impl - impl Clone for $thing { - #[inline] - fn clone(&self) -> $thing { - $thing::from(&self[..]) - } - } - - impl Copy for $thing {} - - impl ::std::hash::Hash for $thing { - #[inline] - fn hash(&self, state: &mut H) - where H: ::std::hash::Hasher - { - (&self[..]).hash(state); - } - - fn hash_slice(data: &[$thing], state: &mut H) - where H: ::std::hash::Hasher - { - for d in data.iter() { - (&d[..]).hash(state); - } - } - } - } -} - -macro_rules! impl_array_newtype_show { - ($thing:ident) => { - impl ::std::fmt::Debug for $thing { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, concat!(stringify!($thing), "({:?})"), &self[..]) - } - } - } -} - -macro_rules! impl_index_newtype { - ($thing:ident, $ty:ty) => { - impl ::std::ops::Index<::std::ops::Range> for $thing { - type Output = [$ty]; - - #[inline] - fn index(&self, index: ::std::ops::Range) -> &[$ty] { - &self.0[index] - } - } - - impl ::std::ops::Index<::std::ops::RangeTo> for $thing { - type Output = [$ty]; - - #[inline] - fn index(&self, index: ::std::ops::RangeTo) -> &[$ty] { - &self.0[index] - } - } - - impl ::std::ops::Index<::std::ops::RangeFrom> for $thing { - type Output = [$ty]; - - #[inline] - fn index(&self, index: ::std::ops::RangeFrom) -> &[$ty] { - &self.0[index] - } - } - - impl ::std::ops::Index<::std::ops::RangeFull> for $thing { - type Output = [$ty]; - - #[inline] - fn index(&self, _: ::std::ops::RangeFull) -> &[$ty] { - &self.0[..] - } - } - - } -} - -macro_rules! display_from_debug { - ($thing:ident) => { - impl ::std::fmt::Display for $thing { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { - ::std::fmt::Debug::fmt(self, f) - } - } - } -} - -#[cfg(test)] -macro_rules! hex_script (($s:expr) => (::blockdata::script::Script::from(::hex::decode($s).unwrap()))); - -#[cfg(test)] -macro_rules! hex_hash (($h:ident, $s:expr) => ($h::from_slice(&::hex::decode($s).unwrap()).unwrap())); - -macro_rules! serde_struct_impl { - ($name:ident, $($fe:ident),*) => ( - #[cfg(feature = "serde")] - impl<'de> $crate::serde::Deserialize<'de> for $name { - fn deserialize(deserializer: D) -> Result<$name, D::Error> - where - D: $crate::serde::de::Deserializer<'de>, - { - use $crate::std::fmt::{self, Formatter}; - use $crate::serde::de::IgnoredAny; - - #[allow(non_camel_case_types)] - enum Enum { Unknown__Field, $($fe),* } - - struct EnumVisitor; - impl<'de> $crate::serde::de::Visitor<'de> for EnumVisitor { - type Value = Enum; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a field name") - } - - fn visit_str(self, v: &str) -> Result - where - E: $crate::serde::de::Error, - { - match v { - $( - stringify!($fe) => Ok(Enum::$fe) - ),*, - _ => Ok(Enum::Unknown__Field) - } - } - } - - impl<'de> $crate::serde::Deserialize<'de> for Enum { - fn deserialize(deserializer: D) -> Result - where - D: ::serde::de::Deserializer<'de>, - { - deserializer.deserialize_str(EnumVisitor) - } - } - - struct Visitor; - - impl<'de> $crate::serde::de::Visitor<'de> for Visitor { - type Value = $name; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a struct") - } - - fn visit_map(self, mut map: A) -> Result - where - A: $crate::serde::de::MapAccess<'de>, - { - use $crate::serde::de::Error; - - $(let mut $fe = None;)* - - loop { - match map.next_key::()? { - Some(Enum::Unknown__Field) => { - map.next_value::()?; - } - $( - Some(Enum::$fe) => { - $fe = Some(map.next_value()?); - } - )* - None => { break; } - } - } - - $( - let $fe = match $fe { - Some(x) => x, - None => return Err(A::Error::missing_field(stringify!($fe))), - }; - )* - - let ret = $name { - $($fe: $fe),* - }; - - Ok(ret) - } - } - // end type defs - - static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; - - deserializer.deserialize_struct(stringify!($name), FIELDS, Visitor) - } - } - - #[cfg(feature = "serde")] - impl<'de> $crate::serde::Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: $crate::serde::Serializer, - { - use $crate::serde::ser::SerializeStruct; - - // Only used to get the struct length. - static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; - - let mut st = serializer.serialize_struct(stringify!($name), FIELDS.len())?; - - $( - st.serialize_field(stringify!($fe), &self.$fe)?; - )* - - st.end() - } - } - ) -} - -macro_rules! serde_string_impl { - ($name:ident, $expecting:expr) => { - #[cfg(feature = "serde")] - impl<'de> $crate::serde::Deserialize<'de> for $name { - fn deserialize(deserializer: D) -> Result<$name, D::Error> - where - D: $crate::serde::de::Deserializer<'de>, - { - use $crate::std::fmt::{self, Formatter}; - use $crate::std::str::FromStr; - - struct Visitor; - impl<'de> $crate::serde::de::Visitor<'de> for Visitor { - type Value = $name; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str($expecting) - } - - fn visit_str(self, v: &str) -> Result - where - E: $crate::serde::de::Error, - { - $name::from_str(v).map_err(E::custom) - } - - fn visit_borrowed_str(self, v: &'de str) -> Result - where - E: $crate::serde::de::Error, - { - self.visit_str(v) - } - - fn visit_string(self, v: String) -> Result - where - E: $crate::serde::de::Error, - { - self.visit_str(&v) - } - } - - deserializer.deserialize_str(Visitor) - } - } - - #[cfg(feature = "serde")] - impl<'de> $crate::serde::Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: $crate::serde::Serializer, - { - serializer.collect_str(&self) - } - } - }; -} - -/// A combination of serde_struct_impl and serde_string_impl where string is -/// used for human-readable serialization and struct is used for -/// non-human-readable serialization. -macro_rules! serde_struct_human_string_impl { - ($name:ident, $expecting:expr, $($fe:ident),*) => ( - #[cfg(feature = "serde")] - impl<'de> $crate::serde::Deserialize<'de> for $name { - fn deserialize(deserializer: D) -> Result<$name, D::Error> - where - D: $crate::serde::de::Deserializer<'de>, - { - if deserializer.is_human_readable() { - use $crate::std::fmt::{self, Formatter}; - use $crate::std::str::FromStr; - - struct Visitor; - impl<'de> $crate::serde::de::Visitor<'de> for Visitor { - type Value = $name; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str($expecting) - } - - fn visit_str(self, v: &str) -> Result - where - E: $crate::serde::de::Error, - { - $name::from_str(v).map_err(E::custom) - } - - fn visit_borrowed_str(self, v: &'de str) -> Result - where - E: $crate::serde::de::Error, - { - self.visit_str(v) - } - - fn visit_string(self, v: String) -> Result - where - E: $crate::serde::de::Error, - { - self.visit_str(&v) - } - } - - deserializer.deserialize_str(Visitor) - } else { - use $crate::std::fmt::{self, Formatter}; - use $crate::serde::de::IgnoredAny; - - #[allow(non_camel_case_types)] - enum Enum { Unknown__Field, $($fe),* } - - struct EnumVisitor; - impl<'de> $crate::serde::de::Visitor<'de> for EnumVisitor { - type Value = Enum; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a field name") - } - - fn visit_str(self, v: &str) -> Result - where - E: $crate::serde::de::Error, - { - match v { - $( - stringify!($fe) => Ok(Enum::$fe) - ),*, - _ => Ok(Enum::Unknown__Field) - } - } - } - - impl<'de> $crate::serde::Deserialize<'de> for Enum { - fn deserialize(deserializer: D) -> Result - where - D: $crate::serde::de::Deserializer<'de>, - { - deserializer.deserialize_str(EnumVisitor) - } - } - - struct Visitor; - - impl<'de> $crate::serde::de::Visitor<'de> for Visitor { - type Value = $name; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("a struct") - } - - fn visit_map(self, mut map: A) -> Result - where - A: $crate::serde::de::MapAccess<'de>, - { - use $crate::serde::de::Error; - - $(let mut $fe = None;)* - - loop { - match map.next_key::()? { - Some(Enum::Unknown__Field) => { - map.next_value::()?; - } - $( - Some(Enum::$fe) => { - $fe = Some(map.next_value()?); - } - )* - None => { break; } - } - } - - $( - let $fe = match $fe { - Some(x) => x, - None => return Err(A::Error::missing_field(stringify!($fe))), - }; - )* - - let ret = $name { - $($fe: $fe),* - }; - - Ok(ret) - } - } - // end type defs - - static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; - - deserializer.deserialize_struct(stringify!($name), FIELDS, Visitor) - } - } - } - - #[cfg(feature = "serde")] - impl<'de> $crate::serde::Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: $crate::serde::Serializer, - { - if serializer.is_human_readable() { - serializer.collect_str(&self) - } else { - use $crate::serde::ser::SerializeStruct; - - // Only used to get the struct length. - static FIELDS: &'static [&'static str] = &[$(stringify!($fe)),*]; - - let mut st = serializer.serialize_struct(stringify!($name), FIELDS.len())?; - - $( - st.serialize_field(stringify!($fe), &self.$fe)?; - )* - - st.end() - } - } - } - ) -} - -/// Implements several traits for byte-based newtypes. -/// Implements: -/// - std::fmt::LowerHex (implies hashes::hex::ToHex) -/// - std::fmt::Display -/// - std::str::FromStr -/// - hashes::hex::FromHex -macro_rules! impl_bytes_newtype { - ($t:ident, $len:expr) => ( - - impl ::std::fmt::LowerHex for $t { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for &ch in self.0.iter() { - write!(f, "{:02x}", ch)?; - } - Ok(()) - } - } - - impl ::std::fmt::Display for $t { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::LowerHex::fmt(self, f) - } - } - - impl ::hashes::hex::FromHex for $t { - fn from_byte_iter(iter: I) -> Result - where I: Iterator> + - ExactSizeIterator + - DoubleEndedIterator, - { - if iter.len() == $len { - let mut ret = [0; $len]; - for (n, byte) in iter.enumerate() { - ret[n] = byte?; - } - Ok($t(ret)) - } else { - Err(::hashes::hex::Error::InvalidLength(2 * $len, 2 * iter.len())) - } - } - } - - impl ::std::str::FromStr for $t { - type Err = ::hashes::hex::Error; - fn from_str(s: &str) -> Result { - hex::FromHex::from_hex(s) - } - } - - #[cfg(feature="serde")] - impl ::serde::Serialize for $t { - fn serialize(&self, s: S) -> Result { - if s.is_human_readable() { - s.serialize_str(&::hashes::hex::ToHex::to_hex(self)) - } else { - s.serialize_bytes(&self[..]) - } - } - } - - #[cfg(feature="serde")] - impl<'de> ::serde::Deserialize<'de> for $t { - fn deserialize>(d: D) -> Result<$t, D::Error> { - if d.is_human_readable() { - struct HexVisitor; - - impl<'de> ::serde::de::Visitor<'de> for HexVisitor { - type Value = $t; - - fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - formatter.write_str("an ASCII hex string") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: ::serde::de::Error, - { - if let Ok(hex) = ::std::str::from_utf8(v) { - ::hashes::hex::FromHex::from_hex(hex).map_err(E::custom) - } else { - return Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)); - } - } - - fn visit_str(self, v: &str) -> Result - where - E: ::serde::de::Error, - { - ::hashes::hex::FromHex::from_hex(v).map_err(E::custom) - } - } - - d.deserialize_str(HexVisitor) - } else { - struct BytesVisitor; - - impl<'de> ::serde::de::Visitor<'de> for BytesVisitor { - type Value = $t; - - fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - formatter.write_str("a bytestring") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: ::serde::de::Error, - { - if v.len() != $len { - Err(E::invalid_length(v.len(), &stringify!($len))) - } else { - let mut ret = [0; $len]; - ret.copy_from_slice(v); - Ok($t(ret)) - } - } - } - - d.deserialize_bytes(BytesVisitor) - } - } - } - ) -} - -macro_rules! user_enum { - ( - $(#[$attr:meta])* - pub enum $name:ident { - $(#[$doc:meta] - $elem:ident <-> $txt:expr),* - } - ) => ( - $(#[$attr])* - pub enum $name { - $(#[$doc] $elem),* - } - - impl ::std::fmt::Debug for $name { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - f.pad(match *self { - $($name::$elem => $txt),* - }) - } - } - - impl ::std::fmt::Display for $name { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - f.pad(match *self { - $($name::$elem => $txt),* - }) - } - } - - impl ::std::str::FromStr for $name { - type Err = ::std::io::Error; - #[inline] - fn from_str(s: &str) -> Result { - match s { - $($txt => Ok($name::$elem)),*, - _ => Err(::std::io::Error::new( - ::std::io::ErrorKind::InvalidInput, - format!("Unknown network (type {})", s), - )), - } - } - } - - #[cfg(feature = "serde")] - impl<'de> $crate::serde::Deserialize<'de> for $name { - #[inline] - fn deserialize(deserializer: D) -> Result - where - D: $crate::serde::Deserializer<'de>, - { - use $crate::std::fmt::{self, Formatter}; - - struct Visitor; - impl<'de> $crate::serde::de::Visitor<'de> for Visitor { - type Value = $name; - - fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { - formatter.write_str("an enum value") - } - - fn visit_str(self, v: &str) -> Result - where - E: $crate::serde::de::Error, - { - static FIELDS: &'static [&'static str] = &[$(stringify!($txt)),*]; - - $( if v == $txt { Ok($name::$elem) } )else* - else { - Err(E::unknown_variant(v, FIELDS)) - } - } - - fn visit_borrowed_str(self, v: &'de str) -> Result - where - E: $crate::serde::de::Error, - { - self.visit_str(v) - } - - fn visit_string(self, v: String) -> Result - where - E: $crate::serde::de::Error, - { - self.visit_str(&v) - } - - } - - deserializer.deserialize_str(Visitor) - } - } - - #[cfg(feature = "serde")] - impl ::serde::Serialize for $name { - fn serialize(&self, serializer: S) -> Result - where - S: ::serde::Serializer, - { - serializer.collect_str(&self) - } - } - ); -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 6ba26f92..00000000 --- a/src/lib.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! # Rust Bitcoin Library -//! -//! This is a library for which supports the Bitcoin network protocol and associated -//! primitives. It is designed for Rust programs built to work with the Bitcoin -//! network. -//! -//! It is also written entirely in Rust to illustrate the benefits of strong type -//! safety, including ownership and lifetime, for financial and/or cryptographic -//! software. -//! - -#![crate_name = "bitcoin"] -#![crate_type = "dylib"] -#![crate_type = "rlib"] - -// Experimental features we need -#![cfg_attr(all(test, feature = "unstable"), feature(test))] - -// Clippy whitelist -#![cfg_attr(feature = "clippy", allow(needless_range_loop))] // suggests making a big mess of array newtypes -#![cfg_attr(feature = "clippy", allow(extend_from_slice))] // `extend_from_slice` only available since 1.6 - -// Coding conventions -#![forbid(unsafe_code)] -#![deny(non_upper_case_globals)] -#![deny(non_camel_case_types)] -#![deny(non_snake_case)] -#![deny(unused_mut)] -#![deny(dead_code)] -#![deny(unused_imports)] -#![deny(missing_docs)] -#![forbid(unsafe_code)] - -// In general, rust is absolutely horrid at supporting users doing things like, -// for example, compiling Rust code for real environments. Disable useless lints -// that don't do anything but annoy us and cant actually ever be resolved. -#![allow(bare_trait_objects)] -#![allow(ellipsis_inclusive_range_patterns)] - -// Re-exported dependencies. -#[macro_use] pub extern crate bitcoin_hashes as hashes; -pub extern crate secp256k1; -pub extern crate bech32; - -#[cfg(any(test, feature = "serde"))] extern crate hex; -#[cfg(feature = "serde")] extern crate serde; -#[cfg(all(test, feature = "serde"))] #[macro_use] extern crate serde_derive; // for 1.22.0 compat -#[cfg(all(test, feature = "serde"))] extern crate serde_json; -#[cfg(all(test, feature = "serde"))] extern crate serde_test; -#[cfg(all(test, feature = "unstable"))] extern crate test; -#[cfg(feature="bitcoinconsensus")] extern crate bitcoinconsensus; - -#[cfg(target_pointer_width = "16")] -compile_error!("rust-bitcoin cannot be used on 16-bit architectures"); - -#[cfg(test)] -#[macro_use] -mod test_macros; -#[macro_use] -mod internal_macros; -#[macro_use] -pub mod network; -pub mod blockdata; -pub mod util; -pub mod consensus; -// Do not remove: required in order to get hash types implementation macros to work correctly -#[allow(unused_imports)] -pub mod hash_types; - -pub use hash_types::*; -pub use blockdata::block::Block; -pub use blockdata::block::BlockHeader; -pub use blockdata::script::Script; -pub use blockdata::transaction::Transaction; -pub use blockdata::transaction::TxIn; -pub use blockdata::transaction::TxOut; -pub use blockdata::transaction::OutPoint; -pub use blockdata::transaction::SigHashType; -pub use consensus::encode::VarInt; -pub use network::constants::Network; -pub use util::Error; -pub use util::address::Address; -pub use util::address::AddressType; -pub use util::amount::Amount; -pub use util::amount::SignedAmount; -pub use util::hash::BitcoinHash; -pub use util::key::PrivateKey; -pub use util::key::PublicKey; -pub use util::merkleblock::MerkleBlock; diff --git a/src/network/address.rs b/src/network/address.rs deleted file mode 100644 index f9dcbf0b..00000000 --- a/src/network/address.rs +++ /dev/null @@ -1,195 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Bitcoin network addresses -//! -//! This module defines the structures and functions needed to encode -//! network addresses in Bitcoin messages. -//! - -use std::io; -use std::fmt; -use std::net::{SocketAddr, Ipv6Addr, SocketAddrV4, SocketAddrV6}; - -use network::constants::ServiceFlags; -use consensus::encode::{self, Decodable, Encodable}; - -/// A message which can be sent on the Bitcoin network -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct Address { - /// Services provided by the peer whose address this is - pub services: ServiceFlags, - /// Network byte-order ipv6 address, or ipv4-mapped ipv6 address - pub address: [u16; 8], - /// Network port - pub port: u16 -} - -const ONION : [u16; 3] = [0xFD87, 0xD87E, 0xEB43]; - -impl Address { - /// Create an address message for a socket - pub fn new (socket :&SocketAddr, services: ServiceFlags) -> Address { - let (address, port) = match socket { - &SocketAddr::V4(ref addr) => (addr.ip().to_ipv6_mapped().segments(), addr.port()), - &SocketAddr::V6(ref addr) => (addr.ip().segments(), addr.port()) - }; - Address { address: address, port: port, services: services } - } - - /// extract socket address from an address message - /// This will return io::Error ErrorKind::AddrNotAvailable if the message contains a Tor address. - pub fn socket_addr (&self) -> Result { - let addr = &self.address; - if addr[0..3] == ONION { - return Err(io::Error::from(io::ErrorKind::AddrNotAvailable)); - } - let ipv6 = Ipv6Addr::new( - addr[0],addr[1],addr[2],addr[3], - addr[4],addr[5],addr[6],addr[7] - ); - if let Some(ipv4) = ipv6.to_ipv4() { - Ok(SocketAddr::V4(SocketAddrV4::new(ipv4, self.port))) - } - else { - Ok(SocketAddr::V6(SocketAddrV6::new(ipv6, self.port, 0, 0))) - } - } -} - -fn addr_to_be(addr: [u16; 8]) -> [u16; 8] { - [addr[0].to_be(), addr[1].to_be(), addr[2].to_be(), addr[3].to_be(), - addr[4].to_be(), addr[5].to_be(), addr[6].to_be(), addr[7].to_be()] -} - -impl Encodable for Address { - #[inline] - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let len = self.services.consensus_encode(&mut s)? - + addr_to_be(self.address).consensus_encode(&mut s)? - + self.port.to_be().consensus_encode(s)?; - Ok(len) - } -} - -impl Decodable for Address { - #[inline] - fn consensus_decode(mut d: D) -> Result { - Ok(Address { - services: Decodable::consensus_decode(&mut d)?, - address: addr_to_be(Decodable::consensus_decode(&mut d)?), - port: u16::from_be(Decodable::consensus_decode(d)?) - }) - } -} - -impl fmt::Debug for Address { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let ipv6 = Ipv6Addr::from(self.address); - - match ipv6.to_ipv4() { - Some(addr) => write!(f, "Address {{services: {}, address: {}, port: {}}}", - self.services, addr, self.port), - None => write!(f, "Address {{services: {}, address: {}, port: {}}}", - self.services, ipv6, self.port) - } - } -} - -#[cfg(test)] -mod test { - use std::str::FromStr; - use super::Address; - use network::constants::ServiceFlags; - use std::net::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; - - use consensus::encode::{deserialize, serialize}; - - #[test] - fn serialize_address_test() { - assert_eq!(serialize(&Address { - services: ServiceFlags::NETWORK, - address: [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001], - port: 8333 - }), - vec![1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1, 0x20, 0x8d]); - } - - #[test] - fn debug_format_test() { - assert_eq!( - format!("The address is: {:?}", Address { - services: ServiceFlags::NETWORK.add(ServiceFlags::WITNESS), - address: [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001], - port: 8333 - }), - "The address is: Address {services: ServiceFlags(NETWORK|WITNESS), address: 10.0.0.1, port: 8333}" - ); - - assert_eq!( - format!("The address is: {:?}", Address { - services: ServiceFlags::NETWORK_LIMITED, - address: [0xFD87, 0xD87E, 0xEB43, 0, 0, 0xffff, 0x0a00, 0x0001], - port: 8333 - }), - "The address is: Address {services: ServiceFlags(NETWORK_LIMITED), address: fd87:d87e:eb43::ffff:a00:1, port: 8333}" - ); - } - - #[test] - fn deserialize_address_test() { - let mut addr: Result = deserialize(&[1u8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, - 0, 1, 0x20, 0x8d]); - assert!(addr.is_ok()); - let full = addr.unwrap(); - assert!(match full.socket_addr().unwrap() { - SocketAddr::V4(_) => true, - _ => false - } - ); - assert_eq!(full.services, ServiceFlags::NETWORK); - assert_eq!(full.address, [0, 0, 0, 0, 0, 0xffff, 0x0a00, 0x0001]); - assert_eq!(full.port, 8333); - - addr = deserialize(&[1u8, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x0a, 0, 0, 1]); - assert!(addr.is_err()); - } - - #[test] - fn test_socket_addr () { - let s4 = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(111,222,123,4)), 5555); - let a4 = Address::new(&s4, ServiceFlags::NETWORK | ServiceFlags::WITNESS); - assert_eq!(a4.socket_addr().unwrap(), s4); - let s6 = SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, - 0x5555, 0x6666, 0x7777, 0x8888)), 9999); - let a6 = Address::new(&s6, ServiceFlags::NETWORK | ServiceFlags::WITNESS); - assert_eq!(a6.socket_addr().unwrap(), s6); - } - - #[test] - fn onion_test () { - let onionaddr = SocketAddr::new( - IpAddr::V6( - Ipv6Addr::from_str("FD87:D87E:EB43:edb1:8e4:3588:e546:35ca").unwrap()), 1111); - let addr = Address::new(&onionaddr, ServiceFlags::NONE); - assert!(addr.socket_addr().is_err()); - } -} - diff --git a/src/network/constants.rs b/src/network/constants.rs deleted file mode 100644 index 8724398a..00000000 --- a/src/network/constants.rs +++ /dev/null @@ -1,360 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Network constants -//! -//! This module provides various constants relating to the Bitcoin network -//! protocol, such as protocol versioning and magic header bytes. -//! -//! The [`Network`][1] type implements the [`Decodable`][2] and -//! [`Encodable`][3] traits and encodes the magic bytes of the given -//! network -//! -//! [1]: enum.Network.html -//! [2]: ../../consensus/encode/trait.Decodable.html -//! [3]: ../../consensus/encode/trait.Encodable.html -//! -//! # Example: encoding a network's magic bytes -//! -//! ```rust -//! use bitcoin::network::constants::Network; -//! use bitcoin::consensus::encode::serialize; -//! -//! let network = Network::Bitcoin; -//! let bytes = serialize(&network.magic()); -//! -//! assert_eq!(&bytes[..], &[0xF9, 0xBE, 0xB4, 0xD9]); -//! ``` - -use std::{fmt, io, ops}; - -use consensus::encode::{self, Encodable, Decodable}; - -/// Version of the protocol as appearing in network message headers -pub const PROTOCOL_VERSION: u32 = 70001; - -user_enum! { - /// The cryptocurrency to act on - #[derive(Copy, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] - pub enum Network { - /// Classic Bitcoin - Bitcoin <-> "bitcoin", - /// Bitcoin's testnet - Testnet <-> "testnet", - /// Bitcoin's regtest - Regtest <-> "regtest" - } -} - -impl Network { - /// Creates a `Network` from the magic bytes. - /// - /// # Examples - /// - /// ```rust - /// use bitcoin::network::constants::Network; - /// - /// assert_eq!(Some(Network::Bitcoin), Network::from_magic(0xD9B4BEF9)); - /// assert_eq!(None, Network::from_magic(0xFFFFFFFF)); - /// ``` - pub fn from_magic(magic: u32) -> Option { - // Note: any new entries here must be added to `magic` below - match magic { - 0xD9B4BEF9 => Some(Network::Bitcoin), - 0x0709110B => Some(Network::Testnet), - 0xDAB5BFFA => Some(Network::Regtest), - _ => None - } - } - - /// Return the network magic bytes, which should be encoded little-endian - /// at the start of every message - /// - /// # Examples - /// - /// ```rust - /// use bitcoin::network::constants::Network; - /// - /// let network = Network::Bitcoin; - /// assert_eq!(network.magic(), 0xD9B4BEF9); - /// ``` - pub fn magic(&self) -> u32 { - // Note: any new entries here must be added to `from_magic` above - match *self { - Network::Bitcoin => 0xD9B4BEF9, - Network::Testnet => 0x0709110B, - Network::Regtest => 0xDAB5BFFA, - } - } -} - -/// Flags to indicate which network services a node supports. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ServiceFlags(u64); - -impl ServiceFlags { - /// NONE means no services supported. - pub const NONE: ServiceFlags = ServiceFlags(0); - - /// NETWORK means that the node is capable of serving the complete block chain. It is currently - /// set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light - /// clients. - pub const NETWORK: ServiceFlags = ServiceFlags(1 << 0); - - /// GETUTXO means the node is capable of responding to the getutxo protocol request. Bitcoin - /// Core does not support this but a patch set called Bitcoin XT does. - /// See BIP 64 for details on how this is implemented. - pub const GETUTXO: ServiceFlags = ServiceFlags(1 << 1); - - /// BLOOM means the node is capable and willing to handle bloom-filtered connections. Bitcoin - /// Core nodes used to support this by default, without advertising this bit, but no longer do - /// as of protocol version 70011 (= NO_BLOOM_VERSION) - pub const BLOOM: ServiceFlags = ServiceFlags(1 << 2); - - /// WITNESS indicates that a node can be asked for blocks and transactions including witness - /// data. - pub const WITNESS: ServiceFlags = ServiceFlags(1 << 3); - - /// COMPACT_FILTERS means the node will service basic block filter requests. - /// See BIP157 and BIP158 for details on how this is implemented. - pub const COMPACT_FILTERS: ServiceFlags = ServiceFlags(1 << 6); - - /// NETWORK_LIMITED means the same as NODE_NETWORK with the limitation of only serving the last - /// 288 (2 day) blocks. - /// See BIP159 for details on how this is implemented. - pub const NETWORK_LIMITED: ServiceFlags = ServiceFlags(1 << 10); - - // NOTE: When adding new flags, remember to update the Display impl accordingly. - - /// Add [ServiceFlags] together. - /// - /// Returns itself. - pub fn add(&mut self, other: ServiceFlags) -> ServiceFlags { - self.0 |= other.0; - *self - } - - /// Remove [ServiceFlags] from this. - /// - /// Returns itself. - pub fn remove(&mut self, other: ServiceFlags) -> ServiceFlags { - self.0 ^= other.0; - *self - } - - /// Check whether [ServiceFlags] are included in this one. - pub fn has(&self, flags: ServiceFlags) -> bool { - (self.0 | flags.0) == self.0 - } - - /// Get the integer representation of this [ServiceFlags]. - pub fn as_u64(&self) -> u64 { - self.0 - } -} - -impl fmt::LowerHex for ServiceFlags { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::LowerHex::fmt(&self.0, f) - } -} - -impl fmt::UpperHex for ServiceFlags { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::UpperHex::fmt(&self.0, f) - } -} - -impl fmt::Display for ServiceFlags { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if *self == ServiceFlags::NONE { - return write!(f, "ServiceFlags(NONE)"); - } - - let mut flags = self.clone(); - let mut first = true; - macro_rules! write_flag { - ($f:ident) => { - if flags.has(ServiceFlags::$f) { - if !first { - write!(f, "|")?; - } - first = false; - write!(f, stringify!($f))?; - flags.remove(ServiceFlags::$f); - } - } - } - write!(f, "ServiceFlags(")?; - write_flag!(NETWORK); - write_flag!(GETUTXO); - write_flag!(BLOOM); - write_flag!(WITNESS); - write_flag!(COMPACT_FILTERS); - write_flag!(NETWORK_LIMITED); - // If there are unknown flags left, we append them in hex. - if flags != ServiceFlags::NONE { - if !first { - write!(f, "|")?; - } - write!(f, "0x{:x}", flags)?; - } - write!(f, ")") - } -} - -impl From for ServiceFlags { - fn from(f: u64) -> Self { - ServiceFlags(f) - } -} - -impl Into for ServiceFlags { - fn into(self) -> u64 { - self.0 - } -} - -impl ops::BitOr for ServiceFlags { - type Output = Self; - - fn bitor(mut self, rhs: Self) -> Self { - self.add(rhs) - } -} - -impl ops::BitOrAssign for ServiceFlags { - fn bitor_assign(&mut self, rhs: Self) { - self.add(rhs); - } -} - -impl ops::BitXor for ServiceFlags { - type Output = Self; - - fn bitxor(mut self, rhs: Self) -> Self { - self.remove(rhs) - } -} - -impl ops::BitXorAssign for ServiceFlags { - fn bitxor_assign(&mut self, rhs: Self) { - self.remove(rhs); - } -} - -impl Encodable for ServiceFlags { - #[inline] - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - self.0.consensus_encode(&mut s) - } -} - -impl Decodable for ServiceFlags { - #[inline] - fn consensus_decode(mut d: D) -> Result { - Ok(ServiceFlags(Decodable::consensus_decode(&mut d)?)) - } -} - -#[cfg(test)] -mod tests { - use super::{Network, ServiceFlags}; - use consensus::encode::{deserialize, serialize}; - - #[test] - fn serialize_test() { - assert_eq!( - serialize(&Network::Bitcoin.magic()), - &[0xf9, 0xbe, 0xb4, 0xd9] - ); - assert_eq!( - serialize(&Network::Testnet.magic()), - &[0x0b, 0x11, 0x09, 0x07] - ); - assert_eq!( - serialize(&Network::Regtest.magic()), - &[0xfa, 0xbf, 0xb5, 0xda] - ); - - assert_eq!( - deserialize(&[0xf9, 0xbe, 0xb4, 0xd9]).ok(), - Some(Network::Bitcoin.magic()) - ); - assert_eq!( - deserialize(&[0x0b, 0x11, 0x09, 0x07]).ok(), - Some(Network::Testnet.magic()) - ); - assert_eq!( - deserialize(&[0xfa, 0xbf, 0xb5, 0xda]).ok(), - Some(Network::Regtest.magic()) - ); - } - - #[test] - fn string_test() { - assert_eq!(Network::Bitcoin.to_string(), "bitcoin"); - assert_eq!(Network::Testnet.to_string(), "testnet"); - assert_eq!(Network::Regtest.to_string(), "regtest"); - - assert_eq!("bitcoin".parse::().unwrap(), Network::Bitcoin); - assert_eq!("testnet".parse::().unwrap(), Network::Testnet); - assert_eq!("regtest".parse::().unwrap(), Network::Regtest); - assert!("fakenet".parse::().is_err()); - } - - #[test] - fn service_flags_test() { - let all = [ - ServiceFlags::NETWORK, - ServiceFlags::GETUTXO, - ServiceFlags::BLOOM, - ServiceFlags::WITNESS, - ServiceFlags::COMPACT_FILTERS, - ServiceFlags::NETWORK_LIMITED, - ]; - - let mut flags = ServiceFlags::NONE; - for f in all.iter() { - assert!(!flags.has(*f)); - } - - flags |= ServiceFlags::WITNESS; - assert_eq!(flags, ServiceFlags::WITNESS); - - let mut flags2 = flags | ServiceFlags::GETUTXO; - for f in all.iter() { - assert_eq!(flags2.has(*f), *f == ServiceFlags::WITNESS || *f == ServiceFlags::GETUTXO); - } - - flags2 ^= ServiceFlags::WITNESS; - assert_eq!(flags2, ServiceFlags::GETUTXO); - - flags2 |= ServiceFlags::COMPACT_FILTERS; - flags2 ^= ServiceFlags::GETUTXO; - assert_eq!(flags2, ServiceFlags::COMPACT_FILTERS); - - // Test formatting. - assert_eq!("ServiceFlags(NONE)", ServiceFlags::NONE.to_string()); - assert_eq!("ServiceFlags(WITNESS)", ServiceFlags::WITNESS.to_string()); - let flag = ServiceFlags::WITNESS | ServiceFlags::BLOOM | ServiceFlags::NETWORK; - assert_eq!("ServiceFlags(NETWORK|BLOOM|WITNESS)", flag.to_string()); - let flag = ServiceFlags::WITNESS | 0xf0.into(); - assert_eq!("ServiceFlags(WITNESS|COMPACT_FILTERS|0xb0)", flag.to_string()); - } -} - diff --git a/src/network/message.rs b/src/network/message.rs deleted file mode 100644 index 82c74060..00000000 --- a/src/network/message.rs +++ /dev/null @@ -1,535 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Network message -//! -//! This module defines the `Message` traits which are used -//! for (de)serializing Bitcoin objects for transmission on the network. It -//! also defines (de)serialization routines for many primitives. -//! - -use std::{io, iter, mem, fmt}; -use std::borrow::Cow; -use std::io::Cursor; - -use blockdata::block; -use blockdata::transaction; -use network::address::Address; -use network::message_network; -use network::message_blockdata; -use network::message_filter; -use consensus::encode::{CheckedData, Decodable, Encodable, VarInt}; -use consensus::{encode, serialize}; -use consensus::encode::MAX_VEC_SIZE; - -/// Serializer for command string -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct CommandString(Cow<'static, str>); - -impl fmt::Display for CommandString { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.0.as_ref()) - } -} - -impl From<&'static str> for CommandString { - fn from(f: &'static str) -> Self { - CommandString(f.into()) - } -} - -impl From for CommandString { - fn from(f: String) -> Self { - CommandString(f.into()) - } -} - -impl AsRef for CommandString { - fn as_ref(&self) -> &str { - self.0.as_ref() - } -} - -impl Encodable for CommandString { - #[inline] - fn consensus_encode( - &self, - s: S, - ) -> Result { - let mut rawbytes = [0u8; 12]; - let strbytes = self.0.as_bytes(); - if strbytes.len() > 12 { - return Err(encode::Error::UnrecognizedNetworkCommand(self.0.clone().into_owned())); - } - for x in 0..strbytes.len() { - rawbytes[x] = strbytes[x]; - } - rawbytes.consensus_encode(s) - } -} - -impl Decodable for CommandString { - #[inline] - fn consensus_decode(d: D) -> Result { - let rawbytes: [u8; 12] = Decodable::consensus_decode(d)?; - let rv = iter::FromIterator::from_iter( - rawbytes - .iter() - .filter_map(|&u| if u > 0 { Some(u as char) } else { None }) - ); - Ok(CommandString(rv)) - } -} - -#[derive(Debug, PartialEq, Eq)] -/// A Network message -pub struct RawNetworkMessage { - /// Magic bytes to identify the network these messages are meant for - pub magic: u32, - /// The actual message data - pub payload: NetworkMessage -} - -#[derive(Clone, PartialEq, Eq, Debug)] -/// A Network message payload. Proper documentation is available on at -/// [Bitcoin Wiki: Protocol Specification](https://en.bitcoin.it/wiki/Protocol_specification) -pub enum NetworkMessage { - /// `version` - Version(message_network::VersionMessage), - /// `verack` - Verack, - /// `addr` - Addr(Vec<(u32, Address)>), - /// `inv` - Inv(Vec), - /// `getdata` - GetData(Vec), - /// `notfound` - NotFound(Vec), - /// `getblocks` - GetBlocks(message_blockdata::GetBlocksMessage), - /// `getheaders` - GetHeaders(message_blockdata::GetHeadersMessage), - /// `mempool` - MemPool, - /// tx - Tx(transaction::Transaction), - /// `block` - Block(block::Block), - /// `headers` - Headers(Vec), - /// `sendheaders` - SendHeaders, - /// `getaddr` - GetAddr, - // TODO: checkorder, - // TODO: submitorder, - // TODO: reply, - /// `ping` - Ping(u64), - /// `pong` - Pong(u64), - // TODO: bloom filtering - /// BIP157 getcfilters - GetCFilters(message_filter::GetCFilters), - /// BIP157 cfilter - CFilter(message_filter::CFilter), - /// BIP157 getcfheaders - GetCFHeaders(message_filter::GetCFHeaders), - /// BIP157 cfheaders - CFHeaders(message_filter::CFHeaders), - /// BIP157 getcfcheckpt - GetCFCheckpt(message_filter::GetCFCheckpt), - /// BIP157 cfcheckpt - CFCheckpt(message_filter::CFCheckpt), - /// `alert` - Alert(Vec), - /// `reject` - Reject(message_network::Reject) -} - -impl NetworkMessage { - /// Return the message command. This is useful for debug outputs. - pub fn cmd(&self) -> &'static str { - match *self { - NetworkMessage::Version(_) => "version", - NetworkMessage::Verack => "verack", - NetworkMessage::Addr(_) => "addr", - NetworkMessage::Inv(_) => "inv", - NetworkMessage::GetData(_) => "getdata", - NetworkMessage::NotFound(_) => "notfound", - NetworkMessage::GetBlocks(_) => "getblocks", - NetworkMessage::GetHeaders(_) => "getheaders", - NetworkMessage::MemPool => "mempool", - NetworkMessage::Tx(_) => "tx", - NetworkMessage::Block(_) => "block", - NetworkMessage::Headers(_) => "headers", - NetworkMessage::SendHeaders => "sendheaders", - NetworkMessage::GetAddr => "getaddr", - NetworkMessage::Ping(_) => "ping", - NetworkMessage::Pong(_) => "pong", - NetworkMessage::GetCFilters(_) => "getcfilters", - NetworkMessage::CFilter(_) => "cfilter", - NetworkMessage::GetCFHeaders(_) => "getcfheaders", - NetworkMessage::CFHeaders(_) => "cfheaders", - NetworkMessage::GetCFCheckpt(_) => "getcfcheckpt", - NetworkMessage::CFCheckpt(_) => "cfcheckpt", - NetworkMessage::Alert(_) => "alert", - NetworkMessage::Reject(_) => "reject", - } - } - - /// Return the CommandString for the message command. - pub fn command(&self) -> CommandString { - self.cmd().into() - } -} - -impl RawNetworkMessage { - /// Return the message command. This is useful for debug outputs. - pub fn cmd(&self) -> &'static str { - self.payload.cmd() - } - - /// Return the CommandString for the message command. - pub fn command(&self) -> CommandString { - self.payload.command() - } -} - -struct HeaderSerializationWrapper<'a>(&'a Vec); - -impl<'a> Encodable for HeaderSerializationWrapper<'a> { - #[inline] - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let mut len = 0; - len += VarInt(self.0.len() as u64).consensus_encode(&mut s)?; - for header in self.0.iter() { - len += header.consensus_encode(&mut s)?; - len += 0u8.consensus_encode(&mut s)?; - } - Ok(len) - } -} - -impl Encodable for RawNetworkMessage { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let mut len = 0; - len += self.magic.consensus_encode(&mut s)?; - len += self.command().consensus_encode(&mut s)?; - len += CheckedData(match self.payload { - NetworkMessage::Version(ref dat) => serialize(dat), - NetworkMessage::Addr(ref dat) => serialize(dat), - NetworkMessage::Inv(ref dat) => serialize(dat), - NetworkMessage::GetData(ref dat) => serialize(dat), - NetworkMessage::NotFound(ref dat) => serialize(dat), - NetworkMessage::GetBlocks(ref dat) => serialize(dat), - NetworkMessage::GetHeaders(ref dat) => serialize(dat), - NetworkMessage::Tx(ref dat) => serialize(dat), - NetworkMessage::Block(ref dat) => serialize(dat), - NetworkMessage::Headers(ref dat) => serialize(&HeaderSerializationWrapper(dat)), - NetworkMessage::Ping(ref dat) => serialize(dat), - NetworkMessage::Pong(ref dat) => serialize(dat), - NetworkMessage::GetCFilters(ref dat) => serialize(dat), - NetworkMessage::CFilter(ref dat) => serialize(dat), - NetworkMessage::GetCFHeaders(ref dat) => serialize(dat), - NetworkMessage::CFHeaders(ref dat) => serialize(dat), - NetworkMessage::GetCFCheckpt(ref dat) => serialize(dat), - NetworkMessage::CFCheckpt(ref dat) => serialize(dat), - NetworkMessage::Alert(ref dat) => serialize(dat), - NetworkMessage::Reject(ref dat) => serialize(dat), - NetworkMessage::Verack - | NetworkMessage::SendHeaders - | NetworkMessage::MemPool - | NetworkMessage::GetAddr => vec![], - }).consensus_encode(&mut s)?; - Ok(len) - } -} - -struct HeaderDeserializationWrapper(Vec); - -impl Decodable for HeaderDeserializationWrapper { - #[inline] - fn consensus_decode(mut d: D) -> Result { - let len = VarInt::consensus_decode(&mut d)?.0; - let byte_size = (len as usize) - .checked_mul(mem::size_of::()) - .ok_or(encode::Error::ParseFailed("Invalid length"))?; - if byte_size > MAX_VEC_SIZE { - return Err(encode::Error::OversizedVectorAllocation { requested: byte_size, max: MAX_VEC_SIZE }) - } - let mut ret = Vec::with_capacity(len as usize); - for _ in 0..len { - ret.push(Decodable::consensus_decode(&mut d)?); - if u8::consensus_decode(&mut d)? != 0u8 { - return Err(encode::Error::ParseFailed("Headers message should not contain transactions")); - } - } - Ok(HeaderDeserializationWrapper(ret)) - } -} - -impl Decodable for RawNetworkMessage { - fn consensus_decode(mut d: D) -> Result { - let magic = Decodable::consensus_decode(&mut d)?; - let cmd = CommandString::consensus_decode(&mut d)?.0; - let raw_payload = CheckedData::consensus_decode(&mut d)?.0; - - let mut mem_d = Cursor::new(raw_payload); - let payload = match &cmd[..] { - "version" => NetworkMessage::Version(Decodable::consensus_decode(&mut mem_d)?), - "verack" => NetworkMessage::Verack, - "addr" => NetworkMessage::Addr(Decodable::consensus_decode(&mut mem_d)?), - "inv" => NetworkMessage::Inv(Decodable::consensus_decode(&mut mem_d)?), - "getdata" => NetworkMessage::GetData(Decodable::consensus_decode(&mut mem_d)?), - "notfound" => NetworkMessage::NotFound(Decodable::consensus_decode(&mut mem_d)?), - "getblocks" => NetworkMessage::GetBlocks(Decodable::consensus_decode(&mut mem_d)?), - "getheaders" => NetworkMessage::GetHeaders(Decodable::consensus_decode(&mut mem_d)?), - "mempool" => NetworkMessage::MemPool, - "block" => NetworkMessage::Block(Decodable::consensus_decode(&mut mem_d)?), - "headers" => NetworkMessage::Headers( - HeaderDeserializationWrapper::consensus_decode(&mut mem_d)?.0 - ), - "sendheaders" => NetworkMessage::SendHeaders, - "getaddr" => NetworkMessage::GetAddr, - "ping" => NetworkMessage::Ping(Decodable::consensus_decode(&mut mem_d)?), - "pong" => NetworkMessage::Pong(Decodable::consensus_decode(&mut mem_d)?), - "tx" => NetworkMessage::Tx(Decodable::consensus_decode(&mut mem_d)?), - "getcfilters" => NetworkMessage::GetCFilters(Decodable::consensus_decode(&mut mem_d)?), - "cfilter" => NetworkMessage::CFilter(Decodable::consensus_decode(&mut mem_d)?), - "getcfheaders" => NetworkMessage::GetCFHeaders(Decodable::consensus_decode(&mut mem_d)?), - "cfheaders" => NetworkMessage::CFHeaders(Decodable::consensus_decode(&mut mem_d)?), - "getcfcheckpt" => NetworkMessage::GetCFCheckpt(Decodable::consensus_decode(&mut mem_d)?), - "cfcheckpt" => NetworkMessage::CFCheckpt(Decodable::consensus_decode(&mut mem_d)?), - "reject" => NetworkMessage::Reject(Decodable::consensus_decode(&mut mem_d)?), - "alert" => NetworkMessage::Alert(Decodable::consensus_decode(&mut mem_d)?), - _ => return Err(encode::Error::UnrecognizedNetworkCommand(cmd.into_owned())), - }; - Ok(RawNetworkMessage { - magic: magic, - payload: payload - }) - } -} - -#[cfg(test)] -mod test { - use std::io; - use super::{RawNetworkMessage, NetworkMessage, CommandString}; - use network::constants::ServiceFlags; - use consensus::encode::{Encodable, deserialize, deserialize_partial, serialize}; - use hex::decode as hex_decode; - use hashes::sha256d::Hash; - use hashes::Hash as HashTrait; - use network::address::Address; - use super::message_network::{Reject, RejectReason, VersionMessage}; - use network::message_blockdata::{Inventory, GetBlocksMessage, GetHeadersMessage}; - use blockdata::block::{Block, BlockHeader}; - use network::message_filter::{GetCFilters, CFilter, GetCFHeaders, CFHeaders, GetCFCheckpt, CFCheckpt}; - use blockdata::transaction::Transaction; - - fn hash(slice: [u8;32]) -> Hash { - Hash::from_slice(&slice).unwrap() - } - - #[test] - fn full_round_ser_der_raw_network_message_test() { - // TODO: Impl Rand traits here to easily generate random values. - let version_msg: VersionMessage = deserialize(&hex_decode("721101000100000000000000e6e0845300000000010000000000000000000000000000000000ffff0000000000000100000000000000fd87d87eeb4364f22cf54dca59412db7208d47d920cffce83ee8102f5361746f7368693a302e392e39392f2c9f040001").unwrap()).unwrap(); - let tx: Transaction = deserialize(&hex_decode("0100000001a15d57094aa7a21a28cb20b59aab8fc7d1149a3bdbcddba9c622e4f5f6a99ece010000006c493046022100f93bb0e7d8db7bd46e40132d1f8242026e045f03a0efe71bbb8e3f475e970d790221009337cd7f1f929f00cc6ff01f03729b069a7c21b59b1736ddfee5db5946c5da8c0121033b9b137ee87d5a812d6f506efdd37f0affa7ffc310711c06c7f3e097c9447c52ffffffff0100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000").unwrap()).unwrap(); - let block: Block = deserialize(&hex_decode("000000202aa2f2ca794ccbd40c16e2f3333f6b8b683f9e7179b2c4d7490600000000000010bc26e70a2f672ad420a6153dd0c28b40a6002c55531bfc99bf8994a8e8f67e5503bd5750d4061a4ed90a700f010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff3603da1b0e00045503bd5704c7dd8a0d0ced13bb5785010800000000000a636b706f6f6c122f4e696e6a61506f6f6c2f5345475749542fffffffff02b4e5a212000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9edf91c46b49eb8a29089980f02ee6b57e7d63d33b18b4fddac2bcd7db2a3983704012000000000000000000000000000000000000000000000000000000000000000000000000001000000017e4f81175332a733e26d4ba4e29f53f67b7a5d7c2adebb276e447ca71d130b55000000006b483045022100cac809cd1a3d9ad5d5e31a84e2e1d8ec5542841e4d14c6b52e8b38cbe1ff1728022064470b7fb0c2efeccb2e84bfa36ec5f9e434c84b1101c00f7ee32f726371b7410121020e62280798b6b8c37f068df0915b0865b63fabc401c2457cbc3ef96887dd3647ffffffff02ca2f780c000000001976a914c6b5545b3592cb477d709896fa705592c9b6113a88ac663b2a06000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac0000000001000000011e99f5a785e677e017d36b50aa4fd10010ffd039f38f42f447ca8895250e121f01000000d90047304402200d3d296ad641a281dd5c0d68b9ab0d1ad5f7052bec148c1fb81fb1ba69181ec502201a372bb16fb8e054ee9bef41e300d292153830f841a4db0ab7f7407f6581b9bc01473044022002584f313ae990236b6bebb82fbbb006a2b02a448dd5c93434428991eae960d60220491d67d2660c4dde19025cf86e5164a559e2c79c3b98b40e146fab974acd24690147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9140ffdcf96700455074292a821c74922e8652993998788997bc60000000017a9148ce5408cfeaddb7ccb2545ded41ef478109454848700000000010000000113100b09e6a78d63ec4850654ab0f68806de29710b09172eddfef730652b155501000000da00473044022015389408e3446a3f36a05060e0e4a3c8b92ff3901ba2511aa944ec91a537a1cb022045a33b6ec47605b1718ed2e753263e54918edbf6126508ff039621fb928d28a001483045022100bb952fde81f216f7063575c0bb2bedc050ce08c96d9b437ea922f5eb98c882da02201b7cbf3a2f94ea4c5eb7f0df3af2ebcafa8705af7f410ab5d3d4bac13d6bc6120147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914d3db9a20312c3ab896a316eb108dbd01e47e17d687e0ba7ac60000000017a9148ce5408cfeaddb7ccb2545ded41ef47810945484870000000001000000016e3cca1599cde54878e2f27f434df69df0afd1f313cb6e38c08d3ffb57f97a6c01000000da0048304502210095623b70ec3194fa4037a1c1106c2580caedc390e25e5b330bbeb3111e8184bc02205ae973c4a4454be2a3a03beb66297143c1044a3c4743742c5cdd1d516a1ad3040147304402202f3d6d89996f5b42773dd6ebaf367f1af1f3a95c7c7b487ec040131c40f4a4a30220524ffbb0b563f37b3eb1341228f792e8f84111b7c4a9f49cdd998e052ee42efa0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a9141ade6b95896dde8ec4dee9e59af8849d3797348e8728af7ac60000000017a9148ce5408cfeaddb7ccb2545ded41ef47810945484870000000001000000011d9dc3a5df9b5b2eeb2bd11a2db243be9e8cc23e2f180bf317d32a499904c15501000000db00483045022100ebbd1c9a8ce626edbb1a7881df81e872ef8c6424feda36faa8a5745157400c6a02206eb463bc8acd5ea06a289e86115e1daae0c2cf10d9cbbd199e1311170d5543ef01483045022100809411a917dc8cf4f3a777f0388fdea6de06243ef7691e500c60abd1c7f19ae602205255d2b1191d8adedb77b814ccb66471eb8486cb4ff8727824254ee5589f176b0147522102632178d046673c9729d828cfee388e121f497707f810c131e0d3fc0fe0bd66d62103a0951ec7d3a9da9de171617026442fcd30f34d66100fab539853b43f508787d452aeffffffff0240420f000000000017a914759a49c772347be81c49517f9e1e6def6a88d4dd87800b85c60000000017a9148ce5408cfeaddb7ccb2545ded41ef47810945484870000000001000000018c51902affd8e5247dfcc2e5d0528a3815f53c8b6d2c200ff290b2b2b486d7704f0000006a47304402201be0d485f6a3ce871be80064c593c5327b3fd7e450f05ab7fae38385bc40cfbe02206e2a6c9970b5d1d10207892376733757486634fce4f352e772149c486857612101210350c33bc9a790c9495195761577b34912a949b73d5bc5ae5343f5ba08b33220ccffffffff0110270000000000001976a9142ab1c62710a7bdfdb4bb6394bbedc58b32b4d5a388ac0000000001000000018c51902affd8e5247dfcc2e5d0528a3815f53c8b6d2c200ff290b2b2b486d7704e0000006b483045022100ccc8c0ac90bdb0402842aec91830c765cdead7a728552a6a34de7d13a6dab28e02206c96f8640cf3444054e9632b197be30598a09c3d5defcd95750bdb922a60d64801210350c33bc9a790c9495195761577b34912a949b73d5bc5ae5343f5ba08b33220ccffffffff0110270000000000001976a9142ab1c62710a7bdfdb4bb6394bbedc58b32b4d5a388ac0000000001000000011b436669c06cbf3442e21a2fe3edc20cd3cf13c358c53234bc4d88bfd8c4bd2a000000006a47304402204a63410ee13db52c7609ab08e25b7fe3c608cc21cc1755ad13460685eb55193202204cd1ea80c06a81571119be0b8cccd96ef7cdd90f62c1fe2d538622feb08e22ba0121024baa8b67cc9ed8a97d90895e3716b25469b67cb26d3324d7aff213f507764765ffffffff010000000000000000306a2e516d64523365345261445653324d436a736e536171734a5753324465655446624238354541794a4d5843784c7934000000000100000001be4a95ed36316cada5118b1982e4cb4a07f93e7a4153e227466f1cb0776de995000000006b483045022100a22d5251deea0470806bab817013d675a63cd52218d6e477ab0c9d601d018b7f022042121b46afcdcd0c66f189398212b66085e88c6973ae560f1810c13e55e2bee40121024baa8b67cc9ed8a97d90895e3716b25469b67cb26d3324d7aff213f507764765ffffffff010000000000000000306a2e516d57484d57504e5248515872504c7338554c586b4d483746745356413675366b5a6b4a4e3851796e4e583751340000000001000000016c061a65b49edec21acdbc22f97dc853aa872302aeef13fabf0bf6807de1b8bd010000006b483045022100dd80381f2d158b4dad7f98d2d97317c533fb36e737542473feb05fa74d0b73bb02207097d4331196069167e525b61d132532292fd75cc039a5839c04c2545d427e2b0121035e9a597df8b417bef66811882a2844604fc591c427f642628f0fef46be19a4c9feffffff0280a4bf07000000001976a914573b9106e16ee0b5c143dc40f0724f77dd0e282088ac9533b22c000000001976a9149c4da607efb1d759d33da71778bc6cafa56acb5988acd31b0e0001000000017dae20994b69b28534e5b22f3d7c50f9d7541348cbf6f43fcc654263ebaf8f68000000006b483045022100a85300eb94b24b044877d0b0d61e08e16dbc82ec7d69c723a8a45519f95c35b002203d78376e6bee31b455c097557af7fe4d6b620bc74269e9a75e2aad2b545abddb012103b0d08aba2a5ac6cf2788fda941c386040e35e49d3a57d2aefb16c0438fb98acbfeffffff022222305f000000001976a914cfda30dd836b596db6a9c230c45ae2179107f04888ac80a4bf07000000001976a91442dfcf5823aacb185844e663873c35fb98bfd21b88acd31b0e000100000002ad3e85e4af30678a330f8941ed7a9ca17cd0236368d238cac4e9ff09c466fed1020000006b483045022100d1196c48a0392e09592f1b96b4aec32ab0cecb6fd17b1d0c85ab3250a2fe45d9022059217c82f684fcdecdbe660a2077ea956dfbbb964d2648bc1e8ae0f0fe565449012103b64e32e5f62e03701428fb1e3151e9a57f149c67708f6164a235c8199fe17cc2ffffffff34f0a71c1c2cd610522e9c18c67931cded5e9647d4419c49b99715e2a0795f3d020000006a4730440220316e81d8242abf3c5f885d200feca12c3adb63cf2cd4dc74602f7b8b0cba50340220210d525758df77ccdca6908311c1895275e07bbb29b45963a19252acde55873f012103b64e32e5f62e03701428fb1e3151e9a57f149c67708f6164a235c8199fe17cc2ffffffff0510270000000000001976a914449d2394dde057bc199f23fb8aa2e400f344611788ac10270000000000001976a914449d2394dde057bc199f23fb8aa2e400f344611788aca0860100000000001976a91413d35ad337dd80a055757e5ea0a45b59fee3060c88ac70110100000000001976a91413d35ad337dd80a055757e5ea0a45b59fee3060c88ac0000000000000000026a000000000001000000018e33fecc2ddbd86c5ea919f7bd5a5acf8a09f3e0cdaaaf4f08c5ef095161ef1100000000fdfe0000483045022100d2489b225d39b7d8b6767a6928c8029a2a1297c08fdf00d683ba0c1987e7d7000220176cb66c8a243806bb7421f658325a69a51c82c0c3314e37f2400f33626390210148304502210096cfa57662a545830d0e29610becd41ea031e256339913718ce18dbb1a27bdb00220482911c851d15adcd37097dff99a9ff1f97d953bcebc528835118f447412553e014c695221028d9889862b29430278c084b5c4090b7b807b31e047bcd212ebc2c4e43fc0e3c52103160949a7c8c81f2c25d7763f57eb1cb407d867c5b7c290331bd2dc4b1182c6d32103fbef3b60914bda9173765902013a251ec89450c75d0b5a96a143db1dabf98d9553aeffffffff0220e8891c0100000017a914d996715e081c50f8f6b1b4e7fb6ca214f9924fdf87809698000000000017a9145611d812263f32960228cb5f85329bce4770a218870000000001000000017720507dcbe6c69f652b0c0ce19406f482372d1a8abc05d45fb7acf97fb80eec00000000fdfe00004830450221009821d8e117de44b1202c829c0f5063997acf007cf9b561c6fb8d1212cddb6c40022010ff5067b0d9d4eca2da0ceb876e9a16f1a2142da866d3042a7bae8968813e8001483045022100dea759d14a8a1c5da5f3dcc5509871aaa2c1e3be03752c1b858d80fa4227163702205183d70cc28dcb6df9b037714c8b6442ef84e0ddce07711a30c731e9f0925090014c695221028d70ea66fe7a7def282df7b2b498007e5072933e42c18f63ce85975dcbcf1a8821037e8f842b1e47e21d88002c5aab2559212a4c2c9dbe5ef5347f2a29afd0510ec1210251259cb9fd4f6206488408286e4475c9c9fe887e57a3e32ae4da222778a2aedf53aeffffffff023380cb020000000017a9143b5a7e85b22656a34d43187ac8dd09acd7109d2487809698000000000017a914b9b4b555f594a34deec3ad61d5c5f3738b17ee158700000000").unwrap()).unwrap(); - let header: BlockHeader = deserialize(&hex_decode("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b").unwrap()).unwrap(); - - let msgs = vec![ - NetworkMessage::Version(version_msg), - NetworkMessage::Verack, - NetworkMessage::Addr(vec![(45, Address::new(&([123,255,000,100], 833).into(), ServiceFlags::NETWORK))]), - NetworkMessage::Inv(vec![Inventory::Block(hash([8u8; 32]).into())]), - NetworkMessage::GetData(vec![Inventory::Transaction(hash([45u8; 32]).into())]), - NetworkMessage::NotFound(vec![Inventory::Error]), - NetworkMessage::GetBlocks(GetBlocksMessage::new(vec![hash([1u8; 32]).into(), hash([4u8; 32]).into()], hash([5u8; 32]).into())), - NetworkMessage::GetHeaders(GetHeadersMessage::new(vec![hash([10u8; 32]).into(), hash([40u8; 32]).into()], hash([50u8; 32]).into())), - NetworkMessage::MemPool, - NetworkMessage::Tx(tx), - NetworkMessage::Block(block), - NetworkMessage::Headers(vec![header]), - NetworkMessage::SendHeaders, - NetworkMessage::GetAddr, - NetworkMessage::Ping(15), - NetworkMessage::Pong(23), - NetworkMessage::GetCFilters(GetCFilters{filter_type: 2, start_height: 52, stop_hash: hash([42u8; 32]).into()}), - NetworkMessage::CFilter(CFilter{filter_type: 7, block_hash: hash([25u8; 32]).into(), filter: vec![1,2,3]}), - NetworkMessage::GetCFHeaders(GetCFHeaders{filter_type: 4, start_height: 102, stop_hash: hash([47u8; 32]).into()}), - NetworkMessage::CFHeaders(CFHeaders{filter_type: 13, stop_hash: hash([53u8; 32]).into(), previous_filter: hash([12u8; 32]).into(), filter_hashes: vec![hash([4u8; 32]).into(), hash([12u8; 32]).into()]}), - NetworkMessage::GetCFCheckpt(GetCFCheckpt{filter_type: 17, stop_hash: hash([25u8; 32]).into()}), - NetworkMessage::CFCheckpt(CFCheckpt{filter_type: 27, stop_hash: hash([77u8; 32]).into(), filter_headers: vec![hash([3u8; 32]).into(), hash([99u8; 32]).into()]}), - NetworkMessage::Alert(vec![45,66,3,2,6,8,9,12,3,130]), - NetworkMessage::Reject(Reject{message: "Test reject".into(), ccode: RejectReason::Duplicate, reason: "Cause".into(), hash: hash([255u8; 32])}), - ]; - - for msg in msgs { - let raw_msg = RawNetworkMessage {magic: 57, payload: msg}; - assert_eq!(deserialize::(&serialize(&raw_msg)).unwrap(), raw_msg); - } - - } - - #[test] - fn serialize_commandstring_test() { - let cs = CommandString("Andrew".into()); - assert_eq!(serialize(&cs), vec![0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]); - - // Test oversized one. - let mut encoder = io::Cursor::new(vec![]); - assert!(CommandString("AndrewAndrewA".into()).consensus_encode(&mut encoder).is_err()); - } - - #[test] - fn deserialize_commandstring_test() { - let cs: Result = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0, 0]); - assert!(cs.is_ok()); - assert_eq!(cs.as_ref().unwrap().to_string(), "Andrew".to_owned()); - assert_eq!(cs.unwrap(), "Andrew".into()); - - let short_cs: Result = deserialize(&[0x41u8, 0x6e, 0x64, 0x72, 0x65, 0x77, 0, 0, 0, 0, 0]); - assert!(short_cs.is_err()); - } - - #[test] - fn serialize_verack_test() { - assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Verack }), - vec![0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61, - 0x63, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]); - } - - #[test] - fn serialize_ping_test() { - assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::Ping(100) }), - vec![0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d, - 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); - } - - - #[test] - fn serialize_mempool_test() { - assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::MemPool }), - vec![0xf9, 0xbe, 0xb4, 0xd9, 0x6d, 0x65, 0x6d, 0x70, - 0x6f, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]); - } - - #[test] - fn serialize_getaddr_test() { - assert_eq!(serialize(&RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::GetAddr }), - vec![0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61, - 0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]); - } - - #[test] - fn deserialize_getaddr_test() { - let msg = deserialize( - &[0xf9, 0xbe, 0xb4, 0xd9, 0x67, 0x65, 0x74, 0x61, - 0x64, 0x64, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2]); - let preimage = RawNetworkMessage { magic: 0xd9b4bef9, payload: NetworkMessage::GetAddr }; - assert!(msg.is_ok()); - let msg : RawNetworkMessage = msg.unwrap(); - assert_eq!(preimage.magic, msg.magic); - assert_eq!(preimage.payload, msg.payload); - } - - #[test] - fn deserialize_version_test() { - let msg = deserialize::( - &[ 0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0xbe, 0x61, 0xb8, 0x27, - 0x7f, 0x11, 0x01, 0x00, 0x0d, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x4d, 0x5c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x5b, 0xf0, 0x8c, 0x80, 0xb4, 0xbd, 0x0d, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0xa9, 0x95, 0x59, 0xcc, 0x68, 0xa1, 0xc1, - 0x10, 0x2f, 0x53, 0x61, 0x74, 0x6f, 0x73, 0x68, - 0x69, 0x3a, 0x30, 0x2e, 0x31, 0x37, 0x2e, 0x31, - 0x2f, 0x93, 0x8c, 0x08, 0x00, 0x01 ]); - - assert!(msg.is_ok()); - let msg = msg.unwrap(); - assert_eq!(msg.magic, 0xd9b4bef9); - if let NetworkMessage::Version(version_msg) = msg.payload { - assert_eq!(version_msg.version, 70015); - assert_eq!(version_msg.services, ServiceFlags::NETWORK | ServiceFlags::BLOOM | ServiceFlags::WITNESS | ServiceFlags::NETWORK_LIMITED); - assert_eq!(version_msg.timestamp, 1548554224); - assert_eq!(version_msg.nonce, 13952548347456104954); - assert_eq!(version_msg.user_agent, "/Satoshi:0.17.1/"); - assert_eq!(version_msg.start_height, 560275); - assert_eq!(version_msg.relay, true); - } else { - panic!("Wrong message type"); - } - } - - #[test] - fn deserialize_partial_message_test() { - let data = [ 0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0xbe, 0x61, 0xb8, 0x27, - 0x7f, 0x11, 0x01, 0x00, 0x0d, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x4d, 0x5c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x5b, 0xf0, 0x8c, 0x80, 0xb4, 0xbd, 0x0d, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0xa9, 0x95, 0x59, 0xcc, 0x68, 0xa1, 0xc1, - 0x10, 0x2f, 0x53, 0x61, 0x74, 0x6f, 0x73, 0x68, - 0x69, 0x3a, 0x30, 0x2e, 0x31, 0x37, 0x2e, 0x31, - 0x2f, 0x93, 0x8c, 0x08, 0x00, 0x01, 0, 0 ]; - let msg = deserialize_partial::(&data); - assert!(msg.is_ok()); - - let (msg, consumed) = msg.unwrap(); - assert_eq!(consumed, data.to_vec().len() - 2); - assert_eq!(msg.magic, 0xd9b4bef9); - if let NetworkMessage::Version(version_msg) = msg.payload { - assert_eq!(version_msg.version, 70015); - assert_eq!(version_msg.services, ServiceFlags::NETWORK | ServiceFlags::BLOOM | ServiceFlags::WITNESS | ServiceFlags::NETWORK_LIMITED); - assert_eq!(version_msg.timestamp, 1548554224); - assert_eq!(version_msg.nonce, 13952548347456104954); - assert_eq!(version_msg.user_agent, "/Satoshi:0.17.1/"); - assert_eq!(version_msg.start_height, 560275); - assert_eq!(version_msg.relay, true); - } else { - panic!("Wrong message type"); - } - } -} diff --git a/src/network/message_blockdata.rs b/src/network/message_blockdata.rs deleted file mode 100644 index a758c3c4..00000000 --- a/src/network/message_blockdata.rs +++ /dev/null @@ -1,176 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Blockdata network messages -//! -//! This module describes network messages which are used for passing -//! Bitcoin data (blocks and transactions) around. -//! - -use std::io; - -use hashes::sha256d; - -use network::constants; -use consensus::encode::{self, Decodable, Encodable}; -use hash_types::{BlockHash, Txid, Wtxid}; - -/// An inventory item. -#[derive(PartialEq, Eq, Clone, Debug, Copy, Hash)] -pub enum Inventory { - /// Error --- these inventories can be ignored - Error, - /// Transaction - Transaction(Txid), - /// Block - Block(BlockHash), - /// Witness Transaction - WitnessTransaction(Wtxid), - /// Witness Block - WitnessBlock(BlockHash), -} - -impl Encodable for Inventory { - #[inline] - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - macro_rules! encode_inv { - ($code:expr, $item:expr) => { - u32::consensus_encode(&$code, &mut s)? + - $item.consensus_encode(&mut s)? - } - } - Ok(match *self { - Inventory::Error => encode_inv!(0, sha256d::Hash::default()), - Inventory::Transaction(ref t) => encode_inv!(1, t), - Inventory::Block(ref b) => encode_inv!(2, b), - Inventory::WitnessTransaction(ref t) => encode_inv!(0x40000001, t), - Inventory::WitnessBlock(ref b) => encode_inv!(0x40000002, b), - }) - } -} - -impl Decodable for Inventory { - #[inline] - fn consensus_decode(mut d: D) -> Result { - let inv_type: u32 = Decodable::consensus_decode(&mut d)?; - Ok(match inv_type { - 0 => Inventory::Error, - 1 => Inventory::Transaction(Decodable::consensus_decode(&mut d)?), - 2 => Inventory::Block(Decodable::consensus_decode(&mut d)?), - 0x40000001 => Inventory::WitnessTransaction(Decodable::consensus_decode(&mut d)?), - 0x40000002 => Inventory::WitnessBlock(Decodable::consensus_decode(&mut d)?), - tp => return Err(encode::Error::UnknownInventoryType(tp)), - }) - } -} - -// Some simple messages - -/// The `getblocks` message -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct GetBlocksMessage { - /// The protocol version - pub version: u32, - /// Locator hashes --- ordered newest to oldest. The remote peer will - /// reply with its longest known chain, starting from a locator hash - /// if possible and block 1 otherwise. - pub locator_hashes: Vec, - /// References the block to stop at, or zero to just fetch the maximum 500 blocks - pub stop_hash: BlockHash, -} - -/// The `getheaders` message -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct GetHeadersMessage { - /// The protocol version - pub version: u32, - /// Locator hashes --- ordered newest to oldest. The remote peer will - /// reply with its longest known chain, starting from a locator hash - /// if possible and block 1 otherwise. - pub locator_hashes: Vec, - /// References the header to stop at, or zero to just fetch the maximum 2000 headers - pub stop_hash: BlockHash -} - -impl GetBlocksMessage { - /// Construct a new `getblocks` message - pub fn new(locator_hashes: Vec, stop_hash: BlockHash) -> GetBlocksMessage { - GetBlocksMessage { - version: constants::PROTOCOL_VERSION, - locator_hashes: locator_hashes.clone(), - stop_hash: stop_hash - } - } -} - -impl_consensus_encoding!(GetBlocksMessage, version, locator_hashes, stop_hash); - -impl GetHeadersMessage { - /// Construct a new `getheaders` message - pub fn new(locator_hashes: Vec, stop_hash: BlockHash) -> GetHeadersMessage { - GetHeadersMessage { - version: constants::PROTOCOL_VERSION, - locator_hashes: locator_hashes, - stop_hash: stop_hash - } - } -} - -impl_consensus_encoding!(GetHeadersMessage, version, locator_hashes, stop_hash); - -#[cfg(test)] -mod tests { - use super::{GetHeadersMessage, GetBlocksMessage}; - - use hex::decode as hex_decode; - - use consensus::encode::{deserialize, serialize}; - use std::default::Default; - - #[test] - fn getblocks_message_test() { - let from_sat = hex_decode("72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000").unwrap(); - let genhash = hex_decode("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap(); - - let decode: Result = deserialize(&from_sat); - assert!(decode.is_ok()); - let real_decode = decode.unwrap(); - assert_eq!(real_decode.version, 70002); - assert_eq!(real_decode.locator_hashes.len(), 1); - assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash); - assert_eq!(real_decode.stop_hash, Default::default()); - - assert_eq!(serialize(&real_decode), from_sat); - } - - #[test] - fn getheaders_message_test() { - let from_sat = hex_decode("72110100014a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b0000000000000000000000000000000000000000000000000000000000000000").unwrap(); - let genhash = hex_decode("4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b").unwrap(); - - let decode: Result = deserialize(&from_sat); - assert!(decode.is_ok()); - let real_decode = decode.unwrap(); - assert_eq!(real_decode.version, 70002); - assert_eq!(real_decode.locator_hashes.len(), 1); - assert_eq!(serialize(&real_decode.locator_hashes[0]), genhash); - assert_eq!(real_decode.stop_hash, Default::default()); - - assert_eq!(serialize(&real_decode), from_sat); - } -} - diff --git a/src/network/mod.rs b/src/network/mod.rs deleted file mode 100644 index 4ba6d16a..00000000 --- a/src/network/mod.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Network Support -//! -//! This module defines support for (de)serialization and network transport -//! of Bitcoin data and network messages. -//! - -use std::fmt; -use std::io; -use std::error; - -pub mod constants; - -pub mod address; -pub use self::address::Address; -pub mod message; -pub mod message_blockdata; -pub mod message_network; -pub mod message_filter; -pub mod stream_reader; - -/// Network error -#[derive(Debug)] -pub enum Error { - /// And I/O error - Io(io::Error), - /// Socket mutex was poisoned - SocketMutexPoisoned, - /// Not connected to peer - SocketNotConnectedToPeer, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Io(ref e) => fmt::Display::fmt(e, f), - Error::SocketMutexPoisoned | Error::SocketNotConnectedToPeer => f.write_str(error::Error::description(self)), - } - } -} - -#[doc(hidden)] -impl From for Error { - fn from(err: io::Error) -> Self { - Error::Io(err) - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::Io(ref e) => e.description(), - Error::SocketMutexPoisoned => "socket mutex was poisoned", - Error::SocketNotConnectedToPeer => "not connected to peer", - } - } - - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::Io(ref e) => Some(e), - Error::SocketMutexPoisoned | Error::SocketNotConnectedToPeer => None, - } - } -} diff --git a/src/network/stream_reader.rs b/src/network/stream_reader.rs deleted file mode 100644 index 78923a76..00000000 --- a/src/network/stream_reader.rs +++ /dev/null @@ -1,347 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Stream reader -//! -//! This module defines `StreamReader` struct and its implementation which is used -//! for parsing incoming stream into separate `RawNetworkMessage`s, handling assembling -//! messages from multiple packets or dealing with partial or multiple messages in the stream -//! (like can happen with reading from TCP socket) -//! - -use std::fmt; -use std::io::{self, Read}; - -use consensus::{encode, Decodable}; - -/// Struct used to configure stream reader function -pub struct StreamReader { - /// Stream to read from - pub stream: R, - /// I/O buffer - data: Vec, - /// Buffer containing unparsed message part - unparsed: Vec -} - -impl fmt::Debug for StreamReader { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "StreamReader with buffer_size={} and unparsed content {:?}", - self.data.capacity(), self.unparsed) - } -} - -impl StreamReader { - /// Constructs new stream reader for a given input stream `stream` with - /// optional parameter `buffer_size` determining reading buffer size - pub fn new(stream: R, buffer_size: Option) -> StreamReader { - StreamReader { - stream, - data: vec![0u8; buffer_size.unwrap_or(64 * 1024)], - unparsed: vec![] - } - } - - /// Reads stream and parses next message from its current input, - /// also taking into account previously unparsed partial message (if there was such). - pub fn read_next(&mut self) -> Result { - loop { - match encode::deserialize_partial::(&self.unparsed) { - // In this case we just have an incomplete data, so we need to read more - Err(encode::Error::Io(ref err)) if err.kind () == io::ErrorKind::UnexpectedEof => { - let count = self.stream.read(&mut self.data)?; - if count > 0 { - self.unparsed.extend(self.data[0..count].iter()); - } - else { - return Err(encode::Error::Io(io::Error::from(io::ErrorKind::UnexpectedEof))); - } - }, - Err(err) => return Err(err), - // We have successfully read from the buffer - Ok((message, index)) => { - self.unparsed.drain(..index); - return Ok(message) - }, - } - } - } -} - -#[cfg(test)] -mod test { - use std::thread; - use std::time::Duration; - use std::io::{self, BufReader, Write}; - use std::net::{TcpListener, TcpStream, Shutdown}; - use std::thread::JoinHandle; - use network::constants::ServiceFlags; - - use super::StreamReader; - use network::message::{NetworkMessage, RawNetworkMessage}; - - // First, let's define some byte arrays for sample messages - dumps are taken from live - // Bitcoin Core node v0.17.1 with Wireshark - const MSG_VERSION: [u8; 126] = [ - 0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x73, - 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x66, 0x00, 0x00, 0x00, 0xbe, 0x61, 0xb8, 0x27, - 0x7f, 0x11, 0x01, 0x00, 0x0d, 0x04, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x4d, 0x5c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0x5b, 0xf0, 0x8c, 0x80, 0xb4, 0xbd, 0x0d, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xfa, 0xa9, 0x95, 0x59, 0xcc, 0x68, 0xa1, 0xc1, - 0x10, 0x2f, 0x53, 0x61, 0x74, 0x6f, 0x73, 0x68, - 0x69, 0x3a, 0x30, 0x2e, 0x31, 0x37, 0x2e, 0x31, - 0x2f, 0x93, 0x8c, 0x08, 0x00, 0x01 - ]; - - const MSG_VERACK: [u8; 24] = [ - 0xf9, 0xbe, 0xb4, 0xd9, 0x76, 0x65, 0x72, 0x61, - 0x63, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf6, 0xe0, 0xe2 - ]; - - const MSG_PING: [u8; 32] = [ - 0xf9, 0xbe, 0xb4, 0xd9, 0x70, 0x69, 0x6e, 0x67, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x24, 0x67, 0xf1, 0x1d, - 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ]; - - const MSG_ALERT: [u8; 192] = [ - 0xf9, 0xbe, 0xb4, 0xd9, 0x61, 0x6c, 0x65, 0x72, - 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xa8, 0x00, 0x00, 0x00, 0x1b, 0xf9, 0xaa, 0xea, - 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x7f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0x01, 0xff, 0xff, - 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x00, - 0x2f, 0x55, 0x52, 0x47, 0x45, 0x4e, 0x54, 0x3a, - 0x20, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x20, 0x6b, - 0x65, 0x79, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, - 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x64, 0x2c, 0x20, - 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x20, - 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, - 0x00, 0x46, 0x30, 0x44, 0x02, 0x20, 0x65, 0x3f, - 0xeb, 0xd6, 0x41, 0x0f, 0x47, 0x0f, 0x6b, 0xae, - 0x11, 0xca, 0xd1, 0x9c, 0x48, 0x41, 0x3b, 0xec, - 0xb1, 0xac, 0x2c, 0x17, 0xf9, 0x08, 0xfd, 0x0f, - 0xd5, 0x3b, 0xdc, 0x3a, 0xbd, 0x52, 0x02, 0x20, - 0x6d, 0x0e, 0x9c, 0x96, 0xfe, 0x88, 0xd4, 0xa0, - 0xf0, 0x1e, 0xd9, 0xde, 0xda, 0xe2, 0xb6, 0xf9, - 0xe0, 0x0d, 0xa9, 0x4c, 0xad, 0x0f, 0xec, 0xaa, - 0xe6, 0x6e, 0xcf, 0x68, 0x9b, 0xf7, 0x1b, 0x50 - ]; - - // Helper functions that checks parsed versions of the messages from the byte arrays above - fn check_version_msg(msg: &RawNetworkMessage) { - assert_eq!(msg.magic, 0xd9b4bef9); - if let NetworkMessage::Version(ref version_msg) = msg.payload { - assert_eq!(version_msg.version, 70015); - assert_eq!(version_msg.services, ServiceFlags::NETWORK | ServiceFlags::BLOOM | ServiceFlags::WITNESS | ServiceFlags::NETWORK_LIMITED); - assert_eq!(version_msg.timestamp, 1548554224); - assert_eq!(version_msg.nonce, 13952548347456104954); - assert_eq!(version_msg.user_agent, "/Satoshi:0.17.1/"); - assert_eq!(version_msg.start_height, 560275); - assert_eq!(version_msg.relay, true); - } else { - panic!("Wrong message type: expected VersionMessage"); - } - } - - fn check_alert_msg(msg: &RawNetworkMessage) { - assert_eq!(msg.magic, 0xd9b4bef9); - if let NetworkMessage::Alert(ref alert) = msg.payload { - assert_eq!(alert.clone(), [ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x7f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, - 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0x01, 0xff, 0xff, - 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, - 0xff, 0x7f, 0x00, 0xff, 0xff, 0xff, 0x7f, 0x00, - 0x2f, 0x55, 0x52, 0x47, 0x45, 0x4e, 0x54, 0x3a, - 0x20, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x20, 0x6b, - 0x65, 0x79, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, - 0x6f, 0x6d, 0x69, 0x73, 0x65, 0x64, 0x2c, 0x20, - 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x20, - 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, - 0x00, - ].to_vec()); - } else { - panic!("Wrong message type: expected AlertMessage"); - } - } - - #[test] - fn parse_multipartmsg_test() { - let stream = io::empty(); - let mut reader = StreamReader::new(stream, None); - reader.unparsed = MSG_ALERT[..24].to_vec(); - let message: Result = reader.read_next(); - assert!(message.is_err()); - assert_eq!(reader.unparsed.len(), 24); - - reader.unparsed = MSG_ALERT.to_vec(); - let message = reader.read_next().unwrap(); - assert_eq!(reader.unparsed.len(), 0); - - check_alert_msg(&message); - } - - #[test] - fn read_singlemsg_test() { - let stream = MSG_VERSION[..].to_vec(); - let stream = stream.as_slice(); - let message = StreamReader::new(stream, None).read_next().unwrap(); - check_version_msg(&message); - } - - #[test] - fn read_doublemsgs_test() { - let mut stream = MSG_VERSION.to_vec(); - stream.extend(&MSG_PING); - let stream = stream.as_slice(); - let mut reader = StreamReader::new(stream, None); - let message = reader.read_next().unwrap(); - check_version_msg(&message); - - let msg: RawNetworkMessage = reader.read_next().unwrap(); - assert_eq!(msg.magic, 0xd9b4bef9); - if let NetworkMessage::Ping(nonce) = msg.payload { - assert_eq!(nonce, 100); - } else { - panic!("Wrong message type, expected PingMessage"); - } - } - - // Helper function that set ups emulation of client-server TCP connection for - // testing message transfer via TCP packets - fn serve_tcp(pieces: Vec>) -> (JoinHandle<()>, BufReader) { - // 1. Creating server part (emulating Bitcoin Core node) - let listener = TcpListener::bind(format!("127.0.0.1:{}", 0)).unwrap(); - let port = listener.local_addr().unwrap().port(); - // 2. Spawning thread that will be writing our messages to the TCP Stream at the server side - // in async mode - let handle = thread::spawn(move || { - for ostream in listener.incoming() { - let mut ostream = ostream.unwrap(); - - for piece in pieces { - ostream.write(&piece[..]).unwrap(); - ostream.flush().unwrap(); - thread::sleep(Duration::from_secs(1)); - } - - ostream.shutdown(Shutdown::Both).unwrap(); - break; - } - }); - - // 3. Creating client side of the TCP socket connection - thread::sleep(Duration::from_secs(1)); - let istream = TcpStream::connect(format!("127.0.0.1:{}", port)).unwrap(); - let reader = BufReader::new(istream); - - return (handle, reader) - } - - #[test] - fn read_multipartmsg_test() { - // Setting up TCP connection emulation - let (handle, istream) = serve_tcp(vec![ - // single message split in two parts to emulate real network conditions - MSG_VERSION[..24].to_vec(), MSG_VERSION[24..].to_vec() - ]); - let stream = istream; - let mut reader = StreamReader::new(stream, None); - - // Reading and checking the whole message back - let message = reader.read_next().unwrap(); - check_version_msg(&message); - - // Waiting TCP server thread to terminate - handle.join().unwrap(); - } - - #[test] - fn read_sequencemsg_test() { - // Setting up TCP connection emulation - let (handle, istream) = serve_tcp(vec![ - // Real-world Bitcoin core communication case for /Satoshi:0.17.1/ - MSG_VERSION[..23].to_vec(), MSG_VERSION[23..].to_vec(), - MSG_VERACK.to_vec(), - MSG_ALERT[..24].to_vec(), MSG_ALERT[24..].to_vec() - ]); - let stream = istream; - let mut reader = StreamReader::new(stream, None); - - // Reading and checking the first message (Version) - let message = reader.read_next().unwrap(); - check_version_msg(&message); - - // Reading and checking the second message (Verack) - let msg: RawNetworkMessage = reader.read_next().unwrap(); - assert_eq!(msg.magic, 0xd9b4bef9); - assert_eq!(msg.payload, NetworkMessage::Verack, "Wrong message type, expected VerackMessage"); - - // Reading and checking the third message (Alert) - let msg = reader.read_next().unwrap(); - check_alert_msg(&msg); - - // Waiting TCP server thread to terminate - handle.join().unwrap(); - } - - #[test] - fn read_block_from_file_test() { - use std::io; - use consensus::serialize; - use hex::decode as hex_decode; - use Block; - - let normal_data = hex_decode("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac00000000").unwrap(); - let cutoff_data = hex_decode("010000004ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914cd74d6e49ffff001d323b3a7b0201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0804ffff001d026e04ffffffff0100f2052a0100000043410446ef0102d1ec5240f0d061a4246c1bdef63fc3dbab7733052fbbf0ecd8f41fc26bf049ebb4f9527f374280259e7cfa99c48b0e3f39c51347a19a5819651503a5ac00000000010000000321f75f3139a013f50f315b23b0c9a2b6eac31e2bec98e5891c924664889942260000000049483045022100cb2c6b346a978ab8c61b18b5e9397755cbd17d6eb2fe0083ef32e067fa6c785a02206ce44e613f31d9a6b0517e46f3db1576e9812cc98d159bfdaf759a5014081b5c01ffffffff79cda0945903627c3da1f85fc95d0b8ee3e76ae0cfdc9a65d09744b1f8fc85430000000049483045022047957cdd957cfd0becd642f6b84d82f49b6cb4c51a91f49246908af7c3cfdf4a022100e96b46621f1bffcf5ea5982f88cef651e9354f5791602369bf5a82a6cd61a62501fffffffffe09f5fe3ffbf5ee97a54eb5e5069e9da6b4856ee86fc52938c2f979b0f38e82000000004847304402204165be9a4cbab8049e1af9723b96199bfd3e85f44c6b4c0177e3962686b26073022028f638da23fc003760861ad481ead4099312c60030d4cb57820ce4d33812a5ce01ffffffff01009d966b01000000434104ea1feff861b51fe3f5f8a3b12d0f4712db80e919548a80839fc47c6a21e66d957e9c5d8cd108c7a2d2324bad71f9904ac0ae7336507d785b17a2c115e427a32fac").unwrap(); - let prevhash = hex_decode("4ddccd549d28f385ab457e98d1b11ce80bfea2c5ab93015ade4973e400000000").unwrap(); - let merkle = hex_decode("bf4473e53794beae34e64fccc471dace6ae544180816f89591894e0f417a914c").unwrap(); - - let stream = io::BufReader::new(&normal_data[..]); - let mut reader = StreamReader::new(stream, None); - let normal_block = reader.read_next::(); - - let stream = io::BufReader::new(&cutoff_data[..]); - let mut reader = StreamReader::new(stream, None); - let cutoff_block = reader.read_next::(); - - assert!(normal_block.is_ok()); - assert!(cutoff_block.is_err()); - let block = normal_block.unwrap(); - assert_eq!(block.header.version, 1); - assert_eq!(serialize(&block.header.prev_blockhash), prevhash); - assert_eq!(serialize(&block.header.merkle_root), merkle); - assert_eq!(block.header.time, 1231965655); - assert_eq!(block.header.bits, 486604799); - assert_eq!(block.header.nonce, 2067413810); - - // should be also ok for a non-witness block as commitment is optional in that case - assert!(block.check_witness_commitment()); - } -} diff --git a/src/test_macros.rs b/src/test_macros.rs deleted file mode 100644 index 11c46229..00000000 --- a/src/test_macros.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Macros -//! -//! Internal macros used for unit tests - -#[cfg(feature = "serde")] -macro_rules! serde_round_trip ( - ($var:expr) => ({ - use serde_json; - - let encoded = serde_json::to_value(&$var).unwrap(); - let decoded = serde_json::from_value(encoded).unwrap(); - assert_eq!($var, decoded); - }) -); - diff --git a/src/util/address.rs b/src/util/address.rs deleted file mode 100644 index 7ad2d32b..00000000 --- a/src/util/address.rs +++ /dev/null @@ -1,749 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Addresses -//! -//! Support for ordinary base58 Bitcoin addresses and private keys -//! -//! # Example: creating a new address from a randomly-generated key pair -//! -//! ```rust -//! extern crate secp256k1; -//! extern crate bitcoin; -//! -//! use bitcoin::network::constants::Network; -//! use bitcoin::util::address::Address; -//! use bitcoin::util::key; -//! use secp256k1::Secp256k1; -//! use secp256k1::rand::thread_rng; -//! -//! fn main() { -//! // Generate random key pair -//! let s = Secp256k1::new(); -//! let public_key = key::PublicKey { -//! compressed: true, -//! key: s.generate_keypair(&mut thread_rng()).1, -//! }; -//! -//! // Generate pay-to-pubkey-hash address -//! let address = Address::p2pkh(&public_key, Network::Bitcoin); -//! } -//! ``` - -use std::fmt::{self, Display, Formatter}; -use std::str::FromStr; - -use bech32; -use hashes::Hash; - -use hash_types::{PubkeyHash, WPubkeyHash, ScriptHash, WScriptHash}; -use blockdata::opcodes; -use blockdata::script; -use network::constants::Network; -use util::base58; -use util::key; - -/// Address error. -#[derive(Debug, PartialEq)] -pub enum Error { - /// Base58 encoding error - Base58(base58::Error), - /// Bech32 encoding error - Bech32(bech32::Error), - /// The bech32 payload was empty - EmptyBech32Payload, - /// Script version must be 0 to 16 inclusive - InvalidWitnessVersion(u8), - /// The witness program must be between 2 and 40 bytes in length. - InvalidWitnessProgramLength(usize), - /// A v0 witness program must be either of length 20 or 32. - InvalidSegwitV0ProgramLength(usize), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Base58(ref e) => write!(f, "base58: {}", e), - Error::Bech32(ref e) => write!(f, "bech32: {}", e), - Error::EmptyBech32Payload => write!(f, "the bech32 payload was empty"), - Error::InvalidWitnessVersion(v) => write!(f, "invalid witness script version: {}", v), - Error::InvalidWitnessProgramLength(l) => write!( - f, - "the witness program must be between 2 and 40 bytes in length: lengh={}", - l - ), - Error::InvalidSegwitV0ProgramLength(l) => write!( - f, - "a v0 witness program must be either of length 20 or 32 bytes: length={}", - l - ), - } - } -} - -impl ::std::error::Error for Error { - fn cause(&self) -> Option<&::std::error::Error> { - match *self { - Error::Base58(ref e) => Some(e), - Error::Bech32(ref e) => Some(e), - _ => None, - } - } - - fn description(&self) -> &'static str { - "std::error::Error::description is deprecated" - } -} - -#[doc(hidden)] -impl From for Error { - fn from(e: base58::Error) -> Error { - Error::Base58(e) - } -} - -#[doc(hidden)] -impl From for Error { - fn from(e: bech32::Error) -> Error { - Error::Bech32(e) - } -} - -/// The different types of addresses. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum AddressType { - /// pay-to-pubkey-hash - P2pkh, - /// pay-to-script-hash - P2sh, - /// pay-to-witness-pubkey-hash - P2wpkh, - /// pay-to-witness-script-hash - P2wsh, -} - -impl fmt::Display for AddressType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match *self { - AddressType::P2pkh => "p2pkh", - AddressType::P2sh => "p2sh", - AddressType::P2wpkh => "p2wpkh", - AddressType::P2wsh => "p2wsh", - }) - } -} - -impl FromStr for AddressType { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "p2pkh" => Ok(AddressType::P2pkh), - "p2sh" => Ok(AddressType::P2sh), - "p2wpkh" => Ok(AddressType::P2wpkh), - "p2wsh" => Ok(AddressType::P2wsh), - _ => Err(()), - } - } -} - -/// The method used to produce an address -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum Payload { - /// pay-to-pkhash address - PubkeyHash(PubkeyHash), - /// P2SH address - ScriptHash(ScriptHash), - /// Segwit address - WitnessProgram { - /// The witness program version - version: bech32::u5, - /// The witness program - program: Vec, - }, -} - -impl Payload { - /// Get a [Payload] from an output script (scriptPubkey). - pub fn from_script(script: &script::Script) -> Option { - Some(if script.is_p2pkh() { - Payload::PubkeyHash(PubkeyHash::from_slice(&script.as_bytes()[3..23]).unwrap()) - } else if script.is_p2sh() { - Payload::ScriptHash(ScriptHash::from_slice(&script.as_bytes()[2..22]).unwrap()) - } else if script.is_witness_program() { - // We can unwrap the u5 check and assume script length - // because [Script::is_witness_program] makes sure of this. - Payload::WitnessProgram { - version: { - // Since we passed the [is_witness_program] check, - // the first byte is either 0x00 or 0x50 + version. - let mut verop = script.as_bytes()[0]; - if verop > 0x50 { - verop -= 0x50; - } - bech32::u5::try_from_u8(verop).expect("checked before") - }, - program: script.as_bytes()[2..].to_vec(), - } - } else { - return None; - }) - } - - /// Generates a script pubkey spending to this [Payload]. - pub fn script_pubkey(&self) -> script::Script { - match *self { - Payload::PubkeyHash(ref hash) => script::Builder::new() - .push_opcode(opcodes::all::OP_DUP) - .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&hash[..]) - .push_opcode(opcodes::all::OP_EQUALVERIFY) - .push_opcode(opcodes::all::OP_CHECKSIG), - Payload::ScriptHash(ref hash) => script::Builder::new() - .push_opcode(opcodes::all::OP_HASH160) - .push_slice(&hash[..]) - .push_opcode(opcodes::all::OP_EQUAL), - Payload::WitnessProgram { - version: ver, - program: ref prog, - } => { - assert!(ver.to_u8() <= 16); - let mut verop = ver.to_u8(); - if verop > 0 { - verop = 0x50 + verop; - } - script::Builder::new().push_opcode(verop.into()).push_slice(&prog) - } - } - .into_script() - } -} - -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -/// A Bitcoin address -pub struct Address { - /// The type of the address - pub payload: Payload, - /// The network on which this address is usable - pub network: Network, -} -serde_string_impl!(Address, "a Bitcoin address"); - -impl Address { - /// Creates a pay to (compressed) public key hash address from a public key - /// This is the preferred non-witness type address - #[inline] - pub fn p2pkh(pk: &key::PublicKey, network: Network) -> Address { - let mut hash_engine = PubkeyHash::engine(); - pk.write_into(&mut hash_engine); - - Address { - network: network, - payload: Payload::PubkeyHash(PubkeyHash::from_engine(hash_engine)), - } - } - - /// Creates a pay to script hash P2SH address from a script - /// This address type was introduced with BIP16 and is the popular type to implement multi-sig these days. - #[inline] - pub fn p2sh(script: &script::Script, network: Network) -> Address { - Address { - network: network, - payload: Payload::ScriptHash(ScriptHash::hash(&script[..])), - } - } - - /// Create a witness pay to public key address from a public key - /// This is the native segwit address type for an output redeemable with a single signature - pub fn p2wpkh(pk: &key::PublicKey, network: Network) -> Address { - let mut hash_engine = WPubkeyHash::engine(); - pk.write_into(&mut hash_engine); - - Address { - network: network, - payload: Payload::WitnessProgram { - version: bech32::u5::try_from_u8(0).expect("0<32"), - program: WPubkeyHash::from_engine(hash_engine)[..].to_vec(), - }, - } - } - - /// Create a pay to script address that embeds a witness pay to public key - /// This is a segwit address type that looks familiar (as p2sh) to legacy clients - pub fn p2shwpkh(pk: &key::PublicKey, network: Network) -> Address { - let mut hash_engine = WPubkeyHash::engine(); - pk.write_into(&mut hash_engine); - - let builder = script::Builder::new() - .push_int(0) - .push_slice(&WPubkeyHash::from_engine(hash_engine)[..]); - - Address { - network: network, - payload: Payload::ScriptHash(ScriptHash::hash(builder.into_script().as_bytes())), - } - } - - /// Create a witness pay to script hash address - pub fn p2wsh(script: &script::Script, network: Network) -> Address { - Address { - network: network, - payload: Payload::WitnessProgram { - version: bech32::u5::try_from_u8(0).expect("0<32"), - program: WScriptHash::hash(&script[..])[..].to_vec(), - }, - } - } - - /// Create a pay to script address that embeds a witness pay to script hash address - /// This is a segwit address type that looks familiar (as p2sh) to legacy clients - pub fn p2shwsh(script: &script::Script, network: Network) -> Address { - let ws = script::Builder::new() - .push_int(0) - .push_slice(&WScriptHash::hash(&script[..])[..]) - .into_script(); - - Address { - network: network, - payload: Payload::ScriptHash(ScriptHash::hash(&ws[..])), - } - } - - /// Get the address type of the address. - /// None if unknown or non-standard. - pub fn address_type(&self) -> Option { - match self.payload { - Payload::PubkeyHash(_) => Some(AddressType::P2pkh), - Payload::ScriptHash(_) => Some(AddressType::P2sh), - Payload::WitnessProgram { - version: ver, - program: ref prog, - } => { - // BIP-141 p2wpkh or p2wsh addresses. - match ver.to_u8() { - 0 => match prog.len() { - 20 => Some(AddressType::P2wpkh), - 32 => Some(AddressType::P2wsh), - _ => None, - }, - _ => None, - } - } - } - } - - /// Check whether or not the address is following Bitcoin - /// standardness rules. - /// - /// Segwit addresses with unassigned witness versions or non-standard - /// program sizes are considered non-standard. - pub fn is_standard(&self) -> bool { - self.address_type().is_some() - } - - /// Get an [Address] from an output script (scriptPubkey). - pub fn from_script(script: &script::Script, network: Network) -> Option
{ - Some(Address { - payload: Payload::from_script(script)?, - network: network, - }) - } - - /// Generates a script pubkey spending to this address - pub fn script_pubkey(&self) -> script::Script { - self.payload.script_pubkey() - } -} - -impl Display for Address { - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - match self.payload { - Payload::PubkeyHash(ref hash) => { - let mut prefixed = [0; 21]; - prefixed[0] = match self.network { - Network::Bitcoin => 0, - Network::Testnet | Network::Regtest => 111, - }; - prefixed[1..].copy_from_slice(&hash[..]); - base58::check_encode_slice_to_fmt(fmt, &prefixed[..]) - } - Payload::ScriptHash(ref hash) => { - let mut prefixed = [0; 21]; - prefixed[0] = match self.network { - Network::Bitcoin => 5, - Network::Testnet | Network::Regtest => 196, - }; - prefixed[1..].copy_from_slice(&hash[..]); - base58::check_encode_slice_to_fmt(fmt, &prefixed[..]) - } - Payload::WitnessProgram { - version: ver, - program: ref prog, - } => { - let hrp = match self.network { - Network::Bitcoin => "bc", - Network::Testnet => "tb", - Network::Regtest => "bcrt", - }; - let mut bech32_writer = bech32::Bech32Writer::new(hrp, fmt)?; - bech32::WriteBase32::write_u5(&mut bech32_writer, ver)?; - bech32::ToBase32::write_base32(&prog, &mut bech32_writer) - } - } - } -} - -/// Extract the bech32 prefix. -/// Returns the same slice when no prefix is found. -fn find_bech32_prefix(bech32: &str) -> &str { - // Split at the last occurrence of the separator character '1'. - match bech32.rfind("1") { - None => bech32, - Some(sep) => bech32.split_at(sep).0, - } -} - -impl FromStr for Address { - type Err = Error; - - fn from_str(s: &str) -> Result { - // try bech32 - let bech32_network = match find_bech32_prefix(s) { - // note that upper or lowercase is allowed but NOT mixed case - "bc" | "BC" => Some(Network::Bitcoin), - "tb" | "TB" => Some(Network::Testnet), - "bcrt" | "BCRT" => Some(Network::Regtest), - _ => None, - }; - if let Some(network) = bech32_network { - // decode as bech32 - let (_, payload) = bech32::decode(s)?; - if payload.len() == 0 { - return Err(Error::EmptyBech32Payload); - } - - // Get the script version and program (converted from 5-bit to 8-bit) - let (version, program): (bech32::u5, Vec) = { - let (v, p5) = payload.split_at(1); - (v[0], bech32::FromBase32::from_base32(p5)?) - }; - - // Generic segwit checks. - if version.to_u8() > 16 { - return Err(Error::InvalidWitnessVersion(version.to_u8())); - } - if program.len() < 2 || program.len() > 40 { - return Err(Error::InvalidWitnessProgramLength(program.len())); - } - - // Specific segwit v0 check. - if version.to_u8() == 0 && (program.len() != 20 && program.len() != 32) { - return Err(Error::InvalidSegwitV0ProgramLength(program.len())); - } - - return Ok(Address { - payload: Payload::WitnessProgram { - version: version, - program: program, - }, - network: network, - }); - } - - // Base58 - if s.len() > 50 { - return Err(Error::Base58(base58::Error::InvalidLength(s.len() * 11 / 15))); - } - let data = base58::from_check(s)?; - if data.len() != 21 { - return Err(Error::Base58(base58::Error::InvalidLength(data.len()))); - } - - let (network, payload) = match data[0] { - 0 => ( - Network::Bitcoin, - Payload::PubkeyHash(PubkeyHash::from_slice(&data[1..]).unwrap()), - ), - 5 => ( - Network::Bitcoin, - Payload::ScriptHash(ScriptHash::from_slice(&data[1..]).unwrap()), - ), - 111 => ( - Network::Testnet, - Payload::PubkeyHash(PubkeyHash::from_slice(&data[1..]).unwrap()), - ), - 196 => ( - Network::Testnet, - Payload::ScriptHash(ScriptHash::from_slice(&data[1..]).unwrap()), - ), - x => return Err(Error::Base58(base58::Error::InvalidVersion(vec![x]))), - }; - - Ok(Address { - network: network, - payload: payload, - }) - } -} - -impl ::std::fmt::Debug for Address { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - write!(f, "{}", self.to_string()) - } -} - -#[cfg(test)] -mod tests { - use std::str::FromStr; - use std::string::ToString; - - use hashes::Hash; - use hex::{decode as hex_decode, encode as hex_encode}; - - use blockdata::script::Script; - use network::constants::Network::{Bitcoin, Testnet}; - use util::key::PublicKey; - - use super::*; - - macro_rules! hex (($hex:expr) => (hex_decode($hex).unwrap())); - macro_rules! hex_key (($hex:expr) => (PublicKey::from_slice(&hex!($hex)).unwrap())); - macro_rules! hex_script (($hex:expr) => (Script::from(hex!($hex)))); - macro_rules! hex_pubkeyhash (($hex:expr) => (PubkeyHash::from_slice(&hex!($hex)).unwrap())); - macro_rules! hex_scripthash (($hex:expr) => (ScriptHash::from_slice(&hex!($hex)).unwrap())); - - fn roundtrips(addr: &Address) { - assert_eq!( - Address::from_str(&addr.to_string()).unwrap(), - *addr, - "string round-trip failed for {}", - addr, - ); - assert_eq!( - Address::from_script(&addr.script_pubkey(), addr.network).as_ref(), - Some(addr), - "script round-trip failed for {}", - addr, - ); - //TODO: add serde roundtrip after no-strason PR - } - - #[test] - fn test_p2pkh_address_58() { - let addr = Address { - network: Bitcoin, - payload: Payload::PubkeyHash(hex_pubkeyhash!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")), - }; - - assert_eq!( - addr.script_pubkey(), - hex_script!("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac") - ); - assert_eq!(&addr.to_string(), "132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM"); - assert_eq!(addr.address_type(), Some(AddressType::P2pkh)); - roundtrips(&addr); - } - - #[test] - fn test_p2pkh_from_key() { - let key = hex_key!("048d5141948c1702e8c95f438815794b87f706a8d4cd2bffad1dc1570971032c9b6042a0431ded2478b5c9cf2d81c124a5e57347a3c63ef0e7716cf54d613ba183"); - let addr = Address::p2pkh(&key, Bitcoin); - assert_eq!(&addr.to_string(), "1QJVDzdqb1VpbDK7uDeyVXy9mR27CJiyhY"); - - let key = hex_key!(&"03df154ebfcf29d29cc10d5c2565018bce2d9edbab267c31d2caf44a63056cf99f"); - let addr = Address::p2pkh(&key, Testnet); - assert_eq!(&addr.to_string(), "mqkhEMH6NCeYjFybv7pvFC22MFeaNT9AQC"); - assert_eq!(addr.address_type(), Some(AddressType::P2pkh)); - roundtrips(&addr); - } - - #[test] - fn test_p2sh_address_58() { - let addr = Address { - network: Bitcoin, - payload: Payload::ScriptHash(hex_scripthash!("162c5ea71c0b23f5b9022ef047c4a86470a5b070")), - }; - - assert_eq!( - addr.script_pubkey(), - hex_script!("a914162c5ea71c0b23f5b9022ef047c4a86470a5b07087") - ); - assert_eq!(&addr.to_string(), "33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k"); - assert_eq!(addr.address_type(), Some(AddressType::P2sh)); - roundtrips(&addr); - } - - #[test] - fn test_p2sh_parse() { - let script = hex_script!("552103a765fc35b3f210b95223846b36ef62a4e53e34e2925270c2c7906b92c9f718eb2103c327511374246759ec8d0b89fa6c6b23b33e11f92c5bc155409d86de0c79180121038cae7406af1f12f4786d820a1466eec7bc5785a1b5e4a387eca6d797753ef6db2103252bfb9dcaab0cd00353f2ac328954d791270203d66c2be8b430f115f451b8a12103e79412d42372c55dd336f2eb6eb639ef9d74a22041ba79382c74da2338fe58ad21035049459a4ebc00e876a9eef02e72a3e70202d3d1f591fc0dd542f93f642021f82102016f682920d9723c61b27f562eb530c926c00106004798b6471e8c52c60ee02057ae"); - let addr = Address::p2sh(&script, Testnet); - - assert_eq!(&addr.to_string(), "2N3zXjbwdTcPsJiy8sUK9FhWJhqQCxA8Jjr"); - assert_eq!(addr.address_type(), Some(AddressType::P2sh)); - roundtrips(&addr); - } - - #[test] - fn test_p2wpkh() { - // stolen from Bitcoin transaction: b3c8c2b6cfc335abbcb2c7823a8453f55d64b2b5125a9a61e8737230cdb8ce20 - let key = hex_key!("033bc8c83c52df5712229a2f72206d90192366c36428cb0c12b6af98324d97bfbc"); - let addr = Address::p2wpkh(&key, Bitcoin); - assert_eq!(&addr.to_string(), "bc1qvzvkjn4q3nszqxrv3nraga2r822xjty3ykvkuw"); - assert_eq!(addr.address_type(), Some(AddressType::P2wpkh)); - roundtrips(&addr); - } - - #[test] - fn test_p2wsh() { - // stolen from Bitcoin transaction 5df912fda4becb1c29e928bec8d64d93e9ba8efa9b5b405bd683c86fd2c65667 - let script = hex_script!("52210375e00eb72e29da82b89367947f29ef34afb75e8654f6ea368e0acdfd92976b7c2103a1b26313f430c4b15bb1fdce663207659d8cac749a0e53d70eff01874496feff2103c96d495bfdd5ba4145e3e046fee45e84a8a48ad05bd8dbb395c011a32cf9f88053ae"); - let addr = Address::p2wsh(&script, Bitcoin); - assert_eq!( - &addr.to_string(), - "bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej" - ); - assert_eq!(addr.address_type(), Some(AddressType::P2wsh)); - roundtrips(&addr); - } - - #[test] - fn test_p2shwpkh() { - // stolen from Bitcoin transaction: ad3fd9c6b52e752ba21425435ff3dd361d6ac271531fc1d2144843a9f550ad01 - let key = hex_key!("026c468be64d22761c30cd2f12cbc7de255d592d7904b1bab07236897cc4c2e766"); - let addr = Address::p2shwpkh(&key, Bitcoin); - assert_eq!(&addr.to_string(), "3QBRmWNqqBGme9er7fMkGqtZtp4gjMFxhE"); - assert_eq!(addr.address_type(), Some(AddressType::P2sh)); - roundtrips(&addr); - } - - #[test] - fn test_p2shwsh() { - // stolen from Bitcoin transaction f9ee2be4df05041d0e0a35d7caa3157495ca4f93b233234c9967b6901dacf7a9 - let script = hex_script!("522103e5529d8eaa3d559903adb2e881eb06c86ac2574ffa503c45f4e942e2a693b33e2102e5f10fcdcdbab211e0af6a481f5532536ec61a5fdbf7183770cf8680fe729d8152ae"); - let addr = Address::p2shwsh(&script, Bitcoin); - assert_eq!(&addr.to_string(), "36EqgNnsWW94SreZgBWc1ANC6wpFZwirHr"); - assert_eq!(addr.address_type(), Some(AddressType::P2sh)); - roundtrips(&addr); - } - - #[test] - fn test_non_existent_segwit_version() { - let version = 13; - // 40-byte program - let program = hex!( - "654f6ea368e0acdfd92976b7c2103a1b26313f430654f6ea368e0acdfd92976b7c2103a1b26313f4" - ); - let addr = Address { - payload: Payload::WitnessProgram { - version: bech32::u5::try_from_u8(version).expect("0<32"), - program: program, - }, - network: Network::Bitcoin, - }; - roundtrips(&addr); - } - - #[test] - fn test_bip173_vectors() { - let valid_vectors = [ - ("BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", "0014751e76e8199196d454941c45d1b3a323f1433bd6"), - ("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7", "00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262"), - ("bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx", "5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6"), - ("BC1SW50QA3JX3S", "6002751e"), - ("bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj", "5210751e76e8199196d454941c45d1b3a323"), - ("tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy", "0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433"), - ]; - for vector in &valid_vectors { - let addr: Address = vector.0.parse().unwrap(); - assert_eq!(&hex_encode(addr.script_pubkey().as_bytes()), vector.1); - roundtrips(&addr); - } - - let invalid_vectors = [ - "tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty", - "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5", - "BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2", - "bc1rw5uspcuh", - "bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90", - "BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P", - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7", - "bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du", - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv", - "bc1gmk9yu", - ]; - for vector in &invalid_vectors { - assert!(vector.parse::
().is_err()); - } - } - - #[test] - #[cfg(feature = "serde")] - fn test_json_serialize() { - use serde_json; - - let addr = Address::from_str("132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM").unwrap(); - let json = serde_json::to_value(&addr).unwrap(); - assert_eq!( - json, - serde_json::Value::String("132F25rTsvBdp9JzLLBHP5mvGY66i1xdiM".to_owned()) - ); - let into: Address = serde_json::from_value(json).unwrap(); - assert_eq!(addr.to_string(), into.to_string()); - assert_eq!( - into.script_pubkey(), - hex_script!("76a914162c5ea71c0b23f5b9022ef047c4a86470a5b07088ac") - ); - - let addr = Address::from_str("33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k").unwrap(); - let json = serde_json::to_value(&addr).unwrap(); - assert_eq!( - json, - serde_json::Value::String("33iFwdLuRpW1uK1RTRqsoi8rR4NpDzk66k".to_owned()) - ); - let into: Address = serde_json::from_value(json).unwrap(); - assert_eq!(addr.to_string(), into.to_string()); - assert_eq!( - into.script_pubkey(), - hex_script!("a914162c5ea71c0b23f5b9022ef047c4a86470a5b07087") - ); - - let addr = - Address::from_str("tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7") - .unwrap(); - let json = serde_json::to_value(&addr).unwrap(); - assert_eq!( - json, - serde_json::Value::String( - "tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7".to_owned() - ) - ); - let into: Address = serde_json::from_value(json).unwrap(); - assert_eq!(addr.to_string(), into.to_string()); - assert_eq!( - into.script_pubkey(), - hex_script!("00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262") - ); - - let addr = Address::from_str("bcrt1q2nfxmhd4n3c8834pj72xagvyr9gl57n5r94fsl").unwrap(); - let json = serde_json::to_value(&addr).unwrap(); - assert_eq!( - json, - serde_json::Value::String("bcrt1q2nfxmhd4n3c8834pj72xagvyr9gl57n5r94fsl".to_owned()) - ); - let into: Address = serde_json::from_value(json).unwrap(); - assert_eq!(addr.to_string(), into.to_string()); - assert_eq!( - into.script_pubkey(), - hex_script!("001454d26dddb59c7073c6a197946ea1841951fa7a74") - ); - } -} diff --git a/src/util/amount.rs b/src/util/amount.rs deleted file mode 100644 index 7d3c0f76..00000000 --- a/src/util/amount.rs +++ /dev/null @@ -1,1347 +0,0 @@ -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Amounts -//! -//! This module mainly introduces the [Amount] and [SignedAmount] types. -//! We refer to the documentation on the types for more information. -//! - -use std::default; -use std::error; -use std::fmt::{self, Write}; -use std::ops; -use std::str::FromStr; - -/// A set of denominations in which amounts can be expressed. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] -pub enum Denomination { - /// BTC - Bitcoin, - /// mBTC - MilliBitcoin, - /// uBTC - MicroBitcoin, - /// bits - Bit, - /// satoshi - Satoshi, - /// msat - MilliSatoshi, -} - -impl Denomination { - /// The number of decimal places more than a satoshi. - fn precision(self) -> i32 { - match self { - Denomination::Bitcoin => -8, - Denomination::MilliBitcoin => -5, - Denomination::MicroBitcoin => -2, - Denomination::Bit => -2, - Denomination::Satoshi => 0, - Denomination::MilliSatoshi => 3, - } - } -} - -impl fmt::Display for Denomination { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(match *self { - Denomination::Bitcoin => "BTC", - Denomination::MilliBitcoin => "mBTC", - Denomination::MicroBitcoin => "uBTC", - Denomination::Bit => "bits", - Denomination::Satoshi => "satoshi", - Denomination::MilliSatoshi => "msat", - }) - } -} - -impl FromStr for Denomination { - type Err = ParseAmountError; - - fn from_str(s: &str) -> Result { - match s { - "BTC" => Ok(Denomination::Bitcoin), - "mBTC" => Ok(Denomination::MilliBitcoin), - "uBTC" => Ok(Denomination::MicroBitcoin), - "bits" => Ok(Denomination::Bit), - "satoshi" => Ok(Denomination::Satoshi), - "sat" => Ok(Denomination::Satoshi), - "msat" => Ok(Denomination::MilliSatoshi), - d => Err(ParseAmountError::UnknownDenomination(d.to_owned())), - } - } -} - -/// An error during amount parsing. -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum ParseAmountError { - /// Amount is negative. - Negative, - /// Amount is too big to fit inside the type. - TooBig, - /// Amount has higher precision than supported by the type. - TooPrecise, - /// Invalid number format. - InvalidFormat, - /// Input string was too large. - InputTooLarge, - /// Invalid character in input. - InvalidCharacter(char), - /// The denomination was unknown. - UnknownDenomination(String), -} - -impl fmt::Display for ParseAmountError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let desc = ::std::error::Error::description(self); - match *self { - ParseAmountError::InvalidCharacter(c) => write!(f, "{}: {}", desc, c), - ParseAmountError::UnknownDenomination(ref d) => write!(f, "{}: {}", desc, d), - _ => f.write_str(desc), - } - } -} - -impl error::Error for ParseAmountError { - fn cause(&self) -> Option<&error::Error> { - None - } - - fn description(&self) -> &'static str { - match *self { - ParseAmountError::Negative => "amount is negative", - ParseAmountError::TooBig => "amount is too big", - ParseAmountError::TooPrecise => "amount has a too high precision", - ParseAmountError::InvalidFormat => "invalid number format", - ParseAmountError::InputTooLarge => "input string was too large", - ParseAmountError::InvalidCharacter(_) => "invalid character in input", - ParseAmountError::UnknownDenomination(_) => "unknown denomination", - } - } -} - - -fn is_too_precise(s: &str, precision: usize) -> bool { - s.contains(".") || precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0') -} - -/// Parse decimal string in the given denomination into a satoshi value and a -/// bool indicator for a negative amount. -fn parse_signed_to_satoshi( - mut s: &str, - denom: Denomination, -) -> Result<(bool, u64), ParseAmountError> { - if s.len() == 0 { - return Err(ParseAmountError::InvalidFormat); - } - if s.len() > 50 { - return Err(ParseAmountError::InputTooLarge); - } - - let is_negative = s.chars().next().unwrap() == '-'; - if is_negative { - if s.len() == 1 { - return Err(ParseAmountError::InvalidFormat); - } - s = &s[1..]; - } - - let max_decimals = { - // The difference in precision between native (satoshi) - // and desired denomination. - let precision_diff = -denom.precision(); - if precision_diff < 0 { - // If precision diff is negative, this means we are parsing - // into a less precise amount. That is not allowed unless - // there are no decimals and the last digits are zeroes as - // many as the difference in precision. - let last_n = precision_diff.abs() as usize; - if is_too_precise(s, last_n) { - return Err(ParseAmountError::TooPrecise); - } - s = &s[0..s.len() - last_n]; - 0 - } else { - precision_diff - } - }; - - let mut decimals = None; - let mut value: u64 = 0; // as satoshis - for c in s.chars() { - match c { - '0'...'9' => { - // Do `value = 10 * value + digit`, catching overflows. - match 10_u64.checked_mul(value) { - None => return Err(ParseAmountError::TooBig), - Some(val) => match val.checked_add((c as u8 - b'0') as u64) { - None => return Err(ParseAmountError::TooBig), - Some(val) => value = val, - }, - } - // Increment the decimal digit counter if past decimal. - decimals = match decimals { - None => None, - Some(d) if d < max_decimals => Some(d + 1), - _ => return Err(ParseAmountError::TooPrecise), - }; - } - '.' => match decimals { - None => decimals = Some(0), - // Double decimal dot. - _ => return Err(ParseAmountError::InvalidFormat), - }, - c => return Err(ParseAmountError::InvalidCharacter(c)), - } - } - - // Decimally shift left by `max_decimals - decimals`. - let scale_factor = max_decimals - decimals.unwrap_or(0); - for _ in 0..scale_factor { - value = match 10_u64.checked_mul(value) { - Some(v) => v, - None => return Err(ParseAmountError::TooBig), - }; - } - - Ok((is_negative, value)) -} - -/// Format the given satoshi amount in the given denomination. -/// -/// Does not include the denomination. -fn fmt_satoshi_in( - satoshi: u64, - negative: bool, - f: &mut fmt::Write, - denom: Denomination, -) -> fmt::Result { - if negative { - f.write_str("-")?; - } - - if denom.precision() > 0 { - // add zeroes in the end - let width = denom.precision() as usize; - write!(f, "{}{:0width$}", satoshi, 0, width = width)?; - } else if denom.precision() < 0 { - // need to inject a comma in the number - let nb_decimals = denom.precision().abs() as usize; - let real = format!("{:0width$}", satoshi, width = nb_decimals); - if real.len() == nb_decimals { - write!(f, "0.{}", &real[real.len() - nb_decimals..])?; - } else { - write!( - f, - "{}.{}", - &real[0..(real.len() - nb_decimals)], - &real[real.len() - nb_decimals..] - )?; - } - } else { - // denom.precision() == 0 - write!(f, "{}", satoshi)?; - } - Ok(()) -} - -/// Amount -/// -/// The [Amount] type can be used to express Bitcoin amounts that supports -/// arithmetic and conversion to various denominations. -/// -/// -/// Warning! -/// -/// This type implements several arithmetic operations from [std::ops]. -/// To prevent errors due to overflow or underflow when using these operations, -/// it is advised to instead use the checked arithmetic methods whose names -/// start with `checked_`. The operations from [std::ops] that [Amount] -/// implements will panic when overflow or underflow occurs. Also note that -/// since the internal representation of amounts is unsigned, subtracting below -/// zero is considered an underflow and will cause a panic if you're not using -/// the checked arithmetic methods. -/// -#[derive(Copy, Clone, Hash)] -pub struct Amount(u64); - -impl Amount { - /// The zero amount. - pub const ZERO: Amount = Amount(0); - /// Exactly one satoshi. - pub const ONE_SAT: Amount = Amount(1); - /// Exactly one bitcoin. - pub const ONE_BTC: Amount = Amount(100_000_000); - - /// Create an [Amount] with satoshi precision and the given number of satoshis. - pub fn from_sat(satoshi: u64) -> Amount { - Amount(satoshi) - } - - /// Get the number of satoshis in this [Amount]. - pub fn as_sat(self) -> u64 { - self.0 - } - - /// The maximum value of an [Amount]. - pub fn max_value() -> Amount { - Amount(u64::max_value()) - } - - /// The minimum value of an [Amount]. - pub fn min_value() -> Amount { - Amount(u64::min_value()) - } - - /// Convert from a value expressing bitcoins to an [Amount]. - pub fn from_btc(btc: f64) -> Result { - Amount::from_float_in(btc, Denomination::Bitcoin) - } - - /// Parse a decimal string as a value in the given denomination. - /// - /// Note: This only parses the value string. If you want to parse a value - /// with denomination, use [FromStr]. - pub fn from_str_in(s: &str, denom: Denomination) -> Result { - let (negative, satoshi) = parse_signed_to_satoshi(s, denom)?; - if negative { - return Err(ParseAmountError::Negative); - } - if satoshi > i64::max_value() as u64 { - return Err(ParseAmountError::TooBig); - } - Ok(Amount::from_sat(satoshi)) - } - - /// Parses amounts with denomination suffix like they are produced with - /// [to_string_with_denomination] or with [fmt::Display]. - /// If you want to parse only the amount without the denomination, - /// use [from_str_in]. - pub fn from_str_with_denomination(s: &str) -> Result { - let mut split = s.splitn(3, " "); - let amt_str = split.next().unwrap(); - let denom_str = split.next().ok_or(ParseAmountError::InvalidFormat)?; - if split.next().is_some() { - return Err(ParseAmountError::InvalidFormat); - } - - Ok(Amount::from_str_in(amt_str, denom_str.parse()?)?) - } - - /// Express this [Amount] as a floating-point value in the given denomination. - /// - /// Please be aware of the risk of using floating-point numbers. - pub fn to_float_in(&self, denom: Denomination) -> f64 { - f64::from_str(&self.to_string_in(denom)).unwrap() - } - - /// Express this [Amount] as a floating-point value in Bitcoin. - /// - /// Equivalent to `to_float_in(Denomination::Bitcoin)`. - /// - /// Please be aware of the risk of using floating-point numbers. - pub fn as_btc(&self) -> f64 { - self.to_float_in(Denomination::Bitcoin) - } - - /// Convert this [Amount] in floating-point notation with a given - /// denomination. - /// Can return error if the amount is too big, too precise or negative. - /// - /// Please be aware of the risk of using floating-point numbers. - pub fn from_float_in(value: f64, denom: Denomination) -> Result { - if value < 0.0 { - return Err(ParseAmountError::Negative); - } - // This is inefficient, but the safest way to deal with this. The parsing logic is safe. - // Any performance-critical application should not be dealing with floats. - Amount::from_str_in(&value.to_string(), denom) - } - - /// Format the value of this [Amount] in the given denomination. - /// - /// Does not include the denomination. - pub fn fmt_value_in(&self, f: &mut fmt::Write, denom: Denomination) -> fmt::Result { - fmt_satoshi_in(self.as_sat(), false, f, denom) - } - - /// Get a string number of this [Amount] in the given denomination. - /// - /// Does not include the denomination. - pub fn to_string_in(&self, denom: Denomination) -> String { - let mut buf = String::new(); - self.fmt_value_in(&mut buf, denom).unwrap(); - buf - } - - /// Get a formatted string of this [Amount] in the given denomination, - /// suffixed with the abbreviation for the denomination. - pub fn to_string_with_denomination(&self, denom: Denomination) -> String { - let mut buf = String::new(); - self.fmt_value_in(&mut buf, denom).unwrap(); - write!(buf, " {}", denom).unwrap(); - buf - } - - // Some arithmetic that doesn't fit in `std::ops` traits. - - /// Checked addition. - /// Returns [None] if overflow occurred. - pub fn checked_add(self, rhs: Amount) -> Option { - self.0.checked_add(rhs.0).map(Amount) - } - - /// Checked subtraction. - /// Returns [None] if overflow occurred. - pub fn checked_sub(self, rhs: Amount) -> Option { - self.0.checked_sub(rhs.0).map(Amount) - } - - /// Checked multiplication. - /// Returns [None] if overflow occurred. - pub fn checked_mul(self, rhs: u64) -> Option { - self.0.checked_mul(rhs).map(Amount) - } - - /// Checked integer division. - /// Be aware that integer division loses the remainder if no exact division - /// can be made. - /// Returns [None] if overflow occurred. - pub fn checked_div(self, rhs: u64) -> Option { - self.0.checked_div(rhs).map(Amount) - } - - /// Checked remainder. - /// Returns [None] if overflow occurred. - pub fn checked_rem(self, rhs: u64) -> Option { - self.0.checked_rem(rhs).map(Amount) - } - - /// Convert to a signed amount. - pub fn to_signed(self) -> Result { - if self.as_sat() > SignedAmount::max_value().as_sat() as u64 { - Err(ParseAmountError::TooBig) - } else { - Ok(SignedAmount::from_sat(self.as_sat() as i64)) - } - } -} - -impl default::Default for Amount { - fn default() -> Self { - Amount::ZERO - } -} - -impl PartialEq for Amount { - fn eq(&self, other: &Amount) -> bool { - PartialEq::eq(&self.0, &other.0) - } -} -impl Eq for Amount {} - -impl PartialOrd for Amount { - fn partial_cmp(&self, other: &Amount) -> Option<::std::cmp::Ordering> { - PartialOrd::partial_cmp(&self.0, &other.0) - } -} - -impl Ord for Amount { - fn cmp(&self, other: &Amount) -> ::std::cmp::Ordering { - Ord::cmp(&self.0, &other.0) - } -} - -impl fmt::Debug for Amount { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Amount({} satoshi)", self.as_sat()) - } -} - -// No one should depend on a binding contract for Display for this type. -// Just using Bitcoin denominated string. -impl fmt::Display for Amount { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.fmt_value_in(f, Denomination::Bitcoin)?; - write!(f, " {}", Denomination::Bitcoin) - } -} - -impl ops::Add for Amount { - type Output = Amount; - - fn add(self, rhs: Amount) -> Self::Output { - self.checked_add(rhs).expect("Amount addition error") - } -} - -impl ops::AddAssign for Amount { - fn add_assign(&mut self, other: Amount) { - *self = *self + other - } -} - -impl ops::Sub for Amount { - type Output = Amount; - - fn sub(self, rhs: Amount) -> Self::Output { - self.checked_sub(rhs).expect("Amount subtraction error") - } -} - -impl ops::SubAssign for Amount { - fn sub_assign(&mut self, other: Amount) { - *self = *self - other - } -} - -impl ops::Rem for Amount { - type Output = Amount; - - fn rem(self, modulus: u64) -> Self { - self.checked_rem(modulus).expect("Amount remainder error") - } -} - -impl ops::RemAssign for Amount { - fn rem_assign(&mut self, modulus: u64) { - *self = *self % modulus - } -} - -impl ops::Mul for Amount { - type Output = Amount; - - fn mul(self, rhs: u64) -> Self::Output { - self.checked_mul(rhs).expect("Amount multiplication error") - } -} - -impl ops::MulAssign for Amount { - fn mul_assign(&mut self, rhs: u64) { - *self = *self * rhs - } -} - -impl ops::Div for Amount { - type Output = Amount; - - fn div(self, rhs: u64) -> Self::Output { - self.checked_div(rhs).expect("Amount division error") - } -} - -impl ops::DivAssign for Amount { - fn div_assign(&mut self, rhs: u64) { - *self = *self / rhs - } -} - -impl FromStr for Amount { - type Err = ParseAmountError; - - fn from_str(s: &str) -> Result { - Amount::from_str_with_denomination(s) - } -} - -/// SignedAmount -/// -/// The [SignedAmount] type can be used to express Bitcoin amounts that supports -/// arithmetic and conversion to various denominations. -/// -/// -/// Warning! -/// -/// This type implements several arithmetic operations from [std::ops]. -/// To prevent errors due to overflow or underflow when using these operations, -/// it is advised to instead use the checked arithmetic methods whose names -/// start with `checked_`. The operations from [std::ops] that [Amount] -/// implements will panic when overflow or underflow occurs. -/// -#[derive(Copy, Clone, Hash)] -pub struct SignedAmount(i64); - -impl SignedAmount { - /// The zero amount. - pub const ZERO: SignedAmount = SignedAmount(0); - /// Exactly one satoshi. - pub const ONE_SAT: SignedAmount = SignedAmount(1); - /// Exactly one bitcoin. - pub const ONE_BTC: SignedAmount = SignedAmount(100_000_000); - - /// Create an [SignedAmount] with satoshi precision and the given number of satoshis. - pub fn from_sat(satoshi: i64) -> SignedAmount { - SignedAmount(satoshi) - } - - /// Get the number of satoshis in this [SignedAmount]. - pub fn as_sat(self) -> i64 { - self.0 - } - - /// The maximum value of an [SignedAmount]. - pub fn max_value() -> SignedAmount { - SignedAmount(i64::max_value()) - } - - /// The minimum value of an [SignedAmount]. - pub fn min_value() -> SignedAmount { - SignedAmount(i64::min_value()) - } - - /// Convert from a value expressing bitcoins to an [SignedAmount]. - pub fn from_btc(btc: f64) -> Result { - SignedAmount::from_float_in(btc, Denomination::Bitcoin) - } - - /// Parse a decimal string as a value in the given denomination. - /// - /// Note: This only parses the value string. If you want to parse a value - /// with denomination, use [FromStr]. - pub fn from_str_in(s: &str, denom: Denomination) -> Result { - let (negative, satoshi) = parse_signed_to_satoshi(s, denom)?; - if satoshi > i64::max_value() as u64 { - return Err(ParseAmountError::TooBig); - } - Ok(match negative { - true => SignedAmount(-1 * satoshi as i64), - false => SignedAmount(satoshi as i64), - }) - } - - /// Parses amounts with denomination suffix like they are produced with - /// [to_string_with_denomination] or with [fmt::Display]. - /// If you want to parse only the amount without the denomination, - /// use [from_str_in]. - pub fn from_str_with_denomination(s: &str) -> Result { - let mut split = s.splitn(3, " "); - let amt_str = split.next().unwrap(); - let denom_str = split.next().ok_or(ParseAmountError::InvalidFormat)?; - if split.next().is_some() { - return Err(ParseAmountError::InvalidFormat); - } - - Ok(SignedAmount::from_str_in(amt_str, denom_str.parse()?)?) - } - - /// Express this [SignedAmount] as a floating-point value in the given denomination. - /// - /// Please be aware of the risk of using floating-point numbers. - pub fn to_float_in(&self, denom: Denomination) -> f64 { - f64::from_str(&self.to_string_in(denom)).unwrap() - } - - /// Express this [SignedAmount] as a floating-point value in Bitcoin. - /// - /// Equivalent to `to_float_in(Denomination::Bitcoin)`. - /// - /// Please be aware of the risk of using floating-point numbers. - pub fn as_btc(&self) -> f64 { - self.to_float_in(Denomination::Bitcoin) - } - - /// Convert this [SignedAmount] in floating-point notation with a given - /// denomination. - /// Can return error if the amount is too big, too precise or negative. - /// - /// Please be aware of the risk of using floating-point numbers. - pub fn from_float_in( - value: f64, - denom: Denomination, - ) -> Result { - // This is inefficient, but the safest way to deal with this. The parsing logic is safe. - // Any performance-critical application should not be dealing with floats. - SignedAmount::from_str_in(&value.to_string(), denom) - } - - /// Format the value of this [SignedAmount] in the given denomination. - /// - /// Does not include the denomination. - pub fn fmt_value_in(&self, f: &mut fmt::Write, denom: Denomination) -> fmt::Result { - fmt_satoshi_in(self.as_sat().abs() as u64, self.is_negative(), f, denom) - } - - /// Get a string number of this [SignedAmount] in the given denomination. - /// - /// Does not include the denomination. - pub fn to_string_in(&self, denom: Denomination) -> String { - let mut buf = String::new(); - self.fmt_value_in(&mut buf, denom).unwrap(); - buf - } - - /// Get a formatted string of this [SignedAmount] in the given denomination, - /// suffixed with the abbreviation for the denomination. - pub fn to_string_with_denomination(&self, denom: Denomination) -> String { - let mut buf = String::new(); - self.fmt_value_in(&mut buf, denom).unwrap(); - write!(buf, " {}", denom).unwrap(); - buf - } - - // Some arithmetic that doesn't fit in `std::ops` traits. - - /// Get the absolute value of this [SignedAmount]. - pub fn abs(self) -> SignedAmount { - SignedAmount(self.0.abs()) - } - - /// Returns a number representing sign of this [SignedAmount]. - /// - /// - `0` if the amount is zero - /// - `1` if the amount is positive - /// - `-1` if the amount is negative - pub fn signum(self) -> i64 { - self.0.signum() - } - - /// Returns `true` if this [SignedAmount] is positive and `false` if - /// this [SignedAmount] is zero or negative. - pub fn is_positive(self) -> bool { - self.0.is_positive() - } - - /// Returns `true` if this [SignedAmount] is negative and `false` if - /// this [SignedAmount] is zero or positive. - pub fn is_negative(self) -> bool { - self.0.is_negative() - } - - /// Checked addition. - /// Returns [None] if overflow occurred. - pub fn checked_add(self, rhs: SignedAmount) -> Option { - self.0.checked_add(rhs.0).map(SignedAmount) - } - - /// Checked subtraction. - /// Returns [None] if overflow occurred. - pub fn checked_sub(self, rhs: SignedAmount) -> Option { - self.0.checked_sub(rhs.0).map(SignedAmount) - } - - /// Checked multiplication. - /// Returns [None] if overflow occurred. - pub fn checked_mul(self, rhs: i64) -> Option { - self.0.checked_mul(rhs).map(SignedAmount) - } - - /// Checked integer division. - /// Be aware that integer division loses the remainder if no exact division - /// can be made. - /// Returns [None] if overflow occurred. - pub fn checked_div(self, rhs: i64) -> Option { - self.0.checked_div(rhs).map(SignedAmount) - } - - /// Checked remainder. - /// Returns [None] if overflow occurred. - pub fn checked_rem(self, rhs: i64) -> Option { - self.0.checked_rem(rhs).map(SignedAmount) - } - - /// Subtraction that doesn't allow negative [SignedAmount]s. - /// Returns [None] if either [self], [rhs] or the result is strictly negative. - pub fn positive_sub(self, rhs: SignedAmount) -> Option { - if self.is_negative() || rhs.is_negative() || rhs > self { - None - } else { - self.checked_sub(rhs) - } - } - - /// Convert to an unsigned amount. - pub fn to_unsigned(self) -> Result { - if self.is_negative() { - Err(ParseAmountError::Negative) - } else { - Ok(Amount::from_sat(self.as_sat() as u64)) - } - } -} - -impl default::Default for SignedAmount { - fn default() -> Self { - SignedAmount::ZERO - } -} - -impl PartialEq for SignedAmount { - fn eq(&self, other: &SignedAmount) -> bool { - PartialEq::eq(&self.0, &other.0) - } -} -impl Eq for SignedAmount {} - -impl PartialOrd for SignedAmount { - fn partial_cmp(&self, other: &SignedAmount) -> Option<::std::cmp::Ordering> { - PartialOrd::partial_cmp(&self.0, &other.0) - } -} - -impl Ord for SignedAmount { - fn cmp(&self, other: &SignedAmount) -> ::std::cmp::Ordering { - Ord::cmp(&self.0, &other.0) - } -} - -impl fmt::Debug for SignedAmount { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "SignedAmount({} satoshi)", self.as_sat()) - } -} - -// No one should depend on a binding contract for Display for this type. -// Just using Bitcoin denominated string. -impl fmt::Display for SignedAmount { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.fmt_value_in(f, Denomination::Bitcoin)?; - write!(f, " {}", Denomination::Bitcoin) - } -} - -impl ops::Add for SignedAmount { - type Output = SignedAmount; - - fn add(self, rhs: SignedAmount) -> Self::Output { - self.checked_add(rhs).expect("SignedAmount addition error") - } -} - -impl ops::AddAssign for SignedAmount { - fn add_assign(&mut self, other: SignedAmount) { - *self = *self + other - } -} - -impl ops::Sub for SignedAmount { - type Output = SignedAmount; - - fn sub(self, rhs: SignedAmount) -> Self::Output { - self.checked_sub(rhs).expect("SignedAmount subtraction error") - } -} - -impl ops::SubAssign for SignedAmount { - fn sub_assign(&mut self, other: SignedAmount) { - *self = *self - other - } -} - -impl ops::Rem for SignedAmount { - type Output = SignedAmount; - - fn rem(self, modulus: i64) -> Self { - self.checked_rem(modulus).expect("SignedAmount remainder error") - } -} - -impl ops::RemAssign for SignedAmount { - fn rem_assign(&mut self, modulus: i64) { - *self = *self % modulus - } -} - -impl ops::Mul for SignedAmount { - type Output = SignedAmount; - - fn mul(self, rhs: i64) -> Self::Output { - self.checked_mul(rhs).expect("SignedAmount multiplication error") - } -} - -impl ops::MulAssign for SignedAmount { - fn mul_assign(&mut self, rhs: i64) { - *self = *self * rhs - } -} - -impl ops::Div for SignedAmount { - type Output = SignedAmount; - - fn div(self, rhs: i64) -> Self::Output { - self.checked_div(rhs).expect("SignedAmount division error") - } -} - -impl ops::DivAssign for SignedAmount { - fn div_assign(&mut self, rhs: i64) { - *self = *self / rhs - } -} - -impl FromStr for SignedAmount { - type Err = ParseAmountError; - - fn from_str(s: &str) -> Result { - SignedAmount::from_str_with_denomination(s) - } -} - -#[cfg(feature = "serde")] -pub mod serde { - // methods are implementation of a standardized serde-specific signature - #![allow(missing_docs)] - - //! This module adds serde serialization and deserialization support for Amounts. - //! Since there is not a default way to serialize and deserialize Amounts, multiple - //! ways are supported and it's up to the user to decide which serialiation to use. - //! The provided modules can be used as follows: - //! - //! ```rust,ignore - //! use serde::{Serialize, Deserialize}; - //! use bitcoin::Amount; - //! - //! #[derive(Serialize, Deserialize)] - //! pub struct HasAmount { - //! #[serde(with = "bitcoin::util::amount::serde::as_btc")] - //! pub amount: Amount, - //! } - //! ``` - - use serde::{Deserialize, Deserializer, Serialize, Serializer}; - use util::amount::{Amount, Denomination, SignedAmount}; - - /// This trait is used only to avoid code duplication and naming collisions - /// of the different serde serialization crates. - pub trait SerdeAmount: Copy + Sized { - fn ser_sat(self, s: S) -> Result; - fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result; - fn ser_btc(self, s: S) -> Result; - fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result; - } - - impl SerdeAmount for Amount { - fn ser_sat(self, s: S) -> Result { - u64::serialize(&self.as_sat(), s) - } - fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result { - Ok(Amount::from_sat(u64::deserialize(d)?)) - } - fn ser_btc(self, s: S) -> Result { - f64::serialize(&self.to_float_in(Denomination::Bitcoin), s) - } - fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result { - use serde::de::Error; - Ok(Amount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?) - } - } - - impl SerdeAmount for SignedAmount { - fn ser_sat(self, s: S) -> Result { - i64::serialize(&self.as_sat(), s) - } - fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result { - Ok(SignedAmount::from_sat(i64::deserialize(d)?)) - } - fn ser_btc(self, s: S) -> Result { - f64::serialize(&self.to_float_in(Denomination::Bitcoin), s) - } - fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result { - use serde::de::Error; - Ok(SignedAmount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?) - } - } - - pub mod as_sat { - //! Serialize and deserialize [Amount] as real numbers denominated in satoshi. - //! Use with `#[serde(with = "amount::serde::as_sat")]`. - - use serde::{Deserializer, Serializer}; - use util::amount::serde::SerdeAmount; - - pub fn serialize(a: &A, s: S) -> Result { - a.ser_sat(s) - } - - pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result { - A::des_sat(d) - } - - pub mod opt { - //! Serialize and deserialize [Optoin] as real numbers denominated in satoshi. - //! Use with `#[serde(default, with = "amount::serde::as_sat::opt")]`. - - use serde::{Deserializer, Serializer}; - use util::amount::serde::SerdeAmount; - - pub fn serialize( - a: &Option, - s: S, - ) -> Result { - match *a { - Some(a) => a.ser_sat(s), - None => s.serialize_none(), - } - } - - pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>( - d: D, - ) -> Result, D::Error> { - Ok(Some(A::des_sat(d)?)) - } - } - } - - pub mod as_btc { - //! Serialize and deserialize [Amount] as JSON numbers denominated in BTC. - //! Use with `#[serde(with = "amount::serde::as_btc")]`. - - use serde::{Deserializer, Serializer}; - use util::amount::serde::SerdeAmount; - - pub fn serialize(a: &A, s: S) -> Result { - a.ser_btc(s) - } - - pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result { - A::des_btc(d) - } - - pub mod opt { - //! Serialize and deserialize [Option] as JSON numbers denominated in BTC. - //! Use with `#[serde(default, with = "amount::serde::as_btc::opt")]`. - - use serde::{Deserializer, Serializer}; - use util::amount::serde::SerdeAmount; - - pub fn serialize( - a: &Option, - s: S, - ) -> Result { - match *a { - Some(a) => a.ser_btc(s), - None => s.serialize_none(), - } - } - - pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>( - d: D, - ) -> Result, D::Error> { - Ok(Some(A::des_btc(d)?)) - } - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::panic; - use std::str::FromStr; - - #[cfg(feature = "serde")] - use serde_test; - - #[test] - fn add_sub_mul_div() { - let sat = Amount::from_sat; - let ssat = SignedAmount::from_sat; - - assert_eq!(sat(15) + sat(15), sat(30)); - assert_eq!(sat(15) - sat(15), sat(0)); - assert_eq!(sat(14) * 3, sat(42)); - assert_eq!(sat(14) / 2, sat(7)); - assert_eq!(sat(14) % 3, sat(2)); - assert_eq!(ssat(15) - ssat(20), ssat(-5)); - assert_eq!(ssat(-14) * 3, ssat(-42)); - assert_eq!(ssat(-14) / 2, ssat(-7)); - assert_eq!(ssat(-14) % 3, ssat(-2)); - - let mut b = ssat(-5); - b += ssat(13); - assert_eq!(b, ssat(8)); - b -= ssat(3); - assert_eq!(b, ssat(5)); - b *= 6; - assert_eq!(b, ssat(30)); - b /= 3; - assert_eq!(b, ssat(10)); - b %= 3; - assert_eq!(b, ssat(1)); - - // panic on overflow - let result = panic::catch_unwind(|| Amount::max_value() + Amount::from_sat(1)); - assert!(result.is_err()); - let result = panic::catch_unwind(|| Amount::from_sat(8446744073709551615) * 3); - assert!(result.is_err()); - } - - #[test] - fn checked_arithmetic() { - let sat = Amount::from_sat; - let ssat = SignedAmount::from_sat; - - assert_eq!(sat(42).checked_add(sat(1)), Some(sat(43))); - assert_eq!(SignedAmount::max_value().checked_add(ssat(1)), None); - assert_eq!(SignedAmount::min_value().checked_sub(ssat(1)), None); - assert_eq!(Amount::max_value().checked_add(sat(1)), None); - assert_eq!(Amount::min_value().checked_sub(sat(1)), None); - - assert_eq!(sat(5).checked_sub(sat(3)), Some(sat(2))); - assert_eq!(sat(5).checked_sub(sat(6)), None); - assert_eq!(ssat(5).checked_sub(ssat(6)), Some(ssat(-1))); - assert_eq!(sat(5).checked_rem(2), Some(sat(1))); - - assert_eq!(sat(5).checked_div(2), Some(sat(2))); // integer division - assert_eq!(ssat(-6).checked_div(2), Some(ssat(-3))); - - assert_eq!(ssat(-5).positive_sub(ssat(3)), None); - assert_eq!(ssat(5).positive_sub(ssat(-3)), None); - assert_eq!(ssat(3).positive_sub(ssat(5)), None); - assert_eq!(ssat(3).positive_sub(ssat(3)), Some(ssat(0))); - assert_eq!(ssat(5).positive_sub(ssat(3)), Some(ssat(2))); - } - - #[test] - fn floating_point() { - use super::Denomination as D; - let f = Amount::from_float_in; - let sf = SignedAmount::from_float_in; - let sat = Amount::from_sat; - let ssat = SignedAmount::from_sat; - - assert_eq!(f(11.22, D::Bitcoin), Ok(sat(1122000000))); - assert_eq!(sf(-11.22, D::MilliBitcoin), Ok(ssat(-1122000))); - assert_eq!(f(11.22, D::Bit), Ok(sat(1122))); - assert_eq!(sf(-1000.0, D::MilliSatoshi), Ok(ssat(-1))); - assert_eq!(f(0.0001234, D::Bitcoin), Ok(sat(12340))); - assert_eq!(sf(-0.00012345, D::Bitcoin), Ok(ssat(-12345))); - - assert_eq!(f(-100.0, D::MilliSatoshi), Err(ParseAmountError::Negative)); - assert_eq!(f(11.22, D::Satoshi), Err(ParseAmountError::TooPrecise)); - assert_eq!(sf(-100.0, D::MilliSatoshi), Err(ParseAmountError::TooPrecise)); - assert_eq!(sf(-100.0, D::MilliSatoshi), Err(ParseAmountError::TooPrecise)); - assert_eq!(f(42.123456781, D::Bitcoin), Err(ParseAmountError::TooPrecise)); - assert_eq!(sf(-184467440738.0, D::Bitcoin), Err(ParseAmountError::TooBig)); - assert_eq!(f(18446744073709551617.0, D::Satoshi), Err(ParseAmountError::TooBig)); - assert_eq!( - f(SignedAmount::max_value().to_float_in(D::Satoshi) + 1.0, D::Satoshi), - Err(ParseAmountError::TooBig) - ); - assert_eq!( - f(Amount::max_value().to_float_in(D::Satoshi) + 1.0, D::Satoshi), - Err(ParseAmountError::TooBig) - ); - - let btc = move |f| SignedAmount::from_btc(f).unwrap(); - assert_eq!(btc(2.5).to_float_in(D::Bitcoin), 2.5); - assert_eq!(btc(-2.5).to_float_in(D::MilliBitcoin), -2500.0); - assert_eq!(btc(2.5).to_float_in(D::Satoshi), 250000000.0); - assert_eq!(btc(-2.5).to_float_in(D::MilliSatoshi), -250000000000.0); - - let btc = move |f| Amount::from_btc(f).unwrap(); - assert_eq!(&btc(0.0012).to_float_in(D::Bitcoin).to_string(), "0.0012") - } - - #[test] - fn parsing() { - use super::ParseAmountError as E; - let btc = Denomination::Bitcoin; - let p = Amount::from_str_in; - let sp = SignedAmount::from_str_in; - - assert_eq!(p("x", btc), Err(E::InvalidCharacter('x'))); - assert_eq!(p("-", btc), Err(E::InvalidFormat)); - assert_eq!(sp("-", btc), Err(E::InvalidFormat)); - assert_eq!(p("-1.0x", btc), Err(E::InvalidCharacter('x'))); - assert_eq!(p("0.0 ", btc), Err(ParseAmountError::InvalidCharacter(' '))); - assert_eq!(p("0.000.000", btc), Err(E::InvalidFormat)); - let more_than_max = format!("1{}", Amount::max_value()); - assert_eq!(p(&more_than_max, btc), Err(E::TooBig)); - assert_eq!(p("0.000000042", btc), Err(E::TooPrecise)); - - assert_eq!(p("1", btc), Ok(Amount::from_sat(1_000_000_00))); - assert_eq!(sp("-.5", btc), Ok(SignedAmount::from_sat(-500_000_00))); - assert_eq!(p("1.1", btc), Ok(Amount::from_sat(1_100_000_00))); - assert_eq!( - p("12345678901.12345678", btc), - Ok(Amount::from_sat(12_345_678_901__123_456_78)) - ); - assert_eq!(p("12.000", Denomination::MilliSatoshi), Err(E::TooPrecise)); - } - - #[test] - fn to_string() { - use super::Denomination as D; - - assert_eq!(Amount::ONE_BTC.to_string_in(D::Bitcoin), "1.00000000"); - assert_eq!(Amount::ONE_BTC.to_string_in(D::Satoshi), "100000000"); - assert_eq!(Amount::ONE_SAT.to_string_in(D::Bitcoin), "0.00000001"); - assert_eq!(SignedAmount::from_sat(-42).to_string_in(D::Bitcoin), "-0.00000042"); - - assert_eq!(Amount::ONE_BTC.to_string_with_denomination(D::Bitcoin), "1.00000000 BTC"); - assert_eq!(Amount::ONE_SAT.to_string_with_denomination(D::MilliSatoshi), "1000 msat"); - assert_eq!( - SignedAmount::ONE_BTC.to_string_with_denomination(D::Satoshi), - "100000000 satoshi" - ); - assert_eq!(Amount::ONE_SAT.to_string_with_denomination(D::Bitcoin), "0.00000001 BTC"); - assert_eq!( - SignedAmount::from_sat(-42).to_string_with_denomination(D::Bitcoin), - "-0.00000042 BTC" - ); - } - - #[test] - fn from_str() { - use super::ParseAmountError as E; - let p = Amount::from_str; - let sp = SignedAmount::from_str; - - assert_eq!(p("x BTC"), Err(E::InvalidCharacter('x'))); - assert_eq!(p("5 BTC BTC"), Err(E::InvalidFormat)); - assert_eq!(p("5 5 BTC"), Err(E::InvalidFormat)); - - assert_eq!(p("5 BCH"), Err(E::UnknownDenomination("BCH".to_owned()))); - - assert_eq!(p("-1 BTC"), Err(E::Negative)); - assert_eq!(p("-0.0 BTC"), Err(E::Negative)); - assert_eq!(p("0.123456789 BTC"), Err(E::TooPrecise)); - assert_eq!(sp("-0.1 satoshi"), Err(E::TooPrecise)); - assert_eq!(p("0.123456 mBTC"), Err(E::TooPrecise)); - assert_eq!(sp("-1.001 bits"), Err(E::TooPrecise)); - assert_eq!(sp("-200000000000 BTC"), Err(E::TooBig)); - assert_eq!(p("18446744073709551616 sat"), Err(E::TooBig)); - - assert_eq!(sp("0 msat"), Err(E::TooPrecise)); - assert_eq!(sp("-0 msat"), Err(E::TooPrecise)); - assert_eq!(sp("000 msat"), Err(E::TooPrecise)); - assert_eq!(sp("-000 msat"), Err(E::TooPrecise)); - assert_eq!(p("0 msat"), Err(E::TooPrecise)); - assert_eq!(p("-0 msat"), Err(E::TooPrecise)); - assert_eq!(p("000 msat"), Err(E::TooPrecise)); - assert_eq!(p("-000 msat"), Err(E::TooPrecise)); - - assert_eq!(p(".5 bits"), Ok(Amount::from_sat(50))); - assert_eq!(sp("-.5 bits"), Ok(SignedAmount::from_sat(-50))); - assert_eq!(p("0.00253583 BTC"), Ok(Amount::from_sat(253583))); - assert_eq!(sp("-5 satoshi"), Ok(SignedAmount::from_sat(-5))); - assert_eq!(p("0.10000000 BTC"), Ok(Amount::from_sat(100_000_00))); - assert_eq!(sp("-100 bits"), Ok(SignedAmount::from_sat(-10_000))); - } - - #[test] - fn to_string_with_denomination_from_str_roundtrip() { - use super::Denomination as D; - - let amt = Amount::from_sat(42); - let denom = Amount::to_string_with_denomination; - assert_eq!(Amount::from_str(&denom(&amt, D::Bitcoin)), Ok(amt)); - assert_eq!(Amount::from_str(&denom(&amt, D::MilliBitcoin)), Ok(amt)); - assert_eq!(Amount::from_str(&denom(&amt, D::MicroBitcoin)), Ok(amt)); - assert_eq!(Amount::from_str(&denom(&amt, D::Bit)), Ok(amt)); - assert_eq!(Amount::from_str(&denom(&amt, D::Satoshi)), Ok(amt)); - assert_eq!(Amount::from_str(&denom(&amt, D::MilliSatoshi)), Ok(amt)); - } - - #[cfg(feature = "serde")] - #[test] - fn serde_as_sat() { - - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct T { - #[serde(with = "::util::amount::serde::as_sat")] - pub amt: Amount, - #[serde(with = "::util::amount::serde::as_sat")] - pub samt: SignedAmount, - } - - serde_test::assert_tokens( - &T { - amt: Amount::from_sat(123456789), - samt: SignedAmount::from_sat(-123456789), - }, - &[ - serde_test::Token::Struct { - name: "T", - len: 2, - }, - serde_test::Token::Str("amt"), - serde_test::Token::U64(123456789), - serde_test::Token::Str("samt"), - serde_test::Token::I64(-123456789), - serde_test::Token::StructEnd, - ], - ); - } - - #[cfg(feature = "serde")] - #[test] - fn serde_as_btc() { - use serde_json; - - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct T { - #[serde(with = "::util::amount::serde::as_btc")] - pub amt: Amount, - #[serde(with = "::util::amount::serde::as_btc")] - pub samt: SignedAmount, - } - - let orig = T { - amt: Amount::from_sat(21_000_000__000_000_01), - samt: SignedAmount::from_sat(-21_000_000__000_000_01), - }; - - let json = "{\"amt\": 21000000.00000001, \ - \"samt\": -21000000.00000001}"; - let t: T = serde_json::from_str(&json).unwrap(); - assert_eq!(t, orig); - - let value: serde_json::Value = serde_json::from_str(&json).unwrap(); - assert_eq!(t, serde_json::from_value(value).unwrap()); - - // errors - let t: Result = - serde_json::from_str("{\"amt\": 1000000.000000001, \"samt\": 1}"); - assert!(t.unwrap_err().to_string().contains(&ParseAmountError::TooPrecise.to_string())); - let t: Result = serde_json::from_str("{\"amt\": -1, \"samt\": 1}"); - assert!(t.unwrap_err().to_string().contains(&ParseAmountError::Negative.to_string())); - } - - #[cfg(feature = "serde")] - #[test] - fn serde_as_btc_opt() { - use serde_json; - - #[derive(Serialize, Deserialize, PartialEq, Debug)] - struct T { - #[serde(default, with = "::util::amount::serde::as_btc::opt")] - pub amt: Option, - #[serde(default, with = "::util::amount::serde::as_btc::opt")] - pub samt: Option, - } - - let with = T { - amt: Some(Amount::from_sat(2__500_000_00)), - samt: Some(SignedAmount::from_sat(-2__500_000_00)), - }; - let without = T { - amt: None, - samt: None, - }; - - let t: T = serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap(); - assert_eq!(t, with); - - let t: T = serde_json::from_str("{}").unwrap(); - assert_eq!(t, without); - - let value_with: serde_json::Value = - serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap(); - assert_eq!(with, serde_json::from_value(value_with).unwrap()); - - let value_without: serde_json::Value = serde_json::from_str("{}").unwrap(); - assert_eq!(without, serde_json::from_value(value_without).unwrap()); - } -} diff --git a/src/util/base58.rs b/src/util/base58.rs deleted file mode 100644 index 2a268eac..00000000 --- a/src/util/base58.rs +++ /dev/null @@ -1,307 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Base58 encoder and decoder - -use std::{error, fmt, str, slice, iter}; - -use hashes::{sha256d, Hash}; - -use util::endian; - -/// An error that might occur during base58 decoding -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Error { - /// Invalid character encountered - BadByte(u8), - /// Checksum was not correct (expected, actual) - BadChecksum(u32, u32), - /// The length (in bytes) of the object was not correct - /// Note that if the length is excessively long the provided length may be - /// an estimate (and the checksum step may be skipped). - InvalidLength(usize), - /// Version byte(s) were not recognized - InvalidVersion(Vec), - /// Checked data was less than 4 bytes - TooShort(usize), - /// Any other error - Other(String) -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::BadByte(b) => write!(f, "invalid base58 character 0x{:x}", b), - Error::BadChecksum(exp, actual) => write!(f, "base58ck checksum 0x{:x} does not match expected 0x{:x}", actual, exp), - Error::InvalidLength(ell) => write!(f, "length {} invalid for this base58 type", ell), - Error::InvalidVersion(ref v) => write!(f, "version {:?} invalid for this base58 type", v), - Error::TooShort(_) => write!(f, "base58ck data not even long enough for a checksum"), - Error::Other(ref s) => f.write_str(s) - } - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { None } - fn description(&self) -> &'static str { - match *self { - Error::BadByte(_) => "invalid b58 character", - Error::BadChecksum(_, _) => "invalid b58ck checksum", - Error::InvalidLength(_) => "invalid length for b58 type", - Error::InvalidVersion(_) => "invalid version for b58 type", - Error::TooShort(_) => "b58ck data less than 4 bytes", - Error::Other(_) => "unknown b58 error" - } - } -} - -/// Vector-like object that holds the first 100 elements on the stack. If more space is needed it -/// will be allocated on the heap. -struct SmallVec { - len: usize, - stack: [T; 100], - heap: Vec, -} - -impl SmallVec { - pub fn new() -> SmallVec { - SmallVec { - len: 0, - stack: [T::default(); 100], - heap: Vec::new(), - } - } - - pub fn push(&mut self, val: T) { - if self.len < 100 { - self.stack[self.len] = val; - self.len += 1; - } else { - self.heap.push(val); - } - } - - pub fn iter(&self) -> iter::Chain, slice::Iter> { - // If len<100 then we just append an empty vec - self.stack[0..self.len].iter().chain(self.heap.iter()) - } - - pub fn iter_mut(&mut self) -> iter::Chain, slice::IterMut> { - // If len<100 then we just append an empty vec - self.stack[0..self.len].iter_mut().chain(self.heap.iter_mut()) - } -} - -static BASE58_CHARS: &'static [u8] = b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - -static BASE58_DIGITS: [Option; 128] = [ - None, None, None, None, None, None, None, None, // 0-7 - None, None, None, None, None, None, None, None, // 8-15 - None, None, None, None, None, None, None, None, // 16-23 - None, None, None, None, None, None, None, None, // 24-31 - None, None, None, None, None, None, None, None, // 32-39 - None, None, None, None, None, None, None, None, // 40-47 - None, Some(0), Some(1), Some(2), Some(3), Some(4), Some(5), Some(6), // 48-55 - Some(7), Some(8), None, None, None, None, None, None, // 56-63 - None, Some(9), Some(10), Some(11), Some(12), Some(13), Some(14), Some(15), // 64-71 - Some(16), None, Some(17), Some(18), Some(19), Some(20), Some(21), None, // 72-79 - Some(22), Some(23), Some(24), Some(25), Some(26), Some(27), Some(28), Some(29), // 80-87 - Some(30), Some(31), Some(32), None, None, None, None, None, // 88-95 - None, Some(33), Some(34), Some(35), Some(36), Some(37), Some(38), Some(39), // 96-103 - Some(40), Some(41), Some(42), Some(43), None, Some(44), Some(45), Some(46), // 104-111 - Some(47), Some(48), Some(49), Some(50), Some(51), Some(52), Some(53), Some(54), // 112-119 - Some(55), Some(56), Some(57), None, None, None, None, None, // 120-127 -]; - -/// Decode base58-encoded string into a byte vector -pub fn from(data: &str) -> Result, Error> { - // 11/15 is just over log_256(58) - let mut scratch = vec![0u8; 1 + data.len() * 11 / 15]; - // Build in base 256 - for d58 in data.bytes() { - // Compute "X = X * 58 + next_digit" in base 256 - if d58 as usize > BASE58_DIGITS.len() { - return Err(Error::BadByte(d58)); - } - let mut carry = match BASE58_DIGITS[d58 as usize] { - Some(d58) => d58 as u32, - None => { return Err(Error::BadByte(d58)); } - }; - for d256 in scratch.iter_mut().rev() { - carry += *d256 as u32 * 58; - *d256 = carry as u8; - carry /= 256; - } - assert_eq!(carry, 0); - } - - // Copy leading zeroes directly - let mut ret: Vec = data.bytes().take_while(|&x| x == BASE58_CHARS[0]) - .map(|_| 0) - .collect(); - // Copy rest of string - ret.extend(scratch.into_iter().skip_while(|&x| x == 0)); - Ok(ret) -} - -/// Decode a base58check-encoded string -pub fn from_check(data: &str) -> Result, Error> { - let mut ret: Vec = from(data)?; - if ret.len() < 4 { - return Err(Error::TooShort(ret.len())); - } - let ck_start = ret.len() - 4; - let expected = endian::slice_to_u32_le(&sha256d::Hash::hash(&ret[..ck_start])[..4]); - let actual = endian::slice_to_u32_le(&ret[ck_start..(ck_start + 4)]); - if expected != actual { - return Err(Error::BadChecksum(expected, actual)); - } - - ret.truncate(ck_start); - Ok(ret) -} - -fn format_iter(writer: &mut W, data: I) -> Result<(), fmt::Error> -where - I: Iterator + Clone, - W: fmt::Write -{ - let mut ret = SmallVec::new(); - - let mut leading_zero_count = 0; - let mut leading_zeroes = true; - // Build string in little endian with 0-58 in place of characters... - for d256 in data { - let mut carry = d256 as usize; - if leading_zeroes && carry == 0 { - leading_zero_count += 1; - } else { - leading_zeroes = false; - } - - for ch in ret.iter_mut() { - let new_ch = *ch as usize * 256 + carry; - *ch = (new_ch % 58) as u8; - carry = new_ch / 58; - } - while carry > 0 { - ret.push((carry % 58) as u8); - carry /= 58; - } - } - - // ... then reverse it and convert to chars - for _ in 0..leading_zero_count { - ret.push(0); - } - - for ch in ret.iter().rev() { - writer.write_char(BASE58_CHARS[*ch as usize] as char)?; - } - - Ok(()) -} - -fn encode_iter(data: I) -> String -where - I: Iterator + Clone, -{ - let mut ret = String::new(); - format_iter(&mut ret, data).expect("writing into string shouldn't fail"); - ret -} - - -/// Directly encode a slice as base58 -pub fn encode_slice(data: &[u8]) -> String { - encode_iter(data.iter().cloned()) -} - -/// Obtain a string with the base58check encoding of a slice -/// (Tack the first 4 256-digits of the object's Bitcoin hash onto the end.) -pub fn check_encode_slice(data: &[u8]) -> String { - let checksum = sha256d::Hash::hash(&data); - encode_iter( - data.iter() - .cloned() - .chain(checksum[0..4].iter().cloned()) - ) -} - -/// Obtain a string with the base58check encoding of a slice -/// (Tack the first 4 256-digits of the object's Bitcoin hash onto the end.) -pub fn check_encode_slice_to_fmt(fmt: &mut fmt::Formatter, data: &[u8]) -> fmt::Result { - let checksum = sha256d::Hash::hash(&data); - let iter = data.iter() - .cloned() - .chain(checksum[0..4].iter().cloned()); - format_iter(fmt, iter) -} - -#[cfg(test)] -mod tests { - use super::*; - use hex::decode as hex_decode; - - #[test] - fn test_base58_encode() { - // Basics - assert_eq!(&encode_slice(&[0][..]), "1"); - assert_eq!(&encode_slice(&[1][..]), "2"); - assert_eq!(&encode_slice(&[58][..]), "21"); - assert_eq!(&encode_slice(&[13, 36][..]), "211"); - - // Leading zeroes - assert_eq!(&encode_slice(&[0, 13, 36][..]), "1211"); - assert_eq!(&encode_slice(&[0, 0, 0, 0, 13, 36][..]), "1111211"); - - // Long input (>100 bytes => has to use heap) - let res = encode_slice(&"BitcoinBitcoinBitcoinBitcoinBitcoinBitcoinBitcoinBitcoinBitcoinBit\ - coinBitcoinBitcoinBitcoinBitcoinBitcoinBitcoinBitcoinBitcoinBitcoinBitcoin".as_bytes()); - let exp = "ZqC5ZdfpZRi7fjA8hbhX5pEE96MdH9hEaC1YouxscPtbJF16qVWksHWR4wwvx7MotFcs2ChbJqK8KJ9X\ - wZznwWn1JFDhhTmGo9v6GjAVikzCsBWZehu7bm22xL8b5zBR5AsBygYRwbFJsNwNkjpyFuDKwmsUTKvkULCvucPJrN5\ - QUdxpGakhqkZFL7RU4yT"; - assert_eq!(&res, exp); - - // Addresses - let addr = hex_decode("00f8917303bfa8ef24f292e8fa1419b20460ba064d").unwrap(); - assert_eq!(&check_encode_slice(&addr[..]), "1PfJpZsjreyVrqeoAfabrRwwjQyoSQMmHH"); - } - - #[test] - fn test_base58_decode() { - // Basics - assert_eq!(from("1").ok(), Some(vec![0u8])); - assert_eq!(from("2").ok(), Some(vec![1u8])); - assert_eq!(from("21").ok(), Some(vec![58u8])); - assert_eq!(from("211").ok(), Some(vec![13u8, 36])); - - // Leading zeroes - assert_eq!(from("1211").ok(), Some(vec![0u8, 13, 36])); - assert_eq!(from("111211").ok(), Some(vec![0u8, 0, 0, 13, 36])); - - // Addresses - assert_eq!(from_check("1PfJpZsjreyVrqeoAfabrRwwjQyoSQMmHH").ok(), - Some(hex_decode("00f8917303bfa8ef24f292e8fa1419b20460ba064d").unwrap())) - } - - #[test] - fn test_base58_roundtrip() { - let s = "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs"; - let v: Vec = from_check(s).unwrap(); - assert_eq!(check_encode_slice(&v[..]), s); - assert_eq!(from_check(&check_encode_slice(&v[..])).ok(), Some(v)); - } -} - diff --git a/src/util/bip143.rs b/src/util/bip143.rs deleted file mode 100644 index 742a53f2..00000000 --- a/src/util/bip143.rs +++ /dev/null @@ -1,240 +0,0 @@ -// Rust Bitcoin Library -// Written in 2018 by -// Andrew Poelstra -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! BIP143 Implementation -//! -//! Implementation of BIP143 Segwit-style signatures. Should be sufficient -//! to create signatures for Segwit transactions (which should be pushed into -//! the appropriate place in the `Transaction::witness` array) or bcash -//! signatures, which are placed in the scriptSig. -//! - -use hashes::Hash; -use hash_types::SigHash; -use blockdata::script::Script; -use blockdata::transaction::{Transaction, TxIn}; -use consensus::encode::Encodable; - -/// Parts of a sighash which are common across inputs or signatures, and which are -/// sufficient (in conjunction with a private key) to sign the transaction -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct SighashComponents { - tx_version: u32, - tx_locktime: u32, - /// Hash of all the previous outputs - pub hash_prevouts: SigHash, - /// Hash of all the input sequence nos - pub hash_sequence: SigHash, - /// Hash of all the outputs in this transaction - pub hash_outputs: SigHash, -} - -impl SighashComponents { - /// Compute the sighash components from an unsigned transaction and auxiliary - /// information about its inputs. - /// For the generated sighashes to be valid, no fields in the transaction may change except for - /// script_sig and witnesses. - pub fn new(tx: &Transaction) -> SighashComponents { - let hash_prevouts = { - let mut enc = SigHash::engine(); - for txin in &tx.input { - txin.previous_output.consensus_encode(&mut enc).unwrap(); - } - SigHash::from_engine(enc) - }; - - let hash_sequence = { - let mut enc = SigHash::engine(); - for txin in &tx.input { - txin.sequence.consensus_encode(&mut enc).unwrap(); - } - SigHash::from_engine(enc) - }; - - let hash_outputs = { - let mut enc = SigHash::engine(); - for txout in &tx.output { - txout.consensus_encode(&mut enc).unwrap(); - } - SigHash::from_engine(enc) - }; - - SighashComponents { - tx_version: tx.version, - tx_locktime: tx.lock_time, - hash_prevouts: hash_prevouts, - hash_sequence: hash_sequence, - hash_outputs: hash_outputs, - } - } - - /// Compute the BIP143 sighash for a `SIGHASH_ALL` signature for the given - /// input. - pub fn sighash_all(&self, txin: &TxIn, script_code: &Script, value: u64) -> SigHash { - let mut enc = SigHash::engine(); - self.tx_version.consensus_encode(&mut enc).unwrap(); - self.hash_prevouts.consensus_encode(&mut enc).unwrap(); - self.hash_sequence.consensus_encode(&mut enc).unwrap(); - txin - .previous_output - .consensus_encode(&mut enc) - .unwrap(); - script_code.consensus_encode(&mut enc).unwrap(); - value.consensus_encode(&mut enc).unwrap(); - txin.sequence.consensus_encode(&mut enc).unwrap(); - self.hash_outputs.consensus_encode(&mut enc).unwrap(); - self.tx_locktime.consensus_encode(&mut enc).unwrap(); - 1u32.consensus_encode(&mut enc).unwrap(); // hashtype - SigHash::from_engine(enc) - } -} - -#[cfg(test)] -mod tests { - use hash_types::SigHash; - use blockdata::script::Script; - use blockdata::transaction::Transaction; - use consensus::encode::deserialize; - use network::constants::Network; - use util::address::Address; - use util::key::PublicKey; - use hashes::hex::FromHex; - use hex; - - use super::*; - - fn p2pkh_hex(pk: &str) -> Script { - let pk = hex::decode(pk).unwrap(); - let pk = PublicKey::from_slice(pk.as_slice()).unwrap(); - let witness_script = Address::p2pkh(&pk, Network::Bitcoin).script_pubkey(); - witness_script - } - - #[test] - fn bip143_p2wpkh() { - let tx = deserialize::( - &Vec::::from_hex( - "0100000002fff7f7881a8099afa6940d42d1e7f6362bec38171ea3edf433541db4e4ad969f000000\ - 0000eeffffffef51e1b804cc89d182d279655c3aa89e815b1b309fe287d9b2b55d57b90ec68a01000000\ - 00ffffffff02202cb206000000001976a9148280b37df378db99f66f85c95a783a76ac7a6d5988ac9093\ - 510d000000001976a9143bde42dbee7e4dbe6a21b2d50ce2f0167faa815988ac11000000", - ).unwrap()[..], - ).unwrap(); - - let witness_script = p2pkh_hex("025476c2e83188368da1ff3e292e7acafcdb3566bb0ad253f62fc70f07aeee6357"); - let value = 600_000_000; - - let comp = SighashComponents::new(&tx); - assert_eq!( - comp, - SighashComponents { - tx_version: 1, - tx_locktime: 17, - hash_prevouts: hex_hash!( - SigHash, "96b827c8483d4e9b96712b6713a7b68d6e8003a781feba36c31143470b4efd37" - ), - hash_sequence: hex_hash!( - SigHash, "52b0a642eea2fb7ae638c36f6252b6750293dbe574a806984b8e4d8548339a3b" - ), - hash_outputs: hex_hash!( - SigHash, "863ef3e1a92afbfdb97f31ad0fc7683ee943e9abcf2501590ff8f6551f47e5e5" - ), - } - ); - - assert_eq!( - comp.sighash_all(&tx.input[1], &witness_script, value), - hex_hash!(SigHash, "c37af31116d1b27caf68aae9e3ac82f1477929014d5b917657d0eb49478cb670") - ); - } - - #[test] - fn bip143_p2wpkh_nested_in_p2sh() { - let tx = deserialize::( - &Vec::::from_hex( - "0100000001db6b1b20aa0fd7b23880be2ecbd4a98130974cf4748fb66092ac4d3ceb1a5477010000\ - 0000feffffff02b8b4eb0b000000001976a914a457b684d7f0d539a46a45bbc043f35b59d0d96388ac00\ - 08af2f000000001976a914fd270b1ee6abcaea97fea7ad0402e8bd8ad6d77c88ac92040000", - ).unwrap()[..], - ).unwrap(); - - let witness_script = p2pkh_hex("03ad1d8e89212f0b92c74d23bb710c00662ad1470198ac48c43f7d6f93a2a26873"); - let value = 1_000_000_000; - - let comp = SighashComponents::new(&tx); - assert_eq!( - comp, - SighashComponents { - tx_version: 1, - tx_locktime: 1170, - hash_prevouts: hex_hash!( - SigHash, "b0287b4a252ac05af83d2dcef00ba313af78a3e9c329afa216eb3aa2a7b4613a" - ), - hash_sequence: hex_hash!( - SigHash, "18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198" - ), - hash_outputs: hex_hash!( - SigHash, "de984f44532e2173ca0d64314fcefe6d30da6f8cf27bafa706da61df8a226c83" - ), - } - ); - - assert_eq!( - comp.sighash_all(&tx.input[0], &witness_script, value), - hex_hash!(SigHash, "64f3b0f4dd2bb3aa1ce8566d220cc74dda9df97d8490cc81d89d735c92e59fb6") - ); - } - - #[test] - fn bip143_p2wsh_nested_in_p2sh() { - let tx = deserialize::( - &Vec::::from_hex( - "010000000136641869ca081e70f394c6948e8af409e18b619df2ed74aa106c1ca29787b96e0100000000\ - ffffffff0200e9a435000000001976a914389ffce9cd9ae88dcc0631e88a821ffdbe9bfe2688acc0832f\ - 05000000001976a9147480a33f950689af511e6e84c138dbbd3c3ee41588ac00000000").unwrap()[..], - ).unwrap(); - - let witness_script = hex_script!( - "56210307b8ae49ac90a048e9b53357a2354b3334e9c8bee813ecb98e99a7e07e8c3ba32103b28f0c28\ - bfab54554ae8c658ac5c3e0ce6e79ad336331f78c428dd43eea8449b21034b8113d703413d57761b8b\ - 9781957b8c0ac1dfe69f492580ca4195f50376ba4a21033400f6afecb833092a9a21cfdf1ed1376e58\ - c5d1f47de74683123987e967a8f42103a6d48b1131e94ba04d9737d61acdaa1322008af9602b3b1486\ - 2c07a1789aac162102d8b661b0b3302ee2f162b09e07a55ad5dfbe673a9f01d9f0c19617681024306b\ - 56ae" - ); - let value = 987654321; - - let comp = SighashComponents::new(&tx); - assert_eq!( - comp, - SighashComponents { - tx_version: 1, - tx_locktime: 0, - hash_prevouts: hex_hash!( - SigHash, "74afdc312af5183c4198a40ca3c1a275b485496dd3929bca388c4b5e31f7aaa0" - ), - hash_sequence: hex_hash!( - SigHash, "3bb13029ce7b1f559ef5e747fcac439f1455a2ec7c5f09b72290795e70665044" - ), - hash_outputs: hex_hash!( - SigHash, "bc4d309071414bed932f98832b27b4d76dad7e6c1346f487a8fdbb8eb90307cc" - ), - } - ); - - assert_eq!( - comp.sighash_all(&tx.input[0], &witness_script, value), - hex_hash!(SigHash, "185c0be5263dce5b4bb50a047973c1b6272bfbd0103a89444597dc40b248ee7c") - ); - } -} diff --git a/src/util/bip158.rs b/src/util/bip158.rs deleted file mode 100644 index 1d71d01d..00000000 --- a/src/util/bip158.rs +++ /dev/null @@ -1,704 +0,0 @@ -// Rust Bitcoin Library -// Written in 2019 by -// The rust-bitcoin developers -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -// This module was largely copied from https://github.com/rust-bitcoin/murmel/blob/master/src/blockfilter.rs -// on 11. June 2019 which is licensed under Apache, that file specifically -// was written entirely by Tamas Blummer, who is re-licensing its contents here as CC0. - -//! -//! # BIP158 Compact Block Filters for Light Clients -//! -//! Implements a structure for compact filters on block data, for use in the BIP 157 light client protocol. -//! The filter construction proposed is an alternative to Bloom filters, as used in BIP 37, -//! that minimizes filter size by using Golomb-Rice coding for compression. -//! -//! USE : -//! // create a block filter for a block (server side) -//! -//! fn get_script_for_coin (coin: &OutPoint) -> Result { -//! // get utxo ... -//! } -//! -//! let filter = BlockFilter::new_script_filter (&block, get_script_for_coin)?; -//! -//! // or create a filter from known raw data -//! let filter = BlockFilter::new(content); -//! -//! // read and evaluate a filter -//! -//! let query: Iterator = // .. some scripts you care about -//! if filter.match_any (&block_hash, &mut query.map(|s| s.as_bytes())) { -//! // get this block -//! } -//! -//! - -use std::{cmp, fmt, io}; -use std::collections::HashSet; -use std::error; -use std::fmt::{Display, Formatter}; -use std::io::Cursor; - -use hashes::{Hash, siphash24}; -use hash_types::{BlockHash, FilterHash}; - -use blockdata::block::Block; -use blockdata::script::Script; -use blockdata::transaction::OutPoint; -use consensus::{Decodable, Encodable}; -use consensus::encode::VarInt; -use util::endian; -use util::hash::BitcoinHash; - -/// Golomb encoding parameter as in BIP-158, see also https://gist.github.com/sipa/576d5f09c3b86c3b1b75598d799fc845 -const P: u8 = 19; -const M: u64 = 784931; - -/// Errors for blockfilter -#[derive(Debug)] -pub enum Error { - /// missing UTXO, can not calculate script filter - UtxoMissing(OutPoint), - /// some IO error reading or writing binary serialization of the filter - Io(io::Error), -} - -impl error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::UtxoMissing(_) => "unresolved UTXO", - Error::Io(_) => "IO Error" - } - } -} - -impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> { - match *self { - Error::UtxoMissing(ref coin) => write!(f, "unresolved UTXO {}", coin), - Error::Io(ref io) => write!(f, "{}", io) - } - } -} - -impl From for Error { - fn from(io: io::Error) -> Self { - Error::Io(io) - } -} - - -/// a computed or read block filter -pub struct BlockFilter { - /// Golomb encoded filter - pub content: Vec -} - -impl BlockFilter { - /// compute this filter's id in a chain of filters - pub fn filter_id(&self, previous_filter_id: &FilterHash) -> FilterHash { - let filter_hash = FilterHash::hash(self.content.as_slice()); - let mut header_data = [0u8; 64]; - header_data[0..32].copy_from_slice(&filter_hash[..]); - header_data[32..64].copy_from_slice(&previous_filter_id[..]); - FilterHash::hash(&header_data) - } - - /// create a new filter from pre-computed data - pub fn new (content: &[u8]) -> BlockFilter { - BlockFilter { content: content.to_vec() } - } - - /// Compute a SCRIPT_FILTER that contains spent and output scripts - pub fn new_script_filter(block: &Block, script_for_coin: M) -> Result - where M: Fn(&OutPoint) -> Result { - let mut out = Cursor::new(Vec::new()); - { - let mut writer = BlockFilterWriter::new(&mut out, block); - writer.add_output_scripts(); - writer.add_input_scripts(script_for_coin)?; - writer.finish()?; - } - Ok(BlockFilter { content: out.into_inner() }) - } - - /// match any query pattern - pub fn match_any(&self, block_hash: &BlockHash, query: &mut Iterator) -> Result { - let filter_reader = BlockFilterReader::new(block_hash); - filter_reader.match_any(&mut Cursor::new(self.content.as_slice()), query) - } - - /// match all query pattern - pub fn match_all(&self, block_hash: &BlockHash, query: &mut Iterator) -> Result { - let filter_reader = BlockFilterReader::new(block_hash); - filter_reader.match_all(&mut Cursor::new(self.content.as_slice()), query) - } -} - -/// Compiles and writes a block filter -pub struct BlockFilterWriter<'a> { - block: &'a Block, - writer: GCSFilterWriter<'a>, -} - -impl<'a> BlockFilterWriter<'a> { - /// Create a block filter writer - pub fn new(writer: &'a mut io::Write, block: &'a Block) -> BlockFilterWriter<'a> { - let block_hash_as_int = block.bitcoin_hash().into_inner(); - let k0 = endian::slice_to_u64_le(&block_hash_as_int[0..8]); - let k1 = endian::slice_to_u64_le(&block_hash_as_int[8..16]); - let writer = GCSFilterWriter::new(writer, k0, k1, M, P); - BlockFilterWriter { block, writer } - } - - /// Add output scripts of the block - excluding OP_RETURN scripts - pub fn add_output_scripts(&mut self) { - for transaction in &self.block.txdata { - for output in &transaction.output { - if !output.script_pubkey.is_op_return() { - self.add_element(output.script_pubkey.as_bytes()); - } - } - } - } - - /// Add consumed output scripts of a block to filter - pub fn add_input_scripts(&mut self, script_for_coin: M) -> Result<(), Error> - where M: Fn(&OutPoint) -> Result { - for script in self.block.txdata.iter() - .skip(1) // skip coinbase - .flat_map(|t| t.input.iter().map(|i| &i.previous_output)) - .map(script_for_coin) { - match script { - Ok(script) => self.add_element(script.as_bytes()), - Err(e) => return Err(e) - } - } - Ok(()) - } - - /// Add arbitrary element to a filter - pub fn add_element(&mut self, data: &[u8]) { - self.writer.add_element(data); - } - - /// Write block filter - pub fn finish(&mut self) -> Result { - self.writer.finish() - } -} - - -/// Reads and interpret a block filter -pub struct BlockFilterReader { - reader: GCSFilterReader -} - -impl BlockFilterReader { - /// Create a block filter reader - pub fn new(block_hash: &BlockHash) -> BlockFilterReader { - let block_hash_as_int = block_hash.into_inner(); - let k0 = endian::slice_to_u64_le(&block_hash_as_int[0..8]); - let k1 = endian::slice_to_u64_le(&block_hash_as_int[8..16]); - BlockFilterReader { reader: GCSFilterReader::new(k0, k1, M, P) } - } - - /// match any query pattern - pub fn match_any(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { - self.reader.match_any(reader, query) - } - - /// match all query pattern - pub fn match_all(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { - self.reader.match_all(reader, query) - } -} - - -/// Golomb-Rice encoded filter reader -pub struct GCSFilterReader { - filter: GCSFilter, - m: u64 -} - -impl GCSFilterReader { - /// Create a new filter reader with specific seed to siphash - pub fn new(k0: u64, k1: u64, m: u64, p: u8) -> GCSFilterReader { - GCSFilterReader { filter: GCSFilter::new(k0, k1, p), m } - } - - /// match any query pattern - pub fn match_any(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { - let mut decoder = reader; - let n_elements: VarInt = Decodable::consensus_decode(&mut decoder).unwrap_or(VarInt(0)); - let ref mut reader = decoder; - // map hashes to [0, n_elements << grp] - let nm = n_elements.0 * self.m; - let mut mapped = query.map(|e| map_to_range(self.filter.hash(e), nm)).collect::>(); - // sort - mapped.sort(); - if mapped.is_empty() { - return Ok(true); - } - if n_elements.0 == 0 { - return Ok(false); - } - - // find first match in two sorted arrays in one read pass - let mut reader = BitStreamReader::new(reader); - let mut data = self.filter.golomb_rice_decode(&mut reader)?; - let mut remaining = n_elements.0 - 1; - for p in mapped { - loop { - if data == p { - return Ok(true); - } else if data < p { - if remaining > 0 { - data += self.filter.golomb_rice_decode(&mut reader)?; - remaining -= 1; - } else { - return Ok(false); - } - } else { - break; - } - } - } - Ok(false) - } - - /// match all query pattern - pub fn match_all(&self, reader: &mut io::Read, query: &mut Iterator) -> Result { - let mut decoder = reader; - let n_elements: VarInt = Decodable::consensus_decode(&mut decoder).unwrap_or(VarInt(0)); - let ref mut reader = decoder; - // map hashes to [0, n_elements << grp] - let nm = n_elements.0 * self.m; - let mut mapped = query.map(|e| map_to_range(self.filter.hash(e), nm)).collect::>(); - // sort - mapped.sort(); - mapped.dedup(); - if mapped.is_empty() { - return Ok(true); - } - if n_elements.0 == 0 { - return Ok(false); - } - - // figure if all mapped are there in one read pass - let mut reader = BitStreamReader::new(reader); - let mut data = self.filter.golomb_rice_decode(&mut reader)?; - let mut remaining = n_elements.0 - 1; - for p in mapped { - loop { - if data == p { - break; - } else if data < p { - if remaining > 0 { - data += self.filter.golomb_rice_decode(&mut reader)?; - remaining -= 1; - } else { - return Ok(false); - } - } else { - return Ok(false); - } - } - } - Ok(true) - } -} - -// fast reduction of hash to [0, nm) range -fn map_to_range(hash: u64, nm: u64) -> u64 { - // Use this once we upgrade to rustc >= 1.26 - // ((hash as u128 * nm as u128) >> 64) as u64 - - #[inline] - fn l(n: u64) -> u64 { n & 0xffffffff } - #[inline] - fn h(n: u64) -> u64 { n >> 32 } - - let a = h(hash); - let b = l(hash); - let c = h(nm); - let d = l(nm); - - a * c + h(a * d + c * b + h(b * d)) -} - -/// Colomb-Rice encoded filter writer -pub struct GCSFilterWriter<'a> { - filter: GCSFilter, - writer: &'a mut io::Write, - elements: HashSet>, - m: u64 -} - -impl<'a> GCSFilterWriter<'a> { - /// Create a new GCS writer wrapping a generic writer, with specific seed to siphash - pub fn new(writer: &'a mut io::Write, k0: u64, k1: u64, m: u64, p: u8) -> GCSFilterWriter<'a> { - GCSFilterWriter { - filter: GCSFilter::new(k0, k1, p), - writer, - elements: HashSet::new(), - m - } - } - - /// Add some data to the filter - pub fn add_element(&mut self, element: &[u8]) { - if !element.is_empty() { - self.elements.insert(element.to_vec()); - } - } - - /// write the filter to the wrapped writer - pub fn finish(&mut self) -> Result { - let nm = self.elements.len() as u64 * self.m; - - // map hashes to [0, n_elements * M) - let mut mapped: Vec<_> = self.elements.iter() - .map(|e| map_to_range(self.filter.hash(e.as_slice()), nm)).collect(); - mapped.sort(); - - // write number of elements as varint - let mut encoder = io::Cursor::new(Vec::new()); - VarInt(mapped.len() as u64).consensus_encode(&mut encoder).unwrap(); - let mut wrote = self.writer.write(encoder.into_inner().as_slice())?; - - // write out deltas of sorted values into a Golonb-Rice coded bit stream - let mut writer = BitStreamWriter::new(self.writer); - let mut last = 0; - for data in mapped { - wrote += self.filter.golomb_rice_encode(&mut writer, data - last)?; - last = data; - } - wrote += writer.flush()?; - Ok(wrote) - } -} - -/// Golomb Coded Set Filter -struct GCSFilter { - k0: u64, // sip hash key - k1: u64, // sip hash key - p: u8 -} - -impl GCSFilter { - /// Create a new filter - fn new(k0: u64, k1: u64, p: u8) -> GCSFilter { - GCSFilter { k0, k1, p } - } - - /// Golomb-Rice encode a number n to a bit stream (Parameter 2^k) - fn golomb_rice_encode(&self, writer: &mut BitStreamWriter, n: u64) -> Result { - let mut wrote = 0; - let mut q = n >> self.p; - while q > 0 { - let nbits = cmp::min(q, 64); - wrote += writer.write(!0u64, nbits as u8)?; - q -= nbits; - } - wrote += writer.write(0, 1)?; - wrote += writer.write(n, self.p)?; - Ok(wrote) - } - - /// Golomb-Rice decode a number from a bit stream (Parameter 2^k) - fn golomb_rice_decode(&self, reader: &mut BitStreamReader) -> Result { - let mut q = 0u64; - while reader.read(1)? == 1 { - q += 1; - } - let r = reader.read(self.p)?; - return Ok((q << self.p) + r); - } - - /// Hash an arbitrary slice with siphash using parameters of this filter - fn hash(&self, element: &[u8]) -> u64 { - siphash24::Hash::hash_to_u64_with_keys(self.k0, self.k1, element) - } -} - -/// Bitwise stream reader -pub struct BitStreamReader<'a> { - buffer: [u8; 1], - offset: u8, - reader: &'a mut io::Read, -} - -impl<'a> BitStreamReader<'a> { - /// Create a new BitStreamReader that reads bitwise from a given reader - pub fn new(reader: &'a mut io::Read) -> BitStreamReader { - BitStreamReader { - buffer: [0u8], - reader: reader, - offset: 8, - } - } - - /// Read nbit bits - pub fn read(&mut self, mut nbits: u8) -> Result { - if nbits > 64 { - return Err(io::Error::new(io::ErrorKind::Other, "can not read more than 64 bits at once")); - } - let mut data = 0u64; - while nbits > 0 { - if self.offset == 8 { - self.reader.read_exact(&mut self.buffer)?; - self.offset = 0; - } - let bits = cmp::min(8 - self.offset, nbits); - data <<= bits; - data |= ((self.buffer[0] << self.offset) >> (8 - bits)) as u64; - self.offset += bits; - nbits -= bits; - } - Ok(data) - } -} - -/// Bitwise stream writer -pub struct BitStreamWriter<'a> { - buffer: [u8; 1], - offset: u8, - writer: &'a mut io::Write, -} - -impl<'a> BitStreamWriter<'a> { - /// Create a new BitStreamWriter that writes bitwise to a given writer - pub fn new(writer: &'a mut io::Write) -> BitStreamWriter { - BitStreamWriter { - buffer: [0u8], - writer: writer, - offset: 0, - } - } - - /// Write nbits bits from data - pub fn write(&mut self, data: u64, mut nbits: u8) -> Result { - if nbits > 64 { - return Err(io::Error::new(io::ErrorKind::Other, "can not write more than 64 bits at once")); - } - let mut wrote = 0; - while nbits > 0 { - let bits = cmp::min(8 - self.offset, nbits); - self.buffer[0] |= ((data << (64 - nbits)) >> (64 - 8 + self.offset)) as u8; - self.offset += bits; - nbits -= bits; - if self.offset == 8 { - wrote += self.flush()?; - } - } - Ok(wrote) - } - - /// flush bits not yet written - pub fn flush(&mut self) -> Result { - if self.offset > 0 { - self.writer.write_all(&self.buffer)?; - self.buffer[0] = 0u8; - self.offset = 0; - Ok(1) - } else { - Ok(0) - } - } -} - -#[cfg(test)] -mod test { - use std::collections::{HashSet, HashMap}; - use std::io::Cursor; - - use hash_types::BlockHash; - use hashes::hex::FromHex; - - use super::*; - - extern crate hex; - extern crate serde_json; - use self::serde_json::{Value}; - - use consensus::encode::deserialize; - - #[test] - fn test_blockfilters() { - - // test vectors from: https://github.com/jimpo/bitcoin/blob/c7efb652f3543b001b4dd22186a354605b14f47e/src/test/data/blockfilters.json - let data = r#" - [ - ["Block Height,Block Hash,Block,[Prev Output Scripts for Block],Previous Basic Header,Basic Filter,Basic Header,Notes"], - [0,"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943","0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4adae5494dffff001d1aa4ae180101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73ffffffff0100f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac00000000",[],"0000000000000000000000000000000000000000000000000000000000000000","019dfca8","21584579b7eb08997773e5aeff3a7f932700042d0ed2a6129012b7d7ae81b750","Genesis block"], - [2,"000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820","0100000006128e87be8b1b4dea47a7247d5528d2702c96826c7a648497e773b800000000e241352e3bec0a95a6217e10c3abb54adfa05abb12c126695595580fb92e222032e7494dffff001d00d235340101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0432e7494d010e062f503253482fffffffff0100f2052a010000002321038a7f6ef1c8ca0c588aa53fa860128077c9e6c11e6830f4d7ee4e763a56b7718fac00000000",[],"d7bdac13a59d745b1add0d2ce852f1a0442e8945fc1bf3848d3cbffd88c24fe1","0174a170","186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0",""], - [3,"000000008b896e272758da5297bcd98fdc6d97c9b765ecec401e286dc1fdbe10","0100000020782a005255b657696ea057d5b98f34defcf75196f64f6eeac8026c0000000041ba5afc532aae03151b8aa87b65e1594f97504a768e010c98c0add79216247186e7494dffff001d058dc2b60101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0486e7494d0151062f503253482fffffffff0100f2052a01000000232103f6d9ff4c12959445ca5549c811683bf9c88e637b222dd2e0311154c4c85cf423ac00000000",[],"186afd11ef2b5e7e3504f2e8cbf8df28a1fd251fe53d60dff8b1467d1b386cf0","016cf7a0","8d63aadf5ab7257cb6d2316a57b16f517bff1c6388f124ec4c04af1212729d2a",""], - [15007,"0000000038c44c703bae0f98cdd6bf30922326340a5996cc692aaae8bacf47ad","0100000002394092aa378fe35d7e9ac79c869b975c4de4374cd75eb5484b0e1e00000000eb9b8670abd44ad6c55cee18e3020fb0c6519e7004b01a16e9164867531b67afc33bc94fffff001d123f10050101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e04c33bc94f0115062f503253482fffffffff0100f2052a01000000232103f268e9ae07e0f8cb2f6e901d87c510d650b97230c0365b021df8f467363cafb1ac00000000",[],"18b5c2b0146d2d09d24fb00ff5b52bd0742f36c9e65527abdb9de30c027a4748","013c3710","07384b01311867949e0c046607c66b7a766d338474bb67f66c8ae9dbd454b20e","Tx has non-standard OP_RETURN output followed by opcodes"], - [49291,"0000000018b07dca1b28b4b5a119f6d6e71698ce1ed96f143f54179ce177a19c","02000000abfaf47274223ca2fea22797e44498240e482cb4c2f2baea088962f800000000604b5b52c32305b15d7542071d8b04e750a547500005d4010727694b6e72a776e55d0d51ffff001d211806480201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0d038bc0000102062f503253482fffffffff01a078072a01000000232102971dd6034ed0cf52450b608d196c07d6345184fcb14deb277a6b82d526a6163dac0000000001000000081cefd96060ecb1c4fbe675ad8a4f8bdc61d634c52b3a1c4116dee23749fe80ff000000009300493046022100866859c21f306538152e83f115bcfbf59ab4bb34887a88c03483a5dff9895f96022100a6dfd83caa609bf0516debc2bf65c3df91813a4842650a1858b3f61cfa8af249014730440220296d4b818bb037d0f83f9f7111665f49532dfdcbec1e6b784526e9ac4046eaa602204acf3a5cb2695e8404d80bf49ab04828bcbe6fc31d25a2844ced7a8d24afbdff01ffffffff1cefd96060ecb1c4fbe675ad8a4f8bdc61d634c52b3a1c4116dee23749fe80ff020000009400483045022100e87899175991aa008176cb553c6f2badbb5b741f328c9845fcab89f8b18cae2302200acce689896dc82933015e7230e5230d5cff8a1ffe82d334d60162ac2c5b0c9601493046022100994ad29d1e7b03e41731a4316e5f4992f0d9b6e2efc40a1ccd2c949b461175c502210099b69fdc2db00fbba214f16e286f6a49e2d8a0d5ffc6409d87796add475478d601ffffffff1e4a6d2d280ea06680d6cf8788ac90344a9c67cca9b06005bbd6d3f6945c8272010000009500493046022100a27400ba52fd842ce07398a1de102f710a10c5599545e6c95798934352c2e4df022100f6383b0b14c9f64b6718139f55b6b9494374755b86bae7d63f5d3e583b57255a01493046022100fdf543292f34e1eeb1703b264965339ec4a450ec47585009c606b3edbc5b617b022100a5fbb1c8de8aaaa582988cdb23622838e38de90bebcaab3928d949aa502a65d401ffffffff1e4a6d2d280ea06680d6cf8788ac90344a9c67cca9b06005bbd6d3f6945c8272020000009400493046022100ac626ac3051f875145b4fe4cfe089ea895aac73f65ab837b1ac30f5d875874fa022100bc03e79fa4b7eb707fb735b95ff6613ca33adeaf3a0607cdcead4cfd3b51729801483045022100b720b04a5c5e2f61b7df0fcf334ab6fea167b7aaede5695d3f7c6973496adbf1022043328c4cc1cdc3e5db7bb895ccc37133e960b2fd3ece98350f774596badb387201ffffffff23a8733e349c97d6cd90f520fdd084ba15ce0a395aad03cd51370602bb9e5db3010000004a00483045022100e8556b72c5e9c0da7371913a45861a61c5df434dfd962de7b23848e1a28c86ca02205d41ceda00136267281be0974be132ac4cda1459fe2090ce455619d8b91045e901ffffffff6856d609b881e875a5ee141c235e2a82f6b039f2b9babe82333677a5570285a6000000006a473044022040a1c631554b8b210fbdf2a73f191b2851afb51d5171fb53502a3a040a38d2c0022040d11cf6e7b41fe1b66c3d08f6ada1aee07a047cb77f242b8ecc63812c832c9a012102bcfad931b502761e452962a5976c79158a0f6d307ad31b739611dac6a297c256ffffffff6856d609b881e875a5ee141c235e2a82f6b039f2b9babe82333677a5570285a601000000930048304502205b109df098f7e932fbf71a45869c3f80323974a826ee2770789eae178a21bfc8022100c0e75615e53ee4b6e32b9bb5faa36ac539e9c05fa2ae6b6de5d09c08455c8b9601483045022009fb7d27375c47bea23b24818634df6a54ecf72d52e0c1268fb2a2c84f1885de022100e0ed4f15d62e7f537da0d0f1863498f9c7c0c0a4e00e4679588c8d1a9eb20bb801ffffffffa563c3722b7b39481836d5edfc1461f97335d5d1e9a23ade13680d0e2c1c371f030000006c493046022100ecc38ae2b1565643dc3c0dad5e961a5f0ea09cab28d024f92fa05c922924157e022100ebc166edf6fbe4004c72bfe8cf40130263f98ddff728c8e67b113dbd621906a601210211a4ed241174708c07206601b44a4c1c29e5ad8b1f731c50ca7e1d4b2a06dc1fffffffff02d0223a00000000001976a91445db0b779c0b9fa207f12a8218c94fc77aff504588ac80f0fa02000000000000000000",["5221033423007d8f263819a2e42becaaf5b06f34cb09919e06304349d950668209eaed21021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae","52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821021d69e2b68c3960903b702af7829fadcd80bd89b158150c85c4a75b2c8cb9c39452ae","522102a7ae1e0971fc1689bd66d2a7296da3a1662fd21a53c9e38979e0f090a375c12d21022adb62335f41eb4e27056ac37d462cda5ad783fa8e0e526ed79c752475db285d52ae","52210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f8179821022adb62335f41eb4e27056ac37d462cda5ad783fa8e0e526ed79c752475db285d52ae","512103b9d1d0e2b4355ec3cdef7c11a5c0beff9e8b8d8372ab4b4e0aaf30e80173001951ae","76a9149144761ebaccd5b4bbdc2a35453585b5637b2f8588ac","522103f1848b40621c5d48471d9784c8174ca060555891ace6d2b03c58eece946b1a9121020ee5d32b54d429c152fdc7b1db84f2074b0564d35400d89d11870f9273ec140c52ae","76a914f4fa1cc7de742d135ea82c17adf0bb9cf5f4fb8388ac"],"ed47705334f4643892ca46396eb3f4196a5e30880589e4009ef38eae895d4a13","0afbc2920af1b027f31f87b592276eb4c32094bb4d3697021b4c6380","b6d98692cec5145f67585f3434ec3c2b3030182e1cb3ec58b855c5c164dfaaa3","Tx pays to empty output script"], - [180480,"00000000fd3ceb2404ff07a785c7fdcc76619edc8ed61bd25134eaa22084366a","020000006058aa080a655aa991a444bd7d1f2defd9a3bbe68aabb69030cf3b4e00000000d2e826bfd7ef0beaa891a7eedbc92cd6a544a6cb61c7bdaa436762eb2123ef9790f5f552ffff001d0002c90f0501000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0e0300c102024608062f503253482fffffffff01c0c6072a01000000232102e769e60137a4df6b0df8ebd387cca44c4c57ae74cc0114a8e8317c8f3bfd85e9ac00000000010000000381a0802911a01ffb025c4dea0bc77963e8c1bb46313b71164c53f72f37fe5248010000000151ffffffffc904b267833d215e2128bd9575242232ac2bc311550c7fc1f0ef6f264b40d14c010000000151ffffffffdf0915666649dba81886519c531649b7b02180b4af67d6885e871299e9d5f775000000000151ffffffff0180817dcb00000000232103bb52138972c48a132fc1f637858c5189607dd0f7fe40c4f20f6ad65f2d389ba4ac0000000001000000018da38b434fba82d66052af74fc5e4e94301b114d9bc03f819dc876398404c8b4010000006c493046022100fe738b7580dc5fb5168e51fc61b5aed211125eb71068031009a22d9bbad752c5022100be5086baa384d40bcab0fa586e4f728397388d86e18b66cc417dc4f7fa4f9878012103f233299455134caa2687bdf15cb0becdfb03bd0ff2ff38e65ec6b7834295c34fffffffff022ebc1400000000001976a9147779b7fba1c1e06b717069b80ca170e8b04458a488ac9879c40f000000001976a9142a0307cd925dbb66b534c4db33003dd18c57015788ac0000000001000000026139a62e3422a602de36c873a225c1d3ca5aeee598539ceecb9f0dc8d1ad0f83010000006b483045022100ad9f32b4a0a2ddc19b5a74eba78123e57616f1b3cfd72ce68c03ea35a3dda1f002200dbd22aa6da17213df5e70dfc3b2611d40f70c98ed9626aa5e2cde9d97461f0a012103ddb295d2f1e8319187738fb4b230fdd9aa29d0e01647f69f6d770b9ab24eea90ffffffff983c82c87cf020040d671956525014d5c2b28c6d948c85e1a522362c0059eeae010000006b4830450221009ca544274c786d30a5d5d25e17759201ea16d3aedddf0b9e9721246f7ef6b32e02202cfa5564b6e87dfd9fd98957820e4d4e6238baeb0f65fe305d91506bb13f5f4f012103c99113deac0d5d044e3ac0346abc02501542af8c8d3759f1382c72ff84e704f7ffffffff02c0c62d00000000001976a914ae19d27efe12f5a886dc79af37ad6805db6f922d88ac70ce2000000000001976a9143b8d051d37a07ea1042067e93efe63dbf73920b988ac000000000100000002be566e8cd9933f0c75c4a82c027f7d0c544d5c101d0607ef6ae5d07b98e7f1dc000000006b483045022036a8cdfd5ea7ebc06c2bfb6e4f942bbf9a1caeded41680d11a3a9f5d8284abad022100cacb92a5be3f39e8bc14db1710910ef7b395fa1e18f45d41c28d914fcdde33be012102bf59abf110b5131fae0a3ce1ec379329b4c896a6ae5d443edb68529cc2bc7816ffffffff96cf67645b76ceb23fe922874847456a15feee1655082ff32d25a6bf2c0dfc90000000006a47304402203471ca2001784a5ac0abab583581f2613523da47ec5f53df833c117b5abd81500220618a2847723d57324f2984678db556dbca1a72230fc7e39df04c2239942ba942012102925c9794fd7bb9f8b29e207d5fc491b1150135a21f505041858889fa4edf436fffffffff026c840f00000000001976a914797fb8777d7991d8284d88bfd421ce520f0f843188ac00ca9a3b000000001976a9146d10f3f592699265d10b106eda37c3ce793f7a8588ac00000000",["","","","76a9142903b138c24be9e070b3e73ec495d77a204615e788ac","76a91433a1941fd9a37b9821d376f5a51bd4b52fa50e2888ac","76a914e4374e8155d0865742ca12b8d4d14d41b57d682f88ac","76a914001fa7459a6cfc64bdc178ba7e7a21603bb2568f88ac","76a914f6039952bc2b307aeec5371bfb96b66078ec17f688ac"],"d34ef98386f413769502808d4bac5f20f8dfd5bffc9eedafaa71de0eb1f01489","0db414c859a07e8205876354a210a75042d0463404913d61a8e068e58a3ae2aa080026","c582d51c0ca365e3fcf36c51cb646d7f83a67e867cb4743fd2128e3e022b700c","Tx spends from empty output script"], - [926485,"000000000000015d6077a411a8f5cc95caf775ccf11c54e27df75ce58d187313","0000002060bbab0edbf3ef8a49608ee326f8fd75c473b7e3982095e2d100000000000000c30134f8c9b6d2470488d7a67a888f6fa12f8692e0c3411fbfb92f0f68f67eedae03ca57ef13021acc22dc4105010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff2f0315230e0004ae03ca57043e3d1e1d0c8796bf579aef0c0000000000122f4e696e6a61506f6f6c2f5345475749542fffffffff038427a112000000001976a914876fbb82ec05caa6af7a3b5e5a983aae6c6cc6d688ac0000000000000000266a24aa21a9ed5c748e121c0fe146d973a4ac26fa4a68b0549d46ee22d25f50a5e46fe1b377ee00000000000000002952534b424c4f434b3acd16772ad61a3c5f00287480b720f6035d5e54c9efc71be94bb5e3727f10909001200000000000000000000000000000000000000000000000000000000000000000000000000100000000010145310e878941a1b2bc2d33797ee4d89d95eaaf2e13488063a2aa9a74490f510a0100000023220020b6744de4f6ec63cc92f7c220cdefeeb1b1bed2b66c8e5706d80ec247d37e65a1ffffffff01002d3101000000001976a9143ebc40e411ed3c76f86711507ab952300890397288ac0400473044022001dd489a5d4e2fbd8a3ade27177f6b49296ba7695c40dbbe650ea83f106415fd02200b23a0602d8ff1bdf79dee118205fc7e9b40672bf31563e5741feb53fb86388501483045022100f88f040e90cc5dc6c6189d04718376ac19ed996bf9e4a3c29c3718d90ffd27180220761711f16c9e3a44f71aab55cbc0634907a1fa8bb635d971a9a01d368727bea10169522103b3623117e988b76aaabe3d63f56a4fc88b228a71e64c4cc551d1204822fe85cb2103dd823066e096f72ed617a41d3ca56717db335b1ea47a1b4c5c9dbdd0963acba621033d7c89bd9da29fa8d44db7906a9778b53121f72191184a9fee785c39180e4be153ae00000000010000000120925534261de4dcebb1ed5ab1b62bfe7a3ef968fb111dc2c910adfebc6e3bdf010000006b483045022100f50198f5ae66211a4f485190abe4dc7accdabe3bc214ebc9ea7069b97097d46e0220316a70a03014887086e335fc1b48358d46cd6bdc9af3b57c109c94af76fc915101210316cff587a01a2736d5e12e53551b18d73780b83c3bfb4fcf209c869b11b6415effffffff0220a10700000000001976a91450333046115eaa0ac9e0216565f945070e44573988ac2e7cd01a000000001976a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac00000000010000000203a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322010000006a47304402204efc3d70e4ca3049c2a425025edf22d5ca355f9ec899dbfbbeeb2268533a0f2b02204780d3739653035af4814ea52e1396d021953f948c29754edd0ee537364603dc012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff03a25f58630d7a1ea52550365fd2156683f56daf6ca73a4b4bbd097e66516322000000006a47304402202d96defdc5b4af71d6ba28c9a6042c2d5ee7bc6de565d4db84ef517445626e03022022da80320e9e489c8f41b74833dfb6a54a4eb5087cdb46eb663eef0b25caa526012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a914b7e6f7ff8658b2d1fb107e3d7be7af4742e6b1b3876f88fc00000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac0000000001000000043ffd60d3818431c495b89be84afac205d5d1ed663009291c560758bbd0a66df5010000006b483045022100f344607de9df42049688dcae8ff1db34c0c7cd25ec05516e30d2bc8f12ac9b2f022060b648f6a21745ea6d9782e17bcc4277b5808326488a1f40d41e125879723d3a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffffa5379401cce30f84731ef1ba65ce27edf2cc7ce57704507ebe8714aa16a96b92010000006a473044022020c37a63bf4d7f564c2192528709b6a38ab8271bd96898c6c2e335e5208661580220435c6f1ad4d9305d2c0a818b2feb5e45d443f2f162c0f61953a14d097fd07064012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff70e731e193235ff12c3184510895731a099112ffca4b00246c60003c40f843ce000000006a473044022053760f74c29a879e30a17b5f03a5bb057a5751a39f86fa6ecdedc36a1b7db04c022041d41c9b95f00d2d10a0373322a9025dba66c942196bc9d8adeb0e12d3024728012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff66b7a71b3e50379c8e85fc18fe3f1a408fc985f257036c34702ba205cef09f6f000000006a4730440220499bf9e2db3db6e930228d0661395f65431acae466634d098612fd80b08459ee022040e069fc9e3c60009f521cef54c38aadbd1251aee37940e6018aadb10f194d6a012103f7a897e4dbecab2264b21917f90664ea8256189ea725d28740cf7ba5d85b5763ffffffff0200e1f5050000000017a9148fc37ad460fdfbd2b44fe446f6e3071a4f64faa6878f447f0b000000001976a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac00000000",["a914feb8a29635c56d9cd913122f90678756bf23887687","76a914c01a7ca16b47be50cbdbc60724f701d52d75156688ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac","76a914913bcc2be49cb534c20474c4dee1e9c4c317e7eb88ac"],"8f13b9a9c85611635b47906c3053ac53cfcec7211455d4cb0d63dc9acc13d472","09027acea61b6cc3fb33f5d52f7d088a6b2f75d234e89ca800","546c574a0472144bcaf9b6aeabf26372ad87c7af7d1ee0dbfae5e099abeae49c","Duplicate pushdata 913bcc2be49cb534c20474c4dee1e9c4c317e7eb"], - [987876,"0000000000000c00901f2049055e2a437c819d79a3d54fd63e6af796cd7b8a79","000000202694f74969fdb542090e95a56bc8aa2d646e27033850e32f1c5f000000000000f7e53676b3f12d5beb524ed617f2d25f5a93b5f4f52c1ba2678260d72712f8dd0a6dfe5740257e1a4b1768960101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff1603e4120ff9c30a1c216900002f424d4920546573742fffffff0001205fa012000000001e76a914c486de584a735ec2f22da7cd9681614681f92173d83d0aa68688ac00000000",[],"fe4d230dbb0f4fec9bed23a5283e08baf996e3f32b93f52c7de1f641ddfd04ad","010c0b40","0965a544743bbfa36f254446e75630c09404b3d164a261892372977538928ed5","Coinbase tx has unparseable output script"], - [1263442,"000000006f27ddfe1dd680044a34548f41bed47eba9e6f0b310da21423bc5f33","000000201c8d1a529c39a396db2db234d5ec152fa651a2872966daccbde028b400000000083f14492679151dbfaa1a825ef4c18518e780c1f91044180280a7d33f4a98ff5f45765aaddc001d38333b9a02010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff230352471300fe5f45765afe94690a000963676d696e6572343208000000000000000000ffffffff024423a804000000001976a914f2c25ac3d59f3d674b1d1d0a25c27339aaac0ba688ac0000000000000000266a24aa21a9edcb26cb3052426b9ebb4d19c819ef87c19677bbf3a7c46ef0855bd1b2abe83491012000000000000000000000000000000000000000000000000000000000000000000000000002000000000101d20978463906ba4ff5e7192494b88dd5eb0de85d900ab253af909106faa22cc5010000000004000000014777ff000000000016001446c29eabe8208a33aa1023c741fa79aa92e881ff0347304402207d7ca96134f2bcfdd6b536536fdd39ad17793632016936f777ebb32c22943fda02206014d2fb8a6aa58279797f861042ba604ebd2f8f61e5bddbd9d3be5a245047b201004b632103eeaeba7ce5dc2470221e9517fb498e8d6bd4e73b85b8be655196972eb9ccd5566754b2752103a40b74d43df244799d041f32ce1ad515a6cd99501701540e38750d883ae21d3a68ac00000000",["002027a5000c7917f785d8fc6e5a55adfca8717ecb973ebb7743849ff956d896a7ed"],"31d66d516a9eda7de865df29f6ef6cb8e4bf9309e5dac899968a9a62a5df61e3","0385acb4f0fe889ef0","4e6d564c2a2452065c205dd7eb2791124e0c4e0dbb064c410c24968572589dec","Includes witness data"], - [1414221,"0000000000000027b2b3b3381f114f674f481544ff2be37ae3788d7e078383b1","000000204ea88307a7959d8207968f152bedca5a93aefab253f1fb2cfb032a400000000070cebb14ec6dbc27a9dfd066d9849a4d3bac5f674665f73a5fe1de01a022a0c851fda85bf05f4c19a779d1450102000000010000000000000000000000000000000000000000000000000000000000000000ffffffff18034d94154d696e6572476174653030310d000000f238f401ffffffff01c817a804000000000000000000",[],"5e5e12d90693c8e936f01847859404c67482439681928353ca1296982042864e","00","021e8882ef5a0ed932edeebbecfeda1d7ce528ec7b3daa27641acf1189d7b5dc","Empty data"] - ] - "#; - - let testdata = serde_json::from_str::(data).unwrap().as_array().unwrap().clone(); - for t in testdata.iter().skip(1) { - let block_hash = BlockHash::from_hex(&t.get(1).unwrap().as_str().unwrap()).unwrap(); - let block: Block = deserialize(hex::decode(&t.get(2).unwrap().as_str().unwrap().as_bytes()).unwrap().as_slice()).unwrap(); - assert_eq!(block.bitcoin_hash(), block_hash); - let scripts = t.get(3).unwrap().as_array().unwrap(); - let previous_filter_id = FilterHash::from_hex(&t.get(4).unwrap().as_str().unwrap()).unwrap(); - let filter_content = hex::decode(&t.get(5).unwrap().as_str().unwrap().as_bytes()).unwrap(); - let filter_id = FilterHash::from_hex(&t.get(6).unwrap().as_str().unwrap()).unwrap(); - - let mut txmap = HashMap::new(); - let mut si = scripts.iter(); - for tx in block.txdata.iter().skip(1) { - for input in tx.input.iter() { - txmap.insert(input.previous_output.clone(), Script::from(hex::decode(si.next().unwrap().as_str().unwrap()).unwrap())); - } - } - - let filter = BlockFilter::new_script_filter(&block, - |o| if let Some(s) = txmap.get(o) { - Ok(s.clone()) - } else { - Err(Error::UtxoMissing(o.clone())) - }).unwrap(); - - let test_filter = BlockFilter::new(filter_content.as_slice()); - - assert_eq!(test_filter.content, filter.content); - - let block_hash = &block.header.bitcoin_hash(); - assert!(filter.match_all(block_hash, &mut txmap.iter() - .filter_map(|(_, s)| if !s.is_empty() { Some(s.as_bytes()) } else { None })).unwrap()); - - for (_, script) in &txmap { - let query = vec![script]; - if !script.is_empty () { - assert!(filter.match_any(&block_hash, &mut query.iter() - .map(|s| s.as_bytes())).unwrap()); - } - } - - assert_eq!(filter_id, filter.filter_id(&previous_filter_id)); - } - } - - #[test] - fn test_filter () { - let mut patterns = HashSet::new(); - - patterns.insert(hex::decode("000000").unwrap()); - patterns.insert(hex::decode("111111").unwrap()); - patterns.insert(hex::decode("222222").unwrap()); - patterns.insert(hex::decode("333333").unwrap()); - patterns.insert(hex::decode("444444").unwrap()); - patterns.insert(hex::decode("555555").unwrap()); - patterns.insert(hex::decode("666666").unwrap()); - patterns.insert(hex::decode("777777").unwrap()); - patterns.insert(hex::decode("888888").unwrap()); - patterns.insert(hex::decode("999999").unwrap()); - patterns.insert(hex::decode("aaaaaa").unwrap()); - patterns.insert(hex::decode("bbbbbb").unwrap()); - patterns.insert(hex::decode("cccccc").unwrap()); - patterns.insert(hex::decode("dddddd").unwrap()); - patterns.insert(hex::decode("eeeeee").unwrap()); - patterns.insert(hex::decode("ffffff").unwrap()); - - let mut out = Cursor::new(Vec::new()); - { - let mut writer = GCSFilterWriter::new(&mut out, 0, 0, M, P); - for p in &patterns { - writer.add_element(p.as_slice()); - } - writer.finish().unwrap(); - } - - let bytes = out.into_inner(); - - { - let mut query = Vec::new(); - query.push(hex::decode("abcdef").unwrap()); - query.push(hex::decode("eeeeee").unwrap()); - - let reader = GCSFilterReader::new(0, 0, M, P); - let mut input = Cursor::new(bytes.clone()); - assert!(reader.match_any(&mut input, &mut query.iter().map(|v| v.as_slice())).unwrap()); - } - { - let mut query = Vec::new(); - query.push(hex::decode("abcdef").unwrap()); - query.push(hex::decode("123456").unwrap()); - - let reader = GCSFilterReader::new(0, 0, M, P); - let mut input = Cursor::new(bytes.clone()); - assert!(!reader.match_any(&mut input, &mut query.iter().map(|v| v.as_slice())).unwrap()); - } - { - let reader = GCSFilterReader::new(0, 0, M, P); - let mut query = Vec::new(); - for p in &patterns { - query.push(p.clone()); - } - let mut input = Cursor::new(bytes.clone()); - assert!(reader.match_all(&mut input, &mut query.iter().map(|v| v.as_slice())).unwrap()); - } - { - let reader = GCSFilterReader::new(0, 0, M, P); - let mut query = Vec::new(); - for p in &patterns { - query.push(p.clone()); - } - query.push(hex::decode("abcdef").unwrap()); - let mut input = Cursor::new(bytes.clone()); - assert!(!reader.match_all(&mut input, &mut query.iter().map(|v| v.as_slice())).unwrap()); - } - } - - #[test] - fn test_bit_stream() { - let mut out = Cursor::new(Vec::new()); - { - let mut writer = BitStreamWriter::new(&mut out); - writer.write(0, 1).unwrap(); // 0 - writer.write(2, 2).unwrap(); // 10 - writer.write(6, 3).unwrap(); // 110 - writer.write(11, 4).unwrap(); // 1011 - writer.write(1, 5).unwrap(); // 00001 - writer.write(32, 6).unwrap(); // 100000 - writer.write(7, 7).unwrap(); // 0000111 - writer.flush().unwrap(); - } - let bytes = out.into_inner(); - assert_eq!("01011010110000110000000001110000", format!("{:08b}{:08b}{:08b}{:08b}", bytes[0], bytes[1], bytes[2], bytes[3])); - { - let mut input = Cursor::new(bytes); - let mut reader = BitStreamReader::new(&mut input); - assert_eq!(reader.read(1).unwrap(), 0); - assert_eq!(reader.read(2).unwrap(), 2); - assert_eq!(reader.read(3).unwrap(), 6); - assert_eq!(reader.read(4).unwrap(), 11); - assert_eq!(reader.read(5).unwrap(), 1); - assert_eq!(reader.read(6).unwrap(), 32); - assert_eq!(reader.read(7).unwrap(), 7); - // 4 bits remained - assert!(reader.read(5).is_err()); - } - } -} diff --git a/src/util/bip32.rs b/src/util/bip32.rs deleted file mode 100644 index 6228dd24..00000000 --- a/src/util/bip32.rs +++ /dev/null @@ -1,980 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! BIP32 Implementation -//! -//! Implementation of BIP32 hierarchical deterministic wallets, as defined -//! at https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki - -use std::default::Default; -use std::{error, fmt}; -use std::str::FromStr; -#[cfg(feature = "serde")] use serde; - -use hash_types::XpubIdentifier; -use hashes::{hex, sha512, Hash, HashEngine, Hmac, HmacEngine}; -use secp256k1::{self, Secp256k1}; - -use network::constants::Network; -use util::{base58, endian}; -use util::key::{PublicKey, PrivateKey}; - -/// A chain code -pub struct ChainCode([u8; 32]); -impl_array_newtype!(ChainCode, u8, 32); -impl_array_newtype_show!(ChainCode); -impl_bytes_newtype!(ChainCode, 32); - -/// A fingerprint -pub struct Fingerprint([u8; 4]); -impl_array_newtype!(Fingerprint, u8, 4); -impl_array_newtype_show!(Fingerprint); -impl_bytes_newtype!(Fingerprint, 4); - -impl Default for Fingerprint { - fn default() -> Fingerprint { Fingerprint([0; 4]) } -} - -/// Extended private key -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct ExtendedPrivKey { - /// The network this key is to be used on - pub network: Network, - /// How many derivations this key is from the master (which is 0) - pub depth: u8, - /// Fingerprint of the parent key (0 for master) - pub parent_fingerprint: Fingerprint, - /// Child number of the key used to derive from parent (0 for master) - pub child_number: ChildNumber, - /// Private key - pub private_key: PrivateKey, - /// Chain code - pub chain_code: ChainCode -} -serde_string_impl!(ExtendedPrivKey, "a BIP-32 extended private key"); - -/// Extended public key -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct ExtendedPubKey { - /// The network this key is to be used on - pub network: Network, - /// How many derivations this key is from the master (which is 0) - pub depth: u8, - /// Fingerprint of the parent key - pub parent_fingerprint: Fingerprint, - /// Child number of the key used to derive from parent (0 for master) - pub child_number: ChildNumber, - /// Public key - pub public_key: PublicKey, - /// Chain code - pub chain_code: ChainCode -} -serde_string_impl!(ExtendedPubKey, "a BIP-32 extended public key"); - -/// A child number for a derived key -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum ChildNumber { - /// Non-hardened key - Normal { - /// Key index, within [0, 2^31 - 1] - index: u32 - }, - /// Hardened key - Hardened { - /// Key index, within [0, 2^31 - 1] - index: u32 - }, -} - -impl ChildNumber { - /// Create a [`Normal`] from an index, returns an error if the index is not within - /// [0, 2^31 - 1]. - /// - /// [`Normal`]: #variant.Normal - pub fn from_normal_idx(index: u32) -> Result { - if index & (1 << 31) == 0 { - Ok(ChildNumber::Normal { index: index }) - } else { - Err(Error::InvalidChildNumber(index)) - } - } - - /// Create a [`Hardened`] from an index, returns an error if the index is not within - /// [0, 2^31 - 1]. - /// - /// [`Hardened`]: #variant.Hardened - pub fn from_hardened_idx(index: u32) -> Result { - if index & (1 << 31) == 0 { - Ok(ChildNumber::Hardened { index: index }) - } else { - Err(Error::InvalidChildNumber(index)) - } - } - - /// Returns `true` if the child number is a [`Normal`] value. - /// - /// [`Normal`]: #variant.Normal - pub fn is_normal(&self) -> bool { - !self.is_hardened() - } - - /// Returns `true` if the child number is a [`Hardened`] value. - /// - /// [`Hardened`]: #variant.Hardened - pub fn is_hardened(&self) -> bool { - match *self { - ChildNumber::Hardened {..} => true, - ChildNumber::Normal {..} => false, - } - } - - /// Returns the child number that is a single increment from this one. - pub fn increment(self) -> Result { - match self { - ChildNumber::Normal{ index: idx } => ChildNumber::from_normal_idx(idx+1), - ChildNumber::Hardened{ index: idx } => ChildNumber::from_hardened_idx(idx+1), - } - } -} - -impl From for ChildNumber { - fn from(number: u32) -> Self { - if number & (1 << 31) != 0 { - ChildNumber::Hardened { index: number ^ (1 << 31) } - } else { - ChildNumber::Normal { index: number } - } - } -} - -impl From for u32 { - fn from(cnum: ChildNumber) -> Self { - match cnum { - ChildNumber::Normal { index } => index, - ChildNumber::Hardened { index } => index | (1 << 31), - } - } -} - -impl fmt::Display for ChildNumber { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - ChildNumber::Hardened { index } => write!(f, "{}'", index), - ChildNumber::Normal { index } => write!(f, "{}", index), - } - } -} - -impl FromStr for ChildNumber { - type Err = Error; - - fn from_str(inp: &str) -> Result { - Ok(match inp.chars().last().map_or(false, |l| l == '\'' || l == 'h') { - true => ChildNumber::from_hardened_idx( - inp[0..inp.len() - 1].parse().map_err(|_| Error::InvalidChildNumberFormat)? - )?, - false => ChildNumber::from_normal_idx( - inp.parse().map_err(|_| Error::InvalidChildNumberFormat)? - )?, - }) - } -} - -#[cfg(feature = "serde")] -impl<'de> serde::Deserialize<'de> for ChildNumber { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - u32::deserialize(deserializer).map(ChildNumber::from) - } -} - -#[cfg(feature = "serde")] -impl serde::Serialize for ChildNumber { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - u32::from(*self).serialize(serializer) - } -} - -/// A BIP-32 derivation path. -#[derive(Clone, PartialEq, Eq)] -pub struct DerivationPath(Vec); -impl_index_newtype!(DerivationPath, ChildNumber); -serde_string_impl!(DerivationPath, "a BIP-32 derivation path"); - -impl From> for DerivationPath { - fn from(numbers: Vec) -> Self { - DerivationPath(numbers) - } -} - -impl Into> for DerivationPath { - fn into(self) -> Vec { - self.0 - } -} - -impl<'a> From<&'a [ChildNumber]> for DerivationPath { - fn from(numbers: &'a [ChildNumber]) -> Self { - DerivationPath(numbers.to_vec()) - } -} - -impl ::std::iter::FromIterator for DerivationPath { - fn from_iter(iter: T) -> Self where T: IntoIterator { - DerivationPath(Vec::from_iter(iter)) - } -} - -impl<'a> ::std::iter::IntoIterator for &'a DerivationPath { - type Item = &'a ChildNumber; - type IntoIter = ::std::slice::Iter<'a, ChildNumber>; - fn into_iter(self) -> Self::IntoIter { - self.0.iter() - } -} - -impl AsRef<[ChildNumber]> for DerivationPath { - fn as_ref(&self) -> &[ChildNumber] { - &self.0 - } -} - -impl FromStr for DerivationPath { - type Err = Error; - - fn from_str(path: &str) -> Result { - let mut parts = path.split("/"); - // First parts must be `m`. - if parts.next().unwrap() != "m" { - return Err(Error::InvalidDerivationPathFormat); - } - - let ret: Result, Error> = parts.map(str::parse).collect(); - Ok(DerivationPath(ret?)) - } -} - -/// An iterator over children of a [DerivationPath]. -/// -/// It is returned by the methods [DerivationPath::children_since], -/// [DerivationPath::normal_children] and [DerivationPath::hardened_children]. -pub struct DerivationPathIterator<'a> { - base: &'a DerivationPath, - next_child: Option, -} - -impl<'a> DerivationPathIterator<'a> { - /// Start a new [DerivationPathIterator] at the given child. - pub fn start_from(path: &'a DerivationPath, start: ChildNumber) -> DerivationPathIterator<'a> { - DerivationPathIterator { - base: path, - next_child: Some(start), - } - } -} - -impl<'a> Iterator for DerivationPathIterator<'a> { - type Item = DerivationPath; - - fn next(&mut self) -> Option { - if self.next_child.is_none() { - return None; - } - - let ret = self.next_child.unwrap(); - self.next_child = ret.increment().ok(); - Some(self.base.child(ret)) - } -} - -impl DerivationPath { - /// Create a new [DerivationPath] that is a child of this one. - pub fn child(&self, cn: ChildNumber) -> DerivationPath { - let mut path = self.0.clone(); - path.push(cn); - DerivationPath(path) - } - - /// Convert into a [DerivationPath] that is a child of this one. - pub fn into_child(self, cn: ChildNumber) -> DerivationPath { - let mut path = self.0; - path.push(cn); - DerivationPath(path) - } - - /// Get an [Iterator] over the children of this [DerivationPath] - /// starting with the given [ChildNumber]. - pub fn children_from(&self, cn: ChildNumber) -> DerivationPathIterator { - DerivationPathIterator::start_from(&self, cn) - } - - /// Get an [Iterator] over the unhardened children of this [DerivationPath]. - pub fn normal_children(&self) -> DerivationPathIterator { - DerivationPathIterator::start_from(&self, ChildNumber::Normal{ index: 0 }) - } - - /// Get an [Iterator] over the hardened children of this [DerivationPath]. - pub fn hardened_children(&self) -> DerivationPathIterator { - DerivationPathIterator::start_from(&self, ChildNumber::Hardened{ index: 0 }) - } -} - -impl fmt::Display for DerivationPath { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("m")?; - for cn in self.0.iter() { - f.write_str("/")?; - fmt::Display::fmt(cn, f)?; - } - Ok(()) - } -} - -impl fmt::Debug for DerivationPath { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self, f) - } -} - -/// A BIP32 error -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum Error { - /// A pk->pk derivation was attempted on a hardened key - CannotDeriveFromHardenedKey, - /// A secp256k1 error occurred - Ecdsa(secp256k1::Error), - /// A child number was provided that was out of range - InvalidChildNumber(u32), - /// Error creating a master seed --- for application use - RngError(String), - /// Invalid childnumber format. - InvalidChildNumberFormat, - /// Invalid derivation path format. - InvalidDerivationPathFormat, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::CannotDeriveFromHardenedKey => f.write_str("cannot derive hardened key from public key"), - Error::Ecdsa(ref e) => fmt::Display::fmt(e, f), - Error::InvalidChildNumber(ref n) => write!(f, "child number {} is invalid (not within [0, 2^31 - 1])", n), - Error::RngError(ref s) => write!(f, "rng error {}", s), - Error::InvalidChildNumberFormat => f.write_str("invalid child number format"), - Error::InvalidDerivationPathFormat => f.write_str("invalid derivation path format"), - } - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { - if let Error::Ecdsa(ref e) = *self { - Some(e) - } else { - None - } - } - - fn description(&self) -> &str { - match *self { - Error::CannotDeriveFromHardenedKey => "cannot derive hardened key from public key", - Error::Ecdsa(ref e) => error::Error::description(e), - Error::InvalidChildNumber(_) => "child number is invalid", - Error::RngError(_) => "rng error", - Error::InvalidChildNumberFormat => "invalid child number format", - Error::InvalidDerivationPathFormat => "invalid derivation path format", - } - } -} - -impl From for Error { - fn from(e: secp256k1::Error) -> Error { Error::Ecdsa(e) } -} - -impl ExtendedPrivKey { - /// Construct a new master key from a seed value - pub fn new_master(network: Network, seed: &[u8]) -> Result { - let mut hmac_engine: HmacEngine = HmacEngine::new(b"Bitcoin seed"); - hmac_engine.input(seed); - let hmac_result: Hmac = Hmac::from_engine(hmac_engine); - - Ok(ExtendedPrivKey { - network: network, - depth: 0, - parent_fingerprint: Default::default(), - child_number: ChildNumber::from_normal_idx(0)?, - private_key: PrivateKey { - compressed: true, - network: network, - key: secp256k1::SecretKey::from_slice( - &hmac_result[..32] - ).map_err(Error::Ecdsa)?, - }, - chain_code: ChainCode::from(&hmac_result[32..]), - }) - } - - /// Attempts to derive an extended private key from a path. - /// - /// The `path` argument can be both of type `DerivationPath` or `Vec`. - pub fn derive_priv>( - &self, - secp: &Secp256k1, - path: &P, - ) -> Result { - let mut sk: ExtendedPrivKey = *self; - for cnum in path.as_ref() { - sk = sk.ckd_priv(secp, *cnum)?; - } - Ok(sk) - } - - /// Private->Private child key derivation - pub fn ckd_priv(&self, secp: &Secp256k1, i: ChildNumber) -> Result { - let mut hmac_engine: HmacEngine = HmacEngine::new(&self.chain_code[..]); - match i { - ChildNumber::Normal {..} => { - // Non-hardened key: compute public data and use that - hmac_engine.input(&PublicKey::from_private_key(secp, &self.private_key).key.serialize()[..]); - } - ChildNumber::Hardened {..} => { - // Hardened key: use only secret data to prevent public derivation - hmac_engine.input(&[0u8]); - hmac_engine.input(&self.private_key[..]); - } - } - - hmac_engine.input(&endian::u32_to_array_be(u32::from(i))); - let hmac_result: Hmac = Hmac::from_engine(hmac_engine); - let mut sk = PrivateKey { - compressed: true, - network: self.network, - key: secp256k1::SecretKey::from_slice(&hmac_result[..32]).map_err(Error::Ecdsa)?, - }; - sk.key.add_assign(&self.private_key[..]).map_err(Error::Ecdsa)?; - - Ok(ExtendedPrivKey { - network: self.network, - depth: self.depth + 1, - parent_fingerprint: self.fingerprint(secp), - child_number: i, - private_key: sk, - chain_code: ChainCode::from(&hmac_result[32..]) - }) - } - - /// Returns the HASH160 of the chaincode - pub fn identifier(&self, secp: &Secp256k1) -> XpubIdentifier { - ExtendedPubKey::from_private(secp, self).identifier() - } - - /// Returns the first four bytes of the identifier - pub fn fingerprint(&self, secp: &Secp256k1) -> Fingerprint { - Fingerprint::from(&self.identifier(secp)[0..4]) - } -} - -impl ExtendedPubKey { - /// Derives a public key from a private key - pub fn from_private(secp: &Secp256k1, sk: &ExtendedPrivKey) -> ExtendedPubKey { - ExtendedPubKey { - network: sk.network, - depth: sk.depth, - parent_fingerprint: sk.parent_fingerprint, - child_number: sk.child_number, - public_key: PublicKey::from_private_key(secp, &sk.private_key), - chain_code: sk.chain_code - } - } - - /// Attempts to derive an extended public key from a path. - /// - /// The `path` argument can be both of type `DerivationPath` or `Vec`. - pub fn derive_pub>( - &self, - secp: &Secp256k1, - path: &P, - ) -> Result { - let mut pk: ExtendedPubKey = *self; - for cnum in path.as_ref() { - pk = pk.ckd_pub(secp, *cnum)? - } - Ok(pk) - } - - /// Compute the scalar tweak added to this key to get a child key - pub fn ckd_pub_tweak(&self, i: ChildNumber) -> Result<(PrivateKey, ChainCode), Error> { - match i { - ChildNumber::Hardened {..} => { - Err(Error::CannotDeriveFromHardenedKey) - } - ChildNumber::Normal { index: n } => { - let mut hmac_engine: HmacEngine = HmacEngine::new(&self.chain_code[..]); - hmac_engine.input(&self.public_key.key.serialize()[..]); - hmac_engine.input(&endian::u32_to_array_be(n)); - - let hmac_result: Hmac = Hmac::from_engine(hmac_engine); - - let private_key = PrivateKey { - compressed: true, - network: self.network, - key: secp256k1::SecretKey::from_slice(&hmac_result[..32])?, - }; - let chain_code = ChainCode::from(&hmac_result[32..]); - Ok((private_key, chain_code)) - } - } - } - - /// Public->Public child key derivation - pub fn ckd_pub( - &self, - secp: &Secp256k1, - i: ChildNumber, - ) -> Result { - let (sk, chain_code) = self.ckd_pub_tweak(i)?; - let mut pk = self.public_key.clone(); - pk.key.add_exp_assign(secp, &sk[..]).map_err(Error::Ecdsa)?; - - Ok(ExtendedPubKey { - network: self.network, - depth: self.depth + 1, - parent_fingerprint: self.fingerprint(), - child_number: i, - public_key: pk, - chain_code: chain_code - }) - } - - /// Returns the HASH160 of the chaincode - pub fn identifier(&self) -> XpubIdentifier { - let mut engine = XpubIdentifier::engine(); - self.public_key.write_into(&mut engine); - XpubIdentifier::from_engine(engine) - } - - /// Returns the first four bytes of the identifier - pub fn fingerprint(&self) -> Fingerprint { - Fingerprint::from(&self.identifier()[0..4]) - } -} - -impl fmt::Display for ExtendedPrivKey { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut ret = [0; 78]; - ret[0..4].copy_from_slice(&match self.network { - Network::Bitcoin => [0x04, 0x88, 0xAD, 0xE4], - Network::Testnet | Network::Regtest => [0x04, 0x35, 0x83, 0x94], - }[..]); - ret[4] = self.depth as u8; - ret[5..9].copy_from_slice(&self.parent_fingerprint[..]); - ret[9..13].copy_from_slice(&endian::u32_to_array_be(u32::from(self.child_number))); - ret[13..45].copy_from_slice(&self.chain_code[..]); - ret[45] = 0; - ret[46..78].copy_from_slice(&self.private_key[..]); - fmt.write_str(&base58::check_encode_slice(&ret[..])) - } -} - -impl FromStr for ExtendedPrivKey { - type Err = base58::Error; - - fn from_str(inp: &str) -> Result { - let data = base58::from_check(inp)?; - - if data.len() != 78 { - return Err(base58::Error::InvalidLength(data.len())); - } - - let cn_int: u32 = endian::slice_to_u32_be(&data[9..13]); - let child_number: ChildNumber = ChildNumber::from(cn_int); - - let network = if &data[0..4] == [0x04u8, 0x88, 0xAD, 0xE4] { - Network::Bitcoin - } else if &data[0..4] == [0x04u8, 0x35, 0x83, 0x94] { - Network::Testnet - } else { - return Err(base58::Error::InvalidVersion((&data[0..4]).to_vec())); - }; - - Ok(ExtendedPrivKey { - network: network, - depth: data[4], - parent_fingerprint: Fingerprint::from(&data[5..9]), - child_number: child_number, - chain_code: ChainCode::from(&data[13..45]), - private_key: PrivateKey { - compressed: true, - network: network, - key: secp256k1::SecretKey::from_slice( - &data[46..78] - ).map_err(|e| - base58::Error::Other(e.to_string()) - )?, - }, - }) - } -} - -impl fmt::Display for ExtendedPubKey { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - let mut ret = [0; 78]; - ret[0..4].copy_from_slice(&match self.network { - Network::Bitcoin => [0x04u8, 0x88, 0xB2, 0x1E], - Network::Testnet | Network::Regtest => [0x04u8, 0x35, 0x87, 0xCF], - }[..]); - ret[4] = self.depth as u8; - ret[5..9].copy_from_slice(&self.parent_fingerprint[..]); - ret[9..13].copy_from_slice(&endian::u32_to_array_be(u32::from(self.child_number))); - ret[13..45].copy_from_slice(&self.chain_code[..]); - ret[45..78].copy_from_slice(&self.public_key.key.serialize()[..]); - fmt.write_str(&base58::check_encode_slice(&ret[..])) - } -} - -impl FromStr for ExtendedPubKey { - type Err = base58::Error; - - fn from_str(inp: &str) -> Result { - let data = base58::from_check(inp)?; - - if data.len() != 78 { - return Err(base58::Error::InvalidLength(data.len())); - } - - let cn_int: u32 = endian::slice_to_u32_be(&data[9..13]); - let child_number: ChildNumber = ChildNumber::from(cn_int); - - Ok(ExtendedPubKey { - network: if &data[0..4] == [0x04u8, 0x88, 0xB2, 0x1E] { - Network::Bitcoin - } else if &data[0..4] == [0x04u8, 0x35, 0x87, 0xCF] { - Network::Testnet - } else { - return Err(base58::Error::InvalidVersion((&data[0..4]).to_vec())); - }, - depth: data[4], - parent_fingerprint: Fingerprint::from(&data[5..9]), - child_number: child_number, - chain_code: ChainCode::from(&data[13..45]), - public_key: PublicKey::from_slice( - &data[45..78]).map_err(|e| - base58::Error::Other(e.to_string()))? - }) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use super::ChildNumber::{Hardened, Normal}; - - use std::str::FromStr; - use std::string::ToString; - - use secp256k1::{self, Secp256k1}; - use hex::decode as hex_decode; - - use network::constants::Network::{self, Bitcoin}; - - #[test] - fn test_parse_derivation_path() { - assert_eq!(DerivationPath::from_str("42"), Err(Error::InvalidDerivationPathFormat)); - assert_eq!(DerivationPath::from_str("n/0'/0"), Err(Error::InvalidDerivationPathFormat)); - assert_eq!(DerivationPath::from_str("4/m/5"), Err(Error::InvalidDerivationPathFormat)); - assert_eq!(DerivationPath::from_str("m//3/0'"), Err(Error::InvalidChildNumberFormat)); - assert_eq!(DerivationPath::from_str("m/0h/0x"), Err(Error::InvalidChildNumberFormat)); - assert_eq!(DerivationPath::from_str("m/2147483648"), Err(Error::InvalidChildNumber(2147483648))); - - assert_eq!(DerivationPath::from_str("m"), Ok(vec![].into())); - assert_eq!( - DerivationPath::from_str("m/0'"), - Ok(vec![ChildNumber::from_hardened_idx(0).unwrap()].into()) - ); - assert_eq!( - DerivationPath::from_str("m/0'/1"), - Ok(vec![ChildNumber::from_hardened_idx(0).unwrap(), ChildNumber::from_normal_idx(1).unwrap()].into()) - ); - assert_eq!( - DerivationPath::from_str("m/0h/1/2'"), - Ok(vec![ - ChildNumber::from_hardened_idx(0).unwrap(), - ChildNumber::from_normal_idx(1).unwrap(), - ChildNumber::from_hardened_idx(2).unwrap(), - ].into()) - ); - assert_eq!( - DerivationPath::from_str("m/0'/1/2h/2"), - Ok(vec![ - ChildNumber::from_hardened_idx(0).unwrap(), - ChildNumber::from_normal_idx(1).unwrap(), - ChildNumber::from_hardened_idx(2).unwrap(), - ChildNumber::from_normal_idx(2).unwrap(), - ].into()) - ); - assert_eq!( - DerivationPath::from_str("m/0'/1/2'/2/1000000000"), - Ok(vec![ - ChildNumber::from_hardened_idx(0).unwrap(), - ChildNumber::from_normal_idx(1).unwrap(), - ChildNumber::from_hardened_idx(2).unwrap(), - ChildNumber::from_normal_idx(2).unwrap(), - ChildNumber::from_normal_idx(1000000000).unwrap(), - ].into()) - ); - } - - #[test] - fn test_derivation_path_conversion_index() { - let path = DerivationPath::from_str("m/0h/1/2'").unwrap(); - let numbers: Vec = path.clone().into(); - let path2: DerivationPath = numbers.into(); - assert_eq!(path, path2); - assert_eq!(&path[..2], &[ChildNumber::from_hardened_idx(0).unwrap(), ChildNumber::from_normal_idx(1).unwrap()]); - let indexed: DerivationPath = path[..2].into(); - assert_eq!(indexed, DerivationPath::from_str("m/0h/1").unwrap()); - assert_eq!(indexed.child(ChildNumber::from_hardened_idx(2).unwrap()), path); - } - - fn test_path(secp: &Secp256k1, - network: Network, - seed: &[u8], - path: DerivationPath, - expected_sk: &str, - expected_pk: &str) { - - let mut sk = ExtendedPrivKey::new_master(network, seed).unwrap(); - let mut pk = ExtendedPubKey::from_private(secp, &sk); - - // Check derivation convenience method for ExtendedPrivKey - assert_eq!( - &sk.derive_priv(secp, &path).unwrap().to_string()[..], - expected_sk - ); - - // Check derivation convenience method for ExtendedPubKey, should error - // appropriately if any ChildNumber is hardened - if path.0.iter().any(|cnum| cnum.is_hardened()) { - assert_eq!( - pk.derive_pub(secp, &path), - Err(Error::CannotDeriveFromHardenedKey) - ); - } else { - assert_eq!( - &pk.derive_pub(secp, &path).unwrap().to_string()[..], - expected_pk - ); - } - - // Derive keys, checking hardened and non-hardened derivation one-by-one - for &num in path.0.iter() { - sk = sk.ckd_priv(secp, num).unwrap(); - match num { - Normal {..} => { - let pk2 = pk.ckd_pub(secp, num).unwrap(); - pk = ExtendedPubKey::from_private(secp, &sk); - assert_eq!(pk, pk2); - } - Hardened {..} => { - assert_eq!( - pk.ckd_pub(secp, num), - Err(Error::CannotDeriveFromHardenedKey) - ); - pk = ExtendedPubKey::from_private(secp, &sk); - } - } - } - - // Check result against expected base58 - assert_eq!(&sk.to_string()[..], expected_sk); - assert_eq!(&pk.to_string()[..], expected_pk); - // Check decoded base58 against result - let decoded_sk = ExtendedPrivKey::from_str(expected_sk); - let decoded_pk = ExtendedPubKey::from_str(expected_pk); - assert_eq!(Ok(sk), decoded_sk); - assert_eq!(Ok(pk), decoded_pk); - } - - #[test] - fn test_increment() { - let idx = 9345497; // randomly generated, I promise - let cn = ChildNumber::from_normal_idx(idx).unwrap(); - assert_eq!(cn.increment().ok(), Some(ChildNumber::from_normal_idx(idx+1).unwrap())); - let cn = ChildNumber::from_hardened_idx(idx).unwrap(); - assert_eq!(cn.increment().ok(), Some(ChildNumber::from_hardened_idx(idx+1).unwrap())); - - let max = (1<<31)-1; - let cn = ChildNumber::from_normal_idx(max).unwrap(); - assert_eq!(cn.increment().err(), Some(Error::InvalidChildNumber(1<<31))); - let cn = ChildNumber::from_hardened_idx(max).unwrap(); - assert_eq!(cn.increment().err(), Some(Error::InvalidChildNumber(1<<31))); - - let cn = ChildNumber::from_normal_idx(350).unwrap(); - let path = DerivationPath::from_str("m/42'").unwrap(); - let mut iter = path.children_from(cn); - assert_eq!(iter.next(), Some("m/42'/350".parse().unwrap())); - assert_eq!(iter.next(), Some("m/42'/351".parse().unwrap())); - - let path = DerivationPath::from_str("m/42'/350'").unwrap(); - let mut iter = path.normal_children(); - assert_eq!(iter.next(), Some("m/42'/350'/0".parse().unwrap())); - assert_eq!(iter.next(), Some("m/42'/350'/1".parse().unwrap())); - - let path = DerivationPath::from_str("m/42'/350'").unwrap(); - let mut iter = path.hardened_children(); - assert_eq!(iter.next(), Some("m/42'/350'/0'".parse().unwrap())); - assert_eq!(iter.next(), Some("m/42'/350'/1'".parse().unwrap())); - - let cn = ChildNumber::from_hardened_idx(42350).unwrap(); - let path = DerivationPath::from_str("m/42'").unwrap(); - let mut iter = path.children_from(cn); - assert_eq!(iter.next(), Some("m/42'/42350'".parse().unwrap())); - assert_eq!(iter.next(), Some("m/42'/42351'".parse().unwrap())); - - let cn = ChildNumber::from_hardened_idx(max).unwrap(); - let path = DerivationPath::from_str("m/42'").unwrap(); - let mut iter = path.children_from(cn); - assert!(iter.next().is_some()); - assert!(iter.next().is_none()); - } - - #[test] - fn test_vector_1() { - let secp = Secp256k1::new(); - let seed = hex_decode("000102030405060708090a0b0c0d0e0f").unwrap(); - - // m - test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(), - "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi", - "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8"); - - // m/0h - test_path(&secp, Bitcoin, &seed, "m/0h".parse().unwrap(), - "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7", - "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw"); - - // m/0h/1 - test_path(&secp, Bitcoin, &seed, "m/0h/1".parse().unwrap(), - "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs", - "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ"); - - // m/0h/1/2h - test_path(&secp, Bitcoin, &seed, "m/0h/1/2h".parse().unwrap(), - "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM", - "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5"); - - // m/0h/1/2h/2 - test_path(&secp, Bitcoin, &seed, "m/0h/1/2h/2".parse().unwrap(), - "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334", - "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV"); - - // m/0h/1/2h/2/1000000000 - test_path(&secp, Bitcoin, &seed, "m/0h/1/2h/2/1000000000".parse().unwrap(), - "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76", - "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy"); - } - - #[test] - fn test_vector_2() { - let secp = Secp256k1::new(); - let seed = hex_decode("fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542").unwrap(); - - // m - test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(), - "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U", - "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB"); - - // m/0 - test_path(&secp, Bitcoin, &seed, "m/0".parse().unwrap(), - "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt", - "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH"); - - // m/0/2147483647h - test_path(&secp, Bitcoin, &seed, "m/0/2147483647h".parse().unwrap(), - "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9", - "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a"); - - // m/0/2147483647h/1 - test_path(&secp, Bitcoin, &seed, "m/0/2147483647h/1".parse().unwrap(), - "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef", - "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon"); - - // m/0/2147483647h/1/2147483646h - test_path(&secp, Bitcoin, &seed, "m/0/2147483647h/1/2147483646h".parse().unwrap(), - "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc", - "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL"); - - // m/0/2147483647h/1/2147483646h/2 - test_path(&secp, Bitcoin, &seed, "m/0/2147483647h/1/2147483646h/2".parse().unwrap(), - "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j", - "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt"); - } - - #[test] - fn test_vector_3() { - let secp = Secp256k1::new(); - let seed = hex_decode("4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be").unwrap(); - - // m - test_path(&secp, Bitcoin, &seed, "m".parse().unwrap(), - "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6", - "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13"); - - // m/0h - test_path(&secp, Bitcoin, &seed, "m/0h".parse().unwrap(), - "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L", - "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y"); - - } - - #[test] - #[cfg(feature = "serde")] - pub fn encode_decode_childnumber() { - serde_round_trip!(ChildNumber::from_normal_idx(0).unwrap()); - serde_round_trip!(ChildNumber::from_normal_idx(1).unwrap()); - serde_round_trip!(ChildNumber::from_normal_idx((1 << 31) - 1).unwrap()); - serde_round_trip!(ChildNumber::from_hardened_idx(0).unwrap()); - serde_round_trip!(ChildNumber::from_hardened_idx(1).unwrap()); - serde_round_trip!(ChildNumber::from_hardened_idx((1 << 31) - 1).unwrap()); - } - - #[test] - #[cfg(feature = "serde")] - pub fn encode_fingerprint_chaincode() { - use serde_json; - let fp = Fingerprint::from(&[1u8,2,3,42][..]); - let cc = ChainCode::from( - &[1u8,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2][..] - ); - - serde_round_trip!(fp); - serde_round_trip!(cc); - - assert_eq!("\"0102032a\"", serde_json::to_string(&fp).unwrap()); - assert_eq!( - "\"0102030405060708090001020304050607080900010203040506070809000102\"", - serde_json::to_string(&cc).unwrap() - ); - assert_eq!("0102032a", fp.to_string()); - assert_eq!( - "0102030405060708090001020304050607080900010203040506070809000102", - cc.to_string() - ); - } -} - diff --git a/src/util/contracthash.rs b/src/util/contracthash.rs deleted file mode 100644 index 62691915..00000000 --- a/src/util/contracthash.rs +++ /dev/null @@ -1,413 +0,0 @@ -// Rust Bitcoin Library -// Written in 2015 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Pay-to-contract-hash support -//! -//! See Appendix A of the Blockstream sidechains whitepaper -//! at http://blockstream.com/sidechains.pdf for details of -//! what this does. - -use secp256k1::{self, Secp256k1}; -use PrivateKey; -use PublicKey; -use hashes::{sha256, Hash, HashEngine, Hmac, HmacEngine}; -use blockdata::{opcodes, script}; - -use std::{error, fmt}; - -use hash_types::ScriptHash; -use network::constants::Network; -use util::address; - -/// Encoding of "pubkey here" in script; from Bitcoin Core `src/script/script.h` -static PUBKEY: u8 = 0xFE; - -/// A contract-hash error -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Error { - /// Other secp256k1 related error - Secp(secp256k1::Error), - /// Script parsing error - Script(script::Error), - /// Encountered an uncompressed key in a script we were deserializing. The - /// reserialization will compress it which might be surprising so we call - /// this an error. - UncompressedKey, - /// Expected a public key when deserializing a script, but we got something else. - ExpectedKey, - /// Expected some sort of CHECKSIG operator when deserializing a script, but - /// we got something else. - ExpectedChecksig, - /// Did not have enough keys to instantiate a script template - TooFewKeys(usize), - /// Had too many keys; template does not match key list - TooManyKeys(usize) -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Secp(ref e) => fmt::Display::fmt(&e, f), - Error::Script(ref e) => fmt::Display::fmt(&e, f), - Error::UncompressedKey => f.write_str("encountered uncompressed secp public key"), - Error::ExpectedKey => f.write_str("expected key when deserializing script"), - Error::ExpectedChecksig => f.write_str("expected OP_*CHECKSIG* when deserializing script"), - Error::TooFewKeys(n) => write!(f, "got {} keys, which was not enough", n), - Error::TooManyKeys(n) => write!(f, "got {} keys, which was too many", n) - } - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::Secp(ref e) => Some(e), - Error::Script(ref e) => Some(e), - _ => None - } - } - - fn description(&self) -> &'static str { - match *self { - Error::Secp(_) => "libsecp256k1 error", - Error::Script(_) => "script error", - Error::UncompressedKey => "encountered uncompressed secp public key", - Error::ExpectedKey => "expected key when deserializing script", - Error::ExpectedChecksig => "expected OP_*CHECKSIG* when deserializing script", - Error::TooFewKeys(_) => "too few keys for template", - Error::TooManyKeys(_) => "too many keys for template" - } - } -} - -/// An element of a script template -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -enum TemplateElement { - Op(opcodes::All), - Key -} - -/// A script template -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct Template(Vec); - -impl Template { - /// Instantiate a template - pub fn to_script(&self, keys: &[PublicKey]) -> Result { - let mut key_index = 0; - let mut ret = script::Builder::new(); - for elem in &self.0 { - ret = match *elem { - TemplateElement::Op(opcode) => ret.push_opcode(opcode), - TemplateElement::Key => { - if key_index == keys.len() { - return Err(Error::TooFewKeys(key_index)); - } - key_index += 1; - ret.push_key(&keys[key_index - 1]) - } - } - } - if key_index == keys.len() { - Ok(ret.into_script()) - } else { - Err(Error::TooManyKeys(keys.len())) - } - } - - /// Returns the number of keys this template requires to instantiate - pub fn required_keys(&self) -> usize { - self.0.iter().filter(|e| **e == TemplateElement::Key).count() - } - - /// If the first push in the template is a number, return this number. For the - /// common case of standard multisig templates, such a number will exist and - /// will represent the number of signatures that are required for the script - /// to pass. - pub fn first_push_as_number(&self) -> Option { - if !self.0.is_empty() { - if let TemplateElement::Op(op) = self.0[0] { - if let opcodes::Class::PushNum(n) = op.classify() { - if n >= 0 { - return Some(n as usize); - } - } - } - } - None - } -} - -impl<'a> From<&'a [u8]> for Template { - fn from(slice: &'a [u8]) -> Template { - Template(slice.iter().map(|&byte| { - if byte == PUBKEY { - TemplateElement::Key - } else { - TemplateElement::Op(opcodes::All::from(byte)) - } - }).collect()) - } -} - -/// Tweak a single key using some arbitrary data -pub fn tweak_key(secp: &Secp256k1, mut key: PublicKey, contract: &[u8]) -> PublicKey { - let hmac_result = compute_tweak(&key, contract); - key.key.add_exp_assign(secp, &hmac_result[..]).expect("HMAC cannot produce invalid tweak"); - key -} - -/// Tweak keys using some arbitrary data -pub fn tweak_keys(secp: &Secp256k1, keys: &[PublicKey], contract: &[u8]) -> Vec { - keys.iter().cloned().map(|key| tweak_key(secp, key, contract)).collect() -} - -/// Compute a tweak from some given data for the given public key -pub fn compute_tweak(pk: &PublicKey, contract: &[u8]) -> Hmac { - let mut hmac_engine: HmacEngine = if pk.compressed { - HmacEngine::new(&pk.key.serialize()) - } else { - HmacEngine::new(&pk.key.serialize_uncompressed()) - }; - hmac_engine.input(contract); - Hmac::from_engine(hmac_engine) -} - -/// Tweak a secret key using some arbitrary data (calls `compute_tweak` internally) -pub fn tweak_secret_key(secp: &Secp256k1, key: &PrivateKey, contract: &[u8]) -> Result { - // Compute public key - let pk = PublicKey::from_private_key(secp, &key); - // Compute tweak - let hmac_sk = compute_tweak(&pk, contract); - // Execute the tweak - let mut key = *key; - key.key.add_assign(&hmac_sk[..]).map_err(Error::Secp)?; - // Return - Ok(key) -} - -/// Takes a contract, template and key set and runs through all the steps -pub fn create_address(secp: &Secp256k1, - network: Network, - contract: &[u8], - keys: &[PublicKey], - template: &Template) - -> Result { - let keys = tweak_keys(secp, keys, contract); - let script = template.to_script(&keys)?; - Ok(address::Address { - network: network, - payload: address::Payload::ScriptHash( - ScriptHash::hash(&script[..]) - ) - }) -} - -/// Extract the keys and template from a completed script -pub fn untemplate(script: &script::Script) -> Result<(Template, Vec), Error> { - let mut ret = script::Builder::new(); - let mut retkeys = vec![]; - - #[derive(Copy, Clone, PartialEq, Eq)] - enum Mode { - SeekingKeys, - CopyingKeys, - SeekingCheckMulti - } - - let mut mode = Mode::SeekingKeys; - for instruction in script.iter(false) { - match instruction { - script::Instruction::PushBytes(data) => { - let n = data.len(); - ret = match PublicKey::from_slice(data) { - Ok(key) => { - if n == 65 { return Err(Error::UncompressedKey); } - if mode == Mode::SeekingCheckMulti { return Err(Error::ExpectedChecksig); } - retkeys.push(key); - mode = Mode::CopyingKeys; - ret.push_opcode(opcodes::All::from(PUBKEY)) - } - Err(_) => { - // Arbitrary pushes are only allowed before we've found any keys. - // Otherwise we have to wait for a N CHECKSIG pair. - match mode { - Mode::SeekingKeys => { ret.push_slice(data) } - Mode::CopyingKeys => { return Err(Error::ExpectedKey); }, - Mode::SeekingCheckMulti => { return Err(Error::ExpectedChecksig); } - } - } - } - } - script::Instruction::Op(op) => { - match op.classify() { - // CHECKSIG should only come after a list of keys - opcodes::Class::Ordinary(opcodes::Ordinary::OP_CHECKSIG) | - opcodes::Class::Ordinary(opcodes::Ordinary::OP_CHECKSIGVERIFY) => { - if mode == Mode::SeekingKeys { return Err(Error::ExpectedKey); } - mode = Mode::SeekingKeys; - } - // CHECKMULTISIG should only come after a number - opcodes::Class::Ordinary(opcodes::Ordinary::OP_CHECKMULTISIG) | - opcodes::Class::Ordinary(opcodes::Ordinary::OP_CHECKMULTISIGVERIFY) => { - if mode == Mode::SeekingKeys { return Err(Error::ExpectedKey); } - if mode == Mode::CopyingKeys { return Err(Error::ExpectedKey); } - mode = Mode::SeekingKeys; - } - // Numbers after keys mean we expect a CHECKMULTISIG. - opcodes::Class::PushNum(_) => { - if mode == Mode::SeekingCheckMulti { return Err(Error::ExpectedChecksig); } - if mode == Mode::CopyingKeys { mode = Mode::SeekingCheckMulti; } - } - // All other opcodes do nothing - _ => {} - } - ret = ret.push_opcode(op); - } - script::Instruction::Error(e) => { return Err(Error::Script(e)); } - } - } - Ok((Template::from(&ret[..]), retkeys)) -} - -#[cfg(test)] -mod tests { - use secp256k1::Secp256k1; - use hex::decode as hex_decode; - use secp256k1::rand::thread_rng; - use std::str::FromStr; - - use blockdata::script::Script; - use network::constants::Network; - - use super::*; - use PublicKey; - - macro_rules! hex (($hex:expr) => (hex_decode($hex).unwrap())); - macro_rules! hex_key (($hex:expr) => (PublicKey::from_slice(&hex!($hex)).unwrap())); - macro_rules! alpha_template(() => (Template::from(&hex!("55fefefefefefefe57AE")[..]))); - macro_rules! alpha_keys(() => ( - &[hex_key!("0269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d933"), - hex_key!("021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a"), - hex_key!("02174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea1"), - hex_key!("033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a"), - hex_key!("0313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c2"), - hex_key!("030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab0"), - hex_key!("02fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce")] - )); - - #[test] - fn sanity() { - let secp = Secp256k1::new(); - let keys = alpha_keys!(); - // This is the first withdraw ever, in alpha a94f95cc47b444c10449c0eed51d895e4970560c4a1a9d15d46124858abc3afe - let contract = hex!("5032534894ffbf32c1f1c0d3089b27c98fd991d5d7329ebd7d711223e2cde5a9417a1fa3e852c576"); - - let addr = create_address(&secp, Network::Testnet, &contract, keys, &alpha_template!()).unwrap(); - assert_eq!(addr.to_string(), "2N3zXjbwdTcPsJiy8sUK9FhWJhqQCxA8Jjr".to_owned()); - } - - #[test] - fn script() { - let alpha_keys = alpha_keys!(); - let alpha_template = alpha_template!(); - - let alpha_redeem = Script::from(hex!("55210269992fb441ae56968e5b77d46a3e53b69f136444ae65a94041fc937bdb28d93321021df31471281d4478df85bfce08a10aab82601dca949a79950f8ddf7002bd915a2102174c82021492c2c6dfcbfa4187d10d38bed06afb7fdcd72c880179fddd641ea121033f96e43d72c33327b6a4631ccaa6ea07f0b106c88b9dc71c9000bb6044d5e88a210313d8748790f2a86fb524579b46ce3c68fedd58d2a738716249a9f7d5458a15c221030b632eeb079eb83648886122a04c7bf6d98ab5dfb94cf353ee3e9382a4c2fab02102fb54a7fcaa73c307cfd70f3fa66a2e4247a71858ca731396343ad30c7c4009ce57ae")); - let (template, keys) = untemplate(&alpha_redeem).unwrap(); - - assert_eq!(keys, alpha_keys); - assert_eq!(template, alpha_template); - } - - #[test] - fn tweak_secret() { - let secp = Secp256k1::new(); - let (sk1, pk1) = secp.generate_keypair(&mut thread_rng()); - let (sk2, pk2) = secp.generate_keypair(&mut thread_rng()); - let (sk3, pk3) = secp.generate_keypair(&mut thread_rng()); - - let sk1 = PrivateKey { - key: sk1, - compressed: true, - network: Network::Bitcoin, - }; - let sk2 = PrivateKey { - key: sk2, - compressed: false, - network: Network::Bitcoin, - }; - let sk3 = PrivateKey { - key: sk3, - compressed: true, - network: Network::Bitcoin, - }; - let pks = [ - PublicKey { key: pk1, compressed: true }, - PublicKey { key: pk2, compressed: false }, - PublicKey { key: pk3, compressed: true }, - ]; - let contract = b"if bottle mt dont remembr drink wont pay"; - - // Directly compute tweaks on pubkeys - let tweaked_pks = tweak_keys(&secp, &pks, &contract[..]); - // Compute tweaks on secret keys - let tweaked_pk1 = PublicKey::from_private_key(&secp, &tweak_secret_key(&secp, &sk1, &contract[..]).unwrap()); - let tweaked_pk2 = PublicKey::from_private_key(&secp, &tweak_secret_key(&secp, &sk2, &contract[..]).unwrap()); - let tweaked_pk3 = PublicKey::from_private_key(&secp, &tweak_secret_key(&secp, &sk3, &contract[..]).unwrap()); - // Check equality - assert_eq!(tweaked_pks[0], tweaked_pk1); - assert_eq!(tweaked_pks[1], tweaked_pk2); - assert_eq!(tweaked_pks[2], tweaked_pk3); - } - - #[test] - fn tweak_fixed_vector() { - let secp = Secp256k1::new(); - - let pks = [ - PublicKey::from_str("02ba604e6ad9d3864eda8dc41c62668514ef7d5417d3b6db46e45cc4533bff001c").unwrap(), - PublicKey::from_str("0365c0755ea55ce85d8a1900c68a524dbfd1c0db45ac3b3840dbb10071fe55e7a8").unwrap(), - PublicKey::from_str("0202313ca315889b2e69c94cf86901119321c7288139ba53ac022b7af3dc250054").unwrap(), - ]; - let tweaked_pks = [ - PublicKey::from_str("03b3597221b5982a3f1a77aed50f0015d1b6edfc69023ef7f25cfac0e8af1b2041").unwrap(), - PublicKey::from_str("0296ece1fd954f7ae94f8d6bad19fd6d583f5b36335cf13135a3053a22f3c1fb05").unwrap(), - PublicKey::from_str("0230bb1ca5dbc7fcf49294c2c3e582e5582eabf7c87e885735dc774da45d610e51").unwrap(), - ]; - let contract = b"if bottle mt dont remembr drink wont pay"; - - // Directly compute tweaks on pubkeys - assert_eq!( - tweak_keys(&secp, &pks, &contract[..]), - tweaked_pks - ); - } - - #[test] - fn bad_key_number() { - let alpha_keys = alpha_keys!(); - let template_short = Template::from(&hex!("55fefefefefefe57AE")[..]); - let template_long = Template::from(&hex!("55fefefefefefefefe57AE")[..]); - let template = Template::from(&hex!("55fefefefefefefe57AE")[..]); - - assert_eq!(template_short.required_keys(), 6); - assert_eq!(template_long.required_keys(), 8); - assert_eq!(template.required_keys(), 7); - assert_eq!(template_short.to_script(alpha_keys), Err(Error::TooManyKeys(7))); - assert_eq!(template_long.to_script(alpha_keys), Err(Error::TooFewKeys(7))); - assert!(template.to_script(alpha_keys).is_ok()); - } -} - - diff --git a/src/util/endian.rs b/src/util/endian.rs deleted file mode 100644 index 8c10b57a..00000000 --- a/src/util/endian.rs +++ /dev/null @@ -1,125 +0,0 @@ -macro_rules! define_slice_to_be { - ($name: ident, $type: ty) => { - #[inline] - pub fn $name(slice: &[u8]) -> $type { - assert_eq!(slice.len(), ::std::mem::size_of::<$type>()); - let mut res = 0; - for i in 0..::std::mem::size_of::<$type>() { - res |= (slice[i] as $type) << (::std::mem::size_of::<$type>() - i - 1)*8; - } - res - } - } -} -macro_rules! define_slice_to_le { - ($name: ident, $type: ty) => { - #[inline] - pub fn $name(slice: &[u8]) -> $type { - assert_eq!(slice.len(), ::std::mem::size_of::<$type>()); - let mut res = 0; - for i in 0..::std::mem::size_of::<$type>() { - res |= (slice[i] as $type) << i*8; - } - res - } - } -} -macro_rules! define_be_to_array { - ($name: ident, $type: ty, $byte_len: expr) => { - #[inline] - pub fn $name(val: $type) -> [u8; $byte_len] { - assert_eq!(::std::mem::size_of::<$type>(), $byte_len); // size_of isn't a constfn in 1.22 - let mut res = [0; $byte_len]; - for i in 0..$byte_len { - res[i] = ((val >> ($byte_len - i - 1)*8) & 0xff) as u8; - } - res - } - } -} -macro_rules! define_le_to_array { - ($name: ident, $type: ty, $byte_len: expr) => { - #[inline] - pub fn $name(val: $type) -> [u8; $byte_len] { - assert_eq!(::std::mem::size_of::<$type>(), $byte_len); // size_of isn't a constfn in 1.22 - let mut res = [0; $byte_len]; - for i in 0..$byte_len { - res[i] = ((val >> i*8) & 0xff) as u8; - } - res - } - } -} - -define_slice_to_be!(slice_to_u32_be, u32); -define_be_to_array!(u32_to_array_be, u32, 4); -define_slice_to_le!(slice_to_u16_le, u16); -define_slice_to_le!(slice_to_u32_le, u32); -define_slice_to_le!(slice_to_u64_le, u64); -define_le_to_array!(u16_to_array_le, u16, 2); -define_le_to_array!(u32_to_array_le, u32, 4); -define_le_to_array!(u64_to_array_le, u64, 8); - -#[inline] -pub fn i16_to_array_le(val: i16) -> [u8; 2] { - u16_to_array_le(val as u16) -} -#[inline] -pub fn slice_to_i16_le(slice: &[u8]) -> i16 { - slice_to_u16_le(slice) as i16 -} -#[inline] -pub fn slice_to_i32_le(slice: &[u8]) -> i32 { - slice_to_u32_le(slice) as i32 -} -#[inline] -pub fn i32_to_array_le(val: i32) -> [u8; 4] { - u32_to_array_le(val as u32) -} -#[inline] -pub fn slice_to_i64_le(slice: &[u8]) -> i64 { - slice_to_u64_le(slice) as i64 -} -#[inline] -pub fn i64_to_array_le(val: i64) -> [u8; 8] { - u64_to_array_le(val as u64) -} - -macro_rules! define_chunk_slice_to_int { - ($name: ident, $type: ty, $converter: ident) => { - #[inline] - pub fn $name(inp: &[u8], outp: &mut [$type]) { - assert_eq!(inp.len(), outp.len() * ::std::mem::size_of::<$type>()); - for (outp_val, data_bytes) in outp.iter_mut().zip(inp.chunks(::std::mem::size_of::<$type>())) { - *outp_val = $converter(data_bytes); - } - } - } -} -define_chunk_slice_to_int!(bytes_to_u64_slice_le, u64, slice_to_u64_le); - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn endianness_test() { - assert_eq!(slice_to_u32_be(&[0xde, 0xad, 0xbe, 0xef]), 0xdeadbeef); - assert_eq!(u32_to_array_be(0xdeadbeef), [0xde, 0xad, 0xbe, 0xef]); - - assert_eq!(slice_to_u16_le(&[0xad, 0xde]), 0xdead); - assert_eq!(slice_to_u32_le(&[0xef, 0xbe, 0xad, 0xde]), 0xdeadbeef); - assert_eq!(slice_to_u64_le(&[0xef, 0xbe, 0xad, 0xde, 0xfe, 0xca, 0xad, 0x1b]), 0x1badcafedeadbeef); - assert_eq!(u16_to_array_le(0xdead), [0xad, 0xde]); - assert_eq!(u32_to_array_le(0xdeadbeef), [0xef, 0xbe, 0xad, 0xde]); - assert_eq!(u64_to_array_le(0x1badcafedeadbeef), [0xef, 0xbe, 0xad, 0xde, 0xfe, 0xca, 0xad, 0x1b]); - } - - #[test] - fn endian_chunk_test() { - let inp = [0xef, 0xbe, 0xad, 0xde, 0xfe, 0xca, 0xad, 0x1b, 0xfe, 0xca, 0xad, 0x1b, 0xce, 0xfa, 0x01, 0x02]; - let mut out = [0; 2]; - bytes_to_u64_slice_le(&inp, &mut out); - assert_eq!(out, [0x1badcafedeadbeef, 0x0201face1badcafe]); - } -} diff --git a/src/util/hash.rs b/src/util/hash.rs deleted file mode 100644 index 0de4731f..00000000 --- a/src/util/hash.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Hash functions -//! -//! Utility functions related to hashing data, including merkleization - -use std::cmp::min; -use std::io; - -use hashes::Hash; -use consensus::encode::Encodable; - -/// Calculates the merkle root of a list of hashes inline -/// into the allocated slice. -/// -/// In most cases, you'll want to use [bitcoin_merkle_root] instead. -pub fn bitcoin_merkle_root_inline(data: &mut [T]) -> T - where T: Hash + Encodable, - ::Engine: io::Write, -{ - // Base case - if data.len() < 1 { - return Default::default(); - } - if data.len() < 2 { - return T::from_inner(data[0].into_inner()); - } - // Recursion - for idx in 0..((data.len() + 1) / 2) { - let idx1 = 2 * idx; - let idx2 = min(idx1 + 1, data.len() - 1); - let mut encoder = T::engine(); - data[idx1].consensus_encode(&mut encoder).unwrap(); - data[idx2].consensus_encode(&mut encoder).unwrap(); - data[idx] = T::from_engine(encoder); - } - let half_len = data.len() / 2 + data.len() % 2; - bitcoin_merkle_root_inline(&mut data[0..half_len]) -} - -/// Calculates the merkle root of an iterator of hashes. -pub fn bitcoin_merkle_root(mut iter: I) -> T - where T: Hash + Encodable, - ::Engine: io::Write, - I: ExactSizeIterator, -{ - // Base case - if iter.len() == 0 { - return Default::default(); - } - if iter.len() == 1 { - return T::from_inner(iter.nth(0).unwrap().into_inner()); - } - // Recursion - let half_len = iter.len() / 2 + iter.len() % 2; - let mut alloc = Vec::with_capacity(half_len); - while let Some(hash1) = iter.next() { - // If the size is odd, use the last element twice. - let hash2 = iter.next().unwrap_or(hash1); - let mut encoder = T::engine(); - hash1.consensus_encode(&mut encoder).unwrap(); - hash2.consensus_encode(&mut encoder).unwrap(); - alloc.push(T::from_engine(encoder)); - } - bitcoin_merkle_root_inline(&mut alloc) -} - -/// Objects which are referred to by hash -pub trait BitcoinHash { - /// Produces a Sha256dHash which can be used to refer to the object - fn bitcoin_hash(&self) -> T; -} diff --git a/src/util/key.rs b/src/util/key.rs deleted file mode 100644 index c9f81faf..00000000 --- a/src/util/key.rs +++ /dev/null @@ -1,448 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Bitcoin Keys -//! -//! Keys used in Bitcoin that can be roundtrip (de)serialized. -//! - -use std::fmt::{self, Write}; -use std::{io, ops, error}; -use std::str::FromStr; - -use secp256k1::{self, Secp256k1}; -use network::constants::Network; -use util::base58; - -/// A key-related error. -#[derive(Debug)] -pub enum Error { - /// Base58 encoding error - Base58(base58::Error), - /// secp256k1-related error - Secp256k1(secp256k1::Error), -} - - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Base58(ref e) => write!(f, "base58 error: {}", e), - Error::Secp256k1(ref e) => write!(f, "secp256k1 error: {}", e), - } - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::Base58(ref e) => Some(e), - Error::Secp256k1(ref e) => Some(e), - } - } - - fn description(&self) -> &str { - "Bitcoin key error" - } -} - -#[doc(hidden)] -impl From for Error { - fn from(e: base58::Error) -> Error { - Error::Base58(e) - } -} - -#[doc(hidden)] -impl From for Error { - fn from(e: secp256k1::Error) -> Error { - Error::Secp256k1(e) - } -} - -/// A Bitcoin ECDSA public key -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct PublicKey { - /// Whether this public key should be serialized as compressed - pub compressed: bool, - /// The actual ECDSA key - pub key: secp256k1::PublicKey, -} - -impl PublicKey { - /// Write the public key into a writer - pub fn write_into(&self, mut writer: W) { - let write_res: io::Result<()> = if self.compressed { - writer.write_all(&self.key.serialize()) - } else { - writer.write_all(&self.key.serialize_uncompressed()) - }; - debug_assert!(write_res.is_ok()); - } - - /// Serialize the public key to bytes - pub fn to_bytes(&self) -> Vec { - let mut buf = Vec::new(); - self.write_into(&mut buf); - buf - } - - /// Deserialize a public key from a slice - pub fn from_slice(data: &[u8]) -> Result { - let compressed: bool = match data.len() { - 33 => true, - 65 => false, - len => { return Err(base58::Error::InvalidLength(len).into()); }, - }; - - Ok(PublicKey { - compressed: compressed, - key: secp256k1::PublicKey::from_slice(data)?, - }) - } - - /// Computes the public key as supposed to be used with this secret - pub fn from_private_key(secp: &Secp256k1, sk: &PrivateKey) -> PublicKey { - sk.public_key(secp) - } -} - -impl fmt::Display for PublicKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.compressed { - for ch in &self.key.serialize()[..] { - write!(f, "{:02x}", ch)?; - } - } else { - for ch in &self.key.serialize_uncompressed()[..] { - write!(f, "{:02x}", ch)?; - } - } - Ok(()) - } -} - -impl FromStr for PublicKey { - type Err = Error; - fn from_str(s: &str) -> Result { - let key = secp256k1::PublicKey::from_str(s)?; - Ok(PublicKey { - key: key, - compressed: s.len() == 66 - }) - } -} - -#[derive(Copy, Clone, PartialEq, Eq)] -/// A Bitcoin ECDSA private key -pub struct PrivateKey { - /// Whether this private key should be serialized as compressed - pub compressed: bool, - /// The network on which this key should be used - pub network: Network, - /// The actual ECDSA key - pub key: secp256k1::SecretKey, -} - -impl PrivateKey { - /// Creates a public key from this private key - pub fn public_key(&self, secp: &Secp256k1) -> PublicKey { - PublicKey { - compressed: self.compressed, - key: secp256k1::PublicKey::from_secret_key(secp, &self.key) - } - } - - /// Serialize the private key to bytes - pub fn to_bytes(&self) -> Vec { - self.key[..].to_vec() - } - - /// Format the private key to WIF format. - pub fn fmt_wif(&self, fmt: &mut fmt::Write) -> fmt::Result { - let mut ret = [0; 34]; - ret[0] = match self.network { - Network::Bitcoin => 128, - Network::Testnet | Network::Regtest => 239, - }; - ret[1..33].copy_from_slice(&self.key[..]); - let privkey = if self.compressed { - ret[33] = 1; - base58::check_encode_slice(&ret[..]) - } else { - base58::check_encode_slice(&ret[..33]) - }; - fmt.write_str(&privkey) - } - - /// Get WIF encoding of this private key. - pub fn to_wif(&self) -> String { - let mut buf = String::new(); - buf.write_fmt(format_args!("{}", self)).unwrap(); - buf.shrink_to_fit(); - buf - } - - /// Parse WIF encoded private key. - pub fn from_wif(wif: &str) -> Result { - let data = base58::from_check(wif)?; - - let compressed = match data.len() { - 33 => false, - 34 => true, - _ => { return Err(Error::Base58(base58::Error::InvalidLength(data.len()))); } - }; - - let network = match data[0] { - 128 => Network::Bitcoin, - 239 => Network::Testnet, - x => { return Err(Error::Base58(base58::Error::InvalidVersion(vec![x]))); } - }; - - Ok(PrivateKey { - compressed: compressed, - network: network, - key: secp256k1::SecretKey::from_slice(&data[1..33])?, - }) - } -} - -impl fmt::Display for PrivateKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.fmt_wif(f) - } -} - -impl fmt::Debug for PrivateKey { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[private key data]") - } -} - -impl FromStr for PrivateKey { - type Err = Error; - fn from_str(s: &str) -> Result { - PrivateKey::from_wif(s) - } -} - -impl ops::Index for PrivateKey { - type Output = [u8]; - fn index(&self, _: ops::RangeFull) -> &[u8] { - &self.key[..] - } -} - -#[cfg(feature = "serde")] -impl ::serde::Serialize for PrivateKey { - fn serialize(&self, s: S) -> Result { - s.collect_str(self) - } -} - -#[cfg(feature = "serde")] -impl<'de> ::serde::Deserialize<'de> for PrivateKey { - fn deserialize>(d: D) -> Result { - struct WifVisitor; - - impl<'de> ::serde::de::Visitor<'de> for WifVisitor { - type Value = PrivateKey; - - fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - formatter.write_str("an ASCII WIF string") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: ::serde::de::Error, - { - if let Ok(s) = ::std::str::from_utf8(v) { - PrivateKey::from_str(s).map_err(E::custom) - } else { - Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)) - } - } - - fn visit_str(self, v: &str) -> Result - where - E: ::serde::de::Error, - { - PrivateKey::from_str(v).map_err(E::custom) - } - } - - d.deserialize_str(WifVisitor) - } -} - -#[cfg(feature = "serde")] -impl ::serde::Serialize for PublicKey { - fn serialize(&self, s: S) -> Result { - if s.is_human_readable() { - s.collect_str(self) - } else { - if self.compressed { - s.serialize_bytes(&self.key.serialize()[..]) - } else { - s.serialize_bytes(&self.key.serialize_uncompressed()[..]) - } - } - } -} - -#[cfg(feature = "serde")] -impl<'de> ::serde::Deserialize<'de> for PublicKey { - fn deserialize>(d: D) -> Result { - if d.is_human_readable() { - struct HexVisitor; - - impl<'de> ::serde::de::Visitor<'de> for HexVisitor { - type Value = PublicKey; - - fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - formatter.write_str("an ASCII hex string") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: ::serde::de::Error, - { - if let Ok(hex) = ::std::str::from_utf8(v) { - PublicKey::from_str(hex).map_err(E::custom) - } else { - Err(E::invalid_value(::serde::de::Unexpected::Bytes(v), &self)) - } - } - - fn visit_str(self, v: &str) -> Result - where - E: ::serde::de::Error, - { - PublicKey::from_str(v).map_err(E::custom) - } - } - d.deserialize_str(HexVisitor) - } else { - struct BytesVisitor; - - impl<'de> ::serde::de::Visitor<'de> for BytesVisitor { - type Value = PublicKey; - - fn expecting(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - formatter.write_str("a bytestring") - } - - fn visit_bytes(self, v: &[u8]) -> Result - where - E: ::serde::de::Error, - { - PublicKey::from_slice(v).map_err(E::custom) - } - } - - d.deserialize_bytes(BytesVisitor) - } - } -} - -#[cfg(test)] -mod tests { - use super::{PrivateKey, PublicKey}; - use secp256k1::Secp256k1; - use std::str::FromStr; - use network::constants::Network::Testnet; - use network::constants::Network::Bitcoin; - use util::address::Address; - - #[test] - fn test_key_derivation() { - // testnet compressed - let sk = PrivateKey::from_wif("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap(); - assert_eq!(sk.network, Testnet); - assert_eq!(sk.compressed, true); - assert_eq!(&sk.to_wif(), "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy"); - - let secp = Secp256k1::new(); - let pk = Address::p2pkh(&sk.public_key(&secp), sk.network); - assert_eq!(&pk.to_string(), "mqwpxxvfv3QbM8PU8uBx2jaNt9btQqvQNx"); - - // test string conversion - assert_eq!(&sk.to_string(), "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy"); - let sk_str = - PrivateKey::from_str("cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy").unwrap(); - assert_eq!(&sk.to_wif(), &sk_str.to_wif()); - - // mainnet uncompressed - let sk = PrivateKey::from_wif("5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3").unwrap(); - assert_eq!(sk.network, Bitcoin); - assert_eq!(sk.compressed, false); - assert_eq!(&sk.to_wif(), "5JYkZjmN7PVMjJUfJWfRFwtuXTGB439XV6faajeHPAM9Z2PT2R3"); - - let secp = Secp256k1::new(); - let mut pk = sk.public_key(&secp); - assert_eq!(pk.compressed, false); - assert_eq!(&pk.to_string(), "042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133"); - assert_eq!(pk, PublicKey::from_str("042e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af191923a2964c177f5b5923ae500fca49e99492d534aa3759d6b25a8bc971b133").unwrap()); - let addr = Address::p2pkh(&pk, sk.network); - assert_eq!(&addr.to_string(), "1GhQvF6dL8xa6wBxLnWmHcQsurx9RxiMc8"); - pk.compressed = true; - assert_eq!(&pk.to_string(), "032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af"); - assert_eq!(pk, PublicKey::from_str("032e58afe51f9ed8ad3cc7897f634d881fdbe49a81564629ded8156bebd2ffd1af").unwrap()); - } - - #[cfg(feature = "serde")] - #[test] - fn test_key_serde() { - use serde_test::{Configure, Token, assert_tokens}; - - static KEY_WIF: &'static str = "cVt4o7BGAig1UXywgGSmARhxMdzP5qvQsxKkSsc1XEkw3tDTQFpy"; - static PK_STR: &'static str = "039b6347398505f5ec93826dc61c19f47c66c0283ee9be980e29ce325a0f4679ef"; - static PK_STR_U: &'static str = "\ - 04\ - 9b6347398505f5ec93826dc61c19f47c66c0283ee9be980e29ce325a0f4679ef\ - 87288ed73ce47fc4f5c79d19ebfa57da7cff3aff6e819e4ee971d86b5e61875d\ - "; - static PK_BYTES: [u8; 33] = [ - 0x03, - 0x9b, 0x63, 0x47, 0x39, 0x85, 0x05, 0xf5, 0xec, - 0x93, 0x82, 0x6d, 0xc6, 0x1c, 0x19, 0xf4, 0x7c, - 0x66, 0xc0, 0x28, 0x3e, 0xe9, 0xbe, 0x98, 0x0e, - 0x29, 0xce, 0x32, 0x5a, 0x0f, 0x46, 0x79, 0xef, - ]; - static PK_BYTES_U: [u8; 65] = [ - 0x04, - 0x9b, 0x63, 0x47, 0x39, 0x85, 0x05, 0xf5, 0xec, - 0x93, 0x82, 0x6d, 0xc6, 0x1c, 0x19, 0xf4, 0x7c, - 0x66, 0xc0, 0x28, 0x3e, 0xe9, 0xbe, 0x98, 0x0e, - 0x29, 0xce, 0x32, 0x5a, 0x0f, 0x46, 0x79, 0xef, - 0x87, 0x28, 0x8e, 0xd7, 0x3c, 0xe4, 0x7f, 0xc4, - 0xf5, 0xc7, 0x9d, 0x19, 0xeb, 0xfa, 0x57, 0xda, - 0x7c, 0xff, 0x3a, 0xff, 0x6e, 0x81, 0x9e, 0x4e, - 0xe9, 0x71, 0xd8, 0x6b, 0x5e, 0x61, 0x87, 0x5d, - ]; - - let s = Secp256k1::new(); - let sk = PrivateKey::from_str(&KEY_WIF).unwrap(); - let pk = PublicKey::from_private_key(&s, &sk); - let pk_u = PublicKey { - key: pk.key, - compressed: false, - }; - - assert_tokens(&sk, &[Token::BorrowedStr(KEY_WIF)]); - assert_tokens(&pk.compact(), &[Token::BorrowedBytes(&PK_BYTES[..])]); - assert_tokens(&pk.readable(), &[Token::BorrowedStr(PK_STR)]); - assert_tokens(&pk_u.compact(), &[Token::BorrowedBytes(&PK_BYTES_U[..])]); - assert_tokens(&pk_u.readable(), &[Token::BorrowedStr(PK_STR_U)]); - } -} diff --git a/src/util/merkleblock.rs b/src/util/merkleblock.rs deleted file mode 100644 index 3dca69d8..00000000 --- a/src/util/merkleblock.rs +++ /dev/null @@ -1,786 +0,0 @@ -// Rust Bitcoin Library -// Written by -// John L. Jegutanis -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// -// -// This code was translated from merkleblock.h, merkleblock.cpp and pmt_tests.cpp -// Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2018 The Bitcoin Core developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -//! Merkle Block and Partial Merkle Tree -//! -//! Support proofs that transaction(s) belong to a block. -//! -//! # Examples -//! -//! ```rust -//! extern crate bitcoin; -//! use bitcoin::hash_types::Txid; -//! use bitcoin::hashes::hex::FromHex; -//! use bitcoin::{Block, MerkleBlock}; -//! -//! # fn main() { -//! // Get the proof from a bitcoind by running in the terminal: -//! // $ TXID="5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2" -//! // $ bitcoin-cli gettxoutproof [\"$TXID\"] -//! let mb_bytes = Vec::from_hex("01000000ba8b9cda965dd8e536670f9ddec10e53aab14b20bacad27b913719\ -//! 0000000000190760b278fe7b8565fda3b968b918d5fd997f993b23674c0af3b6fde300b38f33a5914ce6ed5b\ -//! 1b01e32f570200000002252bf9d75c4f481ebb6278d708257d1f12beb6dd30301d26c623f789b2ba6fc0e2d3\ -//! 2adb5f8ca820731dff234a84e78ec30bce4ec69dbd562d0b2b8266bf4e5a0105").unwrap(); -//! let mb: MerkleBlock = bitcoin::consensus::deserialize(&mb_bytes).unwrap(); -//! -//! // Authenticate and extract matched transaction ids -//! let mut matches: Vec = vec![]; -//! let mut index: Vec = vec![]; -//! assert!(mb.extract_matches(&mut matches, &mut index).is_ok()); -//! assert_eq!(1, matches.len()); -//! assert_eq!( -//! Txid::from_hex( -//! "5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2").unwrap(), -//! matches[0] -//! ); -//! assert_eq!(1, index.len()); -//! assert_eq!(1, index[0]); -//! # } -//! ``` - -use std::collections::HashSet; -use std::io; - -use hashes::Hash; -use hash_types::{Txid, TxMerkleNode}; - -use blockdata::transaction::Transaction; -use blockdata::constants::{MAX_BLOCK_WEIGHT, MIN_TRANSACTION_WEIGHT}; -use consensus::encode::{self, Decodable, Encodable}; -use util::merkleblock::MerkleBlockError::*; -use {Block, BlockHeader}; - -/// An error when verifying the merkle block -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum MerkleBlockError { - /// When header merkle root don't match to the root calculated from the partial merkle tree - MerkleRootMismatch, - /// When partial merkle tree contains no transactions - NoTransactions, - /// When there are too many transactions - TooManyTransactions, - /// General format error - BadFormat(String), -} - -/// Data structure that represents a partial merkle tree. -/// -/// It represents a subset of the txid's of a known block, in a way that -/// allows recovery of the list of txid's and the merkle root, in an -/// authenticated way. -/// -/// The encoding works as follows: we traverse the tree in depth-first order, -/// storing a bit for each traversed node, signifying whether the node is the -/// parent of at least one matched leaf txid (or a matched txid itself). In -/// case we are at the leaf level, or this bit is 0, its merkle node hash is -/// stored, and its children are not explored further. Otherwise, no hash is -/// stored, but we recurse into both (or the only) child branch. During -/// decoding, the same depth-first traversal is performed, consuming bits and -/// hashes as they written during encoding. -/// -/// The serialization is fixed and provides a hard guarantee about the -/// encoded size: -/// -/// SIZE <= 10 + ceil(32.25*N) -/// -/// Where N represents the number of leaf nodes of the partial tree. N itself -/// is bounded by: -/// -/// N <= total_transactions -/// N <= 1 + matched_transactions*tree_height -/// -/// The serialization format: -/// - uint32 total_transactions (4 bytes) -/// - varint number of hashes (1-3 bytes) -/// - uint256[] hashes in depth-first order (<= 32*N bytes) -/// - varint number of bytes of flag bits (1-3 bytes) -/// - byte[] flag bits, packed per 8 in a byte, least significant bit first (<= 2*N-1 bits) -/// The size constraints follow from this. -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct PartialMerkleTree { - /// The total number of transactions in the block - num_transactions: u32, - /// node-is-parent-of-matched-txid bits - bits: Vec, - /// Transaction ids and internal hashes - hashes: Vec, -} - -impl PartialMerkleTree { - /// Construct a partial merkle tree - /// The `txids` are the transaction hashes of the block and the `matches` is the contains flags - /// wherever a tx hash should be included in the proof. - /// - /// Panics when `txids` is empty or when `matches` has a different length - /// - /// # Examples - /// - /// ```rust - /// extern crate bitcoin; - /// use bitcoin::hash_types::Txid; - /// use bitcoin::hashes::hex::FromHex; - /// use bitcoin::util::merkleblock::PartialMerkleTree; - /// - /// # fn main() { - /// // Block 80000 - /// let txids: Vec = [ - /// "c06fbab289f723c6261d3030ddb6be121f7d2508d77862bb1e484f5cd7f92b25", - /// "5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2", - /// ] - /// .iter() - /// .map(|hex| Txid::from_hex(hex).unwrap()) - /// .collect(); - /// - /// // Select the second transaction - /// let matches = vec![false, true]; - /// let tree = PartialMerkleTree::from_txids(&txids, &matches); - /// assert!(tree.extract_matches(&mut vec![], &mut vec![]).is_ok()); - /// # } - /// ``` - pub fn from_txids(txids: &[Txid], matches: &[bool]) -> Self { - // We can never have zero txs in a merkle block, we always need the coinbase tx - assert_ne!(txids.len(), 0); - assert_eq!(txids.len(), matches.len()); - - let mut pmt = PartialMerkleTree { - num_transactions: txids.len() as u32, - bits: Vec::with_capacity(txids.len()), - hashes: vec![], - }; - // calculate height of tree - let mut height = 0; - while pmt.calc_tree_width(height) > 1 { - height += 1; - } - // traverse the partial tree - pmt.traverse_and_build(height, 0, txids, matches); - pmt - } - - /// Extract the matching txid's represented by this partial merkle tree - /// and their respective indices within the partial tree. - /// returns the merkle root, or error in case of failure - pub fn extract_matches( - &self, - matches: &mut Vec, - indexes: &mut Vec, - ) -> Result { - matches.clear(); - indexes.clear(); - // An empty set will not work - if self.num_transactions == 0 { - return Err(NoTransactions); - }; - // check for excessively high numbers of transactions - if self.num_transactions > MAX_BLOCK_WEIGHT / MIN_TRANSACTION_WEIGHT { - return Err(TooManyTransactions); - } - // there can never be more hashes provided than one for every txid - if self.hashes.len() as u32 > self.num_transactions { - return Err(BadFormat( - "Proof contains more hashes than transactions".to_owned(), - )); - }; - // there must be at least one bit per node in the partial tree, and at least one node per hash - if self.bits.len() < self.hashes.len() { - return Err(BadFormat("Proof contains less bits than hashes".to_owned())); - }; - // calculate height of tree - let mut height = 0; - while self.calc_tree_width(height) > 1 { - height += 1; - } - // traverse the partial tree - let mut bits_used = 0u32; - let mut hash_used = 0u32; - let hash_merkle_root = - self.traverse_and_extract(height, 0, &mut bits_used, &mut hash_used, matches, indexes)?; - // Verify that all bits were consumed (except for the padding caused by - // serializing it as a byte sequence) - if (bits_used + 7) / 8 != (self.bits.len() as u32 + 7) / 8 { - return Err(BadFormat("Not all bit were consumed".to_owned())); - } - // Verify that all hashes were consumed - if hash_used != self.hashes.len() as u32 { - return Err(BadFormat("Not all hashes were consumed".to_owned())); - } - Ok(TxMerkleNode::from_inner(hash_merkle_root.into_inner())) - } - - /// Helper function to efficiently calculate the number of nodes at given height - /// in the merkle tree - #[inline] - fn calc_tree_width(&self, height: u32) -> u32 { - (self.num_transactions + (1 << height) - 1) >> height - } - - /// Calculate the hash of a node in the merkle tree (at leaf level: the txid's themselves) - fn calc_hash(&self, height: u32, pos: u32, txids: &[Txid]) -> TxMerkleNode { - if height == 0 { - // Hash at height 0 is the txid itself - TxMerkleNode::from_inner(txids[pos as usize].into_inner()) - } else { - // Calculate left hash - let left = self.calc_hash(height - 1, pos * 2, txids); - // Calculate right hash if not beyond the end of the array - copy left hash otherwise - let right = if pos * 2 + 1 < self.calc_tree_width(height - 1) { - self.calc_hash(height - 1, pos * 2 + 1, txids) - } else { - left - }; - // Combine subhashes - PartialMerkleTree::parent_hash(left, right) - } - } - - /// Recursive function that traverses tree nodes, storing the data as bits and hashes - fn traverse_and_build( - &mut self, - height: u32, - pos: u32, - txids: &[Txid], - matches: &[bool], - ) { - // Determine whether this node is the parent of at least one matched txid - let mut parent_of_match = false; - let mut p = pos << height; - while p < (pos + 1) << height && p < self.num_transactions { - parent_of_match |= matches[p as usize]; - p += 1; - } - // Store as flag bit - self.bits.push(parent_of_match); - - if height == 0 || !parent_of_match { - // If at height 0, or nothing interesting below, store hash and stop - let hash = self.calc_hash(height, pos, txids); - self.hashes.push(hash.into()); - } else { - // Otherwise, don't store any hash, but descend into the subtrees - self.traverse_and_build(height - 1, pos * 2, txids, matches); - if pos * 2 + 1 < self.calc_tree_width(height - 1) { - self.traverse_and_build(height - 1, pos * 2 + 1, txids, matches); - } - } - } - - /// Recursive function that traverses tree nodes, consuming the bits and hashes produced by - /// TraverseAndBuild. It returns the hash of the respective node and its respective index. - fn traverse_and_extract( - &self, - height: u32, - pos: u32, - bits_used: &mut u32, - hash_used: &mut u32, - matches: &mut Vec, - indexes: &mut Vec, - ) -> Result { - if *bits_used as usize >= self.bits.len() { - return Err(BadFormat("Overflowed the bits array".to_owned())); - } - let parent_of_match = self.bits[*bits_used as usize]; - *bits_used += 1; - if height == 0 || !parent_of_match { - // If at height 0, or nothing interesting below, use stored hash and do not descend - if *hash_used as usize >= self.hashes.len() { - return Err(BadFormat("Overflowed the hash array".to_owned())); - } - let hash = self.hashes[*hash_used as usize]; - *hash_used += 1; - if height == 0 && parent_of_match { - // in case of height 0, we have a matched txid - matches.push(Txid::from_inner(hash.into_inner())); - indexes.push(pos); - } - Ok(hash) - } else { - // otherwise, descend into the subtrees to extract matched txids and hashes - let left = self.traverse_and_extract( - height - 1, - pos * 2, - bits_used, - hash_used, - matches, - indexes, - )?; - let right; - if pos * 2 + 1 < self.calc_tree_width(height - 1) { - right = self.traverse_and_extract( - height - 1, - pos * 2 + 1, - bits_used, - hash_used, - matches, - indexes, - )?; - if right == left { - // The left and right branches should never be identical, as the transaction - // hashes covered by them must each be unique. - return Err(BadFormat("Found identical transaction hashes".to_owned())); - } - } else { - right = left; - } - // and combine them before returning - Ok(PartialMerkleTree::parent_hash(left, right)) - } - } - - /// Helper method to produce SHA256D(left + right) - fn parent_hash(left: TxMerkleNode, right: TxMerkleNode) -> TxMerkleNode { - let mut encoder = TxMerkleNode::engine(); - left.consensus_encode(&mut encoder).unwrap(); - right.consensus_encode(&mut encoder).unwrap(); - TxMerkleNode::from_engine(encoder) - } -} - -impl Encodable for PartialMerkleTree { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let ret = self.num_transactions.consensus_encode(&mut s)? - + self.hashes.consensus_encode(&mut s)?; - let mut bytes: Vec = vec![0; (self.bits.len() + 7) / 8]; - for p in 0..self.bits.len() { - bytes[p / 8] |= (self.bits[p] as u8) << (p % 8) as u8; - } - Ok(ret + bytes.consensus_encode(s)?) - } -} - -impl Decodable for PartialMerkleTree { - fn consensus_decode(mut d: D) -> Result { - let num_transactions: u32 = Decodable::consensus_decode(&mut d)?; - let hashes: Vec = Decodable::consensus_decode(&mut d)?; - - let bytes: Vec = Decodable::consensus_decode(d)?; - let mut bits: Vec = vec![false; bytes.len() * 8]; - - for (p, bit) in bits.iter_mut().enumerate() { - *bit = (bytes[p / 8] & (1 << (p % 8) as u8)) != 0; - } - Ok(PartialMerkleTree { - num_transactions, - hashes, - bits, - }) - } -} - -/// Data structure that represents a block header paired to a partial merkle tree. -/// -/// NOTE: This assumes that the given Block has *at least* 1 transaction. If the Block has 0 txs, -/// it will hit an assertion. -#[derive(PartialEq, Eq, Clone, Debug)] -pub struct MerkleBlock { - /// The block header - pub header: BlockHeader, - /// Transactions making up a partial merkle tree - pub txn: PartialMerkleTree, -} - -impl MerkleBlock { - /// Create a MerkleBlock from a block, that should contain proofs for the txids. - /// - /// The `block` is a full block containing the header and transactions and `match_txids` is a - /// set containing the transaction ids that should be included in the partial merkle tree. - /// - /// # Examples - /// - /// ```rust - /// extern crate bitcoin; - /// use bitcoin::hash_types::Txid; - /// use bitcoin::hashes::hex::FromHex; - /// use bitcoin::{Block, MerkleBlock}; - /// - /// # fn main() { - /// // Block 80000 - /// let block_bytes = Vec::from_hex("01000000ba8b9cda965dd8e536670f9ddec10e53aab14b20bacad2\ - /// 7b9137190000000000190760b278fe7b8565fda3b968b918d5fd997f993b23674c0af3b6fde300b38f33\ - /// a5914ce6ed5b1b01e32f5702010000000100000000000000000000000000000000000000000000000000\ - /// 00000000000000ffffffff0704e6ed5b1b014effffffff0100f2052a01000000434104b68a50eaa0287e\ - /// ff855189f949c1c6e5f58b37c88231373d8a59809cbae83059cc6469d65c665ccfd1cfeb75c6e8e19413\ - /// bba7fbff9bc762419a76d87b16086eac000000000100000001a6b97044d03da79c005b20ea9c0e1a6d9d\ - /// c12d9f7b91a5911c9030a439eed8f5000000004948304502206e21798a42fae0e854281abd38bacd1aee\ - /// d3ee3738d9e1446618c4571d1090db022100e2ac980643b0b82c0e88ffdfec6b64e3e6ba35e7ba5fdd7d\ - /// 5d6cc8d25c6b241501ffffffff0100f2052a010000001976a914404371705fa9bd789a2fcd52d2c580b6\ - /// 5d35549d88ac00000000").unwrap(); - /// let block: Block = bitcoin::consensus::deserialize(&block_bytes).unwrap(); - /// - /// // Create a merkle block containing a single transaction - /// let txid = Txid::from_hex( - /// "5a4ebf66822b0b2d56bd9dc64ece0bc38ee7844a23ff1d7320a88c5fdb2ad3e2").unwrap(); - /// let match_txids = vec![txid].into_iter().collect(); - /// let mb = MerkleBlock::from_block(&block, &match_txids); - /// - /// // Authenticate and extract matched transaction ids - /// let mut matches: Vec = vec![]; - /// let mut index: Vec = vec![]; - /// assert!(mb.extract_matches(&mut matches, &mut index).is_ok()); - /// assert_eq!(txid, matches[0]); - /// # } - /// ``` - pub fn from_block(block: &Block, match_txids: &HashSet) -> Self { - let header = block.header; - - let mut matches: Vec = Vec::with_capacity(block.txdata.len()); - let mut hashes: Vec = Vec::with_capacity(block.txdata.len()); - - for hash in block.txdata.iter().map(Transaction::txid) { - matches.push(match_txids.contains(&hash)); - hashes.push(hash); - } - - let pmt = PartialMerkleTree::from_txids(&hashes, &matches); - MerkleBlock { header, txn: pmt } - } - - /// Extract the matching txid's represented by this partial merkle tree - /// and their respective indices within the partial tree. - /// returns Ok(()) on success, or error in case of failure - pub fn extract_matches( - &self, - matches: &mut Vec, - indexes: &mut Vec, - ) -> Result<(), MerkleBlockError> { - let merkle_root = self.txn.extract_matches(matches, indexes)?; - - if merkle_root.eq(&self.header.merkle_root) { - Ok(()) - } else { - Err(MerkleRootMismatch) - } - } -} - -impl Encodable for MerkleBlock { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let len = self.header.consensus_encode(&mut s)? - + self.txn.consensus_encode(s)?; - Ok(len) - } -} - -impl Decodable for MerkleBlock { - fn consensus_decode(mut d: D) -> Result { - Ok(MerkleBlock { - header: Decodable::consensus_decode(&mut d)?, - txn: Decodable::consensus_decode(d)?, - }) - } -} - -#[cfg(test)] -mod tests { - use std::cmp::min; - - use hashes::Hash; - use hashes::hex::{FromHex, ToHex}; - use hash_types::{Txid, TxMerkleNode}; - use secp256k1::rand::prelude::*; - - use consensus::encode::{deserialize, serialize}; - use util::hash::{bitcoin_merkle_root, BitcoinHash}; - use util::merkleblock::{MerkleBlock, PartialMerkleTree}; - use {hex, Block}; - - #[test] - fn pmt_tests() { - let mut rng = thread_rng(); - let tx_counts = vec![1, 4, 7, 17, 56, 100, 127, 256, 312, 513, 1000, 4095]; - - for num_tx in tx_counts { - // Create some fake tx ids - let txids = (1..num_tx + 1) // change to `1..=num_tx` when min Rust >= 1.26.0 - .map(|i| Txid::from_hex(&format!("{:064x}", i)).unwrap()) - .collect::>(); - - // Calculate the merkle root and height - let hashes = txids.iter().map(|t| t.as_hash()); - let merkle_root_1: TxMerkleNode = bitcoin_merkle_root(hashes).into(); - let mut height = 1; - let mut ntx = num_tx; - while ntx > 1 { - ntx = (ntx + 1) / 2; - height += 1; - } - - // Check with random subsets with inclusion chances 1, 1/2, 1/4, ..., 1/128 - for att in 1..15 { - let mut matches = vec![false; num_tx]; - let mut match_txid1 = vec![]; - for j in 0..num_tx { - // Generate `att / 2` random bits - let rand_bits = match att / 2 { - 0 => 0, - bits => rng.gen::() >> (64 - bits), - }; - let include = rand_bits == 0; - matches[j] = include; - - if include { - match_txid1.push(txids[j]); - }; - } - - // Build the partial merkle tree - let pmt1 = PartialMerkleTree::from_txids(&txids, &matches); - let serialized = serialize(&pmt1); - - // Verify PartialMerkleTree's size guarantees - let n = min(num_tx, 1 + match_txid1.len() * height); - assert!(serialized.len() <= 10 + (258 * n + 7) / 8); - - // Deserialize into a tester copy - let pmt2: PartialMerkleTree = - deserialize(&serialized).expect("Could not deserialize own data"); - - // Extract merkle root and matched txids from copy - let mut match_txid2: Vec = vec![]; - let mut indexes = vec![]; - let merkle_root_2 = pmt2 - .extract_matches(&mut match_txid2, &mut indexes) - .expect("Could not extract matches"); - - // Check that it has the same merkle root as the original, and a valid one - assert_eq!(merkle_root_1, merkle_root_2); - assert_ne!(merkle_root_2, TxMerkleNode::default()); - - // check that it contains the matched transactions (in the same order!) - assert_eq!(match_txid1, match_txid2); - - // check that random bit flips break the authentication - for _ in 0..4 { - let mut pmt3: PartialMerkleTree = deserialize(&serialized).unwrap(); - pmt3.damage(&mut rng); - let mut match_txid3 = vec![]; - let merkle_root_3 = pmt3 - .extract_matches(&mut match_txid3, &mut indexes) - .unwrap(); - assert_ne!(merkle_root_3, merkle_root_1); - } - } - } - } - - #[test] - fn pmt_malleability() { - // Create some fake tx ids with the last 2 hashes repeating - let txids: Vec = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 10] - .iter() - .map(|i| Txid::from_hex(&format!("{:064x}", i)).unwrap()) - .collect(); - - let matches = vec![ - false, false, false, false, false, false, false, false, false, true, true, false, - ]; - - let tree = PartialMerkleTree::from_txids(&txids, &matches); - // Should fail due to duplicate txs found - let result = tree.extract_matches(&mut vec![], &mut vec![]); - assert!(result.is_err()); - } - - #[test] - fn merkleblock_serialization() { - // Got it by running the rpc call - // `gettxoutproof '["220ebc64e21abece964927322cba69180ed853bb187fbc6923bac7d010b9d87a"]'` - let mb_hex = - "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c\ - 9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930900000005fac\ - 7708a6e81b2a986dea60db2663840ed141130848162eb1bd1dee54f309a1b2ee1e12587e497ada70d9bd10d\ - 31e83f0a924825b96cb8d04e8936d793fb60db7ad8b910d0c7ba2369bc7f18bb53d80e1869ba2c32274996c\ - ebe1ae264bc0e2289189ff0316cdc10511da71da757e553cada9f3b5b1434f3923673adb57d83caac392c38\ - af156d6fc30b55fad4112df2b95531e68114e9ad10011e72f7b7cfdb025700"; - - let mb: MerkleBlock = deserialize(&hex::decode(mb_hex).unwrap()).unwrap(); - assert_eq!(get_block_13b8a().bitcoin_hash(), mb.header.bitcoin_hash()); - assert_eq!( - mb.header.merkle_root, - mb.txn.extract_matches(&mut vec![], &mut vec![]).unwrap() - ); - // Serialize again and check that it matches the original bytes - assert_eq!(mb_hex, serialize(&mb).to_hex().as_str()); - } - - /// Create a CMerkleBlock using a list of txids which will be found in the - /// given block. - #[test] - fn merkleblock_construct_from_txids_found() { - let block = get_block_13b8a(); - - let txids: Vec = [ - "74d681e0e03bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20", - "f9fc751cb7dc372406a9f8d738d5e6f8f63bab71986a39cf36ee70ee17036d07", - ] - .iter() - .map(|hex| Txid::from_hex(hex).unwrap()) - .collect(); - - let txid1 = txids[0]; - let txid2 = txids[1]; - let txids = txids.into_iter().collect(); - - let merkle_block = MerkleBlock::from_block(&block, &txids); - - assert_eq!(merkle_block.header.bitcoin_hash(), block.bitcoin_hash()); - - let mut matches: Vec = vec![]; - let mut index: Vec = vec![]; - - assert_eq!( - merkle_block - .txn - .extract_matches(&mut matches, &mut index) - .unwrap(), - block.header.merkle_root - ); - assert_eq!(matches.len(), 2); - - // Ordered by occurrence in depth-first tree traversal. - assert_eq!(matches[0], txid2); - assert_eq!(index[0], 1); - - assert_eq!(matches[1], txid1); - assert_eq!(index[1], 8); - } - - /// Create a CMerkleBlock using a list of txids which will not be found in the given block - #[test] - fn merkleblock_construct_from_txids_not_found() { - let block = get_block_13b8a(); - let txids = ["c0ffee00003bafa802c8aa084379aa98d9fcd632ddc2ed9782b586ec87451f20"] - .iter() - .map(|hex| Txid::from_hex(hex).unwrap()) - .collect(); - - let merkle_block = MerkleBlock::from_block(&block, &txids); - - assert_eq!(merkle_block.header.bitcoin_hash(), block.bitcoin_hash()); - - let mut matches: Vec = vec![]; - let mut index: Vec = vec![]; - - assert_eq!( - merkle_block - .txn - .extract_matches(&mut matches, &mut index) - .unwrap(), - block.header.merkle_root - ); - assert_eq!(matches.len(), 0); - assert_eq!(index.len(), 0); - } - - impl PartialMerkleTree { - /// Flip one bit in one of the hashes - this should break the authentication - fn damage(&mut self, rng: &mut ThreadRng) { - let n = rng.gen_range(0, self.hashes.len()); - let bit = rng.gen::(); - let hashes = &mut self.hashes; - let mut hash = hashes[n].into_inner(); - hash[(bit >> 3) as usize] ^= 1 << (bit & 7); - hashes[n] = TxMerkleNode::from_slice(&hash).unwrap(); - } - } - - /// Returns a real block (0000000000013b8ab2cd513b0261a14096412195a72a0c4827d229dcc7e0f7af) - /// with 9 txs. - fn get_block_13b8a() -> Block { - let block_hex = - "0100000090f0a9f110702f808219ebea1173056042a714bad51b916cb6800000000000005275289558f51c\ - 9966699404ae2294730c3c9f9bda53523ce50e9b95e558da2fdb261b4d4c86041b1ab1bf930901000000010\ - 000000000000000000000000000000000000000000000000000000000000000ffffffff07044c86041b0146\ - ffffffff0100f2052a01000000434104e18f7afbe4721580e81e8414fc8c24d7cfacf254bb5c7b949450c3e\ - 997c2dc1242487a8169507b631eb3771f2b425483fb13102c4eb5d858eef260fe70fbfae0ac000000000100\ - 00000196608ccbafa16abada902780da4dc35dafd7af05fa0da08cf833575f8cf9e836000000004a4930460\ - 22100dab24889213caf43ae6adc41cf1c9396c08240c199f5225acf45416330fd7dbd022100fe37900e0644\ - bf574493a07fc5edba06dbc07c311b947520c2d514bc5725dcb401ffffffff0100f2052a010000001976a91\ - 4f15d1921f52e4007b146dfa60f369ed2fc393ce288ac000000000100000001fb766c1288458c2bafcfec81\ - e48b24d98ec706de6b8af7c4e3c29419bfacb56d000000008c493046022100f268ba165ce0ad2e6d93f089c\ - fcd3785de5c963bb5ea6b8c1b23f1ce3e517b9f022100da7c0f21adc6c401887f2bfd1922f11d76159cbc59\ - 7fbd756a23dcbb00f4d7290141042b4e8625a96127826915a5b109852636ad0da753c9e1d5606a50480cd0c\ - 40f1f8b8d898235e571fe9357d9ec842bc4bba1827daaf4de06d71844d0057707966affffffff0280969800\ - 000000001976a9146963907531db72d0ed1a0cfb471ccb63923446f388ac80d6e34c000000001976a914f06\ - 88ba1c0d1ce182c7af6741e02658c7d4dfcd388ac000000000100000002c40297f730dd7b5a99567eb8d27b\ - 78758f607507c52292d02d4031895b52f2ff010000008b483045022100f7edfd4b0aac404e5bab4fd3889e0\ - c6c41aa8d0e6fa122316f68eddd0a65013902205b09cc8b2d56e1cd1f7f2fafd60a129ed94504c4ac7bdc67\ - b56fe67512658b3e014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c3423e18b4fb5\ - d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffffca5065ff9617cbcb\ - a45eb23726df6498a9b9cafed4f54cbab9d227b0035ddefb000000008a473044022068010362a13c7f9919f\ - a832b2dee4e788f61f6f5d344a7c2a0da6ae740605658022006d1af525b9a14a35c003b78b72bd59738cd67\ - 6f845d1ff3fc25049e01003614014104732012cb962afa90d31b25d8fb0e32c94e513ab7a17805c14ca4c34\ - 23e18b4fb5d0e676841733cb83abaf975845c9f6f2a8097b7d04f4908b18368d6fc2d68ecffffffff01001e\ - c4110200000043410469ab4181eceb28985b9b4e895c13fa5e68d85761b7eee311db5addef76fa862186513\ - 4a221bd01f28ec9999ee3e021e60766e9d1f3458c115fb28650605f11c9ac000000000100000001cdaf2f75\ - 8e91c514655e2dc50633d1e4c84989f8aa90a0dbc883f0d23ed5c2fa010000008b48304502207ab51be6f12\ - a1962ba0aaaf24a20e0b69b27a94fac5adf45aa7d2d18ffd9236102210086ae728b370e5329eead9accd880\ - d0cb070aea0c96255fae6c4f1ddcce1fd56e014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf3\ - 3d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffff\ - ffff02404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37c32f5c388ac002d310100000\ - 0001976a9141befba0cdc1ad56529371864d9f6cb042faa06b588ac000000000100000001b4a47603e71b61\ - bc3326efd90111bf02d2f549b067f4c4a8fa183b57a0f800cb010000008a4730440220177c37f9a505c3f1a\ - 1f0ce2da777c339bd8339ffa02c7cb41f0a5804f473c9230220585b25a2ee80eb59292e52b987dad92acb0c\ - 64eced92ed9ee105ad153cdb12d001410443bd44f683467e549dae7d20d1d79cbdb6df985c6e9c029c8d0c6\ - cb46cc1a4d3cf7923c5021b27f7a0b562ada113bc85d5fda5a1b41e87fe6e8802817cf69996ffffffff0280\ - 651406000000001976a9145505614859643ab7b547cd7f1f5e7e2a12322d3788ac00aa0271000000001976a\ - 914ea4720a7a52fc166c55ff2298e07baf70ae67e1b88ac00000000010000000586c62cd602d219bb60edb1\ - 4a3e204de0705176f9022fe49a538054fb14abb49e010000008c493046022100f2bc2aba2534becbdf062eb\ - 993853a42bbbc282083d0daf9b4b585bd401aa8c9022100b1d7fd7ee0b95600db8535bbf331b19eed8d961f\ - 7a8e54159c53675d5f69df8c014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d\ - 0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff03ad0e58\ - ccdac3df9dc28a218bcf6f1997b0a93306faaa4b3a28ae83447b2179010000008b483045022100be12b2937\ - 179da88599e27bb31c3525097a07cdb52422d165b3ca2f2020ffcf702200971b51f853a53d644ebae9ec8f3\ - 512e442b1bcb6c315a5b491d119d10624c83014104462e76fd4067b3a0aa42070082dcb0bf2f388b6495cf3\ - 3d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8ebbb12dcd4ffff\ - ffff2acfcab629bbc8685792603762c921580030ba144af553d271716a95089e107b010000008b483045022\ - 100fa579a840ac258871365dd48cd7552f96c8eea69bd00d84f05b283a0dab311e102207e3c0ee9234814cf\ - bb1b659b83671618f45abc1326b9edcc77d552a4f2a805c0014104462e76fd4067b3a0aa42070082dcb0bf2\ - f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15312ef1c0e8eb\ - bb12dcd4ffffffffdcdc6023bbc9944a658ddc588e61eacb737ddf0a3cd24f113b5a8634c517fcd20000000\ - 08b4830450221008d6df731df5d32267954bd7d2dda2302b74c6c2a6aa5c0ca64ecbabc1af03c75022010e5\ - 5c571d65da7701ae2da1956c442df81bbf076cdbac25133f99d98a9ed34c014104462e76fd4067b3a0aa420\ - 70082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812b1d5fbcade15\ - 312ef1c0e8ebbb12dcd4ffffffffe15557cd5ce258f479dfd6dc6514edf6d7ed5b21fcfa4a038fd69f06b83\ - ac76e010000008b483045022023b3e0ab071eb11de2eb1cc3a67261b866f86bf6867d4558165f7c8c8aca2d\ - 86022100dc6e1f53a91de3efe8f63512850811f26284b62f850c70ca73ed5de8771fb451014104462e76fd4\ - 067b3a0aa42070082dcb0bf2f388b6495cf33d789904f07d0f55c40fbd4b82963c69b3dc31895d0c772c812\ - b1d5fbcade15312ef1c0e8ebbb12dcd4ffffffff01404b4c00000000001976a9142b6ba7c9d796b75eef794\ - 2fc9288edd37c32f5c388ac00000000010000000166d7577163c932b4f9690ca6a80b6e4eb001f0a2fa9023\ - df5595602aae96ed8d000000008a4730440220262b42546302dfb654a229cefc86432b89628ff259dc87edd\ - 1154535b16a67e102207b4634c020a97c3e7bbd0d4d19da6aa2269ad9dded4026e896b213d73ca4b63f0141\ - 04979b82d02226b3a4597523845754d44f13639e3bf2df5e82c6aab2bdc79687368b01b1ab8b19875ae3c90\ - d661a3d0a33161dab29934edeb36aa01976be3baf8affffffff02404b4c00000000001976a9144854e695a0\ - 2af0aeacb823ccbc272134561e0a1688ac40420f00000000001976a914abee93376d6b37b5c2940655a6fca\ - f1c8e74237988ac0000000001000000014e3f8ef2e91349a9059cb4f01e54ab2597c1387161d3da89919f7e\ - a6acdbb371010000008c49304602210081f3183471a5ca22307c0800226f3ef9c353069e0773ac76bb58065\ - 4d56aa523022100d4c56465bdc069060846f4fbf2f6b20520b2a80b08b168b31e66ddb9c694e24001410497\ - 6c79848e18251612f8940875b2b08d06e6dc73b9840e8860c066b7e87432c477e9a59a453e71e6d76d5fe34\ - 058b800a098fc1740ce3012e8fc8a00c96af966ffffffff02c0e1e400000000001976a9144134e75a6fcb60\ - 42034aab5e18570cf1f844f54788ac404b4c00000000001976a9142b6ba7c9d796b75eef7942fc9288edd37\ - c32f5c388ac00000000"; - deserialize(&hex::decode(block_hex).unwrap()).unwrap() - } -} diff --git a/src/util/misc.rs b/src/util/misc.rs deleted file mode 100644 index f5c2a545..00000000 --- a/src/util/misc.rs +++ /dev/null @@ -1,123 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Miscellaneous functions -//! -//! Various utility functions - -use hashes::{sha256d, Hash}; -use blockdata::opcodes; -use consensus::encode; - -static MSG_SIGN_PREFIX: &'static [u8] = b"\x18Bitcoin Signed Message:\n"; - -/// Search for `needle` in the vector `haystack` and remove every -/// instance of it, returning the number of instances removed. -/// Loops through the vector opcode by opcode, skipping pushed data. -pub fn script_find_and_remove(haystack: &mut Vec, needle: &[u8]) -> usize { - if needle.len() > haystack.len() { return 0; } - if needle.len() == 0 { return 0; } - - let mut top = haystack.len() - needle.len(); - let mut n_deleted = 0; - - let mut i = 0; - while i <= top { - if &haystack[i..(i + needle.len())] == needle { - for j in i..top { - haystack.swap(j + needle.len(), j); - } - n_deleted += 1; - // This is ugly but prevents infinite loop in case of overflow - let overflow = top < needle.len(); - top = top.wrapping_sub(needle.len()); - if overflow { break; } - } else { - i += match opcodes::All::from((*haystack)[i]).classify() { - opcodes::Class::PushBytes(n) => n as usize + 1, - opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA1) => 2, - opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA2) => 3, - opcodes::Class::Ordinary(opcodes::Ordinary::OP_PUSHDATA4) => 5, - _ => 1 - }; - } - } - haystack.truncate(top.wrapping_add(needle.len())); - n_deleted -} - -/// Hash message for signature using Bitcoin's message signing format -pub fn signed_msg_hash(msg: &str) -> sha256d::Hash { - sha256d::Hash::hash( - &[ - MSG_SIGN_PREFIX, - &encode::serialize(&encode::VarInt(msg.len() as u64)), - msg.as_bytes(), - ] - .concat(), - ) -} - -#[cfg(test)] -mod tests { - use hashes::hex::ToHex; - use super::script_find_and_remove; - use super::signed_msg_hash; - - #[test] - fn test_script_find_and_remove() { - let mut v = vec![101u8, 102, 103, 104, 102, 103, 104, 102, 103, 104, 105, 106, 107, 108, 109]; - - assert_eq!(script_find_and_remove(&mut v, &[]), 0); - assert_eq!(script_find_and_remove(&mut v, &[105, 105, 105]), 0); - assert_eq!(v, vec![101, 102, 103, 104, 102, 103, 104, 102, 103, 104, 105, 106, 107, 108, 109]); - - assert_eq!(script_find_and_remove(&mut v, &[105, 106, 107]), 1); - assert_eq!(v, vec![101, 102, 103, 104, 102, 103, 104, 102, 103, 104, 108, 109]); - - assert_eq!(script_find_and_remove(&mut v, &[104, 108, 109]), 1); - assert_eq!(v, vec![101, 102, 103, 104, 102, 103, 104, 102, 103]); - - assert_eq!(script_find_and_remove(&mut v, &[101]), 1); - assert_eq!(v, vec![102, 103, 104, 102, 103, 104, 102, 103]); - - assert_eq!(script_find_and_remove(&mut v, &[102]), 3); - assert_eq!(v, vec![103, 104, 103, 104, 103]); - - assert_eq!(script_find_and_remove(&mut v, &[103, 104]), 2); - assert_eq!(v, vec![103]); - - assert_eq!(script_find_and_remove(&mut v, &[105, 105, 5]), 0); - assert_eq!(script_find_and_remove(&mut v, &[105]), 0); - assert_eq!(script_find_and_remove(&mut v, &[103]), 1); - assert_eq!(v, Vec::::new()); - - assert_eq!(script_find_and_remove(&mut v, &[105, 105, 5]), 0); - assert_eq!(script_find_and_remove(&mut v, &[105]), 0); - } - - #[test] - fn test_script_codesep_remove() { - let mut s = vec![33u8, 3, 132, 121, 160, 250, 153, 140, 211, 82, 89, 162, 239, 10, 122, 92, 104, 102, 44, 20, 116, 248, 140, 203, 109, 8, 167, 103, 123, 190, 199, 242, 32, 65, 173, 171, 33, 3, 132, 121, 160, 250, 153, 140, 211, 82, 89, 162, 239, 10, 122, 92, 104, 102, 44, 20, 116, 248, 140, 203, 109, 8, 167, 103, 123, 190, 199, 242, 32, 65, 173, 171, 81]; - assert_eq!(script_find_and_remove(&mut s, &[171]), 2); - assert_eq!(s, vec![33, 3, 132, 121, 160, 250, 153, 140, 211, 82, 89, 162, 239, 10, 122, 92, 104, 102, 44, 20, 116, 248, 140, 203, 109, 8, 167, 103, 123, 190, 199, 242, 32, 65, 173, 33, 3, 132, 121, 160, 250, 153, 140, 211, 82, 89, 162, 239, 10, 122, 92, 104, 102, 44, 20, 116, 248, 140, 203, 109, 8, 167, 103, 123, 190, 199, 242, 32, 65, 173, 81]); - } - - #[test] - fn test_signed_msg_hash() { - let hash = signed_msg_hash("test"); - assert_eq!(hash.to_hex(), "a6f87fe6d58a032c320ff8d1541656f0282c2c7bfcc69d61af4c8e8ed528e49c"); - } -} - diff --git a/src/util/mod.rs b/src/util/mod.rs deleted file mode 100644 index 36ebc5ee..00000000 --- a/src/util/mod.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Rust Bitcoin Library -// Written in 2014 by -// Andrew Poelstra -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -//! Utility functions -//! -//! Functions needed by all parts of the Bitcoin library - -pub mod key; -pub mod address; -pub mod amount; -pub mod base58; -pub mod bip32; -pub mod bip143; -pub mod contracthash; -pub mod hash; -pub mod merkleblock; -pub mod misc; -pub mod psbt; -pub mod uint; -pub mod bip158; - -pub(crate) mod endian; - -use std::{error, fmt}; - -use network; -use consensus::encode; - -/// A trait which allows numbers to act as fixed-size bit arrays -pub trait BitArray { - /// Is bit set? - fn bit(&self, idx: usize) -> bool; - - /// Returns an array which is just the bits from start to end - fn bit_slice(&self, start: usize, end: usize) -> Self; - - /// Bitwise and with `n` ones - fn mask(&self, n: usize) -> Self; - - /// Trailing zeros - fn trailing_zeros(&self) -> usize; - - /// Create all-zeros value - fn zero() -> Self; - - /// Create value representing one - fn one() -> Self; -} - -/// A general error code, other errors should implement conversions to/from this -/// if appropriate. -#[derive(Debug)] -pub enum Error { - /// Encoding error - Encode(encode::Error), - /// Network error - Network(network::Error), - /// The header hash is not below the target - BlockBadProofOfWork, - /// The `target` field of a block header did not match the expected difficulty - BlockBadTarget, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::Encode(ref e) => fmt::Display::fmt(e, f), - Error::Network(ref e) => fmt::Display::fmt(e, f), - Error::BlockBadProofOfWork | Error::BlockBadTarget => f.write_str(error::Error::description(self)), - } - } -} - -impl error::Error for Error { - fn cause(&self) -> Option<&error::Error> { - match *self { - Error::Encode(ref e) => Some(e), - Error::Network(ref e) => Some(e), - Error::BlockBadProofOfWork | Error::BlockBadTarget => None - } - } - - fn description(&self) -> &str { - match *self { - Error::Encode(ref e) => e.description(), - Error::Network(ref e) => e.description(), - Error::BlockBadProofOfWork => "block target correct but not attained", - Error::BlockBadTarget => "block target incorrect", - } - } -} - -#[doc(hidden)] -impl From for Error { - fn from(e: encode::Error) -> Error { - Error::Encode(e) - } -} - -#[doc(hidden)] -impl From for Error { - fn from(e: network::Error) -> Error { - Error::Network(e) - } -} diff --git a/src/util/psbt/error.rs b/src/util/psbt/error.rs deleted file mode 100644 index 1f3cb928..00000000 --- a/src/util/psbt/error.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Rust Bitcoin Library -// Written by -// The Rust Bitcoin developers -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -use std::error; -use std::fmt; - -use blockdata::transaction::Transaction; -use util::psbt::raw; - -/// Ways that a Partially Signed Transaction might fail. -#[derive(Debug)] -pub enum Error { - /// Magic bytes for a PSBT must be the ASCII for "psbt" serialized in most - /// significant byte order. - InvalidMagic, - /// The separator for a PSBT must be `0xff`. - InvalidSeparator, - /// Known keys must be according to spec. - InvalidKey(raw::Key), - /// Keys within key-value map should never be duplicated. - DuplicateKey(raw::Key), - /// The scriptSigs for the unsigned transaction must be empty. - UnsignedTxHasScriptSigs, - /// The scriptWitnesses for the unsigned transaction must be empty. - UnsignedTxHasScriptWitnesses, - /// A PSBT must have an unsigned transaction. - MustHaveUnsignedTx, - /// Signals that there are no more key-value pairs in a key-value map. - NoMorePairs, - /// Attempting to merge with a PSBT describing a different unsigned - /// transaction. - UnexpectedUnsignedTx { - /// Expected - expected: Transaction, - /// Actual - actual: Transaction, - }, - /// Unable to parse as a standard SigHash type. - NonStandardSigHashType(u32), -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - Error::InvalidKey(ref rkey) => write!(f, "{}: {}", error::Error::description(self), rkey), - Error::DuplicateKey(ref rkey) => write!(f, "{}: {}", error::Error::description(self), rkey), - Error::UnexpectedUnsignedTx { expected: ref e, actual: ref a } => write!(f, "{}: expected {}, actual {}", error::Error::description(self), e.txid(), a.txid()), - Error::NonStandardSigHashType(ref sht) => write!(f, "{}: {}", error::Error::description(self), sht), - Error::InvalidMagic - | Error::InvalidSeparator - | Error::UnsignedTxHasScriptSigs - | Error::UnsignedTxHasScriptWitnesses - | Error::MustHaveUnsignedTx - | Error::NoMorePairs => f.write_str(error::Error::description(self)) - } - } -} - -impl error::Error for Error { - fn description(&self) -> &str { - match *self { - Error::InvalidMagic => "invalid magic", - Error::InvalidSeparator => "invalid separator", - Error::InvalidKey(..) => "invalid key", - Error::DuplicateKey(..) => "duplicate key", - Error::UnsignedTxHasScriptSigs => "the unsigned transaction has script sigs", - Error::UnsignedTxHasScriptWitnesses => "the unsigned transaction has script witnesses", - Error::MustHaveUnsignedTx => { - "partially signed transactions must have an unsigned transaction" - } - Error::NoMorePairs => "no more key-value pairs for this psbt map", - Error::UnexpectedUnsignedTx { .. } => "different unsigned transaction", - Error::NonStandardSigHashType(..) => "non-standard sighash type", - } - } -} diff --git a/src/util/psbt/macros.rs b/src/util/psbt/macros.rs deleted file mode 100644 index 020f1ff6..00000000 --- a/src/util/psbt/macros.rs +++ /dev/null @@ -1,159 +0,0 @@ -// Rust Bitcoin Library -// Written by -// The Rust Bitcoin developers -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -#[allow(unused_macros)] -macro_rules! hex_psbt { - ($s:expr) => { ::consensus::deserialize(&::hex::decode($s).unwrap()) }; -} - -macro_rules! merge { - ($thing:ident, $slf:ident, $other:ident) => { - if let (&None, Some($thing)) = (&$slf.$thing, $other.$thing) { - $slf.$thing = Some($thing); - } - }; -} - -macro_rules! impl_psbt_de_serialize { - ($thing:ty) => { - impl_psbt_serialize!($thing); - impl_psbt_deserialize!($thing); - }; -} - -macro_rules! impl_psbt_deserialize { - ($thing:ty) => { - impl ::util::psbt::serialize::Deserialize for $thing { - fn deserialize(bytes: &[u8]) -> Result { - ::consensus::deserialize(&bytes[..]) - } - } - }; -} - -macro_rules! impl_psbt_serialize { - ($thing:ty) => { - impl ::util::psbt::serialize::Serialize for $thing { - fn serialize(&self) -> Vec { - ::consensus::serialize(self) - } - } - }; -} - -macro_rules! impl_psbtmap_consensus_encoding { - ($thing:ty) => { - impl ::consensus::Encodable for $thing { - fn consensus_encode( - &self, - mut s: S, - ) -> Result { - let mut len = 0; - for pair in ::util::psbt::Map::get_pairs(self)? { - len += ::consensus::Encodable::consensus_encode( - &pair, - &mut s, - )?; - } - - Ok(len + ::consensus::Encodable::consensus_encode(&0x00_u8, s)?) - } - } - }; -} - -macro_rules! impl_psbtmap_consensus_decoding { - ($thing:ty) => { - impl ::consensus::Decodable for $thing { - fn consensus_decode( - mut d: D, - ) -> Result { - let mut rv: Self = ::std::default::Default::default(); - - loop { - match ::consensus::Decodable::consensus_decode(&mut d) { - Ok(pair) => ::util::psbt::Map::insert_pair(&mut rv, pair)?, - Err(::consensus::encode::Error::Psbt(::util::psbt::Error::NoMorePairs)) => return Ok(rv), - Err(e) => return Err(e), - } - } - } - } - }; -} - -macro_rules! impl_psbtmap_consensus_enc_dec_oding { - ($thing:ty) => { - impl_psbtmap_consensus_decoding!($thing); - impl_psbtmap_consensus_encoding!($thing); - }; -} - -#[cfg_attr(rustfmt, rustfmt_skip)] -macro_rules! impl_psbt_insert_pair { - ($slf:ident.$unkeyed_name:ident <= <$raw_key:ident: _>|<$raw_value:ident: $unkeyed_value_type:ty>) => { - if $raw_key.key.is_empty() { - if let None = $slf.$unkeyed_name { - let val: $unkeyed_value_type = ::util::psbt::serialize::Deserialize::deserialize(&$raw_value)?; - - $slf.$unkeyed_name = Some(val) - } else { - return Err(::util::psbt::Error::DuplicateKey($raw_key).into()); - } - } else { - return Err(::util::psbt::Error::InvalidKey($raw_key).into()); - } - }; - ($slf:ident.$keyed_name:ident <= <$raw_key:ident: $keyed_key_type:ty>|<$raw_value:ident: $keyed_value_type:ty>) => { - if !$raw_key.key.is_empty() { - let key_val: $keyed_key_type = ::util::psbt::serialize::Deserialize::deserialize(&$raw_key.key)?; - - if $slf.$keyed_name.contains_key(&key_val) { - return Err(::util::psbt::Error::DuplicateKey($raw_key).into()); - } else { - let val: $keyed_value_type = ::util::psbt::serialize::Deserialize::deserialize(&$raw_value)?; - - $slf.$keyed_name.insert(key_val, val); - } - } else { - return Err(::util::psbt::Error::InvalidKey($raw_key).into()); - } - }; -} - -#[cfg_attr(rustfmt, rustfmt_skip)] -macro_rules! impl_psbt_get_pair { - ($rv:ident.push($slf:ident.$unkeyed_name:ident as <$unkeyed_typeval:expr, _>|<$unkeyed_value_type:ty>)) => { - if let Some(ref $unkeyed_name) = $slf.$unkeyed_name { - $rv.push(::util::psbt::raw::Pair { - key: ::util::psbt::raw::Key { - type_value: $unkeyed_typeval, - key: vec![], - }, - value: ::util::psbt::serialize::Serialize::serialize($unkeyed_name), - }); - } - }; - ($rv:ident.push($slf:ident.$keyed_name:ident as <$keyed_typeval:expr, $keyed_key_type:ty>|<$keyed_value_type:ty>)) => { - for (key, val) in &$slf.$keyed_name { - $rv.push(::util::psbt::raw::Pair { - key: ::util::psbt::raw::Key { - type_value: $keyed_typeval, - key: ::util::psbt::serialize::Serialize::serialize(key), - }, - value: ::util::psbt::serialize::Serialize::serialize(val), - }); - } - }; -} diff --git a/src/util/psbt/map/global.rs b/src/util/psbt/map/global.rs deleted file mode 100644 index b34b4114..00000000 --- a/src/util/psbt/map/global.rs +++ /dev/null @@ -1,183 +0,0 @@ -// Rust Bitcoin Library -// Written by -// The Rust Bitcoin developers -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -use std::collections::BTreeMap; -use std::io::{self, Cursor}; - -use blockdata::transaction::Transaction; -use consensus::{encode, Encodable, Decodable}; -use util::psbt::map::Map; -use util::psbt::raw; -use util::psbt; -use util::psbt::Error; - -/// A key-value map for global data. -#[derive(Clone, Debug, PartialEq)] -pub struct Global { - /// The unsigned transaction, scriptSigs and witnesses for each input must be - /// empty. - pub unsigned_tx: Transaction, - /// Unknown global key-value pairs. - pub unknown: BTreeMap>, -} - -impl Global { - /// Create a Global from an unsigned transaction, error if not unsigned - pub fn from_unsigned_tx(tx: Transaction) -> Result { - for txin in &tx.input { - if !txin.script_sig.is_empty() { - return Err(Error::UnsignedTxHasScriptSigs); - } - - if !txin.witness.is_empty() { - return Err(Error::UnsignedTxHasScriptWitnesses); - } - } - - Ok(Global { - unsigned_tx: tx, - unknown: Default::default(), - }) - } -} - -impl Map for Global { - fn insert_pair(&mut self, pair: raw::Pair) -> Result<(), encode::Error> { - let raw::Pair { - key: raw_key, - value: raw_value, - } = pair; - - match raw_key.type_value { - 0u8 => { - return Err(Error::DuplicateKey(raw_key).into()); - } - _ => { - if self.unknown.contains_key(&raw_key) { - return Err(Error::DuplicateKey(raw_key).into()); - } else { - self.unknown.insert(raw_key, raw_value); - } - } - } - - Ok(()) - } - - fn get_pairs(&self) -> Result, encode::Error> { - let mut rv: Vec = Default::default(); - - rv.push(raw::Pair { - key: raw::Key { - type_value: 0u8, - key: vec![], - }, - value: { - // Manually serialized to ensure 0-input txs are serialized - // without witnesses. - let mut ret = Vec::new(); - self.unsigned_tx.version.consensus_encode(&mut ret)?; - self.unsigned_tx.input.consensus_encode(&mut ret)?; - self.unsigned_tx.output.consensus_encode(&mut ret)?; - self.unsigned_tx.lock_time.consensus_encode(&mut ret)?; - ret - }, - }); - - for (key, value) in self.unknown.iter() { - rv.push(raw::Pair { - key: key.clone(), - value: value.clone(), - }); - } - - Ok(rv) - } - - fn merge(&mut self, other: Self) -> Result<(), psbt::Error> { - if self.unsigned_tx != other.unsigned_tx { - return Err(psbt::Error::UnexpectedUnsignedTx { - expected: self.unsigned_tx.clone(), - actual: other.unsigned_tx, - }); - } - - self.unknown.extend(other.unknown); - Ok(()) - } -} - -impl_psbtmap_consensus_encoding!(Global); - -impl Decodable for Global { - fn consensus_decode(mut d: D) -> Result { - - let mut tx: Option = None; - let mut unknowns: BTreeMap> = Default::default(); - - loop { - match raw::Pair::consensus_decode(&mut d) { - Ok(pair) => { - match pair.key.type_value { - 0u8 => { - // key has to be empty - if pair.key.key.is_empty() { - // there can only be one unsigned transaction - if tx.is_none() { - let vlen: usize = pair.value.len(); - let mut decoder = Cursor::new(pair.value); - - // Manually deserialized to ensure 0-input - // txs without witnesses are deserialized - // properly. - tx = Some(Transaction { - version: Decodable::consensus_decode(&mut decoder)?, - input: Decodable::consensus_decode(&mut decoder)?, - output: Decodable::consensus_decode(&mut decoder)?, - lock_time: Decodable::consensus_decode(&mut decoder)?, - }); - - if decoder.position() != vlen as u64 { - return Err(encode::Error::ParseFailed("data not consumed entirely when explicitly deserializing")) - } - } else { - return Err(Error::DuplicateKey(pair.key).into()) - } - } else { - return Err(Error::InvalidKey(pair.key).into()) - } - } - _ => { - if unknowns.contains_key(&pair.key) { - return Err(Error::DuplicateKey(pair.key).into()); - } else { - unknowns.insert(pair.key, pair.value); - } - } - } - } - Err(::consensus::encode::Error::Psbt(::util::psbt::Error::NoMorePairs)) => break, - Err(e) => return Err(e), - } - } - - if let Some(tx) = tx { - let mut rv: Global = Global::from_unsigned_tx(tx)?; - rv.unknown = unknowns; - Ok(rv) - } else { - Err(Error::MustHaveUnsignedTx.into()) - } - } -} diff --git a/src/util/psbt/map/input.rs b/src/util/psbt/map/input.rs deleted file mode 100644 index 32f19bc5..00000000 --- a/src/util/psbt/map/input.rs +++ /dev/null @@ -1,197 +0,0 @@ -// Rust Bitcoin Library -// Written by -// The Rust Bitcoin developers -// -// To the extent possible under law, the author(s) have dedicated all -// copyright and related and neighboring rights to this software to -// the public domain worldwide. This software is distributed without -// any warranty. -// -// You should have received a copy of the CC0 Public Domain Dedication -// along with this software. -// If not, see . -// - -use std::collections::BTreeMap; - -use blockdata::script::Script; -use blockdata::transaction::{SigHashType, Transaction, TxOut}; -use consensus::encode; -use util::bip32::{DerivationPath, Fingerprint}; -use util::key::PublicKey; -use util::psbt; -use util::psbt::map::Map; -use util::psbt::raw; -use util::psbt::Error; - -/// A key-value map for an input of the corresponding index in the unsigned -/// transaction. -#[derive(Clone, Default, Debug, PartialEq)] -pub struct Input { - /// The non-witness transaction this input spends from. Should only be - /// [std::option::Option::Some] for inputs which spend non-segwit outputs or - /// if it is unknown whether an input spends a segwit output. - pub non_witness_utxo: Option, - /// The transaction output this input spends from. Should only be - /// [std::option::Option::Some] for inputs which spend segwit outputs, - /// including P2SH embedded ones. - pub witness_utxo: Option, - /// A map from public keys to their corresponding signature as would be - /// pushed to the stack from a scriptSig or witness. - pub partial_sigs: BTreeMap>, - /// The sighash type to be used for this input. Signatures for this input - /// must use the sighash type. - pub sighash_type: Option, - /// The redeem script for this input. - pub redeem_script: Option