core/vm, crypto/bls12381, params: add bls12-381 elliptic curve precompiles (#21018)

* crypto: add bls12-381 elliptic curve wrapper

* params: add bls12-381 precompile gas parameters

* core/vm: add bls12-381 precompiles

* core/vm: add bls12-381 precompile tests

* go.mod, go.sum: use latest bls12381 lib

* core/vm: move point encode/decode functions to base library

* crypto/bls12381: introduce bls12-381 library init function

* crypto/bls12381: import bls12381 elliptic curve implementation

* go.mod, go.sum: remove bls12-381 library

* remove unsued frobenious coeffs

supress warning for inp that used in asm

* add mappings tests for zero inputs

fix swu g2 minus z inverse constant

* crypto/bls12381: fix typo

* crypto/bls12381: better comments for bls12381 constants

* crypto/bls12381: swu, use single conditional for e2

* crypto/bls12381: utils, delete empty line

* crypto/bls12381: utils, use FromHex for string to big

* crypto/bls12381: g1, g2, strict length check for FromBytes

* crypto/bls12381: field_element, comparision changes

* crypto/bls12381: change swu, isogeny constants with hex values

* core/vm: fix point multiplication comments

* core/vm: fix multiexp gas calculation and lookup for g1 and g2

* core/vm: simpler imput length check for multiexp and pairing precompiles

* core/vm: rm empty multiexp result declarations

* crypto/bls12381: remove modulus type definition

* crypto/bls12381: use proper init function

* crypto/bls12381: get rid of new lines at fatal desciprtions

* crypto/bls12-381: fix no-adx assembly multiplication

* crypto/bls12-381: remove old config function

* crypto/bls12381: update multiplication backend

this commit changes mul backend to 6limb eip1962 backend

mul assign operations are dropped

* core/vm/contracts_tests: externalize test vectors for precompiles

* core/vm/contracts_test: externalize failure-cases for precompiles

* core/vm: linting

* go.mod: tiny up sum file

* core/vm: fix goimports linter issues

* crypto/bls12381: build tags for plain ASM or ADX implementation

Co-authored-by: Martin Holst Swende <martin@swende.se>
Co-authored-by: Péter Szilágyi <peterke@gmail.com>
This commit is contained in:
kilic
2020-06-03 09:44:32 +03:00
committed by GitHub
parent 3f649d4852
commit 4fc678542d
53 changed files with 15578 additions and 493 deletions

View File

@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/blake2b"
"github.com/ethereum/go-ethereum/crypto/bls12381"
"github.com/ethereum/go-ethereum/crypto/bn256"
"github.com/ethereum/go-ethereum/params"
@ -77,6 +78,29 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{9}): &blake2F{},
}
// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
// contracts used in the Berlin release.
var PrecompiledContractsBerlin = 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}): &bn256AddIstanbul{},
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{10}): &bls12381G1Add{},
common.BytesToAddress([]byte{11}): &bls12381G1Mul{},
common.BytesToAddress([]byte{12}): &bls12381G1MultiExp{},
common.BytesToAddress([]byte{13}): &bls12381G2Add{},
common.BytesToAddress([]byte{14}): &bls12381G2Mul{},
common.BytesToAddress([]byte{15}): &bls12381G2MultiExp{},
common.BytesToAddress([]byte{16}): &bls12381Pairing{},
common.BytesToAddress([]byte{17}): &bls12381MapG1{},
common.BytesToAddress([]byte{18}): &bls12381MapG2{},
}
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
func RunPrecompiledContract(p PrecompiledContract, input []byte, contract *Contract) (ret []byte, err error) {
gas := p.RequiredGas(input)
@ -502,3 +526,426 @@ func (c *blake2F) Run(input []byte) ([]byte, error) {
}
return output, nil
}
var (
errBLS12381InvalidInputLength = errors.New("invalid input length")
errBLS12381InvalidFieldElementTopBytes = errors.New("invalid field element top bytes")
errBLS12381G1PointSubgroup = errors.New("g1 point is not on correct subgroup")
errBLS12381G2PointSubgroup = errors.New("g2 point is not on correct subgroup")
)
// bls12381G1Add implements EIP-2537 G1Add precompile.
type bls12381G1Add struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G1Add) RequiredGas(input []byte) uint64 {
return params.Bls12381G1AddGas
}
func (c *bls12381G1Add) Run(input []byte) ([]byte, error) {
// Implements EIP-2537 G1Add precompile.
// > G1 addition call expects `256` bytes as an input that is interpreted as byte concatenation of two G1 points (`128` bytes each).
// > Output is an encoding of addition operation result - single G1 point (`128` bytes).
if len(input) != 256 {
return nil, errBLS12381InvalidInputLength
}
var err error
var p0, p1 *bls12381.PointG1
// Initialize G1
g := bls12381.NewG1()
// Decode G1 point p_0
if p0, err = g.DecodePoint(input[:128]); err != nil {
return nil, err
}
// Decode G1 point p_1
if p1, err = g.DecodePoint(input[128:]); err != nil {
return nil, err
}
// Compute r = p_0 + p_1
r := g.New()
g.Add(r, p0, p1)
// Encode the G1 point result into 128 bytes
return g.EncodePoint(r), nil
}
// bls12381G1Mul implements EIP-2537 G1Mul precompile.
type bls12381G1Mul struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G1Mul) RequiredGas(input []byte) uint64 {
return params.Bls12381G1MulGas
}
func (c *bls12381G1Mul) Run(input []byte) ([]byte, error) {
// Implements EIP-2537 G1Mul precompile.
// > G1 multiplication call expects `160` bytes as an input that is interpreted as byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
// > Output is an encoding of multiplication operation result - single G1 point (`128` bytes).
if len(input) != 160 {
return nil, errBLS12381InvalidInputLength
}
var err error
var p0 *bls12381.PointG1
// Initialize G1
g := bls12381.NewG1()
// Decode G1 point
if p0, err = g.DecodePoint(input[:128]); err != nil {
return nil, err
}
// Decode scalar value
e := new(big.Int).SetBytes(input[128:])
// Compute r = e * p_0
r := g.New()
g.MulScalar(r, p0, e)
// Encode the G1 point into 128 bytes
return g.EncodePoint(r), nil
}
// bls12381G1MultiExp implements EIP-2537 G1MultiExp precompile.
type bls12381G1MultiExp struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G1MultiExp) RequiredGas(input []byte) uint64 {
// Calculate G1 point, scalar value pair length
k := len(input) / 160
if k == 0 {
// Return 0 gas for small input length
return 0
}
// Lookup discount value for G1 point, scalar value pair length
maxDiscountLen := len(params.Bls12381MultiExpDiscountTable)
if k > maxDiscountLen {
k = maxDiscountLen
}
discount := params.Bls12381MultiExpDiscountTable[k-1]
// Calculate gas and return the result
return (uint64(k) * params.Bls12381G1MulGas * discount) / 1000
}
func (c *bls12381G1MultiExp) Run(input []byte) ([]byte, error) {
// Implements EIP-2537 G1MultiExp precompile.
// G1 multiplication call expects `160*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G1 point (`128` bytes) and encoding of a scalar value (`32` bytes).
// Output is an encoding of multiexponentiation operation result - single G1 point (`128` bytes).
k := len(input) / 160
if len(input) == 0 || len(input)%160 != 0 {
return nil, errBLS12381InvalidInputLength
}
var err error
points := make([]*bls12381.PointG1, k)
scalars := make([]*big.Int, k)
// Initialize G1
g := bls12381.NewG1()
// Decode point scalar pairs
for i := 0; i < k; i++ {
off := 160 * i
t0, t1, t2 := off, off+128, off+160
// Decode G1 point
if points[i], err = g.DecodePoint(input[t0:t1]); err != nil {
return nil, err
}
// Decode scalar value
scalars[i] = new(big.Int).SetBytes(input[t1:t2])
}
// Compute r = e_0 * p_0 + e_1 * p_1 + ... + e_(k-1) * p_(k-1)
r := g.New()
g.MultiExp(r, points, scalars)
// Encode the G1 point to 128 bytes
return g.EncodePoint(r), nil
}
// bls12381G2Add implements EIP-2537 G2Add precompile.
type bls12381G2Add struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G2Add) RequiredGas(input []byte) uint64 {
return params.Bls12381G2AddGas
}
func (c *bls12381G2Add) Run(input []byte) ([]byte, error) {
// Implements EIP-2537 G2Add precompile.
// > G2 addition call expects `512` bytes as an input that is interpreted as byte concatenation of two G2 points (`256` bytes each).
// > Output is an encoding of addition operation result - single G2 point (`256` bytes).
if len(input) != 512 {
return nil, errBLS12381InvalidInputLength
}
var err error
var p0, p1 *bls12381.PointG2
// Initialize G2
g := bls12381.NewG2()
r := g.New()
// Decode G2 point p_0
if p0, err = g.DecodePoint(input[:256]); err != nil {
return nil, err
}
// Decode G2 point p_1
if p1, err = g.DecodePoint(input[256:]); err != nil {
return nil, err
}
// Compute r = p_0 + p_1
g.Add(r, p0, p1)
// Encode the G2 point into 256 bytes
return g.EncodePoint(r), nil
}
// bls12381G2Mul implements EIP-2537 G2Mul precompile.
type bls12381G2Mul struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G2Mul) RequiredGas(input []byte) uint64 {
return params.Bls12381G2MulGas
}
func (c *bls12381G2Mul) Run(input []byte) ([]byte, error) {
// Implements EIP-2537 G2MUL precompile logic.
// > G2 multiplication call expects `288` bytes as an input that is interpreted as byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
// > Output is an encoding of multiplication operation result - single G2 point (`256` bytes).
if len(input) != 288 {
return nil, errBLS12381InvalidInputLength
}
var err error
var p0 *bls12381.PointG2
// Initialize G2
g := bls12381.NewG2()
// Decode G2 point
if p0, err = g.DecodePoint(input[:256]); err != nil {
return nil, err
}
// Decode scalar value
e := new(big.Int).SetBytes(input[256:])
// Compute r = e * p_0
r := g.New()
g.MulScalar(r, p0, e)
// Encode the G2 point into 256 bytes
return g.EncodePoint(r), nil
}
// bls12381G2MultiExp implements EIP-2537 G2MultiExp precompile.
type bls12381G2MultiExp struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381G2MultiExp) RequiredGas(input []byte) uint64 {
// Calculate G2 point, scalar value pair length
k := len(input) / 288
if k == 0 {
// Return 0 gas for small input length
return 0
}
// Lookup discount value for G2 point, scalar value pair length
maxDiscountLen := len(params.Bls12381MultiExpDiscountTable)
if k > maxDiscountLen {
k = maxDiscountLen
}
discount := params.Bls12381MultiExpDiscountTable[k-1]
// Calculate gas and return the result
return (uint64(k) * params.Bls12381G2MulGas * discount) / 1000
}
func (c *bls12381G2MultiExp) Run(input []byte) ([]byte, error) {
// Implements EIP-2537 G2MultiExp precompile logic
// > G2 multiplication call expects `288*k` bytes as an input that is interpreted as byte concatenation of `k` slices each of them being a byte concatenation of encoding of G2 point (`256` bytes) and encoding of a scalar value (`32` bytes).
// > Output is an encoding of multiexponentiation operation result - single G2 point (`256` bytes).
k := len(input) / 288
if len(input) == 0 || len(input)%288 != 0 {
return nil, errBLS12381InvalidInputLength
}
var err error
points := make([]*bls12381.PointG2, k)
scalars := make([]*big.Int, k)
// Initialize G2
g := bls12381.NewG2()
// Decode point scalar pairs
for i := 0; i < k; i++ {
off := 288 * i
t0, t1, t2 := off, off+256, off+288
// Decode G1 point
if points[i], err = g.DecodePoint(input[t0:t1]); err != nil {
return nil, err
}
// Decode scalar value
scalars[i] = new(big.Int).SetBytes(input[t1:t2])
}
// Compute r = e_0 * p_0 + e_1 * p_1 + ... + e_(k-1) * p_(k-1)
r := g.New()
g.MultiExp(r, points, scalars)
// Encode the G2 point to 256 bytes.
return g.EncodePoint(r), nil
}
// bls12381Pairing implements EIP-2537 Pairing precompile.
type bls12381Pairing struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381Pairing) RequiredGas(input []byte) uint64 {
return params.Bls12381PairingBaseGas + uint64(len(input)/384)*params.Bls12381PairingPerPairGas
}
func (c *bls12381Pairing) Run(input []byte) ([]byte, error) {
// Implements EIP-2537 Pairing precompile logic.
// > Pairing call expects `384*k` bytes as an inputs that is interpreted as byte concatenation of `k` slices. Each slice has the following structure:
// > - `128` bytes of G1 point encoding
// > - `256` bytes of G2 point encoding
// > Output is a `32` bytes where last single byte is `0x01` if pairing result is equal to multiplicative identity in a pairing target field and `0x00` otherwise
// > (which is equivalent of Big Endian encoding of Solidity values `uint256(1)` and `uin256(0)` respectively).
k := len(input) / 384
if len(input) == 0 || len(input)%384 != 0 {
return nil, errBLS12381InvalidInputLength
}
// Initialize BLS12-381 pairing engine
e := bls12381.NewPairingEngine()
g1, g2 := e.G1, e.G2
// Decode pairs
for i := 0; i < k; i++ {
off := 384 * i
t0, t1, t2 := off, off+128, off+384
// Decode G1 point
p1, err := g1.DecodePoint(input[t0:t1])
if err != nil {
return nil, err
}
// Decode G2 point
p2, err := g2.DecodePoint(input[t1:t2])
if err != nil {
return nil, err
}
// 'point is on curve' check already done,
// Here we need to apply subgroup checks.
if !g1.InCorrectSubgroup(p1) {
return nil, errBLS12381G1PointSubgroup
}
if !g2.InCorrectSubgroup(p2) {
return nil, errBLS12381G2PointSubgroup
}
// Update pairing engine with G1 and G2 ponits
e.AddPair(p1, p2)
}
// Prepare 32 byte output
out := make([]byte, 32)
// Compute pairing and set the result
if e.Check() {
out[31] = 1
}
return out, nil
}
// decodeBLS12381FieldElement decodes BLS12-381 elliptic curve field element.
// Removes top 16 bytes of 64 byte input.
func decodeBLS12381FieldElement(in []byte) ([]byte, error) {
if len(in) != 64 {
return nil, errors.New("invalid field element length")
}
// check top bytes
for i := 0; i < 16; i++ {
if in[i] != byte(0x00) {
return nil, errBLS12381InvalidFieldElementTopBytes
}
}
out := make([]byte, 48)
copy(out[:], in[16:])
return out, nil
}
// bls12381MapG1 implements EIP-2537 MapG1 precompile.
type bls12381MapG1 struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381MapG1) RequiredGas(input []byte) uint64 {
return params.Bls12381MapG1Gas
}
func (c *bls12381MapG1) Run(input []byte) ([]byte, error) {
// Implements EIP-2537 Map_To_G1 precompile.
// > Field-to-curve call expects `64` bytes an an input that is interpreted as a an element of the base field.
// > Output of this call is `128` bytes and is G1 point following respective encoding rules.
if len(input) != 64 {
return nil, errBLS12381InvalidInputLength
}
// Decode input field element
fe, err := decodeBLS12381FieldElement(input)
if err != nil {
return nil, err
}
// Initialize G1
g := bls12381.NewG1()
// Compute mapping
r, err := g.MapToCurve(fe)
if err != nil {
return nil, err
}
// Encode the G1 point to 256 bytes
return g.EncodePoint(r), nil
}
// bls12381MapG2 implements EIP-2537 MapG2 precompile.
type bls12381MapG2 struct{}
// RequiredGas returns the gas required to execute the pre-compiled contract.
func (c *bls12381MapG2) RequiredGas(input []byte) uint64 {
return params.Bls12381MapG2Gas
}
func (c *bls12381MapG2) Run(input []byte) ([]byte, error) {
// Implements EIP-2537 Map_FP2_TO_G2 precompile logic.
// > Field-to-curve call expects `128` bytes an an input that is interpreted as a an element of the quadratic extension field.
// > Output of this call is `256` bytes and is G2 point following respective encoding rules.
if len(input) != 128 {
return nil, errBLS12381InvalidInputLength
}
// Decode input field element
fe := make([]byte, 96)
c0, err := decodeBLS12381FieldElement(input[:64])
if err != nil {
return nil, err
}
copy(fe[48:], c0)
c1, err := decodeBLS12381FieldElement(input[64:])
if err != nil {
return nil, err
}
copy(fe[:48], c1)
// Initialize G2
g := bls12381.NewG2()
// Compute mapping
r, err := g.MapToCurve(fe)
if err != nil {
return nil, err
}
// Encode the G2 point to 256 bytes
return g.EncodePoint(r), nil
}