@@ -1,262 +1,5 @@ | |||
package sike | |||
// Helpers | |||
// uint128 representation | |||
type uint128 struct { | |||
H, L uint64 | |||
} | |||
func addc64(cin, a, b uint64) (ret, cout uint64) { | |||
ret = cin | |||
ret = ret + a | |||
if ret < a { | |||
cout = 1 | |||
} | |||
ret = ret + b | |||
if ret < b { | |||
cout = 1 | |||
} | |||
return | |||
} | |||
func subc64(bIn, a, b uint64) (ret, bOut uint64) { | |||
tmp := a - bIn | |||
if tmp > a { | |||
bOut = 1 | |||
} | |||
ret = tmp - b | |||
if ret > tmp { | |||
bOut = 1 | |||
} | |||
return | |||
} | |||
func mul64(a, b uint64) (res uint128) { | |||
var al, bl, ah, bh, albl, albh, ahbl, ahbh uint64 | |||
var res1, res2, res3 uint64 | |||
var carry, maskL, maskH, temp uint64 | |||
maskL = (^maskL) >> 32 | |||
maskH = ^maskL | |||
al = a & maskL | |||
ah = a >> 32 | |||
bl = b & maskL | |||
bh = b >> 32 | |||
albl = al * bl | |||
albh = al * bh | |||
ahbl = ah * bl | |||
ahbh = ah * bh | |||
res.L = albl & maskL | |||
res1 = albl >> 32 | |||
res2 = ahbl & maskL | |||
res3 = albh & maskL | |||
temp = res1 + res2 + res3 | |||
carry = temp >> 32 | |||
res.L ^= temp << 32 | |||
res1 = ahbl >> 32 | |||
res2 = albh >> 32 | |||
res3 = ahbh & maskL | |||
temp = res1 + res2 + res3 + carry | |||
res.H = temp & maskL | |||
carry = temp & maskH | |||
res.H ^= (ahbh & maskH) + carry | |||
return | |||
} | |||
// Fp implementation | |||
// Compute z = x + y (mod 2*p). | |||
func fpAddRdc(z, x, y *Fp) { | |||
var carry uint64 | |||
// z=x+y % p503 | |||
for i := 0; i < FP_WORDS; i++ { | |||
z[i], carry = addc64(carry, x[i], y[i]) | |||
} | |||
// z = z - p503x2 | |||
carry = 0 | |||
for i := 0; i < FP_WORDS; i++ { | |||
z[i], carry = subc64(carry, z[i], p503x2[i]) | |||
} | |||
// if z<0 add p503x2 back | |||
mask := uint64(0 - carry) | |||
carry = 0 | |||
for i := 0; i < FP_WORDS; i++ { | |||
z[i], carry = addc64(carry, z[i], p503x2[i]&mask) | |||
} | |||
} | |||
// Compute z = x - y (mod 2*p). | |||
func fpSubRdc(z, x, y *Fp) { | |||
var borrow uint64 | |||
// z = z - p503x2 | |||
for i := 0; i < FP_WORDS; i++ { | |||
z[i], borrow = subc64(borrow, x[i], y[i]) | |||
} | |||
// if z<0 add p503x2 back | |||
mask := uint64(0 - borrow) | |||
borrow = 0 | |||
for i := 0; i < FP_WORDS; i++ { | |||
z[i], borrow = addc64(borrow, z[i], p503x2[i]&mask) | |||
} | |||
} | |||
// Reduce a field element in [0, 2*p) to one in [0,p). | |||
func fpRdcP(x *Fp) { | |||
var borrow, mask uint64 | |||
for i := 0; i < FP_WORDS; i++ { | |||
x[i], borrow = subc64(borrow, x[i], p503[i]) | |||
} | |||
// Sets all bits if borrow = 1 | |||
mask = 0 - borrow | |||
borrow = 0 | |||
for i := 0; i < FP_WORDS; i++ { | |||
x[i], borrow = addc64(borrow, x[i], p503[i]&mask) | |||
} | |||
} | |||
// Implementation doesn't actually depend on a prime field. | |||
func fpSwapCond(x, y *Fp, mask uint8) { | |||
if mask != 0 { | |||
var tmp Fp | |||
copy(tmp[:], y[:]) | |||
copy(y[:], x[:]) | |||
copy(x[:], tmp[:]) | |||
} | |||
} | |||
// Compute z = x * y. | |||
func fpMul(z *FpX2, x, y *Fp) { | |||
var u, v, t uint64 | |||
var carry uint64 | |||
var uv uint128 | |||
for i := uint64(0); i < FP_WORDS; i++ { | |||
for j := uint64(0); j <= i; j++ { | |||
uv = mul64(x[j], y[i-j]) | |||
v, carry = addc64(0, uv.L, v) | |||
u, carry = addc64(carry, uv.H, u) | |||
t += carry | |||
} | |||
z[i] = v | |||
v = u | |||
u = t | |||
t = 0 | |||
} | |||
for i := FP_WORDS; i < (2*FP_WORDS)-1; i++ { | |||
for j := i - FP_WORDS + 1; j < FP_WORDS; j++ { | |||
uv = mul64(x[j], y[i-j]) | |||
v, carry = addc64(0, uv.L, v) | |||
u, carry = addc64(carry, uv.H, u) | |||
t += carry | |||
} | |||
z[i] = v | |||
v = u | |||
u = t | |||
t = 0 | |||
} | |||
z[2*FP_WORDS-1] = v | |||
} | |||
// Perform Montgomery reduction: set z = x R^{-1} (mod 2*p) | |||
// with R=2^512. Destroys the input value. | |||
func fpMontRdc(z *Fp, x *FpX2) { | |||
var carry, t, u, v uint64 | |||
var uv uint128 | |||
var count int | |||
count = 3 // number of 0 digits in the least significat part of p503 + 1 | |||
for i := 0; i < FP_WORDS; i++ { | |||
for j := 0; j < i; j++ { | |||
if j < (i - count + 1) { | |||
uv = mul64(z[j], p503p1[i-j]) | |||
v, carry = addc64(0, uv.L, v) | |||
u, carry = addc64(carry, uv.H, u) | |||
t += carry | |||
} | |||
} | |||
v, carry = addc64(0, v, x[i]) | |||
u, carry = addc64(carry, u, 0) | |||
t += carry | |||
z[i] = v | |||
v = u | |||
u = t | |||
t = 0 | |||
} | |||
for i := FP_WORDS; i < 2*FP_WORDS-1; i++ { | |||
if count > 0 { | |||
count-- | |||
} | |||
for j := i - FP_WORDS + 1; j < FP_WORDS; j++ { | |||
if j < (FP_WORDS - count) { | |||
uv = mul64(z[j], p503p1[i-j]) | |||
v, carry = addc64(0, uv.L, v) | |||
u, carry = addc64(carry, uv.H, u) | |||
t += carry | |||
} | |||
} | |||
v, carry = addc64(0, v, x[i]) | |||
u, carry = addc64(carry, u, 0) | |||
t += carry | |||
z[i-FP_WORDS] = v | |||
v = u | |||
u = t | |||
t = 0 | |||
} | |||
v, carry = addc64(0, v, x[2*FP_WORDS-1]) | |||
z[FP_WORDS-1] = v | |||
} | |||
// Compute z = x + y, without reducing mod p. | |||
func fp2Add(z, x, y *FpX2) { | |||
var carry uint64 | |||
for i := 0; i < 2*FP_WORDS; i++ { | |||
z[i], carry = addc64(carry, x[i], y[i]) | |||
} | |||
} | |||
// Compute z = x - y, without reducing mod p. | |||
func fp2Sub(z, x, y *FpX2) { | |||
var borrow, mask uint64 | |||
for i := 0; i < 2*FP_WORDS; i++ { | |||
z[i], borrow = subc64(borrow, x[i], y[i]) | |||
} | |||
// Sets all bits if borrow = 1 | |||
mask = 0 - borrow | |||
borrow = 0 | |||
for i := FP_WORDS; i < 2*FP_WORDS; i++ { | |||
z[i], borrow = addc64(borrow, z[i], p503[i-FP_WORDS]&mask) | |||
} | |||
} | |||
// Montgomery multiplication. Input values must be already | |||
// in Montgomery domain. | |||
func fpMulRdc(dest, lhs, rhs *Fp) { | |||
a := lhs // = a*R | |||
b := rhs // = b*R | |||
var ab FpX2 | |||
fpMul(&ab, a, b) // = a*b*R*R | |||
fpMontRdc(dest, &ab) // = a*b*R mod p | |||
} | |||
// Set dest = x^((p-3)/4). If x is square, this is 1/sqrt(x). | |||
// Uses variation of sliding-window algorithm from with window size | |||
// of 5 and least to most significant bit sliding (left-to-right) | |||
@@ -0,0 +1,70 @@ | |||
package sike | |||
// Helpers | |||
// uint128 representation | |||
type uint128 struct { | |||
H, L uint64 | |||
} | |||
func addc64(cin, a, b uint64) (ret, cout uint64) { | |||
ret = cin | |||
ret = ret + a | |||
if ret < a { | |||
cout = 1 | |||
} | |||
ret = ret + b | |||
if ret < b { | |||
cout = 1 | |||
} | |||
return | |||
} | |||
func subc64(bIn, a, b uint64) (ret, bOut uint64) { | |||
tmp := a - bIn | |||
if tmp > a { | |||
bOut = 1 | |||
} | |||
ret = tmp - b | |||
if ret > tmp { | |||
bOut = 1 | |||
} | |||
return | |||
} | |||
func mul64(a, b uint64) (res uint128) { | |||
var al, bl, ah, bh, albl, albh, ahbl, ahbh uint64 | |||
var res1, res2, res3 uint64 | |||
var carry, maskL, maskH, temp uint64 | |||
maskL = (^maskL) >> 32 | |||
maskH = ^maskL | |||
al = a & maskL | |||
ah = a >> 32 | |||
bl = b & maskL | |||
bh = b >> 32 | |||
albl = al * bl | |||
albh = al * bh | |||
ahbl = ah * bl | |||
ahbh = ah * bh | |||
res.L = albl & maskL | |||
res1 = albl >> 32 | |||
res2 = ahbl & maskL | |||
res3 = albh & maskL | |||
temp = res1 + res2 + res3 | |||
carry = temp >> 32 | |||
res.L ^= temp << 32 | |||
res1 = ahbl >> 32 | |||
res2 = albh >> 32 | |||
res3 = ahbh & maskL | |||
temp = res1 + res2 + res3 + carry | |||
res.H = temp & maskL | |||
carry = temp & maskH | |||
res.H ^= (ahbh & maskH) + carry | |||
return | |||
} |
@@ -0,0 +1,189 @@ | |||
package sike | |||
// Fp implementation | |||
// Compute z = x + y (mod 2*p). | |||
func fpAddRdc(z, x, y *Fp) { | |||
var carry uint64 | |||
// z=x+y % p503 | |||
for i := 0; i < FP_WORDS; i++ { | |||
z[i], carry = addc64(carry, x[i], y[i]) | |||
} | |||
// z = z - p503x2 | |||
carry = 0 | |||
for i := 0; i < FP_WORDS; i++ { | |||
z[i], carry = subc64(carry, z[i], p503x2[i]) | |||
} | |||
// if z<0 add p503x2 back | |||
mask := uint64(0 - carry) | |||
carry = 0 | |||
for i := 0; i < FP_WORDS; i++ { | |||
z[i], carry = addc64(carry, z[i], p503x2[i]&mask) | |||
} | |||
} | |||
// Compute z = x - y (mod 2*p). | |||
func fpSubRdc(z, x, y *Fp) { | |||
var borrow uint64 | |||
// z = z - p503x2 | |||
for i := 0; i < FP_WORDS; i++ { | |||
z[i], borrow = subc64(borrow, x[i], y[i]) | |||
} | |||
// if z<0 add p503x2 back | |||
mask := uint64(0 - borrow) | |||
borrow = 0 | |||
for i := 0; i < FP_WORDS; i++ { | |||
z[i], borrow = addc64(borrow, z[i], p503x2[i]&mask) | |||
} | |||
} | |||
// Reduce a field element in [0, 2*p) to one in [0,p). | |||
func fpRdcP(x *Fp) { | |||
var borrow, mask uint64 | |||
for i := 0; i < FP_WORDS; i++ { | |||
x[i], borrow = subc64(borrow, x[i], p503[i]) | |||
} | |||
// Sets all bits if borrow = 1 | |||
mask = 0 - borrow | |||
borrow = 0 | |||
for i := 0; i < FP_WORDS; i++ { | |||
x[i], borrow = addc64(borrow, x[i], p503[i]&mask) | |||
} | |||
} | |||
// Implementation doesn't actually depend on a prime field. | |||
func fpSwapCond(x, y *Fp, mask uint8) { | |||
if mask != 0 { | |||
var tmp Fp | |||
copy(tmp[:], y[:]) | |||
copy(y[:], x[:]) | |||
copy(x[:], tmp[:]) | |||
} | |||
} | |||
// Compute z = x * y. | |||
func fpMul(z *FpX2, x, y *Fp) { | |||
var u, v, t uint64 | |||
var carry uint64 | |||
var uv uint128 | |||
for i := uint64(0); i < FP_WORDS; i++ { | |||
for j := uint64(0); j <= i; j++ { | |||
uv = mul64(x[j], y[i-j]) | |||
v, carry = addc64(0, uv.L, v) | |||
u, carry = addc64(carry, uv.H, u) | |||
t += carry | |||
} | |||
z[i] = v | |||
v = u | |||
u = t | |||
t = 0 | |||
} | |||
for i := FP_WORDS; i < (2*FP_WORDS)-1; i++ { | |||
for j := i - FP_WORDS + 1; j < FP_WORDS; j++ { | |||
uv = mul64(x[j], y[i-j]) | |||
v, carry = addc64(0, uv.L, v) | |||
u, carry = addc64(carry, uv.H, u) | |||
t += carry | |||
} | |||
z[i] = v | |||
v = u | |||
u = t | |||
t = 0 | |||
} | |||
z[2*FP_WORDS-1] = v | |||
} | |||
// Perform Montgomery reduction: set z = x R^{-1} (mod 2*p) | |||
// with R=2^512. Destroys the input value. | |||
func fpMontRdc(z *Fp, x *FpX2) { | |||
var carry, t, u, v uint64 | |||
var uv uint128 | |||
var count int | |||
count = 3 // number of 0 digits in the least significat part of p503 + 1 | |||
for i := 0; i < FP_WORDS; i++ { | |||
for j := 0; j < i; j++ { | |||
if j < (i - count + 1) { | |||
uv = mul64(z[j], p503p1[i-j]) | |||
v, carry = addc64(0, uv.L, v) | |||
u, carry = addc64(carry, uv.H, u) | |||
t += carry | |||
} | |||
} | |||
v, carry = addc64(0, v, x[i]) | |||
u, carry = addc64(carry, u, 0) | |||
t += carry | |||
z[i] = v | |||
v = u | |||
u = t | |||
t = 0 | |||
} | |||
for i := FP_WORDS; i < 2*FP_WORDS-1; i++ { | |||
if count > 0 { | |||
count-- | |||
} | |||
for j := i - FP_WORDS + 1; j < FP_WORDS; j++ { | |||
if j < (FP_WORDS - count) { | |||
uv = mul64(z[j], p503p1[i-j]) | |||
v, carry = addc64(0, uv.L, v) | |||
u, carry = addc64(carry, uv.H, u) | |||
t += carry | |||
} | |||
} | |||
v, carry = addc64(0, v, x[i]) | |||
u, carry = addc64(carry, u, 0) | |||
t += carry | |||
z[i-FP_WORDS] = v | |||
v = u | |||
u = t | |||
t = 0 | |||
} | |||
v, carry = addc64(0, v, x[2*FP_WORDS-1]) | |||
z[FP_WORDS-1] = v | |||
} | |||
// Compute z = x + y, without reducing mod p. | |||
func fp2Add(z, x, y *FpX2) { | |||
var carry uint64 | |||
for i := 0; i < 2*FP_WORDS; i++ { | |||
z[i], carry = addc64(carry, x[i], y[i]) | |||
} | |||
} | |||
// Compute z = x - y, without reducing mod p. | |||
func fp2Sub(z, x, y *FpX2) { | |||
var borrow, mask uint64 | |||
for i := 0; i < 2*FP_WORDS; i++ { | |||
z[i], borrow = subc64(borrow, x[i], y[i]) | |||
} | |||
// Sets all bits if borrow = 1 | |||
mask = 0 - borrow | |||
borrow = 0 | |||
for i := FP_WORDS; i < 2*FP_WORDS; i++ { | |||
z[i], borrow = addc64(borrow, z[i], p503[i-FP_WORDS]&mask) | |||
} | |||
} | |||
// Montgomery multiplication. Input values must be already | |||
// in Montgomery domain. | |||
func fpMulRdc(dest, lhs, rhs *Fp) { | |||
a := lhs // = a*R | |||
b := rhs // = b*R | |||
var ab FpX2 | |||
fpMul(&ab, a, b) // = a*b*R*R | |||
fpMontRdc(dest, &ab) // = a*b*R mod p | |||
} |
@@ -1,10 +1,9 @@ | |||
package sike | |||
import ( | |||
"crypto/hmac" | |||
"crypto/sha256" | |||
"crypto/subtle" | |||
"errors" | |||
"golang.org/x/crypto/sha3" | |||
"io" | |||
) | |||
@@ -16,10 +15,10 @@ var H = []byte{0x01, 0x00} | |||
var F = []byte{0x02, 0x00} | |||
// Generates HMAC-SHA256 sum | |||
func hashMac(out, in, S []byte) { | |||
h := hmac.New(sha256.New, in) | |||
h.Write(S) | |||
copy(out, h.Sum(nil)) | |||
func cshakeSum(out, in, S []byte) { | |||
h := sha3.NewCShake256(nil, S) | |||
h.Write(in) | |||
h.Read(out) | |||
} | |||
// Zeroize Fp2 | |||
@@ -377,7 +376,7 @@ func encrypt(skA *PrivateKey, pkA, pkB *PublicKey, ptext []byte) ([]byte, error) | |||
return nil, err | |||
} | |||
hashMac(n[:ptextLen], j, F) | |||
cshakeSum(n[:ptextLen], j, F) | |||
for i, _ := range ptext { | |||
n[i] ^= ptext[i] | |||
} | |||
@@ -594,7 +593,7 @@ func Decrypt(prv *PrivateKey, ctext []byte) ([]byte, error) { | |||
return nil, err | |||
} | |||
hashMac(n[:c1_len], j, F) | |||
cshakeSum(n[:c1_len], j, F) | |||
for i, _ := range n[:c1_len] { | |||
n[i] ^= ctext[pk_len+i] | |||
} | |||
@@ -623,7 +622,7 @@ func Encapsulate(rng io.Reader, pub *PublicKey) (ctext []byte, secret []byte, er | |||
var hmac_key = make([]byte, pub.Size()+2*Params.MsgLen) | |||
copy(hmac_key, ptext) | |||
copy(hmac_key[len(ptext):], pub.Export()) | |||
hashMac(r, hmac_key[:len(ptext)+pub.Size()], G) | |||
cshakeSum(r, hmac_key[:len(ptext)+pub.Size()], G) | |||
// Ensure bitlength is not bigger then to 2^e2-1 | |||
r[len(r)-1] &= (1 << (pub.params.A.SecretBitLen % 8)) - 1 | |||
@@ -643,7 +642,7 @@ func Encapsulate(rng io.Reader, pub *PublicKey) (ctext []byte, secret []byte, er | |||
// K = H(ptext||(c0||c1)) | |||
copy(hmac_key, ptext) | |||
copy(hmac_key[len(ptext):], ctext) | |||
hashMac(secret, hmac_key[:len(ptext)+len(ctext)], H) | |||
cshakeSum(secret, hmac_key[:len(ptext)+len(ctext)], H) | |||
return ctext, secret, nil | |||
} | |||
@@ -666,7 +665,7 @@ func Decapsulate(prv *PrivateKey, pub *PublicKey, ctext []byte) ([]byte, error) | |||
var hmac_key = make([]byte, pub.Size()+2*Params.MsgLen) | |||
copy(hmac_key, m) | |||
copy(hmac_key[len(m):], pub.Export()) | |||
hashMac(r, hmac_key[:len(m)+pub.Size()], G) | |||
cshakeSum(r, hmac_key[:len(m)+pub.Size()], G) | |||
// Ensure bitlength is not bigger than 2^e2-1 | |||
r[len(r)-1] &= (1 << (pub.params.A.SecretBitLen % 8)) - 1 | |||
@@ -690,6 +689,6 @@ func Decapsulate(prv *PrivateKey, pub *PublicKey, ctext []byte) ([]byte, error) | |||
copy(hmac_key, prv.S) | |||
} | |||
copy(hmac_key[len(m):], ctext) | |||
hashMac(secret, hmac_key[:len(m)+len(ctext)], H) | |||
cshakeSum(secret, hmac_key[:len(m)+len(ctext)], H) | |||
return secret, nil | |||
} |
@@ -598,8 +598,8 @@ func TestDecapsulation(t *testing.T) { | |||
0xBD, 0x7C, | |||
} | |||
var ss_exp = []byte{ | |||
0x74, 0x3D, 0x25, 0x36, 0x00, 0x24, 0x63, 0x1A, 0x39, 0x1A, | |||
0xB4, 0xAD, 0x01, 0x17, 0x78, 0xE9} | |||
0xbe, 0x07, 0x1d, 0xa6, 0x95, 0x4b, 0x03, 0x49, 0x6b, 0x2a, | |||
0x8e, 0x25, 0x80, 0xab, 0x9c, 0xdd} | |||
var prvObj = NewPrivateKey(KeyVariant_SIKE) | |||
var pubObj = NewPublicKey(KeyVariant_SIKE) | |||