Coverage Report

Created: 2026-05-30 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/liboqs/tests/fuzz_test_sig_stfl_xmss.c
Line
Count
Source
1
/*
2
 * fuzz_test_sig_stfl_xmss.c
3
 *
4
 * Fuzz test for XMSS stateful hash-based signature verification in liboqs.
5
 * Targets OQS_SIG_STFL_verify for the following parameter sets as specified
6
 * in https://github.com/open-quantum-safe/liboqs/issues/2399:
7
 *   - XMSS-SHA2_10_256
8
 *   - XMSSMT-SHA2_20/2_256
9
 *
10
 * Baseline pk / message / signature bytes are copied from the KAT .rsp files
11
 * under tests/KATs/sig_stfl/xmss/ (count = 0 vectors). The fuzzer mutates
12
 * those inputs to detect crashes, memory errors, and undefined behaviour.
13
 *
14
 * SPDX-License-Identifier: MIT
15
 */
16
17
#include <stdbool.h>
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <string.h>
21
22
#include <oqs/oqs.h>
23
24
/* The two target algorithms specified in issue #2399 */
25
static const char *TARGET_ALGS[] = {
26
  "XMSS-SHA2_10_256",
27
  "XMSSMT-SHA2_20/2_256",
28
};
29
static const size_t NUM_TARGET_ALGS = 2;
30
31
/*
32
 * Fuzz input layout:
33
 *   [0]              algorithm selector byte (index into TARGET_ALGS)
34
 *   [1..pk_len]      mutated public key
35
 *   [pk_len+1..end]  mutated signature + message (split at sig_len boundary)
36
 */
37
38
typedef struct {
39
  OQS_SIG_STFL *sig;
40
  uint8_t *public_key;
41
  uint8_t *signature;
42
  size_t signature_len;
43
  uint8_t *message;
44
  size_t message_len;
45
} stfl_keypair_t;
46
47
/* One cached vector per target algorithm, initialised once */
48
static stfl_keypair_t cached[2];
49
static bool initialised = false;
50
51
/* XMSS-SHA2_10_256.rsp */
52
static const char KAT_XMSS_SHA2_10_256_PK_HEX[] =
53
    "00000001B901B8D9332FE458EB6DE87AF74655D0B5AD936A66FDB6AC9D1B8CF25BB6DB8404562AD35E8ECAFAAFDA16981CDAA147606BEEA62801342AF13C8B5535F72F94";
54
static const char KAT_XMSS_SHA2_10_256_MSG_HEX[] =
55
    "B338DD755D5618C464AB331F14DE3DD4A358BBA00D28FB35236741E902F7B248CE";
