| 
7 | 7 | 	"math"  | 
8 | 8 | 	"math/big"  | 
9 | 9 | 	"slices"  | 
 | 10 | +	"strings"  | 
10 | 11 | 	"testing"  | 
11 | 12 | 
 
  | 
12 | 13 | 	"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"  | 
@@ -393,3 +394,130 @@ func TestKeccak256(t *testing.T) {  | 
393 | 394 | 
 
  | 
394 | 395 | 	require.Equal(t, expected, actual)  | 
395 | 396 | }  | 
 | 397 | + | 
 | 398 | +func TestBn254(t *testing.T) {  | 
 | 399 | +	const (  | 
 | 400 | +		Bn254G1X              = "1"  | 
 | 401 | +		Bn254G1Y              = "2"  | 
 | 402 | +		Bn254DoubleX          = "030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3"  | 
 | 403 | +		Bn254DoubleY          = "15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4"  | 
 | 404 | +		Bn254G2XIm            = "1800deef121f1e7641a819fe67140f7f8f87b140996fbbd1ba87fb145641f404"  | 
 | 405 | +		Bn254G2XRe            = "198e9393920d483a7260bfb731fb5db382322bc5b47fbf6c80f6321231df581"  | 
 | 406 | +		Bn254G2YIm            = "12c85ea5db8c6deb43baf7868f1c5341fd8ed84a82f89ed36e80b6a4a8dd22e1"  | 
 | 407 | +		Bn254G2YRe            = "090689d0585ff0756c27a122072274f89d4d1c6d2f9d3af03d86c6b29b53e2b"  | 
 | 408 | +		Bn254PairingPositive  = "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002203e205db4f19b37b60121b83a7333706db86431c6d835849957ed8c3928ad7927dc7234fd11d3e8c36c59277c3e6f149d5cd3cfa9a62aee49f8130962b4b3b9195e8aa5b7827463722b8c153931579d3505566b4edf48d498e185f0509de15204bb53b8977e5f92a0bc372742c4830944a59b4fe6b1c0466e2a6dad122b5d2e104316c97997c17267a1bb67365523b4388e1306d66ea6e4d8f4a4a4b65f5c7d06e286b49c56f6293b2cea30764f0d5eabe5817905468a41f09b77588f692e8b081070efe3d4913dde35bba2513c426d065dee815c478700cef07180fb6146182432428b1490a4f25053d4c20c8723a73de6f0681bd3a8fca41008a6c3c288252d50f18403272e96c10135f96db0f8d0aec25033ebdffb88d2e7956c9bb198ec072462211ebc0a2f042f993d5bd76caf4adb5e99610dcf7c1d992595e6976aa3"  | 
 | 409 | +		Bn254PairingNegative  = "0x142c9123c08a0d7f66d95f3ad637a06b95700bc525073b75610884ef45416e1610104c796f40bfeef3588e996c040d2a88c0b4b85afd2578327b99413c6fe820198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed275dc4a288d1afb3cbb1ac09187524c7db36395df7be3b99e673b13a075a65ec1d9befcd05a5323e6da4d435f3b617cdb3af83285c2df711ef39c01571827f9d"  | 
 | 410 | +		Bn254PairingInvalidG1 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000be00be00bebebebebebe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"  | 
 | 411 | +	)  | 
 | 412 | +	crypto := newCrypto()  | 
 | 413 | + | 
 | 414 | +	t.Run("Add", func(t *testing.T) {  | 
 | 415 | +		input := make([]byte, 128)  | 
 | 416 | +		writeBn254Field(t, Bn254G1X, input, 0)  | 
 | 417 | +		writeBn254Field(t, Bn254G1Y, input, 32)  | 
 | 418 | +		writeBn254Field(t, Bn254G1X, input, 64)  | 
 | 419 | +		writeBn254Field(t, Bn254G1Y, input, 96)  | 
 | 420 | + | 
 | 421 | +		resItem := crypto.bn254Add(nil, []stackitem.Item{stackitem.NewByteArray(input)})  | 
 | 422 | +		resBytes, err := resItem.TryBytes()  | 
 | 423 | +		require.NoError(t, err)  | 
 | 424 | + | 
 | 425 | +		expected := make([]byte, 64)  | 
 | 426 | +		writeBn254Field(t, Bn254DoubleX, expected, 0)  | 
 | 427 | +		writeBn254Field(t, Bn254DoubleY, expected, 32)  | 
 | 428 | +		require.Equal(t, expected, resBytes)  | 
 | 429 | +	})  | 
 | 430 | + | 
 | 431 | +	t.Run("Mul", func(t *testing.T) {  | 
 | 432 | +		input := make([]byte, 96)  | 
 | 433 | +		writeBn254Field(t, Bn254G1X, input, 0)  | 
 | 434 | +		writeBn254Field(t, Bn254G1Y, input, 32)  | 
 | 435 | +		writeBn254Field(t, "2", input, 64)  | 
 | 436 | + | 
 | 437 | +		resItem := crypto.bn254Mul(nil, []stackitem.Item{stackitem.NewByteArray(input)})  | 
 | 438 | +		resBytes, err := resItem.TryBytes()  | 
 | 439 | +		require.NoError(t, err)  | 
 | 440 | + | 
 | 441 | +		expected := make([]byte, 64)  | 
 | 442 | +		writeBn254Field(t, Bn254DoubleX, expected, 0)  | 
 | 443 | +		writeBn254Field(t, Bn254DoubleY, expected, 32)  | 
 | 444 | +		require.Equal(t, expected, resBytes)  | 
 | 445 | +	})  | 
 | 446 | + | 
 | 447 | +	t.Run("PairingGenerator", func(t *testing.T) {  | 
 | 448 | +		input := make([]byte, 192)  | 
 | 449 | +		writeBn254Field(t, Bn254G1X, input, 0)  | 
 | 450 | +		writeBn254Field(t, Bn254G1Y, input, 32)  | 
 | 451 | +		writeBn254Field(t, Bn254G2XIm, input, 64)  | 
 | 452 | +		writeBn254Field(t, Bn254G2XRe, input, 96)  | 
 | 453 | +		writeBn254Field(t, Bn254G2YIm, input, 128)  | 
 | 454 | +		writeBn254Field(t, Bn254G2YRe, input, 160)  | 
 | 455 | + | 
 | 456 | +		resItem := crypto.bn254Pairing(nil, []stackitem.Item{stackitem.NewByteArray(input)})  | 
 | 457 | +		resBytes, err := resItem.TryBytes()  | 
 | 458 | +		require.NoError(t, err)  | 
 | 459 | +		require.Equal(t, make([]byte, FieldElementLength), resBytes)  | 
 | 460 | +	})  | 
 | 461 | + | 
 | 462 | +	t.Run("PairingEmpty", func(t *testing.T) {  | 
 | 463 | +		resItem := crypto.bn254Pairing(nil, []stackitem.Item{stackitem.NewByteArray(nil)})  | 
 | 464 | +		resBytes, err := resItem.TryBytes()  | 
 | 465 | +		require.NoError(t, err)  | 
 | 466 | +		expected := [FieldElementLength]byte{FieldElementLength - 1: 1}  | 
 | 467 | +		require.Equal(t, expected[:], resBytes)  | 
 | 468 | +	})  | 
 | 469 | + | 
 | 470 | +	t.Run("PairingVectors", func(t *testing.T) {  | 
 | 471 | +		testCases := []struct {  | 
 | 472 | +			hexStr   string  | 
 | 473 | +			lastByte byte  | 
 | 474 | +		}{  | 
 | 475 | +			{Bn254PairingPositive, 1},  | 
 | 476 | +			{Bn254PairingNegative, 0},  | 
 | 477 | +			{Bn254PairingInvalidG1, 0},  | 
 | 478 | +		}  | 
 | 479 | + | 
 | 480 | +		hexToBytes := func(hexStr string) []byte {  | 
 | 481 | +			if strings.HasPrefix(strings.ToLower(hexStr), "0x") {  | 
 | 482 | +				hexStr = hexStr[2:]  | 
 | 483 | +			}  | 
 | 484 | +			b, err := hex.DecodeString(hexStr)  | 
 | 485 | +			require.NoError(t, err)  | 
 | 486 | +			return b  | 
 | 487 | +		}  | 
 | 488 | + | 
 | 489 | +		for _, tc := range testCases {  | 
 | 490 | +			input := hexToBytes(tc.hexStr)  | 
 | 491 | + | 
 | 492 | +			resItem := crypto.bn254Pairing(nil, []stackitem.Item{stackitem.NewByteArray(input)})  | 
 | 493 | +			resBytes, err := resItem.TryBytes()  | 
 | 494 | +			require.NoError(t, err)  | 
 | 495 | + | 
 | 496 | +			expected := [FieldElementLength]byte{FieldElementLength - 1: tc.lastByte}  | 
 | 497 | +			require.Equal(t, expected[:], resBytes)  | 
 | 498 | +		}  | 
 | 499 | +	})  | 
 | 500 | + | 
 | 501 | +	t.Run("InvalidInputs", func(t *testing.T) {  | 
 | 502 | +		require.Panics(t, func() {  | 
 | 503 | +			crypto.bn254Add(nil, []stackitem.Item{stackitem.NewByteArray(nil)})  | 
 | 504 | +		})  | 
 | 505 | +		require.Panics(t, func() {  | 
 | 506 | +			crypto.bn254Mul(nil, []stackitem.Item{stackitem.NewByteArray(nil)})  | 
 | 507 | +		})  | 
 | 508 | +		require.Panics(t, func() {  | 
 | 509 | +			crypto.bn254Pairing(nil, []stackitem.Item{stackitem.NewByteArray([]byte{0})})  | 
 | 510 | +		})  | 
 | 511 | +	})  | 
 | 512 | +}  | 
 | 513 | + | 
 | 514 | +func writeBn254Field(t *testing.T, hexStr string, buf []byte, offset int) {  | 
 | 515 | +	if strings.HasPrefix(strings.ToLower(hexStr), "0x") {  | 
 | 516 | +		hexStr = hexStr[2:]  | 
 | 517 | +	}  | 
 | 518 | +	require.LessOrEqual(t, len(hexStr), 2*FieldElementLength)  | 
 | 519 | +	hexStr = strings.Repeat("0", 2*FieldElementLength-len(hexStr)) + hexStr  | 
 | 520 | +	b, err := hex.DecodeString(hexStr)  | 
 | 521 | +	require.NoError(t, err)  | 
 | 522 | +	copy(buf[offset:offset+FieldElementLength], b)  | 
 | 523 | +}  | 
0 commit comments