基於shamir門限的秘密分存


基於shamir門限的秘密分存

一、秘密分存

將一個秘密拆分成幾塊,分給幾個人保管,每個人保管一塊,只有當n塊組合在一起才能恢復出秘密,單獨的一塊對自己是沒有用的,n即為門限。

二、shamir門限方案

  • SHAMIR門限方案是基於多項式的拉格朗日插值公式的,即已知Φ(x)在k個互相不同的點的函數值Φ(xi),可構造k-1次插值多項式為f(x)=∑Φ(xi)∏(x-xj)/(xi-xj)。
  • 如:已知Φ(2)=10,Φ(5)=3,Φ(4)=7,求Φ(1),則可以構造f(x)=10[(x-5)(x-4)]/[(2-5)(2-4)]+3[(x-2)(x-4)]/[(5-2)(5-4)]+7*[(x-2)(x-5)]/[(4-2)(4-5)],帶入x=1即得
  • 因此,可以在一個GF(q)上構造一個多項式f(x)(q為一個隨機大素數),秘密s為之上的一個隨機數,n個參與者分到子密鑰f(i),有k個能還原,即可采用拉格朗日插值公式構造多項式,f(0)即為秘密。

三、說明

  • 分解秘密過程:首先得到要分解的秘密,為一個整數(要小於2,147,483,647),然后利用Java中的函數BigInteger q = BigInteger.probablePrime(bit_num, rand)生成一個大於秘密的隨機大整數,作為模值,rand為隨機數因子,bit_num為生成的隨機大素數的二進制的位數。之后生成隨機的多項式的系數和要分配的子密鑰(子密鑰在程序中設置小於100),之后根據構造好的多項式算出子密鑰的值,即子密鑰包括子密鑰及子密鑰的值。
  • 還原秘密過程:先輸入各個子密鑰,再輸入各子密鑰對應的模值。因為秘密為f(0),實際上只要求出多項式的常數即可,得到每個拉格郎日插值多項式的各個部分的常數,相加模p即為秘密。
  • 用廣義歐幾里得除法求逆時,這兩個數都為正數,開始忽視了這一點,導致寫求逆函數時出現錯誤
  • java的BigInteger類,可以用該類的方法計算大數的加減乘除等運算,相關方法如下:
    BigInteger.add(b); //大整數加法,b也為一個大數
    BigInteger.subtract(b); //大整數減法
    BigInteger.multiply(b); //大整數乘法
    BigInteger.divide(b); //大整數除法(取整)
    BigInteger.remainder(b); //大整數取模
    BigInteger.pow(exponent); //大整數a的exponent次冪

結果

四、源代碼

package shamir;

import java.math.BigInteger;
import java.util.Random;
import java.util.Scanner;

public class Shamir {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		while (true) {
			System.out.println("分解秘密請選擇1,還原秘密選擇2, 退出選擇3");
			int flag = in.nextInt();
			if (flag == 1) {
				long a[] = new long[100];// 放系數
				long f[] = new long[100];// 放密鑰的值
				long dian[] = new long[100];// 放密鑰的點
				System.out.println("輸入你的秘密");
				int secret = in.nextInt();// 輸入為一個數小於2,147,483,647
				Random rand = new Random();
				int bit_num = rand.nextInt(29) + 2;// 隨機2到31位
				BigInteger q = BigInteger.probablePrime(bit_num, rand);// 生成一個隨機大素數,必須大於輸入的隨機整數
				long p = q.longValue();
				while (p < secret) {// 如果不大於輸入的數
					bit_num = rand.nextInt(29) + 2;
					q = BigInteger.probablePrime(bit_num, rand);
					p = q.longValue();
				}
				System.out.println("模為  " + p);
				System.out.println("輸入門限值");// 門限值小於等於100
				int k = in.nextInt();
				System.out.println("輸入得到幾個子密鑰");// 子密鑰值小於等於100
				int zi_key = in.nextInt();
				for (int i = 0; i < k - 1; i++) {
					a[i] = (long) (Math.random() * p);// 生成偽隨機系數
					if (a[i] == 0) {// 生成的隨機系數不能為0
						i--;
					}
				}
				for (int i = 0; i < zi_key; i++) {
					dian[i] = (long) (Math.random() * 100);// 生成100以內隨機點,不能重復,如果大了,可能在以后的運算中超出數據類型范圍,導致錯誤
					if (dian[i] == 0) {// 生成的隨機點不能為0
						i--;
					}
				}
				System.out.println("子密鑰為(確保子密鑰沒有重復,如果有請重新生成)   ");
				for (int i = 0; i < zi_key; i++) {// 計算zi_key個子密鑰
					f[i] = secret;
					for (int j = 0; j < k - 1; j++) {// 一個子密鑰
						long zhishu = j + 1;
						f[i] = Math.floorMod((long) (a[j] * Math.pow(dian[i], zhishu)) + f[i], p);
					}
					System.out.print(dian[i] + " ");
					System.out.println(f[i]);
				}
			} else if (flag == 2) {
				System.out.println("輸入模值");
				int m = in.nextInt();
				System.out.println("輸入門限");
				int k = in.nextInt();
				long key_d[] = new long[k];
				long key_z[] = new long[k];
				long num_x[] = new long[k];
				long num_s[] = new long[k];
				long s = 0;
				System.out.println("請輸入密鑰(先輸入所有的點,再輸入各點對應的值) ");
				for (int i = 0; i < k; i++) {
					key_d[i] = in.nextLong();
				}
				for (int i = 0; i < k; i++) {
					key_z[i] = in.nextLong();
				}
				for (int i = 0; i < k; i++) {
					num_x[i] = 1;
					num_s[i] = 1;
					for (int j = 0; j < k; j++) {
						if (j == i) {
							j++;
						}
						if (j == k) {
							break;
						}
						num_x[i] = num_x[i] * (key_d[i] - key_d[j]);
						num_s[i] = (-key_d[j]) * num_s[i];
					}
					num_x[i] = qiu_ni(num_x[i], m);
					s = num_x[i] * num_s[i] * key_z[i] + s;
				}
				s = Math.floorMod(s, m);
				System.out.println("秘密為 " + s);
			} else {
				break;
			}
		}
	}

	// 求逆函數
	static long qiu_ni(long a, long b) {// 最后s[1]為s即逆元,t[1]為t
		long s[] = { 1, 0, 0 };
		long t[] = { 0, 1, 0 };
		long r1 = a;
		long r2 = b;
		long tmp;
		int i = (int) (r1 / r2);
		tmp = r2;
		r2 = Math.floorMod(r1, r2);
		r1 = tmp;
		while (r2 != 0) {
			s[2] = s[0] - i * s[1];
			t[2] = t[0] - i * t[1];
			s[0] = s[1];
			s[1] = s[2];
			t[0] = t[1];
			t[1] = t[2];
			if (r2 != 0)
				i = (int) (r1 / r2);
			tmp = r2;
			r2 = Math.floorMod(r1, r2);
			r1 = tmp;
		}
		return s[1];
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM