Skip to content

Flow 22 --- Detached-JWS Stream Verification

This scenario walks through a constant-memory verification of a detached JWS created from a multi-megabyte payload:

  1. Generate an XMSS key-pair that can sign and verify.

  2. Create a 100 KB dummy payload.

  3. Sign that file as a detached JWS (General JSON with "payload": null) via signFileStream.

  4. Verify the detached signature in streaming mode with verifySignatureStream.

  5. Print rich server metadata and confirm the signature's validity.

Key points

  • Uses tree-based XMSS signatures --- quantum-resistant and state-aware.

  • Detached-JWS keeps large payloads out of the token; the signature file stays tiny.

  • Streaming helpers (signFileStream, verifySignatureStream) hold only a small buffer in RAM --- ideal for 100 MiB+ artefacts.

  • Produces repeatable 100 KB test data under temp_files/, then cleans itself up automatically.

When to use it

  • High-volume log pipelines that need to stamp gigabytes with a quantum-safe signature without exhausting memory.

  • Content-distribution networks where the asset (video, image, dataset) travels separately from its JWS header & signature.

  • Compliance or audit trails that demand verifiable integrity proofs while keeping tokens lightweight.

Shared helper – this code imports the utility class from
example_util.md (configuration, authentication, JSON).


Complete Java implementation

src/main/java/co/ankatech/ankasecure/sdk/examples/ExampleScenario22.java

/* *****************************************************************************
* FILE: ExampleScenario22.java
* Copyright © 2025 Anka Technologies.
* SPDX-License-Identifier: MIT
* ---------------------------------------------------------------------------
* Scenario 22 – Streaming Verification of a *Detached JWS*
* ---------------------------------------------------------------------------
* Demonstrates how to:
*   * Generate an **XMSS** key-pair capable of sign / verify.
*   * Produce a 100 Kb payload and sign it as a *detached JWS*
*     (General JSON; `"payload": null`) using `signFileStream`.
*   * Verify that signature in constant-memory streaming mode via
*     `verifySignatureStream`.
*
* All artefacts live only under <temp_files/> and are recreated on every run;
* no manual clean-up is needed.
* ****************************************************************************/
  package co.ankatech.ankasecure.sdk.examples;

import co.ankatech.ankasecure.sdk.AnkaSecureSdk;
import co.ankatech.ankasecure.sdk.model.GenerateKeySpec;
import co.ankatech.ankasecure.sdk.model.SignResult;
import co.ankatech.ankasecure.sdk.model.VerifySignatureResult;

import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.List;
import java.util.Properties;

/**
* End-to-end, file-oriented demonstration of streaming *detached JWS*
* verification with an XMSS key.
  */
  public final class ExampleScenario22 {

  private static final String SIGN_KID =
  "scenario22_XMSS_" + System.currentTimeMillis();

  private static final Path TMP_DIR       = Path.of("temp_files");
  private static final Path LARGE_PAYLOAD = TMP_DIR.resolve("scenario22_payload.bin");
  private static final Path DETACHED_SIG  = TMP_DIR.resolve("scenario22_payload.sig");

  public static void main(String[] args) {
  System.out.println("===== SCENARIO 22 START =====");

       try {
           Files.createDirectories(TMP_DIR);

           Properties props = ExampleUtil.loadProperties();
           AnkaSecureSdk sdk = ExampleUtil.authenticate(props);

           runScenario(sdk);

       } catch (Exception ex) {
           fatal("Scenario 22 failed", ex);
       }

       System.out.println("===== SCENARIO 22 END =====");
  }

  private static void runScenario(AnkaSecureSdk sdk) throws Exception {

       /* 1 – XMSS key generation ------------------------------------- */
       sdk.generateKey(new GenerateKeySpec()
               .setKid(SIGN_KID)
               .setKty("XMSS")
               .setAlg("XMSS")
               .setKeyOps(List.of("sign", "verify")));
       System.out.println("[1] XMSS key generated      -> kid = " + SIGN_KID);

       /* 2 – 100 Kb dummy payload ------------------------------------ */
       byte[] blob = new byte[3 * 1024 * 1024];           // zero-filled buffer
       Files.write(LARGE_PAYLOAD, blob);
       System.out.println("[2] Payload created         -> " + LARGE_PAYLOAD);

       /* 3 – detached-JWS streaming sign ----------------------------- */
       SignResult signMeta = sdk.signFileStream(SIGN_KID, LARGE_PAYLOAD, DETACHED_SIG);
       System.out.println("[3] Detached JWS written    -> " + DETACHED_SIG);
       printSignMeta(signMeta);

       /* 4 – detached-JWS streaming verify --------------------------- */
       VerifySignatureResult verifyMeta =
               sdk.verifySignatureStream(LARGE_PAYLOAD, DETACHED_SIG);
       System.out.println("[4] Signature valid?        -> " + verifyMeta.isValid());
       printVerifyMeta(verifyMeta);
  }

  /* ------------------------- diagnostics -------------------------- */
  private static void printSignMeta(SignResult r) {
  System.out.println("----- SIGN METADATA -----");
  System.out.println("Key requested : " + ns(r.getKeyRequested()));
  System.out.println("Key used      : " + ns(r.getActualKeyUsed()));
  System.out.println("Algorithm     : " + ns(r.getAlgorithmUsed()));
  printWarnings(r.getWarnings());
  }

  private static void printVerifyMeta(VerifySignatureResult r) {
  System.out.println("----- VERIFY METADATA -----");
  System.out.println("Key requested : " + ns(r.getKeyRequested()));
  System.out.println("Key used      : " + ns(r.getActualKeyUsed()));
  System.out.println("Algorithm     : " + ns(r.getAlgorithmUsed()));
  printWarnings(r.getWarnings());
  }

  private static void printWarnings(List<String> w) {
  if (w != null && !w.isEmpty()) {
  System.out.println("Warnings      :");
  w.forEach(x -> System.out.println("  * " + x));
  }
  }

  private static String ns(String s) {
  return (s == null || s.isBlank()) ? "(none)" : s;
  }

  private static void fatal(String msg, Throwable t) {
  System.err.println(MessageFormat.format("{0}: {1}",
  msg, t != null ? t.getMessage() : "(no cause)"));
  if (t != null) t.printStackTrace(System.err);
  System.exit(1);
  }

  private ExampleScenario22() {/* no-instantiation */}
  }

How to run

mvn -q compile exec:java\
  -Dexec.mainClass="co.ankatech.ankasecure.sdk.examples.ExampleScenario22"

Console milestones

  • XMSS key generated

  • 100 KB payload written to scenario22_payload.bin

  • Detached-JWS signature file created

  • Signature verified valid in streaming mode

  • Sign & verify metadata (key IDs, algorithm, warnings)


Where next?

© 2025 Anka Technologies. All rights reserved.