feat(alg): sha2 with generics
This commit is contained in:
parent
1b582ba202
commit
afff4c8aa4
4 changed files with 148 additions and 33 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -16,6 +16,7 @@ name = "algorithms"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"criterion",
|
"criterion",
|
||||||
|
"generic-array",
|
||||||
"iai",
|
"iai",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -307,6 +308,15 @@ dependencies = [
|
||||||
"num",
|
"num",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "generic-array"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8c8444bc9d71b935156cc0ccab7f622180808af7867b1daae6547d773591703"
|
||||||
|
dependencies = [
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "half"
|
name = "half"
|
||||||
version = "1.8.3"
|
version = "1.8.3"
|
||||||
|
@ -788,6 +798,12 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.18.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.18"
|
version = "1.0.18"
|
||||||
|
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
generic-array = "1.2.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
criterion = "0.3"
|
criterion = "0.3"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::ffi::{ref_to_ptr, ref_to_ptr_mut};
|
use crate::ffi::{ref_to_ptr, ref_to_ptr_mut};
|
||||||
|
|
||||||
use super::super::sha2::*;
|
use super::super::sha2::{DIGEST256_EMPTY, Digest256, SHA2_256_BLOCK_SIZE};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
@ -17,8 +17,8 @@ pub enum SHA2Result {
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||||
pub struct SHA2Context {
|
pub struct Sha2_256Context {
|
||||||
pub intermediate_hash: Digest,
|
pub intermediate_hash: Digest256,
|
||||||
pub length_low: u32,
|
pub length_low: u32,
|
||||||
pub length_high: u32,
|
pub length_high: u32,
|
||||||
pub message_block_index: i16,
|
pub message_block_index: i16,
|
||||||
|
@ -27,10 +27,10 @@ pub struct SHA2Context {
|
||||||
pub corrupted: bool,
|
pub corrupted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SHA2Context {
|
impl Sha2_256Context {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
intermediate_hash: DIGEST_EMPTY,
|
intermediate_hash: DIGEST256_EMPTY,
|
||||||
length_low: 0,
|
length_low: 0,
|
||||||
length_high: 0,
|
length_high: 0,
|
||||||
message_block_index: 0,
|
message_block_index: 0,
|
||||||
|
@ -41,7 +41,7 @@ impl SHA2Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for SHA2Context {
|
impl Default for Sha2_256Context {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
|
@ -50,40 +50,44 @@ impl Default for SHA2Context {
|
||||||
mod ffi {
|
mod ffi {
|
||||||
use super::*;
|
use super::*;
|
||||||
unsafe extern "C" {
|
unsafe extern "C" {
|
||||||
pub fn sha2_256_oneshot(data: *const u8, len: usize, digest: *mut Digest) -> SHA2Result;
|
pub fn sha2_256_oneshot(data: *const u8, len: usize, digest: *mut Digest256) -> SHA2Result;
|
||||||
pub fn sha2_256_reset(context: *mut SHA2Context) -> SHA2Result;
|
pub fn sha2_256_reset(context: *mut Sha2_256Context) -> SHA2Result;
|
||||||
pub fn sha2_256_input(context: *mut SHA2Context, data: *const u8, len: usize)
|
pub fn sha2_256_input(
|
||||||
|
context: *mut Sha2_256Context,
|
||||||
|
data: *const u8,
|
||||||
|
len: usize,
|
||||||
|
) -> SHA2Result;
|
||||||
|
pub fn sha2_256_result(context: *mut Sha2_256Context, digest: *mut Digest256)
|
||||||
-> SHA2Result;
|
-> SHA2Result;
|
||||||
pub fn sha2_256_result(context: *mut SHA2Context, digest: *mut Digest) -> SHA2Result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest, SHA2Result> {
|
pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Result> {
|
||||||
let mut digest: Digest = DIGEST_EMPTY;
|
let mut digest: Digest256 = DIGEST256_EMPTY;
|
||||||
let res =
|
let res =
|
||||||
unsafe { ffi::sha2_256_oneshot(ref_to_ptr(data), data.len(), ref_to_ptr_mut(&mut digest)) };
|
unsafe { ffi::sha2_256_oneshot(ref_to_ptr(data), data.len(), ref_to_ptr_mut(&mut digest)) };
|
||||||
to_res(digest, res)
|
to_res(digest, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sha2_256_reset(context: &mut SHA2Context) -> Result<(), SHA2Result> {
|
pub fn sha2_256_reset(context: &mut Sha2_256Context) -> Result<(), SHA2Result> {
|
||||||
let res = unsafe { ffi::sha2_256_reset(ref_to_ptr_mut(context)) };
|
let res = unsafe { ffi::sha2_256_reset(ref_to_ptr_mut(context)) };
|
||||||
to_res((), res)
|
to_res((), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sha2_256_input(context: &mut SHA2Context, data: &[u8]) -> Result<(), SHA2Result> {
|
pub fn sha2_256_input(context: &mut Sha2_256Context, data: &[u8]) -> Result<(), SHA2Result> {
|
||||||
let res = unsafe { ffi::sha2_256_input(ref_to_ptr_mut(context), ref_to_ptr(data), data.len()) };
|
let res = unsafe { ffi::sha2_256_input(ref_to_ptr_mut(context), ref_to_ptr(data), data.len()) };
|
||||||
to_res((), res)
|
to_res((), res)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sha2_256_result(context: &mut SHA2Context) -> Result<Digest, SHA2Result> {
|
pub fn sha2_256_result(context: &mut Sha2_256Context) -> Result<Digest256, SHA2Result> {
|
||||||
let mut digest: Digest = DIGEST_EMPTY;
|
let mut digest: Digest256 = DIGEST256_EMPTY;
|
||||||
let res = unsafe { ffi::sha2_256_result(ref_to_ptr_mut(context), ref_to_ptr_mut(&mut digest)) };
|
let res = unsafe { ffi::sha2_256_result(ref_to_ptr_mut(context), ref_to_ptr_mut(&mut digest)) };
|
||||||
to_res(digest, res)
|
to_res(digest, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_res<T>(if_ok: T, res: SHA2Result) -> Result<T, SHA2Result> {
|
pub(crate) fn to_res<T>(if_ok: T, res: SHA2Result) -> Result<T, SHA2Result> {
|
||||||
if res == SHA2Result::shaSuccess {
|
if res == SHA2Result::shaSuccess {
|
||||||
Ok(if_ok)
|
Ok(if_ok)
|
||||||
} else {
|
} else {
|
||||||
|
@ -91,26 +95,28 @@ fn to_res<T>(if_ok: T, res: SHA2Result) -> Result<T, SHA2Result> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: this SHA2_256 implementation does not suit core::hash::Hasher in Rust, since that expects
|
||||||
|
// a finish method with &self and that the hasher can be used after finish.
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::digest;
|
use crate::hash::Digest256;
|
||||||
use crate::hash::Digest;
|
|
||||||
use crate::hash::ffi::sha2_256_oneshot;
|
use crate::hash::ffi::sha2_256_oneshot;
|
||||||
|
|
||||||
const TEST_VALUES: &[(&str, Digest)] = &[
|
const TEST_VALUES: &[(&str, Digest256)] = &[
|
||||||
(
|
(
|
||||||
"AAAA",
|
"AAAA",
|
||||||
digest!(
|
[
|
||||||
0x63c1dd95, 0x1ffedf6f, 0x7fd968ad, 0x4efa39b8, 0xed584f16, 0x2f46e715, 0x114ee184,
|
0x63c1dd95, 0x1ffedf6f, 0x7fd968ad, 0x4efa39b8, 0xed584f16, 0x2f46e715, 0x114ee184,
|
||||||
0xf8de9201
|
0xf8de9201,
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"BAAA",
|
"BAAA",
|
||||||
digest!(
|
[
|
||||||
0x49e3cd45, 0x27c96cdc, 0x010160ff, 0x08520e0c, 0xb63c6ef8, 0xc4e7d486, 0x08995343,
|
0x49e3cd45, 0x27c96cdc, 0x010160ff, 0x08520e0c, 0xb63c6ef8, 0xc4e7d486, 0x08995343,
|
||||||
0x7f83a159
|
0x7f83a159,
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,107 @@
|
||||||
|
use generic_array::GenericArray;
|
||||||
|
|
||||||
|
use crate::hash::{ffi::SHA2Result, sha2::sealed::SHA2Mode};
|
||||||
|
|
||||||
pub const SHA2_256_HASH_BITS: usize = 256;
|
pub const SHA2_256_HASH_BITS: usize = 256;
|
||||||
pub const SHA2_256_HASH_BYTES: usize = SHA2_256_HASH_BITS / 8;
|
pub const SHA2_256_HASH_BYTES: usize = SHA2_256_HASH_BITS / 8;
|
||||||
pub const SHA2_256_HASH_PARTS: usize = SHA2_256_HASH_BYTES / 4 /* storing with u32 */;
|
pub const SHA2_256_HASH_PARTS: usize = SHA2_256_HASH_BYTES / 4 /* storing with u32 */;
|
||||||
pub const SHA2_256_BLOCK_SIZE: usize = 2 * SHA2_256_HASH_BYTES;
|
pub const SHA2_256_BLOCK_SIZE: usize = 2 * SHA2_256_HASH_BYTES;
|
||||||
|
|
||||||
pub type Digest = [u32; SHA2_256_HASH_PARTS];
|
pub type Digest256 = [u32; SHA2_256_HASH_PARTS];
|
||||||
|
pub(crate) const DIGEST256_EMPTY: Digest256 = [0; SHA2_256_HASH_PARTS];
|
||||||
|
|
||||||
#[macro_export]
|
pub struct Mode256;
|
||||||
macro_rules! digest {
|
mod sealed {
|
||||||
($($block:literal$(,)?)+) => {
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
[$($block,)+ ]
|
|
||||||
};
|
use super::Mode256;
|
||||||
|
pub trait SHA2Mode {
|
||||||
|
type HashBits: ArrayLength;
|
||||||
|
type HashBytes: ArrayLength;
|
||||||
|
type HashParts: ArrayLength;
|
||||||
|
type BlockSize: ArrayLength;
|
||||||
|
type Digest: AsRef<[u32]> + AsMut<[u32]>;
|
||||||
|
type Block: AsRef<[u8]> + AsMut<[u8]>;
|
||||||
|
}
|
||||||
|
impl SHA2Mode for Mode256 {
|
||||||
|
type HashBits = generic_array::typenum::U256;
|
||||||
|
type HashBytes = generic_array::typenum::U32;
|
||||||
|
type HashParts = generic_array::typenum::U8;
|
||||||
|
type BlockSize = generic_array::typenum::U512;
|
||||||
|
type Digest = GenericArray<u32, Self::HashParts>;
|
||||||
|
type Block = GenericArray<u8, Self::BlockSize>;
|
||||||
|
}
|
||||||
|
impl Mode256 {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const DIGEST_EMPTY: Digest = [0; SHA2_256_HASH_PARTS];
|
#[derive(Debug, PartialEq, Eq, Clone, Hash)]
|
||||||
|
pub struct SHA2Context<M: sealed::SHA2Mode> {
|
||||||
|
intermediate_hash: GenericArray<u32, M::HashParts>,
|
||||||
|
block: GenericArray<u8, M::BlockSize>,
|
||||||
|
block_idx: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: sealed::SHA2Mode> SHA2Context<M> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
intermediate_hash: Default::default(),
|
||||||
|
block: Default::default(),
|
||||||
|
block_idx: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
*self = Self::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input(&mut self, data: &[u8]) -> Result<(), SHA2Result> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> Result<M::Digest, SHA2Result> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: sealed::SHA2Mode> Default for SHA2Context<M> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sha2_oneshot<M: sealed::SHA2Mode>(data: &[u8]) -> Result<M::Digest, SHA2Result> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sha2_256_oneshot(data: &[u8]) -> Result<Digest256, SHA2Result> {
|
||||||
|
sha2_oneshot::<Mode256>(data).map(|dig| dig.into_array())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const TEST_VALUES: &[(&str, Digest256)] = &[
|
||||||
|
(
|
||||||
|
"AAAA",
|
||||||
|
[
|
||||||
|
0x63c1dd95, 0x1ffedf6f, 0x7fd968ad, 0x4efa39b8, 0xed584f16, 0x2f46e715, 0x114ee184,
|
||||||
|
0xf8de9201,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"BAAA",
|
||||||
|
[
|
||||||
|
0x49e3cd45, 0x27c96cdc, 0x010160ff, 0x08520e0c, 0xb63c6ef8, 0xc4e7d486, 0x08995343,
|
||||||
|
0x7f83a159,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_check() {
|
||||||
|
for (input, expected_output) in TEST_VALUES.iter().copied() {
|
||||||
|
assert_eq!(sha2_256_oneshot(input.as_bytes()), Ok(expected_output))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue