@@ -726,6 +726,115 @@ int test_wc_dilithium_make_key(void)
726726 return EXPECT_RESULT();
727727}
728728
729+ int test_wc_dilithium_pub_from_priv(void)
730+ {
731+ EXPECT_DECLS;
732+ #if defined(HAVE_DILITHIUM) && defined(WOLFSSL_WC_DILITHIUM) && \
733+ defined(WOLFSSL_DILITHIUM_PRIVATE_KEY) && defined(WOLFSSL_DILITHIUM_PUBLIC_KEY)
734+ dilithium_key* key = NULL;
735+ dilithium_key* importKey = NULL;
736+ WC_RNG rng;
737+ byte* privKey = NULL;
738+ word32 privKeyLen = DILITHIUM_MAX_KEY_SIZE;
739+ byte* pubKey = NULL;
740+ word32 pubKeyLen = DILITHIUM_MAX_PUB_KEY_SIZE;
741+ byte* origPub = NULL;
742+ word32 origPubLen = DILITHIUM_MAX_PUB_KEY_SIZE;
743+ int ret;
744+
745+ key = (dilithium_key*)XMALLOC(sizeof(*key), NULL, DYNAMIC_TYPE_TMP_BUFFER);
746+ ExpectNotNull(key);
747+ importKey = (dilithium_key*)XMALLOC(sizeof(*importKey), NULL,
748+ DYNAMIC_TYPE_TMP_BUFFER);
749+ ExpectNotNull(importKey);
750+ privKey = (byte*)XMALLOC(DILITHIUM_MAX_KEY_SIZE, NULL,
751+ DYNAMIC_TYPE_TMP_BUFFER);
752+ ExpectNotNull(privKey);
753+ pubKey = (byte*)XMALLOC(DILITHIUM_MAX_PUB_KEY_SIZE, NULL,
754+ DYNAMIC_TYPE_TMP_BUFFER);
755+ ExpectNotNull(pubKey);
756+ origPub = (byte*)XMALLOC(DILITHIUM_MAX_PUB_KEY_SIZE, NULL,
757+ DYNAMIC_TYPE_TMP_BUFFER);
758+ ExpectNotNull(origPub);
759+
760+ if (key != NULL) XMEMSET(key, 0, sizeof(*key));
761+ if (importKey != NULL) XMEMSET(importKey, 0, sizeof(*importKey));
762+ XMEMSET(&rng, 0, sizeof(WC_RNG));
763+
764+ ExpectIntEQ(wc_InitRng(&rng), 0);
765+ ExpectIntEQ(wc_dilithium_init(key), 0);
766+
767+ #ifndef WOLFSSL_NO_ML_DSA_44
768+ ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_44), 0);
769+ #elif !defined(WOLFSSL_NO_ML_DSA_65)
770+ ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_65), 0);
771+ #else
772+ ExpectIntEQ(wc_dilithium_set_level(key, WC_ML_DSA_87), 0);
773+ #endif
774+
775+ #if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY)
776+ /* Generate key then export private to simulate having only priv key */
777+ ExpectIntEQ(wc_dilithium_make_key(key, &rng), 0);
778+ ExpectIntEQ(wc_dilithium_export_private(key, privKey, &privKeyLen), 0);
779+ /* Export original public key for later comparison. */
780+ origPubLen = DILITHIUM_MAX_PUB_KEY_SIZE;
781+ ExpectIntEQ(wc_dilithium_export_public(key, origPub, &origPubLen), 0);
782+ ExpectIntGT(origPubLen, 0);
783+ #else
784+ /* Use built-in bench private keys when make_key not available */
785+ #ifndef WOLFSSL_NO_ML_DSA_44
786+ XMEMCPY(privKey, bench_dilithium_level2_key, sizeof_bench_dilithium_level2_key);
787+ privKeyLen = sizeof_bench_dilithium_level2_key;
788+ #elif !defined(WOLFSSL_NO_ML_DSA_65)
789+ XMEMCPY(privKey, bench_dilithium_level3_key, sizeof_bench_dilithium_level3_key);
790+ privKeyLen = sizeof_bench_dilithium_level3_key;
791+ #else
792+ XMEMCPY(privKey, bench_dilithium_level5_key, sizeof_bench_dilithium_level5_key);
793+ privKeyLen = sizeof_bench_dilithium_level5_key;
794+ #endif
795+ #endif
796+
797+ ExpectIntEQ(wc_dilithium_init(importKey), 0);
798+ /* Ensure importKey has the same security level set as key so import
799+ * functions that validate level do not fail. */
800+ #ifndef WOLFSSL_NO_ML_DSA_44
801+ ExpectIntEQ(wc_dilithium_set_level(importKey, WC_ML_DSA_44), 0);
802+ #elif !defined(WOLFSSL_NO_ML_DSA_65)
803+ ExpectIntEQ(wc_dilithium_set_level(importKey, WC_ML_DSA_65), 0);
804+ #else
805+ ExpectIntEQ(wc_dilithium_set_level(importKey, WC_ML_DSA_87), 0);
806+ #endif
807+ ExpectIntEQ(wc_dilithium_import_private(privKey, privKeyLen, importKey), 0);
808+
809+ /* At this point importKey should only have private key; derive public */
810+ ret = wc_dilithium_pub_from_priv(importKey);
811+ ExpectIntEQ(ret, 0);
812+
813+ pubKeyLen = DILITHIUM_MAX_PUB_KEY_SIZE;
814+ ExpectIntEQ(wc_dilithium_export_public(importKey, pubKey, &pubKeyLen), 0);
815+ ExpectIntGT(pubKeyLen, 0);
816+
817+ /* If we generated the original key, compare its public key to the one
818+ * derived from the imported private key. */
819+ #if !defined(WOLFSSL_DILITHIUM_NO_MAKE_KEY)
820+ ExpectIntEQ(origPubLen, pubKeyLen);
821+ ExpectIntEQ(XMEMCMP(origPub, pubKey, pubKeyLen), 0);
822+ #endif
823+
824+ wc_dilithium_free(importKey);
825+ wc_dilithium_free(key);
826+ wc_FreeRng(&rng);
827+
828+ XFREE(pubKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
829+ XFREE(origPub, NULL, DYNAMIC_TYPE_TMP_BUFFER);
830+ XFREE(privKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
831+ XFREE(importKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
832+ XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
833+ #endif /* HAVE_DILITHIUM && WOLFSSL_WC_DILITHIUM && PRIVATE+PUBLIC */
834+
835+ return EXPECT_RESULT();
836+ }
837+
729838int test_wc_dilithium_sign(void)
730839{
731840 EXPECT_DECLS;
0 commit comments