From 46bee92f9e64c0a06a12586a5d21cffc49d1ba8e Mon Sep 17 00:00:00 2001 From: fengjian <445077+fengjian@users.noreply.github.com> Date: Thu, 29 Jan 2026 17:56:12 +0800 Subject: [PATCH 1/5] crypto/ecies: fix ECIES invalid-curve handling (#33669) Fix ECIES invalid-curve handling in RLPx handshake (reject invalid ephemeral pubkeys early) - Add curve validation in crypto/ecies.GenerateShared to reject invalid public keys before ECDH. - Update RLPx PoC test to assert invalid curve points fail with ErrInvalidPublicKey. Motivation / Context RLPx handshake uses ECIES decryption on unauthenticated network input. Prior to this change, an invalid-curve ephemeral public key would proceed into ECDH and only fail at MAC verification, returning ErrInvalidMessage. This allows an oracle on decrypt success/failure and leaves the code path vulnerable to invalid-curve/small-subgroup attacks. The fix enforces IsOnCurve validation up front. --- crypto/ecies/ecies.go | 3 ++ p2p/rlpx/rlpx_oracle_poc_test.go | 57 ++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 p2p/rlpx/rlpx_oracle_poc_test.go diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 9a892781f4..378d764a19 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -124,6 +124,9 @@ func (prv *PrivateKey) GenerateShared(pub *PublicKey, skLen, macLen int) (sk []b if prv.PublicKey.Curve != pub.Curve { return nil, ErrInvalidCurve } + if pub.X == nil || pub.Y == nil || !pub.Curve.IsOnCurve(pub.X, pub.Y) { + return nil, ErrInvalidPublicKey + } if skLen+macLen > MaxSharedKeyLength(pub) { return nil, ErrSharedKeyTooBig } diff --git a/p2p/rlpx/rlpx_oracle_poc_test.go b/p2p/rlpx/rlpx_oracle_poc_test.go new file mode 100644 index 0000000000..3497f0026e --- /dev/null +++ b/p2p/rlpx/rlpx_oracle_poc_test.go @@ -0,0 +1,57 @@ +package rlpx + +import ( + "bytes" + "errors" + "testing" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/ecies" +) + +func TestHandshakeECIESInvalidCurveOracle(t *testing.T) { + initKey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + respKey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + + init := handshakeState{ + initiator: true, + remote: ecies.ImportECDSAPublic(&respKey.PublicKey), + } + authMsg, err := init.makeAuthMsg(initKey) + if err != nil { + t.Fatal(err) + } + packet, err := init.sealEIP8(authMsg) + if err != nil { + t.Fatal(err) + } + + var recv handshakeState + if _, err := recv.readMsg(new(authMsgV4), respKey, bytes.NewReader(packet)); err != nil { + t.Fatalf("expected valid packet to decrypt: %v", err) + } + + tampered := append([]byte(nil), packet...) + if len(tampered) < 2+65 { + t.Fatalf("unexpected packet length %d", len(tampered)) + } + tampered[2] = 0x04 + for i := 1; i < 65; i++ { + tampered[2+i] = 0x00 + } + + var recv2 handshakeState + _, err = recv2.readMsg(new(authMsgV4), respKey, bytes.NewReader(tampered)) + if err == nil { + t.Fatal("expected decryption failure for invalid curve point") + } + if !errors.Is(err, ecies.ErrInvalidPublicKey) { + t.Fatalf("unexpected error: %v", err) + } +} From 895a8597cb16c02203e38707ed2d1da5c500fe60 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Feb 2026 17:01:39 +0100 Subject: [PATCH 2/5] crypto/secp256k1: fix coordinate check --- crypto/secp256k1/curve.go | 4 ++++ crypto/secp256k1/ext.h | 6 ++++-- crypto/signature_nocgo.go | 7 +++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/crypto/secp256k1/curve.go b/crypto/secp256k1/curve.go index b82b147e3c..504602f5be 100644 --- a/crypto/secp256k1/curve.go +++ b/crypto/secp256k1/curve.go @@ -73,6 +73,10 @@ func (bitCurve *BitCurve) Params() *elliptic.CurveParams { // IsOnCurve returns true if the given (x,y) lies on the BitCurve. func (bitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool { + if x.Cmp(bitCurve.P) >= 0 || y.Cmp(bitCurve.P) >= 0 { + return false + } + // y² = x³ + b y2 := new(big.Int).Mul(y, y) //y² y2.Mod(y2, bitCurve.P) //y²%P diff --git a/crypto/secp256k1/ext.h b/crypto/secp256k1/ext.h index 1c485e2603..baafb4404b 100644 --- a/crypto/secp256k1/ext.h +++ b/crypto/secp256k1/ext.h @@ -109,8 +109,10 @@ int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, unsigned char *point, ARG_CHECK(scalar != NULL); (void)ctx; - secp256k1_fe_set_b32_limit(&feX, point); - secp256k1_fe_set_b32_limit(&feY, point+32); + if (!secp256k1_fe_set_b32_limit(&feX, point) || + !secp256k1_fe_set_b32_limit(&feY, point+32)) { + return 0; + } secp256k1_ge_set_xy(&ge, &feX, &feY); secp256k1_scalar_set_b32(&s, scalar, &overflow); if (overflow || secp256k1_scalar_is_zero(&s)) { diff --git a/crypto/signature_nocgo.go b/crypto/signature_nocgo.go index d76127c258..2fd830ffc5 100644 --- a/crypto/signature_nocgo.go +++ b/crypto/signature_nocgo.go @@ -164,6 +164,13 @@ type btCurve struct { *secp256k1.KoblitzCurve } +func (curve btCurve) IsOnCurve(x, y *big.Int) bool { + if x.Cmp(secp256k1.Params().P) >= 0 || y.Cmp(secp256k1.Params().P) >= 0 { + return false + } + return curve.KoblitzCurve.IsOnCurve(x, y) +} + // Marshal converts a point given as (x, y) into a byte slice. func (curve btCurve) Marshal(x, y *big.Int) []byte { byteLen := (curve.Params().BitSize + 7) / 8 From 95665d5703e1023995a0ff93e4ce9eb77e8a59bd Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Feb 2026 17:04:51 +0100 Subject: [PATCH 3/5] version: release go-ethereum v1.16.9 --- version/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version/version.go b/version/version.go index dd944470ea..84a1ec2e17 100644 --- a/version/version.go +++ b/version/version.go @@ -19,6 +19,6 @@ package version const ( Major = 1 // Major version component of the current release Minor = 16 // Minor version component of the current release - Patch = 8 // Patch version component of the current release + Patch = 9 // Patch version component of the current release Meta = "stable" // Version metadata to append to the version string ) From 90e37d18dddc81fbc899e74e9947d84096e17469 Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Mon, 6 Jul 2026 17:14:04 +0530 Subject: [PATCH 4/5] docs: add v1.17.4 upstream-merge plan and ledger (v1.16.9 milestone chores) --- docs/upstream-merges/v1.17.4/ledger.md | 9 +++ docs/upstream-merges/v1.17.4/plan.md | 89 ++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 docs/upstream-merges/v1.17.4/ledger.md create mode 100644 docs/upstream-merges/v1.17.4/plan.md diff --git a/docs/upstream-merges/v1.17.4/ledger.md b/docs/upstream-merges/v1.17.4/ledger.md new file mode 100644 index 0000000000..c860c693e5 --- /dev/null +++ b/docs/upstream-merges/v1.17.4/ledger.md @@ -0,0 +1,9 @@ +# Decision ledger: go-ethereum v1.17.4 sync + +Append-only. One line per non-trivial resolution: file — class — upstream PR — decision — why. + +## v1.16.9 + +- `crypto/ecies/ecies.go` — class 3 — #33669 — took upstream's `IsOnCurve` validation in `GenerateShared` — genuine invalid-curve guard absent from Bor; expect the duplicate commit (`c974722dc`, v1.17.0 batch 10) to now merge clean. +- `crypto/secp256k1/curve.go` — class 3 — upstream `895a8597c` — kept Bor's text — Bor pre-applied the identical coordinate check via `d9fac7a4c`; only delta was Bor's comment. +- `crypto/secp256k1/ext.h` — class 3 — upstream `895a8597c` — took upstream's combined `if (!a || !b)` form over Bor's equivalent two-if variant — zero behavior delta; converges text with upstream to de-conflict future syncs. diff --git a/docs/upstream-merges/v1.17.4/plan.md b/docs/upstream-merges/v1.17.4/plan.md new file mode 100644 index 0000000000..8870338a4a --- /dev/null +++ b/docs/upstream-merges/v1.17.4/plan.md @@ -0,0 +1,89 @@ +# Upstream merge plan: go-ethereum v1.17.4 + +| Field | Value | +| --------------- | ------------------------------------------------------------ | +| Target | `v1.17.4` (`36a7dc72e96b3f42846be925cfeb2fad18489917`) | +| SYNC_BASE | `v1.16.8` (`abeb78c647e354ed922726a1d719ac7bc64a07e2`) — highest upstream release tag that is an ancestor of `develop`. Persisted; never recompute on resume. | +| Batch size | 20 first-parent commits | +| Upstream remote | `upstream` (https://github.com/ethereum/go-ethereum.git) | +| Base branch | `upstream-merge/v1.17.4` (cut from `origin/develop`; **not yet created** — plan-only run) | +| Planned | 2026-07-06 (plan-only; no merges performed) | +| Totals | 607 first-parent commits, 6 milestones, 33 batches | + +Notes: + +- `v1.16.9` is not integrated into `develop` (it lives on upstream `release/1.16`), so it is the first milestone. Expect already-applied no-op conflicts when crossing between release branches (its two crypto fixes reappear on the v1.17.0 line as `c974722dc` / `9b78f45e3`). +- Already-integrated guard: none of the six milestone tags is an ancestor of `origin/develop` (checked 2026-07-06); all six stand. +- Boundary SHAs are upstream first-parent commits (trees upstream CI passed). + +## Batches + +Status legend: `pending` / `in-progress` / `merged` / `skipped`. + +| # | Milestone | Batch | Boundary | Commits | Theme | Status | +| -- | --------- | ----- | ----------- | ------- | ---------------------------------------------------------------------------------------------- | ------- | +| 1 | v1.16.9 | 1/1 | `95665d570` | 3 | crypto security backports (ECIES invalid-curve, secp256k1 coordinate check) + release | merged (`a06dbd7d2`) | +| 2 | v1.17.0 | 1/12 | `f23d506b7` | 20 | bugfix sweep: rawdb/state/pathdb fixes, RPC framing, blobpool, filters | pending | +| 3 | v1.17.0 | 2/12 | `cf93077fa` | 20 | verkle/UBT groundwork, rawdb+rlp hardening, fusaka beacon update | pending | +| 4 | v1.17.0 | 3/12 | `a122dbe45` | 20 | **EIP-8024 introduced** (`core/vm`), miner `--miner.maxblobs`, gnark-crypto bump | pending | +| 5 | v1.17.0 | 4/12 | `228933a66` | 20 | catalyst getPayload fork checks, pebble config, slow-block stats, downloader syncmode | pending | +| 6 | v1.17.0 | 5/12 | `5dfcffcf3` | 20 | state/code-read metrics, tx fetcher validation, blobpool legacy sidecar removal | pending | +| 7 | v1.17.0 | 6/12 | `710008450` | 20 | snap-sync locking, getBlobsV3, pathdb history indexing, go-verkle removal | pending | +| 8 | v1.17.0 | 7/12 | `94710f79a` | 20 | state update hook, trienode history compression, blobpool gaps; KZG peer-drop fix | pending | +| 9 | v1.17.0 | 8/12 | `8fad02ac6` | 20 | OpenTelemetry RPC tracing, **read-only gas handlers (`core/vm`)**, trienode history enable | pending | +| 10 | v1.17.0 | 9/12 | `845009f68` | 20 | eth_getProofs for history, **EIP-8024 immediate-byte update**, alloc reductions | pending | +| 11 | v1.17.0 | 10/12 | `c12959dc8` | 20 | perf/alloc sweep, keccak vendoring, Ledger Gen5, rlp RawList | pending | +| 12 | v1.17.0 | 11/12 | `c50e5edfa` | 20 | EraE format, rlp iterators, HTTP/2 JSON-RPC, telemetry CLI wiring | pending | +| 13 | v1.17.0 | 12/12 | `0cf3d3ba4` | 7 | delayed p2p decoding, header-verification hardening, **v1.17.0 release** | pending | +| 14 | v1.17.1 | 1/2 | `9ecb6c4ae` | 20 | **syscall value-transfer disable (`core/vm`)**, BAL type changes, **Amsterdam precompile touch** | pending | +| 15 | v1.17.1 | 2/2 | `16783c167` | 20 | **eth/68 protocol drop**, **EIP-7843 SLOTNUM**, **8024 enabled in Amsterdam**, Go 1.26; release | pending | +| 16 | v1.17.2 | 1/4 | `00540f946` | 20 | **EIP-7778 block gas accounting**, miner prefetcher, **amsterdam jump table**, default cache 4096 | pending | +| 17 | v1.17.2 | 2/4 | `77e7e5ad1` | 20 | codedb refactor, **EIP-7954 max contract size**, trienode history alongside data | pending | +| 18 | v1.17.2 | 3/4 | `e23b0cbc2` | 20 | stateless codedb fix, **call-variant gas measurement rework (`core/vm`)**, bintrie parallel hash | pending | +| 19 | v1.17.2 | 4/4 | `be4dc0c4b` | 17 | **EIP-7708**, simulateV1/getProofs limits, **v1.17.2 release** | pending | +| 20 | v1.17.3 | 1/7 | `04e40995d` | 20 | **eth/70 partial receipts**, BAL storage layer + snap/2 BAL serving | pending | +| 21 | v1.17.3 | 2/7 | `c453b99a5` | 20 | **gas becomes vector (`core`)**, bintrie fixes | pending | +| 22 | v1.17.3 | 3/7 | `5af5510b1` | 20 | EIP-7610 rework, CachingDB split (merkle/binary), freezer fsync fix | pending | +| 23 | v1.17.3 | 4/7 | `33c1bd59f` | 20 | **gas budget (`core/vm`)**, **EIP-7976 calldata floor**, **FinalizeAndAssemble removed (consensus iface)** | pending | +| 24 | v1.17.3 | 5/7 | `41b856d47` | 20 | BAL spec update, **stack arena (`core/vm`)**, skip tx gas cap post-Amsterdam | pending | +| 25 | v1.17.3 | 6/7 | `1abbae239` | 20 | **EIP-7981 access-list cost**, eth_call block overrides, TypeMux removal | pending | +| 26 | v1.17.3 | 7/7 | `117e067f0` | 16 | misc fixes, **core.Message moves to uint256**, **v1.17.3 release** | pending | +| 27 | v1.17.4 | 1/7 | `1149f76dc` | 20 | pre/post-execution wrap (`core`+miner), GasChangeHook v2, block-level accessList | pending | +| 28 | v1.17.4 | 2/7 | `ca1a027fa` | 20 | **block accessList construction (consensus/miner)**, eth71 BAL response, engine_hasBlobs | pending | +| 29 | v1.17.4 | 3/7 | `4017efe34` | 20 | **jumpdest bitmap global cache (`core/vm`)**, RPC hardening, deprecated CLI flag removal | pending | +| 30 | v1.17.4 | 4/7 | `80d9ba5d9` | 20 | blobpool status queue, BAL freezer management, snapv2 skeleton | pending | +| 31 | v1.17.4 | 5/7 | `e444c267a` | 20 | **clef removed**, repo-wide typo sweep (`all:`), blob sidecar fixes | pending | +| 32 | v1.17.4 | 6/7 | `8c540cb08` | 20 | **snap/2 sync logic**, **EIP-8037 state-creation gas**, cgroup memlimit | pending | +| 33 | v1.17.4 | 7/7 | `36a7dc72e` | 4 | reflect.Pointer sweep (`all:`), **v1.17.4 release** | pending | + +## Bor-specific risk flags (advance warning, not a substitute for per-batch review) + +- **Consensus interface churn:** batch 23 removes `FinalizeAndAssemble` from the + consensus interface and batches 27–28 rework block assembly around block + access lists — `consensus/bor` implements this interface, so expect class-3 + conflicts and real porting work there, not mechanical merges. +- **EVM/hardfork surfaces** (invariant: full individual walkthrough, never + grouped): EIP-8024 (batches 4, 10, 15), EIP-7843 SLOTNUM (15), EIP-7778 (16), + EIP-7954 (17), EIP-7708 (19), EIP-7976 (23), EIP-7981 (25), EIP-8037 (32), + Amsterdam jump-table/precompile wiring (14–16), call-gas rework (18), gas + vector (21), gas budget (23), jumpdest cache (29). Every one of these touches + `core/vm` / `params` and lands behind upstream's Amsterdam fork — Bor must + decide fork-gating against its own hardfork schedule; precompile continuity + tests (`core/vm/contracts_continuity_test.go`) must be preserved. +- **P2P protocol changes:** eth/68 dropped (15), eth/70 partial receipts (20), + eth/71 BAL (28), snap/2 (20, 30, 32) — check against Bor's protocol + registration and peer management. +- **Miner:** prefetcher enable (16), payload rebuild timing (15), slot number + (27–30) — interacts with Bor's sprint-based mining loop. +- **Wide-but-shallow sweeps:** typo sweep (31) and reflect.Pointer sweep (33) + touch `all:` — expect many trivial conflicts against Bor-modified files. +- **v1.16.9 duplicates:** its two crypto fixes reappear in batches 10 and 13 — + expect no-op/already-applied conflicts there. + +## Resume anchors + +- `PROGRESS_TIP`: none yet (no batch merged). +- Working branch for milestone 1 (`v1.16.9`): `ppatil/upstream-v1.16.9` — to be + cut from `upstream-merge/v1.17.4` on the milestone's first batch. +- Full first-parent logs per milestone captured in the planning run directory: + `runs/pos-merge-upstream/2026-07-06T09-56-56Z-claude-v1.17.4-plan/log-.txt`. From 452398d09eba25f91ad9771804929fc169b7251e Mon Sep 17 00:00:00 2001 From: Pratik Patil Date: Thu, 16 Jul 2026 13:55:47 +0530 Subject: [PATCH 5/5] docs: use slash-free upstream-merge branch names (ruleset fnmatch constraint) --- docs/upstream-merges/v1.17.4/plan.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/upstream-merges/v1.17.4/plan.md b/docs/upstream-merges/v1.17.4/plan.md index 8870338a4a..e7bf4b51aa 100644 --- a/docs/upstream-merges/v1.17.4/plan.md +++ b/docs/upstream-merges/v1.17.4/plan.md @@ -6,7 +6,7 @@ | SYNC_BASE | `v1.16.8` (`abeb78c647e354ed922726a1d719ac7bc64a07e2`) — highest upstream release tag that is an ancestor of `develop`. Persisted; never recompute on resume. | | Batch size | 20 first-parent commits | | Upstream remote | `upstream` (https://github.com/ethereum/go-ethereum.git) | -| Base branch | `upstream-merge/v1.17.4` (cut from `origin/develop`; **not yet created** — plan-only run) | +| Base branch | `upstream-merge-v1.17.4` (cut from `origin/develop`). Slash-free on purpose: bor ruleset 626146 excludes `refs/heads/**upstream**` from the signed-commit requirement, and `**` does not cross `/` — slashed names stay rule-covered and reject unsigned upstream commits. Working branches follow the same constraint (`-upstream-`). | | Planned | 2026-07-06 (plan-only; no merges performed) | | Totals | 607 first-parent commits, 6 milestones, 33 batches | @@ -83,7 +83,7 @@ Status legend: `pending` / `in-progress` / `merged` / `skipped`. ## Resume anchors - `PROGRESS_TIP`: none yet (no batch merged). -- Working branch for milestone 1 (`v1.16.9`): `ppatil/upstream-v1.16.9` — to be - cut from `upstream-merge/v1.17.4` on the milestone's first batch. +- Working branch for milestone 1 (`v1.16.9`): `ppatil-upstream-v1.16.9` — cut + from `upstream-merge-v1.17.4` on the milestone's first batch. - Full first-parent logs per milestone captured in the planning run directory: `runs/pos-merge-upstream/2026-07-06T09-56-56Z-claude-v1.17.4-plan/log-.txt`.