Skip to content

Commit 4e358c5

Browse files
committed
Supported p256 for event initiator
1 parent 9cf994c commit 4e358c5

9 files changed

Lines changed: 360 additions & 50 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ node0
2121
node1
2222
node2
2323
config.yaml
24+
peers.json

cmd/mpcium-cli/generate-initiator.go

Lines changed: 81 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@ package main
22

33
import (
44
"context"
5+
"crypto/ecdsa"
56
"crypto/ed25519"
7+
"crypto/elliptic"
68
"crypto/rand"
9+
"crypto/x509"
710
"encoding/hex"
811
"encoding/json"
912
"fmt"
@@ -21,18 +24,34 @@ import (
2124
// Identity struct to store node metadata
2225
type InitiatorIdentity struct {
2326
NodeName string `json:"node_name"`
27+
Algorithm string `json:"algorithm,omitempty"`
2428
PublicKey string `json:"public_key"`
2529
CreatedAt string `json:"created_at"`
2630
CreatedBy string `json:"created_by"`
2731
MachineOS string `json:"machine_os"`
2832
MachineName string `json:"machine_name"`
2933
}
3034

35+
// KeyData holds the generated key information
36+
type KeyData struct {
37+
PublicKeyHex string
38+
PrivateKeyHex string
39+
}
40+
3141
func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
3242
nodeName := c.String("node-name")
3343
outputDir := c.String("output-dir")
3444
encrypt := c.Bool("encrypt")
3545
overwrite := c.Bool("overwrite")
46+
algorithm := c.String("algorithm")
47+
48+
if algorithm == "" {
49+
algorithm = "ed25519"
50+
}
51+
52+
if algorithm != "ed25519" && algorithm != "p256" {
53+
return fmt.Errorf("invalid algorithm: %s. Must be 'ed25519' or 'p256'", algorithm)
54+
}
3655

3756
// Create output directory if it doesn't exist
3857
if err := os.MkdirAll(outputDir, 0750); err != nil {
@@ -46,7 +65,10 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
4665

4766
// Check for existing identity file
4867
if _, err := os.Stat(identityPath); err == nil && !overwrite {
49-
return fmt.Errorf("identity file already exists: %s (use --overwrite to force)", identityPath)
68+
return fmt.Errorf(
69+
"identity file already exists: %s (use --overwrite to force)",
70+
identityPath,
71+
)
5072
}
5173

5274
// Check for existing key files
@@ -56,19 +78,26 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
5678

5779
if encrypt {
5880
if _, err := os.Stat(encKeyPath); err == nil && !overwrite {
59-
return fmt.Errorf("encrypted key file already exists: %s (use --overwrite to force)", encKeyPath)
81+
return fmt.Errorf(
82+
"encrypted key file already exists: %s (use --overwrite to force)",
83+
encKeyPath,
84+
)
6085
}
6186
}
6287

63-
// Generate Ed25519 keypair
64-
pubKey, privKeyFull, err := ed25519.GenerateKey(rand.Reader)
65-
if err != nil {
66-
return fmt.Errorf("failed to generate Ed25519 keypair: %w", err)
88+
// Generate keys based on algorithm
89+
var keyData KeyData
90+
var err error
91+
92+
if algorithm == "ed25519" {
93+
keyData, err = generateEd25519Keys()
94+
} else {
95+
keyData, err = generateP256Keys()
6796
}
6897

69-
// Extract 32-byte seed
70-
privKeySeed := privKeyFull.Seed()
71-
privHex := hex.EncodeToString(privKeySeed)
98+
if err != nil {
99+
return fmt.Errorf("failed to generate %s keys: %w", algorithm, err)
100+
}
72101

73102
// Get current user
74103
currentUser, err := user.Current()
@@ -85,7 +114,8 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
85114
// Create Identity object
86115
identity := InitiatorIdentity{
87116
NodeName: nodeName,
88-
PublicKey: hex.EncodeToString(pubKey),
117+
Algorithm: algorithm,
118+
PublicKey: keyData.PublicKeyHex,
89119
CreatedAt: time.Now().UTC().Format(time.RFC3339),
90120
CreatedBy: currentUser.Username,
91121
MachineOS: runtime.GOOS,
@@ -136,7 +166,7 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
136166
}
137167

138168
// Write the encrypted private key
139-
if _, err := identityWriter.Write([]byte(privHex)); err != nil {
169+
if _, err := identityWriter.Write([]byte(keyData.PrivateKeyHex)); err != nil {
140170
return fmt.Errorf("failed to write encrypted private key: %w", err)
141171
}
142172

@@ -152,7 +182,7 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
152182
fmt.Println("WARNING: You are generating the private key without encryption.")
153183
fmt.Println("This is less secure. Consider using --encrypt flag for better security.")
154184

155-
if err := os.WriteFile(keyPath, []byte(privHex), 0600); err != nil {
185+
if err := os.WriteFile(keyPath, []byte(keyData.PrivateKeyHex), 0600); err != nil {
156186
return fmt.Errorf("failed to save private key: %w", err)
157187
}
158188
}
@@ -162,3 +192,42 @@ func generateInitiatorIdentity(ctx context.Context, c *cli.Command) error {
162192
fmt.Println("- Identity JSON:", identityPath)
163193
return nil
164194
}
195+
196+
// generateEd25519Keys generates Ed25519 keypair
197+
func generateEd25519Keys() (KeyData, error) {
198+
pubKey, privKeyFull, err := ed25519.GenerateKey(rand.Reader)
199+
if err != nil {
200+
return KeyData{}, err
201+
}
202+
203+
privKeySeed := privKeyFull.Seed()
204+
return KeyData{
205+
PublicKeyHex: hex.EncodeToString(pubKey),
206+
PrivateKeyHex: hex.EncodeToString(privKeySeed),
207+
}, nil
208+
}
209+
210+
// generateP256Keys generates P-256 keypair
211+
func generateP256Keys() (KeyData, error) {
212+
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
213+
if err != nil {
214+
return KeyData{}, err
215+
}
216+
217+
// Convert private key to PEM format
218+
privateKeyBytes, err := x509.MarshalECPrivateKey(privateKey)
219+
if err != nil {
220+
return KeyData{}, err
221+
}
222+
223+
// Convert public key to DER format
224+
publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey)
225+
if err != nil {
226+
return KeyData{}, err
227+
}
228+
229+
return KeyData{
230+
PublicKeyHex: hex.EncodeToString(publicKeyBytes),
231+
PrivateKeyHex: hex.EncodeToString(privateKeyBytes),
232+
}, nil
233+
}

cmd/mpcium-cli/main.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,17 @@ func main() {
122122
Value: false,
123123
Usage: "Overwrite identity files if they already exist",
124124
},
125+
&cli.StringFlag{
126+
Name: "algorithm",
127+
Aliases: []string{"a"},
128+
Value: "ed25519",
129+
Usage: "Algorithm to use for key generation (ed25519,p256)",
130+
},
131+
&cli.StringFlag{
132+
Name: "pubkey",
133+
Aliases: []string{"p"},
134+
Usage: "Path to PEM file containing P-256 public key (required when algorithm=p256)",
135+
},
125136
},
126137
Action: generateInitiatorIdentity,
127138
},

config.yaml.template

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ consul:
66
mpc_threshold: 2
77
environment: development
88
badger_password: "F))ysJp?E]ol&I;^"
9+
event_initiator_algorithm: "p256" # or "ed25519", default: ed25519
910
event_initiator_pubkey: "event_initiator_pubkey"
1011
db_path: "."
1112
backup_enabled: true

examples/generate/main.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,13 @@ func main() {
103103
go func() {
104104
wg.Wait()
105105
totalDuration := time.Since(startAll).Seconds()
106-
logger.Info("All wallets generated", "count", completedCount, "total_duration_seconds", fmt.Sprintf("%.3f", totalDuration))
106+
logger.Info(
107+
"All wallets generated",
108+
"count",
109+
completedCount,
110+
"total_duration_seconds",
111+
fmt.Sprintf("%.3f", totalDuration),
112+
)
107113

108114
// Save wallet IDs to wallets.json
109115
walletIDsMu.Lock()

peers.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"node0": "0ce02715-0ead-48ef-9772-2583316cc860",
3-
"node1": "c95c340e-5a18-472d-b9b0-5ac68218213a",
4-
"node2": "ac37e85f-caca-4bee-8a3a-49a0fe35abff"
5-
}
2+
"node0": "56cb951b-8f0e-4a58-91c1-4ee55180718a",
3+
"node1": "5f7d2a52-bc81-46ef-9cae-b73c0d78cce6",
4+
"node2": "0bbc804f-dd76-4888-baeb-0be6612064f2"
5+
}

pkg/client/client.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,25 @@ func NewMPCClient(opts Options) MPCClient {
117117
priv := ed25519.NewKeyFromSeed(privSeed)
118118

119119
// 2) Create the PubSub for both publish & subscribe
120-
signingBroker, err := messaging.NewJetStreamBroker(context.Background(), opts.NatsConn, "mpc-signing", []string{
121-
"mpc.signing_request.*",
122-
})
120+
signingBroker, err := messaging.NewJetStreamBroker(
121+
context.Background(),
122+
opts.NatsConn,
123+
"mpc-signing",
124+
[]string{
125+
"mpc.signing_request.*",
126+
},
127+
)
123128
if err != nil {
124129
logger.Fatal("Failed to create signing jetstream broker", err)
125130
}
126-
keygenBroker, err := messaging.NewJetStreamBroker(context.Background(), opts.NatsConn, "mpc-keygen", []string{
127-
"mpc.keygen_request.*",
128-
})
131+
keygenBroker, err := messaging.NewJetStreamBroker(
132+
context.Background(),
133+
opts.NatsConn,
134+
"mpc-keygen",
135+
[]string{
136+
"mpc.keygen_request.*",
137+
},
138+
)
129139
if err != nil {
130140
logger.Fatal("Failed to create keygen jetstream broker", err)
131141
}

0 commit comments

Comments
 (0)