Реализация генерации и проверки подписи ECDSA с использованием Javascript - PullRequest
2 голосов
/ 27 марта 2019

У меня есть некоторый код ниже, который будет использоваться для проверки подлинности сообщения с использованием 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

Что не так с моей реализацией? Я что-то пропустил? Я сделал что-то не так?

EDIT:

После некоторой ревизии я придумал следующее:

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 голосов
/ 29 марта 2019

часть вашей проблемы в том, что 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

...