Introduce the `small-hash` feature for `bitcoin_hashes`
When enabled this feature swaps the hash implementation of sha512, sha256 and ripemd160 for a smaller (but also slower) one. On embedded processors (Cortex-M4) it can lead to up to a 52% size reduction, from around 37KiB for just the `process_block` methods of the three hash functions to 17.8KiB.
This commit is contained in:
parent
29af523beb
commit
f2c5f19557
|
@ -1 +1,2 @@
|
|||
msrv = "1.48.0"
|
||||
too-many-arguments-threshold = 13
|
||||
|
|
|
@ -19,6 +19,8 @@ alloc = ["internals/alloc", "hex/alloc"]
|
|||
serde-std = ["serde/std"]
|
||||
# If you want I/O you must enable either "std" or "core2".
|
||||
core2 = ["actual-core2", "hex/core2"]
|
||||
# Smaller (but slower) implementation of sha256, sha512 and ripemd160
|
||||
small-hash = []
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = true
|
||||
|
|
|
@ -90,6 +90,31 @@ impl crate::HashEngine for HashEngine {
|
|||
engine_input_impl!();
|
||||
}
|
||||
|
||||
#[cfg(feature = "small-hash")]
|
||||
#[macro_use]
|
||||
mod small_hash {
|
||||
#[rustfmt::skip]
|
||||
pub(super) fn round(a: u32, _b: u32, c: u32, _d: u32, e: u32,
|
||||
x: u32, bits: u32, add: u32, round: u32,
|
||||
) -> (u32, u32) {
|
||||
let a = a.wrapping_add(round).wrapping_add(x).wrapping_add(add);
|
||||
let a = a.rotate_left(bits).wrapping_add(e);
|
||||
let c = c.rotate_left(10);
|
||||
|
||||
(a, c)
|
||||
}
|
||||
|
||||
macro_rules! round(
|
||||
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr,
|
||||
$x:expr, $bits:expr, $add:expr, $round:expr) => ({
|
||||
let updates = small_hash::round($a, $b, $c, $d, $e, $x, $bits, $add, $round);
|
||||
$a = updates.0;
|
||||
$c = updates.1;
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "small-hash"))]
|
||||
macro_rules! round(
|
||||
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr,
|
||||
$x:expr, $bits:expr, $add:expr, $round:expr) => ({
|
||||
|
|
|
@ -186,27 +186,75 @@ impl hex::FromHex for Midstate {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! Ch( ($x:expr, $y:expr, $z:expr) => ($z ^ ($x & ($y ^ $z))) );
|
||||
macro_rules! Maj( ($x:expr, $y:expr, $z:expr) => (($x & $y) | ($z & ($x | $y))) );
|
||||
macro_rules! Sigma0( ($x:expr) => ($x.rotate_left(30) ^ $x.rotate_left(19) ^ $x.rotate_left(10)) );
|
||||
macro_rules! Sigma1( ($x:expr) => ( $x.rotate_left(26) ^ $x.rotate_left(21) ^ $x.rotate_left(7)) );
|
||||
macro_rules! sigma0( ($x:expr) => ($x.rotate_left(25) ^ $x.rotate_left(14) ^ ($x >> 3)) );
|
||||
macro_rules! sigma1( ($x:expr) => ($x.rotate_left(15) ^ $x.rotate_left(13) ^ ($x >> 10)) );
|
||||
#[allow(non_snake_case)]
|
||||
const fn Ch(x: u32, y: u32, z: u32) -> u32 { z ^ (x & (y ^ z)) }
|
||||
#[allow(non_snake_case)]
|
||||
const fn Maj(x: u32, y: u32, z: u32) -> u32 { (x & y) | (z & (x | y)) }
|
||||
#[allow(non_snake_case)]
|
||||
const fn Sigma0(x: u32) -> u32 { x.rotate_left(30) ^ x.rotate_left(19) ^ x.rotate_left(10) }
|
||||
#[allow(non_snake_case)]
|
||||
const fn Sigma1(x: u32) -> u32 { x.rotate_left(26) ^ x.rotate_left(21) ^ x.rotate_left(7) }
|
||||
const fn sigma0(x: u32) -> u32 { x.rotate_left(25) ^ x.rotate_left(14) ^ (x >> 3) }
|
||||
const fn sigma1(x: u32) -> u32 { x.rotate_left(15) ^ x.rotate_left(13) ^ (x >> 10) }
|
||||
|
||||
#[cfg(feature = "small-hash")]
|
||||
#[macro_use]
|
||||
mod small_hash {
|
||||
use super::*;
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub(super) const fn round(a: u32, b: u32, c: u32, d: u32, e: u32,
|
||||
f: u32, g: u32, h: u32, k: u32, w: u32) -> (u32, u32) {
|
||||
let t1 =
|
||||
h.wrapping_add(Sigma1(e)).wrapping_add(Ch(e, f, g)).wrapping_add(k).wrapping_add(w);
|
||||
let t2 = Sigma0(a).wrapping_add(Maj(a, b, c));
|
||||
(d.wrapping_add(t1), t1.wrapping_add(t2))
|
||||
}
|
||||
#[rustfmt::skip]
|
||||
pub(super) const fn later_round(a: u32, b: u32, c: u32, d: u32, e: u32,
|
||||
f: u32, g: u32, h: u32, k: u32, w: u32,
|
||||
w1: u32, w2: u32, w3: u32,
|
||||
) -> (u32, u32, u32) {
|
||||
let w = w.wrapping_add(sigma1(w1)).wrapping_add(w2).wrapping_add(sigma0(w3));
|
||||
let (d, h) = round(a, b, c, d, e, f, g, h, k, w);
|
||||
(d, h, w)
|
||||
}
|
||||
|
||||
macro_rules! round(
|
||||
// first round
|
||||
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => (
|
||||
let t1 = $h.wrapping_add(Sigma1!($e)).wrapping_add(Ch!($e, $f, $g)).wrapping_add($k).wrapping_add($w);
|
||||
let t2 = Sigma0!($a).wrapping_add(Maj!($a, $b, $c));
|
||||
let updates = small_hash::round($a, $b, $c, $d, $e, $f, $g, $h, $k, $w);
|
||||
$d = updates.0;
|
||||
$h = updates.1;
|
||||
);
|
||||
// later rounds we reassign $w before doing the first-round computation
|
||||
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => (
|
||||
let updates = small_hash::later_round($a, $b, $c, $d, $e, $f, $g, $h, $k, $w, $w1, $w2, $w3);
|
||||
$d = updates.0;
|
||||
$h = updates.1;
|
||||
$w = updates.2;
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "small-hash"))]
|
||||
#[macro_use]
|
||||
mod fast_hash {
|
||||
macro_rules! round(
|
||||
// first round
|
||||
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => (
|
||||
let t1 = $h.wrapping_add(Sigma1($e)).wrapping_add(Ch($e, $f, $g)).wrapping_add($k).wrapping_add($w);
|
||||
let t2 = Sigma0($a).wrapping_add(Maj($a, $b, $c));
|
||||
$d = $d.wrapping_add(t1);
|
||||
$h = t1.wrapping_add(t2);
|
||||
);
|
||||
// later rounds we reassign $w before doing the first-round computation
|
||||
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => (
|
||||
$w = $w.wrapping_add(sigma1!($w1)).wrapping_add($w2).wrapping_add(sigma0!($w3));
|
||||
$w = $w.wrapping_add(sigma1($w1)).wrapping_add($w2).wrapping_add(sigma0($w3));
|
||||
round!($a, $b, $c, $d, $e, $f, $g, $h, $k, $w);
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
impl Midstate {
|
||||
#[allow(clippy::identity_op)] // more readble
|
||||
|
|
|
@ -123,27 +123,72 @@ pub(crate) fn from_engine(e: HashEngine) -> Hash {
|
|||
Hash(hash)
|
||||
}
|
||||
|
||||
macro_rules! Ch( ($x:expr, $y:expr, $z:expr) => ($z ^ ($x & ($y ^ $z))) );
|
||||
macro_rules! Maj( ($x:expr, $y:expr, $z:expr) => (($x & $y) | ($z & ($x | $y))) );
|
||||
macro_rules! Sigma0( ($x:expr) => ($x.rotate_left(36) ^ $x.rotate_left(30) ^ $x.rotate_left(25)) );
|
||||
macro_rules! Sigma1( ($x:expr) => ($x.rotate_left(50) ^ $x.rotate_left(46) ^ $x.rotate_left(23)) );
|
||||
macro_rules! sigma0( ($x:expr) => ($x.rotate_left(63) ^ $x.rotate_left(56) ^ ($x >> 7)) );
|
||||
macro_rules! sigma1( ($x:expr) => ($x.rotate_left(45) ^ $x.rotate_left(3) ^ ($x >> 6)) );
|
||||
#[allow(non_snake_case)]
|
||||
fn Ch(x: u64, y: u64, z: u64) -> u64 { z ^ (x & (y ^ z)) }
|
||||
#[allow(non_snake_case)]
|
||||
fn Maj(x: u64, y: u64, z: u64) -> u64 { (x & y) | (z & (x | y)) }
|
||||
#[allow(non_snake_case)]
|
||||
fn Sigma0(x: u64) -> u64 { x.rotate_left(36) ^ x.rotate_left(30) ^ x.rotate_left(25) }
|
||||
#[allow(non_snake_case)]
|
||||
fn Sigma1(x: u64) -> u64 { x.rotate_left(50) ^ x.rotate_left(46) ^ x.rotate_left(23) }
|
||||
fn sigma0(x: u64) -> u64 { x.rotate_left(63) ^ x.rotate_left(56) ^ (x >> 7) }
|
||||
fn sigma1(x: u64) -> u64 { x.rotate_left(45) ^ x.rotate_left(3) ^ (x >> 6) }
|
||||
|
||||
#[cfg(feature = "small-hash")]
|
||||
#[macro_use]
|
||||
mod small_hash {
|
||||
use super::*;
|
||||
|
||||
#[rustfmt::skip]
|
||||
pub(super) fn round(a: u64, b: u64, c: u64, d: &mut u64, e: u64,
|
||||
f: u64, g: u64, h: &mut u64, k: u64, w: u64,
|
||||
) {
|
||||
let t1 =
|
||||
h.wrapping_add(Sigma1(e)).wrapping_add(Ch(e, f, g)).wrapping_add(k).wrapping_add(w);
|
||||
let t2 = Sigma0(a).wrapping_add(Maj(a, b, c));
|
||||
*d = d.wrapping_add(t1);
|
||||
*h = t1.wrapping_add(t2);
|
||||
}
|
||||
#[rustfmt::skip]
|
||||
pub(super) fn later_round(a: u64, b: u64, c: u64, d: &mut u64, e: u64,
|
||||
f: u64, g: u64, h: &mut u64, k: u64, w: u64,
|
||||
w1: u64, w2: u64, w3: u64,
|
||||
) -> u64 {
|
||||
let w = w.wrapping_add(sigma1(w1)).wrapping_add(w2).wrapping_add(sigma0(w3));
|
||||
round(a, b, c, d, e, f, g, h, k, w);
|
||||
w
|
||||
}
|
||||
|
||||
macro_rules! round(
|
||||
// first round
|
||||
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => (
|
||||
let t1 = $h.wrapping_add(Sigma1!($e)).wrapping_add(Ch!($e, $f, $g)).wrapping_add($k).wrapping_add($w);
|
||||
let t2 = Sigma0!($a).wrapping_add(Maj!($a, $b, $c));
|
||||
small_hash::round($a, $b, $c, &mut $d, $e, $f, $g, &mut $h, $k, $w)
|
||||
);
|
||||
// later rounds we reassign $w before doing the first-round computation
|
||||
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => (
|
||||
$w = small_hash::later_round($a, $b, $c, &mut $d, $e, $f, $g, &mut $h, $k, $w, $w1, $w2, $w3)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "small-hash"))]
|
||||
#[macro_use]
|
||||
mod fast_hash {
|
||||
macro_rules! round(
|
||||
// first round
|
||||
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr) => (
|
||||
let t1 = $h.wrapping_add(Sigma1($e)).wrapping_add(Ch($e, $f, $g)).wrapping_add($k).wrapping_add($w);
|
||||
let t2 = Sigma0($a).wrapping_add(Maj($a, $b, $c));
|
||||
$d = $d.wrapping_add(t1);
|
||||
$h = t1.wrapping_add(t2);
|
||||
);
|
||||
// later rounds we reassign $w before doing the first-round computation
|
||||
($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr, $k:expr, $w:expr, $w1:expr, $w2:expr, $w3:expr) => (
|
||||
$w = $w.wrapping_add(sigma1!($w1)).wrapping_add($w2).wrapping_add(sigma0!($w3));
|
||||
$w = $w.wrapping_add(sigma1($w1)).wrapping_add($w2).wrapping_add(sigma0($w3));
|
||||
round!($a, $b, $c, $d, $e, $f, $g, $h, $k, $w);
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
impl HashEngine {
|
||||
// Algorithm copied from libsecp256k1
|
||||
|
|
Loading…
Reference in New Issue