使用Javascript的ECDSA签名生成和验证实现

时间:2019-03-27 04:08:51

标签: javascript digital-signature verification elliptic-curve ecdsa

我下面有一些代码,这些代码将用于使用JavaScript验证邮件的真实性。使用椭圆曲线secp256k1生成密钥对非常简单,但是我无法理解为什么我的签名实现不起作用(为什么消息未成功验证)。这是我的代码:

https://pastebin.com/k1WT6apV

/**
* 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;
}

但是,它仍然无法验证签名。希望它能使它更清晰。

1 个答案:

答案 0 :(得分:0)

问题的一部分是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