Commit df5b9d80 authored by Nadim Kobeissi's avatar Nadim Kobeissi 💾
Browse files

Add code documentation

parent 58e8c60e
......@@ -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])
......@@ -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
......@@ -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)
......@@ -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))
......@@ -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))
......
......@@ -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
......@@ -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)
......@@ -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)
......@@ -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)
......@@ -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)
......
......@@ -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]...))
......@@ -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]...))
......@@ -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]...))
......
......@@ -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
......@@ -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
......@@ -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,
......
......@@ -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
......@@ -4,21 +4,16 @@
package kyberk2so
type poly [paramsPolyBytes]int16
type polyvec []poly
func polyvecNew(paramsK int) polyvec {
var pv polyvec = make([]poly, paramsK)
return pv
}
// polyCompress lossily compresses and subsequently serializes a polynomial.
func polyCompress(a poly, paramsK int) []byte {
t := make([]byte, 8)
a = polyCSubQ(a)
rr := 0
switch paramsK {
case 2:
r := make([]byte, paramsPolyCompressedBytesK2)
r := make([]byte, paramsPolyCompressedBytesK512)
for i := 0; i < paramsN/8; i++ {
for j := 0; j < 8; j++ {
t[j] = byte(((uint16(a[8*i+j])<<3)+uint16(paramsQ)/2)/uint16(paramsQ)) & 7
......@@ -30,7 +25,7 @@ func polyCompress(a poly, paramsK int) []byte {
}
return r
case 3:
r := make([]byte, paramsPolyCompressedBytesK3)
r := make([]byte, paramsPolyCompressedBytesK768)
for i := 0; i < paramsN/8; i++ {
for j := 0; j < 8; j++ {
t[j] = byte(((uint16(a[8*i+j])<<4)+uint16(paramsQ/2))/uint16(paramsQ)) & 15
......@@ -43,7 +38,7 @@ func polyCompress(a poly, paramsK int) []byte {
}
return r
default:
r := make([]byte, paramsPolyCompressedBytesK4)
r := make([]byte, paramsPolyCompressedBytesK1024)
for i := 0; i < paramsN/8; i++ {
for j := 0; j < 8; j++ {
t[j] = byte(((uint32(a[8*i+j])<<5)+uint32(paramsQ/2))/uint32(paramsQ)) & 31
......@@ -59,6 +54,10 @@ func polyCompress(a poly, paramsK int) []byte {
}
}
// polyDecompress de-serializes and subsequently decompresses a polynomial,
// representing the approximate inverse of polyCompress.
// Note that compression is lossy, and thus decompression will not match the
// original input.
func polyDecompress(a []byte, paramsK int) poly {
var r poly
t := make([]byte, 8)
......@@ -104,6 +103,7 @@ func polyDecompress(a []byte, paramsK int) poly {
return r
}
// polyToBytes serializes a polynomial into an array of bytes.
func polyToBytes(a poly) []byte {
var t0, t1 uint16
r := make([]byte, paramsPolyBytes)
......@@ -118,6 +118,8 @@ func polyToBytes(a poly) []byte {
return r
}
// polyFromBytes de-serialises an array of bytes into a polynomial,
// and represents the inverse of polyToBytes.
func polyFromBytes(a []byte) poly {
var r poly
for i := 0; i < paramsN/2; i++ {
......@@ -127,6 +129,7 @@ func polyFromBytes(a []byte) poly {
return r
}
// polyFromMsg converts a 32-byte message to a polynomial.
func polyFromMsg(msg []byte) poly {
var r poly
var mask int16
......@@ -139,6 +142,8 @@ func polyFromMsg(msg []byte) poly {
return r
}
// polyToMsg converts a polynomial to a 32-byte message
// and represents the inverse of polyFromMsg.
func polyToMsg(a poly) []byte {
msg := make([]byte, paramsSymBytes)
var t uint16
......@@ -153,20 +158,31 @@ func polyToMsg(a poly) []byte {
return msg
}
// polyGetNoise samples a polynomial deterministically from a seed
// and nonce, with the output polynomial being close to a centered
// binomial distribution with parameter paramsETA = 2.
func polyGetNoise(seed []byte, nonce byte) poly {
l := paramsETA * paramsN / 4
p := indcpaPrf(l, seed, nonce)
return byteopsCbd(p)
}
// polyNtt computes a negacyclic number-theoretic transform (NTT) of
// a polynomial in-place; the input is assumed to be in normal order,
// while the output is in bit-reversed order.
func polyNtt(r poly) poly {
return polyReduce(ntt(r))
}
// polyInvNttToMont computes the inverse of a negacyclic number-theoretic
// transform (NTT) of a polynomial in-place; the input is assumed to be in
// bit-reversed order, while the output is in normal order.
func polyInvNttToMont(r poly) poly {
return nttInv(r)
}
// polyBaseMulMontgomery performs the multiplication of two polynomials
// in the number-theoretic transform (NTT) domain.
func polyBaseMulMontgomery(a poly, b poly) poly {
for i := 0; i < paramsN/4; i++ {
rx := nttBaseMul(
......@@ -187,6 +203,8 @@ func polyBaseMulMontgomery(a poly, b poly) poly {
return a
}
// polyToMont performs the in-place conversion of all coefficients
// of a polynomial from the normal domain to the Montgomery domain.
func polyToMont(r poly) poly {
var f int16 = int16((uint64(1) << 32) % uint64(paramsQ))
for i := 0; i < paramsN; i++ {
......@@ -195,6 +213,7 @@ func polyToMont(r poly) poly {
return r
}
// polyReduce applies Barrett reduction to all coefficients of a polynomial.
func polyReduce(r poly) poly {
for i := 0; i < paramsN; i++ {
r[i] = byteopsBarrettReduce(r[i])
......@@ -202,6 +221,8 @@ func polyReduce(r poly) poly {
return r
}
// polyCSubQ applies the conditional subtraction of `Q` to each coefficient
// of a polynomial.
func polyCSubQ(r poly) poly {
for i := 0; i < paramsN; i++ {
r[i] = byteopsCSubQ(r[i])
......@@ -209,6 +230,7 @@ func polyCSubQ(r poly) poly {
return r
}
// polyAdd adds two polynomials.
func polyAdd(a poly, b poly) poly {
for i := 0; i < paramsN; i++ {
a[i] = a[i] + b[i]
......@@ -216,6 +238,7 @@ func polyAdd(a poly, b poly) poly {
return a
}
// polySub subtracts two polynomials.
func polySub(a poly, b poly) poly {
for i := 0; i < paramsN; i++ {
a[i] = a[i] - b[i]
......@@ -223,17 +246,24 @@ func polySub(a poly, b poly) poly {
return a
}
// polyvecNew instantiates a new vector of polynomials.
func polyvecNew(paramsK int) polyvec {
var pv polyvec = make([]poly, paramsK)
return pv
}
// polyvecCompress lossily compresses and serializes a vector of polynomials.
func polyvecCompress(a polyvec, paramsK int) []byte {
var r []byte
polyvecCSubQ(a, paramsK)
rr := 0
switch paramsK {
case 2:
r = make([]byte, paramsPolyvecCompressedBytesK2)
r = make([]byte, paramsPolyvecCompressedBytesK512)
case 3:
r = make([]byte, paramsPolyvecCompressedBytesK3)
r = make([]byte, paramsPolyvecCompressedBytesK768)
case 4:
r = make([]byte, paramsPolyvecCompressedBytesK4)
r = make([]byte, paramsPolyvecCompressedBytesK1024)
}
switch paramsK {
case 2, 3:
......@@ -277,6 +307,9 @@ func polyvecCompress(a polyvec, paramsK int) []byte {
}
}
// polyvecDecompress de-serializes and decompresses a vector of polynomials and
// represents the approximate inverse of polyvecCompress. Since compression is lossy,
// the results of decompression will may not match the original vector of polynomials.
func polyvecDecompress(a []byte, paramsK int) polyvec {
r := polyvecNew(paramsK)
aa := 0
......@@ -317,6 +350,7 @@ func polyvecDecompress(a []byte, paramsK int) polyvec {
return r
}
// polyvecToBytes serializes a vector of polynomials.
func polyvecToBytes(a polyvec, paramsK int) []byte {
r := []byte{}
for i := 0; i < paramsK; i++ {
......@@ -325,6 +359,7 @@ func polyvecToBytes(a polyvec, paramsK int) []byte {
return r
}
// polyvecFromBytes deserializes a vector of polynomials.
func polyvecFromBytes(a []byte, paramsK int) polyvec {
r := polyvecNew(paramsK)
for i := 0; i < paramsK; i++ {
......@@ -335,18 +370,25 @@ func polyvecFromBytes(a []byte, paramsK int) polyvec {
return r
}
// polyvecNtt applies forward number-theoretic transforms (NTT)
// to all elements of a vector of polynomials.
func polyvecNtt(r polyvec, paramsK int) {
for i := 0; i < paramsK; i++ {
r[i] = polyNtt(r[i])
}
}
// polyvecInvNttToMont applies the inverse number-theoretic transform (NTT)
// to all elements of a vector of polynomials and multiplies by Montgomery
// factor `2^16`.
func polyvecInvNttToMont(r polyvec, paramsK int) {
for i := 0; i < paramsK; i++ {
r[i] = polyInvNttToMont(r[i])
}
}
// polyvecPointWiseAccMontgomery pointwise-multiplies elements of polynomial-vectors
// `a` and `b`, accumulates the results into `r`, and then multiplies by `2^-16`.
func polyvecPointWiseAccMontgomery(a polyvec, b polyvec, paramsK int) poly {
r := polyBaseMulMontgomery(a[0], b[0])
for i := 1; i < paramsK; i++ {
......@@ -356,18 +398,23 @@ func polyvecPointWiseAccMontgomery(a polyvec, b polyvec, paramsK int) poly {
return polyReduce(r)
}
// polyvecReduce applies Barrett reduction to each coefficient of each element
// of a vector of polynomials.
func polyvecReduce(r polyvec, paramsK int) {
for i := 0; i < paramsK; i++ {
r[i] = polyReduce(r[i])
}
}
// polyvecCSubQ applies the conditional subtraction of `Q` to each coefficient
// of each element of a vector of polynomials.
func polyvecCSubQ(r polyvec, paramsK int) {
for i := 0; i < paramsK; i++ {
r[i] = polyCSubQ(r[i])
}
}
// polyvecAdd adds two vectors of polynomials.
func polyvecAdd(a polyvec, b polyvec, paramsK int) {
for i := 0; i < paramsK; i++ {
a[i] = polyAdd(a[i], b[i])
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment