Javascript - 将字符串解析为long

时间:2017-09-27 12:24:26

标签: javascript python cryptography

我在python中有一个工作脚本,使用long(16)基于指定的基数进行字符串到整数的转换:

modulus=public_key["n"]    
modulusDecoded = long(public_key["n"], 16)

打印: 8079d7ae567dd2c02dadd1068843136314fa3893fa1fb1ab331682c6a85cad62b208d66c9974bbbb15d52676fd9907efb158c284e96f5c7a4914fd927b7326c40efa14922c68402d05ff53b0e4ccda90bbee5e6c473613e836e2c79da1072e366d0d50933327e77651b6984ddbac1fdecf1fd8fa17e0f0646af662a8065bd873

90218878289834622370514047239437874345637539049004160177768047103383444023879266805615186962965710608753937825108429415800005684101842952518531920633990402573136677611127418094912644368840442620417414685225340199872975797295511475162170060618806831021437109054760851445152320452665575790602072479287289305203

分别。 这看起来像十六进制到十进制转换。 我尝试在JS中获得相同的结果,但parseInt()parseFloat()产生了完全不同的东西。最重要的是,JavaScript似乎不喜欢输入字符串中的字符,有时会返回NaN。

有人可以提供一个函数/指导如何获得与Python脚本相同的功能吗?

3 个答案:

答案 0 :(得分:6)

JavaScript中的数字是浮点数,因此在某个数字后它们总是会失去精度。要拥有无限数字,我们可以使用0到9之间的数字数组,它具有无限范围。要基于十六进制字符串输入执行此操作,我执行十六进制到int数组转换,然后使用double dabble algorithm将数组转换为BCD。这可以很容易打印出来:

const hexToArray = arr => arr.split("").map(n => parseInt(n,16));


const doubleDabble = arr => {
  var l = arr.length;
  for( var b = l * 4; b--;){

    //add && leftshift
    const overflow = arr.reduceRight((carry,n,i) => {

      //apply the >4 +3, then leftshift
      var shifted = ((i < (arr.length - l ) && n>4)?n+3:n ) << 1;

      //just take the right four bits and add the eventual carry value
      arr[i] = (shifted & 0b1111) | carry;

      //carry on
      return shifted > 0b1111;
    }, 0);
    // we've exceeded the current array, lets extend it:
    if(overflow) arr.unshift(overflow);
  }
  return arr.slice(0,-l);
};

const arr = hexToArray("8079d7");
const result = doubleDabble(arr);      
console.log(result.join(""));

Try it

答案 1 :(得分:3)

使用内置的api parseInt,您可以在Firefox上获得高达100的精确度,在Chrome上获得20位精确度。

a = parseInt('8079d7ae567dd2c02dadd1068843136314fa3893fa1fb1ab331682c6a85cad62b208d66c9974bbbb15d52676fd9907efb158c284e96f5c7a4914fd927b7326c40efa14922c68402d05ff53b0e4ccda90bbee5e6c473613e836e2c79da1072e366d0d50933327e77651b6984ddbac1fdecf1fd8fa17e0f0646af662a8065bd873', 16)

a.toPrecision(110)
> Uncaught RangeError: toPrecision() argument must be between 1 and 21

# Chrome
a.toPrecision(20)
"9.0218878289834615508e+307"  

# Firefox
a.toPrecision(100)
"9.021887828983461550807409292694387726882781812072572899692574101215517323445643340153182035092932819e+307"

来自ECMAScript Spec

  
      
  1. 让p成为? ToInteger(精度)。
      ......
  2.   
  3. 如果p < 1或p> 100,抛出RangeError异常。
  4.   

答案 2 :(得分:0)

this answer所述,JavaScript数字不能代表大于9.007199254740991e+15的整数而不会损失精度。

在JavaScript中使用较大的整数需要BigInt库或其他专用代码,然后大整数通常表示为字符串或数组。

重用this answer中的代码有助于转换十六进制数字表示

  

8079d7ae567dd2c02dadd1068843136314fa3893fa1fb1ab331682c6a85cad62b208d66c9974bbbb15d52676fd9907efb158c284e96f5c7a4914fd927b7326c40efa14922c68402d05ff53b0e4ccda90bbee5e6c473613e836e2c79da1072e366d0d50933327e77651b6984ddbac1fdecf1fd8fa17e0f0646af662a8065bd873

到十进制表示

  

90218878289834622370514047239437874345637539049004160177768047103383444023879266805615186962965710608753937825108429415800005684101842952518531920633990402573136677611127418094912644368840442620417414685225340199872975797295511475162170060618806831021437109054760851445152320452665575790602072479287289305203

如以下代码段所示:

function parseBigInt(bigint, base) {
  //convert bigint string to array of digit values
  for (var values = [], i = 0; i < bigint.length; i++) {
    values[i] = parseInt(bigint.charAt(i), base);
  }
  return values;
}

function formatBigInt(values, base) {
  //convert array of digit values to bigint string
  for (var bigint = '', i = 0; i < values.length; i++) {
    bigint += values[i].toString(base);
  }
  return bigint;
}

function convertBase(bigint, inputBase, outputBase) {
  //takes a bigint string and converts to different base
  var inputValues = parseBigInt(bigint, inputBase),
    outputValues = [], //output array, little-endian/lsd order
    remainder,
    len = inputValues.length,
    pos = 0,
    i;
  while (pos < len) { //while digits left in input array
    remainder = 0; //set remainder to 0
    for (i = pos; i < len; i++) {
      //long integer division of input values divided by output base
      //remainder is added to output array
      remainder = inputValues[i] + remainder * inputBase;
      inputValues[i] = Math.floor(remainder / outputBase);
      remainder -= inputValues[i] * outputBase;
      if (inputValues[i] == 0 && i == pos) {
        pos++;
      }
    }
    outputValues.push(remainder);
  }
  outputValues.reverse(); //transform to big-endian/msd order
  return formatBigInt(outputValues, outputBase);
}

var largeNumber =
'8079d7ae567dd2c02dadd1068843136314fa389'+
'3fa1fb1ab331682c6a85cad62b208d66c9974bb'+
'bb15d52676fd9907efb158c284e96f5c7a4914f'+
'd927b7326c40efa14922c68402d05ff53b0e4cc'+
'da90bbee5e6c473613e836e2c79da1072e366d0'+
'd50933327e77651b6984ddbac1fdecf1fd8fa17'+
'e0f0646af662a8065bd873';

//convert largeNumber from base 16 to base 10
var largeIntDecimal = convertBase(largeNumber, 16, 10);

//show decimal result in console:
console.log(largeIntDecimal);

//check that it matches the expected output:
console.log('Matches expected:',
  largeIntDecimal === '90218878289834622370514047239437874345637539049'+
    '0041601777680471033834440238792668056151869629657106087539378251084294158000056'+
    '8410184295251853192063399040257313667761112741809491264436884044262041741468522'+
    '5340199872975797295511475162170060618806831021437109054760851445152320452665575'+
    '790602072479287289305203'
);

//check that conversion and back-conversion results in the original number
console.log('Converts back:',
  convertBase(convertBase(largeNumber, 16, 10), 10, 16) === largeNumber
);