ECDSA(椭圆曲线数字签名算法) 被广泛应用于比特币和以太坊(使用 secp256k1 曲线),用于生成消息()的签名()。整个过程包括对消息进行哈希处理,然后使用私钥创建签名。公钥可用于验证签名。我们可以使用多种曲线(如 192 位、256 位、384 位和 521 位曲线)和多种哈希算法(如 MD5、SHA-1 和 SHA-256)。
在椭圆曲线上,我们有一个基点 和阶数 。首先生成一个私钥 ,然后计算公钥:
公钥是曲线上的一个点,通过对基点 进行 次点加运算得到。
对于消息 ,我们使用私钥生成签名()。首先创建一个随机 nonce 值 ,然后计算曲线上的点:
接着计算该点的 x 坐标:
这样就得到了签名的 值。然后计算消息的哈希值:
最后计算 值:
签名就是()。在 aardio 中可以这样实现:
import BouncyCastle;
// 初始化签名器
var signer = BouncyCastle.Security.SignerUtilities.GetSigner(signtype);
// 获取密钥对中的私钥和公钥
var privateKey = keyPair.Private;
var publicKey = keyPair.Public;
// 初始化签名器进行签名
signer.Init(true, privateKey);
// 更新要签名的消息数据
signer.BlockUpdate(raw.buffer(msg), 0, #msg);
我们可以通过消息 、签名()和公钥 来验证签名:
然后计算:
接着计算曲线上的点:
然后取 点的 x 坐标:
如果 等于 ,则签名验证通过。aardio 实现如下:
// 初始化签名器进行验证
var signer2 = BouncyCastle.Security.SignerUtilities.GetSigner(signtype);
signer2.Init(false, publicKey);
signer2.BlockUpdate(raw.buffer(msg), 0, #msg);
// 验证签名
var rtn = signer2.VerifySignature(signer.GenerateSignature());
以下是在 aardio 中使用 BouncyCastle 实现 ECDSA 的完整示例:
import crypt;
import BouncyCastle;
import console;
// 配置参数
var curvename = "secp256k1";
var signtype = "SHA1withECDSA";
var msg = "Hello";
// 支持的签名类型: SHA1withECDSA, SHA256withECDSA, SHA224withECDSA, SHA384withECDSA, SHA512withECDSA
// 获取指定曲线的参数
var ecParams = BouncyCastle.Asn1.X9.ECNamedCurveTable.GetByName(curvename);
var curveparam = BouncyCastle.Crypto.Parameters.ECDomainParameters(
ecParams.Curve,
ecParams.G,
ecParams.N,
ecParams.H,
ecParams.GetSeed()
);
// 初始化密钥对生成器
var keygenParams = BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters(
curveparam,
BouncyCastle.Security.SecureRandom()
);
var generator = BouncyCastle.Crypto.Generators.ECKeyPairGenerator("ECDSA");
generator.Init(keygenParams);
var keyPair = generator.GenerateKeyPair();
// 创建签名
var signer = BouncyCastle.Security.SignerUtilities.GetSigner(signtype);
var privateKey = keyPair.Private;
var publicKey = keyPair.Public;
signer.Init(true, privateKey);
signer.BlockUpdate(raw.buffer(msg), 0, #msg);
// 验证签名
var signer2 = BouncyCastle.Security.SignerUtilities.GetSigner(signtype);
signer2.Init(false, publicKey);
signer2.BlockUpdate(raw.buffer(msg), 0, #msg);
var rtn = signer2.VerifySignature(signer.GenerateSignature());
// 输出结果
console.log("== 曲线:", curvename);
console.log("== 消息:", msg);
console.log("== 签名类型:", signtype);
console.log("== 签名 ===");
console.log("== 签名:", string.hex(signer.GenerateSignature(),""),
"[", crypt.encodeBin(signer.GenerateSignature()), "]");
console.log("== 验证结果:", rtn);
console.log("== 私钥 ===");
console.log("== D ==", tostring(privateKey.D));
console.log("== 公钥 ===");
console.log("== Q_x ==", publicKey.Q.XCoord);
console.log("== Q_y ==", publicKey.Q.YCoord);
console.log("曲线详情: G=", ecParams.G);
console.log("N=", ecParams.N);
console.log("H=", ecParams.H);
console.log("A=", ecParams.Curve.A);
console.log("B=", ecParams.Curve.B);
console.log("字段大小=", ecParams.Curve.FieldSize);
console.pause();
以下是更简化的 ECDSA 实现示例:
import BouncyCastle;
import console;
var msg = "Hello";
var method = "SHA-1withECDSA";
// 初始化密钥对生成器
var gen = BouncyCastle.Crypto.Generators.ECKeyPairGenerator("ECDSA");
var secureRandom = BouncyCastle.Security.SecureRandom();
var keyGenParam = BouncyCastle.Crypto.KeyGenerationParameters(secureRandom, 256);
gen.Init(keyGenParam);
var keyPair = gen.GenerateKeyPair();
// 获取私钥和公钥参数
var privateKeyParam = keyPair.Private;
var publicKeyParam = keyPair.Public;
// 创建签名
var signer = BouncyCastle.Security.SignerUtilities.GetSigner(method);
signer.Init(true, keyPair.Private);
signer.BlockUpdate(raw.buffer(msg), 0, #msg);
var signature = signer.GenerateSignature();
// 验证签名
signer = BouncyCastle.Security.SignerUtilities.GetSigner(method);
signer.Init(false, keyPair.Public);
signer.BlockUpdate(raw.buffer(msg), 0, #msg);
var rtn = signer.VerifySignature(signature);
// 输出结果
console.log("消息:", msg);
console.log("=== 私钥 ===");
console.log("D=", privateKeyParam.D.ToString());
console.log("方法=", method);
console.log("=== 公钥 ===");
console.log("Gy=", publicKeyParam.Parameters.G.YCoord.ToString());
console.log("Gx=", publicKeyParam.Parameters.G.XCoord.ToString());
console.log("曲线=", publicKeyParam.Parameters.Curve.ToString());
console.log("阶数=", publicKeyParam.Parameters.N.ToString());
console.log("Qx=", publicKeyParam.Q.XCoord.ToString());
console.log("Qy=", publicKeyParam.Q.YCoord.ToString());
console.log("=== 签名 ===");
console.log("签名: r=", string.left(string.hex(signature), 64));
console.log("验证结果=", rtn);
console.pause();
通过 BouncyCastle 扩展库,aardio 可以方便地实现各种密码学操作,包括 ECDSA 签名和验证。