-
Notifications
You must be signed in to change notification settings - Fork 317
Description
Hi!
This is my first time making a bug report on a public repo ever so I am sorry if I miss something.
I understand, as this seems to be a small / one man team maintaining this, if this isn't the highest of priorities but I thought it was worth bringing up
Overview
The upgrade from 9.3.1 to 10 seems to result in a 12% reduction in validation speed.
System
I am running this benchmark on a laptop running a Ryzen 7 5800H on Nixos version 25.11.20250905.8eb28ad (Xantusia) using cargo 1.89.0 (c24e10642 2025-06-23).
Issue
On version 9.3.1 running the benchmark provided below, I get:
time: [4.3268 µs 4.3421 µs 4.3595 µs]
On 10.0.0 with aws_lc_rs, I get (change is against 9.3.1 version):
time: [4.9559 µs 4.9599 µs 4.9636 µs]
change: [+10.881% +12.039% +13.235%]
On 10.0.0 with rust_crypto, I get (change is against 9.3.1 version):
time: [7.6077 µs 7.6146 µs 7.6221 µs]
change: [+75.762% +77.116% +78.459%]
I see the new example is using aws_lc_rs so that is what I am basing my changes on for that ~12% change.
Expected
I see that jsonwebtoken has made the underlying crypto library a feature but I would expect that, even as a feature, not a 12% penalty.
I don't have a deep understanding what changed from 9.3.1 to 10.0.0 and if there were necessary library changes but I would expect to maintain under +5% of the original performance even in a major version bump.
My files
Here is my config just in case.
.cargo/config.toml
rustflags = [
"-Ctarget-cpu=native",
]
I combined all my functions to a single benchmark.rs to make it easier to test. I still see the 12% with this file. I hope it helps.
benchmark.rs
use anyhow::Result;
use chrono::Utc;
use criterion::Criterion;
use jsonwebtoken::{DecodingKey, EncodingKey, Header, Validation, encode};
use std::hint::black_box;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct Claim {
pub sub: u64,
pub exp: i64,
pub first_name: String,
pub last_name: String,
pub app_id: u64,
}
pub fn create_from_claim(claim: &Claim) -> Result<String> {
let jwt = match encode(
&Header::default(),
&claim,
&EncodingKey::from_secret(b"test-key"),
) {
Ok(token) => token,
Err(e) => {
return Err(e.into());
}
};
Ok(jwt)
}
pub fn validate_token(token: &str) -> Result<Claim> {
let token_data = match jsonwebtoken::decode::<Claim>(
token,
&DecodingKey::from_secret(b"test-key"),
&Validation::default(),
) {
Ok(data) => data,
Err(e) => {
return Err(e.into());
}
};
// Check if the token is expired
if token_data.claims.exp < Utc::now().timestamp() {
return Err(anyhow::anyhow!("Token has expired"));
}
Ok(token_data.claims)
}
pub fn benchmark(c: &mut Criterion) {
let claim = Claim {
sub: 32u64,
exp: chrono::Utc::now().timestamp() + 3600,
first_name: "John".into(),
last_name: "Doe".into(),
app_id: 0,
};
c.bench_function("token validation", |b| {
let token = create_from_claim(&claim).unwrap();
b.iter(|| {
let _ = validate_token(black_box(&token)).unwrap();
})
});
}
criterion_group!(benches, benchmark);
criterion_main!(benches);