simple-js-ecdsa
Advanced tools
Comparing version 1.4.6 to 1.5.0
{ | ||
"name": "simple-js-ecdsa", | ||
"version": "1.4.6", | ||
"version": "1.5.0", | ||
"description": "easy and light weight ecdsa implementation", | ||
@@ -30,4 +30,5 @@ "main": "./src/index.js", | ||
"simple-js-ec-math": "^1.3.2", | ||
"simple-js-secp256k1": "github:Azero123/simple-js-secp256k1#master", | ||
"simple-js-sha2-256": "^1.0.2" | ||
} | ||
} |
@@ -20,2 +20,7 @@ # simple-js-ecdsa | ||
opening a identity using sec1 | ||
``` | ||
Identity.fromSec1(<private wif>) | ||
``` | ||
retrievable items in a identity | ||
@@ -33,3 +38,3 @@ ``` | ||
``` | ||
const signature = identity.sign(message) | ||
const signature = identity.sign(<message>) | ||
``` | ||
@@ -39,3 +44,3 @@ | ||
``` | ||
identity.verify(message, signature) | ||
identity.verify(<message>, <signature>) | ||
``` | ||
@@ -45,3 +50,3 @@ | ||
``` | ||
const signature = identity.bip66Sign(message) | ||
const signature = identity.bip66Sign(<message>) | ||
``` | ||
@@ -51,5 +56,10 @@ | ||
``` | ||
identity.verifyBip66(message, signature) | ||
identity.verifyBip66(<message>, <signature>) | ||
``` | ||
verify address | ||
``` | ||
identity.validateAddress(<address>) | ||
``` | ||
# contribute | ||
@@ -56,0 +66,0 @@ |
const bigInt = require('big-integer') | ||
const base58 = require('bs58') | ||
const crypto = require('crypto') | ||
const secp256k1 = require('./secp256k1.js') | ||
const secp256k1 = require('simple-js-secp256k1') | ||
const ModPoint = require('simple-js-ec-math').ModPoint | ||
@@ -28,2 +29,3 @@ let hex = { '0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15 } | ||
} | ||
static fromKey(key, curve = secp256k1) { | ||
@@ -35,2 +37,3 @@ const wallet = new Identity() | ||
} | ||
static fromWif(wif, curve = secp256k1) { | ||
@@ -46,2 +49,32 @@ const wallet = new Identity() | ||
} | ||
static fromSec1(sec1, curve = secp256k1) { | ||
const mode = sec1.substr(0, 2) | ||
const x = bigInt(sec1.substr(2, 64), 16) | ||
const y = bigInt(sec1.substr(66, 130), 16) | ||
/* | ||
compressed guide | ||
https://crypto.stackexchange.com/questions/8914/ecdsa-compressed-public-key-point-back-to-uncompressed-public-key-point | ||
𝑍=𝑌/𝑋 | ||
𝑍2+𝑍=𝑋+𝑎+𝑏𝑋2 | ||
𝑌=𝑋𝑍 | ||
const w = secp256k1.b.divmod(x.modPow(2, secp256k1.p), secp256k1.p) | ||
console.log(w) | ||
const z2z = x.add(secp256k1.a).add(w) | ||
console.log(z2z) | ||
*/ | ||
const identity = new Identity() | ||
identity.curve = curve | ||
identity._publicPoint = new ModPoint(x, y) | ||
if ( | ||
(mode === '04' && sec1.length !== 130) || | ||
((mode === '03' || mode === '02') && sec1.length !== 66) || | ||
!secp256k1.verify(identity.publicPoint) | ||
) { | ||
throw 'invalid address' + (mode === '03' || mode === '02') ? ' compressed addresses not yet supported' : '' | ||
} | ||
return identity | ||
} | ||
sign(message, k = this.curve.modSet.random()) { | ||
@@ -63,2 +96,12 @@ const e = bigInt(sha256(message), 16) | ||
static validateAddress(address) { | ||
if (address.length !== 34) { | ||
throw 'invalid address' | ||
} | ||
address = base58.decode(address).toString('hex') | ||
const addressChecksum = binSha256(binSha256(address.substr(0,42))).substr(0, 8) | ||
const checksum = address.substr(42,50) | ||
return addressChecksum === checksum | ||
} | ||
bip66Sign(message, k = this.curve.modSet.random()) { | ||
@@ -106,9 +149,3 @@ let signature = this.sign(message, k) | ||
} | ||
static fromAddress(address, curve = secp256k1) { | ||
const wallet = new Identity() | ||
wallet.curve = curve | ||
wallet._address = address | ||
return wallet | ||
} | ||
get wif() { | ||
@@ -122,2 +159,3 @@ if (this._wif) { | ||
} | ||
get publicPoint() { | ||
@@ -129,26 +167,22 @@ if (this._publicPoint) { | ||
} | ||
get sec1Compressed() { | ||
if (this._sec1Compressed) { | ||
return this._sec1Compressed | ||
} | ||
let xStr = bigInt(this.publicPoint.x).toString(16) | ||
while (xStr.length < 64) { | ||
xStr = '0' + xStr | ||
} | ||
return this._sec1Compressed = `${bigInt(this.publicPoint.y).isOdd() ? '03' : '02'}${xStr}` | ||
return this._sec1Compressed || (this._sec1Compressed = | ||
`${ | ||
bigInt(this.publicPoint.y).isOdd() ? '03' : '02' | ||
}${ | ||
bigInt(this.publicPoint.x).toString(16).padStart(64, '0') | ||
}` | ||
) | ||
} | ||
get sec1Uncompressed() { | ||
if (this._sec1Uncompressed) { | ||
return this._sec1Uncompressed | ||
} | ||
let yStr = bigInt(this.publicPoint.y).toString(16) | ||
while (yStr.length < 64) { | ||
yStr = '0' + yStr | ||
} | ||
let xStr = bigInt(this.publicPoint.x).toString(16) | ||
while (xStr.length < 64) { | ||
xStr = '0' + xStr | ||
} | ||
return this._sec1Uncompressed = `04${xStr}${yStr}` | ||
return this._sec1Uncompressed || (this._sec1Uncompressed = | ||
`04${ | ||
bigInt(this.publicPoint.x).toString(16).padStart(64, '0') | ||
}${ | ||
bigInt(this.publicPoint.y).toString(16).padStart(64, '0') | ||
}` | ||
) | ||
} | ||
get address() { | ||
@@ -162,2 +196,3 @@ if (this._address) { | ||
} | ||
get compressAddress() { | ||
@@ -164,0 +199,0 @@ if (this._compressAddress) { |
@@ -53,8 +53,2 @@ try { | ||
let identity = Identity.fromWif(private) | ||
// console.log('key', identity.key) | ||
// console.log('sec1 (compressed)',identity.sec1Compressed) | ||
// console.log('sec1 (uncompressed)',identity.sec1Uncompressed) | ||
// console.log('wif',identity.wif) | ||
// console.log('address',identity.address) | ||
// console.log('compressAddress',identity.compressAddress) | ||
if (identity.address !== privateToPublic[private]) { | ||
@@ -153,2 +147,103 @@ throw 'invalid public key generation '+privateToPublic[private] | ||
})() | ||
;(()=>{ | ||
const Identity = require('../src/index.js') | ||
const identity = Identity.fromWif('5JJQHQSZP9z5wHjerG8QL3mPXVpCgrWR8dw1TfiJHhjR5DieHTX') | ||
if (identity.sec1Compressed !== '02d2cb1636c8800502112f346f10a62e256d42b5ea46b3a55e2ff4607167afd2fd') { | ||
throw 'invalid sec1 (compressed)' | ||
} | ||
if (identity.sec1Uncompressed !== '04d2cb1636c8800502112f346f10a62e256d42b5ea46b3a55e2ff4607167afd2fdbdb2bfd6280aca239796dc4eb6283ad2d31a5ef417620efb095887c7dc56a5ba') { | ||
throw 'invalid sec1 (uncompressed)' | ||
} | ||
if (identity.key !== '3fd6fd76821d9b1191cb24894be0f760b8d08fe837347e3d940b53a49f9a884e') { | ||
throw 'invalid private key' | ||
} | ||
if (identity.wif !== '5JJQHQSZP9z5wHjerG8QL3mPXVpCgrWR8dw1TfiJHhjR5DieHTX') { | ||
throw 'invalid wif' | ||
} | ||
if (identity.address !== '1C4cseQKY442fKKHP8LvrakkBdZRJYWGmh') { | ||
throw 'invalid address (uncompressed)' | ||
} | ||
if (identity.compressAddress !== '1AHbAE2SyMp2hAPDZiCo1RsdZyAFqPsyRg') { | ||
throw 'invalid address (compressed)' | ||
} | ||
if (!Identity.validateAddress(identity.compressAddress)) { | ||
throw 'unable to validate valid address (compressed)' | ||
} | ||
if (!Identity.validateAddress(identity.address)) { | ||
throw 'unable to validate valid address (uncompressed)' | ||
} | ||
let threwError = false | ||
try { | ||
const invalidAddress = identity.compressAddress | ||
invalidAddress[49] = '3' | ||
if (Identity.validateAddress(invalidAddress)) { | ||
throw 'unable to invalidate invalid address (compressed)' | ||
} | ||
if (Identity.validateAddress(identity.compressAddress.substr(0, 49))) { | ||
throw 'unable to invalidate invalid address (compressed)' | ||
} | ||
} | ||
catch (e) { | ||
threwError = true | ||
} | ||
if (!threwError) { | ||
throw 'should have thrown an error on invalid address' | ||
} | ||
threwError = false | ||
try { | ||
const invalidAddress = identity.address | ||
invalidAddress[49] = '3' | ||
if (Identity.validateAddress(invalidAddress)) { | ||
throw 'unable to invalidate invalid address (uncompressed)' | ||
} | ||
if (Identity.validateAddress(identity.address.substr(0, 49))) { | ||
throw 'unable to invalidate invalid address (uncompressed)' | ||
} | ||
} | ||
catch (e) { | ||
threwError = true | ||
} | ||
if (!threwError) { | ||
throw 'should have thrown an error on invalid address' | ||
} | ||
// threwError = false | ||
// try { Identity.fromSec1(identity.sec1Compressed) } catch (e) { threwError = true; console.error(e) } | ||
// if (threwError) { | ||
// throw 'should not have thrown an error when making an identity from sec1 format (compressed)' | ||
// } | ||
threwError = false | ||
try { Identity.fromSec1(identity.sec1Uncompressed) } catch (e) { threwError = true } | ||
if (threwError) { | ||
throw 'should not have thrown an error when making an identity from sec1 format (uncompressed)' | ||
} | ||
threwError = false | ||
try { | ||
const sec1 = identity.sec1Compressed.replace('8800', '1111') | ||
sec1[8] = '3' | ||
Identity.fromSec1(sec1) | ||
} catch (e) { threwError = true; } | ||
if (!threwError) { | ||
throw 'should have thrown an error when provided a bad sec1 point (compressed)' | ||
} | ||
threwError = false | ||
try { | ||
const sec1 = identity.sec1Uncompressed.replace('8800', '1111') | ||
Identity.fromSec1(sec1) | ||
} catch (e) { threwError = true } | ||
if (!threwError) { | ||
throw 'should have thrown an error when provided a bad sec1 point (uncompressed)' | ||
} | ||
console.log('✅ formats passed') | ||
})() | ||
} | ||
@@ -155,0 +250,0 @@ catch (e) { |
Sorry, the diff of this file is not supported yet
GitHub dependency
Supply chain riskContains a dependency which resolves to a GitHub URL. Dependencies fetched from GitHub specifiers are not immutable can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
64
46026
4
8
1