Repository navigation
Description
Problem:
The AWS Rust SDK recently updated our default version of rustls to one that uses aws-lc-rs as the crypto provider. This has caused a substantial (consistently ~4MB in my tests) increase in binary size. This has caused some pain points for customers: smithy-lang/smithy-rs#4049. In our debugging using cargo-bloat it appears that much of this size comes from aws-lc functions as can be seen in the output below from a small test application.
$ cargo bloat --release -n 50
File .text Size Crate Name
1.0% 2.1% 173.1KiB aws_sdk_s3 aws_sdk_s3::config::endpoint::internals::resolve_endpoint
0.3% 0.6% 47.2KiB [Unknown] edwards25519_scalarmulbase_alt_edwards25519_gtable
0.3% 0.6% 47.2KiB [Unknown] edwards25519_scalarmulbase_edwards25519_gtable
0.3% 0.6% 47.2KiB [Unknown] curve25519_x25519base_byte_alt_edwards25519_gtable
0.3% 0.6% 47.2KiB [Unknown] curve25519_x25519base_byte_edwards25519_gtable
0.2% 0.4% 30.7KiB aws_lc_sys _aws_lc_0_27_0_pqcrystals_kyber512_ref_indcpa_keypair_derand
0.2% 0.4% 28.7KiB aws_lc_sys _aws_lc_0_27_0_pqcrystals_kyber768_ref_indcpa_keypair_derand
0.2% 0.3% 25.7KiB aws_lc_sys _aws_lc_0_27_0_pqcrystals_kyber768_ref_indcpa_enc
0.1% 0.3% 24.9KiB [Unknown] p384_montjscalarmul_p384_montjadd
0.1% 0.3% 23.1KiB aws_lc_sys _aws_lc_0_27_0_pqcrystals_kyber512_ref_indcpa_enc
0.1% 0.3% 21.8KiB aws_config aws_config::loader::ConfigLoader::load::{{closure}}
0.1% 0.3% 21.8KiB aws_config aws_config::loader::ConfigLoader::load::{{closure}}
0.1% 0.3% 21.8KiB aws_config aws_config::loader::ConfigLoader::load::{{closure}}
0.1% 0.2% 17.1KiB [Unknown] p384_montjscalarmul_alt_p384_montjadd
0.1% 0.2% 17.0KiB aws_sdk_sts aws_sdk_sts::config::endpoint::internals::resolve_endpoint
0.1% 0.2% 16.4KiB aws_lc_sys _aws_lc_0_27_0_pqcrystals_kyber1024_ref_indcpa_keypair_derand
0.1% 0.2% 16.0KiB aws_config aws_config::sso::credentials::load_sso_credentials::{{closure}}
0.1% 0.2% 15.9KiB aws_config aws_config::ecs::EcsCredentialsProvider::credentials::{{closure}}
0.1% 0.2% 14.0KiB [Unknown] _ec_GFp_nistp224_point_get_affine_coordinates
0.1% 0.2% 14.0KiB aws_config aws_config::sso::token::SsoTokenProvider::refresh_cached_token::{{closure}}
0.1% 0.2% 13.1KiB aws_lc_sys _aws_lc_0_27_0_pqcrystals_kyber1024_ref_indcpa_enc
0.1% 0.2% 12.7KiB http http::header::name::StandardHeader::from_bytes
0.1% 0.2% 12.7KiB http http::header::name::StandardHeader::from_bytes
0.1% 0.2% 12.4KiB aws_config <core::pin::Pin<P> as core::future::future::Future>::poll
0.1% 0.2% 12.4KiB aws_config aws_config::imds::credentials::ImdsCredentialsProvider::credentials::{{closure}}
0.1% 0.1% 12.2KiB [Unknown] p256_montjscalarmul_p256_montjadd
0.1% 0.1% 12.2KiB aws_sigv4 aws_sigv4::http_request::canonical_request::CanonicalRequest::from
0.1% 0.1% 12.1KiB [Unknown] p384_montjscalarmul_p384_montjdouble
0.1% 0.1% 12.1KiB aws_lc_sys _p384_montjdouble
0.1% 0.1% 12.0KiB aws_smithy_runtime aws_smithy_runtime::client::orchestrator::try_attempt::{{closure}}
0.1% 0.1% 12.0KiB aws_smithy_runtime aws_smithy_runtime::client::orchestrator::try_attempt::{{closure}}
0.1% 0.1% 11.9KiB aws_smithy_runtime aws_smithy_runtime::client::orchestrator::try_attempt::{{closure}}
0.1% 0.1% 11.9KiB aws_smithy_runtime aws_smithy_runtime::client::orchestrator::try_attempt::{{closure}}
0.1% 0.1% 11.8KiB aws_lc_sys _aws_lc_0_27_0_ml_kem_indcpa_enc_ref
0.1% 0.1% 11.7KiB aws_smithy_runtime aws_smithy_runtime::client::orchestrator::try_attempt::{{closure}}
0.1% 0.1% 11.7KiB aws_smithy_runtime aws_smithy_runtime::client::orchestrator::try_attempt::{{closure}}
0.1% 0.1% 11.6KiB hyper_util hyper_util::client::legacy::client::Client<C,B>::send_request::{{closure}}
0.1% 0.1% 11.5KiB aws_lc_sys _aws_lc_0_27_0_ml_kem_indcpa_keypair_derand_ref
0.1% 0.1% 11.4KiB aws_sdk_s3 aws_sdk_s3::protocol_serde::shape_put_object::ser_put_object_headers
0.1% 0.1% 11.3KiB aws_config aws_config::sso::token::SsoTokenProvider::refresh_cached_token::{{closure}}
0.1% 0.1% 11.3KiB aws_config aws_config::profile::credentials::ProfileFileCredentialsProvider::load_credentials::{{closure}}
0.1% 0.1% 11.0KiB aws_sdk_s3 aws_sdk_s3::s3_express::identity_provider::DefaultS3ExpressIdentityProvider::identity::{{closure}}
0.1% 0.1% 10.9KiB aws_lc_sys _aws_lc_0_27_0_ml_dsa_sign_internal
0.1% 0.1% 10.7KiB aws_config aws_config::web_identity_token::WebIdentityTokenCredentialsProvider::credentials::{{closure}}
0.1% 0.1% 10.7KiB aws_sdk_sts <aws_sdk_sts::operation::assume_role_with_web_identity::AssumeRoleWithWebIdentityResponseDeserializer as aws_smithy_runtime_api::client::ser_de::DeserializeResponse>::deseriali...
0.1% 0.1% 10.6KiB h2 h2::codec::framed_read::decode_frame
0.1% 0.1% 10.6KiB h2 h2::codec::framed_read::decode_frame
0.1% 0.1% 10.5KiB aws_config? <aws_config::imds::client::token::TokenResolver as aws_smithy_runtime_api::client::identity::ResolveIdentity>::resolve_identity::{{closure}}
0.1% 0.1% 10.5KiB aws_lc_sys _p521_jdouble_alt
0.1% 0.1% 10.3KiB aws_smithy_http_client h2::proto::connection::Connection<T,P,B>::poll
42.0% 87.6% 7.0MiB And 23518 smaller methods. Use -n N to show more.
47.9% 100.0% 7.9MiB .text section size, the file size is 16.6MiBSolution:
I'm afraid I don't have many suggestions for a full solution to this. I suspect that, since aws-lc is a mostly C based dependency, much of rustc's dead code elimination doesn't work for it so we are getting stuck pulling in functions we aren't actually using. The cheeky suggestion there is rewrite it in Rust, but that isn't a reasonable solution on any kind of short timescale.
Potentially splitting the various algorithms into their own crates could help rustc clean up better?
Activity
amyspark commentedon Apr 16, 2025
In our case it's not 4MB, it's 17 MB. The usual offender in gst-plugins-rs, gstrswebrtc, now sits at 804MB when statically built for MSVC.
The increase in size, combined with aws-smithy's own bloat, is now preventing us from shipping gst-plugins-rs's network-based plugins inside a MSI, at least as MSVC-based static libraries.
I assume the same will occur with MinGW, as there are no tools to prelink static libraries for PE/COFF.
faern commentedon May 8, 2026
We are also trying to migrate from
ringtoaws-lc-rs, and were surprised by the very large bump in binary size. After some investigation it seems like I was able to avoid most of the size increase by setting this environment variable:On x86_64 Linux and macOS this pulls down the size increase compared to ring from ~1.8 MiB to ~300 kiB. And on Windows from ~700 kiB to ~300 kiB. The best I have been able to do is a size regression of those ~300 kiB compared to
ring.Warning: as this removes some precomputed tables and removes some optimized code, it can potentially cost you performance, depending on what cryptographic primitives you are actually using and what target platform the binary runs on. For our use case this was completely acceptable.
I made a little github repository to experiment with these sizes. It contains more info about what these variables do, and how much size it saves on various platforms: https://github.com/faern/showcase-aws-lc-binary-size
I think it would be awesome if
aws-lc-rscould be more lean by default, and maybe expose cargo features that allow the user to opt-in to further optimizations, at the cost of binary size (and/or compile time). This would IMHO be better than having everyone pay a large binary tax for things most people might not use.OPENSSL_SMALL: imply MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX on x86_64 (#3319
Gate s2n-bignum _alt variants under OPENSSL_SMALL (#3320)
justsmth commentedon Aug 7, 2026
We just released aws-lc-rs v1.18.0 which adds built-in support for AWS-LC's size-optimized configuration:
-DOPENSSL_SMALL -DMY_ASSEMBLER_IS_TOO_OLD_FOR_512AVXworkaround @faern documented above, so it no longer requires hand-writtenAWS_LC_SYS_CFLAGS.The trade-off is slower elliptic-curve performance, but no algorithms are removed and all outputs are unchanged. It activates automatically when Cargo is already building for size (
opt-level = "s"or"z"), and can be forced independently of opt-level withAWS_LC_SYS_SMALL=1(or disabled with=0). FIPS builds require an explicitAWS_LC_FIPS_SYS_SMALL=1and warn when set.Measured in our CI on an executable that uses SHA-256, AES-256-GCM, and ECDSA P-256,
opt-level=zversusopt-level=3:This doesn't resolve everything raised here, so I'll leave this open for now.
@landonxjames @amyspark @faern -- would you mind re-measuring your respective cases against v1.18.0? @amyspark, yours (17 MB, MSVC static) is the one furthest from what our CI covers, so I'm particularly interested in whether it helps there.
Many thanks to all of you! π
amyspark commentedon Aug 7, 2026
I can confirm it's back under control. We've already been running
opt-level = "s"and can squash the rest of the overhead away by deduplicating the object files manually, or withlto = thin.