native: allow to use EQUAL opcode for BLS12-381 points comparison

That's the way how C# node handles equality checks for stackitem.Interop types
for these points. Ref. https://github.com/nspcc-dev/neo-go/issues/3002#issuecomment-1591220501.

Along the way, add GT case for CryptoLib's bls12381Equal method. It should be there since #2940.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
This commit is contained in:
Anna Shaleva 2023-06-14 16:42:11 +03:00
parent a2daad6ba6
commit 71bcb8bade
5 changed files with 275 additions and 109 deletions

View file

@ -178,32 +178,11 @@ func curveFromStackitem(si stackitem.Item) (elliptic.Curve, error) {
}
func (c *Crypto) bls12381Serialize(_ *interop.Context, args []stackitem.Item) stackitem.Item {
val := args[0].(*stackitem.Interop).Value()
var res []byte
switch p := val.(type) {
case *bls12381.G1Affine:
compressed := p.Bytes()
res = compressed[:]
case *bls12381.G1Jac:
g1Affine := new(bls12381.G1Affine)
g1Affine.FromJacobian(p)
compressed := g1Affine.Bytes()
res = compressed[:]
case *bls12381.G2Affine:
compressed := p.Bytes()
res = compressed[:]
case *bls12381.G2Jac:
g2Affine := new(bls12381.G2Affine)
g2Affine.FromJacobian(p)
compressed := g2Affine.Bytes()
res = compressed[:]
case *bls12381.GT:
compressed := p.Bytes()
res = compressed[:]
default:
panic(errors.New("unknown bls12381 point type"))
val, ok := args[0].(*stackitem.Interop).Value().(blsPoint)
if !ok {
panic(errors.New("not a bls12381 point"))
}
return stackitem.NewByteArray(res)
return stackitem.NewByteArray(val.Bytes())
}
func (c *Crypto) bls12381Deserialize(_ *interop.Context, args []stackitem.Item) stackitem.Item {
@ -235,51 +214,32 @@ func (c *Crypto) bls12381Deserialize(_ *interop.Context, args []stackitem.Item)
}
res = gt
}
return stackitem.NewInterop(res)
return stackitem.NewInterop(blsPoint{point: res})
}
func (c *Crypto) bls12381Equal(_ *interop.Context, args []stackitem.Item) stackitem.Item {
a := args[0].(*stackitem.Interop).Value()
b := args[1].(*stackitem.Interop).Value()
var res bool
switch x := a.(type) {
case *bls12381.G1Affine:
y, ok := b.(*bls12381.G1Affine)
if !ok {
panic(errors.New("y is not bls12381 G1Affine point"))
}
res = x.Equal(y)
case *bls12381.G1Jac:
y, ok := b.(*bls12381.G1Jac)
if !ok {
panic(errors.New("y is not bls12381 G1Jac point"))
}
res = x.Equal(y)
case *bls12381.G2Affine:
y, ok := b.(*bls12381.G2Affine)
if !ok {
panic(errors.New("y is not bls12381 G2Affine point"))
}
res = x.Equal(y)
case *bls12381.G2Jac:
y, ok := b.(*bls12381.G2Jac)
if !ok {
panic(errors.New("y is not bls12381 G2Jac point"))
}
res = x.Equal(y)
default:
panic(fmt.Errorf("unexpected x bls12381 point type: %T", x))
a, okA := args[0].(*stackitem.Interop).Value().(blsPoint)
b, okB := args[1].(*stackitem.Interop).Value().(blsPoint)
if !(okA && okB) {
panic("some of the arguments are not a bls12381 point")
}
res, err := a.EqualsCheckType(b)
if err != nil {
panic(err)
}
return stackitem.NewBool(res)
}
func (c *Crypto) bls12381Add(_ *interop.Context, args []stackitem.Item) stackitem.Item {
a := args[0].(*stackitem.Interop).Value()
b := args[1].(*stackitem.Interop).Value()
a, okA := args[0].(*stackitem.Interop).Value().(blsPoint)
b, okB := args[1].(*stackitem.Interop).Value().(blsPoint)
if !(okA && okB) {
panic("some of the arguments are not a bls12381 point")
}
var res interface{}
switch x := a.(type) {
switch x := a.point.(type) {
case *bls12381.G1Affine:
switch y := b.(type) {
switch y := b.point.(type) {
case *bls12381.G1Affine:
xJac := new(bls12381.G1Jac)
xJac.FromAffine(x)
@ -296,7 +256,7 @@ func (c *Crypto) bls12381Add(_ *interop.Context, args []stackitem.Item) stackite
case *bls12381.G1Jac:
resJac := new(bls12381.G1Jac)
resJac.Set(x)
switch y := b.(type) {
switch y := b.point.(type) {
case *bls12381.G1Affine:
resJac.AddMixed(y)
case *bls12381.G1Jac:
@ -306,7 +266,7 @@ func (c *Crypto) bls12381Add(_ *interop.Context, args []stackitem.Item) stackite
}
res = resJac
case *bls12381.G2Affine:
switch y := b.(type) {
switch y := b.point.(type) {
case *bls12381.G2Affine:
xJac := new(bls12381.G2Jac)
xJac.FromAffine(x)
@ -323,7 +283,7 @@ func (c *Crypto) bls12381Add(_ *interop.Context, args []stackitem.Item) stackite
case *bls12381.G2Jac:
resJac := new(bls12381.G2Jac)
resJac.Set(x)
switch y := b.(type) {
switch y := b.point.(type) {
case *bls12381.G2Affine:
resJac.AddMixed(y)
case *bls12381.G2Jac:
@ -335,7 +295,7 @@ func (c *Crypto) bls12381Add(_ *interop.Context, args []stackitem.Item) stackite
case *bls12381.GT:
resGT := new(bls12381.GT)
resGT.Set(x)
switch y := b.(type) {
switch y := b.point.(type) {
case *bls12381.GT:
// It's multiplication, see https://github.com/neo-project/Neo.Cryptography.BLS12_381/issues/4.
resGT.Mul(x, y)
@ -346,7 +306,7 @@ func (c *Crypto) bls12381Add(_ *interop.Context, args []stackitem.Item) stackite
default:
panic(fmt.Errorf("unexpected bls12381 point type: %T", x))
}
return stackitem.NewInterop(res)
return stackitem.NewInterop(blsPoint{point: res})
}
func scalarFromBytes(bytes []byte, neg bool) (*fr.Element, error) {
@ -368,7 +328,10 @@ func scalarFromBytes(bytes []byte, neg bool) (*fr.Element, error) {
}
func (c *Crypto) bls12381Mul(_ *interop.Context, args []stackitem.Item) stackitem.Item {
a := args[0].(*stackitem.Interop).Value()
a, okA := args[0].(*stackitem.Interop).Value().(blsPoint)
if !okA {
panic("multiplier is not a bls12381 point")
}
mulBytes, err := args[1].TryBytes()
if err != nil {
panic(fmt.Errorf("invalid multiplier: %w", err))
@ -385,7 +348,7 @@ func (c *Crypto) bls12381Mul(_ *interop.Context, args []stackitem.Item) stackite
alpha.BigInt(alphaBi)
var res interface{}
switch x := a.(type) {
switch x := a.point.(type) {
case *bls12381.G1Affine:
// The result is in Jacobian form in the reference implementation.
g1Jac := new(bls12381.G1Jac)
@ -423,17 +386,20 @@ func (c *Crypto) bls12381Mul(_ *interop.Context, args []stackitem.Item) stackite
default:
panic(fmt.Errorf("unexpected bls12381 point type: %T", x))
}
return stackitem.NewInterop(res)
return stackitem.NewInterop(blsPoint{point: res})
}
func (c *Crypto) bls12381Pairing(_ *interop.Context, args []stackitem.Item) stackitem.Item {
a := args[0].(*stackitem.Interop).Value()
b := args[1].(*stackitem.Interop).Value()
a, okA := args[0].(*stackitem.Interop).Value().(blsPoint)
b, okB := args[1].(*stackitem.Interop).Value().(blsPoint)
if !(okA && okB) {
panic("some of the arguments are not a bls12381 point")
}
var (
x *bls12381.G1Affine
y *bls12381.G2Affine
)
switch p := a.(type) {
switch p := a.point.(type) {
case *bls12381.G1Affine:
x = p
case *bls12381.G1Jac:
@ -442,7 +408,7 @@ func (c *Crypto) bls12381Pairing(_ *interop.Context, args []stackitem.Item) stac
default:
panic(fmt.Errorf("unexpected bls12381 point type (g1): %T", x))
}
switch p := b.(type) {
switch p := b.point.(type) {
case *bls12381.G2Affine:
y = p
case *bls12381.G2Jac:
@ -455,7 +421,7 @@ func (c *Crypto) bls12381Pairing(_ *interop.Context, args []stackitem.Item) stac
if err != nil {
panic(fmt.Errorf("failed to perform pairing operation"))
}
return stackitem.NewInterop(interface{}(&gt))
return stackitem.NewInterop(blsPoint{&gt})
}
// Metadata implements the Contract interface.