prysm-pulse/shared/bls/bls.go
Ivan Martinez 23072983ff Create and Verify Signatures for Attestations (#1908)
* Verify signatures of attestations

* Implement BLS Signing for attestations

* Remove custody bit 0 from the attestation for now

* Fixes tests for attestations

* Fix tests to ensure they use proper attester indice

* Run gazelle

* Goimports

* Test attestation sigs in block operations

* Change formatting and make sure signatures are actually verified

* Fix duplicate import

* Fix duplicate import from merge

* Organize attestation sig to be conssitent with codebase

* Update to comments

* Change signatures to use aggregation

* Run gazelle

* Change function to return err instead of bool
Also gofmt

* Fix for comments

* Move createAggregationSignature to a function in attestations.go
2019-03-08 15:30:01 +08:00

145 lines
4.3 KiB
Go

// Package bls implements a go-wrapper around a library implementing the
// the BLS12-381 curve and signature scheme. This package exposes a public API for
// verifying and aggregating BLS signatures used by Ethereum 2.0.
package bls
import (
"fmt"
"io"
gobls "github.com/phoreproject/bls"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
)
// Signature used in the BLS signature scheme.
type Signature struct {
val *gobls.Signature
}
// SecretKey used in the BLS signature scheme.
type SecretKey struct {
val *gobls.SecretKey
}
// PublicKey used in the BLS signature scheme.
type PublicKey struct {
val *gobls.PublicKey
}
// RandKey creates a new private key using a random method provided as an io.Reader.
func RandKey(r io.Reader) (*SecretKey, error) {
k, err := gobls.RandKey(r)
if err != nil {
return nil, fmt.Errorf("could not initialize secret key: %v", err)
}
return &SecretKey{val: k}, nil
}
// SecretKeyFromBytes creates a BLS private key from a byte slice.
func SecretKeyFromBytes(priv []byte) (*SecretKey, error) {
if len(priv) != 32 {
return nil, fmt.Errorf("expected byte slice of length 32, received: %d", len(priv))
}
k := bytesutil.ToBytes32(priv)
return &SecretKey{val: gobls.DeserializeSecretKey(k)}, nil
}
// PublicKeyFromBytes creates a BLS public key from a byte slice.
func PublicKeyFromBytes(pub []byte) (*PublicKey, error) {
b := bytesutil.ToBytes96(pub)
k, err := gobls.DeserializePublicKey(b)
if err != nil {
return nil, fmt.Errorf("could not unmarshal bytes into public key: %v", err)
}
return &PublicKey{val: k}, nil
}
// SignatureFromBytes creates a BLS signature from a byte slice.
func SignatureFromBytes(sig []byte) (*Signature, error) {
b := bytesutil.ToBytes48(sig)
s, err := gobls.DeserializeSignature(b)
if err != nil {
return nil, fmt.Errorf("could not unmarshal bytes into signature: %v", err)
}
return &Signature{val: s}, nil
}
// PublicKey obtains the public key corresponding to the BLS secret key.
func (s *SecretKey) PublicKey() *PublicKey {
return &PublicKey{val: gobls.PrivToPub(s.val)}
}
// Sign a message using a secret key - in a beacon/validator client,
func (s *SecretKey) Sign(msg []byte, domain uint64) *Signature {
sig := gobls.Sign(msg, s.val, domain)
return &Signature{val: sig}
}
// Marshal a secret key into a byte slice.
func (s *SecretKey) Marshal() []byte {
k := s.val.Serialize()
return k[:]
}
// Marshal a public key into a byte slice.
func (p *PublicKey) Marshal() []byte {
k := p.val.Serialize()
return k[:]
}
// Aggregate two public keys.
func (p *PublicKey) Aggregate(p2 *PublicKey) *PublicKey {
p1 := p.val
p1.Aggregate(p2.val)
return &PublicKey{val: p1}
}
// Verify a bls signature given a public key, a message, and a domain.
func (s *Signature) Verify(pub *PublicKey, msg []byte, domain uint64) bool {
return gobls.Verify(msg, pub.val, s.val, domain)
}
// VerifyAggregate verifies each public key against a message.
// This is vulnerable to rogue public-key attack. Each user must
// provide a proof-of-knowledge of the public key.
func (s *Signature) VerifyAggregate(pubKeys []*PublicKey, msg []byte, domain uint64) bool {
keys := make([]*gobls.PublicKey, len(pubKeys))
for idx, v := range pubKeys {
keys[idx] = v.val
}
return s.val.VerifyAggregateCommon(keys, msg, domain)
}
// VerifyMultiple verifies each public key against each message.
func (s *Signature) VerifyMultiple(pubKeys []*PublicKey, msgs [][]byte, domain uint64) bool {
keys := make([]*gobls.PublicKey, len(pubKeys))
for idx, v := range pubKeys {
keys[idx] = v.val
}
return s.val.VerifyAggregate(keys, msgs, domain)
}
// Marshal a signature into a byte slice.
func (s *Signature) Marshal() []byte {
k := s.val.Serialize()
return k[:]
}
// AggregateSignatures converts a list of signatures into a single, aggregated sig.
func AggregateSignatures(sigs []*Signature) *Signature {
ss := make([]*gobls.Signature, len(sigs))
for idx, v := range sigs {
ss[idx] = v.val
}
return &Signature{val: gobls.AggregateSignatures(ss)}
}
// AggregatePublicKeys converts a list of public keys into a single, aggregated public key.
func AggregatePublicKeys(publicKeys []*PublicKey) *PublicKey {
ss := make([]*gobls.PublicKey, len(publicKeys))
for idx, pub := range publicKeys {
ss[idx] = pub.val
}
return &PublicKey{val: gobls.AggregatePublicKeys(ss)}
}