// Pick a uint32 uniformly at random func randUint32() uint32 { return random.Uint32(random.Stream) }
func (rh *RandHound) handleR1(r1 WR1) error { msg := &r1.R1 idx := r1.RosterIndex grp := rh.ServerIdxToGroupNum[idx] pos := rh.ServerIdxToGroupIdx[idx] rh.mutex.Lock() defer rh.mutex.Unlock() // Verify R1 message signature if err := verifySchnorr(rh.Suite(), rh.key[grp][pos], msg); err != nil { return err } // Verify that server replied to the correct I1 message if err := verifyMessage(rh.Suite(), rh.i1s[grp], msg.HI1); err != nil { return err } // Record R1 message rh.r1s[idx] = msg // Prepare data for recovery of polynomial commits and verification of shares n := len(msg.EncShare) poly := make([][]byte, n) index := make([]int, n) encShare := make([]abstract.Point, n) encProof := make([]ProofCore, n) for i := 0; i < n; i++ { poly[i] = msg.CommitPoly index[i] = msg.EncShare[i].Pos encShare[i] = msg.EncShare[i].Val encProof[i] = msg.EncShare[i].Proof } // Init PVSS and recover polynomial commits H, _ := rh.Suite().Point().Pick(nil, rh.Suite().Cipher(rh.sid)) pvss := NewPVSS(rh.Suite(), H, rh.threshold[grp]) polyCommit, err := pvss.Commits(poly, index) if err != nil { return err } // Record polynomial commits rh.polyCommit[idx] = polyCommit // Return, if we already committed to secrets previously if len(rh.chosenSecret) > 0 { return nil } // Verify encrypted shares good, _, err := pvss.Verify(H, rh.key[grp], polyCommit, encShare, encProof) if err != nil { return err } // Record valid encrypted shares per secret/server for _, g := range good { if _, ok := rh.secret[idx]; !ok { rh.secret[idx] = make([]int, 0) } rh.secret[idx] = append(rh.secret[idx], msg.EncShare[g].Target) } // Check if there is at least a threshold number of reconstructable secrets // in each group. If yes proceed to the next phase. Note the double-usage // of the threshold which is used to determine if enough valid shares for a // single secret are available and if enough secrets for a given group are // available goodSecret := make(map[int][]int) for i, group := range rh.server { var secret []int for _, server := range group { j := server.RosterIndex if share, ok := rh.secret[j]; ok && rh.threshold[i] <= len(share) { secret = append(secret, j) } } if rh.threshold[i] <= len(secret) { goodSecret[i] = secret } } // Proceed, if there are enough good secrets if len(goodSecret) == rh.groups { // Reset secret for the next phase (see handleR2) rh.secret = make(map[int][]int) // Choose secrets that contribute to collective randomness for i := range rh.server { // Randomly remove some secrets so that a threshold of secrets remains rand := random.Bytes(rh.Suite().Hash().Size(), random.Stream) prng := rh.Suite().Cipher(rand) secret := goodSecret[i] for j := 0; j < len(secret)-rh.threshold[i]; j++ { k := int(random.Uint32(prng) % uint32(len(secret))) secret = append(secret[:k], secret[k+1:]...) } rh.chosenSecret[i] = secret } log.Lvlf3("Grouping: %v", rh.group) log.Lvlf3("ChosenSecret: %v", rh.chosenSecret) // Transformation of commitments from int to uint32 to avoid protobuff errors var chosenSecret = make([][]uint32, len(rh.chosenSecret)) for i := range rh.chosenSecret { var l []uint32 for j := range rh.chosenSecret[i] { l = append(l, uint32(rh.chosenSecret[i][j])) } chosenSecret[i] = l } // Prepare a message for each server of a group and send it for i, group := range rh.server { for j, server := range group { // Among the good secrets chosen previously collect all valid // shares, proofs, and polynomial commits intended for the // target server var encShare []Share var polyCommit []abstract.Point for _, k := range rh.chosenSecret[i] { r1 := rh.r1s[k] pc := rh.polyCommit[k] encShare = append(encShare, r1.EncShare[j]) polyCommit = append(polyCommit, pc[j]) } i2 := &I2{ Sig: crypto.SchnorrSig{}, SID: rh.sid, ChosenSecret: chosenSecret, EncShare: encShare, PolyCommit: polyCommit, } if err := signSchnorr(rh.Suite(), rh.Private(), i2); err != nil { return err } rh.i2s[server.RosterIndex] = i2 if err := rh.SendTo(server, i2); err != nil { return err } } } } return nil }