litecoin_hashes/
hash160.rs

1// Bitcoin Hashes Library
2// Written in 2018 by
3//   Andrew Poelstra <apoelstra@wpsoftware.net>
4//
5// To the extent possible under law, the author(s) have dedicated all
6// copyright and related and neighboring rights to this software to
7// the public domain worldwide. This software is distributed without
8// any warranty.
9//
10// You should have received a copy of the CC0 Public Domain Dedication
11// along with this software.
12// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
13//
14
15// This module is largely copied from the rust-crypto ripemd.rs file;
16// while rust-crypto is licensed under Apache, that file specifically
17// was written entirely by Andrew Poelstra, who is re-licensing its
18// contents here as CC0.
19
20//! HASH160 (SHA256 then RIPEMD160) implementation.
21//!
22
23use core::str;
24use core::ops::Index;
25use core::slice::SliceIndex;
26
27use crate::{Error, ripemd160, sha256};
28
29crate::internal_macros::hash_type! {
30    160,
31    false,
32    "Output of the Bitcoin HASH160 hash function. (RIPEMD160(SHA256))",
33    "crate::util::json_hex_string::len_20"
34}
35
36type HashEngine = sha256::HashEngine;
37
38fn from_engine(e: HashEngine) -> Hash {
39    use crate::Hash as _;
40
41    let sha2 = sha256::Hash::from_engine(e);
42    let rmd = ripemd160::Hash::hash(&sha2[..]);
43
44    let mut ret = [0; 20];
45    ret.copy_from_slice(&rmd[..]);
46    Hash(ret)
47}
48
49#[cfg(test)]
50mod tests {
51    #[test]
52    #[cfg(feature = "alloc")]
53    fn test() {
54        use crate::{hash160, Hash, HashEngine};
55
56        #[derive(Clone)]
57        #[cfg(feature = "alloc")]
58        struct Test {
59            input: Vec<u8>,
60            output: Vec<u8>,
61            output_str: &'static str,
62        }
63
64        let tests = vec![
65            // Uncompressed pubkey obtained from Bitcoin key; data from validateaddress
66            Test {
67                input: vec![
68                    0x04, 0xa1, 0x49, 0xd7, 0x6c, 0x5d, 0xe2, 0x7a, 0x2d,
69                    0xdb, 0xfa, 0xa1, 0x24, 0x6c, 0x4a, 0xdc, 0xd2, 0xb6,
70                    0xf7, 0xaa, 0x29, 0x54, 0xc2, 0xe2, 0x53, 0x03, 0xf5,
71                    0x51, 0x54, 0xca, 0xad, 0x91, 0x52, 0xe4, 0xf7, 0xe4,
72                    0xb8, 0x5d, 0xf1, 0x69, 0xc1, 0x8a, 0x3c, 0x69, 0x7f,
73                    0xbb, 0x2d, 0xc4, 0xec, 0xef, 0x94, 0xac, 0x55, 0xfe,
74                    0x81, 0x64, 0xcc, 0xf9, 0x82, 0xa1, 0x38, 0x69, 0x1a,
75                    0x55, 0x19,
76                ],
77                output: vec![
78                    0xda, 0x0b, 0x34, 0x52, 0xb0, 0x6f, 0xe3, 0x41,
79                    0x62, 0x6a, 0xd0, 0x94, 0x9c, 0x18, 0x3f, 0xbd,
80                    0xa5, 0x67, 0x68, 0x26,
81                ],
82                output_str: "da0b3452b06fe341626ad0949c183fbda5676826",
83            },
84        ];
85
86        for test in tests {
87            // Hash through high-level API, check hex encoding/decoding
88            let hash = hash160::Hash::hash(&test.input[..]);
89            assert_eq!(hash, test.output_str.parse::<hash160::Hash>().expect("parse hex"));
90            assert_eq!(&hash[..], &test.output[..]);
91            assert_eq!(&hash.to_string(), &test.output_str);
92
93            // Hash through engine, checking that we can input byte by byte
94            let mut engine = hash160::Hash::engine();
95            for ch in test.input {
96                engine.input(&[ch]);
97            }
98            let manual_hash = Hash::from_engine(engine);
99            assert_eq!(hash, manual_hash);
100            assert_eq!(hash.into_inner()[..].as_ref(), test.output.as_slice());
101        }
102    }
103
104    #[cfg(feature = "serde")]
105    #[test]
106    fn ripemd_serde() {
107        use serde_test::{Configure, Token, assert_tokens};
108        use crate::{hash160, Hash};
109
110        static HASH_BYTES: [u8; 20] = [
111            0x13, 0x20, 0x72, 0xdf,
112            0x69, 0x09, 0x33, 0x83,
113            0x5e, 0xb8, 0xb6, 0xad,
114            0x0b, 0x77, 0xe7, 0xb6,
115            0xf1, 0x4a, 0xca, 0xd7,
116        ];
117
118        let hash = hash160::Hash::from_slice(&HASH_BYTES).expect("right number of bytes");
119        assert_tokens(&hash.compact(), &[Token::BorrowedBytes(&HASH_BYTES[..])]);
120        assert_tokens(&hash.readable(), &[Token::Str("132072df690933835eb8b6ad0b77e7b6f14acad7")]);
121    }
122}
123
124#[cfg(bench)]
125mod benches {
126    use test::Bencher;
127
128    use crate::{Hash, HashEngine, hash160};
129
130    #[bench]
131    pub fn hash160_10(bh: &mut Bencher) {
132        let mut engine = hash160::Hash::engine();
133        let bytes = [1u8; 10];
134        bh.iter( || {
135            engine.input(&bytes);
136        });
137        bh.bytes = bytes.len() as u64;
138    }
139
140    #[bench]
141    pub fn hash160_1k(bh: &mut Bencher) {
142        let mut engine = hash160::Hash::engine();
143        let bytes = [1u8; 1024];
144        bh.iter( || {
145            engine.input(&bytes);
146        });
147        bh.bytes = bytes.len() as u64;
148    }
149
150    #[bench]
151    pub fn hash160_64k(bh: &mut Bencher) {
152        let mut engine = hash160::Hash::engine();
153        let bytes = [1u8; 65536];
154        bh.iter( || {
155            engine.input(&bytes);
156        });
157        bh.bytes = bytes.len() as u64;
158    }
159}