Compare commits
4 Commits
e400b87e9f
...
74e9959c6d
Author | SHA1 | Date | |
---|---|---|---|
74e9959c6d | |||
944a68c18c | |||
55bfa38d1c | |||
b2424c1fba |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
||||
/target
|
||||
site
|
||||
|
49
CLAUDE.md
Normal file
49
CLAUDE.md
Normal file
@ -0,0 +1,49 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a Rust implementation of the Cryptopal challenges - a collection of cryptography exercises. The codebase follows a workspace structure with individual problem solutions and shared utilities.
|
||||
|
||||
## Workspace Structure
|
||||
|
||||
- **Root workspace**: Defined in `Cargo.toml` with `edition = "2024"`
|
||||
- **Individual problems**: Located in `problems/p1/`, `problems/p2/`, etc. Each has its own `Cargo.toml` and `src/main.rs`
|
||||
- **Common utilities**: Located in `common/` crate with shared cryptographic functions like `is_valid_english()` and `xor_with_key()`
|
||||
- **Documentation**: `cryptopal_book/` contains mdBook documentation for each challenge
|
||||
|
||||
## Key Commands
|
||||
|
||||
### Building and Running
|
||||
- `cargo build` - Build the entire workspace
|
||||
- `cargo run -p p1` - Run a specific problem (e.g., problem 1)
|
||||
- `cargo build -p p1` - Build a specific problem
|
||||
- `cargo test` - Run tests across the workspace
|
||||
- `cargo check` - Quick syntax check without full compilation
|
||||
|
||||
### Documentation
|
||||
- `mdbook build cryptopal_book/` - Build the challenge documentation
|
||||
- `mdbook serve cryptopal_book/` - Serve documentation locally
|
||||
|
||||
## Architecture Notes
|
||||
|
||||
- Each problem is isolated in its own binary crate under `problems/`
|
||||
- Common cryptographic utilities are shared via the `common` crate
|
||||
- Problems use dependencies like `hex`, `base64`, and `anyhow` for encoding/error handling
|
||||
- Code includes Chinese comments for educational purposes
|
||||
- The `common` crate provides utilities for English text validation and XOR operations
|
||||
|
||||
## Dependencies Pattern
|
||||
|
||||
Individual problems typically use:
|
||||
- `hex` for hexadecimal encoding/decoding
|
||||
- `base64` for Base64 operations
|
||||
- `anyhow` for error handling (via common crate)
|
||||
- Local `common` crate for shared utilities
|
||||
|
||||
## Development Notes
|
||||
|
||||
- Each challenge solution should be self-contained in its respective `problems/pN/` directory
|
||||
- Use the `common` crate for shared cryptographic functions
|
||||
- Follow the existing pattern of having a simple `main.rs` that demonstrates the solution
|
169
Cargo.lock
generated
169
Cargo.lock
generated
@ -20,6 +20,12 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.1"
|
||||
@ -31,21 +37,53 @@ name = "common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"rand",
|
||||
"rand 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-deque"
|
||||
version = "0.8.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
|
||||
dependencies = [
|
||||
"crossbeam-epoch",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-epoch"
|
||||
version = "0.9.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "cryptopal_rs"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.16"
|
||||
name = "either"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi",
|
||||
]
|
||||
|
||||
@ -69,7 +107,7 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -118,7 +156,7 @@ name = "p11"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"common",
|
||||
"rand",
|
||||
"rand 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -128,7 +166,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"common",
|
||||
"rand",
|
||||
"rand 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -146,7 +184,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"common",
|
||||
"rand",
|
||||
"rand 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -167,6 +205,22 @@ version = "0.1.0"
|
||||
[[package]]
|
||||
name = "p18"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"common",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p19"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"common",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p2"
|
||||
@ -175,6 +229,37 @@ dependencies = [
|
||||
"hex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p20"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "p21"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "p22"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"common",
|
||||
"rand 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p23"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rand 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "p24"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "p28"
|
||||
version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "p3"
|
||||
version = "0.1.0"
|
||||
@ -191,7 +276,7 @@ dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
"once_cell",
|
||||
"rand",
|
||||
"rand 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -270,25 +355,39 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||
dependencies = [
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -296,10 +395,36 @@ name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.103"
|
||||
@ -319,9 +444,21 @@ checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.1+wasi-snapshot-preview1"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
|
@ -10,7 +10,8 @@ members = ["problems/*", "common"]
|
||||
hex = "0.4.3"
|
||||
base64 = "0.22.1"
|
||||
anyhow = "1.0.98"
|
||||
rand = "0.8"
|
||||
rand = "0.9"
|
||||
num-bigint = { version = "0.4", features = ["rand"] }
|
||||
num-traits = "0.2"
|
||||
once_cell = "1.21"
|
||||
rayon = "1.11.0"
|
||||
|
@ -482,3 +482,67 @@ pub fn gen_random_key() -> [u8; 16] {
|
||||
rng.fill(&mut key);
|
||||
key
|
||||
}
|
||||
|
||||
pub fn aes_ctr_enc(input: &[u8], key: &[u8; 16], nonce: u64) -> Result<Vec<u8>> {
|
||||
let mut key_stream = Vec::new();
|
||||
for round in 0..=(input.len() / 16) as u64 {
|
||||
let input: Vec<u8> = nonce
|
||||
.to_le_bytes()
|
||||
.into_iter()
|
||||
.chain(round.to_le_bytes())
|
||||
.collect();
|
||||
let stream_block = aes_ecb_enc(&input, key)?;
|
||||
key_stream.extend(stream_block);
|
||||
}
|
||||
let output: Vec<u8> = input.iter().zip(key_stream).map(|(&a, b)| a ^ b).collect();
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
pub fn aes_ctr_dec(input: &[u8], key: &[u8; 16], nonce: u64) -> Result<Vec<u8>> {
|
||||
aes_ctr_enc(input, key, nonce)
|
||||
}
|
||||
|
||||
pub struct MT19937 {
|
||||
mt: [u32; 624],
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl MT19937 {
|
||||
pub fn new(seed: u32) -> Self {
|
||||
let mut mt = [0; 624];
|
||||
mt[0] = seed;
|
||||
for i in 1..624 {
|
||||
mt[i] = 0x6c078965u32
|
||||
.wrapping_mul(mt[i - 1] ^ (mt[i - 1] >> 30))
|
||||
.wrapping_add(i as u32)
|
||||
}
|
||||
let index = 0;
|
||||
MT19937 { mt, index }
|
||||
}
|
||||
|
||||
pub fn extract_number(&mut self) -> u32 {
|
||||
if self.index == 0 {
|
||||
self.generate_numbers();
|
||||
}
|
||||
let mut result = self.mt[self.index];
|
||||
|
||||
result ^= result >> 11;
|
||||
result ^= (result << 7) & 0x9d2c5680;
|
||||
result ^= (result << 15) & 0xefc60000;
|
||||
result ^= result >> 18;
|
||||
self.index = (self.index + 1) % 624;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn generate_numbers(&mut self) {
|
||||
for i in 0..624 {
|
||||
let y: u32 = (self.mt[i] & 0x80000000) + (self.mt[(i + 1) % 624] & 0x7fffffff);
|
||||
self.mt[i] = self.mt[(i + 397) % 624] ^ (y >> 1);
|
||||
if y % 2 != 0 {
|
||||
self.mt[i] ^= 0x9908b0df;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,3 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
common = { path = "../../common" }
|
||||
rand = { workspace = true }
|
||||
base64 = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
|
@ -1,3 +1,96 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use std::process::exit;
|
||||
|
||||
use anyhow::Result;
|
||||
use base64::{Engine, engine::general_purpose::STANDARD};
|
||||
use common::{aes_ecb_enc, gen_random_key, pkcs7_padding};
|
||||
use rand::random;
|
||||
|
||||
fn oracle(
|
||||
unknown_prefix: &[u8],
|
||||
controlled_input: &[u8],
|
||||
key: &[u8; 16],
|
||||
unknown_string: &[u8],
|
||||
) -> Vec<u8> {
|
||||
let mut data = Vec::new();
|
||||
data.extend_from_slice(unknown_prefix);
|
||||
data.extend_from_slice(controlled_input);
|
||||
data.extend_from_slice(unknown_string);
|
||||
|
||||
pkcs7_padding(&mut data, 16);
|
||||
|
||||
aes_ecb_enc(&data, key).unwrap()
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let b64_unknown_string = "Um9sbGluJyBpbiBteSA1LjAKV2l0aCBteSByYWctdG9wIGRvd24gc28gbXkgaGFpciBjYW4gYmxvdwpUaGUgZ2lybGllcyBvbiBzdGFuZGJ5IHdhdmluZyBqdXN0IHRvIHNheSBoaQpEaWQgeW91IHN0b3A/IE5vLCBJIGp1c3QgZHJvdmUgYnkK";
|
||||
let unknown_string = STANDARD.decode(b64_unknown_string)?;
|
||||
let key = gen_random_key();
|
||||
|
||||
let prefix_len = random::<u8>();
|
||||
let unknown_prefix = vec![6u8; prefix_len as usize];
|
||||
|
||||
// step1. find padding length and unknown_string length.
|
||||
let mut padding_len = 0;
|
||||
|
||||
let prev_cipher = oracle(
|
||||
&unknown_prefix,
|
||||
&vec![0; padding_len],
|
||||
&key,
|
||||
&unknown_string,
|
||||
);
|
||||
while prev_cipher.len() + 16
|
||||
!= oracle(
|
||||
&unknown_prefix,
|
||||
&vec![0; padding_len],
|
||||
&key,
|
||||
&unknown_string,
|
||||
)
|
||||
.len()
|
||||
{
|
||||
padding_len += 1;
|
||||
}
|
||||
println!("padding_len: {padding_len}"); // 6
|
||||
let unknown_str_len = prev_cipher.len() - padding_len;
|
||||
println!("unknown_str_len: {unknown_str_len}");
|
||||
|
||||
assert_eq!(unknown_str_len, unknown_string.len()); // debug use
|
||||
|
||||
let mut cracked: Vec<u8> = Vec::new();
|
||||
|
||||
let mut flag = false;
|
||||
|
||||
while cracked.len() != unknown_str_len {
|
||||
padding_len += 1;
|
||||
for i in 0..=255u8 {
|
||||
let mut block = Vec::new();
|
||||
block.push(i);
|
||||
block.extend_from_slice(&cracked[..cracked.len().min(15)]);
|
||||
|
||||
pkcs7_padding(&mut block, 16);
|
||||
block.extend(b"1".repeat(padding_len));
|
||||
let cipher = oracle(&unknown_prefix, &block, &key, &unknown_string);
|
||||
|
||||
let chunks: Vec<&[u8]> = cipher.chunks(16).collect();
|
||||
let first_16 = chunks[0];
|
||||
let need_crack_16 = chunks[chunks.len() - 1 - ((cracked.len() + 1) / 16)];
|
||||
if first_16 == need_crack_16 {
|
||||
cracked.insert(0, i);
|
||||
flag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if flag {
|
||||
flag = false;
|
||||
} else {
|
||||
println!("Error. Some byte not found.");
|
||||
println!("Cerrent length: {}", cracked.len());
|
||||
exit(0)
|
||||
}
|
||||
}
|
||||
println!("{}", String::from_utf8_lossy(&cracked));
|
||||
// println!("{}", String::from_utf8_lossy(&plaintext));
|
||||
assert_eq!(cracked, unknown_string);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use anyhow::{Result, anyhow};
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn pkcs7_unpadding(input: &[u8]) -> Result<Vec<u8>> {
|
||||
if input.is_empty() {
|
||||
return Err(anyhow!("Input cannot be empty"));
|
||||
|
@ -4,3 +4,7 @@ version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
common = { path = "../../common" }
|
||||
base64 = { workspace = true }
|
||||
rayon = { workspace = true }
|
||||
|
@ -1,3 +1,42 @@
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
use anyhow::Result;
|
||||
use base64::{Engine as _, engine::general_purpose::STANDARD};
|
||||
use rayon::prelude::*;
|
||||
|
||||
use common::aes_ecb_enc;
|
||||
|
||||
fn aes_ctr_enc(input: &[u8], key: &[u8; 16], nonce: u64) -> Result<Vec<u8>> {
|
||||
let mut key_stream = Vec::new();
|
||||
for round in 0..=(input.len() / 16) as u64 {
|
||||
let input: Vec<u8> = nonce
|
||||
.to_le_bytes()
|
||||
.into_iter()
|
||||
.chain(round.to_le_bytes())
|
||||
.collect();
|
||||
let stream_block = aes_ecb_enc(&input, key)?;
|
||||
key_stream.extend(stream_block);
|
||||
}
|
||||
let output: Vec<u8> = input
|
||||
.par_iter()
|
||||
.zip(key_stream)
|
||||
.map(|(&a, b)| a ^ b)
|
||||
.collect();
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
fn aes_ctr_dec(input: &[u8], key: &[u8; 16], nonce: u64) -> Result<Vec<u8>> {
|
||||
aes_ctr_enc(input, key, nonce)
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let cipher = STANDARD
|
||||
.decode("L77na/nrFsKvynd6HzOoG7GHTLXsTVu9qvY/2syLXzhPweyyMTJULu/6/kXX0KSvoOLSFQ==")?;
|
||||
|
||||
let key: [u8; 16] = "YELLOW SUBMARINE".as_bytes().try_into()?;
|
||||
|
||||
let plain = aes_ctr_dec(&cipher, &key, 0)?;
|
||||
let plain = String::from_utf8(plain)?;
|
||||
println!("{plain}");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
6
problems/p21/Cargo.toml
Normal file
6
problems/p21/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
||||
[package]
|
||||
name = "p21"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
8
problems/p21/src/main.cpp
Normal file
8
problems/p21/src/main.cpp
Normal file
@ -0,0 +1,8 @@
|
||||
#include <iostream>
|
||||
#include <random>
|
||||
|
||||
int main() {
|
||||
std::mt19937 gen(12345);
|
||||
std::cout << gen() << std::endl; // 第一个输出
|
||||
return 0;
|
||||
}
|
93
problems/p21/src/main.rs
Normal file
93
problems/p21/src/main.rs
Normal file
@ -0,0 +1,93 @@
|
||||
// //創建一個長度為624的數組來存儲發生器的狀態
|
||||
// int[0..623] MT
|
||||
// int index = 0
|
||||
//
|
||||
// //初始化產生器,種子作為首項內容
|
||||
// function initialize_generator(int seed) {
|
||||
// i := 0
|
||||
// MT[0] := seed
|
||||
// for i from 1 to 623 { // 走訪剩下的每個元素
|
||||
// MT[i] := last 32 bits of(1812433253 * (MT[i-1] xor (right shift by 30 bits(MT[i-1]))) + i) // 1812433253 == 0x6c078965
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // Extract a tempered pseudorandom number based on the index-th value,
|
||||
// // calling generate_numbers() every 624 numbers
|
||||
// function extract_number() {
|
||||
// if index == 0 {
|
||||
// generate_numbers()
|
||||
// }
|
||||
//
|
||||
// int y := MT[index]
|
||||
// y := y xor (right shift by 11 bits(y))
|
||||
// y := y xor (left shift by 7 bits(y) and (2636928640)) // 2636928640 == 0x9d2c5680
|
||||
// y := y xor (left shift by 15 bits(y) and (4022730752)) // 4022730752 == 0xefc60000
|
||||
// y := y xor (right shift by 18 bits(y))
|
||||
//
|
||||
// index := (index + 1) mod 624
|
||||
// return y
|
||||
// }
|
||||
//
|
||||
// // Generate an array of 624 untempered numbers
|
||||
// function generate_numbers() {
|
||||
// for i from 0 to 623 {
|
||||
// int y := (MT[i] & 0x80000000) // bit 31 (32nd bit) of MT[i]
|
||||
// + (MT[(i+1) mod 624] & 0x7fffffff) // bits 0-30 (first 31 bits) of MT[...]
|
||||
// MT[i] := MT[(i + 397) mod 624] xor (right shift by 1 bit(y))
|
||||
// if (y mod 2) != 0 { // y is odd
|
||||
// MT[i] := MT[i] xor (2567483615) // 2567483615 == 0x9908b0df
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
struct MT19937 {
|
||||
mt: [u32; 624],
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl MT19937 {
|
||||
fn new(seed: u32) -> Self {
|
||||
let mut mt = [0; 624];
|
||||
mt[0] = seed;
|
||||
for i in 1..624 {
|
||||
mt[i] = 0x6c078965u32
|
||||
.wrapping_mul(mt[i - 1] ^ (mt[i - 1] >> 30))
|
||||
.wrapping_add(i as u32)
|
||||
}
|
||||
let index = 0;
|
||||
MT19937 { mt, index }
|
||||
}
|
||||
|
||||
fn extract_number(&mut self) -> u32 {
|
||||
if self.index == 0 {
|
||||
self.generate_numbers();
|
||||
}
|
||||
let mut result = self.mt[self.index];
|
||||
|
||||
result ^= result >> 11;
|
||||
result ^= (result << 7) & 0x9d2c5680;
|
||||
result ^= (result << 15) & 0xefc60000;
|
||||
result ^= result >> 18;
|
||||
self.index = (self.index + 1) % 624;
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn generate_numbers(&mut self) {
|
||||
for i in 0..624 {
|
||||
let y: u32 = (self.mt[i] & 0x80000000) + (self.mt[(i + 1) % 624] & 0x7fffffff);
|
||||
self.mt[i] = self.mt[(i + 397) % 624] ^ (y >> 1);
|
||||
if y % 2 != 0 {
|
||||
self.mt[i] ^= 0x9908b0df;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// use C++ std::mt19937 to verify.
|
||||
let mut mt19937 = MT19937::new(12345);
|
||||
let result = mt19937.extract_number();
|
||||
|
||||
println!("{result}");
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user