mirror of https://github.com/certusone/dc4bc.git
WIP: airgapped
This commit is contained in:
parent
689fe15368
commit
7e50689971
|
@ -7,16 +7,26 @@ import (
|
|||
"github.com/depools/dc4bc/dkg"
|
||||
"github.com/depools/dc4bc/fsm/fsm"
|
||||
"github.com/depools/dc4bc/fsm/state_machines/dkg_proposal_fsm"
|
||||
"github.com/depools/dc4bc/fsm/state_machines/signature_proposal_fsm"
|
||||
"github.com/depools/dc4bc/fsm/types/requests"
|
||||
"github.com/depools/dc4bc/fsm/types/responses"
|
||||
"github.com/depools/dc4bc/qr"
|
||||
"go.dedis.ch/kyber/v3"
|
||||
"go.dedis.ch/kyber/v3/encrypt/ecies"
|
||||
"go.dedis.ch/kyber/v3/group/edwards25519"
|
||||
"go.dedis.ch/kyber/v3/pairing/bn256"
|
||||
dkg2 "go.dedis.ch/kyber/v3/share/dkg/pedersen"
|
||||
dkgPedersen "go.dedis.ch/kyber/v3/share/dkg/pedersen"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
resultQRFolder = "result_qr_codes"
|
||||
)
|
||||
|
||||
type AirgappedMachine struct {
|
||||
dkgInstances map[string]*dkg.DKG // should be a map or something to distinguish different rounds
|
||||
sync.Mutex
|
||||
|
||||
dkgInstances map[string]*dkg.DKG
|
||||
qrProcessor qr.Processor
|
||||
}
|
||||
|
||||
|
@ -28,6 +38,63 @@ func NewAirgappedMachine() *AirgappedMachine {
|
|||
return machine
|
||||
}
|
||||
|
||||
func (am *AirgappedMachine) encryptData(dkgIdentifier, to string, data []byte) ([]byte, error) {
|
||||
suite := edwards25519.NewBlakeSHA256Ed25519()
|
||||
dkgInstance, ok := am.dkgInstances[dkgIdentifier]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid dkg identifier: %s", dkgIdentifier)
|
||||
}
|
||||
|
||||
pk, err := dkgInstance.GetPubKeyByParticipantID(to)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get pk for participant %s: %w", to, err)
|
||||
}
|
||||
|
||||
encryptedData, err := ecies.Encrypt(suite, pk, data, suite.Hash)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encrypt data: %w", err)
|
||||
}
|
||||
return encryptedData, nil
|
||||
}
|
||||
|
||||
func (am *AirgappedMachine) decryptData(dkgIdentifier string, data []byte) ([]byte, error) {
|
||||
suite := edwards25519.NewBlakeSHA256Ed25519()
|
||||
dkgInstance, ok := am.dkgInstances[dkgIdentifier]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid dkg identifier: %s", dkgIdentifier)
|
||||
}
|
||||
|
||||
privateKey := dkgInstance.GetSecKey()
|
||||
|
||||
decryptedData, err := ecies.Decrypt(suite, privateKey, data, suite.Hash)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decrypt data: %w", err)
|
||||
}
|
||||
return decryptedData, nil
|
||||
}
|
||||
|
||||
func (am *AirgappedMachine) handleStateAwaitParticipantsConfirmations(o *client.Operation) error {
|
||||
var (
|
||||
payload responses.SignatureProposalParticipantInvitationsResponse
|
||||
err error
|
||||
)
|
||||
|
||||
if err = json.Unmarshal(o.Payload, &payload); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal payload: %w", err)
|
||||
}
|
||||
|
||||
if _, ok := am.dkgInstances[o.DKGIdentifier]; ok {
|
||||
return fmt.Errorf("dkg instance %s already exists", o.DKGIdentifier)
|
||||
}
|
||||
|
||||
am.dkgInstances[o.DKGIdentifier] = dkg.Init()
|
||||
|
||||
// sMaybe we should do something with Title and ParticipantID
|
||||
// And i think threshold should be here
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (am *AirgappedMachine) handleStateDkgPubKeysAwaitConfirmations(o *client.Operation) error {
|
||||
dkgInstance, ok := am.dkgInstances[o.DKGIdentifier]
|
||||
if !ok {
|
||||
|
@ -97,7 +164,7 @@ func (am *AirgappedMachine) handleStateDkgCommitsAwaitConfirmations(o *client.Op
|
|||
return nil
|
||||
}
|
||||
|
||||
func (am *AirgappedMachine) handleStateDkgDealsAwaitConfirmations(o *client.Operation) error {
|
||||
func (am *AirgappedMachine) handleStateDkgDealsAwaitConfirmations(o client.Operation) ([]client.Operation, error) {
|
||||
var (
|
||||
payload responses.DKGProposalCommitParticipantResponse
|
||||
err error
|
||||
|
@ -105,47 +172,53 @@ func (am *AirgappedMachine) handleStateDkgDealsAwaitConfirmations(o *client.Oper
|
|||
|
||||
dkgInstance, ok := am.dkgInstances[o.DKGIdentifier]
|
||||
if !ok {
|
||||
return fmt.Errorf("dkg instance with identifier %s does not exist", o.DKGIdentifier)
|
||||
return nil, fmt.Errorf("dkg instance with identifier %s does not exist", o.DKGIdentifier)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(o.Payload, &payload); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal payload: %w", err)
|
||||
return nil, fmt.Errorf("failed to unmarshal payload: %w", err)
|
||||
}
|
||||
|
||||
for _, entry := range payload {
|
||||
var commits []kyber.Point
|
||||
if err = json.Unmarshal(entry.Commit, &commits); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal commits: %w", err)
|
||||
return nil, fmt.Errorf("failed to unmarshal commits: %w", err)
|
||||
}
|
||||
dkgInstance.StoreCommits(entry.Title, commits)
|
||||
}
|
||||
|
||||
deals, err := dkgInstance.GetDeals()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get deals: %w", err)
|
||||
return nil, fmt.Errorf("failed to get deals: %w", err)
|
||||
}
|
||||
|
||||
operations := make([]client.Operation, 0, len(deals))
|
||||
|
||||
am.dkgInstances[o.DKGIdentifier] = dkgInstance
|
||||
|
||||
// Here we should create N=len(deals) private (encrypted) messages to participants but i don't know how to it yet
|
||||
//-------------------------------------------------------
|
||||
dealsBz, err := json.Marshal(deals)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal deals")
|
||||
for index, deal := range deals {
|
||||
dealBz, err := json.Marshal(deal)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal dea;: %w", err)
|
||||
}
|
||||
toParticipant := dkgInstance.GetParticipantByIndex(index)
|
||||
encryptedDeal, err := am.encryptData(o.DKGIdentifier, toParticipant, dealBz)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to encrypt deal: %w", err)
|
||||
}
|
||||
req := requests.DKGProposalDealConfirmationRequest{
|
||||
ParticipantId: dkgInstance.ParticipantID,
|
||||
Deal: encryptedDeal,
|
||||
}
|
||||
o.To = toParticipant
|
||||
reqBz, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||
}
|
||||
o.Result = reqBz
|
||||
operations = append(operations, o)
|
||||
}
|
||||
|
||||
req := requests.DKGProposalDealConfirmationRequest{
|
||||
ParticipantId: dkgInstance.ParticipantID,
|
||||
Deal: dealsBz,
|
||||
}
|
||||
//-------------------------------------------------------
|
||||
|
||||
reqBz, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal request: %w", err)
|
||||
}
|
||||
o.Result = reqBz
|
||||
return nil
|
||||
return operations, nil
|
||||
}
|
||||
|
||||
func (am *AirgappedMachine) handleStateDkgResponsesAwaitConfirmations(o *client.Operation) error {
|
||||
|
@ -164,7 +237,7 @@ func (am *AirgappedMachine) handleStateDkgResponsesAwaitConfirmations(o *client.
|
|||
}
|
||||
|
||||
for _, entry := range payload {
|
||||
var deals []dkg2.Deal // mock, must be another logic, because of encryption
|
||||
var deals []dkgPedersen.Deal // mock, must be another logic, because of encryption
|
||||
if err = json.Unmarshal(entry.Deal, &deals); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal commits: %w", err)
|
||||
}
|
||||
|
@ -198,49 +271,64 @@ func (am *AirgappedMachine) handleStateDkgResponsesAwaitConfirmations(o *client.
|
|||
return nil
|
||||
}
|
||||
|
||||
func (am *AirgappedMachine) HandleQR() error {
|
||||
func (am *AirgappedMachine) HandleQR() ([]string, error) {
|
||||
var (
|
||||
err error
|
||||
operation client.Operation
|
||||
qrData []byte
|
||||
err error
|
||||
operation client.Operation
|
||||
qrData []byte
|
||||
operations []client.Operation
|
||||
)
|
||||
|
||||
am.Lock()
|
||||
defer am.Unlock()
|
||||
|
||||
if qrData, err = am.qrProcessor.ReadQR(); err != nil {
|
||||
return fmt.Errorf("failed to read QR: %w", err)
|
||||
return nil, fmt.Errorf("failed to read QR: %w", err)
|
||||
}
|
||||
if err = json.Unmarshal(qrData, &operation); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal operation: %w", err)
|
||||
return nil, fmt.Errorf("failed to unmarshal operation: %w", err)
|
||||
}
|
||||
|
||||
switch fsm.State(operation.Type) {
|
||||
case signature_proposal_fsm.StateAwaitParticipantsConfirmations:
|
||||
////////
|
||||
case dkg_proposal_fsm.StateDkgPubKeysAwaitConfirmations:
|
||||
if err = am.handleStateDkgPubKeysAwaitConfirmations(&operation); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
case dkg_proposal_fsm.StateDkgCommitsAwaitConfirmations:
|
||||
if err = am.handleStateDkgCommitsAwaitConfirmations(&operation); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
case dkg_proposal_fsm.StateDkgDealsAwaitConfirmations:
|
||||
if err = am.handleStateDkgCommitsAwaitConfirmations(&operation); err != nil {
|
||||
return err
|
||||
if operations, err = am.handleStateDkgDealsAwaitConfirmations(operation); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case dkg_proposal_fsm.StateDkgResponsesAwaitConfirmations:
|
||||
if err = am.handleStateDkgResponsesAwaitConfirmations(&operation); err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("invalid operation type: %s", operation.Type)
|
||||
return nil, fmt.Errorf("invalid operation type: %s", operation.Type)
|
||||
}
|
||||
|
||||
operationBz, err := json.Marshal(operation)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal operation: %w", err)
|
||||
if len(operation.Result) > 0 {
|
||||
operations = append(operations, operation)
|
||||
}
|
||||
|
||||
//TODO: return path
|
||||
if err := am.qrProcessor.WriteQR(fmt.Sprintf("%s.png", operation.ID), operationBz); err != nil {
|
||||
return fmt.Errorf("failed to write QR")
|
||||
qrPath := "%s/%s_%s_%s.png"
|
||||
qrPaths := make([]string, 0, len(operations))
|
||||
for _, o := range operations {
|
||||
operationBz, err := json.Marshal(o)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal operation: %w", err)
|
||||
}
|
||||
|
||||
if err := am.qrProcessor.WriteQR(fmt.Sprintf(qrPath, resultQRFolder, o.Type, o.ID, o.To), operationBz); err != nil {
|
||||
return nil, fmt.Errorf("failed to write QR")
|
||||
}
|
||||
qrPaths = append(qrPaths, qrPath)
|
||||
}
|
||||
|
||||
return nil
|
||||
return qrPaths, nil
|
||||
}
|
||||
|
|
16
dkg/dkg.go
16
dkg/dkg.go
|
@ -46,6 +46,22 @@ func (d *DKG) GetPubKey() kyber.Point {
|
|||
return d.pubKey
|
||||
}
|
||||
|
||||
func (d *DKG) GetSecKey() kyber.Scalar {
|
||||
return d.secKey
|
||||
}
|
||||
|
||||
func (d *DKG) GetPubKeyByParticipantID(pid string) (kyber.Point, error) {
|
||||
pk, err := d.pubkeys.GetPKByParticipant(pid)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get pk for participant %s: %w", pid, err)
|
||||
}
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
func (d *DKG) GetParticipantByIndex(index int) string {
|
||||
return d.pubkeys.GetParticipantByIndex(index)
|
||||
}
|
||||
|
||||
func (d *DKG) StorePubKey(participant string, pk kyber.Point) bool {
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
|
10
dkg/types.go
10
dkg/types.go
|
@ -1,6 +1,7 @@
|
|||
package dkg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go.dedis.ch/kyber/v3"
|
||||
)
|
||||
|
||||
|
@ -33,6 +34,15 @@ func (s PKStore) GetPKs() []kyber.Point {
|
|||
return out
|
||||
}
|
||||
|
||||
func (s PKStore) GetPKByParticipant(p string) (kyber.Point, error) {
|
||||
for _, val := range s {
|
||||
if val.Participant == p {
|
||||
return val.PK, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("participant %s does not exist", p)
|
||||
}
|
||||
|
||||
func (s PKStore) GetParticipantByIndex(index int) string {
|
||||
if index < 0 || index > len(s) {
|
||||
return ""
|
||||
|
|
Loading…
Reference in New Issue