forked from kudelskisecurity/crystals-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ccakem.go
103 lines (85 loc) · 2.86 KB
/
ccakem.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package kyber
import (
"crypto/rand"
"crypto/subtle"
"golang.org/x/crypto/sha3"
)
// KeyGen creates a public and private key pair.
// A 64 byte long seed can be given as argument. If a nil seed is given, the seed is generated using Go crypto's random number generator.
// The keys returned are packed into byte arrays.
func (k *Kyber) KeyGen(seed []byte) ([]byte, []byte) {
if seed == nil || len(seed) != SIZEZ+SEEDBYTES {
seed = make([]byte, SIZEZ+SEEDBYTES)
rand.Read(seed)
}
pk, skP := k.PKEKeyGen(seed[:SEEDBYTES])
return pk, k.PackSK(&PrivateKey{SkP: skP, Pk: pk, Z: seed[SEEDBYTES:]})
}
// Encaps generates a shared secret and the encryption of said shared secret using a given public key.
// A 32 byte long seed can be given as argument (coins). If a nil seed is given, the seed is generated using Go crypto's random number generator.
// The shared secret and ciphertext returned are packed into byte arrays.
// If an error occurs during the encaps process, nil arrays are returned.
func (k *Kyber) Encaps(packedPK, coins []byte) ([]byte, []byte) {
if len(packedPK) != k.SIZEPK() {
println("Public key does not have the correct size.")
return nil, nil
}
if coins == nil || len(coins) != SEEDBYTES {
coins = make([]byte, SEEDBYTES)
rand.Read(coins[:])
}
var m, ss [32]byte
hState := sha3.New256()
hState.Write(coins[:])
copy(m[:], hState.Sum(nil))
hpk := make([]byte, 32)
hState.Reset()
hState.Write(packedPK[:])
copy(hpk[:], hState.Sum(nil))
var kr, kc [64]byte
gState := sha3.New512()
gState.Write(m[:])
gState.Write(hpk[:])
copy(kr[:], gState.Sum(nil))
copy(kc[:32], kr[:32])
c := k.Encrypt(packedPK, m[:], kr[32:])
hState.Reset()
hState.Write(c[:])
copy(kc[32:], hState.Sum(nil))
kdfState := sha3.NewShake256()
kdfState.Write(kc[:])
kdfState.Read(ss[:])
return c[:], ss[:]
}
// Decaps decryps a ciphertext given a secret key and checks its validity.
// The secret key and ciphertext must be give as packed byte array.
// The recovered shared secret is returned as byte array.
// If an error occurs durirng the decapsulation process, a nil shared secret is returned.
func (k *Kyber) Decaps(packedSK, c []byte) []byte {
if len(c) != k.SIZEC() || len(packedSK) != k.SIZESK() {
println("Cannot decapsulate, inputs do not have the correct size.")
return nil
}
sk := k.UnpackSK(packedSK)
m := k.Decrypt(sk.SkP, c)
hpk := make([]byte, 32)
hState := sha3.New256()
hState.Write(sk.Pk[:])
copy(hpk[:], hState.Sum(nil))
var kr, kc [64]byte
gState := sha3.New512()
gState.Write(m[:])
gState.Write(hpk[:])
copy(kr[:], gState.Sum(nil))
copy(kc[:], kr[:32])
c2 := k.Encrypt(sk.Pk, m, kr[32:])
hState.Reset()
hState.Write(c2[:])
copy(kc[32:], hState.Sum(nil))
subtle.ConstantTimeCopy(1-subtle.ConstantTimeCompare(c, c2), kc[:32], sk.Z[:])
var ss [32]byte
kdfState := sha3.NewShake256()
kdfState.Write(kc[:])
kdfState.Read(ss[:])
return ss[:]
}