|
|
|
@ -149,30 +149,41 @@ func (c *dataCopy) Run(in []byte) ([]byte, error) { |
|
|
|
|
// bigModExp implements a native big integer exponential modular operation.
|
|
|
|
|
type bigModExp struct{} |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
big1 = big.NewInt(1) |
|
|
|
|
big4 = big.NewInt(4) |
|
|
|
|
big8 = big.NewInt(8) |
|
|
|
|
big16 = big.NewInt(16) |
|
|
|
|
big32 = big.NewInt(32) |
|
|
|
|
big64 = big.NewInt(64) |
|
|
|
|
big96 = big.NewInt(96) |
|
|
|
|
big480 = big.NewInt(480) |
|
|
|
|
big1024 = big.NewInt(1024) |
|
|
|
|
big3072 = big.NewInt(3072) |
|
|
|
|
big199680 = big.NewInt(199680) |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// RequiredGas returns the gas required to execute the pre-compiled contract.
|
|
|
|
|
func (c *bigModExp) RequiredGas(input []byte) uint64 { |
|
|
|
|
// Pad the input with zeroes to the minimum size to read the field lengths
|
|
|
|
|
input = common.RightPadBytes(input, 96) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
baseLen = new(big.Int).SetBytes(input[:32]) |
|
|
|
|
expLen = new(big.Int).SetBytes(input[32:64]) |
|
|
|
|
modLen = new(big.Int).SetBytes(input[64:96]) |
|
|
|
|
baseLen = new(big.Int).SetBytes(getData(input, 0, 32)) |
|
|
|
|
expLen = new(big.Int).SetBytes(getData(input, 32, 32)) |
|
|
|
|
modLen = new(big.Int).SetBytes(getData(input, 64, 32)) |
|
|
|
|
) |
|
|
|
|
input = input[96:] |
|
|
|
|
|
|
|
|
|
if len(input) > 96 { |
|
|
|
|
input = input[96:] |
|
|
|
|
} else { |
|
|
|
|
input = input[:0] |
|
|
|
|
} |
|
|
|
|
// Retrieve the head 32 bytes of exp for the adjusted exponent length
|
|
|
|
|
var expHead *big.Int |
|
|
|
|
if big.NewInt(int64(len(input))).Cmp(baseLen) <= 0 { |
|
|
|
|
expHead = new(big.Int) |
|
|
|
|
} else { |
|
|
|
|
offset := int(baseLen.Uint64()) |
|
|
|
|
|
|
|
|
|
input = common.RightPadBytes(input, offset+32) |
|
|
|
|
if expLen.Cmp(big.NewInt(32)) > 0 { |
|
|
|
|
expHead = new(big.Int).SetBytes(input[offset : offset+32]) |
|
|
|
|
if expLen.Cmp(big32) > 0 { |
|
|
|
|
expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), 32)) |
|
|
|
|
} else { |
|
|
|
|
expHead = new(big.Int).SetBytes(input[offset : offset+int(expLen.Uint64())]) |
|
|
|
|
expHead = new(big.Int).SetBytes(getData(input, baseLen.Uint64(), expLen.Uint64())) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Calculate the adjusted exponent length
|
|
|
|
@ -181,29 +192,29 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { |
|
|
|
|
msb = bitlen - 1 |
|
|
|
|
} |
|
|
|
|
adjExpLen := new(big.Int) |
|
|
|
|
if expLen.Cmp(big.NewInt(32)) > 0 { |
|
|
|
|
adjExpLen.Sub(expLen, big.NewInt(32)) |
|
|
|
|
adjExpLen.Mul(big.NewInt(8), adjExpLen) |
|
|
|
|
if expLen.Cmp(big32) > 0 { |
|
|
|
|
adjExpLen.Sub(expLen, big32) |
|
|
|
|
adjExpLen.Mul(big8, adjExpLen) |
|
|
|
|
} |
|
|
|
|
adjExpLen.Add(adjExpLen, big.NewInt(int64(msb))) |
|
|
|
|
|
|
|
|
|
// Calculate the gas cost of the operation
|
|
|
|
|
gas := new(big.Int).Set(math.BigMax(modLen, baseLen)) |
|
|
|
|
switch { |
|
|
|
|
case gas.Cmp(big.NewInt(64)) <= 0: |
|
|
|
|
case gas.Cmp(big64) <= 0: |
|
|
|
|
gas.Mul(gas, gas) |
|
|
|
|
case gas.Cmp(big.NewInt(1024)) <= 0: |
|
|
|
|
case gas.Cmp(big1024) <= 0: |
|
|
|
|
gas = new(big.Int).Add( |
|
|
|
|
new(big.Int).Div(new(big.Int).Mul(gas, gas), big.NewInt(4)), |
|
|
|
|
new(big.Int).Sub(new(big.Int).Mul(big.NewInt(96), gas), big.NewInt(3072)), |
|
|
|
|
new(big.Int).Div(new(big.Int).Mul(gas, gas), big4), |
|
|
|
|
new(big.Int).Sub(new(big.Int).Mul(big96, gas), big3072), |
|
|
|
|
) |
|
|
|
|
default: |
|
|
|
|
gas = new(big.Int).Add( |
|
|
|
|
new(big.Int).Div(new(big.Int).Mul(gas, gas), big.NewInt(16)), |
|
|
|
|
new(big.Int).Sub(new(big.Int).Mul(big.NewInt(480), gas), big.NewInt(199680)), |
|
|
|
|
new(big.Int).Div(new(big.Int).Mul(gas, gas), big16), |
|
|
|
|
new(big.Int).Sub(new(big.Int).Mul(big480, gas), big199680), |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
gas.Mul(gas, math.BigMax(adjExpLen, big.NewInt(1))) |
|
|
|
|
gas.Mul(gas, math.BigMax(adjExpLen, big1)) |
|
|
|
|
gas.Div(gas, new(big.Int).SetUint64(params.ModExpQuadCoeffDiv)) |
|
|
|
|
|
|
|
|
|
if gas.BitLen() > 64 { |
|
|
|
@ -213,23 +224,25 @@ func (c *bigModExp) RequiredGas(input []byte) uint64 { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *bigModExp) Run(input []byte) ([]byte, error) { |
|
|
|
|
// Pad the input with zeroes to the minimum size to read the field lengths
|
|
|
|
|
input = common.RightPadBytes(input, 96) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
baseLen = new(big.Int).SetBytes(input[:32]).Uint64() |
|
|
|
|
expLen = new(big.Int).SetBytes(input[32:64]).Uint64() |
|
|
|
|
modLen = new(big.Int).SetBytes(input[64:96]).Uint64() |
|
|
|
|
baseLen = new(big.Int).SetBytes(getData(input, 0, 32)).Uint64() |
|
|
|
|
expLen = new(big.Int).SetBytes(getData(input, 32, 32)).Uint64() |
|
|
|
|
modLen = new(big.Int).SetBytes(getData(input, 64, 32)).Uint64() |
|
|
|
|
) |
|
|
|
|
input = input[96:] |
|
|
|
|
|
|
|
|
|
// Pad the input with zeroes to the minimum size to read the field contents
|
|
|
|
|
input = common.RightPadBytes(input, int(baseLen+expLen+modLen)) |
|
|
|
|
|
|
|
|
|
if len(input) > 96 { |
|
|
|
|
input = input[96:] |
|
|
|
|
} else { |
|
|
|
|
input = input[:0] |
|
|
|
|
} |
|
|
|
|
// Handle a special case when both the base and mod length is zero
|
|
|
|
|
if baseLen == 0 && modLen == 0 { |
|
|
|
|
return []byte{}, nil |
|
|
|
|
} |
|
|
|
|
// Retrieve the operands and execute the exponentiation
|
|
|
|
|
var ( |
|
|
|
|
base = new(big.Int).SetBytes(input[:baseLen]) |
|
|
|
|
exp = new(big.Int).SetBytes(input[baseLen : baseLen+expLen]) |
|
|
|
|
mod = new(big.Int).SetBytes(input[baseLen+expLen : baseLen+expLen+modLen]) |
|
|
|
|
base = new(big.Int).SetBytes(getData(input, 0, baseLen)) |
|
|
|
|
exp = new(big.Int).SetBytes(getData(input, baseLen, expLen)) |
|
|
|
|
mod = new(big.Int).SetBytes(getData(input, baseLen+expLen, modLen)) |
|
|
|
|
) |
|
|
|
|
if mod.BitLen() == 0 { |
|
|
|
|
// Modulo 0 is undefined, return zero
|
|
|
|
@ -286,14 +299,11 @@ func (c *bn256Add) RequiredGas(input []byte) uint64 { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *bn256Add) Run(input []byte) ([]byte, error) { |
|
|
|
|
// Ensure we have enough data to operate on
|
|
|
|
|
input = common.RightPadBytes(input, 128) |
|
|
|
|
|
|
|
|
|
x, err := newCurvePoint(input[:64]) |
|
|
|
|
x, err := newCurvePoint(getData(input, 0, 64)) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
y, err := newCurvePoint(input[64:128]) |
|
|
|
|
y, err := newCurvePoint(getData(input, 64, 64)) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
@ -310,14 +320,11 @@ func (c *bn256ScalarMul) RequiredGas(input []byte) uint64 { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *bn256ScalarMul) Run(input []byte) ([]byte, error) { |
|
|
|
|
// Ensure we have enough data to operate on
|
|
|
|
|
input = common.RightPadBytes(input, 96) |
|
|
|
|
|
|
|
|
|
p, err := newCurvePoint(input[:64]) |
|
|
|
|
p, err := newCurvePoint(getData(input, 0, 64)) |
|
|
|
|
if err != nil { |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
p.ScalarMult(p, new(big.Int).SetBytes(input[64:96])) |
|
|
|
|
p.ScalarMult(p, new(big.Int).SetBytes(getData(input, 64, 32))) |
|
|
|
|
return p.Marshal(), nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|