cloudflared-mirror/vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/cpapke.go

177 lines
4.2 KiB
Go
Raw Normal View History

// Code generated from kyber512/internal/cpapke.go by gen.go
package internal
import (
"github.com/cloudflare/circl/internal/sha3"
"github.com/cloudflare/circl/pke/kyber/internal/common"
)
// A Kyber.CPAPKE private key.
type PrivateKey struct {
sh Vec // NTT(s), normalized
}
// A Kyber.CPAPKE public key.
type PublicKey struct {
rho [32]byte // ρ, the seed for the matrix A
th Vec // NTT(t), normalized
// cached values
aT Mat // the matrix Aᵀ
}
// Packs the private key to buf.
func (sk *PrivateKey) Pack(buf []byte) {
sk.sh.Pack(buf)
}
// Unpacks the private key from buf.
func (sk *PrivateKey) Unpack(buf []byte) {
sk.sh.Unpack(buf)
sk.sh.Normalize()
}
// Packs the public key to buf.
func (pk *PublicKey) Pack(buf []byte) {
pk.th.Pack(buf)
copy(buf[K*common.PolySize:], pk.rho[:])
}
// Unpacks the public key from buf.
func (pk *PublicKey) Unpack(buf []byte) {
pk.th.Unpack(buf)
pk.th.Normalize()
copy(pk.rho[:], buf[K*common.PolySize:])
pk.aT.Derive(&pk.rho, true)
}
// Derives a new Kyber.CPAPKE keypair from the given seed.
func NewKeyFromSeed(seed []byte) (*PublicKey, *PrivateKey) {
var pk PublicKey
var sk PrivateKey
var expandedSeed [64]byte
h := sha3.New512()
_, _ = h.Write(seed)
// This writes hash into expandedSeed. Yes, this is idiomatic Go.
_, _ = h.Read(expandedSeed[:])
copy(pk.rho[:], expandedSeed[:32])
sigma := expandedSeed[32:] // σ, the noise seed
pk.aT.Derive(&pk.rho, false) // Expand ρ to matrix A; we'll transpose later
var eh Vec
sk.sh.DeriveNoise(sigma, 0, Eta1) // Sample secret vector s
sk.sh.NTT()
sk.sh.Normalize()
eh.DeriveNoise(sigma, K, Eta1) // Sample blind e
eh.NTT()
// Next, we compute t = A s + e.
for i := 0; i < K; i++ {
// Note that coefficients of s are bounded by q and those of A
// are bounded by 4.5q and so their product is bounded by 2¹⁵q
// as required for multiplication.
PolyDotHat(&pk.th[i], &pk.aT[i], &sk.sh)
// A and s were not in Montgomery form, so the Montgomery
// multiplications in the inner product added a factor R⁻¹ which
// we'll cancel out now. This will also ensure the coefficients of
// t are bounded in absolute value by q.
pk.th[i].ToMont()
}
pk.th.Add(&pk.th, &eh) // bounded by 8q.
pk.th.Normalize()
pk.aT.Transpose()
return &pk, &sk
}
// Decrypts ciphertext ct meant for private key sk to plaintext pt.
func (sk *PrivateKey) DecryptTo(pt, ct []byte) {
var u Vec
var v, m common.Poly
u.Decompress(ct, DU)
v.Decompress(ct[K*compressedPolySize(DU):], DV)
// Compute m = v - <s, u>
u.NTT()
PolyDotHat(&m, &sk.sh, &u)
m.BarrettReduce()
m.InvNTT()
m.Sub(&v, &m)
m.Normalize()
// Compress polynomial m to original message
m.CompressMessageTo(pt)
}
// Encrypts message pt for the public key to ciphertext ct using randomness
// from seed.
//
// seed has to be of length SeedSize, pt of PlaintextSize and ct of
// CiphertextSize.
func (pk *PublicKey) EncryptTo(ct, pt, seed []byte) {
var rh, e1, u Vec
var e2, v, m common.Poly
// Sample r, e₁ and e₂ from B_η
rh.DeriveNoise(seed, 0, Eta1)
rh.NTT()
rh.BarrettReduce()
e1.DeriveNoise(seed, K, common.Eta2)
e2.DeriveNoise(seed, 2*K, common.Eta2)
// Next we compute u = Aᵀ r + e₁. First Aᵀ.
for i := 0; i < K; i++ {
// Note that coefficients of r are bounded by q and those of Aᵀ
// are bounded by 4.5q and so their product is bounded by 2¹⁵q
// as required for multiplication.
PolyDotHat(&u[i], &pk.aT[i], &rh)
}
u.BarrettReduce()
// Aᵀ and r were not in Montgomery form, so the Montgomery
// multiplications in the inner product added a factor R⁻¹ which
// the InvNTT cancels out.
u.InvNTT()
u.Add(&u, &e1) // u = Aᵀ r + e₁
// Next compute v = <t, r> + e₂ + Decompress_q(m, 1).
PolyDotHat(&v, &pk.th, &rh)
v.BarrettReduce()
v.InvNTT()
m.DecompressMessage(pt)
v.Add(&v, &m)
v.Add(&v, &e2) // v = <t, r> + e₂ + Decompress_q(m, 1)
// Pack ciphertext
u.Normalize()
v.Normalize()
u.CompressTo(ct, DU)
v.CompressTo(ct[K*compressedPolySize(DU):], DV)
}
// Returns whether sk equals other.
func (sk *PrivateKey) Equal(other *PrivateKey) bool {
ret := int16(0)
for i := 0; i < K; i++ {
for j := 0; j < common.N; j++ {
ret |= sk.sh[i][j] ^ other.sh[i][j]
}
}
return ret == 0
}