56
static const char KAT_XMSS_SHA2_10_256_SM_HEX[] =
57
    "00000000404DFF9B9F3931FE6158FFF355A8EE715C9BC6A87FE6627928F3CA1055FA7010C534B0D4C6FFDF4DBFE00E72405EFE83BBCF19AA2030A8CB163808482B6376FF8CE01FB8090F4842896A1EA5E9282F35CACD245A4B9DE9FE84E9315851D68A72B3ECB9F440937C8BA4AC3F0429246CBC2777E8B92D84F4BA49FAB89465FCB0FC8017E582746F531B4697925154A22E2D6A0F1B81913438000C295153D7ADCA8F852C50D360F65F887479E9631A2CA30FE3AD92E7BF648643835F4F8CC081A6C951B83B77608A08C021821DA61962CFCC8E97D75441921D39C5AD537543EFBAF0345DC70826E6E950929570C72E51619600C58D932A72657B19AF163E0B8F7AAF2949A5EB26C517909E0E663E36753491182975206009107509DFFC898D308B903E84A8B29718BF7125397AFF5467D53CF8F36EB945B6B98D48E81C0174A0E03541D24369CF8EDDA4288FFA615D16FBC7355CFC0966BA9256E5B8A44DA95760DFB61301B10FD3E82436E267DB089773E43B984297D1E0D395DCC77FCFECCEFEBD4B80B3F241872EA251DA466CA6C5324346F4B5E6886654A86592641A8C32AC554261B2D9130462C976B039E593F873AD1712820FF3E723FE57F137751AB3CA8B5B20D28D1B9384DF1D710AC39FAF699989418B7856C2034C695A693ECC336EB472DE5049C743089529695B028F2F72BE0893E59169E9A2376C64BC5CCAC5482E5A6E9C88D710A3FF8F23C206B09D314BF50568228B1BACF1CE330D529BD3793D7C7CD9EC770C111D9681D6F1B97D908CBBD436444853FEB47F234D31F5E92B9E0465D67AC0FE48859126BEFA7F7D121A67C2C2970B37B8081B4E73C5A21A41F60160A61FAFBD48649A3D2032C1679A67F348E3E25275FCD9AF650937FEB0A30F25878CEED7D6CA693518B5A2F5418135EA9316EFFDECDB1DFFC9EE3A62EFF0E66F3D05BD9D5F8679B536BB6D39792B28DF2481A6EECB9BEE40B11A10D39A90EA1AAC47BF956FBFE9B0427B599B9BC024F326515E71615419423FEC3F19F621D49B6EED59F129A6B1411B7B1AFCF073095D57B03F25A16F946ED716BF705F567A151BE85B8E8195CC2F070BFD482702182B8A4A43ED942F6BD3CBF9DE7E8AEB17C41E1C009C94FF4A2050E3731088B75474B38DC52BADF53C7DCD3FB98D023649FC4799CE060ADDACEC7CD4E656074E631C1CB8AEF88EFEE0817C2E3D79E287F4510E48DFB7E23CB49D6FCA39A1E0F471F16A8BB65AF02150D059036D00386DD287BEA4D52FB263B57AE5ADD901CADE838B1D7347D9E47EAF6456148C6C4E44B0FA3DFCF5C9CEC2D80AD509A65AEF0E3E663B7F31BCA437311BA799D4C2ACC138F85D73CB40792FF03F8F20427D951444990CA3976A71368A7DC1455E880722F06F02163BC712E852A914F22E5675EB9B1C6C8B7FD20A8880AD2EEF97982C065C937BD3639357E4C7450CBDA0B51CCA8E3E078DC760FD99EBF646B82369576539B2BD5B2C866ED5AE94423A5CE18C685352398D01C983F080D7BEB8A9243AAA9AC1DDCC1B058B92BEAD301E8F3B8F5EF71EEE7966302B44D2E26D2A02393713E5D4D3FEF42196FAA368274C78C2932D22840ECA6018CE7D16B19A0727CB1966EB28B57D137C5264CC2E627F24A3BAD50EA4F75C7BD8998709C01ED5ACFFF0891934E94DA2CACCA212FB48BE3F9EAA310547E73C388D881F36AE21EFEDD23744F6B07C5D6D2776C191ED41E607316F61BBEF7A20E1A03150AE833D18952AE35188FBFDFA55C12A388836717BB2BDD97E89121C56C3B53E8198242315C9E438512E0C8354A3E599CB7217AE688647A72985606BBD0720F6FA5C5B6F70E88234EE54C6DB0A41106C866564650829FE4B232635B06B18240C9F86369C75B2F7D237211A380C43F95D362E0680D9EA2CA47E1DC8C49703E22650B765F847AD86BE25A3B7630D640A0097632DF13F600E8A025DD9A1FC67B0EB09C1CA9FA3923896927DEE1E3CC0C81F4B82E43B89CACC69C9B8ADCA1670F7D4E50DB7BCD94C2115E75F2BFD2336DA5A304D0F3455927360BF5040E95D1454106F2A8A7CD27D5510E7B5BE7B5B9EDEFDC3D4249D655C51F4C1DBA0F359BE4769AB66EDBC802824E9AB866E8EEAA2FEB1CC855F0A745AAC84A610DF0238112C6519F8E7346C45331A6036F84D5B6250F4B5BC0A2A6A31DAF9C60EB13C20CC649A18E27A6C98B82F08E21706A8BDF338CC69C1679D25ECFF733A721211C1F6DD28091AAA9C93B047EFCD2C8A55F2DA65E616F07DCC0F44081D4E359C1688A00F062EC925D24432862B547BB70F2AF126A3DABA5C918B224DE444B8733E6FA601B3D349307E94583D0EC976AEDA2B90972324B3ACE8C7B79A67723AEA037E12DA9EFA9CA9668A4F5FDADFB9EEE13398921F5023E354A6894825431DBA7317E6A6F69F0E77294BCD02D7616E75AC31EC528FC070B8C34027C4E9CD0672903412FCA6B723650D56AF562069312FC7EF1891A77E1A3F29D810C205EE212E75863F3B8B1ED216DF888ADD07AFF45F1B5C01196329311414797CD5F67FFC54AAD04C803FF7E83C2E8BA224CE83695BB7916AC42B1861F5CB527FDBCD82DBFA31C5ACF981D8414203837504263C96A0015841FBCC721F96D50A86D6E096AB54AF9980F06CEE6341C78D6583F6BAE8081B3C44B0F10FB7300874B5011FF0F97C52F975A31355884C2F12B6FFEE20E8371D38183C9D04977BFA037C9BD4DD7F7CE203FD7FAD3852B3C2AE9D078ADEC70DB1A7140EF1114EBB03E8DE03237E0A27FF510015AC76FCEFE4EBD4C3A1B6C67DB2A82FE2B1BF18723DB0F29FE4AD47B2EEF22AC3C6661CFA7DA7476D23B470FA2E0441B6473EBD291791F09B4ADA70A5286EB05167BD59BFD8C464"
