mirror of
				https://source.quilibrium.com/quilibrium/ceremonyclient.git
				synced 2025-11-04 00:27:41 +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
 | 
						|
}
 |