Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bls12381 support #387

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
4 changes: 2 additions & 2 deletions asserter/construction.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ func CurveType(
curve types.CurveType,
) error {
switch curve {
case types.Secp256k1, types.Secp256r1, types.Edwards25519, types.Tweedle, types.Pallas:
case types.Secp256k1, types.Secp256r1, types.Edwards25519, types.Tweedle, types.Pallas, types.Bls12381:
return nil
default:
return fmt.Errorf("%w: %s", ErrCurveTypeNotSupported, curve)
Expand Down Expand Up @@ -304,7 +304,7 @@ func SignatureType(
signature types.SignatureType,
) error {
switch signature {
case types.Ecdsa, types.EcdsaRecovery, types.Ed25519, types.Schnorr1, types.SchnorrPoseidon:
case types.Ecdsa, types.EcdsaRecovery, types.Ed25519, types.Schnorr1, types.SchnorrPoseidon, types.Bls12381BasicMpl, types.Bls12381AugMpl:
return nil
default:
return fmt.Errorf("%w: %s", ErrSignatureTypeNotSupported, signature)
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ require (
github.com/lucasjones/reggen v0.0.0-20180717132126-cdb49ff09d77
github.com/mitchellh/mapstructure v1.4.3
github.com/neilotoole/errgroup v0.1.6
github.com/nixberg/chacha-rng-go v0.1.0 // indirect
github.com/segmentio/fasthash v1.0.3
github.com/stretchr/testify v1.7.0
github.com/tidwall/gjson v1.14.0
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ github.com/naoina/go-stringutil v0.1.0/go.mod h1:XJ2SJL9jCtBh+P9q5btrd/Ylo8XwT/h
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416/go.mod h1:NBIhNtsFMo3G2szEBne+bO4gS192HuIYRqfvOWb4i1E=
github.com/neilotoole/errgroup v0.1.6 h1:PODGqPXdT5BC/zCYIMoTrwV+ujKcW+gBXM6Ye9Ve3R8=
github.com/neilotoole/errgroup v0.1.6/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C2S41udRnToE=
github.com/nixberg/chacha-rng-go v0.1.0/go.mod h1:iPf1i6Vcwgoue86dblORobEXNCd1PFQiysFiImawfCM=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
Expand Down
3 changes: 3 additions & 0 deletions keys/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ var (
ErrKeyGenPallasFailed = errors.New(
"keygen: error generating key pair for pallas curve type",
)
ErrKeyGenBls12381Failed = errors.New(
"keygen: error generating key pair for bls12381 curve type",
)
ErrCurveTypeNotSupported = errors.New("not a supported CurveType")

ErrSignUnsupportedPayloadSignatureType = errors.New(
Expand Down
33 changes: 33 additions & 0 deletions keys/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"math/big"

"github.com/btcsuite/btcd/btcec"
"github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig"
"github.com/coinbase/kryptology/pkg/signatures/schnorr/mina"

"github.com/coinbase/rosetta-sdk-go/asserter"
Expand Down Expand Up @@ -132,6 +133,20 @@ func ImportPrivateKey(privKeyHex string, curve types.CurveType) (*KeyPair, error
},
PrivateKey: priKeyBytes,
}
case types.Bls12381:
rawPrivKey := &bls_sig.SecretKey{}
_ = rawPrivKey.UnmarshalBinary(privKey)

pubKey, _ := rawPrivKey.GetPublicKey()
pubKeyBin, _ := pubKey.MarshalBinary()
priKeyBytes, _ := rawPrivKey.MarshalBinary()
keyPair = &KeyPair{
PublicKey: &types.PublicKey{
Bytes: pubKeyBin,
CurveType: curve,
},
PrivateKey: priKeyBytes,
}

default:
return nil, fmt.Errorf("%w: %s", ErrCurveTypeNotSupported, curve)
Expand Down Expand Up @@ -210,6 +225,22 @@ func GenerateKeypair(curve types.CurveType) (*KeyPair, error) {
CurveType: curve,
}

keyPair = &KeyPair{
PublicKey: pubKey,
PrivateKey: rawPrivKeyBytes,
}
case types.Bls12381:
rawPubKey, rawPrivKey, err := bls_sig.NewSigBasic().Keygen()
rawPubKeyBytes, _ := rawPubKey.MarshalBinary()
rawPrivKeyBytes, _ := rawPrivKey.MarshalBinary()
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrKeyGenBls12381Failed, err)
}
pubKey := &types.PublicKey{
Bytes: rawPubKeyBytes,
CurveType: curve,
}

keyPair = &KeyPair{
PublicKey: pubKey,
PrivateKey: rawPrivKeyBytes,
Expand Down Expand Up @@ -252,6 +283,8 @@ func (k *KeyPair) Signer() (Signer, error) {
return &SignerSecp256r1{k}, nil
case types.Pallas:
return &SignerPallas{k}, nil
case types.Bls12381:
return &SignerBls12381{k}, nil
default:
return nil, fmt.Errorf("%w: %s", ErrCurveTypeNotSupported, k.PublicKey.CurveType)
}
Expand Down
14 changes: 14 additions & 0 deletions keys/keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ func TestGenerateKeypairPallas(t *testing.T) {
assert.Len(t, keypair.PrivateKey, PrivKeyBytesLen)
}

func TestGenerateKeypairBls12381(t *testing.T) {
curve := types.Bls12381
keypair, err := GenerateKeypair(curve)

assert.NoError(t, err)
assert.Equal(t, keypair.PublicKey.CurveType, curve)
assert.Len(t, keypair.PrivateKey, PrivKeyBytesLen)
}

func mockKeyPair(privKey []byte, curveType types.CurveType) *KeyPair {
keypair, _ := GenerateKeypair(curveType)
keypair.PrivateKey = privKey
Expand Down Expand Up @@ -139,6 +148,11 @@ func TestImportPrivateKey(t *testing.T) {
types.Pallas,
nil,
},
"simple Bls12381": {
"3ffb736d41737fc1fac8856458650742bfd01997bd96dd016215828b16309f58",
types.Bls12381,
nil,
},
"short ed25519": {"asd", types.Secp256k1, ErrPrivKeyUndecodable},
"short Secp256k1": {"asd", types.Edwards25519, ErrPrivKeyUndecodable},
"short pallas": {"asd", types.Pallas, ErrPrivKeyUndecodable},
Expand Down
180 changes: 180 additions & 0 deletions keys/signer_bls12381.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// Copyright 2022 Coinbase, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package keys

import (
"errors"
"fmt"

"github.com/coinbase/kryptology/pkg/signatures/bls/bls_sig"
"github.com/coinbase/rosetta-sdk-go/asserter"
"github.com/coinbase/rosetta-sdk-go/types"
)

var ErrBlsTransactionValidationErr = errors.New("transaction with bls validation failed")

type SignerBls12381 struct {
KeyPair *KeyPair
}

func (s *SignerBls12381) PublicKey() *types.PublicKey {
return s.KeyPair.PublicKey
}

// Sign transaction payloads using a KeyPair
func (s *SignerBls12381) Sign(
payload *types.SigningPayload,
sigType types.SignatureType,
) (*types.Signature, error) {
err := s.KeyPair.IsValid()
if err != nil {
return nil, err
}

if !(payload.SignatureType == types.Bls12381BasicMpl || payload.SignatureType == types.Bls12381AugMpl || payload.SignatureType == "") {
return nil, fmt.Errorf(
"%w: expected %v or %v but got %v",
ErrSignUnsupportedPayloadSignatureType,
types.Bls12381BasicMpl,
types.Bls12381AugMpl,
payload.SignatureType,
)
}

// Generate private key bytes
privKeyBytes := s.KeyPair.PrivateKey
privKey := &bls_sig.SecretKey{}
_ = privKey.UnmarshalBinary(privKeyBytes)

switch sigType {
case types.Bls12381BasicMpl:
sigBytes, _ := signBasic(privKey, payload)

return &types.Signature{
SigningPayload: payload,
PublicKey: s.KeyPair.PublicKey,
SignatureType: payload.SignatureType,
Bytes: sigBytes,
}, nil
case types.Bls12381AugMpl:
sigBytes, _ := signAug(privKey, payload)

return &types.Signature{
SigningPayload: payload,
PublicKey: s.KeyPair.PublicKey,
SignatureType: payload.SignatureType,
Bytes: sigBytes,
}, nil
default:
return nil, fmt.Errorf(
"%w: expected %v or %v but got %v",
ErrSignUnsupportedSignatureType,
types.Bls12381BasicMpl,
types.Bls12381AugMpl,
sigType,
)
}
}

func signBasic(sk *bls_sig.SecretKey, payload *types.SigningPayload) ([]byte, error) {
bls := bls_sig.NewSigBasic()

sig, err := bls.Sign(sk, payload.Bytes)

if err != nil {
return nil, err
}
sigBytes, _ := sig.MarshalBinary()

return sigBytes, nil
}

func signAug(sk *bls_sig.SecretKey, payload *types.SigningPayload) ([]byte, error) {
// Domain separation tag for aug scheme
// according to section 4.2.2 in
// https://tools.ietf.org/html/draft-irtf-cfrg-bls-signature-03
bls := bls_sig.NewSigBasicWithDst("BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_AUG_")

sig, err := bls.Sign(sk, payload.Bytes)

if err != nil {
return nil, err
}
sigBytes, _ := sig.MarshalBinary()

return sigBytes, nil
}

// Verify verifies a Signature, by checking the validity of a Signature,
// the SigningPayload, and the PublicKey of the Signature.
func (s *SignerBls12381) Verify(signature *types.Signature) error {
pubKeyBytes := signature.PublicKey.Bytes
pubKey := &bls_sig.PublicKey{}
_ = pubKey.UnmarshalBinary(pubKeyBytes)

sigBytes := signature.Bytes
sig := &bls_sig.Signature{}
_ = sig.UnmarshalBinary(sigBytes)

err := asserter.Signatures([]*types.Signature{signature})
if err != nil {
return fmt.Errorf("%w: %s", ErrVerifyFailed, err)
}

switch signature.SignatureType {
case types.Bls12381BasicMpl:
return verifyBasic(pubKey, signature.SigningPayload.Bytes, sig)
case types.Bls12381AugMpl:
return verifyAug(pubKey, signature.SigningPayload.Bytes, sig)
default:
return fmt.Errorf(
"%w: expected %v or %v but got %v",
ErrVerifyUnsupportedPayloadSignatureType,
types.Bls12381BasicMpl,
types.Bls12381AugMpl,
signature.SignatureType,
)
}
}

func verifyBasic(pubKey *bls_sig.PublicKey, payload []byte, signature *bls_sig.Signature) error {
bls := bls_sig.NewSigBasic()
result, err := bls.Verify(pubKey, payload, signature)

if err != nil {
return err
}

if !result {
return fmt.Errorf("%w: %s", ErrVerifyFailed, "Verify failed")
}

return nil
}

func verifyAug(pubKey *bls_sig.PublicKey, payload []byte, signature *bls_sig.Signature) error {
bls := bls_sig.NewSigAug()
result, err := bls.Verify(pubKey, payload, signature)

if err != nil {
return err
}

if !result {
return fmt.Errorf("%w: %s", ErrVerifyFailed, "Verify failed")
}

return nil
}
Loading