58
    "27413D60692382EFB7882F60DC53AAAFDF2014CA7D27F8FA93C187A8371B41796557AE739912E5991C713532E81FA57F9BA562E1D3026D2D2D7373D99871BC62768AD70D3DB184EABED83E30C11C9BC62F3340923A0082B987EC45CC7BD1DB4B2B15E8AD3EAD74E96D8C20D85617BBEDC0BDAF8ED48B7EE8D7C42990028EC0669AFC0861C22F2E9109F9BB35426BDDB4A69EB8F45CD5B226F92E8026F1E62DE1DE435A4FC0CAEDA91C38A88F0037BDB296CD7B07FF040B1E08F02711E946B307A5A38487F53070985B8E28BE6CCE809F34100F0CA780996CD38E91BA7773BB632D0BE7978F3AF3A92B961BD3A8759590726D6C1811F9E0BCA87377334E7C1F12FE37401CA0200823938C816ED98981521470F7F2CCDD69D85E7530EBF39E3A592B1C09BC6C352C3FDB108FB26E7ACD3D5A4FC0442962E2C09651AC0D026E370F1EE1A8219C4833D70793D6E581FD25B0E95FAB1EDA67232C2FA12C4E379A6627E75AD408C1D2526005F2567CED8608E88CF53064FCDC58007198ADFA860F9FED1DF80EFACC768A0A063E1AFEE6DF1BE3483105B1C45EB50BF7863B4278422CEBA9001EA00299AC0415BF28A9C49CC2E92FC15565B547538A027886C6EB0D83B71138CE1A";
59
/* XMSSMT-SHA2_20-2_256.rsp */
60
static const char KAT_XMSSMT_SHA2_20_2_256_PK_HEX[] =
61
    "00000001049D5FE86EA348F4C6D28583AA3F9F86C36156FD23AAE68BD09B104163E2E2EB04562AD35E8ECAFAAFDA16981CDAA147606BEEA62801342AF13C8B5535F72F94";
62
static const char KAT_XMSSMT_SHA2_20_2_256_MSG_HEX[] =
63
    "B338DD755D5618C464AB331F14DE3DD4A358BBA00D28FB35236741E902F7B248CE";
64
static const char KAT_XMSSMT_SHA2_20_2_256_SM_HEX[] =
65
    "000000404DFF9B9F3931FE6158FFF355A8EE715C9BC6A87FE6627928F3CA1055FA701095690ED3CAA8519B752CDFBACE3666EDC260EE5325F9EA849CF9DFE6CDAD655BFAEEE83253874CD01D7C5D07C53050812648A4891B86ED9B949459337CE4E48A389B5FA7E67C06E689894EBA9EF2B30A6E85FAE21DB5E8D5F6499CF1C5A59A6D7A8D490A5464AF68854E65606D09C887C8A95A511E76865A1B432139E0C164EEAEDB66976EB9610DA9403923B229A8A81AD64A8292003BCC9A8FBD97284FB83F255CA9569583D0B40DC8A5942B9284515CCD9497D7AC749BEFAB0032A08D412C0291B9F93EA852A8937854ABE02DA2E505DE98BE606DF1ECF315300F6145C26529510438E87AB06D786CF52C18D7F9C95D7B82F4F0E1AEB59E4221D40C67EB13EF80BB3601C44E35C901ABEE1EE25BFAAB80639021377FDA25672D97ED4126B888B571BCF4A34CE363BF227A5830ACB4844CB17A942625686FEB09DBDA47AF7568C4ED2AD3DC8191BE8F775AB35E37528F5B94BE4DDFF4E56600E488856881A622BB8619A78752AB810E1EF1E95A04A10597D7B674C38102590FA8BB21B909B3E05A4453E58D0D1EFC4EE285C0B3EB81F2DB7E57C22946C3ED1D4155D0A6041072FB2968834D281510FE4DCCE2D85ED825C3F2C646CB718C5C742C8E7694C288548F3B542B812369DE5C5B650683CCAA23D4B8BBEB833B694BE7EAB094F39BD8D4E6FC2CFF5A94DF26DA0C0170FD8713CFC44391EB96DA0957FD5066FD83C6A49E07417E807C087062711DCC7BBFA4B0D54077AD8DB142A191E6BA6BB2518374F77E9F7FB8C2790CBA9844A7FC11D1E6C38E1E9EA573E0A80CE46DB790375D915D3C1F311F819D63F288CAAC1F49DCEFCF8F9B30E025FB946B8A8520860ED5D425878CEED7D6CA693518B5A2F5418135EA9316EFFDECDB1DFFC9EE3A62EFF0E6647A2D39C98B01A8BA4A8B9FDFF89292303C02C3AEEC2EEDB69DB6CAB0F45463BA7A25D6C3E4B7D39A28A65A5628A93556FA9F54E273B583F9A197BFF4731E04237D992BAB4119585A36F7584D2B25A2263A428A218CF009BF9EB533839059E362FDFAC5E8EE98639254EB106410A8BEE8214C66A7BB81C99C989737A7EC3EDB303EDD88D20A7D32FE8E2735A21A0055B3473BA260666DC3A9CD83E3AE3B6FF7D7D8D5964AF6A4DDD928553D5D44D3A6ED501CED954E06F89F82D334C458125844219EE3DB69A83DDED1030CBEA57D3D2EFE8AE168D83856DA3FBADB0102D52C5EB3E72F1046CBFF94254043D879CA0B64F7BD7AEC79F5F87C11DE3DE80756E92F7BDF93266EA7D5A17B974C518C7024DE642D12B495063AC5363EF6C532E0D9C96AA96BFC9E1D6A851663336861DA97A10FFC00A4D5A8E4F1CA04A8C91FAB90CEA2895370C57B8BD4DAEBA7B426B8E8B3968A6ECA166D917889AEBDB335E3B8115DAFADB4F258D8BBED23B21C65486E46D8BCA833B6967A09FC7DA038DE146403C9AF2D41510FE1D89C15CE442C7FCE52DD7AEF5B65923DD8CE7C031E671882B33206242916D836656273E7BCF440A020F6BD2212AFED89DB1DF7C77FEDA1143CC52238532A9293D465022828337D62D54CD964879D20BD79F2F5C8042F16A9C2FB2E1A7013828FF9CFA9903E4C46D7F0A4409133EA2AF9207A68E5DF1EBB203398C519742B581D604C13E10DFEDBCAD3EB1F66133D21F83B2C15BA70E2084E20169B68E73B20457198BA678C4496B02F7124E0474EE3BB9B7107646385F85E396D5B6413A9FF0BC969B011DC3639F1798CE4EDACACC625459A25639F6F2C5C15DB24488CAC196FD09E1A5AA1ADF13D6A4316B27BABDF3ADD912C5D1A25114B322FAC7F9853AD29B44EAFA7AA9A4ED2471B0BC91B4E1FDB7E6A80056C0F264C07EA4901DD4FF16E8E94B742AB1BA0D9B7C12674D959DF58DA15C7E22363C8AE8B2D2003632CBB912A4F788E97B9BB1C7EED5532B3026F7B8574061C607F615F7BE429B3D9A386E40B99329DE24163911705BC3137F0C728AB5848532999315D2BFD2336DA5A304D0F3455927360BF5040E95D1454106F2A8A7CD27D5510E7B54E165DB2CBF8027EE9B5CF5EBCC9DD06A5C319E2B9611BE946B6020CE4D9DD7329B336BF3E1A68CE17D1FB3485EC4AE8A823AD73C293A8AD9C8A45B2313792CEC3A649FB0DB6EE6F511B9B48E3DA2B198695DF9ACDD096ED9BE58CB5A6DFE702D4F9CEF844F63D60F6E671DF4C58FA9737EF38E41D273D28CB5091AFD0A9857C87AD54963C2B8344F1B0B7D04CF60AF2F462FC9E118D52827FEA10BB9FFE8A0669C43C7F0FD2B44AFC59F5F1E04E13D3FAEC42EF2E5CE5C39BB7E9A671F6FC6AE6BF9D49BB099E99E115FB80548BDCA3276CA7DD2F3200DA1FC5724E17D63321E7518484F9CBC19EAA901C9B4359152FCD7C0E51C82C962FF3F9A68B4F8B30440B23AD28725612F5FB98FF740AFB457915740084644120ADD17B445078AAF541DDAAE3B630834D387AA4B42958AAFD178D333B9E1D92DDDDC028609DD1C65C57A704637AD2E628163EE49D33FFA1530ED03F0A3E771B74CCF546BEF58EF21DD186BD74BB36D42E7D9D5F94DD718412DD7417024BA0156A865CBF27A461847E450F0DD03D0B6940BF0A7A3D0DCF04FFA9F744E8EDE879679E9B2B30DF30EC5C8C9AB598E42C39CE458F83C500EFAE48C4B8B2B688A9AE8C84C68CCA9D73C640BF005BBEC6C139005A872F0D032278DDCFEE8E636303308F418F73E3FCB7B63464D0B798AF6C9717BBC5DEE4C9150E8B271E12B53D2DC24D62BB1B522696BA13C5F73022D8B7CF740D798573335CAA3B04CEE0BDCADCC2DFD20E920A0B83391E2CFA2E0441B6473EBD291791F09B4ADA70A5286EB05167BD59BFD8C46427"
