Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not store max_corr and rank, unify cpa struct, check for processor compatibility #14

Merged
merged 10 commits into from
Jul 15, 2024
8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ readme = "README.md"

[features]
progress_bar = ["dep:indicatif"]
quicklog = ["dep:thiserror"]

[dependencies]
serde_json = "1.0.115"
Expand All @@ -21,14 +22,19 @@ rayon = "1.10.0"
indicatif = { version = "0.17.8", optional = true }
ndarray-npy ="0.8.1"
itertools = "0.12.1"
thiserror = "1.0.58"
thiserror = { version = "1.0.58", optional = true }

[dev-dependencies]
criterion = "0.5.1"
ndarray-rand = "0.14.0"
anyhow = "1.0.81"
muscat = { path = ".", features = ["progress_bar"] }

[[example]]
name = "snr"
path = "examples/snr.rs"
required-features = ["quicklog"]

[[bench]]
name = "cpa"
harness = false
Expand Down
2 changes: 1 addition & 1 deletion benches/cpa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub fn leakage_model_normal(value: ArrayView1<usize>, guess: usize) -> usize {
hw(sbox((value[1] ^ guess) as u8) as usize)
}

fn cpa_normal_sequential(leakages: &Array2<f64>, plaintexts: &Array2<u8>) -> cpa_normal::Cpa {
fn cpa_normal_sequential(leakages: &Array2<f64>, plaintexts: &Array2<u8>) -> Cpa {
let chunk_size = 500;

let mut cpa =
Expand Down
4 changes: 2 additions & 2 deletions benches/dpa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use ndarray_rand::rand::{rngs::StdRng, SeedableRng};
use ndarray_rand::rand_distr::Uniform;
use ndarray_rand::RandomExt;

fn selection_function(metadata: Array1<u8>, guess: usize) -> usize {
sbox(metadata[1] ^ guess as u8).into()
fn selection_function(metadata: Array1<u8>, guess: usize) -> bool {
usize::from(sbox(metadata[1] ^ guess as u8)) & 1 == 1
}

fn dpa_sequential(leakages: &Array2<f32>, plaintexts: &Array2<u8>) -> Dpa {
Expand Down
31 changes: 20 additions & 11 deletions examples/cpa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use muscat::cpa_normal::CpaProcessor;
use muscat::leakage::{hw, sbox};
use muscat::util::{progress_bar, read_array2_from_npy_file, save_array2};
use ndarray::*;
use ndarray_npy::write_npy;
use rayon::iter::{ParallelBridge, ParallelIterator};
use std::time;

Expand Down Expand Up @@ -50,9 +51,9 @@ fn cpa() -> Result<()> {
);

let cpa = cpa_parallel.finalize();
println!("Guessed key = {}", cpa.pass_guess());
println!("Guessed key = {}", cpa.best_guess());

save_array2("results/corr.npy", cpa.pass_corr_array().view())?;
save_array2("results/corr.npy", cpa.corr())?;

Ok(())
}
Expand All @@ -70,30 +71,38 @@ fn success() -> Result<()> {

let mut cpa = CpaProcessor::new(size, batch, guess_range, leakage_model);

cpa.success_traces(rank_traces);
let mut rank = Array1::zeros(guess_range);
let mut processed_traces = 0;
for i in (0..nfiles).progress() {
let dir_l = format!("{folder}/l/{i}.npy");
let dir_p = format!("{folder}/p/{i}.npy");
let leakages = read_array2_from_npy_file::<FormatTraces>(&dir_l)?;
let plaintext = read_array2_from_npy_file::<FormatMetadata>(&dir_p)?;
let len_leakages = leakages.shape()[0];
for row in (0..len_leakages).step_by(batch) {
for row in (0..leakages.shape()[0]).step_by(batch) {
let range_samples = start_sample..end_sample;
let range_rows: std::ops::Range<usize> = row..row + batch;
let range_metadat = 0..plaintext.shape()[1];
let range_rows = row..row + batch;
let range_metadata = 0..plaintext.shape()[1];
let sample_traces = leakages
.slice(s![range_rows.clone(), range_samples])
.map(|l| *l as f32);
let sample_metadata = plaintext.slice(s![range_rows, range_metadat]);
cpa.update_success(sample_traces.view(), sample_metadata);
let sample_metadata = plaintext.slice(s![range_rows, range_metadata]);

cpa.update(sample_traces.view(), sample_metadata);
processed_traces += sample_traces.len();
if processed_traces % rank_traces == 0 {
// rank can be saved to get its evolution
rank = cpa.finalize().rank();
}
}
}

let cpa = cpa.finalize();
println!("Guessed key = {}", cpa.pass_guess());
println!("Guessed key = {}", cpa.best_guess());

println!("{:?}", rank);

// save corr key curves in npy
save_array2("results/success.npy", cpa.pass_rank().view())?;
write_npy("results/success.npy", &cpa.rank().map(|&x| x as u64))?;

Ok(())
}
Expand Down
6 changes: 3 additions & 3 deletions examples/cpa_partioned.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ fn cpa() -> Result<()> {
})
.reduce(
|| CpaProcessor::new(size, guess_range, target_byte, leakage_model),
|a: CpaProcessor, b| a + b,
|a, b| a + b,
);

let cpa_result = cpa.finalize();
println!("Guessed key = {}", cpa_result.pass_guess());
println!("Guessed key = {}", cpa_result.best_guess());

// save corr key curves in npy
save_array("../results/corr.npy", &cpa_result.pass_corr_array())?;
save_array("../results/corr.npy", &cpa_result.corr())?;

Ok(())
}
Expand Down
69 changes: 37 additions & 32 deletions examples/dpa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ use indicatif::ProgressIterator;
use muscat::dpa::DpaProcessor;
use muscat::leakage::sbox;
use muscat::util::read_array2_from_npy_file;
use ndarray::{s, Array1, Array2};
use ndarray::{s, Array1};
use rayon::iter::{ParallelBridge, ParallelIterator};

// traces format
type FormatTraces = f64;
type FormatMetadata = u8;

// leakage model
pub fn leakage_model(value: Array1<FormatMetadata>, guess: usize) -> usize {
(sbox((value[1] as usize ^ guess) as u8)) as usize
pub fn selection_function(value: Array1<FormatMetadata>, guess: usize) -> bool {
(sbox((value[1] as usize ^ guess) as u8)) as usize & 1 == 1
}

fn dpa() -> Result<()> {
Expand All @@ -23,21 +22,21 @@ fn dpa() -> Result<()> {
let folder = String::from("../../data/cw");
let dir_l = format!("{folder}/leakages.npy");
let dir_p = format!("{folder}/plaintexts.npy");
let leakages: Array2<FormatTraces> = read_array2_from_npy_file::<FormatTraces>(&dir_l)?;
let plaintext: Array2<FormatMetadata> = read_array2_from_npy_file::<FormatMetadata>(&dir_p)?;
let leakages = read_array2_from_npy_file::<FormatTraces>(&dir_l)?;
let plaintext = read_array2_from_npy_file::<FormatMetadata>(&dir_p)?;
let len_traces = 20000; //leakages.shape()[0];
let mut dpa = DpaProcessor::new(size, guess_range, leakage_model);
let mut dpa_proc = DpaProcessor::new(size, guess_range, selection_function);
for i in (0..len_traces).progress() {
let tmp_trace = leakages
.row(i)
.slice(s![start_sample..end_sample])
.map(|t| *t as f32);
.mapv(|t| t as f32);
let tmp_metadata = plaintext.row(i);
dpa.update(tmp_trace.view(), tmp_metadata.to_owned());
dpa_proc.update(tmp_trace.view(), tmp_metadata.to_owned());
}
let dpa = dpa.finalize();
println!("Guessed key = {:02x}", dpa.pass_guess());
// let corr = dpa.pass_corr_array();
let dpa = dpa_proc.finalize();
println!("Guessed key = {:02x}", dpa.best_guess());
// let corr = dpa.corr();

Ok(())
}
Expand All @@ -51,25 +50,30 @@ fn dpa_success() -> Result<()> {
let folder = String::from("../../data/cw");
let dir_l = format!("{folder}/leakages.npy");
let dir_p = format!("{folder}/plaintexts.npy");
let leakages: Array2<FormatTraces> = read_array2_from_npy_file::<FormatTraces>(&dir_l)?;
let plaintext: Array2<FormatMetadata> = read_array2_from_npy_file::<FormatMetadata>(&dir_p)?;
let leakages = read_array2_from_npy_file::<FormatTraces>(&dir_l)?;
let plaintext = read_array2_from_npy_file::<FormatMetadata>(&dir_p)?;
let len_traces = leakages.shape()[0];
let mut dpa = DpaProcessor::new(size, guess_range, leakage_model);
let mut dpa_proc = DpaProcessor::new(size, guess_range, selection_function);
let rank_traces: usize = 100;
dpa.assign_rank_traces(rank_traces);

let mut rank = Array1::zeros(guess_range);
for i in (0..len_traces).progress() {
let tmp_trace = leakages
.row(i)
.slice(s![start_sample..end_sample])
.map(|t| *t as f32);
.mapv(|t| t as f32);
let tmp_metadata = plaintext.row(i).to_owned();
dpa.update_success(tmp_trace.view(), tmp_metadata);
dpa_proc.update(tmp_trace.view(), tmp_metadata);

if i % rank_traces == 0 {
// rank can be saved to get its evolution
rank = dpa_proc.finalize().rank();
}
}

let dpa = dpa.finalize();
println!("Guessed key = {:02x}", dpa.pass_guess());
// let succss = dpa.pass_rank().to_owned();
let dpa = dpa_proc.finalize();
println!("Guessed key = {:02x}", dpa.best_guess());
println!("{:?}", rank);

Ok(())
}
Expand All @@ -83,21 +87,22 @@ fn dpa_parallel() -> Result<()> {
let folder = String::from("../../data/cw");
let dir_l = format!("{folder}/leakages.npy");
let dir_p = format!("{folder}/plaintexts.npy");
let leakages: Array2<FormatTraces> = read_array2_from_npy_file::<FormatTraces>(&dir_l)?;
let plaintext: Array2<FormatMetadata> = read_array2_from_npy_file::<FormatMetadata>(&dir_p)?;
let leakages = read_array2_from_npy_file::<FormatTraces>(&dir_l)?;
let plaintext = read_array2_from_npy_file::<FormatMetadata>(&dir_p)?;
let len_traces = 20000; //leakages.shape()[0];
let batch = 2500;
let mut dpa = (0..len_traces)
let dpa = (0..len_traces)
.step_by(batch)
.par_bridge()
.map(|range_rows: usize| {
.map(|range_rows| {
let tmp_leakages = leakages
.slice(s![range_rows..range_rows + batch, start_sample..end_sample])
.map(|l| *l as f32);
.mapv(|l| l as f32);
let tmp_metadata = plaintext
.slice(s![range_rows..range_rows + batch, ..])
.to_owned();
let mut dpa_inner = DpaProcessor::new(size, guess_range, leakage_model);

let mut dpa_inner = DpaProcessor::new(size, guess_range, selection_function);
for i in 0..batch {
let trace = tmp_leakages.row(i);
let metadata = tmp_metadata.row(i).to_owned();
Expand All @@ -106,13 +111,13 @@ fn dpa_parallel() -> Result<()> {
dpa_inner
})
.reduce(
|| DpaProcessor::new(size, guess_range, leakage_model),
|| DpaProcessor::new(size, guess_range, selection_function),
|x, y| x + y,
);
)
.finalize();

let dpa = dpa.finalize();
println!("{:2x}", dpa.pass_guess());
// let corr = dpa.pass_corr_array();
println!("{:2x}", dpa.best_guess());
// let corr = dpa.corr();

Ok(())
}
Expand Down
4 changes: 2 additions & 2 deletions examples/rank.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn rank() -> Result<()> {
.par_bridge()
.fold(
|| CpaProcessor::new(size, guess_range, target_byte, leakage_model),
|mut r: CpaProcessor, n| {
|mut r, n| {
r.update(
l_sample.row(n).map(|l| *l as usize).view(),
p_sample.row(n).map(|p| *p as usize).view(),
Expand All @@ -58,7 +58,7 @@ fn rank() -> Result<()> {
let rank = rank.finalize();

// save rank key curves in npy
save_array("../results/rank.npy", &rank.pass_rank())?;
save_array("../results/rank.npy", &rank.rank().map(|&x| x as u64))?;

Ok(())
}
Expand Down
Loading