Back to DashboardHardware InfrastructurePhase 7 · Vendor & Supply Chainadvanced90 min

ACVP Lab Workflow: From Vector Set to Evidence

How algorithm validation testing runs end to end — and how to state a result at exactly the evidence level it reached.

Why this matters: A passing test is only evidence for the exact operation, parameters, build and source it was run against. Laboratories, vendors and buyers who blur a public reference sample, an ACVTS-issued vector set and a validation certificate make claims no evidence supports.

Start here: Classify ten real-world test-log observations into the evidence classes, then see the highest claim each one supports and the overclaim it tempts you into.

Practice in the Simulation

Reviewed and signed off by the PQC Today owner on 1 November 2026

Not yet reviewed by an accredited laboratory or certification body. It is not a laboratory training resource and not a substitute for an accredited testing laboratory. Every factual statement cites its primary source; where the Hub Library does not carry a source yet, the citation links the source directly.

PQC Today executes selected public reference vectors, standards tests, conformance cases, and implementation probes. A passing result is evidence only for the identified test, operation, parameters, implementation build, and target. It is not an ACVTS verdict, a CAVP/CMVP certificate, or proof of exhaustive conformance.

General security practitioner route

Focus on the lifecycle and claim boundaries: a passing sample, an ACVTS disposition and a validation certificate are different evidence.

This is the algorithm-testing companion to PQC Network Testing & Validation, whose workshop walks the ACVP workflow at overview level. Here the same workflow is taken apart the way a testing laboratory meets it: what a registration commits you to, what each test type asks the implementation to do, where a PKCS#11 interface cannot follow, and how to state a result without claiming more than the evidence shows. The programme landscape itself (who runs CAVP, CMVP and the testing labs) is covered in Standards, Certification & Compliance Bodies.

Revision discipline: ACVP is a moving protocol family

The core protocol used here is draft-ietf-acvp-spec-01, an independent draft whose name has stayed the same while NIST has kept revising its protocol sections in the repository (the latest change is dated 16 October 2025); this module pins it by repository commit [ACVP spec]. What changes is the algorithm JSON specifications, which evolve separately, so evidence must name the exact core draft, algorithm-specification revision, operational environment and vector-set source.

The eight evidence classes and the nine-rung claim ladder in this module are PQC Today’s own scale for describing test results; NIST does not define one. The scale prevents a public ACVP-Server sample, an imported prompt and an ACVTS-issued vector set from being reported as if they were interchangeable.

Algorithm Validation vs Module Validation

Two NIST programmes are routinely blurred together. The Cryptographic Algorithm Validation Program (CAVP) validates implementations of approved algorithms and their components; NIST calls algorithm validation “a prerequisite of cryptographic module validation” [CAVP]. The Cryptographic Module Validation Program (CMVP), run jointly by NIST and the Canadian Centre for Cyber Security, validates whole cryptographic modules to FIPS 140-3, using independent NVLAP-accredited Cryptographic and Security Testing (CST) laboratories [FIPS 140-3].

  • What is tested?
    Algorithm validation (CAVP)
    An algorithm implementation, by comparing its outputs with known or expected answers [CMVP Management Manual §1.4]
    Module validation (CMVP)
    A defined module against FIPS 140-3’s eleven requirement areas — module specification, interfaces, roles/services/authentication, software/firmware, operating environment, physical, non-invasive, SSP management, self-tests, life-cycle assurance, mitigation of other attacks — at one of four security levels [FIPS 140-3]
  • Which algorithms?
    Algorithm validation (CAVP)
    Approved algorithms; NIST points to SP 800-140C and SP 800-140D for the lists [CAVP] [SP 800-140Cr2]
    Module validation (CMVP)
    The approved algorithms the module claims; the lab confirms each complies with all requirements of its standard, including those CAVP tests do not reach [CMVP Management Manual §2.6.2]
  • How is it run?
    Algorithm validation (CAVP)
    Black-box, through the Automated Cryptographic Validation Testing System (ACVTS): the implementation is never sent to NIST [CAVP]
    Module validation (CMVP)
    A CST laboratory tests the module, reviews documentation and source, and submits a report to the CMVP validation authorities [CMVP Management Manual §2.6.2]
  • What is published?
    Algorithm validation (CAVP)
    An algorithm validation certificate on the CAVP validation list [CAVP]
    Module validation (CMVP)
    A module certificate; its entry links to the CAVP certificates of the algorithms the module uses [CMVP Management Manual §4.9.3.5]

