github.com/dusk-network/dusk-crypto@v0.1.3/bls/bls.go (about)

     1  // Package bls implements the compact BLS Multisignature construction which preappends the public key to the signature
     2  // according to the *plain public-key model*.
     3  // The form implemented uses an array of distinct keys (as in https://crypto.stanford.edu/~dabo/pubs/papers/BLSmultisig.html)
     4  // instead of the aggregated form (as in https://eprint.iacr.org/2018/483.pdf where {pk₁,...,pkₙ} would be appended to each pkᵢ
     5  //according to apk ← ∏ⁿᵢ₌₁ pk^H₁(pkᵢ, {pk₁,...,pkₙ})
     6  package bls
     7  
     8  import (
     9  	"crypto/rand"
    10  	"crypto/subtle"
    11  	"encoding/base64"
    12  	"encoding/hex"
    13  	"fmt"
    14  	"io"
    15  	"math/big"
    16  
    17  	"github.com/dusk-network/bn256"
    18  	"github.com/dusk-network/dusk-crypto/hash"
    19  	"github.com/pkg/errors"
    20  	"golang.org/x/crypto/sha3"
    21  )
    22  
    23  var (
    24  	// g1Str is the hexadecimal string representing the base specified for the G1 base point. It is taken from the cloudflare's bn256 implementation.
    25  	g1Str = "00000000000000000000000000000000000000000000000000000000000000018fb501e34aa387f9aa6fecb86184dc21ee5b88d120b5b59e185cac6c5e089665"
    26  
    27  	// g1Base is the base point specified for the G1 group. If one wants to use a
    28  	// different point, set this variable before using any public methods / structs of this package.
    29  	g1Base *bn256.G1
    30  
    31  	// g2Str is the hexadecimal string representing the base specified for the G1 base point.
    32  	g2Str = "012ecca446ff6f3d4d03c76e9b5c752f28bc37b364cb05ac4a37eb32e1c32459708f25386f72c9462b81597d65ae2092c4b97792155dcdaad32b8a6dd41792534c2db10ef5233b0fe3962b9ee6a4bbc2b5bde01a54f3513d42df972e128f31bf12274e5747e8cafacc3716cc8699db79b22f0e4ff3c23e898f694420a3be3087a5"
    33  
    34  	// g2Base is the base point specified for the G2 group. If one wants to use a
    35  	// different point, set this variable before using any public methods / structs of this package.
    36  	g2Base *bn256.G2
    37  )
    38  
    39  // TODO: We should probably transform BLS in a struct and delegate initialization to the code user. The motivation is that they might want to use a different curve altogether
    40  func init() {
    41  	g1Base = newG1Base(g1Str)
    42  	g2Base = newG2Base(g2Str)
    43  }
    44  
    45  // newG1 is the constructor for the G1 group as in the BN256 curve
    46  func newG1() *bn256.G1 {
    47  	return new(bn256.G1)
    48  }
    49  
    50  // newG2 is the constructor for the G2 group as in the BN256 curve
    51  func newG2() *bn256.G2 {
    52  	return new(bn256.G2)
    53  }
    54  
    55  // newG1Base is the initialization function for the G1Base point for BN256. It takes as input the HEX string representation of a base point
    56  func newG1Base(strRepr string) *bn256.G1 {
    57  	buff, err := hex.DecodeString(strRepr)
    58  	if err != nil {
    59  		panic(errors.Wrap(err, "bn256: can't decode base point on G1. Fatal error"))
    60  	}
    61  	g1Base = new(bn256.G1)
    62  
    63  	_, err = g1Base.Unmarshal(buff)
    64  	if err != nil {
    65  		panic(errors.Wrap(err, "bn256: can't decode base point on G1. Fatal error"))
    66  	}
    67  
    68  	return g1Base
    69  }
    70  
    71  // newG2Base is the initialization function for the G2Base point for BN256
    72  func newG2Base(strRepr string) *bn256.G2 {
    73  	buff, err := hex.DecodeString(strRepr)
    74  	if err != nil {
    75  		panic(errors.Wrap(err, "bn256: can't decode base point on G2. Fatal error"))
    76  	}
    77  	g2Base = new(bn256.G2)
    78  
    79  	_, err = g2Base.Unmarshal(buff)
    80  	if err != nil {
    81  		panic(errors.Wrap(err, "bn256: can't decode base point on G2. Fatal error"))
    82  	}
    83  
    84  	return g2Base
    85  }
    86  
    87  // SecretKey has "x" as secret for the BLS signature
    88  type SecretKey struct {
    89  	x *big.Int
    90  }
    91  
    92  // PublicKey is calculated as g^x
    93  type PublicKey struct {
    94  	gx *bn256.G2
    95  }
    96  
    97  // Apk is the short aggregated public key struct
    98  type Apk struct {
    99  	*PublicKey
   100  }
   101  
   102  // Signature is the plain public key model of the BLS signature being resilient to rogue key attack
   103  type Signature struct {
   104  	e *bn256.G1
   105  }
   106  
   107  // UnsafeSignature is the BLS Signature Struct not resilient to rogue-key attack
   108  type UnsafeSignature struct {
   109  	e *bn256.G1
   110  }
   111  
   112  // GenKeyPair generates Public and Private Keys
   113  func GenKeyPair(randReader io.Reader) (*PublicKey, *SecretKey, error) {
   114  	if randReader == nil {
   115  		randReader = rand.Reader
   116  	}
   117  	x, gx, err := bn256.RandomG2(randReader)
   118  
   119  	if err != nil {
   120  		return nil, nil, err
   121  	}
   122  
   123  	return &PublicKey{gx}, &SecretKey{x}, nil
   124  }
   125  
   126  // UnmarshalPk unmarshals a byte array into a BLS PublicKey
   127  func UnmarshalPk(b []byte) (*PublicKey, error) {
   128  	pk := &PublicKey{nil}
   129  	if err := pk.Unmarshal(b); err != nil {
   130  		return nil, err
   131  	}
   132  	return pk, nil
   133  }
   134  
   135  //hashFn is the hash function used to digest a message before mapping it to a point.
   136  var hashFn = sha3.New256
   137  
   138  // h0 is the hash-to-curve-point function
   139  // Hₒ : M -> Gₒ
   140  // TODO: implement the Elligator algorithm for deterministic random-looking hashing to BN256 point. See https://eprint.iacr.org/2014/043.pdf
   141  func h0(msg []byte) (*bn256.G1, error) {
   142  	hashed, err := hash.PerformHash(hashFn(), msg)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  	k := new(big.Int).SetBytes(hashed)
   147  	return newG1().ScalarBaseMult(k), nil
   148  }
   149  
   150  // h1 is the hashing function used in the modified BLS multi-signature construction
   151  // H₁: G₂->R
   152  func h1(pk *PublicKey) (*big.Int, error) {
   153  	// marshalling G2 into a []byte
   154  	pkb := pk.Marshal()
   155  	// hashing into Z
   156  	h, err := hash.PerformHash(hashFn(), pkb)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	return new(big.Int).SetBytes(h), nil
   162  }
   163  
   164  func pkt(pk *PublicKey) (*bn256.G2, error) {
   165  	t, err := h1(pk)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  
   170  	//TODO: maybe a bit inefficient to recreate G2 instances instead of mutating the underlying group
   171  	return newG2().ScalarMult(pk.gx, t), nil
   172  }
   173  
   174  // NewApk creates an Apk either from a public key or scratch
   175  func NewApk(pk *PublicKey) *Apk {
   176  	if pk == nil {
   177  		return nil
   178  	}
   179  
   180  	gx, _ := pkt(pk)
   181  	return &Apk{
   182  		PublicKey: &PublicKey{gx},
   183  	}
   184  }
   185  
   186  // Copy the APK by marshalling and unmarshalling the internals. It is somewhat
   187  // wasteful but does the job
   188  func (apk *Apk) Copy() *Apk {
   189  	g2 := new(bn256.G2)
   190  	b := apk.gx.Marshal()
   191  	// no need to check errors. We deal with well formed APKs
   192  	_, _ = g2.Unmarshal(b)
   193  
   194  	cpy := &Apk{
   195  		PublicKey: &PublicKey{g2},
   196  	}
   197  	return cpy
   198  }
   199  
   200  // UnmarshalApk unmarshals a byte array into an aggregated PublicKey
   201  func UnmarshalApk(b []byte) (*Apk, error) {
   202  	apk := &Apk{
   203  		PublicKey: &PublicKey{gx: nil},
   204  	}
   205  
   206  	if err := apk.Unmarshal(b); err != nil {
   207  		return nil, err
   208  	}
   209  	return apk, nil
   210  }
   211  
   212  // AggregateApk aggregates the public key according to the following formula:
   213  // apk ← ∏ⁿᵢ₌₁ pk^H₁(pkᵢ)
   214  func AggregateApk(pks []*PublicKey) (*Apk, error) {
   215  	var apk *Apk
   216  	for i, pk := range pks {
   217  		if i == 0 {
   218  			apk = NewApk(pk)
   219  			continue
   220  		}
   221  
   222  		if err := apk.Aggregate(pk); err != nil {
   223  			return nil, err
   224  		}
   225  	}
   226  
   227  	return apk, nil
   228  }
   229  
   230  // Aggregate a Public Key to the Apk struct
   231  // according to the formula pk^H₁(pkᵢ)
   232  func (apk *Apk) Aggregate(pk *PublicKey) error {
   233  	gxt, err := pkt(pk)
   234  	if err != nil {
   235  		return err
   236  	}
   237  
   238  	apk.gx.Add(apk.gx, gxt)
   239  	return nil
   240  }
   241  
   242  // AggregateBytes is a convenient method to aggregate the unmarshalled form of PublicKey directly
   243  func (apk *Apk) AggregateBytes(b []byte) error {
   244  	pk := &PublicKey{}
   245  	if err := pk.Unmarshal(b); err != nil {
   246  		return err
   247  	}
   248  	return apk.Aggregate(pk)
   249  }
   250  
   251  // Sign creates a signature from the private key and the public key pk
   252  func Sign(sk *SecretKey, pk *PublicKey, msg []byte) (*Signature, error) {
   253  	sig, err := UnsafeSign(sk, msg)
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  
   258  	return apkSigWrap(pk, sig)
   259  }
   260  
   261  // UnmarshalSignature unmarshals a byte array into a BLS signature
   262  func UnmarshalSignature(sig []byte) (*Signature, error) {
   263  	sigma := &Signature{}
   264  	if err := sigma.Unmarshal(sig); err != nil {
   265  		return nil, err
   266  	}
   267  	return sigma, nil
   268  }
   269  
   270  // Copy (inefficiently) the Signature by unmarshaling and marshaling the
   271  // embedded G1
   272  func (sigma *Signature) Copy() *Signature {
   273  	b := sigma.e.Marshal()
   274  	s := &Signature{
   275  		e: new(bn256.G1),
   276  	}
   277  	_, _ = s.e.Unmarshal(b)
   278  	return s
   279  }
   280  
   281  // Add creates an aggregated signature from a normal BLS Signature and related public key
   282  func (sigma *Signature) Add(pk *PublicKey, sig *UnsafeSignature) error {
   283  	other, err := apkSigWrap(pk, sig)
   284  	if err != nil {
   285  		return err
   286  	}
   287  
   288  	sigma.Aggregate(other)
   289  	return nil
   290  }
   291  
   292  // AggregateBytes is a shorthand for unmarshalling a byte array into a Signature and thus mutate Signature sigma by aggregating the unmarshalled signature
   293  func (sigma *Signature) AggregateBytes(other []byte) error {
   294  	sig := &Signature{e: nil}
   295  	if err := sig.Unmarshal(other); err != nil {
   296  		return err
   297  	}
   298  	sigma.Aggregate(sig)
   299  	return nil
   300  }
   301  
   302  // Aggregate two Signature
   303  func (sigma *Signature) Aggregate(other *Signature) *Signature {
   304  	sigma.e.Add(sigma.e, other.e)
   305  	return sigma
   306  }
   307  
   308  // Compress the signature to the 32 byte form
   309  func (sigma *Signature) Compress() []byte {
   310  	return sigma.e.Compress()
   311  }
   312  
   313  // Decompress reconstructs the 64 byte signature from the compressed form
   314  func (sigma *Signature) Decompress(x []byte) error {
   315  	e, err := bn256.Decompress(x)
   316  	if err != nil {
   317  		return err
   318  	}
   319  	sigma.e = e
   320  	return nil
   321  }
   322  
   323  // Marshal a Signature into a byte array
   324  func (sigma *Signature) Marshal() []byte {
   325  	return sigma.e.Marshal()
   326  }
   327  
   328  // Unmarshal a byte array into a Signature
   329  func (sigma *Signature) Unmarshal(msg []byte) error {
   330  	var err error
   331  	var e *bn256.G1
   332  	if len(msg) == 33 {
   333  		e, err = bn256.Decompress(msg)
   334  		if err != nil {
   335  			return err
   336  		}
   337  		sigma.e = e
   338  		return nil
   339  	}
   340  
   341  	e = newG1()
   342  	if _, err := e.Unmarshal(msg); err != nil {
   343  		return err
   344  	}
   345  	sigma.e = e
   346  	return nil
   347  }
   348  
   349  // apkSigWrap turns a BLS Signature into its modified construction
   350  func apkSigWrap(pk *PublicKey, signature *UnsafeSignature) (*Signature, error) {
   351  	// creating tᵢ by hashing PKᵢ
   352  	t, err := h1(pk)
   353  	if err != nil {
   354  		return nil, err
   355  	}
   356  
   357  	sigma := newG1()
   358  
   359  	sigma.ScalarMult(signature.e, t)
   360  
   361  	return &Signature{e: sigma}, nil
   362  }
   363  
   364  // Verify is the verification step of an aggregated apk signature
   365  func Verify(apk *Apk, msg []byte, sigma *Signature) error {
   366  	return verify(apk.gx, msg, sigma.e)
   367  }
   368  
   369  // VerifyBatch is the verification step of a batch of aggregated apk signatures
   370  // TODO: consider adding the possibility to handle non distinct messages (at batch level after aggregating APK)
   371  func VerifyBatch(apks []*Apk, msgs [][]byte, sigma *Signature) error {
   372  	if len(msgs) != len(apks) {
   373  		return fmt.Errorf(
   374  			"BLS Verify APK Batch: the nr of Public Keys (%d) and the nr. of messages (%d) do not match",
   375  			len(apks),
   376  			len(msgs),
   377  		)
   378  	}
   379  
   380  	pks := make([]*bn256.G2, len(apks))
   381  	for i, pk := range apks {
   382  		pks[i] = pk.gx
   383  	}
   384  
   385  	return verifyBatch(pks, msgs, sigma.e, false)
   386  }
   387  
   388  // UnsafeSign generates an UnsafeSignature being vulnerable to the rogue-key attack and therefore can only be used if the messages are distinct
   389  func UnsafeSign(key *SecretKey, msg []byte) (*UnsafeSignature, error) {
   390  	hash, err := h0(msg)
   391  	if err != nil {
   392  		return nil, err
   393  	}
   394  	p := newG1()
   395  	p.ScalarMult(hash, key.x)
   396  	return &UnsafeSignature{p}, nil
   397  }
   398  
   399  // Compress the signature to the 32 byte form
   400  func (usig *UnsafeSignature) Compress() []byte {
   401  	return usig.e.Compress()
   402  }
   403  
   404  // Decompress reconstructs the 64 byte signature from the compressed form
   405  func (usig *UnsafeSignature) Decompress(x []byte) error {
   406  	e, err := bn256.Decompress(x)
   407  	if err != nil {
   408  		return err
   409  	}
   410  	usig.e = e
   411  	return nil
   412  }
   413  
   414  // Marshal an UnsafeSignature into a byte array
   415  func (usig *UnsafeSignature) Marshal() []byte {
   416  	return usig.e.Marshal()
   417  }
   418  
   419  // Unmarshal a byte array into an UnsafeSignature
   420  func (usig *UnsafeSignature) Unmarshal(msg []byte) error {
   421  	e := newG1()
   422  	if _, err := e.Unmarshal(msg); err != nil {
   423  		return err
   424  	}
   425  	usig.e = e
   426  	return nil
   427  }
   428  
   429  // UnsafeAggregate combines signatures on distinct messages.
   430  func UnsafeAggregate(one, other *UnsafeSignature) *UnsafeSignature {
   431  	res := newG1()
   432  	res.Add(one.e, other.e)
   433  	return &UnsafeSignature{e: res}
   434  }
   435  
   436  // UnsafeBatch is a utility function to aggregate distinct messages
   437  // (if not distinct the scheme is vulnerable to chosen-key attack)
   438  func UnsafeBatch(sigs ...*UnsafeSignature) (*UnsafeSignature, error) {
   439  	var sum *UnsafeSignature
   440  	for i, sig := range sigs {
   441  		if i == 0 {
   442  			sum = sig
   443  		} else {
   444  			sum = UnsafeAggregate(sum, sig)
   445  		}
   446  	}
   447  
   448  	return sum, nil
   449  }
   450  
   451  // VerifyUnsafeBatch verifies a batch of messages signed with aggregated signature
   452  // the rogue-key attack is prevented by making all messages distinct
   453  func VerifyUnsafeBatch(pkeys []*PublicKey, msgList [][]byte, signature *UnsafeSignature) error {
   454  	g2s := make([]*bn256.G2, len(pkeys))
   455  	for i, pk := range pkeys {
   456  		g2s[i] = pk.gx
   457  	}
   458  	return verifyBatch(g2s, msgList, signature.e, false)
   459  }
   460  
   461  // VerifyUnsafe checks the given BLS signature bls on the message m using the
   462  // public key pkey by verifying that the equality e(H(m), X) == e(H(m), x*B2) ==
   463  // e(x*H(m), B2) == e(S, B2) holds where e is the pairing operation and B2 is the base point from curve G2.
   464  func VerifyUnsafe(pkey *PublicKey, msg []byte, signature *UnsafeSignature) error {
   465  	return verify(pkey.gx, msg, signature.e)
   466  }
   467  
   468  func verify(pk *bn256.G2, msg []byte, sigma *bn256.G1) error {
   469  	h0m, err := h0(msg)
   470  	if err != nil {
   471  		return err
   472  	}
   473  
   474  	pairH0mPK := bn256.Pair(h0m, pk).Marshal()
   475  	pairSigG2 := bn256.Pair(sigma, g2Base).Marshal()
   476  	if subtle.ConstantTimeCompare(pairH0mPK, pairSigG2) != 1 {
   477  		msg := fmt.Sprintf(
   478  			"bls apk: Invalid Signature.\nG1Sig pair (length %d): %v...\nApk H0(m) pair (length %d): %v...",
   479  			len(pairSigG2),
   480  			hex.EncodeToString(pairSigG2[0:10]),
   481  			len(pairH0mPK),
   482  			hex.EncodeToString(pairH0mPK[0:10]),
   483  		)
   484  		return errors.New(msg)
   485  	}
   486  
   487  	return nil
   488  }
   489  
   490  func verifyBatch(pkeys []*bn256.G2, msgList [][]byte, sig *bn256.G1, allowDistinct bool) error {
   491  	if !allowDistinct && !distinct(msgList) {
   492  		return errors.New("bls: Messages are not distinct")
   493  	}
   494  
   495  	var pairH0mPKs *bn256.GT
   496  	// TODO: I suspect that this could be sped up by doing the addition through a pool of goroutines
   497  	for i := range msgList {
   498  		h0m, err := h0(msgList[i])
   499  		if err != nil {
   500  			return err
   501  		}
   502  
   503  		if i == 0 {
   504  			pairH0mPKs = bn256.Pair(h0m, pkeys[i])
   505  		} else {
   506  			pairH0mPKs.Add(pairH0mPKs, bn256.Pair(h0m, pkeys[i]))
   507  		}
   508  	}
   509  
   510  	pairSigG2 := bn256.Pair(sig, g2Base)
   511  
   512  	if subtle.ConstantTimeCompare(pairSigG2.Marshal(), pairH0mPKs.Marshal()) != 1 {
   513  		return errors.New("bls: Invalid Signature")
   514  	}
   515  
   516  	return nil
   517  }
   518  
   519  // VerifyCompressed verifies a Compressed marshalled signature
   520  func VerifyCompressed(pks []*bn256.G2, msgList [][]byte, compressedSig []byte, allowDistinct bool) error {
   521  	sig, err := bn256.Decompress(compressedSig)
   522  	if err != nil {
   523  		return err
   524  	}
   525  	return verifyBatch(pks, msgList, sig, allowDistinct)
   526  }
   527  
   528  // distinct makes sure that the msg list is composed of different messages
   529  func distinct(msgList [][]byte) bool {
   530  	m := make(map[[32]byte]bool)
   531  	for _, msg := range msgList {
   532  		h := sha3.Sum256(msg)
   533  		if m[h] {
   534  			return false
   535  		}
   536  		m[h] = true
   537  	}
   538  	return true
   539  }
   540  
   541  // Aggregate is a shortcut for Public Key aggregation
   542  func (pk *PublicKey) Aggregate(pp *PublicKey) *PublicKey {
   543  	p3 := newG2()
   544  	p3.Add(pk.gx, pp.gx)
   545  	return &PublicKey{p3}
   546  }
   547  
   548  // MarshalText encodes the string representation of the public key
   549  func (pk *PublicKey) MarshalText() ([]byte, error) {
   550  	return encodeToText(pk.gx.Marshal()), nil
   551  }
   552  
   553  // UnmarshalText decode the string/byte representation into the public key
   554  func (pk *PublicKey) UnmarshalText(data []byte) error {
   555  	bs, err := decodeText(data)
   556  	if err != nil {
   557  		return err
   558  	}
   559  	pk.gx = newG2()
   560  	_, err = pk.gx.Unmarshal(bs)
   561  	if err != nil {
   562  		return err
   563  	}
   564  	return nil
   565  }
   566  
   567  // Marshal returns the binary representation of the G2 point being the public key
   568  func (pk *PublicKey) Marshal() []byte {
   569  	return pk.gx.Marshal()
   570  }
   571  
   572  // Unmarshal a public key from a byte array
   573  func (pk *PublicKey) Unmarshal(data []byte) error {
   574  	pk.gx = newG2()
   575  	_, err := pk.gx.Unmarshal(data)
   576  	if err != nil {
   577  		return err
   578  	}
   579  	return nil
   580  }
   581  
   582  func encodeToText(data []byte) []byte {
   583  	buf := make([]byte, base64.RawURLEncoding.EncodedLen(len(data)))
   584  	base64.RawURLEncoding.Encode(buf, data)
   585  	return buf
   586  }
   587  
   588  func decodeText(data []byte) ([]byte, error) {
   589  	buf := make([]byte, base64.RawURLEncoding.DecodedLen(len(data)))
   590  	n, err := base64.RawURLEncoding.Decode(buf, data)
   591  	return buf[:n], err
   592  }