// // Copyright Coinbase, Inc. All Rights Reserved. // // SPDX-License-Identifier: Apache-2.0 // package bbs import ( "errors" "fmt" "source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves" ) // PublicKey is a BBS+ verification key type PublicKey struct { value curves.PairingPoint } func (pk *PublicKey) Init(curve *curves.PairingCurve) *PublicKey { pk.value = curve.NewG2IdentityPoint() return pk } func (pk PublicKey) MarshalBinary() ([]byte, error) { return pk.value.ToAffineCompressed(), nil } func (pk *PublicKey) UnmarshalBinary(in []byte) error { value, err := pk.value.FromAffineCompressed(in) if err != nil { return err } var ok bool pk.value, ok = value.(curves.PairingPoint) if !ok { return errors.New("incorrect type conversion") } return nil } // Verify checks a signature where all messages are known to the verifier func (pk PublicKey) Verify(signature *Signature, generators *MessageGenerators, msgs []curves.Scalar) error { if generators.length < len(msgs) { return fmt.Errorf("not enough message generators") } if len(msgs) < 1 { return fmt.Errorf("invalid messages") } // Identity Point will always return true which is not what we want if pk.value.IsIdentity() { return fmt.Errorf("invalid public key") } if signature.a.IsIdentity() { return fmt.Errorf("invalid signature") } a, ok := pk.value.Generator().Mul(signature.e).Add(pk.value).(curves.PairingPoint) if !ok { return fmt.Errorf("not a valid point") } b, ok := computeB(signature.s, msgs, generators).Neg().(curves.PairingPoint) if !ok { return fmt.Errorf("not a valid point") } res := a.MultiPairing(signature.a, a, b, pk.value.Generator().(curves.PairingPoint)) if !res.IsOne() { return fmt.Errorf("invalid result") } return nil }