bs58-0.5.1/.cargo_vcs_info.json0000644000000001360000000000100116200ustar { "git": { "sha1": "7d3c9282d2595612e5474df93dd0e017db9b684f" }, "path_in_vcs": "" }bs58-0.5.1/.github/workflows/nightly.yml000064400000000000000000000002241046102023000162040ustar 00000000000000jobs: nightly: uses: Nullus157/.github/.github/workflows/nightly.yml@main on: schedule: - cron: '0 2 * * *' push: branches: [main] bs58-0.5.1/.github/workflows/pull_request.yml000064400000000000000000000007011046102023000172520ustar 00000000000000jobs: pull_request: uses: Nullus157/.github/.github/workflows/pull_request.yml@main success: runs-on: ubuntu-latest needs: [pull_request] if: ${{ always() }} steps: - if: ${{ contains(needs.*.result, 'failure') }} run: exit 1 - if: ${{ contains(needs.*.result, 'cancelled') }} run: exit 1 - if: ${{ contains(needs.*.result, 'skipped') }} run: exit 1 on: pull_request: branches: [main] bs58-0.5.1/.github/workflows/staging.yml000064400000000000000000000010331046102023000161610ustar 00000000000000jobs: pull_request: uses: Nullus157/.github/.github/workflows/pull_request.yml@main staging: uses: Nullus157/.github/.github/workflows/staging.yml@main success: runs-on: ubuntu-latest needs: [pull_request, staging] if: ${{ always() }} steps: - if: ${{ contains(needs.*.result, 'failure') }} run: exit 1 - if: ${{ contains(needs.*.result, 'cancelled') }} run: exit 1 - if: ${{ contains(needs.*.result, 'skipped') }} run: exit 1 on: merge_group: type: [checks_requested] bs58-0.5.1/.gitignore000064400000000000000000000000071046102023000123750ustar 00000000000000target bs58-0.5.1/CHANGELOG.md000064400000000000000000000041571046102023000122300ustar 00000000000000# Changelog ## Unreleased ## 0.5.1 - 2024-03-19 * Make it possible to decode in `const`-context (by @joncinque) ## 0.5.0 - 2023-05-23 * Breaking change: make encoding onto resizable buffers not clear them, instead appending onto any existing data * Breaking change: rename `into` methods to `onto` to allow for implementing `Into` in the future (or a similar inherent method) * Add new `cb58` feature to support injecting and verifying that checksum (by @Zondax) * Update `sha2` to 0.10 (by @madninja) * Tighten max-encoded length estimation to reduce overallocation of resizable buffers (by @mina86) * Add optional support for encoding/decoding to `smallvec::SmallVec` (by @mina86) * Add optional support for encoding/decoding to `tinyvec`'s various types ## 0.4.0 - 2020-11-06 * Correct documentation on version mismatch error (by @taoweicn) * Update `sha2` from 0.8 to 0.9 * Switch error enums to use new `#[non_exhaustive]` attribute * Use new `const fn` features to drastically simplify construction of a prepared alphabet * Update documentation and examples to use `?` instead of `unwrap` * Remove the non-prepared alphabet APIs, update alphabet construction to pre-verify requirements of a consistent alphabet ## 0.3.1 - 2020-04-20 * Removed an unnecessary unsafe block (by @fanatid) * Internal code cleanup (by @fanatid) * Add ability to pre-prepare the alphabet for performance (by @fanatid) * Add function to append the version onto the data automatically for Base58Check encoding (by @fanatid) ## 0.3.0 - 2019-09-16 ## 0.2.5 - 2019-08-30 ## 0.2.4 - 2019-08-19 ## 0.2.3 - 2019-08-19 ## 0.2.2 - 2018-09-15 * Base58Check support (thanks to @devin-fisher) ## 0.2.1 - 2018-06-12 * Fix tests on Rust 1.27+ * Fix potential unsoundness when encoding with a custom alphabet ## 0.2.0 - 2017-01-07 * Major refactor to use a builder pattern instead of traits * Traits still kept, but deprecated and likely to disappear in next major version * Now supports writing output to a provided buffer for better performance/heapless code. ## 0.1.3 - 2016-11-05 ## 0.1.2 - 2016-11-02 ## 0.1.1 - 2016-11-02 ## 0.1.0 - 2016-11-02 bs58-0.5.1/Cargo.lock0000644000000506040000000000100076000ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "anes" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" [[package]] name = "anstyle" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "assert_matches" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base58" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] [[package]] name = "bs58" version = "0.5.1" dependencies = [ "assert_matches", "base58", "criterion", "rust-base58", "sha2", "smallvec", "tinyvec", ] [[package]] name = "bumpalo" version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "cast" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "ciborium" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ "ciborium-io", "ciborium-ll", "serde", ] [[package]] name = "ciborium-io" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] name = "ciborium-ll" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" dependencies = [ "ciborium-io", "half", ] [[package]] name = "clap" version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" dependencies = [ "clap_builder", ] [[package]] name = "clap_builder" version = "4.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" dependencies = [ "anstyle", "clap_lex", ] [[package]] name = "clap_lex" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "cpufeatures" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "criterion" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" dependencies = [ "anes", "cast", "ciborium", "clap", "criterion-plot", "is-terminal", "itertools", "num-traits", "once_cell", "oorandom", "plotters", "rayon", "regex", "serde", "serde_derive", "serde_json", "tinytemplate", "walkdir", ] [[package]] name = "criterion-plot" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" dependencies = [ "cast", "itertools", ] [[package]] name = "crossbeam-deque" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", ] [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", ] [[package]] name = "either" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", ] [[package]] name = "half" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5eceaaeec696539ddaf7b333340f1af35a5aa87ae3e4f3ead0532f72affab2e" dependencies = [ "cfg-if", "crunchy", ] [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "is-terminal" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", "libc", "windows-sys", ] [[package]] name = "itertools" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "libc" version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "memchr" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "num" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" dependencies = [ "num-bigint", "num-complex", "num-integer", "num-iter", "num-rational", "num-traits", ] [[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", ] [[package]] name = "num-complex" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6" dependencies = [ "num-traits", ] [[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-iter" version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-rational" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", "num-bigint", "num-integer", "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 = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "oorandom" version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" [[package]] name = "plotters" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ "num-traits", "plotters-backend", "plotters-svg", "wasm-bindgen", "web-sys", ] [[package]] name = "plotters-backend" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" [[package]] name = "plotters-svg" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" dependencies = [ "plotters-backend", ] [[package]] name = "proc-macro2" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "regex" version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rust-base58" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b313b91fcdc6719ad41fa2dad2b7e810b03833fae4bf911950e15529a5f04439" dependencies = [ "num", ] [[package]] name = "ryu" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "serde" version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "smallvec" version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "syn" version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tinytemplate" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ "serde", "serde_json", ] [[package]] name = "tinyvec" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "wasm-bindgen" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" bs58-0.5.1/Cargo.toml0000644000000030570000000000100076230ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "bs58" version = "0.5.1" description = "Another Base58 codec implementation." readme = "README.md" keywords = ["base58"] license = "MIT/Apache-2.0" repository = "https://github.com/Nullus157/bs58-rs" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [[bench]] name = "encode" path = "benches/encode.rs" harness = false [[bench]] name = "decode" path = "benches/decode.rs" harness = false [dependencies.sha2] version = "0.10" optional = true default-features = false [dependencies.smallvec] version = "1" optional = true [dependencies.tinyvec] version = "1.6.0" features = ["grab_spare_slice"] optional = true default-features = false [dev-dependencies.assert_matches] version = "1.3.0" [dev-dependencies.base58] version = "0.1.0" [dev-dependencies.criterion] version = "0.5" [dev-dependencies.rust-base58] version = "0.0.4" [dev-dependencies.tinyvec] version = "1.6.0" features = ["rustc_1_55"] [features] alloc = ["tinyvec?/alloc"] cb58 = ["sha2"] check = ["sha2"] default = ["std"] std = [ "alloc", "tinyvec?/std", ] bs58-0.5.1/Cargo.toml.orig000064400000000000000000000017641046102023000133070ustar 00000000000000[package] name = "bs58" version = "0.5.1" description = "Another Base58 codec implementation." repository = "https://github.com/Nullus157/bs58-rs" readme = "README.md" keywords = ["base58"] license = "MIT/Apache-2.0" edition = "2021" [workspace] members = ["cli"] [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] [features] default = ["std"] std = ["alloc", "tinyvec?/std"] alloc = ["tinyvec?/alloc"] check = ["sha2"] cb58 = ["sha2"] [dependencies] sha2 = { version = "0.10", optional = true, default-features = false } smallvec = { version = "1", optional = true } tinyvec = { version = "1.6.0", default-features = false, optional = true, features = ["grab_spare_slice"] } [dev-dependencies] criterion = "0.5" base58 = "0.1.0" rust-base58 = "0.0.4" assert_matches = "1.3.0" tinyvec = { version = "1.6.0", features = ["rustc_1_55"] } [[bench]] name = "encode" path = "benches/encode.rs" harness = false [[bench]] name = "decode" path = "benches/decode.rs" harness = false bs58-0.5.1/LICENSE-APACHE000064400000000000000000000251371046102023000123440ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. bs58-0.5.1/LICENSE-MIT000064400000000000000000000020721046102023000120450ustar 00000000000000MIT License Copyright (c) 2016 The roaring-rs developers. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bs58-0.5.1/README.md000064400000000000000000000033671046102023000117000ustar 00000000000000[![version-badge][]][version] [![license-badge][]][license] [![rust-version-badge][]][rust-version] Another Rust [Base58][] codec implementation. Compared to [`base58`][] this is significantly faster at decoding (about 2.4x as fast when decoding 32 bytes), almost the same speed for encoding (about 3% slower when encoding 32 bytes), doesn't have the 128 byte limitation and supports a configurable alphabet. Compared to [`rust-base58`][] this is massively faster (over ten times as fast when decoding 32 bytes, almost 40 times as fast when encoding 32 bytes), has no external dependencies and supports a configurable alphabet. # Rust Version Policy This crate only supports the current stable version of Rust, patch releases may use new features at any time. # License Licensed under either of * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) at your option. ## Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions. [version-badge]: https://img.shields.io/crates/v/bs58.svg?style=flat-square [version]: https://crates.io/crates/bs58 [license-badge]: https://img.shields.io/crates/l/bs58.svg?style=flat-square [license]: #license [rust-version-badge]: https://img.shields.io/badge/rust-latest%20stable-blueviolet.svg?style=flat-square [rust-version]: #rust-version-policy [Base58]: https://en.wikipedia.org/wiki/Base58 [`base58`]: https://github.com/debris/base58 [`rust-base58`]: https://github.com/nham/rust-base58 [clippy]: https://github.com/rust-lang-nursery/rust-clippy bs58-0.5.1/benches/decode.rs000064400000000000000000000124221046102023000136110ustar 00000000000000use criterion::{criterion_group, criterion_main, Criterion}; macro_rules! group_decode { ($criterion:ident, $name:expr, $encoded:expr => $decoded:expr, $decoded_length:expr) => {{ let mut group = $criterion.benchmark_group($name); group.bench_function("decode_base58", |b| { use base58::FromBase58; let temp = $encoded; b.iter(|| temp.from_base58().unwrap()); }); group.bench_function("decode_rust_base58", |b| { use rust_base58::FromBase58; let temp = $encoded; b.iter(|| temp.from_base58().unwrap()); }); group.bench_function("decode_bs58", |b| { b.iter(|| bs58::decode($encoded).into_vec().unwrap()) }); group.bench_function("decode_bs58_noalloc_slice", |b| { let mut output = [0; $decoded_length]; b.iter(|| bs58::decode($encoded).onto(&mut output[..]).unwrap()); }); group.bench_function("decode_bs58_noalloc_array", |b| { let mut output = [0; $decoded_length]; b.iter(|| bs58::decode($encoded).onto(&mut output).unwrap()); }); group.finish(); }}; } macro_rules! group_decode_long { ($criterion:ident, $name:expr, $encoded:expr => $decoded:expr, $decoded_length:expr) => {{ let mut group = $criterion.benchmark_group($name); // base58 can't handle more than 32 bytes group.bench_function("decode_rust_base58", |b| { use rust_base58::FromBase58; let temp = $encoded; b.iter(|| temp.from_base58().unwrap()); }); group.bench_function("decode_bs58", |b| { b.iter(|| bs58::decode($encoded).into_vec().unwrap()) }); group.bench_function("decode_bs58_noalloc_slice", |b| { let mut output = [0; $decoded_length]; b.iter(|| bs58::decode($encoded).onto(&mut output[..]).unwrap()); }); // bs58_noalloc_array is not possible because of limited array lengths in trait impls group.finish(); }}; } fn bench_decode(c: &mut Criterion) { group_decode!(c, "empty", "" => vec![], 0); group_decode!(c, "1_byte", "2g" => vec![0x61], 1); group_decode!(c, "5_bytes", "ABnLTmg" => vec![0x51, 0x6b, 0x6f, 0xcd, 0x0f], 5); group_decode!(c, "10_bytes", "EJDM8drfXA6uyA" => vec![0xec, 0xac, 0x89, 0xca, 0xd9, 0x39, 0x23, 0xc0, 0x23, 0x21], 10); group_decode!(c, "10_bytes_zero", "1111111111" => vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 10); group_decode!(c, "10_bytes_max", "FPBt6CHo3fovdL" => vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], 10); group_decode!(c, "32_bytes", "2gPihUTjt3FJqf1VpidgrY5cZ6PuyMccGVwQHRfjMPZG" => vec![ 0x18, 0xf3, 0x06, 0xdf, 0xe6, 0x99, 0xd2, 0x08, 0x5c, 0x89, 0x7b, 0x43, 0xa4, 0xc5, 0x4f, 0xc4, 0x7d, 0x2b, 0xb7, 0x55, 0x67, 0x5b, 0xe8, 0xa7, 0x49, 0x83, 0x68, 0x83, 0x00, 0x65, 0xd6, 0xe7 ], 32 ); group_decode_long!(c, "256_bytes", "\ 5gkXES6JSFLhJ3pkwQsV3MT3TBjsW5vQnAW8CwPLS1oDsJgjq8dchz994yCJHD1C16k3Pk\ Gp8o61dMfXy1vVwXcD147ix2BXD87xcXGnzB4mxaUEvgqDonZz8xQE9XL44XvLQshJw7kp\ 54MkSPbVkxvzKdxiYHkgAjLfmx5wdyDNjPu2DUYmxRrTtjDw5QVMaqAp3fLrQ6GnXuhZmB\ Jdj8rTprjADLM5tox6tHgyj2bm37ECxKevEapzy4nDGmZrzMubp9s58TsV1wk3LUQsRF49\ L9NzDatxVUetHTjQennpEHEuMTU9D8GM6De44J7Sk5fnJGh614ZtmrYyFcCE3X5mdTwaxA\ " => vec![ 0x65, 0x5f, 0x65, 0x20, 0xc4, 0xd8, 0xa5, 0x86, 0xce, 0x80, 0x1a, 0x4e, 0x60, 0x73, 0x91, 0x40, 0x10, 0x8f, 0xd5, 0xdc, 0x5b, 0x3e, 0x8e, 0x08, 0x47, 0x98, 0x82, 0xc6, 0x29, 0xee, 0x49, 0x8d, 0xb6, 0x41, 0xa1, 0xc6, 0xa9, 0xd3, 0x63, 0xcb, 0xe2, 0x4e, 0x3f, 0x90, 0x78, 0x04, 0xf4, 0x49, 0x5c, 0x4b, 0x39, 0x73, 0x9b, 0x5c, 0x4b, 0x9f, 0x23, 0xde, 0xc4, 0x8a, 0x3d, 0xb8, 0x1a, 0x6c, 0xfd, 0x5a, 0xc1, 0xe3, 0x28, 0x9a, 0xf6, 0x72, 0xfb, 0x2d, 0x33, 0x9d, 0xb6, 0xc4, 0x38, 0xfa, 0x8d, 0x16, 0xc9, 0x0d, 0x00, 0xab, 0xc7, 0x9a, 0x27, 0xd2, 0x8e, 0x45, 0xdc, 0x49, 0x8d, 0xf9, 0x80, 0x86, 0x11, 0x91, 0x86, 0x98, 0xcc, 0xc2, 0x6e, 0x85, 0xd2, 0x38, 0xfc, 0xff, 0x66, 0xf0, 0x9d, 0x7d, 0xa5, 0x4c, 0x6f, 0x0d, 0xe5, 0xd0, 0x60, 0x6c, 0xe7, 0x31, 0x38, 0xa0, 0x86, 0xde, 0x24, 0x28, 0x05, 0x6c, 0x03, 0xb6, 0x21, 0xde, 0xaa, 0x8b, 0x81, 0xcc, 0xb6, 0x0e, 0x19, 0xdc, 0xe5, 0x50, 0xb5, 0xb7, 0x6e, 0x8f, 0x22, 0xa7, 0x6f, 0x86, 0x75, 0x06, 0xb8, 0xca, 0xa0, 0xc6, 0x29, 0x8f, 0xf6, 0xc4, 0x8b, 0x22, 0x24, 0xc0, 0xf7, 0x09, 0x10, 0x6f, 0x10, 0x8a, 0xc2, 0x57, 0x90, 0x50, 0x62, 0x9e, 0x95, 0x4c, 0x47, 0x79, 0xdb, 0xc9, 0x82, 0x9f, 0x45, 0xac, 0x8b, 0x31, 0xa4, 0xfb, 0x6b, 0xdd, 0x86, 0x7f, 0x9b, 0x6f, 0x48, 0xe4, 0x34, 0x84, 0x0c, 0x45, 0x6c, 0xfa, 0xa3, 0x14, 0x52, 0x22, 0x46, 0xf9, 0x20, 0x5f, 0x6a, 0xb4, 0x25, 0x09, 0xb1, 0xae, 0x04, 0x3f, 0x27, 0xa0, 0xda, 0xb6, 0x91, 0x45, 0x09, 0x37, 0xf1, 0x17, 0x2d, 0xb8, 0xa8, 0xaa, 0x5a, 0x61, 0xf1, 0xbe, 0x08, 0x40, 0x47, 0xa8, 0x16, 0xf9, 0xb0, 0x0f, 0x6d, 0x34, 0x62, 0x29, 0x2b, 0xb3 ], 256 ); } criterion_group!(benches, bench_decode); criterion_main!(benches); bs58-0.5.1/benches/encode.rs000064400000000000000000000101441046102023000136220ustar 00000000000000use criterion::{criterion_group, criterion_main, Criterion}; macro_rules! group_encode { ($criterion:ident, $name:expr, $decoded:expr => $encoded:expr) => {{ let mut group = $criterion.benchmark_group($name); group.bench_function("encode_base58", |b| { use base58::ToBase58; let temp = $decoded; b.iter(|| temp.to_base58()) }); group.bench_function("encode_rust_base58", |b| { use rust_base58::ToBase58; let temp = $decoded; b.iter(|| temp.to_base58()) }); group.bench_function("encode_bs58", |b| { b.iter(|| bs58::encode($decoded).into_string()) }); group.bench_function("encode_bs58_noalloc", |b| { let mut output = String::with_capacity($encoded.len()); b.iter(|| bs58::encode($decoded).onto(&mut output)); }); group.finish(); }}; } fn bench_encode(c: &mut Criterion) { group_encode!(c, "empty", vec![] => ""); group_encode!(c, "1_byte", vec![0x61] => "2g"); group_encode!(c, "5_bytes", vec![0x51, 0x6b, 0x6f, 0xcd, 0x0f] => "ABnLTmg"); group_encode!(c, "10_bytes", vec![0xec, 0xac, 0x89, 0xca, 0xd9, 0x39, 0x23, 0xc0, 0x23, 0x21] => "EJDM8drfXA6uyA"); group_encode!(c, "10_bytes_zero", vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] => "1111111111"); group_encode!(c, "10_bytes_max", vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] => "FPBt6CHo3fovdL"); group_encode!(c, "32_bytes", vec![ 0x18, 0xf3, 0x06, 0xdf, 0xe6, 0x99, 0xd2, 0x08, 0x5c, 0x89, 0x7b, 0x43, 0xa4, 0xc5, 0x4f, 0xc4, 0x7d, 0x2b, 0xb7, 0x55, 0x67, 0x5b, 0xe8, 0xa7, 0x49, 0x83, 0x68, 0x83, 0x00, 0x65, 0xd6, 0xe7 ] => "2gPihUTjt3FJqf1VpidgrY5cZ6PuyMccGVwQHRfjMPZG" ); group_encode!(c, "256_bytes", vec![ 0x65, 0x5f, 0x65, 0x20, 0xc4, 0xd8, 0xa5, 0x86, 0xce, 0x80, 0x1a, 0x4e, 0x60, 0x73, 0x91, 0x40, 0x10, 0x8f, 0xd5, 0xdc, 0x5b, 0x3e, 0x8e, 0x08, 0x47, 0x98, 0x82, 0xc6, 0x29, 0xee, 0x49, 0x8d, 0xb6, 0x41, 0xa1, 0xc6, 0xa9, 0xd3, 0x63, 0xcb, 0xe2, 0x4e, 0x3f, 0x90, 0x78, 0x04, 0xf4, 0x49, 0x5c, 0x4b, 0x39, 0x73, 0x9b, 0x5c, 0x4b, 0x9f, 0x23, 0xde, 0xc4, 0x8a, 0x3d, 0xb8, 0x1a, 0x6c, 0xfd, 0x5a, 0xc1, 0xe3, 0x28, 0x9a, 0xf6, 0x72, 0xfb, 0x2d, 0x33, 0x9d, 0xb6, 0xc4, 0x38, 0xfa, 0x8d, 0x16, 0xc9, 0x0d, 0x00, 0xab, 0xc7, 0x9a, 0x27, 0xd2, 0x8e, 0x45, 0xdc, 0x49, 0x8d, 0xf9, 0x80, 0x86, 0x11, 0x91, 0x86, 0x98, 0xcc, 0xc2, 0x6e, 0x85, 0xd2, 0x38, 0xfc, 0xff, 0x66, 0xf0, 0x9d, 0x7d, 0xa5, 0x4c, 0x6f, 0x0d, 0xe5, 0xd0, 0x60, 0x6c, 0xe7, 0x31, 0x38, 0xa0, 0x86, 0xde, 0x24, 0x28, 0x05, 0x6c, 0x03, 0xb6, 0x21, 0xde, 0xaa, 0x8b, 0x81, 0xcc, 0xb6, 0x0e, 0x19, 0xdc, 0xe5, 0x50, 0xb5, 0xb7, 0x6e, 0x8f, 0x22, 0xa7, 0x6f, 0x86, 0x75, 0x06, 0xb8, 0xca, 0xa0, 0xc6, 0x29, 0x8f, 0xf6, 0xc4, 0x8b, 0x22, 0x24, 0xc0, 0xf7, 0x09, 0x10, 0x6f, 0x10, 0x8a, 0xc2, 0x57, 0x90, 0x50, 0x62, 0x9e, 0x95, 0x4c, 0x47, 0x79, 0xdb, 0xc9, 0x82, 0x9f, 0x45, 0xac, 0x8b, 0x31, 0xa4, 0xfb, 0x6b, 0xdd, 0x86, 0x7f, 0x9b, 0x6f, 0x48, 0xe4, 0x34, 0x84, 0x0c, 0x45, 0x6c, 0xfa, 0xa3, 0x14, 0x52, 0x22, 0x46, 0xf9, 0x20, 0x5f, 0x6a, 0xb4, 0x25, 0x09, 0xb1, 0xae, 0x04, 0x3f, 0x27, 0xa0, 0xda, 0xb6, 0x91, 0x45, 0x09, 0x37, 0xf1, 0x17, 0x2d, 0xb8, 0xa8, 0xaa, 0x5a, 0x61, 0xf1, 0xbe, 0x08, 0x40, 0x47, 0xa8, 0x16, 0xf9, 0xb0, 0x0f, 0x6d, 0x34, 0x62, 0x29, 0x2b, 0xb3 ] => "\ 5gkXES6JSFLhJ3pkwQsV3MT3TBjsW5vQnAW8CwPLS1oDsJgjq8dchz994yCJHD1C16k3Pk\ Gp8o61dMfXy1vVwXcD147ix2BXD87xcXGnzB4mxaUEvgqDonZz8xQE9XL44XvLQshJw7kp\ 54MkSPbVkxvzKdxiYHkgAjLfmx5wdyDNjPu2DUYmxRrTtjDw5QVMaqAp3fLrQ6GnXuhZmB\ Jdj8rTprjADLM5tox6tHgyj2bm37ECxKevEapzy4nDGmZrzMubp9s58TsV1wk3LUQsRF49\ L9NzDatxVUetHTjQennpEHEuMTU9D8GM6De44J7Sk5fnJGh614ZtmrYyFcCE3X5mdTwaxA" ); } criterion_group!(benches, bench_encode); criterion_main!(benches); bs58-0.5.1/deny.toml000064400000000000000000000001061046102023000122410ustar 00000000000000[licenses] allow = [ "MIT", "Apache-2.0", "Unicode-DFS-2016", ] bs58-0.5.1/examples/decode.rs000064400000000000000000000004211046102023000140140ustar 00000000000000use std::io::{self, Read, Write}; fn main() -> Result<(), Box> { let mut input = String::new(); io::stdin().read_to_string(&mut input)?; let data = &bs58::decode(input.trim()).into_vec()?; io::stdout().write_all(data)?; Ok(()) } bs58-0.5.1/examples/encode.rs000064400000000000000000000003461046102023000140340ustar 00000000000000use std::io::{self, Read}; fn main() -> Result<(), Box> { let mut input = Vec::::new(); io::stdin().read_to_end(&mut input)?; println!("{}", bs58::encode(input).into_string()); Ok(()) } bs58-0.5.1/src/alphabet.rs000064400000000000000000000156511046102023000133350ustar 00000000000000//! Support for configurable alphabets use core::fmt; /// Prepared Alphabet for /// [`EncodeBuilder::with_alphabet`](crate::encode::EncodeBuilder::with_alphabet) and /// [`DecodeBuilder::with_alphabet`](crate::decode::DecodeBuilder::with_alphabet). #[derive(Clone, Copy)] pub struct Alphabet { pub(crate) encode: [u8; 58], pub(crate) decode: [u8; 128], } /// Errors that could occur when preparing a Base58 alphabet. #[non_exhaustive] #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Error { /// The alphabet contained a duplicate character at at least 2 indexes. DuplicateCharacter { /// The duplicate character encountered. character: char, /// The first index the character was seen at. first: usize, /// The second index the character was seen at. second: usize, }, /// The alphabet contained a multi-byte (or non-utf8) character. NonAsciiCharacter { /// The index at which the non-ASCII character was seen. index: usize, }, } impl Alphabet { /// Bitcoin's alphabet as defined in their Base58Check encoding. /// /// See pub const BITCOIN: &'static Self = &Self::new_unwrap(b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"); /// Monero's alphabet as defined in this forum post. /// /// See pub const MONERO: &'static Self = &Self::new_unwrap(b"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"); /// Ripple's alphabet as defined in their wiki. /// /// See pub const RIPPLE: &'static Self = &Self::new_unwrap(b"rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"); /// Flickr's alphabet for creating short urls from photo ids. /// /// See pub const FLICKR: &'static Self = &Self::new_unwrap(b"123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ"); /// The default alphabet used if none is given. Currently is the /// [`BITCOIN`](Self::BITCOIN) alphabet. pub const DEFAULT: &'static Self = Self::BITCOIN; /// Create prepared alphabet, checks that the alphabet is pure ASCII and that there are no /// duplicate characters, which would result in inconsistent encoding/decoding /// /// ```rust /// let alpha = bs58::Alphabet::new( /// b" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXY" /// )?; /// /// let decoded = bs58::decode("he11owor1d") /// .with_alphabet(bs58::Alphabet::RIPPLE) /// .into_vec()?; /// let encoded = bs58::encode(decoded) /// .with_alphabet(&alpha) /// .into_string(); /// /// assert_eq!("#ERRN)N RD", encoded); /// # Ok::<(), Box>(()) /// ``` /// ## Errors /// /// ### Duplicate Character /// /// ```rust /// let alpha = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; /// assert_eq!( /// bs58::alphabet::Error::DuplicateCharacter { character: 'a', first: 0, second: 1 }, /// bs58::Alphabet::new(alpha).unwrap_err()); /// ``` /// /// ### Non-ASCII Character /// /// ```rust /// let mut alpha = *b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; /// alpha[1] = 255; /// assert_eq!( /// bs58::alphabet::Error::NonAsciiCharacter { index: 1 }, /// bs58::Alphabet::new(&alpha).unwrap_err()); /// ``` pub const fn new(base: &[u8; 58]) -> Result { let mut encode = [0x00; 58]; let mut decode = [0xFF; 128]; let mut i = 0; while i < encode.len() { if base[i] >= 128 { return Err(Error::NonAsciiCharacter { index: i }); } if decode[base[i] as usize] != 0xFF { return Err(Error::DuplicateCharacter { character: base[i] as char, first: decode[base[i] as usize] as usize, second: i, }); } encode[i] = base[i]; decode[base[i] as usize] = i as u8; i += 1; } Ok(Self { encode, decode }) } /// Same as [`Self::new`], but gives a panic instead of an [`Err`] on bad input. /// /// Intended to support usage in `const` context until [`Result::unwrap`] is able to be called. /// /// ```rust /// const ALPHA: &'static bs58::Alphabet = &bs58::Alphabet::new_unwrap( /// b" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXY" /// ); /// /// let decoded = bs58::decode("he11owor1d") /// .with_alphabet(bs58::Alphabet::RIPPLE) /// .into_vec()?; /// let encoded = bs58::encode(decoded) /// .with_alphabet(ALPHA) /// .into_string(); /// /// assert_eq!("#ERRN)N RD", encoded); /// # Ok::<(), Box>(()) /// ``` /// /// If your alphabet is inconsistent then this will fail to compile in a `const` context: /// /// ```compile_fail /// const _: &'static bs58::Alphabet = &bs58::Alphabet::new_unwrap( /// b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" /// ); /// ``` pub const fn new_unwrap(base: &[u8; 58]) -> Self { let result = Self::new(base); #[allow(unconditional_panic)] // https://github.com/rust-lang/rust/issues/78803 [][match result { Ok(alphabet) => return alphabet, Err(_) => 0, }] } } impl fmt::Debug for Alphabet { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if let Ok(s) = core::str::from_utf8(&self.encode) { f.debug_tuple("Alphabet").field(&s).finish() } else { unreachable!() } } } #[cfg(feature = "std")] impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::DuplicateCharacter { character, first, second, } => write!( f, "alphabet contained a duplicate character `{}` at indexes {} and {}", character, first, second, ), Error::NonAsciiCharacter { index } => { write!(f, "alphabet contained a non-ascii character at {}", index) } } } } // Force evaluation of the associated constants to make sure they don't error const _: () = { let _ = Alphabet::BITCOIN; let _ = Alphabet::MONERO; let _ = Alphabet::RIPPLE; let _ = Alphabet::FLICKR; let _ = Alphabet::DEFAULT; }; #[test] #[should_panic] fn test_new_unwrap_does_panic() { Alphabet::new_unwrap(b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); } bs58-0.5.1/src/decode.rs000064400000000000000000000505711046102023000130000ustar 00000000000000//! Functions for decoding Base58 encoded strings. use core::fmt; #[cfg(feature = "alloc")] use alloc::vec::Vec; use crate::Check; #[cfg(any(feature = "check", feature = "cb58"))] use crate::CHECKSUM_LEN; use crate::Alphabet; /// A builder for setting up the alphabet and output of a base58 decode. /// /// See the documentation for [`bs58::decode`](crate::decode()) for a more /// high level view of how to use this. #[allow(missing_debug_implementations)] pub struct DecodeBuilder<'a, I: AsRef<[u8]>> { input: I, alpha: &'a Alphabet, check: Check, } /// A specialized [`Result`](core::result::Result) type for [`bs58::decode`](module@crate::decode) pub type Result = core::result::Result; /// Errors that could occur when decoding a Base58 encoded string. #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum Error { /// The output buffer was too small to contain the entire input. BufferTooSmall, /// The input contained a character that was not part of the current Base58 /// alphabet. InvalidCharacter { /// The unexpected character. character: char, /// The (byte) index in the input string the character was at. index: usize, }, /// The input contained a multi-byte (or non-utf8) character which is /// unsupported by this Base58 decoder. NonAsciiCharacter { /// The (byte) index in the input string the start of the character was /// at. index: usize, }, #[cfg(any(feature = "check", feature = "cb58"))] /// The checksum did not match the payload bytes InvalidChecksum { ///The given checksum checksum: [u8; CHECKSUM_LEN], ///The checksum calculated for the payload expected_checksum: [u8; CHECKSUM_LEN], }, #[cfg(any(feature = "check", feature = "cb58"))] /// The version did not match the payload bytes InvalidVersion { ///The given version ver: u8, ///The expected version expected_ver: u8, }, #[cfg(any(feature = "check", feature = "cb58"))] ///Not enough bytes to have both a checksum and a payload (less than to CHECKSUM_LEN) NoChecksum, } /// Represents a buffer that can be decoded into. See [`DecodeBuilder::onto`] and the provided /// implementations for more details. pub trait DecodeTarget { /// Decodes into this buffer, provides the maximum length for implementations that wish to /// preallocate space, along with a function that will write bytes into the buffer and return /// the length written to it. fn decode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result; } impl DecodeTarget for &mut T { fn decode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { T::decode_with(self, max_len, f) } } #[cfg(feature = "alloc")] impl DecodeTarget for Vec { fn decode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let original = self.len(); self.resize(original + max_len, 0); let len = f(&mut self[original..])?; self.truncate(original + len); Ok(len) } } #[cfg(feature = "smallvec")] impl> DecodeTarget for smallvec::SmallVec { /// Decodes data into a [`smallvec::SmallVec`]. fn decode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let original = self.len(); self.resize(original + max_len, 0); let len = f(&mut self[original..])?; self.truncate(original + len); Ok(len) } } #[cfg(feature = "tinyvec")] impl> DecodeTarget for tinyvec::ArrayVec { fn decode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let _ = max_len; let original = self.len(); let len = f(self.grab_spare_slice_mut())?; self.set_len(original + len); Ok(len) } } #[cfg(feature = "tinyvec")] impl DecodeTarget for tinyvec::SliceVec<'_, u8> { fn decode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let _ = max_len; let original = self.len(); let len = f(self.grab_spare_slice_mut())?; self.set_len(original + len); Ok(len) } } #[cfg(all(feature = "tinyvec", feature = "alloc"))] impl> DecodeTarget for tinyvec::TinyVec { fn decode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let original = self.len(); self.resize(original + max_len, 0); let len = f(&mut self[original..])?; self.truncate(original + len); Ok(len) } } impl DecodeTarget for [u8] { fn decode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let _ = max_len; f(&mut *self) } } impl DecodeTarget for [u8; N] { fn decode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let _ = max_len; f(&mut *self) } } impl<'a, I: AsRef<[u8]>> DecodeBuilder<'a, I> { /// Setup decoder for the given string using the given alphabet. /// Preferably use [`bs58::decode`](crate::decode()) instead of this directly. pub const fn new(input: I, alpha: &'a Alphabet) -> DecodeBuilder<'a, I> { DecodeBuilder { input, alpha, check: Check::Disabled, } } /// Setup decoder for the given string using default prepared alphabet. pub(crate) const fn from_input(input: I) -> DecodeBuilder<'static, I> { DecodeBuilder { input, alpha: Alphabet::DEFAULT, check: Check::Disabled, } } /// Change the alphabet that will be used for decoding. /// /// # Examples /// /// ```rust /// assert_eq!( /// vec![0x60, 0x65, 0xe7, 0x9b, 0xba, 0x2f, 0x78], /// bs58::decode("he11owor1d") /// .with_alphabet(bs58::Alphabet::RIPPLE) /// .into_vec()?); /// # Ok::<(), bs58::decode::Error>(()) /// ``` pub const fn with_alphabet(mut self, alpha: &'a Alphabet) -> DecodeBuilder<'a, I> { self.alpha = alpha; self } /// Expect and check checksum using the [Base58Check][] algorithm when /// decoding. /// /// Optional parameter for version byte. If provided, the version byte will /// be used in verification. /// /// [Base58Check]: https://en.bitcoin.it/wiki/Base58Check_encoding /// /// # Examples /// /// ```rust /// assert_eq!( /// vec![0x2d, 0x31], /// bs58::decode("PWEu9GGN") /// .with_check(None) /// .into_vec()?); /// # Ok::<(), bs58::decode::Error>(()) /// ``` #[cfg(feature = "check")] pub fn with_check(self, expected_ver: Option) -> DecodeBuilder<'a, I> { let check = Check::Enabled(expected_ver); DecodeBuilder { check, ..self } } /// Expect and check checksum using the [CB58][] algorithm when /// decoding. /// /// Optional parameter for version byte. If provided, the version byte will /// be used in verification. /// /// [CB58]: https://support.avax.network/en/articles/4587395-what-is-cb58 /// /// # Examples /// /// ```rust /// assert_eq!( /// vec![0x2d, 0x31], /// bs58::decode("PWHVMzdR") /// .as_cb58(None) /// .into_vec()?); /// # Ok::<(), bs58::decode::Error>(()) /// ``` #[cfg(feature = "cb58")] pub fn as_cb58(self, expected_ver: Option) -> DecodeBuilder<'a, I> { let check = Check::CB58(expected_ver); DecodeBuilder { check, ..self } } /// Decode into a new vector of bytes. /// /// See the documentation for [`bs58::decode`](crate::decode()) for an /// explanation of the errors that may occur. /// /// # Examples /// /// ```rust /// assert_eq!( /// vec![0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58], /// bs58::decode("he11owor1d").into_vec()?); /// # Ok::<(), bs58::decode::Error>(()) /// ``` /// #[cfg(feature = "alloc")] pub fn into_vec(self) -> Result> { let mut output = Vec::new(); self.onto(&mut output)?; Ok(output) } /// Decode into the given buffer. /// /// Returns the length written into the buffer. /// /// If the buffer is resizeable it will be extended and the new data will be written to the end /// of it. /// /// If the buffer is not resizeable bytes will be written from the beginning and bytes after /// the final encoded byte will not be touched. /// /// See the documentation for [`bs58::decode`](crate::decode()) for an /// explanation of the errors that may occur. /// /// # Examples /// /// ## `Vec` /// /// ```rust /// let mut output = b"hello ".to_vec(); /// assert_eq!(5, bs58::decode("EUYUqQf").onto(&mut output)?); /// assert_eq!(b"hello world", output.as_slice()); /// # Ok::<(), bs58::decode::Error>(()) /// ``` /// /// ## `&mut [u8]` /// /// ```rust /// let mut output = b"hello ".to_owned(); /// assert_eq!(5, bs58::decode("EUYUqQf").onto(&mut output)?); /// assert_eq!(b"world ", output.as_ref()); /// # Ok::<(), bs58::decode::Error>(()) /// ``` pub fn onto(self, mut output: impl DecodeTarget) -> Result { let max_decoded_len = self.input.as_ref().len(); match self.check { Check::Disabled => output.decode_with(max_decoded_len, |output| { decode_into(self.input.as_ref(), output, self.alpha) }), #[cfg(feature = "check")] Check::Enabled(expected_ver) => output.decode_with(max_decoded_len, |output| { decode_check_into(self.input.as_ref(), output, self.alpha, expected_ver) }), #[cfg(feature = "cb58")] Check::CB58(expected_ver) => output.decode_with(max_decoded_len, |output| { decode_cb58_into(self.input.as_ref(), output, self.alpha, expected_ver) }), } } } /// For `const` compatibility we are restricted to using a concrete input and output type, as /// `const` trait implementations and `&mut` are unstable. These methods will eventually be /// deprecated once the primary interfaces can be converted into `const fn` directly. impl<'a, 'b> DecodeBuilder<'a, &'b [u8]> { /// Decode into a new array. /// /// Returns the decoded array as bytes. /// /// See the documentation for [`bs58::decode`](crate::decode()) /// for an explanation of the errors that may occur. /// /// # Examples /// /// ```rust /// const _: () = { /// let Ok(output) = bs58::decode(b"EUYUqQf".as_slice()).into_array_const::<5>() else { /// panic!() /// }; /// assert!(matches!(&output, b"world")); /// }; /// ``` pub const fn into_array_const(self) -> Result<[u8; N]> { assert!( matches!(self.check, Check::Disabled), "checksums in const aren't supported (why are you using this API at runtime)", ); decode_into_const(self.input, self.alpha) } /// [`Self::into_array_const`] but the result will be unwrapped, turning any error into a panic /// message via [`Error::unwrap_const`], as a simple `into_array_const().unwrap()` isn't /// possible yet. /// /// # Examples /// /// ```rust /// const _: () = { /// let output: [u8; 5] = bs58::decode(b"EUYUqQf".as_slice()).into_array_const_unwrap(); /// assert!(matches!(&output, b"world")); /// }; /// ``` /// /// ```rust /// const _: () = { /// assert!(matches!( /// bs58::decode(b"he11owor1d".as_slice()) /// .with_alphabet(bs58::Alphabet::RIPPLE) /// .into_array_const_unwrap(), /// [0x60, 0x65, 0xe7, 0x9b, 0xba, 0x2f, 0x78], /// )); /// }; /// ``` pub const fn into_array_const_unwrap(self) -> [u8; N] { match self.into_array_const() { Ok(result) => result, Err(err) => err.unwrap_const(), } } } fn decode_into(input: &[u8], output: &mut [u8], alpha: &Alphabet) -> Result { let mut index = 0; let zero = alpha.encode[0]; for (i, c) in input.iter().enumerate() { if *c > 127 { return Err(Error::NonAsciiCharacter { index: i }); } let mut val = alpha.decode[*c as usize] as usize; if val == 0xFF { return Err(Error::InvalidCharacter { character: *c as char, index: i, }); } for byte in &mut output[..index] { val += (*byte as usize) * 58; *byte = (val & 0xFF) as u8; val >>= 8; } while val > 0 { let byte = output.get_mut(index).ok_or(Error::BufferTooSmall)?; *byte = (val & 0xFF) as u8; index += 1; val >>= 8 } } for _ in input.iter().take_while(|c| **c == zero) { let byte = output.get_mut(index).ok_or(Error::BufferTooSmall)?; *byte = 0; index += 1; } output[..index].reverse(); Ok(index) } #[cfg(feature = "check")] fn decode_check_into( input: &[u8], output: &mut [u8], alpha: &Alphabet, expected_ver: Option, ) -> Result { use sha2::{Digest, Sha256}; let decoded_len = decode_into(input, output, alpha)?; if decoded_len < CHECKSUM_LEN { return Err(Error::NoChecksum); } let checksum_index = decoded_len - CHECKSUM_LEN; let expected_checksum = &output[checksum_index..decoded_len]; let first_hash = Sha256::digest(&output[0..checksum_index]); let second_hash = Sha256::digest(first_hash); let (checksum, _) = second_hash.split_at(CHECKSUM_LEN); if checksum == expected_checksum { if let Some(ver) = expected_ver { if output[0] == ver { Ok(checksum_index) } else { Err(Error::InvalidVersion { ver: output[0], expected_ver: ver, }) } } else { Ok(checksum_index) } } else { let mut a: [u8; CHECKSUM_LEN] = Default::default(); a.copy_from_slice(checksum); let mut b: [u8; CHECKSUM_LEN] = Default::default(); b.copy_from_slice(expected_checksum); Err(Error::InvalidChecksum { checksum: a, expected_checksum: b, }) } } #[cfg(feature = "cb58")] fn decode_cb58_into( input: &[u8], output: &mut [u8], alpha: &Alphabet, expected_ver: Option, ) -> Result { use sha2::{Digest, Sha256}; let decoded_len = decode_into(input, output, alpha)?; if decoded_len < CHECKSUM_LEN { return Err(Error::NoChecksum); } let checksum_index = decoded_len - CHECKSUM_LEN; let expected_checksum = &output[checksum_index..decoded_len]; let hash = Sha256::digest(&output[0..checksum_index]); let (_, checksum) = hash.split_at(hash.len() - CHECKSUM_LEN); if checksum == expected_checksum { if let Some(ver) = expected_ver { if output[0] == ver { Ok(checksum_index) } else { Err(Error::InvalidVersion { ver: output[0], expected_ver: ver, }) } } else { Ok(checksum_index) } } else { let mut a: [u8; CHECKSUM_LEN] = Default::default(); a.copy_from_slice(checksum); let mut b: [u8; CHECKSUM_LEN] = Default::default(); b.copy_from_slice(expected_checksum); Err(Error::InvalidChecksum { checksum: a, expected_checksum: b, }) } } const fn decode_into_const(input: &[u8], alpha: &Alphabet) -> Result<[u8; N]> { let mut output = [0u8; N]; let mut index = 0; let zero = alpha.encode[0]; let mut i = 0; while i < input.len() { let c = input[i]; if c > 127 { return Err(Error::NonAsciiCharacter { index: i }); } let mut val = alpha.decode[c as usize] as usize; if val == 0xFF { return Err(Error::InvalidCharacter { character: c as char, index: i, }); } let mut j = 0; while j < index { let byte = output[j]; val += (byte as usize) * 58; output[j] = (val & 0xFF) as u8; val >>= 8; j += 1; } while val > 0 { if index >= output.len() { return Err(Error::BufferTooSmall); } output[index] = (val & 0xFF) as u8; index += 1; val >>= 8 } i += 1; } let mut i = 0; while i < input.len() && input[i] == zero { if index >= output.len() { return Err(Error::BufferTooSmall); } output[index] = 0; index += 1; i += 1; } // reverse let mut i = 0; let n = index / 2; while i < n { let x = output[i]; output[i] = output[index - 1 - i]; output[index - 1 - i] = x; i += 1; } Ok(output) } #[cfg(feature = "std")] impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::BufferTooSmall => write!( f, "buffer provided to decode base58 encoded string into was too small" ), Error::InvalidCharacter { character, index } => write!( f, "provided string contained invalid character {:?} at byte {}", character, index ), Error::NonAsciiCharacter { index } => write!( f, "provided string contained non-ascii character starting at byte {}", index ), #[cfg(any(feature = "check", feature = "cb58"))] Error::InvalidChecksum { checksum, expected_checksum, } => write!( f, "invalid checksum, calculated checksum: '{:?}', expected checksum: {:?}", checksum, expected_checksum ), #[cfg(any(feature = "check", feature = "cb58"))] Error::InvalidVersion { ver, expected_ver } => write!( f, "invalid version, payload version: '{:?}', expected version: {:?}", ver, expected_ver ), #[cfg(any(feature = "check", feature = "cb58"))] Error::NoChecksum => write!(f, "provided string is too small to contain a checksum"), } } } impl Error { /// Panic with an error message based on this error. This cannot include any of the dynamic /// content because formatting in `const` is not yet possible. pub const fn unwrap_const(self) -> ! { match self { Error::BufferTooSmall => { panic!("buffer provided to decode base58 encoded string into was too small") } Error::InvalidCharacter { .. } => panic!("provided string contained invalid character"), Error::NonAsciiCharacter { .. } => { panic!("provided string contained non-ascii character") } #[cfg(any(feature = "check", feature = "cb58"))] Error::InvalidChecksum { .. } => panic!("invalid checksum"), #[cfg(any(feature = "check", feature = "cb58"))] Error::InvalidVersion { .. } => panic!("invalid version"), #[cfg(any(feature = "check", feature = "cb58"))] Error::NoChecksum => panic!("provided string is too small to contain a checksum"), } } } bs58-0.5.1/src/encode.rs000064400000000000000000000402521046102023000130050ustar 00000000000000//! Functions for encoding into Base58 encoded strings. use core::fmt; #[cfg(feature = "alloc")] use alloc::{string::String, vec::Vec}; use crate::Check; #[cfg(any(feature = "check", feature = "cb58"))] use crate::CHECKSUM_LEN; use crate::Alphabet; /// A builder for setting up the alphabet and output of a base58 encode. #[allow(missing_debug_implementations)] pub struct EncodeBuilder<'a, I: AsRef<[u8]>> { input: I, alpha: &'a Alphabet, check: Check, } /// A specialized [`Result`](core::result::Result) type for [`bs58::encode`](module@crate::encode) pub type Result = core::result::Result; /// Errors that could occur when encoding a Base58 encoded string. #[derive(Copy, Clone, Debug, Eq, PartialEq)] #[non_exhaustive] pub enum Error { /// The output buffer was too small to contain the entire input. BufferTooSmall, } /// Represents a buffer that can be encoded into. See [`EncodeBuilder::onto`] and the provided /// implementations for more details. pub trait EncodeTarget { /// Encodes into this buffer, provides the maximum length for implementations that wish to /// preallocate space, along with a function that will encode ASCII bytes into the buffer and /// return the length written to it. fn encode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result; } impl EncodeTarget for &mut T { fn encode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { T::encode_with(self, max_len, f) } } #[cfg(feature = "alloc")] impl EncodeTarget for Vec { fn encode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let original = self.len(); self.resize(original + max_len, 0); let len = f(&mut self[original..])?; self.truncate(original + len); Ok(len) } } #[cfg(feature = "smallvec")] impl> EncodeTarget for smallvec::SmallVec { /// Encodes data into a [`smallvec::SmallVec`]. /// /// Note that even if the encoded value fits into vector’s inline buffer, /// this may result in allocation if `max_len` is greater than vector’s /// inline size. To make sure that the inline buffer is enough for N-byte /// buffer encoded in base58, use smallvec with ⌈N*1.5⌉-byte long inline /// buffer (or ⌈(N+5)*1.5⌉ if version and checksum are included). fn encode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let original = self.len(); self.resize(original + max_len, 0); let len = f(&mut self[original..])?; self.truncate(original + len); Ok(len) } } #[cfg(feature = "tinyvec")] impl> EncodeTarget for tinyvec::ArrayVec { fn encode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let _ = max_len; let original = self.len(); let len = f(self.grab_spare_slice_mut())?; self.set_len(original + len); Ok(len) } } #[cfg(feature = "tinyvec")] impl EncodeTarget for tinyvec::SliceVec<'_, u8> { fn encode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let _ = max_len; let original = self.len(); let len = f(self.grab_spare_slice_mut())?; self.set_len(original + len); Ok(len) } } #[cfg(all(feature = "tinyvec", feature = "alloc"))] impl> EncodeTarget for tinyvec::TinyVec { fn encode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let original = self.len(); self.resize(original + max_len, 0); let len = f(&mut self[original..])?; self.truncate(original + len); Ok(len) } } #[cfg(feature = "alloc")] impl EncodeTarget for String { fn encode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let mut output = core::mem::take(self).into_bytes(); let len = output.encode_with(max_len, f)?; *self = String::from_utf8(output).unwrap(); Ok(len) } } impl EncodeTarget for [u8] { fn encode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { let _ = max_len; f(&mut *self) } } impl EncodeTarget for str { fn encode_with( &mut self, max_len: usize, f: impl for<'a> FnOnce(&'a mut [u8]) -> Result, ) -> Result { struct Guard<'a>(&'a mut [u8]); impl Drop for Guard<'_> { fn drop(&mut self) { let mut index = 0; loop { match core::str::from_utf8(&self.0[index..]) { Ok(_) => return, Err(e) => { index += e.valid_up_to(); if let Some(len) = e.error_len() { for i in &mut self.0[index..index + len] { *i = 0; } index += len; } else { for i in &mut self.0[index..] { *i = 0; } index += self.0[index..].len(); } } } } } } let _ = max_len; #[allow(unsafe_code)] // SAFETY: before returning the guard will be dropped and ensure the slice is valid utf-8 // by replacing invalid bytes with nul-bytes let guard = Guard(unsafe { self.as_bytes_mut() }); f(&mut *guard.0) } } impl<'a, I: AsRef<[u8]>> EncodeBuilder<'a, I> { /// Setup encoder for the given string using the given alphabet. /// Preferably use [`bs58::encode`](crate::encode()) instead of this /// directly. pub fn new(input: I, alpha: &'a Alphabet) -> EncodeBuilder<'a, I> { EncodeBuilder { input, alpha, check: Check::Disabled, } } /// Setup encoder for the given string using default prepared alphabet. pub(crate) fn from_input(input: I) -> EncodeBuilder<'static, I> { EncodeBuilder { input, alpha: Alphabet::DEFAULT, check: Check::Disabled, } } /// Change the alphabet that will be used for encoding. /// /// # Examples /// /// ```rust /// let input = [0x60, 0x65, 0xe7, 0x9b, 0xba, 0x2f, 0x78]; /// assert_eq!( /// "he11owor1d", /// bs58::encode(input) /// .with_alphabet(bs58::Alphabet::RIPPLE) /// .into_string()); /// ``` pub fn with_alphabet(self, alpha: &'a Alphabet) -> EncodeBuilder<'a, I> { EncodeBuilder { alpha, ..self } } /// Include checksum calculated using the [Base58Check][] algorithm when /// encoding. /// /// [Base58Check]: https://en.bitcoin.it/wiki/Base58Check_encoding /// /// # Examples /// /// ```rust /// let input = [0x60, 0x65, 0xe7, 0x9b, 0xba, 0x2f, 0x78]; /// assert_eq!( /// "QuT57JNzzWTu7mW", /// bs58::encode(input) /// .with_check() /// .into_string()); /// ``` #[cfg(feature = "check")] pub fn with_check(self) -> EncodeBuilder<'a, I> { let check = Check::Enabled(None); EncodeBuilder { check, ..self } } /// Include checksum calculated using the [Base58Check][] algorithm and /// version when encoding. /// /// [Base58Check]: https://en.bitcoin.it/wiki/Base58Check_encoding /// /// # Examples /// /// ```rust /// let input = [0x60, 0x65, 0xe7, 0x9b, 0xba, 0x2f, 0x78]; /// assert_eq!( /// "oP8aA4HEEyFxxYhp", /// bs58::encode(input) /// .with_check_version(42) /// .into_string()); /// ``` #[cfg(feature = "check")] pub fn with_check_version(self, expected_ver: u8) -> EncodeBuilder<'a, I> { let check = Check::Enabled(Some(expected_ver)); EncodeBuilder { check, ..self } } /// Include checksum calculated using the [CB58][] algorithm and /// version (if specified) when encoding. /// /// [CB58]: https://support.avax.network/en/articles/4587395-what-is-cb58 /// /// # Examples /// /// ```rust /// let input = [0x60, 0x65, 0xe7, 0x9b, 0xba, 0x2f, 0x78]; /// assert_eq!( /// "oP8aA4HEEyChXhM2", /// bs58::encode(input) /// .as_cb58(Some(42)) /// .into_string()); /// ``` #[cfg(feature = "cb58")] pub fn as_cb58(self, expected_ver: Option) -> EncodeBuilder<'a, I> { let check = Check::CB58(expected_ver); EncodeBuilder { check, ..self } } /// Encode into a new owned string. /// /// # Examples /// /// ```rust /// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58]; /// assert_eq!("he11owor1d", bs58::encode(input).into_string()); /// ``` #[cfg(feature = "alloc")] pub fn into_string(self) -> String { let mut output = String::new(); self.onto(&mut output).unwrap(); output } /// Encode into a new owned vector. /// /// # Examples /// /// ```rust /// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58]; /// assert_eq!(b"he11owor1d", &*bs58::encode(input).into_vec()); /// ``` #[cfg(feature = "alloc")] pub fn into_vec(self) -> Vec { let mut output = Vec::new(); self.onto(&mut output).unwrap(); output } /// Encode onto the given buffer. /// /// Returns the length written onto the buffer. /// /// If the buffer is resizeable it will be extended and the new data will be written to the end /// of it, otherwise the data will be overwritten from the start. /// /// If the buffer is not resizeable bytes after the final character will be left alone, except /// up to 3 null bytes may be written to an `&mut str` to overwrite remaining characters of a /// partially overwritten multi-byte character. /// /// See the documentation for [`bs58::encode`](crate::encode()) for an /// explanation of the errors that may occur. /// /// # Examples /// /// ## `Vec` /// /// ```rust /// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58]; /// let mut output = b"goodbye world ".to_vec(); /// bs58::encode(input).onto(&mut output)?; /// assert_eq!(b"goodbye world he11owor1d", output.as_slice()); /// # Ok::<(), bs58::encode::Error>(()) /// ``` /// /// ## `&mut [u8]` /// /// ```rust /// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58]; /// let mut output = b"goodbye world".to_owned(); /// bs58::encode(input).onto(&mut output[..])?; /// assert_eq!(b"he11owor1drld", output.as_ref()); /// # Ok::<(), bs58::encode::Error>(()) /// ``` /// /// ## `String` /// /// ```rust /// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58]; /// let mut output = "goodbye world ".to_owned(); /// bs58::encode(input).onto(&mut output)?; /// assert_eq!("goodbye world he11owor1d", output); /// # Ok::<(), bs58::encode::Error>(()) /// ``` /// /// ## `&mut str` /// /// ```rust /// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58]; /// let mut output = "goodbye world".to_owned(); /// bs58::encode(input).onto(output.as_mut_str())?; /// assert_eq!("he11owor1drld", output); /// # Ok::<(), bs58::encode::Error>(()) /// ``` /// /// ### Clearing partially overwritten characters /// /// ```rust /// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58]; /// let mut output = "goodbye w®ld".to_owned(); /// bs58::encode(input).onto(output.as_mut_str())?; /// assert_eq!("he11owor1d\0ld", output); /// # Ok::<(), bs58::encode::Error>(()) /// ``` pub fn onto(self, mut output: impl EncodeTarget) -> Result { let input = self.input.as_ref(); match self.check { Check::Disabled => output.encode_with(max_encoded_len(input.len()), |output| { encode_into(input, output, self.alpha) }), #[cfg(feature = "check")] Check::Enabled(version) => { let input_len = input.len() + CHECKSUM_LEN + version.map_or(0, |_| 1); output.encode_with(max_encoded_len(input_len), |output| { encode_check_into(self.input.as_ref(), output, self.alpha, version) }) } #[cfg(feature = "cb58")] Check::CB58(version) => { let input_len = input.len() + CHECKSUM_LEN + version.map_or(0, |_| 1); output.encode_with(max_encoded_len(input_len), |output| { encode_cb58_into(self.input.as_ref(), output, self.alpha, version) }) } } } } /// Return maximum possible encoded length of a buffer with given length. /// /// Assumes that the `len` already includes version and checksum bytes if those /// are fn max_encoded_len(len: usize) -> usize { // log_2(256) / log_2(58) ≈ 1.37. Assume 1.5 for easier calculation. len + (len + 1) / 2 } fn encode_into<'a, I>(input: I, output: &mut [u8], alpha: &Alphabet) -> Result where I: Clone + IntoIterator, { let mut index = 0; for &val in input.clone() { let mut carry = val as usize; for byte in &mut output[..index] { carry += (*byte as usize) << 8; *byte = (carry % 58) as u8; carry /= 58; } while carry > 0 { if index == output.len() { return Err(Error::BufferTooSmall); } output[index] = (carry % 58) as u8; index += 1; carry /= 58; } } for _ in input.into_iter().take_while(|v| **v == 0) { if index == output.len() { return Err(Error::BufferTooSmall); } output[index] = 0; index += 1; } for val in &mut output[..index] { *val = alpha.encode[*val as usize]; } output[..index].reverse(); Ok(index) } #[cfg(feature = "check")] fn encode_check_into( input: &[u8], output: &mut [u8], alpha: &Alphabet, version: Option, ) -> Result { use sha2::{Digest, Sha256}; let mut first_hash = Sha256::new(); if let Some(version) = version { first_hash.update([version; 1]); } let first_hash = first_hash.chain_update(input).finalize(); let second_hash = Sha256::digest(first_hash); let checksum = &second_hash[0..CHECKSUM_LEN]; encode_into( version.iter().chain(input.iter()).chain(checksum.iter()), output, alpha, ) } #[cfg(feature = "cb58")] fn encode_cb58_into( input: &[u8], output: &mut [u8], alpha: &Alphabet, version: Option, ) -> Result { use sha2::{Digest, Sha256}; let mut hash = Sha256::new(); if let Some(version) = version { hash.update([version; 1]); } let hash = hash.chain_update(input).finalize(); let checksum = &hash[hash.len() - CHECKSUM_LEN..]; encode_into( version.iter().chain(input.iter()).chain(checksum.iter()), output, alpha, ) } #[cfg(feature = "std")] impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::BufferTooSmall => write!( f, "buffer provided to encode base58 string into was too small" ), } } } bs58-0.5.1/src/lib.rs000064400000000000000000000145521046102023000123220ustar 00000000000000#![no_std] #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![warn(missing_copy_implementations)] #![warn(missing_debug_implementations)] #![warn(missing_docs)] #![warn(trivial_casts)] #![warn(trivial_numeric_casts)] #![warn(unused_extern_crates)] #![warn(unused_import_braces)] #![warn(variant_size_differences)] // This would be forbid, except unsafe is necessary to work with `&mut str`, // nowhere else should use it #![deny(unsafe_code)] #![doc(test(attr(deny(warnings))))] //! Another [Base58][] codec implementation. //! //! Compared to [`base58`][] this is significantly faster at decoding (about //! 2.4x as fast when decoding 32 bytes), almost the same speed for encoding //! (about 3% slower when encoding 32 bytes) and doesn't have the 128 byte //! limitation. //! //! Compared to [`rust-base58`][] this is massively faster (over ten times as //! fast when decoding 32 bytes, almost 40 times as fast when encoding 32 //! bytes) and has no external dependencies. //! //! Compared to both this supports a configurable alphabet and user provided //! buffers for zero-allocation {en,de}coding. //! //! [Base58]: https://en.wikipedia.org/wiki/Base58 //! [`base58`]: https://github.com/debris/base58 //! [`rust-base58`]: https://github.com/nham/rust-base58 //! //! # Features //! //! Feature | Activation | Effect //! ---------|--------------------|-------- //! `std` | **on**-by-default | Implement [`Error`](std::error::Error) for error types //! `alloc` | implied by `std` | Support encoding/decoding to [`Vec`](alloc::vec::Vec) and [`String`](alloc::string::String) as appropriate //! `check` | **off**-by-default | Integrated support for [Base58Check][] //! `cb58` | **off**-by-default | Integrated support for [CB58][] //! //! [Base58Check]: https://en.bitcoin.it/wiki/Base58Check_encoding //! [CB58]: https://support.avax.network/en/articles/4587395-what-is-cb58 //! //! # Examples //! //! ## Basic example //! //! ```rust //! let decoded = bs58::decode("he11owor1d").into_vec()?; //! let encoded = bs58::encode(decoded).into_string(); //! assert_eq!("he11owor1d", encoded); //! # Ok::<(), bs58::decode::Error>(()) //! ``` //! //! ## Changing the alphabet //! //! ```rust //! let decoded = bs58::decode("he11owor1d") //! .with_alphabet(bs58::Alphabet::RIPPLE) //! .into_vec()?; //! let encoded = bs58::encode(decoded) //! .with_alphabet(bs58::Alphabet::FLICKR) //! .into_string(); //! assert_eq!("4DSSNaN1SC", encoded); //! # Ok::<(), bs58::decode::Error>(()) //! ``` //! //! ## Decoding into an existing buffer //! //! ```rust //! let (mut decoded, mut encoded) = ([0xFF; 8], String::with_capacity(10)); //! bs58::decode("he11owor1d").onto(&mut decoded)?; //! bs58::encode(decoded).onto(&mut encoded)?; //! assert_eq!("he11owor1d", encoded); //! # Ok::<(), Box>(()) //! ``` #[cfg(feature = "std")] extern crate std; #[cfg(feature = "alloc")] extern crate alloc; pub mod alphabet; #[doc(inline)] pub use alphabet::Alphabet; pub mod decode; pub mod encode; #[cfg(any(feature = "check", feature = "cb58"))] const CHECKSUM_LEN: usize = 4; /// Possible check variants. enum Check { Disabled, #[cfg(feature = "check")] Enabled(Option), #[cfg(feature = "cb58")] CB58(Option), } /// Setup decoder for the given string using the [default alphabet][Alphabet::DEFAULT]. /// /// # Examples /// /// ## Basic example /// /// ```rust /// assert_eq!( /// vec![0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58], /// bs58::decode("he11owor1d").into_vec()?); /// # Ok::<(), bs58::decode::Error>(()) /// ``` /// /// ## Changing the alphabet /// /// ```rust /// assert_eq!( /// vec![0x60, 0x65, 0xe7, 0x9b, 0xba, 0x2f, 0x78], /// bs58::decode("he11owor1d") /// .with_alphabet(bs58::Alphabet::RIPPLE) /// .into_vec()?); /// # Ok::<(), bs58::decode::Error>(()) /// ``` /// /// ## Decoding into an existing buffer /// /// ```rust /// let mut output = [0xFF; 10]; /// assert_eq!(8, bs58::decode("he11owor1d").onto(&mut output)?); /// assert_eq!( /// [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58, 0xFF, 0xFF], /// output); /// # Ok::<(), bs58::decode::Error>(()) /// ``` /// /// ## Errors /// /// ### Invalid Character /// /// ```rust /// assert_eq!( /// bs58::decode::Error::InvalidCharacter { character: 'l', index: 2 }, /// bs58::decode("hello world").into_vec().unwrap_err()); /// ``` /// /// ### Non-ASCII Character /// /// ```rust /// assert_eq!( /// bs58::decode::Error::NonAsciiCharacter { index: 5 }, /// bs58::decode("he11o🇳🇿").into_vec().unwrap_err()); /// ``` /// /// ### Too Small Buffer /// /// This error can only occur when reading into a provided buffer, when using /// [`into_vec()`][decode::DecodeBuilder::into_vec] a vector large enough is guaranteed to be /// used. /// /// ```rust /// let mut output = [0; 7]; /// assert_eq!( /// bs58::decode::Error::BufferTooSmall, /// bs58::decode("he11owor1d").onto(&mut output).unwrap_err()); /// ``` pub const fn decode>(input: I) -> decode::DecodeBuilder<'static, I> { decode::DecodeBuilder::from_input(input) } /// Setup encoder for the given bytes using the [default alphabet][Alphabet::DEFAULT]. /// /// # Examples /// /// ## Basic example /// /// ```rust /// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58]; /// assert_eq!("he11owor1d", bs58::encode(input).into_string()); /// ``` /// /// ## Changing the alphabet /// /// ```rust /// let input = [0x60, 0x65, 0xe7, 0x9b, 0xba, 0x2f, 0x78]; /// assert_eq!( /// "he11owor1d", /// bs58::encode(input) /// .with_alphabet(bs58::Alphabet::RIPPLE) /// .into_string()); /// ``` /// /// ## Encoding into an existing string /// /// ```rust /// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58]; /// let mut output = "goodbye world ".to_owned(); /// bs58::encode(input).onto(&mut output)?; /// assert_eq!("goodbye world he11owor1d", output); /// # Ok::<(), bs58::encode::Error>(()) /// ``` /// /// ## Errors /// /// ### Too Small Buffer /// /// This error can only occur when reading into an unresizeable buffer. /// /// ```rust /// let input = [0x04, 0x30, 0x5e, 0x2b, 0x24, 0x73, 0xf0, 0x58]; /// let mut output = [0; 7]; /// assert_eq!( /// bs58::encode::Error::BufferTooSmall, /// bs58::encode(input).onto(&mut output[..]).unwrap_err()); /// ``` pub fn encode>(input: I) -> encode::EncodeBuilder<'static, I> { encode::EncodeBuilder::from_input(input) } bs58-0.5.1/tests/cases.rs000064400000000000000000000111131046102023000132130ustar 00000000000000const DIGITS_OF_PI: [u8; 128] = [ 0x03, 0x24, 0x3F, 0x6A, 0x88, 0x85, 0xA3, 0x08, 0xD3, 0x13, 0x19, 0x8A, 0x2E, 0x03, 0x70, 0x73, 0x44, 0xA4, 0x09, 0x38, 0x22, 0x29, 0x9F, 0x31, 0xD0, 0x08, 0x2E, 0xFA, 0x98, 0xEC, 0x4E, 0x6C, 0x89, 0x45, 0x28, 0x21, 0xE6, 0x38, 0xD0, 0x13, 0x77, 0xBE, 0x54, 0x66, 0xCF, 0x34, 0xE9, 0x0C, 0x6C, 0xC0, 0xAC, 0x29, 0xB7, 0xC9, 0x7C, 0x50, 0xDD, 0x3F, 0x84, 0xD5, 0xB5, 0xB5, 0x47, 0x09, 0x17, 0x92, 0x16, 0xD5, 0xD9, 0x89, 0x79, 0xFB, 0x1B, 0xD1, 0x31, 0x0B, 0xA6, 0x98, 0xDF, 0xB5, 0xAC, 0x2F, 0xFD, 0x72, 0xDB, 0xD0, 0x1A, 0xDF, 0xB7, 0xB8, 0xE1, 0xAF, 0xED, 0x6A, 0x26, 0x7E, 0x96, 0xBA, 0x7C, 0x90, 0x45, 0xF1, 0x2C, 0x7F, 0x99, 0x24, 0xA1, 0x99, 0x47, 0xB3, 0x91, 0x6C, 0xF7, 0x08, 0x01, 0xF2, 0xE2, 0x85, 0x8E, 0xFC, 0x16, 0x63, 0x69, 0x20, 0xD8, 0x71, 0x57, 0x4E, ]; // Subset of test cases from https://github.com/cryptocoinjs/base-x/blob/master/test/fixtures.json pub const TEST_CASES: &[(&[u8], &str)] = &[ (&[], ""), (&[0x61], "2g"), (&[0x62, 0x62, 0x62], "a3gV"), (&[0x63, 0x63, 0x63], "aPEr"), (&[0x57, 0x2e, 0x47, 0x94], "3EFU7m"), (&[0x10, 0xc8, 0x51, 0x1e], "Rt5zm"), (&[0x51, 0x6b, 0x6f, 0xcd, 0x0f], "ABnLTmg"), ( &[0xbf, 0x4f, 0x89, 0x00, 0x1e, 0x67, 0x02, 0x74, 0xdd], "3SEo3LWLoPntC", ), ( &[0xec, 0xac, 0x89, 0xca, 0xd9, 0x39, 0x23, 0xc0, 0x23, 0x21], "EJDM8drfXA6uyA", ), ( &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], "1111111111", ), ( &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff], "FPBt6CHo3fovdL", ), ( &[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ], "NKioeUVktgzXLJ1B3t", ), ( &[ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, ], "YcVfxkQb6JRzqk5kF2tNLv", ), ( &[ 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x79, 0x20, 0x61, 0x20, 0x6c, 0x6f, 0x6e, 0x67, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, ], "2cFupjhnEsSn59qHXstmK2ffpLv2", ), ( &[ 0x00, 0xeb, 0x15, 0x23, 0x1d, 0xfc, 0xeb, 0x60, 0x92, 0x58, 0x86, 0xb6, 0x7d, 0x06, 0x52, 0x99, 0x92, 0x59, 0x15, 0xae, 0xb1, 0x72, 0xc0, 0x66, 0x47, ], "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L", ), ( &[ 0x00, 0x3c, 0x17, 0x6e, 0x65, 0x9b, 0xea, 0x0f, 0x29, 0xa3, 0xe9, 0xbf, 0x78, 0x80, 0xc1, 0x12, 0xb1, 0xb3, 0x1b, 0x4d, 0xc8, 0x26, 0x26, 0x81, 0x87, ], "16UjcYNBG9GTK4uq2f7yYEbuifqCzoLMGS", ), ( &[ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ], "11111111111111111111111111111111", ), ( &[ 0x80, 0x11, 0x84, 0xcd, 0x2c, 0xdd, 0x64, 0x0c, 0xa4, 0x2c, 0xfc, 0x3a, 0x09, 0x1c, 0x51, 0xd5, 0x49, 0xb2, 0xf0, 0x16, 0xd4, 0x54, 0xb2, 0x77, 0x40, 0x19, 0xc2, 0xb2, 0xd2, 0xe0, 0x85, 0x29, 0xfd, 0x20, 0x6e, 0xc9, 0x7e, ], "5Hx15HFGyep2CfPxsJKe2fXJsCVn5DEiyoeGGF6JZjGbTRnqfiD", ), (&DIGITS_OF_PI, "KeThPkHTv5nsa4576Z47NqEtuSfUcKwv7YeueZ8dquGTDeBpimjGEZ1a7k1FCz8m8FEBcoJZjP5Aui6eKfPjdmGooHKtEPRbVotw6mRxNU3WbLtAH41mea9g8AB9Qe1DAFDReBWa67ZEP6ApWGhw9Dfr2vVXkLXEWj6W8HFApw4DKK"), ]; #[cfg(feature = "check")] pub const CHECK_TEST_CASES: &[(&[u8], &str)] = &[ (&[], "3QJmnh"), (&[0x31], "6bdbJ1U"), (&[0x39], "7VsrQCP"), (&[0x2d, 0x31], "PWEu9GGN"), (&[0x31, 0x31], "RVnPfpC2"), ( &[0x31, 0x32, 0x33, 0x34, 0x35, 0x39, 0x38, 0x37, 0x36, 0x30], "K5zqBMZZTzUbAZQgrt4", ), ( &[ 0x00, 0x9b, 0x41, 0x54, 0xbb, 0xf2, 0x03, 0xe4, 0x13, 0x0c, 0x4b, 0x86, 0x25, 0x93, 0x18, 0xa4, 0x98, 0x75, 0xdd, 0x04, 0x56, ], "1F9v11cupBVMpz3CrVfCppv9Rw2xEtU1c6", ), ( &[ 0x53, 0x25, 0xb1, 0xe2, 0x3b, 0x5b, 0x24, 0xf3, 0x47, 0xed, 0x19, 0xde, 0x61, 0x23, 0x8a, 0xf1, 0x4b, 0xc4, 0x71, 0xca, 0xa1, 0xa7, 0x7a, 0xa5, 0x5d, 0xb2, 0xa7, 0xaf, 0x7d, 0xaa, 0x93, 0xaa, ], "dctKSXBbv2My3TGGUgTFjkxu1A9JM3Sscd5FydY4dkxnfwA7q", ), (&DIGITS_OF_PI, "371hJQw3jVfFQtQfQ1NnUFV4Z3i166yKJe3yyPAvJziEfUenJBD8SM6xGFop9cfCDCn4j9HcT9fS73jgGp8XZzYKmSxjxLcxfgETzg4BcDHLgHSynSFDGR5wJ58NkZSv2mVxvqVwG8hqxNFXrWms66ppx45yAjc7dYuBXqCPZ2GatCMmrhuX"), ]; bs58-0.5.1/tests/decode.rs000064400000000000000000000100661046102023000133460ustar 00000000000000mod cases; #[cfg(feature = "check")] use assert_matches::assert_matches; #[test] fn test_decode() { for &(val, s) in cases::TEST_CASES.iter() { assert_eq!(val.to_vec(), bs58::decode(s).into_vec().unwrap()); const PREFIX: &[u8] = &[0, 1, 2]; { let mut vec = PREFIX.to_vec(); assert_eq!(Ok(val.len()), bs58::decode(s).onto(&mut vec)); assert_eq!((PREFIX, val), vec.split_at(3)); } { let vec = bs58::decode(s.as_bytes()).into_array_const_unwrap::<128>(); let mut check = [0; 128]; check[..val.len()].copy_from_slice(val); assert_eq!(vec, check); } #[cfg(feature = "smallvec")] { let mut vec = smallvec::SmallVec::<[u8; 36]>::from(PREFIX); assert_eq!(Ok(val.len()), bs58::decode(s).onto(&mut vec)); assert_eq!((PREFIX, val), vec.split_at(3)); } #[cfg(feature = "tinyvec")] { { let mut vec = tinyvec::ArrayVec::<[u8; 36]>::from_iter(PREFIX.iter().copied()); let res = bs58::decode(s).onto(&mut vec); if PREFIX.len() + val.len() <= vec.capacity() { assert_eq!(Ok(val.len()), res); assert_eq!((PREFIX, val), vec.split_at(3)); } else { assert_eq!(Err(bs58::decode::Error::BufferTooSmall), res); } } { let mut array = [0; 36]; array[..PREFIX.len()].copy_from_slice(PREFIX); let mut vec = tinyvec::SliceVec::from_slice_len(&mut array, PREFIX.len()); let res = bs58::decode(s).onto(&mut vec); if PREFIX.len() + val.len() <= vec.capacity() { assert_eq!(Ok(val.len()), res); assert_eq!((PREFIX, val), vec.split_at(3)); } else { assert_eq!(Err(bs58::decode::Error::BufferTooSmall), res); } } { let mut vec = tinyvec::TinyVec::<[u8; 36]>::from(PREFIX); assert_eq!(Ok(val.len()), bs58::decode(s).onto(&mut vec)); assert_eq!((PREFIX, val), vec.split_at(3)); } } } } #[test] fn test_decode_small_buffer_err() { let mut output = [0; 2]; assert_eq!( bs58::decode("a3gV").onto(&mut output), Err(bs58::decode::Error::BufferTooSmall) ); } #[test] #[should_panic] fn test_decode_const_small_buffer_panic() { bs58::decode(&b"a3gV"[..]).into_array_const_unwrap::<2>(); } #[test] #[should_panic] fn test_decode_const_invalid_char_panic() { let sample = "123456789abcd!efghij"; let _ = bs58::decode(sample.as_bytes()).into_array_const_unwrap::<32>(); } #[test] fn test_decode_invalid_char() { let sample = "123456789abcd!efghij"; assert_eq!( bs58::decode(sample).into_vec().unwrap_err(), bs58::decode::Error::InvalidCharacter { character: '!', index: 13 } ); } #[test] #[cfg(feature = "check")] fn test_decode_check() { for &(val, s) in cases::CHECK_TEST_CASES.iter() { assert_eq!( val.to_vec(), bs58::decode(s).with_check(None).into_vec().unwrap() ); } for &(val, s) in cases::CHECK_TEST_CASES[1..].iter() { assert_eq!( val.to_vec(), bs58::decode(s).with_check(Some(val[0])).into_vec().unwrap() ); } } #[test] #[cfg(feature = "check")] fn test_check_ver_failed() { let d = bs58::decode("K5zqBMZZTzUbAZQgrt4") .with_check(Some(0x01)) .into_vec(); assert!(d.is_err()); assert_matches!(d.unwrap_err(), bs58::decode::Error::InvalidVersion { .. }); } #[test] fn append() { let mut buf = b"hello world".to_vec(); bs58::decode("a").onto(&mut buf).unwrap(); assert_eq!(b"hello world!", buf.as_slice()); } #[test] fn no_append() { let mut buf = b"hello world".to_owned(); bs58::decode("a").onto(buf.as_mut()).unwrap(); assert_eq!(b"!ello world", buf.as_ref()); } bs58-0.5.1/tests/encode.rs000064400000000000000000000143151046102023000133610ustar 00000000000000mod cases; const FILLER: [u8; 512] = [b'~'; 512]; #[test] fn test_encode() { for &(val, s) in cases::TEST_CASES.iter() { assert_eq!(s, bs58::encode(val).into_string()); assert_eq!(s.as_bytes(), &*bs58::encode(val).into_vec()); { let mut bytes = FILLER; assert_eq!(Ok(s.len()), bs58::encode(val).onto(&mut bytes[..])); assert_eq!(s.as_bytes(), &bytes[..s.len()]); assert_eq!(&FILLER[s.len()..], &bytes[s.len()..]); } { let mut bytes = FILLER; if !s.is_empty() { bytes[(s.len() - 1)..=s.len()].copy_from_slice("Ę".as_bytes()); } let string = core::str::from_utf8_mut(&mut bytes[..]).unwrap(); assert_eq!(Ok(s.len()), bs58::encode(val).onto(string)); assert_eq!(s.as_bytes(), &bytes[..s.len()]); if !s.is_empty() { assert_eq!(0, bytes[s.len()]); } assert_eq!(&FILLER[(s.len() + 1)..], &bytes[(s.len() + 1)..]); } const PREFIX: &[u8] = &[0, 1, 2]; { let mut vec = PREFIX.to_vec(); assert_eq!(Ok(s.len()), bs58::encode(val).onto(&mut vec)); assert_eq!((PREFIX, s.as_bytes()), vec.split_at(3)); } #[cfg(feature = "smallvec")] { let mut vec = smallvec::SmallVec::<[u8; 36]>::from(PREFIX); assert_eq!(Ok(s.len()), bs58::encode(val).onto(&mut vec)); assert_eq!((PREFIX, s.as_bytes()), vec.split_at(3)); } #[cfg(feature = "tinyvec")] { { let mut vec = tinyvec::ArrayVec::<[u8; 36]>::from_iter(PREFIX.iter().copied()); let res = bs58::encode(val).onto(&mut vec); if PREFIX.len() + s.len() <= vec.capacity() { assert_eq!(Ok(s.len()), res); assert_eq!((PREFIX, s.as_bytes()), vec.split_at(3)); } else { assert_eq!(Err(bs58::encode::Error::BufferTooSmall), res); } } { let mut array = [0; 36]; array[..PREFIX.len()].copy_from_slice(PREFIX); let mut vec = tinyvec::SliceVec::from_slice_len(&mut array, PREFIX.len()); let res = bs58::encode(val).onto(&mut vec); if PREFIX.len() + s.len() <= vec.capacity() { assert_eq!(Ok(s.len()), res); assert_eq!((PREFIX, s.as_bytes()), vec.split_at(3)); } else { assert_eq!(Err(bs58::encode::Error::BufferTooSmall), res); } } { let mut vec = tinyvec::TinyVec::<[u8; 36]>::from(PREFIX); assert_eq!(Ok(s.len()), bs58::encode(val).onto(&mut vec)); assert_eq!((PREFIX, s.as_bytes()), vec.split_at(3)); } } } } #[test] #[cfg(feature = "check")] fn test_encode_check() { for &(val, s) in cases::CHECK_TEST_CASES.iter() { assert_eq!(s, bs58::encode(val).with_check().into_string()); assert_eq!(s.as_bytes(), &*bs58::encode(val).with_check().into_vec()); { let mut bytes = FILLER; assert_eq!( Ok(s.len()), bs58::encode(val).with_check().onto(&mut bytes[..]) ); assert_eq!(s.as_bytes(), &bytes[..s.len()]); assert_eq!(&FILLER[s.len()..], &bytes[s.len()..]); if !val.is_empty() { assert_eq!( Ok(s.len()), bs58::encode(&val[1..]) .with_check_version(val[0]) .onto(&mut bytes[..]) ); assert_eq!(s.as_bytes(), &bytes[..s.len()]); assert_eq!(&FILLER[s.len()..], &bytes[s.len()..]); } } { let mut bytes = FILLER; if !s.is_empty() { bytes[(s.len() - 1)..=s.len()].copy_from_slice("Ę".as_bytes()); } let string = core::str::from_utf8_mut(&mut bytes[..]).unwrap(); assert_eq!(Ok(s.len()), bs58::encode(val).with_check().onto(string)); assert_eq!(s.as_bytes(), &bytes[..s.len()]); if !s.is_empty() { assert_eq!(0, bytes[s.len()]); } assert_eq!(&FILLER[(s.len() + 1)..], &bytes[(s.len() + 1)..]); } } } #[test] fn append() { let mut buf = "hello world".to_string(); bs58::encode(&[92]).onto(&mut buf).unwrap(); assert_eq!("hello world2b", buf.as_str()); } /// Verify that encode_into doesn’t try to write over provided buffer. #[test] fn test_buffer_too_small() { let mut output = [0u8; 256]; for &(val, s) in cases::TEST_CASES.iter() { let expected_len = s.len(); if expected_len > 0 { let res = bs58::encode(val).onto(&mut output[..(expected_len - 1)]); assert_eq!(Err(bs58::encode::Error::BufferTooSmall), res); } let res = bs58::encode(val).onto(&mut output[..expected_len]); assert_eq!(Ok(expected_len), res); } } /// Verify that encode_into doesn’t try to write over provided buffer. #[test] #[cfg(feature = "check")] fn test_buffer_too_small_check() { let mut output = [0u8; 256]; for &(val, s) in cases::CHECK_TEST_CASES.iter() { let expected_len = s.len(); if expected_len > 0 { let res = bs58::encode(val) .with_check() .onto(&mut output[..(expected_len - 1)]); assert_eq!(Err(bs58::encode::Error::BufferTooSmall), res); } let res = bs58::encode(val) .with_check() .onto(&mut output[..expected_len]); assert_eq!(Ok(expected_len), res); } } /// Stress test encoding by trying to encode increasingly long buffers. #[test] fn encode_stress_test() { let input = b"\xff".repeat(512); for len in 0..=input.len() { bs58::encode(&input[..len]).into_string(); #[cfg(feature = "check")] bs58::encode(&input[..len]).with_check().into_string(); #[cfg(feature = "check")] bs58::encode(&input[..len]) .with_check_version(255) .into_string(); } }