Clean up challenge 1 for easier future use.
This commit is contained in:
17
src/main.rs
17
src/main.rs
@@ -1,20 +1,7 @@
|
|||||||
mod set1;
|
mod set1;
|
||||||
|
|
||||||
use crate::set1::{base64_to_string, bytes_to_base64, to_bytes};
|
use crate::set1::challenge1;
|
||||||
|
|
||||||
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),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
test_set1();
|
challenge1();
|
||||||
}
|
}
|
||||||
|
|||||||
173
src/set1.rs
173
src/set1.rs
@@ -1,65 +1,122 @@
|
|||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
pub fn to_bytes(s: &str) -> Result<Vec<u8>, String> {
|
pub struct HexBytes(Vec<u8>);
|
||||||
if s.len() % 2 != 0 {
|
pub struct Base64Bytes(Vec<u8>);
|
||||||
return Err(String::from("Input string has uneven number of characters"));
|
|
||||||
}
|
|
||||||
|
|
||||||
let bytes_result: Result<Vec<u8>, ParseIntError> = (0..s.len())
|
impl std::fmt::Display for Base64Bytes {
|
||||||
.step_by(2)
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
.map(|i| u8::from_str_radix(&s[i..i + 2], 16))
|
let Base64Bytes(digits) = self;
|
||||||
.collect();
|
let mut r: Vec<u8> = digits
|
||||||
|
.iter()
|
||||||
match bytes_result {
|
.map(|d| match d {
|
||||||
Ok(b) => Ok(b),
|
0..=25 => *d + ('A' as u8),
|
||||||
Err(_) => Err(String::from("Could not convert all digit pairs to hex.")),
|
26..=51 => *d - 26 + ('a' as u8),
|
||||||
}
|
52..=61 => *d - 52 + ('0' as u8),
|
||||||
}
|
62 => '+' as u8,
|
||||||
|
63 => '/' as u8,
|
||||||
fn chunk_to_base64(c: &[u8]) -> Vec<u8> {
|
_ => panic!("Unexpected base64 digit '{}'", d),
|
||||||
let (value, iterations) = match c.len() {
|
})
|
||||||
0 => return vec![],
|
.collect();
|
||||||
1 => ((c[0] as u32) << 16, 2),
|
// Handle padding
|
||||||
2 => ((c[0] as u32) << 16 | (c[1] as u32) << 8, 3),
|
let pad = '=' as u8;
|
||||||
3 => ((c[0] as u32) << 16 | (c[1] as u32) << 8 | (c[2] as u32), 4),
|
match r.len() % 4 {
|
||||||
_ => panic!("Unexpected number of chunks {}.", c.len()),
|
0 => (),
|
||||||
};
|
2 => {
|
||||||
(0..iterations)
|
r.push(pad);
|
||||||
.map(|i| (value.rotate_right((3 - i) * 6) & 0b111111) as u8)
|
r.push(pad);
|
||||||
.collect()
|
}
|
||||||
}
|
3 => r.push(pad),
|
||||||
|
_ => (),
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
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),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user