chadtmiller.com/knotless
git that lives in your Atmosphere account
knotless takes its keys, JWTs, base32 and TIDs from the atproto crate
MergedThis swaps knotless's own keys, JWT, base32 and TID code for the atproto crate. P256Key stays as a thin wrapper, so its callers keep working, and the call sites move to the crate's names. I read the whole diff and found nothing that must change.
- High-S refusal:
verify_jwtand the commit check inarchive.rsboth now go through the crate'sPublicKey::verifyand rely on it to refuse high-S signatures, as the old code did. The new high-S test incrypto.rscoversverify_jwtonly.archive::checkedhas no such test, so check that the crate'sverifyitself refuses high-S, since that is what keeps commit verification as strict as before. - base32 decode: The looser decode in the crate means
drislwill now take a non-canonical$linksuch asmaa, and re-encode it differently. The body names this and the 0.1.1 fix. It is harmless for CIDs from others, but update to 0.1.1 soon. - Builds: They now depend on knotless.dev's registry being reachable, as the body says. I couldn't confirm that the deploy image's build context includes
.cargo/config.toml, so check that.
The check, test, e2e and docs runs were still queued when I looked. The coverage gate and clippy are what to watch. web, shots, lexicons and ios were skipped as unaffected.
Since my approval, the only change is the bump to atproto 0.1.1, in Cargo.toml and Cargo.lock. The new checksum is in the lockfile. This is the stricter base32 decode my last review asked for, so the non-canonical $link concern is resolved. The earlier approval stands.
I couldn't check from here that the crate's verify refuses high-S signatures, so that is still open for the archive::checked path. The check and test runs were still queued when I looked, so clippy and the coverage gate haven't reported.
1 cancelled, 1 passed, 1 skipped
What changes
knotless now takes atproto's primitives from the
atprotocrate, which lives in its own repository (https://knotless.dev/chadtmiller.com/atproto) and is published to that repository's Cargo registry..cargo/config.tomlnames the registry, and the workspace depends onatproto = { version = "0.1.1", registry = "atproto" }. This is the first of several pulls.Keys and JWTs.
crypto::PublicKeyis now the crate's.P256Keystays as a small wrapper over the crate'sKeypair, so its callers don't change.jwt_partsandverify_jwtcall the crate's JOSE code.verify_jwtstill refuses a high-S signature, as before: the crate's ownjose::verifyaccepts either, but knotless keeps its stricter check. Four methods have different names in the crate (did_key,to_sec1,curve().alg(), andverify, which returns abool), and their callers are updated. The tests of key parsing moved to the crate, which checks them against atproto's interop vectors.base32 and TIDs.
knotless::base32is gone.drislandspace_syncuse the crate's base32, andkeys::tid_fromandtid_microsuse the crate'stidmodule. The output is the same, and so is what counts as a TID.AGENTS.mdsays where these come from now, and that a primitive knotless needs goes into the crate first.Why
knotless, group-host and grain's Rust rewrite each had their own copy of these primitives, and the copies had drifted. With one crate, a fix lands once, and it's checked against the interop vectors.
How it was checked
cargo check --workspace --testsis clean, and the knotless library's unit tests pass (219). The crate's owncheckandtestpass, with every line insrc/covered. Everything else is left to CI.Shortcomings
decodeis as strict as knotless's was from 0.1.1 on, which this pull takes: 0.1.0 accepted a whole character of zero bits left over.Changeset: none
🤖 Generated with Claude Code