66
    "413D6079846BE00FC21D586D7F2C2AF4FEF5A3F2E0AD8F4D487B9B6BF50ACE604177339912E5991C713532E81FA57F9BA562E1D3026D2D2D7373D99871BC62768AD70D676B893C9B7BEF24DF70145E4CE1DD2B660884C82FB0EE47D1473FDD0B8C4414011CBE8E48BFCBC428382A66B103B905C0CAB36A7511B1BD6E23F4C69073CBE6C22F2E9109F9BB35426BDDB4A69EB8F45CD5B226F92E8026F1E62DE1DE435A4FC0CAEDA91C38A88F0037BDB296CD7B07FF040B1E08F02711E946B307A5A38487F53070985B8E28BE6CCE809F34100F0CA780996CD38E91BA7773BB632D0BE7978F3AF3A92B961BD3A8759590726D6C1811F9E0BCA87377334E7C1F12FE37401CA0200823938C816ED98981521470F7F2CCDD69D85E7530EBF39E3A592B1C09BC6C352C3FDB108FB26E7ACD3D5A4FC0442962E2C09651AC0D026E370F1EE1A8219C4833D70793D6E581FD25B0E95FAB1EDA67232C2FA12C4E379A6627E75AD408C1D2526005F2567CED8608E88CF53064FCDC58007198ADFA860F9FED1DF80EFACC768A0A063E1AFEE6DF1BE3483105B1C45EB50BF7863B4278422CEBA9001EA00299AC0415BF28A9C49CC2E92FC15565B547538A027886C6EB0D83B71138CE1A14BCBE4FA64052B0853EDE00CD41BF95B66DA2A519216FA1A0A8BA5F10B4EAFD8BE62C40DA2A76DFD8A5EE8EF42A8B808C55A533FC488A2B33A935A635E24F3E0C717E2320FF575ADDB18C567B1333DECB0855E069D5759C48FE6D8C6A9D217BFCB7A9D40735A3151382E3456CC4BEDF6C7EC94F186FCB6BF9398FEC934714E8E231402FC7BD5153981C7C789B26208DDD77E4796F70D6A72B7B9C5EC75E4E3CD122F72621E92B1AC515A33B12B1801B2C3E461AF788661815E6BAD2E6472116B89B941A0E68A232089C6F831229BE2EB0CD244BE4FED78C8371D2DC614445C76907F4A3EDF18722BF0998FD03209C31C348CC79A2AD06ABB1B3CC549E73B206A05345EC801A1C5C42D794BA1A35747493D76CA8567B62F0C2151923D8D9CD2F37D77E70EF7E12A80A3DC73CE284F2BAAE3816C351BAF037F5FBDF29A970BB385C19D6AC3BDECA5BE59F322A17FBAFF466E945FBB943BFE35854802837FEFEA3937069240712886742E890428C0C21BC057E82D5BB961095A5A18DE149CD19F79E9DC3CF0FEB5149F856C5A7BB82B6AFD4B5310993D9E4E1D33B4CC601265906186B98CAB4AF1570CFDC928C0A221A3BBFFE8E566D580A689AB51BB69826FA60135F60C1A1EA97CCCC9AE96CC93B66942370BCF910D916CBB7F87A0BF5EF46DFEBB050637754B0E40509441E19465B238EA45270D7BF5E0610A89B4A47AA821D9A3BA58127DDCEE4E7204C38E0EEDDFF72B07FA5AD8EB1FA89554D940C2C88EF588F62EA602BA30FA9ECF3462711612B3E1AC0CDC4C11C85ABB04AE5966743689380FD336A081B8C7F753B889BD73F10345B8C4988A7A4C865250E3707A8424B606059E3ACEA75F2F732058477097D5BF8F5A2DF82E4AF0EE9C4BB251A5657C15808B7EF26806E2F3D61137B44C9DF4196A9208065ED1C70F9DCE3C75AFD719F14D79818812360E4709E521E78B983F99B31863039069D3F86FFAAF318853EB4A1AFFC5E598ACB6B15198E016C779BB7D77C54971E4566C2071EDFC0D19B41827913C5F7EE5D8A9411AB2706F3C9DD8E2CF4AF497765A647C1AA42E3645485AD6598A776E2A46C9609C73AADC67A7477172D9F497556348B5CC055D8A6A0A752E5B9A508BCDC346BD1AD8643FA19EB36D922A018690D37D0E437857A78C47291B3530D6094FDEDB782E1C927C11235EE632F6C3FA150DE1BC1125FEB330079EDB0733B58F1CDD3D20904F85DE31C06FE375E7D1E20F4C79484C5431A026EF8F5C8AC47E7FEA2A80E17256ED956484E9004BD99AD8ECD0D1EE5790A83CF9A14827C3B5D5C25AA18255F5D512917BC1FA868AF35ED3540BF0C10CABB267F612C26AE27DEDB5665A4DE3913AA2631C034C1BD22E5A721194BE6D1E4337D1CF488E9F438BF7F77A856295E0D55A3AF7F55BEF0D7643D85B8892A69304AB1FECE1EA498B7DA996B2692EB8C3D1D8BC9BECCFECC8EC67EE3A87DF5B0B9C7C887DCB0CBA7F5E1372399F3A4F4CC7DF247752994CE0D024D2C6E620EDD0B8CD30891FAF58D6603D01C8308F95620A16B4B993AEC83DC9E71A16C2D22B89E7CF8290DB074AA6092A1F23DCD01D8B8C70674D55670C07A6D0655CF37D0516E6E1102865F0C53C5AF80A45B09B078337D61AFBD12DA2820AE45CC4B213C00576FF3D5FC21D0DB8D877757226F81078653EB4C90C0D2C7D304A6E0C4265DC3C1DB343202664008385964C6C56FA11532D7CF41E93F92EF28F3DE2CA1D5817AF2114A97BDA7F6504EBB2A6EE6BF4753274BE064D3CE467673717AD7350DE4E83A1BA27306F11DF36A2E30572E3FEF2EF6B2518419395DA9B7D4B191C88F3A863A477A2D226E5BCC04E39AAF1AA042A7B115CA26BE8DA52A162FDCEC6E511B1497FFB8B8AD23D3C429F71236DCAF9DE275D7B1D2DBE83822FF7D8C9BC7BA3AB5CB517228AFE2E30C53E64C44D02CF9CB51CE371827CDBDF798B1723B418EC7CDF66CF09F444A06DDB94355F529337D6A3178D754D68BE658934FEABD4F4874B11E739F0EE4E95D2D23B41F037B9668C9F74D2B3D31027861779FF8516A29246D766D2A61A02CD5B8E338B9630E8E0ED5BDACB017A6D3B89C8A1108E525BAD96E203E7A0C0B7F2148274FD20F9B53601F2B38DF303D7F8785D06260485D7507782E11855EA62F44C755E11DC4E5E06CA263A2E6D229726B08A66962C1AAFE0B85A896D3A21AB0E695CCF3818C69AE16DC71782D99440EC9AF4A9C33FFBC728C9C62C47E0D"
