On 1 November Agave gave the sol_big_mod_exp syscall a new feature key. The syscall did not change that day. Its price had changed five days earlier: the exponentiation in an RSA-2048 signature check went from 15,457 compute units to 24,108. The old key had already shipped, with the old price, in every Agave release since 4.3.0.
We traced the key through Agave and Firedancer, timed the arithmetic both prices pay for in Rust, on the same library Agave calls, and checked what each client charges when a call fails. The syscall is SIMD-0529’s modular exponentiation, the building block for RSA signatures and other big-number cryptography.
A feature key names one behaviour
A feature gate is a switch that every validator flips at the same slot. What the switch turns on is written in each validator’s own code. If two releases define it differently, the cluster splits the moment it flips.
Suppose the old key had been activated while both versions ran, and take a transaction whose compute budget leaves 20,000 units for one RSA-2048 check. At the old price the call succeeds and the program writes its result; at the final price it runs out of compute and the transaction fails. Nodes on Agave 4.4.0 and nodes on newer code would disagree about that account, and so about the bank hash.
Agave’s activation check cannot see a price. Its CLI refuses to activate a feature, unless forced with a hidden flag, when less than 95% of stake runs the same feature set as the CLI, and that feature set is the first four bytes of a hash over the sorted feature keys a release knows. A price change under an unchanged key leaves it untouched. A new key is what makes the change visible: after the rekey, the only code that knows expHkkp… is code that charges the final price.
The rule is not new. In March 2025 Anza rekeyed SIMD-0215, the accounts lattice hash, for the same reason: its code had to change after the gate had shipped in Agave 2.2.
Where the old key had already gone
Agave #12321 added the syscall in July; SIMD #699 replaced its draft price after benchmarks, and Agave #16231 implemented the new one. Firedancer wrote its version straight to the final numbers while the SIMD change was still under review, then rekeyed first. Agave #16585 and SIMD #715 followed, with the stated reason that the new price needs a new key.
From 21 October on Firedancer’s main branch, and from 27 October on Agave’s master, expH2pp… meant the final price, while in every Agave release it meant the draft one. Firedancer moved to the new key on 30 October, Agave on 1 November. Firedancer’s releases listed the key but marked it not implemented. Nothing in these pull requests mentions an activation, and the SIMD is still marked Idea.
This is the syscall’s third key. A 2023 version under EBq48m8… was repriced in place in 2024, when its pull request said the gate was blocked and not active on any network, and removed in April 2026 because its price was still too low.
The two prices
Draft: Agave 4.3.0 to 4.4.0, key expH2pp...
x = max(base_len, modulus_len) in bytes
mult = x^2 if x <= 64
x^2/4 + 96x - 3072 if x <= 1024
bits = max(adjusted_exponent_length, 75)
exponent 1: 422 + ceil(15 * mult / 189)
otherwise: 422 + ceil(mult * bits / 189)
Final: Agave master from 27 Oct, key expHkkp... from 1 Nov
w = ceil(max(base_len, modulus_len) / 8) in 64-bit words
mult = w^2 + 22
words = floor(adjusted_exponent_length / 64) + 1
exponent 1: 50 + ceil(mult / 15)
otherwise: 50 + mult * (3 + 20 * words)The draft is Ethereum’s EIP-198 pricing scaled to compute units (v4.4.0 code, constants). The final price changes three things. It counts the operands in 64-bit words and adds a fixed 22 to every multiplication. It charges the exponent per 64-bit word instead of per bit, with no minimum. And it prices a plain reduction, exponent 1, at a fifteenth of one multiplication instead of fifteen multiplications. The flat part drops from 422 to 50.
What each price pays for
We copied both cost functions from the pinned source, checked them against the five published values for each, and timed the arithmetic they price: solana-big-mod-exp 4.0.0 on num-bigint 0.4.6, the versions Agave’s lockfile pins, with jemalloc as in agave-validator. Operands are the worst case for their length, as in the calibration: an odd modulus with its top bit set, every exponent bit set, a random full-length base. Each time is the median of 15 batches on one core of an Apple M1 Pro; two runs agreed within 2.6%.
shape draft CU final CU µs ns/CU ns/CU
draft final
RSA-1024, e = 65537 5,705 6,444 35.3 6.2 5.5
RSA-2048, e = 65537 15,457 24,108 125 8.1 5.2
RSA-3072, e = 65537 28,461 53,548 274 9.6 5.1
RSA-4096, e = 65537 44,715 94,764 478 10.7 5.0
8 B mod, 64-bit exp 448 579 3.5 7.8 6.1
8 B mod, 4096-bit exp 1,809 29,559 169 93.4 5.7
32 B mod, 256-bit exp 1,804 3,204 27.7 15.4 8.6
64 B mod, 512-bit exp 11,497 14,068 94.6 8.2 6.7
256 B mod, 129-bit exp 26,082 65,948 337 12.9 5.1
256 B mod, 2048-bit exp 410,776 672,628 3,415 8.3 5.1
same, top bit only 410,776 672,628 3,409 8.3 5.1
512 B mod, 64-bit exp 44,715 94,764 481 10.8 5.1
512 B mod, 65-bit exp 44,715 177,124 888 19.9 5.0
512 B mod, 1024-bit exp 604,566 1,330,164 6,574 10.9 4.9
512 B base mod 32 B 9,281 325 2.0 0.2 6.1
512 B base mod 256 B 9,281 325 2.8 0.3 8.6The draft price undercharged long exponents on small operands. An 8-byte modulus with a 4,096-bit exponent cost 1,809 units and took 169 µs: 93 ns per unit, against 8 for RSA-2048, about eleven times cheaper for the same work. EIP-198 prices a multiplication at the square of the operand’s length in bytes, 64 for 8 bytes, which misses the fixed cost of each multiplication that dominates small operands. The final formula’s added 22 is that cost.
It overcharged reductions. Exponent 1 cost 9,281 units for 2 to 3 µs of work, between 27 and 39 times more per unit than an RSA-2048 check. The final price is 325. And it ignored the exponent below 75 bits: every 512-byte call with an exponent of up to 76 bits cost 44,715 units, although moving from a 64-bit to a 65-bit exponent took 1.84 times as long, because num-bigint works through the exponent one 64-bit word at a time. The final price steps at the same place.
Density does not matter: a 2,048-bit exponent with only its top bit set took as long as one with every bit set, so pricing by length is right for this library. Under the final price, the RSA sizes and every 256- and 512-byte shape land between 4.9 and 5.5 ns per unit on our machine, while the small operands and the reductions take 5.7 to 8.6, so on an M1 Pro those calls buy the most time per unit. SIMD #699 calibrated the price on AMD EPYC validators replaying full blocks at about 7.1 ns per unit, with margin. One core without a VM can show the shape of the curve, not the rate.
The operand rules did not change
Between Agave 4.4.0 and master only the price moved: the syscall’s checks and the crate it calls are the same. The SIMD sets rules that differ from Ethereum’s precompile on purpose:
EIP-198 also accepts even moduli; SIMD-0529 rejects them so that implementations can rely on the faster reduction an odd modulus allows. 512 bytes covers RSA-4096. With a 512-byte modulus, any exponent longer than 1,024 bits costs more than a transaction’s 1.4 million units: 1,412,524 at 1,025 bits.
What a failing call costs
The SIMD fixes an order: read and check the parameters, lengths, pointers and modulus, then compute and charge the price, then do the arithmetic. Aborts before the charge “MUST NOT charge the syscall compute cost”.
Neither client works that way. Agave and Firedancer both charge the flat 50 units before reading the parameters, and the whole price before reading the base and modulus, checking the modulus, or checking the output buffer. Firedancer’s source says it in a comment: a bad modulus fails “having been charged”.
call aborts because SIMD-0529 text Agave, Firedancer
params pointer not readable 0 50
an operand over 512 bytes 0 50
exponent not readable 0 50
modulus_len is 0 0 full price
modulus even, 0 or 1 0 full price
base or modulus not readable 0 full price
result buffer not writable 0 full priceBecause the two clients charge the same, this cannot split the cluster today; it shows up in the compute units a failed transaction reports. But the SIMD lists abort behaviour among the things implementations must agree on, and a third client built from its text would charge failing calls differently. Before activation, either the text or the code has to move. Programs that go through the crate never reach these cases: its big_mod_exp checks the lengths and the modulus itself and returns None before calling the syscall.
For program developers
The crate programs call, solana-big-mod-exp 4.0.0 from June, still exports the draft constants: BIG_MOD_EXP_BASE_CU = 422, BIG_MOD_EXP_CU_DIVISOR = 189 and BIG_MOD_EXP_MIN_EXPONENT_LENGTH = 75. Agave no longer reads them. Budget from the final formula instead:
Those are the syscall alone; the padding and hash checks that make a signature check are the program’s own work. On chain the crate’s function calls the syscall, which exists only once expHkkp… is active, and on 1 November no release of either client contained that key. Like the P-256 syscalls, it will be usable only after both clients ship it and the feature activates. How the compute limit you request then affects your transaction’s priority is a separate calculation.
What this does not show
We did not run either client’s syscall: no release charges the final price, and the Agave we have installed, 4.2.1, predates the syscall. The cost functions are copied from Agave’s v4.4.0 tag and from master at c84fccdb (1 November) and match the SIMD pull request’s published values. Times are one core of an M1 Pro without the VM, so they show how each price tracks the work across inputs, not what a validator spends. Firedancer computes with s2n-bignum rather than num-bigint, so its times would differ, though it charges the same price. Nothing here measures whether any cluster ever activated a key.
sol_big_mod_exp: Questions People Actually Ask
Why did SIMD-0529 get a new feature gate?
Its price changed after the old key had shipped. Agave 4.3.0 to 4.4.0 carry the key expH2pp… with the draft price; Agave’s master branch moved to the final price on 27 October under the same key. Had that key been activated, nodes on those releases and nodes on newer code would have charged different amounts for the same call and disagreed about which transactions run out of compute. The new key, expHkkp…, is known only to code that charges the final price.
How many compute units does sol_big_mod_exp cost to verify an RSA signature?
With exponent 65537, the final SIMD-0529 price is 24,108 compute units for RSA-2048, 53,548 for RSA-3072 and 94,764 for RSA-4096. The draft price in Agave 4.3.0 to 4.4.0 was 15,457, 28,461 and 44,715. Padding and hash checks run in the program and cost extra.
What is the compute-unit formula for sol_big_mod_exp?
Take w = ceil(max(base length, modulus length) / 8) and m = w² + 22. If the exponent is 1, the call costs 50 + ceil(m / 15). Otherwise it costs 50 + m × (3 + 20 × k), where k is the number of 64-bit words the exponent spans, counted from its highest set bit with the EIP-198 adjusted length.
Does sol_big_mod_exp accept even moduli or big-endian input?
No. Unlike Ethereum’s EIP-198 precompile, the modulus must be odd and greater than 1, every operand is a little-endian unsigned integer of at most 512 bytes, and the result is written as exactly as many bytes as the modulus.
Can Solana programs call sol_big_mod_exp yet?
Not as of 1 November 2026. The syscall exists only while its feature, now expHkkp…, is active, and no release of Agave or Firedancer contained that key on that date. SIMD-0529 was still marked Idea.
The one-line version
A feature key stands for one behaviour, and the old big_mod_exp key had shipped in Agave 4.3.0 to 4.4.0 with the draft price, so the final price, whose time per unit varied 1.7-fold across our inputs against the draft’s 440-fold, needed a key that only code charging it would know.
Sources: SIMD-0529 at 0434aab3, SIMD pull requests #699, #715 and #265; Agave #12321, #16231, #16585, #2807 and #12192, the v4.4.0 tag and master at c84fccdb; Firedancer commits f0ebe3b0 and ced4e9b0 and release v26.10.5. Timings are from our own Rust harness on solana-big-mod-exp 4.0.0.