mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 17:15:18 +00:00
307 lines
8.3 KiB
Go
307 lines
8.3 KiB
Go
//
|
|
// Copyright Coinbase, Inc. All Rights Reserved.
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
// Package dkls is an implementation of https://eprint.iacr.org/2018/499.pdf
|
|
package v0
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/gob"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
|
|
"source.quilibrium.com/quilibrium/monorepo/nekryptology/pkg/core/curves"
|
|
)
|
|
|
|
type (
|
|
// ProtocolIterator a generalized interface for multi-party protocols that follows the iterator pattern.
|
|
ProtocolIterator interface {
|
|
// Next runs the next round of the protocol.
|
|
// Inputs are read from rw.Read(); outputs are written to rw.Write().
|
|
// Returns io.EOF when protocol has completed.
|
|
Next(rw io.ReadWriter) error
|
|
|
|
// Result returns the final result, if any, of the completed protocol.
|
|
// Reports an error if the protocol has not yet terminated
|
|
// or if an error was encountered during protocol execution.
|
|
Result() (interface{}, error)
|
|
|
|
// SetDebug enables or disables (passing a nil value as input) debugging.
|
|
// At the moment, we only print the final dkls dkg result as json value to this log, but if needed more debugging
|
|
// can be added for various steps of the other protocols.
|
|
SetDebug(log io.Writer)
|
|
}
|
|
|
|
// Basic protocol interface implementation that calls the next step func in a pre-defined list
|
|
protoStepper struct {
|
|
steps []func(rw io.ReadWriter) error
|
|
step uint
|
|
log io.Writer //nolint:structcheck // This is only used in some of the protocols.
|
|
}
|
|
|
|
// DKG protocols produce the following result on successful completion
|
|
DkgResult struct {
|
|
DkgState []byte
|
|
Pubkey *curves.EcPoint
|
|
}
|
|
// AliceDkg DKLS DKG implementation that satisfies the protocol iterator interface.
|
|
AliceDkg struct {
|
|
protoStepper
|
|
Alice *Alice
|
|
}
|
|
|
|
// BobDkg DKLS DKG implementation that satisfies the protocol iterator interface.
|
|
BobDkg struct {
|
|
protoStepper
|
|
Bob *Bob
|
|
}
|
|
|
|
// AliceSign DKLS sign implementation that satisfies the protocol iterator interface.
|
|
AliceSign struct {
|
|
protoStepper
|
|
alice *Alice
|
|
}
|
|
|
|
// BobSign DKLS sign implementation that satisfies the protocol iterator interface.
|
|
BobSign struct {
|
|
protoStepper
|
|
bob *Bob
|
|
}
|
|
)
|
|
|
|
var (
|
|
// Static type assertions
|
|
_ ProtocolIterator = &AliceDkg{}
|
|
_ ProtocolIterator = &BobDkg{}
|
|
_ ProtocolIterator = &AliceSign{}
|
|
_ ProtocolIterator = &BobSign{}
|
|
|
|
errProtocolNotComplete = fmt.Errorf("protocol has not completed")
|
|
errNotInitialized = fmt.Errorf("object has not been initialized")
|
|
errNoSig = fmt.Errorf("dkls.Alice does not produce a signature")
|
|
)
|
|
|
|
// Reports true if the step index exceeds the number of steps
|
|
func (p *protoStepper) complete() bool { return int(p.step) >= len(p.steps) }
|
|
|
|
// Next runs the next step in the protocol and reports errors or increments the step index
|
|
func (p *protoStepper) Next(rw io.ReadWriter) error {
|
|
// Signal EOF if the protocol has completed.
|
|
if p.complete() {
|
|
return io.EOF
|
|
}
|
|
|
|
// Run the current protocol step and report any errors
|
|
if err := p.steps[p.step](rw); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Increment the step index and report success
|
|
p.step++
|
|
return nil
|
|
}
|
|
|
|
// NewAliceDkg creates a new protocol that can compute a DKG as Alice
|
|
func NewAliceDkg(params *Params) *AliceDkg {
|
|
a := &AliceDkg{Alice: NewAlice(params)}
|
|
a.steps = []func(rw io.ReadWriter) error{
|
|
func(rw io.ReadWriter) error { return a.Alice.dkgCommit(rw) },
|
|
a.Alice.dkgVerify,
|
|
func(rw io.ReadWriter) error {
|
|
if err := a.Alice.Receiver.pubKey(rw); err != nil {
|
|
return err
|
|
}
|
|
return a.Alice.Receiver.padTransfer(rw)
|
|
},
|
|
a.Alice.Receiver.verification,
|
|
func(rw io.ReadWriter) error { return a.Alice.Receiver.final(rw) },
|
|
}
|
|
return a
|
|
}
|
|
|
|
// NewBobDkg Creates a new protocol that can compute a DKG as Bob
|
|
func NewBobDkg(params *Params) *BobDkg {
|
|
b := &BobDkg{Bob: NewBob(params)}
|
|
b.steps = []func(rw io.ReadWriter) error{
|
|
b.Bob.dkgCommit,
|
|
func(rw io.ReadWriter) error {
|
|
if err := b.Bob.dkgVerify(rw); err != nil {
|
|
return err
|
|
}
|
|
return b.Bob.Sender.pubKey(rw)
|
|
},
|
|
b.Bob.Sender.padTransfer,
|
|
b.Bob.Sender.verification,
|
|
}
|
|
return b
|
|
}
|
|
|
|
func (a *AliceDkg) SetDebug(log io.Writer) {
|
|
a.log = log
|
|
}
|
|
|
|
// Result Returns an encoded version of Alice as sequence of bytes that can be used to initialize an AliceSign protocol.
|
|
func (a *AliceDkg) Result() (interface{}, error) {
|
|
// Sanity check
|
|
if !a.complete() {
|
|
return nil, errProtocolNotComplete
|
|
}
|
|
if a.Alice == nil {
|
|
return nil, errNotInitialized
|
|
}
|
|
|
|
// Encode DKG state of alice for future signing
|
|
state, err := EncodeAlice(a.Alice)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := &DkgResult{
|
|
DkgState: state,
|
|
Pubkey: a.Alice.Pk,
|
|
}
|
|
|
|
if a.log != nil {
|
|
resultBytes, err := json.Marshal(result)
|
|
if err != nil {
|
|
_, _ = a.log.Write([]byte(fmt.Sprintf("Error while json marshaling the results: %v", err)))
|
|
} else {
|
|
_, _ = a.log.Write([]byte("Alice Dkg result:\n"))
|
|
_, _ = a.log.Write(resultBytes)
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (b *BobDkg) SetDebug(log io.Writer) {
|
|
b.log = log
|
|
}
|
|
|
|
// Result returns an encoded version of Alice as sequence of bytes that can be used to
|
|
// initialize an AliceSign protocol.
|
|
func (b *BobDkg) Result() (interface{}, error) {
|
|
// Sanity check
|
|
if !b.complete() {
|
|
return nil, errProtocolNotComplete
|
|
}
|
|
if b.Bob == nil {
|
|
return nil, errNotInitialized
|
|
}
|
|
// Encode DKG state of bob for future signing
|
|
state, err := EncodeBob(b.Bob)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := &DkgResult{
|
|
DkgState: state,
|
|
Pubkey: b.Bob.Pk,
|
|
}
|
|
if b.log != nil {
|
|
resultBytes, err := json.Marshal(result)
|
|
if err != nil {
|
|
_, _ = b.log.Write([]byte(fmt.Sprintf("Error while json marshaling the results: %v", err)))
|
|
} else {
|
|
_, _ = b.log.Write([]byte("Alice Dkg result:\n"))
|
|
_, _ = b.log.Write(resultBytes)
|
|
}
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// Creates a new protocol that can compute a signature as Alice.
|
|
// Requires dkg state that was produced at the end of DKG.Result().
|
|
func NewAliceSign(params *Params, msg []byte, dkgResult []byte) (*AliceSign, error) {
|
|
// Reconstitute Alice
|
|
alice, err := DecodeAlice(params, dkgResult)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Configure Alice with her 1 signing step
|
|
a := &AliceSign{alice: alice}
|
|
a.steps = []func(rw io.ReadWriter) error{
|
|
func(rw io.ReadWriter) error { return alice.signInit(msg, rw) },
|
|
}
|
|
return a, nil
|
|
}
|
|
|
|
// NewBobSign creates a new protocol that can compute a signature as Bob.
|
|
// Requires dkg state that was produced at the end of DKG.Result().
|
|
func NewBobSign(params *Params, msg []byte, dkgResult []byte) (*BobSign, error) {
|
|
// Reconstitute Bob
|
|
bob, err := DecodeBob(params, dkgResult)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Configure Bob with 2 signing steps
|
|
b := &BobSign{bob: bob}
|
|
b.steps = []func(rw io.ReadWriter) error{
|
|
func(rw io.ReadWriter) error { return bob.signInit(rw) },
|
|
func(rw io.ReadWriter) error { return bob.signFinal(msg, rw) },
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
func (a *AliceSign) SetDebug(log io.Writer) {
|
|
a.log = log
|
|
}
|
|
|
|
// Result always returns errNoSig.
|
|
// Alice does not compute a signature in the DKLS protocol; only Bob computes the signature.
|
|
func (a *AliceSign) Result() (interface{}, error) {
|
|
return nil, errNoSig
|
|
}
|
|
|
|
func (b *BobSign) SetDebug(log io.Writer) {
|
|
b.log = log
|
|
}
|
|
|
|
// If the signing protocol completed successfully, returns the signature that
|
|
// Bob computed as a *core.EcdsaSignature.
|
|
func (d *BobSign) Result() (interface{}, error) {
|
|
// We can't produce a signature until the protocol completes
|
|
if !d.complete() {
|
|
return nil, errProtocolNotComplete
|
|
}
|
|
if d.bob == nil {
|
|
// Object wasn't created with NewXSign()
|
|
return nil, errNotInitialized
|
|
|
|
}
|
|
return d.bob.Sig, nil
|
|
}
|
|
|
|
// Encodes an alice object as a byte sequence after DKG has been completed.
|
|
func EncodeAlice(a *Alice) ([]byte, error) {
|
|
var buf bytes.Buffer
|
|
err := gob.NewEncoder(&buf).Encode(a)
|
|
return buf.Bytes(), err
|
|
}
|
|
|
|
// Decodes an alice object that was encoded after DKG.
|
|
func DecodeAlice(params *Params, b []byte) (*Alice, error) {
|
|
alice := NewAlice(params)
|
|
err := gob.NewDecoder(bytes.NewBuffer(b)).Decode(alice)
|
|
return alice, err
|
|
}
|
|
|
|
// Encodes a bob object as a byte sequence after DKG has been completed.
|
|
func EncodeBob(b *Bob) ([]byte, error) {
|
|
var buf bytes.Buffer
|
|
err := gob.NewEncoder(&buf).Encode(b)
|
|
return buf.Bytes(), err
|
|
}
|
|
|
|
// Decodes an bob object that was encoded after DKG.
|
|
func DecodeBob(params *Params, b []byte) (*Bob, error) {
|
|
bob := NewBob(params)
|
|
err := gob.NewDecoder(bytes.NewBuffer(b)).Decode(bob)
|
|
return bob, err
|
|
}
|