Algorithm testing does not cover every algorithm requirement

The CMVP Management Manual requires the laboratory to confirm compliance with the algorithm standards’ “shall” statements that CAVP testing does not address [CMVP Management Manual §2.6.2]. The ACVP sub-specifications say the same from the other side: the ML-DSA test types do not test zeroization of intermediate values, DRBG strength, or incorrect-length keys and signatures [ACVP ML-DSA sub-spec]. The ML-KEM sub-specification carries the same list word for word, including “signatures”, which ML-KEM does not produce: the section was copied from ML-DSA [ACVP ML-KEM sub-spec].

Where this Hub stands: it runs neither programme. It executes selected public reference vectors, standards tests, conformance cases and probes, and its results are never an ACVTS verdict or a CAVP/CMVP certificate (see the notice at the top of this page).

The module side (security levels, the Modules In Process queue, and the CMVP routes for adding ML-KEM or ML-DSA to an already-validated module) is taught in FIPS 140-3 Certification.

Capability Registration & Vector-Set Negotiation

ACVP testing starts with the client, not the server. A registration is the client’s description of the capabilities of one or more algorithm / mode / revision combinations [ACVP spec §3.2.2]. ACVTS generates test cases that match those capabilities and hands the inputs to the implementation [CAVP]. Each algorithm in the registration becomes one test vector set (identified by vsId), made of test groups (tgId) that share properties, made of test cases (tcId) [ACVP spec §5.4].

The registration below is the ML-DSA sigGen example from the ACVP ML-DSA sub-specification, with its hash list shortened. Every array is a promise: the server will generate test groups for combinations of these values, and the implementation has to answer all of them [ACVP ML-DSA sigGen registration] [ACVP ML-DSA sub-spec].

{
  "algorithm": "ML-DSA",
  "mode": "sigGen",
  "revision": "FIPS204-tr1",
  "prereqVals": [{ "algorithm": "SHA", "valValue": "123456" }],
  "capabilities": [{
    "parameterSets": ["ML-DSA-44", "ML-DSA-65", "ML-DSA-87"],
    "messageLength": [{ "min": 8, "max": 65536, "increment": 8 }],
    "hashAlgs": ["SHA2-256", "SHA2-512", "SHAKE-256"],
    "contextLength": [{ "min": 0, "max": 2040, "increment": 8 }]
  }],
  "deterministic": [true, false],
  "externalMu": [true, false],
  "signatureInterfaces": ["external", "internal"],
  "preHash": ["pure", "preHash"],
  "keyFormats": ["expanded", "seed"]
}
  • deterministic: [true, false] commits the implementation to both signing variants, including hedged groups that carry the server’s randomness [ACVP ML-DSA sub-spec].
  • signatureInterfaces: ["internal"] commits it to answering ML-DSA.Sign_internal on a formatted message, and externalMu: [true] to accepting a message representative μ computed outside the module [ACVP ML-DSA sigGen registration] [FIPS 204 Alg. 7].
  • prereqVals names prerequisite algorithm validations (here SHA) [ACVP ML-DSA sigGen registration].
  • The revision is part of the identity: the sub-specification lists ML-DSA / sigGen as both FIPS204 and FIPS204-tr1, “a new test revision against the same standard” [ACVP ML-DSA supported revisions].

Register what you can answer, not what you implement

A module may implement hedged signing and still be unable to answer a hedged sigGen test, because the test must inject the randomness. The registration therefore has to match what the test harness can drive, not just what the product does. The Hub’s own ACVP-format prototype makes the same decision in reverse: it accepts only the algorithm / mode / revision triples it pins, and rejects any other with a diagnostic rather than guessing a closest revision.

Prompt → Response → Disposition → Validation

