Move BLS related wrapper structure into a separate package (#3209)
parent
af38bc655d
commit
a168517dfc
@ -1,283 +1,89 @@ |
||||
package bls |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/hex" |
||||
"math/big" |
||||
|
||||
"github.com/harmony-one/bls/ffi/go/bls" |
||||
lru "github.com/hashicorp/golang-lru" |
||||
"github.com/pkg/errors" |
||||
) |
||||
|
||||
const ( |
||||
blsPubKeyCacheSize = 1024 |
||||
) |
||||
|
||||
var ( |
||||
// BLSPubKeyCache is the Cache of the Deserialized BLS PubKey
|
||||
BLSPubKeyCache, _ = lru.New(blsPubKeyCacheSize) |
||||
emptyBLSPubKey = SerializedPublicKey{} |
||||
) |
||||
|
||||
func init() { |
||||
bls.Init(bls.BLS12_381) |
||||
} |
||||
|
||||
// RandPrivateKey returns a random private key.
|
||||
func RandPrivateKey() *bls.SecretKey { |
||||
sec := bls.SecretKey{} |
||||
sec.SetByCSPRNG() |
||||
return &sec |
||||
} |
||||
|
||||
var ( |
||||
errEmptyInput = errors.New("BytesToBLSPublicKey: empty input") |
||||
errPubKeyCast = errors.New("BytesToBLSPublicKey: cast error") |
||||
// PublicKeySizeInBytes ..
|
||||
const ( |
||||
PublicKeySizeInBytes = 48 |
||||
BLSSignatureSizeInBytes = 96 |
||||
) |
||||
|
||||
// BytesToBLSPublicKey converts bytes into bls.PublicKey pointer.
|
||||
func BytesToBLSPublicKey(bytes []byte) (*bls.PublicKey, error) { |
||||
if len(bytes) == 0 { |
||||
return nil, errEmptyInput |
||||
} |
||||
kkey := string(bytes) |
||||
if k, ok := BLSPubKeyCache.Get(kkey); ok { |
||||
if pk, ok := k.(bls.PublicKey); ok { |
||||
return &pk, nil |
||||
// PrivateKeyWrapper combines the bls private key and the corresponding public key
|
||||
type PrivateKeyWrapper struct { |
||||
Pri *bls.SecretKey |
||||
Pub *PublicKeyWrapper |
||||
} |
||||
return nil, errPubKeyCast |
||||
} |
||||
pubKey := &bls.PublicKey{} |
||||
err := pubKey.Deserialize(bytes) |
||||
|
||||
if err == nil { |
||||
BLSPubKeyCache.Add(kkey, *pubKey) |
||||
return pubKey, nil |
||||
// PublicKeyWrapper defines the bls public key in both serialized and
|
||||
// deserialized form.
|
||||
type PublicKeyWrapper struct { |
||||
Bytes SerializedPublicKey |
||||
Object *bls.PublicKey |
||||
} |
||||
|
||||
return nil, err |
||||
} |
||||
// SerializedPublicKey defines the serialized bls public key
|
||||
type SerializedPublicKey [PublicKeySizeInBytes]byte |
||||
|
||||
// AggregateSig aggregates all the BLS signature into a single multi-signature.
|
||||
func AggregateSig(sigs []*bls.Sign) *bls.Sign { |
||||
var aggregatedSig bls.Sign |
||||
for _, sig := range sigs { |
||||
aggregatedSig.Add(sig) |
||||
} |
||||
return &aggregatedSig |
||||
} |
||||
// SerializedSignature defines the bls signature
|
||||
type SerializedSignature [BLSSignatureSizeInBytes]byte |
||||
|
||||
// Mask represents a cosigning participation bitmask.
|
||||
type Mask struct { |
||||
Bitmap []byte |
||||
Publics []*bls.PublicKey |
||||
AggregatePublic *bls.PublicKey |
||||
// Big ..
|
||||
func (pk SerializedPublicKey) Big() *big.Int { |
||||
return new(big.Int).SetBytes(pk[:]) |
||||
} |
||||
|
||||
// NewMask returns a new participation bitmask for cosigning where all
|
||||
// cosigners are disabled by default. If a public key is given it verifies that
|
||||
// it is present in the list of keys and sets the corresponding index in the
|
||||
// bitmask to 1 (enabled).
|
||||
func NewMask(publics []*bls.PublicKey, myKey *bls.PublicKey) (*Mask, error) { |
||||
m := &Mask{ |
||||
Publics: publics, |
||||
} |
||||
m.Bitmap = make([]byte, m.Len()) |
||||
m.AggregatePublic = &bls.PublicKey{} |
||||
if myKey != nil { |
||||
found := false |
||||
for i, key := range publics { |
||||
if key.IsEqual(myKey) { |
||||
m.SetBit(i, true) |
||||
found = true |
||||
break |
||||
} |
||||
} |
||||
if !found { |
||||
return nil, errors.New("key not found") |
||||
} |
||||
} |
||||
return m, nil |
||||
// IsEmpty returns whether the bls public key is empty 0 bytes
|
||||
func (pk SerializedPublicKey) IsEmpty() bool { |
||||
return bytes.Equal(pk[:], emptyBLSPubKey[:]) |
||||
} |
||||
|
||||
// Clear clears the existing bits and aggregate public keys.
|
||||
func (m *Mask) Clear() { |
||||
m.Bitmap = make([]byte, m.Len()) |
||||
m.AggregatePublic = &bls.PublicKey{} |
||||
// Hex returns the hex string of bls public key
|
||||
func (pk SerializedPublicKey) Hex() string { |
||||
return hex.EncodeToString(pk[:]) |
||||
} |
||||
|
||||
// Mask returns a copy of the participation bitmask.
|
||||
func (m *Mask) Mask() []byte { |
||||
clone := make([]byte, len(m.Bitmap)) |
||||
copy(clone[:], m.Bitmap) |
||||
return clone |
||||
// MarshalText so that we can use this as JSON printable when used as
|
||||
// key in a map
|
||||
func (pk SerializedPublicKey) MarshalText() (text []byte, err error) { |
||||
text = make([]byte, BLSSignatureSizeInBytes) |
||||
hex.Encode(text, pk[:]) |
||||
return text, nil |
||||
} |
||||
|
||||
// Len returns the Bitmap length in bytes.
|
||||
func (m *Mask) Len() int { |
||||
return (len(m.Publics) + 7) >> 3 |
||||
// FromLibBLSPublicKeyUnsafe could give back nil, use only in cases when
|
||||
// have invariant that return value won't be nil
|
||||
func FromLibBLSPublicKeyUnsafe(key *bls.PublicKey) *SerializedPublicKey { |
||||
result := &SerializedPublicKey{} |
||||
if err := result.FromLibBLSPublicKey(key); err != nil { |
||||
return nil |
||||
} |
||||
return result |
||||
} |
||||
|
||||
// SetMask sets the participation bitmask according to the given byte slice
|
||||
// interpreted in little-endian order, i.e., bits 0-7 of byte 0 correspond to
|
||||
// cosigners 0-7, bits 0-7 of byte 1 correspond to cosigners 8-15, etc.
|
||||
func (m *Mask) SetMask(mask []byte) error { |
||||
if m.Len() != len(mask) { |
||||
// FromLibBLSPublicKey replaces the key contents with the given key,
|
||||
func (pk *SerializedPublicKey) FromLibBLSPublicKey(key *bls.PublicKey) error { |
||||
bytes := key.Serialize() |
||||
if len(bytes) != len(pk) { |
||||
return errors.Errorf( |
||||
"mismatching bitmap lengths expectedBitmapLength %d providedBitmapLength %d", |
||||
m.Len(), |
||||
len(mask), |
||||
"key size (BLS) size mismatch, expected %d have %d", len(pk), len(bytes), |
||||
) |
||||
} |
||||
for i := range m.Publics { |
||||
byt := i >> 3 |
||||
msk := byte(1) << uint(i&7) |
||||
if ((m.Bitmap[byt] & msk) == 0) && ((mask[byt] & msk) != 0) { |
||||
m.Bitmap[byt] ^= msk // flip bit in Bitmap from 0 to 1
|
||||
m.AggregatePublic.Add(m.Publics[i]) |
||||
} |
||||
if ((m.Bitmap[byt] & msk) != 0) && ((mask[byt] & msk) == 0) { |
||||
m.Bitmap[byt] ^= msk // flip bit in Bitmap from 1 to 0
|
||||
m.AggregatePublic.Sub(m.Publics[i]) |
||||
} |
||||
} |
||||
copy(pk[:], bytes) |
||||
return nil |
||||
} |
||||
|
||||
// SetBit enables (enable: true) or disables (enable: false) the bit
|
||||
// in the participation Bitmap of the given cosigner.
|
||||
func (m *Mask) SetBit(i int, enable bool) error { |
||||
if i >= len(m.Publics) { |
||||
return errors.New("index out of range") |
||||
} |
||||
byt := i >> 3 |
||||
msk := byte(1) << uint(i&7) |
||||
if ((m.Bitmap[byt] & msk) == 0) && enable { |
||||
m.Bitmap[byt] ^= msk // flip bit in Bitmap from 0 to 1
|
||||
m.AggregatePublic.Add(m.Publics[i]) |
||||
} |
||||
if ((m.Bitmap[byt] & msk) != 0) && !enable { |
||||
m.Bitmap[byt] ^= msk // flip bit in Bitmap from 1 to 0
|
||||
m.AggregatePublic.Sub(m.Publics[i]) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetPubKeyFromMask will return pubkeys which masked either zero or one depending on the flag
|
||||
// it is used to show which signers are signed or not in the cosign message
|
||||
func (m *Mask) GetPubKeyFromMask(flag bool) []*bls.PublicKey { |
||||
pubKeys := []*bls.PublicKey{} |
||||
for i := range m.Publics { |
||||
byt := i >> 3 |
||||
msk := byte(1) << uint(i&7) |
||||
if flag { |
||||
if (m.Bitmap[byt] & msk) != 0 { |
||||
pubKeys = append(pubKeys, m.Publics[i]) |
||||
} |
||||
} else { |
||||
if (m.Bitmap[byt] & msk) == 0 { |
||||
pubKeys = append(pubKeys, m.Publics[i]) |
||||
} |
||||
} |
||||
} |
||||
return pubKeys |
||||
} |
||||
|
||||
// IndexEnabled checks whether the given index is enabled in the Bitmap or not.
|
||||
func (m *Mask) IndexEnabled(i int) (bool, error) { |
||||
if i >= len(m.Publics) { |
||||
return false, errors.New("index out of range") |
||||
} |
||||
byt := i >> 3 |
||||
msk := byte(1) << uint(i&7) |
||||
return ((m.Bitmap[byt] & msk) != 0), nil |
||||
} |
||||
|
||||
// KeyEnabled checks whether the index, corresponding to the given key, is
|
||||
// enabled in the Bitmap or not.
|
||||
func (m *Mask) KeyEnabled(public *bls.PublicKey) (bool, error) { |
||||
for i, key := range m.Publics { |
||||
if key.IsEqual(public) { |
||||
return m.IndexEnabled(i) |
||||
} |
||||
} |
||||
return false, errors.New("key not found") |
||||
} |
||||
|
||||
// SetKey set the bit in the Bitmap for the given cosigner
|
||||
func (m *Mask) SetKey(public *bls.PublicKey, enable bool) error { |
||||
for i, key := range m.Publics { |
||||
if key.IsEqual(public) { |
||||
return m.SetBit(i, enable) |
||||
} |
||||
} |
||||
return errors.New("key not found") |
||||
} |
||||
|
||||
// CountEnabled returns the number of enabled nodes in the CoSi participation
|
||||
// Bitmap.
|
||||
func (m *Mask) CountEnabled() int { |
||||
// hw is hamming weight
|
||||
hw := 0 |
||||
for i := range m.Publics { |
||||
byt := i >> 3 |
||||
msk := byte(1) << uint(i&7) |
||||
if (m.Bitmap[byt] & msk) != 0 { |
||||
hw++ |
||||
} |
||||
} |
||||
return hw |
||||
} |
||||
|
||||
// CountTotal returns the total number of nodes this CoSi instance knows.
|
||||
func (m *Mask) CountTotal() int { |
||||
return len(m.Publics) |
||||
} |
||||
|
||||
// AggregateMasks computes the bitwise OR of the two given participation masks.
|
||||
func AggregateMasks(a, b []byte) ([]byte, error) { |
||||
if len(a) != len(b) { |
||||
return nil, errors.New("mismatching Bitmap lengths") |
||||
} |
||||
m := make([]byte, len(a)) |
||||
for i := range m { |
||||
m[i] = a[i] | b[i] |
||||
} |
||||
return m, nil |
||||
} |
||||
|
||||
// Policy represents a fully customizable cosigning policy deciding what
|
||||
// cosigner sets are and aren't sufficient for a collective signature to be
|
||||
// considered acceptable to a verifier. The Check method may inspect the set of
|
||||
// participants that cosigned by invoking cosi.Mask and/or cosi.MaskBit, and may
|
||||
// use any other relevant contextual information (e.g., how security-critical
|
||||
// the operation relying on the collective signature is) in determining whether
|
||||
// the collective signature was produced by an acceptable set of cosigners.
|
||||
type Policy interface { |
||||
Check(m *Mask) bool |
||||
} |
||||
|
||||
// CompletePolicy is the default policy requiring that all participants have
|
||||
// cosigned to make a collective signature valid.
|
||||
type CompletePolicy struct { |
||||
} |
||||
|
||||
// Check verifies that all participants have contributed to a collective
|
||||
// signature.
|
||||
func (p CompletePolicy) Check(m *Mask) bool { |
||||
return m.CountEnabled() == m.CountTotal() |
||||
} |
||||
|
||||
// ThresholdPolicy allows to specify a simple t-of-n policy requring that at
|
||||
// least the given threshold number of participants t have cosigned to make a
|
||||
// collective signature valid.
|
||||
type ThresholdPolicy struct { |
||||
thold int |
||||
} |
||||
|
||||
// NewThresholdPolicy returns a new ThresholdPolicy with the given threshold.
|
||||
func NewThresholdPolicy(thold int) *ThresholdPolicy { |
||||
return &ThresholdPolicy{thold: thold} |
||||
} |
||||
|
||||
// Check verifies that at least a threshold number of participants have
|
||||
// contributed to a collective signature.
|
||||
func (p ThresholdPolicy) Check(m *Mask) bool { |
||||
return m.CountEnabled() >= p.thold |
||||
// ToLibBLSPublicKey copies the key contents into the given key.
|
||||
func (pk *SerializedPublicKey) ToLibBLSPublicKey(key *bls.PublicKey) error { |
||||
return key.Deserialize(pk[:]) |
||||
} |
||||
|
@ -0,0 +1,283 @@ |
||||
package bls |
||||
|
||||
import ( |
||||
"github.com/harmony-one/bls/ffi/go/bls" |
||||
lru "github.com/hashicorp/golang-lru" |
||||
"github.com/pkg/errors" |
||||
) |
||||
|
||||
const ( |
||||
blsPubKeyCacheSize = 1024 |
||||
) |
||||
|
||||
var ( |
||||
// BLSPubKeyCache is the Cache of the Deserialized BLS PubKey
|
||||
BLSPubKeyCache, _ = lru.New(blsPubKeyCacheSize) |
||||
) |
||||
|
||||
func init() { |
||||
bls.Init(bls.BLS12_381) |
||||
} |
||||
|
||||
// RandPrivateKey returns a random private key.
|
||||
func RandPrivateKey() *bls.SecretKey { |
||||
sec := bls.SecretKey{} |
||||
sec.SetByCSPRNG() |
||||
return &sec |
||||
} |
||||
|
||||
var ( |
||||
errEmptyInput = errors.New("BytesToBLSPublicKey: empty input") |
||||
errPubKeyCast = errors.New("BytesToBLSPublicKey: cast error") |
||||
) |
||||
|
||||
// BytesToBLSPublicKey converts bytes into bls.PublicKey pointer.
|
||||
func BytesToBLSPublicKey(bytes []byte) (*bls.PublicKey, error) { |
||||
if len(bytes) == 0 { |
||||
return nil, errEmptyInput |
||||
} |
||||
kkey := string(bytes) |
||||
if k, ok := BLSPubKeyCache.Get(kkey); ok { |
||||
if pk, ok := k.(bls.PublicKey); ok { |
||||
return &pk, nil |
||||
} |
||||
return nil, errPubKeyCast |
||||
} |
||||
pubKey := &bls.PublicKey{} |
||||
err := pubKey.Deserialize(bytes) |
||||
|
||||
if err == nil { |
||||
BLSPubKeyCache.Add(kkey, *pubKey) |
||||
return pubKey, nil |
||||
} |
||||
|
||||
return nil, err |
||||
} |
||||
|
||||
// AggregateSig aggregates all the BLS signature into a single multi-signature.
|
||||
func AggregateSig(sigs []*bls.Sign) *bls.Sign { |
||||
var aggregatedSig bls.Sign |
||||
for _, sig := range sigs { |
||||
aggregatedSig.Add(sig) |
||||
} |
||||
return &aggregatedSig |
||||
} |
||||
|
||||
// Mask represents a cosigning participation bitmask.
|
||||
type Mask struct { |
||||
Bitmap []byte |
||||
Publics []*bls.PublicKey |
||||
AggregatePublic *bls.PublicKey |
||||
} |
||||
|
||||
// NewMask returns a new participation bitmask for cosigning where all
|
||||
// cosigners are disabled by default. If a public key is given it verifies that
|
||||
// it is present in the list of keys and sets the corresponding index in the
|
||||
// bitmask to 1 (enabled).
|
||||
func NewMask(publics []*bls.PublicKey, myKey *bls.PublicKey) (*Mask, error) { |
||||
m := &Mask{ |
||||
Publics: publics, |
||||
} |
||||
m.Bitmap = make([]byte, m.Len()) |
||||
m.AggregatePublic = &bls.PublicKey{} |
||||
if myKey != nil { |
||||
found := false |
||||
for i, key := range publics { |
||||
if key.IsEqual(myKey) { |
||||
m.SetBit(i, true) |
||||
found = true |
||||
break |
||||
} |
||||
} |
||||
if !found { |
||||
return nil, errors.New("key not found") |
||||
} |
||||
} |
||||
return m, nil |
||||
} |
||||
|
||||
// Clear clears the existing bits and aggregate public keys.
|
||||
func (m *Mask) Clear() { |
||||
m.Bitmap = make([]byte, m.Len()) |
||||
m.AggregatePublic = &bls.PublicKey{} |
||||
} |
||||
|
||||
// Mask returns a copy of the participation bitmask.
|
||||
func (m *Mask) Mask() []byte { |
||||
clone := make([]byte, len(m.Bitmap)) |
||||
copy(clone[:], m.Bitmap) |
||||
return clone |
||||
} |
||||
|
||||
// Len returns the Bitmap length in bytes.
|
||||
func (m *Mask) Len() int { |
||||
return (len(m.Publics) + 7) >> 3 |
||||
} |
||||
|
||||
// SetMask sets the participation bitmask according to the given byte slice
|
||||
// interpreted in little-endian order, i.e., bits 0-7 of byte 0 correspond to
|
||||
// cosigners 0-7, bits 0-7 of byte 1 correspond to cosigners 8-15, etc.
|
||||
func (m *Mask) SetMask(mask []byte) error { |
||||
if m.Len() != len(mask) { |
||||
return errors.Errorf( |
||||
"mismatching bitmap lengths expectedBitmapLength %d providedBitmapLength %d", |
||||
m.Len(), |
||||
len(mask), |
||||
) |
||||
} |
||||
for i := range m.Publics { |
||||
byt := i >> 3 |
||||
msk := byte(1) << uint(i&7) |
||||
if ((m.Bitmap[byt] & msk) == 0) && ((mask[byt] & msk) != 0) { |
||||
m.Bitmap[byt] ^= msk // flip bit in Bitmap from 0 to 1
|
||||
m.AggregatePublic.Add(m.Publics[i]) |
||||
} |
||||
if ((m.Bitmap[byt] & msk) != 0) && ((mask[byt] & msk) == 0) { |
||||
m.Bitmap[byt] ^= msk // flip bit in Bitmap from 1 to 0
|
||||
m.AggregatePublic.Sub(m.Publics[i]) |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// SetBit enables (enable: true) or disables (enable: false) the bit
|
||||
// in the participation Bitmap of the given cosigner.
|
||||
func (m *Mask) SetBit(i int, enable bool) error { |
||||
if i >= len(m.Publics) { |
||||
return errors.New("index out of range") |
||||
} |
||||
byt := i >> 3 |
||||
msk := byte(1) << uint(i&7) |
||||
if ((m.Bitmap[byt] & msk) == 0) && enable { |
||||
m.Bitmap[byt] ^= msk // flip bit in Bitmap from 0 to 1
|
||||
m.AggregatePublic.Add(m.Publics[i]) |
||||
} |
||||
if ((m.Bitmap[byt] & msk) != 0) && !enable { |
||||
m.Bitmap[byt] ^= msk // flip bit in Bitmap from 1 to 0
|
||||
m.AggregatePublic.Sub(m.Publics[i]) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetPubKeyFromMask will return pubkeys which masked either zero or one depending on the flag
|
||||
// it is used to show which signers are signed or not in the cosign message
|
||||
func (m *Mask) GetPubKeyFromMask(flag bool) []*bls.PublicKey { |
||||
pubKeys := []*bls.PublicKey{} |
||||
for i := range m.Publics { |
||||
byt := i >> 3 |
||||
msk := byte(1) << uint(i&7) |
||||
if flag { |
||||
if (m.Bitmap[byt] & msk) != 0 { |
||||
pubKeys = append(pubKeys, m.Publics[i]) |
||||
} |
||||
} else { |
||||
if (m.Bitmap[byt] & msk) == 0 { |
||||
pubKeys = append(pubKeys, m.Publics[i]) |
||||
} |
||||
} |
||||
} |
||||
return pubKeys |
||||
} |
||||
|
||||
// IndexEnabled checks whether the given index is enabled in the Bitmap or not.
|
||||
func (m *Mask) IndexEnabled(i int) (bool, error) { |
||||
if i >= len(m.Publics) { |
||||
return false, errors.New("index out of range") |
||||
} |
||||
byt := i >> 3 |
||||
msk := byte(1) << uint(i&7) |
||||
return ((m.Bitmap[byt] & msk) != 0), nil |
||||
} |
||||
|
||||
// KeyEnabled checks whether the index, corresponding to the given key, is
|
||||
// enabled in the Bitmap or not.
|
||||
func (m *Mask) KeyEnabled(public *bls.PublicKey) (bool, error) { |
||||
for i, key := range m.Publics { |
||||
if key.IsEqual(public) { |
||||
return m.IndexEnabled(i) |
||||
} |
||||
} |
||||
return false, errors.New("key not found") |
||||
} |
||||
|
||||
// SetKey set the bit in the Bitmap for the given cosigner
|
||||
func (m *Mask) SetKey(public *bls.PublicKey, enable bool) error { |
||||
for i, key := range m.Publics { |
||||
if key.IsEqual(public) { |
||||
return m.SetBit(i, enable) |
||||
} |
||||
} |
||||
return errors.New("key not found") |
||||
} |
||||
|
||||
// CountEnabled returns the number of enabled nodes in the CoSi participation
|
||||
// Bitmap.
|
||||
func (m *Mask) CountEnabled() int { |
||||
// hw is hamming weight
|
||||
hw := 0 |
||||
for i := range m.Publics { |
||||
byt := i >> 3 |
||||
msk := byte(1) << uint(i&7) |
||||
if (m.Bitmap[byt] & msk) != 0 { |
||||
hw++ |
||||
} |
||||
} |
||||
return hw |
||||
} |
||||
|
||||
// CountTotal returns the total number of nodes this CoSi instance knows.
|
||||
func (m *Mask) CountTotal() int { |
||||
return len(m.Publics) |
||||
} |
||||
|
||||
// AggregateMasks computes the bitwise OR of the two given participation masks.
|
||||
func AggregateMasks(a, b []byte) ([]byte, error) { |
||||
if len(a) != len(b) { |
||||
return nil, errors.New("mismatching Bitmap lengths") |
||||
} |
||||
m := make([]byte, len(a)) |
||||
for i := range m { |
||||
m[i] = a[i] | b[i] |
||||
} |
||||
return m, nil |
||||
} |
||||
|
||||
// Policy represents a fully customizable cosigning policy deciding what
|
||||
// cosigner sets are and aren't sufficient for a collective signature to be
|
||||
// considered acceptable to a verifier. The Check method may inspect the set of
|
||||
// participants that cosigned by invoking cosi.Mask and/or cosi.MaskBit, and may
|
||||
// use any other relevant contextual information (e.g., how security-critical
|
||||
// the operation relying on the collective signature is) in determining whether
|
||||
// the collective signature was produced by an acceptable set of cosigners.
|
||||
type Policy interface { |
||||
Check(m *Mask) bool |
||||
} |
||||
|
||||
// CompletePolicy is the default policy requiring that all participants have
|
||||
// cosigned to make a collective signature valid.
|
||||
type CompletePolicy struct { |
||||
} |
||||
|
||||
// Check verifies that all participants have contributed to a collective
|
||||
// signature.
|
||||
func (p CompletePolicy) Check(m *Mask) bool { |
||||
return m.CountEnabled() == m.CountTotal() |
||||
} |
||||
|
||||
// ThresholdPolicy allows to specify a simple t-of-n policy requring that at
|
||||
// least the given threshold number of participants t have cosigned to make a
|
||||
// collective signature valid.
|
||||
type ThresholdPolicy struct { |
||||
thold int |
||||
} |
||||
|
||||
// NewThresholdPolicy returns a new ThresholdPolicy with the given threshold.
|
||||
func NewThresholdPolicy(thold int) *ThresholdPolicy { |
||||
return &ThresholdPolicy{thold: thold} |
||||
} |
||||
|
||||
// Check verifies that at least a threshold number of participants have
|
||||
// contributed to a collective signature.
|
||||
func (p ThresholdPolicy) Check(m *Mask) bool { |
||||
return m.CountEnabled() >= p.thold |
||||
} |
Loading…
Reference in new issue