Source: type/openpgp.type.mpi.js

// GPG4Browsers - An OpenPGP implementation in javascript
// Copyright (C) 2011 Recurity Labs GmbH
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

// Hint: We hold our MPIs as an array of octets in big endian format preceeding a two
// octet scalar: MPI: [a,b,c,d,e,f]
// - MPI size: (a << 8) | b 
// - MPI = c | d << 8 | e << ((MPI.length -2)*8) | f ((MPI.length -2)*8)

/**
 * @class
 * @classdescImplementation of type MPI (RFC4880 3.2)
 * Multiprecision integers (also called MPIs) are unsigned integers used
 * to hold large integers such as the ones used in cryptographic
 * calculations.
 * An MPI consists of two pieces: a two-octet scalar that is the length
 * of the MPI in bits followed by a string of octets that contain the
 * actual integer.
 */
function openpgp_type_mpi() {
	this.MPI = null;
	this.mpiBitLength = null;
	this.mpiByteLength = null;
	this.data = null;
	/**
	 * Parsing function for a mpi (RFC 4880 3.2).
	 * @param {String} input Payload of mpi data
	 * @param {Integer} position Position to start reading from the input 
	 * string
	 * @param {Integer} len Length of the packet or the remaining length of 
	 * input at position
	 * @return {openpgp_type_mpi} Object representation
	 */
	function read(input, position, len) {
		var mypos = position;
		
		this.mpiBitLength = (input[mypos++].charCodeAt() << 8) | input[mypos++].charCodeAt();
		
		// Additional rules:
		//
		//    The size of an MPI is ((MPI.length + 7) / 8) + 2 octets.
		//
		//    The length field of an MPI describes the length starting from its
		//	  most significant non-zero bit.  Thus, the MPI [00 02 01] is not
		//    formed correctly.  It should be [00 01 01].

		// TODO: Verification of this size method! This size calculation as
		// 		 specified above is not applicable in JavaScript
		this.mpiByteLength = (this.mpiBitLength - (this.mpiBitLength % 8)) / 8;
		if (this.mpiBitLength % 8 != 0)
			this.mpiByteLength++;
		
		this.MPI = input.substring(mypos,mypos+this.mpiByteLength);
		this.data = input.substring(position, position+2+this.mpiByteLength);
		this.packetLength = this.mpiByteLength +2;
		return this;
	}
	
	/**
	 * Generates debug output (pretty print)
	 * @return {String} String which gives some information about the mpi
	 */
	function toString() {
		var r = "    MPI("+this.mpiBitLength+"b/"+this.mpiByteLength+"B) : 0x";
		r+=util.hexstrdump(this.MPI);
		return r+'\n';
	}
	
	/**
	 * Converts the mpi to an BigInteger object
	 * @return {BigInteger}
	 */
	function getBigInteger() {
		return new BigInteger(util.hexstrdump(this.MPI),16); 
	}

	
	function getBits(num) {
		for (var i = 0; i < 9; i++)
		if (num >> i == 0)
		return i;
	}
	
	/**
	 * Gets the length of the mpi in bytes
	 * @return {Integer} Mpi byte length
	 */
	function getByteLength() {
		return this.mpiByteLength;
	}
	
	/**
	 * Creates an mpi from the specified string
	 * @param {String} data Data to read the mpi from
	 * @return {openpgp_type_mpi} 
	 */
	function create(data) {
		this.MPI = data;
		this.mpiBitLength = (data.length -1) *8 + getBits(data.charCodeAt(0));
		this.mpiByteLength = data.length;
		return this;
	}
	
	/**
	 * Converts the mpi object to a string as specified in RFC4880 3.2
	 * @return {String} mpi Byte representation
	 */
	function toBin() {
		var result = String.fromCharCode((this.mpiBitLength >> 8) & 0xFF);
		result += String.fromCharCode(this.mpiBitLength & 0xFF);
		result += this.MPI;
		return result;
	}
	
	this.read = read;
	this.toBigInteger = getBigInteger;
	this.toString = toString;
	this.create = create;
	this.toBin = toBin;
	this.getByteLength = getByteLength;
}