1 简介
- 作者:Shamir
- 时间:1979年
- 理念:基于多项式插值算法
2 具体实现
I 秘密分割算法
-
(1)选择一个随机素数 p p p,并产生一个随机的 t − 1 t-1 t−1 次多项式;
f ( x ) = a t − 1 x t − 1 + ⋯ + a 1 x + a 0 m o d p f(x)=a_{t-1} x^{t-1}+\cdots+a_{1} x+a_{0} \bmod p f(x)=at−1xt−1+⋯+a1x+a0modp
令 a 0 = S a_0 = S a0=S( S S S为想要分享的秘密),则 f ( 0 ) = a 0 = S f(0) = a_0 = S f(0)=a0=S。 f ( x ) f(x) f(x)的最高次必须设置为 x t − 1 x^{t-1} xt−1。 -
(2)选择 n n n 个互不相同的整数 1 ≤ x 1 , … , x n ≤ p − 1 1≤ x_1,…,x_n ≤ p-1 1≤x1,…,xn≤p−1;
-
(3)第 i i i 个参与者计算 S i = f ( x i ) S_i = f(x_i) Si=f(xi)作为其分享的秘密;
-
(4)销毁 f ( x ) f(x) f(x)。
II 秘密重构算法
-
(1) t t t 个参与者拿出自己的秘密消息。假设 S 1 , … , S t S_1, …, S_t S1,…,St 是这 t t t 个秘密,分别对应 x 1 , … , x t x_1, …, x_t x1,…,xt。利用这些信息可以重构出 f ( x ) f(x) f(x);
f ( x ) = ∑ i S i ∏ j ≠ i ( x − x j ) ∏ j ≠ i ( x i − x j ) m o d p or f ( x ) = ∑ i = 1 t S i ∏ j ∈ { 1 , 2 , … , t } ∖ { i } ( x − x j ) ∏ j ∈ { 1 , 2 , … , t } ∖ { i } ( x i − x j ) m o d p \begin{array}{l} f(x) = \sum_{i} \frac{S_i \prod_{j \neq i} (x - x_j)}{\prod_{j \neq i} (x_i - x_j)} \bmod p \\ \textrm{or} \\ f(x) = \sum_{i=1}^t \frac{S_i \prod_{j \in \{1, 2, \dots, t\} \setminus \{i\}} (x - x_j)}{\prod_{j \in \{1, 2, \dots, t\} \setminus \{i\}} (x_i - x_j)} \bmod p\\ \end{array} f(x)=∑i∏j=i(xi−xj)Si∏j=i(x−xj)modporf(x)=∑i=1t∏j∈{1,2,…,t}∖{i}(xi−xj)Si∏j∈{1,2,…,t}∖{i}(x−xj)modp
令 a 0 = S a_0 = S a0=S( S S S为想要分享的秘密),则 f ( 0 ) = a 0 = S f(0) = a_0 = S f(0)=a0=S。 f ( x ) f(x) f(x)的最高次必须设置为 x t − 1 x^{t-1} xt−1。 -
(2)重构出 f ( x ) f(x) f(x)以后,计算 S = f ( 0 ) S = f(0) S=f(0), 多于 t t t个参与者重构 f ( x ) f(x) f(x)的过程也是适用的。
3 实例
设秘密
S
=
13
S = 13
S=13,
n
=
5
n = 5
n=5,
t
=
3
t = 3
t=3,选择模数
p
=
17
p = 17
p=17。
I 秘密分割
- (1)生成 t − 1 t - 1 t−1个小于等于 p p p的随机数, a 1 = 10 a_1 = 10 a1=10, a 2 = 2 a_2 = 2 a2=2, a 0 = S = 13 a_0 = S = 13 a0=S=13;
- (2)分别计算
S 1 = ( 13 + 10 ∗ 1 + 2 ∗ 1 2 ) m o d 17 = 8 S 2 = ( 13 + 10 ∗ 2 + 2 ∗ 2 2 ) m o d 17 = 7 S 3 = ( 13 + 10 ∗ 3 + 2 ∗ 3 2 ) m o d 17 = 10 S 4 = ( 13 + 10 ∗ 4 + 2 ∗ 4 2 ) m o d 17 = 0 S 5 = ( 13 + 10 ∗ 5 + 2 ∗ 5 2 ) m o d 17 = 11 \begin{array}{l} S_{1}=\left(13+10 * 1+2 * 1^{2}\right) \bmod 17=8 \\ S_{2}=\left(13+10 * 2+2 * 2^{2}\right) \bmod 17=7 \\ S_{3}=\left(13+10 * 3+2 * 3^{2}\right) \bmod 17=10 \\ S_{4}=\left(13+10 * 4+2 * 4^{2}\right) \bmod 17=0 \\ S_{5}=\left(13+10 * 5+2 * 5^{2}\right) \bmod 17=11 \end{array} S1=(13+10∗1+2∗12)mod17=8S2=(13+10∗2+2∗22)mod17=7S3=(13+10∗3+2∗32)mod17=10S4=(13+10∗4+2∗42)mod17=0S5=(13+10∗5+2∗52)mod17=11
(3)将 ( S i , i ) (S_i, i) (Si,i)作为钥匙分发给第 i i i个参与者。
II 秘密重构
(1)收集任意 t = 3 t = 3 t=3个参与者的钥匙,例如第1个人的(8, 1),第2个人的(7, 2),第5个人的(11, 5);
(2)列出方程
f
(
x
)
=
∑
i
S
i
∏
j
≠
i
(
x
−
x
j
)
∏
j
≠
i
(
x
i
−
x
j
)
m
o
d
p
=
(
8
(
x
−
2
)
(
x
−
5
)
(
1
−
2
)
(
1
−
5
)
+
7
(
x
−
1
)
(
x
−
5
)
(
2
−
1
)
(
2
−
5
)
+
11
(
x
−
1
)
(
x
−
2
)
(
5
−
1
)
(
5
−
2
)
)
m
o
d
17
\begin{array}{l} f(x) &=& \sum_{i} \frac{S_i \prod_{j \neq i} (x - x_j)}{\prod_{j \neq i} (x_i - x_j)} \bmod p \\ &=&(\frac{8(x - 2)(x-5)}{(1-2)(1-5)} + \frac{7(x - 1)(x-5)}{(2-1)(2-5)} + \frac{11(x - 1)(x-2)}{(5-1)(5-2)}) \bmod 17 \\ \end{array}
f(x)==∑i∏j=i(xi−xj)Si∏j=i(x−xj)modp((1−2)(1−5)8(x−2)(x−5)+(2−1)(2−5)7(x−1)(x−5)+(5−1)(5−2)11(x−1)(x−2))mod17
计算
S
=
f
(
0
)
=
13
S = f(0) = 13
S=f(0)=13。
或者列出方程组:
a
0
+
a
1
∗
(
1
m
o
d
17
)
+
a
2
∗
(
1
2
m
o
d
17
)
=
8
a
0
+
a
1
∗
(
2
m
o
d
17
)
+
a
2
∗
(
2
2
m
o
d
17
)
=
7
a
0
+
a
1
∗
(
5
m
o
d
17
)
+
a
2
∗
(
5
2
m
o
d
17
)
=
11
\begin{array}{l} a_0 + a_1 * (1 \bmod 17) + a_2 * (1^2 \bmod 17) = 8 \\ a_0 + a_1 * (2 \bmod 17) + a_2 * (2^2 \bmod 17) = 7 \\ a_0 + a_1 * (5 \bmod 17) + a_2 * (5^2 \bmod 17) = 11 \\ \end{array}
a0+a1∗(1mod17)+a2∗(12mod17)=8a0+a1∗(2mod17)+a2∗(22mod17)=7a0+a1∗(5mod17)+a2∗(52mod17)=11
求解方程组,得到
a
0
=
13
,
a
1
=
10
,
a
2
=
2
a_0 = 13, a_1 = 10, a_2 = 2
a0=13,a1=10,a2=2,则
S
=
a
0
=
13
S = a_0 = 13
S=a0=13。
4 代码
package com.duwei.crypto;
import java.math.BigInteger;
import java.util.Random;
/**
* @BelongsProject: Secure_Aggregation
* @BelongsPackage: com.duwei.crypto
* @Author: duwei
* @Date: 2022/4/28 16:37
* @Description: Shamir秘密共享方法
*/
public class SecretShare {
private static BigInteger p;
private static Random random;
/**
* 秘密分享算法
*
* @param secret 秘密
* @param m 系统总用户数
* @param t 秘密分享的阈值
* @return m个用户的秘密数组
*/
public static BigInteger[] share(BigInteger secret, int m, int t) {
//储存t - 1次多项系系数
BigInteger[] coefficients = new BigInteger[t];
coefficients[0] = secret;
for (int i = 1; i < t; i++) {
coefficients[i] = generateRandomBigInteger();
}
BigInteger[] userShares = new BigInteger[m];
//进行秘密分享
for (int i = 0; i < m; i++) {
userShares[i] = computeShare(coefficients, (i + 1));
}
return userShares;
}
/**
* 为指定用户计算秘密份额
*
* @param coefficients 系数向量
* @param userIndex 用户索引,即对于用户的x值
* 这里计算f(x)时x取值为 (下标 + 1)
* 如果直接从下标开始不加1会 直接暴露出 f(0)即秘密
* @return
*/
public static BigInteger computeShare(BigInteger[] coefficients, int userIndex) {
BigInteger index = new BigInteger(String.valueOf(userIndex));
int len = coefficients.length;
BigInteger temp = BigInteger.ONE;
BigInteger result = BigInteger.ZERO;
for (int i = 0; i < len; i++) {
BigInteger cur = coefficients[i].multiply(temp);
temp = temp.multiply(index);
result = result.add(cur).mod(p);
}
return result.mod(p);
}
/**
* 生成小于p的随机数
*
* @return
*/
public static BigInteger generateRandomBigInteger() {
BigInteger result;
do {
result = new BigInteger(p.bitLength(), random);
} while ((result.compareTo(p) >= 0) && (result.compareTo(BigInteger.ZERO) != 0));
return result;
}
/**
* 初始化方法,指定模数的bit长度
* @param bitLen
*/
public static void init(int bitLen) {
random = new Random();
p = BigInteger.probablePrime(bitLen,random);
}
/**
* 秘密重建算法
*
* @param shares 用户输入的秘密
* @param t 可以恢复秘密的阈值
* @return
*/
public static BigInteger reconstruction(BigInteger[] shares, int t) throws Exception {
int n = shares.length;
if (t > n) {
throw new Exception("你当前收集的秘密份额不足以恢复秘密");
}
BigInteger result = new BigInteger("0");
for (int i = 0; i < t; i++) {
result = result.add(interpolation(shares, i + 1, t));
}
return result.mod(p);
}
/**
* 求第i号用户(xK = i + 1)的了拉格朗日插值
*
* @param values
* @param t
* @return
*/
public static BigInteger interpolation(BigInteger[] values, int xK, int t) {
BigInteger result;
//常量0,计算f(0)
BigInteger zero = BigInteger.ZERO;
BigInteger x_k = new BigInteger(String.valueOf(xK));
//拉格朗日多项式
BigInteger up = BigInteger.ONE;
BigInteger down = BigInteger.ONE;
//i代表第i个用户的份额
for (int i = 0; i < t; i++) {
BigInteger x_i = new BigInteger(String.valueOf((i + 1)));
if (x_i.equals(x_k)) {
continue;
}
up = up.multiply(zero.subtract(x_i));
down = down.multiply(x_k.subtract(x_i));
}
result = up.multiply(down.modInverse(p));
result = result.multiply(values[xK - 1]);
return result;
}
public static void main(String[] args) throws Exception {
init(1024);
int times = 1000;
System.out.println("测试开始.....");
for (int i = 0;i < times;i++){
//生成小于p的随机秘密
BigInteger secret = generateRandomBigInteger();
int m = (int) (Math.random() * 100 ) + 5;
int t = (int) (Math.random() * 50 ) + 1;
//阈值必须小于总用户数
while (t > m){
t = (int) (Math.random() * 50 ) + 1;
}
BigInteger[] shares = share(secret, m, t);
BigInteger reconstruction = reconstruction(shares, t);
if (reconstruction.compareTo(secret) != 0){
System.out.println("秘密值恢复错误");
}
}
System.out.println("测试结束.....");
}
}