mirror of https://gogs.blitter.com/RLabs/xs
136 lines
3.2 KiB
Go
136 lines
3.2 KiB
Go
// error_correction.go - NewHope key exchange error correction.
|
|
//
|
|
// To the extent possible under law, Yawning Angel has waived all copyright
|
|
// and related or neighboring rights to newhope, using the Creative
|
|
// Commons "CC0" public domain dedication. See LICENSE or
|
|
// <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
|
|
|
|
package newhope
|
|
|
|
import "blitter.com/go/chacha20"
|
|
|
|
func abs(v int32) int32 {
|
|
mask := v >> 31
|
|
return (v ^ mask) - mask
|
|
}
|
|
|
|
func f(v0, v1 *int32, x int32) int32 {
|
|
// The`ref` code uses uint32 for x, but none of the values ever get large
|
|
// enough for that, and that would be cast-tastic due to Go being Go.
|
|
|
|
// Next 6 lines compute t = x/PARAM_Q
|
|
b := x * 2730
|
|
t := b >> 25
|
|
b = x - t*paramQ
|
|
b = (paramQ - 1) - b
|
|
b >>= 31
|
|
t -= b
|
|
|
|
r := t & 1
|
|
xit := t >> 1
|
|
*v0 = xit + r // v0 = round(x/(2*PARAM_Q))
|
|
|
|
t--
|
|
r = t & 1
|
|
*v1 = (t >> 1) + r
|
|
|
|
return abs(x - ((*v0) * 2 * paramQ))
|
|
}
|
|
|
|
func g(x int32) int32 {
|
|
// Next 6 lines compute t = x/(4 *PARAMQ)
|
|
b := x * 2730
|
|
t := b >> 27
|
|
b = x - t*(paramQ*4)
|
|
b = (paramQ * 4) - b
|
|
b >>= 31
|
|
t -= b
|
|
|
|
c := t & 1
|
|
t = (t >> 1) + c // t = round(x/(8*PARAM_Q))
|
|
|
|
t *= 8 * paramQ
|
|
|
|
return abs(t - x)
|
|
}
|
|
|
|
func llDecode(xi0, xi1, xi2, xi3 int32) int16 {
|
|
t := g(xi0)
|
|
t += g(xi1)
|
|
t += g(xi2)
|
|
t += g(xi3)
|
|
|
|
t -= 8 * paramQ
|
|
t >>= 31
|
|
return int16(t & 1)
|
|
}
|
|
|
|
func (c *poly) helpRec(v *poly, seed *[SeedBytes]byte, nonce byte) {
|
|
var v0, v1, vTmp [4]int32
|
|
var k int32
|
|
var rand [32]byte
|
|
var n [8]byte
|
|
|
|
n[7] = nonce
|
|
|
|
stream, err := chacha20.New(seed[:], n[:])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
stream.KeyStream(rand[:])
|
|
stream.Reset()
|
|
defer memwipe(rand[:])
|
|
|
|
for i := uint(0); i < 256; i++ {
|
|
rBit := int32((rand[i>>3] >> (i & 7)) & 1)
|
|
|
|
vTmp[0], vTmp[1], vTmp[2], vTmp[3] = int32(v.coeffs[i]), int32(v.coeffs[256+i]), int32(v.coeffs[512+i]), int32(v.coeffs[768+i])
|
|
|
|
// newhope-20151209 - New version of the reconciliation.
|
|
k = f(&v0[0], &v1[0], 8*vTmp[0]+4*rBit)
|
|
k += f(&v0[1], &v1[1], 8*vTmp[1]+4*rBit)
|
|
k += f(&v0[2], &v1[2], 8*vTmp[2]+4*rBit)
|
|
k += f(&v0[3], &v1[3], 8*vTmp[3]+4*rBit)
|
|
|
|
k = (2*paramQ - 1 - k) >> 31
|
|
|
|
vTmp[0] = ((^k) & v0[0]) ^ (k & v1[0])
|
|
vTmp[1] = ((^k) & v0[1]) ^ (k & v1[1])
|
|
vTmp[2] = ((^k) & v0[2]) ^ (k & v1[2])
|
|
vTmp[3] = ((^k) & v0[3]) ^ (k & v1[3])
|
|
|
|
c.coeffs[0+i] = uint16((vTmp[0] - vTmp[3]) & 3)
|
|
c.coeffs[256+i] = uint16((vTmp[1] - vTmp[3]) & 3)
|
|
c.coeffs[512+i] = uint16((vTmp[2] - vTmp[3]) & 3)
|
|
c.coeffs[768+i] = uint16((-k + 2*vTmp[3]) & 3)
|
|
}
|
|
|
|
for i := range vTmp {
|
|
vTmp[i] = 0
|
|
}
|
|
}
|
|
|
|
func rec(key *[32]byte, v, c *poly) {
|
|
var tmp, vTmp, cTmp [4]int32
|
|
for i := range key {
|
|
key[i] = 0
|
|
}
|
|
|
|
for i := uint(0); i < 256; i++ {
|
|
vTmp[0], vTmp[1], vTmp[2], vTmp[3] = int32(v.coeffs[i]), int32(v.coeffs[256+i]), int32(v.coeffs[512+i]), int32(v.coeffs[768+i])
|
|
cTmp[0], cTmp[1], cTmp[2], cTmp[3] = int32(c.coeffs[i]), int32(c.coeffs[256+i]), int32(c.coeffs[512+i]), int32(c.coeffs[768+i])
|
|
tmp[0] = 16*paramQ + 8*vTmp[0] - paramQ*(2*cTmp[0]+cTmp[3])
|
|
tmp[1] = 16*paramQ + 8*vTmp[1] - paramQ*(2*cTmp[1]+cTmp[3])
|
|
tmp[2] = 16*paramQ + 8*vTmp[2] - paramQ*(2*cTmp[2]+cTmp[3])
|
|
tmp[3] = 16*paramQ + 8*vTmp[3] - paramQ*(cTmp[3])
|
|
|
|
key[i>>3] |= byte(llDecode(tmp[0], tmp[1], tmp[2], tmp[3]) << (i & 7))
|
|
}
|
|
|
|
for i := 0; i < 4; i++ {
|
|
tmp[i] = 0
|
|
vTmp[i] = 0
|
|
cTmp[i] = 0
|
|
}
|
|
}
|