Skip to content

Commit 2c7afe6

Browse files
committed
Introduce modexp precompile (EIP101)
1 parent 7041680 commit 2c7afe6

File tree

2 files changed

+56
-0
lines changed

2 files changed

+56
-0
lines changed

lib/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const num01 = require('./precompiled/01-ecrecover.js')
88
const num02 = require('./precompiled/02-sha256.js')
99
const num03 = require('./precompiled/03-ripemd160.js')
1010
const num04 = require('./precompiled/04-identity.js')
11+
const num09 = require('./precompiled/09-modexp.js')
1112

1213
module.exports = VM
1314

@@ -43,6 +44,7 @@ function VM (opts = {}) {
4344
this._precompiled['0000000000000000000000000000000000000002'] = num02
4445
this._precompiled['0000000000000000000000000000000000000003'] = num03
4546
this._precompiled['0000000000000000000000000000000000000004'] = num04
47+
this._precompiled['0000000000000000000000000000000000000009'] = num09
4648

4749
if (this.opts.activatePrecompiles) {
4850
for (var i = 1; i <= 4; i++) {

lib/precompiled/09-modexp.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
At the address 0x0000....09, add a precompile that expects input in the following format:
3+
4+
<length of B, as a 32-byte-padded integer> <bytes of B> <length of E, as a 32-byte-padded integer> <bytes of E> <bytes of M>
5+
6+
This should return B**E % M, and the data should be returned in the same format as above. If M = 0, it returns zero. Gas cost GMODEXPBASE + GARITHWORD * ceil(<total length of input data> / 32) + <length of M> * <length of M> * <length of E> / GQUADDIVISOR.
7+
*
8+
*/
9+
10+
const utils = require('ethereumjs-util')
11+
const BN = utils.BN
12+
const error = require('../constants.js').ERROR
13+
14+
const Gmodexpbase = 45
15+
const Garithword = 6
16+
const Gquaddivisor = 32
17+
18+
module.exports = function (opts) {
19+
var results = {}
20+
21+
var i = 0
22+
var Blen = new BN(data.slice(i, 32)).toNumber()
23+
i += 32
24+
var B = new BN(data.slice(i, i + Blen))
25+
i += Blen
26+
var Elen = new BN(data.slice(i, i + 32)).toNumber()
27+
i += 32
28+
var E = new BN(data.slice(i, Elen))
29+
i += Elen
30+
var Mlen = data.length - i
31+
var M = new BN(data.slice(i, Mlen))
32+
33+
console.log('MODEXP input', Blen, B, Elen, E, Mlen, M)
34+
35+
result.gasUsed = new BN(Gmodexpbase).addi(Math.ceil(data.length / 32) * Garithword).addi(Blen * Mlen * Elen / Gquaddivisor)
36+
37+
if (opts.gasLimit.cmp(results.gasUsed) === -1) {
38+
results.gasUsed = opts.gasLimit
39+
results.exception = 0 // 0 means VM fail (in this case because of OOG)
40+
results.exceptionError = error.OUT_OF_GAS
41+
return results
42+
}
43+
44+
// FIXME: use reduction contexts
45+
var R = B.pow(E).mod(M).toArrayLike(Buffer, 'be')
46+
var Rlen = new BN(R).toArrayLike(Buffer, 'be', 32)
47+
48+
results.return = Buffer.concat(Rlen, R)
49+
results.exception = 1
50+
51+
console.log('MODEXP output', Rlen, R)
52+
53+
return results
54+
}

0 commit comments

Comments
 (0)