Skip to content

ecc: return infinity for a scalar that is 0 modulo the order - #11932

Open
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/f-mulmod
Open

yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/f-mulmod

Conversation

@yosuke-wolfssl

Copy link
Copy Markdown
Contributor

Problem

Only the public wc_ecc_mulmod() returns infinity for k == 0. Direct callers of wc_ecc_mulmod_ex() / wc_ecc_mulmod_ex2() (exported with WOLFSSL_PUBLIC_ECC_ADD_DBL) and ecc_mul2add() reach scalar multiplications that never produce a zero result.

accel_fp_mul2add() also lost a correct result. When the zA add reached infinity, the zB add in the same column made R a real point again but left first set. Later columns then skipped doublings, and in the last column ecc_map() read the copied table entry's z = 0 as infinity. ecc_mul2add(G, n - 2, G, 3) returned infinity instead of G.

Fix (wolfcrypt/src/ecc.c)

  • Entry guard: wc_ecc_mulmod_ex() and wc_ecc_mulmod_ex2(), FP and non-FP, set R to (0, 0, 1) and return when k is zero.
  • After the loop: accel_fp_mul(), accel_fp_mul2add() and normal_ecc_mul2add() set the result to infinity when first is still set, which covers scalars that reduce to 0.
  • accel_fp_mul2add(): when the zA add sets first, LUT[zB] is copied in with z = mu and first cleared, as the loop's other branch already does.

Closes f-16895, f-16896, f-16904.

Tests

test_wc_ecc_mulmod_zero (P-256) checks for exactly (0, 0, 1) on k == 0 through _ex / _ex2, with R pre-filled and with R aliasing G, and on k == 2n. It also checks ecc_mul2add() with both scalars 0 or 2n, and that ecc_mul2add(G, n - 2, G, 3) is G. The FP_ECC cache is reset before each loop so the cached-table paths run. It needs WOLFSSL_PUBLIC_MP and WOLFSSL_PUBLIC_ECC_ADD_DBL, so the all-public-mp job in os-check-linux.json now also defines the latter.

Verification

  • Six configs (default, --disable-harden, --enable-fpecc, fpecc + --disable-harden, --enable-heapmath, WC_PROTECT_ENCRYPTED_MEM): pass under GCC -Werror, ASan + UBSan clean. Each fails or crashes with its fix reverted.
  • all-public-mp through parallel-make-check.py with the CI flags: make check 24 suites, 0 failures. The new test runs and passes.

@yosuke-wolfssl yosuke-wolfssl self-assigned this Oct 30, 2026
Copilot AI balanced review requested due to automatic review settings October 30, 2026 02:11

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.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

@yosuke-wolfssl

Copy link
Copy Markdown
Contributor Author

@claude review

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

MemBrowse Memory Report · Explore what changed →

gcc-arm-cortex-m4

  • FLASH: .text +128 B (+0.1%, 208,432 B / 262,144 B, total: 80% used)

gcc-arm-cortex-m4-crypto-only

  • FLASH: .text +64 B (+0.0%, 181,651 B / 262,144 B, total: 69% used)

gcc-arm-cortex-m4-dtls13

  • FLASH: .text +128 B (+0.1%, 195,096 B / 1,048,576 B, total: 19% used)

gcc-arm-cortex-m4-openssl-compat

  • FLASH: .text +128 B (+0.0%, 796,252 B / 1,048,576 B, total: 76% used)

gcc-arm-cortex-m4-pkcs7

  • FLASH: .text +128 B (+0.1%, 222,804 B / 262,144 B, total: 85% used)

gcc-arm-cortex-m4-pq

  • FLASH: .text +192 B (+0.1%, 311,888 B / 1,048,576 B, total: 30% used)

gcc-arm-cortex-m4-tls13

  • FLASH: .text +128 B (+0.1%, 248,802 B / 262,144 B, total: 95% used)

gcc-arm-cortex-m7

  • FLASH: .text +128 B (+0.1%, 208,496 B / 262,144 B, total: 80% used)

gcc-arm-cortex-m7-pq

  • FLASH: .text +128 B (+0.0%, 312,720 B / 1,048,576 B, total: 30% used)

gcc-arm-cortex-m7-tls13

  • FLASH: .text +128 B (+0.1%, 248,802 B / 262,144 B, total: 95% used)

zephyr-frdm_rw612

  • FLASH: log_const_area -8 B, rodata -8 B, text +1,600 B (+0.6%, 284,048 B / 67,108,864 B, total: 0% used)

No memory changes detected for:


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

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #11932

Scan targets checked: wolfcrypt-src, wolfcrypt-bugs, wolfssl-bugs
Not reviewed (no scan target covers them): .github/configs/os-check-linux.json, tests/api/test_ecc.h
Coverage: 2 of 2 in-scope changed file(s) opened by the reviewer

Fenrir result: Approved ✅

No new issues found in the changed files.

Advisory only — this automated result does not count as a GitHub approval.

Review tier: Lite

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I reviewed this PR and didn't find any bugs. It changes core ECC scalar multiplication in both the FP_ECC and non-FP_ECC builds, so a human look from someone who owns ecc.c is still worthwhile.

What was reviewed:

  • The zero-k early return in the non-FP wc_ecc_mulmod_ex: it jumps to exit before anything is allocated, and the cleanup code there handles NULL tG, NULL M[] and NULL key.
  • The new first == 1 handling after the loops in ecc_mul2add, accel_fp_mul and accel_fp_mul2add. In the accel_fp_mul2add zB branch, copying LUT[zB] with z = mu matches the existing zA copy.
  • ecc_set_point_infinity is defined in a block guarded the same way as its new callers. The zero-scalar early return branches on a public-zero condition rather than on secret bits, but whether that is acceptable in hardened builds is a maintainer call.
Extended reasoning...

The change touches wolfcrypt/src/ecc.c, which handles ECC scalar multiplication and point addition: early returns for k == 0, setting the result to infinity after the loop, and a fix to how accel_fp_mul2add tracks first. It also adds a P-256 regression test and turns on WOLFSSL_PUBLIC_ECC_ADD_DBL in one CI config. This is security-sensitive crypto code, and the change could affect correctness and constant-time behaviour across several build variants (FP_ECC, SMALL_STACK_CACHE, NO_MALLOC). That is why I deferred instead of approving, even though the bug hunt ran until it stopped finding anything and reported no bugs.

- wc_ecc_mulmod_ex() and wc_ecc_mulmod_ex2(), with and without
  FP_ECC, set R to (0, 0, 1) and return when k is zero.
- accel_fp_mul(), accel_fp_mul2add() and normal_ecc_mul2add() set
  the result to infinity when first is still set after the loop.
- accel_fp_mul2add() copies LUT[zB] into R and clears first when
  the add of LUT[zA] in the same column set first.
- tests: add test_wc_ecc_mulmod_zero for k == 0, k == 2n, and
  ecc_mul2add() with both scalars 0 or 2n and with (n - 2, 3).
- os-check: all-public-mp adds -DWOLFSSL_PUBLIC_ECC_ADD_DBL.

Issue: F-16895, F-16896, F-16904
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.

4 participants