Why are the results of hash() and hasher.write() not the same? - hash

A number like 1234 has the same results if I use either hash() or hasher.write() functions, but a byte slice like b"Cool" does not. I think it should be the same; why is it not?
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::mem;
fn main() {
let mut hasher = DefaultHasher::new();
1234.hash(&mut hasher);
println!("Hash is {:x}", hasher.finish());
let mut hasher = DefaultHasher::new();
hasher.write(unsafe { &mem::transmute::<i32, [u8; 4]>(1234) });
println!("Hash is {:x}", hasher.finish());
let mut hasher = DefaultHasher::new();
b"Cool".hash(&mut hasher);
println!("Hash is {:x}", hasher.finish());
let mut hasher = DefaultHasher::new();
hasher.write(b"Cool");
println!("Hash is {:x}", hasher.finish());
}
Hash is 702c1e2053bd76
Hash is 702c1e2053bd76
Hash is 9bf15988582e5a3f
Hash is 7fe67a564a06876a

As the documentation says:
The default Hasher used by RandomState. The internal algorithm is not specified, and so it and its hashes should not be relied upon over releases.
If we follow RandomState...
A particular instance RandomState will create the same instances of Hasher, but the hashers created by two different RandomState instances are unlikely to produce the same result for the same values.
Rationale:
By default, HashMap uses a hashing algorithm selected to provide resistance against HashDoS attacks. The algorithm is randomly seeded, and a reasonable best-effort is made to generate this seed from a high quality, secure source of randomness provided by the host without blocking the program. Because of this, the randomness of the seed depends on the output quality of the system's random number generator when the seed is created. In particular, seeds generated when the system's entropy pool is abnormally low such as during system boot may be of a lower quality.
I dug into it a little bit and there is no requirement that hash() and write() share the same behavior.
The only requirement is that k1 == k2 -> hash(k1) == hash(k2) for the Hash trait. The Hasher trait has the same property, but there is no requirement that k1 -> hash(k1) == hasher(k1).
That makes sense as the Hash trait is intended to be implemented by the user, and they can implement it as they like. For example, one could want to add salt into the hash.
Here is a minimal complete and not verifiable example, that could produce either the same output or different output, depending on the implementation:
use std::collections::hash_map::{DefaultHasher, RandomState};
use std::hash::{BuildHasher, Hasher, Hash};
fn main() {
let s = RandomState::new();
let mut hasher = s.build_hasher();
b"Cool".hash(&mut hasher);
println!("Hash is {:x}", hasher.finish());
let mut hasher = s.build_hasher();
hasher.write(b"Cool");
println!("Hash is {:x}", hasher.finish());
let s = DefaultHasher::new();
let mut hasher = s.clone();
b"Cool".hash(&mut hasher);
println!("Hash is {:x}", hasher.finish());
let mut hasher = s.clone();
hasher.write(b"Cool");
println!("Hash is {:x}", hasher.finish());
}
You can see that the implementation of Hash for a slice also writes the length of the slice:
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Hash> Hash for [T] {
fn hash<H: Hasher>(&self, state: &mut H) {
self.len().hash(state);
Hash::hash_slice(self, state)
}
}
Also, it looks like hash_slice() has the behavior you want, but it's not stated that it would always be the case (but I think this is the intended behavior and that will not change, I asked here).
use std::collections::hash_map::DefaultHasher;
use std::hash::Hasher;
fn main() {
let s = DefaultHasher::new();
let mut hasher = s.clone();
std::hash::Hash::hash_slice(b"Cool", &mut hasher);
println!("Hash is {:x}", hasher.finish());
let mut hasher = s.clone();
hasher.write(b"Cool");
println!("Hash is {:x}", hasher.finish());
}

Related

Merging two dictionaries asynchronously in Swift

I am having a problem with merging two dictionaries asynchronously. The idea is to execute calculation function that returns a dictionary multiple times asynchronously and then merge results into a single dictionary. I tried following:
var subResult: [String: Result] = [:]
let stride = (max_val - min_val) / 2 + 1
DispatchQueue.concurrentPerform(iterations: stride) { index in
let c_size = max_val + 2*index
var s_size = min_provided
var localResult: [String: Result] = [:]
repeat {
let res = SubFlow().process(data: data, cSize: c_size, sSize: s_size)
localResult.merge( res ) { (current, _) in current }
s_size += 2
} while (s_size <= c_size)
subResult.merge( localResult ) { (current, _) in current }
}
This solution works, but I don't see it as a reliable one as we are mutating dictionary asynchronously. I am new to Swift and not sure how I can implement "safe" and performant merge in this case?
As dictionaries are not thread-safe in Swift, you need to make sure that all writes to a dictionary happen on the same queue.
You can achieve it by either creating a serial queue or by creating a concurrent queue while making sure that the write operations are executed with barriers. The latter approach will allow concurrent reads from the object while it's not being written to:
var subResult: [String: Int] = [:]
let resultUpdateQueue = DispatchQueue(label: "com.example.myapp.resultUpdateQueue", attributes: .concurrent)
DispatchQueue.concurrentPerform(iterations: 10) { index in
let localResult = ["sample\(index)":index]
resultUpdateQueue.sync(flags: .barrier) {
subResult.merge( localResult ) { (current, _) in current }
}
}
print(subResult)
Be sure not to execute .concurrentPerform() on the main queue because it will wait until all the iterations have completed.
No, this is not safe. It's undefined behavior and I'm somewhat surprised it works.
Instead, you should be generating sub-results in parallel, and then merging them together serially. Something along the lines of:
DispatchQueue.concurrentPerform(iterations: stride) { index in
// ... call process and generated localResults ...
serialQueue.dispatchAsync { subResult.merge ... }
}

Wy md5 hash gives me different result using swift

I want to implement digest authentication with Swift. Unfortunately after hours of testing I saw that using this method of creating the md5 hash gives me the wrong result.
extension String {
var md5: String {
let data = Data(self.utf8)
let hash = data.withUnsafeBytes { (bytes: UnsafeRawBufferPointer) -> [UInt8] in
var hash = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
CC_MD5(bytes.baseAddress, CC_LONG(data.count), &hash)
return hash
}
return hash.map { String(format: "%02x", $0) }.joined()
}
}
using this string
let test = "test:testrealm#host.com:pwd123".md5
test has the value: 4ec2086d6f09366e4683dbdc5809444a but it should have 939e7578ed9e3c518a452acee763bce9 (following a digest auth. documentation). So me digest was always calculated in the wrong manner.
Thanks
Arnold
My error, it gives me the right result. I had an error computing the hash. The string extension is ok.

How to include a json-rpc in the pow consensus building on Substrate?

In the pow consensus module of substrate, the miner does not dig ore by means of RPC access, how to access?
I don't have idea.
fn mine(
&self,
parent: &BlockId<B>,
pre_hash: &H256,
difficulty: Difficulty,
round: u32,
) -> Result<Option<RawSeal>, String> {
let mut rng = SmallRng::from_rng(&mut thread_rng())
.map_err(|e| format!("Initialize RNG failed for mining: {:?}", e))?;
let key_hash = key_hash(self.client.as_ref(), parent)?;
for _ in 0..round {
let nonce = H256::random_using(&mut rng);
let compute = Compute {
key_hash,
difficulty,
pre_hash: *pre_hash,
nonce,
};
let seal = compute.compute();
if is_valid_hash(&seal.work, difficulty) {
return Ok(Some(seal.encode()))
}
}
Ok(None)
}
I suggest you follow a pattern similar to Kulupu for creating a PoW Substrate blockchain.
In Kulupu, it seems the Substrate service starts mining if it detects your are an "authority":
/// Builds a new service for a full client.
pub fn new_full<C: Send + Default + 'static>(config: Configuration<C, GenesisConfig>, author: Option<&str>, threads: usize, round: u32)
-> Result<impl AbstractService, ServiceError>
{
let is_authority = config.roles.is_authority();
let (builder, inherent_data_providers) = new_full_start!(config, author);
let service = builder
.with_network_protocol(|_| Ok(NodeProtocol::new()))?
.with_finality_proof_provider(|_client, _backend| {
Ok(Arc::new(()) as _)
})?
.build()?;
if is_authority {
for _ in 0..threads {
let proposer = basic_authorship::ProposerFactory {
client: service.client(),
transaction_pool: service.transaction_pool(),
};
consensus_pow::start_mine(
Box::new(service.client().clone()),
service.client(),
kulupu_pow::RandomXAlgorithm::new(service.client()),
proposer,
None,
round,
service.network(),
std::time::Duration::new(2, 0),
service.select_chain().map(|v| v.clone()),
inherent_data_providers.clone(),
);
}
}
Ok(service)
}
In this case, you just need to start your node with the --validator flag and an --author flag with address:
cargo run --release -- --validator --author 0x7e946b7dd192307b4538d664ead95474062ac3738e04b5f3084998b76bc5122d

