Shamir门限方案的秘钥分享(不要求支持大数)

题目描述

【实验目的】

  1. 通过基于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插值公式重构的多项式为

image.png

具体步骤如下。如图所示

image.png

其中
image.png

需要使用到逆元计算;

关于逆元,可以参看csdn一篇文章
其中有些例子不够完善,请谨慎选取,小心验证。

具体例子:

n=5, t=3, p=17; 随机选取K=13,a1=10,a2=2;

于是有

image.png

解密的时候选取 (1 8)(2 7) (5 11)来解密

image.png

上面的例子每个倒数都计算了一次逆元,大家可以想想有没有什么简化的方法。

输入

大素数p

子秘钥总数n

门限值t

输出

设置的密钥与恢复的密钥的差值

样例

输入:
1006000813
10
3
输出:
0

解题

其实你可以先不看问题描述的,我先大白话解释一下。
Shamir算法解决的问题是,将一个数字密钥key分解成n个碎片交给每一个人,当有至少t个人聚在一起的时候,就可以解出密码key。

然后可以看回上面的问题描述了。

主要分为两大模块:

  • 分发
  • 重构

分发

从具体例子入手,在描述中,

n=5, t=3, p=17; 随机选取 K=13, a_1=10, a_2=2;

image.png

这里的K就是密钥key,随机选取,在问题中,我们定死它为13
t是还原出密钥的最少碎片数,同时意味着最高次项为t-1=2,即平方
每个碎片i的形式都是
{ y_i=(K + a_1 \ast i + a_2 \ast i^2 + ... )}
那很方便写出,产生第i个碎片的函数(i<=n):

func makeKey(i, t, p, K int) int {
    ans := K
    for time := 1; time < t; time++ {
        ans += CONST_A[time] * pow(i, time)
    }
    return ans % p
}

其中
CONST_A = []int{0, 10, 2, 3, 8, 7, 5, 4, 3}
由我随机生成,注意数组索引为1和2的两个元素,为题意给的10、2
其实问题描述没有给出这个a_i序列的话,意味着测试用例t不会超过3

重构

本题的难点就是重构,这里需要一点先决知识

欢迎回来,通过上面链接,我获得了求逆元的一个函数

func qpow(a, b int) int {
    ans := 1
    p := b+2
    a = (a%p + p) % p
    for ; b != 0; b >>= 1 {
        if b&1 != 0 {
            ans = (a * ans) % p
        }
        a = a * a % p
    }
    return ans
}

用的是快速幂那个,几乎原封不动的搬了

然后就是解密,或者说重构了,因为任意t个可以揭秘,不妨取前t个
下面的arr为通过makeKey获得的碎片的序列,p是输入里面的大素数

func deKey(arr []int, t int, p int) int {
    ans := 0
    for i := 0; i < t; i++ {
        tmp := i
        Vi := arr[i]
        for j := (i + 1) % t; j != tmp; j %= t {
            Vi *= (0 - j -1)
            Vi *= qpow(i-j, p-2)
            Vi %= p
            j++
        }
        ans += Vi
    }
    return ans % p
}

内部的for循环写得有点抽象,但意思是要:
当i=0时,j遍历的数组元素为1,2
当i=1时,j遍历的数组元素为2,0
当i=2时,j遍历的数组元素为0,1

其实你也可以写成从0开始,让j!=i,且j最多为t-1
我这种写法类似于循环的队列,这一步卡我挺久,嘿嘿
毕竟有时候,顺序就有价值

于是加上输入输出,可以得到我们的完成程序:

package main

import (
    "bufio"
    "fmt"
    "io"
    "os"
)

var CONST_A []int

// 生成第i个碎片
func makeKey(i, t, p, K int) int {
    ans := K
    for time := 1; time < t; time++ {
        ans += CONST_A[time] * pow(i, time)
    }
    return ans % p
}
// 重构,获得密钥
func deKey(arr []int, t int, p int) int {
    ans := 0
    for i := 0; i < t; i++ {
        tmp := i
        Vi := arr[i]
        for j := (i + 1) % t; j != tmp; j %= t {
            Vi *= (0 - j -1)
            Vi *= qpow(i-j, p-2)
            Vi%=p
            j++
        }
        ans += Vi
    }
    return ans % p
}
// 求a对b+2的逆元
func qpow(a, b int) int {
    ans := 1
    p := b+2
    a = (a%p + p) % p
    for ; b != 0; b >>= 1 {
        if b&1 != 0 {
            ans = (a * ans) % p
        }
        a = a * a % p
    }
    return ans
}
func id_195(_r io.Reader, _w io.Writer) {
    in := bufio.NewReader(_r)
    out := bufio.NewWriter(_w)
    defer out.Flush()

    var t, n, p int
    K := 13
    fmt.Fscan(in, &p, &n, &t)
    y_seq := []int{} // 子密钥的序列
    for i := 1; i <= n; i++ {
        y_seq = append(y_seq, makeKey(i, t, p, K))
    }
    DE_K := deKey(y_seq, t, p)
    fmt.Println(K-DE_K)

}
func main() {
    CONST_A = []int{0, 10, 2, 3, 8, 7, 5, 4, 3}
    id_195(os.Stdin, os.Stdout)
}

func pow(x int, n int) int {
    result := 1
    for i := 0; i < n; i++ {
        result *= x
    }
    return result
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容