base-x-0.2.3/.gitignore010064400017500001750000000000221333771173300131060ustar0000000000000000target Cargo.lock base-x-0.2.3/.travis.yml010064400017500001750000000001421333771173300132320ustar0000000000000000language: rust rust: - stable - beta - nightly matrix: allow_failures: - rust: nightlybase-x-0.2.3/Cargo.toml.orig010064400017500001750000000006701333771227300140160ustar0000000000000000[package] name = "base-x" description = "Encode/decode any base" version = "0.2.3" authors = ["Alex R. "] license = "MIT" license-file = "LICENSE.md" readme = "README.md" keywords = ["base-x", "base", "convert"] repository = "https://github.com/OrKoN/base-x-rs" homepage = "https://github.com/OrKoN/base-x-rs" [dev-dependencies] json = "0.11" bencher = "0.1" rand = "0.3" [[bench]] name = "base" harness = false base-x-0.2.3/Cargo.toml0000644000000020030000000000000102450ustar00# 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 believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "base-x" version = "0.2.3" authors = ["Alex R. "] description = "Encode/decode any base" homepage = "https://github.com/OrKoN/base-x-rs" readme = "README.md" keywords = ["base-x", "base", "convert"] license = "MIT" license-file = "LICENSE.md" repository = "https://github.com/OrKoN/base-x-rs" [[bench]] name = "base" harness = false [dev-dependencies.bencher] version = "0.1" [dev-dependencies.json] version = "0.11" [dev-dependencies.rand] version = "0.3" base-x-0.2.3/LICENSE.md010064400017500001750000000021211333771173300125240ustar0000000000000000The 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.3/README.md010064400017500001750000000015471333771173300124120ustar0000000000000000# 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 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.3/benches/base.rs010064400017500001750000000031751333771173300140210ustar0000000000000000#[macro_use] extern crate bencher; extern crate rand; extern crate base_x; use bencher::Bencher; use base_x::{encode, decode, Alphabet}; 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: &'static str = "01"; test_encode(bench, ALPH); } fn encode_base16(bench: &mut Bencher) { const ALPH: &'static str = "0123456789abcdef"; test_encode(bench, ALPH); } fn encode_base58(bench: &mut Bencher) { const ALPH: &'static str = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; test_encode(bench, ALPH); } // Decode UTF-8 fn decode_base2(bench: &mut Bencher) { const ALPH: &'static str = "01"; test_decode(bench, ALPH); } fn decode_base16(bench: &mut Bencher) { const ALPH: &'static str = "0123456789abcdef"; test_decode(bench, ALPH); } fn decode_base58(bench: &mut Bencher) { const ALPH: &'static 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.3/fixtures/fixtures.json010064400017500001750000000322541333771173300155470ustar0000000000000000{ "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.3/src/alphabet.rs010064400017500001750000000025101333771173300140370ustar0000000000000000use encoder::{AsciiEncoder, Utf8Encoder}; use decoder::{AsciiDecoder, Utf8Decoder}; use DecodeError; use std::ascii::AsciiExt; const INVALID_INDEX: u8 = 0xFF; pub trait Alphabet { fn encode(&self, input: &[u8]) -> String; fn decode(&self, input: &str) -> Result, DecodeError>; } impl<'a> Alphabet for &'a [u8] { #[inline(always)] fn encode(&self, input: &[u8]) -> String { AsciiEncoder::encode(*self, input) } #[inline(always)] fn decode(&self, input: &str) -> Result, DecodeError> { let mut lookup = [INVALID_INDEX; 256]; for (i, byte) in self.iter().enumerate() { lookup[*byte as usize] = i as u8; } AsciiDecoder::decode(*self, lookup, input) } } impl<'a> Alphabet for &'a str { #[inline(always)] fn encode(&self, input: &[u8]) -> String { if self.is_ascii() { return self.as_bytes().encode(input); } let alphabet: Vec = self.chars().collect(); Utf8Encoder::encode(&alphabet, input) } #[inline(always)] fn decode(&self, input: &str) -> Result, DecodeError> { if self.is_ascii() { return self.as_bytes().decode(input); } let alphabet: Vec = self.chars().collect(); Utf8Decoder::decode(&alphabet, input) } } base-x-0.2.3/src/bigint.rs010064400017500001750000000115751333771173300135460ustar0000000000000000use 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: 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) | *chunk as u64; *chunk = (carry / divider as u64) as u32; carry %= divider as u64; } if self.chunks[0] == 0 && self.chunks.len() > 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 = (*chunk as u64 * multiplicator as u64) + addition as u64; *chunk = carry as u32; carry >>= 32; } for chunk in iter { carry += *chunk as u64 * multiplicator as u64; *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); } unsafe { let mut bytes = Vec::with_capacity(len); 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: chunks } } } #[cfg(test)] mod tests { 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 = ((big.chunks[0] as u64) << 32) | big.chunks[1] as u64; assert_eq!(merged, 0x136AD71284322759 / 58); assert_eq!(rem as u64, 0x136AD71284322759 % 58); } #[test] fn big_uint_add_mul() { let mut big = BigUint { chunks: vec![0x000AD712,0x84322759] }; big.mul_add(58, 37); let merged = ((big.chunks[0] as u64) << 32) | big.chunks[1] as u64; assert_eq!(merged, (0x000AD71284322759 * 58) + 37); } } base-x-0.2.3/src/decoder.rs010064400017500001750000000031021333771173300136620ustar0000000000000000use DecodeError; use bigint::BigUint; pub struct AsciiDecoder; pub struct Utf8Decoder; macro_rules! decode { ($alpha:ident, $input:ident, $iter:ident, $c:pat => $carry:expr) => ({ if $input.len() == 0 { return Ok(Vec::new()); } let base = $alpha.len() as u32; let mut big = BigUint::with_capacity(4); for $c in $input.$iter() { big.mul_add(base, $carry as u32); } let mut bytes = big.into_bytes_be(); let leader = $alpha[0]; let leaders = $input .$iter() .take_while(|byte| *byte == leader) .count(); for _ in 0..leaders { bytes.insert(0, 0); } Ok(bytes) }) } impl AsciiDecoder { #[inline(always)] pub fn decode(alphabet: &[u8], lookup: [u8; 256], input: &str) -> Result, DecodeError> { decode!( alphabet, input, bytes, c => match lookup[c as usize] { 0xFF => return Err(DecodeError), index => index } ) } } impl Utf8Decoder { #[inline(always)] pub fn decode(alphabet: &[char], input: &str) -> Result, DecodeError> { decode!( alphabet, input, chars, // Vector find is faster than HashMap even for Base58 c => alphabet .iter() .enumerate() .find(|&(_, ch)| *ch == c) .map(|(i, _)| i) .ok_or(DecodeError)? ) } } base-x-0.2.3/src/encoder.rs010064400017500001750000000042701333771173300137030ustar0000000000000000use bigint::BigUint; pub struct AsciiEncoder; pub struct Utf8Encoder; macro_rules! encode { ($alpha:ident, $input:ident) => ({ if $input.len() == 0 { return String::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 { out.push($alpha[(big_rem % base) as usize]); big_rem /= base; if big_rem == 0 { break 'fast; // teehee } } } else { for _ in 0..big_pow { out.push($alpha[(big_rem % base) as usize]); big_rem /= base; } } } let leaders = $input .iter() .take($input.len() - 1) .take_while(|i| **i == 0) .map(|_| $alpha[0]); out.extend(leaders); out }) } impl AsciiEncoder { #[inline(always)] pub fn encode(alphabet: &[u8], input: &[u8]) -> String { let mut out = encode!(alphabet, input); out.reverse(); String::from_utf8(out).expect("Alphabet must be ASCII") } } impl Utf8Encoder { #[inline(always)] pub fn encode(alphabet: &[char], input: &[u8]) -> String { let out = encode!(alphabet, input); out.iter().rev().map(|char| *char).collect() } } base-x-0.2.3/src/lib.rs010064400017500001750000000055321333771173300130340ustar0000000000000000//! # 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"); //! } //! ``` mod bigint; pub mod decoder; pub mod encoder; pub mod alphabet; pub use decoder::{AsciiDecoder, Utf8Decoder}; pub use encoder::{AsciiEncoder, Utf8Encoder}; pub use alphabet::Alphabet; use std::error::Error; 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") } } impl 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::encode; use super::decode; 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]); } }