本节将所有密码学原语整合为一个可运行的验证工具箱。通过亲手组装这些组件,你将建立从"知道实现"到"能用密码学解决实际问题"的跨越。
2.10.1 工具箱架构
graph TD
Tool[Crypto Toolset]
Tool --> H[哈希层<br/>SHA-256 / Keccak-256]
Tool --> ECC[ECC 层<br/>secp256k1 点运算]
Tool --> K[密钥层<br/>BIP-39 助记词 + BIP-32 HD]
Tool --> S[签名层<br/>ECDSA / Schnorr]
Tool --> C[承诺层<br/>密码学承诺]
H --> ECC
ECC --> K
K --> S
S --> C
style Tool fill:#bbdefb
style S fill:#c8e6c9
text
┌─────────────────────────────────────────────┐
│ 密码学工具箱 (Crypto Toolset) │
├─────────────────────────────────────────────┤
│ [哈希层] │
│ - SHA-256 从零实现 │
│ - 雪崩效应测试器 │
│ - 碰撞概率计算器 │
├─────────────────────────────────────────────┤
│ [椭圆曲线层] │
│ - secp256k1 点运算 │
│ - 标量乘法 (私钥→公钥) │
│ - 公钥压缩/解压 │
├─────────────────────────────────────────────┤
│ [签名层] │
│ - ECDSA 签名/验证 │
│ - RFC 6979 确定性 k │
│ - 签名 malleability 检测 │
├─────────────────────────────────────────────┤
│ [钱包层] │
│ - 熵生成 → 助记词 → 种子 → 子密钥 │
│ - BIP-44 路径解析 │
├─────────────────────────────────────────────┤
│ [Merkle 层] │
│ - 构建 Merkle 树 │
│ - 生成/验证 Merkle 证明 │
│ - 批量验证优化 │
└─────────────────────────────────────────────┘2.10.2 完整整合代码
typescript
// =====================================================
// 密码学工具箱整合实现
// 所有底层实现复用 2.1-2.7 节代码,此处展示整合调用
// =====================================================
/**
* 工具箱:密码学验证套件
*/
class CryptoToolkit {
// --- 1. 哈希层 ---
sha256(message: string): string {
return sha256(message); // 复用 2.2 节完整实现
}
/**
* 雪崩效应测试:单 bit 变化导致多少输出位变化
*/
avalancheTest(input: string, rounds: number = 20): {
avgDistance: number;
avgRate: number;
results: number[];
} {
const baseHash = this.sha256(input);
const results: number[] = [];
for (let i = 0; i < rounds; i++) {
const modified = this._flipRandomBit(input);
const modifiedHash = this.sha256(modified);
results.push(this._hammingDistance(baseHash, modifiedHash));
}
const avgDist = results.reduce((a, b) => a + b, 0) / results.length;
return {
avgDistance: avgDist,
avgRate: (avgDist / 256) * 100,
results,
};
}
// --- 2. 密钥对生成层 ---
generateKeyPair(): { privateKey: bigint; publicKey: ECPoint } {
const d = generatePrivateKey(); // CSPRNG 生成
const pub = scalarMultiply(d, new ECPoint(G.x, G.y), 0n, SECP256K1.p);
return { privateKey: d, publicKey: pub };
}
/**
* 公钥压缩:65 字节 → 33 字节
*/
compressPublicKey(pubKey: ECPoint): Uint8Array {
const isEven = (pubKey.y! % 2n) === 0n;
const prefix = isEven ? 0x02 : 0x03;
const bytes = new Uint8Array(33);
bytes[0] = prefix;
// ... 将 x 写入后 32 字节
return bytes;
}
// --- 3. 签名层 ---
sign(privateKey: bigint, message: string): { r: bigint; s: bigint } {
return ecdsaSign(privateKey, message); // 复用 2.5 节实现
}
verify(
publicKey: ECPoint,
message: string,
signature: { r: bigint; s: bigint },
): boolean {
return ecdsaVerify(publicKey, message, signature); // 复用 2.5 节实现
}
/**
* 检测签名可锻性(malleability)
* 如果 s > n/2,攻击者可用 n-s 构造等价但不同的签名
*/
isSignatureMalleable(signature: { r: bigint; s: bigint }): boolean {
return signature.s > SECP256K1.n / 2n;
}
normalizeSignature(signature: { r: bigint; s: bigint }): { r: bigint; s: bigint } {
if (this.isSignatureMalleable(signature)) {
return { r: signature.r, s: SECP256K1.n - signature.s };
}
return signature;
}
// --- 4. Merkle 层 ---
buildMerkleTree(txHashes: Uint8Array[]): MerkleTree {
return new MerkleTree(txHashes); // 复用 2.7 节实现
}
// --- 私有辅助 ---
private _flipRandomBit(s: string): string {
const chars = s.split('');
const pos = Math.floor(Math.random() * s.length);
const bit = Math.floor(Math.random() * 8);
const code = s.charCodeAt(pos);
chars[pos] = String.fromCharCode(code ^ (1 << bit));
return chars.join('');
}
private _hammingDistance(a: string, b: string): number {
let dist = 0;
for (let i = 0; i < a.length && i < b.length; i++) {
const x = parseInt(a[i], 16);
const y = parseInt(b[i], 16);
let diff = x ^ y;
while (diff) { dist++; diff &= diff - 1; }
}
return dist;
}
}
// =====================================================
// 验证测试套件
// =====================================================
function runTests() {
const kit = new CryptoToolkit();
console.log("╔════════════════════════════════════════╗");
console.log("║ 密码学工具箱验证套件 ║");
console.log("╚════════════════════════════════════════╝\n");
// Test 1: 哈希雪崩效应
console.log("[Test 1] 雪崩效应测试");
const avalanche = kit.avalancheTest("Blockchain Crypto Toolkit v1.0", 10);
console.log(` 平均翻转: ${avalanche.avgRate.toFixed(1)}% (目标: 50%)`);
console.log(` 结果: ${avalanche.avgRate > 45 && avalanche.avgRate < 55 ? '✅ 通过' : '❌ 异常'}`);
// Test 2: 密钥对生成
console.log("\n[Test 2] 密钥对生成与验证");
const { privateKey, publicKey } = kit.generateKeyPair();
console.log(` 私钥位数: ${privateKey.toString(2).length} (目标: 256)`);
console.log(` 公钥有效性: ${isValidCurvePoint(publicKey, 0n, 7n, SECP256K1.p) ? '✅ 在曲线上' : '❌ 无效'}`);
// Test 3: ECDSA 全流程
console.log("\n[Test 3] ECDSA 签名验证循环");
const msg = "Transfer 1.0 BTC to 1A1z...";
const sig = kit.sign(privateKey, msg);
const valid = kit.verify(publicKey, msg, sig);
console.log(` 原始消息: ${valid ? '✅ 验证通过' : '❌ 失败'}`);
const tampered = kit.verify(publicKey, msg + "_tampered", sig);
console.log(` 篡改消息: ${tampered ? '❌ 未检测出篡改' : '✅ 正确拒绝'}`);
// Test 4: 签名规范化
console.log("\n[Test 4] 签名可锻性检测");
const highS = { r: sig.r, s: SECP256K1.n - sig.s };
console.log(` 高 s 值: ${kit.isSignatureMalleable(highS) ? '✅ 检测到可锻性' : '❌ 未检测'}`);
const normalized = kit.normalizeSignature(highS);
console.log(` 规范化后: ${kit.isSignatureMalleable(normalized) ? '❌ 仍有问题' : '✅ 安全'}`);
console.log(` 等价验证: ${kit.verify(publicKey, msg, normalized) ? '✅ 仍有效' : '❌ 被破坏'}`);
// Test 5: Merkle 证明
console.log("\n[Test 5] Merkle 树构建与验证");
const txData = Array.from({ length: 8 }, (_, i) => `tx_${i}_data`);
const txHashes = txData.map(tx => {
const hex = kit.sha256(tx);
const bytes = new Uint8Array(32);
for (let j = 0; j < 32; j++) bytes[j] = parseInt(hex.slice(j * 2, j * 2 + 2), 16);
return bytes;
});
const tree = kit.buildMerkleTree(txHashes);
const root = tree.getRoot();
if (root) {
console.log(` 树根: ${Array.from(root).slice(0, 4).map(b => b.toString(16).padStart(2, '0')).join('')}...`);
const proof = tree.getProof(3);
const verified = verifyMerkleProof(txHashes[3], proof, root, 3);
console.log(` 证明大小: {proof.length * 32} 字节`);
console.log(` 验证结果: ${verified ? '✅ 通过' : '❌ 失败'}`);
}
console.log("\n╔════════════════════════════════════════╗");
console.log("║ 全部测试完成 ║");
console.log("╚════════════════════════════════════════╝");
}
// 执行测试
runTests();2.10.3 扩展挑战
完成基础工具箱后,以下扩展项目可以加深理解:
挑战 1:实现 RFC 6979 确定性
替代随机 ,实现基于 HMAC-SHA256 的确定性签名:
验证:同一 总是产生相同的 ,且 Sony 攻击不再可能。
挑战 2:Schnorr 签名实现
实现 BIP-340 的 Schnorr 签名:
验证等式:。
比较:签名大小降为 64 字节( 和 各 32 字节,不需要编码 和 ),无 DER 编码复杂性。
挑战 3:批量验证优化
Schnorr 的核心优势——线性——允许批量验证多个签名:
其中 是随机挑战系数。将 次独立验证的 运算合并为少量群运算。
挑战 4:Patricia Trie 简化实现
实现一个键值存储的 Patricia Trie(16 进制前缀压缩),并扩展为 Merkle Patricia Trie——在每次修改后重新计算到根的路径哈希。这是以太坊状态树的简化模型。
2.10.4 最佳安全实践清单
- [ ] 所有随机数使用
crypto.getRandomValues或crypto.randomBytes - [ ] ECDSA 使用 RFC 6979 确定性 或 CSPRNG + 防重放机制
- [ ] 所有外部输入的公钥在使用前验证曲线方程
- [ ] 签名后检查 ,拒绝高 s 可锻性签名
- [ ] 助记词不在任何联网设备存储
- [ ] HD 钱包使用 BIP-44 标准路径,记录 hardened 索引
- [ ] 消息签名前包含协议标识/链 ID 防止跨链重放
- [ ] 密钥存储使用 AES-256-GCM 或 ChaCha20-Poly1305
本章小结:从 SHA-256 的 64 轮压缩函数,到 secp256k1 的标量乘法,到 ECDSA 的灵魂 ,到 BIP-39 的 12 个记忆词——每个密码学原语都是"信任机器"的基石。理解它们的数学、实现和安全边界,是理解区块链"为什么可信"的必经之路。
评论
0评论加载中…