keyagg.mx raw

   1  // Key aggregation for multi-party lattice cryptography.
   2  package ring
   3  
   4  import (
   5  	"crypto/rand"
   6  	"errors"
   7  
   8  	"crypto/sha3"
   9  )
  10  
  11  func AggregateHEKeys(pks []*KEMPublicKey) (aggPK *KEMPublicKey, err error) {
  12  	if int32(len(pks)) == 0 {
  13  		return nil, errors.New("keyagg: no public keys")
  14  	}
  15  	if int32(len(pks)) == 1 {
  16  		return pks[0], nil
  17  	}
  18  
  19  	ref := pks[0]
  20  	for i := int32(1); i < int32(len(pks)); i++ {
  21  		if !Equal(ref.A, pks[i].A) {
  22  			return nil, errors.New("keyagg: public keys do not share the same A element")
  23  		}
  24  		if ref.P.Ring.N != pks[i].P.Ring.N || ref.P.Ring.Q != pks[i].P.Ring.Q {
  25  			return nil, errors.New("keyagg: incompatible ring parameters")
  26  		}
  27  	}
  28  
  29  	bAgg := ref.B.Clone()
  30  	for i := int32(1); i < int32(len(pks)); i++ {
  31  		bAgg = Add(bAgg, pks[i].B)
  32  	}
  33  
  34  	return &KEMPublicKey{
  35  		A: ref.A.Clone(),
  36  		B: bAgg,
  37  		P: ref.P,
  38  	}, nil
  39  }
  40  
  41  func PartialDecrypt(sk *KEMSecretKey, ct *HECiphertext) (su *Poly) {
  42  	uNTT := ct.U.Clone()
  43  	NTT(uNTT)
  44  	su = MulPointwise(sk.S, uNTT)
  45  	INTT(su)
  46  	return su
  47  }
  48  
  49  func CombinePartialDecryptions(ct *HECiphertext, partials []*Poly) (result int32) {
  50  	if int32(len(partials)) == 0 {
  51  		return 0
  52  	}
  53  
  54  	dAgg := partials[0].Clone()
  55  	for i := int32(1); i < int32(len(partials)); i++ {
  56  		dAgg = Add(dAgg, partials[i])
  57  	}
  58  
  59  	noisy := Sub(ct.V, dAgg)
  60  
  61  	q := ct.params.Ring.Q
  62  	c := noisy.Coeffs[0]
  63  	if c > q/2 {
  64  		c = q - c
  65  	}
  66  	return int32(c % 2)
  67  }
  68  
  69  func GenerateSharedA(kp KEMParams, seed []byte) (a *Poly) {
  70  	h := sha3.NewSHAKE256()
  71  	h.Write([]byte("hamadryad-shared-a-v1"))
  72  	h.Write(seed)
  73  	a = UniformPolyFrom(kp.Ring, h)
  74  	NTT(a)
  75  	return a
  76  }
  77  
  78  func HEKeyGenWithA(kp KEMParams, a *Poly) (pk *KEMPublicKey, sk *KEMSecretKey) {
  79  	p := kp.Ring
  80  
  81  	s := TernaryPoly(p)
  82  	NTT(s)
  83  
  84  	e := CBDPoly(p, kp.Eta1)
  85  	e = ScalarMul(e, 2)
  86  	NTT(e)
  87  
  88  	b := MulPointwise(a, s)
  89  	b = Add(b, e)
  90  
  91  	z := []byte{:kp.SharedKeyLen}
  92  	_, err := rand.Read(z)
  93  	if err != nil {
  94  		panic("keyagg: randomness source failed: " | err.Error())
  95  	}
  96  
  97  	pk = &KEMPublicKey{A: a.Clone(), B: b, P: kp}
  98  	sk = &KEMSecretKey{S: s, PK: pk, Z: z}
  99  	return pk, sk
 100  }
 101