Skip to content

[prover] Fix signed integer division semantics in Move Prover#18580

Draft
GotenJBZ wants to merge 5 commits intomainfrom
fix-signed-div-mod-semantics
Draft

[prover] Fix signed integer division semantics in Move Prover#18580
GotenJBZ wants to merge 5 commits intomainfrom
fix-signed-div-mod-semantics

Conversation

@GotenJBZ
Copy link
Member

@GotenJBZ GotenJBZ commented Feb 2, 2026

Boogie's built-in div/mod operators use floor division, while Move/Rust use truncation division. This causes incorrect verification for signed integers with negative operands.

Add $truncDiv and $truncMod functions to implement truncation semantics and update spec_translator to use them for div/mod operations.

Description

How Has This Been Tested?

Key Areas to Review

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Performance improvement
  • Refactoring
  • Dependency update
  • Documentation update
  • Tests

Which Components or Systems Does This Change Impact?

  • Validator Node
  • Full Node (API, Indexer, etc.)
  • Move/Aptos Virtual Machine
  • Aptos Framework
  • Aptos CLI/SDK
  • Developer Infrastructure
  • Move Compiler
  • Other (specify)

Checklist

  • I have read and followed the CONTRIBUTING doc
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I identified and added all stakeholders and component owners affected by this change as reviewers
  • I tested both happy and unhappy path of the functionality
  • I have made corresponding changes to the documentation

Note

High Risk
High risk because it introduces automated deletion of state Merkle stale nodes via a new background cleaner and adds new allocator configuration paths (jemalloc), both of which can impact node stability and data integrity if misconfigured.

Overview
Adds a new state tree debugging command (check_stale_nodes) plus a background leaked stale node cleanup worker (leaked_stale_node_cleaner) that snapshots pruner progress, iterates shard/metadata DBs, and batch-deletes JellyfishMerkleNode + stale-index entries up to persisted target versions.

Introduces a new aptos-jemalloc crate with a setup_jemalloc! macro (global allocator + malloc_conf) and an optional metrics collection thread exporting aptos_jemalloc_bytes; also adds TelemetryServiceConfig with a configurable/default thread count.

Expands Move and crypto test coverage: new e2e tests for crypto_algebra type-tag budget handling and gas-profiler HTML report generation, new randomness smoke tests (fast-path on/off + optimistic verification scenarios), new order_id_generation framework module (bit-reversed monotonic order IDs) with tests, additional trading bulk order validation tests, and a large set of new Move bytecode verifier transactional tests. Also adds DKG crypto types/serialization utilities (Subtranscript aggregation + sigma Proof enum serialization) and new docker builder scripts for CLI/perf profiles.

Written by Cursor Bugbot for commit 726fac2. This will update automatically on new commits. Configure here.

@GotenJBZ GotenJBZ requested review from junxzm1990 and wrwg February 2, 2026 22:56
@GotenJBZ GotenJBZ changed the title [vm] Fix signed integer division semantics in Move Prover [prover] Fix signed integer division semantics in Move Prover Feb 2, 2026
@gregnazario gregnazario requested a review from Copilot February 2, 2026 23:01
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes incorrect verification behavior in the Move Prover for signed integer division and modulo operations. Boogie's built-in div/mod operators use floor division semantics, while Move/Rust use truncation division, causing verification failures when negative operands are involved.

Changes:

  • Added $truncDiv and $truncMod helper functions implementing truncation semantics
  • Updated $Div and $Mod procedures to use truncation logic
  • Modified spec_translator to call truncation helpers for non-bitvector division/modulo operations

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
third_party/move/move-prover/boogie-backend/src/prelude/prelude.bpl Implements truncation division/modulo functions and updates $Div/$Mod procedures
third_party/move/move-prover/boogie-backend/src/spec_translator.rs Routes Div/Mod operations through new truncation helpers
third_party/move/move-prover/tests/sources/functional/signed_int/signed_div_cast.move Adds functional test for signed division with casts

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@GotenJBZ GotenJBZ force-pushed the fix-signed-div-mod-semantics branch from ac9a143 to fe474df Compare February 3, 2026 00:58
@GotenJBZ GotenJBZ enabled auto-merge (squash) February 4, 2026 21:12
@junxzm1990 junxzm1990 disabled auto-merge February 4, 2026 21:37
@junxzm1990 junxzm1990 enabled auto-merge (squash) February 4, 2026 21:40
@GotenJBZ GotenJBZ force-pushed the fix-signed-div-mod-semantics branch from f5721d1 to 78fecc4 Compare February 4, 2026 21:44
@junxzm1990 junxzm1990 disabled auto-merge February 4, 2026 22:04
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 4, 2026

