在说明Hill加密之前要先复习线性代数的知识,主要是关于矩阵的一些运算和概念。
一、矩阵的逆:
定义方阵M的逆矩阵应该满足M*M^-1==I,其中I是单位矩阵,比如:
但是这个地方是对英文字母进行加密,所以矩阵中的数字都是模26的值,比如:
* =
这个地方结果就应该mod26, 最后结果就是:
那么上面两个相乘的矩阵就互为逆矩阵。
这个地方要多说一下密码学中的mod运算,数学中-5%26结果肯定是-5,但是这个地方我们取值只能在0-25之间,所以-5%26的结果应该是21。
求解一个方阵的逆矩阵的公式是: (det A)-1*(-1)i+j(Dji),其中:
1.det A 是矩阵A 的行列式,当然最后结果也要是mod26,(det A)-1的意思是取矩阵A的行列式的逆,比如:
的行列式是5*3-8*17=-121mod26=9
那么(det A)-1 = 3,因为3*8mod26=1,符合矩阵逆的定义。
2.Dji 是将A去掉第j行和dii行的子行列式的值,比如:
是个2*2的方阵,那么i和j就有4种组合:0,0:0,1:1,0:1,1, 那么分别去掉对应的列和行后,就成了4个1*1的方阵,再分别计算这四个方阵的行列式,结果就是:
Dji =
3. (-1)i+j
这个与Dji相乘的结果就是:
mod26 =
最后得到A的逆矩阵为:
mod26=
二、Java中关于矩阵计算的工具包
其中最常用的就是jama了, http://math.nist.gov/javanumerics/jama/
但是要用到我们这个对应26个英文字母的加密算法中还需要进行改造,‘主要是以下几点:
1. jama是针对double类型的,要切换到int或者short
2. jama结果不会取模, 比如手动实现取模
三、我的实现
还是直接来个工具类吧,使用jama:
1 package com.owner.util.matrix; 2 3 import Jama.Matrix; 4 5 import java.text.NumberFormat; 6 7 /** 8 * Created by wellmax on 2015/10/8. 9 */ 10 public class MatrixUtil { 11 private Matrix matrix; 12 13 public MatrixUtil(Matrix matrix) { 14 this.matrix = matrix; 15 } 16 17 public MatrixUtil() { 18 } 19 20 public int dimension(){ 21 return this.getMatrix().getArray().length; 22 } 23 private int mod(int number){ 24 int mod = number%26; 25 return mod < 0 ? mod + 26 : mod;//+26 避免取模结果为负 26 } 27 private int convertDouble2Int(Double d){ 28 return d.intValue(); 29 } 30 31 /** 32 * 计算构成Dji 矩阵的子矩阵矩阵 33 */ 34 private Matrix excludeRowAndColumn(int row, int column){ 35 double[][] subArr = new double[dimension() - 1][dimension() - 1]; 36 double[][] arr = this.getMatrix().getArray(); 37 int rowFlag = 0; 38 int columnFlag = 0; 39 for(int i = 0 ; i < arr.length ; i++){ 40 if(i == row){ 41 continue; 42 } 43 for(int j = 0 ; j < arr.length ; j++){ 44 if(j == column){ 45 continue; 46 } 47 subArr[rowFlag][columnFlag] = arr[i][j]; 48 columnFlag++; 49 } 50 rowFlag++; 51 columnFlag = 0; 52 } 53 return new Matrix(subArr); 54 } 55 56 /** 57 * 计算行列式 58 */ 59 public int determinant(Matrix matrix){ 60 double doubleDeterminant = matrix.det(); 61 return this.mod(this.convertDouble2Int(doubleDeterminant)); 62 } 63 64 /** 65 * 计算行列式的逆,这个方法有点坑。。。 66 */ 67 public int negativeDeterminant(int determinant){ 68 int i = 1; 69 while(true){ 70 if((determinant * i) % 26 == 1){ 71 return i; 72 } 73 if (i == Integer.MAX_VALUE >> 1){ 74 break; 75 } 76 i++; 77 } 78 throw new RuntimeException("Could not find the negative determinant"); 79 } 80 81 /** 82 * 计算D矩阵 83 */ 84 public Matrix getD(){ 85 double[][] arr = this.getMatrix().getArray(); 86 if (arr == null || arr.length == 0){ 87 return null; 88 } 89 double[][] arrD = new double[arr.length][arr.length]; 90 for(int i = 0 ; i < arr.length ; i++){ 91 for(int j = 0 ; j < arr[i].length ; j ++){ 92 arrD[i][j] = this.determinant(this.excludeRowAndColumn(j,i)); 93 } 94 } 95 return new Matrix(arrD); 96 } 97 98 /** 99 * 计算(-1)i+j 乘上 D矩阵 100 */ 101 public Matrix negative(Matrix matrix){ 102 double[][] arr = matrix.getArray(); 103 for (int i = 0 ; i < arr.length ; i ++){ 104 for(int j = 0 ; j < arr.length ; j++){ 105 if((i+j) % 2 == 1){ 106 arr[i][j] = mod(-1 * new Double(arr[i][j]).intValue()); 107 } 108 } 109 } 110 return new Matrix(arr); 111 } 112 113 /** 114 * 最后一个求矩阵的逆矩阵 115 */ 116 public Matrix inverse(){ 117 int negativeDeterminant = negativeDeterminant(determinant(this.getMatrix())); 118 Matrix D = this.negative(this.getD()); 119 double[][] arr = D.getArray(); 120 double[][] inverseArr = new double[arr.length][arr.length]; 121 for(int i = 0 ; i < arr.length ; i++){ 122 for (int j = 0 ; j < arr.length ; j++){ 123 inverseArr[i][j] = mod(new Double(arr[i][j]).intValue() * negativeDeterminant); 124 } 125 } 126 return new Matrix(inverseArr); 127 } 128 129 public Matrix getMatrix() { 130 return matrix; 131 } 132 133 public void setMatrix(Matrix matrix) { 134 this.matrix = matrix; 135 } 136 public static void main(String[] args){ 137 double[][] arr = new double[][]{{5,8},{17,3}}; 138 Matrix m = new Matrix(arr,2,2); 139 MatrixUtil util = new MatrixUtil(new Matrix(arr)); 140 // System.out.println(util.determinant()); 141 Matrix D = util.getD(); 142 // m.print(NumberFormat.getInstance(),3); 143 // util.negative(D).print(NumberFormat.getInstance(), 3); 144 util.inverse().print(NumberFormat.getInstance(), 3); 145 146 147 // double[][] det = new double[][]{{9}}; 148 // Matrix detMatrix = new Matrix(det); 149 // detMatrix.inverse().print(NumberFormat.getInstance(),3); 150 } 151 }
-wellmaxwang