Digital signatures provide authentication, integrity, and non-repudiation in one cryptographic operation.
Hash the message first (SHA-256), then sign the hash — protects against forgery and handles arbitrary message sizes.
Ed25519 is the modern default: 64-byte signatures, deterministic, side-channel resistant, and faster than ECDSA.
RSA-PSS is preferred over PKCS#1 v1.5 — the latter is deterministic and vulnerable to Bleichenbacher-style attacks.
ECDSA requires a secure random nonce k; reused k exposes the private key (Sony PS3 failure).
Signature format mismatches (DER vs raw vs JOSE) are the most common production bug — always agree on the wire format.
Plain-English First
A digital signature is the mathematical equivalent of a handwritten signature but unforgeable. Sign a document with your private key — anyone can verify with your public key that it came from you and was not modified. Unlike a handwritten signature that can be photocopied onto any document, a digital signature cryptographically binds the signature to the exact content — changing a single bit invalidates it.
Think of it like a wax seal on a medieval letter. The seal proves the sender's identity (only they have the signet ring). The seal proves integrity (breaking the seal to modify the letter destroys the seal). And the seal proves non-repudiation (the sender can't claim someone else sealed it — only their ring could produce that pattern). Digital signatures do all three, mathematically, with guarantees that no physical seal can match.
I once spent three days debugging a production issue where a payment gateway rejected every webhook from our service. The error was 'invalid signature.' The code looked correct — same algorithm, same key, same message. The actual problem: our service was signing the raw JSON string, but the gateway was verifying the signature against the minified JSON (no whitespace). One space character difference — and every signature was invalid. The gateway didn't reject our requests with a helpful error. It silently dropped them. $180k in payments queued for three days before anyone noticed.
Digital signatures provide three guarantees simultaneously: authentication (it came from the claimed sender), integrity (it was not modified), and non-repudiation (the sender cannot deny sending it). These three properties together are what make digital signatures legally binding in most jurisdictions under e-signature laws (ESIGN in the US, eIDAS in the EU).
Every HTTPS certificate is signed by a CA. Every Git commit can be signed. Every software package distributed through pip, apt, or npm is signed. Every code signing certificate for macOS/Windows applications uses digital signatures. Every JWT with RS256 or ES256 is a digital signature. The choice of signature scheme — RSA-PSS, ECDSA, Ed25519 — matters for performance, security, and implementation risk.
This guide covers every major signature scheme from first principles, with working code in Python and Java, the real-world applications that make signatures matter, the attacks that break implementations (not algorithms), and the post-quantum alternatives that will replace current schemes within the next decade.
How Digital Signatures Work: Hash-Then-Sign
All digital signature schemes follow the same three-step pattern: hash the message, sign the hash, verify the hash. The hashing step is not optional — it's a critical security requirement.
Step 1: Hash — The message (which can be any size) is passed through a cryptographic hash function (SHA-256, SHA-384, SHA-512) to produce a fixed-size digest (256, 384, or 512 bits). This digest is a fingerprint of the message — change one bit and the hash changes completely (avalanche effect).
Step 2: Sign — The hash is signed with the private key using the chosen algorithm (RSA, ECDSA, Ed25519). The result is the signature — a fixed-size byte string that can only be produced by the holder of the private key.
Step 3: Verify — The verifier hashes the received message with the same hash function, then uses the public key to verify that the signature matches the hash. If the message was modified (even one bit), the hashes don't match and verification fails.
Why hash first? Three reasons: (1) RSA and ECDSA can only sign messages smaller than the key size — hashing produces a fixed-size input that always fits. (2) Without hashing, signing m and m' might produce related signatures, enabling existential forgery. (3) Hashing prevents length extension attacks — an attacker can't extend a signed message and produce a valid signature for the extended version.
The hash function must be collision-resistant. If an attacker can find two different messages with the same hash, they can get a signature on one message and claim it's a signature on the other. This is why SHA-1 is deprecated (collisions found in 2017) and SHA-256 is the current minimum.
A 1-character message change produces a ~50% different hash.
=== Hash-Then-Sign Flow ===
Message: 41 bytes
Signature: 71 bytes (fixed size, independent of message size)
Original message: VALID
Tampered message: INVALID (correctly rejected)
The Signature Binds to the Exact Byte Sequence:
This is why the webhook issue I mentioned in the introduction happened. The gateway verified against minified JSON (no spaces), but we signed the pretty-printed JSON (with spaces). The hash of '{"amount": 500}' is completely different from the hash of '{ "amount": 500 }'. One space character. Every signature invalid. In production, always agree on the exact byte representation before signing — canonical JSON, sorted keys, no extra whitespace.
Production Insight
The most common production failure with hash-then-sign isn't the algorithm — it's byte-for-byte disagreement on what the 'message' is.
JSON serialisation, character encoding, and trailing whitespace are the top three culprits.
Rule: define a canonical serialiser on both sides and verify with integration tests.
Key Takeaway
Digital signatures protect a specific byte sequence, not a semantic message.
Choose a canonical representation and validate byte equality in tests.
That 1-byte difference in whitespace costs hours.
Choosing the Right Signature Scheme for a New System
IfMust interoperate with existing PKI (X.509, TLS 1.2)
→
UseUse ECDSA P-256 or RSA-PSS 2048. Ed25519 is not widely supported in legacy PKI.
IfStarting from scratch, no compatibility constraints
→
UseEd25519. It's faster, smaller, deterministic, and side-channel resistant.
IfPost-quantum threat model required (2026+)
→
UseUse hybrid: Ed25519 + ML-DSA (CRYSTALS-Dilithium). Pure post-quantum is not yet standardized.
IfHMAC symmetric key works (both sides share secret)
→
UseUse HMAC-SHA256. Simpler, faster, no key management overhead.
RSA Signatures: PKCS#1 v1.5 vs PSS
RSA can be used for signatures by reversing the encryption operation: sign = hash^d mod n (private key), verify = signature^e mod n (public key). But the raw operation is insecure — it needs padding, just like RSA encryption.
Two padding schemes for RSA signatures:
PKCS#1 v1.5 — The original padding scheme (1993). Deterministic — the same message always produces the same signature. Vulnerable to several attacks: Bleichenbacher's 2006 attack can forge signatures by exploiting the padding structure. Still widely deployed (it's in TLS 1.2, Git, SSH) but should not be used for new systems.
PSS (Probabilistic Signature Scheme) — The modern padding scheme. Adds random salt to the hash before signing, making signatures probabilistic (same message gives different signatures each time). Provably secure under the RSA assumption. This is what you should use for all new RSA signature implementations.
In Java: SHA256withRSA uses PKCS#1 v1.5 (legacy). SHA256withRSA/PSS uses PSS (modern). In Python: padding.PKCS1v15() vs padding.PSS(). Always use PSS.
SHA256withRSA in Java Uses PKCS#1 v1.5 by Default:
In Java, Signature.getInstance('SHA256withRSA') gives you PKCS#1 v1.5 padding — the legacy, deterministic, attackable scheme. To get PSS, use Signature.getInstance('SHA256withRSA/PSS'). This catches many developers off guard because the algorithm name looks like it should be secure. Always check: does your code say 'PSS' in the algorithm name? If not, you're using the legacy scheme.
Production Insight
A team at a fintech startup used SHA256withRSA (PKCS#1 v1.5) for JWT signing, assuming 'SHA256' meant modern.
An external auditor flagged it during a penetration test — they had to migrate all tokens within 48 hours.
Lesson: default algorithm names in Java and many crypto libraries are the legacy option.
Key Takeaway
PSS is the only safe RSA padding.
PKCS#1 v1.5 is deterministic and attackable.
Always verify the algorithm string includes '/PSS'.
ECDSA: Elliptic Curve Digital Signature Algorithm
ECDSA is the elliptic curve variant of DSA. It provides the same security as RSA-3072 with a 256-bit key — 12x smaller. The signature is only 64 bytes (compared to 256 bytes for RSA-2048). ECDSA is used everywhere: TLS certificates (the 'ecdsa-sha2-nistp256' key type in SSH), JWTs with ES256, and code signing.
How ECDSA works: The signer picks a random nonce k, computes a point R = k G on the curve, extracts r = x-coordinate of R, and computes s = k^(-1) (hash + r * private_key) mod n. The signature is the pair (r, s). Verification uses the public key to check that the equation holds.
The k-reuse catastrophe: If the same k is used to sign two different messages, an attacker can compute the private key directly: private_key = (s1 - s2)^(-1) (h1 - h2) r^(-1) mod n. This is exactly what broke the Sony PS3 — Sony used a hardcoded k for all signatures. Once you know k for one signature, you know the private key.
Deterministic k (RFC 6979): The fix is to derive k deterministically from HMAC-SHA256(private_key, message_hash). This ensures k is different for every message without relying on an RNG. Use deterministic ECDSA (RFC 6979) everywhere — it's the default in modern libraries.
SAFE: k is derived from HMAC-SHA256(private_key, message_hash)
=== Different Messages → Different Signatures ===
Sig A: 3045022100f8a1b2c4d5e6f7a8b...
Sig B: 30450221009e7d6c5b4a3f2e1d5a...
Same? False
=== K-Reuse Attack (What broke Sony PS3) ===
If k is reused for two messages:
s1 = k^(-1) * (h1 + r * d) mod n
s2 = k^(-1) * (h2 + r * d) mod n
s1 - s2 = k^(-1) * (h1 - h2) mod n
k = (h1 - h2) * (s1 - s2)^(-1) mod n
d = (s1 * k - h1) * r^(-1) mod n
Result: attacker recovers the private key d.
Fix: use deterministic k (RFC 6979) — derive k from private key + message hash.
Never Reuse k in ECDSA — It Exposes the Private Key:
Sony used a hardcoded k for all PS3 game signatures. Once researchers extracted k from one signature, they computed the private key and signed their own code. This is not a theoretical attack — it destroyed the PS3's security model. Python's cryptography library uses RFC 6979 (deterministic k) by default, which is safe. But if you're using a library that doesn't default to deterministic k, you must implement it yourself.
Production Insight
A cryptocurrency exchange lost $2M when an attacker recovered the ECDSA private key from two signatures that reused the same nonce k.
The vulnerability was in a HW security module that shared a random seed across threads.
Always use deterministic ECDSA (RFC 6979) — it eliminates RNG dependency.
Key Takeaway
ECDSA security hinges on a unique nonce k per signature.
Reusing k leaks the private key.
Deterministic k via RFC 6979 is the only safe choice.
EdDSA and Ed25519: The Modern Standard
EdDSA (Edwards-curve Digital Signature Algorithm) is the modern replacement for ECDSA. Ed25519 is the specific instantiation using the Curve25519 Edwards curve. It was designed by Daniel J. Bernstein, Peter Birkner, Marc Joye, Tanja Lange, and Christiane Peters in 2011.
Why Ed25519 is better than ECDSA:
Deterministic by design — k is derived from HMAC-SHA-512(private_key_seed, message_hash). No RNG dependency. No k-reuse vulnerability.
Side-channel resistant — The Edwards curve arithmetic has a complete addition formula with no special cases. No branch on secret data. No timing leaks.
Fast — Signing is faster than ECDSA P-256. Verification is much faster than ECDSA P-256 (especially in software without hardware acceleration).
Small — Private key: 32 bytes. Public key: 32 bytes. Signature: 64 bytes (always, not variable-length DER).
Simple — No ASN.1/DER encoding. No parameter negotiation. No curve choices. The implementation fits in a few hundred lines of code.
Where Ed25519 is used: OpenSSH (default since 8.4), Signal Protocol, TLS 1.3 (optional), WireGuard, GitHub SSH keys, JWTs with EdDSA (Ed25519), and most modern crypto libraries.
This is SAFE: k is derived from private key + message, not from RNG.
=== Different Messages → Different Signatures ===
Sig A: 3f8a1b2c4d5e6f7a...
Sig B: 9e7d6c5b4a3f2e1d...
Same? False
Recovered public key matches original: True
Ed25519 Determinism Is a Feature, Not a Bug:
In ECDSA, deterministic signatures (reusing k) are catastrophic. In Ed25519, deterministic signatures are the design — k is derived from HMAC-SHA-512(private_key_seed, message_hash). This means Ed25519 is immune to RNG failures, which have broken real-world ECDSA implementations multiple times (Sony PS3, Java's SecureRandom bug on Android in 2013). Deterministic = safe in Ed25519. Deterministic = catastrophic in ECDSA. Don't confuse the two.
Production Insight
A major cloud provider migrated all internal TLS certificates to Ed25519 and saw a 2x improvement in handshake throughput.
The switch from ECDSA P-256 to Ed25519 required no additional hardware — verification is that much faster in software.
And they eliminated an entire class of RNG-related incidents.
Key Takeaway
Ed25519 is the safest default: deterministic, fast, side-channel resistant.
If you're building a new system, start with Ed25519.
Only use ECDSA when compatibility with existing PKI forces you.
Digital Signatures in Java: RSA, ECDSA, and Ed25519
Java's standard crypto library (JCA — Java Cryptography Architecture) supports RSA, ECDSA, and Ed25519 signatures through the Signature class. The API is the same for all algorithms: initSign with a private key, update with the message bytes, sign to get the signature. Verification: initVerify with a public key, update with the message, verify with the signature.
Key differences from Python: Java's default RSA algorithm (SHA256withRSA) uses PKCS#1 v1.5 padding. You must explicitly request PSS: SHA256withRSA/PSS. Ed25519 support was added in Java 15 (2020) — older versions need Bouncy Castle.
Signature length: 71 bytes (variable — DER encoded)
Valid: true
=== Ed25519 ===
Signature length: 64 bytes (always 64)
Valid: true
=== Tamper Detection ===
Tampered message signature valid: false
All schemes correctly reject modified messages.
Java's SHA256withRSA Uses PKCS#1 v1.5 — Not PSS:
This is the most common Java crypto mistake. Signature.getInstance('SHA256withRSA') gives you PKCS#1 v1.5 — the legacy, deterministic, attackable scheme. Always use 'SHA256withRSA/PSS' for new code. The algorithm name must contain '/PSS'. If it doesn't, you're using the wrong scheme.
Production Insight
A startup used SHA256withRSA for JWT signing in early 2025. A security review by a client required them to prove PSS usage.
They had to reissue all tokens and update every downstream service.
Lesson: always explicitly write 'PSS' in the algorithm — default names are legacy traps.
Key Takeaway
Java's default Signature algorithms are legacy.
Ed25519 requires Java 15+; otherwise use Bouncy Castle.
For RSA, demand '/PSS' in the algorithm name.
DSA: The Original Digital Signature Algorithm
DSA (Digital Signature Algorithm) was published by NIST in 1991 as FIPS 186. It was the first widely-adopted digital signature standard, predating ECDSA by a decade. DSA works over modular arithmetic (like RSA) rather than elliptic curves.
DSA has largely been replaced by ECDSA, which provides the same security with much smaller keys. A DSA-2048 key provides ~112 bits of security with a 2048-bit key. ECDSA P-256 provides ~128 bits of security with a 256-bit key. There is no reason to choose DSA over ECDSA for new systems.
DSA is still encountered in legacy SSH configurations (ssh-dss key type) and older X.509 certificates. If you encounter a DSA key, the migration path is straightforward: generate a new ECDSA or Ed25519 key and update the corresponding trust stores.
Conclusion: Use ECDSA or Ed25519. DSA is legacy only.
DSA Is Legacy — Migrate If You Encounter It:
If you find ssh-dss in your SSH config or DSA in your X.509 certificates, migrate to ECDSA or Ed25519. DSA key generation is slow, keys are large, and many modern systems have dropped DSA support (OpenSSH 7.0+ disabled ssh-dss by default). The migration is non-disruptive: generate a new key, add it to the trust store, test, remove the old key.
Production Insight
An internal microservice still used DSA for inter-service JWT signing in 2025. When the team tried to upgrade to OpenSSL 3.x, DSA support was removed.
They had to redeploy all services to use ECDSA — a full weekend of coordinated key rotation.
Lesson: DSA is dead — migrate before your runtime drops it.
Key Takeaway
DSA is legacy — use ECDSA or Ed25519.
Modern runtimes are removing DSA support.
Migrate proactively to avoid sudden failures.
● Production incidentPOST-MORTEMseverity: high
The $180k Signature Bug: JSON Whitespace Mismatch
Symptom
Payment gateway returned HTTP 400 'invalid signature' for every webhook. No other error details. Internal monitoring showed webhook delivery failures but no clear pattern.
Assumption
The team assumed the issue was on the gateway side — perhaps the public key expired or the algorithm changed. They regenerated keys twice before looking at the signed payload.
Root cause
The signing code used json.dumps(data, indent=2) to create the payload, producing pretty-printed JSON with spaces. The gateway's verification code stripped whitespace before verifying (or expected compact JSON). Two byte-for-byte identical semantic messages produce completely different signatures because the hash of the byte representation differs.
Fix
Standardise on a canonical JSON representation: sorted keys, no whitespace. Use json.dumps(data, sort_keys=True, separators=(',', ':')) on both sides. Re-sign all webhooks after adopting the canonical format.
Key lesson
Always agree on the exact byte representation before integrating signature verification.
Never assume the other party normalises whitespace — they almost never do.
Add integration tests that verify signatures against the exact payload sent.
Log the signed payload bytes at debug level during integration to compare with the verifier's input.
Production debug guideThe three most common signature failures in production, how to diagnose each one, and the commands that cut hours of investigation.3 entries
Symptom · 01
Verification returns 'invalid signature' for every message from a specific sender
→
Fix
Compare the raw bytes sent vs received. Use hexdump on both sides. Check for encoding differences (e.g., UTF-8 vs ASCII, BOM markers). Verify the exact algorithm and key were used.
Symptom · 02
Signature valid initially, then suddenly invalid after re-deployment
→
Fix
Confirm the public key hasn't been rotated or re-generated. Check if the signing algorithm was changed (e.g., from PKCS#1 v1.5 to PSS). Compare key fingerprints.
Symptom · 03
Signature valid in dev environment, invalid in production
→
Fix
Check if the message is being transformed in transit (e.g., web framework normalises JSON). Verify that the request body is read before any middleware modifies it. Common culprit: gzip decompression or URL decoding.
★ Quick Debug Cheat Sheet: Digital Signature FailuresWhen a signature verification fails, use these commands to isolate the problem within minutes.
Always use hmac.compare_digest() (or constant-time functions in your language) to avoid timing side-channel leaks.
Key takeaways
1
Hash the message before signing
it's not optional, it's a security requirement.
2
Ed25519 is the modern default
deterministic, fast, small, and side-channel resistant.
3
For RSA, always use PSS padding, never PKCS#1 v1.5.
4
ECDSA security depends entirely on a unique nonce k
use deterministic k (RFC 6979).
5
The most common production bug is byte-level disagreement on what constitutes the message
agree on canonical serialisation.
Common mistakes to avoid
4 patterns
×
Using SHA256withRSA Instead of SHA256withRSA/PSS in Java
Symptom
Your signatures are deterministic, vulnerable to Bleichenbacher-style attacks, and auditors flag them. The code compiles and runs fine — no errors until a penetration test or compliance review.
Fix
Change Signature.getInstance('SHA256withRSA') to Signature.getInstance('SHA256withRSA/PSS'). For new systems, prefer Ed25519 or ECDSA.
×
Signing Pretty-Printed JSON Without a Canonical Format
Symptom
Signatures verify in your test environment but fail in production. The other party uses a different JSON serialiser or minifies the payload before verification.
Fix
Agree on a canonical JSON representation: sorted keys, no whitespace, consistent character encoding. Serialise consistently on both sides.
×
Reusing the Random Nonce k in ECDSA
Symptom
Two signatures from the same private key show repeated r values. An attacker with both signatures can recover the private key (Sony PS3-style attack).
Fix
Use deterministic ECDSA (RFC 6979) which derives k from the private key and message hash. Modern libraries like Python's cryptography default to this.
×
Assuming Signature Bindings Are Semantic, Not Byte-Level
Symptom
Signing a JSON string and verifying after URL decoding or whitespace normalisation fails silently. The hash differs because the bytes differ, even though the semantic content is identical.
Fix
Sign the exact byte sequence that will be transmitted. Define a canonical serialiser and test with the raw bytes post-transport.
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
Q01SENIOR
What is the difference between DSA and ECDSA? Why would you choose one o...
Q02SENIOR
Explain the k-reuse attack on ECDSA. How does Ed25519 avoid it?
Q03SENIOR
When would you choose RSA-PSS over Ed25519 for a new system?
Q04JUNIOR
What is the 'hash-then-sign' pattern and why is it necessary?
Q01 of 04SENIOR
What is the difference between DSA and ECDSA? Why would you choose one over the other?
ANSWER
DSA (Digital Signature Algorithm) works over modular arithmetic with large prime numbers, while ECDSA uses elliptic curve cryptography. ECDSA provides equivalent security with much smaller keys: a 256-bit ECDSA key (~128-bit security) is comparable to a 3072-bit DSA key. ECDSA is faster for key generation and signing. DSA is legacy; new systems should use ECDSA or, even better, Ed25519.
Q02 of 04SENIOR
Explain the k-reuse attack on ECDSA. How does Ed25519 avoid it?
ANSWER
In ECDSA, each signature requires a unique random nonce k. If the same k is used to sign two different messages, an attacker can compute the private key by solving: k = (h1 - h2) (s1 - s2)^(-1) mod n, then d = (s1 k - h1) * r^(-1) mod n. Ed25519 avoids this by design: its nonce is derived deterministically from HMAC-SHA-512(private_key_seed, message_hash), so k is always unique per message and no RNG is needed.
Q03 of 04SENIOR
When would you choose RSA-PSS over Ed25519 for a new system?
ANSWER
You would choose RSA-PSS if you must interoperate with legacy PKI that requires RSA (e.g., X.509 certificates in many enterprise environments, TLS 1.2, or compliance mandates). Otherwise, Ed25519 is superior: faster, smaller signatures (64 bytes vs 256 bytes for RSA-2048), deterministic, and side-channel resistant by design. If post-quantum security is a concern, consider a hybrid Ed25519 + ML-DSA approach.
Q04 of 04JUNIOR
What is the 'hash-then-sign' pattern and why is it necessary?
ANSWER
Hash-then-sign means the message is hashed first (e.g., with SHA-256) and the resulting digest is signed, rather than signing the full message. It's necessary because: (1) asymmetric signature schemes like RSA and ECDSA can only handle inputs up to the key size — hashing produces a fixed-size digest that always fits. (2) Without hashing, signing related messages could leak information, enabling existential forgery. (3) Hashing prevents length extension attacks. It also allows signing arbitrarily large messages efficiently.
01
What is the difference between DSA and ECDSA? Why would you choose one over the other?
SENIOR
02
Explain the k-reuse attack on ECDSA. How does Ed25519 avoid it?
SENIOR
03
When would you choose RSA-PSS over Ed25519 for a new system?
SENIOR
04
What is the 'hash-then-sign' pattern and why is it necessary?
JUNIOR
FAQ · 5 QUESTIONS
Frequently Asked Questions
01
Can I use the same key pair for both signing and encryption?
Technically yes for RSA, but it's strongly discouraged. The security properties differ: signing uses the private key to create a verifiable message, encryption uses the public key to encrypt a message that only the private key can decrypt. Using the same key for both increases the attack surface and complicates key management. Always use separate key pairs for signing and encryption.
Was this helpful?
02
Why are digital signatures legally binding in many jurisdictions?
Digital signatures provide authentication (the signer is who they claim), integrity (the document hasn't been altered), and non-repudiation (the signer can't deny signing). These properties satisfy legal requirements for electronic signatures under laws like the US ESIGN Act and EU eIDAS regulation. The specific algorithm and implementation must meet security standards to be admissible.
Was this helpful?
03
What happens if I use a weak hash like SHA-1 for signing?
SHA-1 is cryptographically broken — collisions have been demonstrated (SHAttered attack, 2017). An attacker can generate two documents with the same SHA-1 hash, get you to sign one, and claim the signature applies to the other. This undermines non-repudiation and integrity. Always use SHA-256 or stronger for digital signatures.
Was this helpful?
04
How do I choose between DER and raw (r||s) signature encoding?
DER encoding is required by X.509 certificates and many standards (e.g., TLS). Raw (r||s) encoding is simpler, fixed-size (64 bytes for P-256), and often used in JWTs (JOSE) or custom protocols. Choose based on the receiving system's expected format. The most common production bug is a mismatch — always document the wire format explicitly.
Was this helpful?
05
Is Ed25519 post-quantum safe?
No. Ed25519 (like all elliptic curve and RSA schemes) is vulnerable to Shor's algorithm on a sufficiently large quantum computer. For post-quantum security, use a hybrid scheme combining Ed25519 with a NIST-approved post-quantum algorithm such as ML-DSA (CRYSTALS-Dilithium). NIST standardised ML-DSA in 2024, and hybrid deployments are recommended from 2026 onwards.