Scripts

Lineaire combinatie en greatest common divisor

Voor het gebruiken van RSA heb je de modulo inverse van een bepaald getal nodig in een bepaalde modulo! Daar kon ik niet heel snel een scriptje voor vinden, dus heb ik het zelf maar gemaakt. Het maakt gebruik van het algoritme van Euclides en het uitgebreide algoritme van Euclides ('weer naar boven gaan').

lineaire-combinatie-en-greatest-common-divisor
[code]
<?php

/**	Getting the lineair combination and the greatest common divider  of 2 integers
*	@description Used to get the modulo inverse of some integer
*	@author Ruud Verbij
*	@date April the 8th 2008
*/

class LineairCombination {

	/**	@var			Integer
		@description	For counting the total steps used for the algorithm 
	*/
	private $steps = 0;
	
	/**	@var			Array
		@description	These 2 Arrays are used in this way:
					a[0] = q[0]*a[1] + a[2]
					a[1] = q[1]*a[2] + a[3]
					etc. 
	*/
	private $A = Array();
	private $Q = Array();
	
	/**	@var			Array
		@description 	This array is used to get the lineair combination of a[0] (table[i][0]) and a[1] (table[i][1]) for every i > 1
					Offcourse most valuable at table[count(table)+1] (the last A, the greatest common divider  of a[0] and a[1]) 
					So, table[i][0]*a[0] + table[i][1]*a[1] = a[i], this means that table[i] stores the lineair combination of a[0] and a[1] for a[i]
	*/
	private $table = Array();
	
	/**	@var			Array
		@description	The same as table[count(table)+1], so, used to store the information on a more easy way to find
	*/
	private $lineairCombination = Array();
	
	/**	@var			Integer
		@description	Used to store the greatest common divider , the same as a[count(a)-1]
	*/
	private $gcd = -1;
	
	/** 	Constructor
		@param		Integer
		@param		Integer
		@description	Inputs the 2 integers for which the greatest common divider  and the lineair combination must be calculated
		@require		$a != $b && is_integer($a) && is_integer($b) && $a > 0 && $b > 0
	*/
	public function __construct($a,$b) {
		// make sure that a[0] > a[1]
		$this->A[0] = ($a < $b) ? $b : $a;
		$this->A[1] = ($a > $b) ? $b : $a;
	}
	
	/**	Returns the greatest common divider 
		@require		called AFTER run method has been called
		@return		Integer, containing the greatest common divider  of A[0] and A[1]
	*/
	public function getGcd() {
		return $this->gcd;
	}
	
	/**	Returns the lineair combination
		@require		called AFTER run method has been called
		@return		Array, containing the lineair combination of A[0] and A[1] --> return[0]*A[0] + return[1]*A[1] = returnGcd()
	*/
	public function getLinComb() {
		return $this->lineairCombination;
	}	
	
	/**	Return the module inverse of A[1] in module A[0], only exists whenever getGcd() == 1, otherwhise the return is false
		@require		called AFTER run method has been called && getGcd() == 1, otherwhise a[1] has no modulo-inverse in modulo a[0]
		@return		Integer, 0 < return < A[0] OR false if getGcd != 1
		@ensure		return * A[1] mod A[0] = 1 OR return is false
	*/
	public function getModuloInverse() {
		return ($this->getGcd == 1) ? (($this->lineairCombination[1] < 0) ? $this->lineairCombination[1] + $this->A[0] : $this->lineairCombination[1]) : false;
	}
	
	/**	Some sort of reset function
		@ensure		Object == new LineairCombination($a,$b);
	*/
	public function setAandB($a, $b) {
		// reset all variables
		$this->steps 				= 0;
		$this->A 					= Array();
		$this->Q					= Array();
		$this->table				= Array();
		$this->lineairCombination 	= Array();
		$this->gcd 					= -1;
		
		// make sure that a[0] > a[1]
		$this->A[0] = ($a < $b) ? $b : $a;
		$this->A[1] = ($a > $b) ? $b : $a;
	}
	
