我在下面有一些代码,用于使用javascript验证消息的真实性。使用椭圆曲线secp256k1生成密钥对非常简单,但是我无法理解为什么我的签名实现不起作用(为什么消息没有被成功验证)。这是我的代码:
/**
* Signature Generation
*/
var g = bigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240');
var n = bigInt('115792089237316195423570985008687907852837564279074904382605163141518161494337');
var p = bigInt('115792089237316195423570985008687907853269984665640564039457584007908834671663');
var k = bigInt.randBetween("1", n.subtract(1));
var r = bigInt("0");
var s = bigInt("0");
var privateKey = bigInt('5943918703142138746985297990399309008462887494775678462183405629775262082646');
var publicKey = bigInt(privateKey.multiply(g)).mod(p);
while(s.equals("0")){
while(r.equals("0")){
k = bigInt.randBetween("1", n.subtract(1));
while(bigInt(k).isPrime() == false){
k = bigInt.randBetween("1", n.subtract(1));
}
var xCoord = bigInt(k.multiply(g)).mod(p);
r = xCoord.mod(n);
}
var kInverse = k.modInv(n);
var hashedMessage = bigInt(sha1('hello'),16);
s = bigInt(kInverse*(hashedMessage.add(privateKey.multiply(r)))).mod(n)
}
var signatureParams = {
"publicKey": publicKey.toString(),
"r": r.toString(),
"sign": s.toString()
}
/**
* Signature Verification
*/
var sInverse = bigInt(signatureParams.sign).modInv(n);
var publicKey = bigInt(signatureParams.publicKey);
var w = sInverse.mod(n);
var hashedMessage = bigInt(sha1('hello'),16);
var u1 = bigInt(hashedMessage.multiply(w)).mod(n);
var u2 = bigInt(bigInt(r).multiply(w)).mod(n);
var P = bigInt(u1.multiply(g)).add(u2.multiply(publicKey));
P == r
它可以使用浏览器控制台轻松测试。我使用了以下指南中的信息合并:
https://www.maximintegrated.com/en/app-notes/index.mvp/id/5767
http://www.cs.miami.edu/home/burt/learning/Csc609.142/ecdsa-cert.pdf
https://pdfs.semanticscholar.org/c06a/d6512775be1076e4abd43e3f2928729da776.pdf
我的实施有什么问题?我错过了什么吗?我做错什么了吗?
编辑:
做了一些修改后,我想出了以下内容:
var g = bigInt('55066263022277343669578718895168534326250603453777594175500187360389116729240');
var n = bigInt('115792089237316195423570985008687907852837564279074904382605163141518161494337');
var p = bigInt('115792089237316195423570985008687907853269984665640564039457584007908834671663');
var privateKey = bigInt('90436540941140970165633788406609967146985661161263948799654498545867952662296');
var publicKey = bigInt(privateKey.multiply(g)).mod(p);
var generateSignature = function(hashedMessage){
hashedMessage = bigInt(hashedMessage,16);
var k = bigInt.randBetween("1", n.subtract(1));
var r = bigInt("0");
var s = bigInt("0");
while(s.equals("0")){
r = bigInt("0");
while(r.equals("0")){
k = bigInt.randBetween("1", n.subtract(1));
r = bigInt(bigInt(k.multiply(g)).mod(p)).mod(n);
}
var kInverse = k.modInv(n);
var pr = privateKey.multiply(r);
hashedMessage = hashedMessage.add(pr);
kInverse = kInverse.multiply(hashedMessage);
s = kInverse.mod(n);
}
return [r.toString(),s.toString()];
}
var validateSignature = function(hashedMessage, signature){
hashedMessage = bigInt(hashedMessage,16);
var r = bigInt(signature[0]);
var s = bigInt(signature[1]);
var w = s.modInv(n);
var u1 = bigInt(hashedMessage.multiply(w)).mod(n);
var u2 = bigInt(r.multiply(w)).mod(n);
var u1g = u1.multiply(g);
var u2pu = u2.multiply(publicKey);
var xCoord =u1g.add(u2pu);
var v = xCoord.mod(n);
if(v.equals(r))
return true;
return false;
}
但是它仍然无法验证签名。希望它能让它更清晰一些。
你问题的一部分是g实际上不是一个数字而是一个点
这是你所写内容的粗略翻译:
g = 55066263022277343669578718895168534326250603453777594175500187360389116729240
privateKey = 90436540941140970165633788406609967146985661161263948799654498545867952662296
k = <random number>
r = k*g%p%n
e = sha(m)
ki = k^-1%n
pr = privateKey*r
ki*e
s = ki%n
在过去的几周里,我写了一个这样的实现:
g = {
x: 55066263022277343669578718895168534326250603453777594175500187360389116729240,
y: 32670510020758816978083085130507043184471273380659243275938904335757337482424
}
k = <random number>
r = <random number>
e = sha(m)
privateKey = 90436540941140970165633788406609967146985661161263948799654498545867952662296
r = g * k
s = ((privateKey * r.x + e) * (k^-1%n)) % n
r = r.x
它可能会帮助你理解点乘法如何工作检查这些链接:https://github.com/Azero123/simple-js-ec-math
https://www.npmjs.com/package/simple-js-ec-math
https://eng.paxos.com/blockchain-101-foundational-math
或许也可以看看我的simple-js-ecdsa实现
只是另一个注释,你可能不应该使用sha1,因为它被认为是“官方不安全”,并且有使用它的碰撞公式。也许试试sha2或sha3