// ShuffleDecrypt performs a shuffle and partial decyption of the given ciphertexts, producing correctness // proofs in the process func ShuffleDecrypt(suite abstract.Suite, ciphertexts []*elgamal.CipherText, pks []*elgamal.PubKey, sk *elgamal.PriKey, nonce string, position int) (*VerifiableShuffle, error) { amount := len(ciphertexts) if amount == 0 { panic("Can't shuffle 0 ciphertexts") } c1, c2 := elgamal.Unpack(ciphertexts) // The ciphertexts are encrypted against these public keys; it still includes ours // The proof of the shuffle will also be w.r.t. this public key sumpk := elgamal.SumKeys(pks[position:]) // Do the shuffle, create a proof of its correctness shuffledC1, shuffledC2, prover := shuffle.Shuffle(suite, sumpk.Base, sumpk.Key, c1, c2, suite.Cipher(nil)) shuffleProof, err := proof.HashProve(suite, "ElGamalShuffle"+nonce, suite.Cipher(nil), prover) if err != nil { return nil, err } shuffled := elgamal.Pack(shuffledC1, shuffledC2) // Do the partial decryption, create a proof of its correctness decryptionProofs, decrypted := make([][]byte, amount), make([]*elgamal.CipherText, amount) for i := range shuffledC1 { decrypted[i], decryptionProofs[i], err = sk.PartialProofDecrypt(shuffled[i], nonce) if err != nil { return nil, err } } return &VerifiableShuffle{shuffled, decrypted, decryptionProofs, shuffleProof}, nil }
// ProofDecrypt decrypts the specified ciphertext, and include a proof that we did this correctly // (i.e., that the ciphertext was indeed an encryption of the plaintext). func (sk *PriKey) ProofDecrypt(ciphertext *CipherText, nonce string) (abstract.Point, []byte, error) { plaintext := sk.Decrypt(ciphertext) c2m := sk.Suite.Point().Sub(ciphertext.C2, plaintext) predicate := getProofPredicate() secret := map[string]abstract.Secret{"x": sk.Secret} public := map[string]abstract.Point{"h": sk.Key, "g": sk.Base, "c2/m": c2m, "c1": ciphertext.C1} prover := predicate.Prover(sk.Suite, secret, public, nil) proof, err := proof.HashProve(sk.Suite, "ElGamalDecryption"+nonce, sk.Suite.Cipher(nil), prover) return plaintext, proof, err }
func (v *stateVector) addShuffle(suite abstract.Suite, shuf *shuffler, rand abstract.Cipher) error { // Get the previous shuffle state. i := len(v.States) prev := v.States[i-1] X, Y := prev.X, prev.Dec // Compute the new base using the public keys of the remaining // servers. H := suite.Point().Null() for j := i - 1; j < shuf.N; j++ { H = suite.Point().Add(H, shuf.HH[j]) } // Do a key-shuffle. Xbar, Ybar, prover := shuffle.Shuffle(suite, nil, H, X, Y, rand) prf, err := proof.HashProve(suite, "PairShuffle", rand, prover) if err != nil { return err } // Seeded random for the decryption proof. seed := abstract.Sum(suite, prf) prfRand := suite.Cipher(seed) // Scratch space for calculations. zs := suite.Secret() zp := suite.Point() // Peel off a layer of encryption. dec := make([]abstract.Point, len(Xbar)) decPrf := make([]*decryptionProof, len(Xbar)) for j := range Xbar { // Decryption. zp.Mul(Xbar[j], shuf.h) dec[j] = suite.Point().Sub(Ybar[j], zp) // Decryption proof. t := suite.Secret().Pick(rand) T := suite.Point().Mul(Xbar[j], t) c := suite.Secret().Pick(prfRand) s := suite.Secret().Add(t, zs.Mul(c, shuf.h)) decPrf[j] = &decryptionProof{T, s} } // Append the new state to the state vector. state := &shuffleState{H, Xbar, Ybar, dec, prf, decPrf} v.States = append(v.States, state) return nil }
func TestShuffle(suite abstract.Suite, k int, N int) { rand := suite.Cipher(abstract.RandomKey) // Create a "server" private/public keypair h := suite.Scalar().Pick(rand) H := suite.Point().Mul(nil, h) // Create a set of ephemeral "client" keypairs to shuffle c := make([]abstract.Scalar, k) C := make([]abstract.Point, k) // fmt.Println("\nclient keys:") for i := 0; i < k; i++ { c[i] = suite.Scalar().Pick(rand) C[i] = suite.Point().Mul(nil, c[i]) // fmt.Println(" "+C[i].String()) } // ElGamal-encrypt all these keypairs with the "server" key X := make([]abstract.Point, k) Y := make([]abstract.Point, k) r := suite.Scalar() // temporary for i := 0; i < k; i++ { r.Pick(rand) X[i] = suite.Point().Mul(nil, r) Y[i] = suite.Point().Mul(H, r) // ElGamal blinding factor Y[i].Add(Y[i], C[i]) // Encrypted client public key } // Repeat only the actual shuffle portion for test purposes. for i := 0; i < N; i++ { // Do a key-shuffle Xbar, Ybar, prover := Shuffle(suite, nil, H, X, Y, rand) prf, err := proof.HashProve(suite, "PairShuffle", rand, prover) if err != nil { panic("Shuffle proof failed: " + err.Error()) } //fmt.Printf("proof:\n%s\n",hex.Dump(prf)) // Check it verifier := Verifier(suite, nil, H, X, Y, Xbar, Ybar) err = proof.HashVerify(suite, "PairShuffle", verifier, prf) if err != nil { panic("Shuffle verify failed: " + err.Error()) } } }
/* Create a blameProof that the Dealer maliciously constructed a shared secret. * This should be called if verifyShare fails due to the public polynomial * check failing. If it failed for other reasons (such as a bad index) it is not * advised to call this function since the share might actually be valid. * * Arguments * i = the index of the malicious shared secret * gKeyPair = the long term key pair of the insurer of share i * * Return * A blameProof that the Dealer is malicious or nil if an error occurs * An error object denoting the status of the blameProof construction * * TODO: Consider whether it is worthwile to produce some form of blame if * the Dealer gives an invalid index. */ func (p *Deal) blame(i int, gKeyPair *config.KeyPair) (*blameProof, error) { diffieKey := p.suite.Point().Mul(p.pubKey, gKeyPair.Secret) insurerSig := p.sign(i, gKeyPair, sigBlameMsg) choice := make(map[proof.Predicate]int) pred := proof.Rep("D", "x", "P") choice[pred] = 1 rand := p.suite.Cipher(abstract.RandomKey) sval := map[string]abstract.Secret{"x": gKeyPair.Secret} pval := map[string]abstract.Point{"D": diffieKey, "P": p.pubKey} prover := pred.Prover(p.suite, sval, pval, choice) proof, err := proof.HashProve(p.suite, protocolName, rand, prover) if err != nil { return nil, err } return new(blameProof).init(p.suite, diffieKey, proof, insurerSig), nil }
// getCipherText is a helper function that, given the group elements, secrets, and choice, // constructs the proof and ciphertext. func (u *User) getCipherText(data *Data, msgs []abstract.Point, slot int, choice int, secrets map[string]abstract.Secret) (*UserCipherText, error) { var suite = crypto.Suite amount := len(msgs) // Get the statement we will prove pred := GetUserPredicate(amount) proofchoice := map[proof.Predicate]int{pred: choice} // Get the group elements occuring in the statement points := u.getProofPoints(data, msgs, slot) // Prove it and return prover := pred.Prover(suite, secrets, points, proofchoice) prf, err := proof.HashProve(suite, "VerdictUserCipher"+data.Nonce, suite.Cipher(nil), prover) return &UserCipherText{Points: msgs, Proof: prf, Index: u.Index, Slot: slot}, err }
// GetCiphertext constructs a notary ciphertext along with the correctness proof. func (n *Notary) GetCiphertext(data *Data, amount int) (*NotaryCipherText, error) { var suite = crypto.Suite msgs := make([]abstract.Point, amount) // Construct the secret and points secrets := map[string]abstract.Secret{"r_j": n.secretSum} points := map[string]abstract.Point{"R_j": n.commitmentsSum, "g_hat": crypto.Generator} for l := 0; l < amount; l++ { neggl := suite.Point().Neg(data.getGenerator(l)) msgs[l] = suite.Point().Mul(neggl, n.secretSum) points["-g_"+strconv.Itoa(l)] = neggl points["S_j,"+strconv.Itoa(l)] = msgs[l] } // Construct the proof pred := getNotaryPredicate(amount) prover := pred.Prover(suite, secrets, points, nil) prf, err := proof.HashProve(suite, "VerdictNotaryCipher"+data.Nonce, crypto.Suite.Cipher(nil), prover) return &NotaryCipherText{Points: msgs, Proof: prf, Index: n.Index}, err }
func (s *Server) shuffleKeys(_ uint64) { keys := <-s.keyShuffleChan serversLeft := len(s.servers) - s.id Xss := make([][]abstract.Point, serversLeft) Yss := make([][]abstract.Point, serversLeft) for i := range Xss { Xss[i] = make([]abstract.Point, s.totalClients) Yss[i] = make([]abstract.Point, s.totalClients) for j := range Xss[i] { Xss[i][j] = UnmarshalPoint(s.suite, keys.Xss[i+1][j]) Yss[i][j] = UnmarshalPoint(s.suite, keys.Yss[i+1][j]) } } Xbarss := make([][]abstract.Point, serversLeft) Ybarss := make([][]abstract.Point, serversLeft) decss := make([][]abstract.Point, serversLeft) prfs := make([][]byte, serversLeft) var shuffleWG sync.WaitGroup for i := 0; i < serversLeft; i++ { shuffleWG.Add(1) go func(i int, pk abstract.Point) { defer shuffleWG.Done() //only one chunk rand := s.suite.Cipher(abstract.RandomKey) var prover proof.Prover var err error Xbarss[i], Ybarss[i], prover = Shuffle(s.pi, s.g, nil, pk, Xss[i], Yss[i], rand) prfs[i], err = proof.HashProve(s.suite, "PairShuffle", rand, prover) if err != nil { log.Fatal("Shuffle proof failed: " + err.Error()) } var decWG sync.WaitGroup decss[i] = make([]abstract.Point, s.totalClients) for j := range decss[i] { decWG.Add(1) go func(i int, j int) { defer decWG.Done() decss[i][j] = Decrypt(s.g, Xbarss[i][j], Ybarss[i][j], s.sk) }(i, j) } decWG.Wait() }(i, s.nextPks[i]) } shuffleWG.Wait() //whatever is at index 0 belongs to me for i := range decss[0] { s.keys[i] = MarshalPoint(decss[0][i]) } ik := InternalKey{ Xss: make([][][]byte, serversLeft), Yss: make([][][]byte, serversLeft), SId: s.id, Ybarss: make([][][]byte, serversLeft), Proofs: prfs, Keys: make([][]byte, serversLeft), } for i := range ik.Xss { ik.Xss[i] = make([][]byte, s.totalClients) ik.Yss[i] = make([][]byte, s.totalClients) ik.Ybarss[i] = make([][]byte, s.totalClients) for j := range ik.Xss[i] { ik.Xss[i][j] = MarshalPoint(Xbarss[i][j]) if i == 0 { //i == 0 is my point, so don't pass it to next person ik.Yss[i][j] = MarshalPoint(s.g.Point().Base()) } else { ik.Yss[i][j] = MarshalPoint(decss[i][j]) } ik.Ybarss[i][j] = MarshalPoint(Ybarss[i][j]) } ik.Keys[i] = s.nextPksBin[i] } var wg sync.WaitGroup for _, rpcServer := range s.rpcServers { wg.Add(1) go func(rpcServer *rpc.Client) { defer wg.Done() err := rpcServer.Call("Server.ShareServerKeys", &ik, nil) if err != nil { log.Fatal("Failed uploading shuffled and decoded blocks: ", err) } }(rpcServer) } wg.Wait() }
func handleRoundEnd(params map[string]interface{}) { keyList := util.ProtobufDecodePointList(params["keys"].([]byte)) size := len(keyList) byteValList := make([][]byte, size) if _, ok := params["is_start"]; ok { intValList := params["vals"].([]int) // The request is sent by coordinator, deserialize the data part for i := 0; i < len(intValList); i++ { byteValList[i] = util.IntToByte(intValList[i]) } } else { // verify neff shuffle if needed verifyNeffShuffle(params) // deserialize data part byteArr := params["vals"].([]util.ByteArray) for i := 0; i < len(byteArr); i++ { byteValList[i] = byteArr[i].Arr } } rand1 := anonServer.Suite.Cipher([]byte("example")) // Create a public/private keypair (X[mine],x) X := make([]abstract.Point, 1) X[0] = anonServer.PublicKey newKeys := make([]abstract.Point, size) newVals := make([][]byte, size) for i := 0; i < size; i++ { // decrypt the public key newKeys[i] = anonServer.KeyMap[keyList[i].String()] // encrypt the reputation using ElGamal algorithm C := anon.Encrypt(anonServer.Suite, rand1, byteValList[i], anon.Set(X), false) newVals[i] = C } byteNewKeys := util.ProtobufEncodePointList(newKeys) // type is []ByteArr byteNewVals := util.SerializeTwoDimensionArray(newVals) if size <= 1 { // no need to shuffle, just send the package to next server pm := map[string]interface{}{ "keys": byteNewKeys, "vals": byteNewVals, } event := &proto.Event{proto.ROUND_END, pm} util.Send(anonServer.Socket, anonServer.PreviousHop, util.Encode(event)) // reset RoundKey and key map anonServer.Roundkey = anonServer.Suite.Secret().Pick(random.Stream) anonServer.KeyMap = make(map[string]abstract.Point) return } Xori := make([]abstract.Point, len(newVals)) for i := 0; i < size; i++ { Xori[i] = anonServer.Suite.Point().Mul(nil, anonServer.PrivateKey) } byteOri := util.ProtobufEncodePointList(Xori) rand := anonServer.Suite.Cipher(abstract.RandomKey) // *** perform neff shuffle here *** Xbar, Ybar, _, Ytmp, prover := neffShuffle(Xori, newKeys, rand) prf, err := proof.HashProve(anonServer.Suite, "PairShuffle", rand, prover) util.CheckErr(err) // this is the shuffled key finalKeys := convertToOrigin(Ybar, Ytmp) finalVals := rebindReputation(newKeys, newVals, finalKeys) // send data to the next server byteXbar := util.ProtobufEncodePointList(Xbar) byteYbar := util.ProtobufEncodePointList(Ybar) byteFinalKeys := util.ProtobufEncodePointList(finalKeys) byteFinalVals := util.SerializeTwoDimensionArray(finalVals) bytePublicKey, _ := anonServer.PublicKey.MarshalBinary() // prev keys means the key before shuffle pm := map[string]interface{}{ "xbar": byteXbar, "ybar": byteYbar, "keys": byteFinalKeys, "vals": byteFinalVals, "proof": prf, "prev_keys": byteOri, "prev_vals": byteNewKeys, "shuffled": true, "public_key": bytePublicKey, } event := &proto.Event{proto.ROUND_END, pm} util.Send(anonServer.Socket, anonServer.PreviousHop, util.Encode(event)) // reset RoundKey and key map anonServer.Roundkey = anonServer.Suite.Secret().Pick(random.Stream) anonServer.KeyMap = make(map[string]abstract.Point) }
func handleAnnouncement(params map[string]interface{}) { var g abstract.Point = nil keyList := util.ProtobufDecodePointList(params["keys"].([]byte)) valList := params["vals"].([]util.ByteArray) size := len(keyList) if val, ok := params["g"]; ok { // contains g byteG := val.([]byte) g = anonServer.Suite.Point() g.UnmarshalBinary(byteG) g = anonServer.Suite.Point().Mul(g, anonServer.Roundkey) // verify the previous shuffle verifyNeffShuffle(params) } else { g = anonServer.Suite.Point().Mul(nil, anonServer.Roundkey) } X1 := make([]abstract.Point, 1) X1[0] = anonServer.PublicKey newKeys := make([]abstract.Point, size) newVals := make([][]byte, size) for i := 0; i < len(keyList); i++ { // encrypt the public key using modPow newKeys[i] = anonServer.Suite.Point().Mul(keyList[i], anonServer.Roundkey) // decrypt the reputation using ElGamal algorithm MM, err := anon.Decrypt(anonServer.Suite, valList[i].Arr, anon.Set(X1), 0, anonServer.PrivateKey, false) util.CheckErr(err) newVals[i] = MM // update key map anonServer.KeyMap[newKeys[i].String()] = keyList[i] } byteNewKeys := util.ProtobufEncodePointList(newKeys) byteNewVals := util.SerializeTwoDimensionArray(newVals) byteG, err := g.MarshalBinary() util.CheckErr(err) if size <= 1 { // no need to shuffle, just send the package to next server pm := map[string]interface{}{ "keys": byteNewKeys, "vals": byteNewVals, "g": byteG, } event := &proto.Event{proto.ANNOUNCEMENT, pm} util.Send(anonServer.Socket, anonServer.NextHop, util.Encode(event)) return } Xori := make([]abstract.Point, len(newVals)) for i := 0; i < size; i++ { Xori[i] = anonServer.Suite.Point().Mul(nil, anonServer.PrivateKey) } byteOri := util.ProtobufEncodePointList(Xori) rand := anonServer.Suite.Cipher(abstract.RandomKey) // *** perform neff shuffle here *** Xbar, Ybar, _, Ytmp, prover := neffShuffle(Xori, newKeys, rand) prf, err := proof.HashProve(anonServer.Suite, "PairShuffle", rand, prover) util.CheckErr(err) // this is the shuffled key finalKeys := convertToOrigin(Ybar, Ytmp) finalVals := rebindReputation(newKeys, newVals, finalKeys) // send data to the next server byteXbar := util.ProtobufEncodePointList(Xbar) byteYbar := util.ProtobufEncodePointList(Ybar) byteFinalKeys := util.ProtobufEncodePointList(finalKeys) byteFinalVals := util.SerializeTwoDimensionArray(finalVals) bytePublicKey, _ := anonServer.PublicKey.MarshalBinary() // prev keys means the key before shuffle pm := map[string]interface{}{ "xbar": byteXbar, "ybar": byteYbar, "keys": byteFinalKeys, "vals": byteFinalVals, "proof": prf, "prev_keys": byteOri, "prev_vals": byteNewKeys, "shuffled": true, "public_key": bytePublicKey, "g": byteG, } event := &proto.Event{proto.ANNOUNCEMENT, pm} util.Send(anonServer.Socket, anonServer.NextHop, util.Encode(event)) }