✅ Forge suite compat success on 1543a9cac46a100c4ab4cafe6b3f2c35bd50538c ==> 78fecc4efa5e891a87bdbf36eefc74d25784a007

Compatibility test results for 1543a9cac46a100c4ab4cafe6b3f2c35bd50538c ==> 78fecc4efa5e891a87bdbf36eefc74d25784a007 (PR)
1. Check liveness of validators at old version: 1543a9cac46a100c4ab4cafe6b3f2c35bd50538c
compatibility::simple-validator-upgrade::liveness-check : committed: 13141.29 txn/s, latency: 2643.74 ms, (p50: 2700 ms, p70: 3000, p90: 3300 ms, p99: 3700 ms), latency samples: 431600
2. Upgrading first Validator to new version: 78fecc4efa5e891a87bdbf36eefc74d25784a007
compatibility::simple-validator-upgrade::single-validator-upgrade : committed: 5874.46 txn/s, latency: 5734.74 ms, (p50: 6300 ms, p70: 6400, p90: 6600 ms, p99: 6800 ms), latency samples: 202700
3. Upgrading rest of first batch to new version: 78fecc4efa5e891a87bdbf36eefc74d25784a007
compatibility::simple-validator-upgrade::half-validator-upgrade : committed: 5793.16 txn/s, latency: 5850.80 ms, (p50: 6500 ms, p70: 6600, p90: 6700 ms, p99: 6800 ms), latency samples: 198600
4. upgrading second batch to new version: 78fecc4efa5e891a87bdbf36eefc74d25784a007
compatibility::simple-validator-upgrade::rest-validator-upgrade : committed: 9716.05 txn/s, latency: 3322.97 ms, (p50: 3300 ms, p70: 3800, p90: 4500 ms, p99: 5000 ms), latency samples: 323780
5. check swarm health
Compatibility test for 1543a9cac46a100c4ab4cafe6b3f2c35bd50538c ==> 78fecc4efa5e891a87bdbf36eefc74d25784a007 passed
Test Ok

@github-actions
Copy link
Contributor

github-actions bot commented Feb 4, 2026

✅ Forge suite realistic_env_max_load success on 78fecc4efa5e891a87bdbf36eefc74d25784a007

two traffics test: inner traffic : committed: 13662.25 txn/s, submitted: 13662.79 txn/s, expired: 0.54 txn/s, latency: 2754.31 ms, (p50: 2700 ms, p70: 2900, p90: 3000 ms, p99: 3600 ms), latency samples: 5087740
two traffics test : committed: 100.00 txn/s, latency: 765.13 ms, (p50: 700 ms, p70: 800, p90: 900 ms, p99: 1000 ms), latency samples: 1740
Latency breakdown for phase 0: ["MempoolToBlockCreation: max: 2.239, avg: 2.161", "ConsensusProposalToOrdered: max: 0.169, avg: 0.167", "ConsensusOrderedToCommit: max: 0.056, avg: 0.049", "ConsensusProposalToCommit: max: 0.221, avg: 0.216"]
Max non-epoch-change gap was: 0 rounds at version 0 (avg 0.00) [limit 4], 0.45s no progress at version 5234955 (avg 0.07s) [limit 15].
Max epoch-change gap was: 0 rounds at version 0 (avg 0.00) [limit 4], 0.34s no progress at version 2444200 (avg 0.34s) [limit 16].
Test Ok

@github-actions
Copy link
Contributor

github-actions bot commented Feb 4, 2026

✅ Forge suite framework_upgrade success on 1543a9cac46a100c4ab4cafe6b3f2c35bd50538c ==> 78fecc4efa5e891a87bdbf36eefc74d25784a007