How to replicate hash_hmac('sha256', $key, $secret_key) function in Swift 4?

I've tried generating the hash_hmac('sha256', $key, $secret_key) php function equivalent in Swift 4 without success, after using libraries like CommonCrypto, CryptoSwift. I need these function for API authentication, using Alamofire library, which is a great library. Since i use Swift 4 the compatibility with other Swift libraries is not so good. Even with CryptoSwift which has the latest version(0.7.1) for Swift 4 i still get a lot of compatibility errors likes
enter image description here
Swift 3/4:
HMAC with MD5, SHA1, SHA224, SHA256, SHA384, SHA512 (Swift 3)
These functions will hash either String or Data input with one of eight cryptographic hash algorithms.
The name parameter specifies the hash function name as a String
Supported functions are MD5, SHA1, SHA224, SHA256, SHA384 and SHA512
This example requires Common Crypto
It is necessary to have a bridging header to the project:
#import <CommonCrypto/CommonCrypto.h>
Add the Security.framework to the project.
These functions takes a hash name, message to be hashed, a key and return a digest:
hashName: name of a hash function as String
message: message as Data
key: key as Data
returns: digest as Data
func hmac(hashName:String, message:Data, key:Data) -> Data? {
let algos = ["SHA1": (kCCHmacAlgSHA1, CC_SHA1_DIGEST_LENGTH),
"MD5": (kCCHmacAlgMD5, CC_MD5_DIGEST_LENGTH),
"SHA224": (kCCHmacAlgSHA224, CC_SHA224_DIGEST_LENGTH),
"SHA256": (kCCHmacAlgSHA256, CC_SHA256_DIGEST_LENGTH),
"SHA384": (kCCHmacAlgSHA384, CC_SHA384_DIGEST_LENGTH),
"SHA512": (kCCHmacAlgSHA512, CC_SHA512_DIGEST_LENGTH)]
guard let (hashAlgorithm, length) = algos[hashName] else { return nil }
var macData = Data(count: Int(length))
macData.withUnsafeMutableBytes {macBytes in
message.withUnsafeBytes {messageBytes in
key.withUnsafeBytes {keyBytes in
CCHmac(CCHmacAlgorithm(hashAlgorithm),
keyBytes, key.count,
messageBytes, message.count,
macBytes)
}
}
}
return macData
}
hashName: name of a hash function as String
message: message as String
key: key as String
returns: digest as Data
func hmac(hashName:String, message:String, key:String) -> Data? {
let messageData = message.data(using:.utf8)!
let keyData = key.data(using:.utf8)!
return hmac(hashName:hashName, message:messageData, key:keyData)
}
hashName: name of a hash function as String
message: message as String
key: key as Data
returns: digest as Data
func hmac(hashName:String, message:String, key:Data) -> Data? {
let messageData = message.data(using:.utf8)!
return hmac(hashName:hashName, message:messageData, key:key)
}
// Examples
let clearString = "clearData0123456"
let keyString = "keyData8901234562"
let clearData = clearString.data(using:.utf8)!
let keyData = keyString.data(using:.utf8)!
print("clearString: \(clearString)")
print("keyString: \(keyString)")
print("clearData: \(clearData as NSData)")
print("keyData: \(keyData as NSData)")
let hmacData1 = hmac(hashName:"SHA1", message:clearData, key:keyData)
print("hmacData1: \(hmacData1! as NSData)")
let hmacData2 = hmac(hashName:"SHA1", message:clearString, key:keyString)
print("hmacData2: \(hmacData2! as NSData)")
let hmacData3 = hmac(hashName:"SHA1", message:clearString, key:keyData)
print("hmacData3: \(hmacData3! as NSData)")
Output:
clearString: clearData0123456
keyString: keyData8901234562
clearData: <636c6561 72446174 61303132 33343536>
keyData: <6b657944 61746138 39303132 33343536 32>
hmacData1: <bb358f41 79b68c08 8e93191a da7dabbc 138f2ae6>
hmacData2: <bb358f41 79b68c08 8e93191a da7dabbc 138f2ae6>
hmacData3: <bb358f41 79b68c08 8e93191a da7dabbc 138f2ae6>
First of all it might be better to go straight for SHA512, SHA is notoriously easy to crack with GPU's, thus upping the memory scale a bit is not a bad idea.
Second, using CommonCrypto it is actually extremely easy to generate HMAC's, this is the implementation that I use:
static func hmac(_ secretKey: inout [UInt8], cipherText: inout [UInt8], algorithm: CommonCrypto.HMACAlgorithm = .sha512) -> [UInt8] {
var mac = [UInt8](repeating: 0, count: 64)
CCHmac(algorithm.value, &secretKey, secretKey.count, &cipherText, cipherText.count, &mac)
return mac
}
Where the algorithm is defined as such:
enum HMACAlgorithm {
case sha512
var value: UInt32 {
switch(self) {
case .sha512:
return UInt32(kCCHmacAlgSHA512)
}
}
}
My cipher text is cipherText+IV in this instance. When you are not using AES-GCM it seems suggested / recommended to HMAC IV+Cipher, but I cannot give you the technical details as to why.
Converting Data or NSData to a byte array:
var byteArray = data.withUnsafeBytes { [UInt8](UnsafeBufferPointer(start: $0, count: data.count) }
The reason for using an array is a substantial performance increase over Data, I don't know what the core team is doing but Data performs worse than NSMutableData even.

MD5 of Data in Swift 3

I am trying to get MD5 hash of my data (image downloaded from the interweb). Unfortunately I have upgraded the framework to swift 3 and the method I have been using doesn't work now.
I have converted most of it but I am unable to get bytes out of the data:
import Foundation
import CommonCrypto
struct MD5 {
static func get(data: Data) -> String {
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
CC_MD5(data.bytes, CC_LONG(data.count), &digest)
var digestHex = ""
for index in 0..<Int(CC_MD5_DIGEST_LENGTH) {
digestHex += String(format: "%02x", digest[index])
}
return digestHex
}
}
the CommonCrypto is already imported as a custom module. Problem is I am getting 'bytes' is unavailable: use withUnsafeBytes instead on CC_MD5(data.bytes,...
So the question really is, how do I get the bytes out of the data and will this solution work?
CC_MD5(data.bytes, CC_LONG(data.count), &digest)
As noted, bytes is unavailable because it's dangerous. It's a raw pointer into memory than can vanish. The recommended solution is to use withUnsafeBytes which promises that the target cannot vanish during the scope of the pointer. From memory, it would look something like this:
data.withUnsafeBytes { bytes in
CC_MD5(bytes, CC_LONG(data.count), &digest)
}
The point is that the bytes pointer can't escape into scopes where data is no longer valid.
For an example of this with CCHmac, which is pretty similar to MD5, see RNCryptor.
Here's a one liner:
import CryptoKit
let md5String = Insecure.MD5.hash(data: data).map { String(format: "%02hhx", $0) }.joined()
And for anyone that's interested, here's an example that you could build upon to support different Algorithms:
Usage:
Checksum.hash(data: data, using: .md5) == "MyMD5Hash"
Code Snippet:
import Foundation
import CommonCrypto
struct Checksum {
private init() {}
static func hash(data: Data, using algorithm: HashAlgorithm) -> String {
/// Creates an array of unsigned 8 bit integers that contains zeros equal in amount to the digest length
var digest = [UInt8](repeating: 0, count: algorithm.digestLength())
/// Call corresponding digest calculation
data.withUnsafeBytes {
algorithm.digestCalculation(data: $0.baseAddress, len: UInt32(data.count), digestArray: &digest)
}
var hashString = ""
/// Unpack each byte in the digest array and add them to the hashString
for byte in digest {
hashString += String(format:"%02x", UInt8(byte))
}
return hashString
}
/**
* Hash using CommonCrypto
* API exposed from CommonCrypto-60118.50.1:
* https://opensource.apple.com/source/CommonCrypto/CommonCrypto-60118.50.1/include/CommonDigest.h.auto.html
**/
enum HashAlgorithm {
case md5
case sha256
func digestLength() -> Int {
switch self {
case .md5:
return Int(CC_MD5_DIGEST_LENGTH)
case .sha256:
return Int(CC_SHA256_DIGEST_LENGTH)
}
}
/// CC_[HashAlgorithm] performs a digest calculation and places the result in the caller-supplied buffer for digest
/// Calls the given closure with a pointer to the underlying unsafe bytes of the data's contiguous storage.
func digestCalculation(data: UnsafeRawPointer!, len: UInt32, digestArray: UnsafeMutablePointer<UInt8>!) {
switch self {
case .md5:
CC_MD5(data, len, digestArray)
case .sha256:
CC_SHA256(data, len, digestArray)
}
}
}
}