Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ecdsa-methods #25

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions ellipticcurve/curve.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
const BigInt = require("big-integer");
const Point = require("./point").Point;
const modulo = require("./utils/integer").modulo;
const EcdsaMath = require("./math");


class CurveFp {
Expand Down Expand Up @@ -41,6 +42,18 @@ class CurveFp {
get oid() {
return this._oid.slice();
}

y(x, isEven)
{
let ySquared = (((x.value ** BigInt(3).value) % this.P.value) + this.A.value * x.value + this.B.value) % this.P.value
let y = EcdsaMath.modularSquareRoot(ySquared, this.P.value)
if (isEven != ((y % BigInt(2).value).toString() == "0"))
{
y = this.P.value - y;
}
return BigInt(y)
}

};


Expand Down
16 changes: 15 additions & 1 deletion ellipticcurve/math.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ const Point = require("./point").Point;
const modulo = require("./utils/integer").modulo;
const BigInt = require("big-integer");

var modularSquareRoot = function(value, prime){

let base = value
let exp = (prime + BigInt(1).value) / BigInt(4).value
let p = prime

var result = 1n;
while (exp !== 0n) {
if (exp % 2n === 1n) result = result * base % p;
base = base * base % p;
exp >>= 1n;
}
return result;
}

var multiply = function (p, n, N, A, P) {
// Fast way to multily point and scalar in elliptic curves
Expand Down Expand Up @@ -184,7 +198,7 @@ var jacobianMultiply = function (p, n, N, A, P) {
throw new Error("logical failure: p: " + p + ", n: " + n + ", N: " + N + ", A: " + A + ", P: " + P);
};


exports.modularSquareRoot = modularSquareRoot;
exports.multiply = multiply;
exports.add = add;
exports.inv = inv;
29 changes: 29 additions & 0 deletions ellipticcurve/publicKey.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const EcdsaCurve = require("./curve");
const Point = require("./point").Point;
const der = require("./utils/der");
const Math = require("./math");
const { PrivateKey } = require("..");


class PublicKey {
Expand All @@ -21,6 +22,19 @@ class PublicKey {
return xString + yString;
};

toCompressed(encoded=false) {
let baseLen = this.curve.length();

if ((this.point.y["value"] % BigInt("2")).toString() == "0")
{
var parityTag = "02";
} else {
var parityTag = "03";
}
let xString = BinaryAscii.hexFromBinary(BinaryAscii.stringFromNumber(this.point.x, baseLen))
return parityTag + xString
}

toDer () {
let encodeEcAndOid = der.encodeSequence(der.encodeOid([1, 2, 840, 10045, 2, 1]), der.encodeOid(this.curve.oid));

Expand Down Expand Up @@ -102,6 +116,21 @@ class PublicKey {
}
return publicKey
};

static fromCompressed(string, curve=EcdsaCurve.secp256k1)
{
let parityTag = string.slice(0, 2);
let xString = string.slice(2, string.length);

if (!["02", "03"].includes(parityTag))
{
throw new Error("Compressed string should start with 02 or 03");
}
let isEven = parityTag == "02"
let x = BinaryAscii.numberFromHex(xString)
let y = curve.y(x, isEven=isEven)
return new PublicKey(new Point(x, y), curve)
};
};


Expand Down
52 changes: 52 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,58 @@ describe("PublicKey test", function() {
});
});
});

describe("ComPubKeyTest", function() {
describe("#testBatch()", function() {
it("should validate publicKey x and y points", function() {
this.timeout(10000);
for (let i = 0; i < 1000; i++) {
let privateKey = new PrivateKey()
let publicKey = privateKey.publicKey()
let publicKeyString = publicKey.toCompressed()
let recoveredPublicKey = PublicKey.fromCompressed(publicKeyString, publicKey.curve)

assert.equal(publicKey.point.x.value, recoveredPublicKey.point.x.value)
assert.equal(publicKey.point.y.value, recoveredPublicKey.point.y.value)
}
});
});
describe("#testFromCompressedEven()", function() {
it("should validate publicKey from Even compressed", function() {
let publicKeyCompressed = "0252972572d465d016d4c501887b8df303eee3ed602c056b1eb09260dfa0da0ab2"
let publicKey = PublicKey.fromCompressed(publicKeyCompressed)
let publicKey2 = PublicKey.fromPem("\n-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEUpclctRl0BbUxQGIe43zA+7j7WAsBWse\nsJJg36DaCrKIdC9NyX2e22/ZRrq8AC/fsG8myvEXuUBe15J1dj/bHA==\n-----END PUBLIC KEY-----\n")

assert.equal(publicKey.toPem(), publicKey2.toPem());
});
});
describe("#testFromCompressedOdd()", function() {
it("should validate publicKey from Odd compressed", function() {
let publicKeyCompressed = "0318ed2e1ec629e2d3dae7be1103d4f911c24e0c80e70038f5eb5548245c475f50"
let publicKey = PublicKey.fromCompressed(publicKeyCompressed)
let publicKey2 = PublicKey.fromPem("\n-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGO0uHsYp4tPa574RA9T5EcJODIDnADj1\n61VIJFxHX1BMIg0B4cpBnLG6SzOTthXpndIKpr8HEHj3D9lJAI50EQ==\n-----END PUBLIC KEY-----\n")

assert.equal(publicKey.toPem(), publicKey2.toPem());
});
});
describe("#testToCompressedEven()", function() {
it("should validate publicKey to Even compressed", function() {
let publicKey = PublicKey.fromPem("\n-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEUpclctRl0BbUxQGIe43zA+7j7WAsBWse\nsJJg36DaCrKIdC9NyX2e22/ZRrq8AC/fsG8myvEXuUBe15J1dj/bHA==\n-----END PUBLIC KEY-----\n")
let publicKeyCompressed = publicKey.toCompressed()

assert.equal(publicKeyCompressed, "0252972572d465d016d4c501887b8df303eee3ed602c056b1eb09260dfa0da0ab2");
});
});
describe("#testToCompressedOdd()", function() {
it("should validate publicKey to Odd compressed", function() {
let publicKey = PublicKey.fromPem("-----BEGIN PUBLIC KEY-----\nMFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEGO0uHsYp4tPa574RA9T5EcJODIDnADj1\n61VIJFxHX1BMIg0B4cpBnLG6SzOTthXpndIKpr8HEHj3D9lJAI50EQ==\n-----END PUBLIC KEY-----")
let publicKeyCompressed = publicKey.toCompressed()

assert.equal(publicKeyCompressed, "0318ed2e1ec629e2d3dae7be1103d4f911c24e0c80e70038f5eb5548245c475f50");
});
});
});

describe("Signature test", function() {
describe("#testDerConversion()", function() {
it("should validate DER signature generation and convertion", function() {
Expand Down