Compatibility test results for 1543a9cac46a100c4ab4cafe6b3f2c35bd50538c ==> 78fecc4efa5e891a87bdbf36eefc74d25784a007 (PR)
Upgrade the nodes to version: 78fecc4efa5e891a87bdbf36eefc74d25784a007
framework_upgrade::framework-upgrade::full-framework-upgrade : committed: 2231.62 txn/s, submitted: 2240.61 txn/s, failed submission: 8.99 txn/s, expired: 8.99 txn/s, latency: 1307.24 ms, (p50: 1200 ms, p70: 1500, p90: 1800 ms, p99: 2100 ms), latency samples: 198682
framework_upgrade::framework-upgrade::full-framework-upgrade : committed: 2153.00 txn/s, submitted: 2160.91 txn/s, failed submission: 7.91 txn/s, expired: 7.91 txn/s, latency: 1349.98 ms, (p50: 1200 ms, p70: 1500, p90: 1800 ms, p99: 2100 ms), latency samples: 195881
5. check swarm health
Compatibility test for 1543a9cac46a100c4ab4cafe6b3f2c35bd50538c ==> 78fecc4efa5e891a87bdbf36eefc74d25784a007 passed
Upgrade the remaining nodes to version: 78fecc4efa5e891a87bdbf36eefc74d25784a007
framework_upgrade::framework-upgrade::full-framework-upgrade : committed: 1850.61 txn/s, submitted: 1856.71 txn/s, failed submission: 6.09 txn/s, expired: 6.09 txn/s, latency: 1846.03 ms, (p50: 1200 ms, p70: 1400, p90: 2000 ms, p99: 11800 ms), latency samples: 151861
Test Ok

Boogie's built-in div/mod operators use floor division, while Move/Rust
use truncation division. This causes incorrect verification for signed
integers with negative operands.

Add $truncDiv and $truncMod functions to implement truncation semantics
and update spec_translator to use them for div/mod operations.
@GotenJBZ GotenJBZ force-pushed the fix-signed-div-mod-semantics branch from 78fecc4 to 64df3f6 Compare February 4, 2026 23:23
@GotenJBZ GotenJBZ requested a review from junxzm1990 February 4, 2026 23:37
@GotenJBZ GotenJBZ force-pushed the fix-signed-div-mod-semantics branch from 0afd265 to 10340ce Compare February 5, 2026 23:18
// When src1 < 0 and src2 < 0 and not exact: trunc = euc - 1
if ( src1 >= 0 ) then
src1 div src2
else if (src1 mod src2 == 0) then
Copy link
Contributor

Choose a reason for hiding this comment

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

This has two division ops (mod and div) in strict execution path which is very expensive for SMT solving.

Why don't we do

if (src1 >= 0 && src2 >= 0) { <<old code>> } else { <<new code>> }

... as I suggested? Then all existing verification or uNN do the same as before (just a little comparison tests). Signed ints are very new and we hit the more expensive case only then.

Again: it is super important to minimize the number of division/mod/mul ops for SMT preformance.

GotenJBZ and others added 2 commits February 12, 2026 11:29
Correct $truncDiv and $truncMod in the Boogie prelude to properly handle
cases where src2 < 0 or src1 >= 0 with negative src2. The previous
implementation only checked src1 >= 0 in the fast path, which was
incorrect when src2 < 0. Update baseline expectation for
loops_with_memory_ops accordingly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.

self.translate_exp(&args[1]);
emit!(self.writer, ")");
}
}
Copy link

Choose a reason for hiding this comment

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

Bitwise branch duplicated between translate_op and translate_trunc_div_mod_op

Low Severity

The Bitwise branch in translate_trunc_div_mod_op (lines 2097–2105) is an exact copy of the Bitwise branch in translate_op (lines 2073–2081). Only the else branches differ between the two methods. This duplication risks the two methods diverging if the bitvector emission logic is updated in one but not the other. The shared Bitwise handling could be extracted into a helper, with each method only providing its own non-Bitwise logic.

Additional Locations (1)

Fix in Cursor Fix in Web

@GotenJBZ GotenJBZ marked this pull request as draft February 12, 2026 13:54
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