Skip to content

Commit

Permalink
Merge rust-bitcoin#3989: Do hashes file re-org
Browse files Browse the repository at this point in the history
85e0330 Run the formatter (Tobin C. Harding)
7be0db7 hashes: Move bench and test code into files (Tobin C. Harding)
665fa9d hashes: Pull crypto out into submodule (Tobin C. Harding)
1bfd1e0 hashes: Make module subdirectories (Tobin C. Harding)

Pull request description:

  This is an attempt at point 3 in rust-bitcoin#3961 (comment)

  However instead of using `api.rs` and `implementation.rs` it uses `crypto.rs` for the cryptography stuff and leaves the rest in `mod.rs`.

  This whole PR is internal changes only. Almost entirely code moves, review is easy if you have your `diff` configured nicely.

ACKs for top commit:
  Kixunil:
    ACK 85e0330
  apoelstra:
    ACK 85e0330; successfully ran local tests; look great! thanks!

Tree-SHA512: e52e6410e86fc93ec34a72be8c64f02148f46958f8f5c1850075b1a7f41886c220f09144ccd05a98a551c356a5d25524c8884fc8578a205b27f385ec0725f13b
  • Loading branch information
apoelstra committed Feb 6, 2025
2 parents a380d4b + 85e0330 commit 16cf1f7
Show file tree
Hide file tree
Showing 26 changed files with 1,291 additions and 1,287 deletions.
3 changes: 2 additions & 1 deletion bitcoin/src/blockdata/script/instruction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ impl Instruction<'_> {
_ => None,
}
}
Instruction::PushBytes(bytes) => super::read_scriptint_non_minimal(bytes.as_bytes()).ok(),
Instruction::PushBytes(bytes) =>
super::read_scriptint_non_minimal(bytes.as_bytes()).ok(),
}
}

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
33 changes: 33 additions & 0 deletions hashes/src/ripemd160/benches.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use test::Bencher;

use crate::{ripemd160, Hash, HashEngine};

#[bench]
pub fn ripemd160_10(bh: &mut Bencher) {
let mut engine = ripemd160::Hash::engine();
let bytes = [1u8; 10];
bh.iter(|| {
engine.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}

#[bench]
pub fn ripemd160_1k(bh: &mut Bencher) {
let mut engine = ripemd160::Hash::engine();
let bytes = [1u8; 1024];
bh.iter(|| {
engine.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}

#[bench]
pub fn ripemd160_64k(bh: &mut Bencher) {
let mut engine = ripemd160::Hash::engine();
let bytes = [1u8; 65536];
bh.iter(|| {
engine.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}
236 changes: 2 additions & 234 deletions hashes/src/ripemd160.rs → hashes/src/ripemd160/crypto.rs
Original file line number Diff line number Diff line change
@@ -1,92 +1,6 @@
// SPDX-License-Identifier: CC0-1.0

//! RIPEMD160 implementation.
use core::cmp;

use crate::{incomplete_block_len, HashEngine as _};

crate::internal_macros::general_hash_type! {
160,
false,
"Output of the RIPEMD160 hash function."
}

#[cfg(not(hashes_fuzz))]
fn from_engine(mut e: HashEngine) -> Hash {
// pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining
let n_bytes_hashed = e.bytes_hashed;

let zeroes = [0; BLOCK_SIZE - 8];
e.input(&[0x80]);
if crate::incomplete_block_len(&e) > zeroes.len() {
e.input(&zeroes);
}
let pad_length = zeroes.len() - incomplete_block_len(&e);
e.input(&zeroes[..pad_length]);
debug_assert_eq!(incomplete_block_len(&e), zeroes.len());

e.input(&(8 * n_bytes_hashed).to_le_bytes());
debug_assert_eq!(incomplete_block_len(&e), 0);

Hash(e.midstate())
}

#[cfg(hashes_fuzz)]
fn from_engine(e: HashEngine) -> Hash {
let mut res = e.midstate();
res[0] ^= (e.bytes_hashed & 0xff) as u8;
Hash(res)
}

const BLOCK_SIZE: usize = 64;

/// Engine to compute RIPEMD160 hash function.
#[derive(Clone)]
pub struct HashEngine {
buffer: [u8; BLOCK_SIZE],
h: [u32; 5],
bytes_hashed: u64,
}

impl HashEngine {
/// Constructs a new SHA256 hash engine.
pub const fn new() -> Self {
Self {
h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0],
bytes_hashed: 0,
buffer: [0; BLOCK_SIZE],
}
}

#[cfg(not(hashes_fuzz))]
fn midstate(&self) -> [u8; 20] {
let mut ret = [0; 20];
for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(4)) {
ret_bytes.copy_from_slice(&(*val).to_le_bytes());
}
ret
}

#[cfg(hashes_fuzz)]
fn midstate(&self) -> [u8; 20] {
let mut ret = [0; 20];
ret.copy_from_slice(&self.buffer[..20]);
ret
}
}

impl Default for HashEngine {
fn default() -> Self { Self::new() }
}

impl crate::HashEngine for HashEngine {
const BLOCK_SIZE: usize = 64;

fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }

crate::internal_macros::engine_input_impl!();
}
use super::{HashEngine, BLOCK_SIZE};

#[cfg(feature = "small-hash")]
#[macro_use]
Expand Down Expand Up @@ -214,7 +128,7 @@ macro_rules! process_block(
);

impl HashEngine {
fn process_block(&mut self) {
pub(super) fn process_block(&mut self) {
debug_assert_eq!(self.buffer.len(), BLOCK_SIZE);

let mut w = [0u32; 16];
Expand Down Expand Up @@ -405,149 +319,3 @@ impl HashEngine {
);
}
}

#[cfg(test)]
mod tests {
#[test]
#[cfg(feature = "alloc")]
fn test() {
use alloc::string::ToString;

use crate::{ripemd160, HashEngine};

#[derive(Clone)]
struct Test {
input: &'static str,
output: [u8; 20],
output_str: &'static str,
}

#[rustfmt::skip]
let tests = [
// Test messages from FIPS 180-1
Test {
input: "abc",
output: [
0x8e, 0xb2, 0x08, 0xf7,
0xe0, 0x5d, 0x98, 0x7a,
0x9b, 0x04, 0x4a, 0x8e,
0x98, 0xc6, 0xb0, 0x87,
0xf1, 0x5a, 0x0b, 0xfc,
],
output_str: "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"
},
Test {
input:
"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
output: [
0x12, 0xa0, 0x53, 0x38,
0x4a, 0x9c, 0x0c, 0x88,
0xe4, 0x05, 0xa0, 0x6c,
0x27, 0xdc, 0xf4, 0x9a,
0xda, 0x62, 0xeb, 0x2b,
],
output_str: "12a053384a9c0c88e405a06c27dcf49ada62eb2b"
},
// Examples from wikipedia
Test {
input: "The quick brown fox jumps over the lazy dog",
output: [
0x37, 0xf3, 0x32, 0xf6,
0x8d, 0xb7, 0x7b, 0xd9,
0xd7, 0xed, 0xd4, 0x96,
0x95, 0x71, 0xad, 0x67,
0x1c, 0xf9, 0xdd, 0x3b,
],
output_str: "37f332f68db77bd9d7edd4969571ad671cf9dd3b",
},
Test {
input: "The quick brown fox jumps over the lazy cog",
output: [
0x13, 0x20, 0x72, 0xdf,
0x69, 0x09, 0x33, 0x83,
0x5e, 0xb8, 0xb6, 0xad,
0x0b, 0x77, 0xe7, 0xb6,
0xf1, 0x4a, 0xca, 0xd7,
],
output_str: "132072df690933835eb8b6ad0b77e7b6f14acad7",
},
];

for mut test in tests {
// Hash through high-level API, check hex encoding/decoding
let hash = ripemd160::Hash::hash(test.input.as_bytes());
assert_eq!(hash, test.output_str.parse::<ripemd160::Hash>().expect("parse hex"));
assert_eq!(hash.as_byte_array(), &test.output);
assert_eq!(hash.to_string(), test.output_str);
assert_eq!(ripemd160::Hash::from_bytes_ref(&test.output), &hash);
assert_eq!(ripemd160::Hash::from_bytes_mut(&mut test.output), &hash);

// Hash through engine, checking that we can input byte by byte
let mut engine = ripemd160::Hash::engine();
for ch in test.input.as_bytes() {
engine.input(&[*ch]);
}
let manual_hash = ripemd160::Hash::from_engine(engine);
assert_eq!(hash, manual_hash);
assert_eq!(hash.to_byte_array(), test.output);
}
}

#[test]
#[cfg(feature = "serde")]
fn ripemd_serde() {
use serde_test::{assert_tokens, Configure, Token};

use crate::ripemd160;

#[rustfmt::skip]
static HASH_BYTES: [u8; 20] = [
0x13, 0x20, 0x72, 0xdf,
0x69, 0x09, 0x33, 0x83,
0x5e, 0xb8, 0xb6, 0xad,
0x0b, 0x77, 0xe7, 0xb6,
0xf1, 0x4a, 0xca, 0xd7,
];

let hash = ripemd160::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]);
}
}

#[cfg(bench)]
mod benches {
use test::Bencher;

use crate::{ripemd160, Hash, HashEngine};

#[bench]
pub fn ripemd160_10(bh: &mut Bencher) {
let mut engine = ripemd160::Hash::engine();
let bytes = [1u8; 10];
bh.iter(|| {
engine.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}

#[bench]
pub fn ripemd160_1k(bh: &mut Bencher) {
let mut engine = ripemd160::Hash::engine();
let bytes = [1u8; 1024];
bh.iter(|| {
engine.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}

#[bench]
pub fn ripemd160_64k(bh: &mut Bencher) {
let mut engine = ripemd160::Hash::engine();
let bytes = [1u8; 65536];
bh.iter(|| {
engine.input(&bytes);
});
bh.bytes = bytes.len() as u64;
}
}
95 changes: 95 additions & 0 deletions hashes/src/ripemd160/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// SPDX-License-Identifier: CC0-1.0

//! RIPEMD160 implementation.
#[cfg(bench)]
mod benches;
mod crypto;
#[cfg(bench)]
mod tests;

use core::cmp;

use crate::{incomplete_block_len, HashEngine as _};

crate::internal_macros::general_hash_type! {
160,
false,
"Output of the RIPEMD160 hash function."
}

#[cfg(not(hashes_fuzz))]
fn from_engine(mut e: HashEngine) -> Hash {
// pad buffer with a single 1-bit then all 0s, until there are exactly 8 bytes remaining
let n_bytes_hashed = e.bytes_hashed;

let zeroes = [0; BLOCK_SIZE - 8];
e.input(&[0x80]);
if crate::incomplete_block_len(&e) > zeroes.len() {
e.input(&zeroes);
}
let pad_length = zeroes.len() - incomplete_block_len(&e);
e.input(&zeroes[..pad_length]);
debug_assert_eq!(incomplete_block_len(&e), zeroes.len());

e.input(&(8 * n_bytes_hashed).to_le_bytes());
debug_assert_eq!(incomplete_block_len(&e), 0);

Hash(e.midstate())
}

#[cfg(hashes_fuzz)]
fn from_engine(e: HashEngine) -> Hash {
let mut res = e.midstate();
res[0] ^= (e.bytes_hashed & 0xff) as u8;
Hash(res)
}

const BLOCK_SIZE: usize = 64;

/// Engine to compute RIPEMD160 hash function.
#[derive(Clone)]
pub struct HashEngine {
buffer: [u8; BLOCK_SIZE],
h: [u32; 5],
bytes_hashed: u64,
}

impl HashEngine {
/// Constructs a new SHA256 hash engine.
pub const fn new() -> Self {
Self {
h: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0],
bytes_hashed: 0,
buffer: [0; BLOCK_SIZE],
}
}

#[cfg(not(hashes_fuzz))]
fn midstate(&self) -> [u8; 20] {
let mut ret = [0; 20];
for (val, ret_bytes) in self.h.iter().zip(ret.chunks_exact_mut(4)) {
ret_bytes.copy_from_slice(&(*val).to_le_bytes());
}
ret
}

#[cfg(hashes_fuzz)]
fn midstate(&self) -> [u8; 20] {
let mut ret = [0; 20];
ret.copy_from_slice(&self.buffer[..20]);
ret
}
}

impl Default for HashEngine {
fn default() -> Self { Self::new() }
}

impl crate::HashEngine for HashEngine {
const BLOCK_SIZE: usize = 64;

fn n_bytes_hashed(&self) -> u64 { self.bytes_hashed }

crate::internal_macros::engine_input_impl!();
}
Loading

0 comments on commit 16cf1f7

Please sign in to comment.