diff --git a/src/sjcl-custom/sjcl-ecdsa-recoverablepublickey.js b/src/sjcl-custom/sjcl-ecdsa-recoverablepublickey.js index 468abc5d..8b5e338c 100644 --- a/src/sjcl-custom/sjcl-ecdsa-recoverablepublickey.js +++ b/src/sjcl-custom/sjcl-ecdsa-recoverablepublickey.js @@ -2,7 +2,7 @@ /* eslint new-cap: [2, {newIsCapExceptions: [ "bn", "invalid", "point", "corrupt", "bug", "publicKey"]}] */ 'use strict'; -var sjcl = require('sjcl'); +const sjcl = require('sjcl'); /** * This module uses the public key recovery method @@ -16,7 +16,7 @@ var sjcl = require('sjcl'); */ // Defined here so that this value only needs to be calculated once -var FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR; +let FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR; /** * Retrieve the r and s components of a signature @@ -27,7 +27,7 @@ var FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR; */ function getRandSFromSignature(curve, signature) { - var r_length = curve.r.bitLength(); + const r_length = curve.r.bitLength(); return { r: sjcl.bn.fromBits(sjcl.bitArray.bitSlice(signature, 0, r_length)), @@ -50,7 +50,7 @@ function getRandSFromSignature(curve, signature) { */ function verify_raw(curve, e, r, s, public_key_point) { - var field_order = curve.r; + const field_order = curve.r; // Return false if r is out of bounds if ((new sjcl.bn(1)).greaterEquals(r) @@ -67,11 +67,11 @@ function verify_raw(curve, e, r, s, public_key_point) { // 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); + const s_mod_inverse_field_order = s.inverseMod(field_order); + const u1 = e.mul(s_mod_inverse_field_order).mod(field_order); + const u2 = r.mul(s_mod_inverse_field_order).mod(field_order); - var point_computed = curve.G.mult2(u1, u2, public_key_point); + const point_computed = curve.G.mult2(u1, u2, public_key_point); return r.equals(point_computed.x.mod(field_order)); @@ -90,19 +90,16 @@ function verify_raw(curve, e, r, s, public_key_point) { function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, hash_bits, recovery_factor) { - var field_order = curve.r; - var field_modulus = curve.field.modulus; - - // Reduce the recovery_factor to the two bits used - recovery_factor = recovery_factor & 3; + const field_order = curve.r; + const field_modulus = curve.field.modulus; // The less significant bit specifies whether the y coordinate // of the compressed point is even or not. - var compressed_point_y_coord_is_even = recovery_factor & 1; + const compressed_point_y_coord_is_even = recovery_factor & 1; // The more significant bit specifies whether we should use the // first or second candidate key. - var use_second_candidate_key = recovery_factor >> 1; + const use_second_candidate_key = (recovery_factor & 2) >> 1; // Calculate (field_order + 1) / 4 if (!FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR) { @@ -113,7 +110,7 @@ function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, // That is not necessary here because we are given the recovery_factor // step 1.1 Let x = r + jn // Here "j" is either 0 or 1 - var x; + let x; if (use_second_candidate_key) { x = signature_r.add(field_order); } else { @@ -123,16 +120,16 @@ function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, // 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( + const alpha = x.mul(x).mul(x).add(curve.a.mul(x)).add(curve.b).mod( field_modulus); - var beta = alpha.powermod(FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR, + const beta = alpha.powermod(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 // then subtract beta from the field_modulus - var y; - var beta_is_even = beta.mod(2).equals(0); + let y; + const beta_is_even = beta.mod(2).equals(0); if (beta_is_even && !compressed_point_y_coord_is_even || !beta_is_even && compressed_point_y_coord_is_even) { y = beta; @@ -141,7 +138,7 @@ function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, } // generated_point_R is the point generated from x and y - var generated_point_R = new sjcl.ecc.point(curve, x, y); + const generated_point_R = new sjcl.ecc.point(curve, x, y); // step 1.4 check that R is valid and R x field_order !== infinity // TODO: add check for R x field_order === infinity @@ -151,13 +148,13 @@ function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, } // step 1.5 Compute e from M - var message_e = sjcl.bn.fromBits(hash_bits); - var message_e_neg = new sjcl.bn(0).sub(message_e).mod(field_order); + const message_e = sjcl.bn.fromBits(hash_bits); + const message_e_neg = new sjcl.bn(0).sub(message_e).mod(field_order); // 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, + const signature_r_inv = signature_r.inverseMod(field_order); + const public_key_point = generated_point_R.mult2(signature_s, message_e_neg, curve.G).mult(signature_r_inv); // Validate public key point @@ -190,14 +187,14 @@ function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, function calculateRecoveryFactor(curve, r, s, hash_bits, original_public_key_point) { - var original_public_key_point_bits = original_public_key_point.toBits(); + const 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++) { + for (let possible_factor = 0; possible_factor < 4; possible_factor++) { - var resulting_public_key_point; + let resulting_public_key_point; try { resulting_public_key_point = recoverPublicKeyPointFromSignature( curve, r, s, hash_bits, possible_factor); @@ -229,10 +226,10 @@ function calculateRecoveryFactor(curve, r, s, hash_bits, sjcl.ecc.ecdsa.secretKey.prototype.signWithRecoverablePublicKey = function( hash, paranoia, k_for_testing) { - var self = this; + const self = this; // Convert hash to bits and determine encoding for output - var hash_bits; + let hash_bits; if (typeof hash === 'object' && hash.length > 0 && typeof hash[0] === 'number') { hash_bits = hash; @@ -241,25 +238,25 @@ sjcl.ecc.ecdsa.secretKey.prototype.signWithRecoverablePublicKey = function( } // Sign hash with standard, canonicalized method - var standard_signature = self.sign(hash_bits, paranoia, k_for_testing); - var canonical_signature = self.canonicalizeSignature(standard_signature); + const standard_signature = self.sign(hash_bits, paranoia, k_for_testing); + const canonical_signature = self.canonicalizeSignature(standard_signature); // Extract r and s signature components from canonical signature - var r_and_s = getRandSFromSignature(self._curve, canonical_signature); + const r_and_s = getRandSFromSignature(self._curve, canonical_signature); // Rederive public key - var public_key = self._curve.G.mult(sjcl.bn.fromBits(self.get())); + const 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, + const 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; + const value_to_prepend = recovery_factor + 27; - var final_signature_bits = sjcl.bitArray.concat([value_to_prepend], + const final_signature_bits = sjcl.bitArray.concat([value_to_prepend], canonical_signature); // Return value in bits @@ -280,19 +277,15 @@ sjcl.ecc.ecdsa.secretKey.prototype.signWithRecoverablePublicKey = function( * @returns {sjcl.ecc.ecdsa.publicKey} Public key */ sjcl.ecc.ecdsa.publicKey.recoverFromSignature = function( - hash, signature, curve) { + hash, signature, curve=sjcl.ecc.curves.k256) { 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; + let hash_bits; if (typeof hash === 'object' && hash.length > 0 && typeof hash[0] === 'number') { hash_bits = hash; @@ -300,7 +293,7 @@ sjcl.ecc.ecdsa.publicKey.recoverFromSignature = function( throw new sjcl.exception.invalid('hash. Must be a bitArray'); } - var signature_bits; + let signature_bits; if (typeof signature === 'object' && signature.length > 0 && typeof signature[0] === 'number') { signature_bits = signature; @@ -309,7 +302,7 @@ sjcl.ecc.ecdsa.publicKey.recoverFromSignature = function( } // Extract recovery_factor from first 4 bytes - var recovery_factor = signature_bits[0] - 27; + const recovery_factor = signature_bits[0] - 27; if (recovery_factor < 0 || recovery_factor > 3) { throw new sjcl.exception.invalid( @@ -318,14 +311,14 @@ sjcl.ecc.ecdsa.publicKey.recoverFromSignature = function( } // 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; + const r_and_s = getRandSFromSignature(curve, signature_bits.slice(1)); + const signature_r = r_and_s.r; + const signature_s = r_and_s.s; // Recover public key using recovery_factor - var recovered_public_key_point = recoverPublicKeyPointFromSignature( + const recovered_public_key_point = recoverPublicKeyPointFromSignature( curve, signature_r, signature_s, hash_bits, recovery_factor); - var recovered_public_key = new sjcl.ecc.ecdsa.publicKey( + const recovered_public_key = new sjcl.ecc.ecdsa.publicKey( curve, recovered_public_key_point); return recovered_public_key;