commit
3a70d81043
3 changed files with 36 additions and 41 deletions
67
src/ecdsa.js
67
src/ecdsa.js
|
@ -75,25 +75,21 @@ function deterministicGenerateK (curve, hash, d, checkSig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function sign (curve, hash, d) {
|
function sign (curve, hash, d) {
|
||||||
var r, s
|
|
||||||
|
|
||||||
var e = BigInteger.fromBuffer(hash)
|
var e = BigInteger.fromBuffer(hash)
|
||||||
var n = curve.n
|
var n = curve.n
|
||||||
var G = curve.G
|
var G = curve.G
|
||||||
|
|
||||||
|
var r, s
|
||||||
deterministicGenerateK(curve, hash, d, function (k) {
|
deterministicGenerateK(curve, hash, d, function (k) {
|
||||||
var Q = G.multiply(k)
|
var Q = G.multiply(k)
|
||||||
|
|
||||||
if (curve.isInfinity(Q))
|
if (curve.isInfinity(Q)) return false
|
||||||
return false
|
|
||||||
|
|
||||||
r = Q.affineX.mod(n)
|
r = Q.affineX.mod(n)
|
||||||
if (r.signum() === 0)
|
if (r.signum() === 0) return false
|
||||||
return false
|
|
||||||
|
|
||||||
s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n)
|
s = k.modInverse(n).multiply(e.add(d.multiply(r))).mod(n)
|
||||||
if (s.signum() === 0)
|
if (s.signum() === 0) return false
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
@ -108,7 +104,7 @@ function sign (curve, hash, d) {
|
||||||
return new ECSignature(r, s)
|
return new ECSignature(r, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyRaw (curve, e, signature, Q) {
|
function verify (curve, hash, signature, Q) {
|
||||||
var n = curve.n
|
var n = curve.n
|
||||||
var G = curve.G
|
var G = curve.G
|
||||||
|
|
||||||
|
@ -119,31 +115,33 @@ function verifyRaw (curve, e, signature, Q) {
|
||||||
if (r.signum() <= 0 || r.compareTo(n) >= 0) return false
|
if (r.signum() <= 0 || r.compareTo(n) >= 0) return false
|
||||||
if (s.signum() <= 0 || s.compareTo(n) >= 0) return false
|
if (s.signum() <= 0 || s.compareTo(n) >= 0) return false
|
||||||
|
|
||||||
// c = s^-1 mod n
|
|
||||||
var c = s.modInverse(n)
|
|
||||||
|
|
||||||
// 1.4.4 Compute u1 = es^−1 mod n
|
|
||||||
// u2 = rs^−1 mod n
|
|
||||||
var u1 = e.multiply(c).mod(n)
|
|
||||||
var u2 = r.multiply(c).mod(n)
|
|
||||||
|
|
||||||
// 1.4.5 Compute R = (xR, yR) = u1G + u2Q
|
|
||||||
var R = G.multiplyTwo(u1, Q, u2)
|
|
||||||
var v = R.affineX.mod(n)
|
|
||||||
|
|
||||||
// 1.4.5 (cont.) Enforce R is not at infinity
|
|
||||||
if (curve.isInfinity(R)) return false
|
|
||||||
|
|
||||||
// 1.4.8 If v = r, output "valid", and if v != r, output "invalid"
|
|
||||||
return v.equals(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
function verify (curve, hash, signature, Q) {
|
|
||||||
// 1.4.2 H = Hash(M), already done by the user
|
// 1.4.2 H = Hash(M), already done by the user
|
||||||
// 1.4.3 e = H
|
// 1.4.3 e = H
|
||||||
var e = BigInteger.fromBuffer(hash)
|
var e = BigInteger.fromBuffer(hash)
|
||||||
|
|
||||||
return verifyRaw(curve, e, signature, Q)
|
// Compute s^-1
|
||||||
|
var sInv = s.modInverse(n)
|
||||||
|
|
||||||
|
// 1.4.4 Compute u1 = es^−1 mod n
|
||||||
|
// u2 = rs^−1 mod n
|
||||||
|
var u1 = e.multiply(sInv).mod(n)
|
||||||
|
var u2 = r.multiply(sInv).mod(n)
|
||||||
|
|
||||||
|
// 1.4.5 Compute R = (xR, yR)
|
||||||
|
// R = u1G + u2Q
|
||||||
|
var R = G.multiplyTwo(u1, Q, u2)
|
||||||
|
|
||||||
|
// 1.4.5 (cont.) Enforce R is not at infinity
|
||||||
|
if (curve.isInfinity(R)) return false
|
||||||
|
|
||||||
|
// 1.4.6 Convert the field element R.x to an integer
|
||||||
|
var xR = R.affineX
|
||||||
|
|
||||||
|
// 1.4.7 Set v = xR mod n
|
||||||
|
var v = xR.mod(n)
|
||||||
|
|
||||||
|
// 1.4.8 If v = r, output "valid", and if v != r, output "invalid"
|
||||||
|
return v.equals(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,14 +179,16 @@ function recoverPubKey (curve, e, signature, i) {
|
||||||
var nR = R.multiply(n)
|
var nR = R.multiply(n)
|
||||||
assert(curve.isInfinity(nR), 'nR is not a valid curve point')
|
assert(curve.isInfinity(nR), 'nR is not a valid curve point')
|
||||||
|
|
||||||
|
// Compute r^-1
|
||||||
|
var rInv = r.modInverse(n)
|
||||||
|
|
||||||
// Compute -e from e
|
// Compute -e from e
|
||||||
var eNeg = e.negate().mod(n)
|
var eNeg = e.negate().mod(n)
|
||||||
|
|
||||||
// 1.6.1 Compute Q = r^-1 (sR - eG)
|
// 1.6.1 Compute Q = r^-1 (sR - eG)
|
||||||
// Q = r^-1 (sR + -eG)
|
// Q = r^-1 (sR + -eG)
|
||||||
var rInv = r.modInverse(n)
|
|
||||||
|
|
||||||
var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv)
|
var Q = R.multiplyTwo(s, G, eNeg).multiply(rInv)
|
||||||
|
|
||||||
curve.validate(Q)
|
curve.validate(Q)
|
||||||
|
|
||||||
return Q
|
return Q
|
||||||
|
@ -223,6 +223,5 @@ module.exports = {
|
||||||
deterministicGenerateK: deterministicGenerateK,
|
deterministicGenerateK: deterministicGenerateK,
|
||||||
recoverPubKey: recoverPubKey,
|
recoverPubKey: recoverPubKey,
|
||||||
sign: sign,
|
sign: sign,
|
||||||
verify: verify,
|
verify: verify
|
||||||
verifyRaw: verifyRaw
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,30 +158,26 @@ describe('ecdsa', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('verify/verifyRaw', function () {
|
describe('verify', function () {
|
||||||
fixtures.valid.ecdsa.forEach(function (f) {
|
fixtures.valid.ecdsa.forEach(function (f) {
|
||||||
it('verifies a valid signature for "' + f.message + '"', function () {
|
it('verifies a valid signature for "' + f.message + '"', function () {
|
||||||
var d = BigInteger.fromHex(f.d)
|
var d = BigInteger.fromHex(f.d)
|
||||||
var H = crypto.sha256(f.message)
|
var H = crypto.sha256(f.message)
|
||||||
var e = BigInteger.fromBuffer(H)
|
|
||||||
var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
|
var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
|
||||||
var Q = curve.G.multiply(d)
|
var Q = curve.G.multiply(d)
|
||||||
|
|
||||||
assert(ecdsa.verify(curve, H, signature, Q))
|
assert(ecdsa.verify(curve, H, signature, Q))
|
||||||
assert(ecdsa.verifyRaw(curve, e, signature, Q))
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
fixtures.invalid.verifyRaw.forEach(function (f) {
|
fixtures.invalid.verify.forEach(function (f) {
|
||||||
it('fails to verify with ' + f.description, function () {
|
it('fails to verify with ' + f.description, function () {
|
||||||
var H = crypto.sha256(f.message)
|
var H = crypto.sha256(f.message)
|
||||||
var e = BigInteger.fromBuffer(H)
|
|
||||||
var d = BigInteger.fromHex(f.d)
|
var d = BigInteger.fromHex(f.d)
|
||||||
var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
|
var signature = new ECSignature(new BigInteger(f.signature.r), new BigInteger(f.signature.s))
|
||||||
var Q = curve.G.multiply(d)
|
var Q = curve.G.multiply(d)
|
||||||
|
|
||||||
assert.equal(ecdsa.verify(curve, H, signature, Q), false)
|
assert.equal(ecdsa.verify(curve, H, signature, Q), false)
|
||||||
assert.equal(ecdsa.verifyRaw(curve, e, signature, Q), false)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
2
test/fixtures/ecdsa.json
vendored
2
test/fixtures/ecdsa.json
vendored
|
@ -218,7 +218,7 @@
|
||||||
"i": 4
|
"i": 4
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"verifyRaw": [
|
"verify": [
|
||||||
{
|
{
|
||||||
"description": "The wrong signature",
|
"description": "The wrong signature",
|
||||||
"d": "01",
|
"d": "01",
|
||||||
|
|
Loading…
Add table
Reference in a new issue