base-x-0.2.11/.cargo_vcs_info.json0000644000000001360000000000100122740ustar { "git": { "sha1": "5fd81272464eca6a78b4dfff85c1cf25027e4a6b" }, "path_in_vcs": "" }base-x-0.2.11/.github/workflows/rust.yml000064400000000000000000000004740072674642500162360ustar 00000000000000name: Rust on: push: branches: [ master ] pull_request: branches: [ master ] env: CARGO_TERM_COLOR: always jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Build run: cargo build --verbose - name: Run tests run: cargo test --verbose base-x-0.2.11/.gitignore000064400000000000000000000000220072674642500130760ustar 00000000000000target Cargo.lock base-x-0.2.11/.travis.yml000064400000000000000000000001420072674642500132220ustar 00000000000000language: rust rust: - stable - beta - nightly matrix: allow_failures: - rust: nightlybase-x-0.2.11/Cargo.toml0000644000000020100000000000100102630ustar # 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] name = "base-x" version = "0.2.11" authors = ["Alex R. "] description = "Encode/decode any base" homepage = "https://github.com/OrKoN/base-x-rs" readme = "README.md" keywords = [ "base-x", "base", "convert", ] categories = ["value-formatting"] license = "MIT" repository = "https://github.com/OrKoN/base-x-rs" [[bench]] name = "base" harness = false [dev-dependencies.bencher] version = "0.1" [dev-dependencies.json] version = "0.12" [dev-dependencies.rand] version = "0.8" [features] default = ["std"] std = [] base-x-0.2.11/Cargo.toml.orig000064400000000000000000000007460072674642500140120ustar 00000000000000[package] name = "base-x" description = "Encode/decode any base" version = "0.2.11" authors = ["Alex R. "] license = "MIT" readme = "README.md" keywords = ["base-x", "base", "convert"] repository = "https://github.com/OrKoN/base-x-rs" homepage = "https://github.com/OrKoN/base-x-rs" categories = ["value-formatting"] [dev-dependencies] json = "0.12" bencher = "0.1" rand = "0.8" [[bench]] name = "base" harness = false [features] default = ["std"] std = [] base-x-0.2.11/LICENSE.md000064400000000000000000000021210072674642500125140ustar 00000000000000The MIT License (MIT) Copyright base-x contributors and Oleksii Rudenko (c) 2016 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.base-x-0.2.11/README.md000064400000000000000000000020020072674642500123650ustar 00000000000000# base-x [![Build Status](https://travis-ci.org/OrKoN/base-x-rs.svg?branch=master)](https://travis-ci.org/OrKoN/base-x-rs) This is a Rust fork of https://github.com/cryptocoinjs/base-x **WARNING:** This module is **NOT RFC3548** compliant, it cannot be used for base16 (hex), base32, or base64 encoding in a standards compliant manner. And this my very first Rust project: please review the source code! ## Installation Add this to `Cargo.toml` file: ```toml [dependencies] base-x = "0.2.0" ``` ## Usage ```rust extern crate base_x; fn main() { let decoded = base_x::decode("01", "11111111000000001111111100000000").unwrap(); let encoded = base_x::encode("01", &decoded); assert_eq!(encoded, "11111111000000001111111100000000"); } ``` ## Changelog - 0.2.0 Breaking change: alphabet has to be provided as an array of bytes instead of a string. - 0.1.0 initial version ## Contributors - [Friedel Ziegelmayer](https://github.com/dignifiedquire) - [Maciej Hirsz](https://github.com/maciejhirsz) base-x-0.2.11/benches/base.rs000064400000000000000000000030750072674642500140100ustar 00000000000000#[macro_use] extern crate bencher; extern crate base_x; extern crate rand; use base_x::{decode, encode, Alphabet}; use bencher::Bencher; fn random_input(size: usize) -> Vec { let mut v = vec![0; size]; for x in v.iter_mut() { *x = rand::random() } v } fn test_decode(bench: &mut Bencher, alph: A) { let input = random_input(100); let out = encode(alph, &input); bench.iter(|| decode(alph, &out).unwrap()); } fn test_encode(bench: &mut Bencher, alph: A) { let input = random_input(100); bench.iter(|| encode(alph, &input)); } // Actual benchmarks // Encode UTF-8 fn encode_base2(bench: &mut Bencher) { const ALPH: &str = "01"; test_encode(bench, ALPH); } fn encode_base16(bench: &mut Bencher) { const ALPH: &str = "0123456789abcdef"; test_encode(bench, ALPH); } fn encode_base58(bench: &mut Bencher) { const ALPH: &str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; test_encode(bench, ALPH); } // Decode UTF-8 fn decode_base2(bench: &mut Bencher) { const ALPH: &str = "01"; test_decode(bench, ALPH); } fn decode_base16(bench: &mut Bencher) { const ALPH: &str = "0123456789abcdef"; test_decode(bench, ALPH); } fn decode_base58(bench: &mut Bencher) { const ALPH: &str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; test_decode(bench, ALPH); } benchmark_group!( benches, encode_base2, decode_base2, encode_base16, decode_base16, encode_base58, decode_base58 ); benchmark_main!(benches); base-x-0.2.11/fixtures/fixtures.json000064400000000000000000000322540072674642500155370ustar 00000000000000{ "alphabets": { "base2": "01", "base16": "0123456789abcdef", "base58": "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" }, "valid": [ { "alphabet": "base2", "hex": "000f", "string": "01111" }, { "alphabet": "base2", "hex": "00ff", "comment": "Note the first leading zero byte is compressed into 1 char", "string": "011111111" }, { "alphabet": "base2", "hex": "0fff", "string": "111111111111" }, { "alphabet": "base2", "hex": "ff00ff00", "string": "11111111000000001111111100000000" }, { "alphabet": "base16", "hex": "0000000f", "string": "000f" }, { "alphabet": "base16", "hex": "000fff", "string": "0fff" }, { "alphabet": "base16", "hex": "ffff", "string": "ffff" }, { "alphabet": "base58", "hex": "", "string": "" }, { "alphabet": "base58", "hex": "61", "string": "2g" }, { "alphabet": "base58", "hex": "626262", "string": "a3gV" }, { "alphabet": "base58", "hex": "636363", "string": "aPEr" }, { "alphabet": "base58", "hex": "73696d706c792061206c6f6e6720737472696e67", "string": "2cFupjhnEsSn59qHXstmK2ffpLv2" }, { "alphabet": "base58", "hex": "00eb15231dfceb60925886b67d065299925915aeb172c06647", "string": "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L" }, { "alphabet": "base58", "hex": "516b6fcd0f", "string": "ABnLTmg" }, { "alphabet": "base58", "hex": "bf4f89001e670274dd", "string": "3SEo3LWLoPntC" }, { "alphabet": "base58", "hex": "572e4794", "string": "3EFU7m" }, { "alphabet": "base58", "hex": "ecac89cad93923c02321", "string": "EJDM8drfXA6uyA" }, { "alphabet": "base58", "hex": "10c8511e", "string": "Rt5zm" }, { "alphabet": "base58", "hex": "00000000000000000000", "string": "1111111111" }, { "alphabet": "base58", "hex": "801184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd206ec97e", "string": "5Hx15HFGyep2CfPxsJKe2fXJsCVn5DEiyoeGGF6JZjGbTRnqfiD" }, { "alphabet": "base58", "hex": "003c176e659bea0f29a3e9bf7880c112b1b31b4dc826268187", "string": "16UjcYNBG9GTK4uq2f7yYEbuifqCzoLMGS" }, { "alphabet": "base58", "hex": "ffffffffffffffffffff", "string": "FPBt6CHo3fovdL" }, { "alphabet": "base58", "hex": "ffffffffffffffffffffffffff", "string": "NKioeUVktgzXLJ1B3t" }, { "alphabet": "base58", "hex": "ffffffffffffffffffffffffffffffff", "string": "YcVfxkQb6JRzqk5kF2tNLv" }, { "alphabet": "base2", "hex": "fb6f9ac3", "string": "11111011011011111001101011000011" }, { "alphabet": "base2", "hex": "179eea7a", "string": "10111100111101110101001111010" }, { "alphabet": "base2", "hex": "6db825db", "string": "1101101101110000010010111011011" }, { "alphabet": "base2", "hex": "93976aa7", "string": "10010011100101110110101010100111" }, { "alphabet": "base58", "hex": "ef41b9ce7e830af7", "string": "h26E62FyLQN" }, { "alphabet": "base58", "hex": "606cbc791036d2e9", "string": "H8Sa62HVULG" }, { "alphabet": "base58", "hex": "bdcb0ea69c2c8ec8", "string": "YkESUPpnfoD" }, { "alphabet": "base58", "hex": "1a2358ba67fb71d5", "string": "5NaBN89ajtQ" }, { "alphabet": "base58", "hex": "e6173f0f4d5fb5d7", "string": "fVAoezT1ZkS" }, { "alphabet": "base58", "hex": "91c81cbfdd58bbd2", "string": "RPGNSU3bqTX" }, { "alphabet": "base58", "hex": "329e0bf0e388dbfe", "string": "9U41ZkwwysT" }, { "alphabet": "base58", "hex": "30b10393210fa65b", "string": "99NMW3WHjjY" }, { "alphabet": "base58", "hex": "ab3bdd18e3623654", "string": "VeBbqBb4rCT" }, { "alphabet": "base58", "hex": "fe29d1751ec4af8a", "string": "jWhmYLN9dUm" }, { "alphabet": "base58", "hex": "c1273ab5488769807d", "string": "3Tbh4kL3WKW6g" }, { "alphabet": "base58", "hex": "6c7907904de934f852", "string": "2P5jNYhfpTJxy" }, { "alphabet": "base58", "hex": "05f0be055db47a0dc9", "string": "5PN768Kr5oEp" }, { "alphabet": "base58", "hex": "3511e6206829b35b12", "string": "gBREojGaJ6DF" }, { "alphabet": "base58", "hex": "d1c7c2ddc4a459d503", "string": "3fsekq5Esq2KC" }, { "alphabet": "base58", "hex": "1f88efd17ab073e9a1", "string": "QHJbmW9ZY7jn" }, { "alphabet": "base58", "hex": "0f45dadf4e64c5d5c2", "string": "CGyVUMmCKLRf" }, { "alphabet": "base58", "hex": "de1e5c5f718bb7fafa", "string": "3pyy8U7w3KUa5" }, { "alphabet": "base58", "hex": "123190b93e9a49a46c", "string": "ES3DeFrG1zbd" }, { "alphabet": "base58", "hex": "8bee94a543e7242e5a", "string": "2nJnuWyLpGf6y" }, { "alphabet": "base58", "hex": "9fd5f2285362f5cfd834", "string": "9yqFhqeewcW3pF" }, { "alphabet": "base58", "hex": "6987bac63ad23828bb31", "string": "6vskE5Y1LhS3U4" }, { "alphabet": "base58", "hex": "19d4a0f9d459cc2a08b0", "string": "2TAsHPuaLhh5Aw" }, { "alphabet": "base58", "hex": "a1e47ffdbea5a807ab26", "string": "A6XzPgSUJDf1W5" }, { "alphabet": "base58", "hex": "35c231e5b3a86a9b83db", "string": "42B8reRwPAAoAa" }, { "alphabet": "base58", "hex": "b2351012a48b8347c351", "string": "B1hPyomGx4Vhqa" }, { "alphabet": "base58", "hex": "71d402694dd9517ea653", "string": "7Pv2SyAQx2Upu8" }, { "alphabet": "base58", "hex": "55227c0ec7955c2bd6e8", "string": "5nR64BkskyjHMq" }, { "alphabet": "base58", "hex": "17b3d8ee7907c1be34df", "string": "2LEg7TxosoxTGS" }, { "alphabet": "base58", "hex": "7e7bba7b68bb8e95827f", "string": "879o2ATGnmYyAW" }, { "alphabet": "base58", "hex": "db9c13f5ba7654b01407fb", "string": "wTYfxjDVbiks874" }, { "alphabet": "base58", "hex": "6186449d20f5fd1e6c4393", "string": "RBeiWhzZNL6VtMG" }, { "alphabet": "base58", "hex": "5248751cebf4ad1c1a83c3", "string": "MQSVNnc8ehFCqtW" }, { "alphabet": "base58", "hex": "32090ef18cd479fc376a74", "string": "DQdu351ExDaeYeX" }, { "alphabet": "base58", "hex": "7cfa5d6ed1e467d986c426", "string": "XzW67T5qfEnFcaZ" }, { "alphabet": "base58", "hex": "9d8707723c7ede51103b6d", "string": "g4eTCg6QJnB1UU4" }, { "alphabet": "base58", "hex": "6f4d1e392d6a9b4ed8b223", "string": "Ubo7kZY5aDpAJp2" }, { "alphabet": "base58", "hex": "38057d98797cd39f80a0c9", "string": "EtjQ2feamJvuqse" }, { "alphabet": "base58", "hex": "de7e59903177e20880e915", "string": "xB2N7yRBnDYEoT2" }, { "alphabet": "base58", "hex": "b2ea24a28bc4a60b5c4b8d", "string": "mNFMpJ2P3TGYqhv" }, { "alphabet": "base58", "hex": "cf84938958589b6ffba6114d", "string": "4v8ZbsGh2ePz5sipt" }, { "alphabet": "base58", "hex": "dee13be7b8d8a08c94a3c02a", "string": "5CwmE9jQqwtHkTF45" }, { "alphabet": "base58", "hex": "14cb9c6b3f8cd2e02710f569", "string": "Pm85JHVAAdeUdxtp" }, { "alphabet": "base58", "hex": "ca3f2d558266bdcc44c79cb5", "string": "4pMwomBAQHuUnoLUC" }, { "alphabet": "base58", "hex": "c031215be44cbad745f38982", "string": "4dMeTrcxiVw9RWvj3" }, { "alphabet": "base58", "hex": "1435ab1dbc403111946270a5", "string": "P7wX3sCWNrbqhBEC" }, { "alphabet": "base58", "hex": "d8c6e4d775e7a66a0d0f9f41", "string": "56GLoRDGWGuGJJwPN" }, { "alphabet": "base58", "hex": "dcee35e74f0fd74176fce2f4", "string": "5Ap1zyuYiJJFwWcMR" }, { "alphabet": "base58", "hex": "bfcc0ca4b4855d1cf8993fc0", "string": "4cvafQW4PEhARKv9D" }, { "alphabet": "base58", "hex": "e02a3ac25ece7b54584b670a", "string": "5EMM28xkpxZ1kkVUM" }, { "alphabet": "base58", "hex": "fe4d938fc3719f064cabb4bfff", "string": "NBXKkbHwrAsiWTLAk6" }, { "alphabet": "base58", "hex": "9289cb4f6b15c57e6086b87ea5", "string": "DCvDpjEXEbHjZqskKv" }, { "alphabet": "base58", "hex": "fc266f35626b3612bfe978537b", "string": "N186PVoBWrNre35BGE" }, { "alphabet": "base58", "hex": "33ff08c06d92502bf258c07166", "string": "5LC4SoW6jmTtbkbePw" }, { "alphabet": "base58", "hex": "6a81cac1f3666bc59dc67b1c3c", "string": "9sXgUySUzwiqDU5WHy" }, { "alphabet": "base58", "hex": "9dfb8e7e744c544c0f323ea729", "string": "EACsmGmkgcwsrPFzLg" }, { "alphabet": "base58", "hex": "1e7a1e284f70838b38442b682b", "string": "3YEVk9bE7rw5qExMkv" }, { "alphabet": "base58", "hex": "2a862ad57901a8235f5dc74eaf", "string": "4YS259nuTLfeXa5Wuc" }, { "alphabet": "base58", "hex": "74c82096baef21f9d3089e5462", "string": "AjAcKEhUfrqm8smvM7" }, { "alphabet": "base58", "hex": "7a3edbc23d7b600263920261cc", "string": "BBZXyRgey5S5DDZkcK" }, { "alphabet": "base58", "hex": "20435664c357d25a9c8df751cf4f", "string": "CrwNL6Fbv4pbRx1zd9g" }, { "alphabet": "base58", "hex": "51a7aa87cf5cb1c12d045ec3422d", "string": "X27NHGgKXmGzzQvDtpC" }, { "alphabet": "base58", "hex": "344d2e116aa26f1062a2cb6ebbef", "string": "LEDLDvL1Hg4qt1efVXt" }, { "alphabet": "base58", "hex": "6941add7be4c0b5c7163e4928f8e", "string": "fhMyN6gwoxE3uYraVzV" }, { "alphabet": "base58", "hex": "10938fcbb7c4ab991649734a14bf", "string": "76TPrSDxzGQfSzMu974" }, { "alphabet": "base58", "hex": "eafe04d944ba504e9af9117b07de", "string": "2VPgov563ryfe4L2Bj6M" }, { "alphabet": "base58", "hex": "58d0aeed4d35da20b6f052127edf", "string": "ZenZhXF9YwP8nQvNtNz" }, { "alphabet": "base58", "hex": "d734984e2f5aecf25f7a3e353f8a", "string": "2N7n3jFsTdyN49Faoq6h" }, { "alphabet": "base58", "hex": "57d873fdb405b7daf4bafa62068a", "string": "ZJ7NwoP4wHvwyZg3Wjs" }, { "alphabet": "base58", "hex": "bda4ec7b40d0d65ca95dec4c4d3b", "string": "2CijxjsNyvqTwPCfDcpA" }, { "alphabet": "base58", "hex": "826c4abdceb1b91f0d4ad665f86d2e", "string": "4edfvuDQu9KzVxLuXHfMo" }, { "alphabet": "base58", "hex": "e7ecb35d07e65b960cb10574a4f51a", "string": "7VLRYdB4cToipp2J2p3v9" }, { "alphabet": "base58", "hex": "4f2d72ead87b31d6869fba39eac6dc", "string": "3DUjqJRcfdWhpsrLrGcQs" }, { "alphabet": "base58", "hex": "8b4f5788d60030950d5dfbf94c585d", "string": "4u44JSRH5jP5X39YhPsmE" }, { "alphabet": "base58", "hex": "ee4c0a0025d1a74ace9fe349355cc5", "string": "7fgACjABRQUGUEpN6VBBA" }, { "alphabet": "base58", "hex": "58ac05b9a0b4b66083ff1d489b8d84", "string": "3UtJPyTwGXapcxHx8Rom5" }, { "alphabet": "base58", "hex": "1aa35c05e1132e8e049aafaef035d8", "string": "kE2eSU7gM2619pT82iGP" }, { "alphabet": "base58", "hex": "771b0c28608484562a292e5d5d2b30", "string": "4LGYeWhyfrjUByibUqdVR" }, { "alphabet": "base58", "hex": "78ff9a0e56f9e88dc1cd654b40d019", "string": "4PLggs66qAdbmZgkaPihe" }, { "alphabet": "base58", "hex": "6d691bdd736346aa5a0a95b373b2ab", "string": "44Y6qTgSvRMkdqpQ5ufkN" } ], "invalid": [ { "alphabet": "base58", "description": "non-base58 string", "exception": "^Error: Non-base58 character$", "string": "invalid" }, { "alphabet": "base58", "description": "non-base58 alphabet", "exception": "^Error: Non-base58 character$", "string": "c2F0b3NoaQo=" }, { "alphabet": "base58", "description": "leading whitespace", "exception": "^Error: Non-base58 character$", "string": " 1111111111" }, { "alphabet": "base58", "description": "trailing whitespace", "exception": "^Error: Non-base58 character$", "string": "1111111111 " }, { "alphabet": "base58", "description": "unexpected character after whitespace", "exception": "^Error: Non-base58 character$", "string": " \t\n\u000b\f\r skip \r\f\u000b\n\t a" } ] } base-x-0.2.11/src/alphabet.rs000064400000000000000000000027360072674642500140410ustar 00000000000000#[cfg(not(feature = "std"))] use alloc::{string::String, vec::Vec}; use DecodeError; use decoder::*; use encoder; pub trait Alphabet { fn encode(self, input: &[u8]) -> String; fn decode(self, input: &str) -> Result, DecodeError>; } impl<'a> Alphabet for &[u8] { #[inline(always)] fn encode(self, input: &[u8]) -> String { if !self.is_ascii() { panic!("Alphabet must be ASCII"); } let mut out = encoder::encode(self, input); out.reverse(); unsafe { String::from_utf8_unchecked(out) } } #[inline(always)] fn decode(self, input: &str) -> Result, DecodeError> { U8Decoder::new(self).decode(input) } } impl<'a> Alphabet for &str { #[inline(always)] fn encode(self, input: &[u8]) -> String { if self.is_ascii() { let mut out = encoder::encode(self.as_bytes(), input); out.reverse(); unsafe { String::from_utf8_unchecked(out) } } else { let alphabet: Vec = self.chars().collect(); let out = encoder::encode(&alphabet, input); out.iter().rev().collect() } } #[inline(always)] fn decode(self, input: &str) -> Result, DecodeError> { if self.is_ascii() { U8Decoder::new(self.as_bytes()).decode(input) } else { let alphabet: Vec = self.chars().collect(); CharDecoder(&alphabet).decode(input) } } } base-x-0.2.11/src/bigint.rs000064400000000000000000000120140072674642500135230ustar 00000000000000#[cfg(not(feature = "std"))] use alloc::vec::Vec; #[cfg(not(feature = "std"))] use core as std; use std::{ptr, u32}; /// This is a pretty naive implementation of a BigUint abstracting all /// math out to a vector of `u32` chunks. /// /// It can only do a few things: /// - Be instantiated from an arbitrary big-endian byte slice /// - Be converted to a vector of big-endian bytes. /// - Do a division by `u32`, mutating self and returning the remainder. /// - Do a multiplication with addition in one pass. /// - Check if it's zero. /// /// Turns out those are all the operations you need to encode and decode /// base58, or anything else, really. pub struct BigUint { pub chunks: Vec, } impl BigUint { #[inline] pub fn with_capacity(capacity: usize) -> Self { let mut chunks = Vec::with_capacity(capacity); chunks.push(0); BigUint { chunks } } /// Divide self by `divider`, return the remainder of the operation. #[inline] pub fn div_mod(&mut self, divider: u32) -> u32 { let mut carry = 0u64; for chunk in self.chunks.iter_mut() { carry = (carry << 32) | u64::from(*chunk); *chunk = (carry / u64::from(divider)) as u32; carry %= u64::from(divider); } if let Some(0) = self.chunks.get(0) { self.chunks.remove(0); } carry as u32 } /// Perform a multiplication followed by addition. This is a reverse /// of `div_mod` in the sense that when supplied remained for addition /// and the same base for multiplication as divison, the result is /// the original BigUint. #[inline] pub fn mul_add(&mut self, multiplicator: u32, addition: u32) { let mut carry = 0u64; { let mut iter = self.chunks.iter_mut().rev(); if let Some(chunk) = iter.next() { carry = u64::from(*chunk) * u64::from(multiplicator) + u64::from(addition); *chunk = carry as u32; carry >>= 32; } for chunk in iter { carry += u64::from(*chunk) * u64::from(multiplicator); *chunk = carry as u32; carry >>= 32; } } if carry > 0 { self.chunks.insert(0, carry as u32); } } /// Check if self is zero. #[inline] pub fn is_zero(&self) -> bool { self.chunks.iter().all(|chunk| *chunk == 0) } #[inline] pub fn into_bytes_be(mut self) -> Vec { let mut skip = 0; for chunk in self.chunks.iter() { if *chunk != 0 { skip += chunk.leading_zeros() / 8; break; } skip += 4; } let len = self.chunks.len() * 4 - skip as usize; if len == 0 { return Vec::new(); } for chunk in self.chunks.iter_mut() { *chunk = u32::to_be(*chunk); } let mut bytes = Vec::with_capacity(len); unsafe { bytes.set_len(len); let chunks_ptr = (self.chunks.as_ptr() as *const u8).offset(skip as isize); ptr::copy_nonoverlapping(chunks_ptr, bytes.as_mut_ptr(), len); } bytes } #[inline] pub fn from_bytes_be(bytes: &[u8]) -> Self { let modulo = bytes.len() % 4; let len = bytes.len() / 4 + (modulo > 0) as usize; let mut chunks = Vec::with_capacity(len); unsafe { chunks.set_len(len); let mut chunks_ptr = chunks.as_mut_ptr() as *mut u8; if modulo > 0 { *chunks.get_unchecked_mut(0) = 0u32; chunks_ptr = chunks_ptr.offset(4 - modulo as isize); } ptr::copy_nonoverlapping(bytes.as_ptr(), chunks_ptr, bytes.len()); } for chunk in chunks.iter_mut() { *chunk = u32::from_be(*chunk); } BigUint { chunks } } } #[cfg(test)] mod tests { #![allow(clippy::unreadable_literal)] use super::BigUint; #[test] fn big_uint_from_bytes() { let bytes: &[u8] = &[ 0xDE, 0xAD, 0x00, 0x00, 0x00, 0x13, 0x37, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, ]; let big = BigUint::from_bytes_be(bytes); assert_eq!( big.chunks, vec![0x0000DEAD, 0x00000013, 0x37AD0000, 0x0000DEAD] ); } #[test] fn big_uint_rem_div() { let mut big = BigUint { chunks: vec![0x136AD712, 0x84322759], }; let rem = big.div_mod(58); let merged = (u64::from(big.chunks[0]) << 32) | u64::from(big.chunks[1]); assert_eq!(merged, 0x136AD71284322759 / 58); assert_eq!(u64::from(rem), 0x136AD71284322759 % 58); } #[test] fn big_uint_add_mul() { let mut big = BigUint { chunks: vec![0x000AD712, 0x84322759], }; big.mul_add(58, 37); let merged = (u64::from(big.chunks[0]) << 32) | u64::from(big.chunks[1]); assert_eq!(merged, (0x000AD71284322759 * 58) + 37); } } base-x-0.2.11/src/decoder.rs000064400000000000000000000051540072674642500136630ustar 00000000000000#[cfg(not(feature = "std"))] use alloc::vec::Vec; #[cfg(not(feature = "std"))] use core as std; use bigint::BigUint; use DecodeError; pub(crate) trait Decoder<'a, 'b> where ::Item: std::cmp::PartialEq + Copy, { type Iter: std::iter::Iterator; fn iter(_: &'a str) -> Self::Iter; fn carry(&self, _: ::Item) -> Option; fn alphabet<'c>(&self) -> &'c [::Item] where 'b: 'c; fn decode(&self, input: &'a str) -> Result, DecodeError> { if input.is_empty() { return Ok(Vec::new()); } let alpha = self.alphabet(); let base = alpha.len() as u32; let mut big = BigUint::with_capacity(4); for c in Self::iter(input) { if let Some(carry) = self.carry(c) { big.mul_add(base, carry); } else { return Err(DecodeError); } } let mut bytes = big.into_bytes_be(); let leader = alpha[0]; let leaders = Self::iter(input).take_while(|byte| *byte == leader).count(); for _ in 0..leaders { bytes.insert(0, 0); } Ok(bytes) } } pub(crate) struct U8Decoder<'b> { alphabet: &'b [u8], lookup: [u8; 256], } impl<'a> U8Decoder<'a> { #[inline] pub(crate) fn new(alphabet: &'a [u8]) -> Self { const INVALID_INDEX: u8 = 0xFF; let mut lookup = [INVALID_INDEX; 256]; for (i, byte) in alphabet.iter().enumerate() { lookup[*byte as usize] = i as u8; } U8Decoder { alphabet, lookup } } } impl<'a, 'b> Decoder<'a, 'b> for U8Decoder<'b> { type Iter = std::str::Bytes<'a>; #[inline] fn iter(s: &'a str) -> Self::Iter { s.bytes() } #[inline] fn carry(&self, c: u8) -> Option { match self.lookup[c as usize] { 0xFF => None, index => Some(index.into()), } } #[inline] fn alphabet<'c>(&self) -> &'c [u8] where 'b: 'c, { self.alphabet } } pub(crate) struct CharDecoder<'b>(pub &'b [char]); impl<'a, 'b> Decoder<'a, 'b> for CharDecoder<'b> { type Iter = std::str::Chars<'a>; #[inline] fn iter(s: &'a str) -> Self::Iter { s.chars() } #[inline] fn carry(&self, c: char) -> Option { self.0 .iter() .enumerate() .find(|&(_, ch)| *ch == c) .map(|(i, _)| i as u32) } #[inline] fn alphabet<'c>(&self) -> &'c [char] where 'b: 'c, { self.0 } } base-x-0.2.11/src/encoder.rs000064400000000000000000000033310072674642500136700ustar 00000000000000#[cfg(not(feature = "std"))] use alloc::vec::Vec; use bigint::BigUint; pub(crate) fn encode(alpha: &[T], input: &[u8]) -> Vec where T: Copy, { if input.is_empty() { return Vec::new(); } let base = alpha.len() as u32; // Convert the input byte array to a BigUint let mut big = BigUint::from_bytes_be(input); let mut out = Vec::with_capacity(input.len()); // Find the highest power of `base` that fits in `u32` let big_pow = 32 / (32 - base.leading_zeros()); let big_base = base.pow(big_pow); 'fast: loop { // Instead of diving by `base`, we divide by the `big_base`, // giving us a bigger remainder that we can further subdivide // by the original `base`. This greatly (in case of base58 it's // a factor of 5) reduces the amount of divisions that need to // be done on BigUint, delegating the hard work to regular `u32` // operations, which are blazing fast. let mut big_rem = big.div_mod(big_base); if big.is_zero() { loop { let (result, remainder) = (big_rem / base, big_rem % base); out.push(alpha[remainder as usize]); big_rem = result; if big_rem == 0 { break 'fast; // teehee } } } else { for _ in 0..big_pow { let (result, remainder) = (big_rem / base, big_rem % base); out.push(alpha[remainder as usize]); big_rem = result; } } } let leaders = input .iter() .take(input.len() - 1) .take_while(|i| **i == 0) .map(|_| alpha[0]); out.extend(leaders); out } base-x-0.2.11/src/lib.rs000064400000000000000000000060050072674642500130200ustar 00000000000000//! # base_x //! //! Encode and decode any base alphabet. //! //! ## Installation //! //! Add this to `Cargo.toml` file: //! //! ```toml //! [dependencies] //! base-x = "0.2.0" //! ``` //! //! ## Usage //! //! ```rust //! extern crate base_x; //! //! fn main() { //! let decoded = base_x::decode("01", "11111111000000001111111100000000").unwrap(); //! let encoded = base_x::encode("01", &decoded); //! assert_eq!(encoded, "11111111000000001111111100000000"); //! } //! ``` #![cfg_attr(not(feature = "std"), no_std)] #[cfg(not(feature = "std"))] extern crate alloc; pub mod alphabet; mod bigint; pub mod decoder; pub mod encoder; pub use alphabet::Alphabet; #[cfg(not(feature = "std"))] use alloc::{string::String, vec::Vec}; #[cfg(not(feature = "std"))] use core as std; use std::fmt; #[derive(Debug)] pub struct DecodeError; impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Failed to decode the given data") } } #[cfg(feature = "std")] impl std::error::Error for DecodeError { fn description(&self) -> &str { "Can not decode the provided data" } } /// Encode an input vector using the given alphabet. pub fn encode(alphabet: A, input: &[u8]) -> String { alphabet.encode(input) } /// Decode an input vector using the given alphabet. pub fn decode(alphabet: A, input: &str) -> Result, DecodeError> { alphabet.decode(input) } #[cfg(test)] mod test { use super::decode; use super::encode; extern crate json; use self::json::parse; use std::fs::File; use std::io::Read; #[test] fn works() { let mut file = File::open("./fixtures/fixtures.json").unwrap(); let mut data = String::new(); file.read_to_string(&mut data).unwrap(); let json = parse(&data).unwrap(); let alphabets = &json["alphabets"]; for value in json["valid"].members() { let alphabet_name = value["alphabet"].as_str().unwrap(); let input = value["string"].as_str().unwrap(); let alphabet = alphabets[alphabet_name].as_str().unwrap(); // Alphabet works as unicode let decoded = decode(alphabet, input).unwrap(); let encoded = encode(alphabet, &decoded); assert_eq!(encoded, input); // Alphabet works as ASCII let decoded = decode(alphabet.as_bytes(), input).unwrap(); let encoded = encode(alphabet.as_bytes(), &decoded); assert_eq!(encoded, input); } } #[test] fn is_unicode_sound() { // binary, kinda... let alphabet = "😐😀"; let encoded = encode(alphabet, &[0xff, 0x00, 0xff, 0x00]); let decoded = decode(alphabet, &encoded).unwrap(); assert_eq!( encoded, "😀😀😀😀😀😀😀😀😐😐😐😐😐😐😐😐😀😀😀😀😀😀😀😀😐😐😐😐😐😐😐😐" ); assert_eq!(decoded, &[0xff, 0x00, 0xff, 0x00]); } }