Clean up challenge 1 for easier future use.

This commit is contained in:
2022-03-25 18:57:16 -04:00
parent fcf882991c
commit 4a077ade98
2 changed files with 117 additions and 73 deletions

View File

@@ -1,20 +1,7 @@
mod set1;
use crate::set1::{base64_to_string, bytes_to_base64, to_bytes};
fn test_set1() {
let input = to_bytes("49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d");
let expected = String::from("SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t");
match input {
Ok(bytes) => {
let output = base64_to_string(bytes_to_base64(bytes));
assert_eq!(output, expected);
println!("{:?}", output);
}
Err(e) => println!("Error: {:?}", e),
};
}
use crate::set1::challenge1;
fn main() {
test_set1();
challenge1();
}

View File

@@ -1,65 +1,122 @@
use std::num::ParseIntError;
use std::str;
pub fn to_bytes(s: &str) -> Result<Vec<u8>, String> {
if s.len() % 2 != 0 {
return Err(String::from("Input string has uneven number of characters"));
}
pub struct HexBytes(Vec<u8>);
pub struct Base64Bytes(Vec<u8>);
let bytes_result: Result<Vec<u8>, ParseIntError> = (0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16))
.collect();
match bytes_result {
Ok(b) => Ok(b),
Err(_) => Err(String::from("Could not convert all digit pairs to hex.")),
}
}
fn chunk_to_base64(c: &[u8]) -> Vec<u8> {
let (value, iterations) = match c.len() {
0 => return vec![],
1 => ((c[0] as u32) << 16, 2),
2 => ((c[0] as u32) << 16 | (c[1] as u32) << 8, 3),
3 => ((c[0] as u32) << 16 | (c[1] as u32) << 8 | (c[2] as u32), 4),
_ => panic!("Unexpected number of chunks {}.", c.len()),
};
(0..iterations)
.map(|i| (value.rotate_right((3 - i) * 6) & 0b111111) as u8)
.collect()
}
pub fn bytes_to_base64(bytes: Vec<u8>) -> Vec<u8> {
bytes
.chunks(3)
.map(|c| chunk_to_base64(c))
.flatten()
.collect()
}
pub fn base64_to_string(digits: Vec<u8>) -> String {
let mut r: Vec<u8> = digits
.iter()
.map(|d| match d {
0..=25 => *d + ('A' as u8),
26..=51 => *d - 26 + ('a' as u8),
52..=61 => *d - 52 + ('0' as u8),
62 => '+' as u8,
63 => '/' as u8,
_ => panic!("Unexpected base64 digit '{}'", d),
})
.collect();
// Handle padding
let pad = '=' as u8;
match r.len() % 4 {
0 => (),
2 => {
r.push(pad);
r.push(pad);
impl std::fmt::Display for Base64Bytes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Base64Bytes(digits) = self;
let mut r: Vec<u8> = digits
.iter()
.map(|d| match d {
0..=25 => *d + ('A' as u8),
26..=51 => *d - 26 + ('a' as u8),
52..=61 => *d - 52 + ('0' as u8),
62 => '+' as u8,
63 => '/' as u8,
_ => panic!("Unexpected base64 digit '{}'", d),
})
.collect();
// Handle padding
let pad = '=' as u8;
match r.len() % 4 {
0 => (),
2 => {
r.push(pad);
r.push(pad);
}
3 => r.push(pad),
_ => (),
}
3 => r.push(pad),
_ => (),
write!(f, "Base64({})", str::from_utf8(r.as_slice()).unwrap())
}
str::from_utf8(r.as_slice()).unwrap().to_string()
}
impl Base64Bytes {
pub fn to_string(&self) -> String {
let Base64Bytes(digits) = self;
let mut r: Vec<u8> = digits
.iter()
.map(|d| match d {
0..=25 => *d + ('A' as u8),
26..=51 => *d - 26 + ('a' as u8),
52..=61 => *d - 52 + ('0' as u8),
62 => '+' as u8,
63 => '/' as u8,
_ => panic!("Unexpected base64 digit '{}'", d),
})
.collect();
// Handle padding
let pad = '=' as u8;
match r.len() % 4 {
0 => (),
2 => {
r.push(pad);
r.push(pad);
}
3 => r.push(pad),
_ => (),
}
str::from_utf8(r.as_slice()).unwrap().to_string()
}
}
impl HexBytes {
pub fn to_base64(&self) -> Base64Bytes {
fn chunk_to_base64(c: &[u8]) -> Vec<u8> {
let (value, iterations) = match c.len() {
0 => return vec![],
1 => ((c[0] as u32) << 16, 2),
2 => ((c[0] as u32) << 16 | (c[1] as u32) << 8, 3),
3 => ((c[0] as u32) << 16 | (c[1] as u32) << 8 | (c[2] as u32), 4),
_ => panic!("Unexpected number of chunks {}.", c.len()),
};
(0..iterations)
.map(|i| (value.rotate_right((3 - i) * 6) & 0b111111) as u8)
.collect()
}
let HexBytes(bytes) = self;
Base64Bytes(
bytes
.chunks(3)
.map(|c| chunk_to_base64(c))
.flatten()
.collect(),
)
}
pub fn from_str(s: &str) -> Result<HexBytes, String> {
if s.len() % 2 != 0 {
return Err(String::from("Input string has uneven number of characters"));
}
let bytes_result: Result<Vec<u8>, ParseIntError> = (0..s.len())
.step_by(2)
.map(|i| u8::from_str_radix(&s[i..i + 2], 16))
.collect();
match bytes_result {
Ok(b) => Ok(HexBytes(b)),
Err(_) => Err(String::from("Could not convert all digit pairs to hex.")),
}
}
}
pub fn challenge1() {
let input = HexBytes::from_str("49276d206b696c6c696e6720796f757220627261696e206c696b65206120706f69736f6e6f7573206d757368726f6f6d");
let expected = String::from("SSdtIGtpbGxpbmcgeW91ciBicmFpbiBsaWtlIGEgcG9pc29ub3VzIG11c2hyb29t");
match input {
Ok(bytes) => {
let output = bytes.to_base64();
if output.to_string() != expected {
println!("HexBytes.to_base64 failed.")
} else {
println!("[okay] Challenge 1: {}", output);
}
}
Err(e) => println!("Error: {}", e),
};
}