ceremonyclient/nekryptology/pkg/tecdsa/dkls/v0/proto.go
2023-07-05 00:32:28 -05:00

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
}