use base64::{
engine::general_purpose::{STANDARD, STANDARD_NO_PAD, URL_SAFE, URL_SAFE_NO_PAD},
Engine as _,
};
use bech32::{Bech32, Hrp};
use const_decoder::{decode, Decoder, Pem};
use rand::{thread_rng, RngCore};
#[test]
fn reading_from_file_works() {
const RAW_INPUT: &[u8] = include_bytes!("certificate.crt");
const CERT: &[u8] = &decode!(Pem, RAW_INPUT);
let parsed = pem::parse(RAW_INPUT).unwrap();
assert_eq!(CERT, parsed.contents());
}
fn fuzz_hex_decoder<const N: usize>(samples: usize) {
const CUSTOM_HEX: Decoder = Decoder::custom("0123456789abcdef");
let mut rng = thread_rng();
for _ in 0..samples {
let mut bytes = [0_u8; N];
rng.fill_bytes(&mut bytes);
let encoded = hex::encode(bytes);
let decoded = Decoder::Hex.decode::<N>(encoded.as_bytes());
assert_eq!(decoded, bytes);
let decoded_custom = CUSTOM_HEX.decode::<N>(encoded.as_bytes());
assert_eq!(decoded_custom, bytes);
let encoded_upper_case = hex::encode_upper(bytes);
let decoded_upper_case = Decoder::Hex.decode::<N>(encoded_upper_case.as_bytes());
assert_eq!(decoded_upper_case, bytes);
}
}
#[test]
fn hex_decoder_mini_fuzz() {
fuzz_hex_decoder::<1>(50);
fuzz_hex_decoder::<8>(10_000);
fuzz_hex_decoder::<16>(10_000);
fuzz_hex_decoder::<64>(10_000);
fuzz_hex_decoder::<1024>(10_000);
}
fn fuzz_base64_decoder<const N: usize>(samples: usize) {
let mut rng = thread_rng();
for _ in 0..samples {
let mut bytes = [0_u8; N];
rng.fill_bytes(&mut bytes);
let encoded = STANDARD.encode(bytes);
let decoded = Decoder::Base64.decode::<N>(encoded.as_bytes());
assert_eq!(decoded, bytes);
let encoded_no_pad = STANDARD_NO_PAD.encode(bytes);
let decoded_no_pad = Decoder::Base64.decode::<N>(encoded_no_pad.as_bytes());
assert_eq!(decoded_no_pad, bytes);
}
}
#[test]
fn base64_decoder_mini_fuzz() {
fuzz_base64_decoder::<1>(50);
fuzz_base64_decoder::<8>(10_000);
fuzz_base64_decoder::<16>(10_000);
fuzz_base64_decoder::<24>(10_000);
fuzz_base64_decoder::<64>(10_000);
fuzz_base64_decoder::<1024>(10_000);
}
fn fuzz_base64url_decoder<const N: usize>(samples: usize) {
let mut rng = thread_rng();
for _ in 0..samples {
let mut bytes = [0_u8; N];
rng.fill_bytes(&mut bytes);
let encoded = URL_SAFE.encode(bytes);
let decoded = Decoder::Base64Url.decode::<N>(encoded.as_bytes());
assert_eq!(decoded, bytes);
let encoded_no_pad = URL_SAFE_NO_PAD.encode(bytes);
let decoded_no_pad = Decoder::Base64Url.decode::<N>(encoded_no_pad.as_bytes());
assert_eq!(decoded_no_pad, bytes);
}
}
#[test]
fn base64url_decoder_mini_fuzz() {
fuzz_base64url_decoder::<1>(50);
fuzz_base64url_decoder::<8>(10_000);
fuzz_base64url_decoder::<16>(10_000);
fuzz_base64url_decoder::<24>(10_000);
fuzz_base64url_decoder::<64>(10_000);
fuzz_base64url_decoder::<1024>(10_000);
}
const BECH32: Decoder = Decoder::custom("qpzry9x8gf2tvdw0s3jn54khce6mua7l");
fn fuzz_bech32_decoder<const N: usize>(samples: usize) {
let mut rng = thread_rng();
for _ in 0..samples {
let mut bytes = [0_u8; N];
rng.fill_bytes(&mut bytes);
let hrp = Hrp::parse("bc").unwrap();
let encoded = bech32::encode::<Bech32>(hrp, &bytes).unwrap();
let data_part = &encoded.as_bytes()[3..(encoded.len() - 6)];
let decoded = BECH32.decode::<N>(data_part);
assert_eq!(decoded, bytes);
}
}
#[test]
fn bech32_decoder_mini_fuzz() {
fuzz_bech32_decoder::<1>(50);
fuzz_bech32_decoder::<8>(10_000);
fuzz_bech32_decoder::<16>(10_000);
fuzz_bech32_decoder::<24>(10_000);
fuzz_bech32_decoder::<64>(10_000);
}