From 0906d61746ea75af7d380b1145f64d85d2fedb8b Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Wed, 1 Feb 2017 22:36:51 +0100 Subject: [PATCH 01/13] core/vm: implements big int expmod precompile - EIP#198 --- core/vm/contracts.go | 90 ++++++++++++++++++++++++++++++++++++------ core/vm/evm.go | 25 +++++++++--- core/vm/interpreter.go | 6 --- params/config.go | 37 ++++++++++++++--- params/util.go | 7 +++- 5 files changed, 136 insertions(+), 29 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index e87640d022..4d757dabdd 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -31,11 +31,11 @@ import ( // requires a deterministic gas count based on the input size of the Run method of the // contract. type PrecompiledContract interface { - RequiredGas(inputSize int) uint64 // RequiredPrice calculates the contract gas use - Run(input []byte) []byte // Run runs the precompiled contract + RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use + Run(input []byte) []byte // Run runs the precompiled contract } -// Precompiled contains the default set of ethereum contracts +// PrecompiledContracts contains the default set of ethereum contracts var PrecompiledContracts = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{2}): &sha256hash{}, @@ -43,9 +43,19 @@ var PrecompiledContracts = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{4}): &dataCopy{}, } +// PrecompiledContractsEIP198 contains the default set of ethereum contracts +// for EIP198. +var PrecompiledContractsEIP198 = map[common.Address]PrecompiledContract{ + common.BytesToAddress([]byte{1}): &ecrecover{}, + common.BytesToAddress([]byte{2}): &sha256{}, + common.BytesToAddress([]byte{3}): &ripemd160{}, + common.BytesToAddress([]byte{4}): &dataCopy{}, + common.BytesToAddress([]byte{5}): &bigModexp{}, +} + // RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) { - gas := p.RequiredGas(len(input)) + gas := p.RequiredGas(input) if contract.UseGas(gas) { ret = p.Run(input) @@ -58,7 +68,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contr // ECRECOVER implemented as a native contract type ecrecover struct{} -func (c *ecrecover) RequiredGas(inputSize int) uint64 { +func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } @@ -97,8 +107,8 @@ type sha256hash struct{} // // This method does not require any overflow checking as the input size gas costs // required for anything significant is so high it's impossible to pay for. -func (c *sha256hash) RequiredGas(inputSize int) uint64 { - return uint64(inputSize+31)/32*params.Sha256WordGas + params.Sha256Gas +func (c *sha256hash) RequiredGas(input []byte) uint64 { + return uint64(len(input)+31)/32*params.Sha256WordGas + params.Sha256Gas } func (c *sha256hash) Run(in []byte) []byte { h := sha256.Sum256(in) @@ -112,8 +122,8 @@ type ripemd160hash struct{} // // This method does not require any overflow checking as the input size gas costs // required for anything significant is so high it's impossible to pay for. -func (c *ripemd160hash) RequiredGas(inputSize int) uint64 { - return uint64(inputSize+31)/32*params.Ripemd160WordGas + params.Ripemd160Gas +func (c *ripemd160hash) RequiredGas(input []byte) uint64 { + return uint64(len(input)+31)/32*params.Ripemd160WordGas + params.Ripemd160Gas } func (c *ripemd160hash) Run(in []byte) []byte { ripemd := ripemd160.New() @@ -128,9 +138,67 @@ type dataCopy struct{} // // This method does not require any overflow checking as the input size gas costs // required for anything significant is so high it's impossible to pay for. -func (c *dataCopy) RequiredGas(inputSize int) uint64 { - return uint64(inputSize+31)/32*params.IdentityWordGas + params.IdentityGas +func (c *dataCopy) RequiredGas(input []byte) uint64 { + return uint64(len(input)+31)/32*params.IdentityWordGas + params.IdentityGas } func (c *dataCopy) Run(in []byte) []byte { return in } + +// bigModexp implements a native big integer exponential modular operation. +type bigModexp struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *bigModexp) RequiredGas(input []byte) uint64 { + // TODO reword required gas to have error reporting and convert arithmetic + // to uint64. + if len(input) < 3*32 { + input = append(input, make([]byte, 3*32-len(input))...) + } + var ( + baseLen = common.BytesToBig(input[:31]) + expLen = common.BigMax(common.BytesToBig(input[32:64]), big.NewInt(1)) + modLen = common.BytesToBig(input[65:97]) + ) + x := new(big.Int).Set(common.BigMax(baseLen, modLen)) + x.Mul(x, x) + x.Mul(x, expLen) + x.Div(x, new(big.Int).SetUint64(params.QuadCoeffDiv)) + + return x.Uint64() +} + +func (c *bigModexp) Run(input []byte) []byte { + if len(input) < 3*32 { + input = append(input, make([]byte, 3*32-len(input))...) + } + // why 32-byte? These values won't fit anyway + var ( + baseLen = common.BytesToBig(input[:32]).Uint64() + expLen = common.BytesToBig(input[32:64]).Uint64() + modLen = common.BytesToBig(input[64:96]).Uint64() + ) + + input = input[96:] + if uint64(len(input)) < baseLen { + input = append(input, make([]byte, baseLen-uint64(len(input)))...) + } + base := common.BytesToBig(input[:baseLen]) + + input = input[baseLen:] + if uint64(len(input)) < expLen { + input = append(input, make([]byte, expLen-uint64(len(input)))...) + } + exp := common.BytesToBig(input[:expLen]) + + input = input[expLen:] + if uint64(len(input)) < modLen { + input = append(input, make([]byte, modLen-uint64(len(input)))...) + } + mod := common.BytesToBig(input[:modLen]) + + return base.Exp(base, exp, mod).Bytes() +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 71efcfa458..8c28bef718 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -33,6 +33,22 @@ type ( GetHashFunc func(uint64) common.Hash ) +// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. +func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) { + if contract.CodeAddr != nil { + precompiledContracts := PrecompiledContracts + if evm.ChainConfig().IsEIP198(evm.BlockNumber) { + precompiledContracts = PrecompiledContractsEIP198 + } + + if p := precompiledContracts[*contract.CodeAddr]; p != nil { + return RunPrecompiledContract(p, input, contract) + } + } + + return evm.interpreter.Run(contract, input) +} + // Context provides the EVM with auxiliary information. Once provided it shouldn't be modified. type Context struct { // CanTransfer returns whether the account contains @@ -134,7 +150,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas contract := NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = evm.interpreter.Run(contract, input) + ret, err = run(evm, contract, input) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in homestead this also counts for code storage gas errors. @@ -175,7 +191,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, contract := NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = evm.interpreter.Run(contract, input) + ret, err = run(evm, contract, input) if err != nil { contract.UseGas(contract.Gas) @@ -210,7 +226,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by contract := NewContract(caller, to, nil, gas).AsDelegate() contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = evm.interpreter.Run(contract, input) + ret, err = run(evm, contract, input) if err != nil { contract.UseGas(contract.Gas) @@ -253,8 +269,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I contract := NewContract(caller, AccountRef(contractAddr), value, gas) contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code) - ret, err = evm.interpreter.Run(contract, nil) - + ret, err = run(evm, contract, nil) // check whether the max code size has been exceeded maxCodeSizeExceeded := len(ret) > params.MaxCodeSize // if the contract creation ran successfully and no errors were returned diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 8ee9d3ca79..00eb3ac418 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -84,12 +84,6 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e evm.env.depth++ defer func() { evm.env.depth-- }() - if contract.CodeAddr != nil { - if p := PrecompiledContracts[*contract.CodeAddr]; p != nil { - return RunPrecompiledContract(p, input, contract) - } - } - // Don't bother with the execution if there's no code. if len(contract.Code) == 0 { return nil, nil diff --git a/params/config.go b/params/config.go index 47d7c2ad06..0556142237 100644 --- a/params/config.go +++ b/params/config.go @@ -34,9 +34,10 @@ var ( EIP150Hash: MainNetHomesteadGasRepriceHash, EIP155Block: MainNetSpuriousDragon, EIP158Block: MainNetSpuriousDragon, + EIP198Block: MainNetMetropolis, } - // TestnetChainConfig contains the chain parameters to run a node on the ropsten test network. + // TestnetChainConfig is the chain parameters to run a node on the test network. TestnetChainConfig = &ChainConfig{ ChainId: big.NewInt(3), HomesteadBlock: big.NewInt(0), @@ -46,19 +47,20 @@ var ( EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), EIP155Block: big.NewInt(10), EIP158Block: big.NewInt(10), + EIP198Block: TestNetMetropolis, } // AllProtocolChanges contains every protocol change (EIPs) // introduced and accepted by the Ethereum core developers. - // TestChainConfig is like AllProtocolChanges but has chain ID 1. // // This configuration is intentionally not using keyed fields. // This configuration must *always* have all forks enabled, which // means that all fields must be set at all times. This forces // anyone adding flags to the config to also have to set these // fields. - AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0)} + AllProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0)} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), nil} + TestRules = TestChainConfig.Rules(new(big.Int)) ) // ChainConfig is the core config which determines the blockchain settings. @@ -79,11 +81,13 @@ type ChainConfig struct { EIP155Block *big.Int `json:"eip155Block"` // EIP155 HF block EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block + + EIP198Block *big.Int `json:"eip198Block"` // EIP198 HF block } // String implements the fmt.Stringer interface. func (c *ChainConfig) String() string { - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v}", + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v EIP198: %v}", c.ChainId, c.HomesteadBlock, c.DAOForkBlock, @@ -91,6 +95,7 @@ func (c *ChainConfig) String() string { c.EIP150Block, c.EIP155Block, c.EIP158Block, + c.EIP198Block, ) } @@ -200,6 +205,14 @@ func configNumEqual(x, y *big.Int) bool { return x.Cmp(y) == 0 } +func (c *ChainConfig) IsEIP198(num *big.Int) bool { + if c.EIP198Block == nil || num == nil { + return false + } + return num.Cmp(c.EIP198Block) >= 0 + +} + // ConfigCompatError is raised if the locally-stored blockchain is initialised with a // ChainConfig that would alter the past. type ConfigCompatError struct { @@ -230,3 +243,17 @@ func newCompatError(what string, storedblock, newblock *big.Int) *ConfigCompatEr func (err *ConfigCompatError) Error() string { return fmt.Sprintf("mismatching %s in database (have %d, want %d, rewindto %d)", err.What, err.StoredConfig, err.NewConfig, err.RewindTo) } + +// Rules wraps ChainConfig and is merely syntatic sugar or can be used for functions +// that do not have or require information about the block. +// +// Rules is a one time interface meaning that it shouldn't be used in between transition +// phases. +type Rules struct { + ChainId *big.Int + IsHomestead, IsEIP150, IsEIP155, IsEIP158, IsEIP198 bool +} + +func (c *ChainConfig) Rules(num *big.Int) Rules { + return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsEIP198: c.IsEIP198(num)} +} diff --git a/params/util.go b/params/util.go index bf833d5107..149dab4292 100644 --- a/params/util.go +++ b/params/util.go @@ -38,6 +38,9 @@ var ( TestNetSpuriousDragon = big.NewInt(10) MainNetSpuriousDragon = big.NewInt(2675000) - TestNetChainID = big.NewInt(3) // Testnet default chain ID - MainNetChainID = big.NewInt(1) // Mainnet default chain ID + TestNetMetropolis = big.NewInt(11) + MainNetMetropolis = big.NewInt(10000000) + + TestNetChainID = big.NewInt(3) // Test net default chain ID + MainNetChainID = big.NewInt(1) // main net default chain ID ) From 591ac8133d504b3e49d81a3d17f0a9f873d6bede Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Wed, 1 Feb 2017 15:01:34 +0100 Subject: [PATCH 02/13] core/vm: implement opcode REVERT - EIP#140 --- core/vm/evm.go | 20 +++++++++------ core/vm/instructions.go | 20 ++++++++++++++- core/vm/jump_table.go | 8 ++++++ core/vm/opcodes.go | 3 +++ params/config.go | 56 ++++++++++++++++++++--------------------- params/util.go | 4 +-- 6 files changed, 73 insertions(+), 38 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 8c28bef718..87d12d2cb1 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -155,8 +155,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in homestead this also counts for code storage gas errors. if err != nil { - contract.UseGas(contract.Gas) - + if err != errRevert { + contract.UseGas(contract.Gas) + } evm.StateDB.RevertToSnapshot(snapshot) } return ret, contract.Gas, err @@ -193,7 +194,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, ret, err = run(evm, contract, input) if err != nil { - contract.UseGas(contract.Gas) + if err != errRevert { + contract.UseGas(contract.Gas) + } evm.StateDB.RevertToSnapshot(snapshot) } @@ -228,7 +231,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by ret, err = run(evm, contract, input) if err != nil { - contract.UseGas(contract.Gas) + if err != errRevert { + contract.UseGas(contract.Gas) + } evm.StateDB.RevertToSnapshot(snapshot) } @@ -290,10 +295,11 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I // when we're in homestead this also counts for code storage gas errors. if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { - evm.StateDB.RevertToSnapshot(snapshot) + if err != errRevert { + contract.UseGas(contract.Gas) + } - // Nothing should be returned when an error is thrown. - return nil, contractAddr, 0, err + evm.StateDB.RevertToSnapshot(snapshot) } // If the vm returned with an error the return value should be set to nil. // This isn't consensus critical but merely to for behaviour reasons such as diff --git a/core/vm/instructions.go b/core/vm/instructions.go index bfc0a668e4..d8737785f1 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -17,6 +17,7 @@ package vm import ( + "errors" "fmt" "math/big" @@ -27,7 +28,10 @@ import ( "github.com/ethereum/go-ethereum/params" ) -var bigZero = new(big.Int) +var ( + bigZero = new(big.Int) + errRevert = errors.New("standard throw") +) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { x, y := stack.pop(), stack.pop() @@ -669,6 +673,20 @@ func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S return ret, nil } +func opRevert(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // if not metropolis return an error. REVERT is not supported + // during pre-metropolis. + if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) { + return nil, fmt.Errorf("invalid opcode %x", REVERT) + } + + offset, size := stack.pop(), stack.pop() + ret := memory.GetPtr(offset.Int64(), size.Int64()) + + evm.interpreter.intPool.put(offset, size) + return ret, errRevert +} + func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { return nil, nil } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index ed30100ac1..ccb38e8dae 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -390,6 +390,14 @@ func NewJumpTable() [256]operation { validateStack: makeStackFunc(0, 1), valid: true, }, + // TODO: + // * Determine cost + REVERT: { + execute: opRevert, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 0), + valid: true, + }, JUMPDEST: { execute: opJumpdest, gasCost: constGasFunc(params.JumpdestGas), diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index d4ba7f1563..3c3796d2d2 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -202,6 +202,7 @@ const ( RETURN DELEGATECALL + REVERT = 0xfd SELFDESTRUCT = 0xff ) @@ -353,6 +354,7 @@ var opCodeToString = map[OpCode]string{ CREATE: "CREATE", CALL: "CALL", RETURN: "RETURN", + REVERT: "REVERT", CALLCODE: "CALLCODE", DELEGATECALL: "DELEGATECALL", SELFDESTRUCT: "SELFDESTRUCT", @@ -500,6 +502,7 @@ var stringToOp = map[string]OpCode{ "CREATE": CREATE, "CALL": CALL, "RETURN": RETURN, + "REVERT": REVERT, "CALLCODE": CALLCODE, "SELFDESTRUCT": SELFDESTRUCT, } diff --git a/params/config.go b/params/config.go index 0556142237..b29371960d 100644 --- a/params/config.go +++ b/params/config.go @@ -26,28 +26,28 @@ import ( var ( // MainnetChainConfig is the chain parameters to run a node on the main network. MainnetChainConfig = &ChainConfig{ - ChainId: MainNetChainID, - HomesteadBlock: MainNetHomesteadBlock, - DAOForkBlock: MainNetDAOForkBlock, - DAOForkSupport: true, - EIP150Block: MainNetHomesteadGasRepriceBlock, - EIP150Hash: MainNetHomesteadGasRepriceHash, - EIP155Block: MainNetSpuriousDragon, - EIP158Block: MainNetSpuriousDragon, - EIP198Block: MainNetMetropolis, + ChainId: MainNetChainID, + HomesteadBlock: MainNetHomesteadBlock, + DAOForkBlock: MainNetDAOForkBlock, + DAOForkSupport: true, + EIP150Block: MainNetHomesteadGasRepriceBlock, + EIP150Hash: MainNetHomesteadGasRepriceHash, + EIP155Block: MainNetSpuriousDragon, + EIP158Block: MainNetSpuriousDragon, + MetropolisBlock: MainNetMetropolis, } // TestnetChainConfig is the chain parameters to run a node on the test network. TestnetChainConfig = &ChainConfig{ - ChainId: big.NewInt(3), - HomesteadBlock: big.NewInt(0), - DAOForkBlock: nil, - DAOForkSupport: true, - EIP150Block: big.NewInt(0), - EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), - EIP155Block: big.NewInt(10), - EIP158Block: big.NewInt(10), - EIP198Block: TestNetMetropolis, + ChainId: big.NewInt(3), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: nil, + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), + EIP155Block: big.NewInt(10), + EIP158Block: big.NewInt(10), + MetropolisBlock: TestNetMetropolis, } // AllProtocolChanges contains every protocol change (EIPs) @@ -82,12 +82,12 @@ type ChainConfig struct { EIP155Block *big.Int `json:"eip155Block"` // EIP155 HF block EIP158Block *big.Int `json:"eip158Block"` // EIP158 HF block - EIP198Block *big.Int `json:"eip198Block"` // EIP198 HF block + MetropolisBlock *big.Int `json:"metropolisBlock"` // Metropolis switch block (nil = no fork, 0 = alraedy on homestead) } // String implements the fmt.Stringer interface. func (c *ChainConfig) String() string { - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v EIP198: %v}", + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Metropolis: %v}", c.ChainId, c.HomesteadBlock, c.DAOForkBlock, @@ -95,7 +95,7 @@ func (c *ChainConfig) String() string { c.EIP150Block, c.EIP155Block, c.EIP158Block, - c.EIP198Block, + c.MetropolisBlock, ) } @@ -205,12 +205,11 @@ func configNumEqual(x, y *big.Int) bool { return x.Cmp(y) == 0 } -func (c *ChainConfig) IsEIP198(num *big.Int) bool { - if c.EIP198Block == nil || num == nil { +func (c *ChainConfig) IsMetropolis(num *big.Int) bool { + if c.MetropolisBlock == nil || num == nil { return false } - return num.Cmp(c.EIP198Block) >= 0 - + return num.Cmp(c.MetropolisBlock) >= 0 } // ConfigCompatError is raised if the locally-stored blockchain is initialised with a @@ -250,10 +249,11 @@ func (err *ConfigCompatError) Error() string { // Rules is a one time interface meaning that it shouldn't be used in between transition // phases. type Rules struct { - ChainId *big.Int - IsHomestead, IsEIP150, IsEIP155, IsEIP158, IsEIP198 bool + ChainId *big.Int + IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool + IsMetropolis bool } func (c *ChainConfig) Rules(num *big.Int) Rules { - return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsEIP198: c.IsEIP198(num)} + return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsMetropolis: c.IsMetropolis(num)} } diff --git a/params/util.go b/params/util.go index 149dab4292..e2ee921475 100644 --- a/params/util.go +++ b/params/util.go @@ -38,8 +38,8 @@ var ( TestNetSpuriousDragon = big.NewInt(10) MainNetSpuriousDragon = big.NewInt(2675000) - TestNetMetropolis = big.NewInt(11) - MainNetMetropolis = big.NewInt(10000000) + TestNetMetropolisBlock = big.NewInt(11) + MainNetMetropolisBlock = big.NewInt(5000000) TestNetChainID = big.NewInt(3) // Test net default chain ID MainNetChainID = big.NewInt(1) // main net default chain ID From e09a836655fae65a916eb4de380acf74986d59fb Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Thu, 2 Feb 2017 00:12:58 +0100 Subject: [PATCH 03/13] core/vm, params: implemented STATIC_CALL - EIP#116 --- core/vm/evm.go | 45 +++++++++++++++++++++++++++++++++++++++++ core/vm/instructions.go | 39 +++++++++++++++++++++++++++++++++-- core/vm/interpreter.go | 11 ++++++++++ core/vm/jump_table.go | 5 +++++ core/vm/opcodes.go | 3 +++ 5 files changed, 101 insertions(+), 2 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 87d12d2cb1..e36ca33d44 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -114,6 +114,51 @@ func (evm *EVM) Cancel() { atomic.StoreInt32(&evm.abort, 1) } +func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { + if evm.vmConfig.NoRecursion && evm.depth > 0 { + return nil, gas, nil + } + + // Depth check execution. Fail if we're trying to execute above the + // limit. + if evm.depth > int(params.CallCreateDepth) { + return nil, gas, ErrDepth + } + + // make sure the readonly is only set if we aren't in readonly yet + // this makes also sure that the readonly flag isn't removed for + // child calls. + if !evm.interpreter.readonly { + evm.interpreter.readonly = true + defer func() { evm.interpreter.readonly = false }() + } + + var ( + to = AccountRef(addr) + snapshot = evm.StateDB.Snapshot() + ) + if !evm.StateDB.Exist(addr) { + return nil, gas, nil + } + + // initialise a new contract and set the code that is to be used by the + // E The contract is a scoped evmironment for this execution context + // only. + contract := NewContract(caller, to, new(big.Int), gas) + contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + + ret, err = evm.interpreter.Run(contract, input) + // When an error was returned by the EVM or when setting the creation code + // above we revert to the snapshot and consume any gas remaining. Additionally + // when we're in homestead this also counts for code storage gas errors. + if err != nil { + contract.UseGas(contract.Gas) + + evm.StateDB.RevertToSnapshot(snapshot) + } + return ret, contract.Gas, err +} + // Call executes the contract associated with the addr with the given input as parameters. It also handles any // necessary value transfer required and takes the necessary steps to create accounts and reverses the state in // case of an execution error or failed value transfer. diff --git a/core/vm/instructions.go b/core/vm/instructions.go index d8737785f1..2e1959e8c0 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -29,8 +29,9 @@ import ( ) var ( - bigZero = new(big.Int) - errRevert = errors.New("standard throw") + bigZero = new(big.Int) + errWriteProtection = errors.New("evm write protection") + errRevert = errors.New("standard throw") ) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -573,6 +574,40 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S return nil, nil } +func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + // EIP116 availability check; return an invalid opcode error on fault + if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) { + return nil, fmt.Errorf("invalid opcode %x", STATIC_CALL) + } + + // pop gas + gas := stack.pop().Uint64() + // pop address + addr := stack.pop() + // pop input size and offset + inOffset, inSize := stack.pop(), stack.pop() + // pop return size and offset + retOffset, retSize := stack.pop(), stack.pop() + + address := common.BigToAddress(addr) + + // Get the arguments from the memory + args := memory.Get(inOffset.Int64(), inSize.Int64()) + + ret, returnGas, err := evm.StaticCall(contract, address, args, gas) + if err != nil { + stack.push(new(big.Int)) + } else { + stack.push(big.NewInt(1)) + + memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) + } + contract.Gas += returnGas + + evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) + return nil, nil +} + func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { gas := stack.pop().Uint64() // pop gas and value of the stack. diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 00eb3ac418..b38d42ed3f 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -60,6 +60,8 @@ type Interpreter struct { cfg Config gasTable params.GasTable intPool *intPool + + readonly bool } // NewInterpreter returns a new instance of the Interpreter. @@ -128,6 +130,15 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e // get the operation from the jump table matching the opcode operation := evm.cfg.JumpTable[op] + // if the interpreter is operating in readonly mode, make sure no + // state-modifying operation is performed. + if evm.readonly && evm.env.chainConfig.IsMetropolis(evm.env.BlockNumber) { + if operation.writes || + ((op == CALL || op == CALLCODE) && stack.Back(3).BitLen() > 0) { + return nil, errWriteProtection + } + + } // if the op is invalid abort the process and return an error if !operation.valid { diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index ccb38e8dae..3e5097857d 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -47,6 +47,8 @@ type operation struct { // jumps indicates whether operation made a jump. This prevents the program // counter from further incrementing. jumps bool + // writes determines whether this a state modifying operation + writes bool // valid is used to check whether the retrieved operation is valid and known valid bool } @@ -357,6 +359,7 @@ func NewJumpTable() [256]operation { gasCost: gasSStore, validateStack: makeStackFunc(2, 0), valid: true, + writes: true, }, JUMP: { execute: opJump, @@ -829,6 +832,7 @@ func NewJumpTable() [256]operation { validateStack: makeStackFunc(3, 1), memorySize: memoryCreate, valid: true, + writes: true, }, CALL: { execute: opCall, @@ -865,6 +869,7 @@ func NewJumpTable() [256]operation { validateStack: makeStackFunc(1, 0), halts: true, valid: true, + writes: true, }, } } diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 3c3796d2d2..d063bffb0e 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -201,6 +201,7 @@ const ( CALLCODE RETURN DELEGATECALL + STATIC_CALL REVERT = 0xfd SELFDESTRUCT = 0xff @@ -358,6 +359,7 @@ var opCodeToString = map[OpCode]string{ CALLCODE: "CALLCODE", DELEGATECALL: "DELEGATECALL", SELFDESTRUCT: "SELFDESTRUCT", + STATIC_CALL: "STATIC_CALL", PUSH: "PUSH", DUP: "DUP", @@ -407,6 +409,7 @@ var stringToOp = map[string]OpCode{ "CALLDATASIZE": CALLDATASIZE, "CALLDATACOPY": CALLDATACOPY, "DELEGATECALL": DELEGATECALL, + "STATIC_CALL": STATIC_CALL, "CODESIZE": CODESIZE, "CODECOPY": CODECOPY, "GASPRICE": GASPRICE, From e1598fa996fe1a40f4b3446e0fd10d9e850e0b8d Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Wed, 1 Feb 2017 23:27:38 +0100 Subject: [PATCH 04/13] core, params: difficulty includes uncle count - EIP#100 --- consensus/ethash/consensus.go | 69 ++++++++++++++++++---- consensus/ethash/consensus_test.go | 7 ++- core/chain_makers.go | 22 +++++--- core/state/statedb.go | 91 +++++++++++++++++++----------- core/state_processor.go | 11 +++- miner/worker.go | 2 +- 6 files changed, 147 insertions(+), 55 deletions(-) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 603be3e531..7cfcf9bca5 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -265,7 +265,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent * return ErrZeroBlockTime } // Verify the block's difficulty based in it's timestamp and parent's difficulty - expected := CalcDifficulty(chain.Config(), header.Time.Uint64(), parent.Time.Uint64(), parent.Number, parent.Difficulty) + expected := CalcDifficulty(chain.Config(), header.Time.Uint64(), parent) if expected.Cmp(header.Difficulty) != 0 { return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected) } @@ -300,16 +300,21 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent * return nil } -// CalcDifficulty is the difficulty adjustment algorithm. It returns the difficulty -// that a new block should have when created at time given the parent block's time -// and difficulty. +// CalcDifficulty is the difficulty adjustment algorithm. It returns +// the difficulty that a new block should have when created at time +// given the parent block's time and difficulty. // // TODO (karalabe): Move the chain maker into this package and make this private! -func CalcDifficulty(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { - if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) { - return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff) +func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int { + next := new(big.Int).Add(parent.Number, common.Big1) + switch { + case config.IsEIP100(next): + return CalcDifficultyMetropolis(time, parent) + case config.IsHomestead(next): + return calcDifficultyHomestead(time, parent) + default: + return calcDifficultyFrontier(time, parent) } - return calcDifficultyFrontier(time, parentTime, parentNumber, parentDiff) } // Some weird constants to avoid constant memory allocs for them. @@ -319,6 +324,51 @@ var ( bigMinus99 = big.NewInt(-99) ) +func CalcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int { + bigTime := new(big.Int).SetUint64(time) + bigParentTime := new(big.Int).Set(parent.Time) + + // adj_factor = max((2 if len(parent.uncles) else 1) - ((timestamp - parent.timestamp) // 9), -99) + var x *big.Int + if parent.UncleHash == types.EmptyUncleHash { + x = big.NewInt(1) + } else { + x = big.NewInt(2) + } + z := new(big.Int).Sub(bigTime, bigParentTime) + z.Div(x, big9) + x.Sub(x, z) + + // max(1 - (block_timestamp - parent_timestamp) // 10, -99))) + if x.Cmp(bigMinus99) < 0 { + x.Set(bigMinus99) + } + + // (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) + y := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor) + x.Mul(y, x) + x.Add(parent.Difficulty, x) + + // minimum difficulty can ever be (before exponential factor) + if x.Cmp(params.MinimumDifficulty) < 0 { + x.Set(params.MinimumDifficulty) + } + + // for the exponential factor + periodCount := new(big.Int).Add(parent.Number, common.Big1) + periodCount.Div(periodCount, ExpDiffPeriod) + + // the exponential factor, commonly referred to as "the bomb" + // diff = diff + 2^(periodCount - 2) + if periodCount.Cmp(common.Big1) > 0 { + y.Sub(periodCount, common.Big2) + y.Exp(common.Big2, y, nil) + x.Add(x, y) + } + + return x +} + // calcDifficultyHomestead is the difficulty adjustment algorithm. It returns // the difficulty that a new block should have when created at time given the // parent block's time and difficulty. The calculation uses the Homestead rules. @@ -451,8 +501,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainReader, header *types.Header) if parent == nil { return ErrParentUnknown } - header.Difficulty = CalcDifficulty(chain.Config(), header.Time.Uint64(), - parent.Time.Uint64(), parent.Number, parent.Difficulty) + header.Difficulty = CalcDifficulty(chain.Config(), header.Time.Uint64(), parent) return nil } diff --git a/consensus/ethash/consensus_test.go b/consensus/ethash/consensus_test.go index 683c10be49..78464bd224 100644 --- a/consensus/ethash/consensus_test.go +++ b/consensus/ethash/consensus_test.go @@ -23,6 +23,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) @@ -71,7 +72,11 @@ func TestCalcDifficulty(t *testing.T) { config := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(1150000)} for name, test := range tests { number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1)) - diff := CalcDifficulty(config, test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty) + diff := CalcDifficulty(config, test.CurrentTimestamp, &types.Header{ + Number: number, + Time: test.ParentTimestamp, + Difficulty: test.ParentDifficulty, + }) if diff.Cmp(test.CurrentDifficulty) != 0 { t.Error(name, "failed. Expected", test.CurrentDifficulty, "and calculated", diff) } diff --git a/core/chain_makers.go b/core/chain_makers.go index c47c719f64..35655c68aa 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -84,7 +84,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { if b.gasPool == nil { b.SetCoinbase(common.Address{}) } - b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs)) + b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) receipt, _, err := ApplyTransaction(b.config, nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{}) if err != nil { panic(err) @@ -142,7 +142,7 @@ func (b *BlockGen) OffsetTime(seconds int64) { if b.header.Time.Cmp(b.parent.Header().Time) <= 0 { panic("block time out of range") } - b.header.Difficulty = ethash.CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent.Time().Uint64(), b.parent.Number(), b.parent.Difficulty()) + b.header.Difficulty = ethash.CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent) } // GenerateChain creates a chain of n blocks. The first block's @@ -209,15 +209,23 @@ func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.St } else { time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds } + parentHeader := parent.Header() + // adjust the parent time + parentHeader.Time = new(big.Int).Sub(time, big.NewInt(10)) + return &types.Header{ Root: state.IntermediateRoot(config.IsEIP158(parent.Number())), ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), - Difficulty: ethash.CalcDifficulty(config, time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()), - GasLimit: CalcGasLimit(parent), - GasUsed: new(big.Int), - Number: new(big.Int).Add(parent.Number(), common.Big1), - Time: time, + Difficulty: ethash.CalcDifficulty(config, time.Uint64(), &types.Header{ + Number: parent.Number(), + Time: new(big.Int).Sub(time, big.NewInt(10)), + Difficulty: parent.Difficulty(), + }), + GasLimit: CalcGasLimit(parent), + GasUsed: new(big.Int), + Number: new(big.Int).Add(parent.Number(), common.Big1), + Time: time, } } diff --git a/core/state/statedb.go b/core/state/statedb.go index 0c72fc6b07..fa1673d52a 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -62,8 +62,9 @@ type StateDB struct { codeSizeCache *lru.Cache // This map holds 'live' objects, which will get modified while processing a state transition. - stateObjects map[common.Address]*stateObject - stateObjectsDirty map[common.Address]struct{} + stateObjects map[common.Address]*stateObject + stateObjectsDirty map[common.Address]struct{} + stateObjectsDestructed map[common.Address]struct{} // The refund counter, also used by state transitioning. refund *big.Int @@ -92,14 +93,15 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) { } csc, _ := lru.New(codeSizeCacheSize) return &StateDB{ - db: db, - trie: tr, - codeSizeCache: csc, - stateObjects: make(map[common.Address]*stateObject), - stateObjectsDirty: make(map[common.Address]struct{}), - refund: new(big.Int), - logs: make(map[common.Hash][]*types.Log), - preimages: make(map[common.Hash][]byte), + db: db, + trie: tr, + codeSizeCache: csc, + stateObjects: make(map[common.Address]*stateObject), + stateObjectsDirty: make(map[common.Address]struct{}), + stateObjectsDestructed: make(map[common.Address]struct{}), + refund: new(big.Int), + logs: make(map[common.Hash][]*types.Log), + preimages: make(map[common.Hash][]byte), }, nil } @@ -114,14 +116,15 @@ func (self *StateDB) New(root common.Hash) (*StateDB, error) { return nil, err } return &StateDB{ - db: self.db, - trie: tr, - codeSizeCache: self.codeSizeCache, - stateObjects: make(map[common.Address]*stateObject), - stateObjectsDirty: make(map[common.Address]struct{}), - refund: new(big.Int), - logs: make(map[common.Hash][]*types.Log), - preimages: make(map[common.Hash][]byte), + db: self.db, + trie: tr, + codeSizeCache: self.codeSizeCache, + stateObjects: make(map[common.Address]*stateObject), + stateObjectsDirty: make(map[common.Address]struct{}), + stateObjectsDestructed: make(map[common.Address]struct{}), + refund: new(big.Int), + logs: make(map[common.Hash][]*types.Log), + preimages: make(map[common.Hash][]byte), }, nil } @@ -138,6 +141,7 @@ func (self *StateDB) Reset(root common.Hash) error { self.trie = tr self.stateObjects = make(map[common.Address]*stateObject) self.stateObjectsDirty = make(map[common.Address]struct{}) + self.stateObjectsDestructed = make(map[common.Address]struct{}) self.thash = common.Hash{} self.bhash = common.Hash{} self.txIndex = 0 @@ -173,12 +177,6 @@ func (self *StateDB) pushTrie(t *trie.SecureTrie) { } } -func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) { - self.thash = thash - self.bhash = bhash - self.txIndex = ti -} - func (self *StateDB) AddLog(log *types.Log) { self.journal = append(self.journal, addLogChange{txhash: self.thash}) @@ -499,21 +497,25 @@ func (self *StateDB) Copy() *StateDB { // Copy all the basic fields, initialize the memory ones state := &StateDB{ - db: self.db, - trie: self.trie, - pastTries: self.pastTries, - codeSizeCache: self.codeSizeCache, - stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)), - stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)), - refund: new(big.Int).Set(self.refund), - logs: make(map[common.Hash][]*types.Log, len(self.logs)), - logSize: self.logSize, - preimages: make(map[common.Hash][]byte), + db: self.db, + trie: self.trie, + pastTries: self.pastTries, + codeSizeCache: self.codeSizeCache, + stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)), + stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)), + stateObjectsDestructed: make(map[common.Address]struct{}, len(self.stateObjectsDestructed)), + refund: new(big.Int).Set(self.refund), + logs: make(map[common.Hash][]*types.Log, len(self.logs)), + logSize: self.logSize, + preimages: make(map[common.Hash][]byte), } // Copy the dirty states, logs, and preimages for addr := range self.stateObjectsDirty { state.stateObjects[addr] = self.stateObjects[addr].deepCopy(state, state.MarkStateObjectDirty) state.stateObjectsDirty[addr] = struct{}{} + if self.stateObjects[addr].suicided { + state.stateObjectsDestructed[addr] = struct{}{} + } } for hash, logs := range self.logs { state.logs[hash] = make([]*types.Log, len(logs)) @@ -579,6 +581,27 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { return s.trie.Hash() } +// Prepare sets the current transaction hash and index and block hash which is +// used when the EVM emits new state logs. +func (self *StateDB) Prepare(thash, bhash common.Hash, ti int) { + self.thash = thash + self.bhash = bhash + self.txIndex = ti +} + +// Finalise finalises the state by removing the self destructed objects +// in the current stateObjectsDestructed buffer and clears the journal +// as well as the refunds. +// +// Please note that Finalise is used by EIP#98 and is used instead of +// IntermediateRoot. +func (s *StateDB) Finalise() { + for addr := range s.stateObjectsDestructed { + s.deleteStateObject(s.stateObjects[addr]) + } + s.clearJournalAndRefund() +} + // DeleteSuicides flags the suicided objects for deletion so that it // won't be referenced again when called / queried up on. // diff --git a/core/state_processor.go b/core/state_processor.go index aca2929eb2..9effd4fbb2 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -19,6 +19,7 @@ package core import ( "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" @@ -68,7 +69,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { - statedb.StartRecord(tx.Hash(), block.Hash(), i) + statedb.Prepare(tx.Hash(), block.Hash(), i) receipt, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg) if err != nil { return nil, nil, nil, err @@ -104,9 +105,15 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, s // Update the state with pending changes usedGas.Add(usedGas, gas) + var root common.Hash + if config.IsMetropolis(header.Number) { + statedb.Finalise() + } else { + root = statedb.IntermediateRoot(config.IsEIP158(header.Number)) + } // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // based on the eip phase, we're passing wether the root touch-delete accounts. - receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas) + receipt := types.NewReceipt(root.Bytes(), usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) // if the transaction created a contract, store the creation address in the receipt. diff --git a/miner/worker.go b/miner/worker.go index 347de4e08a..eb65a2a0d1 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -561,7 +561,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB continue } // Start executing the transaction - env.state.StartRecord(tx.Hash(), common.Hash{}, env.tcount) + env.state.Prepare(tx.Hash(), common.Hash{}, env.tcount) err, logs := env.commitTransaction(tx, bc, gp) switch { From ca6d94b66ceb42bbab5b473264073042b090cf6b Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Tue, 7 Mar 2017 17:48:33 +0100 Subject: [PATCH 05/13] core, core/vm: cleaned up compile errors --- core/vm/contracts.go | 25 +++++++++++++------------ core/vm/evm.go | 2 +- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 4d757dabdd..8a42f88844 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -21,6 +21,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -47,8 +48,8 @@ var PrecompiledContracts = map[common.Address]PrecompiledContract{ // for EIP198. var PrecompiledContractsEIP198 = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{1}): &ecrecover{}, - common.BytesToAddress([]byte{2}): &sha256{}, - common.BytesToAddress([]byte{3}): &ripemd160{}, + common.BytesToAddress([]byte{2}): &sha256hash{}, + common.BytesToAddress([]byte{3}): &ripemd160hash{}, common.BytesToAddress([]byte{4}): &dataCopy{}, common.BytesToAddress([]byte{5}): &bigModexp{}, } @@ -159,11 +160,11 @@ func (c *bigModexp) RequiredGas(input []byte) uint64 { input = append(input, make([]byte, 3*32-len(input))...) } var ( - baseLen = common.BytesToBig(input[:31]) - expLen = common.BigMax(common.BytesToBig(input[32:64]), big.NewInt(1)) - modLen = common.BytesToBig(input[65:97]) + baseLen = new(big.Int).SetBytes(input[:31]) + expLen = math.BigMax(new(big.Int).SetBytes(input[32:64]), big.NewInt(1)) + modLen = new(big.Int).SetBytes(input[65:97]) ) - x := new(big.Int).Set(common.BigMax(baseLen, modLen)) + x := new(big.Int).Set(math.BigMax(baseLen, modLen)) x.Mul(x, x) x.Mul(x, expLen) x.Div(x, new(big.Int).SetUint64(params.QuadCoeffDiv)) @@ -177,28 +178,28 @@ func (c *bigModexp) Run(input []byte) []byte { } // why 32-byte? These values won't fit anyway var ( - baseLen = common.BytesToBig(input[:32]).Uint64() - expLen = common.BytesToBig(input[32:64]).Uint64() - modLen = common.BytesToBig(input[64:96]).Uint64() + 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() ) input = input[96:] if uint64(len(input)) < baseLen { input = append(input, make([]byte, baseLen-uint64(len(input)))...) } - base := common.BytesToBig(input[:baseLen]) + base := new(big.Int).SetBytes(input[:baseLen]) input = input[baseLen:] if uint64(len(input)) < expLen { input = append(input, make([]byte, expLen-uint64(len(input)))...) } - exp := common.BytesToBig(input[:expLen]) + exp := new(big.Int).SetBytes(input[:expLen]) input = input[expLen:] if uint64(len(input)) < modLen { input = append(input, make([]byte, modLen-uint64(len(input)))...) } - mod := common.BytesToBig(input[:modLen]) + mod := new(big.Int).SetBytes(input[:modLen]) return base.Exp(base, exp, mod).Bytes() } diff --git a/core/vm/evm.go b/core/vm/evm.go index e36ca33d44..f104492c30 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -37,7 +37,7 @@ type ( func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) { if contract.CodeAddr != nil { precompiledContracts := PrecompiledContracts - if evm.ChainConfig().IsEIP198(evm.BlockNumber) { + if evm.ChainConfig().IsMetropolis(evm.BlockNumber) { precompiledContracts = PrecompiledContractsEIP198 } From c230e5518b976960f361683726d55e3213244ffd Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Fri, 10 Feb 2017 13:21:17 +0100 Subject: [PATCH 06/13] core/types, params: account abstraction - EIP#86 --- core/types/transaction_signing.go | 51 ++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index b4bab0aad7..f90d3ebe25 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -27,7 +27,12 @@ import ( "github.com/ethereum/go-ethereum/params" ) -var ErrInvalidChainId = errors.New("invalid chaid id for signer") +var ( + ErrInvalidChainId = errors.New("invalid chaid id for signer") + + errAbstractSigner = errors.New("abstract signer") + abstractSignerAddress = common.HexToAddress("ffffffffffffffffffffffffffffffffffffff") +) // sigCache is used to cache the derived sender and contains // the signer used to derive it. @@ -40,6 +45,8 @@ type sigCache struct { func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer { var signer Signer switch { + case config.IsMetropolis(blockNumber): + signer = NewEIP86Signer(config.ChainId) case config.IsEIP155(blockNumber): signer = NewEIP155Signer(config.ChainId) case config.IsHomestead(blockNumber): @@ -83,6 +90,10 @@ func Sender(signer Signer, tx *Transaction) (common.Address, error) { pubkey, err := signer.PublicKey(tx) if err != nil { + if err == errAbstractSigner { + return abstractSignerAddress, nil + } + return common.Address{}, err } var addr common.Address @@ -103,6 +114,44 @@ type Signer interface { Equal(Signer) bool } +type EIP86Signer struct { + EIP155Signer +} + +func NewEIP86Signer(chainId *big.Int) EIP86Signer { + return EIP86Signer{ + EIP155Signer: NewEIP155Signer(chainId), + } +} + +func (s EIP86Signer) Equal(s2 Signer) bool { + _, ok := s2.(EIP86Signer) + return ok && s.EIP155Signer.Equal(s2) +} + +func isAbstractSigner(tx *Transaction) bool { + v, r, s := tx.RawSignatureValues() + return v.BitLen() == 0 && r.BitLen() == 0 && s.BitLen() == 0 +} + +func (s EIP86Signer) PublicKey(tx *Transaction) ([]byte, error) { + if isAbstractSigner(tx) { + return nil, errAbstractSigner + } + return s.EIP155Signer.PublicKey(tx) +} + +/* +// WithSignature returns a new transaction with the given signature. This signature +// needs to be in the [R || S || V] format where V is 0 or 1. +func (s EIP86Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) { +} + +// Hash returns the hash to be signed by the sender. +// It does not uniquely identify the transaction. +func (s EIP86Signer) Hash(tx *Transaction) common.Hash {} +*/ + // EIP155Transaction implements TransactionInterface using the // EIP155 rules type EIP155Signer struct { From 49f47639eb047e7c22aeabc7ff75091d13d52742 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Tue, 7 Mar 2017 22:55:46 +0100 Subject: [PATCH 07/13] core/vm: make pre compile return errors --- core/vm/contracts.go | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 8a42f88844..a22abf2aff 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -32,8 +32,8 @@ import ( // requires a deterministic gas count based on the input size of the Run method of the // contract. type PrecompiledContract interface { - RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use - Run(input []byte) []byte // Run runs the precompiled contract + RequiredGas(input []byte) uint64 // RequiredPrice calculates the contract gas use + Run(input []byte) ([]byte, error) // Run runs the precompiled contract } // PrecompiledContracts contains the default set of ethereum contracts @@ -58,9 +58,7 @@ var PrecompiledContractsEIP198 = map[common.Address]PrecompiledContract{ func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) { gas := p.RequiredGas(input) if contract.UseGas(gas) { - ret = p.Run(input) - - return ret, nil + return p.Run(input) } else { return nil, ErrOutOfGas } @@ -73,7 +71,7 @@ func (c *ecrecover) RequiredGas(input []byte) uint64 { return params.EcrecoverGas } -func (c *ecrecover) Run(in []byte) []byte { +func (c *ecrecover) Run(in []byte) ([]byte, error) { const ecRecoverInputLength = 128 in = common.RightPadBytes(in, ecRecoverInputLength) @@ -94,11 +92,11 @@ func (c *ecrecover) Run(in []byte) []byte { // make sure the public key is a valid one if err != nil { log.Trace("ECRECOVER failed", "err", err) - return nil + return nil, nil } // the first byte of pubkey is bitcoin heritage - return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32) + return common.LeftPadBytes(crypto.Keccak256(pubKey[1:])[12:], 32), nil } // SHA256 implemented as a native contract @@ -111,9 +109,9 @@ type sha256hash struct{} func (c *sha256hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Sha256WordGas + params.Sha256Gas } -func (c *sha256hash) Run(in []byte) []byte { +func (c *sha256hash) Run(in []byte) ([]byte, error) { h := sha256.Sum256(in) - return h[:] + return h[:], nil } // RIPMED160 implemented as a native contract @@ -126,10 +124,10 @@ type ripemd160hash struct{} func (c *ripemd160hash) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.Ripemd160WordGas + params.Ripemd160Gas } -func (c *ripemd160hash) Run(in []byte) []byte { +func (c *ripemd160hash) Run(in []byte) ([]byte, error) { ripemd := ripemd160.New() ripemd.Write(in) - return common.LeftPadBytes(ripemd.Sum(nil), 32) + return common.LeftPadBytes(ripemd.Sum(nil), 32), nil } // data copy implemented as a native contract @@ -142,8 +140,8 @@ type dataCopy struct{} func (c *dataCopy) RequiredGas(input []byte) uint64 { return uint64(len(input)+31)/32*params.IdentityWordGas + params.IdentityGas } -func (c *dataCopy) Run(in []byte) []byte { - return in +func (c *dataCopy) Run(in []byte) ([]byte, error) { + return in, nil } // bigModexp implements a native big integer exponential modular operation. @@ -172,7 +170,7 @@ func (c *bigModexp) RequiredGas(input []byte) uint64 { return x.Uint64() } -func (c *bigModexp) Run(input []byte) []byte { +func (c *bigModexp) Run(input []byte) ([]byte, error) { if len(input) < 3*32 { input = append(input, make([]byte, 3*32-len(input))...) } @@ -201,5 +199,5 @@ func (c *bigModexp) Run(input []byte) []byte { } mod := new(big.Int).SetBytes(input[:modLen]) - return base.Exp(base, exp, mod).Bytes() + return base.Exp(base, exp, mod).Bytes(), nil } From cdcf490127fdda2a84938df6f46ebcafd119e288 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Fri, 3 Feb 2017 18:29:43 +0100 Subject: [PATCH 08/13] core/vm: implemented bn256 mul and add pre compiled - EIP#197 core/vm, crypto/bn256: added bn256 curve and added precompile core/vm: use crypto/bn256 crypto/bn256: exported P constant core/vm, crypto/bn256: pairing pre-compile core/vm: added pairing test core, crypto, internal/ethapi, params: fixed tests core/vm: fixed nil length input for pairing --- core/vm/contracts.go | 145 ++++++++++- core/vm/contracts_test.go | 35 +++ core/vm/evm.go | 2 +- crypto/bn256/bn256.go | 428 +++++++++++++++++++++++++++++++++ crypto/bn256/bn256_test.go | 304 +++++++++++++++++++++++ crypto/bn256/constants.go | 44 ++++ crypto/bn256/curve.go | 278 +++++++++++++++++++++ crypto/bn256/example_test.go | 43 ++++ crypto/bn256/gfp12.go | 200 +++++++++++++++ crypto/bn256/gfp2.go | 227 +++++++++++++++++ crypto/bn256/gfp6.go | 296 +++++++++++++++++++++++ crypto/bn256/main_test.go | 71 ++++++ crypto/bn256/optate.go | 398 ++++++++++++++++++++++++++++++ crypto/bn256/twist.go | 249 +++++++++++++++++++ internal/ethapi/tracer_test.go | 2 +- 15 files changed, 2716 insertions(+), 6 deletions(-) create mode 100644 core/vm/contracts_test.go create mode 100644 crypto/bn256/bn256.go create mode 100644 crypto/bn256/bn256_test.go create mode 100644 crypto/bn256/constants.go create mode 100644 crypto/bn256/curve.go create mode 100644 crypto/bn256/example_test.go create mode 100644 crypto/bn256/gfp12.go create mode 100644 crypto/bn256/gfp2.go create mode 100644 crypto/bn256/gfp6.go create mode 100644 crypto/bn256/main_test.go create mode 100644 crypto/bn256/optate.go create mode 100644 crypto/bn256/twist.go diff --git a/core/vm/contracts.go b/core/vm/contracts.go index a22abf2aff..084b99dadc 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -18,16 +18,20 @@ package vm import ( "crypto/sha256" + "errors" "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/bn256" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "golang.org/x/crypto/ripemd160" ) +var errBadPrecompileInput = errors.New("bad pre compile input") + // Precompiled contract is the basic interface for native Go contracts. The implementation // requires a deterministic gas count based on the input size of the Run method of the // contract. @@ -44,14 +48,17 @@ var PrecompiledContracts = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{4}): &dataCopy{}, } -// PrecompiledContractsEIP198 contains the default set of ethereum contracts -// for EIP198. -var PrecompiledContractsEIP198 = map[common.Address]PrecompiledContract{ +// PrecompiledContractsMetropolis contains the default set of ethereum contracts +// for metropolis hardfork +var PrecompiledContractsMetropolis = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{1}): &ecrecover{}, common.BytesToAddress([]byte{2}): &sha256hash{}, common.BytesToAddress([]byte{3}): &ripemd160hash{}, common.BytesToAddress([]byte{4}): &dataCopy{}, common.BytesToAddress([]byte{5}): &bigModexp{}, + common.BytesToAddress([]byte{6}): &bn256Add{}, + common.BytesToAddress([]byte{6}): &bn256ScalarMul{}, + common.BytesToAddress([]byte{8}): &pairing{}, } // RunPrecompile runs and evaluate the output of a precompiled contract defined in contracts.go @@ -85,7 +92,7 @@ func (c *ecrecover) Run(in []byte) ([]byte, error) { // tighter sig s values in homestead only apply to tx sigs if !allZero(in[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { log.Trace("ECRECOVER error: v, r or s value invalid") - return nil + return nil, nil } // v needs to be at the end for libsecp256k1 pubKey, err := crypto.Ecrecover(in[:32], append(in[64:128], v)) @@ -201,3 +208,133 @@ func (c *bigModexp) Run(input []byte) ([]byte, error) { return base.Exp(base, exp, mod).Bytes(), nil } + +type bn256Add struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *bn256Add) RequiredGas(input []byte) uint64 { + return 0 // TODO +} + +func (c *bn256Add) Run(in []byte) ([]byte, error) { + if len(in) != 96 { + return nil, errBadPrecompileInput + } + + g1, onCurve := new(bn256.G1).Unmarshal(in[:64]) + if !onCurve { + return nil, errNotOnCurve + } + x, y, _, _ := g1.CurvePoints() + if x.Cmp(bn256.P) >= 0 || y.Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + g1.ScalarMult(g1, new(big.Int).SetBytes(in[64:])) + + return g1.Marshal(), nil +} + +type bn256ScalarMul struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *bn256ScalarMul) RequiredGas(input []byte) uint64 { + return 0 // TODO +} + +func (c *bn256ScalarMul) Run(in []byte) ([]byte, error) { + if len(in) != 128 { + return nil, errBadPrecompileInput + } + + x, onCurve := new(bn256.G1).Unmarshal(in[:64]) + if !onCurve { + return nil, errNotOnCurve + } + gx, gy, _, _ := x.CurvePoints() + if gx.Cmp(bn256.P) >= 0 || gy.Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + + y, onCurve := new(bn256.G1).Unmarshal(in[:64]) + if !onCurve { + return nil, errNotOnCurve + } + gx, gy, _, _ = x.CurvePoints() + if gx.Cmp(bn256.P) >= 0 || gy.Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + + return x.Add(x, y).Marshal(), nil +} + +// pairing implements a pairing pre-compile for the bn256 curve +type pairing struct{} + +// RequiredGas returns the gas required to execute the pre-compiled contract. +// +// This method does not require any overflow checking as the input size gas costs +// required for anything significant is so high it's impossible to pay for. +func (c *pairing) RequiredGas(input []byte) uint64 { + return 0 // TODO +} + +const pairSize = 192 + +var ( + true32Byte = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} + fals32Byte = make([]byte, 32) + errNotOnCurve = errors.New("point not on elliptic curve") + errInvalidCurvePoint = errors.New("invalid elliptic curve point") +) + +func (c *pairing) Run(in []byte) ([]byte, error) { + if len(in) == 0 { + return true32Byte, nil + } + + if len(in)%pairSize > 0 { + return nil, errBadPrecompileInput + } + + var ( + g1s []*bn256.G1 + g2s []*bn256.G2 + ) + for i := 0; i < len(in); i += pairSize { + g1, onCurve := new(bn256.G1).Unmarshal(in[i : i+64]) + if !onCurve { + return nil, errNotOnCurve + } + + x, y, _, _ := g1.CurvePoints() + if x.Cmp(bn256.P) >= 0 || y.Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + + g2, onCurve := new(bn256.G2).Unmarshal(in[i+64 : i+192]) + if !onCurve { + return nil, errNotOnCurve + } + x2, y2, _, _ := g2.CurvePoints() + if x2.Real().Cmp(bn256.P) >= 0 || x2.Imag().Cmp(bn256.P) >= 0 || + y2.Real().Cmp(bn256.P) >= 0 || y2.Imag().Cmp(bn256.P) >= 0 { + return nil, errInvalidCurvePoint + } + + g1s = append(g1s, g1) + g2s = append(g2s, g2) + } + + isOne := bn256.PairingCheck(g1s, g2s) + if isOne { + return true32Byte, nil + } + + return fals32Byte, nil +} diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go new file mode 100644 index 0000000000..2b4070ede7 --- /dev/null +++ b/core/vm/contracts_test.go @@ -0,0 +1,35 @@ +package vm + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" +) + +const input = "" + +func TestPairing(t *testing.T) { + pairing := &pairing{} + + for i, test := range []struct { + input string + valid int + }{ + {"1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c2032c61a830e3c17286de9462bf242fca2883585b93870a73853face6a6bf411198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1}, + {"2eca0c7238bf16e83e7a1e6c5d49540685ff51380f309842a98561558019fc0203d3260361bb8451de5ff5ecd17f010ff22f5c31cdf184e9020b06fa5997db841213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f06967a1237ebfeca9aaae0d6d0bab8e28c198c5a339ef8a2407e31cdac516db922160fa257a5fd5b280642ff47b65eca77e626cb685c84fa6d3b6882a283ddd1198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1}, + {"0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd216da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba2e89718ad33c8bed92e210e81d1853435399a271913a6520736a4729cf0d51eb01a9e2ffa2e92599b68e44de5bcf354fa2642bd4f26b259daa6f7ce3ed57aeb314a9a87b789a58af499b314e13c3d65bede56c07ea2d418d6874857b70763713178fb49a2d6cd347dc58973ff49613a20757d0fcc22079f9abd10c3baee245901b9e027bd5cfc2cb5db82d4dc9677ac795ec500ecd47deee3b5da006d6d049b811d7511c78158de484232fc68daf8a45cf217d1c2fae693ff5871e8752d73b21198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1}, + {"2f2ea0b3da1e8ef11914acf8b2e1b32d99df51f5f4f206fc6b947eae860eddb6068134ddb33dc888ef446b648d72338684d678d2eb2371c61a50734d78da4b7225f83c8b6ab9de74e7da488ef02645c5a16a6652c3c71a15dc37fe3a5dcb7cb122acdedd6308e3bb230d226d16a105295f523a8a02bfc5e8bd2da135ac4c245d065bbad92e7c4e31bf3757f1fe7362a63fbfee50e7dc68da116e67d600d9bf6806d302580dc0661002994e7cd3a7f224e7ddc27802777486bf80f40e4ca3cfdb186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008122ae2b09e539e152ec5364e7e2204b03d11d3caa038bfc7cd499f8176aacbee1f39e4e4afc4bc74790a4a028aff2c3d2538731fb755edefd8cb48d6ea589b5e283f150794b6736f670d6a1033f9b46c6f5204f50813eb85c8dc4b59db1c5d39140d97ee4d2b36d99bc49974d18ecca3e7ad51011956051b464d9e27d46cc25e0764bb98575bd466d32db7b15f582b2d5c452b36aa394b789366e5e3ca5aabd415794ab061441e51d01e94640b7e3084a07e02c78cf3103c542bc5b298669f211b88da1679b0b64a63b7e0e7bfe52aae524f73a55be7fe70c7e9bfc94b4cf0da1213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f", 1}, + {"20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed30211213d2149b006137fcfb23036606f848d638d576a120ca981b5b1a5f9300b3ee2276cf730cf493cd95d64677bbb75fc42db72513a4c1e387b476d056f80aa75f21ee6226d31426322afcda621464d0611d226783262e21bb3bc86b537e986237096df1f82dff337dd5972e32a8ad43e28a78a96a823ef1cd4debe12b6552ea5f1abb4a25eb9379ae96c84fff9f0540abcfc0a0d11aeda02d4f37e4baf74cb0c11073b3ff2cdbb38755f8691ea59e9606696b3ff278acfc098fa8226470d03869217cee0a9ad79a4493b5253e2e4e3a39fc2df38419f230d341f60cb064a0ac290a3d76f140db8418ba512272381446eb73958670f00cf46f1d9e64cba057b53c26f64a8ec70387a13e41430ed3ee4a7db2059cc5fc13c067194bcc0cb49a98552fd72bd9edb657346127da132e5b82ab908f5816c826acb499e22f2412d1a2d70f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2198a1f162a73261f112401aa2db79c7dab1533c9935c77290a6ce3b191f2318d198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 1}, + {"1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f593034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41209dd15ebff5d46c4bd888e51a93cf99a7329636c63514396b4a452003a35bf704bf11ca01483bfa8b34b43561848d28905960114c8ac04049af4b6315a416782bb8324af6cfc93537a2ad1a445cfd0ca2a71acd7ac41fadbf933c2a51be344d120a2a4cf30c1bf9845f20c6fe39e07ea2cce61f0c9bb048165fe5e4de877550111e129f1cf1097710d41c4ac70fcdfa5ba2023c6ff1cbeac322de49d1b6df7c103188585e2364128fe25c70558f1560f4f9350baf3959e603cc91486e110936198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa", 0}, + } { + r, err := pairing.Run(common.FromHex(test.input)) + if err != nil { + t.Error(i, ":", err) + } + + if int(r[31]) != test.valid { + t.Error(i, "expected", test.valid, "but was", r[31]) + } + } + +} diff --git a/core/vm/evm.go b/core/vm/evm.go index f104492c30..9264d88659 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -38,7 +38,7 @@ func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) { if contract.CodeAddr != nil { precompiledContracts := PrecompiledContracts if evm.ChainConfig().IsMetropolis(evm.BlockNumber) { - precompiledContracts = PrecompiledContractsEIP198 + precompiledContracts = PrecompiledContractsMetropolis } if p := precompiledContracts[*contract.CodeAddr]; p != nil { diff --git a/crypto/bn256/bn256.go b/crypto/bn256/bn256.go new file mode 100644 index 0000000000..92418369b0 --- /dev/null +++ b/crypto/bn256/bn256.go @@ -0,0 +1,428 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package bn256 implements a particular bilinear group at the 128-bit security level. +// +// Bilinear groups are the basis of many of the new cryptographic protocols +// that have been proposed over the past decade. They consist of a triplet of +// groups (G₁, G₂ and GT) such that there exists a function e(g₁ˣ,g₂ʸ)=gTˣʸ +// (where gₓ is a generator of the respective group). That function is called +// a pairing function. +// +// This package specifically implements the Optimal Ate pairing over a 256-bit +// Barreto-Naehrig curve as described in +// http://cryptojedi.org/papers/dclxvi-20100714.pdf. Its output is compatible +// with the implementation described in that paper. +package bn256 + +import ( + "crypto/rand" + "io" + "math/big" +) + +// BUG(agl): this implementation is not constant time. +// TODO(agl): keep GF(p²) elements in Mongomery form. + +// G1 is an abstract cyclic group. The zero value is suitable for use as the +// output of an operation, but cannot be used as an input. +type G1 struct { + p *curvePoint +} + +// RandomG1 returns x and g₁ˣ where x is a random, non-zero number read from r. +func RandomG1(r io.Reader) (*big.Int, *G1, error) { + var k *big.Int + var err error + + for { + k, err = rand.Int(r, Order) + if err != nil { + return nil, nil, err + } + if k.Sign() > 0 { + break + } + } + + return k, new(G1).ScalarBaseMult(k), nil +} + +func (g *G1) String() string { + return "bn256.G1" + g.p.String() +} + +// CurvePoints returns p's curve points in big integer +func (e *G1) CurvePoints() (*big.Int, *big.Int, *big.Int, *big.Int) { + return e.p.x, e.p.y, e.p.z, e.p.t +} + +// ScalarBaseMult sets e to g*k where g is the generator of the group and +// then returns e. +func (e *G1) ScalarBaseMult(k *big.Int) *G1 { + if e.p == nil { + e.p = newCurvePoint(nil) + } + e.p.Mul(curveGen, k, new(bnPool)) + return e +} + +// ScalarMult sets e to a*k and then returns e. +func (e *G1) ScalarMult(a *G1, k *big.Int) *G1 { + if e.p == nil { + e.p = newCurvePoint(nil) + } + e.p.Mul(a.p, k, new(bnPool)) + return e +} + +// Add sets e to a+b and then returns e. +// BUG(agl): this function is not complete: a==b fails. +func (e *G1) Add(a, b *G1) *G1 { + if e.p == nil { + e.p = newCurvePoint(nil) + } + e.p.Add(a.p, b.p, new(bnPool)) + return e +} + +// Neg sets e to -a and then returns e. +func (e *G1) Neg(a *G1) *G1 { + if e.p == nil { + e.p = newCurvePoint(nil) + } + e.p.Negative(a.p) + return e +} + +// Marshal converts n to a byte slice. +func (n *G1) Marshal() []byte { + n.p.MakeAffine(nil) + + xBytes := new(big.Int).Mod(n.p.x, P).Bytes() + yBytes := new(big.Int).Mod(n.p.y, P).Bytes() + + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + ret := make([]byte, numBytes*2) + copy(ret[1*numBytes-len(xBytes):], xBytes) + copy(ret[2*numBytes-len(yBytes):], yBytes) + + return ret +} + +// Unmarshal sets e to the result of converting the output of Marshal back into +// a group element and then returns e. +func (e *G1) Unmarshal(m []byte) (*G1, bool) { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + if len(m) != 2*numBytes { + return nil, false + } + + if e.p == nil { + e.p = newCurvePoint(nil) + } + + e.p.x.SetBytes(m[0*numBytes : 1*numBytes]) + e.p.y.SetBytes(m[1*numBytes : 2*numBytes]) + + if e.p.x.Sign() == 0 && e.p.y.Sign() == 0 { + // This is the point at infinity. + e.p.y.SetInt64(1) + e.p.z.SetInt64(0) + e.p.t.SetInt64(0) + } else { + e.p.z.SetInt64(1) + e.p.t.SetInt64(1) + + if !e.p.IsOnCurve() { + return nil, false + } + } + + return e, true +} + +// G2 is an abstract cyclic group. The zero value is suitable for use as the +// output of an operation, but cannot be used as an input. +type G2 struct { + p *twistPoint +} + +// RandomG1 returns x and g₂ˣ where x is a random, non-zero number read from r. +func RandomG2(r io.Reader) (*big.Int, *G2, error) { + var k *big.Int + var err error + + for { + k, err = rand.Int(r, Order) + if err != nil { + return nil, nil, err + } + if k.Sign() > 0 { + break + } + } + + return k, new(G2).ScalarBaseMult(k), nil +} + +func (g *G2) String() string { + return "bn256.G2" + g.p.String() +} + +// CurvePoints returns the curve points of p which includes the real +// and imaginary parts of the curve point. +func (e *G2) CurvePoints() (*gfP2, *gfP2, *gfP2, *gfP2) { + return e.p.x, e.p.y, e.p.z, e.p.t +} + +// ScalarBaseMult sets e to g*k where g is the generator of the group and +// then returns out. +func (e *G2) ScalarBaseMult(k *big.Int) *G2 { + if e.p == nil { + e.p = newTwistPoint(nil) + } + e.p.Mul(twistGen, k, new(bnPool)) + return e +} + +// ScalarMult sets e to a*k and then returns e. +func (e *G2) ScalarMult(a *G2, k *big.Int) *G2 { + if e.p == nil { + e.p = newTwistPoint(nil) + } + e.p.Mul(a.p, k, new(bnPool)) + return e +} + +// Add sets e to a+b and then returns e. +// BUG(agl): this function is not complete: a==b fails. +func (e *G2) Add(a, b *G2) *G2 { + if e.p == nil { + e.p = newTwistPoint(nil) + } + e.p.Add(a.p, b.p, new(bnPool)) + return e +} + +// Marshal converts n into a byte slice. +func (n *G2) Marshal() []byte { + n.p.MakeAffine(nil) + + xxBytes := new(big.Int).Mod(n.p.x.x, P).Bytes() + xyBytes := new(big.Int).Mod(n.p.x.y, P).Bytes() + yxBytes := new(big.Int).Mod(n.p.y.x, P).Bytes() + yyBytes := new(big.Int).Mod(n.p.y.y, P).Bytes() + + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + ret := make([]byte, numBytes*4) + copy(ret[1*numBytes-len(xxBytes):], xxBytes) + copy(ret[2*numBytes-len(xyBytes):], xyBytes) + copy(ret[3*numBytes-len(yxBytes):], yxBytes) + copy(ret[4*numBytes-len(yyBytes):], yyBytes) + + return ret +} + +// Unmarshal sets e to the result of converting the output of Marshal back into +// a group element and then returns e. +func (e *G2) Unmarshal(m []byte) (*G2, bool) { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + if len(m) != 4*numBytes { + return nil, false + } + + if e.p == nil { + e.p = newTwistPoint(nil) + } + + e.p.x.x.SetBytes(m[0*numBytes : 1*numBytes]) + e.p.x.y.SetBytes(m[1*numBytes : 2*numBytes]) + e.p.y.x.SetBytes(m[2*numBytes : 3*numBytes]) + e.p.y.y.SetBytes(m[3*numBytes : 4*numBytes]) + + if e.p.x.x.Sign() == 0 && + e.p.x.y.Sign() == 0 && + e.p.y.x.Sign() == 0 && + e.p.y.y.Sign() == 0 { + // This is the point at infinity. + e.p.y.SetOne() + e.p.z.SetZero() + e.p.t.SetZero() + } else { + e.p.z.SetOne() + e.p.t.SetOne() + + if !e.p.IsOnCurve() { + return nil, false + } + } + + return e, true +} + +// GT is an abstract cyclic group. The zero value is suitable for use as the +// output of an operation, but cannot be used as an input. +type GT struct { + p *gfP12 +} + +func (g *GT) String() string { + return "bn256.GT" + g.p.String() +} + +// ScalarMult sets e to a*k and then returns e. +func (e *GT) ScalarMult(a *GT, k *big.Int) *GT { + if e.p == nil { + e.p = newGFp12(nil) + } + e.p.Exp(a.p, k, new(bnPool)) + return e +} + +// Add sets e to a+b and then returns e. +func (e *GT) Add(a, b *GT) *GT { + if e.p == nil { + e.p = newGFp12(nil) + } + e.p.Mul(a.p, b.p, new(bnPool)) + return e +} + +// Neg sets e to -a and then returns e. +func (e *GT) Neg(a *GT) *GT { + if e.p == nil { + e.p = newGFp12(nil) + } + e.p.Invert(a.p, new(bnPool)) + return e +} + +// Marshal converts n into a byte slice. +func (n *GT) Marshal() []byte { + n.p.Minimal() + + xxxBytes := n.p.x.x.x.Bytes() + xxyBytes := n.p.x.x.y.Bytes() + xyxBytes := n.p.x.y.x.Bytes() + xyyBytes := n.p.x.y.y.Bytes() + xzxBytes := n.p.x.z.x.Bytes() + xzyBytes := n.p.x.z.y.Bytes() + yxxBytes := n.p.y.x.x.Bytes() + yxyBytes := n.p.y.x.y.Bytes() + yyxBytes := n.p.y.y.x.Bytes() + yyyBytes := n.p.y.y.y.Bytes() + yzxBytes := n.p.y.z.x.Bytes() + yzyBytes := n.p.y.z.y.Bytes() + + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + ret := make([]byte, numBytes*12) + copy(ret[1*numBytes-len(xxxBytes):], xxxBytes) + copy(ret[2*numBytes-len(xxyBytes):], xxyBytes) + copy(ret[3*numBytes-len(xyxBytes):], xyxBytes) + copy(ret[4*numBytes-len(xyyBytes):], xyyBytes) + copy(ret[5*numBytes-len(xzxBytes):], xzxBytes) + copy(ret[6*numBytes-len(xzyBytes):], xzyBytes) + copy(ret[7*numBytes-len(yxxBytes):], yxxBytes) + copy(ret[8*numBytes-len(yxyBytes):], yxyBytes) + copy(ret[9*numBytes-len(yyxBytes):], yyxBytes) + copy(ret[10*numBytes-len(yyyBytes):], yyyBytes) + copy(ret[11*numBytes-len(yzxBytes):], yzxBytes) + copy(ret[12*numBytes-len(yzyBytes):], yzyBytes) + + return ret +} + +// Unmarshal sets e to the result of converting the output of Marshal back into +// a group element and then returns e. +func (e *GT) Unmarshal(m []byte) (*GT, bool) { + // Each value is a 256-bit number. + const numBytes = 256 / 8 + + if len(m) != 12*numBytes { + return nil, false + } + + if e.p == nil { + e.p = newGFp12(nil) + } + + e.p.x.x.x.SetBytes(m[0*numBytes : 1*numBytes]) + e.p.x.x.y.SetBytes(m[1*numBytes : 2*numBytes]) + e.p.x.y.x.SetBytes(m[2*numBytes : 3*numBytes]) + e.p.x.y.y.SetBytes(m[3*numBytes : 4*numBytes]) + e.p.x.z.x.SetBytes(m[4*numBytes : 5*numBytes]) + e.p.x.z.y.SetBytes(m[5*numBytes : 6*numBytes]) + e.p.y.x.x.SetBytes(m[6*numBytes : 7*numBytes]) + e.p.y.x.y.SetBytes(m[7*numBytes : 8*numBytes]) + e.p.y.y.x.SetBytes(m[8*numBytes : 9*numBytes]) + e.p.y.y.y.SetBytes(m[9*numBytes : 10*numBytes]) + e.p.y.z.x.SetBytes(m[10*numBytes : 11*numBytes]) + e.p.y.z.y.SetBytes(m[11*numBytes : 12*numBytes]) + + return e, true +} + +// Pair calculates an Optimal Ate pairing. +func Pair(g1 *G1, g2 *G2) *GT { + return >{optimalAte(g2.p, g1.p, new(bnPool))} +} + +func PairingCheck(a []*G1, b []*G2) bool { + pool := new(bnPool) + e := newGFp12(pool) + e.SetOne() + for i := 0; i < len(a); i++ { + new_e := miller(b[i].p, a[i].p, pool) + e.Mul(e, new_e, pool) + } + ret := finalExponentiation(e, pool) + e.Put(pool) + return ret.IsOne() +} + +// bnPool implements a tiny cache of *big.Int objects that's used to reduce the +// number of allocations made during processing. +type bnPool struct { + bns []*big.Int + count int +} + +func (pool *bnPool) Get() *big.Int { + if pool == nil { + return new(big.Int) + } + + pool.count++ + l := len(pool.bns) + if l == 0 { + return new(big.Int) + } + + bn := pool.bns[l-1] + pool.bns = pool.bns[:l-1] + return bn +} + +func (pool *bnPool) Put(bn *big.Int) { + if pool == nil { + return + } + pool.bns = append(pool.bns, bn) + pool.count-- +} + +func (pool *bnPool) Count() int { + return pool.count +} diff --git a/crypto/bn256/bn256_test.go b/crypto/bn256/bn256_test.go new file mode 100644 index 0000000000..866065d0ca --- /dev/null +++ b/crypto/bn256/bn256_test.go @@ -0,0 +1,304 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bn256 + +import ( + "bytes" + "crypto/rand" + "math/big" + "testing" +) + +func TestGFp2Invert(t *testing.T) { + pool := new(bnPool) + + a := newGFp2(pool) + a.x.SetString("23423492374", 10) + a.y.SetString("12934872398472394827398470", 10) + + inv := newGFp2(pool) + inv.Invert(a, pool) + + b := newGFp2(pool).Mul(inv, a, pool) + if b.x.Int64() != 0 || b.y.Int64() != 1 { + t.Fatalf("bad result for a^-1*a: %s %s", b.x, b.y) + } + + a.Put(pool) + b.Put(pool) + inv.Put(pool) + + if c := pool.Count(); c > 0 { + t.Errorf("Pool count non-zero: %d\n", c) + } +} + +func isZero(n *big.Int) bool { + return new(big.Int).Mod(n, P).Int64() == 0 +} + +func isOne(n *big.Int) bool { + return new(big.Int).Mod(n, P).Int64() == 1 +} + +func TestGFp6Invert(t *testing.T) { + pool := new(bnPool) + + a := newGFp6(pool) + a.x.x.SetString("239487238491", 10) + a.x.y.SetString("2356249827341", 10) + a.y.x.SetString("082659782", 10) + a.y.y.SetString("182703523765", 10) + a.z.x.SetString("978236549263", 10) + a.z.y.SetString("64893242", 10) + + inv := newGFp6(pool) + inv.Invert(a, pool) + + b := newGFp6(pool).Mul(inv, a, pool) + if !isZero(b.x.x) || + !isZero(b.x.y) || + !isZero(b.y.x) || + !isZero(b.y.y) || + !isZero(b.z.x) || + !isOne(b.z.y) { + t.Fatalf("bad result for a^-1*a: %s", b) + } + + a.Put(pool) + b.Put(pool) + inv.Put(pool) + + if c := pool.Count(); c > 0 { + t.Errorf("Pool count non-zero: %d\n", c) + } +} + +func TestGFp12Invert(t *testing.T) { + pool := new(bnPool) + + a := newGFp12(pool) + a.x.x.x.SetString("239846234862342323958623", 10) + a.x.x.y.SetString("2359862352529835623", 10) + a.x.y.x.SetString("928836523", 10) + a.x.y.y.SetString("9856234", 10) + a.x.z.x.SetString("235635286", 10) + a.x.z.y.SetString("5628392833", 10) + a.y.x.x.SetString("252936598265329856238956532167968", 10) + a.y.x.y.SetString("23596239865236954178968", 10) + a.y.y.x.SetString("95421692834", 10) + a.y.y.y.SetString("236548", 10) + a.y.z.x.SetString("924523", 10) + a.y.z.y.SetString("12954623", 10) + + inv := newGFp12(pool) + inv.Invert(a, pool) + + b := newGFp12(pool).Mul(inv, a, pool) + if !isZero(b.x.x.x) || + !isZero(b.x.x.y) || + !isZero(b.x.y.x) || + !isZero(b.x.y.y) || + !isZero(b.x.z.x) || + !isZero(b.x.z.y) || + !isZero(b.y.x.x) || + !isZero(b.y.x.y) || + !isZero(b.y.y.x) || + !isZero(b.y.y.y) || + !isZero(b.y.z.x) || + !isOne(b.y.z.y) { + t.Fatalf("bad result for a^-1*a: %s", b) + } + + a.Put(pool) + b.Put(pool) + inv.Put(pool) + + if c := pool.Count(); c > 0 { + t.Errorf("Pool count non-zero: %d\n", c) + } +} + +func TestCurveImpl(t *testing.T) { + pool := new(bnPool) + + g := &curvePoint{ + pool.Get().SetInt64(1), + pool.Get().SetInt64(-2), + pool.Get().SetInt64(1), + pool.Get().SetInt64(0), + } + + x := pool.Get().SetInt64(32498273234) + X := newCurvePoint(pool).Mul(g, x, pool) + + y := pool.Get().SetInt64(98732423523) + Y := newCurvePoint(pool).Mul(g, y, pool) + + s1 := newCurvePoint(pool).Mul(X, y, pool).MakeAffine(pool) + s2 := newCurvePoint(pool).Mul(Y, x, pool).MakeAffine(pool) + + if s1.x.Cmp(s2.x) != 0 || + s2.x.Cmp(s1.x) != 0 { + t.Errorf("DH points don't match: (%s, %s) (%s, %s)", s1.x, s1.y, s2.x, s2.y) + } + + pool.Put(x) + X.Put(pool) + pool.Put(y) + Y.Put(pool) + s1.Put(pool) + s2.Put(pool) + g.Put(pool) + + if c := pool.Count(); c > 0 { + t.Errorf("Pool count non-zero: %d\n", c) + } +} + +func TestOrderG1(t *testing.T) { + g := new(G1).ScalarBaseMult(Order) + if !g.p.IsInfinity() { + t.Error("G1 has incorrect order") + } + + one := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1)) + g.Add(g, one) + g.p.MakeAffine(nil) + if g.p.x.Cmp(one.p.x) != 0 || g.p.y.Cmp(one.p.y) != 0 { + t.Errorf("1+0 != 1 in G1") + } +} + +func TestOrderG2(t *testing.T) { + g := new(G2).ScalarBaseMult(Order) + if !g.p.IsInfinity() { + t.Error("G2 has incorrect order") + } + + one := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1)) + g.Add(g, one) + g.p.MakeAffine(nil) + if g.p.x.x.Cmp(one.p.x.x) != 0 || + g.p.x.y.Cmp(one.p.x.y) != 0 || + g.p.y.x.Cmp(one.p.y.x) != 0 || + g.p.y.y.Cmp(one.p.y.y) != 0 { + t.Errorf("1+0 != 1 in G2") + } +} + +func TestOrderGT(t *testing.T) { + gt := Pair(&G1{curveGen}, &G2{twistGen}) + g := new(GT).ScalarMult(gt, Order) + if !g.p.IsOne() { + t.Error("GT has incorrect order") + } +} + +func TestBilinearity(t *testing.T) { + for i := 0; i < 2; i++ { + a, p1, _ := RandomG1(rand.Reader) + b, p2, _ := RandomG2(rand.Reader) + e1 := Pair(p1, p2) + + e2 := Pair(&G1{curveGen}, &G2{twistGen}) + e2.ScalarMult(e2, a) + e2.ScalarMult(e2, b) + + minusE2 := new(GT).Neg(e2) + e1.Add(e1, minusE2) + + if !e1.p.IsOne() { + t.Fatalf("bad pairing result: %s", e1) + } + } +} + +func TestG1Marshal(t *testing.T) { + g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(1)) + form := g.Marshal() + _, ok := new(G1).Unmarshal(form) + if !ok { + t.Fatalf("failed to unmarshal") + } + + g.ScalarBaseMult(Order) + form = g.Marshal() + g2, ok := new(G1).Unmarshal(form) + if !ok { + t.Fatalf("failed to unmarshal ∞") + } + if !g2.p.IsInfinity() { + t.Fatalf("∞ unmarshaled incorrectly") + } +} + +func TestG2Marshal(t *testing.T) { + g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(1)) + form := g.Marshal() + _, ok := new(G2).Unmarshal(form) + if !ok { + t.Fatalf("failed to unmarshal") + } + + g.ScalarBaseMult(Order) + form = g.Marshal() + g2, ok := new(G2).Unmarshal(form) + if !ok { + t.Fatalf("failed to unmarshal ∞") + } + if !g2.p.IsInfinity() { + t.Fatalf("∞ unmarshaled incorrectly") + } +} + +func TestG1Identity(t *testing.T) { + g := new(G1).ScalarBaseMult(new(big.Int).SetInt64(0)) + if !g.p.IsInfinity() { + t.Error("failure") + } +} + +func TestG2Identity(t *testing.T) { + g := new(G2).ScalarBaseMult(new(big.Int).SetInt64(0)) + if !g.p.IsInfinity() { + t.Error("failure") + } +} + +func TestTripartiteDiffieHellman(t *testing.T) { + a, _ := rand.Int(rand.Reader, Order) + b, _ := rand.Int(rand.Reader, Order) + c, _ := rand.Int(rand.Reader, Order) + + pa, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(a).Marshal()) + qa, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(a).Marshal()) + pb, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(b).Marshal()) + qb, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(b).Marshal()) + pc, _ := new(G1).Unmarshal(new(G1).ScalarBaseMult(c).Marshal()) + qc, _ := new(G2).Unmarshal(new(G2).ScalarBaseMult(c).Marshal()) + + k1 := Pair(pb, qc) + k1.ScalarMult(k1, a) + k1Bytes := k1.Marshal() + + k2 := Pair(pc, qa) + k2.ScalarMult(k2, b) + k2Bytes := k2.Marshal() + + k3 := Pair(pa, qb) + k3.ScalarMult(k3, c) + k3Bytes := k3.Marshal() + + if !bytes.Equal(k1Bytes, k2Bytes) || !bytes.Equal(k2Bytes, k3Bytes) { + t.Errorf("keys didn't agree") + } +} + +func BenchmarkPairing(b *testing.B) { + for i := 0; i < b.N; i++ { + Pair(&G1{curveGen}, &G2{twistGen}) + } +} diff --git a/crypto/bn256/constants.go b/crypto/bn256/constants.go new file mode 100644 index 0000000000..ab649d7f3f --- /dev/null +++ b/crypto/bn256/constants.go @@ -0,0 +1,44 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bn256 + +import ( + "math/big" +) + +func bigFromBase10(s string) *big.Int { + n, _ := new(big.Int).SetString(s, 10) + return n +} + +// u is the BN parameter that determines the prime: 1868033³. +var u = bigFromBase10("4965661367192848881") + +// p is a prime over which we form a basic field: 36u⁴+36u³+24u²+6u+1. +var P = bigFromBase10("21888242871839275222246405745257275088696311157297823662689037894645226208583") + +// Order is the number of elements in both G₁ and G₂: 36u⁴+36u³+18u²+6u+1. +var Order = bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617") + +// xiToPMinus1Over6 is ξ^((p-1)/6) where ξ = i+9. +var xiToPMinus1Over6 = &gfP2{bigFromBase10("16469823323077808223889137241176536799009286646108169935659301613961712198316"), bigFromBase10("8376118865763821496583973867626364092589906065868298776909617916018768340080")} + +// xiToPMinus1Over3 is ξ^((p-1)/3) where ξ = i+9. +var xiToPMinus1Over3 = &gfP2{bigFromBase10("10307601595873709700152284273816112264069230130616436755625194854815875713954"), bigFromBase10("21575463638280843010398324269430826099269044274347216827212613867836435027261")} + +// xiToPMinus1Over2 is ξ^((p-1)/2) where ξ = i+9. +var xiToPMinus1Over2 = &gfP2{bigFromBase10("3505843767911556378687030309984248845540243509899259641013678093033130930403"), bigFromBase10("2821565182194536844548159561693502659359617185244120367078079554186484126554")} + +// xiToPSquaredMinus1Over3 is ξ^((p²-1)/3) where ξ = i+9. +var xiToPSquaredMinus1Over3 = bigFromBase10("21888242871839275220042445260109153167277707414472061641714758635765020556616") + +// xiTo2PSquaredMinus2Over3 is ξ^((2p²-2)/3) where ξ = i+9 (a cubic root of unity, mod p). +var xiTo2PSquaredMinus2Over3 = bigFromBase10("2203960485148121921418603742825762020974279258880205651966") + +// xiToPSquaredMinus1Over6 is ξ^((1p²-1)/6) where ξ = i+9 (a cubic root of -1, mod p). +var xiToPSquaredMinus1Over6 = bigFromBase10("21888242871839275220042445260109153167277707414472061641714758635765020556617") + +// xiTo2PMinus2Over3 is ξ^((2p-2)/3) where ξ = i+9. +var xiTo2PMinus2Over3 = &gfP2{bigFromBase10("19937756971775647987995932169929341994314640652964949448313374472400716661030"), bigFromBase10("2581911344467009335267311115468803099551665605076196740867805258568234346338")} diff --git a/crypto/bn256/curve.go b/crypto/bn256/curve.go new file mode 100644 index 0000000000..93f858def7 --- /dev/null +++ b/crypto/bn256/curve.go @@ -0,0 +1,278 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bn256 + +import ( + "math/big" +) + +// curvePoint implements the elliptic curve y²=x³+3. Points are kept in +// Jacobian form and t=z² when valid. G₁ is the set of points of this curve on +// GF(p). +type curvePoint struct { + x, y, z, t *big.Int +} + +var curveB = new(big.Int).SetInt64(3) + +// curveGen is the generator of G₁. +var curveGen = &curvePoint{ + new(big.Int).SetInt64(1), + new(big.Int).SetInt64(-2), + new(big.Int).SetInt64(1), + new(big.Int).SetInt64(1), +} + +func newCurvePoint(pool *bnPool) *curvePoint { + return &curvePoint{ + pool.Get(), + pool.Get(), + pool.Get(), + pool.Get(), + } +} + +func (c *curvePoint) String() string { + c.MakeAffine(new(bnPool)) + return "(" + c.x.String() + ", " + c.y.String() + ")" +} + +func (c *curvePoint) Put(pool *bnPool) { + pool.Put(c.x) + pool.Put(c.y) + pool.Put(c.z) + pool.Put(c.t) +} + +func (c *curvePoint) Set(a *curvePoint) { + c.x.Set(a.x) + c.y.Set(a.y) + c.z.Set(a.z) + c.t.Set(a.t) +} + +// IsOnCurve returns true iff c is on the curve where c must be in affine form. +func (c *curvePoint) IsOnCurve() bool { + yy := new(big.Int).Mul(c.y, c.y) + xxx := new(big.Int).Mul(c.x, c.x) + xxx.Mul(xxx, c.x) + yy.Sub(yy, xxx) + yy.Sub(yy, curveB) + if yy.Sign() < 0 || yy.Cmp(P) >= 0 { + yy.Mod(yy, P) + } + return yy.Sign() == 0 +} + +func (c *curvePoint) SetInfinity() { + c.z.SetInt64(0) +} + +func (c *curvePoint) IsInfinity() bool { + return c.z.Sign() == 0 +} + +func (c *curvePoint) Add(a, b *curvePoint, pool *bnPool) { + if a.IsInfinity() { + c.Set(b) + return + } + if b.IsInfinity() { + c.Set(a) + return + } + + // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 + + // Normalize the points by replacing a = [x1:y1:z1] and b = [x2:y2:z2] + // by [u1:s1:z1·z2] and [u2:s2:z1·z2] + // where u1 = x1·z2², s1 = y1·z2³ and u1 = x2·z1², s2 = y2·z1³ + z1z1 := pool.Get().Mul(a.z, a.z) + z1z1.Mod(z1z1, P) + z2z2 := pool.Get().Mul(b.z, b.z) + z2z2.Mod(z2z2, P) + u1 := pool.Get().Mul(a.x, z2z2) + u1.Mod(u1, P) + u2 := pool.Get().Mul(b.x, z1z1) + u2.Mod(u2, P) + + t := pool.Get().Mul(b.z, z2z2) + t.Mod(t, P) + s1 := pool.Get().Mul(a.y, t) + s1.Mod(s1, P) + + t.Mul(a.z, z1z1) + t.Mod(t, P) + s2 := pool.Get().Mul(b.y, t) + s2.Mod(s2, P) + + // Compute x = (2h)²(s²-u1-u2) + // where s = (s2-s1)/(u2-u1) is the slope of the line through + // (u1,s1) and (u2,s2). The extra factor 2h = 2(u2-u1) comes from the value of z below. + // This is also: + // 4(s2-s1)² - 4h²(u1+u2) = 4(s2-s1)² - 4h³ - 4h²(2u1) + // = r² - j - 2v + // with the notations below. + h := pool.Get().Sub(u2, u1) + xEqual := h.Sign() == 0 + + t.Add(h, h) + // i = 4h² + i := pool.Get().Mul(t, t) + i.Mod(i, P) + // j = 4h³ + j := pool.Get().Mul(h, i) + j.Mod(j, P) + + t.Sub(s2, s1) + yEqual := t.Sign() == 0 + if xEqual && yEqual { + c.Double(a, pool) + return + } + r := pool.Get().Add(t, t) + + v := pool.Get().Mul(u1, i) + v.Mod(v, P) + + // t4 = 4(s2-s1)² + t4 := pool.Get().Mul(r, r) + t4.Mod(t4, P) + t.Add(v, v) + t6 := pool.Get().Sub(t4, j) + c.x.Sub(t6, t) + + // Set y = -(2h)³(s1 + s*(x/4h²-u1)) + // This is also + // y = - 2·s1·j - (s2-s1)(2x - 2i·u1) = r(v-x) - 2·s1·j + t.Sub(v, c.x) // t7 + t4.Mul(s1, j) // t8 + t4.Mod(t4, P) + t6.Add(t4, t4) // t9 + t4.Mul(r, t) // t10 + t4.Mod(t4, P) + c.y.Sub(t4, t6) + + // Set z = 2(u2-u1)·z1·z2 = 2h·z1·z2 + t.Add(a.z, b.z) // t11 + t4.Mul(t, t) // t12 + t4.Mod(t4, P) + t.Sub(t4, z1z1) // t13 + t4.Sub(t, z2z2) // t14 + c.z.Mul(t4, h) + c.z.Mod(c.z, P) + + pool.Put(z1z1) + pool.Put(z2z2) + pool.Put(u1) + pool.Put(u2) + pool.Put(t) + pool.Put(s1) + pool.Put(s2) + pool.Put(h) + pool.Put(i) + pool.Put(j) + pool.Put(r) + pool.Put(v) + pool.Put(t4) + pool.Put(t6) +} + +func (c *curvePoint) Double(a *curvePoint, pool *bnPool) { + // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 + A := pool.Get().Mul(a.x, a.x) + A.Mod(A, P) + B := pool.Get().Mul(a.y, a.y) + B.Mod(B, P) + C := pool.Get().Mul(B, B) + C.Mod(C, P) + + t := pool.Get().Add(a.x, B) + t2 := pool.Get().Mul(t, t) + t2.Mod(t2, P) + t.Sub(t2, A) + t2.Sub(t, C) + d := pool.Get().Add(t2, t2) + t.Add(A, A) + e := pool.Get().Add(t, A) + f := pool.Get().Mul(e, e) + f.Mod(f, P) + + t.Add(d, d) + c.x.Sub(f, t) + + t.Add(C, C) + t2.Add(t, t) + t.Add(t2, t2) + c.y.Sub(d, c.x) + t2.Mul(e, c.y) + t2.Mod(t2, P) + c.y.Sub(t2, t) + + t.Mul(a.y, a.z) + t.Mod(t, P) + c.z.Add(t, t) + + pool.Put(A) + pool.Put(B) + pool.Put(C) + pool.Put(t) + pool.Put(t2) + pool.Put(d) + pool.Put(e) + pool.Put(f) +} + +func (c *curvePoint) Mul(a *curvePoint, scalar *big.Int, pool *bnPool) *curvePoint { + sum := newCurvePoint(pool) + sum.SetInfinity() + t := newCurvePoint(pool) + + for i := scalar.BitLen(); i >= 0; i-- { + t.Double(sum, pool) + if scalar.Bit(i) != 0 { + sum.Add(t, a, pool) + } else { + sum.Set(t) + } + } + + c.Set(sum) + sum.Put(pool) + t.Put(pool) + return c +} + +func (c *curvePoint) MakeAffine(pool *bnPool) *curvePoint { + if words := c.z.Bits(); len(words) == 1 && words[0] == 1 { + return c + } + + zInv := pool.Get().ModInverse(c.z, P) + t := pool.Get().Mul(c.y, zInv) + t.Mod(t, P) + zInv2 := pool.Get().Mul(zInv, zInv) + zInv2.Mod(zInv2, P) + c.y.Mul(t, zInv2) + c.y.Mod(c.y, P) + t.Mul(c.x, zInv2) + t.Mod(t, P) + c.x.Set(t) + c.z.SetInt64(1) + c.t.SetInt64(1) + + pool.Put(zInv) + pool.Put(t) + pool.Put(zInv2) + + return c +} + +func (c *curvePoint) Negative(a *curvePoint) { + c.x.Set(a.x) + c.y.Neg(a.y) + c.z.Set(a.z) + c.t.SetInt64(0) +} diff --git a/crypto/bn256/example_test.go b/crypto/bn256/example_test.go new file mode 100644 index 0000000000..b2d19807a2 --- /dev/null +++ b/crypto/bn256/example_test.go @@ -0,0 +1,43 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bn256 + +import ( + "crypto/rand" +) + +func ExamplePair() { + // This implements the tripartite Diffie-Hellman algorithm from "A One + // Round Protocol for Tripartite Diffie-Hellman", A. Joux. + // http://www.springerlink.com/content/cddc57yyva0hburb/fulltext.pdf + + // Each of three parties, a, b and c, generate a private value. + a, _ := rand.Int(rand.Reader, Order) + b, _ := rand.Int(rand.Reader, Order) + c, _ := rand.Int(rand.Reader, Order) + + // Then each party calculates g₁ and g₂ times their private value. + pa := new(G1).ScalarBaseMult(a) + qa := new(G2).ScalarBaseMult(a) + + pb := new(G1).ScalarBaseMult(b) + qb := new(G2).ScalarBaseMult(b) + + pc := new(G1).ScalarBaseMult(c) + qc := new(G2).ScalarBaseMult(c) + + // Now each party exchanges its public values with the other two and + // all parties can calculate the shared key. + k1 := Pair(pb, qc) + k1.ScalarMult(k1, a) + + k2 := Pair(pc, qa) + k2.ScalarMult(k2, b) + + k3 := Pair(pa, qb) + k3.ScalarMult(k3, c) + + // k1, k2 and k3 will all be equal. +} diff --git a/crypto/bn256/gfp12.go b/crypto/bn256/gfp12.go new file mode 100644 index 0000000000..f084eddf21 --- /dev/null +++ b/crypto/bn256/gfp12.go @@ -0,0 +1,200 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bn256 + +// For details of the algorithms used, see "Multiplication and Squaring on +// Pairing-Friendly Fields, Devegili et al. +// http://eprint.iacr.org/2006/471.pdf. + +import ( + "math/big" +) + +// gfP12 implements the field of size p¹² as a quadratic extension of gfP6 +// where ω²=τ. +type gfP12 struct { + x, y *gfP6 // value is xω + y +} + +func newGFp12(pool *bnPool) *gfP12 { + return &gfP12{newGFp6(pool), newGFp6(pool)} +} + +func (e *gfP12) String() string { + return "(" + e.x.String() + "," + e.y.String() + ")" +} + +func (e *gfP12) Put(pool *bnPool) { + e.x.Put(pool) + e.y.Put(pool) +} + +func (e *gfP12) Set(a *gfP12) *gfP12 { + e.x.Set(a.x) + e.y.Set(a.y) + return e +} + +func (e *gfP12) SetZero() *gfP12 { + e.x.SetZero() + e.y.SetZero() + return e +} + +func (e *gfP12) SetOne() *gfP12 { + e.x.SetZero() + e.y.SetOne() + return e +} + +func (e *gfP12) Minimal() { + e.x.Minimal() + e.y.Minimal() +} + +func (e *gfP12) IsZero() bool { + e.Minimal() + return e.x.IsZero() && e.y.IsZero() +} + +func (e *gfP12) IsOne() bool { + e.Minimal() + return e.x.IsZero() && e.y.IsOne() +} + +func (e *gfP12) Conjugate(a *gfP12) *gfP12 { + e.x.Negative(a.x) + e.y.Set(a.y) + return a +} + +func (e *gfP12) Negative(a *gfP12) *gfP12 { + e.x.Negative(a.x) + e.y.Negative(a.y) + return e +} + +// Frobenius computes (xω+y)^p = x^p ω·ξ^((p-1)/6) + y^p +func (e *gfP12) Frobenius(a *gfP12, pool *bnPool) *gfP12 { + e.x.Frobenius(a.x, pool) + e.y.Frobenius(a.y, pool) + e.x.MulScalar(e.x, xiToPMinus1Over6, pool) + return e +} + +// FrobeniusP2 computes (xω+y)^p² = x^p² ω·ξ^((p²-1)/6) + y^p² +func (e *gfP12) FrobeniusP2(a *gfP12, pool *bnPool) *gfP12 { + e.x.FrobeniusP2(a.x) + e.x.MulGFP(e.x, xiToPSquaredMinus1Over6) + e.y.FrobeniusP2(a.y) + return e +} + +func (e *gfP12) Add(a, b *gfP12) *gfP12 { + e.x.Add(a.x, b.x) + e.y.Add(a.y, b.y) + return e +} + +func (e *gfP12) Sub(a, b *gfP12) *gfP12 { + e.x.Sub(a.x, b.x) + e.y.Sub(a.y, b.y) + return e +} + +func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 { + tx := newGFp6(pool) + tx.Mul(a.x, b.y, pool) + t := newGFp6(pool) + t.Mul(b.x, a.y, pool) + tx.Add(tx, t) + + ty := newGFp6(pool) + ty.Mul(a.y, b.y, pool) + t.Mul(a.x, b.x, pool) + t.MulTau(t, pool) + e.y.Add(ty, t) + e.x.Set(tx) + + tx.Put(pool) + ty.Put(pool) + t.Put(pool) + return e +} + +func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 { + e.x.Mul(e.x, b, pool) + e.y.Mul(e.y, b, pool) + return e +} + +func (c *gfP12) Exp(a *gfP12, power *big.Int, pool *bnPool) *gfP12 { + sum := newGFp12(pool) + sum.SetOne() + t := newGFp12(pool) + + for i := power.BitLen() - 1; i >= 0; i-- { + t.Square(sum, pool) + if power.Bit(i) != 0 { + sum.Mul(t, a, pool) + } else { + sum.Set(t) + } + } + + c.Set(sum) + + sum.Put(pool) + t.Put(pool) + + return c +} + +func (e *gfP12) Square(a *gfP12, pool *bnPool) *gfP12 { + // Complex squaring algorithm + v0 := newGFp6(pool) + v0.Mul(a.x, a.y, pool) + + t := newGFp6(pool) + t.MulTau(a.x, pool) + t.Add(a.y, t) + ty := newGFp6(pool) + ty.Add(a.x, a.y) + ty.Mul(ty, t, pool) + ty.Sub(ty, v0) + t.MulTau(v0, pool) + ty.Sub(ty, t) + + e.y.Set(ty) + e.x.Double(v0) + + v0.Put(pool) + t.Put(pool) + ty.Put(pool) + + return e +} + +func (e *gfP12) Invert(a *gfP12, pool *bnPool) *gfP12 { + // See "Implementing cryptographic pairings", M. Scott, section 3.2. + // ftp://136.206.11.249/pub/crypto/pairings.pdf + t1 := newGFp6(pool) + t2 := newGFp6(pool) + + t1.Square(a.x, pool) + t2.Square(a.y, pool) + t1.MulTau(t1, pool) + t1.Sub(t2, t1) + t2.Invert(t1, pool) + + e.x.Negative(a.x) + e.y.Set(a.y) + e.MulScalar(e, t2, pool) + + t1.Put(pool) + t2.Put(pool) + + return e +} diff --git a/crypto/bn256/gfp2.go b/crypto/bn256/gfp2.go new file mode 100644 index 0000000000..3981f6cb4f --- /dev/null +++ b/crypto/bn256/gfp2.go @@ -0,0 +1,227 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bn256 + +// For details of the algorithms used, see "Multiplication and Squaring on +// Pairing-Friendly Fields, Devegili et al. +// http://eprint.iacr.org/2006/471.pdf. + +import ( + "math/big" +) + +// gfP2 implements a field of size p² as a quadratic extension of the base +// field where i²=-1. +type gfP2 struct { + x, y *big.Int // value is xi+y. +} + +func newGFp2(pool *bnPool) *gfP2 { + return &gfP2{pool.Get(), pool.Get()} +} + +func (e *gfP2) String() string { + x := new(big.Int).Mod(e.x, P) + y := new(big.Int).Mod(e.y, P) + return "(" + x.String() + "," + y.String() + ")" +} + +func (e *gfP2) Put(pool *bnPool) { + pool.Put(e.x) + pool.Put(e.y) +} + +func (e *gfP2) Set(a *gfP2) *gfP2 { + e.x.Set(a.x) + e.y.Set(a.y) + return e +} + +func (e *gfP2) SetZero() *gfP2 { + e.x.SetInt64(0) + e.y.SetInt64(0) + return e +} + +func (e *gfP2) SetOne() *gfP2 { + e.x.SetInt64(0) + e.y.SetInt64(1) + return e +} + +func (e *gfP2) Minimal() { + if e.x.Sign() < 0 || e.x.Cmp(P) >= 0 { + e.x.Mod(e.x, P) + } + if e.y.Sign() < 0 || e.y.Cmp(P) >= 0 { + e.y.Mod(e.y, P) + } +} + +func (e *gfP2) IsZero() bool { + return e.x.Sign() == 0 && e.y.Sign() == 0 +} + +func (e *gfP2) IsOne() bool { + if e.x.Sign() != 0 { + return false + } + words := e.y.Bits() + return len(words) == 1 && words[0] == 1 +} + +func (e *gfP2) Conjugate(a *gfP2) *gfP2 { + e.y.Set(a.y) + e.x.Neg(a.x) + return e +} + +func (e *gfP2) Negative(a *gfP2) *gfP2 { + e.x.Neg(a.x) + e.y.Neg(a.y) + return e +} + +func (e *gfP2) Add(a, b *gfP2) *gfP2 { + e.x.Add(a.x, b.x) + e.y.Add(a.y, b.y) + return e +} + +func (e *gfP2) Sub(a, b *gfP2) *gfP2 { + e.x.Sub(a.x, b.x) + e.y.Sub(a.y, b.y) + return e +} + +func (e *gfP2) Double(a *gfP2) *gfP2 { + e.x.Lsh(a.x, 1) + e.y.Lsh(a.y, 1) + return e +} + +func (c *gfP2) Exp(a *gfP2, power *big.Int, pool *bnPool) *gfP2 { + sum := newGFp2(pool) + sum.SetOne() + t := newGFp2(pool) + + for i := power.BitLen() - 1; i >= 0; i-- { + t.Square(sum, pool) + if power.Bit(i) != 0 { + sum.Mul(t, a, pool) + } else { + sum.Set(t) + } + } + + c.Set(sum) + + sum.Put(pool) + t.Put(pool) + + return c +} + +// See "Multiplication and Squaring in Pairing-Friendly Fields", +// http://eprint.iacr.org/2006/471.pdf +func (e *gfP2) Mul(a, b *gfP2, pool *bnPool) *gfP2 { + tx := pool.Get().Mul(a.x, b.y) + t := pool.Get().Mul(b.x, a.y) + tx.Add(tx, t) + tx.Mod(tx, P) + + ty := pool.Get().Mul(a.y, b.y) + t.Mul(a.x, b.x) + ty.Sub(ty, t) + e.y.Mod(ty, P) + e.x.Set(tx) + + pool.Put(tx) + pool.Put(ty) + pool.Put(t) + + return e +} + +func (e *gfP2) MulScalar(a *gfP2, b *big.Int) *gfP2 { + e.x.Mul(a.x, b) + e.y.Mul(a.y, b) + return e +} + +// MulXi sets e=ξa where ξ=i+9 and then returns e. +func (e *gfP2) MulXi(a *gfP2, pool *bnPool) *gfP2 { + // (xi+y)(i+3) = (9x+y)i+(9y-x) + tx := pool.Get().Lsh(a.x, 3) + tx.Add(tx, a.x) + tx.Add(tx, a.y) + + ty := pool.Get().Lsh(a.y, 3) + ty.Add(ty, a.y) + ty.Sub(ty, a.x) + + e.x.Set(tx) + e.y.Set(ty) + + pool.Put(tx) + pool.Put(ty) + + return e +} + +func (e *gfP2) Square(a *gfP2, pool *bnPool) *gfP2 { + // Complex squaring algorithm: + // (xi+b)² = (x+y)(y-x) + 2*i*x*y + t1 := pool.Get().Sub(a.y, a.x) + t2 := pool.Get().Add(a.x, a.y) + ty := pool.Get().Mul(t1, t2) + ty.Mod(ty, P) + + t1.Mul(a.x, a.y) + t1.Lsh(t1, 1) + + e.x.Mod(t1, P) + e.y.Set(ty) + + pool.Put(t1) + pool.Put(t2) + pool.Put(ty) + + return e +} + +func (e *gfP2) Invert(a *gfP2, pool *bnPool) *gfP2 { + // See "Implementing cryptographic pairings", M. Scott, section 3.2. + // ftp://136.206.11.249/pub/crypto/pairings.pdf + t := pool.Get() + t.Mul(a.y, a.y) + t2 := pool.Get() + t2.Mul(a.x, a.x) + t.Add(t, t2) + + inv := pool.Get() + inv.ModInverse(t, P) + + e.x.Neg(a.x) + e.x.Mul(e.x, inv) + e.x.Mod(e.x, P) + + e.y.Mul(a.y, inv) + e.y.Mod(e.y, P) + + pool.Put(t) + pool.Put(t2) + pool.Put(inv) + + return e +} + +func (e *gfP2) Real() *big.Int { + return e.x +} + +func (e *gfP2) Imag() *big.Int { + return e.y +} diff --git a/crypto/bn256/gfp6.go b/crypto/bn256/gfp6.go new file mode 100644 index 0000000000..8fd777d528 --- /dev/null +++ b/crypto/bn256/gfp6.go @@ -0,0 +1,296 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bn256 + +// For details of the algorithms used, see "Multiplication and Squaring on +// Pairing-Friendly Fields, Devegili et al. +// http://eprint.iacr.org/2006/471.pdf. + +import ( + "math/big" +) + +// gfP6 implements the field of size p⁶ as a cubic extension of gfP2 where τ³=ξ +// and ξ=i+9. +type gfP6 struct { + x, y, z *gfP2 // value is xτ² + yτ + z +} + +func newGFp6(pool *bnPool) *gfP6 { + return &gfP6{newGFp2(pool), newGFp2(pool), newGFp2(pool)} +} + +func (e *gfP6) String() string { + return "(" + e.x.String() + "," + e.y.String() + "," + e.z.String() + ")" +} + +func (e *gfP6) Put(pool *bnPool) { + e.x.Put(pool) + e.y.Put(pool) + e.z.Put(pool) +} + +func (e *gfP6) Set(a *gfP6) *gfP6 { + e.x.Set(a.x) + e.y.Set(a.y) + e.z.Set(a.z) + return e +} + +func (e *gfP6) SetZero() *gfP6 { + e.x.SetZero() + e.y.SetZero() + e.z.SetZero() + return e +} + +func (e *gfP6) SetOne() *gfP6 { + e.x.SetZero() + e.y.SetZero() + e.z.SetOne() + return e +} + +func (e *gfP6) Minimal() { + e.x.Minimal() + e.y.Minimal() + e.z.Minimal() +} + +func (e *gfP6) IsZero() bool { + return e.x.IsZero() && e.y.IsZero() && e.z.IsZero() +} + +func (e *gfP6) IsOne() bool { + return e.x.IsZero() && e.y.IsZero() && e.z.IsOne() +} + +func (e *gfP6) Negative(a *gfP6) *gfP6 { + e.x.Negative(a.x) + e.y.Negative(a.y) + e.z.Negative(a.z) + return e +} + +func (e *gfP6) Frobenius(a *gfP6, pool *bnPool) *gfP6 { + e.x.Conjugate(a.x) + e.y.Conjugate(a.y) + e.z.Conjugate(a.z) + + e.x.Mul(e.x, xiTo2PMinus2Over3, pool) + e.y.Mul(e.y, xiToPMinus1Over3, pool) + return e +} + +// FrobeniusP2 computes (xτ²+yτ+z)^(p²) = xτ^(2p²) + yτ^(p²) + z +func (e *gfP6) FrobeniusP2(a *gfP6) *gfP6 { + // τ^(2p²) = τ²τ^(2p²-2) = τ²ξ^((2p²-2)/3) + e.x.MulScalar(a.x, xiTo2PSquaredMinus2Over3) + // τ^(p²) = ττ^(p²-1) = τξ^((p²-1)/3) + e.y.MulScalar(a.y, xiToPSquaredMinus1Over3) + e.z.Set(a.z) + return e +} + +func (e *gfP6) Add(a, b *gfP6) *gfP6 { + e.x.Add(a.x, b.x) + e.y.Add(a.y, b.y) + e.z.Add(a.z, b.z) + return e +} + +func (e *gfP6) Sub(a, b *gfP6) *gfP6 { + e.x.Sub(a.x, b.x) + e.y.Sub(a.y, b.y) + e.z.Sub(a.z, b.z) + return e +} + +func (e *gfP6) Double(a *gfP6) *gfP6 { + e.x.Double(a.x) + e.y.Double(a.y) + e.z.Double(a.z) + return e +} + +func (e *gfP6) Mul(a, b *gfP6, pool *bnPool) *gfP6 { + // "Multiplication and Squaring on Pairing-Friendly Fields" + // Section 4, Karatsuba method. + // http://eprint.iacr.org/2006/471.pdf + + v0 := newGFp2(pool) + v0.Mul(a.z, b.z, pool) + v1 := newGFp2(pool) + v1.Mul(a.y, b.y, pool) + v2 := newGFp2(pool) + v2.Mul(a.x, b.x, pool) + + t0 := newGFp2(pool) + t0.Add(a.x, a.y) + t1 := newGFp2(pool) + t1.Add(b.x, b.y) + tz := newGFp2(pool) + tz.Mul(t0, t1, pool) + + tz.Sub(tz, v1) + tz.Sub(tz, v2) + tz.MulXi(tz, pool) + tz.Add(tz, v0) + + t0.Add(a.y, a.z) + t1.Add(b.y, b.z) + ty := newGFp2(pool) + ty.Mul(t0, t1, pool) + ty.Sub(ty, v0) + ty.Sub(ty, v1) + t0.MulXi(v2, pool) + ty.Add(ty, t0) + + t0.Add(a.x, a.z) + t1.Add(b.x, b.z) + tx := newGFp2(pool) + tx.Mul(t0, t1, pool) + tx.Sub(tx, v0) + tx.Add(tx, v1) + tx.Sub(tx, v2) + + e.x.Set(tx) + e.y.Set(ty) + e.z.Set(tz) + + t0.Put(pool) + t1.Put(pool) + tx.Put(pool) + ty.Put(pool) + tz.Put(pool) + v0.Put(pool) + v1.Put(pool) + v2.Put(pool) + return e +} + +func (e *gfP6) MulScalar(a *gfP6, b *gfP2, pool *bnPool) *gfP6 { + e.x.Mul(a.x, b, pool) + e.y.Mul(a.y, b, pool) + e.z.Mul(a.z, b, pool) + return e +} + +func (e *gfP6) MulGFP(a *gfP6, b *big.Int) *gfP6 { + e.x.MulScalar(a.x, b) + e.y.MulScalar(a.y, b) + e.z.MulScalar(a.z, b) + return e +} + +// MulTau computes τ·(aτ²+bτ+c) = bτ²+cτ+aξ +func (e *gfP6) MulTau(a *gfP6, pool *bnPool) { + tz := newGFp2(pool) + tz.MulXi(a.x, pool) + ty := newGFp2(pool) + ty.Set(a.y) + e.y.Set(a.z) + e.x.Set(ty) + e.z.Set(tz) + tz.Put(pool) + ty.Put(pool) +} + +func (e *gfP6) Square(a *gfP6, pool *bnPool) *gfP6 { + v0 := newGFp2(pool).Square(a.z, pool) + v1 := newGFp2(pool).Square(a.y, pool) + v2 := newGFp2(pool).Square(a.x, pool) + + c0 := newGFp2(pool).Add(a.x, a.y) + c0.Square(c0, pool) + c0.Sub(c0, v1) + c0.Sub(c0, v2) + c0.MulXi(c0, pool) + c0.Add(c0, v0) + + c1 := newGFp2(pool).Add(a.y, a.z) + c1.Square(c1, pool) + c1.Sub(c1, v0) + c1.Sub(c1, v1) + xiV2 := newGFp2(pool).MulXi(v2, pool) + c1.Add(c1, xiV2) + + c2 := newGFp2(pool).Add(a.x, a.z) + c2.Square(c2, pool) + c2.Sub(c2, v0) + c2.Add(c2, v1) + c2.Sub(c2, v2) + + e.x.Set(c2) + e.y.Set(c1) + e.z.Set(c0) + + v0.Put(pool) + v1.Put(pool) + v2.Put(pool) + c0.Put(pool) + c1.Put(pool) + c2.Put(pool) + xiV2.Put(pool) + + return e +} + +func (e *gfP6) Invert(a *gfP6, pool *bnPool) *gfP6 { + // See "Implementing cryptographic pairings", M. Scott, section 3.2. + // ftp://136.206.11.249/pub/crypto/pairings.pdf + + // Here we can give a short explanation of how it works: let j be a cubic root of + // unity in GF(p²) so that 1+j+j²=0. + // Then (xτ² + yτ + z)(xj²τ² + yjτ + z)(xjτ² + yj²τ + z) + // = (xτ² + yτ + z)(Cτ²+Bτ+A) + // = (x³ξ²+y³ξ+z³-3ξxyz) = F is an element of the base field (the norm). + // + // On the other hand (xj²τ² + yjτ + z)(xjτ² + yj²τ + z) + // = τ²(y²-ξxz) + τ(ξx²-yz) + (z²-ξxy) + // + // So that's why A = (z²-ξxy), B = (ξx²-yz), C = (y²-ξxz) + t1 := newGFp2(pool) + + A := newGFp2(pool) + A.Square(a.z, pool) + t1.Mul(a.x, a.y, pool) + t1.MulXi(t1, pool) + A.Sub(A, t1) + + B := newGFp2(pool) + B.Square(a.x, pool) + B.MulXi(B, pool) + t1.Mul(a.y, a.z, pool) + B.Sub(B, t1) + + C := newGFp2(pool) + C.Square(a.y, pool) + t1.Mul(a.x, a.z, pool) + C.Sub(C, t1) + + F := newGFp2(pool) + F.Mul(C, a.y, pool) + F.MulXi(F, pool) + t1.Mul(A, a.z, pool) + F.Add(F, t1) + t1.Mul(B, a.x, pool) + t1.MulXi(t1, pool) + F.Add(F, t1) + + F.Invert(F, pool) + + e.x.Mul(C, F, pool) + e.y.Mul(B, F, pool) + e.z.Mul(A, F, pool) + + t1.Put(pool) + A.Put(pool) + B.Put(pool) + C.Put(pool) + F.Put(pool) + + return e +} diff --git a/crypto/bn256/main_test.go b/crypto/bn256/main_test.go new file mode 100644 index 0000000000..0230f1b199 --- /dev/null +++ b/crypto/bn256/main_test.go @@ -0,0 +1,71 @@ +package bn256 + +import ( + "testing" + + "crypto/rand" +) + +func TestRandomG2Marshal(t *testing.T) { + for i := 0; i < 10; i++ { + n, g2, err := RandomG2(rand.Reader) + if err != nil { + t.Error(err) + continue + } + t.Logf("%d: %x\n", n, g2.Marshal()) + } +} + +func TestPairings(t *testing.T) { + a1 := new(G1).ScalarBaseMult(bigFromBase10("1")) + a2 := new(G1).ScalarBaseMult(bigFromBase10("2")) + a37 := new(G1).ScalarBaseMult(bigFromBase10("37")) + an1 := new(G1).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616")) + + b0 := new(G2).ScalarBaseMult(bigFromBase10("0")) + b1 := new(G2).ScalarBaseMult(bigFromBase10("1")) + b2 := new(G2).ScalarBaseMult(bigFromBase10("2")) + b27 := new(G2).ScalarBaseMult(bigFromBase10("27")) + b999 := new(G2).ScalarBaseMult(bigFromBase10("999")) + bn1 := new(G2).ScalarBaseMult(bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495616")) + + p1 := Pair(a1, b1) + pn1 := Pair(a1, bn1) + np1 := Pair(an1, b1) + if pn1.String() != np1.String() { + t.Error("Pairing mismatch: e(a, -b) != e(-a, b)") + } + if !PairingCheck([]*G1{a1, an1}, []*G2{b1, b1}) { + t.Error("MultiAte check gave false negative!") + } + p0 := new(GT).Add(p1, pn1) + p0_2 := Pair(a1, b0) + if p0.String() != p0_2.String() { + t.Error("Pairing mismatch: e(a, b) * e(a, -b) != 1") + } + p0_3 := new(GT).ScalarMult(p1, bigFromBase10("21888242871839275222246405745257275088548364400416034343698204186575808495617")) + if p0.String() != p0_3.String() { + t.Error("Pairing mismatch: e(a, b) has wrong order") + } + p2 := Pair(a2, b1) + p2_2 := Pair(a1, b2) + p2_3 := new(GT).ScalarMult(p1, bigFromBase10("2")) + if p2.String() != p2_2.String() { + t.Error("Pairing mismatch: e(a, b * 2) != e(a * 2, b)") + } + if p2.String() != p2_3.String() { + t.Error("Pairing mismatch: e(a, b * 2) != e(a, b) ** 2") + } + if p2.String() == p1.String() { + t.Error("Pairing is degenerate!") + } + if PairingCheck([]*G1{a1, a1}, []*G2{b1, b1}) { + t.Error("MultiAte check gave false positive!") + } + p999 := Pair(a37, b27) + p999_2 := Pair(a1, b999) + if p999.String() != p999_2.String() { + t.Error("Pairing mismatch: e(a * 37, b * 27) != e(a, b * 999)") + } +} diff --git a/crypto/bn256/optate.go b/crypto/bn256/optate.go new file mode 100644 index 0000000000..24e0bbc131 --- /dev/null +++ b/crypto/bn256/optate.go @@ -0,0 +1,398 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bn256 + +func lineFunctionAdd(r, p *twistPoint, q *curvePoint, r2 *gfP2, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) { + // See the mixed addition algorithm from "Faster Computation of the + // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf + + B := newGFp2(pool).Mul(p.x, r.t, pool) + + D := newGFp2(pool).Add(p.y, r.z) + D.Square(D, pool) + D.Sub(D, r2) + D.Sub(D, r.t) + D.Mul(D, r.t, pool) + + H := newGFp2(pool).Sub(B, r.x) + I := newGFp2(pool).Square(H, pool) + + E := newGFp2(pool).Add(I, I) + E.Add(E, E) + + J := newGFp2(pool).Mul(H, E, pool) + + L1 := newGFp2(pool).Sub(D, r.y) + L1.Sub(L1, r.y) + + V := newGFp2(pool).Mul(r.x, E, pool) + + rOut = newTwistPoint(pool) + rOut.x.Square(L1, pool) + rOut.x.Sub(rOut.x, J) + rOut.x.Sub(rOut.x, V) + rOut.x.Sub(rOut.x, V) + + rOut.z.Add(r.z, H) + rOut.z.Square(rOut.z, pool) + rOut.z.Sub(rOut.z, r.t) + rOut.z.Sub(rOut.z, I) + + t := newGFp2(pool).Sub(V, rOut.x) + t.Mul(t, L1, pool) + t2 := newGFp2(pool).Mul(r.y, J, pool) + t2.Add(t2, t2) + rOut.y.Sub(t, t2) + + rOut.t.Square(rOut.z, pool) + + t.Add(p.y, rOut.z) + t.Square(t, pool) + t.Sub(t, r2) + t.Sub(t, rOut.t) + + t2.Mul(L1, p.x, pool) + t2.Add(t2, t2) + a = newGFp2(pool) + a.Sub(t2, t) + + c = newGFp2(pool) + c.MulScalar(rOut.z, q.y) + c.Add(c, c) + + b = newGFp2(pool) + b.SetZero() + b.Sub(b, L1) + b.MulScalar(b, q.x) + b.Add(b, b) + + B.Put(pool) + D.Put(pool) + H.Put(pool) + I.Put(pool) + E.Put(pool) + J.Put(pool) + L1.Put(pool) + V.Put(pool) + t.Put(pool) + t2.Put(pool) + + return +} + +func lineFunctionDouble(r *twistPoint, q *curvePoint, pool *bnPool) (a, b, c *gfP2, rOut *twistPoint) { + // See the doubling algorithm for a=0 from "Faster Computation of the + // Tate Pairing", http://arxiv.org/pdf/0904.0854v3.pdf + + A := newGFp2(pool).Square(r.x, pool) + B := newGFp2(pool).Square(r.y, pool) + C := newGFp2(pool).Square(B, pool) + + D := newGFp2(pool).Add(r.x, B) + D.Square(D, pool) + D.Sub(D, A) + D.Sub(D, C) + D.Add(D, D) + + E := newGFp2(pool).Add(A, A) + E.Add(E, A) + + G := newGFp2(pool).Square(E, pool) + + rOut = newTwistPoint(pool) + rOut.x.Sub(G, D) + rOut.x.Sub(rOut.x, D) + + rOut.z.Add(r.y, r.z) + rOut.z.Square(rOut.z, pool) + rOut.z.Sub(rOut.z, B) + rOut.z.Sub(rOut.z, r.t) + + rOut.y.Sub(D, rOut.x) + rOut.y.Mul(rOut.y, E, pool) + t := newGFp2(pool).Add(C, C) + t.Add(t, t) + t.Add(t, t) + rOut.y.Sub(rOut.y, t) + + rOut.t.Square(rOut.z, pool) + + t.Mul(E, r.t, pool) + t.Add(t, t) + b = newGFp2(pool) + b.SetZero() + b.Sub(b, t) + b.MulScalar(b, q.x) + + a = newGFp2(pool) + a.Add(r.x, E) + a.Square(a, pool) + a.Sub(a, A) + a.Sub(a, G) + t.Add(B, B) + t.Add(t, t) + a.Sub(a, t) + + c = newGFp2(pool) + c.Mul(rOut.z, r.t, pool) + c.Add(c, c) + c.MulScalar(c, q.y) + + A.Put(pool) + B.Put(pool) + C.Put(pool) + D.Put(pool) + E.Put(pool) + G.Put(pool) + t.Put(pool) + + return +} + +func mulLine(ret *gfP12, a, b, c *gfP2, pool *bnPool) { + a2 := newGFp6(pool) + a2.x.SetZero() + a2.y.Set(a) + a2.z.Set(b) + a2.Mul(a2, ret.x, pool) + t3 := newGFp6(pool).MulScalar(ret.y, c, pool) + + t := newGFp2(pool) + t.Add(b, c) + t2 := newGFp6(pool) + t2.x.SetZero() + t2.y.Set(a) + t2.z.Set(t) + ret.x.Add(ret.x, ret.y) + + ret.y.Set(t3) + + ret.x.Mul(ret.x, t2, pool) + ret.x.Sub(ret.x, a2) + ret.x.Sub(ret.x, ret.y) + a2.MulTau(a2, pool) + ret.y.Add(ret.y, a2) + + a2.Put(pool) + t3.Put(pool) + t2.Put(pool) + t.Put(pool) +} + +// sixuPlus2NAF is 6u+2 in non-adjacent form. +var sixuPlus2NAF = []int8{0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, + 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, 1, 1, + 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, + 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, 1, 1} + +// miller implements the Miller loop for calculating the Optimal Ate pairing. +// See algorithm 1 from http://cryptojedi.org/papers/dclxvi-20100714.pdf +func miller(q *twistPoint, p *curvePoint, pool *bnPool) *gfP12 { + ret := newGFp12(pool) + ret.SetOne() + + aAffine := newTwistPoint(pool) + aAffine.Set(q) + aAffine.MakeAffine(pool) + + bAffine := newCurvePoint(pool) + bAffine.Set(p) + bAffine.MakeAffine(pool) + + minusA := newTwistPoint(pool) + minusA.Negative(aAffine, pool) + + r := newTwistPoint(pool) + r.Set(aAffine) + + r2 := newGFp2(pool) + r2.Square(aAffine.y, pool) + + for i := len(sixuPlus2NAF) - 1; i > 0; i-- { + a, b, c, newR := lineFunctionDouble(r, bAffine, pool) + if i != len(sixuPlus2NAF)-1 { + ret.Square(ret, pool) + } + + mulLine(ret, a, b, c, pool) + a.Put(pool) + b.Put(pool) + c.Put(pool) + r.Put(pool) + r = newR + + switch sixuPlus2NAF[i-1] { + case 1: + a, b, c, newR = lineFunctionAdd(r, aAffine, bAffine, r2, pool) + case -1: + a, b, c, newR = lineFunctionAdd(r, minusA, bAffine, r2, pool) + default: + continue + } + + mulLine(ret, a, b, c, pool) + a.Put(pool) + b.Put(pool) + c.Put(pool) + r.Put(pool) + r = newR + } + + // In order to calculate Q1 we have to convert q from the sextic twist + // to the full GF(p^12) group, apply the Frobenius there, and convert + // back. + // + // The twist isomorphism is (x', y') -> (xω², yω³). If we consider just + // x for a moment, then after applying the Frobenius, we have x̄ω^(2p) + // where x̄ is the conjugate of x. If we are going to apply the inverse + // isomorphism we need a value with a single coefficient of ω² so we + // rewrite this as x̄ω^(2p-2)ω². ξ⁶ = ω and, due to the construction of + // p, 2p-2 is a multiple of six. Therefore we can rewrite as + // x̄ξ^((p-1)/3)ω² and applying the inverse isomorphism eliminates the + // ω². + // + // A similar argument can be made for the y value. + + q1 := newTwistPoint(pool) + q1.x.Conjugate(aAffine.x) + q1.x.Mul(q1.x, xiToPMinus1Over3, pool) + q1.y.Conjugate(aAffine.y) + q1.y.Mul(q1.y, xiToPMinus1Over2, pool) + q1.z.SetOne() + q1.t.SetOne() + + // For Q2 we are applying the p² Frobenius. The two conjugations cancel + // out and we are left only with the factors from the isomorphism. In + // the case of x, we end up with a pure number which is why + // xiToPSquaredMinus1Over3 is ∈ GF(p). With y we get a factor of -1. We + // ignore this to end up with -Q2. + + minusQ2 := newTwistPoint(pool) + minusQ2.x.MulScalar(aAffine.x, xiToPSquaredMinus1Over3) + minusQ2.y.Set(aAffine.y) + minusQ2.z.SetOne() + minusQ2.t.SetOne() + + r2.Square(q1.y, pool) + a, b, c, newR := lineFunctionAdd(r, q1, bAffine, r2, pool) + mulLine(ret, a, b, c, pool) + a.Put(pool) + b.Put(pool) + c.Put(pool) + r.Put(pool) + r = newR + + r2.Square(minusQ2.y, pool) + a, b, c, newR = lineFunctionAdd(r, minusQ2, bAffine, r2, pool) + mulLine(ret, a, b, c, pool) + a.Put(pool) + b.Put(pool) + c.Put(pool) + r.Put(pool) + r = newR + + aAffine.Put(pool) + bAffine.Put(pool) + minusA.Put(pool) + r.Put(pool) + r2.Put(pool) + + return ret +} + +// finalExponentiation computes the (p¹²-1)/Order-th power of an element of +// GF(p¹²) to obtain an element of GT (steps 13-15 of algorithm 1 from +// http://cryptojedi.org/papers/dclxvi-20100714.pdf) +func finalExponentiation(in *gfP12, pool *bnPool) *gfP12 { + t1 := newGFp12(pool) + + // This is the p^6-Frobenius + t1.x.Negative(in.x) + t1.y.Set(in.y) + + inv := newGFp12(pool) + inv.Invert(in, pool) + t1.Mul(t1, inv, pool) + + t2 := newGFp12(pool).FrobeniusP2(t1, pool) + t1.Mul(t1, t2, pool) + + fp := newGFp12(pool).Frobenius(t1, pool) + fp2 := newGFp12(pool).FrobeniusP2(t1, pool) + fp3 := newGFp12(pool).Frobenius(fp2, pool) + + fu, fu2, fu3 := newGFp12(pool), newGFp12(pool), newGFp12(pool) + fu.Exp(t1, u, pool) + fu2.Exp(fu, u, pool) + fu3.Exp(fu2, u, pool) + + y3 := newGFp12(pool).Frobenius(fu, pool) + fu2p := newGFp12(pool).Frobenius(fu2, pool) + fu3p := newGFp12(pool).Frobenius(fu3, pool) + y2 := newGFp12(pool).FrobeniusP2(fu2, pool) + + y0 := newGFp12(pool) + y0.Mul(fp, fp2, pool) + y0.Mul(y0, fp3, pool) + + y1, y4, y5 := newGFp12(pool), newGFp12(pool), newGFp12(pool) + y1.Conjugate(t1) + y5.Conjugate(fu2) + y3.Conjugate(y3) + y4.Mul(fu, fu2p, pool) + y4.Conjugate(y4) + + y6 := newGFp12(pool) + y6.Mul(fu3, fu3p, pool) + y6.Conjugate(y6) + + t0 := newGFp12(pool) + t0.Square(y6, pool) + t0.Mul(t0, y4, pool) + t0.Mul(t0, y5, pool) + t1.Mul(y3, y5, pool) + t1.Mul(t1, t0, pool) + t0.Mul(t0, y2, pool) + t1.Square(t1, pool) + t1.Mul(t1, t0, pool) + t1.Square(t1, pool) + t0.Mul(t1, y1, pool) + t1.Mul(t1, y0, pool) + t0.Square(t0, pool) + t0.Mul(t0, t1, pool) + + inv.Put(pool) + t1.Put(pool) + t2.Put(pool) + fp.Put(pool) + fp2.Put(pool) + fp3.Put(pool) + fu.Put(pool) + fu2.Put(pool) + fu3.Put(pool) + fu2p.Put(pool) + fu3p.Put(pool) + y0.Put(pool) + y1.Put(pool) + y2.Put(pool) + y3.Put(pool) + y4.Put(pool) + y5.Put(pool) + y6.Put(pool) + + return t0 +} + +func optimalAte(a *twistPoint, b *curvePoint, pool *bnPool) *gfP12 { + e := miller(a, b, pool) + ret := finalExponentiation(e, pool) + e.Put(pool) + + if a.IsInfinity() || b.IsInfinity() { + ret.SetOne() + } + + return ret +} diff --git a/crypto/bn256/twist.go b/crypto/bn256/twist.go new file mode 100644 index 0000000000..1e052456e5 --- /dev/null +++ b/crypto/bn256/twist.go @@ -0,0 +1,249 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package bn256 + +import ( + "math/big" +) + +// twistPoint implements the elliptic curve y²=x³+3/ξ over GF(p²). Points are +// kept in Jacobian form and t=z² when valid. The group G₂ is the set of +// n-torsion points of this curve over GF(p²) (where n = Order) +type twistPoint struct { + x, y, z, t *gfP2 +} + +var twistB = &gfP2{ + bigFromBase10("266929791119991161246907387137283842545076965332900288569378510910307636690"), + bigFromBase10("19485874751759354771024239261021720505790618469301721065564631296452457478373"), +} + +// twistGen is the generator of group G₂. +var twistGen = &twistPoint{ + &gfP2{ + bigFromBase10("11559732032986387107991004021392285783925812861821192530917403151452391805634"), + bigFromBase10("10857046999023057135944570762232829481370756359578518086990519993285655852781"), + }, + &gfP2{ + bigFromBase10("4082367875863433681332203403145435568316851327593401208105741076214120093531"), + bigFromBase10("8495653923123431417604973247489272438418190587263600148770280649306958101930"), + }, + &gfP2{ + bigFromBase10("0"), + bigFromBase10("1"), + }, + &gfP2{ + bigFromBase10("0"), + bigFromBase10("1"), + }, +} + +func newTwistPoint(pool *bnPool) *twistPoint { + return &twistPoint{ + newGFp2(pool), + newGFp2(pool), + newGFp2(pool), + newGFp2(pool), + } +} + +func (c *twistPoint) String() string { + return "(" + c.x.String() + ", " + c.y.String() + ", " + c.z.String() + ")" +} + +func (c *twistPoint) Put(pool *bnPool) { + c.x.Put(pool) + c.y.Put(pool) + c.z.Put(pool) + c.t.Put(pool) +} + +func (c *twistPoint) Set(a *twistPoint) { + c.x.Set(a.x) + c.y.Set(a.y) + c.z.Set(a.z) + c.t.Set(a.t) +} + +// IsOnCurve returns true iff c is on the curve where c must be in affine form. +func (c *twistPoint) IsOnCurve() bool { + pool := new(bnPool) + yy := newGFp2(pool).Square(c.y, pool) + xxx := newGFp2(pool).Square(c.x, pool) + xxx.Mul(xxx, c.x, pool) + yy.Sub(yy, xxx) + yy.Sub(yy, twistB) + yy.Minimal() + return yy.x.Sign() == 0 && yy.y.Sign() == 0 +} + +func (c *twistPoint) SetInfinity() { + c.z.SetZero() +} + +func (c *twistPoint) IsInfinity() bool { + return c.z.IsZero() +} + +func (c *twistPoint) Add(a, b *twistPoint, pool *bnPool) { + // For additional comments, see the same function in curve.go. + + if a.IsInfinity() { + c.Set(b) + return + } + if b.IsInfinity() { + c.Set(a) + return + } + + // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3 + z1z1 := newGFp2(pool).Square(a.z, pool) + z2z2 := newGFp2(pool).Square(b.z, pool) + u1 := newGFp2(pool).Mul(a.x, z2z2, pool) + u2 := newGFp2(pool).Mul(b.x, z1z1, pool) + + t := newGFp2(pool).Mul(b.z, z2z2, pool) + s1 := newGFp2(pool).Mul(a.y, t, pool) + + t.Mul(a.z, z1z1, pool) + s2 := newGFp2(pool).Mul(b.y, t, pool) + + h := newGFp2(pool).Sub(u2, u1) + xEqual := h.IsZero() + + t.Add(h, h) + i := newGFp2(pool).Square(t, pool) + j := newGFp2(pool).Mul(h, i, pool) + + t.Sub(s2, s1) + yEqual := t.IsZero() + if xEqual && yEqual { + c.Double(a, pool) + return + } + r := newGFp2(pool).Add(t, t) + + v := newGFp2(pool).Mul(u1, i, pool) + + t4 := newGFp2(pool).Square(r, pool) + t.Add(v, v) + t6 := newGFp2(pool).Sub(t4, j) + c.x.Sub(t6, t) + + t.Sub(v, c.x) // t7 + t4.Mul(s1, j, pool) // t8 + t6.Add(t4, t4) // t9 + t4.Mul(r, t, pool) // t10 + c.y.Sub(t4, t6) + + t.Add(a.z, b.z) // t11 + t4.Square(t, pool) // t12 + t.Sub(t4, z1z1) // t13 + t4.Sub(t, z2z2) // t14 + c.z.Mul(t4, h, pool) + + z1z1.Put(pool) + z2z2.Put(pool) + u1.Put(pool) + u2.Put(pool) + t.Put(pool) + s1.Put(pool) + s2.Put(pool) + h.Put(pool) + i.Put(pool) + j.Put(pool) + r.Put(pool) + v.Put(pool) + t4.Put(pool) + t6.Put(pool) +} + +func (c *twistPoint) Double(a *twistPoint, pool *bnPool) { + // See http://hyperelliptic.org/EFD/g1p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3 + A := newGFp2(pool).Square(a.x, pool) + B := newGFp2(pool).Square(a.y, pool) + C := newGFp2(pool).Square(B, pool) + + t := newGFp2(pool).Add(a.x, B) + t2 := newGFp2(pool).Square(t, pool) + t.Sub(t2, A) + t2.Sub(t, C) + d := newGFp2(pool).Add(t2, t2) + t.Add(A, A) + e := newGFp2(pool).Add(t, A) + f := newGFp2(pool).Square(e, pool) + + t.Add(d, d) + c.x.Sub(f, t) + + t.Add(C, C) + t2.Add(t, t) + t.Add(t2, t2) + c.y.Sub(d, c.x) + t2.Mul(e, c.y, pool) + c.y.Sub(t2, t) + + t.Mul(a.y, a.z, pool) + c.z.Add(t, t) + + A.Put(pool) + B.Put(pool) + C.Put(pool) + t.Put(pool) + t2.Put(pool) + d.Put(pool) + e.Put(pool) + f.Put(pool) +} + +func (c *twistPoint) Mul(a *twistPoint, scalar *big.Int, pool *bnPool) *twistPoint { + sum := newTwistPoint(pool) + sum.SetInfinity() + t := newTwistPoint(pool) + + for i := scalar.BitLen(); i >= 0; i-- { + t.Double(sum, pool) + if scalar.Bit(i) != 0 { + sum.Add(t, a, pool) + } else { + sum.Set(t) + } + } + + c.Set(sum) + sum.Put(pool) + t.Put(pool) + return c +} + +func (c *twistPoint) MakeAffine(pool *bnPool) *twistPoint { + if c.z.IsOne() { + return c + } + + zInv := newGFp2(pool).Invert(c.z, pool) + t := newGFp2(pool).Mul(c.y, zInv, pool) + zInv2 := newGFp2(pool).Square(zInv, pool) + c.y.Mul(t, zInv2, pool) + t.Mul(c.x, zInv2, pool) + c.x.Set(t) + c.z.SetOne() + c.t.SetOne() + + zInv.Put(pool) + t.Put(pool) + zInv2.Put(pool) + + return c +} + +func (c *twistPoint) Negative(a *twistPoint, pool *bnPool) { + c.x.Set(a.x) + c.y.SetZero() + c.y.Sub(c.y, a.y) + c.z.Set(a.z) + c.t.SetZero() +} diff --git a/internal/ethapi/tracer_test.go b/internal/ethapi/tracer_test.go index 0ef450ce32..5093dafd6e 100644 --- a/internal/ethapi/tracer_test.go +++ b/internal/ethapi/tracer_test.go @@ -48,7 +48,7 @@ func runTrace(tracer *JavascriptTracer) (interface{}, error) { contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} - _, err := env.Interpreter().Run(contract, []byte{}) + _, err := env.Interpreter().Run(0, contract, []byte{}) if err != nil { return nil, err } From 1e5725f03b366cf094f18c68994bc1d7397a17dd Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Thu, 9 Mar 2017 09:10:54 +0100 Subject: [PATCH 09/13] core/vm: removed err checks from EVM and added snapshot to interpreter The REVERT op codes reverts the state by returning an error from the instruction. The instruction was checked during in the EVM. This error would then determine whether any gas should be consumed or not. If the error was an errRevert, no gas was further reduced and only state was reverted. This solution is error prone as you'll need an err check in multiple locations and removes the no-err check requirement of the evm. This has been solved by passing the snapshot to the interpreter and letting the interpreter do the state reverting if the operation so requires. --- core/vm/evm.go | 51 +++++++++++++++++++---------------------- core/vm/instructions.go | 3 +-- core/vm/interpreter.go | 25 ++++++++++++++++---- core/vm/jump_table.go | 3 +++ 4 files changed, 49 insertions(+), 33 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 9264d88659..09197e14fe 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -34,7 +34,7 @@ type ( ) // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. -func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) { +func run(evm *EVM, snapshot int, contract *Contract, input []byte) ([]byte, error) { if contract.CodeAddr != nil { precompiledContracts := PrecompiledContracts if evm.ChainConfig().IsMetropolis(evm.BlockNumber) { @@ -46,10 +46,11 @@ func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) { } } - return evm.interpreter.Run(contract, input) + return evm.interpreter.Run(snapshot, contract, input) } -// Context provides the EVM with auxiliary information. Once provided it shouldn't be modified. +// Context provides the EVM with auxiliary information. Once provided +// it shouldn't be modified. type Context struct { // CanTransfer returns whether the account contains // sufficient ether to transfer the value @@ -71,7 +72,13 @@ type Context struct { Difficulty *big.Int // Provides information for DIFFICULTY } -// EVM provides information about external sources for the EVM +// EVM is the Ethereum Virtual Machine base object and provides +// the necessary tools to run a contract on the given state with +// the provided context. It should be noted that any error +// generated through any of the calls should be considered a +// revert-state-and-consume-all-gas operation, no checks on +// specific errors should ever be performed. The interpreter makes +// sure that any errors generated are to be considered faulty code. // // The EVM should never be reused and is not thread safe. type EVM struct { @@ -95,7 +102,8 @@ type EVM struct { abort int32 } -// NewEVM retutrns a new EVM evmironment. +// NewEVM retutrns a new EVM evmironment. The returned EVM is not thread safe +// and should only ever be used *once*. func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM { evm := &EVM{ Context: ctx, @@ -108,8 +116,8 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon return evm } -// Cancel cancels any running EVM operation. This may be called concurrently and it's safe to be -// called multiple times. +// Cancel cancels any running EVM operation. This may be called concurrently and +// it's safe to be called multiple times. func (evm *EVM) Cancel() { atomic.StoreInt32(&evm.abort, 1) } @@ -147,7 +155,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte contract := NewContract(caller, to, new(big.Int), gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = evm.interpreter.Run(contract, input) + ret, err = evm.interpreter.Run(snapshot, contract, input) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in homestead this also counts for code storage gas errors. @@ -195,14 +203,12 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas contract := NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = run(evm, contract, input) + ret, err = run(evm, snapshot, contract, input) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in homestead this also counts for code storage gas errors. if err != nil { - if err != errRevert { - contract.UseGas(contract.Gas) - } + contract.UseGas(contract.Gas) evm.StateDB.RevertToSnapshot(snapshot) } return ret, contract.Gas, err @@ -237,12 +243,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, contract := NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = run(evm, contract, input) + ret, err = run(evm, snapshot, contract, input) if err != nil { - if err != errRevert { - contract.UseGas(contract.Gas) - } - + contract.UseGas(contract.Gas) evm.StateDB.RevertToSnapshot(snapshot) } @@ -274,12 +277,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by contract := NewContract(caller, to, nil, gas).AsDelegate() contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) - ret, err = run(evm, contract, input) + ret, err = run(evm, snapshot, contract, input) if err != nil { - if err != errRevert { - contract.UseGas(contract.Gas) - } - + contract.UseGas(contract.Gas) evm.StateDB.RevertToSnapshot(snapshot) } @@ -319,7 +319,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I contract := NewContract(caller, AccountRef(contractAddr), value, gas) contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code) - ret, err = run(evm, contract, nil) + ret, err = run(evm, snapshot, contract, nil) // check whether the max code size has been exceeded maxCodeSizeExceeded := len(ret) > params.MaxCodeSize // if the contract creation ran successfully and no errors were returned @@ -340,10 +340,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I // when we're in homestead this also counts for code storage gas errors. if maxCodeSizeExceeded || (err != nil && (evm.ChainConfig().IsHomestead(evm.BlockNumber) || err != ErrCodeStoreOutOfGas)) { - if err != errRevert { - contract.UseGas(contract.Gas) - } - + contract.UseGas(contract.Gas) evm.StateDB.RevertToSnapshot(snapshot) } // If the vm returned with an error the return value should be set to nil. diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 2e1959e8c0..181a04d124 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -31,7 +31,6 @@ import ( var ( bigZero = new(big.Int) errWriteProtection = errors.New("evm write protection") - errRevert = errors.New("standard throw") ) func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -719,7 +718,7 @@ func opRevert(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S ret := memory.GetPtr(offset.Int64(), size.Int64()) evm.interpreter.intPool.put(offset, size) - return ret, errRevert + return ret, nil } func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index b38d42ed3f..cf96200305 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -18,6 +18,7 @@ package vm import ( "fmt" + "math/big" "sync/atomic" "time" @@ -81,8 +82,13 @@ func NewInterpreter(env *EVM, cfg Config) *Interpreter { } } -// Run loops and evaluates the contract's code with the given input data -func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) { +// Run loops and evaluates the contract's code with the given input data and returns +// the return byte-slice and an error if one occured. +// +// It's important to note that any errors returned by the interpreter should be +// considered a revert-and-consume-all-gas operation. No error specific checks +// should be handled to reduce complexity and errors further down the EVM. +func (evm *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret []byte, err error) { evm.env.depth++ defer func() { evm.env.depth-- }() @@ -101,7 +107,8 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e mem = NewMemory() // bound memory stack = newstack() // local stack // For optimisation reason we're using uint64 as the program counter. - // It's theoretically possible to go above 2^64. The YP defines the PC to be uint256. Practically much less so feasible. + // It's theoretically possible to go above 2^64. The YP defines the PC + // to be uint256. Practically much less so feasible. pc = uint64(0) // program counter cost uint64 ) @@ -112,6 +119,8 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e if err != nil && evm.cfg.Debug { // XXX For debugging //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d ERR = %v\n", pc, op, cost, stack.len(), err) + // TODO update the tracer to accept uint64 instead of *big.Int + g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost) evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err) } }() @@ -179,7 +188,9 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e } if evm.cfg.Debug { - evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err) + // TODO update the tracer to accept uint64 instead of *big.Int + g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost) + evm.cfg.Tracer.CaptureState(evm.env, pc, op, g, c, mem, stack, contract, evm.env.depth, err) } // XXX For debugging //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d\n", pc, op, cost, stack.len()) @@ -191,6 +202,12 @@ func (evm *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err e if verifyPool { verifyIntegerPool(evm.intPool) } + + // checks whether the operation should revert state. + if operation.reverts { + evm.env.StateDB.RevertToSnapshot(snapshot) + } + switch { case err != nil: return nil, err diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 3e5097857d..2ffd300bd1 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -51,6 +51,8 @@ type operation struct { writes bool // valid is used to check whether the retrieved operation is valid and known valid bool + // reverts determined whether the operation reverts state + reverts bool } var defaultJumpTable = NewJumpTable() @@ -400,6 +402,7 @@ func NewJumpTable() [256]operation { gasCost: constGasFunc(GasFastestStep), validateStack: makeStackFunc(2, 0), valid: true, + reverts: true, }, JUMPDEST: { execute: opJumpdest, From 5f972398ae6cd806f20c5606db65e226281f7f27 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Thu, 9 Mar 2017 22:20:48 +0100 Subject: [PATCH 10/13] core/vm: implemented RETURNDATA{COPY, SIZE} --- core/vm/gas_table.go | 26 ++++ core/vm/instructions.go | 34 ++++- core/vm/interpreter.go | 5 + core/vm/jump_table.go | 13 ++ core/vm/memory.go | 1 + core/vm/memory_table.go | 4 + core/vm/opcodes.go | 273 +++++++++++++++++++++------------------- 7 files changed, 220 insertions(+), 136 deletions(-) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index f1c62df8e7..49ab2ed062 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -71,6 +71,32 @@ func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *St return gas, nil } +func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + + var overflow bool + if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { + return 0, errGasUintOverflow + } + + words, overflow := bigUint64(stack.Back(2)) + if overflow { + return 0, errGasUintOverflow + } + + if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { + return 0, errGasUintOverflow + } + + if gas, overflow = math.SafeAdd(gas, words); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var ( y, x = stack.Back(1), stack.Back(0) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 181a04d124..dd41202687 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -604,7 +604,7 @@ func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac contract.Gas += returnGas evm.interpreter.intPool.put(addr, inOffset, inSize, retOffset, retSize) - return nil, nil + return ret, nil } func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -637,7 +637,7 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta contract.Gas += returnGas evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) - return nil, nil + return ret, nil } func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -671,7 +671,7 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack contract.Gas += returnGas evm.interpreter.intPool.put(addr, value, inOffset, inSize, retOffset, retSize) - return nil, nil + return ret, nil } func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -696,7 +696,7 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st contract.Gas += returnGas evm.interpreter.intPool.put(to, inOffset, inSize, outOffset, outSize) - return nil, nil + return ret, nil } func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { @@ -704,6 +704,7 @@ func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S ret := memory.GetPtr(offset.Int64(), size.Int64()) evm.interpreter.intPool.put(offset, size) + return ret, nil } @@ -734,6 +735,31 @@ func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack * return nil, nil } +func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) { + return nil, fmt.Errorf("invalid opcode %x", RETURNDATASIZE) + } + + stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(memory.lastReturn)))) + return nil, nil +} + +func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { + if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) { + return nil, fmt.Errorf("invalid opcode %x", RETURNDATACOPY) + } + + var ( + mOff = stack.pop() + cOff = stack.pop() + l = stack.pop() + ) + memory.Set(mOff.Uint64(), l.Uint64(), getData(memory.lastReturn, cOff, l)) + + evm.interpreter.intPool.put(mOff, cOff, l) + return nil, nil +} + // following functions are used by the instruction jump table // make log instruction function diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index cf96200305..b003684c08 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -216,6 +216,11 @@ func (evm *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret case !operation.jumps: pc++ } + // if the operation returned a value make sure that is also set + // the last return data. + if res != nil { + mem.lastReturn = ret + } } return nil, nil } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 2ffd300bd1..8e580b5c6a 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -829,6 +829,19 @@ func NewJumpTable() [256]operation { memorySize: memoryLog, valid: true, }, + RETURNDATASIZE: { + execute: opReturnDataSize, + gasCost: constGasFunc(0), // TODO + validateStack: makeStackFunc(0, 1), + valid: true, + }, + RETURNDATACOPY: { + execute: opReturnDataCopy, + gasCost: gasReturnDataCopy, + validateStack: makeStackFunc(3, 0), + memorySize: memoryReturnDataCopy, + valid: true, + }, CREATE: { execute: opCreate, gasCost: gasCreate, diff --git a/core/vm/memory.go b/core/vm/memory.go index 99a84d2271..6dbee94eff 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -22,6 +22,7 @@ import "fmt" type Memory struct { store []byte lastGasCost uint64 + lastReturn []byte } func NewMemory() *Memory { diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index 3141a2f61a..06d3fcb814 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -14,6 +14,10 @@ func memoryCalldataCopy(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(2)) } +func memoryReturnDataCopy(stack *Stack) *big.Int { + return calcMemSize(stack.Back(0), stack.Back(2)) +} + func memoryCodeCopy(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(2)) } diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index d063bffb0e..3ded3e219d 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -194,6 +194,11 @@ const ( SWAP ) +const ( + RETURNDATASIZE OpCode = 0xd0 + iota + RETURNDATACOPY +) + const ( // 0xf0 range - closures CREATE OpCode = 0xf0 + iota @@ -351,6 +356,8 @@ var opCodeToString = map[OpCode]string{ LOG3: "LOG3", LOG4: "LOG4", + RETURNDATASIZE: "RETURNDATASIZE", + RETURNDATACOPY: "RETURNDATACOPY", // 0xf0 range CREATE: "CREATE", CALL: "CALL", @@ -376,138 +383,140 @@ func (o OpCode) String() string { } var stringToOp = map[string]OpCode{ - "STOP": STOP, - "ADD": ADD, - "MUL": MUL, - "SUB": SUB, - "DIV": DIV, - "SDIV": SDIV, - "MOD": MOD, - "SMOD": SMOD, - "EXP": EXP, - "NOT": NOT, - "LT": LT, - "GT": GT, - "SLT": SLT, - "SGT": SGT, - "EQ": EQ, - "ISZERO": ISZERO, - "SIGNEXTEND": SIGNEXTEND, - "AND": AND, - "OR": OR, - "XOR": XOR, - "BYTE": BYTE, - "ADDMOD": ADDMOD, - "MULMOD": MULMOD, - "SHA3": SHA3, - "ADDRESS": ADDRESS, - "BALANCE": BALANCE, - "ORIGIN": ORIGIN, - "CALLER": CALLER, - "CALLVALUE": CALLVALUE, - "CALLDATALOAD": CALLDATALOAD, - "CALLDATASIZE": CALLDATASIZE, - "CALLDATACOPY": CALLDATACOPY, - "DELEGATECALL": DELEGATECALL, - "STATIC_CALL": STATIC_CALL, - "CODESIZE": CODESIZE, - "CODECOPY": CODECOPY, - "GASPRICE": GASPRICE, - "BLOCKHASH": BLOCKHASH, - "COINBASE": COINBASE, - "TIMESTAMP": TIMESTAMP, - "NUMBER": NUMBER, - "DIFFICULTY": DIFFICULTY, - "GASLIMIT": GASLIMIT, - "EXTCODESIZE": EXTCODESIZE, - "EXTCODECOPY": EXTCODECOPY, - "POP": POP, - "MLOAD": MLOAD, - "MSTORE": MSTORE, - "MSTORE8": MSTORE8, - "SLOAD": SLOAD, - "SSTORE": SSTORE, - "JUMP": JUMP, - "JUMPI": JUMPI, - "PC": PC, - "MSIZE": MSIZE, - "GAS": GAS, - "JUMPDEST": JUMPDEST, - "PUSH1": PUSH1, - "PUSH2": PUSH2, - "PUSH3": PUSH3, - "PUSH4": PUSH4, - "PUSH5": PUSH5, - "PUSH6": PUSH6, - "PUSH7": PUSH7, - "PUSH8": PUSH8, - "PUSH9": PUSH9, - "PUSH10": PUSH10, - "PUSH11": PUSH11, - "PUSH12": PUSH12, - "PUSH13": PUSH13, - "PUSH14": PUSH14, - "PUSH15": PUSH15, - "PUSH16": PUSH16, - "PUSH17": PUSH17, - "PUSH18": PUSH18, - "PUSH19": PUSH19, - "PUSH20": PUSH20, - "PUSH21": PUSH21, - "PUSH22": PUSH22, - "PUSH23": PUSH23, - "PUSH24": PUSH24, - "PUSH25": PUSH25, - "PUSH26": PUSH26, - "PUSH27": PUSH27, - "PUSH28": PUSH28, - "PUSH29": PUSH29, - "PUSH30": PUSH30, - "PUSH31": PUSH31, - "PUSH32": PUSH32, - "DUP1": DUP1, - "DUP2": DUP2, - "DUP3": DUP3, - "DUP4": DUP4, - "DUP5": DUP5, - "DUP6": DUP6, - "DUP7": DUP7, - "DUP8": DUP8, - "DUP9": DUP9, - "DUP10": DUP10, - "DUP11": DUP11, - "DUP12": DUP12, - "DUP13": DUP13, - "DUP14": DUP14, - "DUP15": DUP15, - "DUP16": DUP16, - "SWAP1": SWAP1, - "SWAP2": SWAP2, - "SWAP3": SWAP3, - "SWAP4": SWAP4, - "SWAP5": SWAP5, - "SWAP6": SWAP6, - "SWAP7": SWAP7, - "SWAP8": SWAP8, - "SWAP9": SWAP9, - "SWAP10": SWAP10, - "SWAP11": SWAP11, - "SWAP12": SWAP12, - "SWAP13": SWAP13, - "SWAP14": SWAP14, - "SWAP15": SWAP15, - "SWAP16": SWAP16, - "LOG0": LOG0, - "LOG1": LOG1, - "LOG2": LOG2, - "LOG3": LOG3, - "LOG4": LOG4, - "CREATE": CREATE, - "CALL": CALL, - "RETURN": RETURN, - "REVERT": REVERT, - "CALLCODE": CALLCODE, - "SELFDESTRUCT": SELFDESTRUCT, + "STOP": STOP, + "ADD": ADD, + "MUL": MUL, + "SUB": SUB, + "DIV": DIV, + "SDIV": SDIV, + "MOD": MOD, + "SMOD": SMOD, + "EXP": EXP, + "NOT": NOT, + "LT": LT, + "GT": GT, + "SLT": SLT, + "SGT": SGT, + "EQ": EQ, + "ISZERO": ISZERO, + "SIGNEXTEND": SIGNEXTEND, + "AND": AND, + "OR": OR, + "XOR": XOR, + "BYTE": BYTE, + "ADDMOD": ADDMOD, + "MULMOD": MULMOD, + "SHA3": SHA3, + "ADDRESS": ADDRESS, + "BALANCE": BALANCE, + "ORIGIN": ORIGIN, + "CALLER": CALLER, + "CALLVALUE": CALLVALUE, + "CALLDATALOAD": CALLDATALOAD, + "CALLDATASIZE": CALLDATASIZE, + "CALLDATACOPY": CALLDATACOPY, + "DELEGATECALL": DELEGATECALL, + "STATIC_CALL": STATIC_CALL, + "CODESIZE": CODESIZE, + "CODECOPY": CODECOPY, + "GASPRICE": GASPRICE, + "BLOCKHASH": BLOCKHASH, + "COINBASE": COINBASE, + "TIMESTAMP": TIMESTAMP, + "NUMBER": NUMBER, + "DIFFICULTY": DIFFICULTY, + "GASLIMIT": GASLIMIT, + "EXTCODESIZE": EXTCODESIZE, + "EXTCODECOPY": EXTCODECOPY, + "POP": POP, + "MLOAD": MLOAD, + "MSTORE": MSTORE, + "MSTORE8": MSTORE8, + "SLOAD": SLOAD, + "SSTORE": SSTORE, + "JUMP": JUMP, + "JUMPI": JUMPI, + "PC": PC, + "MSIZE": MSIZE, + "GAS": GAS, + "JUMPDEST": JUMPDEST, + "PUSH1": PUSH1, + "PUSH2": PUSH2, + "PUSH3": PUSH3, + "PUSH4": PUSH4, + "PUSH5": PUSH5, + "PUSH6": PUSH6, + "PUSH7": PUSH7, + "PUSH8": PUSH8, + "PUSH9": PUSH9, + "PUSH10": PUSH10, + "PUSH11": PUSH11, + "PUSH12": PUSH12, + "PUSH13": PUSH13, + "PUSH14": PUSH14, + "PUSH15": PUSH15, + "PUSH16": PUSH16, + "PUSH17": PUSH17, + "PUSH18": PUSH18, + "PUSH19": PUSH19, + "PUSH20": PUSH20, + "PUSH21": PUSH21, + "PUSH22": PUSH22, + "PUSH23": PUSH23, + "PUSH24": PUSH24, + "PUSH25": PUSH25, + "PUSH26": PUSH26, + "PUSH27": PUSH27, + "PUSH28": PUSH28, + "PUSH29": PUSH29, + "PUSH30": PUSH30, + "PUSH31": PUSH31, + "PUSH32": PUSH32, + "DUP1": DUP1, + "DUP2": DUP2, + "DUP3": DUP3, + "DUP4": DUP4, + "DUP5": DUP5, + "DUP6": DUP6, + "DUP7": DUP7, + "DUP8": DUP8, + "DUP9": DUP9, + "DUP10": DUP10, + "DUP11": DUP11, + "DUP12": DUP12, + "DUP13": DUP13, + "DUP14": DUP14, + "DUP15": DUP15, + "DUP16": DUP16, + "SWAP1": SWAP1, + "SWAP2": SWAP2, + "SWAP3": SWAP3, + "SWAP4": SWAP4, + "SWAP5": SWAP5, + "SWAP6": SWAP6, + "SWAP7": SWAP7, + "SWAP8": SWAP8, + "SWAP9": SWAP9, + "SWAP10": SWAP10, + "SWAP11": SWAP11, + "SWAP12": SWAP12, + "SWAP13": SWAP13, + "SWAP14": SWAP14, + "SWAP15": SWAP15, + "SWAP16": SWAP16, + "LOG0": LOG0, + "LOG1": LOG1, + "LOG2": LOG2, + "LOG3": LOG3, + "LOG4": LOG4, + "CREATE": CREATE, + "CALL": CALL, + "RETURN": RETURN, + "REVERT": REVERT, + "CALLCODE": CALLCODE, + "SELFDESTRUCT": SELFDESTRUCT, + "RETURNDATASIZE": RETURNDATASIZE, + "RETURNDATACOPY": RETURNDATACOPY, } func StringToOp(str string) OpCode { From 87bbc432ab27aed8f5123a9739bc61e5258ad8fb Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Fri, 10 Mar 2017 20:03:13 +0100 Subject: [PATCH 11/13] core/vm: separated fork instruction sets --- core/vm/gas_table.go | 29 +++++++++++++++ core/vm/instructions.go | 25 ------------- core/vm/interpreter.go | 9 ++++- core/vm/jump_table.go | 81 +++++++++++++++++++++++++---------------- core/vm/memory_table.go | 7 ++++ 5 files changed, 94 insertions(+), 57 deletions(-) diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 49ab2ed062..f1e32a50e5 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -429,6 +429,35 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St return gas, nil } +func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + panic("verify this one") + + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + var overflow bool + if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow { + return 0, errGasUintOverflow + } + + cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) + if err != nil { + return 0, err + } + // Replace the stack item with the new gas calculation. This means that + // either the original item is left on the stack or the item is replaced by: + // (availableGas - gas) * 63 / 64 + // We replace the stack item so that it's available when the opCall instruction is + // called. + stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) + + if gas, overflow = math.SafeAdd(gas, cg); overflow { + return 0, errGasUintOverflow + } + return gas, nil +} + func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { return GasFastestStep, nil } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index dd41202687..065db0561a 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -574,11 +574,6 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S } func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // EIP116 availability check; return an invalid opcode error on fault - if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) { - return nil, fmt.Errorf("invalid opcode %x", STATIC_CALL) - } - // pop gas gas := stack.pop().Uint64() // pop address @@ -675,12 +670,6 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack } func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // if not homestead return an error. DELEGATECALL is not supported - // during pre-homestead. - if !evm.ChainConfig().IsHomestead(evm.BlockNumber) { - return nil, fmt.Errorf("invalid opcode %x", DELEGATECALL) - } - gas, to, inOffset, inSize, outOffset, outSize := stack.pop().Uint64(), stack.pop(), stack.pop(), stack.pop(), stack.pop(), stack.pop() toAddr := common.BigToAddress(to) @@ -709,12 +698,6 @@ func opReturn(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S } func opRevert(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - // if not metropolis return an error. REVERT is not supported - // during pre-metropolis. - if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) { - return nil, fmt.Errorf("invalid opcode %x", REVERT) - } - offset, size := stack.pop(), stack.pop() ret := memory.GetPtr(offset.Int64(), size.Int64()) @@ -736,19 +719,11 @@ func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack * } func opReturnDataSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) { - return nil, fmt.Errorf("invalid opcode %x", RETURNDATASIZE) - } - stack.push(evm.interpreter.intPool.get().SetUint64(uint64(len(memory.lastReturn)))) return nil, nil } func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - if !evm.ChainConfig().IsMetropolis(evm.BlockNumber) { - return nil, fmt.Errorf("invalid opcode %x", RETURNDATACOPY) - } - var ( mOff = stack.pop() cOff = stack.pop() diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index b003684c08..f571744739 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -71,7 +71,14 @@ func NewInterpreter(env *EVM, cfg Config) *Interpreter { // the jump table was initialised. If it was not // we'll set the default jump table. if !cfg.JumpTable[STOP].valid { - cfg.JumpTable = defaultJumpTable + switch { + case env.ChainConfig().IsMetropolis(env.BlockNumber): + cfg.JumpTable = metropolisInstructionSet + case env.ChainConfig().IsHomestead(env.BlockNumber): + cfg.JumpTable = homesteadInstructionSet + default: + cfg.JumpTable = baseInstructionSet + } } return &Interpreter{ diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 8e580b5c6a..2b3a477ef3 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -55,9 +55,57 @@ type operation struct { reverts bool } -var defaultJumpTable = NewJumpTable() +var ( + baseInstructionSet = NewBaseInstructionSet() + homesteadInstructionSet = NewHomesteadInstructionSet() + metropolisInstructionSet = NewMetropolisInstructionSet() +) -func NewJumpTable() [256]operation { +func NewMetropolisInstructionSet() [256]operation { + instructionSet := NewHomesteadInstructionSet() + instructionSet[STATIC_CALL] = operation{ + execute: opStaticCall, + gasCost: gasStaticCall, + validateStack: makeStackFunc(6, 1), + memorySize: memoryStaticCall, + valid: true, + } + instructionSet[REVERT] = operation{ + execute: opRevert, + gasCost: constGasFunc(GasFastestStep), + validateStack: makeStackFunc(2, 0), + valid: true, + reverts: true, + } + instructionSet[RETURNDATASIZE] = operation{ + execute: opReturnDataSize, + gasCost: constGasFunc(0), // TODO + validateStack: makeStackFunc(0, 1), + valid: true, + } + instructionSet[RETURNDATACOPY] = operation{ + execute: opReturnDataCopy, + gasCost: gasReturnDataCopy, + validateStack: makeStackFunc(3, 0), + memorySize: memoryReturnDataCopy, + valid: true, + } + return instructionSet +} + +func NewHomesteadInstructionSet() [256]operation { + instructionSet := NewBaseInstructionSet() + instructionSet[DELEGATECALL] = operation{ + execute: opDelegateCall, + gasCost: gasDelegateCall, + validateStack: makeStackFunc(6, 1), + memorySize: memoryDelegateCall, + valid: true, + } + return instructionSet +} + +func NewBaseInstructionSet() [256]operation { return [256]operation{ STOP: { execute: opStop, @@ -395,15 +443,6 @@ func NewJumpTable() [256]operation { validateStack: makeStackFunc(0, 1), valid: true, }, - // TODO: - // * Determine cost - REVERT: { - execute: opRevert, - gasCost: constGasFunc(GasFastestStep), - validateStack: makeStackFunc(2, 0), - valid: true, - reverts: true, - }, JUMPDEST: { execute: opJumpdest, gasCost: constGasFunc(params.JumpdestGas), @@ -829,19 +868,6 @@ func NewJumpTable() [256]operation { memorySize: memoryLog, valid: true, }, - RETURNDATASIZE: { - execute: opReturnDataSize, - gasCost: constGasFunc(0), // TODO - validateStack: makeStackFunc(0, 1), - valid: true, - }, - RETURNDATACOPY: { - execute: opReturnDataCopy, - gasCost: gasReturnDataCopy, - validateStack: makeStackFunc(3, 0), - memorySize: memoryReturnDataCopy, - valid: true, - }, CREATE: { execute: opCreate, gasCost: gasCreate, @@ -872,13 +898,6 @@ func NewJumpTable() [256]operation { halts: true, valid: true, }, - DELEGATECALL: { - execute: opDelegateCall, - gasCost: gasDelegateCall, - validateStack: makeStackFunc(6, 1), - memorySize: memoryDelegateCall, - valid: true, - }, SELFDESTRUCT: { execute: opSuicide, gasCost: gasSuicide, diff --git a/core/vm/memory_table.go b/core/vm/memory_table.go index 06d3fcb814..51bf21524d 100644 --- a/core/vm/memory_table.go +++ b/core/vm/memory_table.go @@ -62,6 +62,13 @@ func memoryDelegateCall(stack *Stack) *big.Int { return math.BigMax(x, y) } +func memoryStaticCall(stack *Stack) *big.Int { + x := calcMemSize(stack.Back(4), stack.Back(5)) + y := calcMemSize(stack.Back(2), stack.Back(3)) + + return math.BigMax(x, y) +} + func memoryReturn(stack *Stack) *big.Int { return calcMemSize(stack.Back(0), stack.Back(1)) } From 22ca13fa85de18093b87d924b58df9ce072077ba Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Mon, 13 Mar 2017 21:45:05 +0100 Subject: [PATCH 12/13] core/vm: renamed variables --- core/vm/evm.go | 3 ++ core/vm/interpreter.go | 76 +++++++++++++++++++++++------------------- params/config.go | 6 +++- 3 files changed, 50 insertions(+), 35 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 09197e14fe..8c8322bd16 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -91,6 +91,8 @@ type EVM struct { // chainConfig contains information about the current chain chainConfig *params.ChainConfig + // chain rules contains the chain rules for the current epoch + chainRules params.Rules // virtual machine configuration options used to initialise the // evm. vmConfig Config @@ -110,6 +112,7 @@ func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmCon StateDB: statedb, vmConfig: vmConfig, chainConfig: chainConfig, + chainRules: chainConfig.Rules(ctx.BlockNumber), } evm.interpreter = NewInterpreter(evm, vmConfig) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index f571744739..1614838cb5 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -46,18 +46,18 @@ type Config struct { DisableGasMetering bool // Enable recording of SHA3/keccak preimages EnablePreimageRecording bool - // JumpTable contains the EVM instruction table. This + // JumpTable contains the in instruction table. This // may me left uninitialised and will be set the default // table. JumpTable [256]operation } // Interpreter is used to run Ethereum based contracts and will utilise the -// passed environment to query external sources for state information. +// passed evmironment to query external sources for state information. // The Interpreter will run the byte code VM or JIT VM based on the passed // configuration. type Interpreter struct { - env *EVM + evm *EVM cfg Config gasTable params.GasTable intPool *intPool @@ -66,15 +66,15 @@ type Interpreter struct { } // NewInterpreter returns a new instance of the Interpreter. -func NewInterpreter(env *EVM, cfg Config) *Interpreter { +func NewInterpreter(evm *EVM, cfg Config) *Interpreter { // We use the STOP instruction whether to see // the jump table was initialised. If it was not // we'll set the default jump table. if !cfg.JumpTable[STOP].valid { switch { - case env.ChainConfig().IsMetropolis(env.BlockNumber): + case evm.ChainConfig().IsMetropolis(evm.BlockNumber): cfg.JumpTable = metropolisInstructionSet - case env.ChainConfig().IsHomestead(env.BlockNumber): + case evm.ChainConfig().IsHomestead(evm.BlockNumber): cfg.JumpTable = homesteadInstructionSet default: cfg.JumpTable = baseInstructionSet @@ -82,22 +82,36 @@ func NewInterpreter(env *EVM, cfg Config) *Interpreter { } return &Interpreter{ - env: env, + evm: evm, cfg: cfg, - gasTable: env.ChainConfig().GasTable(env.BlockNumber), + gasTable: evm.ChainConfig().GasTable(evm.BlockNumber), intPool: newIntPool(), } } +func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack *Stack) error { + if in.evm.chainRules.IsMetropolis { + if in.readonly { + // if the interpreter is operating in readonly mode, make sure no + // state-modifying operation is performed. + if operation.writes || + ((op == CALL || op == CALLCODE) && stack.Back(3).BitLen() > 0) { + return errWriteProtection + } + } + } + return nil +} + // Run loops and evaluates the contract's code with the given input data and returns // the return byte-slice and an error if one occured. // // It's important to note that any errors returned by the interpreter should be // considered a revert-and-consume-all-gas operation. No error specific checks -// should be handled to reduce complexity and errors further down the EVM. -func (evm *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret []byte, err error) { - evm.env.depth++ - defer func() { evm.env.depth-- }() +// should be handled to reduce complexity and errors further down the in. +func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret []byte, err error) { + in.evm.depth++ + defer func() { in.evm.depth-- }() // Don't bother with the execution if there's no code. if len(contract.Code) == 0 { @@ -123,37 +137,31 @@ func (evm *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret // User defer pattern to check for an error and, based on the error being nil or not, use all gas and return. defer func() { - if err != nil && evm.cfg.Debug { + if err != nil && in.cfg.Debug { // XXX For debugging //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d ERR = %v\n", pc, op, cost, stack.len(), err) // TODO update the tracer to accept uint64 instead of *big.Int g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost) - evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.depth, err) + in.cfg.Tracer.CaptureState(in.evm, pc, op, g, c, mem, stack, contract, in.evm.depth, err) } }() - log.Debug("EVM running contract", "hash", codehash[:]) + log.Debug("in running contract", "hash", codehash[:]) tstart := time.Now() - defer log.Debug("EVM finished running contract", "hash", codehash[:], "elapsed", time.Since(tstart)) + defer log.Debug("in finished running contract", "hash", codehash[:], "elapsed", time.Since(tstart)) // The Interpreter main run loop (contextual). This loop runs until either an // explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during - // the execution of one of the operations or until the evm.done is set by + // the execution of one of the operations or until the in.done is set by // the parent context.Context. - for atomic.LoadInt32(&evm.env.abort) == 0 { + for atomic.LoadInt32(&in.evm.abort) == 0 { // Get the memory location of pc op = contract.GetOp(pc) // get the operation from the jump table matching the opcode - operation := evm.cfg.JumpTable[op] - // if the interpreter is operating in readonly mode, make sure no - // state-modifying operation is performed. - if evm.readonly && evm.env.chainConfig.IsMetropolis(evm.env.BlockNumber) { - if operation.writes || - ((op == CALL || op == CALLCODE) && stack.Back(3).BitLen() > 0) { - return nil, errWriteProtection - } - + operation := in.cfg.JumpTable[op] + if err := in.enforceRestrictions(op, operation, stack); err != nil { + return nil, err } // if the op is invalid abort the process and return an error @@ -182,10 +190,10 @@ func (evm *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret } } - if !evm.cfg.DisableGasMetering { + if !in.cfg.DisableGasMetering { // consume the gas and return an error if not enough gas is available. // cost is explicitly set so that the capture state defer method cas get the proper cost - cost, err = operation.gasCost(evm.gasTable, evm.env, contract, stack, mem, memorySize) + cost, err = operation.gasCost(in.gasTable, in.evm, contract, stack, mem, memorySize) if err != nil || !contract.UseGas(cost) { return nil, ErrOutOfGas } @@ -194,25 +202,25 @@ func (evm *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret mem.Resize(memorySize) } - if evm.cfg.Debug { + if in.cfg.Debug { // TODO update the tracer to accept uint64 instead of *big.Int g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost) - evm.cfg.Tracer.CaptureState(evm.env, pc, op, g, c, mem, stack, contract, evm.env.depth, err) + in.cfg.Tracer.CaptureState(in.evm, pc, op, g, c, mem, stack, contract, in.evm.depth, err) } // XXX For debugging //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d\n", pc, op, cost, stack.len()) // execute the operation - res, err := operation.execute(&pc, evm.env, contract, mem, stack) + res, err := operation.execute(&pc, in.evm, contract, mem, stack) // verifyPool is a build flag. Pool verification makes sure the integrity // of the integer pool by comparing values to a default value. if verifyPool { - verifyIntegerPool(evm.intPool) + verifyIntegerPool(in.intPool) } // checks whether the operation should revert state. if operation.reverts { - evm.env.StateDB.RevertToSnapshot(snapshot) + in.evm.StateDB.RevertToSnapshot(snapshot) } switch { diff --git a/params/config.go b/params/config.go index b29371960d..be00b9f1f8 100644 --- a/params/config.go +++ b/params/config.go @@ -255,5 +255,9 @@ type Rules struct { } func (c *ChainConfig) Rules(num *big.Int) Rules { - return Rules{ChainId: new(big.Int).Set(c.ChainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsMetropolis: c.IsMetropolis(num)} + chainId := c.ChainId + if chainId == nil { + chainId = new(big.Int) + } + return Rules{ChainId: new(big.Int).Set(chainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsMetropolis: c.IsMetropolis(num)} } From 363cfd850f2d24ef41628ba49ee3270791af250f Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Sun, 26 Mar 2017 10:50:27 +0200 Subject: [PATCH 13/13] consensus, core/vm, params: fixed rebase issues --- consensus/ethash/consensus.go | 33 +++++++++++++++++---------------- core/chain_makers.go | 2 +- core/vm/interpreter.go | 9 ++------- params/config.go | 4 ++-- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 7cfcf9bca5..d65fe4af96 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -308,8 +308,8 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent * func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Header) *big.Int { next := new(big.Int).Add(parent.Number, common.Big1) switch { - case config.IsEIP100(next): - return CalcDifficultyMetropolis(time, parent) + case config.IsMetropolis(next): + return calcDifficultyMetropolis(time, parent) case config.IsHomestead(next): return calcDifficultyHomestead(time, parent) default: @@ -320,11 +320,12 @@ func CalcDifficulty(config *params.ChainConfig, time uint64, parent *types.Heade // Some weird constants to avoid constant memory allocs for them. var ( expDiffPeriod = big.NewInt(100000) + big9 = big.NewInt(9) big10 = big.NewInt(10) bigMinus99 = big.NewInt(-99) ) -func CalcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int { +func calcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int { bigTime := new(big.Int).SetUint64(time) bigParentTime := new(big.Int).Set(parent.Time) @@ -356,7 +357,7 @@ func CalcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int { // for the exponential factor periodCount := new(big.Int).Add(parent.Number, common.Big1) - periodCount.Div(periodCount, ExpDiffPeriod) + periodCount.Div(periodCount, expDiffPeriod) // the exponential factor, commonly referred to as "the bomb" // diff = diff + 2^(periodCount - 2) @@ -372,15 +373,15 @@ func CalcDifficultyMetropolis(time uint64, parent *types.Header) *big.Int { // calcDifficultyHomestead is the difficulty adjustment algorithm. It returns // the difficulty that a new block should have when created at time given the // parent block's time and difficulty. The calculation uses the Homestead rules. -func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { +func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int { // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki // algorithm: // diff = (parent_diff + // (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) // ) + 2^(periodCount - 2) - bigTime := new(big.Int).SetUint64(time) - bigParentTime := new(big.Int).SetUint64(parentTime) + bigTime := new(big.Int).Set(parent.Time) + bigParentTime := new(big.Int).Set(parent.Time) // holds intermediate values to make the algo easier to read & audit x := new(big.Int) @@ -396,16 +397,16 @@ func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff * x.Set(bigMinus99) } // (parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) - y.Div(parentDiff, params.DifficultyBoundDivisor) + y.Div(parent.Difficulty, params.DifficultyBoundDivisor) x.Mul(y, x) - x.Add(parentDiff, x) + x.Add(parent.Difficulty, x) // minimum difficulty can ever be (before exponential factor) if x.Cmp(params.MinimumDifficulty) < 0 { x.Set(params.MinimumDifficulty) } // for the exponential factor - periodCount := new(big.Int).Add(parentNumber, common.Big1) + periodCount := new(big.Int).Add(parent.Number, common.Big1) periodCount.Div(periodCount, expDiffPeriod) // the exponential factor, commonly referred to as "the bomb" @@ -421,25 +422,25 @@ func calcDifficultyHomestead(time, parentTime uint64, parentNumber, parentDiff * // calcDifficultyFrontier is the difficulty adjustment algorithm. It returns the // difficulty that a new block should have when created at time given the parent // block's time and difficulty. The calculation uses the Frontier rules. -func calcDifficultyFrontier(time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int { +func calcDifficultyFrontier(time uint64, parent *types.Header) *big.Int { diff := new(big.Int) - adjust := new(big.Int).Div(parentDiff, params.DifficultyBoundDivisor) + adjust := new(big.Int).Div(parent.Difficulty, params.DifficultyBoundDivisor) bigTime := new(big.Int) bigParentTime := new(big.Int) bigTime.SetUint64(time) - bigParentTime.SetUint64(parentTime) + bigParentTime.Set(parent.Time) if bigTime.Sub(bigTime, bigParentTime).Cmp(params.DurationLimit) < 0 { - diff.Add(parentDiff, adjust) + diff.Add(parent.Difficulty, adjust) } else { - diff.Sub(parentDiff, adjust) + diff.Sub(parent.Difficulty, adjust) } if diff.Cmp(params.MinimumDifficulty) < 0 { diff.Set(params.MinimumDifficulty) } - periodCount := new(big.Int).Add(parentNumber, common.Big1) + periodCount := new(big.Int).Add(parent.Number, common.Big1) periodCount.Div(periodCount, expDiffPeriod) if periodCount.Cmp(common.Big1) > 0 { // diff = diff + 2^(periodCount - 2) diff --git a/core/chain_makers.go b/core/chain_makers.go index 35655c68aa..c3b1de4ce2 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -142,7 +142,7 @@ func (b *BlockGen) OffsetTime(seconds int64) { if b.header.Time.Cmp(b.parent.Header().Time) <= 0 { panic("block time out of range") } - b.header.Difficulty = ethash.CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent) + b.header.Difficulty = ethash.CalcDifficulty(b.config, b.header.Time.Uint64(), b.parent.Header()) } // GenerateChain creates a chain of n blocks. The first block's diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 1614838cb5..28305ff680 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -18,7 +18,6 @@ package vm import ( "fmt" - "math/big" "sync/atomic" "time" @@ -140,9 +139,7 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret if err != nil && in.cfg.Debug { // XXX For debugging //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d ERR = %v\n", pc, op, cost, stack.len(), err) - // TODO update the tracer to accept uint64 instead of *big.Int - g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost) - in.cfg.Tracer.CaptureState(in.evm, pc, op, g, c, mem, stack, contract, in.evm.depth, err) + in.cfg.Tracer.CaptureState(in.evm, pc, op, contract.Gas, cost, mem, stack, contract, in.evm.depth, err) } }() @@ -203,9 +200,7 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret } if in.cfg.Debug { - // TODO update the tracer to accept uint64 instead of *big.Int - g, c := new(big.Int).SetUint64(contract.Gas), new(big.Int).SetUint64(cost) - in.cfg.Tracer.CaptureState(in.evm, pc, op, g, c, mem, stack, contract, in.evm.depth, err) + in.cfg.Tracer.CaptureState(in.evm, pc, op, contract.Gas, cost, mem, stack, contract, in.evm.depth, err) } // XXX For debugging //fmt.Printf("%04d: %8v cost = %-8d stack = %-8d\n", pc, op, cost, stack.len()) diff --git a/params/config.go b/params/config.go index be00b9f1f8..5b35e02a30 100644 --- a/params/config.go +++ b/params/config.go @@ -34,7 +34,7 @@ var ( EIP150Hash: MainNetHomesteadGasRepriceHash, EIP155Block: MainNetSpuriousDragon, EIP158Block: MainNetSpuriousDragon, - MetropolisBlock: MainNetMetropolis, + MetropolisBlock: MainNetMetropolisBlock, } // TestnetChainConfig is the chain parameters to run a node on the test network. @@ -47,7 +47,7 @@ var ( EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"), EIP155Block: big.NewInt(10), EIP158Block: big.NewInt(10), - MetropolisBlock: TestNetMetropolis, + MetropolisBlock: TestNetMetropolisBlock, } // AllProtocolChanges contains every protocol change (EIPs)