@@ -60,6 +60,100 @@ public void testEIP7823() {
6060 }
6161 }
6262
63+ /**
64+ * Build ModExp input data for energy calculation testing.
65+ */
66+ private static byte [] buildModExpData (int baseLen , int expLen , int modLen , byte [] expValue ) {
67+ byte [] base = new byte [baseLen ];
68+ byte [] exp = new byte [expLen ];
69+ if (expValue .length > 0 && expLen > 0 ) {
70+ System .arraycopy (expValue , 0 , exp , 0 , Math .min (expValue .length , expLen ));
71+ }
72+ byte [] mod = new byte [modLen ];
73+ return ByteUtil .merge (toLenBytes (baseLen ), toLenBytes (expLen ), toLenBytes (modLen ),
74+ base , exp , mod );
75+ }
76+
77+ private static long getEnergy (int baseLen , int expLen , int modLen , byte [] expValue ) {
78+ return modExp .getEnergyForData (buildModExpData (baseLen , expLen , modLen , expValue ));
79+ }
80+
81+ @ Test
82+ public void testEIP7883ModExpPricing () {
83+ ConfigLoader .disable = true ;
84+ VMConfig .initAllowTvmOsaka (1 );
85+
86+ try {
87+ byte [] square = {0x02 };
88+ byte [] qube = {0x03 };
89+ byte [] pow0x10001 = {0x01 , 0x00 , 0x01 };
90+
91+ // nagydani_1: baseLen=64, expLen=square/qube:1 pow:3, modLen=64
92+ Assert .assertEquals (500L , getEnergy (64 , 1 , 64 , square ));
93+ Assert .assertEquals (500L , getEnergy (64 , 1 , 64 , qube ));
94+ Assert .assertEquals (2048L , getEnergy (64 , 3 , 64 , pow0x10001 ));
95+
96+ // nagydani_2: baseLen=128, modLen=128
97+ Assert .assertEquals (512L , getEnergy (128 , 1 , 128 , square ));
98+ Assert .assertEquals (512L , getEnergy (128 , 1 , 128 , qube ));
99+ Assert .assertEquals (8192L , getEnergy (128 , 3 , 128 , pow0x10001 ));
100+
101+ // nagydani_3: baseLen=256, modLen=256
102+ Assert .assertEquals (2048L , getEnergy (256 , 1 , 256 , square ));
103+ Assert .assertEquals (2048L , getEnergy (256 , 1 , 256 , qube ));
104+ Assert .assertEquals (32768L , getEnergy (256 , 3 , 256 , pow0x10001 ));
105+
106+ // nagydani_4: baseLen=512, modLen=512
107+ Assert .assertEquals (8192L , getEnergy (512 , 1 , 512 , square ));
108+ Assert .assertEquals (8192L , getEnergy (512 , 1 , 512 , qube ));
109+ Assert .assertEquals (131072L , getEnergy (512 , 3 , 512 , pow0x10001 ));
110+
111+ // nagydani_5: baseLen=1024, modLen=1024
112+ Assert .assertEquals (32768L , getEnergy (1024 , 1 , 1024 , square ));
113+ Assert .assertEquals (32768L , getEnergy (1024 , 1 , 1024 , qube ));
114+ Assert .assertEquals (524288L , getEnergy (1024 , 3 , 1024 , pow0x10001 ));
115+
116+ // Minimum energy: zero-length inputs
117+ Assert .assertEquals (500L , getEnergy (0 , 0 , 0 , new byte []{}));
118+
119+ // Small base/mod (<=32): complexity=16
120+ Assert .assertEquals (500L , getEnergy (1 , 1 , 1 , square ));
121+ Assert .assertEquals (500L , getEnergy (32 , 1 , 32 , square ));
122+
123+ // Boundary: base/mod at 33 (just over 32) uses doubled formula
124+ // words = ceil(33/8) = 5, complexity = 2 * 25 = 50, iterCount = 1
125+ Assert .assertEquals (500L , getEnergy (33 , 1 , 33 , square ));
126+
127+ // Exponent > 32 bytes: multiplier is 16
128+ // expLen=64, high bytes all zero → highestBit=0, iterCount = 16*(64-32)+0 = 512
129+ // baseLen=64, modLen=64 → complexity=128, energy=128*512=65536
130+ Assert .assertEquals (65536L , getEnergy (64 , 64 , 64 , new byte []{}));
131+
132+ // Exponent > 32 bytes with non-zero high bytes
133+ // expLen=64, first byte=0x01 → highestBit=248, iterCount = 16*32+248 = 760
134+ // baseLen=64, modLen=64 → complexity=128, energy=128*760=97280
135+ Assert .assertEquals (97280L , getEnergy (64 , 64 , 64 , new byte []{0x01 }));
136+ } finally {
137+ VMConfig .initAllowTvmOsaka (0 );
138+ ConfigLoader .disable = false ;
139+ }
140+ }
141+
142+ @ Test
143+ public void testEIP7883DisabledPreservesOldPricing () {
144+ ConfigLoader .disable = true ;
145+ VMConfig .initAllowTvmOsaka (0 );
146+
147+ try {
148+ // When Osaka is disabled, old pricing formula should be used
149+ // nagydani_1_square: old formula = 4096 * 1 / 20 = 204
150+ long energy = getEnergy (64 , 1 , 64 , new byte []{0x02 });
151+ Assert .assertEquals (204L , energy );
152+ } finally {
153+ ConfigLoader .disable = false ;
154+ }
155+ }
156+
63157 @ Test
64158 public void testEIP7823DisabledShouldPass () {
65159 ConfigLoader .disable = true ;
0 commit comments