* 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>
		
			
				
	
	
		
			284 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			284 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package bls12381
 | 
						|
 | 
						|
import (
 | 
						|
	"bytes"
 | 
						|
	"crypto/rand"
 | 
						|
	"math/big"
 | 
						|
	"testing"
 | 
						|
 | 
						|
	"github.com/ethereum/go-ethereum/common"
 | 
						|
)
 | 
						|
 | 
						|
func (g *G1) one() *PointG1 {
 | 
						|
	one, _ := g.fromBytesUnchecked(
 | 
						|
		common.FromHex("" +
 | 
						|
			"17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb" +
 | 
						|
			"08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1",
 | 
						|
		),
 | 
						|
	)
 | 
						|
	return one
 | 
						|
}
 | 
						|
 | 
						|
func (g *G1) rand() *PointG1 {
 | 
						|
	k, err := rand.Int(rand.Reader, q)
 | 
						|
	if err != nil {
 | 
						|
		panic(err)
 | 
						|
	}
 | 
						|
	return g.MulScalar(&PointG1{}, g.one(), k)
 | 
						|
}
 | 
						|
 | 
						|
func TestG1Serialization(t *testing.T) {
 | 
						|
	g1 := NewG1()
 | 
						|
	for i := 0; i < fuz; i++ {
 | 
						|
		a := g1.rand()
 | 
						|
		buf := g1.ToBytes(a)
 | 
						|
		b, err := g1.FromBytes(buf)
 | 
						|
		if err != nil {
 | 
						|
			t.Fatal(err)
 | 
						|
		}
 | 
						|
		if !g1.Equal(a, b) {
 | 
						|
			t.Fatal("bad serialization from/to")
 | 
						|
		}
 | 
						|
	}
 | 
						|
	for i := 0; i < fuz; i++ {
 | 
						|
		a := g1.rand()
 | 
						|
		encoded := g1.EncodePoint(a)
 | 
						|
		b, err := g1.DecodePoint(encoded)
 | 
						|
		if err != nil {
 | 
						|
			t.Fatal(err)
 | 
						|
		}
 | 
						|
		if !g1.Equal(a, b) {
 | 
						|
			t.Fatal("bad serialization encode/decode")
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestG1IsOnCurve(t *testing.T) {
 | 
						|
	g := NewG1()
 | 
						|
	zero := g.Zero()
 | 
						|
	if !g.IsOnCurve(zero) {
 | 
						|
		t.Fatal("zero must be on curve")
 | 
						|
	}
 | 
						|
	one := new(fe).one()
 | 
						|
	p := &PointG1{*one, *one, *one}
 | 
						|
	if g.IsOnCurve(p) {
 | 
						|
		t.Fatal("(1, 1) is not on curve")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestG1AdditiveProperties(t *testing.T) {
 | 
						|
	g := NewG1()
 | 
						|
	t0, t1 := g.New(), g.New()
 | 
						|
	zero := g.Zero()
 | 
						|
	for i := 0; i < fuz; i++ {
 | 
						|
		a, b := g.rand(), g.rand()
 | 
						|
		g.Add(t0, a, zero)
 | 
						|
		if !g.Equal(t0, a) {
 | 
						|
			t.Fatal("a + 0 == a")
 | 
						|
		}
 | 
						|
		g.Add(t0, zero, zero)
 | 
						|
		if !g.Equal(t0, zero) {
 | 
						|
			t.Fatal("0 + 0 == 0")
 | 
						|
		}
 | 
						|
		g.Sub(t0, a, zero)
 | 
						|
		if !g.Equal(t0, a) {
 | 
						|
			t.Fatal("a - 0 == a")
 | 
						|
		}
 | 
						|
		g.Sub(t0, zero, zero)
 | 
						|
		if !g.Equal(t0, zero) {
 | 
						|
			t.Fatal("0 - 0 == 0")
 | 
						|
		}
 | 
						|
		g.Neg(t0, zero)
 | 
						|
		if !g.Equal(t0, zero) {
 | 
						|
			t.Fatal("- 0 == 0")
 | 
						|
		}
 | 
						|
		g.Sub(t0, zero, a)
 | 
						|
		g.Neg(t0, t0)
 | 
						|
		if !g.Equal(t0, a) {
 | 
						|
			t.Fatal(" - (0 - a) == a")
 | 
						|
		}
 | 
						|
		g.Double(t0, zero)
 | 
						|
		if !g.Equal(t0, zero) {
 | 
						|
			t.Fatal("2 * 0 == 0")
 | 
						|
		}
 | 
						|
		g.Double(t0, a)
 | 
						|
		g.Sub(t0, t0, a)
 | 
						|
		if !g.Equal(t0, a) || !g.IsOnCurve(t0) {
 | 
						|
			t.Fatal(" (2 * a) - a == a")
 | 
						|
		}
 | 
						|
		g.Add(t0, a, b)
 | 
						|
		g.Add(t1, b, a)
 | 
						|
		if !g.Equal(t0, t1) {
 | 
						|
			t.Fatal("a + b == b + a")
 | 
						|
		}
 | 
						|
		g.Sub(t0, a, b)
 | 
						|
		g.Sub(t1, b, a)
 | 
						|
		g.Neg(t1, t1)
 | 
						|
		if !g.Equal(t0, t1) {
 | 
						|
			t.Fatal("a - b == - ( b - a )")
 | 
						|
		}
 | 
						|
		c := g.rand()
 | 
						|
		g.Add(t0, a, b)
 | 
						|
		g.Add(t0, t0, c)
 | 
						|
		g.Add(t1, a, c)
 | 
						|
		g.Add(t1, t1, b)
 | 
						|
		if !g.Equal(t0, t1) {
 | 
						|
			t.Fatal("(a + b) + c == (a + c ) + b")
 | 
						|
		}
 | 
						|
		g.Sub(t0, a, b)
 | 
						|
		g.Sub(t0, t0, c)
 | 
						|
		g.Sub(t1, a, c)
 | 
						|
		g.Sub(t1, t1, b)
 | 
						|
		if !g.Equal(t0, t1) {
 | 
						|
			t.Fatal("(a - b) - c == (a - c) -b")
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestG1MultiplicativeProperties(t *testing.T) {
 | 
						|
	g := NewG1()
 | 
						|
	t0, t1 := g.New(), g.New()
 | 
						|
	zero := g.Zero()
 | 
						|
	for i := 0; i < fuz; i++ {
 | 
						|
		a := g.rand()
 | 
						|
		s1, s2, s3 := randScalar(q), randScalar(q), randScalar(q)
 | 
						|
		sone := big.NewInt(1)
 | 
						|
		g.MulScalar(t0, zero, s1)
 | 
						|
		if !g.Equal(t0, zero) {
 | 
						|
			t.Fatal(" 0 ^ s == 0")
 | 
						|
		}
 | 
						|
		g.MulScalar(t0, a, sone)
 | 
						|
		if !g.Equal(t0, a) {
 | 
						|
			t.Fatal(" a ^ 1 == a")
 | 
						|
		}
 | 
						|
		g.MulScalar(t0, zero, s1)
 | 
						|
		if !g.Equal(t0, zero) {
 | 
						|
			t.Fatal(" 0 ^ s == a")
 | 
						|
		}
 | 
						|
		g.MulScalar(t0, a, s1)
 | 
						|
		g.MulScalar(t0, t0, s2)
 | 
						|
		s3.Mul(s1, s2)
 | 
						|
		g.MulScalar(t1, a, s3)
 | 
						|
		if !g.Equal(t0, t1) {
 | 
						|
			t.Errorf(" (a ^ s1) ^ s2 == a ^ (s1 * s2)")
 | 
						|
		}
 | 
						|
		g.MulScalar(t0, a, s1)
 | 
						|
		g.MulScalar(t1, a, s2)
 | 
						|
		g.Add(t0, t0, t1)
 | 
						|
		s3.Add(s1, s2)
 | 
						|
		g.MulScalar(t1, a, s3)
 | 
						|
		if !g.Equal(t0, t1) {
 | 
						|
			t.Errorf(" (a ^ s1) + (a ^ s2) == a ^ (s1 + s2)")
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestG1MultiExpExpected(t *testing.T) {
 | 
						|
	g := NewG1()
 | 
						|
	one := g.one()
 | 
						|
	var scalars [2]*big.Int
 | 
						|
	var bases [2]*PointG1
 | 
						|
	scalars[0] = big.NewInt(2)
 | 
						|
	scalars[1] = big.NewInt(3)
 | 
						|
	bases[0], bases[1] = new(PointG1).Set(one), new(PointG1).Set(one)
 | 
						|
	expected, result := g.New(), g.New()
 | 
						|
	g.MulScalar(expected, one, big.NewInt(5))
 | 
						|
	_, _ = g.MultiExp(result, bases[:], scalars[:])
 | 
						|
	if !g.Equal(expected, result) {
 | 
						|
		t.Fatal("bad multi-exponentiation")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestG1MultiExpBatch(t *testing.T) {
 | 
						|
	g := NewG1()
 | 
						|
	one := g.one()
 | 
						|
	n := 1000
 | 
						|
	bases := make([]*PointG1, n)
 | 
						|
	scalars := make([]*big.Int, n)
 | 
						|
	// scalars: [s0,s1 ... s(n-1)]
 | 
						|
	// bases: [P0,P1,..P(n-1)] = [s(n-1)*G, s(n-2)*G ... s0*G]
 | 
						|
	for i, j := 0, n-1; i < n; i, j = i+1, j-1 {
 | 
						|
		scalars[j], _ = rand.Int(rand.Reader, big.NewInt(100000))
 | 
						|
		bases[i] = g.New()
 | 
						|
		g.MulScalar(bases[i], one, scalars[j])
 | 
						|
	}
 | 
						|
	// expected: s(n-1)*P0 + s(n-2)*P1 + s0*P(n-1)
 | 
						|
	expected, tmp := g.New(), g.New()
 | 
						|
	for i := 0; i < n; i++ {
 | 
						|
		g.MulScalar(tmp, bases[i], scalars[i])
 | 
						|
		g.Add(expected, expected, tmp)
 | 
						|
	}
 | 
						|
	result := g.New()
 | 
						|
	_, _ = g.MultiExp(result, bases, scalars)
 | 
						|
	if !g.Equal(expected, result) {
 | 
						|
		t.Fatal("bad multi-exponentiation")
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func TestG1MapToCurve(t *testing.T) {
 | 
						|
	for i, v := range []struct {
 | 
						|
		u        []byte
 | 
						|
		expected []byte
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			u:        make([]byte, 48),
 | 
						|
			expected: common.FromHex("11a9a0372b8f332d5c30de9ad14e50372a73fa4c45d5f2fa5097f2d6fb93bcac592f2e1711ac43db0519870c7d0ea415" + "092c0f994164a0719f51c24ba3788de240ff926b55f58c445116e8bc6a47cd63392fd4e8e22bdf9feaa96ee773222133"),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			u:        common.FromHex("07fdf49ea58e96015d61f6b5c9d1c8f277146a533ae7fbca2a8ef4c41055cd961fbc6e26979b5554e4b4f22330c0e16d"),
 | 
						|
			expected: common.FromHex("1223effdbb2d38152495a864d78eee14cb0992d89a241707abb03819a91a6d2fd65854ab9a69e9aacb0cbebfd490732c" + "0f925d61e0b235ecd945cbf0309291878df0d06e5d80d6b84aa4ff3e00633b26f9a7cb3523ef737d90e6d71e8b98b2d5"),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			u:        common.FromHex("1275ab3adbf824a169ed4b1fd669b49cf406d822f7fe90d6b2f8c601b5348436f89761bb1ad89a6fb1137cd91810e5d2"),
 | 
						|
			expected: common.FromHex("179d3fd0b4fb1da43aad06cea1fb3f828806ddb1b1fa9424b1e3944dfdbab6e763c42636404017da03099af0dcca0fd6" + "0d037cb1c6d495c0f5f22b061d23f1be3d7fe64d3c6820cfcd99b6b36fa69f7b4c1f4addba2ae7aa46fb25901ab483e4"),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			u:        common.FromHex("0e93d11d30de6d84b8578827856f5c05feef36083eef0b7b263e35ecb9b56e86299614a042e57d467fa20948e8564909"),
 | 
						|
			expected: common.FromHex("15aa66c77eded1209db694e8b1ba49daf8b686733afaa7b68c683d0b01788dfb0617a2e2d04c0856db4981921d3004af" + "0952bb2f61739dd1d201dd0a79d74cda3285403d47655ee886afe860593a8a4e51c5b77a22d2133e3a4280eaaaa8b788"),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			u:        common.FromHex("015a41481155d17074d20be6d8ec4d46632a51521cd9c916e265bd9b47343b3689979b50708c8546cbc2916b86cb1a3a"),
 | 
						|
			expected: common.FromHex("06328ce5106e837935e8da84bd9af473422e62492930aa5f460369baad9545defa468d9399854c23a75495d2a80487ee" + "094bfdfe3e552447433b5a00967498a3f1314b86ce7a7164c8a8f4131f99333b30a574607e301d5f774172c627fd0bca"),
 | 
						|
		},
 | 
						|
	} {
 | 
						|
		g := NewG1()
 | 
						|
		p0, err := g.MapToCurve(v.u)
 | 
						|
		if err != nil {
 | 
						|
			t.Fatal("map to curve fails", i, err)
 | 
						|
		}
 | 
						|
		if !bytes.Equal(g.ToBytes(p0), v.expected) {
 | 
						|
			t.Fatal("map to curve fails", i)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkG1Add(t *testing.B) {
 | 
						|
	g1 := NewG1()
 | 
						|
	a, b, c := g1.rand(), g1.rand(), PointG1{}
 | 
						|
	t.ResetTimer()
 | 
						|
	for i := 0; i < t.N; i++ {
 | 
						|
		g1.Add(&c, a, b)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkG1Mul(t *testing.B) {
 | 
						|
	g1 := NewG1()
 | 
						|
	a, e, c := g1.rand(), q, PointG1{}
 | 
						|
	t.ResetTimer()
 | 
						|
	for i := 0; i < t.N; i++ {
 | 
						|
		g1.MulScalar(&c, a, e)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func BenchmarkG1MapToCurve(t *testing.B) {
 | 
						|
	a := make([]byte, 48)
 | 
						|
	g1 := NewG1()
 | 
						|
	t.ResetTimer()
 | 
						|
	for i := 0; i < t.N; i++ {
 | 
						|
		_, err := g1.MapToCurve(a)
 | 
						|
		if err != nil {
 | 
						|
			t.Fatal(err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |