init: v1.0.0
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package ssss
|
||||
|
||||
/*
|
||||
package ssss implements Shamir's Secret Sharing Scheme
|
||||
|
||||
Usage:
|
||||
func TestSSSS() {
|
||||
secret := make([]byte, 16)
|
||||
// (3,5)门限
|
||||
shares, err := Split(secret, 3, 5, 0, rand.Reader)
|
||||
if err != nil {
|
||||
//
|
||||
}
|
||||
|
||||
// shares 是5份分片数据
|
||||
|
||||
// 收集至少3份分片数据
|
||||
recoveryShares := shares[:3]
|
||||
|
||||
//
|
||||
recoveredSecret, err := Restore(recoveryShares)
|
||||
if err != nil {
|
||||
//
|
||||
}
|
||||
|
||||
if bytes.Compare(secret, recoveredSecret) != 0 {
|
||||
fmt.Println("recoveredSecret and secret are different")
|
||||
}
|
||||
}
|
||||
|
||||
每个分片数据格式定义为:
|
||||
SharedSlice ::= SEQUENCE {
|
||||
Version INTEGER DEFAULT 0,-- default 0
|
||||
Threshold INTEGER, -- 门限值
|
||||
Length INTEGER, -- 原秘密值字节数
|
||||
Degree INTEGER, -- 拉格朗日多项式系数域在F_2上的扩域次数
|
||||
X INTEGER, -- x值
|
||||
Y INTEGER, -- y=f(x)
|
||||
Token [0]IMPLICIT OCTET STRING OPTINAL --随机字节,同一secret的n个分片应该一致
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,23 @@
|
||||
package ssss
|
||||
|
||||
import (
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
)
|
||||
|
||||
//go:generate stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go
|
||||
type ErrorCode gerrors.ErrorCode
|
||||
|
||||
func (e ErrorCode) Error() string {
|
||||
return gerrors.Format(uint32(e), e.String())
|
||||
}
|
||||
|
||||
// error codes
|
||||
const (
|
||||
ErrInvalidInput ErrorCode = 0x0100c000 + iota //输入不合法
|
||||
ErrRestoreFailed //恢复秘密值失败
|
||||
ErrDivideZero //除数为0
|
||||
ErrSharesMayBeTheSame //输入相同分片
|
||||
ErrNeedMoreShares //分片数量不足
|
||||
ErrSecretTooLarge //秘密值太大
|
||||
ErrBadShares //分片错误
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
// Code generated by "stringer -type=ErrorCode -linecomment -output=errors_string.go errors.go"; DO NOT EDIT.
|
||||
|
||||
package ssss
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[ErrInvalidInput-16826368]
|
||||
_ = x[ErrRestoreFailed-16826369]
|
||||
_ = x[ErrDivideZero-16826370]
|
||||
_ = x[ErrSharesMayBeTheSame-16826371]
|
||||
_ = x[ErrNeedMoreShares-16826372]
|
||||
_ = x[ErrSecretTooLarge-16826373]
|
||||
_ = x[ErrBadShares-16826374]
|
||||
}
|
||||
|
||||
const _ErrorCode_name = "输入不合法恢复秘密值失败除数为0输入相同分片分片数量不足秘密值太大分片错误"
|
||||
|
||||
var _ErrorCode_index = [...]uint8{0, 15, 36, 46, 64, 82, 97, 109}
|
||||
|
||||
func (i ErrorCode) String() string {
|
||||
i -= 16826368
|
||||
if i >= ErrorCode(len(_ErrorCode_index)-1) {
|
||||
return "ErrorCode(" + strconv.FormatInt(int64(i+16826368), 10) + ")"
|
||||
}
|
||||
return _ErrorCode_name[_ErrorCode_index[i]:_ErrorCode_index[i+1]]
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
package ssss
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
)
|
||||
|
||||
/* coefficients of some irreducible polynomials over GF(2) */
|
||||
// var irred_coeff = [...]byte{
|
||||
// 4, 3, 1, 5, 3, 1, 4, 3, 1, 7, 3, 2, 5, 4, 3, 5, 3, 2, 7, 4, 2, 4, 3, 1, 10, 9, 3, 9, 4, 2, 7, 6, 2, 10, 9,
|
||||
// 6, 4, 3, 1, 5, 4, 3, 4, 3, 1, 7, 2, 1, 5, 3, 2, 7, 4, 2, 6, 3, 2, 5, 3, 2, 15, 3, 2, 11, 3, 2, 9, 8, 7, 7,
|
||||
// 2, 1, 5, 3, 2, 9, 3, 1, 7, 3, 1, 9, 8, 3, 9, 4, 2, 8, 5, 3, 15, 14, 10, 10, 5, 2, 9, 6, 2, 9, 3, 2, 9, 5,
|
||||
// 2, 11, 10, 1, 7, 3, 2, 11, 2, 1, 9, 7, 4, 4, 3, 1, 8, 3, 1, 7, 4, 1, 7, 2, 1, 13, 11, 6, 5, 3, 2, 7, 3, 2,
|
||||
// 8, 7, 5, 12, 3, 2, 13, 10, 6, 5, 3, 2, 5, 3, 2, 9, 5, 2, 9, 7, 2, 13, 4, 3, 4, 3, 1, 11, 6, 4, 18, 9, 6,
|
||||
// 19, 18, 13, 11, 3, 2, 15, 9, 6, 4, 3, 1, 16, 5, 2, 15, 14, 6, 8, 5, 2, 15, 11, 2, 11, 6, 2, 7, 5, 3, 8,
|
||||
// 3, 1, 19, 16, 9, 11, 9, 6, 15, 7, 6, 13, 4, 3, 14, 13, 3, 13, 6, 3, 9, 5, 2, 19, 13, 6, 19, 10, 3, 11,
|
||||
// 6, 5, 9, 2, 1, 14, 3, 2, 13, 3, 1, 7, 5, 4, 11, 9, 8, 11, 6, 5, 23, 16, 9, 19, 14, 6, 23, 10, 2, 8, 3,
|
||||
// 2, 5, 4, 3, 9, 6, 4, 4, 3, 2, 13, 8, 6, 13, 11, 1, 13, 10, 3, 11, 6, 5, 19, 17, 4, 15, 14, 7, 13, 9, 6,
|
||||
// 9, 7, 3, 9, 7, 1, 14, 3, 2, 11, 8, 2, 11, 6, 4, 13, 5, 2, 11, 5, 1, 11, 4, 1, 19, 10, 3, 21, 10, 6, 13,
|
||||
// 3, 1, 15, 7, 5, 19, 18, 10, 7, 5, 3, 12, 7, 2, 7, 5, 1, 14, 9, 6, 10, 3, 2, 15, 13, 12, 12, 11, 9, 16,
|
||||
// 9, 7, 12, 9, 3, 9, 5, 2, 17, 10, 6, 24, 9, 3, 17, 15, 13, 5, 4, 3, 19, 17, 8, 15, 6, 3, 19, 6, 1}
|
||||
|
||||
// irreducible polynomials of GF(2)
|
||||
var irred_coeff = [...][3]byte{
|
||||
{4, 3, 1}, // x^8 + x^4 + x^3 + x + 1
|
||||
{5, 3, 1}, // x^16 + x^5 + x^3 + x + 1
|
||||
{4, 3, 1}, // x^24 + x^4 + x^3 + x + 1
|
||||
{7, 3, 2}, // x^32 + x^7 + x^3 + x^2 + 1
|
||||
{5, 4, 3}, // x^40 + x^5 + x^4 + x^3 + 1
|
||||
{5, 3, 2}, // x^48 + x^5 + x^3 + x^2 + 1
|
||||
{7, 4, 2}, // x^56 + x^7 + x^4 + x^2 + 1
|
||||
{4, 3, 1}, // x^64 + x^4 + x^3 + x + 1
|
||||
{10, 9, 3}, // x^72 + x^10 + x^9 + x^3 + 1
|
||||
{9, 4, 2}, // x^80 + x^9 + x^4 + x^2 + 1
|
||||
{7, 6, 2}, // x^88 + x^7 + x^6 + x^2 + 1
|
||||
{10, 9, 6}, // x^96 + x^10 + x^9 + x^6 + 1
|
||||
{4, 3, 1}, // x^104 + x^4 + x^3 + x + 1
|
||||
{5, 4, 3}, // x^112 + x^5 + x^4 + x^3 + 1
|
||||
{4, 3, 1}, // x^120 + x^4 + x^3 + x + 1
|
||||
{7, 2, 1}, // x^128 + x^7 + x^2 + x + 1
|
||||
{5, 3, 2}, // x^136 + x^5 + x^3 + x^2 + 1
|
||||
{7, 4, 2}, // x^144 + x^7 + x^4 + x^2 + 1
|
||||
{6, 3, 2}, // x^152 + x^6 + x^3 + x^2 + 1
|
||||
{5, 3, 2}, // x^160 + x^5 + x^3 + x^2 + 1
|
||||
{15, 3, 2}, // x^168 + x^15 + x^3 + x^2 + 1
|
||||
{11, 3, 2}, // x^176 + x^11 + x^3 + x^2 + 1
|
||||
{9, 8, 7}, // x^184 + x^9 + x^8 + x^7 + 1
|
||||
{7, 2, 1}, // x^192 + x^7 + x^2 + x + 1
|
||||
{5, 3, 2}, // x^200 + x^5 + x^3 + x^2 + 1
|
||||
{9, 3, 1}, // x^208 + x^9 + x^3 + x + 1
|
||||
{7, 3, 1}, // x^216 + x^7 + x^3 + x + 1
|
||||
{9, 8, 3}, // x^224 + x^9 + x^8 + x^3 + 1
|
||||
{9, 4, 2}, // x^232 + x^9 + x^4 + x^2 + 1
|
||||
{8, 5, 3}, // x^240 + x^8 + x^5 + x^3 + 1
|
||||
{15, 14, 10}, // x^248 + x^15 + x^14 + x^10 + 1
|
||||
{10, 5, 2}, // x^256 + x^10 + x^5 + x^2 + 1
|
||||
{9, 6, 2}, // x^264 + x^9 + x^6 + x^2 + 1
|
||||
{9, 3, 2}, // x^272 + x^9 + x^3 + x^2 + 1
|
||||
{9, 5, 2}, // x^280 + x^9 + x^5 + x^2 + 1
|
||||
{11, 10, 1}, // x^288 + x^11 + x^10 + x + 1
|
||||
{7, 3, 2}, // x^296 + x^7 + x^3 + x^2 + 1
|
||||
{11, 2, 1}, // x^304 + x^11 + x^2 + x + 1
|
||||
{9, 7, 4}, // x^312 + x^9 + x^7 + x^4 + 1
|
||||
{4, 3, 1}, // x^320 + x^4 + x^3 + x + 1
|
||||
{8, 3, 1}, // x^328 + x^8 + x^3 + x + 1
|
||||
{7, 4, 1}, // x^336 + x^7 + x^4 + x + 1
|
||||
{7, 2, 1}, // x^344 + x^7 + x^2 + x + 1
|
||||
{13, 11, 6}, // x^352 + x^13 + x^11 + x^6 + 1
|
||||
{5, 3, 2}, // x^360 + x^5 + x^3 + x^2 + 1
|
||||
{7, 3, 2}, // x^368 + x^7 + x^3 + x^2 + 1
|
||||
{8, 7, 5}, // x^376 + x^8 + x^7 + x^5 + 1
|
||||
{12, 3, 2}, // x^384 + x^12 + x^3 + x^2 + 1
|
||||
{13, 10, 6}, // x^392 + x^13 + x^10 + x^6 + 1
|
||||
{5, 3, 2}, // x^400 + x^5 + x^3 + x^2 + 1
|
||||
{5, 3, 2}, // x^408 + x^5 + x^3 + x^2 + 1
|
||||
{9, 5, 2}, // x^416 + x^9 + x^5 + x^2 + 1
|
||||
{9, 7, 2}, // x^424 + x^9 + x^7 + x^2 + 1
|
||||
{13, 4, 3}, // x^432 + x^13 + x^4 + x^3 + 1
|
||||
{4, 3, 1}, // x^440 + x^4 + x^3 + x + 1
|
||||
{11, 6, 4}, // x^448 + x^11 + x^6 + x^4 + 1
|
||||
{18, 9, 6}, // x^456 + x^18 + x^9 + x^6 + 1
|
||||
{19, 18, 13}, // x^464 + x^19 + x^18 + x^13 + 1
|
||||
{11, 3, 2}, // x^472 + x^11 + x^3 + x^2 + 1
|
||||
{15, 9, 6}, // x^480 + x^15 + x^9 + x^6 + 1
|
||||
{4, 3, 1}, // x^488 + x^4 + x^3 + x + 1
|
||||
{16, 5, 2}, // x^496 + x^16 + x^5 + x^2 + 1
|
||||
{15, 14, 6}, // x^504 + x^15 + x^14 + x^6 + 1
|
||||
{8, 5, 2}, // x^512 + x^8 + x^5 + x^2 + 1
|
||||
{15, 11, 2}, // x^520 + x^15 + x^11 + x^2 + 1
|
||||
{11, 6, 2}, // x^528 + x^11 + x^6 + x^2 + 1
|
||||
{7, 5, 3}, // x^536 + x^7 + x^5 + x^3 + 1
|
||||
{8, 3, 1}, // x^544 + x^8 + x^3 + x + 1
|
||||
{19, 16, 9}, // x^552 + x^19 + x^16 + x^9 + 1
|
||||
{11, 9, 6}, // x^560 + x^11 + x^9 + x^6 + 1
|
||||
{15, 7, 6}, // x^568 + x^15 + x^7 + x^6 + 1
|
||||
{13, 4, 3}, // x^576 + x^13 + x^4 + x^3 + 1
|
||||
{14, 13, 3}, // x^584 + x^14 + x^13 + x^3 + 1
|
||||
{13, 6, 3}, // x^592 + x^13 + x^6 + x^3 + 1
|
||||
{9, 5, 2}, // x^600 + x^9 + x^5 + x^2 + 1
|
||||
{19, 13, 6}, // x^608 + x^19 + x^13 + x^6 + 1
|
||||
{19, 10, 3}, // x^616 + x^19 + x^10 + x^3 + 1
|
||||
{11, 6, 5}, // x^624 + x^11 + x^6 + x^5 + 1
|
||||
{9, 2, 1}, // x^632 + x^9 + x^2 + x + 1
|
||||
{14, 3, 2}, // x^640 + x^14 + x^3 + x^2 + 1
|
||||
{13, 3, 1}, // x^648 + x^13 + x^3 + x + 1
|
||||
{7, 5, 4}, // x^656 + x^7 + x^5 + x^4 + 1
|
||||
{11, 9, 8}, // x^664 + x^11 + x^9 + x^8 + 1
|
||||
{11, 6, 5}, // x^672 + x^11 + x^6 + x^5 + 1
|
||||
{23, 16, 9}, // x^680 + x^23 + x^16 + x^9 + 1
|
||||
{19, 14, 6}, // x^688 + x^19 + x^14 + x^6 + 1
|
||||
{23, 10, 2}, // x^696 + x^23 + x^10 + x^2 + 1
|
||||
{8, 3, 2}, // x^704 + x^8 + x^3 + x^2 + 1
|
||||
{5, 4, 3}, // x^712 + x^5 + x^4 + x^3 + 1
|
||||
{9, 6, 4}, // x^720 + x^9 + x^6 + x^4 + 1
|
||||
{4, 3, 2}, // x^728 + x^4 + x^3 + x^2 + 1
|
||||
{13, 8, 6}, // x^736 + x^13 + x^8 + x^6 + 1
|
||||
{13, 11, 1}, // x^744 + x^13 + x^11 + x + 1
|
||||
{13, 10, 3}, // x^752 + x^13 + x^10 + x^3 + 1
|
||||
{11, 6, 5}, // x^760 + x^11 + x^6 + x^5 + 1
|
||||
{19, 17, 4}, // x^768 + x^19 + x^17 + x^4 + 1
|
||||
{15, 14, 7}, // x^776 + x^15 + x^14 + x^7 + 1
|
||||
{13, 9, 6}, // x^784 + x^13 + x^9 + x^6 + 1
|
||||
{9, 7, 3}, // x^792 + x^9 + x^7 + x^3 + 1
|
||||
{9, 7, 1}, // x^800 + x^9 + x^7 + x + 1
|
||||
{14, 3, 2}, // x^808 + x^14 + x^3 + x^2 + 1
|
||||
{11, 8, 2}, // x^816 + x^11 + x^8 + x^2 + 1
|
||||
{11, 6, 4}, // x^824 + x^11 + x^6 + x^4 + 1
|
||||
{13, 5, 2}, // x^832 + x^13 + x^5 + x^2 + 1
|
||||
{11, 5, 1}, // x^840 + x^11 + x^5 + x + 1
|
||||
{11, 4, 1}, // x^848 + x^11 + x^4 + x + 1
|
||||
{19, 10, 3}, // x^856 + x^19 + x^10 + x^3 + 1
|
||||
{21, 10, 6}, // x^864 + x^21 + x^10 + x^6 + 1
|
||||
{13, 3, 1}, // x^872 + x^13 + x^3 + x + 1
|
||||
{15, 7, 5}, // x^880 + x^15 + x^7 + x^5 + 1
|
||||
{19, 18, 10}, // x^888 + x^19 + x^18 + x^10 + 1
|
||||
{7, 5, 3}, // x^896 + x^7 + x^5 + x^3 + 1
|
||||
{12, 7, 2}, // x^904 + x^12 + x^7 + x^2 + 1
|
||||
{7, 5, 1}, // x^912 + x^7 + x^5 + x + 1
|
||||
{14, 9, 6}, // x^920 + x^14 + x^9 + x^6 + 1
|
||||
{10, 3, 2}, // x^928 + x^10 + x^3 + x^2 + 1
|
||||
{15, 13, 12}, // x^936 + x^15 + x^13 + x^12 + 1
|
||||
{12, 11, 9}, // x^944 + x^12 + x^11 + x^9 + 1
|
||||
{16, 9, 7}, // x^952 + x^16 + x^9 + x^7 + 1
|
||||
{12, 9, 3}, // x^960 + x^12 + x^9 + x^3 + 1
|
||||
{9, 5, 2}, // x^968 + x^9 + x^5 + x^2 + 1
|
||||
{17, 10, 6}, // x^976 + x^17 + x^10 + x^6 + 1
|
||||
{24, 9, 3}, // x^984 + x^24 + x^9 + x^3 + 1
|
||||
{17, 15, 13}, // x^992 + x^17 + x^15 + x^13 + 1
|
||||
{5, 4, 3}, // x^1000 + x^5 + x^4 + x^3 + 1
|
||||
{19, 17, 8}, // x^1008 + x^19 + x^17 + x^8 + 1
|
||||
{15, 6, 3}, // x^1016 + x^15 + x^6 + x^3 + 1
|
||||
{19, 6, 1}, // x^1024 + x^19 + x^6 + x + 1
|
||||
}
|
||||
|
||||
// f2m, the extention filed over GF(2) of degree m
|
||||
type gf2x struct {
|
||||
poly *big.Int
|
||||
degree int
|
||||
intPool []*big.Int
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
||||
|
||||
// newGF2x return the irred. polynomial of degree deg, where deg must divided by 8.
|
||||
func newGF2x(deg int) *gf2x {
|
||||
poly := big.NewInt(1)
|
||||
poly.SetBit(poly, deg, 1)
|
||||
// poly.SetBit(poly, int(irred_coeff[3*(deg/8-1)+0]), 1)
|
||||
// poly.SetBit(poly, int(irred_coeff[3*(deg/8-1)+1]), 1)
|
||||
// poly.SetBit(poly, int(irred_coeff[3*(deg/8-1)+2]), 1)
|
||||
poly.SetBit(poly, int(irred_coeff[deg/8-1][0]), 1)
|
||||
poly.SetBit(poly, int(irred_coeff[deg/8-1][1]), 1)
|
||||
poly.SetBit(poly, int(irred_coeff[deg/8-1][2]), 1)
|
||||
return &gf2x{
|
||||
poly: poly,
|
||||
degree: deg,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *gf2x) getInt() (r *big.Int) {
|
||||
if len(g.intPool) > 0 {
|
||||
r = g.intPool[len(g.intPool)-1]
|
||||
r.SetInt64(0)
|
||||
g.intPool = g.intPool[:len(g.intPool)-1]
|
||||
return
|
||||
}
|
||||
return new(big.Int)
|
||||
|
||||
}
|
||||
|
||||
func (g *gf2x) putInt(r *big.Int) {
|
||||
g.intPool = append(g.intPool, r)
|
||||
}
|
||||
|
||||
func (g *gf2x) rand(r io.Reader) (*big.Int, error) {
|
||||
for {
|
||||
x, err := rand.Int(r, g.poly)
|
||||
x.SetBit(x, g.degree, 0)
|
||||
if err == nil && x.Sign() != 0 {
|
||||
return x, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, gerrors.WithStack(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *gf2x) add(z, x, y *big.Int) {
|
||||
z.Xor(x, y)
|
||||
}
|
||||
|
||||
// z can't be y, z could be x
|
||||
func (g *gf2x) mul(z, x, y *big.Int) {
|
||||
var yy *big.Int
|
||||
if z == y {
|
||||
yy = g.getInt().Set(y)
|
||||
defer g.putInt(yy)
|
||||
} else {
|
||||
yy = y
|
||||
}
|
||||
|
||||
b := g.getInt()
|
||||
defer g.putInt(b)
|
||||
// note that z may be x, so make b a copy of x
|
||||
b.Set(x)
|
||||
|
||||
if yy.Bit(0) == 1 {
|
||||
// y = 1 + y1*X + y2*X^2 + ...
|
||||
z.Set(b)
|
||||
} else {
|
||||
z.SetInt64(0)
|
||||
}
|
||||
|
||||
for i := 1; i < g.degree; i++ {
|
||||
b.Lsh(b, 1)
|
||||
if b.Bit(g.degree) == 1 {
|
||||
b.Xor(b, g.poly)
|
||||
}
|
||||
if yy.Bit(i) == 1 {
|
||||
z.Xor(z, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var one = new(big.Int).SetInt64(1)
|
||||
|
||||
// extend eudlic algorithm
|
||||
func (f *gf2x) invert(z, x *big.Int) error {
|
||||
u := f.getInt()
|
||||
v := f.getInt()
|
||||
g := f.getInt()
|
||||
h := f.getInt()
|
||||
t := f.getInt()
|
||||
defer func() {
|
||||
f.putInt(u)
|
||||
f.putInt(v)
|
||||
f.putInt(g)
|
||||
f.putInt(h)
|
||||
f.putInt(t)
|
||||
}()
|
||||
|
||||
if x.Sign() == 0 {
|
||||
return gerrors.WithAnnotating(ErrDivideZero, "input x is zero")
|
||||
}
|
||||
u.Set(x)
|
||||
v.Set(f.poly)
|
||||
g.SetInt64(0)
|
||||
h.SetInt64(1)
|
||||
|
||||
// x*h = u mod poly
|
||||
// x*g = v mod poly
|
||||
for u.Cmp(one) != 0 {
|
||||
i := u.BitLen() - v.BitLen()
|
||||
if i < 0 {
|
||||
u, v, h, g = v, u, g, h
|
||||
i = -i
|
||||
}
|
||||
t.Lsh(v, uint(i))
|
||||
u.Xor(u, t)
|
||||
t.Lsh(g, uint(i))
|
||||
h.Xor(h, t)
|
||||
}
|
||||
|
||||
z.Set(h)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
package ssss
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/asn1"
|
||||
"io"
|
||||
"math/big"
|
||||
|
||||
"xdx.jelly/xgcl/gerrors"
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
)
|
||||
|
||||
const MaxSecretLength = 1024 / 8
|
||||
|
||||
// SharedSlice 秘密分片数据结构
|
||||
//
|
||||
// SharedSlice ::= SEQUENCE {
|
||||
// Version INTEGER
|
||||
// Threshold INTEGER
|
||||
// Length INTEGER
|
||||
// Degree INTEGER
|
||||
// X INTEGER
|
||||
// Y INTEGER
|
||||
// Token [0]IMPLICIT OCTET STRING OPTINAL
|
||||
// }
|
||||
type SharedSlice struct {
|
||||
Version int `asn1:"default:0"`
|
||||
Threshold int // 门限
|
||||
Length int // 原秘密消息长度
|
||||
Degree int
|
||||
X int // 分片x值
|
||||
Y *big.Int // 分片f(x)值
|
||||
Token []byte `asn1:"optional,implicit,tag:0"` // Optional 随机值,一个secret的n个分享值相同。
|
||||
}
|
||||
|
||||
// Sharing 秘密分享
|
||||
// secret 待分拆的秘密值,不超过MaxSecretLength字节(64),返回nShares个分享值。
|
||||
// threshold, nShares, (t,n)门限值,例如(3,5)
|
||||
// securityParam, 安全参数,取值128,256,512或1024. 取0则自动适配。如16字节secret对应128.
|
||||
// rand, 随机数Reader
|
||||
//
|
||||
// 注: securityParam取值应不小于len(secret)*8, 若输入的securityParam < len(secret)*8,
|
||||
// 则securityParam自动适配为 (len(secret) + 7)/8)*64
|
||||
// 例: secret为16字节的SM4密钥,(3,5)门限分割
|
||||
//
|
||||
// shares, err := Split(secret, 3,5,0,rand.Reader)
|
||||
// shares为5个share([]byte). 每个share为SharedSlice的ASN.1编码。
|
||||
func Split(secret []byte, threshold, nShares int, securityParam int, rand io.Reader) ([][]byte, error) {
|
||||
if len(secret) > MaxSecretLength {
|
||||
return nil, gerrors.WithAnnotatingf(ErrSecretTooLarge, "secret is limits to %d bytes", MaxSecretLength)
|
||||
}
|
||||
if securityParam < len(secret)*8 {
|
||||
securityParam = len(secret) * 8
|
||||
}
|
||||
|
||||
switch {
|
||||
case securityParam <= 128:
|
||||
securityParam = 128
|
||||
case securityParam <= 256:
|
||||
securityParam = 256
|
||||
case securityParam <= 512:
|
||||
securityParam = 512
|
||||
default:
|
||||
securityParam = 1024
|
||||
}
|
||||
|
||||
f := newGF2x(securityParam)
|
||||
iSecret := new(big.Int).SetBytes(secret)
|
||||
iShares, err := split(rand, threshold, nShares, iSecret, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
shares := make([][]byte, 0, nShares)
|
||||
token := make([]byte, 16)
|
||||
n, err := rand.Read(token)
|
||||
if n < len(token) || err != nil {
|
||||
token = nil
|
||||
}
|
||||
|
||||
for k, v := range iShares {
|
||||
slice := SharedSlice{
|
||||
Version: 0,
|
||||
Threshold: threshold,
|
||||
Length: len(secret),
|
||||
Degree: securityParam,
|
||||
X: k,
|
||||
Y: v,
|
||||
Token: token,
|
||||
}
|
||||
b, err := asn1.Marshal(slice)
|
||||
if err != nil {
|
||||
return nil, gerrors.WithStack(err)
|
||||
}
|
||||
shares = append(shares, b)
|
||||
}
|
||||
return shares, nil
|
||||
}
|
||||
|
||||
// Restore 秘密恢复,输入threshold个秘密分享值,返回 Secret.
|
||||
// tShares 包含至少t个分拆值。否则返回错误。
|
||||
func Restore(tShares [][]byte) ([]byte, error) {
|
||||
iShares := make(map[int]*big.Int)
|
||||
t := -1
|
||||
length := -1
|
||||
var token []byte
|
||||
securityParam := -1
|
||||
for _, s := range tShares {
|
||||
slice := new(SharedSlice)
|
||||
_, err := asn1.Unmarshal(s, slice)
|
||||
if err != nil {
|
||||
return nil, gerrors.ChainErrors(ErrInvalidInput, err)
|
||||
}
|
||||
if t == -1 {
|
||||
t = slice.Threshold
|
||||
} else if t != slice.Threshold {
|
||||
return nil, gerrors.WithAnnotating(ErrBadShares, "share slices are not compatible")
|
||||
}
|
||||
|
||||
if length == -1 {
|
||||
length = slice.Length
|
||||
} else if length != slice.Length {
|
||||
return nil, gerrors.WithAnnotating(ErrBadShares, "share slices are not compatible")
|
||||
}
|
||||
|
||||
if token == nil {
|
||||
token = slice.Token
|
||||
} else if !bytes.Equal(token, slice.Token) {
|
||||
return nil, gerrors.WithAnnotating(ErrBadShares, "share slices are not compatible")
|
||||
}
|
||||
if securityParam == -1 {
|
||||
securityParam = slice.Degree
|
||||
} else if securityParam != slice.Degree {
|
||||
return nil, gerrors.WithAnnotating(ErrBadShares, "share slices are not compatible")
|
||||
}
|
||||
|
||||
if securityParam < slice.Y.BitLen() {
|
||||
return nil, gerrors.WithAnnotating(ErrBadShares, "Share slices are broken")
|
||||
}
|
||||
|
||||
iShares[slice.X] = slice.Y
|
||||
}
|
||||
f := newGF2x(securityParam)
|
||||
iSecret, err := restore(t, iShares, f)
|
||||
if err != nil {
|
||||
return nil, gerrors.ChainErrors(ErrRestoreFailed, err)
|
||||
}
|
||||
secret := make([]byte, length)
|
||||
if length*8 < iSecret.BitLen() {
|
||||
return nil, gerrors.WithAnnotating(ErrBadShares, "Share slices are broken")
|
||||
}
|
||||
if err = gmath.FillBytes(iSecret, secret); err != nil {
|
||||
return nil, gerrors.WithAnnotating(ErrBadShares, "Share slices are broken")
|
||||
}
|
||||
return secret, nil
|
||||
}
|
||||
|
||||
// eval y = f(x), where f(X) = \sigma coeff[i]*X^i + X^t in field f
|
||||
func horner(y, x *big.Int, coeff []*big.Int, f *gf2x) {
|
||||
y.Set(x)
|
||||
for i := len(coeff) - 1; i > 0; i-- {
|
||||
f.add(y, y, coeff[i])
|
||||
f.mul(y, y, x)
|
||||
}
|
||||
f.add(y, y, coeff[0])
|
||||
}
|
||||
|
||||
// return F(1), F(2),...F(n), satisfy deg(F) = t - 1, F(0) = m
|
||||
// m is the secret, deg(m) < f.degree
|
||||
func split(rand io.Reader, t, n int, secret *big.Int, f *gf2x) (map[int]*big.Int, error) {
|
||||
coeff := make([]*big.Int, t)
|
||||
coeff[0] = secret
|
||||
for i := 1; i < t; i++ {
|
||||
if b, err := f.rand(rand); err != nil {
|
||||
return nil, gerrors.WithStack(err)
|
||||
} else {
|
||||
coeff[i] = b
|
||||
}
|
||||
}
|
||||
x := new(big.Int)
|
||||
y := new(big.Int)
|
||||
shares := make(map[int]*big.Int)
|
||||
for i := 1; i <= n; i++ {
|
||||
x.SetInt64(int64(i))
|
||||
horner(y, x, coeff, f)
|
||||
shares[i] = new(big.Int).Set(y)
|
||||
}
|
||||
|
||||
return shares, nil
|
||||
}
|
||||
|
||||
func restore(t int, shares map[int]*big.Int, f *gf2x) (*big.Int, error) {
|
||||
if len(shares) < t {
|
||||
return nil, ErrNeedMoreShares
|
||||
}
|
||||
A := make([][]*big.Int, 0, t)
|
||||
y := make([]*big.Int, 0, t)
|
||||
for i := 0; i < t; i++ {
|
||||
row := make([]*big.Int, 0, t)
|
||||
for j := 0; j < t; j++ {
|
||||
row = append(row, new(big.Int))
|
||||
}
|
||||
A = append(A, row)
|
||||
y = append(y, new(big.Int))
|
||||
}
|
||||
|
||||
X := new(big.Int)
|
||||
i := 0
|
||||
for x, fx := range shares {
|
||||
X.SetInt64(int64(x))
|
||||
A[t-1][i].SetInt64(1)
|
||||
for j := t - 2; j >= 0; j-- {
|
||||
f.mul(A[j][i], A[j+1][i], X)
|
||||
}
|
||||
y[i].Set(fx)
|
||||
f.mul(X, X, A[0][i])
|
||||
f.add(y[i], y[i], X)
|
||||
i++
|
||||
if i >= t {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Now A =
|
||||
1^{t-1} 2^{t-1} ... t^{t-1}
|
||||
...........
|
||||
1^2 2^2 ... t^2
|
||||
1 2 ... t
|
||||
1 1 ... 1
|
||||
and we have
|
||||
(y[0],..., y[t-1]) = (a[0], ..., a[t-1]) * A.
|
||||
|
||||
All need to do is to solve a[0], which is the secret.
|
||||
*/
|
||||
if err := restore_secret(A, y, f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return y[t-1], nil
|
||||
}
|
||||
|
||||
func restore_secret(A [][]*big.Int, y []*big.Int, f *gf2x) error {
|
||||
n := len(A)
|
||||
h := new(big.Int)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
var j int
|
||||
if A[i][i].Sign() == 0 {
|
||||
found := false
|
||||
for j = i + 1; j < n; j++ {
|
||||
if A[i][j].Sign() != 0 {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return ErrSharesMayBeTheSame
|
||||
}
|
||||
for k := i; k < n; k++ {
|
||||
A[k][i], A[k][j] = A[k][j], A[k][i]
|
||||
}
|
||||
y[i], y[j] = y[j], y[i]
|
||||
}
|
||||
for j = i + 1; j < n; j++ {
|
||||
if A[i][j].Sign() != 0 {
|
||||
for k := i + 1; k < n; k++ {
|
||||
f.mul(h, A[k][i], A[i][j])
|
||||
f.mul(A[k][j], A[k][j], A[i][i])
|
||||
f.add(A[k][j], A[k][j], h)
|
||||
}
|
||||
f.mul(h, y[i], A[i][j])
|
||||
f.mul(y[j], y[j], A[i][i])
|
||||
f.add(y[j], y[j], h)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if A[n-1][n-1].Sign() == 0 {
|
||||
return ErrSharesMayBeTheSame
|
||||
}
|
||||
if err := f.invert(h, A[n-1][n-1]); err != nil {
|
||||
return gerrors.ChainErrors(ErrBadShares, err)
|
||||
}
|
||||
f.mul(y[n-1], y[n-1], h)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
package ssss
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"xdx.jelly/xgcl/gmath"
|
||||
)
|
||||
|
||||
func TestSharingASN1(t *testing.T) {
|
||||
threshold := 3
|
||||
n := 5
|
||||
|
||||
// 16字节b需要拆分
|
||||
b := make([]byte, 16)
|
||||
_, _ = io.ReadFull(rand.Reader, b)
|
||||
|
||||
// Shares是n个秘密分片
|
||||
shares, err := Split(b, threshold, n, 0, rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// recoverdShares 凑齐threshold个秘密分片
|
||||
recoverdShares := make([][]byte, 0)
|
||||
i := 0
|
||||
for _, s := range shares {
|
||||
recoverdShares = append(recoverdShares, s)
|
||||
i++
|
||||
if i == threshold {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// recovered是恢复的秘密值
|
||||
recovered, err := Restore(recoverdShares)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, recovered) {
|
||||
t.Fatal("recoverd and secret are different")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharingASN1Fuzz(t *testing.T) {
|
||||
b := make([]byte, 16)
|
||||
for k := 0; k < 1000; k++ {
|
||||
for n := 3; n < 8; n++ {
|
||||
for threshold := 1; threshold <= n; threshold++ {
|
||||
// 16字节b需要拆分
|
||||
_, _ = io.ReadFull(rand.Reader, b)
|
||||
shares, err := Split(b, threshold, n, 0, rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
recoverdShares := make([][]byte, 0)
|
||||
i := 0
|
||||
for _, s := range shares {
|
||||
recoverdShares = append(recoverdShares, s)
|
||||
i++
|
||||
if i == threshold {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
recovered, err := Restore(recoverdShares)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(b, recovered) {
|
||||
t.Fatal("recoverd and secret are different")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldMul(t *testing.T) {
|
||||
|
||||
f := newGF2x(8)
|
||||
var x *big.Int
|
||||
y := new(big.Int)
|
||||
one := new(big.Int).SetInt64(1)
|
||||
|
||||
for k := 0; k < 10000; k++ {
|
||||
x, _ = f.rand(rand.Reader)
|
||||
y.Set(one)
|
||||
for i := 0; i < 1<<8-1; i++ {
|
||||
f.mul(y, y, x)
|
||||
}
|
||||
if y.Cmp(one) != 0 {
|
||||
t.Log("error x:", x.Text(16))
|
||||
t.Fatal("mul error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFieldInvert(t *testing.T) {
|
||||
|
||||
f := newGF2x(8)
|
||||
z := new(big.Int)
|
||||
y := new(big.Int)
|
||||
one := new(big.Int).SetInt64(1)
|
||||
|
||||
for k := 0; k < 10000; k++ {
|
||||
x, _ := f.rand(rand.Reader)
|
||||
if f.invert(z, x) != nil {
|
||||
t.Fatal()
|
||||
}
|
||||
f.mul(y, x, z)
|
||||
if y.Cmp(one) != 0 {
|
||||
t.Fatal("invert error")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestHorner(t *testing.T) {
|
||||
//f(x) = x^2 + x + 2
|
||||
f := newGF2x(64)
|
||||
coeff := []*big.Int{
|
||||
new(big.Int).SetInt64(2),
|
||||
new(big.Int).SetInt64(1),
|
||||
}
|
||||
|
||||
x := new(big.Int).SetInt64(3)
|
||||
|
||||
y := new(big.Int)
|
||||
horner(y, x, coeff, f)
|
||||
if y.Cmp(gmath.BigInt4) != 0 {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharing(t *testing.T) {
|
||||
b := make([]byte, 16)
|
||||
f := newGF2x(128)
|
||||
for k := 0; k < 1000; k++ {
|
||||
// 16字节b需要拆分
|
||||
_, _ = io.ReadFull(rand.Reader, b)
|
||||
// secret, _ := f.rand(rand.Reader)
|
||||
secret := new(big.Int).SetBytes(b)
|
||||
for n := 3; n < 8; n++ {
|
||||
for threshold := 1; threshold <= n; threshold++ {
|
||||
shares, err := split(rand.Reader, threshold, n, secret, f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
recovered, err := restore(threshold, shares, f)
|
||||
if err != nil || recovered.Cmp(secret) != 0 {
|
||||
t.Log("restore secret:", recovered.Text(16))
|
||||
t.Log("secret :", secret.Text(16))
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSigle(t *testing.T) {
|
||||
f := newGF2x(64)
|
||||
secret, _ := f.rand(rand.Reader)
|
||||
threshold := 1
|
||||
n := 5
|
||||
shares, err := split(rand.Reader, threshold, n, secret, f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for k, v := range shares {
|
||||
t.Logf("%d-%s\n", k, v.Text(16))
|
||||
}
|
||||
|
||||
var v0 big.Int
|
||||
for k, v := range shares {
|
||||
v0.SetInt64(int64(k))
|
||||
f.add(&v0, &v0, v)
|
||||
if v0.Cmp(secret) != 0 {
|
||||
t.Fatal()
|
||||
}
|
||||
}
|
||||
|
||||
recovered, err := restore(threshold, shares, f)
|
||||
if err != nil || recovered.Cmp(secret) != 0 {
|
||||
t.Log("restore secret:", recovered.Text(16))
|
||||
t.Log("secret :", secret.Text(16))
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestASN1(t *testing.T) {
|
||||
slice := SharedSlice{
|
||||
Version: 0,
|
||||
Threshold: 3,
|
||||
Length: 16,
|
||||
X: 1,
|
||||
Y: new(big.Int).SetUint64(16),
|
||||
Token: make([]byte, 16),
|
||||
}
|
||||
b, err := asn1.Marshal(slice)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Printf("%x\n", b)
|
||||
|
||||
slice2 := new(SharedSlice)
|
||||
_, err = asn1.Unmarshal(b, slice2)
|
||||
fmt.Println(err, slice2)
|
||||
}
|
||||
Reference in New Issue
Block a user