我有一个 64 个字符的 SHA256 哈希。
我希望训练一个可以预测用于生成哈希的明文是否以 1 开头的模型。
不管这是否“可能”,什么算法是最好的方法?
我最初的想法:
- 生成大量以 1 开头的散列样本和大量不以 1 开头的散列样本
- 将散列的 64 个字符中的每一个设置为某种无监督逻辑回归模型的参数。
- 通过告诉模型何时正确/错误来训练模型。
- 希望能够创建一个模型,该模型可以预测明文是否以 1 开头,并且具有足够高的准确度(并且具有不错的 kappa)
我有一个 64 个字符的 SHA256 哈希。
我希望训练一个可以预测用于生成哈希的明文是否以 1 开头的模型。
不管这是否“可能”,什么算法是最好的方法?
我最初的想法:
这不是一个真正的统计答案,但是:
不,您无法从哈希中确定明文的第一个字符,因为对于给定的哈希,没有“明文”之类的东西。
SHA-256 是一种散列算法。无论您的明文是什么,您都会得到一个 32 字节的签名,通常表示为 64 个字符的十六进制字符串。可能的明文远多于可能的 64 个字符的十六进制字符串 - 可以从任意数量的不同明文生成相同的哈希。没有理由相信第一个字符是/不是“1”在所有产生给定哈希的明文中是统一的。
SHA256 被设计为尽可能随机,因此您不太可能能够将来自 1 前缀明文的散列与不带前缀的明文分开;散列字符串的任何特征都不应该泄露该信息。
不管这是否“可能”,什么算法是最好的方法?
对不起,这是一个无意义的问题。如果某事是不可能的,那么您就无法寻找解决问题的最佳方法。
在这种情况下,这绝对是不可能的,因为散列是一种单向函数:多个输入(实际上是无限的)可以产生相同的输出。如果输入的第一位本身会以某种方式影响特定哈希值的概率,这将意味着哈希算法完全有缺陷。
您当然可以训练神经网络、线性分类器、SVM 等来尝试预测。如果您能够可靠地预测某个散列算法的输出输入,这将证明该算法毫无价值。我想说,对于像 SHA256 这样广泛使用的算法,这种可能性非常低。然而,快速排除新的、未经证实和未经测试的散列算法是一种合理的方法。
虽然不能用一个例子来证明否定的。我仍然觉得一个例子会很有启发性。也许有用。它确实显示了人们将如何(尝试)解决类似的问题。
在 我想进行二进制预测的情况下,使用二进制向量的特征,随机森林是一个不错的选择。我想这种回答你问题的第二部分:什么是好的算法。
我们很想将 SHA256 字符串预处理为二进制(布尔)向量,因为每个位在统计上是独立的,因此每个位都是一个很好的特征。这将使我们的输入成为 256 个元素的布尔向量。
这是一个演示如何使用 Julia DecisionTree.jl库来完成整个事情。
您可以将以下内容复制粘贴到 julia 提示符中。
using SHA
using DecisionTree
using Statistics: mean
using Random: randstring
const maxlen=10_000 # longest string (document) to be hashed.
gen_plaintext(x) = gen_plaintext(Val{x}())
gen_plaintext(::Val{true}) = "1" * randstring(rand(0:maxlen-1))
gen_plaintext(::Val{false}) = randstring(rand(1:maxlen))
bitvector(x) = BitVector(digits(x, base=2, pad=8sizeof(x)))
bitvector(x::AbstractVector) = reduce(vcat, bitvector.(x))
function gen_observation(class)
plaintext = gen_plaintext(class)
obs = bitvector(sha256(plaintext))
obs
end
function feature_mat(obs)
convert(Array, reduce(hcat, obs)')
end
########################################
const train_labels = rand(Bool, 100_000)
const train_obs = gen_observation.(train_labels)
const train_feature_mat = feature_mat(train_obs)
const test_labels = rand(Bool, 100_000)
const test_obs = gen_observation.(test_labels)
const test_feature_mat = feature_mat(test_obs)
# Train the model
const model = build_forest(train_labels, train_feature_mat)
@show model
#Training Set accuracy:
@show mean(apply_forest(model, train_feature_mat) .== train_labels)
#Test Set accuracy:
@show mean(apply_forest(model, test_feature_mat) .== test_labels)
当我这样做时,训练了 100,000 个长度不超过 10,000 的随机 ASCII 字符串。这是我看到的结果:
julia> const model = build_forest(train_labels, train_feature_mat)
Ensemble of Decision Trees
Trees: 10
Avg Leaves: 16124.7
Avg Depth: 17.9
julia> mean(apply_forest(model, train_feature_mat) .== train_labels)
0.95162
julia> mean(apply_forest(model, test_feature_mat) .== test_labels)
0.5016
所以这基本上没什么。我们从训练集的 95% 到测试集的 50% 以上。有人可以应用适当的假设检验,看看我们是否可以拒绝零
假设,但我很确定我们不能。这是对猜测率的微小改进。
这表明它无法学习。如果是随机森林,则可以从良好拟合到仅达到猜测率。随机森林非常有能力学习困难的输入。如果有什么要学的,我希望至少有几个百分点。
您可以通过更改代码来使用不同的哈希函数。这可能很有趣,当在内置hash
函数中使用 julia 时,我得到了基本相同的结果(这不是加密安全的 hsah,但仍然是一个很好的哈希,因此确实应该分开发送类似的字符串)。我也得到了基本相同的结果 CRC32c
。