// 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 }
// Verify that this shuffle is a valid shuffle of the specified ciphertexts, // with respect to the given public keys func (s *VerifiableShuffle) Verify(ciphers []*elgamal.CipherText, pks []*elgamal.PubKey, nonce string, position int) error { c1, c2 := elgamal.Unpack(ciphers) shufC1, shufC2 := elgamal.Unpack(s.Shuffled) sumpk := elgamal.SumKeys(pks[position:]) // Check the shuffle proof verifier := shuffle.Verifier(pks[0].Suite, pks[0].Base, sumpk.Key, c1, c2, shufC1, shufC2) err := proof.HashVerify(pks[0].Suite, "ElGamalShuffle"+nonce, verifier, s.ShuffleProof) if err != nil { return err } // Check the decryption proofs for i := range ciphers { err = pks[position].VerifyProof(s.Shuffled[i], s.Decrypted[i].C2, s.DecryptionProofs[i], nonce) if err != nil { return err } } return nil }
func TestShuffle(T *testing.T) { amount := 6 servers := 3 suite := ed25519.NewAES128SHA256Ed25519(true) sks, pks := make([]*elgamal.PriKey, servers), make([]*elgamal.PubKey, servers) // Generate keys for the shuffle servers for i := 0; i < servers; i++ { sks[i], pks[i] = elgamal.GenerateKeyPair(suite) } // Generate random plaintexts, encrypt them all to the sum of all server public keys sumpks := elgamal.SumKeys(pks) points, ciphers := make([]abstract.Point, amount), make([]*elgamal.CipherText, amount) for i := 0; i < amount; i++ { points[i], _ = suite.Point().Pick(nil, suite.Cipher(nil)) ciphers[i] = sumpks.Encrypt(points[i]) } var shuffle *VerifiableShuffle var err error for i := 0; i < servers; i++ { shuffle, err = ShuffleDecrypt(suite, ciphers, pks, sks[i], "nonce", i) if err != nil { T.Fatalf("Failed to create proof: %v", err) } if err = shuffle.Verify(ciphers, pks, "nonce", i); err != nil { T.Fatal("Shuffle verification failed: ", err) } // These are the ones that should be shuffled by the next server ciphers = shuffle.Decrypted } for i := 0; i < amount; i++ { T.Log(str(points[i]), str(shuffle.Decrypted[i].C2)) } }