使用加密哈希和以太坊区块链确保数据完整性
TL;DR · AI 摘要
本文提出了一种利用加密哈希与以太坊区块链结合的方法,实现数据完整性验证:通过计算数据集的哈希值并将其写入以太坊测试网的交易输入字段,创建不可篡改、可验证的数据指纹记录,成本低至每笔交易约0.04美元。
核心要点
- 使用SHA-256等加密哈希函数生成数据集的唯一指纹,确保任何微小改动都会导致哈希值完全不同。
- 将哈希值写入以太坊测试网的交易输入字段(calldata),无需智能合约即可实现低成本、不可变的数据存证。
- 该方法适用于分布式团队协作场景,如机器学习特征集共享,支持跨组织、跨版本的数据一致性验证。
结构提纲
按章节快速跳转。
- §引言
文章介绍在分布式机器学习环境中确保数据集同步和不可修改的重要性。
数据完整性对机器学习项目至关重要,微小错误可能导致模型性能严重下降或实验无法复现。
加密哈希函数能为任意大小的数据生成固定长度的唯一指纹,用于快速验证数据是否被篡改。
以太坊区块链提供不可变、去中心化和永久可用的数据存储能力,适合用于数据完整性记录。
通过将哈希值写入以太坊测试网的交易输入字段,避免智能合约开销,实现低成本数据存证。
思维导图
用一张图看清主题之间的关系。
查看大纲文本(无障碍 / 无 JS 友好)
- 数据完整性保障
- 加密哈希
- SHA-256
- 确定性输出
- 以太坊区块链
- 不可变性
- 去中心化
- 测试网成本
- 应用场景
- 分布式机器学习
- 数据集共享
金句 / Highlights
值得收藏与分享的关键句。
Same data in → same hash out: even a single byte change produces a completely different hash.
Writing the hash to Ethereum's calldata field allows for immutability without smart contracts, reducing costs significantly.
On Ethereum testnet, storing a hash costs between $0.04 and $0.10 per transaction, making it feasible for frequent use.
标题:使用密码哈希和以太坊区块链确保数据完整性
来源网址:https://towardsdatascience.com/ensuring-data-integrity-with-cryptographic-hashing-and-the-ethereum-blockchain/
发布日期:2026-06-01T15:00:00+00:00
Markdown 内容: 科学工作流程中,团队通常需要访问一个始终保持同步且无法被修改的共享数据集,例如在分布式机器学习环境中,多个团队依赖完全相同的功能集。
在本文中,我将介绍一种简单、免费的方法,用于对任意大小的数据集进行密码学哈希处理,并将其哈希值不可变地存储在以太坊区块链上,从而创建该数据集完整性的永久且可验证的记录。
这种方法还可以轻松扩展到模型权重、需要以一致方式应用的特定转换、源代码或其他需要不可变性和可验证性的数据。
为什么完整性很重要
如果你对数据科学实践至少有一定了解,你已经意识到数据完整性的重要性。即使输入数据中的微小更改或错误也可能导致项目崩溃。
现代机器学习模型对其训练数据极为敏感。缺失的归一化步骤、修改过的 CSV 文件、打乱的行、损坏的特征或训练与验证数据集之间的不匹配都可能导致截然不同的结果。
完整性失败难以检测,且往往会造成严重干扰。
模型可能仍然看起来正常运行或可以训练,但指标会缓慢下降,漂移累积,实验变得无法重现。当团队分布广泛,可能跨越不同组织,并需要在同一问题的不同版本上工作时,完整性尤为重要。
使用密码哈希作为“真相来源”
密码哈希为我们提供了一种简单而非常有用的机制来验证数据完整性。
密码哈希简要介绍
哈希函数接受任意数量的输入数据(字节),并确定性地生成一个固定长度的输出,称为哈希或摘要。密码哈希是计算机科学的基础,你很可能已经知道这一点。
关键在于确定性:
相同的数据输入 → 相同的哈希输出
即使输入数据中只有一个字节发生变化,也会产生完全不同的哈希值。
由于这一特性,哈希值充当了数据的唯一指纹,对于验证完整性非常有用。有许多不同类型的哈希函数,正如我将描述的那样,其中一些更适合这项任务。
这如何应用于数据集?
由于哈希函数的确定性,一旦应用于数据集,我们就可以快速可靠地测试数据集是否与我们预期的完全相同。
这在由多个团队、多个公司使用的大型数据集中尤其有价值,这些数据集从一个版本过渡到下一个版本。例如,Alpha 研究小组的团队 1 创建功能 1-10,Zeta 研究小组的团队 2 创建功能 10-100,系统 X 消费版本 Y,等等。
我们不再需要质疑数据,只需对数据集计算哈希函数,并将其与参考点计算的哈希值进行比较。如果匹配,则没问题。如果不匹配,则说明某些内容发生了变化。
哈希非常高效。对 10MB 或 10TB 的数据集运行哈希函数可以快速得到一个小型、固定大小的字符串,可以共享、存储或发布。
为什么使用以太坊作为不可变存储?
这才是本文真正有用的部分。
以太坊,正如你已经知道的,是一个区块链。这为我们提供了:
- 不可变性:交易永远无法更改
- 分布式可用性:无需中央权威即可始终访问
- 永久性:一旦写入,就永久可访问
但是,以太坊是用来处理交易的?我们不需要为这个特殊目的编写复杂的智能合约吗?
你确实可以这样做。但我们不需要。
巧妙之处在于利用以太坊 交易 中不常用的“输入数据”字段,有时也称为“calldata”。
但是,以太坊交易需要真实金钱(gas、费用等)吗?
这也是事实。在以太坊上,每个输入数据字节都会收取“gas”。在主网,以每 ETH 2,000 美元的价格计算,这可能会花费我们 0.04 至 0.10 美元的哈希值。这还不包括区块验证者包含实际转账所需的 gas,其费用取决于网络当前的负载情况。
让我们变得更聪明些。
通过将所有内容转移到“测试网”,这是每个区块链通常都有的,我们可以使其完全免费。
Sepolia(以太坊测试网)除非你是智能合约开发者,否则很少使用。Sepolia ETH 是免费且公开可用的,可以从水龙头获取。
这意味着我们可以在公开可访问的测试网(以太坊称为 Sepolia)上创建无限量的交易,而且完全免费!
只要我们的输入数据合理大小,Sepolia 提供了一种方法,利用区块链实现无限数据存储,具有与主网几乎相同的属性*
_* Sepolia 区块链不是永久的,但大多数情况下可信任多年。如果你需要绝对的永久性,你需要使用主网付费。_
记住,我们并没有将实际数据存储在链上。只是存储指纹。
流程
首先,我们需要一种可靠地在以太坊上创建交易的方法。
尽管看起来很复杂,但实际上非常简单。我们不需要任何额外的软件或钱包技术。 钱包不过是一对密钥,其中包含一个用于签名的秘密。
要创建以太坊交易,我们只需创建一个包含所需密钥和格式的 Python 对象,用我们的密钥对其进行编码,然后广播到网络。随后,验证者会从“内存池”中获取我们的交易,并将其包含在区块中。
只要我们包含了所有必需的字段,并且验证通过,它将在大约 12 秒内成为区块链的永久部分。
步骤 1:使用 `web3.py` 编写几行代码来创建密钥和密钥
from eth_account import Account
account = Account.create()
print("Address:", account.address)
print("Private Key:", account.key.hex())步骤 2:在 Sepolia 上获取一些 ETH。将你的地址插入 [这里](https://cloud.google.com/application/web3/faucet/ethereum/sepolia),等待 12 秒。感谢 Google!
步骤 3:哈希数据集
正如我提到的,有些哈希更适合这个过程。我们可以使用 SHA256 哈希,但 Blake2b 实际上更适合吞吐量。实际上,任何哈希函数都可以工作。
使用此函数来哈希数据。
import hashlib
from pathlib import Path
def hash_dataset(dataset, algorithm="blake2b", chunk_size=1024 * 1024):
h = hashlib.new(algorithm)
def update(obj):
if isinstance(obj, (str, Path)) and Path(obj).exists():
with open(obj, "rb") as f:
while chunk := f.read(chunk_size):
h.update(chunk)
elif isinstance(obj, bytes):
h.update(obj)
elif isinstance(obj, str):
h.update(obj.encode("utf-8"))
elif isinstance(obj, dict):
for k in sorted(obj.keys()):
update(k)
update(obj[k])
elif isinstance(obj, (list, tuple)):
for item in obj:
update(item)
elif isinstance(obj, set):
try:
for item in sorted(obj):
update(item)
except TypeError:
for item in sorted(obj, key=str):
update(item)
elif hasattr(obj, "__iter__"):
for item in obj:
update(item)
else:
h.update(repr(obj).encode("utf-8"))
update(dataset)
return h.hexdigest()
digest = hash_dataset("hugedataset.parquet", algorithm="blake2b")步骤 4:编写、签名并发布包含数据集哈希的交易。
使用 web3.py 库,我们可以将交易结构化为一个 Python 字典,然后将其发布到网络。
我们需要一个提供者来广播我们的交易(我们没有节点)。这里我们使用 Infura,但还有其他选择,比如 Alchemy
请注意,我们在计算的数据集哈希前添加了一个零位 “0x”。 我们在验证哈希时需要移除它。
from web3 import Web3
w3 = Web3(Web3.HTTPProvider("https://sepolia.infura.io/v3/YOUR_KEY"))
dataset_hash = "0x" + digest
account = w3.eth.account.from_key("YOUR_PRIVATE_KEY")
tx = {
"to": account.address, # 自发送(无需合约)
"value": 0, # 不转移 ETH
"gas": 50_000,
"maxFeePerGas": w3.to_wei("20", "gwei"),
"maxPriorityFeePerGas": w3.to_wei("2", "gwei"),
"nonce": w3.eth.get_transaction_count(account.address),
"chainId": 11155111, # Sepolia 测试网
"data": dataset_hash
}签名并发送。在这里,我们等待交易完成。
signed_tx = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
print("Broadcast tx hash:", tx_hash.hex())
# 等待挖矿 / 包含在区块中
tx_receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print("Transaction mined in block:", tx_receipt["blockNumber"])
print("Status:", tx_receipt["status"])请务必保留交易 ID。
步骤 5:创建元数据记录以与我们的数据集一起存储
在这里,我们创建一个简单的元数据,可以存储在数据库(DynamoDB、MongoDB)中,或直接与我们的数据对象一起存储(S3、Google Cloud Storage)。
元数据可能如下所示:
{
"dataset_id": "feature_set_v42",
"dataset_uri": "s3://ml-bucket/features/v42.parquet",
"dataset_hash": "0x9f3c...ab21",
"tx_hash": "0x7c1a...e91d",
"timestamp_unix": 1730000000,
"hash_algorithm": "blake2b",
"creator": "0xabc123...",
"notes": "normalized features"
}步骤 6:每次读取数据集时,验证哈希是否与我们数据旁边存储的原始哈希匹配
该过程的最后一步结合了三个操作:
- 获取以太坊交易
- 从 calldata 中提取数据集哈希
- 与本地重新计算的哈希进行比较
from web3 import Web3
w3 = Web3(Web3.HTTPProvider("https://sepolia.infura.io/v3/YOUR_KEY"))
def verify_dataset(dataset_path, tx_hash):
tx = w3.eth.get_transaction(tx_hash)
raw_input = tx["input"]
onchain_hash = raw_input.hex() if hasattr(raw_input, 'hex') else str(raw_input).lower()
computed_hash = "0x" + hash_dataset(dataset_path).lower()
if computed_hash != onchain_hash:
raise ValueError(f"Integrity FAILED: Local {computed_hash} != On-chain {onchain_hash}")
print("Integrity check PASSED. Dataset matches the blockchain record.")
return True就是这样!
重要提示,这并不能阻止任何人重写我们的元数据对象。然而,有许多方法可以防止对内部小块元数据进行修改,例如审计数据库或 S3 对象锁定。
总结
最终,利用加密哈希来验证数据集完整性是一种针对复杂问题的轻量级解决方案。
一些自然的扩展包括使用此方法来验证模型权重,甚至对源代码的部分进行哈希处理,以确保预处理是相关的。
无论您是在跨分布式开源团队协作、构建可复现的研究,还是仅为合规性创建审计跟踪,区块链都是您的数据的一个良好且公正的公证人。您不需要信任基础设施;您只需要信任数学。