COOLJAPAN OÜ / OxiMed
OxiMed — medical imaging & clinical data

IEC 62304 evidence, generated by the build.

DICOM, HL7 FHIR, PACS and EHR interop. Segmentation, registration and reconstruction. Biosignals. Every one of them in Rust — no C, C++, Fortran or assembly compiled into a shipped build — with the regulatory data plane wired into the source rather than bolted on at the end.

25 crates 1,244,017 lines No C in any shipped build No AGPL obligation IEC 62304 · ISO 14971 no_std core, on real bare metal
SOUP inventoryoximed · every feature · every target
ItemCountStatus
C / C++ / Fortran compiled0Absent
Hand-written assembly0Absent
Java runtime0Absent
AGPL / GPL obligations0None
Binary blobs0Absent
Native items behind an optional feature0Absent
OxiMed crates, all traced0All of it
SOUP — software of unknown provenance — is the line item that costs you months, and this is ours. The header names a configuration, because an inventory that does not name one is not an inventory, and this one is the widest there is: every optional feature of the oximed crate, on every target. Two native items used to survive that selection — ring, the default crypto provider of the rustls/rcgen stack, and the bundled C SQLite engine behind sqlx’s sqlite feature. Neither was documented into acceptability. rustls is now built with no provider feature and takes a Pure-Rust one from OxiTLS; the PACS SQL registry runs on oxisqlite, and sqlx is gone from the workspace. deny.toml denies both outright with no wrappers carve-out, so any dependent fails the check, not merely a new one. What remains, so the graph holds no surprises: ring is still an entry in Cargo.lock with no normal edge reaching it; cc appears as a build-dependency of blake3, pinned to the pure feature under which its build script compiles none of its assembly or NEON C, and of iana-time-zone-haiku, which builds only on Haiku. One workspace crate has an opt-in fuzz feature that pulls LLVM’s libFuzzer, which is C++ — a coverage-guided test harness, unreachable from the oximed crate at any feature selection, and never in a device build. No unknown provenance
Clause 01Argument

You are not buying imaging code. You are buying months off the submission.

A DICOM parser is a solved problem. What is not solved is arriving at a design review with a dependency tree that a notified body will accept without a stack of justification documents.

LibraryLanguageLicenceShippable in a device62304 evidence
dcm4cheJavaAGPL / commercialRuntime + licence problemYou produce it
DCMTKC++BSD-styleYesYou produce it
GDCM · ITKC++Apache / BSDYesYou produce it
Commercial toolkitsC / C++Per-seat, per-deviceYesPartial, at a price
OxiMedRustLicensed sourceYesIncluded with licence

Every option above except the last one leaves you holding the same job: classify the software, inventory the SOUP, justify each item, trace requirements to tests, and defend memory safety in code that was written in a language which does not have any. That work is where the schedule goes.

Rust does not make your device safe. It removes an entire category of hazard from the analysis, and it lets the evidence be produced by the build system instead of by a technical writer reading a diff.

Clause 02Scope

What is in the workspace.

Modular. Take the DICOM layer alone for an interop project, or the imaging pipeline for a diagnostic product.

Interoperability
  • DICOM data model, encoding and network services
  • Pixel data: 12 transfer syntaxes decode in pure Rust — three native, four JPEG, two JPEG-LS, two JPEG 2000 and RLE — and 6 of them encode
  • DICOMweb: WADO-RS, QIDO-RS and STOW-RS against one shared store
  • HL7 FHIR resources and REST client
  • PACS integration
  • EHR record handling and OAuth2 / JWT
  • Clinical trial data management
  • no_std core, checked against thumbv7em-none-eabihf
Imaging
  • Segmentation, with from-scratch conv / batchnorm / attention / U-Net layers
  • Registration
  • Reconstruction
  • Detection
  • 3D rendering
  • Radiomics, texture and quantitative MRI
  • Dice, Hausdorff and boundary-IoU losses
Beyond imaging
  • Genomics — a 53-module stack
  • Molecular docking and dynamics
  • QSAR and ADMET prediction
  • Biosignals: ECG, EEG, EMG, PPG
  • Federated learning across sites
  • Face de-identification for shareable datasets
Clause 03Product

The licence includes the evidence kit.

OxiMed is licensed source, not open source. What comes with it is the dossier that goes into your technical file, regenerated for every version you ship. It is produced by oximed-cert230 modules and 42,832 lines of code, a regulatory data plane rather than a folder of templates.

62304 §4.3Software safety classificationClass A / B / C rationale per component, with the segregation argument written out.
62304 §5.3Architecture and interface documentationGenerated from the source, not maintained separately from it.
62304 §5.5–5.7Verification recordsUnit, integration and system test results, tied to build hashes. The corpus behind them is 41,900 #[test] functions and 170 property-based proptest! blocks across 2,372 integration-test files. That is a count of test functions, which is evidence of effort rather than of coverage — treat it as the size of what you inherit, not as an argument that it is sufficient.
62304 §8.1.2SOUP inventory and justificationEvery dependency: version, licence, purpose, known anomalies, and why it is acceptable.
62304 §9Problem resolution recordsDefect history with the fix, the test that catches it, and the affected version range.
14971Risk management file inputsHazard contributions from software, with the classes of failure that Rust structurally removes stated explicitly.
SecuritySBOM, VEX and vulnerability serviceCycloneDX per release, VEX statements within 72 hours of a relevant advisory.
TraceabilityRequirement-to-test matrixMachine-generated, so it is correct at the moment you export it rather than at the last review.
FormalSafety invariants discharged by a solver, in-processverify_invariant() takes the Hoare-style condition (ranges ∧ precondition) → postcondition to the embedded Pure-Rust OxiZ SMT solver and returns Verified, Falsified with a counter-example, or Unknown. Nothing shells out; the solver is a default-enabled dependency. A predicate outside the decidable linear-integer fragment comes back Unknownnever as a pass. Full CTL/LTL model checking of the transition relation is not built.
VacuityAn empty register never reports compliantEvery favourable verdict this crate emits — RELEASABLE, CE-ready, 21 CFR Part 11 compliant, Annex VII complete, SOUP and traceability compliance — is a gate, and a gate has to guard emptiness: Iterator::all over nothing is true, a count of blockers over nothing is 0, and completed ÷ total over nothing is 100%. Each gate carries an assessed flag and reads assessed && …. The count metrics keep their vacuous values, which are arithmetically correct; a metric may stay vacuous only while no gate and no rendered sentence derives from it. A regression test locks the whole family, so the next aggregate anyone adds cannot quietly reintroduce the shape.
Beyond 62304The rest of the regulatory surface — and how deep each part goesDepth is not uniform and this page will not pretend it is. IEC 62304 is the deep one at roughly 12,000 lines. In the low thousands: ISO 14971, the traceability engine, ISO 13485, EU MDR, the SOUP inventory, IEC 60601-2 and SBOM. Real but lighter, a few hundred lines each: ISO 24971, IVDR, EUDAMED, FDA and the 510(k) classifier, IEC 62366 usability, IEC 82304-1, IEC 62443, IEC 80001, GAMP 5, HIPAA, GDPR, ISO 27001, IMDRF SaMD classification, DHF, HAZOP, FMEA/FTA, clinical evaluation, post-market surveillance and the SRS / SDD / SAD / SDP / SRR set. None of them is an empty scaffold — there is not one todo! or unimplemented! across any of it — but a few hundred lines is a starting point for that standard, not coverage of it.

A worked example of the §8.1.2 row, since that is the one that costs you time. DICOM Part 10 parsing is not written from scratch here — it comes from the third-party dicom-rs family, pinned at 0.10.0. So it is a SOUP item, and it is kept as one: the family carries an informational advisory for an unmaintained text-decoding crate, triaged in deny.toml with the reachability argument written out rather than silenced, and the live unchecked-length defect in dicom-parser is mitigated on our side by oximed_dicom::parser::validate_declared_lengths, which has its own regression-test file. Version, licence, purpose, known anomaly, mitigation, why it is acceptable — that is the row you would otherwise be writing yourself.

Scaffolding is the honest word for most of this: oximed-cert generates the structure, the records and the traceability, and the safety-invariant checks above are genuinely discharged by a solver — but a generated document is an input to your technical file, not a substitute for authoring it. We supply evidence for our software as a SOUP item in your device. We are not your notified body, your consultant or your quality system, and the classification of your device remains yours to determine.

Clause 04Status

Where it is thinner than the section above implies.

Most of this workspace is real, working Rust — over a million lines of it. Five areas are not yet what a reader of the capability list would assume, and you should know which before you scope around them, not after.

