Skip to content

Commit 0b2b5d0

Browse files
lukaszobernigcopybara-github
authored andcommitted
Add support for ML-DSA-87 parameter set.
PiperOrigin-RevId: 842177576 Change-Id: I8338def95a8b1cff50ab80ed534c59b07a30b06a
1 parent a9c7292 commit 0b2b5d0

File tree

9 files changed

+455
-36
lines changed

9 files changed

+455
-36
lines changed

signature/mldsa/key.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,16 @@ const (
6161
UnknownInstance Instance = iota
6262
// MLDSA65 yields ML-DSA-65 parameters.
6363
MLDSA65
64+
// MLDSA87 yields ML-DSA-87 parameters.
65+
MLDSA87
6466
)
6567

6668
func (instance Instance) String() string {
6769
switch instance {
6870
case MLDSA65:
6971
return "MLDSA65"
72+
case MLDSA87:
73+
return "MLDSA87"
7074
default:
7175
return "UNKNOWN"
7276
}
@@ -138,6 +142,11 @@ func checkPublicKeyLengthForInstance(length int, instance Instance) error {
138142
if length != expectedLength {
139143
return fmt.Errorf("public key length must be %d bytes", expectedLength)
140144
}
145+
case MLDSA87:
146+
expectedLength := mldsa.MLDSA87.PublicKeyLength()
147+
if length != expectedLength {
148+
return fmt.Errorf("public key length must be %d bytes", expectedLength)
149+
}
141150
default:
142151
return fmt.Errorf("invalid instance: %v", instance)
143152
}
@@ -214,6 +223,11 @@ func keyGenForInstance(seed secretdata.Bytes, instance Instance) ([]byte, secret
214223
copy(seedBytes[:], seed.Data(insecuresecretdataaccess.Token{}))
215224
publicKey, secretKey := mldsa.MLDSA65.KeyGenFromSeed(seedBytes)
216225
return publicKey.Encode(), secretdata.NewBytesFromData(secretKey.Encode(), insecuresecretdataaccess.Token{}), nil
226+
case MLDSA87:
227+
var seedBytes [mldsa.SecretKeySeedSize]byte
228+
copy(seedBytes[:], seed.Data(insecuresecretdataaccess.Token{}))
229+
publicKey, secretKey := mldsa.MLDSA87.KeyGenFromSeed(seedBytes)
230+
return publicKey.Encode(), secretdata.NewBytesFromData(secretKey.Encode(), insecuresecretdataaccess.Token{}), nil
217231
default:
218232
return nil, secretdata.Bytes{}, fmt.Errorf("invalid instance: %v", instance)
219233
}
@@ -304,8 +318,8 @@ func createPrivateKey(p key.Parameters, idRequirement uint32) (key.Key, error) {
304318
if !ok {
305319
return nil, fmt.Errorf("invalid parameters type: %T", p)
306320
}
307-
// Make sure the parameters are not "empty"; only MLDSA65 is supported.
308-
if mlDSAParams.Instance() != MLDSA65 {
321+
// Make sure the parameters are not "empty"; only MLDSA65 and MLDSA87 are supported.
322+
if mlDSAParams.Instance() != MLDSA65 && mlDSAParams.Instance() != MLDSA87 {
309323
return nil, fmt.Errorf("invalid parameters")
310324
}
311325
seed, err := secretdata.NewBytesFromRand(mldsa.SecretKeySeedSize)

signature/mldsa/key_test.go

Lines changed: 333 additions & 20 deletions
Large diffs are not rendered by default.

signature/mldsa/mldsa_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,13 @@ func TestCreateKeysetHandleFromParameters(t *testing.T) {
2727
instance mldsa.Instance
2828
}{
2929
{
30-
name: "MLDSA65",
30+
name: "ML-DSA-65",
3131
instance: mldsa.MLDSA65,
3232
},
33+
{
34+
name: "ML-DSA-87",
35+
instance: mldsa.MLDSA87,
36+
},
3337
} {
3438
t.Run(tc.name, func(t *testing.T) {
3539
params, err := mldsa.NewParameters(tc.instance, mldsa.VariantNoPrefix)

signature/mldsa/protoserialization.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ func protoMlDsaInstanceFromInstance(instance Instance) (mldsapb.MlDsaInstance, e
6161
switch instance {
6262
case MLDSA65:
6363
return mldsapb.MlDsaInstance_ML_DSA_65, nil
64+
case MLDSA87:
65+
return mldsapb.MlDsaInstance_ML_DSA_87, nil
6466
default:
6567
return mldsapb.MlDsaInstance_ML_DSA_UNKNOWN_INSTANCE, fmt.Errorf("unknown instance: %v", instance)
6668
}
@@ -171,6 +173,8 @@ func instanceFromProto(instanceType mldsapb.MlDsaInstance) (Instance, error) {
171173
switch instanceType {
172174
case mldsapb.MlDsaInstance_ML_DSA_65:
173175
return MLDSA65, nil
176+
case mldsapb.MlDsaInstance_ML_DSA_87:
177+
return MLDSA87, nil
174178
default:
175179
return UnknownInstance, fmt.Errorf("unsupported instance type: %v", instanceType)
176180
}

signature/mldsa/signer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ func mldsaSecretKeyFromPrivateKey(privateKey *PrivateKey) (*mldsa.SecretKey, err
3838
switch privateKey.publicKey.params.Instance() {
3939
case MLDSA65:
4040
return mldsa.MLDSA65.DecodeSecretKey(privateKey.expandedKeyBytes.Data(insecuresecretdataaccess.Token{}))
41+
case MLDSA87:
42+
return mldsa.MLDSA87.DecodeSecretKey(privateKey.expandedKeyBytes.Data(insecuresecretdataaccess.Token{}))
4143
default:
4244
return &mldsa.SecretKey{}, fmt.Errorf("invalid instance: %v", privateKey.publicKey.params.Instance())
4345
}

signature/mldsa/signer_key_manager_test.go

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,13 @@ func TestSignerKeyManagerGetPrimitiveBasic(t *testing.T) {
3838
instance tinkmldsa.Instance
3939
}{
4040
{
41-
name: "MLDSA65",
41+
name: "ML-DSA-65",
4242
instance: tinkmldsa.MLDSA65,
4343
},
44+
{
45+
name: "ML-DSA-87",
46+
instance: tinkmldsa.MLDSA87,
47+
},
4448
} {
4549
t.Run(tc.name, func(t *testing.T) {
4650
km, err := registry.GetKeyManager("type.googleapis.com/google.crypto.tink.MlDsaPrivateKey")
@@ -108,9 +112,13 @@ func TestSignerKeyManagerGetPrimitiveWithInvalidInput(t *testing.T) {
108112
instance mldsapb.MlDsaInstance
109113
}{
110114
{
111-
name: "MLDSA65",
115+
name: "ML-DSA-65",
112116
instance: mldsapb.MlDsaInstance_ML_DSA_65,
113117
},
118+
{
119+
name: "ML-DSA-87",
120+
instance: mldsapb.MlDsaInstance_ML_DSA_87,
121+
},
114122
} {
115123
t.Run(tc.name, func(t *testing.T) {
116124
key := newMLDSAPrivateKey(tc.instance)
@@ -139,9 +147,13 @@ func TestSignerKeyManagerNewKeyDataBasic(t *testing.T) {
139147
instance mldsapb.MlDsaInstance
140148
}{
141149
{
142-
name: "MLDSA65",
150+
name: "ML-DSA-65",
143151
instance: mldsapb.MlDsaInstance_ML_DSA_65,
144152
},
153+
{
154+
name: "ML-DSA-87",
155+
instance: mldsapb.MlDsaInstance_ML_DSA_87,
156+
},
145157
} {
146158
t.Run(tc.name, func(t *testing.T) {
147159
km, err := registry.GetKeyManager("type.googleapis.com/google.crypto.tink.MlDsaPrivateKey")
@@ -179,9 +191,13 @@ func TestSignerKeyManagerPublicKeyDataBasic(t *testing.T) {
179191
instance mldsapb.MlDsaInstance
180192
}{
181193
{
182-
name: "MLDSA65",
194+
name: "ML-DSA-65",
183195
instance: mldsapb.MlDsaInstance_ML_DSA_65,
184196
},
197+
{
198+
name: "ML-DSA-87",
199+
instance: mldsapb.MlDsaInstance_ML_DSA_87,
200+
},
185201
} {
186202
t.Run(tc.name, func(t *testing.T) {
187203
km, err := registry.GetKeyManager("type.googleapis.com/google.crypto.tink.MlDsaPrivateKey")
@@ -223,9 +239,13 @@ func TestSignerKeyManagerPublicKeyDataWithInvalidInput(t *testing.T) {
223239
instance mldsapb.MlDsaInstance
224240
}{
225241
{
226-
name: "MLDSA65",
242+
name: "ML-DSA-65",
227243
instance: mldsapb.MlDsaInstance_ML_DSA_65,
228244
},
245+
{
246+
name: "ML-DSA-87",
247+
instance: mldsapb.MlDsaInstance_ML_DSA_87,
248+
},
229249
} {
230250
t.Run(tc.name, func(t *testing.T) {
231251
km, err := registry.GetKeyManager("type.googleapis.com/google.crypto.tink.MlDsaPrivateKey")
@@ -271,6 +291,21 @@ func newMLDSAPrivateKey(instance mldsapb.MlDsaInstance) *mldsapb.MlDsaPrivateKey
271291
PublicKey: publicProto,
272292
KeyValue: seed[:],
273293
}
294+
case mldsapb.MlDsaInstance_ML_DSA_87:
295+
public, private := mldsa.MLDSA87.KeyGen()
296+
publicProto := &mldsapb.MlDsaPublicKey{
297+
Params: &mldsapb.MlDsaParams{
298+
MlDsaInstance: mldsapb.MlDsaInstance_ML_DSA_87,
299+
},
300+
Version: 0,
301+
KeyValue: public.Encode(),
302+
}
303+
seed := private.Seed()
304+
return &mldsapb.MlDsaPrivateKey{
305+
Version: 0,
306+
PublicKey: publicProto,
307+
KeyValue: seed[:],
308+
}
274309
default:
275310
panic(fmt.Sprintf("Unsupported MLDSA instance: %v", instance))
276311
}
@@ -294,6 +329,8 @@ func validateMLDSAPrivateKey(instance mldsapb.MlDsaInstance, key *mldsapb.MlDsaP
294329
switch instance {
295330
case mldsapb.MlDsaInstance_ML_DSA_65:
296331
pub, _ = mldsa.MLDSA65.KeyGenFromSeed(seedBytes)
332+
case mldsapb.MlDsaInstance_ML_DSA_87:
333+
pub, _ = mldsa.MLDSA87.KeyGenFromSeed(seedBytes)
297334
default:
298335
return fmt.Errorf("unsupported instance: %v", instance)
299336
}

signature/mldsa/signer_verifier_test.go

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,29 @@ func TestSignVerifyManager(t *testing.T) {
3636
idRequirement uint32
3737
}{
3838
{
39-
name: "TINK",
39+
name: "TINK ML-DSA-65",
4040
instance: tinkmldsa.MLDSA65,
4141
variant: tinkmldsa.VariantTink,
4242
idRequirement: uint32(0x01020304),
4343
},
4444
{
45-
name: "RAW",
45+
name: "TINK ML-DSA-87",
46+
instance: tinkmldsa.MLDSA87,
47+
variant: tinkmldsa.VariantTink,
48+
idRequirement: uint32(0x01020304),
49+
},
50+
{
51+
name: "RAW ML-DSA-65",
4652
instance: tinkmldsa.MLDSA65,
4753
variant: tinkmldsa.VariantNoPrefix,
4854
idRequirement: uint32(0),
4955
},
56+
{
57+
name: "RAW ML-DSA-87",
58+
instance: tinkmldsa.MLDSA87,
59+
variant: tinkmldsa.VariantNoPrefix,
60+
idRequirement: uint32(0),
61+
},
5062
} {
5163
t.Run(tc.name, func(t *testing.T) {
5264
params, err := tinkmldsa.NewParameters(tc.instance, tc.variant)
@@ -126,15 +138,25 @@ func TestVerifyFails(t *testing.T) {
126138
variant tinkmldsa.Variant
127139
}{
128140
{
129-
name: "TINK",
141+
name: "TINK ML-DSA-65",
130142
instance: tinkmldsa.MLDSA65,
131143
variant: tinkmldsa.VariantTink,
132144
},
133145
{
134-
name: "RAW",
146+
name: "TINK ML-DSA-87",
147+
instance: tinkmldsa.MLDSA87,
148+
variant: tinkmldsa.VariantTink,
149+
},
150+
{
151+
name: "RAW ML-DSA-65",
135152
instance: tinkmldsa.MLDSA65,
136153
variant: tinkmldsa.VariantNoPrefix,
137154
},
155+
{
156+
name: "RAW ML-DSA-87",
157+
instance: tinkmldsa.MLDSA87,
158+
variant: tinkmldsa.VariantNoPrefix,
159+
},
138160
} {
139161
t.Run(tc.name, func(t *testing.T) {
140162
seed := random.GetRandomBytes(32)
@@ -211,15 +233,25 @@ func TestSignVerifyCorrectness(t *testing.T) {
211233
variant tinkmldsa.Variant
212234
}{
213235
{
214-
name: "TINK",
236+
name: "TINK ML-DSA-65",
215237
instance: tinkmldsa.MLDSA65,
216238
variant: tinkmldsa.VariantTink,
217239
},
218240
{
219-
name: "RAW",
241+
name: "TINK ML-DSA-87",
242+
instance: tinkmldsa.MLDSA87,
243+
variant: tinkmldsa.VariantTink,
244+
},
245+
{
246+
name: "RAW ML-DSA-65",
220247
instance: tinkmldsa.MLDSA65,
221248
variant: tinkmldsa.VariantNoPrefix,
222249
},
250+
{
251+
name: "RAW ML-DSA-87",
252+
instance: tinkmldsa.MLDSA87,
253+
variant: tinkmldsa.VariantNoPrefix,
254+
},
223255
} {
224256
t.Run(tc.name, func(t *testing.T) {
225257
seed := random.GetRandomBytes(32)

signature/mldsa/verifier.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ func mldsaPublicKeyFromPublicKey(publicKey *PublicKey) (*mldsa.PublicKey, error)
3737
switch publicKey.params.instance {
3838
case MLDSA65:
3939
return mldsa.MLDSA65.DecodePublicKey(publicKey.KeyBytes())
40+
case MLDSA87:
41+
return mldsa.MLDSA87.DecodePublicKey(publicKey.KeyBytes())
4042
default:
4143
return &mldsa.PublicKey{}, fmt.Errorf("invalid instance: %v", publicKey.params.instance)
4244
}

signature/mldsa/verifier_key_manager_test.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,19 @@ func TestVerifierKeyManagerGetPrimitiveBasic(t *testing.T) {
3535
msg []byte
3636
}{
3737
{
38-
name: "MLDSA65",
38+
name: "ML-DSA-65",
3939
instance: tinkmldsa.MLDSA65,
4040
pub: mustDecodeString(t, pubKey65Hex),
4141
sig: mustDecodeString(t, sig65Hex),
4242
msg: mustDecodeString(t, msg65Hex),
4343
},
44+
{
45+
name: "ML-DSA-87",
46+
instance: tinkmldsa.MLDSA87,
47+
pub: mustDecodeString(t, pubKey87Hex),
48+
sig: mustDecodeString(t, sig87Hex),
49+
msg: mustDecodeString(t, msg87Hex),
50+
},
4451
} {
4552
t.Run(tc.name, func(t *testing.T) {
4653
km, err := registry.GetKeyManager("type.googleapis.com/google.crypto.tink.MlDsaPublicKey")
@@ -86,9 +93,13 @@ func TestVerifierKeyManagerGetPrimitiveWithInvalidInput(t *testing.T) {
8693
instance mldsapb.MlDsaInstance
8794
}{
8895
{
89-
name: "MLDSA65",
96+
name: "ML-DSA-65",
9097
instance: mldsapb.MlDsaInstance_ML_DSA_65,
9198
},
99+
{
100+
name: "ML-DSA-87",
101+
instance: mldsapb.MlDsaInstance_ML_DSA_87,
102+
},
92103
} {
93104
t.Run(tc.name, func(t *testing.T) {
94105
key := newMLDSAPublicKey(tc.instance)

0 commit comments

Comments
 (0)