一、实验目的与原理
通过基于Shamir门限方案的密钥分割及恢复的演示,理解密钥分割的重要性,理解密钥分割的基本原理和作用,掌握基于Shamir门限方案的密钥分割软件的使用。
秘密共享体制为将秘密分给多人掌管提供了可能。例如重要场所的通行、遗嘱的生效等都必须由两人或多人同时参与才能生效,这时都需要将秘密分给多人掌管并同时参与才能恢复。在实际应用中,秘密共享的要求多种多样、形形色色,每一种解决问题的方案都可成为一种体制。1979年,Shamir在提出秘密分享思想的同时,利用拉格朗日插值多项式理论设计出了一个具体的(t,n)秘密分享方案。1979年以后,人们通过对秘密共享问题的分析研究,构建出了许多类型的秘密共享体制。具有代表性和一般性的除了有Shamir提出的(t,n)门限体制,还有Blakley提出的矢量体制,Asmuth和Bloom提出的同余类体制,Karnin提出的矩阵法体制等。
一般地,一个由秘密分发者D和参与者P1,P2,…,Pn构成的(t,n)秘密分享体制包含下面两个协议:
(1) 秘密分发协议:在这个协议中,秘密分发者D在n个参与者中分享秘密s,每个参与者Pi获得一个碎片si,i=1,2,…,n。
(2) 秘密重构协议:在这个协议中,任意不少于t个参与者一起合作,以自己的碎片为输入,重构原秘密s。
一个安全的(t,n)秘密分享体制必须同时提供两个性质:一方面,任意t个参与者通过提供自己的碎片能够协作地恢复出原秘密s;另一方面,任意少于t个参与者即便拥有自己的碎片也无法计算关于原秘密s的任何信息。一般称这里的t为门限值。
Shamir提出的基于LaGrange插值公式的密钥分存思想是,利用有限域GF(p)上的t-1次多项式
h(x)= at- 1xt- 1+ … + a1x+ a0 mod p (1)
构造秘密共享的(t,n)门限体制。其中,所选的随机素数p要大于最大可能的秘密数S和参与者总数n,并且公开;S=h(0)=a0,而at-1,at-2,… ,a1为选用的随机系数,这些都需要保密,在生成n个秘密份额之后即可销毁。通过计算多项式h(x)对n个不同xi的取值就给出每个人的秘密份额:
Si= h(xi)mod p,i= 1,2,3,… ,n (2)
每一(xi,Si)对就是曲线h上的一个点,可看作是用户的标识符。由于任意t个点都可唯一地确定相应的t- 1次多项式,所以,秘密S可以从t个秘密份额重构。给定任意t个秘密份额Si1,Si2,… ,Sit,由LaGrange插值公式重构的多项式为
具体步骤如下。如图所示
其中需要使用到逆元计算。
关于逆元,可以参看逆元(数论中的倒数)_淼润淽涵的博客-优快云博客其中有些例子不够完善,请谨慎选取,小心验证。
具体例子:
n=5, t=3, p=17; 随机选取K=13,a1=10,a2=2;
于是有
解密的时候选取 (1 8)(2 7) (5 11)来解密
上面的例子每个倒数都计算了一次逆元。
输入
大素数p
子秘钥总数n
门限值t
输出
设置的密钥与恢复的密钥的差值
输入样例1
1006000813
10
3
输出样例1
0
代码:(有参考)
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
public class Main {
//定义基本常量
private static long k,x1,x2,x3,x4,x5;
//定义一个类
static class Point {
public long x,y;
//类的初始化
public Point(long x, long y) {
this.x = x;
this.y = y;
}
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
//分别输入大素数p,子密钥总数n,门限值t
long p,n,t,key=0,con,mod;
p = scan.nextInt();
n = scan.nextInt();
t = scan.nextInt();
//获得随机数
Random random = new Random();
//获得1到50的随机数
k = random.nextInt(50) + 1;
//获得1到20之间的随机数
x1 = random.nextInt(20) + 1;
x2 = random.nextInt(2) + 1;
//获取点,为后面进行密钥计算做准备
//使用循环对应一个曲线,将曲线上的一个点当做是用户的标识符
//每个点可以确定t-1个多项式
Long[] arr = new Long[(int) n + 1];
for (int i = 1; i <= n; i++) {
long y = (k + x1 * i + x2 * i * i) % p;
arr[i] = y;
}
List<Long> points=Arrays.asList(arr);
boolean[] boo = new boolean[(int) n + 1];
Point[] pointlist = new Point[(int)t];
for (int i = 0; i < t; i++) {
while (true) {
int x = random.nextInt((int)n) + 1;
if (!boo[x]) {
boo[x] = true;
pointlist[i] = new Point(x, points.get(x));
break;
}
}
}
List<Point> list = Arrays.asList(pointlist);
//解密过程,解密的过程需要选取门限值个数的不重复的点
//恢复密钥过程,里面调用了费马定理函数,解密过程调用费马函数进行循环的逆元计算
for (int i = 0; i < list.size(); i++) {
Point point = list.get(i);
long val = point.y;
for (int j = 0; j < list.size(); j++) {
if (i == j) {
continue;
}
val *= list.get(j).x;
val %= p;
mod =ol(point.x - list.get(j).x,p-2,p);
val *= mod;
val %= p;
}
key += val;
key %= p;
}
con = key - k;
System.out.println(con);
}
//费马定理函数,用于求解逆元
static long ol(long a, long b, long c) {
long t = 1;
long temp = a % c;
while (b != 0) {
if ((b & 1) != 0) t = t * temp % c;
temp = temp * temp % c;
b >>= 1;
}
if (t < 0) {
return t + c;
} else {
return t;
}
}
}