	/**	Run the class
		@description	Used to run the class and find the greatest common divider  and lineair combination
	*/
	public function run() {
		// call both the gcd and lineair combination functions
		$this->recursiveGcd();
		$this->recursiveLineairCombination();
		
		// store the found variables in a logically named variable
		$this->gcd = $this->A[count($this->A)-1];
		$this->lineairCombination = $this->table[count($this->table)+1];
		
		// example echo
		echo "So, the lineair combination of (".$this->A[0].",".$this->A[1].") is:<br />";
		echo $this->gcd." = ".$this->lineairCombination[0]." x ".$this->A[0]." + ".$this->lineairCombination[1]." x ".$this->A[1];
		echo "<br />Calculated in ".$this->steps." steps";
		
		return;
	}
	
	/**	Find the greatest common divider  */
	private function recursiveGcd() {
		// call recursive function
		$this->gcd($this->A[0],$this->A[1],0);
		
		return;
	}
	
	/**	Recursive function gcd
		@description	Find the lineair combination of $a and $b and store it at $this->A[$n+2]
		@require		$a > $b && is_integer($a) && is_integer($b) && $a != 0 && $b != 0
		@ensure		$this->A[$n+2] = gcd($a,$b) && $this->A[$n+2] + $this->Q[$n]*$b = $a
	*/
	private function gcd($a,$b,$n) {	
		// increase steps
		$this->steps++;
		
		// the probably new A and Q values
		$new_A = $a % $b;
		$new_Q = floor($a/$b);
		
		// though, the new A cannot be 0, otherwhise we have already found the greatest common divider  ($b)
		if($new_A != 0) {
			// store the new A and Q
			$this->A[$n+2] = $new_A;
			$this->Q[$n] = $new_Q;
			
			// call the function recursively to find the gcd of A[$n+1] and A[$n+2] ($b and $new_A)
			$this->gcd($this->A[$n+1],$this->A[$n+2],$n+1);
		}
		return;
	}
	
	/**	Find the lineair combination
		@require		Called AFTER the getGcd method is called, therefore made private, and only called from the run method
	*/
	private function recursiveLineairCombination() {
		// first fill the second position of the table (pre-made)
		$this->table[2] = Array(1, -1 * $this->Q[0]);
		
		// if there will be a theird position ($a[0] != m * $a[1])
		if(count($this->Q) > 1)
			// fill it
			$this->table[3] = Array(-1*$this->Q[1],$this->Q[0]*$this->Q[1] + 1);
			
		// find the lineair combination recursively, by starting at the last A and working back
		// using the equation: A[n] = -1 * Q[n-2] * A[n-1] + A[n-2]
		$this->lineairCombination(count($this->A)-1);
		
		return;
	}
	
	/**	Find the lineair combination
		@description	Find the lineair combination of A[0] and A[1] to make A[$n], started at A[count(A)-1] and working back, filling the table
		@param		Integer, for which to find the lineair combination of A[0] and A[1]
		@require		Called AFTER the getGcd method is called, therefor made private, and only called from the getLineairCombination method, which has the same requirement
		@ensure		table[n][0]*a[0] + table[n][1]*a[1] = a[n]
	*/
	private function lineairCombination($n) {
		// increase the number of steps made
		$this->steps++;
		
		// if $n <= 3 --> table[n-2] is not defined AND all necessary $n <= 3 are already in the table
		if($n <= 3) return;
		
		// to make the code a little smaller, fill table[i][0] and table[i][1] with this for-loop
		$temp = Array();
		for($i = 1; $i <= 2; $i++) {
			// if not already in the table, find it recursively
			if(!$this->table[$n-$i][0])
				$this->lineairCombination($n-$i);
			$temp[$i-1] = $this->table[$n - $i];
		}
		
		// Fill the table with the equation: A[n] = -1 * Q[n-2] * A[n-1] + A[n-2]
		$this->table[$n] = Array(-1 * $this->Q[$n-2] * $temp[0][0] + $temp[1][0],
								 -1 * $this->Q[$n-2] * $temp[0][1] + $temp[1][1]);
		return;
	}

}

// Example (and testing)
$a = (isset($_GET['a'])) ? $_GET['a'] : 91;
$b = (isset($_GET['b'])) ? $_GET['b'] : 17;

$linComb = new LineairCombination($a,$b);
$linComb->run();

?>
[/code]

Reacties

0
Nog geen reacties.