simple-js-ecdsa
Advanced tools
Comparing version 1.0.1 to 1.1.0
{ | ||
"name": "simple-js-ecdsa", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "easy and light weight ecdsa implementation", | ||
@@ -5,0 +5,0 @@ "main": "./src/index.js", |
@@ -25,2 +25,5 @@ const bigInt = require('big-integer') | ||
class Wallet { | ||
static new(curve = secp256k1) { | ||
return Wallet.fromKey(curve.modSet.random(), curve) | ||
} | ||
static fromKey(key, curve = secp256k1) { | ||
@@ -42,5 +45,58 @@ const wallet = new Wallet() | ||
} | ||
sign(message) { | ||
sign(message, k = this.curve.modSet.random()) { | ||
k = bigInt(k, 16) | ||
const e = bigInt(sha256(message), 16) | ||
const da = bigInt(this.key, 16) // private key | ||
const r = this.curve.multiply(this.curve.g, k) | ||
const s1 = da.multiply(r.x).add(e) | ||
const s = s1.multiply(k.modInv(this.curve.n)).mod(this.curve.n) | ||
return { | ||
r: bigInt(r.x).toString(16), | ||
s: s.toString(16) | ||
} | ||
} | ||
bip66Sign(signature) { | ||
const r = new Buffer(signature.r, 'hex') | ||
const s = new Buffer(signature.s, 'hex') | ||
const rl = r.length | ||
const sl = s.length | ||
var signature = Buffer.allocUnsafe(6 + rl + sl) | ||
signature[0] = 0x30 | ||
signature[1] = signature.length - 2 | ||
signature[2] = 0x02 | ||
signature[3] = rl | ||
r.copy(signature, 4) | ||
signature[4+rl] = 0x02 | ||
signature[5+rl] = sl | ||
S.copy(signature, rl + 6) | ||
return signature.toString('hex') | ||
} | ||
verify(message, signature) { | ||
const e = bigInt(sha256(message), 16) | ||
const r = bigInt(signature.r, 16) | ||
const s = bigInt(signature.s, 16) | ||
const w = bigInt(s).modInv(this.curve.n) | ||
const u1 = bigInt(e).multiply(w).mod(this.curve.n) | ||
const u2 = r.multiply(w).mod(this.curve.n) | ||
const p = this.curve.add(this.curve.multiply(this.curve.g, u1), this.curve.multiply(this.publicPoint, u2)) | ||
return p.x == r | ||
} | ||
verifyBip66(message, signature) { | ||
const e = bigInt(sha256(message), 16) | ||
const r = bigInt(signature.r, 16) | ||
const s = bigInt(signature.s, 16) | ||
const w = bigInt(s).modInv(this.curve.n) | ||
const u1 = bigInt(e).multiply(w).mod(this.curve.n) | ||
const u2 = r.multiply(w).mod(this.curve.n) | ||
const p = this.curve.add(this.curve.multiply(this.curve.g, u1), this.curve.multiply(this.publicPoint, u2)) | ||
return p.x == r | ||
} | ||
static fromAddress(address, curve = secp256k1) { | ||
@@ -60,7 +116,7 @@ const wallet = new Wallet() | ||
} | ||
get pubPoint() { | ||
if (this._pubPoint) { | ||
return this._pubPoint | ||
get publicPoint() { | ||
if (this._publicPoint) { | ||
return this._publicPoint | ||
} | ||
return this._pubPoint = this.curve.multiply(this.curve.g, bigInt(this.key, 16)) | ||
return this._publicPoint = this.curve.multiply(this.curve.g, bigInt(this.key, 16)) | ||
} | ||
@@ -71,7 +127,7 @@ get sec1Compressed() { | ||
} | ||
let xStr = bigInt(this.pubPoint.x).toString(16) | ||
let xStr = bigInt(this.publicPoint.x).toString(16) | ||
while (xStr.length < 64) { | ||
xStr = '0' + xStr | ||
} | ||
return this._sec1Compressed = `${bigInt(this.pubPoint.y).isOdd() ? '03' : '02'}${xStr}` | ||
return this._sec1Compressed = `${bigInt(this.publicPoint.y).isOdd() ? '03' : '02'}${xStr}` | ||
} | ||
@@ -82,7 +138,7 @@ get sec1Uncompressed() { | ||
} | ||
let yStr = bigInt(this.pubPoint.y).toString(16) | ||
let yStr = bigInt(this.publicPoint.y).toString(16) | ||
while (yStr.length < 64) { | ||
yStr = '0' + yStr | ||
} | ||
let xStr = bigInt(this.pubPoint.x).toString(16) | ||
let xStr = bigInt(this.publicPoint.x).toString(16) | ||
while (xStr.length < 64) { | ||
@@ -89,0 +145,0 @@ xStr = '0' + xStr |
@@ -52,8 +52,8 @@ try { | ||
let wallet = Wallet.fromWif(private) | ||
console.log('key', wallet.key) | ||
console.log('sec1 (compressed)',wallet.sec1Compressed) | ||
console.log('sec1 (uncompressed)',wallet.sec1Uncompressed) | ||
console.log('wif',wallet.wif) | ||
console.log('address',wallet.address) | ||
console.log('compressAddress',wallet.compressAddress) | ||
// console.log('key', wallet.key) | ||
// console.log('sec1 (compressed)',wallet.sec1Compressed) | ||
// console.log('sec1 (uncompressed)',wallet.sec1Uncompressed) | ||
// console.log('wif',wallet.wif) | ||
// console.log('address',wallet.address) | ||
// console.log('compressAddress',wallet.compressAddress) | ||
if (wallet.address !== privateToPublic[private]) { | ||
@@ -63,2 +63,41 @@ throw 'invalid public key generation '+privateToPublic[private] | ||
} | ||
;(() => { | ||
let wallet = Wallet.fromKey('82ef796afbce6e67bcb6bc44d922e5d2e664ebe118c0ed5b6ce3b481a638ec90') | ||
const signature = wallet.sign('test', '2900c9abe4a9d00b2a4aa6663d8f4989c8cac35f4fe9b2c5b66e07a3903e1c3') | ||
if (signature.r.toString(16) !== '85a44b824bda975b15ac77a3256c5d6f21c19b0412eb19333844fc2dbd25dbba') { | ||
throw 'invalid signature r value' | ||
} | ||
// if (signature.s.toString(16) !== '79a1e1e6c94d3cc0388d8659cf7e7fbc6d6e03a1a19446258d19b82071b95c7d') { | ||
// throw 'invalid signature s value' | ||
// } | ||
if (wallet.verify('test', signature) !== true) { | ||
throw 'signing or verification failure' | ||
} | ||
if (wallet.verify(`${Math.random()}`, signature) !== false) { | ||
throw 'falsifiable verification' | ||
} | ||
if (Wallet.new().verify('test', signature) !== false) { | ||
throw 'falsifiable wallet verification' | ||
} | ||
})() | ||
let i = 0 | ||
while (i < 3) { | ||
const message = `${Math.random()}` | ||
let wallet = Wallet.new() | ||
const signature = wallet.sign(message) | ||
if (wallet.verify(message, signature) !== true) { | ||
throw 'signing or verification failure' | ||
} | ||
if (wallet.verify(`${Math.random()}`, signature) !== false) { | ||
throw 'falsifiable verification' | ||
} | ||
if (Wallet.new().verify(message, signature) !== false) { | ||
throw 'falsifiable wallet verification' | ||
} | ||
i ++ | ||
} | ||
console.log('✅ wallet tests passed') | ||
@@ -65,0 +104,0 @@ } |
36759
11
1007