67
    "37CEA661064246A8B2BBA14ABF5767F33E490AEAD721929515F091663B4437BDC34F5B15C7816B7C5CC8035F4FDDB37C9A09712BA1A8E1FB4E0D8B37F0BEABA9D1ACFFBD90B13035960ABEF4E3CFF91B9871E49B16A6F0FF86445C441921D2E698117109D810C864F024F62F8D25C263CADA33916763373D76EC8955ED113F71C40834E79A1BD5E21CC2373598C66168492FFCD083D2A8E7E480F76274C048719AFF98C5E2774BB1039646BD25A240875655A77023B7F884F5852DCD9C5DA173DACEF7F01F6527CB7F5375FEC1FD2D5C90A46D3D0501715B2D4CF51166226D8F35DB7A9ABE320E88F04F460F239DC2C0B65987ADB734C1F9068B89F56E3ABB3B35C1EDBF72E5CE393330FF905F02DA9C591FAC66CBAF1FF1DABB3B199AC4A764EB5272AC230107F230E29845C2E2283763A5832809AF2428C304C07CB21A96D7B7CDADF857F54C91A22B8AE6E4EDC0DEE01FA60697269BB1299F9FD7D3699D4D865A25BF0F31F93DAE1D51C42FE755219BC2A4B2505487483A1B81BFA86BF6A99642C51AC3DC78D5E42FEA4ADCC51C0501A8FD543217134694262E0FF5957CE719766EB0CB34CA2E541992CC2619C65822A763FE6572E3B33C4C8C216B4A62A13BE7FE6FEA1DA8EC1D45CE65C4DFD09532FDAF74F99152DDBF0AAA53806F2C4EB3A156D49ED44C7713B7A50EEEBC575166A1B6CC3AEC2CA98398971F648242C35E8EAA21257BFAC587485D48AC54BC306344EDEBBF2A42B7E37B6086B1D9F54255742F000794155E7245F6CAE1088C20619158F78F7B9554B43C2872DC68AAB415F3065688612EC88D83577278C8A7B64334993F80BE7EDCBF5CEF5B00A2FC5B0CA04564DB35EE027BFB28DA1A7EEE4E72E366A22F6B50780F70355DA825FC2101BF7A057E5D26BF4216269A4C807F6B2055367D88910FBC65533CD0EDE915232B023D039AE21A53217DCF8398A5B70C3F2F1820F5CE459DFBFE7C3C9387F93D488D001F20B039229A704FF0193076F164C378E0AD63A1F11BD3332FAD6A4A6F39302C69607400E8A4B9D9EC1682E88656CF619DE7BA7384B1FD26850B80702BEE5893A4AB526F983AE3F8AD933B2D60CAF51BAAA828B87F55357DDC75A69F41F46493810EB69B9289F0954C9B9AA0A9C4B5B739BB75617C38ECBFE977BE182BE7EEBA3DE73A9F25E491756D4AE3BA047A9542BF62A8AEF9BA9025AAFECBA1F25590F7";
