Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions scripts/build_ffi.py
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,7 @@ def build_ffi(local_wolfssl, features):
int wc_dilithium_set_level(dilithium_key* key, byte level);
void wc_dilithium_free(dilithium_key* key);
int wc_dilithium_make_key(dilithium_key* key, WC_RNG* rng);
int wc_dilithium_make_key_from_seed(dilithium_key* key, const byte* seed);
int wc_dilithium_export_private(dilithium_key* key, byte* out, word32* outLen);
int wc_dilithium_import_private(const byte* priv, word32 privSz, dilithium_key* key);
int wc_dilithium_export_public(dilithium_key* key, byte* out, word32* outLen);
Expand Down
34 changes: 34 additions & 0 deletions tests/test_mldsa.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
from wolfcrypt.ciphers import MlDsaPrivate, MlDsaPublic, MlDsaType
from wolfcrypt.random import Random

ML_DSA_SEED_LENGTH = 32
Comment thread
dgarske marked this conversation as resolved.
Outdated

@pytest.fixture
def rng():
return Random()
Expand Down Expand Up @@ -134,3 +136,35 @@ def test_sign_verify(mldsa_type, rng):
# Verify with wrong message
wrong_message = b"This is a wrong message for ML-DSA signature"
assert not mldsa_pub.verify(signature, wrong_message)

def test_generate_from_seed(mldsa_type, rng):
private_key_seed = rng.bytes(ML_DSA_SEED_LENGTH)
mldsa_priv = MlDsaPrivate.make_key_from_seed(mldsa_type, private_key_seed)
pub_key = mldsa_priv.encode_pub_key()

# Import public key
mldsa_pub = MlDsaPublic(mldsa_type)
mldsa_pub.decode_key(pub_key)

# Sign a message
message = b"This is a test message for ML-DSA signature"
signature = mldsa_priv.sign(message, rng)
assert len(signature) == mldsa_priv.sig_size

# Verify the signature using public key
assert mldsa_pub.verify(signature, message)

# re-generate from the same seed:
mldsa_priv_regenerated = MlDsaPrivate.make_key_from_seed(mldsa_type, private_key_seed)
assert mldsa_priv_regenerated.encode_priv_key() == mldsa_priv.encode_priv_key()
assert mldsa_priv_regenerated.encode_pub_key() == mldsa_priv.encode_pub_key()

# test that the seed is checked:
with pytest.raises(AssertionError):
mldsa_priv = MlDsaPrivate.make_key_from_seed(mldsa_type, private_key_seed[:-1])

with pytest.raises(AssertionError):
mldsa_priv = MlDsaPrivate.make_key_from_seed(mldsa_type, private_key_seed + bytes(1))

with pytest.raises(AssertionError):
Comment thread
dgarske marked this conversation as resolved.
Outdated
mldsa_priv = MlDsaPrivate.make_key_from_seed(mldsa_type, 'a' * 32)
25 changes: 25 additions & 0 deletions wolfcrypt/ciphers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2152,6 +2152,9 @@ def verify(self, signature, message):
return res[0] == 1

class MlDsaPrivate(_MlDsaBase):
_SEED_LENGTH = 32
"""The length of a private key generation seed."""

Comment thread
dgarske marked this conversation as resolved.
Outdated
@classmethod
def make_key(cls, mldsa_type, rng=Random()):
"""
Expand All @@ -2172,6 +2175,28 @@ def make_key(cls, mldsa_type, rng=Random()):

return mldsa_priv

@classmethod
def make_key_from_seed(cls, mldsa_type, seed):
"""
Deterministically generate the key from a seed.

:param mldsa_type: ML-DSA type
:type mldsa_type: MlDsaType
:param seed: the (32 byte) seed from which to deterministically create the key
:type seed: bytes
"""
mldsa_priv = cls(mldsa_type)
assert isinstance(seed, bytes) and len(seed) == MlDsaPrivate._SEED_LENGTH, \
f"Seed for generating ML-DSA key must be {MlDsaPrivate._SEED_LENGTH} bytes"

ret = _lib.wc_dilithium_make_key_from_seed(mldsa_priv.native_object,
_ffi.from_buffer(seed))

Comment thread
dgarske marked this conversation as resolved.
Outdated
if ret < 0: # pragma: no cover
raise WolfCryptError("wc_dilithium_make_key_from_seed() error (%d)" % ret)

return mldsa_priv

@property
def pub_key_size(self):
"""
Expand Down
Loading