CodecHTJ2K refuses. JPEG 2000 decodes.The J2K side is real and written from scratch — MQ arithmetic coder, tag trees, EBCOT tier-1, the 5/3 lifting DWT and the reversible colour transform, with tier-1, DWT and RCT validated byte-exactly against externally produced codestreams. …1.2.4.90 decodes; …1.2.4.91 decodes on its reversible path. HTJ2K is the gap, and it is a narrow one: T.814 replaces exactly that tier-1 stage with an HT block coder, which is not implemented, so the codec validates the codestream framing and returns a typed refusal naming the missing decoder rather than a generic “unsupported transfer syntax”. The reason is written in the module: no HTJ2K conformance stream exists here and none can be produced without an encoder, so nothing could distinguish a correct block decoder from a plausible one. Encoding is asymmetric too — JPEG-LS and RLE encode, JPEG and JPEG 2000 do not, and those paths error rather than fabricate output.
DockingRfScore ships no weightsThe 36 protein–ligand atom-pair count features are the paper-faithful ones. The model is not, and cannot be: RF-Score is a Random Forest whose paper publishes feature importances and no coefficients, so there is no linear approximation of it to derive. RfScore is therefore a generic linear evaluator with no bundled defaults — you pair it with weights fitted against your own data. If you expected a scoring function that works out of the box, this is the row that costs you time.
MDCHARMM36m CMAP grids are not in the boxPME electrostatics now covers the general triclinic cell, not only the orthorhombic one. What is missing is parameter data we cannot redistribute: par_all36m_prot.prm ships from the MacKerell lab, so charmm36::cmap_for_residue returns NotImplemented naming the file, the loader that reads it and where to fetch it. A synthetic Ramachandran surface exists, but it only answers when asked for by name — get_for_production refuses any grid flagged synthetic, so a placeholder cannot be applied as though it were tabulated data.
FormalDecidable fragment onlySafety invariants outside QF_LIA are reported Unknown. Temporal-logic model checking of the transition relation is future work, not a shipped capability.
InteropA few ancillary paths are still stubsThe DICOMweb data path is real and store-backed — a stored instance round-trips through WADO-RS byte for byte, and QIDO-RS filters correctly across studies, both under test. The Orthanc-compatible REST passthrough is not wired.

There is no CI workflow behind these claims; company policy restricts .github/workflows to publishing. The gate is a fixed command set run locally before a change is considered done — nextest at all features, clippy with -D warnings, doctests, cargo deny check, and the three no_std builds against a target that genuinely has no std. A host build would prove nothing about a bare-metal claim, so it is not used for one.

Clause 05Licence

Priced in public. No discovery call.

You should be able to find out whether this fits your budget without talking to anyone. Annual terms, per device family, invoiced once.

Evaluation
US$5,00030 days · full source

Payable in advance. Source access within one business day of receipt.

Credited in full against an Integration or Class C programme licence. Complete workspace, the full evidence kit above, in full detail. Non-commercial evaluation use only. No sales contact unless you ask for it.

Integration
US$48,000per year · one device family

A licensed build for one device family, plus the full evidence kit above — regenerated per release, SBOM and VEX service, 5 business day response.

Class C programme
US$120,000per year

Everything above, plus a named engineer, participation in your design reviews, and a commitment to support your shipped version for the device lifetime.

No royalty on your device revenue, no per-seat runtime fee, no audit clause. Perpetual licences are available on request.

Clause 06Provenance

Nine years removing C. The medical stack is what got built on top.

Registration is optimisation. Reconstruction is transforms. Segmentation is tensors. Every medical imaging toolkit in existence sits on ITK, on VTK, on BLAS, on FFTW — and all of it is C, C++ or Fortran, which is why every SOUP inventory in the industry is long and every justification is hard.

The imaging layer could not be clean until the numerics were replaced. So we started at the bottom and worked up, and OxiMed is what became possible once the floor was Rust.

OxiMed DICOM · FHIR · imaging · biosignal └─ OxiML segmentation, detection, federated learning └─ SciRS2 numerical core └─ OxiBLAS · OxiFFT linear algebra, transforms └─ Rust standard library. Nothing further down.

A Rust wrapper over ITK still puts ITK in your inventory. Ours does not, because the layer beneath it was rewritten first, and the layer beneath that one before it.

The stack is public on GitHub — 60+ projects, Apache-2.0. OxiMed is the part we licence.

Clause 07Next

Send us your SOUP inventory.

Genuinely — send the current list, or just the device class and what it does. You will get back a mapping of which items OxiMed replaces, what stays, and an honest estimate of what that removes from your documentation load. One business day, no call required.