Packages · supply-chain
k2gl/signed-note
Read and write signed notes (Go sumdb / Rekor checkpoint format).
Parse and verify the note-with-signatures format transparency logs use for checkpoints.
Install
composer require k2gl/signed-note Reach for it when
- You parse or verify signed notes (Go checksum database, Rekor checkpoints).
- You’re working with transparency-log checkpoints directly.
Look elsewhere when
- You want a general Sigstore bundle — use sigstore-bundle.
k2gl/signed-note
Parse, verify and sign signed notes in PHP — the format Go's sumdb and transparency-log checkpoints (Sigstore Rekor) use. A note is some text, a blank line, then one or more signature lines:
If you think cryptography is the answer to your problem,
then you don't know what your problem is.
— PeterNeumann x08go/ZJkuBS9UG/SffcvIAQxVBtiFupLLr8pAcElZInNIuGUgYN1FFYC2pZSNXgKvqfqdngotpRZb6KE6RyyBwJnAM=
Each signature line is — <name> <base64>, where the base64 decodes to a 4-byte
key hash and the raw signature over the text. The cryptography is delegated to
[k2gl/dsse].
Install
composer require k2gl/signed-note
Requires PHP 8.1+ with ext-sodium (Ed25519); ext-openssl is needed only for
ECDSA-signed notes such as Rekor v1 checkpoints.
Verify
Give a NoteVerifier the keys you trust; it returns the signatures that verify
and throws if none do.
use K2gl\SignedNote\Note;
use K2gl\SignedNote\NoteVerifier;
use K2gl\SignedNote\VerifierKey;
$key = VerifierKey::fromString('PeterNeumann+c74f20a3+ARpc2QcUPDhMQegwxbzhKqiBfsVkmqq/LDE4izWy10TW');
$verified = (new NoteVerifier($key))->verify(Note::parse($envelope));
// $verified is the list of NoteSignature that checked out; SignatureVerificationFailed otherwise.
A Rekor checkpoint is a note signed by the log's key. Load that key from its PEM — the key hash is derived the Sigstore way (first four bytes of SHA-256 of the DER key), and any RSA/ECDSA/Ed25519 key works:
$log = VerifierKey::fromPem('rekor.sigstore.dev - 1193050959916656506', $logPublicKeyPem);
(new NoteVerifier($log))->verify(Note::parse($checkpoint));
Sign
use K2gl\SignedNote\SignerKey;
$signer = SignerKey::fromString('PRIVATE+KEY+PeterNeumann+c74f20a3+AYEKFALVFGyNhPJEMzD1QIDr+Y7hfZx09iUvxdXHKDFz');
$note = $signer->sign("hello\n"); // text must end with a newline
echo $note; // renders the note with its signature line
The output is byte-for-byte what Go's note.Sign produces (checked against the
golang.org/x/mod/sumdb/note test vectors).
Design
- Format only.
Noteis the generic note; it does not interpret checkpoint fields (origin, tree size, root hash). Parse those fromsignedText()yourself. - Fail-closed. A verified result means a trusted key signed the exact text.
- Ed25519 is the standard.
VerifierKey::fromString()/SignerKeyhandle the Ed25519 key strings from Go'snotepackage;fromPem()covers ECDSA/RSA logs.
License
MIT.
API
Public classes and methods, generated from the source.
K2gl\SignedNote\Exception\InvalidNoteException class
K2gl\SignedNote\Exception\SignatureVerificationFailed class
K2gl\SignedNote\Exception\SignedNoteException interface
K2gl\SignedNote\Note class
__construct( public readonly string $text, public readonly array $signatures, )parse(string $envelope): selfsignedText(): stringsignatures(): array__toString(): string
K2gl\SignedNote\NoteSignature class
__construct( public readonly string $name, public readonly string $keyHash, public readonly string $signature, )
K2gl\SignedNote\NoteVerifier class
__construct(VerifierKey ...$keys)verify(Note $note): array
K2gl\SignedNote\SignerKey class
fromString(string $encoded): selfsign(string $text): Note
K2gl\SignedNote\VerifierKey class
ed25519(string $name, string $publicKey): selffromString(string $encoded): selffromPem(string $name, string $publicKeyPem): selfverify(string $signedText, string $signature): bool