mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-29 12:30:04 +00:00
RTG-1339 Support post-quantum hybrid key exchange
Func spec: https://wiki.cfops.it/x/ZcBKHw
This commit is contained in:

committed by
Devin Carr

parent
3e0ff3a771
commit
11cbff4ff7
176
vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/cpapke.go
generated
vendored
Normal file
176
vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/cpapke.go
generated
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
// 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
|
||||
}
|
85
vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/mat.go
generated
vendored
Normal file
85
vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/mat.go
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
// Code generated from kyber512/internal/mat.go by gen.go
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/cloudflare/circl/pke/kyber/internal/common"
|
||||
)
|
||||
|
||||
// A k by k matrix of polynomials.
|
||||
type Mat [K]Vec
|
||||
|
||||
// Expands the given seed to the corresponding matrix A or its transpose Aᵀ.
|
||||
func (m *Mat) Derive(seed *[32]byte, transpose bool) {
|
||||
if !common.DeriveX4Available {
|
||||
if transpose {
|
||||
for i := 0; i < K; i++ {
|
||||
for j := 0; j < K; j++ {
|
||||
m[i][j].DeriveUniform(seed, uint8(i), uint8(j))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < K; i++ {
|
||||
for j := 0; j < K; j++ {
|
||||
m[i][j].DeriveUniform(seed, uint8(j), uint8(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var ps [4]*common.Poly
|
||||
var xs [4]uint8
|
||||
var ys [4]uint8
|
||||
x := uint8(0)
|
||||
y := uint8(0)
|
||||
|
||||
for x != K {
|
||||
idx := 0
|
||||
for ; idx < 4; idx++ {
|
||||
ps[idx] = &m[x][y]
|
||||
|
||||
if transpose {
|
||||
xs[idx] = x
|
||||
ys[idx] = y
|
||||
} else {
|
||||
xs[idx] = y
|
||||
ys[idx] = x
|
||||
}
|
||||
|
||||
y++
|
||||
if y == K {
|
||||
x++
|
||||
y = 0
|
||||
|
||||
if x == K {
|
||||
if idx == 0 {
|
||||
// If there is just one left, then a plain DeriveUniform
|
||||
// is quicker than the X4 variant.
|
||||
ps[0].DeriveUniform(seed, xs[0], ys[0])
|
||||
return
|
||||
}
|
||||
|
||||
for idx++; idx < 4; idx++ {
|
||||
ps[idx] = nil
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
common.PolyDeriveUniformX4(ps, seed, xs, ys)
|
||||
}
|
||||
}
|
||||
|
||||
// Tranposes A in place.
|
||||
func (m *Mat) Transpose() {
|
||||
for i := 0; i < K-1; i++ {
|
||||
for j := i + 1; j < K; j++ {
|
||||
t := m[i][j]
|
||||
m[i][j] = m[j][i]
|
||||
m[j][i] = t
|
||||
}
|
||||
}
|
||||
}
|
21
vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/params.go
generated
vendored
Normal file
21
vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/params.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Code generated from params.templ.go. DO NOT EDIT.
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/cloudflare/circl/pke/kyber/internal/common"
|
||||
)
|
||||
|
||||
const (
|
||||
K = 3
|
||||
Eta1 = 2
|
||||
DU = 10
|
||||
DV = 4
|
||||
PublicKeySize = 32 + K*common.PolySize
|
||||
|
||||
PrivateKeySize = K * common.PolySize
|
||||
|
||||
PlaintextSize = common.PlaintextSize
|
||||
SeedSize = 32
|
||||
CiphertextSize = 1088
|
||||
)
|
125
vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/vec.go
generated
vendored
Normal file
125
vendor/github.com/cloudflare/circl/pke/kyber/kyber768/internal/vec.go
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
// Code generated from kyber512/internal/vec.go by gen.go
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/cloudflare/circl/pke/kyber/internal/common"
|
||||
)
|
||||
|
||||
// A vector of K polynomials
|
||||
type Vec [K]common.Poly
|
||||
|
||||
// Samples v[i] from a centered binomial distribution with given η,
|
||||
// seed and nonce+i.
|
||||
//
|
||||
// Essentially CBD_η(PRF(seed, nonce+i)) from the specification.
|
||||
func (v *Vec) DeriveNoise(seed []byte, nonce uint8, eta int) {
|
||||
for i := 0; i < K; i++ {
|
||||
v[i].DeriveNoise(seed, nonce+uint8(i), eta)
|
||||
}
|
||||
}
|
||||
|
||||
// Sets p to the inner product of a and b using "pointwise" multiplication.
|
||||
//
|
||||
// See MulHat() and NTT() for a description of the multiplication.
|
||||
// Assumes a and b are in Montgomery form. p will be in Montgomery form,
|
||||
// and its coefficients will be bounded in absolute value by 2kq.
|
||||
// If a and b are not in Montgomery form, then the action is the same
|
||||
// as "pointwise" multiplication followed by multiplying by R⁻¹, the inverse
|
||||
// of the Montgomery factor.
|
||||
func PolyDotHat(p *common.Poly, a, b *Vec) {
|
||||
var t common.Poly
|
||||
*p = common.Poly{} // set p to zero
|
||||
for i := 0; i < K; i++ {
|
||||
t.MulHat(&a[i], &b[i])
|
||||
p.Add(&t, p)
|
||||
}
|
||||
}
|
||||
|
||||
// Almost normalizes coefficients in-place.
|
||||
//
|
||||
// Ensures each coefficient is in {0, …, q}.
|
||||
func (v *Vec) BarrettReduce() {
|
||||
for i := 0; i < K; i++ {
|
||||
v[i].BarrettReduce()
|
||||
}
|
||||
}
|
||||
|
||||
// Normalizes coefficients in-place.
|
||||
//
|
||||
// Ensures each coefficient is in {0, …, q-1}.
|
||||
func (v *Vec) Normalize() {
|
||||
for i := 0; i < K; i++ {
|
||||
v[i].Normalize()
|
||||
}
|
||||
}
|
||||
|
||||
// Applies in-place inverse NTT(). See Poly.InvNTT() for assumptions.
|
||||
func (v *Vec) InvNTT() {
|
||||
for i := 0; i < K; i++ {
|
||||
v[i].InvNTT()
|
||||
}
|
||||
}
|
||||
|
||||
// Applies in-place forward NTT(). See Poly.NTT() for assumptions.
|
||||
func (v *Vec) NTT() {
|
||||
for i := 0; i < K; i++ {
|
||||
v[i].NTT()
|
||||
}
|
||||
}
|
||||
|
||||
// Sets v to a + b.
|
||||
func (v *Vec) Add(a, b *Vec) {
|
||||
for i := 0; i < K; i++ {
|
||||
v[i].Add(&a[i], &b[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Packs v into buf, which must be of length K*PolySize.
|
||||
func (v *Vec) Pack(buf []byte) {
|
||||
for i := 0; i < K; i++ {
|
||||
v[i].Pack(buf[common.PolySize*i:])
|
||||
}
|
||||
}
|
||||
|
||||
// Unpacks v from buf which must be of length K*PolySize.
|
||||
func (v *Vec) Unpack(buf []byte) {
|
||||
for i := 0; i < K; i++ {
|
||||
v[i].Unpack(buf[common.PolySize*i:])
|
||||
}
|
||||
}
|
||||
|
||||
// Writes Compress_q(v, d) to m.
|
||||
//
|
||||
// Assumes v is normalized and d is in {3, 4, 5, 10, 11}.
|
||||
func (v *Vec) CompressTo(m []byte, d int) {
|
||||
size := compressedPolySize(d)
|
||||
for i := 0; i < K; i++ {
|
||||
v[i].CompressTo(m[size*i:], d)
|
||||
}
|
||||
}
|
||||
|
||||
// Set v to Decompress_q(m, 1).
|
||||
//
|
||||
// Assumes d is in {3, 4, 5, 10, 11}. v will be normalized.
|
||||
func (v *Vec) Decompress(m []byte, d int) {
|
||||
size := compressedPolySize(d)
|
||||
for i := 0; i < K; i++ {
|
||||
v[i].Decompress(m[size*i:], d)
|
||||
}
|
||||
}
|
||||
|
||||
// ⌈(256 d)/8⌉
|
||||
func compressedPolySize(d int) int {
|
||||
switch d {
|
||||
case 4:
|
||||
return 128
|
||||
case 5:
|
||||
return 160
|
||||
case 10:
|
||||
return 320
|
||||
case 11:
|
||||
return 352
|
||||
}
|
||||
panic("unsupported d")
|
||||
}
|
Reference in New Issue
Block a user