1 简介
- 作者:Shamir
- 时间:1979年
- 理念:基于多项式插值算法
2 具体实现
I 秘密分割算法
-
(1)选择一个随机素数 ppp,并产生一个随机的 t−1t-1t−1 次多项式;
f(x)=at−1xt−1+⋯+a1x+a0modpf(x)=a_{t-1} x^{t-1}+\cdots+a_{1} x+a_{0} \bmod p f(x)=at−1xt−1+⋯+a1x+a0modp
令a0=Sa_0 = Sa0=S(SSS为想要分享的秘密),则f(0)=a0=Sf(0) = a_0 = Sf(0)=a0=S。f(x)f(x)f(x)的最高次必须设置为xt−1x^{t-1}xt−1。 -
(2)选择 nnn 个互不相同的整数 1≤x1,…,xn≤p−11≤ x_1,…,x_n ≤ p-11≤x1,…,xn≤p−1;
-
(3)第iii 个参与者计算Si=f(xi)S_i = f(x_i)Si=f(xi)作为其分享的秘密;
-
(4)销毁f(x)f(x)f(x)。
II 秘密重构算法
-
(1)ttt 个参与者拿出自己的秘密消息。假设 S1,…,StS_1, …, S_tS1,…,St 是这 ttt 个秘密,分别对应 x1,…,xtx_1, …, x_tx1,…,xt。利用这些信息可以重构出 f(x)f(x)f(x);
f(x)=∑iSi∏j≠i(x−xj)∏j≠i(xi−xj)modporf(x)=∑i=1tSi∏j∈{1,2,…,t}∖{i}(x−xj)∏j∈{1,2,…,t}∖{i}(xi−xj)modp\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
令a0=Sa_0 = Sa0=S(SSS为想要分享的秘密),则f(0)=a0=Sf(0) = a_0 = Sf(0)=a0=S。f(x)f(x)f(x)的最高次必须设置为xt−1x^{t-1}xt−1。 -
(2)重构出f(x)f(x)f(x)以后,计算S=f(0)S = f(0)S=f(0), 多于 ttt个参与者重构f(x)f(x)f(x)的过程也是适用的。
3 实例
设秘密S=13S = 13S=13,n=5n = 5n=5, t=3t = 3t=3,选择模数p=17p = 17p=17。
I 秘密分割
- (1)生成t−1t - 1t−1个小于等于ppp的随机数,a1=10a_1 = 10a1=10,a2=2a_2 = 2a2=2,a0=S=13a_0 = S = 13a0=S=13;
- (2)分别计算
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\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)将(Si,i)(S_i, i)(Si,i)作为钥匙分发给第iii个参与者。
II 秘密重构
(1)收集任意t=3t = 3t=3个参与者的钥匙,例如第1个人的(8, 1),第2个人的(7, 2),第5个人的(11, 5);
(2)列出方程
f(x)=∑iSi∏j≠i(x−xj)∏j≠i(xi−xj)modp=(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))mod17\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)=13S = f(0) = 13S=f(0)=13。
或者列出方程组:
a0+a1∗(1mod17)+a2∗(12mod17)=8a0+a1∗(2mod17)+a2∗(22mod17)=7a0+a1∗(5mod17)+a2∗(52mod17)=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
求解方程组,得到a0=13,a1=10,a2=2a_0 = 13, a_1 = 10, a_2 = 2a0=13,a1=10,a2=2,则S=a0=13S = a_0 = 13S=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("测试结束.....");}
}