Skip to content

Commit

Permalink
added parallel processing sample (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheroz committed Aug 18, 2023
1 parent d4d5a74 commit 3479f83
Show file tree
Hide file tree
Showing 15 changed files with 213 additions and 38 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to this project will be documented in this file.

## 0.8.2 (2023-08-19)

- Added sample for buffer encryption by parallel processing
- Updated documentation

## 0.8.1 (2023-08-17)

- Added bitmap encryption sample
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Please look at [magma_samples](https://github.com/sheroz/magma/tree/main/magma_s
- Text encryption [encrypt_text.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_text.rs)
- Message Authentication Code (MAC) [calculate_mac.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/calculate_mac.rs)
- Buffer encryption [encrypt_buffer.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_buffer.rs)
- Buffer encryption by parallel processing [encrypt_buffer_parallel.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_buffer_parallel.rs)
- File encryption [encrypt_file.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_file.rs)
- Bitmap file encryption [encrypt_bmp.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_bmp.rs)

Expand Down
5 changes: 5 additions & 0 deletions cipher_magma/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

All notable changes to this project will be documented in this file.

## 0.8.2 (2023-08-19)

- Added sample for buffer encryption by parallel processing
- Updated documentation

## 0.8.1 (2023-08-17)

- Added bitmap encryption sample
Expand Down
2 changes: 1 addition & 1 deletion cipher_magma/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cipher_magma"
version = "0.8.1"
version = "0.8.2"
edition = "2021"
authors = ["Sheroz Khaydarov"]
description = "Block Cipher Magma (GOST R 34.12-2015, former GOST 28147-89)"
Expand Down
1 change: 1 addition & 0 deletions cipher_magma/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Please look at [magma_samples](https://github.com/sheroz/magma/tree/main/magma_s
- Text encryption [encrypt_text.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_text.rs)
- Message Authentication Code (MAC) [calculate_mac.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/calculate_mac.rs)
- Buffer encryption [encrypt_buffer.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_buffer.rs)
- Buffer encryption by parallel processing [encrypt_buffer_parallel.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_buffer_parallel.rs)
- File encryption [encrypt_file.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_file.rs)
- Bitmap file encryption [encrypt_bmp.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_bmp.rs)

Expand Down
31 changes: 23 additions & 8 deletions cipher_magma/src/stream/cipher_mode/ctr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,39 @@ pub fn decrypt(magma: &mut MagmaStream, buf: &[u8]) -> Vec<u8> {
cipher_ctr(magma, buf)
}

/// Returns encrypted/decrypted result as `Vec<u8>`
/// Returns ciphering result as `Vec<u8>`
///
/// Implements the core Counter Encryption (CTR) mode
/// Implements the Counter Encryption (CTR) mode
///
/// [GOST R 34.13-2015](https://www.tc26.ru/standard/gost/GOST_R_3413-2015.pdf)
///
/// Page 14, Section 5.2
fn cipher_ctr(magma: &mut MagmaStream, buf: &[u8]) -> Vec<u8> {

let iv_ctr = magma.prepare_vector_ctr();
let mut counter = match magma.context.feedback.block {
let counter = match magma.context.feedback.block {
Some(block) => block,
None => 0
};

let (result, counter) = cipher_ctr_core(&magma, buf, counter);

// update the feedback state
magma.context.feedback.block = Some(counter);
result
}

/// Returns ciphering result as `Vec<u8>` and counter value as u64
///
/// Implements the core Counter Encryption (CTR) mode
///
/// [GOST R 34.13-2015](https://www.tc26.ru/standard/gost/GOST_R_3413-2015.pdf)
///
/// Page 14, Section 5.2
pub fn cipher_ctr_core(magma: &MagmaStream, buf: &[u8], counter: u64) -> (Vec<u8>,u64) {

let iv_ctr = magma.prepare_vector_ctr();
let mut counter = counter;

let mut result = Vec::<u8>::with_capacity(buf.len());

for chunk in buf.chunks(8) {
Expand All @@ -57,10 +75,7 @@ fn cipher_ctr(magma: &mut MagmaStream, buf: &[u8]) -> Vec<u8> {
result.extend_from_slice(&output.to_be_bytes()[..chunk.len()]);
}

// update the feedback state
magma.context.feedback.block = Some(counter);

result
(result, counter)
}

#[cfg(test)]
Expand Down
4 changes: 3 additions & 1 deletion magma_samples/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
[package]
name = "magma_samples"
version = "0.1.1"
version = "0.1.2"
edition = "2021"

[dependencies]
cipher_magma = { path = "../cipher_magma" }
image = "0.24"
rayon = "1.7"
tick_counter = "0.4"

[dev-dependencies]
criterion = "0.5"
Expand Down
1 change: 1 addition & 0 deletions magma_samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ Please look at [magma_samples](https://github.com/sheroz/magma/tree/main/magma_s
- Text encryption [encrypt_text.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_text.rs)
- Message Authentication Code (MAC) [calculate_mac.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/calculate_mac.rs)
- Buffer encryption [encrypt_buffer.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_buffer.rs)
- Buffer encryption by parallel processing [encrypt_buffer_parallel.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_buffer_parallel.rs)
- File encryption [encrypt_file.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_file.rs)
- Bitmap file encryption [encrypt_bmp.rs](https://github.com/sheroz/magma/blob/main/magma_samples/src/encrypt_bmp.rs)

Expand Down
38 changes: 30 additions & 8 deletions magma_samples/src/calculate_mac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@ pub fn calculate_mac() {

let mut magma = MagmaStream::new(key, CipherMode::MAC);
let mac = mac::calculate(&mut magma, &message);
println!("Calculated MAC:\n{:x}\n", mac);
println!("Calculated MAC:{:x}", mac);
assert_eq!(mac, 0x154e7210);

println!("Completed.");
}

/// Message Authentication Code (MAC)
/// Updating context with data chunks and finalizing result
pub fn calculate_mac_data_chunks() {
/// Updating context and finalizing result
pub fn calculate_mac_stream() {
use cipher_magma::{mac, CipherMode, MagmaStream};

const CHUNK_SIZE: usize = 16;

let key: [u8; 32] = [
0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11,
0x00, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd,
Expand All @@ -41,15 +45,33 @@ pub fn calculate_mac_data_chunks() {
println!("Message:\n{:02x?}\n", message);

let mut magma = MagmaStream::new(key, CipherMode::MAC);
let chunks = message.chunks(16);
println!("Chunk size:{}", CHUNK_SIZE);
println!("Chunks count:{}", chunks.clone().count());

// update the context
for chunk in message.chunks(8) {
// update the context in data chunks
for chunk in chunks {
mac::update(&mut magma, &chunk);
}

// finalize and get result
// finalize
let mac = mac::finalize(&mut magma);
println!("Calculated MAC:\n{:x}\n", mac);

println!("Calculated MAC:{:x}", mac);
assert_eq!(mac, 0x154e7210);

println!("Completed.");
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn calculate_mac_test() {
calculate_mac();
}

#[test]
fn calculate_mac_stream_test() {
calculate_mac_stream();
}
}
10 changes: 10 additions & 0 deletions magma_samples/src/encrypt_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,14 @@ pub fn encrypt_block() {
println!("Decrypted:\n{:x}", decrypted);

assert_eq!(decrypted, source);
println!("Completed.");
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encrypt_block_test() {
encrypt_block();
}
}
32 changes: 23 additions & 9 deletions magma_samples/src/encrypt_buffer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pub fn encrypt_buffer() {
use cipher_magma::{CipherMode, MagmaStream};

const BUF_SIZE: usize = 128;
const CHUNK_SIZE: usize = 4096;

let key = [0xab; 32];
let mut magma = MagmaStream::new(key, CipherMode::CFB);
Expand All @@ -13,35 +13,49 @@ pub fn encrypt_buffer() {
Phasellus vel ex nec leo pretium efficitur. Aliquam malesuada vestibulum magna. \
Quisque iaculis est et est volutpat posuere.\n";

// build the source buffer containing 5000x of txt
let repeat_count = 5000;
// build the source buffer containing 500x of txt
let repeat_count = 500;
let mut source = Vec::<u8>::with_capacity(txt.len() * repeat_count);
(0..repeat_count).for_each(|_| source.extend_from_slice(txt));

println!("Source buffer len:{}", source.len());
println!("Source len:{}", source.len());

let mut encrypted = Vec::<u8>::with_capacity(source.len());
let source_chunks = source.chunks(BUF_SIZE);
for chunk in source_chunks {
println!("Chunk size:{}", CHUNK_SIZE);
let chunks = source.chunks(CHUNK_SIZE);
println!("Chunks count:{}", chunks.clone().count());

println!("Encrypting...");
for chunk in chunks {
let mut ciphertext = magma.encrypt(&chunk);
encrypted.append(&mut ciphertext);
}
println!("Encrypted len:{}", encrypted.len());

println!("Decrypting...");
let mut decrypted = Vec::<u8>::with_capacity(encrypted.len());
let encrypted_chunks = encrypted.chunks(BUF_SIZE);
let encrypted_chunks = encrypted.chunks(CHUNK_SIZE);
for chunk in encrypted_chunks {
let mut plaintext = magma.decrypt(&chunk);
decrypted.append(&mut plaintext);
}
println!("Decrypted len:{}", encrypted.len());

// remove padding bytes
if magma.get_mode().has_padding() {
// remove padding bytes
decrypted.truncate(source.len());
}
println!("Decrypted final len:{}", encrypted.len());

assert_eq!(decrypted, source);

println!("Completed.");
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encrypt_buffer_test() {
encrypt_buffer();
}
}
89 changes: 89 additions & 0 deletions magma_samples/src/encrypt_buffer_parallel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/// Sample of buffer encryption by parallel processing of chunks
/// Results (MacBook Pro M1 2021):
///
/// ```text
/// Source len: 16850000
/// Encrypting by parallel processing...
/// Encryption, elapsed ticks: 19012211
/// Encrypted len: 16850000
/// Decrypting in single thread...
/// Decryption, elapsed ticks: 156965972
/// Parallel processing speedup: 8.256060907382103
/// Decrypted len: 16850000
/// Decrypted final len: 16850000
/// Completed.
/// ```
pub fn encrypt_buffer_parallel() {
use cipher_magma::{CipherMode, MagmaStream};
use rayon::prelude::*;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

const CHUNK_SIZE: usize = 4096;

let key = [0xab; 32];
let mut magma = MagmaStream::new(key, CipherMode::CTR);

let txt = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit. \
Aenean ac sem leo. Morbi pretium neque eget felis finibus convallis. \
Praesent tristique rutrum odio at rhoncus. Duis non ligula ut diam tristique commodo. \
Phasellus vel ex nec leo pretium efficitur. Aliquam malesuada vestibulum magna. \
Quisque iaculis est et est volutpat posuere.\n";

// build the source buffer containing 50000x of txt ~ 16 MB
let repeat_count = 50000;
let mut source = Vec::<u8>::with_capacity(txt.len() * repeat_count);
(0..repeat_count).for_each(|_| source.extend_from_slice(txt));
println!("Source len: {}", source.len());

println!("Encrypting by parallel processing...");
let mut encrypted = Vec::<u8>::with_capacity(source.len());
let counter_alignment = if CHUNK_SIZE % 8 == 0 { 0 } else { 1 };
let mutex = Arc::new(Mutex::new(HashMap::<usize, Vec<u8>>::new()));
let encrypt_start = tick_counter::start();
source
.par_chunks(CHUNK_SIZE)
.enumerate()
.for_each(|(index, chunk)| {
let counter = counter_alignment + (index * CHUNK_SIZE / 8) as u64;
let (ciphertext, _counter) = cipher_magma::ctr::cipher_ctr_core(&magma, chunk, counter);
mutex.lock().unwrap().insert(index, ciphertext);
});

// merge encrypted chunks
let mut map = mutex.lock().unwrap();
let mut map_keys = map.keys().map(|v| *v).collect::<Vec<_>>();
map_keys.sort();
map_keys
.iter()
.for_each(|index| encrypted.append(map.get_mut(index).unwrap()));

let encrypt_ticks = tick_counter::stop() - encrypt_start;
println!("Encryption, elapsed ticks: {}", encrypt_ticks);
println!("Encrypted len: {}", encrypted.len());

println!("Decrypting in single thread...");
let mut decrypted = Vec::<u8>::with_capacity(encrypted.len());
let encrypted_chunks = encrypted.chunks(CHUNK_SIZE);
let decrypt_start = tick_counter::start();
for chunk in encrypted_chunks {
let mut plaintext = magma.decrypt(&chunk);
decrypted.append(&mut plaintext);
}
let decrypt_ticks = tick_counter::stop() - decrypt_start;
let speedup = (decrypt_ticks as f64) / (encrypt_ticks as f64);
println!("Decryption, elapsed ticks: {}", decrypt_ticks);
println!("Parallel processing speedup: {}", speedup);

println!("Decrypted len: {}", encrypted.len());

// remove padding bytes
if magma.get_mode().has_padding() {
decrypted.truncate(source.len());
}
println!("Decrypted final len: {}", encrypted.len());

assert_eq!(decrypted, source);

println!("Completed.");
}

0 comments on commit 3479f83

Please sign in to comment.