The ACVP specification’s minimal message flow has six exchanges [ACVP spec §12.4]:

  1. 1

    Register capabilities POST /testSessions

    The registration lists each algorithm / mode / revision and the options the implementation supports. The server answers with a test session and one vector-set URL per algorithm.

  2. 2

    Download each prompt GET /testSessions/{id}/vectorSets/{vsId}

    The prompt (the spec also calls it the request) holds test groups (tgId) of test cases (tcId). Exactly one prompt exists per vector set.

  3. 3

    Submit the response POST …/vectorSets/{vsId}/results

    The client returns the implementation’s output for every test case, linked to the prompt by vsId.

  4. 4

    Read the disposition GET …/vectorSets/{vsId}/results

    The server reports a disposition for the vector set and for each test case: passed, fail, incomplete, expired, missing or unreceived. “error” applies to the vector set only, not to individual test cases.

  5. 5

    Certify the session PUT /testSessions/{id}

    Allowed only when the session is both publishable and passed. The request associates the module and its operational environment (OE) and lists any prerequisite validations.

  6. 6

    Retrieve the validation GET /requests/{requestId}

    The certification is a request; once approved it yields the identifier of the validation record.

Sources for the steps: [ACVP spec §5.4] [ACVP spec §12.16.4] [ACVP spec §12.17.4].

Details that decide what a result means

A passed disposition means every test case in the vector set was processed and passed, and indicates the algorithm is ready for validation — it is not itself the validation [ACVP spec §5.4, §12.17.4].

A session created with isSample: true lets the client retrieve the expected results, and its vector sets may be smaller [ACVP spec §12.16, §12.17.7]. For a validation authority, vector sets are one-time use: an old vector set can never be reused to obtain a new certificate [ACVP spec §14].

NIST runs two ACVTS environments. Demo is a semi-volatile sandbox for testing implementations and ACVP clients. Prod is restricted to accredited CST laboratories and 17ACVT laboratories; a lab may run an algorithm in Prod only after running it at least once through certification in Demo [Accessing the ACVTS]. Only Prod creates the algorithm validation certificates on the CAVP list [CAVP].

Map this onto the Hub’s claim ladder and the boundary is exact: generating a response to an issued prompt is rung 7; the disposition is rung 8; a published validation record is rung 9. The Hub’s ACVP-format prototype stops at local import and response export — it has no ACVTS session, credentials, submission or verdict retrieval.

AFT, VAL, MCT and Algorithm-Specific Test Types

A test type describes the format of a test rather than its intention; several tests of the same type can cover different assurances [ACVP ML-DSA sub-spec]. The vocabulary is defined per algorithm, in each ACVP sub-specification:

  • SHA-1 / SHA-2
    Test type
    AFT
    What the implementation must do
    Hash single, multiple and partial blocks of random data — checks chunking and padding [ACVP SHA sub-spec]
  • SHA-1 / SHA-2
    Test type
    MCT
    What the implementation must do
    Monte Carlo Test: from one seed, run 100 × 1,000 chained hashes where each digest feeds the next message; aimed at state, allocation and error-handling faults [ACVP SHA sub-spec]
  • SHA-1 / SHA-2
    Test type
    LDT
    What the implementation must do
    Large Data Test: hash a multi-gigabyte message described, not transmitted, by the prompt [ACVP SHA sub-spec]
  • ML-KEM / keyGen
    Test type
    AFT
    What the implementation must do
    Generate a key pair from a provided seed (ML-KEM.KeyGen_internal) [ACVP ML-KEM sub-spec]
  • ML-KEM / encapDecap
    Test type
    AFT
    What the implementation must do
    Encapsulate with a server-chosen m (ML-KEM.Encaps_internal) and return c and k [ACVP ML-KEM sub-spec]
  • ML-KEM / encapDecap
    Test type
    VAL
    What the implementation must do
    Decapsulate valid or modified ciphertexts (ML-KEM.Decaps_internal), or decide whether an encapsulation key (FIPS 203 §7.2) or decapsulation key (§7.3) is valid [ACVP ML-KEM sub-spec]
  • ML-DSA / keyGen, sigGen, sigVer
    Test type
    AFT
    What the implementation must do
    Key pair from a seed; signatures compared with the server’s known signature; validity decisions on modified signatures [ACVP ML-DSA sub-spec]
  • SLH-DSA / keyGen, sigGen, sigVer
    Test type
    AFT
    What the implementation must do
    Key pair from SK.seed, SK.prf and PK.seed; signatures from provided keys and randomness; validity decisions on modified signatures [ACVP SLH-DSA sub-spec]

