mirror of
https://github.com/Xahau/xahau.js.git
synced 2025-12-06 17:27:59 +00:00
Remove lint errors in sjcl-custom
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
'use strict';
|
||||
require('./sjcl-ecc-pointextras.js');
|
||||
require('./sjcl-secp256k1.js');
|
||||
require('./sjcl-ripemd160.js');
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
/* eslint new-cap: [2, {newIsCapExceptions: ["bn"]}] */
|
||||
'use strict';
|
||||
var sjcl = require('sjcl');
|
||||
/**
|
||||
* Check that the point is valid based on the method described in
|
||||
* SEC 1: Elliptic Curve Cryptography, section 3.2.2.1:
|
||||
* SEC 1: Elliptic Curve Cryptography, section 3.2.2.1:
|
||||
* Elliptic Curve Public Key Validation Primitive
|
||||
* http://www.secg.org/download/aid-780/sec1-v2.pdf
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* @returns {Boolean} true if point is valid
|
||||
*/
|
||||
sjcl.ecc.point.prototype.isValidPoint = function() {
|
||||
|
||||
@@ -49,19 +51,19 @@ sjcl.ecc.point.prototype.isValidPoint = function() {
|
||||
/**
|
||||
* Check that the point is on the curve
|
||||
*
|
||||
* @returns {Boolean}
|
||||
* @returns {Boolean} true if point is on the curve
|
||||
*/
|
||||
sjcl.ecc.point.prototype.isOnCurve = function() {
|
||||
|
||||
var self = this;
|
||||
|
||||
var field_order = self.curve.r;
|
||||
var component_a = self.curve.a;
|
||||
var component_b = self.curve.b;
|
||||
var field_modulus = self.curve.field.modulus;
|
||||
|
||||
var left_hand_side = self.y.mul(self.y).mod(field_modulus);
|
||||
var right_hand_side = self.x.mul(self.x).mul(self.x).add(component_a.mul(self.x)).add(component_b).mod(field_modulus);
|
||||
var right_hand_side = self.x.mul(self.x).mul(self.x).add(
|
||||
component_a.mul(self.x)).add(component_b).mod(field_modulus);
|
||||
|
||||
return left_hand_side.equals(right_hand_side);
|
||||
|
||||
@@ -69,14 +71,14 @@ sjcl.ecc.point.prototype.isOnCurve = function() {
|
||||
|
||||
|
||||
sjcl.ecc.point.prototype.toString = function() {
|
||||
return '(' +
|
||||
return '(' +
|
||||
this.x.toString() + ', ' +
|
||||
this.y.toString() +
|
||||
')';
|
||||
};
|
||||
|
||||
sjcl.ecc.pointJac.prototype.toString = function() {
|
||||
return '(' +
|
||||
return '(' +
|
||||
this.x.toString() + ', ' +
|
||||
this.y.toString() + ', ' +
|
||||
this.z.toString() +
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use strict';
|
||||
var sjcl = require('sjcl');
|
||||
|
||||
sjcl.ecc.ecdsa.secretKey.prototype.canonicalizeSignature = function(rs) {
|
||||
@@ -5,8 +6,8 @@ sjcl.ecc.ecdsa.secretKey.prototype.canonicalizeSignature = function(rs) {
|
||||
R = this._curve.r,
|
||||
l = R.bitLength();
|
||||
|
||||
var r = sjcl.bn.fromBits(w.bitSlice(rs,0,l)),
|
||||
s = sjcl.bn.fromBits(w.bitSlice(rs,l,2*l));
|
||||
var r = sjcl.bn.fromBits(w.bitSlice(rs, 0, l)),
|
||||
s = sjcl.bn.fromBits(w.bitSlice(rs, l, 2 * l));
|
||||
|
||||
// For a canonical signature we want the lower of two possible values for s
|
||||
// 0 < s <= n/2
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
'use strict';
|
||||
var sjcl = require('sjcl');
|
||||
|
||||
sjcl.ecc.ecdsa.secretKey.prototype.signDER = function(hash, paranoia) {
|
||||
@@ -9,16 +10,24 @@ sjcl.ecc.ecdsa.secretKey.prototype.encodeDER = function(rs) {
|
||||
R = this._curve.r,
|
||||
l = R.bitLength();
|
||||
|
||||
var rb = sjcl.codec.bytes.fromBits(w.bitSlice(rs,0,l)),
|
||||
sb = sjcl.codec.bytes.fromBits(w.bitSlice(rs,l,2*l));
|
||||
var rb = sjcl.codec.bytes.fromBits(w.bitSlice(rs, 0, l)),
|
||||
sb = sjcl.codec.bytes.fromBits(w.bitSlice(rs, l, 2 * l));
|
||||
|
||||
// Drop empty leading bytes
|
||||
while (!rb[0] && rb.length) rb.shift();
|
||||
while (!sb[0] && sb.length) sb.shift();
|
||||
while (!rb[0] && rb.length) {
|
||||
rb.shift();
|
||||
}
|
||||
while (!sb[0] && sb.length) {
|
||||
sb.shift();
|
||||
}
|
||||
|
||||
// If high bit is set, prepend an extra zero byte (DER signed integer)
|
||||
if (rb[0] & 0x80) rb.unshift(0);
|
||||
if (sb[0] & 0x80) sb.unshift(0);
|
||||
if (rb[0] & 0x80) {
|
||||
rb.unshift(0);
|
||||
}
|
||||
if (sb[0] & 0x80) {
|
||||
sb.unshift(0);
|
||||
}
|
||||
|
||||
var buffer = [].concat(
|
||||
0x30,
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/* eslint-disable valid-jsdoc */
|
||||
/* eslint new-cap: [2, {newIsCapExceptions: [
|
||||
"bn", "invalid", "point", "corrupt", "bug", "publicKey"]}] */
|
||||
'use strict';
|
||||
var sjcl = require('sjcl');
|
||||
|
||||
/**
|
||||
@@ -7,121 +11,18 @@ var sjcl = require('sjcl');
|
||||
* http://www.secg.org/download/aid-780/sec1-v2.pdf
|
||||
*
|
||||
* Implementation based on:
|
||||
* https://github.com/bitcoinjs/bitcoinjs-lib/blob/89cf731ac7309b4f98994e3b4b67b7226020181f/src/ecdsa.js
|
||||
* https://github.com/bitcoinjs/bitcoinjs-lib/blob/
|
||||
* 89cf731ac7309b4f98994e3b4b67b7226020181f/src/ecdsa.js
|
||||
*/
|
||||
|
||||
// Defined here so that this value only needs to be calculated once
|
||||
var FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR;
|
||||
|
||||
/**
|
||||
* Sign the given hash such that the public key, prepending an extra byte
|
||||
* so that the public key will be recoverable from the signature
|
||||
* Retrieve the r and s components of a signature
|
||||
*
|
||||
* @param {bitArray} hash
|
||||
* @param {Number} paranoia
|
||||
* @returns {bitArray} Signature formatted as bitArray
|
||||
*/
|
||||
sjcl.ecc.ecdsa.secretKey.prototype.signWithRecoverablePublicKey = function(hash, paranoia, k_for_testing) {
|
||||
|
||||
var self = this;
|
||||
|
||||
// Convert hash to bits and determine encoding for output
|
||||
var hash_bits;
|
||||
if (typeof hash === 'object' && hash.length > 0 && typeof hash[0] === 'number') {
|
||||
hash_bits = hash;
|
||||
} else {
|
||||
throw new sjcl.exception.invalid('hash. Must be a bitArray');
|
||||
}
|
||||
|
||||
// Sign hash with standard, canonicalized method
|
||||
var standard_signature = self.sign(hash_bits, paranoia, k_for_testing);
|
||||
var canonical_signature = self.canonicalizeSignature(standard_signature);
|
||||
|
||||
// Extract r and s signature components from canonical signature
|
||||
var r_and_s = getRandSFromSignature(self._curve, canonical_signature);
|
||||
|
||||
// Rederive public key
|
||||
var public_key = self._curve.G.mult(sjcl.bn.fromBits(self.get()));
|
||||
|
||||
// Determine recovery factor based on which possible value
|
||||
// returns the correct public key
|
||||
var recovery_factor = calculateRecoveryFactor(self._curve, r_and_s.r, r_and_s.s, hash_bits, public_key);
|
||||
|
||||
// Prepend recovery_factor to signature and encode in DER
|
||||
// The value_to_prepend should be 4 bytes total
|
||||
var value_to_prepend = recovery_factor + 27;
|
||||
|
||||
var final_signature_bits = sjcl.bitArray.concat([value_to_prepend], canonical_signature);
|
||||
|
||||
// Return value in bits
|
||||
return final_signature_bits;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Recover the public key from a signature created with the
|
||||
* signWithRecoverablePublicKey method in this module
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @param {bitArray} hash
|
||||
* @param {bitArray} signature
|
||||
* @param {sjcl.ecc.curve} [sjcl.ecc.curves['k256']] curve
|
||||
* @returns {sjcl.ecc.ecdsa.publicKey} Public key
|
||||
*/
|
||||
sjcl.ecc.ecdsa.publicKey.recoverFromSignature = function(hash, signature, curve) {
|
||||
|
||||
if (!signature || signature instanceof sjcl.ecc.curve) {
|
||||
throw new sjcl.exception.invalid('must supply hash and signature to recover public key');
|
||||
}
|
||||
|
||||
if (!curve) {
|
||||
curve = sjcl.ecc.curves['k256'];
|
||||
}
|
||||
|
||||
// Convert hash to bits and determine encoding for output
|
||||
var hash_bits;
|
||||
if (typeof hash === 'object' && hash.length > 0 && typeof hash[0] === 'number') {
|
||||
hash_bits = hash;
|
||||
} else {
|
||||
throw new sjcl.exception.invalid('hash. Must be a bitArray');
|
||||
}
|
||||
|
||||
var signature_bits;
|
||||
if (typeof signature === 'object' && signature.length > 0 && typeof signature[0] === 'number') {
|
||||
signature_bits = signature;
|
||||
} else {
|
||||
throw new sjcl.exception.invalid('signature. Must be a bitArray');
|
||||
}
|
||||
|
||||
// Extract recovery_factor from first 4 bytes
|
||||
var recovery_factor = signature_bits[0] - 27;
|
||||
|
||||
if (recovery_factor < 0 || recovery_factor > 3) {
|
||||
throw new sjcl.exception.invalid('signature. Signature must be generated with algorithm ' +
|
||||
'that prepends the recovery factor in order to recover the public key');
|
||||
}
|
||||
|
||||
// Separate r and s values
|
||||
var r_and_s = getRandSFromSignature(curve, signature_bits.slice(1));
|
||||
var signature_r = r_and_s.r;
|
||||
var signature_s = r_and_s.s;
|
||||
|
||||
// Recover public key using recovery_factor
|
||||
var recovered_public_key_point = recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, hash_bits, recovery_factor);
|
||||
var recovered_public_key = new sjcl.ecc.ecdsa.publicKey(curve, recovered_public_key_point);
|
||||
|
||||
return recovered_public_key;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve the r and s components of a signature
|
||||
*
|
||||
* @param {sjcl.ecc.curve} curve
|
||||
* @param {bitArray} signature
|
||||
* @param {sjcl.ecc.curve} curve - curve
|
||||
* @param {bitArray} signature - signature
|
||||
* @returns {Object} Object with 'r' and 's' fields each as an sjcl.bn
|
||||
*/
|
||||
function getRandSFromSignature(curve, signature) {
|
||||
@@ -130,50 +31,51 @@ function getRandSFromSignature(curve, signature) {
|
||||
|
||||
return {
|
||||
r: sjcl.bn.fromBits(sjcl.bitArray.bitSlice(signature, 0, r_length)),
|
||||
s: sjcl.bn.fromBits(sjcl.bitArray.bitSlice(signature, r_length, sjcl.bitArray.bitLength(signature)))
|
||||
s: sjcl.bn.fromBits(sjcl.bitArray.bitSlice(
|
||||
signature, r_length, sjcl.bitArray.bitLength(signature)))
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the recovery factor by trying all four
|
||||
* possibilities and figuring out which results in the
|
||||
* correct public key
|
||||
* Verify a signature given the raw components
|
||||
* using method defined in section 4.1.5:
|
||||
* "Alternative Verifying Operation"
|
||||
*
|
||||
* @param {sjcl.ecc.curve} curve
|
||||
* @param {sjcl.bn} e
|
||||
* @param {sjcl.bn} r
|
||||
* @param {sjcl.bn} s
|
||||
* @param {bitArray} hash_bits
|
||||
* @param {sjcl.ecc.point} original_public_key_point
|
||||
* @returns {Number, 0-3} Recovery factor
|
||||
* @param {sjcl.ecc.point} public_key_point
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
function calculateRecoveryFactor(curve, r, s, hash_bits, original_public_key_point) {
|
||||
function verify_raw(curve, e, r, s, public_key_point) {
|
||||
|
||||
var original_public_key_point_bits = original_public_key_point.toBits();
|
||||
|
||||
// TODO: verify that it is possible for the recovery_factor to be 2 or 3,
|
||||
// we may only need 1 bit because the canonical signature might remove the
|
||||
// possibility of us needing to "use the second candidate key"
|
||||
for (var possible_factor = 0; possible_factor < 4; possible_factor++) {
|
||||
|
||||
var resulting_public_key_point;
|
||||
try {
|
||||
resulting_public_key_point = recoverPublicKeyPointFromSignature(curve, r, s, hash_bits, possible_factor);
|
||||
} catch (err) {
|
||||
// console.log(err, err.stack);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sjcl.bitArray.equal(resulting_public_key_point.toBits(), original_public_key_point_bits)) {
|
||||
return possible_factor;
|
||||
}
|
||||
var field_order = curve.r;
|
||||
|
||||
// Return false if r is out of bounds
|
||||
if ((new sjcl.bn(1)).greaterEquals(r)
|
||||
|| r.greaterEquals(new sjcl.bn(field_order))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new sjcl.exception.bug('unable to calculate recovery factor from signature');
|
||||
// Return false if s is out of bounds
|
||||
if ((new sjcl.bn(1)).greaterEquals(s)
|
||||
|| s.greaterEquals(new sjcl.bn(field_order))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
// Check that r = (u1 + u2)G
|
||||
// u1 = e x s^-1 (mod field_order)
|
||||
// u2 = r x s^-1 (mod field_order)
|
||||
var s_mod_inverse_field_order = s.inverseMod(field_order);
|
||||
var u1 = e.mul(s_mod_inverse_field_order).mod(field_order);
|
||||
var u2 = r.mul(s_mod_inverse_field_order).mod(field_order);
|
||||
|
||||
var point_computed = curve.G.mult2(u1, u2, public_key_point);
|
||||
|
||||
return r.equals(point_computed.x.mod(field_order));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover the public key from the signature.
|
||||
@@ -185,7 +87,8 @@ function calculateRecoveryFactor(curve, r, s, hash_bits, original_public_key_poi
|
||||
* @param {Number, 0-3} recovery_factor
|
||||
* @returns {sjcl.point} Public key corresponding to signature
|
||||
*/
|
||||
function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, hash_bits, recovery_factor) {
|
||||
function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s,
|
||||
hash_bits, recovery_factor) {
|
||||
|
||||
var field_order = curve.r;
|
||||
var field_modulus = curve.field.modulus;
|
||||
@@ -218,9 +121,12 @@ function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, has
|
||||
}
|
||||
|
||||
// step 1.2 and 1.3 convert x to an elliptic curve point
|
||||
// Following formula in section 2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion
|
||||
var alpha = x.mul(x).mul(x).add(curve.a.mul(x)).add(curve.b).mod(field_modulus);
|
||||
var beta = alpha.powermodMontgomery(FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR, field_modulus);
|
||||
// Following formula in section 2.3.4 Octet-String-to-Elliptic-Curve-Point
|
||||
// Conversion
|
||||
var alpha = x.mul(x).mul(x).add(curve.a.mul(x)).add(curve.b).mod(
|
||||
field_modulus);
|
||||
var beta = alpha.powermodMontgomery(FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR,
|
||||
field_modulus);
|
||||
|
||||
// If beta is even but y isn't or
|
||||
// if beta is odd and y is even
|
||||
@@ -240,7 +146,8 @@ function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, has
|
||||
// step 1.4 check that R is valid and R x field_order !== infinity
|
||||
// TODO: add check for R x field_order === infinity
|
||||
if (!generated_point_R.isValidPoint()) {
|
||||
throw new sjcl.exception.corrupt('point R. Not a valid point on the curve. Cannot recover public key');
|
||||
throw new sjcl.exception.corrupt(
|
||||
'point R. Not a valid point on the curve. Cannot recover public key');
|
||||
}
|
||||
|
||||
// step 1.5 Compute e from M
|
||||
@@ -250,59 +157,176 @@ function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, has
|
||||
// step 1.6 Compute Q = r^-1 (sR - eG)
|
||||
// console.log('r: ', signature_r);
|
||||
var signature_r_inv = signature_r.inverseMod(field_order);
|
||||
var public_key_point = generated_point_R.mult2(signature_s, message_e_neg, curve.G).mult(signature_r_inv);
|
||||
var public_key_point = generated_point_R.mult2(signature_s, message_e_neg,
|
||||
curve.G).mult(signature_r_inv);
|
||||
|
||||
// Validate public key point
|
||||
if (!public_key_point.isValidPoint()) {
|
||||
throw new sjcl.exception.corrupt('public_key_point. Not a valid point on the curve. Cannot recover public key');
|
||||
throw new sjcl.exception.corrupt('public_key_point. Not a valid point'
|
||||
+ ' on the curve. Cannot recover public key');
|
||||
}
|
||||
|
||||
// Verify that this public key matches the signature
|
||||
if (!verify_raw(curve, message_e, signature_r, signature_s, public_key_point)) {
|
||||
if (!verify_raw(curve, message_e, signature_r, signature_s,
|
||||
public_key_point)) {
|
||||
throw new sjcl.exception.corrupt('cannot recover public key');
|
||||
}
|
||||
|
||||
return public_key_point;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the recovery factor by trying all four
|
||||
* possibilities and figuring out which results in the
|
||||
* correct public key
|
||||
*
|
||||
* @param {sjcl.ecc.curve} curve
|
||||
* @param {sjcl.bn} r
|
||||
* @param {sjcl.bn} s
|
||||
* @param {bitArray} hash_bits
|
||||
* @param {sjcl.ecc.point} original_public_key_point
|
||||
* @returns {Number, 0-3} Recovery factor
|
||||
*/
|
||||
function calculateRecoveryFactor(curve, r, s, hash_bits,
|
||||
original_public_key_point) {
|
||||
|
||||
var original_public_key_point_bits = original_public_key_point.toBits();
|
||||
|
||||
// TODO: verify that it is possible for the recovery_factor to be 2 or 3,
|
||||
// we may only need 1 bit because the canonical signature might remove the
|
||||
// possibility of us needing to "use the second candidate key"
|
||||
for (var possible_factor = 0; possible_factor < 4; possible_factor++) {
|
||||
|
||||
var resulting_public_key_point;
|
||||
try {
|
||||
resulting_public_key_point = recoverPublicKeyPointFromSignature(
|
||||
curve, r, s, hash_bits, possible_factor);
|
||||
} catch (err) {
|
||||
// console.log(err, err.stack);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sjcl.bitArray.equal(resulting_public_key_point.toBits(),
|
||||
original_public_key_point_bits)) {
|
||||
return possible_factor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
throw new sjcl.exception.bug(
|
||||
'unable to calculate recovery factor from signature');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign the given hash such that the public key, prepending an extra byte
|
||||
* so that the public key will be recoverable from the signature
|
||||
*
|
||||
* @param {bitArray} hash - hash to sign
|
||||
* @param {Number} paranoia - minimum entropy required
|
||||
* @param {Number} k_for_testing - fixed k value to bypass PRNG
|
||||
* @returns {bitArray} Signature formatted as bitArray
|
||||
*/
|
||||
sjcl.ecc.ecdsa.secretKey.prototype.signWithRecoverablePublicKey = function(
|
||||
hash, paranoia, k_for_testing) {
|
||||
|
||||
var self = this;
|
||||
|
||||
// Convert hash to bits and determine encoding for output
|
||||
var hash_bits;
|
||||
if (typeof hash === 'object' && hash.length > 0
|
||||
&& typeof hash[0] === 'number') {
|
||||
hash_bits = hash;
|
||||
} else {
|
||||
throw new sjcl.exception.invalid('hash. Must be a bitArray');
|
||||
}
|
||||
|
||||
// Sign hash with standard, canonicalized method
|
||||
var standard_signature = self.sign(hash_bits, paranoia, k_for_testing);
|
||||
var canonical_signature = self.canonicalizeSignature(standard_signature);
|
||||
|
||||
// Extract r and s signature components from canonical signature
|
||||
var r_and_s = getRandSFromSignature(self._curve, canonical_signature);
|
||||
|
||||
// Rederive public key
|
||||
var public_key = self._curve.G.mult(sjcl.bn.fromBits(self.get()));
|
||||
|
||||
// Determine recovery factor based on which possible value
|
||||
// returns the correct public key
|
||||
var recovery_factor = calculateRecoveryFactor(self._curve, r_and_s.r,
|
||||
r_and_s.s, hash_bits, public_key);
|
||||
|
||||
// Prepend recovery_factor to signature and encode in DER
|
||||
// The value_to_prepend should be 4 bytes total
|
||||
var value_to_prepend = recovery_factor + 27;
|
||||
|
||||
var final_signature_bits = sjcl.bitArray.concat([value_to_prepend],
|
||||
canonical_signature);
|
||||
|
||||
// Return value in bits
|
||||
return final_signature_bits;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Verify a signature given the raw components
|
||||
* using method defined in section 4.1.5:
|
||||
* "Alternative Verifying Operation"
|
||||
* Recover the public key from a signature created with the
|
||||
* signWithRecoverablePublicKey method in this module
|
||||
*
|
||||
* @param {sjcl.ecc.curve} curve
|
||||
* @param {sjcl.bn} e
|
||||
* @param {sjcl.bn} r
|
||||
* @param {sjcl.bn} s
|
||||
* @param {sjcl.ecc.point} public_key_point
|
||||
* @returns {Boolean}
|
||||
* @static
|
||||
*
|
||||
* @param {bitArray} hash
|
||||
* @param {bitArray} signature
|
||||
* @param {sjcl.ecc.curve} [curve=sjcl.ecc.curves['k256']]
|
||||
* @returns {sjcl.ecc.ecdsa.publicKey} Public key
|
||||
*/
|
||||
function verify_raw(curve, e, r, s, public_key_point) {
|
||||
sjcl.ecc.ecdsa.publicKey.recoverFromSignature = function(
|
||||
hash, signature, curve) {
|
||||
|
||||
var field_order = curve.r;
|
||||
|
||||
// Return false if r is out of bounds
|
||||
if ((new sjcl.bn(1)).greaterEquals(r) || r.greaterEquals(new sjcl.bn(field_order))) {
|
||||
return false;
|
||||
if (!signature || signature instanceof sjcl.ecc.curve) {
|
||||
throw new sjcl.exception.invalid(
|
||||
'must supply hash and signature to recover public key');
|
||||
}
|
||||
|
||||
// Return false if s is out of bounds
|
||||
if ((new sjcl.bn(1)).greaterEquals(s) || s.greaterEquals(new sjcl.bn(field_order))) {
|
||||
return false;
|
||||
if (!curve) {
|
||||
curve = sjcl.ecc.curves.k256;
|
||||
}
|
||||
|
||||
// Check that r = (u1 + u2)G
|
||||
// u1 = e x s^-1 (mod field_order)
|
||||
// u2 = r x s^-1 (mod field_order)
|
||||
var s_mod_inverse_field_order = s.inverseMod(field_order);
|
||||
var u1 = e.mul(s_mod_inverse_field_order).mod(field_order);
|
||||
var u2 = r.mul(s_mod_inverse_field_order).mod(field_order);
|
||||
// Convert hash to bits and determine encoding for output
|
||||
var hash_bits;
|
||||
if (typeof hash === 'object' && hash.length > 0
|
||||
&& typeof hash[0] === 'number') {
|
||||
hash_bits = hash;
|
||||
} else {
|
||||
throw new sjcl.exception.invalid('hash. Must be a bitArray');
|
||||
}
|
||||
|
||||
var point_computed = curve.G.mult2(u1, u2, public_key_point);
|
||||
var signature_bits;
|
||||
if (typeof signature === 'object' && signature.length > 0
|
||||
&& typeof signature[0] === 'number') {
|
||||
signature_bits = signature;
|
||||
} else {
|
||||
throw new sjcl.exception.invalid('signature. Must be a bitArray');
|
||||
}
|
||||
|
||||
return r.equals(point_computed.x.mod(field_order));
|
||||
// Extract recovery_factor from first 4 bytes
|
||||
var recovery_factor = signature_bits[0] - 27;
|
||||
|
||||
if (recovery_factor < 0 || recovery_factor > 3) {
|
||||
throw new sjcl.exception.invalid(
|
||||
'signature. Signature must be generated with algorithm ' +
|
||||
'that prepends the recovery factor in order to recover the public key');
|
||||
}
|
||||
|
||||
// Separate r and s values
|
||||
var r_and_s = getRandSFromSignature(curve, signature_bits.slice(1));
|
||||
var signature_r = r_and_s.r;
|
||||
var signature_s = r_and_s.s;
|
||||
|
||||
// Recover public key using recovery_factor
|
||||
var recovered_public_key_point = recoverPublicKeyPointFromSignature(
|
||||
curve, signature_r, signature_s, hash_bits, recovery_factor);
|
||||
var recovered_public_key = new sjcl.ecc.ecdsa.publicKey(
|
||||
curve, recovered_public_key_point);
|
||||
|
||||
return recovered_public_key;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
/* eslint new-cap: [2, {newIsCapExceptions: ["bn"]}] */
|
||||
'use strict';
|
||||
var sjcl = require('sjcl');
|
||||
|
||||
sjcl.bn.ZERO = new sjcl.bn(0);
|
||||
|
||||
/** [ this / that , this % that ] */
|
||||
sjcl.bn.prototype.divRem = function (that) {
|
||||
if (typeof(that) !== "object") { that = new this._class(that); }
|
||||
/* [ this / that , this % that ] */
|
||||
sjcl.bn.prototype.divRem = function(that) {
|
||||
if (typeof that !== 'object') {
|
||||
that = new this._class(that);
|
||||
}
|
||||
var thisa = this.abs(), thata = that.abs(), quot = new this._class(0),
|
||||
ci = 0;
|
||||
if (!thisa.greaterEquals(thata)) {
|
||||
@@ -27,8 +31,8 @@ sjcl.bn.prototype.divRem = function (that) {
|
||||
return [quot, thisa];
|
||||
};
|
||||
|
||||
/** this /= that (rounded to nearest int) */
|
||||
sjcl.bn.prototype.divRound = function (that) {
|
||||
/* this /= that (rounded to nearest int) */
|
||||
sjcl.bn.prototype.divRound = function(that) {
|
||||
var dr = this.divRem(that), quot = dr[0], rem = dr[1];
|
||||
|
||||
if (rem.doubleM().greaterEquals(that)) {
|
||||
@@ -38,32 +42,33 @@ sjcl.bn.prototype.divRound = function (that) {
|
||||
return quot;
|
||||
};
|
||||
|
||||
/** this /= that (rounded down) */
|
||||
sjcl.bn.prototype.div = function (that) {
|
||||
/* this /= that (rounded down) */
|
||||
sjcl.bn.prototype.div = function(that) {
|
||||
var dr = this.divRem(that);
|
||||
return dr[0];
|
||||
};
|
||||
|
||||
sjcl.bn.prototype.sign = function () {
|
||||
sjcl.bn.prototype.sign = function() {
|
||||
return this.greaterEquals(sjcl.bn.ZERO) ? 1 : -1;
|
||||
};
|
||||
|
||||
/** -this */
|
||||
sjcl.bn.prototype.neg = function () {
|
||||
/* -this */
|
||||
sjcl.bn.prototype.neg = function() {
|
||||
return sjcl.bn.ZERO.sub(this);
|
||||
};
|
||||
|
||||
/** |this| */
|
||||
sjcl.bn.prototype.abs = function () {
|
||||
/* |this| */
|
||||
sjcl.bn.prototype.abs = function() {
|
||||
if (this.sign() === -1) {
|
||||
return this.neg();
|
||||
} else return this;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/** this >> that */
|
||||
sjcl.bn.prototype.shiftRight = function (that) {
|
||||
if ("number" !== typeof that) {
|
||||
throw new Error("shiftRight expects a number");
|
||||
/* this >> that */
|
||||
sjcl.bn.prototype.shiftRight = function(that) {
|
||||
if (typeof that !== 'number') {
|
||||
throw new Error('shiftRight expects a number');
|
||||
}
|
||||
|
||||
that = +that;
|
||||
@@ -86,10 +91,10 @@ sjcl.bn.prototype.shiftRight = function (that) {
|
||||
return a;
|
||||
};
|
||||
|
||||
/** this >> that */
|
||||
sjcl.bn.prototype.shiftLeft = function (that) {
|
||||
if ("number" !== typeof that) {
|
||||
throw new Error("shiftLeft expects a number");
|
||||
/* this >> that */
|
||||
sjcl.bn.prototype.shiftLeft = function(that) {
|
||||
if (typeof that !== 'number') {
|
||||
throw new Error('shiftLeft expects a number');
|
||||
}
|
||||
|
||||
that = +that;
|
||||
@@ -112,28 +117,32 @@ sjcl.bn.prototype.shiftLeft = function (that) {
|
||||
return a;
|
||||
};
|
||||
|
||||
/** (int)this */
|
||||
/* (int)this */
|
||||
// NOTE Truncates to 32-bit integer
|
||||
sjcl.bn.prototype.toNumber = function () {
|
||||
sjcl.bn.prototype.toNumber = function() {
|
||||
return this.limbs[0] | 0;
|
||||
};
|
||||
|
||||
/** find n-th bit, 0 = LSB */
|
||||
sjcl.bn.prototype.testBit = function (bitIndex) {
|
||||
/* find n-th bit, 0 = LSB */
|
||||
sjcl.bn.prototype.testBit = function(bitIndex) {
|
||||
var limbIndex = Math.floor(bitIndex / this.radix);
|
||||
var bitIndexInLimb = bitIndex % this.radix;
|
||||
|
||||
if (limbIndex >= this.limbs.length) return 0;
|
||||
if (limbIndex >= this.limbs.length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (this.limbs[limbIndex] >>> bitIndexInLimb) & 1;
|
||||
};
|
||||
|
||||
/** set n-th bit, 0 = LSB */
|
||||
sjcl.bn.prototype.setBitM = function (bitIndex) {
|
||||
/* set n-th bit, 0 = LSB */
|
||||
sjcl.bn.prototype.setBitM = function(bitIndex) {
|
||||
var limbIndex = Math.floor(bitIndex / this.radix);
|
||||
var bitIndexInLimb = bitIndex % this.radix;
|
||||
|
||||
while (limbIndex >= this.limbs.length) this.limbs.push(0);
|
||||
while (limbIndex >= this.limbs.length) {
|
||||
this.limbs.push(0);
|
||||
}
|
||||
|
||||
this.limbs[limbIndex] |= 1 << bitIndexInLimb;
|
||||
|
||||
@@ -142,6 +151,6 @@ sjcl.bn.prototype.setBitM = function (bitIndex) {
|
||||
return this;
|
||||
};
|
||||
|
||||
sjcl.bn.prototype.modInt = function (n) {
|
||||
sjcl.bn.prototype.modInt = function(n) {
|
||||
return this.toNumber() % n;
|
||||
};
|
||||
|
||||
@@ -1,23 +1,33 @@
|
||||
/* eslint new-cap: [2, {newIsCapExceptions: ["bn"]}] */
|
||||
'use strict';
|
||||
var sjcl = require('sjcl');
|
||||
|
||||
sjcl.bn.prototype.jacobi = function (that) {
|
||||
var a = this;
|
||||
sjcl.bn.prototype.jacobi = function(that) {
|
||||
var self = this;
|
||||
that = new sjcl.bn(that);
|
||||
|
||||
if (that.sign() === -1) return;
|
||||
if (that.sign() === -1) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// 1. If a = 0 then return(0).
|
||||
if (a.equals(0)) { return 0; }
|
||||
if (self.equals(0)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 2. If a = 1 then return(1).
|
||||
if (a.equals(1)) { return 1; }
|
||||
if (self.equals(1)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
var s = 0;
|
||||
|
||||
// 3. Write a = 2^e * a1, where a1 is odd.
|
||||
var e = 0;
|
||||
while (!a.testBit(e)) e++;
|
||||
var a1 = a.shiftRight(e);
|
||||
while (!self.testBit(e)) {
|
||||
e++;
|
||||
}
|
||||
var a1 = self.shiftRight(e);
|
||||
|
||||
// 4. If e is even then set s ← 1.
|
||||
if ((e & 1) === 0) {
|
||||
@@ -41,7 +51,6 @@ sjcl.bn.prototype.jacobi = function (that) {
|
||||
|
||||
if (a1.equals(1)) {
|
||||
return s;
|
||||
} else {
|
||||
return s * that.mod(a1).jacobi(a1);
|
||||
}
|
||||
return s * that.mod(a1).jacobi(a1);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable */
|
||||
/* this is implemented in sjcl, but has not yet been released as of v1.0.2 */
|
||||
var sjcl = require('sjcl');
|
||||
|
||||
sjcl.bn.prototype.invDigit = function ()
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* eslint-disable */
|
||||
/* this is implemented in sjcl, but has not yet been released as of v1.0.2 */
|
||||
var sjcl = require('sjcl');
|
||||
|
||||
/** @fileOverview Javascript RIPEMD-160 implementation.
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
/* eslint new-cap: [2, {newIsCapExceptions: ["pointJac"]}] */
|
||||
'use strict';
|
||||
var sjcl = require('sjcl');
|
||||
|
||||
// ----- for secp256k1 ------
|
||||
|
||||
sjcl.ecc.point.prototype.toBytesCompressed = function () {
|
||||
var header = this.y.mod(2).toString() == "0x0" ? 0x02 : 0x03;
|
||||
return [header].concat(sjcl.codec.bytes.fromBits(this.x.toBits()))
|
||||
sjcl.ecc.point.prototype.toBytesCompressed = function() {
|
||||
var header = this.y.mod(2).toString() === '0x0' ? 0x02 : 0x03;
|
||||
return [header].concat(sjcl.codec.bytes.fromBits(this.x.toBits()));
|
||||
};
|
||||
|
||||
// Replace point addition and doubling algorithms
|
||||
@@ -14,49 +16,50 @@ sjcl.ecc.point.prototype.toBytesCompressed = function () {
|
||||
// only works for a=-3 Jacobian curve. It's much
|
||||
// faster than the generic implementation
|
||||
sjcl.ecc.pointJac.prototype.add = function(T) {
|
||||
var S = this;
|
||||
if (S.curve !== T.curve) {
|
||||
throw("sjcl.ecc.add(): Points must be on the same curve to add them!");
|
||||
var self = this;
|
||||
if (self.curve !== T.curve) {
|
||||
throw ('sjcl.ecc.add(): Points must be on the same curve to add them!');
|
||||
}
|
||||
|
||||
if (S.isIdentity) {
|
||||
if (self.isIdentity) {
|
||||
return T.toJac();
|
||||
} else if (T.isIdentity) {
|
||||
return S;
|
||||
return self;
|
||||
}
|
||||
|
||||
var z1z1 = S.z.square();
|
||||
var h = T.x.mul(z1z1).subM(S.x);
|
||||
var s2 = T.y.mul(S.z).mul(z1z1);
|
||||
var z1z1 = self.z.square();
|
||||
var h = T.x.mul(z1z1).subM(self.x);
|
||||
var s2 = T.y.mul(self.z).mul(z1z1);
|
||||
|
||||
if (h.equals(0)) {
|
||||
if (S.y.equals(T.y.mul(z1z1.mul(S.z)))) {
|
||||
if (self.y.equals(T.y.mul(z1z1.mul(self.z)))) {
|
||||
// same point
|
||||
return S.doubl();
|
||||
} else {
|
||||
// inverses
|
||||
return new sjcl.ecc.pointJac(S.curve);
|
||||
return self.doubl();
|
||||
}
|
||||
// inverses
|
||||
return new sjcl.ecc.pointJac(self.curve);
|
||||
}
|
||||
|
||||
var hh = h.square();
|
||||
var i = hh.copy().doubleM().doubleM();
|
||||
var j = h.mul(i);
|
||||
var r = s2.sub(S.y).doubleM();
|
||||
var v = S.x.mul(i);
|
||||
var r = s2.sub(self.y).doubleM();
|
||||
var v = self.x.mul(i);
|
||||
|
||||
var x = r.square().subM(j).subM(v.copy().doubleM());
|
||||
var y = r.mul(v.sub(x)).subM(S.y.mul(j).doubleM());
|
||||
var z = S.z.add(h).square().subM(z1z1).subM(hh);
|
||||
var y = r.mul(v.sub(x)).subM(self.y.mul(j).doubleM());
|
||||
var z = self.z.add(h).square().subM(z1z1).subM(hh);
|
||||
|
||||
return new sjcl.ecc.pointJac(this.curve,x,y,z);
|
||||
return new sjcl.ecc.pointJac(this.curve, x, y, z);
|
||||
};
|
||||
|
||||
// This is a custom doubling algorithm that
|
||||
// only works for a=-3 Jacobian curve. It's much
|
||||
// faster than the generic implementation
|
||||
sjcl.ecc.pointJac.prototype.doubl = function () {
|
||||
if (this.isIdentity) { return this; }
|
||||
sjcl.ecc.pointJac.prototype.doubl = function() {
|
||||
if (this.isIdentity) {
|
||||
return this;
|
||||
}
|
||||
|
||||
var a = this.x.square();
|
||||
var b = this.y.square();
|
||||
|
||||
@@ -1,40 +1,47 @@
|
||||
/* eslint new-cap: [2, {newIsCapExceptions: ["corrupt"]}] */
|
||||
'use strict';
|
||||
var sjcl = require('sjcl');
|
||||
|
||||
sjcl.ecc.ecdsa.secretKey.prototype.sign = function(hash, paranoia, k_for_testing) {
|
||||
sjcl.ecc.ecdsa.secretKey.prototype.sign = function(hash, paranoia,
|
||||
k_for_testing) {
|
||||
var R = this._curve.r,
|
||||
l = R.bitLength();
|
||||
|
||||
// k_for_testing should ONLY BE SPECIFIED FOR TESTING
|
||||
// specifying it will make the signature INSECURE
|
||||
var k;
|
||||
if (typeof k_for_testing === 'object' && k_for_testing.length > 0 && typeof k_for_testing[0] === 'number') {
|
||||
if (typeof k_for_testing === 'object' && k_for_testing.length > 0
|
||||
&& typeof k_for_testing[0] === 'number') {
|
||||
k = k_for_testing;
|
||||
} else if (typeof k_for_testing === 'string' && /^[0-9a-fA-F]+$/.test(k_for_testing)) {
|
||||
k = sjcl.bn.fromBits(sjcl.codec.hex.toBits(k_for_testing));
|
||||
} else if (typeof k_for_testing === 'string'
|
||||
&& /^[0-9a-fA-F]+$/.test(k_for_testing)) {
|
||||
k = sjcl.bn.fromBits(sjcl.codec.hex.toBits(k_for_testing));
|
||||
} else {
|
||||
// This is the only option that should be used in production
|
||||
k = sjcl.bn.random(R.sub(1), paranoia).add(1);
|
||||
}
|
||||
|
||||
var r = this._curve.G.mult(k).x.mod(R);
|
||||
var s = sjcl.bn.fromBits(hash).add(r.mul(this._exponent)).mul(k.inverseMod(R)).mod(R);
|
||||
var s = sjcl.bn.fromBits(hash).add(r.mul(this._exponent))
|
||||
.mul(k.inverseMod(R)).mod(R);
|
||||
|
||||
return sjcl.bitArray.concat(r.toBits(l), s.toBits(l));
|
||||
};
|
||||
|
||||
sjcl.ecc.ecdsa.publicKey.prototype.verify = function(hash, rs) {
|
||||
var w = sjcl.bitArray,
|
||||
R = this._curve.r,
|
||||
l = R.bitLength(),
|
||||
r = sjcl.bn.fromBits(w.bitSlice(rs,0,l)),
|
||||
s = sjcl.bn.fromBits(w.bitSlice(rs,l,2*l)),
|
||||
sInv = s.inverseMod(R),
|
||||
hG = sjcl.bn.fromBits(hash).mul(sInv).mod(R),
|
||||
hA = r.mul(sInv).mod(R),
|
||||
r2 = this._curve.G.mult2(hG, hA, this._point).x;
|
||||
var w = sjcl.bitArray;
|
||||
var R = this._curve.r;
|
||||
var l = R.bitLength();
|
||||
var r = sjcl.bn.fromBits(w.bitSlice(rs, 0, l));
|
||||
var s = sjcl.bn.fromBits(w.bitSlice(rs, l, 2 * l));
|
||||
var sInv = s.inverseMod(R);
|
||||
var hG = sjcl.bn.fromBits(hash).mul(sInv).mod(R);
|
||||
var hA = r.mul(sInv).mod(R);
|
||||
var r2 = this._curve.G.mult2(hG, hA, this._point).x;
|
||||
|
||||
if (r.equals(0) || s.equals(0) || r.greaterEquals(R) || s.greaterEquals(R) || !r2.equals(r)) {
|
||||
throw (new sjcl.exception.corrupt("signature didn't check out"));
|
||||
if (r.equals(0) || s.equals(0) || r.greaterEquals(R) || s.greaterEquals(R)
|
||||
|| !r2.equals(r)) {
|
||||
throw (new sjcl.exception.corrupt('signature didn\'t check out'));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user