68
69
/* Decode even-length hex ASCII into out[0..out_len-1]. Returns OQS_SUCCESS or OQS_ERROR. */
70
0
static OQS_STATUS hex_decode(const char *hex, uint8_t *out, size_t out_len) {
71
0
  size_t hlen = strlen(hex);
72
0
  if (hlen != out_len * 2) {
73
0
    return OQS_ERROR;
74
0
  }
75
0
  for (size_t i = 0; i < out_len; i++) {
76
0
    unsigned char c0 = (unsigned char)hex[2 * i];
77
0
    unsigned char c1 = (unsigned char)hex[2 * i + 1];
78
0
    unsigned v0, v1;
79
0
    if (c0 >= '0' && c0 <= '9') {
80
0
      v0 = c0 - (unsigned char)'0';
81
0
    } else if (c0 >= 'A' && c0 <= 'F') {
82
0
      v0 = 10 + c0 - (unsigned char)'A';
83
0
    } else if (c0 >= 'a' && c0 <= 'f') {
84
0
      v0 = 10 + c0 - (unsigned char)'a';
85
0
    } else {
86
0
      return OQS_ERROR;
87
0
    }
88
0
    if (c1 >= '0' && c1 <= '9') {
89
0
      v1 = c1 - (unsigned char)'0';
90
0
    } else if (c1 >= 'A' && c1 <= 'F') {
91
0
      v1 = 10 + c1 - (unsigned char)'A';
92
0
    } else if (c1 >= 'a' && c1 <= 'f') {
93
0
      v1 = 10 + c1 - (unsigned char)'a';
94
0
    } else {
95
0
      return OQS_ERROR;
96
0
    }
97
0
    out[i] = (uint8_t)((v0 << 4) | v1);
98
0
  }
99
0
  return OQS_SUCCESS;
100
0
}
101
102
2
static void cleanup_cached(void) {
103
6
  for (size_t i = 0; i < NUM_TARGET_ALGS; i++) {
104
4
    if (cached[i].sig != NULL) {
105
0
      OQS_MEM_insecure_free(cached[i].public_key);
106
0
      OQS_MEM_insecure_free(cached[i].signature);
107
0
      OQS_MEM_secure_free(cached[i].message, cached[i].message_len);
108
0
      OQS_SIG_STFL_free(cached[i].sig);
109
0
      cached[i].sig = NULL;
110
0
    }
111
4
  }
112
2
}
113
114
typedef struct {
115
  const char *pk_hex;
116
  const char *msg_hex;
117
  const char *sm_hex;
118
} kat_hex_triple_t;
119
120
static const kat_hex_triple_t KAT_HEX[NUM_TARGET_ALGS] = {
121
  { KAT_XMSS_SHA2_10_256_PK_HEX, KAT_XMSS_SHA2_10_256_MSG_HEX, KAT_XMSS_SHA2_10_256_SM_HEX },
122
  { KAT_XMSSMT_SHA2_20_2_256_PK_HEX, KAT_XMSSMT_SHA2_20_2_256_MSG_HEX, KAT_XMSSMT_SHA2_20_2_256_SM_HEX },
123
};
124
125
/*
126
 * Load KAT vectors once at startup. Avoids XMSS key generation cost.
127
 */
