`gosop sign --as text` produces incompatible signatures over a message with only carriage return
If i use gosop to sign a message that contains only \r in text-mode, it produces a signature that gosop can verify, but no other OpenPGP implementation can verify:
0 dkg@bob:~$ gosop generate-key x > x.key
0 dkg@bob:~$ gosop extract-cert < x.key > x.cert
0 dkg@bob:~$ printf '\r' > msg.txt
0 dkg@bob:~$ gosop sign --as=text x.key < msg.txt > msg.txt.sig
0 dkg@bob:~$ gosop verify msg.txt.sig x.cert < msg.txt
2025-10-15T19:42:23Z 8E1CB2A13D6A72BD11ABD6D24B3D22B72F20BAC4 8E1CB2A13D6A72BD11ABD6D24B3D22B72F20BAC4 mode:text
0 dkg@bob:~$ for sop in pgpainless-cli sopv-gpgv rsopv sqopv; do $sop verify msg.txt.sig x.cert < msg.txt
> done
No verifiable signature found.
ERROR:root:SOP Error NO_SIGNATURE (3): No Valid Signature found
No acceptable signatures found
No acceptable signatures found
3 dkg@bob:~$
version info:
0 dkg@bob:~$ gosop version --extended
gosop 1.1.0
GopenPGP 3.2.0
Compiled using go1.24.4
0 dkg@bob:~$
Looks like the PGPy variant i've been playing with agrees with gosop here, and can verify this signature. I haven't been able to test OpenPGP.js yet.
OpenPGP.js also likes the signature:
$ sopenpgpjs verify msg.txt.sig x.cert < msg.txt
2025-10-16T09:49:18Z 166EBA1BBC57ACDA25BF4D45564EEF3CA05C50EA 166EBA1BBC57ACDA25BF4D45564EEF3CA05C50EA mode:text {"signers":["x.cert"]}
And, as far as I can tell, the newline normalization in both implementations is at least consistent with the position that \r is not a newline, i.e. the value is signed as-is.
From the implementations that fail to verify, PGPainless, rPGP and Sequoia think that \r is a newline and normalize to \r\n. That leaves only GnuPG, which normally doesn't normalize \r to \n, but I suspect it may be buffering the \r, waiting to see if there's a following \n, but failing to handle the case where EOF follows?