Skip to content

Export ECC private scalar in constant time - #12118

Open
SparkiDev wants to merge 1 commit into
wolfSSL:masterfrom
SparkiDev:hpke_p256_ct
Open

SparkiDev wants to merge 1 commit into
wolfSSL:masterfrom
SparkiDev:hpke_p256_ct

Conversation

@SparkiDev

Copy link
Copy Markdown
Contributor

Description

wc_export_int() sized the scalar with mp_unsigned_bin_size(), which counts its bits and so takes time that depends on the scalar's bit length. It is reached from wc_ecc_export_private_only() and from the HPKE receiver key copy. Since d is in [1, n-1], it always fits when the output covers the order: encode it with
mp_to_unsigned_bin_len_ct() instead.

Fixes zd#22808

Testing

./configure --enable-hpke

@SparkiDev SparkiDev self-assigned this Nov 13, 2026
Copilot AI balanced review requested due to automatic review settings November 13, 2026 00:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new ECC encoder still needs deterministic regression coverage for fixed-width padding, returned size, and undersized-buffer error handling without modifying the buffer.

1 open issue
What changed in this PR

This PR removes scalar-bit-length-dependent sizing from the ECC private-key export path used by wc_ecc_export_private_only() and HPKE receiver key copying.

Changes:

  • Uses constant-time encoding for unsigned binary exports when the output width covers the curve order.
  • Handles undersized buffers explicitly and retains the existing exporter for other formats or widths.
File Description
wolfcrypt/​src/​ecc.c Adds constant-time private-scalar encoding with output-length and buffer checks.

Review effort: Balanced

Comment thread wolfcrypt/src/ecc.c Resolved
@github-actions

github-actions Bot commented Nov 13, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report · Explore what changed →

gcc-arm-cortex-m0plus

  • FLASH: .text +32 B (+0.0%, 71,199 B / 262,144 B, total: 27% used)

gcc-arm-cortex-m3

  • FLASH: .text +32 B (+0.0%, 132,181 B / 262,144 B, total: 50% used)

gcc-arm-cortex-m4

  • FLASH: .text +64 B (+0.0%, 209,548 B / 262,144 B, total: 80% used)

gcc-arm-cortex-m4-dtls13

  • FLASH: .text +64 B (+0.0%, 197,224 B / 1,048,576 B, total: 19% used)

gcc-arm-cortex-m4-min-ecc

  • FLASH: .text +64 B (+0.1%, 68,441 B / 262,144 B, total: 26% used)

gcc-arm-cortex-m4-openssl-compat

  • FLASH: .text +64 B (+0.0%, 804,268 B / 1,048,576 B, total: 77% used)

gcc-arm-cortex-m4-pkcs7

  • FLASH: .text +64 B (+0.0%, 224,084 B / 262,144 B, total: 85% used)

gcc-arm-cortex-m4-pq

  • FLASH: .text +64 B (+0.0%, 314,136 B / 1,048,576 B, total: 30% used)

gcc-arm-cortex-m4-sp-math

  • FLASH: .text +64 B (+0.1%, 68,441 B / 262,144 B, total: 26% used)

gcc-arm-cortex-m4-tls12

  • FLASH: .text +64 B (+0.0%, 132,945 B / 262,144 B, total: 51% used)

gcc-arm-cortex-m4-tls13

  • FLASH: .text +64 B (+0.0%, 250,862 B / 262,144 B, total: 96% used)

gcc-arm-cortex-m7

  • FLASH: .text +64 B (+0.0%, 209,548 B / 262,144 B, total: 80% used)

gcc-arm-cortex-m7-pq

  • FLASH: .text +64 B (+0.0%, 314,968 B / 1,048,576 B, total: 30% used)

zephyr-frdm_rw612

  • FLASH: datas +16 B, log_const_area -8 B, rodata +36 B, text +11,776 B (+4.2%, 294,284 B / 67,108,864 B, total: 0% used)
  • RAM: bss +49 B, datas +16 B (+0.1%, 58,423 B / 983,040 B, total: 6% used)

No memory changes detected for:


Catch memory regressions in CI with MemBrowse. Free for open source.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The new ECC test lacks guards for configurations that exclude SECP256R1 or disable private export, causing failures on otherwise supported builds.

1 open issue
1 resolved since last review

Review effort: Balanced

Comment thread tests/api/test_ecc.c Resolved
wc_export_int() sized the scalar with mp_unsigned_bin_size(), which
counts its bits and so takes time that depends on the scalar's bit
length. It is reached from wc_ecc_export_private_only() and from the
HPKE receiver key copy. Since d is in [1, n-1], it always fits when
the output covers the order: encode it with
mp_to_unsigned_bin_len_ct() instead.
@SparkiDev

Copy link
Copy Markdown
Contributor Author

Jenkins: retest this please

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants