Skip to content

Commit

Permalink
the whole shenanigan
Browse files Browse the repository at this point in the history
  • Loading branch information
nikkolasg committed Nov 14, 2018
1 parent 9e0089b commit 3cfb35b
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 559 deletions.
24 changes: 16 additions & 8 deletions HACKING.md
Expand Up @@ -26,9 +26,9 @@ type Listener interface {
}

type Packet struct {
Origin int
Origin int32
Level int
Signature []byte
MultiSig []byte
}
```
As you can see, Handel only needs to know how to send `Packet`s and how to get
Expand All @@ -44,6 +44,7 @@ type Identity interface {
Address() string
// PublicKey returns the public key associated with that given node
PublicKey() PublicKey
ID() int32
}
```
Handel must know all `Identity` in order to be able to work correctly and
Expand All @@ -70,34 +71,41 @@ way thanks to the following interfaces:
```go
type PublicKey interface {
String() string
VerifySignature(msg []byte, sig MultiSignature) error
VerifySignature(msg []byte, sig Signature) error
// Combine combines two public keys together so that a multi-signature
// produced by both individual public keys can be verified by the combined
// public key
Combine(PublicKey) PublicKey
}

type SecretKey interface {
PublicKey() PublicKey
Public() PublicKey
// Sign returns a signature over the given message and using the reader for
// any randomness necessary, if any. The rand argument can be left nil.
Sign(msg []byte, rand io.Reader) (MultiSignature, error)
Sign(msg []byte, rand io.Reader) (Signature, error)
}

type MultiSignature interface {
type Signature interface {
MarshalBinary() ([]byte, error)
UnmarshalBinary([]byte) error

// Combine "merges" the two signature together so that it produces an unique
// multi-signature that can be verified by the combination of both
// respective public keys that produced the original signatures.
Combine(MultiSignature) MultiSignature
Combine(Signature) Signature
}

type MultiSignature struct {
BitSet
Signature
}

// SignatureScheme holds a private key interface and a method to unmarshal
// multisignatures
type SignatureScheme interface {
SecretKey
UnmarshalSignature([]byte) (MultiSignature, error)
Signature() Signature
PublicKey() PublicKey
}
```
As an example, you can see the implementation of these interfaces using BN256
Expand Down
34 changes: 34 additions & 0 deletions TODO.md
@@ -0,0 +1,34 @@
+ expectations with IDs: all ids starting form 0 without any holes between ids,
show example maybe within ethereum context (separate package ?)
+ Potentially need to sign different things in parallel, Handel should be able
to support this case
- stop waiting from peers that sends you signature for different messages
+ require only signature + message for Handel
+ Do we need to Origin in the packet ? -> we should not need to check

+ Contributions Threshold put as percentage (int is ambiguous)

+ CandidateCount / UpdatePeriod
- periodic


+ if already completed level, skip verification
-- basic check in synchronous manner

+ put asynchronous pattern if verification strategy
+ 1 thread for signature verification
+ 1 thread for logic "waiting" on new verified sig
+ Check first if I have same signature (= same bitset) before verifying
signature

+ optimizations:
- check signature in a separate go routine
- check signatures that are "best" for us in priority

+ Network: send to a list of identities (potential optimizations for example
only sign a message once if same for multiple identities)

+ Measurement architecture / interface bla bla

+ Adapt it to NON POWER OF TWO --> see partitioner test failing with non-power
of two
17 changes: 3 additions & 14 deletions crypto.go
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"encoding/binary"
"errors"
"io"
)

// PublicKey holds methods to verify a signature and to combine multiple public
Expand All @@ -18,19 +17,9 @@ type PublicKey interface {
Combine(PublicKey) PublicKey
}

// SecretKey holds methods to produce a valid signature that can be verified
// under the corresponding public key.
type SecretKey interface {
Public() PublicKey
// Sign returns a signature over the given message and using the reader for
// any randomness necessary, if any. The rand argument can be left nil.
Sign(msg []byte, rand io.Reader) (Signature, error)
}

// SignatureScheme holds a private key interface and a method to create empty
// signatures suitable for unmarshalling
type SignatureScheme interface {
SecretKey
// Constructor is used to create empty signatures suitable for unmarshalling and
// empty public key suitable for aggregation.
type Constructor interface {
// Signature returns a fresh empty signature suitable for unmarshaling
Signature() Signature
// PublicKey returns a fresh empty public key suitable for aggregation
Expand Down
165 changes: 30 additions & 135 deletions handel.go
Expand Up @@ -2,7 +2,6 @@ package handel

import (
"errors"
"fmt"
"sync"
)

Expand All @@ -16,34 +15,39 @@ type Handel struct {
net Network
// Registry holding access to all Handel node's identities
reg Registry
// signature scheme used for this Handel protocol
scheme SignatureScheme
// constructor to unmarshal signatures + aggregate pub keys
cons Constructor
// public identity of this Handel node
id Identity
// Message that is being signed during the Handel protocol
msg []byte
// candidate tree helper to select nodes at each level
tree *candidateTree
// incremental aggregated signature cached by this handel node
aggregate Signature
// signature cache with different merging/caching strategy
cache signatureCache
// signature over the message
sig Signature
// partitions the set of nodes at different levels
part partitioner
// signature store with different merging/caching strategy
cache signatureStore
// channel to exposes multi-signatures to the user
out chan MultiSignature
}

// NewHandel returns a Handle interface that uses the given network and
// registry. The signature scheme is the one to use for this Handel protocol,
// and the message is the message to multi-sign.The first config in the slice is
// taken if not nil. Otherwise, the default config generated by DefaultConfig()
// is used.
func NewHandel(n Network, r Registry, id Identity, s SignatureScheme, msg []byte,
conf ...*Config) (*Handel, error) {
// registry. The identity is the public identity of this Handel's node. The
// constructor defines over which curves / signature scheme Handel runs. The
// message is the message to "multi-sign" by Handel. The first config in the
// slice is taken if not nil. Otherwise, the default config generated by
// DefaultConfig() is used.
func NewHandel(n Network, r Registry, id Identity, c Constructor,
msg []byte, s Signature, conf ...*Config) (*Handel, error) {
h := &Handel{
net: n,
reg: r,
tree: newCandidateTree(id.ID(), r),
scheme: s,
msg: msg,
cache: newReplaceCache(),
net: n,
reg: r,
part: newBinTreePartition(id.ID(), r),
id: id,
cons: c,
msg: msg,
sig: s,
cache: newReplaceStore(),
}

if len(conf) > 0 && conf[0] != nil {
Expand All @@ -52,11 +56,6 @@ func NewHandel(n Network, r Registry, id Identity, s SignatureScheme, msg []byte
h.c = DefaultConfig(r.Size())
}

ms, err := s.Sign(msg, nil)
if err != nil {
return nil, err
}
h.aggregate = ms
return h, nil
}

Expand Down Expand Up @@ -95,45 +94,14 @@ func (h *Handel) parsePacket(p *Packet) (*MultiSignature, error) {
}

ms := new(MultiSignature)
err := ms.Unmarshal(p.MultiSig, h.scheme.Signature(), h.c.NewBitSet())
err := ms.Unmarshal(p.MultiSig, h.cons.Signature(), h.c.NewBitSet())
if err != nil {
return nil, err
}

err = h.verifySignature(ms, p.Origin, p.Level)
return ms, err
}

func (h *Handel) verifySignature(ms *MultiSignature, origin uint32, level byte) error {
// check inclusion of sender within the given range
min, max, err := h.tree.RangeAt(int(level))
if err != nil {
return err
}
if int(origin) < min || int(origin) >= max {
return errors.New("handel: origin not corresponding to level's range")
}
if ms.BitSet.BitLength() != (max - min) {
return errors.New("handel: inconsistent bitset with given level")
}

// compute the aggregate public key corresponding to bitset
ids, ok := h.reg.Identities(min, max)
if !ok {
return errors.New("handel: identities can't be retrieved from given range")
}
aggregateKey := h.scheme.PublicKey()
for i := 0; i < ms.BitSet.BitLength(); i++ {
if !ms.BitSet.Get(i) {
continue
}
aggregateKey = aggregateKey.Combine(ids[i].PublicKey())
}

if err := aggregateKey.VerifySignature(h.msg, ms.Signature); err != nil {
return fmt.Errorf("handel: %s", err)
}
return nil
return nil, nil
//err = h.verifySignature(ms, p.Origin, p.Level)
//return ms, err
}

// processPacket stores the signature to the cache. If it is a new
Expand All @@ -156,79 +124,6 @@ func (h *Handel) processPacket(p *Packet, ms *MultiSignature) {
// 3. if it is complete, ... ?
setCount := ms.BitSet.Cardinality()
if setCount >= h.c.ContributionsThreshold {

}
}

// signatureCache is a generic interface whose role is to store received valid
// multisignature, and to be able to serve the best multisignature received so
// far at a given level. Different strategies can be implemented such as keeping
// only the best one, merging two non-colluding multi-signatures etc
type signatureCache interface {
// Store saves the multi-signature if it is "better"
// (implementation-dependent) than the one previously saved at the same
// level. It returns true if the entry for this level has been updated,i.e.
// if GetBest at the same level will return a new multi-signature.
Store(level byte, ms *MultiSignature) bool
// GetBest returns the "best" multisignature at the requested level. Best
// should be interpreted as "containing the most individual contributions".
Best(level byte) (*MultiSignature, bool)
// Highest returns the highest multisignature contains as well as the
// corresponding level. It is nil if not such multisignatures have been
// found.
Highest() *sigPair
}

type sigPair struct {
level byte
ms *MultiSignature
}

// replaceCache is a signatureCache that only stores multisignature if it
// contains more individual contributions than what's already stored.
type replaceCache struct {
m map[byte]*MultiSignature
highest byte
}

func newReplaceCache() *replaceCache {
return &replaceCache{
m: make(map[byte]*MultiSignature),
}
}

func (r *replaceCache) Store(level byte, ms *MultiSignature) bool {
ms2, ok := r.m[level]
if !ok {
r.store(level, ms)
return true
}

c1 := ms.Cardinality()
c2 := ms2.Cardinality()
if c1 > c2 {
r.store(level, ms)
return true
}
return false
}

func (r *replaceCache) Best(level byte) (*MultiSignature, bool) {
ms, ok := r.m[level]
return ms, ok
}

func (r *replaceCache) Highest() *sigPair {
ms, _ := r.m[r.highest]
return &sigPair{
level: r.highest,
ms: ms,
}
}

func (r *replaceCache) store(level byte, ms *MultiSignature) {
r.m[level] = ms
if level > r.highest {
r.highest = level
// ---
}
}

0 comments on commit 3cfb35b

Please sign in to comment.