やあ、
util.h の Hash()関数は Bitcoin の暗号化の大部分の基盤となっている:
template<typename T1>
inline uint256 Hash(const T1 pbegin, const T1 pend)
{
uint256 hash1;
SHA256((unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]), (unsigned char*)&hash1);
uint256 hash2;
SHA256((unsigned char*)&hash1, sizeof(hash1), (unsigned char*)&hash2);
return hash2;
}
ご覧の通り、これは 2回ハッシュすることでより安全にしようとしている。しかし、これは実際にはセキュリティを低下させる。純粋な SHA256 を破るには、攻撃者は既知の d に対して SHA256(d’) == SHA256(d)となる d’を見つける必要がある。これは Hash()を破るのにも十分だ。しかし攻撃者はハッシュの外側の層を攻撃することもでき、SHA256(d’) != SHA256(d)であっても SHA256(SHA256(d’)) == SHA256(SHA256(d))となる d’を見つけることができる。このように、二重ハッシュはハッシュを破ることを_より容易に_している!
より良い解決策は以下のようなものだろう:
template<typename T1>
inline vector<unsigned char> HashV(const T1 pbegin, const T1 pend)
{
uint256 sharesult;
uint160 riperesult;
SHA256((unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]), (unsigned char *)&sharesult);
RIPEMD160((unsigned char*)&pbegin[0], (pend - pbegin) * sizeof(pbegin[0]), (unsigned char *)&riperesult);
vector<unsigned char> ret;
ret.insert(ret.end(), (unsigned char *)(&sharesult), (unsigned char *)(&sharesult + 1));
ret.insert(ret.end(), (unsigned char *)(&riperesult), (unsigned char *)(&riperesult + 1));
return ret;
}
鍵はハッシュを結合するのではなく連結することだ。これにより攻撃者は両方のハッシュを破る必要がある - 最悪の場合でも、単一のハッシュよりも安全性が低くなることはない。
残念ながら、ハッシュを変更するとチェーンが壊れてしまうが……