128
2
static OQS_STATUS init_vectors(void) {
129
6
  for (size_t i = 0; i < NUM_TARGET_ALGS; i++) {
130
4
    cached[i].sig = NULL;
131
4
    cached[i].public_key = NULL;
132
4
    cached[i].signature = NULL;
133
4
    cached[i].message = NULL;
134
4
  }
135
136
2
  for (size_t i = 0; i < NUM_TARGET_ALGS; i++) {
137
2
    OQS_SIG_STFL *sig = OQS_SIG_STFL_new(TARGET_ALGS[i]);
138
2
    if (sig == NULL) {
139
2
      fprintf(stderr, "ERROR: %s not enabled at compile-time.\n",
140
2
              TARGET_ALGS[i]);
141
2
      cleanup_cached();
142
2
      return OQS_ERROR;
143
2
    }
144
0
    cached[i].sig = sig;
145
146
0
    cached[i].public_key = OQS_MEM_malloc(sig->length_public_key);
147
0
    cached[i].signature = OQS_MEM_malloc(sig->length_signature);
148
0
    cached[i].signature_len = sig->length_signature;
149
0
    cached[i].message_len = strlen(KAT_HEX[i].msg_hex) / 2;
150
0
    cached[i].message = OQS_MEM_malloc(cached[i].message_len);
151
152
0
    if (!cached[i].public_key || !cached[i].message || !cached[i].signature) {
153
0
      fprintf(stderr, "ERROR: OQS_MEM_malloc failed for %s.\n",
154
0
              TARGET_ALGS[i]);
155
0
      cleanup_cached();
156
0
      return OQS_ERROR;
157
0
    }
158
159
0
    if (hex_decode(KAT_HEX[i].pk_hex, cached[i].public_key,
160
0
                   sig->length_public_key) != OQS_SUCCESS) {
161
0
      fprintf(stderr, "ERROR: KAT pk hex length mismatch for %s.\n",
162
0
              TARGET_ALGS[i]);
163
0
      cleanup_cached();
164
0
      return OQS_ERROR;
165
0
    }
166
0
    if (hex_decode(KAT_HEX[i].msg_hex, cached[i].message,
167
0
                   cached[i].message_len) != OQS_SUCCESS) {
168
0
      fprintf(stderr, "ERROR: KAT msg hex for %s.\n", TARGET_ALGS[i]);
169
0
      cleanup_cached();
170
0
      return OQS_ERROR;
171
0
    }
172
0
    if (hex_decode(KAT_HEX[i].sm_hex, cached[i].signature,
173
0
                   sig->length_signature) != OQS_SUCCESS) {
174
0
      fprintf(stderr, "ERROR: KAT sm hex length mismatch for %s.\n",
175
0
              TARGET_ALGS[i]);
176
0
      cleanup_cached();
177
0
      return OQS_ERROR;
178
0
    }
179
0
  }
180
0
  return OQS_SUCCESS;
181
2
}
182
183
0
static OQS_STATUS fuzz_sig_stfl_xmss(const uint8_t *data, size_t data_len) {
184
0
  if (data_len < 1) {
185
0
    return OQS_ERROR;
186
0
  }
187
188
  /* Select target algorithm from first byte of fuzz input */
189
0
  size_t alg_idx = data[0] % NUM_TARGET_ALGS;
190
0
  stfl_keypair_t *kp = &cached[alg_idx];
191
0
  OQS_SIG_STFL *sig = kp->sig;
192
193
0
  const uint8_t *fuzz_data = data + 1;
194
0
  size_t fuzz_len = data_len - 1;
195
196
  /*
197
   * Build mutated public_key, signature, and message from fuzz input.
198
   * Use the real sizes from the sig object but fill with fuzzed bytes.
199
   * If fuzz input is too short, zero-pad.
200
   */
201
0
  size_t pk_len = sig->length_public_key;
202
0
  size_t sig_len = kp->signature_len;
203
0
  size_t msg_len = kp->message_len;
204
205
0
  uint8_t *mutated_pk = OQS_MEM_malloc(pk_len);
206
0
  uint8_t *mutated_sig = OQS_MEM_malloc(sig_len);
207
0
  uint8_t *mutated_msg = OQS_MEM_malloc(msg_len);
208
209
0
  if (!mutated_pk || !mutated_sig || !mutated_msg) {
210
0
    OQS_MEM_insecure_free(mutated_pk);
211
0
    OQS_MEM_insecure_free(mutated_sig);
212
0
    OQS_MEM_insecure_free(mutated_msg);
213
0
    return OQS_ERROR;
214
0
  }
215
216
  /* Start from KAT values, then overwrite with fuzz bytes */
217
0
  memcpy(mutated_pk, kp->public_key, pk_len);
218
0
  memcpy(mutated_sig, kp->signature, sig_len);
219
0
  memcpy(mutated_msg, kp->message, msg_len);
220
221
0
  size_t offset = 0;
222
223
0
  if (offset < fuzz_len) {
224
0
    size_t copy = (fuzz_len - offset) < pk_len ? (fuzz_len - offset) : pk_len;
225
0
    memcpy(mutated_pk, fuzz_data + offset, copy);
226
0
    offset += copy;
227
0
  }
228
0
  if (offset < fuzz_len) {
229
0
    size_t copy = (fuzz_len - offset) < sig_len ? (fuzz_len - offset) : sig_len;
230
0
    memcpy(mutated_sig, fuzz_data + offset, copy);
231
0
    offset += copy;
232
0
  }
233
0
  if (offset < fuzz_len) {
234
0
    size_t copy = (fuzz_len - offset) < msg_len ? (fuzz_len - offset) : msg_len;
235
0
    memcpy(mutated_msg, fuzz_data + offset, copy);
236
0
  }
237
238
  /*
239
   * Call OQS_SIG_STFL_verify with mutated inputs.
240
   * We expect OQS_ERROR for invalid inputs — a crash here is a bug.
241
   */
242
0
  OQS_SIG_STFL_verify(sig, mutated_msg, msg_len, mutated_sig, sig_len,
243
0
                      mutated_pk);
244
245
0
  OQS_MEM_insecure_free(mutated_pk);
246
0
  OQS_MEM_insecure_free(mutated_sig);
247
0
  OQS_MEM_secure_free(mutated_msg, msg_len);
248
249
0
  return OQS_SUCCESS;
250
0
}
251
252
4
int LLVMFuzzerInitialize(int *argc, char ***argv) {
253
4
  (void)argc;
254
4
  (void)argv;
255
4
  OQS_init();
256
4
  if (OQS_SUCCESS != init_vectors()) {
257
4
    return -1;
258
4
  }
259
0
  initialised = true;
260
0
  return 0;
261
4
}
262
263
2
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
264
2
  if (!initialised) {
265
2
    return -1;
266
2
  }
267
0
  fuzz_sig_stfl_xmss(data, size);
268
0
  return 0;
269
2
}