|
| 1 | +// Assumptions and Terminology |
| 2 | +// 1. There are n parties: p_1...p_n |
| 3 | +// 2. Every party has a label and receives a share of the secret key from the core. |
| 4 | +// 3. Elliptic curve E(Z_p) of order q is defined as: y^2=x^3 + ax + b (mod p) |
| 5 | +// where a, b in Z_p and Z_p is the underlying finite field for E. |
| 6 | +// 4. We use Feldman TSS because every party needs to verify the msg from any other party. |
| 7 | + |
| 8 | +package hstmaj |
| 9 | + |
| 10 | +import ( |
| 11 | + "crypto/rand" |
| 12 | + "errors" |
| 13 | + |
| 14 | + "github.com/cloudflare/circl/secretsharing" |
| 15 | + |
| 16 | + "github.com/cloudflare/circl/group" |
| 17 | +) |
| 18 | + |
| 19 | +// Local Sign functions |
| 20 | + |
| 21 | +// During online round, the metals will construct their own signature share upon receiving the message |
| 22 | +// Input: currParty, the local party |
| 23 | +func (currParty *partySign) LocalGenSignatureShare() { |
| 24 | + currParty.sharesig.Share.Mul(currParty.r, currParty.sharesk.Share) |
| 25 | + currParty.sharesig.Share.Add(currParty.sharesig.Share, currParty.hashMSG) |
| 26 | + currParty.sharesig.Share.Mul(currParty.sharesig.Share, currParty.sharekInv.Share) |
| 27 | +} |
| 28 | + |
| 29 | +// Initiate local party parameters for final round of signature generation |
| 30 | +// Input: i, this party index |
| 31 | +// Input: currParty, the local party |
| 32 | +// Input: preSign, the same party with preSign informations |
| 33 | +// Input: myGroup, the group we operate in |
| 34 | +func (currParty *partySign) LocalInit(i uint, myGroup group.Group, preSign partyPreSign) { |
| 35 | + currParty.myGroup = preSign.myGroup |
| 36 | + currParty.index = i |
| 37 | + currParty.sharekInv.ID = i |
| 38 | + currParty.sharekInv.Share = preSign.sharekInv.Share.Copy() |
| 39 | + currParty.r = myGroup.NewScalar() |
| 40 | + currParty.r = preSign.r.Copy() |
| 41 | + currParty.sharesk.ID = i |
| 42 | + currParty.sharesk.Share = myGroup.NewScalar() |
| 43 | + currParty.sharesk.Share.SetUint64(uint64(0)) |
| 44 | + currParty.sharesig.ID = i |
| 45 | + currParty.sharesig.Share = myGroup.NewScalar() |
| 46 | + currParty.sharesig.Share.SetUint64(uint64(0)) |
| 47 | + currParty.hashMSG = myGroup.NewScalar() |
| 48 | +} |
| 49 | + |
| 50 | +// Input: currParty, the local party |
| 51 | +// Input: sssk, the share of secret key |
| 52 | +func (currParty *partySign) Setss(sssk group.Scalar) { |
| 53 | + currParty.sharesk.Share = sssk.Copy() |
| 54 | +} |
| 55 | + |
| 56 | +func (currParty *partySign) SetMSG(hashMSG group.Scalar) { |
| 57 | + currParty.hashMSG = hashMSG.Copy() |
| 58 | +} |
| 59 | + |
| 60 | +// Local Pre computation functions |
| 61 | + |
| 62 | +// Initiate local party parameters for preComputation |
| 63 | +// Input: i, this party index |
| 64 | +// Input: n, the number of parties |
| 65 | +// Input: currParty, the local party |
| 66 | +// Input: myGroup, the group we operate in |
| 67 | +func (currParty *partyPreSign) LocalInit(i, n uint, myGroup group.Group) { |
| 68 | + currParty.index = i |
| 69 | + currParty.myGroup = myGroup |
| 70 | + currParty.sharek.ID = i |
| 71 | + currParty.sharek.Share = myGroup.NewScalar() |
| 72 | + currParty.sharek.Share.SetUint64(uint64(0)) |
| 73 | + currParty.shareb.ID = i |
| 74 | + currParty.shareb.Share = myGroup.NewScalar() |
| 75 | + currParty.shareb.Share.SetUint64(uint64(0)) |
| 76 | + currParty.sharekb.ID = i |
| 77 | + currParty.sharekb.Share = myGroup.NewScalar() |
| 78 | + currParty.sharekb.Share.SetUint64(uint64(0)) |
| 79 | + currParty.sharekInv.ID = i |
| 80 | + currParty.sharekInv.Share = myGroup.NewScalar() |
| 81 | + currParty.sharekInv.Share.SetUint64(uint64(0)) |
| 82 | + currParty.sharekG = myGroup.NewElement() |
| 83 | + currParty.obfCoefks = make([][]group.Element, n) |
| 84 | + currParty.obfCoefbs = make([][]group.Element, n) |
| 85 | +} |
| 86 | + |
| 87 | +// Generate the local party information for nonce k and blinding b, |
| 88 | +// later will be used in Feldman secret sharing to construct shares of the nonce k and k^{-1} |
| 89 | +// Input: t, the threshold parameter |
| 90 | +// Input: n, the number of parties |
| 91 | +// Input: currParty, the local party |
| 92 | +func (currParty *partyPreSign) LocalGenkb(t, n uint) { |
| 93 | + |
| 94 | + // first coefficient of secret polynomial k_i for this party i |
| 95 | + currParty.polyki = currParty.myGroup.RandomNonZeroScalar(rand.Reader) |
| 96 | + vs, err := secretsharing.NewVerifiable(currParty.myGroup, t, n) |
| 97 | + if err != nil { |
| 98 | + panic(err) |
| 99 | + } |
| 100 | + currParty.sski, currParty.obfCoefki = vs.Shard(rand.Reader, currParty.polyki) |
| 101 | + |
| 102 | + // secret polynomial b_i for this party i |
| 103 | + currParty.polybi = currParty.myGroup.RandomNonZeroScalar(rand.Reader) |
| 104 | + vs, err = secretsharing.NewVerifiable(currParty.myGroup, t, n) |
| 105 | + if err != nil { |
| 106 | + panic(err) |
| 107 | + } |
| 108 | + // the shares of polynomial b_i for every single party in the game and the obfuscated coefficient for proving correctness |
| 109 | + currParty.ssbi, currParty.obfCoefbi = vs.Shard(rand.Reader, currParty.polybi) |
| 110 | + |
| 111 | + currParty.sharek = currParty.sski[currParty.index-1] |
| 112 | + currParty.shareb = currParty.ssbi[currParty.index-1] |
| 113 | +} |
| 114 | + |
| 115 | +// Update local shares of k and b |
| 116 | +// Input: t, the threshold parameter |
| 117 | +// Input: n, the number of parties |
| 118 | +// Input: sharekUpdate, update for nonce k share from other party |
| 119 | +// Input: sharebUpdate, update for blinding b share from other party |
| 120 | +// Input: obfCoefk, the obfuscated coefficient (commitment) as for proving correctness of sharekUpdate |
| 121 | +// Input: obfCoefb, the obfuscated coefficient (commitment) as for proving correctness of sharebUpdate |
| 122 | +// Input: currParty, the local party |
| 123 | +// Input: fromIndex, the index of the party who sends this update |
| 124 | +// Output: fromIndex if Feldman check fails, otherwise 0 |
| 125 | +func (currParty *partyPreSign) LocalUpdatekb(t, n uint, sharekUpdate, sharebUpdate secretsharing.Share, obfCoefk, obfCoefb []group.Element, fromIndex uint) uint { |
| 126 | + currParty.sharek.Share.Add(currParty.sharek.Share, sharekUpdate.Share) |
| 127 | + vs, err := secretsharing.NewVerifiable(currParty.myGroup, t, n) |
| 128 | + if err != nil { |
| 129 | + panic(err) |
| 130 | + } |
| 131 | + check := vs.Verify(sharekUpdate, obfCoefk) |
| 132 | + if !check { |
| 133 | + return fromIndex |
| 134 | + } |
| 135 | + |
| 136 | + currParty.shareb.Share.Add(currParty.shareb.Share, sharebUpdate.Share) |
| 137 | + vs, err = secretsharing.NewVerifiable(currParty.myGroup, t, n) |
| 138 | + if err != nil { |
| 139 | + panic(err) |
| 140 | + } |
| 141 | + check = vs.Verify(sharebUpdate, obfCoefb) |
| 142 | + if !check { |
| 143 | + return fromIndex |
| 144 | + } |
| 145 | + |
| 146 | + return 0 |
| 147 | +} |
| 148 | + |
| 149 | +// Compute shares for k*b as sharek*shareb |
| 150 | +// Input: currParty, the local party |
| 151 | +func (currParty *partyPreSign) LocalSharekb() { |
| 152 | + currParty.sharekb.Share.Mul(currParty.sharek.Share, currParty.shareb.Share) |
| 153 | +} |
| 154 | + |
| 155 | +// Compute [sharek]G |
| 156 | +// Input: currParty, the local party |
| 157 | +func (currParty *partyPreSign) LocalkG() { |
| 158 | + currParty.sharekG.MulGen(currParty.sharek.Share) |
| 159 | +} |
| 160 | + |
| 161 | +// Local party as a combiner collects shares for kb and computes kb^{-1} |
| 162 | +// Input: t, the threshold parameter |
| 163 | +// Input: n, the number of parties |
| 164 | +// Input: currParty, the local party |
| 165 | +// Input: shareskb, the shares for kb from other parties |
| 166 | +// Output: kb^{-1} and possible error |
| 167 | +func (currParty *partyPreSign) CombinerCompkbInv(t, n uint, shareskb []secretsharing.Share) (group.Scalar, error) { |
| 168 | + s, err := secretsharing.New(currParty.myGroup, t, n) |
| 169 | + if err != nil { |
| 170 | + panic(err) |
| 171 | + } |
| 172 | + kb, err := s.Recover(shareskb) |
| 173 | + kbInv := currParty.myGroup.NewScalar() |
| 174 | + kbInv.Inv(kb) |
| 175 | + return kbInv, err |
| 176 | +} |
| 177 | + |
| 178 | +// Local party as a combiner collects shares for [sharek]G and computes [k]G |
| 179 | +// Input: t, the threshold parameter |
| 180 | +// Input: n, the number of parties |
| 181 | +// Input: currParty, the local party |
| 182 | +// Input: shareskG, the shares for [k]G from other parties |
| 183 | +// Input: indexes, the indexes for all other parties |
| 184 | +// Output: x coordinate of [k]G and possible error |
| 185 | +func (currParty *partyPreSign) CombinerCompkG(t, n uint, shareskG []group.Element, indexes []group.Scalar) (group.Scalar, error) { |
| 186 | + resultkG, errkG := lagrangeInterpolatePoint(t, currParty.myGroup, shareskG, indexes) |
| 187 | + if errkG != nil { |
| 188 | + return nil, errkG |
| 189 | + } |
| 190 | + |
| 191 | + kGBinary, errBinary := resultkG.MarshalBinary() |
| 192 | + if errBinary != nil { |
| 193 | + panic(errBinary) |
| 194 | + } |
| 195 | + |
| 196 | + xCoor := kGBinary[1 : currParty.myGroup.Params().ScalarLength+1] |
| 197 | + xScalar := currParty.myGroup.NewScalar() |
| 198 | + errBinary = xScalar.UnmarshalBinary(xCoor) |
| 199 | + if errBinary != nil { |
| 200 | + panic(errBinary) |
| 201 | + } |
| 202 | + return xScalar, nil |
| 203 | +} |
| 204 | + |
| 205 | +// Set the x coordinate of [k]G as r |
| 206 | +// Input: currParty, the local party |
| 207 | +// Input: xCoor, the x coordinate of [k]G |
| 208 | +func (currParty *partyPreSign) Setr(xCoor group.Scalar) { |
| 209 | + currParty.r = xCoor.Copy() |
| 210 | +} |
| 211 | + |
| 212 | +// Compute share of k^{-1} as (kb)^{-1}*shareb |
| 213 | +// Input: currParty, the local party |
| 214 | +// Input: kbInv, the (kb)^{-1} |
| 215 | +func (currParty *partyPreSign) LocalSharekInv(kbInv group.Scalar) { |
| 216 | + currParty.kbInv = kbInv.Copy() |
| 217 | + currParty.sharekInv.Share.Mul(currParty.kbInv, currParty.shareb.Share) |
| 218 | +} |
| 219 | + |
| 220 | +// Helper functions |
| 221 | + |
| 222 | +// Check everyone receives the same coefficient for Feldman |
| 223 | +// Input: t, the threshold parameter |
| 224 | +// Input: obfCoefj, the obfuscated coefficient for f_i send to party j |
| 225 | +// Input: obfCoefk, the obfuscated coefficient for f_i send to party k |
| 226 | +// Ouput: true if obfCoefj == obfCoefk, false otherwise. |
| 227 | +func checkObf(t uint, obfCoefj []group.Element, obfCoefk []group.Element) bool { |
| 228 | + check := true |
| 229 | + for i := uint(0); i < t+1; i++ { |
| 230 | + if !(obfCoefj[i].IsEqual(obfCoefk[i])) { |
| 231 | + check = false |
| 232 | + } |
| 233 | + } |
| 234 | + return check |
| 235 | +} |
| 236 | + |
| 237 | +// Lagrange Interpolation of y as element but not scalar |
| 238 | + |
| 239 | +// Input: myGroup, the group we operate in |
| 240 | +// Input: targetIndex, the i |
| 241 | +// Input: currShare, the [y_i]G |
| 242 | +// Input: indexes, the indexes for each party |
| 243 | +// Output: Compute a single [f_i(0)]G |
| 244 | +func lagrangeSinglePoint(myGroup group.Group, targetIndex int, currShare group.Element, indexes []group.Scalar) group.Element { |
| 245 | + // f_i(0) = y_i[G] |
| 246 | + result := currShare.Copy() |
| 247 | + |
| 248 | + // x_i |
| 249 | + targetLabel := (indexes)[targetIndex].Copy() |
| 250 | + |
| 251 | + interValue := myGroup.NewScalar() |
| 252 | + invValue := myGroup.NewScalar() |
| 253 | + |
| 254 | + for k := 0; k < len(indexes); k++ { |
| 255 | + //f_i(0) = f_i(0) * (0-x_k)/(x_i-x_k) |
| 256 | + if k != targetIndex { |
| 257 | + // x_k |
| 258 | + currLabel := (indexes)[k].Copy() |
| 259 | + |
| 260 | + // f_i(0) * (0-x_k) |
| 261 | + interValue.SetUint64(uint64(0)) |
| 262 | + interValue.Sub(interValue, currLabel) |
| 263 | + result.Mul(result, interValue) |
| 264 | + |
| 265 | + // (x_i-x_k) |
| 266 | + invValue.Sub(targetLabel, currLabel) |
| 267 | + invValue.Inv(invValue) |
| 268 | + result.Mul(result, invValue) |
| 269 | + |
| 270 | + } |
| 271 | + } |
| 272 | + return result |
| 273 | +} |
| 274 | + |
| 275 | +// Input: t, the threshold, we need at least t+1 points for Lagrange Interpolation |
| 276 | +// Input: myGroup, the group we operate in |
| 277 | +// Input: ss, the secret shares multiplied by generator G |
| 278 | +// Input: indexes, the indexes for each party |
| 279 | +// Ouput: the re-constructed secret [f(0)]G |
| 280 | +func lagrangeInterpolatePoint(t uint, myGroup group.Group, ss []group.Element, indexes []group.Scalar) (group.Element, error) { |
| 281 | + if uint(len(ss)) < t+1 { |
| 282 | + return nil, errors.New("need at least t+1 points to do Lagrange Interpolation") |
| 283 | + } |
| 284 | + |
| 285 | + secret := myGroup.NewElement() |
| 286 | + for i := 0; i < len(ss); i++ { |
| 287 | + fi := lagrangeSinglePoint(myGroup, i, ss[i], indexes) |
| 288 | + if i == 0 { |
| 289 | + secret.Set(fi) |
| 290 | + } else { |
| 291 | + secret.Add(secret, fi) |
| 292 | + } |
| 293 | + } |
| 294 | + |
| 295 | + return secret, nil |
| 296 | +} |
0 commit comments