@@ -13,8 +13,12 @@ import (
1313
1414 "github.com/cloudflare/circl/dh/x25519"
1515 "github.com/cloudflare/circl/dh/x448"
16+ "github.com/cloudflare/circl/internal/sha3"
1617 "github.com/cloudflare/circl/kem"
1718 "github.com/cloudflare/circl/kem/kyber/kyber768"
19+ "github.com/cloudflare/circl/kem/mlkem/mlkem1024"
20+ "github.com/cloudflare/circl/kem/mlkem/mlkem512"
21+ "github.com/cloudflare/circl/kem/mlkem/mlkem768"
1822 "github.com/cloudflare/circl/kem/xwing"
1923 "golang.org/x/crypto/chacha20poly1305"
2024 "golang.org/x/crypto/hkdf"
@@ -41,6 +45,13 @@ const (
4145 KEM_X25519_KYBER768_DRAFT00 KEM = 0x30
4246 // KEM_XWING is a hybrid KEM using X25519 and ML-KEM-768.
4347 KEM_XWING KEM = 0x647a
48+
49+ KEM_MLKEM512 KEM = 0x0040
50+ KEM_MLKEM768 KEM = 0x0041
51+ KEM_MLKEM1024 KEM = 0x0042
52+
53+ KEM_QSF_P256_MLKEM768 = 0x0050
54+ KEM_QSF_P384_MLKEM1024 = 0x0052
4455)
4556
4657// IsValid returns true if the KEM identifier is supported by the HPKE package.
@@ -52,7 +63,10 @@ func (k KEM) IsValid() bool {
5263 KEM_X25519_HKDF_SHA256 ,
5364 KEM_X448_HKDF_SHA512 ,
5465 KEM_X25519_KYBER768_DRAFT00 ,
55- KEM_XWING :
66+ KEM_XWING ,
67+ KEM_MLKEM512 ,
68+ KEM_MLKEM768 ,
69+ KEM_MLKEM1024 :
5670 return true
5771 default :
5872 return false
@@ -77,6 +91,12 @@ func (k KEM) Scheme() kem.Scheme {
7791 return hybridkemX25519Kyber768
7892 case KEM_XWING :
7993 return kemXwing
94+ case KEM_MLKEM512 :
95+ return kemMLKEM512
96+ case KEM_MLKEM768 :
97+ return kemMLKEM768
98+ case KEM_MLKEM1024 :
99+ return kemMLKEM1024
80100 default :
81101 panic (ErrInvalidKEM )
82102 }
@@ -86,27 +106,57 @@ type KDF uint16
86106
87107//nolint:golint,stylecheck
88108const (
89- // KDF_HKDF_SHA256 is a KDF using HKDF with SHA-256.
109+ // KDF_HKDF_SHA256 is a two-stage KDF using HKDF with SHA-256.
90110 KDF_HKDF_SHA256 KDF = 0x01
91- // KDF_HKDF_SHA384 is a KDF using HKDF with SHA-384.
111+ // KDF_HKDF_SHA384 is a two-stage KDF using HKDF with SHA-384.
92112 KDF_HKDF_SHA384 KDF = 0x02
93- // KDF_HKDF_SHA512 is a KDF using HKDF with SHA-512.
113+ // KDF_HKDF_SHA512 is a two-stage KDF using HKDF with SHA-512.
94114 KDF_HKDF_SHA512 KDF = 0x03
115+
116+ // KDF_SHAKE128 is a one-stage KDF using SHAKE-128.
117+ KDF_SHAKE128 = 0x10
118+ // KDF_SHAKE256 is a one-stage KDF using SHAKE-256.
119+ KDF_SHAKE256 = 0x11
120+ // KDF_TurboSHAKE128 is a one-stage KDF using TurboSHAKE-128.
121+ KDF_TurboSHAKE128 = 0x12
122+ // KDF_TurboSHAKE256 is a one-stage KDF using TurboSHAKE-256.
123+ KDF_TurboSHAKE256 = 0x13
95124)
96125
97- func (k KDF ) IsValid () bool {
126+ func (k KDF ) IsTwoStage () bool {
98127 switch k {
99128 case KDF_HKDF_SHA256 ,
100129 KDF_HKDF_SHA384 ,
101130 KDF_HKDF_SHA512 :
102131 return true
132+ case KDF_SHAKE128 ,
133+ KDF_TurboSHAKE128 ,
134+ KDF_SHAKE256 ,
135+ KDF_TurboSHAKE256 :
136+ return false
137+ default :
138+ panic (ErrInvalidKDF )
139+ }
140+ }
141+
142+ func (k KDF ) IsValid () bool {
143+ switch k {
144+ case KDF_HKDF_SHA256 ,
145+ KDF_HKDF_SHA384 ,
146+ KDF_HKDF_SHA512 ,
147+ KDF_SHAKE128 ,
148+ KDF_TurboSHAKE128 ,
149+ KDF_SHAKE256 ,
150+ KDF_TurboSHAKE256 :
151+ return true
103152 default :
104153 return false
105154 }
106155}
107156
108157// ExtractSize returns the size (in bytes) of the pseudorandom key produced
109- // by KDF.Extract.
158+ // by KDF.Extract() for a two-stage KDF, and the minimum output length
159+ // for full security for KDF.Derive() for a one-stage KDF.
110160func (k KDF ) ExtractSize () int {
111161 switch k {
112162 case KDF_HKDF_SHA256 :
@@ -115,13 +165,19 @@ func (k KDF) ExtractSize() int {
115165 return crypto .SHA384 .Size ()
116166 case KDF_HKDF_SHA512 :
117167 return crypto .SHA512 .Size ()
168+ case KDF_SHAKE128 , KDF_TurboSHAKE128 :
169+ return 32
170+ case KDF_SHAKE256 , KDF_TurboSHAKE256 :
171+ return 64
118172 default :
119173 panic (ErrInvalidKDF )
120174 }
121175}
122176
123177// Extract derives a pseudorandom key from a high-entropy, secret input and a
124178// salt. The size of the output is determined by KDF.ExtractSize.
179+ //
180+ // Panics when called on a one-stage KDF.
125181func (k KDF ) Extract (secret , salt []byte ) (pseudorandomKey []byte ) {
126182 return hkdf .Extract (k .hash (), secret , salt )
127183}
@@ -130,6 +186,8 @@ func (k KDF) Extract(secret, salt []byte) (pseudorandomKey []byte) {
130186// and an information string. Panics if the pseudorandom key is less
131187// than N bytes, or if the output length is greater than 255*N bytes,
132188// where N is the size returned by KDF.Extract function.
189+ //
190+ // Panics when called on a one-stage KDF.
133191func (k KDF ) Expand (pseudorandomKey , info []byte , outputLen uint ) []byte {
134192 extractSize := k .ExtractSize ()
135193 if len (pseudorandomKey ) < extractSize {
@@ -148,6 +206,27 @@ func (k KDF) Expand(pseudorandomKey, info []byte, outputLen uint) []byte {
148206 return output
149207}
150208
209+ // Derive derives a variable-length pseudorandom string from a
210+ // high-entropy, secret input.
211+ //
212+ // Panics when called on a two-stage KDF.
213+ func (k KDF ) Derive (ikm []byte , l uint ) []byte {
214+ ret := make ([]byte , l )
215+ switch k {
216+ case KDF_SHAKE128 :
217+ sha3 .ShakeSum128 (ret , ikm )
218+ case KDF_SHAKE256 :
219+ sha3 .ShakeSum256 (ret , ikm )
220+ case KDF_TurboSHAKE128 :
221+ sha3 .TurboShakeSum128 (ret , ikm , 0x1f )
222+ case KDF_TurboSHAKE256 :
223+ sha3 .TurboShakeSum256 (ret , ikm , 0x1f )
224+ default :
225+ panic (ErrInvalidKDF )
226+ }
227+ return ret
228+ }
229+
151230func (k KDF ) hash () func () hash.Hash {
152231 switch k {
153232 case KDF_HKDF_SHA256 :
@@ -243,6 +322,9 @@ var (
243322 dhkemx25519hkdfsha256 , dhkemx448hkdfsha512 xKEM
244323 hybridkemX25519Kyber768 hybridKEM
245324 kemXwing genericNoAuthKEM
325+ kemMLKEM512 genericNoAuthKEM
326+ kemMLKEM768 genericNoAuthKEM
327+ kemMLKEM1024 genericNoAuthKEM
246328)
247329
248330func init () {
@@ -284,4 +366,11 @@ func init() {
284366
285367 kemXwing .Scheme = xwing .Scheme ()
286368 kemXwing .name = "HPKE_KEM_XWING"
369+
370+ kemMLKEM512 .Scheme = mlkem512 .Scheme ()
371+ kemMLKEM512 .name = "HPKE_KEM_MLKEM512"
372+ kemMLKEM768 .Scheme = mlkem768 .Scheme ()
373+ kemMLKEM768 .name = "HPKE_KEM_MLKEM768"
374+ kemMLKEM1024 .Scheme = mlkem1024 .Scheme ()
375+ kemMLKEM1024 .name = "HPKE_KEM_MLKEM1024"
287376}
0 commit comments