Minimums are part of the test design

The sub-specifications fix minimum test counts per combination of capabilities — for example at least 15 ML-DSA sigGen tests and at least 3 ML-DSA sigVer tests per modification type [ACVP ML-DSA sub-spec], and at least 13 SLH-DSA sigGen tests [ACVP SLH-DSA sub-spec]. ML-DSA sigGen also requires tests that drive every rejection path of ML-DSA.Sign_internal, and tests that force at least 32 rejections, on the internal, deterministic interface [ACVP ML-DSA sub-spec].

A single passing case per parameter set is therefore a sample of an ACVP test type, never its coverage.

Deterministic vs Randomized Algorithms

FIPS 203, 204 and 205 each split their algorithms into an external interface, which generates its own randomness, and an internal interface that takes the randomness as an input. Tests that must supply the random input use the internal interfaces; the current ACVP ML-DSA specification supports testing both the internal and the external interface [ACVP ML-DSA sub-spec §6.1.2]. Each standard says they should not be offered to applications other than for testing, because the random values shall be generated by the module [FIPS 203 §6] [FIPS 204 §6] [FIPS 205 §9].

  • ML-KEM.Encaps
    Randomness
    32-byte m drawn inside the module; Encaps_internal(ek, m) takes it as input [FIPS 203 Alg. 17, 20]
    Consequence for testing
    Byte-exact testing needs the internal interface with the server’s m.
  • ML-DSA.Sign
    Randomness
    Default hedged: rnd from an RBG. Optional deterministic: rnd = 32 zero bytes; that is the only difference [FIPS 204 §3.4, Alg. 2, Alg. 7]
    Consequence for testing
    Deterministic signatures can be compared byte for byte; hedged ones only if the test can inject rnd.
  • SLH-DSA sign
    Randomness
    Default hedged: opt_rand = addrnd. Deterministic: opt_rand = PK.seed [FIPS 205 §9.2, Alg. 19]
    Consequence for testing
    Same split as ML-DSA.

FIPS 204 treats the variants differently for security, not only for testing: hedged signing helps mitigate side-channel attacks, the deterministic variant “should not be used on platforms where side-channel attacks are a concern and where they cannot be otherwise mitigated”, and implementing the hedged variant alone is sufficient for interoperability [FIPS 204 §3.4].

Comparator policy follows from the algorithm

You are comparing two implementations of ML-DSA, the post-quantum digital-signature algorithm. They sign the same message with the same key, context and settings. In normal hedged signing, each call uses fresh random input, so the signatures can differ without either implementation being wrong. Check that both signatures verify; different bytes alone do not establish a fault.

In an ACVP signature-generation test, however, the test supplies the random input as well as the other inputs. The implementation must use those inputs and produce the expected signature exactly. Successful verification alone is not enough to pass that test [ACVP ML-DSA sub-spec §6.1.2].

PKCS#11 Adapter Boundaries

