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:
@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user