Skip to content
Alpha: Odal Node is in active development. APIs, schemas and docs will change before 1.0.

What the core does

The core is the regulatory library: the rules a compliant Digital Product Passport must satisfy, written as code. It is open source under Apache-2.0, has no infrastructure of its own (no database, no server, no configuration), and anyone may build on it. Its crates are published on crates.io, with API documentation on docs.rs.

Validate product data against its regulatory schema, sign it, and verify the signature, using only the published crates. The first build takes about a minute.

Terminal window
cargo new hello-dpp && cd hello-dpp
cargo add dpp-domain dpp-crypto serde_json anyhow

Replace src/main.rs with:

use dpp_crypto::{jws::signer, keystore::KeyStore};
use dpp_domain::schemas::VersionedSchemaRegistry;
use serde_json::json;
fn main() -> anyhow::Result<()> {
// 1. Validate product data against the embedded, versioned JSON Schema.
let schemas = VersionedSchemaRegistry::new();
let (version, _) = schemas.latest("textile").expect("textile schema is embedded");
let data = json!({
"productIdentifier": { "scheme": "gs1", "gtin": "09506000134352" },
"fibreComposition": [{ "fibre": "organic cotton", "pct": 100.0 }],
"countryOfOrigin": "PT",
"careInstructions": "Machine wash 30°C",
"chemicalComplianceStandard": "OEKO-TEX Standard 100"
});
if let Err(e) = schemas.validate("textile", version, &data) {
for err in &e.errors {
println!("invalid at '{}': {}", err.field, err.message);
}
anyhow::bail!("validation failed");
}
println!("valid against textile schema v{version}");
// 2. Sign it as a compact JWS with an Ed25519 key from an encrypted keystore.
let store = KeyStore::open(std::env::temp_dir().join("hello-keys.json"), "change-me")?;
if store.public_key("issuer").is_none() {
store.generate_key("issuer")?;
}
let kid = store.public_key("issuer").expect("generated above").thumbprint_uri()?;
let jws = signer::sign(&store, "issuer", &data, &kid)?;
// 3. Verify the signature.
println!("signature verifies: {}", signer::verify(&store, "issuer", &jws)?);
Ok(())
}
Terminal window
cargo run
valid against textile schema v1.4.0
signature verifies: true

Remove "countryOfOrigin" and the run stops with invalid at '': "countryOfOrigin" is a required property.

  • A definition of a passport: its identity, who issued it, what it is made of, the product-group data the regulation requires, and the lifecycle it moves through. The exact shape is in the code, which is the authoritative reference.
  • Validation: a passport is checked against its product group’s versioned schema and cross-field rules. This runs locally with no network and no services, and nothing leaves the machine.
  • Signing and verification primitives: Ed25519 keys, JSON Web Signatures and the encrypted key store a node signs with. Anyone can verify a passport on their own, without the issuer’s systems and without Odal.
  • A lifecycle: draft, published, suspended, superseded, retired and end of life. Every transition is recorded, a published passport never returns to draft, and retirement and end of life are final, so a passport’s history cannot be rewritten unnoticed.
  • The EU instrument catalog: which acts reach which product group, whether each requires a passport, and from when, with every date marked as read from the text or assumed. The website’s regulations page shows it.
  • Access control: which reader may see which part of a passport, and the verifiable credentials that prove a reader’s role.
  • Product identifiers, digital links, Asset Administration Shell and registry types: what a passport needs to be identified and resolved from the code on the product (a GS1 Digital Link, an identification link or a DID), read by Industry 4.0 systems and registered with the EU.
  • Calculators: carbon footprint, repairability and recycled-content calculations, each with a receipt of the method and version used, published for anyone to use.
  • The plugin SDK: how a product group’s rules are written as a sandboxed plugin. See Product groups & plugins.

The core stays free of infrastructure so that the line between core and engine holds: code that needs a database or a network belongs in the engine, not in the core. It also means the same rules run unchanged anywhere, from a server to an edge runtime.