Payload Standard¶
Why semantics matter¶
A signed blob of raw bytes is useless. The smart contract must be able to:
- Decode the payload
- Verify that all required fields are present
- Check that values are within physically valid ranges
- Compare against previous readings (SoH can't increase, cycles can't decrease)
- Reject malformed or nonsensical submissions
This requires a fixed, standardized payload schema that every BMS manufacturer implements identically.
Why CBOR¶
The payload encoding is CBOR (Concise Binary Object Representation, RFC 8949). The signing envelope is COSE_Sign1 (RFC 9052).
Both are IETF standards, not blockchain-specific. They're already used across the industry:
| Standard / Protocol | Uses CBOR/COSE |
|---|---|
| Cardano ledger | CBOR throughout — transactions, datums, metadata |
| WebAuthn / FIDO2 | CBOR for attestation objects, COSE for signatures |
| SUIT firmware updates (RFC 9019) | CBOR manifest, COSE signatures |
| Matter / Thread (smart home) | CBOR for device commissioning |
| LwM2M (IoT device management) | CBOR as alternative to TLV |
| EU Digital COVID Certificate | CBOR + COSE_Sign1 |
| ISO 18013-5 (mobile driving licence) | CBOR + COSE |
Why not JSON¶
| Concern | JSON | CBOR |
|---|---|---|
| Size | Large (string keys, verbose) | Compact (integer keys, binary) |
| Determinism | No (key order, whitespace, number format) | Yes (RFC 8949 §4.2 Core Deterministic Encoding) |
| Signing | Must canonicalize first (JCS, RFC 8785) | Deterministic encoding = sign directly |
| MCU implementation | String handling, malloc | Integer-only, fixed-size buffers |
| Cardano compatibility | Needs conversion | Native |
| Floating point | Default for numbers | Integer-only by choice |
Deterministic encoding is essential for signing: the same data must always produce the same bytes, so the hash is stable. CBOR guarantees this. JSON doesn't.
COSE_Sign1 envelope¶
The entire signed reading is a COSE_Sign1 structure:
COSE_Sign1 = [
protected : bstr, ; CBOR-encoded { 1: alg }
unprotected : {}, ; empty
payload : bstr, ; CBOR-encoded BMS reading
signature : bstr ; ECDSA-secp256k1 or Ed25519 signature
]
This is the same structure used in the EU Digital COVID Certificate, mobile driving licences, and FIDO2 attestations. It's not an invention — it's a direct application of an existing standard.
Protected header¶
Two algorithms are supported, both with native Plutus built-in verifiers:
{ 1: -47 } ; ES256K: ECDSA with SHA-256 on secp256k1
{ 1: -8 } ; EdDSA: Ed25519
The operator chooses at deployment time. The on-chain validator reads the algorithm from the protected header and dispatches to the appropriate Plutus built-in (verifyEcdsaSecp256k1Signature or verifyEd25519Signature). Both are supported by the NXP SE050 secure element.
Signature computation¶
Per RFC 9052, the signature is computed over the Sig_structure:
Sig_structure = [
"Signature1", ; context string
protected, ; protected header bytes
h'', ; external_aad (empty)
payload ; CBOR-encoded BMS reading
]
The secure element signs SHA-256(CBOR(Sig_structure)).
Payload schema¶
The payload inside the COSE_Sign1 envelope is a CBOR map:
{
1: h'...', ; battery_id (unique identifier, ByteString)
2: 142857000, ; challenge (Cardano slot number, unsigned int)
3: 4891, ; monotonic_counter (strictly increasing, unsigned int)
4: { ; state (map of measurements)
1: 8800, ; soh_bp (State of Health, basis points 0-10000)
2: 7200, ; soc_bp (State of Charge, basis points 0-10000)
3: 1247, ; cycle_count (unsigned int)
4: 352000, ; remaining_capacity_mah (milliamp-hours)
5: 400000, ; nominal_capacity_mah (milliamp-hours)
6: 38920, ; voltage_mv (pack voltage, millivolts)
7: 0, ; current_ma (signed int, positive = charging)
8: 22, ; temp_min_c (signed int, Celsius)
9: 25, ; temp_max_c (signed int, Celsius)
10: 48750000, ; energy_throughput_wh (watt-hours cumulative)
11: 96, ; cell_count (number of cells in series)
12: [ ; cell_voltages_mv (array, one per cell, optional)
3310, 3312, 3308, 3311, ...
]
},
5: 1 ; schema_version (unsigned int)
}
Design choices¶
Integer-only, fixed units. No floating point. SoH is in basis points (88.00% = 8800), voltage in millivolts, capacity in milliamp-hours. This makes CBOR encoding deterministic and smart contract validation simple — Plutus works with integers natively. MCU firmware doesn't need float libraries.
CBOR integer keys. Not string keys. Keeps the payload small (important for NFC transfer and on-chain cost). The key-to-field mapping is defined by the standard.
Core Deterministic Encoding (RFC 8949 §4.2). All implementations must use deterministic encoding — integer keys sorted numerically, shortest-form integers, no indefinite-length encoding. This ensures every BMS producing the same data produces the same bytes.
Mandatory fields. Every reading must include state map keys 1-11. Key 12 (cell voltages) is optional — it makes the payload much larger but provides the most detailed view.
Payload size¶
| Variant | CBOR payload | Full COSE_Sign1 |
|---|---|---|
| Without cell voltages | ~80-120 bytes | ~160-200 bytes |
| With 96 cell voltages | ~280-350 bytes | ~360-430 bytes |
Both fit comfortably in an NFC NDEF message (~64 KB max) and a Cardano transaction (~16 KB max).
Complete example¶
A COSE_Sign1 BMS reading in CBOR diagnostic notation:
18( ; COSE_Sign1 tag
[
h'a10138...', ; protected: { 1: -47 } (ES256K) or { 1: -8 } (EdDSA)
{}, ; unprotected: empty
h'a501....', ; payload: CBOR-encoded BMS reading
h'304502...' ; signature: secp256k1 or Ed25519
]
)
The phone app receives this as a single NDEF record via NFC tap. It can:
- Verify the COSE signature locally (using the public key from the passport)
- Display the decoded battery state to the user
- Submit the entire COSE_Sign1 object to the Cardano smart contract
Validation rules¶
The smart contract (or an off-chain verifier) checks:
Structural validation¶
| Rule | Check |
|---|---|
| Valid COSE_Sign1 structure | Four-element array with correct types |
| Protected header contains known algorithm | ES256K (-47) or EdDSA (-8) |
| All mandatory payload fields present | Keys 1-11 in state map |
| Correct types | All values are integers, cell_voltages is an array |
| Schema version recognized | Must be a known version |
| Battery ID matches datum | The battery_id in the payload matches the CIP-68 datum |
Freshness validation¶
| Rule | Check |
|---|---|
| Challenge is recent | challenge ≤ current_slot and current_slot - challenge < max_age |
| Counter is advancing | monotonic_counter > last_accepted_counter |
Physical plausibility¶
| Rule | Check | Rationale |
|---|---|---|
| SoH in range | 0 ≤ soh_bp ≤ 10000 | Can't be negative or over 100% |
| SoH non-increasing | soh_bp ≤ previous soh_bp | Batteries don't heal |
| Cycles non-decreasing | cycle_count ≥ previous cycle_count | Cycles can't go backwards |
| Voltage in range | Chemistry-dependent (e.g., 2500-4200 mV/cell) | Outside range = damaged or fake |
| Temperature in range | -40 ≤ temp ≤ 80 | Outside operating range |
| Capacity ≤ nominal | remaining ≤ nominal | Can't exceed design capacity |
| Cell count matches | Matches passport's registered count | Physical config can't change |
COSE signature validation¶
| Rule | Check |
|---|---|
| Reconstruct Sig_structure | Per RFC 9052 §4.4 |
| Verify signature | verifyEcdsaSecp256k1Signature (ES256K) or verifyEd25519Signature (EdDSA) |
| Public key matches | bms_key matches the key registered in the CIP-68 datum |
Separation of concerns¶
graph TD
subgraph "IETF Standards"
A[CBOR - RFC 8949]
B[COSE_Sign1 - RFC 9052]
end
subgraph "DPP Standard defines"
C[Payload schema: fields, types, units]
D[Validation rules: ranges, monotonicity]
end
subgraph "Manufacturer implements"
E[AFE registers → CBOR payload]
F[Secure element produces COSE_Sign1]
end
subgraph "Smart contract"
G[Verifies COSE signature]
H[Decodes CBOR payload]
I[Validates schema + plausibility]
J[Releases reward]
end
A --> C
B --> F
C --> E
E --> F
F --> G --> H --> I --> J
The manufacturer is the only party that needs to understand the AFE hardware. They convert proprietary register readings into the standard CBOR format. The COSE envelope and ECDSA signing are handled by the secure element using off-the-shelf libraries. Everything downstream — NFC transport, phone app, smart contract — is hardware-agnostic.
On-chain vs off-chain validation¶
Full CBOR decoding and COSE verification in a Plutus validator is feasible but expensive. Two approaches:
Option A: Full on-chain validation¶
The validator parses the COSE_Sign1, reconstructs the Sig_structure, verifies the signature, decodes the payload, and checks plausibility. Plutus has built-in ECDSA verification (verifyEcdsaSecp256k1Signature), so the signature check is cheap. CBOR decoding of a small payload (~120 bytes) is feasible within Plutus execution limits.
Per-cell voltage validation for 96 cells would be expensive and can be deferred.
Option B: Off-chain verification with on-chain proof¶
An off-chain verifier runs all checks and submits a compact proof. The contract only verifies:
- COSE signature (built-in, cheap)
- Challenge freshness (slot comparison)
- Monotonic counter (integer comparison)
- Hash of the full COSE_Sign1 object (proving the verifier saw the same data)
Recommendation¶
Start with Option A for core checks (COSE signature, freshness, counter, SoH monotonicity) and Option B for detailed checks (per-cell voltages, temperature ranges). Core checks prevent the most important fraud scenarios.
Versioning¶
The schema_version field allows the standard to evolve:
- Version 1: Core fields (SoH, SoC, cycles, voltage, temp, capacity)
- Version 2: Could add impedance data, charging power limits, etc.
The smart contract's datum stores accepted schema versions. Old readings remain valid under their version. The COSE protected header's algorithm field similarly allows cryptographic agility.
Standards reuse summary¶
| Layer | Standard | Status |
|---|---|---|
| Binary encoding | CBOR (RFC 8949) | IETF, widely deployed |
| Deterministic encoding | RFC 8949 §4.2 | IETF |
| Signing envelope | COSE_Sign1 (RFC 9052) | IETF, used in EU DCC, mDL, FIDO2 |
| Signature algorithm | ES256 / EdDSA | IANA COSE Algorithms registry |
| On-chain verification | Plutus built-in ECDSA/Ed25519 | Cardano native |
| NFC transport | NDEF (NFC Forum) | NFC Forum, universal phone support |
Nothing is invented. The payload schema (field definitions and validation rules) is the only new thing. Everything else is existing, proven standards.