ACVP talks to an implementation through whatever interface the test harness can reach [ACVP spec §4.2, §5]. For the Hub that interface is PKCS#11 v3.2, on two WASM engines (C++ and Rust). An ACVP test group can only be answered if the interface takes exactly the inputs the group supplies — nothing coerced, nothing defaulted. Where standard PKCS#11 has no field for an input, this HSM accepts it as an optional test input outside the standard, and every result that used one says so.

  • ML-KEM decapsulation (VAL)
    Interface path
    Import dk, then C_DecapsulateKey with CKM_ML_KEM (ML-KEM.Decaps) [PKCS#11 v3.2 §6.68]
    Hub disposition
    Executed; k is the derived key’s CKA_VALUE
  • ML-KEM encapsulation (AFT)
    Interface path
    Standard PKCS#11 has no field for m: C_EncapsulateKey takes a public-key handle and a template [PKCS#11 v3.2 §5.18.8]. This HSM accepts m (32 bytes) as an optional test input, the CKM_ML_KEM mechanism parameter [FIPS 203 Alg. 17]
    Hub disposition
    Executed on both engines in the Playground suite and in Step 3: c and k are byte-compared with NIST’s, and each result is labelled “test input supplied (outside the standard)”. Step 3 first checks that the engine really uses the supplied m (the same m twice gives the same output, a different m a different ciphertext); if not, nothing is answered
  • ML-KEM key checks (VAL)
    Interface path
    None: in the PKCS#11 v3.2 text read for this module the ML-KEM mechanism covers ML-KEM.Encaps and ML-KEM.Decaps [PKCS#11 v3.2 §6.68], and the FIPS 203 §7.2/§7.3 input checks have no operation of their own [FIPS 203 §7.2, §7.3]
    Hub disposition
    Executed in Step 3 from what these engines do when the key is imported (PKCS#11 itself does not require a key check at import; these engines run one): accepted means valid, refused with exactly CKR_ATTRIBUTE_VALUE_INVALID means invalid, and any other result is an error, never a guess. evidence.json keeps the return code for every key
  • ML-DSA sigVer, external, pure / preHash
    Interface path
    CKM_ML_DSA (ML-DSA.Verify) or CKM_HASH_ML_DSA_<hash>, context in CK_SIGN_ADDITIONAL_CONTEXT [PKCS#11 v3.2 §6.67.5–6.67.7]
    Hub disposition
    Executed. SHA2-512/224 and SHA2-512/256 have no CKM_HASH_ML_DSA_<hash> mechanism [PKCS#11 v3.2 §6.67]; the generic CKM_HASH_ML_DSA takes them as its hash (CKM_SHA512_224 / CKM_SHA512_256) with the caller computing PH(M). Step 3 runs these through that route too, labelled “computed outside the engine”
  • ML-DSA internal interface on M′ (externalMu false)
    Interface path
    CKM_ML_DSA implements FIPS 204 Algorithms 2 and 3 on the message M [PKCS#11 v3.2 §6.67.5], but the internal interface only ever signs μ = SHAKE256(tr ‖ M′, 64) [FIPS 204 Alg. 7, line 6]. The harness computes μ from the public key and M′ and uses the external-μ mechanism below — no extension
    Hub disposition
    Playground suite: executed on both engines (sigGen byte-match and sigVer). Step 3 runs the sigVer groups the same way, labelled “computed outside the engine”
  • ML-DSA internal interface with external μ
    Interface path
    No PKCS#11 v3.2 mechanism. The Hub’s engines use a non-standard mechanism code, 0x403c, for it; FIPS 204 allows μ to be computed in a different module [FIPS 204 Alg. 7, line 6]
    Hub disposition
    Executed (Playground suite and ACVP-format prototype) where an engine advertises 0x403c, labelled vendor-defined in evidence.json
  • ML-DSA sigGen, deterministic
    Interface path
    Import sk, sign with hedgeVariant CKH_DETERMINISTIC_REQUIRED [PKCS#11 v3.2 §6.67.5]
    Hub disposition
    Byte-comparable with NIST’s deterministic sigGen sample (Playground suite)
  • ML-DSA sigGen, hedged
    Interface path
    Standard PKCS#11 has no field for rnd: CKH_HEDGE_REQUIRED demands hedging but offers no input for it [PKCS#11 v3.2 §6.67.5]. This HSM accepts rnd as an optional test input in an extended signing structure: the standard CK_SIGN_ADDITIONAL_CONTEXT fields, then pRandom, ulRandomLen and messageEncoding
    Hub disposition
    Playground suite: byte-comparable with NIST’s hedged sigGen, labelled “test input supplied (outside the standard)”
  • SLH-DSA sigGen hedged, and sign / verify on the internal interface
    Interface path
    Standard PKCS#11 has no field for addrnd and no internal-interface mechanism [PKCS#11 v3.2 §6.69]. This HSM accepts addrnd and messageEncoding = internal (slh_sign_internal / slh_verify_internal) in the same extended structure [FIPS 205 §9.2–9.3, Alg. 19–20]
    Hub disposition
    Playground suite: executed on both engines, labelled “test input supplied (outside the standard)”
  • ECDSA sigGen (AFT, NIST’s k)
    Interface path
    Standard CKM_ECDSA takes no parameter and draws k itself [PKCS#11 v3.2 §6.3]. This HSM accepts k as the optional CKM_ECDSA parameter
    Hub disposition
    Playground suite: r ‖ s byte-compared with NIST’s, labelled “test input supplied (outside the standard)”
  • ML-DSA keyGen (AFT)
    Interface path
    CKM_ML_DSA_KEY_PAIR_GEN with the seed ξ supplied as CKA_SEED. The specification lists CKA_SEED among the attributes the mechanism contributes, so accepting a caller’s seed is engine behaviour, not a PKCS#11 requirement [PKCS#11 v3.2 §6.67.4]
    Hub disposition
    Byte-comparable public key (Playground suite), engine-specific path

Optional test inputs: outside the standard, for testing only

Standard PKCS#11 has no field for the random value an operation draws (ML-KEM m, ML-DSA rnd, SLH-DSA addrnd, ECDSA k) or for the SLH-DSA internal interface. This HSM accepts each as an optional test input: left out, the HSM draws the value itself exactly as the standard says, so a caller using only standard PKCS#11 sees no difference.

FIPS 203, 204 and 205 reserve these internal interfaces for testing; outside testing the module must generate the random values itself [FIPS 203 §6] [FIPS 204 §6] [FIPS 205 §9]. A validated module would keep such inputs out of its approved mode. ML-DSA’s internal interface needs no input of this kind: it goes through the external-μ mechanism with a μ the harness computes. A known ECDSA k recovers the private key from one signature, which is why FIPS 186-5 requires k to be protected from disclosure and no real module should accept one outside testing [FIPS 186-5 §6.3, §6.3.2].

The adapter’s three honest outcomes

For every test case the Hub’s dispatcher produces exactly one of: an answer (e.g. CKR_OK → testPassed: true; CKR_SIGNATURE_INVALID or CKR_SIGNATURE_LEN_RANGE → false), an unsupported record with the reason, or an error (any other return value, which produces no response entry). Unsupported is never counted as a pass, and an API failure is never reported as “signature invalid”.

Negative and Failure Testing

ACVP builds negative cases into the vector sets. An implementation that answers “valid” to everything fails them:

  • ML-DSA sigVer: the server modifies a valid signature — modified message, modified commitment, modified z, modified hint — and includes at least 3 tests per modification type [ACVP ML-DSA sub-spec].
  • SLH-DSA sigVer adds modified R, SIGFORS and SIGHT, and signatures that are too long or too short [ACVP SLH-DSA sub-spec].
  • ML-KEM VAL: modified ciphertexts must go through implicit rejection and still return a key; invalid encapsulation and decapsulation keys must be detected [ACVP ML-KEM sub-spec] [FIPS 203 Alg. 18, §7.2, §7.3].

Why rejecting a bad signature is a passing test

We deliberately give the module a bad signature. If it rejects that signature, the test passes—the module did its job correctly.

A failed internal self-test means something different: the module checked its own cryptographic implementation and that check failed. This does not prove it correctly examined our bad signature.

Therefore, our test must check why the operation failed—not treat every error as a correct rejection.

Implicit rejection is not an error path

You are testing a cryptographic implementation’s ML-KEM decapsulation operation: the step that uses the recipient’s private key and the received ciphertext to recover a shared secret. This ACVP test supplies a ciphertext of the correct length that triggers the algorithm’s internal rejection check, with otherwise valid inputs. The expected result is the fallback shared secret prescribed by FIPS 203—not an error and not an arbitrary random secret. The test passes only if the returned secret exactly matches the expected value. This test checks ML-KEM itself; it does not need to encrypt or decrypt application data. A wrong-length ciphertext is a separate input-error case [FIPS 203 §6.3, §7.3] [ACVP ML-KEM sub-spec §6.1].

Try it. Run the ML-KEM tests in the ACVP suite and compare two results. The row “PKCS#11 boundary · product-authored probe · C_DecapsulateKey with a … (1 short)” gives a ciphertext of the wrong length; the correct result is an input error. A row “Decapsulate · NIST encapDecap VAL … · modified ciphertext → implicit rejection k” gives a correct-length ciphertext that was altered; the correct result is success, with the returned secret equal to NIST’s expected fallback value. Both outcomes are correct: the first input breaks the rules before decapsulation starts, the second passes those checks and is handled by implicit rejection inside the algorithm.

Two kinds of negative testing sit outside ACVP. Requirements ACVP does not test — the sub-specifications list zeroization, DRBG strength and incorrect-length keys and signatures for ML-DSA [ACVP ML-DSA sub-spec] (the ML-KEM sub-specification repeats the ML-DSA list, a copy error, as it names signatures [ACVP ML-KEM sub-spec]). And API behaviour: wrong key type, wrong state, short buffers and other PKCS#11 return codes, which OASIS profile cases and product probes exercise [PKCS#11 Profiles v3.2].

Vocabulary the Hub holds itself to: one happy-path case is “sampled”, never “covered”; positive, negative, boundary and error-path coverage are reported separately, so a passing round-trip can never turn a negative-coverage cell green.

Evidence Provenance & Reproducibility

The Hub gives every result exactly one of eight evidence classes, each with the only claim a passing result of that class may make [PQC Today evidence policy]. The classes are the Hub’s policy, not a NIST taxonomy:

  • NIST ACVP-Server reference sample
    nist-acvp-reference-sample
    Meaning
    Expected values copied from the public NIST ACVP-Server repository with immutable source identity.
    Permitted claim
    “Passes this public NIST ACVP-Server reference sample”
  • ACVTS-issued vector
    acvts-issued-vector
    Meaning
    Prompt issued to an authorized ACVTS test session and executed without changing the prompt.
    Permitted claim
    “Executed ACVTS-issued vector set <id>; no validation claim until accepted”
  • Published standard KAT
    published-standard-kat
    Meaning
    Expected values printed in a cited standard or consensus RFC.
    Permitted claim
    “Passes the cited standard's example/KAT”
  • Independent oracle
    independent-oracle
    Meaning
    Expected values produced by a separately identified implementation such as OpenSSL.
    Permitted claim
    “Agrees with <oracle/version> for this case”
  • Cross-implementation differential
    cross-implementation-differential
    Meaning
    Two implementations agree for the same inputs.
    Permitted claim
    “C++ and Rust agree for this case”
  • Functional round-trip
    functional-round-trip
    Meaning
    Output produced by an implementation is consumed by the same or paired implementation.
    Permitted claim
    “Completes this round-trip; no external correctness claim”
  • OASIS profile case
    oasis-profile-case
    Meaning
    An identified OASIS PKCS#11 Profiles test case is replayed.
    Permitted claim
    “Passes this named OASIS profile case”
  • Product mechanism probe
    product-mechanism-probe
    Meaning
    A PQC Today-authored test of a cited PKCS#11 behavior.
    Permitted claim
    “Passes this product-authored probe”

The claim ladder

Public wording stays on the highest rung actually reached. Passing rung 6 does not imply rungs 7–9 [PQC Today evidence policy].

  1. 1Mechanism is advertised
  2. 2Operation executes
  3. 3Functional round-trip passes
  4. 4Independent implementation agrees
  5. 5Published KAT passes
  6. 6Public NIST ACVP-Server reference sample passes
  7. 7ACVTS-issued vector response is generated
  8. 8ACVTS accepts the response— needs ACVTS and NIST
  9. 9NIST publishes a validation record— needs ACVTS and NIST

Provenance is a hash, not a label

A result is publishable only with its tested scope attached: algorithm and revision, operation, parameters, positive or negative expectation, vector source with an immutable hash (or oracle name and version), engine and build identity, runner and test ID, actual and expected result, timestamp and known limitations.

The Hub’s public NIST fixtures are pinned by ACVP-Server commit and SHA-256 [NIST ACVP-Server]. Its ACVP-format prototype calls a prompt a public reference sample only when the prompt’s SHA-256 matches one of those pins; any other prompt is recorded as an unverified imported vector set. When a vector is transformed — for example a sigGen output reused as a positive sigVer case — both the upstream and the local operation are recorded.

Generated counts, never typed by hand

Read at build time from the Hub’s vector manifest (src/data/validation/validation-counts.generated.json): 98 active vector files, of which 58 carry public NIST ACVP-Server reference samples (1280 active cases).

  • NIST ACVP-Server reference sample
    Active cases
    1280
  • ACVTS-issued vector
    Active cases
    0
  • Published standard KAT
    Active cases
    22
  • Independent oracle
    Active cases
    4253
  • Cross-implementation differential
    Active cases
    0
  • Functional round-trip
    Active cases
    0
  • OASIS profile case
    Active cases
    0
  • Product mechanism probe
    Active cases
    2

Cross-Implementation & Cross-Platform Limits

Running the same case on two implementations or two platforms is valuable — a disagreement is always a finding. Agreement is weaker than it looks:

  • Shared layers. In the Hub’s ACVP-format prototype, the C++ and Rust engines are driven by one dispatcher and one response builder. A defect in that shared code makes both engines agree and both be wrong, so dual-engine agreement is differential evidence, not independent validation. External expected values — a NIST sample, a published KAT — are what break the tie.
  • Byte vs semantic equivalence. Hedged signatures differ on every run by design [FIPS 204 §3.4]; the comparison policy must be declared per operation.
  • Environment identity. ACVP binds testing to an operational environment — “the specific hardware and/or software the client’s cryptographic implementation uses to run” — and certification associates the module with its OE [ACVP spec §5.4, §12.16.4]. A result from WebAssembly in a browser says nothing about a native build, a different CPU, or a hardware accelerator until that target runs the same cases and records its own identity.
  • Confirm the execution path. An “acceleration enabled” setting does not prove that a test used the accelerator. A library may choose different implementations for different operations, or fall back to software. To claim hardware-path coverage, retain evidence showing which implementation handled the tested operation—for example, an implementation-specific execution trace or counter. If that evidence is unavailable, say that the execution path was not confirmed.
  • Honest statuses. Cross-target reports keep pass, fail, unsupported, not run and not comparable apart; the last three never add up to a pass.

Contributing a Source-Backed Test

The Hub accepts a new expected-value vector only with its provenance. Every vector file under src/data/acvp/ must have an entry in the vector manifest, and the gate fails until it does. The manifest’s own header documents the procedure:

  1. Add the vector file under src/data/acvp/.
  2. Generate a skeleton entry with the maintainers’ vector-manifest tool — it records the file’s SHA-256 and one case record per test case.
  3. Fill every TODO: the evidence class; the source (for NIST ACVP-Server material the commit, upstream path, retrieval date and upstream SHA-256); each case’s operation, parameters and positive/negative expectation; and a lineage record for any subset, rename or change of operation.
  4. The maintainers then run the vector-manifest check and regenerate the validation counts.

What a reviewer will check

  • The source is primary and immutable (a commit, a published document revision).
  • A licence or redistribution note exists for the copied values.
  • The expected behaviour is stated, including every negative case.
  • The Hub’s evidence policy asks for two reviewers — one verifies the source, a different one reviews the implementation — and the author is not the only reviewer.
  • Nothing issued to a real ACVTS session is committed: issued vector sets may be controlled laboratory data and are processed locally only.

Propose the test with the validation contribution issue template: it asks for the algorithm and parameters, the immutable source, the licence note and the expected behaviour, which is what a reviewer checks above.

Not a coder? Open a Data Suggestion issue with the source URL and the exact case, and the maintainer does the manifest work.

Check off all sections and mark this reading done.

Classify evidence, dissect a public NIST vector set, and produce a response artifact.

Check your understanding

5 questions on ACVP Lab Workflow: From Vector Set to Evidence, each with its answer and the reason.

Take the quiz

Next step

Practice it: HSM Playground validation workbench

The HSM Playground’s Developer → Validation workbench runs the evidence-labelled validation suite and the same ACVP-format import/export prototype on both PKCS#11 engines.

Learning module content can be inaccurate. Please double-check its information. Report inaccuracies in PQC Today GitHub Discussions.