1.题目
编程实现ElGamal的加密和解密,假设用户A选择素数p=11和本原根g=2,并且选择私钥α=5,输出A的公钥;若用户B向用户A发送消息m=6,随机数k=7,输出对该消息加密后的密文,以及对密文进行解密的明文。
2.文字版题解
(1)求A的公钥
ElGamal的公钥=(选择的素数(p)、本原根(g)、由p,g,α运算得到的一个数(y))
ElGamal的私钥=选择的私钥(α)
A的公钥,只剩y不知道,则:
y=g*α mod p=2*5 mod 11=10
故A的公钥=(11,2,10)
(2)加密后的密文
公式:
r=g^k mod p
s=m*(y^k) mod p
解释:
(r,s)=加密得到的密文
m:消息发送方发送的消息
k:消息发送方选择的随机数
计算:
r=g^k mod p=2^7 mod 11=7
s=m*(y^k) mod p=6*10^7 mod 11=5
故加密得到的密文=(7,5)
(3)解密的明文
公式: 明文=
注:括号上的-1是指括号内容mod p的逆元,不会计算题目数值逆元的看后面的教程
计算:
故解密得到的明文是6
附.如何求逆元
定义:对于正整数a和m,如果有ax≡1(mod m),那么把这个同余方程中的x最小正整数解叫做a模x的逆元
解法:
先化简原数:
1.ax≡1(modm)带入题目数值
(7^5)* x ≡ 1 (mod 11)
2.因为:a*b mod c ≡(a mod c)*(b mod c) mod c
也就是相乘的几个数分别可以替换为‘原数mod被模数’
3.如:10*6 mod 2 ≡5*3 mod 2≡15 mod 2
4.故:
7^5mod11
≡7*7*7*7*7 mod 11
≡49*49*7mod11
≡5*5*7mod11
≡25*7mod11
≡3*7mod11
≡10mod11
化简后转为求10^(-1) mod 11(即10模11的逆元)
即求x:
10* x ≡ 1 (mod 11)
1.代入法:
把数带入一个个尝试
2.辗转相除法:
举例求7^(-1) mod 25(即7模25的逆元):
即求x:
7* x ≡ 1 (mod 25)
(1)把要操作的数中大的放前面
这里是(25,7)
(2)大数(25)=小数(7)乘一个尽可能大的数加上余数(>=1)
25=3*7+4
(3)更新值并重复(2):大数的值是原来的小数(7),小数的值是被减剩余值(4)
7=1*4+3
4=1*3+1
(4)当被减剩余值为1时,停止更新并变换格式
如上述4=1*3+1中被减剩余值为1,变换格式为:1=4-3(省略了1*3中的1)
(5)从下到上(除最后一个)把之前剩余值代表式带入新式子
目的是只剩原始的两个操作数
7=1*4+3得到:剩余值3=7-4 带入 1=4-3 得:1=4-(7-4)=4*2-7
25=3*7+4得到:剩余值4=25-3*7 带入 1=4*2-7 得 1=(25-3*7 )*2-7=25*2-7*7
(6)转换所求原式子格式
7* x ≡ 1 (mod 25) 转换为 1=7*x-25*b
注:
r≡a mod n可以
表示为:a = qn + r
,其中0 ≤ r < n
,q是整数商
(7)若x为正数,则其为逆元;若x为负数,则x mod p为逆元,p是原式子所模的数
对比(5)(6)结果:
1=25*2-7*7
1=7*x-25*b
可知x=-7
故逆元=(-7)mod 25 =18
求10^(-1) mod 11(即10模11的逆元)
(1)11=10*1+1
(2)1=11-10
(3)逆元:(-1)mod11=10
3.相应代码
注释格式:序号(代码顺序)+注解
(1)求A的公钥
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//1.输入基本数据
Scanner sc = new Scanner(System.in);
System.out.println("输入用户A选择的素数:");
int p = sc.nextInt();
System.out.println("输入用户A的本原根:");
int g = sc.nextInt();
System.out.println("输入用户A选择的私钥:");
int α = sc.nextInt();
//4.计算并输出公钥
int y=publicKey(p,g,α);
}
//2.求公钥的方法
public static int publicKey(int p,int g,int α){
//3.Math.floorMod是用来取模的方法
int y=Math.floorMod(g*α,p);
System.out.println("公钥是("+p+","+g+","+y+")");
return y;
}
}
(2)求加密后的密文
//下面代码补充到主函数:
//5.输入基本数据
System.out.println("输入用户B发送的消息:");
int m = sc.nextInt();
System.out.println("输入用户B选择的随机数:");
int k = sc.nextInt();
//6.创建存储密文的变量
int r=0,s=0;
//9.计算密文并输出
r=ciphertext_r(m,k,g,p,y,r);
s=ciphertext_s(m,k,g,p,y,s);
System.out.println("密文是:("+r+","+s+")");
//上面代码补充到主函数:
//下面是新方法:
//7.求密文并输出的方法,不并作一个方法是需要返回两个变量
public static int ciphertext_r(int m,int k,int g,int p,int y,int r) {
//8.Math.pow(x, y)是求指数的方法,注意pow返回double,floorMod参数是int
r=Math.floorMod((int)Math.pow(g, k),p);
return r;
}
public static int ciphertext_s(int m,int k,int g,int p,int y,int s) {
s=Math.floorMod((int)(m*Math.pow(y, k)),p);
return s;
}
(3)解密明文
//下面代码补充到主函数:
//10.创建存储逆元的变量
int x=1;
//13.求逆元
x=opposite(10, p, x);
//14.创建存储明文的变量
int clear =0;
//18.计算明文并输出
clear=clearText( s, r, α, p, x);
System.out.println("明文是:"+clear);
//上面代码补充到主函数:
//下面是新方法
//15.求明文的方法
public static int clearText(int s,int r,int α,int p,int x) {
//16.求逆
x=opposite((int)Math.pow(r,α),p,x);
//17.返回输出明文
return Math.floorMod(s*x,p);
}
//11.求逆元的方法,代入法
public static int opposite(int a,int m,int x) {
//12.从x=1开始循环判断是否满足ax≡1(mod m),满足则退出
while(true){
if(Math.floorMod(a*x,m)==1){
break;
}
x++;
}
return x;
}
4.完整代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
//1.输入基本数据
Scanner sc = new Scanner(System.in);
System.out.println("输入用户A选择的素数:");
int p = sc.nextInt();
System.out.println("输入用户A的本原根:");
int g = sc.nextInt();
System.out.println("输入用户A选择的私钥:");
int α = sc.nextInt();
//4.计算并输出公钥
int y=publicKey(p,g,α);
//5.输入基本数据
System.out.println("输入用户B发送的消息:");
int m = sc.nextInt();
System.out.println("输入用户B选择的随机数:");
int k = sc.nextInt();
//6.创建存储密文的变量
int r=0,s=0;
//9.计算密文并输出
r=ciphertext_r(m,k,g,p,y,r);
s=ciphertext_s(m,k,g,p,y,s);
System.out.println("密文是:("+r+","+s+")");
//10.创建存储逆元的变量
int x=1;
//13.求逆元
x=opposite(10, p, x);
//14.创建存储明文的变量
int clear =0;
//18.计算明文并输出
clear=clearText( s, r, α, p, x);
System.out.println("明文是:"+clear);
}
//15.求明文的方法
public static int clearText(int s,int r,int α,int p,int x) {
//16.求逆
x=opposite((int)Math.pow(r,α),p,x);
//17.返回输出明文
return Math.floorMod(s*x,p);
}
//11.求逆元的方法,代入法
public static int opposite(int a,int m,int x) {
//12.从x=1开始循环判断是否满足ax≡1(mod m),满足则退出
while(true){
if(Math.floorMod(a*x,m)==1){
break;
}
x++;
}
return x;
}
//7.求密文并输出的方法,不并作一个方法是需要返回两个变量
public static int ciphertext_r(int m,int k,int g,int p,int y,int r) {
//8.Math.pow(x, y)是求指数的方法,注意pow返回double,floorMod参数是int
r=Math.floorMod((int)Math.pow(g, k),p);
return r;
}
public static int ciphertext_s(int m,int k,int g,int p,int y,int s) {
s=Math.floorMod((int)(m*Math.pow(y, k)),p);
return s;
}
//2.求公钥的方法
public static int publicKey(int p,int g,int α){
//3.Math.floorMod是用来取模的方法
int y=Math.floorMod(g*α,p);
System.out.println("公钥是("+p+","+g+","+y+")");
return y;
}
}