package mlkem
import (
"crypto/internal/fips140"
"crypto/internal/fips140/drbg"
"crypto/internal/fips140/sha3"
"crypto/internal/fips140/subtle"
"errors"
)
type DecapsulationKey1024 struct {
d [32 ]byte
z [32 ]byte
ρ [32 ]byte
h [32 ]byte
encryptionKey1024
decryptionKey1024
}
func (dk *DecapsulationKey1024 ) Bytes () []byte {
var b [SeedSize ]byte
copy (b [:], dk .d [:])
copy (b [32 :], dk .z [:])
return b [:]
}
func (dk *DecapsulationKey1024 ) EncapsulationKey () *EncapsulationKey1024 {
return &EncapsulationKey1024 {
ρ : dk .ρ ,
h : dk .h ,
encryptionKey1024 : dk .encryptionKey1024 ,
}
}
type EncapsulationKey1024 struct {
ρ [32 ]byte
h [32 ]byte
encryptionKey1024
}
func (ek *EncapsulationKey1024 ) Bytes () []byte {
b := make ([]byte , 0 , EncapsulationKeySize1024 )
return ek .bytes (b )
}
func (ek *EncapsulationKey1024 ) bytes (b []byte ) []byte {
for i := range ek .t {
b = polyByteEncode (b , ek .t [i ])
}
b = append (b , ek .ρ [:]...)
return b
}
type encryptionKey1024 struct {
t [k1024 ]nttElement
a [k1024 * k1024 ]nttElement
}
type decryptionKey1024 struct {
s [k1024 ]nttElement
}
func GenerateKey1024 () (*DecapsulationKey1024 , error ) {
dk := &DecapsulationKey1024 {}
return generateKey1024 (dk )
}
func generateKey1024(dk *DecapsulationKey1024 ) (*DecapsulationKey1024 , error ) {
var d [32 ]byte
drbg .Read (d [:])
var z [32 ]byte
drbg .Read (z [:])
kemKeyGen1024 (dk , &d , &z )
if err := fips140 .PCT ("ML-KEM PCT" , func () error { return kemPCT1024 (dk ) }); err != nil {
panic (err )
}
fips140 .RecordApproved ()
return dk , nil
}
func GenerateKeyInternal1024 (d , z *[32 ]byte ) *DecapsulationKey1024 {
dk := &DecapsulationKey1024 {}
kemKeyGen1024 (dk , d , z )
return dk
}
func NewDecapsulationKey1024 (seed []byte ) (*DecapsulationKey1024 , error ) {
dk := &DecapsulationKey1024 {}
return newKeyFromSeed1024 (dk , seed )
}
func newKeyFromSeed1024(dk *DecapsulationKey1024 , seed []byte ) (*DecapsulationKey1024 , error ) {
if len (seed ) != SeedSize {
return nil , errors .New ("mlkem: invalid seed length" )
}
d := (*[32 ]byte )(seed [:32 ])
z := (*[32 ]byte )(seed [32 :])
kemKeyGen1024 (dk , d , z )
if err := fips140 .PCT ("ML-KEM PCT" , func () error { return kemPCT1024 (dk ) }); err != nil {
panic (err )
}
fips140 .RecordApproved ()
return dk , nil
}
func kemKeyGen1024(dk *DecapsulationKey1024 , d , z *[32 ]byte ) {
dk .d = *d
dk .z = *z
g := sha3 .New512 ()
g .Write (d [:])
g .Write ([]byte {k1024 })
G := g .Sum (make ([]byte , 0 , 64 ))
ρ , σ := G [:32 ], G [32 :]
dk .ρ = [32 ]byte (ρ )
A := &dk .a
for i := byte (0 ); i < k1024 ; i ++ {
for j := byte (0 ); j < k1024 ; j ++ {
A [i *k1024 +j ] = sampleNTT (ρ , j , i )
}
}
var N byte
s := &dk .s
for i := range s {
s [i ] = ntt (samplePolyCBD (σ , N ))
N ++
}
e := make ([]nttElement , k1024 )
for i := range e {
e [i ] = ntt (samplePolyCBD (σ , N ))
N ++
}
t := &dk .t
for i := range t {
t [i ] = e [i ]
for j := range s {
t [i ] = polyAdd (t [i ], nttMul (A [i *k1024 +j ], s [j ]))
}
}
H := sha3 .New256 ()
ek := dk .EncapsulationKey ().Bytes ()
H .Write (ek )
H .Sum (dk .h [:0 ])
}
func kemPCT1024(dk *DecapsulationKey1024 ) error {
ek := dk .EncapsulationKey ()
c , K := ek .Encapsulate ()
K1 , err := dk .Decapsulate (c )
if err != nil {
return err
}
if subtle .ConstantTimeCompare (K , K1 ) != 1 {
return errors .New ("mlkem: PCT failed" )
}
return nil
}
func (ek *EncapsulationKey1024 ) Encapsulate () (ciphertext , sharedKey []byte ) {
var cc [CiphertextSize1024 ]byte
return ek .encapsulate (&cc )
}
func (ek *EncapsulationKey1024 ) encapsulate (cc *[CiphertextSize1024 ]byte ) (ciphertext , sharedKey []byte ) {
var m [messageSize ]byte
drbg .Read (m [:])
fips140 .RecordApproved ()
return kemEncaps1024 (cc , ek , &m )
}
func (ek *EncapsulationKey1024 ) EncapsulateInternal (m *[32 ]byte ) (ciphertext , sharedKey []byte ) {
cc := &[CiphertextSize1024 ]byte {}
return kemEncaps1024 (cc , ek , m )
}
func kemEncaps1024(cc *[CiphertextSize1024 ]byte , ek *EncapsulationKey1024 , m *[messageSize ]byte ) (c , K []byte ) {
g := sha3 .New512 ()
g .Write (m [:])
g .Write (ek .h [:])
G := g .Sum (nil )
K , r := G [:SharedKeySize ], G [SharedKeySize :]
c = pkeEncrypt1024 (cc , &ek .encryptionKey1024 , m , r )
return c , K
}
func NewEncapsulationKey1024 (encapsulationKey []byte ) (*EncapsulationKey1024 , error ) {
ek := &EncapsulationKey1024 {}
return parseEK1024 (ek , encapsulationKey )
}
func parseEK1024(ek *EncapsulationKey1024 , ekPKE []byte ) (*EncapsulationKey1024 , error ) {
if len (ekPKE ) != EncapsulationKeySize1024 {
return nil , errors .New ("mlkem: invalid encapsulation key length" )
}
h := sha3 .New256 ()
h .Write (ekPKE )
h .Sum (ek .h [:0 ])
for i := range ek .t {
var err error
ek .t [i ], err = polyByteDecode [nttElement ](ekPKE [:encodingSize12 ])
if err != nil {
return nil , err
}
ekPKE = ekPKE [encodingSize12 :]
}
copy (ek .ρ [:], ekPKE )
for i := byte (0 ); i < k1024 ; i ++ {
for j := byte (0 ); j < k1024 ; j ++ {
ek .a [i *k1024 +j ] = sampleNTT (ek .ρ [:], j , i )
}
}
return ek , nil
}
func pkeEncrypt1024(cc *[CiphertextSize1024 ]byte , ex *encryptionKey1024 , m *[messageSize ]byte , rnd []byte ) []byte {
var N byte
r , e1 := make ([]nttElement , k1024 ), make ([]ringElement , k1024 )
for i := range r {
r [i ] = ntt (samplePolyCBD (rnd , N ))
N ++
}
for i := range e1 {
e1 [i ] = samplePolyCBD (rnd , N )
N ++
}
e2 := samplePolyCBD (rnd , N )
u := make ([]ringElement , k1024 )
for i := range u {
u [i ] = e1 [i ]
for j := range r {
u [i ] = polyAdd (u [i ], inverseNTT (nttMul (ex .a [j *k1024 +i ], r [j ])))
}
}
μ := ringDecodeAndDecompress1 (m )
var vNTT nttElement
for i := range ex .t {
vNTT = polyAdd (vNTT , nttMul (ex .t [i ], r [i ]))
}
v := polyAdd (polyAdd (inverseNTT (vNTT ), e2 ), μ )
c := cc [:0 ]
for _ , f := range u {
c = ringCompressAndEncode11 (c , f )
}
c = ringCompressAndEncode5 (c , v )
return c
}
func (dk *DecapsulationKey1024 ) Decapsulate (ciphertext []byte ) (sharedKey []byte , err error ) {
if len (ciphertext ) != CiphertextSize1024 {
return nil , errors .New ("mlkem: invalid ciphertext length" )
}
c := (*[CiphertextSize1024 ]byte )(ciphertext )
return kemDecaps1024 (dk , c ), nil
}
func kemDecaps1024(dk *DecapsulationKey1024 , c *[CiphertextSize1024 ]byte ) (K []byte ) {
fips140 .RecordApproved ()
m := pkeDecrypt1024 (&dk .decryptionKey1024 , c )
g := sha3 .New512 ()
g .Write (m [:])
g .Write (dk .h [:])
G := g .Sum (make ([]byte , 0 , 64 ))
Kprime , r := G [:SharedKeySize ], G [SharedKeySize :]
J := sha3 .NewShake256 ()
J .Write (dk .z [:])
J .Write (c [:])
Kout := make ([]byte , SharedKeySize )
J .Read (Kout )
var cc [CiphertextSize1024 ]byte
c1 := pkeEncrypt1024 (&cc , &dk .encryptionKey1024 , (*[32 ]byte )(m ), r )
subtle .ConstantTimeCopy (subtle .ConstantTimeCompare (c [:], c1 ), Kout , Kprime )
return Kout
}
func pkeDecrypt1024(dx *decryptionKey1024 , c *[CiphertextSize1024 ]byte ) []byte {
u := make ([]ringElement , k1024 )
for i := range u {
b := (*[encodingSize11 ]byte )(c [encodingSize11 *i : encodingSize11 *(i +1 )])
u [i ] = ringDecodeAndDecompress11 (b )
}
b := (*[encodingSize5 ]byte )(c [encodingSize11 *k1024 :])
v := ringDecodeAndDecompress5 (b )
var mask nttElement
for i := range dx .s {
mask = polyAdd (mask , nttMul (dx .s [i ], ntt (u [i ])))
}
w := polySub (v , inverseNTT (mask ))
return ringCompressAndEncode1 (nil , w )
}
The pages are generated with Golds v0.7.3-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .