func (tk *ThresholdPublicKey) CombinePartialDecryptionsZKP(shares []*PartialDecryptionZKP) (*big.Int, error) {
	ret := make([]*PartialDecryption, 0)
	for _, share := range shares {
		if share.Verify() {
			ret = append(ret, &share.PartialDecryption)
		}
	}
	return tk.CombinePartialDecryptions(ret)
}
Combines partial decryptions provided by decryption servers and returns
full decrypted message.
Function verifies zero knowledge proofs and filters out all shares that failed
verification.
package paillier
import (
	"crypto/rand"
	"crypto/sha256"
	"errors"
	"io"
	"math/big"
)
type ThresholdPublicKey struct {
	PublicKey
	TotalNumberOfDecryptionServers int
	Threshold                      int
	V                              *big.Int    
	Vi                             []*big.Int  
}
func (tk *ThresholdPublicKey) combineSharesConstant() *big.Int {
	tmp := new(big.Int).Mul(FOUR, new(big.Int).Mul(tk.delta(), tk.delta()))
	return (&big.Int{}).ModInverse(tmp, tk.N)
}
func (tk *ThresholdPublicKey) delta() *big.Int {
	return Factorial(tk.TotalNumberOfDecryptionServers)
}
func (tk *ThresholdPublicKey) verifyPartialDecryptions(shares []*PartialDecryption) error {
	if len(shares) < tk.Threshold {
		return errors.New("Threshold not meet")
	}
	tmp := make(map[int]bool)
	for _, share := range shares {
		tmp[share.Id] = true
	}
	if len(tmp) != len(shares) {
		return errors.New("two shares has been created by the same server")
	}
	return nil
}
func (tk *ThresholdPublicKey) updateLambda(share1, share2 *PartialDecryption, lambda *big.Int) *big.Int {
	num := new(big.Int).Mul(lambda, big.NewInt(int64(-share2.Id)))
	denom := big.NewInt(int64(share1.Id - share2.Id))
	return new(big.Int).Div(num, denom)
}
func (tk *ThresholdPublicKey) computeLambda(share *PartialDecryption, shares []*PartialDecryption) *big.Int {
	lambda := tk.delta()
	for _, share2 := range shares {
		if share2.Id != share.Id {
			lambda = tk.updateLambda(share, share2, lambda)
		}
	}
	return lambda
}
func (tk *ThresholdPublicKey) updateCprime(cprime, lambda *big.Int, share *PartialDecryption) *big.Int {
	twoLambda := new(big.Int).Mul(TWO, lambda)
	ret := tk.exp(share.Decryption, twoLambda, tk.GetNSquare())
	ret = new(big.Int).Mul(cprime, ret)
	return new(big.Int).Mod(ret, tk.GetNSquare())
}
func (tk *ThresholdPublicKey) exp(a, b, c *big.Int) *big.Int {
	if b.Cmp(ZERO) == -1 {  
		ret := new(big.Int).Exp(a, new(big.Int).Neg(b), c)
		return new(big.Int).ModInverse(ret, c)
	}
	return new(big.Int).Exp(a, b, c)
}
func (tk *ThresholdPublicKey) computeDecryption(cprime *big.Int) *big.Int {
	l := L(cprime, tk.N)
	return new(big.Int).Mod(new(big.Int).Mul(tk.combineSharesConstant(), l), tk.N)
}
func (tk *ThresholdPublicKey) CombinePartialDecryptions(shares []*PartialDecryption) (*big.Int, error) {
	if err := tk.verifyPartialDecryptions(shares); err != nil {
		return nil, err
	}
	cprime := ONE
	for _, share := range shares {
		lambda := tk.computeLambda(share, shares)
		cprime = tk.updateCprime(cprime, lambda, share)
	}
	return tk.computeDecryption(cprime), nil
}