bcur 1.0.0

A Rust implementation of Uniform Resources
Documentation

bcur

A Rust implementation of Uniform Resources (URs).

URs encode binary payloads as URI-friendly strings for QR codes and unreliable channels, using bytewords and fountain codes for multi-part transfer.

Status (1.0)

Transport: bytewords + fountain + multi-part UR + frozen DecoderLimits Default.
Typed dCBOR: feature = "dcbor" (Ur, traits, multipart wrappers; implies std).

Layering

L0–L3 (always built). A UR type token is a validated label ([a-z0-9-]+ after ASCII lowercasing). The body is raw bytes plus bytewords CRC. ur::encode / ur::Encoder do not parse or require CBOR. UrType::bytes() and Encoder::bytes exist so tests and generic hosts can move untyped payloads. This is an intentional split, not an accident, and it matches ur-rs.

BCR-2020-005 says a UR message MUST be dCBOR and that type bytes MUST NOT be used except for testing. That MUST is enforced on L4 (feature = "dcbor"): typed::Ur::from_ur_string and MultipartDecoder::message reject non-dCBOR (Error::Cbor). L4 also uses the first registered dcbor tag name as the type token and strips the tag from the UR body (005 "top-level UR is untagged").

This crate will not grow a Blockchain Commons type registry, Envelope, or PSBT module to "satisfy 005." Application types belong in a consumer crate that implements UrEncodable / UrDecodable.

Features

Feature Default Description
std yes Host / std builds
dcbor no Typed Ur / traits / multipart wrappers (implies std)

no_std + alloc: --no-default-features.

Quick start

L3 transport — opaque bytes plus a type token. Encoder::bytes / UrType::bytes remain for tests and generic hosts; they are not the product default.

use bcur::{Decoder, Encoder, UrType};

let data = b"Ten chars!".repeat(10);
let mut encoder = Encoder::new(&data, 5, &UrType::new("alpha").unwrap()).unwrap();
let mut decoder = Decoder::default();
while !decoder.complete() {
    decoder.receive(&encoder.next_part().unwrap()).unwrap();
}
assert_eq!(decoder.message().unwrap().as_deref(), Some(data.as_slice()));

L4 typed dCBOR (feature = "dcbor"). First registered tag name is the UR type; the body is untagged.

use bcur::Ur;

let ur = Ur::new("test", vec![1, 2, 3]).unwrap();
assert_eq!(ur.string(), "ur:test/lsadaoaxjygonesw");

License

MIT OR Apache-2.0