nextMPInt method

BigInt nextMPInt()

Extracts a multiple precision integer from the range.

Extracts an uint32 which indicates the number of following bytes to be interpreted as a two's complement integer. See section 5 of RFC 4251 for a definition of this format.

Returns the integer value. The bytes making up the length and integer are removed from the range.

Throws a BadEncoding if there are insufficient bytes in the range or the bytes do not represent a valid multiple precision integer.

Implementation

BigInt nextMPInt() {
  final length = nextUint32();

  // mpint
  //      Represents multiple precision integers in two's complement format,
  //      stored as a string, 8 bits per byte, MSB first.  Negative numbers
  //      have the value 1 as the most significant bit of the first byte of
  //      the data partition.  If the most significant bit would be set for
  //      a positive number, the number MUST be preceded by a zero byte.
  //      Unnecessary leading bytes with the value 0 or 255 MUST NOT be
  //      included.  The value zero MUST be stored as a string with zero
  //      bytes of data.

  if (length == 0) {
    // Zero is always represented by no bytes.
    return BigInt.zero;
  } else if (_begin + length <= _end) {
    // Length is correct

    // Process first byte

    final firstByte = _bytes[_begin];
    final negative = (firstByte & 0x80) != 0; // 1 MSB from first byte
    var n = BigInt.from(firstByte & 0x7F); // other 7 LSB from first byte
    _begin++; // skip first byte

    if (_begin == _end) {
      if (n == BigInt.zero && !negative) {
        // Zero must be represented by no bytes
        throw KeyBad('invalid mpint');
      }
    } else {
      final secondByte = _bytes[_begin];
      if (firstByte == 0x00 && (secondByte & 0x80 == 0x00) ||
          firstByte == 0xFF && (secondByte & 0x80 == 0x80)) {
        // Unnecessary leading bytes with 0 or 255 MUST NOT be included.
        throw KeyBad('invalid mpint');
      }
    }
    // Process remaining bytes

    for (var i = 1; i < length; i++) {
      n = (n << 8) | BigInt.from(_bytes[_begin++]);
    }

    // Return value (two's complement for negative numbers)

    return (negative) ? n - BigInt.two.pow((8 * length) - 1) : n;
  } else {
    throw KeyBad('data incomplete (for $length byte MPint)');
  }
}