Skip to content

Commit

Permalink
Add code documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
nadimkobeissi committed Jul 31, 2020
1 parent 58e8c60 commit df5b9d8
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 58 deletions.
12 changes: 11 additions & 1 deletion byteops.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

package kyberk2so

// byteopsLoad32 returns a 32-bit unsigned integer loaded from byte x.
func byteopsLoad32(x []byte) uint32 {
var r uint32
r = uint32(x[0])
Expand All @@ -12,6 +13,9 @@ func byteopsLoad32(x []byte) uint32 {
return r
}

// byteopsCbd computers a polynomial with coefficients distributed
// according to a centered binomial distribution with parameter paramsETA,
// given an array of uniformly random bytes.
func byteopsCbd(buf []byte) poly {
var t, d uint32
var a, b int16
Expand All @@ -22,13 +26,15 @@ func byteopsCbd(buf []byte) poly {
d = d + ((t >> 1) & 0x55555555)
for j := 0; j < 8; j++ {
a = int16((d >> (4*j + 0)) & 0x3)
b = int16((d >> (4*j + 2)) & 0x3)
b = int16((d >> (4*j + paramsETA)) & 0x3)
r[8*i+j] = a - b
}
}
return r
}

// byteopsMontgomeryReduce computes a Montgomery reduction; given
// a 32-bit integer `a`, returns `a * R^-1 mod Q` where `R=2^16`.
func byteopsMontgomeryReduce(a int32) int16 {
u := int16(a * int32(paramsQinv))
t := int32(u) * int32(paramsQ)
Expand All @@ -37,6 +43,9 @@ func byteopsMontgomeryReduce(a int32) int16 {
return int16(t)
}

// byteopsBarrettReduce computes a Barrett reduction; given
// a 16-bit integer `a`, returns a 16-bit integer congruent to
// `a mod Q` in {0,...,Q}.
func byteopsBarrettReduce(a int16) int16 {
var t int16
var v int16 = int16(((uint32(1) << 26) + uint32(paramsQ/2)) / uint32(paramsQ))
Expand All @@ -45,6 +54,7 @@ func byteopsBarrettReduce(a int16) int16 {
return a - t
}

// byteopsCSubQ conditionally subtracts Q from a.
func byteopsCSubQ(a int16) int16 {
a = a - int16(paramsQ)
a = a + ((a >> 15) & int16(paramsQ))
Expand Down
52 changes: 40 additions & 12 deletions indcpa.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,56 +9,72 @@ import (
"golang.org/x/crypto/sha3"
)

// indcpaPackPublicKey serializes the public key as a concatenation of the
// serialized vector of polynomials of the public key, and the public seed
// used to generate the matrix `A`.
func indcpaPackPublicKey(publicKey polyvec, seed []byte, paramsK int) []byte {
return append(polyvecToBytes(publicKey, paramsK), seed...)
}

// indcpaUnpackPublicKey de-serializes the public key from a byte array
// and represents the approximate inverse of indcpaPackPublicKey.
func indcpaUnpackPublicKey(packedPublicKey []byte, paramsK int) (polyvec, []byte) {
switch paramsK {
case 2:
publicKeyPolyvec := polyvecFromBytes(packedPublicKey[:paramsPolyvecBytesK2], paramsK)
seed := packedPublicKey[paramsPolyvecBytesK2:]
publicKeyPolyvec := polyvecFromBytes(packedPublicKey[:paramsPolyvecBytesK512], paramsK)
seed := packedPublicKey[paramsPolyvecBytesK512:]
return publicKeyPolyvec, seed
case 3:
publicKeyPolyvec := polyvecFromBytes(packedPublicKey[:paramsPolyvecBytesK3], paramsK)
seed := packedPublicKey[paramsPolyvecBytesK3:]
publicKeyPolyvec := polyvecFromBytes(packedPublicKey[:paramsPolyvecBytesK768], paramsK)
seed := packedPublicKey[paramsPolyvecBytesK768:]
return publicKeyPolyvec, seed
default:
publicKeyPolyvec := polyvecFromBytes(packedPublicKey[:paramsPolyvecBytesK4], paramsK)
seed := packedPublicKey[paramsPolyvecBytesK4:]
publicKeyPolyvec := polyvecFromBytes(packedPublicKey[:paramsPolyvecBytesK1024], paramsK)
seed := packedPublicKey[paramsPolyvecBytesK1024:]
return publicKeyPolyvec, seed
}
}

// indcpaPackPrivateKey serializes the private key.
func indcpaPackPrivateKey(privateKey polyvec, paramsK int) []byte {
return polyvecToBytes(privateKey, paramsK)
}

// indcpaUnpackPrivateKey de-serializes the private key and represents
// the inverse of indcpaPackPrivateKey.
func indcpaUnpackPrivateKey(packedPrivateKey []byte, paramsK int) polyvec {
return polyvecFromBytes(packedPrivateKey, paramsK)
}

// indcpaPackCiphertext serializes the ciphertext as a concatenation of
// the compressed and serialized vector of polynomials `b` and the
// compressed and serialized polynomial `v`.
func indcpaPackCiphertext(b polyvec, v poly, paramsK int) []byte {
return append(polyvecCompress(b, paramsK), polyCompress(v, paramsK)...)
}

// indcpaUnpackCiphertext de-serializes and decompresses the ciphertext
// from a byte array, and represents the approximate inverse of
// indcpaPackCiphertext.
func indcpaUnpackCiphertext(c []byte, paramsK int) (polyvec, poly) {
switch paramsK {
case 2:
b := polyvecDecompress(c[:paramsPolyvecCompressedBytesK2], paramsK)
v := polyDecompress(c[paramsPolyvecCompressedBytesK2:], paramsK)
b := polyvecDecompress(c[:paramsPolyvecCompressedBytesK512], paramsK)
v := polyDecompress(c[paramsPolyvecCompressedBytesK512:], paramsK)
return b, v
case 3:
b := polyvecDecompress(c[:paramsPolyvecCompressedBytesK3], paramsK)
v := polyDecompress(c[paramsPolyvecCompressedBytesK3:], paramsK)
b := polyvecDecompress(c[:paramsPolyvecCompressedBytesK768], paramsK)
v := polyDecompress(c[paramsPolyvecCompressedBytesK768:], paramsK)
return b, v
default:
b := polyvecDecompress(c[:paramsPolyvecCompressedBytesK4], paramsK)
v := polyDecompress(c[paramsPolyvecCompressedBytesK4:], paramsK)
b := polyvecDecompress(c[:paramsPolyvecCompressedBytesK1024], paramsK)
v := polyDecompress(c[paramsPolyvecCompressedBytesK1024:], paramsK)
return b, v
}
}

// indcpaRejUniform runs rejection sampling on uniform random bytes
// to generate uniform random integers modulo `Q`.
func indcpaRejUniform(buf []byte, bufl int) (poly, int) {
var r poly
var val uint16
Expand All @@ -76,6 +92,9 @@ func indcpaRejUniform(buf []byte, bufl int) (poly, int) {
return r, ctr
}

// indcpaGenMatrix deterministically generates a matrix `A` (or the transpose of `A`)
// from a seed. Entries of the matrix are polynomials that look uniformly random.
// Performs rejection sampling on the output of an extendable-output function (XOF).
func indcpaGenMatrix(seed []byte, transposed bool, paramsK int) ([]polyvec, error) {
r := make([]polyvec, paramsK)
buf := make([]byte, 4*168)
Expand Down Expand Up @@ -115,12 +134,17 @@ func indcpaGenMatrix(seed []byte, transposed bool, paramsK int) ([]polyvec, erro
return r, nil
}

// indcpaPrf provides a pseudo-random function (PRF) which returns
// a byte array of length `l`, using the provided key and nonce
// to instantiate the PRF's underlying hash function.
func indcpaPrf(l int, key []byte, nonce byte) []byte {
hash := make([]byte, l)
sha3.ShakeSum256(hash, append(key, nonce))
return hash
}

// indcpaKeypair generates public and private keys for the CPA-secure
// public-key encryption scheme underlying Kyber.
func indcpaKeypair(paramsK int) ([]byte, []byte, error) {
skpv := polyvecNew(paramsK)
pkpv := polyvecNew(paramsK)
Expand Down Expand Up @@ -161,6 +185,8 @@ func indcpaKeypair(paramsK int) ([]byte, []byte, error) {
return indcpaPackPrivateKey(skpv, paramsK), indcpaPackPublicKey(pkpv, publicSeed, paramsK), nil
}

// indcpaEncrypt is the encryption function of the CPA-secure
// public-key encryption scheme underlying Kyber.
func indcpaEncrypt(m []byte, publicKey []byte, coins []byte, paramsK int) ([]byte, error) {
sp := polyvecNew(paramsK)
ep := polyvecNew(paramsK)
Expand Down Expand Up @@ -189,6 +215,8 @@ func indcpaEncrypt(m []byte, publicKey []byte, coins []byte, paramsK int) ([]byt
return indcpaPackCiphertext(bp, polyReduce(v), paramsK), nil
}

// indcpaDecrypt is the decryption function of the CPA-secure
// public-key encryption scheme underlying Kyber.
func indcpaDecrypt(c []byte, privateKey []byte, paramsK int) []byte {
bp, v := indcpaUnpackCiphertext(c, paramsK)
privateKeyPolyvec := indcpaUnpackPrivateKey(privateKey, paramsK)
Expand Down
18 changes: 9 additions & 9 deletions kem.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ func KemDecrypt512(
const paramsK int = 2
var sharedSecretFixedLength [KyberSSBytes]byte
sharedSecret := make([]byte, KyberSSBytes)
indcpaPrivateKey := privateKey[:paramsIndcpaSecretKeyBytesK2]
pki := paramsIndcpaSecretKeyBytesK2 + paramsIndcpaPublicKeyBytesK2
publicKey := privateKey[paramsIndcpaSecretKeyBytesK2:pki]
indcpaPrivateKey := privateKey[:paramsIndcpaSecretKeyBytesK512]
pki := paramsIndcpaSecretKeyBytesK512 + paramsIndcpaPublicKeyBytesK512
publicKey := privateKey[paramsIndcpaSecretKeyBytesK512:pki]
buf := indcpaDecrypt(ciphertext[:], indcpaPrivateKey, paramsK)
ski := Kyber512SKBytes - 2*paramsSymBytes
kr := sha3.Sum512(append(buf, privateKey[ski:ski+paramsSymBytes]...))
Expand All @@ -212,9 +212,9 @@ func KemDecrypt768(
const paramsK int = 3
var sharedSecretFixedLength [KyberSSBytes]byte
sharedSecret := make([]byte, KyberSSBytes)
indcpaPrivateKey := privateKey[:paramsIndcpaSecretKeyBytesK3]
pki := paramsIndcpaSecretKeyBytesK3 + paramsIndcpaPublicKeyBytesK3
publicKey := privateKey[paramsIndcpaSecretKeyBytesK3:pki]
indcpaPrivateKey := privateKey[:paramsIndcpaSecretKeyBytesK768]
pki := paramsIndcpaSecretKeyBytesK768 + paramsIndcpaPublicKeyBytesK768
publicKey := privateKey[paramsIndcpaSecretKeyBytesK768:pki]
buf := indcpaDecrypt(ciphertext[:], indcpaPrivateKey, paramsK)
ski := Kyber768SKBytes - 2*paramsSymBytes
kr := sha3.Sum512(append(buf, privateKey[ski:ski+paramsSymBytes]...))
Expand All @@ -241,9 +241,9 @@ func KemDecrypt1024(
const paramsK int = 4
var sharedSecretFixedLength [KyberSSBytes]byte
sharedSecret := make([]byte, KyberSSBytes)
indcpaPrivateKey := privateKey[:paramsIndcpaSecretKeyBytesK4]
pki := paramsIndcpaSecretKeyBytesK4 + paramsIndcpaPublicKeyBytesK4
publicKey := privateKey[paramsIndcpaSecretKeyBytesK4:pki]
indcpaPrivateKey := privateKey[:paramsIndcpaSecretKeyBytesK1024]
pki := paramsIndcpaSecretKeyBytesK1024 + paramsIndcpaPublicKeyBytesK1024
publicKey := privateKey[paramsIndcpaSecretKeyBytesK1024:pki]
buf := indcpaDecrypt(ciphertext[:], indcpaPrivateKey, paramsK)
ski := Kyber1024SKBytes - 2*paramsSymBytes
kr := sha3.Sum512(append(buf, privateKey[ski:ski+paramsSymBytes]...))
Expand Down
10 changes: 10 additions & 0 deletions ntt.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,14 @@ var nttZetasInv [128]int16 = [128]int16{
3127, 3042, 1907, 1836, 1517, 359, 758, 1441,
}

// nttFqMul performs multiplication followed by Montgomery reduction
// and returns a 16-bit integer congruent to `a*b*R^{-1} mod Q`.
func nttFqMul(a int16, b int16) int16 {
return byteopsMontgomeryReduce(int32(a) * int32(b))
}

// ntt performs an inplace number-theoretic transform (NTT) in `Rq`.
// The input is in standard order, the output is in bit-reversed order.
func ntt(r poly) poly {
j := 0
k := 1
Expand All @@ -50,6 +54,9 @@ func ntt(r poly) poly {
return r
}

// nttInv performs an inplace inverse number-theoretic transform (NTT)
// in `Rq` and multiplication by Montgomery factor 2^16.
// The input is in bit-reversed order, the output is in standard order.
func nttInv(r poly) poly {
j := 0
k := 0
Expand All @@ -71,6 +78,9 @@ func nttInv(r poly) poly {
return r
}

// nttBaseMul performs the multiplication of polynomials
// in `Zq[X]/(X^2-zeta)`. Used for multiplication of elements
// in `Rq` in the number-theoretic transformation domain.
func nttBaseMul(
a0 int16, a1 int16,
b0 int16, b1 int16,
Expand Down
48 changes: 24 additions & 24 deletions params.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,48 @@ const paramsQinv int = 62209
const paramsETA int = 2
const paramsSymBytes int = 32
const paramsPolyBytes int = 384
const paramsPolyvecBytesK2 int = 2 * paramsPolyBytes
const paramsPolyvecBytesK3 int = 3 * paramsPolyBytes
const paramsPolyvecBytesK4 int = 4 * paramsPolyBytes
const paramsPolyCompressedBytesK2 int = 96
const paramsPolyCompressedBytesK3 int = 128
const paramsPolyCompressedBytesK4 int = 160
const paramsPolyvecCompressedBytesK2 int = 2 * 320
const paramsPolyvecCompressedBytesK3 int = 3 * 320
const paramsPolyvecCompressedBytesK4 int = 4 * 352
const paramsIndcpaPublicKeyBytesK2 int = paramsPolyvecBytesK2 + paramsSymBytes
const paramsIndcpaPublicKeyBytesK3 int = paramsPolyvecBytesK3 + paramsSymBytes
const paramsIndcpaPublicKeyBytesK4 int = paramsPolyvecBytesK4 + paramsSymBytes
const paramsIndcpaSecretKeyBytesK2 int = 2 * paramsPolyBytes
const paramsIndcpaSecretKeyBytesK3 int = 3 * paramsPolyBytes
const paramsIndcpaSecretKeyBytesK4 int = 4 * paramsPolyBytes
const paramsPolyvecBytesK512 int = 2 * paramsPolyBytes
const paramsPolyvecBytesK768 int = 3 * paramsPolyBytes
const paramsPolyvecBytesK1024 int = 4 * paramsPolyBytes
const paramsPolyCompressedBytesK512 int = 96
const paramsPolyCompressedBytesK768 int = 128
const paramsPolyCompressedBytesK1024 int = 160
const paramsPolyvecCompressedBytesK512 int = 2 * 320
const paramsPolyvecCompressedBytesK768 int = 3 * 320
const paramsPolyvecCompressedBytesK1024 int = 4 * 352
const paramsIndcpaPublicKeyBytesK512 int = paramsPolyvecBytesK512 + paramsSymBytes
const paramsIndcpaPublicKeyBytesK768 int = paramsPolyvecBytesK768 + paramsSymBytes
const paramsIndcpaPublicKeyBytesK1024 int = paramsPolyvecBytesK1024 + paramsSymBytes
const paramsIndcpaSecretKeyBytesK512 int = 2 * paramsPolyBytes
const paramsIndcpaSecretKeyBytesK768 int = 3 * paramsPolyBytes
const paramsIndcpaSecretKeyBytesK1024 int = 4 * paramsPolyBytes

// Kyber512SKBytes is a constant representing the byte length of private keys in Kyber-512.
const Kyber512SKBytes int = paramsPolyvecBytesK2 + ((paramsPolyvecBytesK2 + paramsSymBytes) + 2*paramsSymBytes)
const Kyber512SKBytes int = paramsPolyvecBytesK512 + ((paramsPolyvecBytesK512 + paramsSymBytes) + 2*paramsSymBytes)

// Kyber768SKBytes is a constant representing the byte length of private keys in Kyber-768.
const Kyber768SKBytes int = paramsPolyvecBytesK3 + ((paramsPolyvecBytesK3 + paramsSymBytes) + 2*paramsSymBytes)
const Kyber768SKBytes int = paramsPolyvecBytesK768 + ((paramsPolyvecBytesK768 + paramsSymBytes) + 2*paramsSymBytes)

// Kyber1024SKBytes is a constant representing the byte length of private keys in Kyber-1024.
const Kyber1024SKBytes int = paramsPolyvecBytesK4 + ((paramsPolyvecBytesK4 + paramsSymBytes) + 2*paramsSymBytes)
const Kyber1024SKBytes int = paramsPolyvecBytesK1024 + ((paramsPolyvecBytesK1024 + paramsSymBytes) + 2*paramsSymBytes)

// Kyber512PKBytes is a constant representing the byte length of public keys in Kyber-512.
const Kyber512PKBytes int = paramsPolyvecBytesK2 + paramsSymBytes
const Kyber512PKBytes int = paramsPolyvecBytesK512 + paramsSymBytes

// Kyber768PKBytes is a constant representing the byte length of public keys in Kyber-768.
const Kyber768PKBytes int = paramsPolyvecBytesK3 + paramsSymBytes
const Kyber768PKBytes int = paramsPolyvecBytesK768 + paramsSymBytes

// Kyber1024PKBytes is a constant representing the byte length of public keys in Kyber-1024.
const Kyber1024PKBytes int = paramsPolyvecBytesK4 + paramsSymBytes
const Kyber1024PKBytes int = paramsPolyvecBytesK1024 + paramsSymBytes

// Kyber512CTBytes is a constant representing the byte length of ciphertexts in Kyber-512.
const Kyber512CTBytes int = paramsPolyvecCompressedBytesK2 + paramsPolyCompressedBytesK2
const Kyber512CTBytes int = paramsPolyvecCompressedBytesK512 + paramsPolyCompressedBytesK512

// Kyber768CTBytes is a constant representing the byte length of ciphertexts in Kyber-768.
const Kyber768CTBytes int = paramsPolyvecCompressedBytesK3 + paramsPolyCompressedBytesK3
const Kyber768CTBytes int = paramsPolyvecCompressedBytesK768 + paramsPolyCompressedBytesK768

// Kyber1024CTBytes is a constant representing the byte length of ciphertexts in Kyber-1024.
const Kyber1024CTBytes int = paramsPolyvecCompressedBytesK4 + paramsPolyCompressedBytesK4
const Kyber1024CTBytes int = paramsPolyvecCompressedBytesK1024 + paramsPolyCompressedBytesK1024

// KyberSSBytes is a constant representing the byte length of shared secrets in Kyber.
const KyberSSBytes int = 32
Loading

0 comments on commit df5b9d8

Please sign in to comment.