Skip to content

Commit

Permalink
Split dpa processor and result
Browse files Browse the repository at this point in the history
  • Loading branch information
TrAyZeN committed May 3, 2024
1 parent cb7ad53 commit 7744995
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 59 deletions.
12 changes: 5 additions & 7 deletions benches/dpa.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use muscat::dpa::{dpa, Dpa};
use muscat::dpa::{dpa, Dpa, DpaProcessor};
use muscat::leakage::sbox;
use ndarray::{Array1, Array2};
use ndarray_rand::rand::{rngs::StdRng, SeedableRng};
Expand All @@ -10,19 +10,17 @@ fn selection_function(metadata: Array1<u8>, guess: usize) -> usize {
sbox(metadata[1] ^ guess as u8).into()
}

fn dpa_sequential(leakages: &Array2<f32>, plaintexts: &Array2<u8>) -> Dpa<Array1<u8>> {
let mut dpa = Dpa::new(leakages.shape()[1], 256, selection_function);
fn dpa_sequential(leakages: &Array2<f32>, plaintexts: &Array2<u8>) -> Dpa {
let mut dpa = DpaProcessor::new(leakages.shape()[1], 256, selection_function);

for i in 0..leakages.shape()[0] {
dpa.update(leakages.row(i), plaintexts.row(i).to_owned());
}

dpa.finalize();

dpa
dpa.finalize()
}

fn dpa_parallel(leakages: &Array2<f32>, plaintexts: &Array2<u8>) -> Dpa<Array1<u8>> {
fn dpa_parallel(leakages: &Array2<f32>, plaintexts: &Array2<u8>) -> Dpa {
dpa(
leakages.view(),
plaintexts
Expand Down
18 changes: 11 additions & 7 deletions examples/dpa.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use anyhow::Result;
use indicatif::ProgressIterator;
use muscat::dpa::Dpa;
use muscat::dpa::DpaProcessor;
use muscat::leakage::sbox;
use muscat::util::read_array2_from_npy_file;
use ndarray::{s, Array1, Array2};
Expand All @@ -26,7 +26,7 @@ fn dpa() -> Result<()> {
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 len_traces = 20000; //leakages.shape()[0];
let mut dpa = Dpa::new(size, guess_range, leakage_model);
let mut dpa = DpaProcessor::new(size, guess_range, leakage_model);
for i in (0..len_traces).progress() {
let tmp_trace = leakages
.row(i)
Expand All @@ -35,7 +35,7 @@ fn dpa() -> Result<()> {
let tmp_metadata = plaintext.row(i);
dpa.update(tmp_trace.view(), tmp_metadata.to_owned());
}
dpa.finalize();
let dpa = dpa.finalize();
println!("Guessed key = {:02x}", dpa.pass_guess());
// let corr = dpa.pass_corr_array();

Expand All @@ -54,7 +54,7 @@ fn dpa_success() -> Result<()> {
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 len_traces = leakages.shape()[0];
let mut dpa = Dpa::new(size, guess_range, leakage_model);
let mut dpa = DpaProcessor::new(size, guess_range, leakage_model);
let rank_traces: usize = 100;
dpa.assign_rank_traces(rank_traces);

Expand All @@ -67,6 +67,7 @@ fn dpa_success() -> Result<()> {
dpa.update_success(tmp_trace.view(), tmp_metadata);
}

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

Expand Down Expand Up @@ -96,17 +97,20 @@ fn dpa_parallel() -> Result<()> {
let tmp_metadata = plaintext
.slice(s![range_rows..range_rows + batch, ..])
.to_owned();
let mut dpa_inner = Dpa::new(size, guess_range, leakage_model);
let mut dpa_inner = DpaProcessor::new(size, guess_range, leakage_model);
for i in 0..batch {
let trace = tmp_leakages.row(i);
let metadata = tmp_metadata.row(i).to_owned();
dpa_inner.update(trace, metadata);
}
dpa_inner
})
.reduce(|| Dpa::new(size, guess_range, leakage_model), |x, y| x + y);
.reduce(
|| DpaProcessor::new(size, guess_range, leakage_model),
|x, y| x + y,
);

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

Expand Down
2 changes: 2 additions & 0 deletions src/cpa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ where
pub struct Cpa {
/// Guess range upper excluded bound
guess_range: usize,
/// Pearson correlation coefficients
corr: Array2<f32>,
/// Max pearson correlation coefficients
max_corr: Array1<f32>,
rank_slice: Array2<f32>,
}
Expand Down
93 changes: 48 additions & 45 deletions src/dpa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@ pub fn dpa<M, T>(
guess_range: usize,
leakage_func: fn(M, usize) -> usize,
chunk_size: usize,
) -> Dpa<M>
) -> Dpa
where
T: Into<f32> + Copy + Sync,
M: Clone + Sync,
{
let mut dpa = zip(
zip(
leakages.axis_chunks_iter(Axis(0), chunk_size),
metadata.axis_chunks_iter(Axis(0), chunk_size),
)
.par_bridge()
.map(|(leakages_chunk, metadata_chunk)| {
let mut dpa = Dpa::new(leakages.shape()[1], guess_range, leakage_func);
let mut dpa = DpaProcessor::new(leakages.shape()[1], guess_range, leakage_func);

for i in 0..leakages_chunk.shape()[0] {
dpa.update(leakages_chunk.row(i), metadata_chunk[i].clone());
Expand All @@ -30,16 +30,40 @@ where
dpa
})
.reduce(
|| Dpa::new(leakages.shape()[1], guess_range, leakage_func),
|| DpaProcessor::new(leakages.shape()[1], guess_range, leakage_func),
|a, b| a + b,
);
)
.finalize()
}

pub struct Dpa {
/// Guess range upper excluded bound
guess_range: usize,
corr: Array2<f32>,
max_corr: Array1<f32>,
}

dpa.finalize();
impl Dpa {
pub fn pass_corr_array(&self) -> ArrayView2<f32> {
self.corr.view()
}

dpa
pub fn pass_guess(&self) -> usize {
let mut init_value = 0.0;
let mut guess = 0;

for i in 0..self.guess_range {
if self.max_corr[i] > init_value {
init_value = self.max_corr[i];
guess = i;
}
}

guess
}
}

pub struct Dpa<M> {
pub struct DpaProcessor<M> {
/// Number of samples per trace
len_samples: usize,
/// Guess range upper excluded bound
Expand All @@ -52,8 +76,6 @@ pub struct Dpa<M> {
count_0: Array1<usize>,
/// Number of traces processed for which the selection function equals 1
count_1: Array1<usize>,
corr: Array2<f32>,
max_corr: Array1<f32>,
rank_slice: Array2<f32>,
rank_traces: usize, // Number of traces to calculate succes rate
/// Selection function
Expand All @@ -66,7 +88,7 @@ pub struct Dpa<M> {
https://paulkocher.com/doc/DifferentialPowerAnalysis.pdf
https://web.mit.edu/6.857/OldStuff/Fall03/ref/kocher-DPATechInfo.pdf */

impl<M: Clone> Dpa<M> {
impl<M: Clone> DpaProcessor<M> {
pub fn new(size: usize, guess_range: usize, f: fn(M, usize) -> usize) -> Self {
Self {
len_samples: size,
Expand All @@ -75,8 +97,6 @@ impl<M: Clone> Dpa<M> {
sum_1: Array2::zeros((guess_range, size)),
count_0: Array1::zeros(guess_range),
count_1: Array1::zeros(guess_range),
corr: Array2::zeros((guess_range, size)),
max_corr: Array1::zeros(guess_range),
rank_slice: Array2::zeros((guess_range, 1)),
rank_traces: 0,
leakage_func: f,
Expand Down Expand Up @@ -125,21 +145,21 @@ impl<M: Clone> Dpa<M> {
self.update(trace_batch, plaintext_batch);

if self.len_leakages % self.rank_traces == 0 {
self.finalize();
let dpa = self.finalize();

if self.len_leakages == self.rank_traces {
self.rank_slice = self
self.rank_slice = dpa
.max_corr
.clone()
.into_shape((self.max_corr.shape()[0], 1))
.into_shape((dpa.max_corr.shape()[0], 1))
.unwrap();
} else {
self.rank_slice = concatenate![
Axis(1),
self.rank_slice,
self.max_corr
dpa.max_corr
.clone()
.into_shape((self.max_corr.shape()[0], 1))
.into_shape((dpa.max_corr.shape()[0], 1))
.unwrap()
];
}
Expand All @@ -150,9 +170,8 @@ impl<M: Clone> Dpa<M> {
self.rank_traces = value;
}

pub fn finalize(&mut self) {
/* This function finalizes the calculation after
feeding all stored acc arrays */
pub fn finalize(&mut self) -> Dpa {
/* This function finalizes the calculation after feeding all stored acc arrays */
let mut tmp_avg_0 = Array2::zeros((self.guess_range, self.len_samples));
let mut tmp_avg_1 = Array2::zeros((self.guess_range, self.len_samples));

Expand All @@ -162,11 +181,15 @@ impl<M: Clone> Dpa<M> {
tmp_avg_0.row_mut(row).assign(&tmp_row_0);
tmp_avg_1.row_mut(row).assign(&tmp_row_1);
}
let diff = tmp_avg_0.clone() - tmp_avg_1;

self.corr = diff.map(|e| f32::abs(*e));
let corr = (tmp_avg_0 - tmp_avg_1).map(|e| f32::abs(*e));
let max_corr = max_per_row(corr.view());

self.max_corr = max_per_row(self.corr.view());
Dpa {
guess_range: self.guess_range,
corr,
max_corr,
}
}

pub fn success_traces(&mut self, traces_no: usize) {
Expand All @@ -176,27 +199,9 @@ impl<M: Clone> Dpa<M> {
pub fn pass_rank(&self) -> ArrayView2<f32> {
self.rank_slice.view()
}

pub fn pass_corr_array(&self) -> ArrayView2<f32> {
self.corr.view()
}

pub fn pass_guess(&self) -> usize {
let mut init_value = 0.0;
let mut guess = 0;

for i in 0..self.guess_range {
if self.max_corr[i] > init_value {
init_value = self.max_corr[i];
guess = i;
}
}

guess
}
}

impl<M> Add for Dpa<M> {
impl<M> Add for DpaProcessor<M> {
type Output = Self;

fn add(self, rhs: Self) -> Self::Output {
Expand All @@ -211,8 +216,6 @@ impl<M> Add for Dpa<M> {
sum_1: self.sum_1 + rhs.sum_1,
count_0: self.count_0 + rhs.count_0,
count_1: self.count_1 + rhs.count_1,
corr: self.corr + rhs.corr,
max_corr: self.max_corr,
rank_slice: self.rank_slice,
rank_traces: self.rank_traces,
leakage_func: self.leakage_func,
Expand Down

0 comments on commit 7744995

Please sign in to comment.