From 38d26d5f2da09d9998be95fe30aedbd9e0e8baca Mon Sep 17 00:00:00 2001 From: "simsonebsv@gmail.com" Date: Tue, 17 Aug 2021 18:56:00 +0530 Subject: [PATCH 1/2] SHA3-FIPS202 precompiled contracts addition --- core/vm/contracts.go | 64 +++++++++++++++++++ core/vm/contracts_test.go | 6 ++ .../precompiles/ecRecoverPublicKey.json | 14 ++++ core/vm/testdata/precompiles/sha3fips.json | 14 ++++ 4 files changed, 98 insertions(+) create mode 100644 core/vm/testdata/precompiles/ecRecoverPublicKey.json create mode 100644 core/vm/testdata/precompiles/sha3fips.json diff --git a/core/vm/contracts.go b/core/vm/contracts.go index 64dde7323c..dfc0a86304 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -42,6 +42,11 @@ import ( //lint:ignore SA1019 Needed for precompile "golang.org/x/crypto/ripemd160" + + //Needed for SHA3-256 FIPS202 + "encoding/hex" + + "golang.org/x/crypto/sha3" ) // PrecompiledContract is the basic interface for native Go contracts. The implementation @@ -103,6 +108,9 @@ var PrecompiledContractsApricotPhase2 = map[common.Address]StatefulPrecompiledCo genesisContractAddr: &deprecatedContract{}, nativeAssetBalanceAddr: &nativeAssetBalance{gasCost: params.AssetBalanceApricot}, nativeAssetCallAddr: &nativeAssetCall{gasCost: params.AssetCallApricot}, + + common.BytesToAddress([]byte{19}): newWrappedPrecompiledContract(&sha3fip{}), + common.BytesToAddress([]byte{20}): newWrappedPrecompiledContract(&ecrecoverPublicKey{}), } var ( @@ -1043,3 +1051,59 @@ func (c *bls12381MapG2) Run(input []byte) ([]byte, error) { // Encode the G2 point to 256 bytes return g.EncodePoint(r), nil } + +// SHA3-256 FIPS 202 standard implemented as a native contract. + +type sha3fip struct{} + +// TODO Check if the gas price calculation needs modification +// 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 *sha3fip) RequiredGas(input []byte) uint64 { + return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas +} +func (c *sha3fip) Run(input []byte) ([]byte, error) { + hexStr := common.Bytes2Hex(input) + pub, _ := hex.DecodeString(hexStr) + h := sha3.Sum256(pub[:]) + return h[:], nil +} + +// ECRECOVER implemented as a native contract. +type ecrecoverPublicKey struct{} + +func (c *ecrecoverPublicKey) RequiredGas(input []byte) uint64 { + return params.EcrecoverGas +} + +func (c *ecrecoverPublicKey) Run(input []byte) ([]byte, error) { + const ecrecoverPublicKeyInputLength = 128 + + input = common.RightPadBytes(input, ecrecoverPublicKeyInputLength) + // "input" is (hash, v, r, s), each 32 bytes + // but for ecrecover we want (r, s, v) + + r := new(big.Int).SetBytes(input[64:96]) + s := new(big.Int).SetBytes(input[96:128]) + v := input[63] + + // tighter sig s values input homestead only apply to tx sigs + if !allZero(input[32:63]) || !crypto.ValidateSignatureValues(v, r, s, false) { + return nil, nil + } + // We must make sure not to modify the 'input', so placing the 'v' along with + // the signature needs to be done on a new allocation + sig := make([]byte, 65) + copy(sig, input[64:128]) + sig[64] = v + // v needs to be at the end for libsecp256k1 + pubKey, err := crypto.Ecrecover(input[:32], sig) + // make sure the public key is a valid one + if err != nil { + return nil, nil + } + + return pubKey, nil +} diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 4b3614ba3c..0de6a2ac17 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -75,6 +75,8 @@ var allPrecompiles = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{16}): &bls12381Pairing{}, common.BytesToAddress([]byte{17}): &bls12381MapG1{}, common.BytesToAddress([]byte{18}): &bls12381MapG2{}, + common.BytesToAddress([]byte{19}): &sha3fip{}, + common.BytesToAddress([]byte{20}): &ecrecoverPublicKey{}, } // EIP-152 test vectors @@ -401,3 +403,7 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) { } benchmarkPrecompiled("0f", testcase, b) } + +func TestPrecompiledSHA3fips(t *testing.T) { testJson("sha3fips", "13", t) } + +func TestPrecompiledEcrecoverPublicKey(t *testing.T) { testJson("ecRecoverPublicKey", "14", t) } diff --git a/core/vm/testdata/precompiles/ecRecoverPublicKey.json b/core/vm/testdata/precompiles/ecRecoverPublicKey.json new file mode 100644 index 0000000000..8772906e5b --- /dev/null +++ b/core/vm/testdata/precompiles/ecRecoverPublicKey.json @@ -0,0 +1,14 @@ +[ + { + "Input": "c5d6c454e4d7a8e8a654f5ef96e8efe41d21a65b171b298925414aa3dc061e3700000000000000000000000000000000000000000000000000000000000000004011de30c04302a2352400df3d1459d6d8799580dceb259f45db1d99243a8d0c64f548b7776cb93e37579b830fc3efce41e12e0958cda9f8c5fcad682c610795", + "Expected": "0448250ebe88d77e0a12bcf530fe6a2cf1ac176945638d309b840d631940c93b78c2bd6d16f227a8877e3f1604cd75b9c5a8ab0cac95174a8a0a0f8ea9e4c10bca", + "Name": "Call ecrecoverPublicKey recoverable Key", + "Gas": 3000 + }, + { + "Input": "c5d6c454e4d7a8e8a654f5ef96e8efe41d21a65b171b298925414aa3dc061e37000000000000000000000000000000000000000000000000000000000000001b4011de30c04302a2352400df3d1459d6d8799580dceb259f45db1d99243a8d0c64f548b7776cb93e37579b830fc3efce41e12e0958cda9f8c5fcad682c610795", + "Expected": "", + "Name": "call ecrecoverPublicKey un-recoverable Key- Invalid 'v' parity", + "Gas": 3000 + } +] \ No newline at end of file diff --git a/core/vm/testdata/precompiles/sha3fips.json b/core/vm/testdata/precompiles/sha3fips.json new file mode 100644 index 0000000000..109e5c1a3d --- /dev/null +++ b/core/vm/testdata/precompiles/sha3fips.json @@ -0,0 +1,14 @@ +[ + { + "Input": "0448250ebe88d77e0a12bcf530fe6a2cf1ac176945638d309b840d631940c93b78c2bd6d16f227a8877e3f1604cd75b9c5a8ab0cac95174a8a0a0f8ea9e4c10bca", + "Expected": "c7647f7e251bf1bd70863c8693e93a4e77dd0c9a689073e987d51254317dc704", + "Name": "sha3fip", + "Gas": 96 + }, + { + "Input": "1234", + "Expected": "19becdc0e8d6dd4aa2c9c2983dbb9c61956a8ade69b360d3e6019f0bcd5557a9", + "Name": "sha3fip", + "Gas": 72 + } +] \ No newline at end of file From 3797c600e0bca0cab3f1bee146ca5da34477a968 Mon Sep 17 00:00:00 2001 From: "simsonebsv@gmail.com" Date: Tue, 17 Aug 2021 19:34:58 +0530 Subject: [PATCH 2/2] SHA3 FIPS gas calculation value change --- core/vm/contracts.go | 2 +- params/protocol_params.go | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/core/vm/contracts.go b/core/vm/contracts.go index dfc0a86304..ae4be93c94 100644 --- a/core/vm/contracts.go +++ b/core/vm/contracts.go @@ -1062,7 +1062,7 @@ type sha3fip 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 *sha3fip) RequiredGas(input []byte) uint64 { - return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas + return uint64(len(input)+31)/32*params.Sha3FipsWordGas + params.Sha3FipsGas } func (c *sha3fip) Run(input []byte) ([]byte, error) { hexStr := common.Bytes2Hex(input) diff --git a/params/protocol_params.go b/params/protocol_params.go index 3782ed6da3..f846e6ade8 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -158,6 +158,11 @@ const ( // asset transfer itself, which is a write to state storage. The cost of creating a new account and // normal value transfer is assessed separately from this cost. AssetCallApricot uint64 = 20000 + + //SHA3-FIPS Precompiled contracts gas price esstimation as per ethereum yellow paper appendix G + Sha3FipsGas uint64 = 30 // Once per SHA3-256 operation. + Sha3FipsWordGas uint64 = 6 // Once per word of the SHA3-256 operation's data. + ) // Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations