Skip to content

Commit 40740f3

Browse files
committed
增加 ecc 包
1 parent dce07ca commit 40740f3

File tree

4 files changed

+433
-0
lines changed

4 files changed

+433
-0
lines changed

ecc/key.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright 2025 FishGoddess. All rights reserved.
2+
// Use of this source code is governed by a MIT style
3+
// license that can be found in the LICENSE file.
4+
5+
package ecc
6+
7+
import (
8+
"crypto/ed25519"
9+
"io"
10+
"os"
11+
12+
"github.com/FishGoddess/cryptox"
13+
)
14+
15+
// GenerateKeys generates a key set.
16+
func GenerateKeys() (PrivateKey, PublicKey, error) {
17+
publicKey, privateKey, err := ed25519.GenerateKey(nil)
18+
if err != nil {
19+
return PrivateKey{}, PublicKey{}, err
20+
}
21+
22+
newPrivateKey := newPrivateKey(privateKey)
23+
newPublicKey := newPublicKey(publicKey)
24+
return newPrivateKey, newPublicKey, nil
25+
}
26+
27+
// GeneratePrivateKey generates a private key.
28+
func GeneratePrivateKey() (PrivateKey, error) {
29+
privateKey, _, err := GenerateKeys()
30+
return privateKey, err
31+
}
32+
33+
// GeneratePublicKey generates a public key from private key.
34+
func GeneratePublicKey(privateKey PrivateKey) (PublicKey, error) {
35+
publicKey := privateKey.Key().Public().(ed25519.PublicKey)
36+
newPublicKey := newPublicKey(publicKey)
37+
return newPublicKey, nil
38+
}
39+
40+
// ParsePrivateKey parses a private key from bytes.
41+
func ParsePrivateKey(keyBytes cryptox.Bytes) (PrivateKey, error) {
42+
privateKey := ed25519.PrivateKey(keyBytes)
43+
newPrivateKey := newPrivateKey(privateKey)
44+
return newPrivateKey, nil
45+
}
46+
47+
// ParsePublicKey parses a public key from bytes.
48+
func ParsePublicKey(keyBytes cryptox.Bytes) (PublicKey, error) {
49+
publicKey := ed25519.PublicKey(keyBytes)
50+
newPublicKey := newPublicKey(publicKey)
51+
return newPublicKey, nil
52+
}
53+
54+
// ReadPrivateKey reads a private key from a reader.
55+
func ReadPrivateKey(keyReader io.Reader) (PrivateKey, error) {
56+
keyBytes, err := io.ReadAll(keyReader)
57+
if err != nil {
58+
return PrivateKey{}, err
59+
}
60+
61+
return ParsePrivateKey(keyBytes)
62+
}
63+
64+
// ReadPublicKey reads a public key from a reader.
65+
func ReadPublicKey(keyReader io.Reader) (PublicKey, error) {
66+
keyBytes, err := io.ReadAll(keyReader)
67+
if err != nil {
68+
return PublicKey{}, err
69+
}
70+
71+
return ParsePublicKey(keyBytes)
72+
}
73+
74+
// LoadPrivateKey loads a private key from a file.
75+
func LoadPrivateKey(keyFile string) (PrivateKey, error) {
76+
keyBytes, err := os.ReadFile(keyFile)
77+
if err != nil {
78+
return PrivateKey{}, err
79+
}
80+
81+
return ParsePrivateKey(keyBytes)
82+
}
83+
84+
// LoadPublicKey loads a public key from a file.
85+
func LoadPublicKey(keyFile string) (PublicKey, error) {
86+
keyBytes, err := os.ReadFile(keyFile)
87+
if err != nil {
88+
return PublicKey{}, err
89+
}
90+
91+
return ParsePublicKey(keyBytes)
92+
}
93+
94+
// MustLoadPrivateKey loads private key from a file or panic if failed.
95+
func MustLoadPrivateKey(keyFile string) PrivateKey {
96+
key, err := LoadPrivateKey(keyFile)
97+
if err != nil {
98+
panic(err)
99+
}
100+
101+
return key
102+
}
103+
104+
// MustLoadPublicKey loads public key from a file or panic if failed.
105+
func MustLoadPublicKey(keyFile string) PublicKey {
106+
key, err := LoadPublicKey(keyFile)
107+
if err != nil {
108+
panic(err)
109+
}
110+
111+
return key
112+
}

ecc/key_test.go

Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
// Copyright 2025 FishGoddess. All rights reserved.
2+
// Use of this source code is governed by a MIT style
3+
// license that can be found in the LICENSE file.
4+
5+
package ecc
6+
7+
import (
8+
"bytes"
9+
"path/filepath"
10+
"testing"
11+
)
12+
13+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestGenerateKeys$
14+
func TestGenerateKeys(t *testing.T) {
15+
privateKey, publicKey, err := GenerateKeys()
16+
if err != nil {
17+
t.Fatal(err)
18+
}
19+
20+
t.Log("Public Key:", privateKey)
21+
t.Log("Private Key:", publicKey)
22+
}
23+
24+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestGeneratePrivateKey$
25+
func TestGeneratePrivateKey(t *testing.T) {
26+
privateKey, err := GeneratePrivateKey()
27+
if err != nil {
28+
t.Fatal(err)
29+
}
30+
31+
t.Log("Private Key:", privateKey)
32+
}
33+
34+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestGeneratePublicKey$
35+
func TestGeneratePublicKey(t *testing.T) {
36+
privateKey, publicKey1, err := GenerateKeys()
37+
if err != nil {
38+
t.Fatal(err)
39+
}
40+
41+
publicKey2, err := GeneratePublicKey(privateKey)
42+
if err != nil {
43+
t.Fatal(err)
44+
}
45+
46+
if !publicKey2.EqualsTo(publicKey1) {
47+
t.Fatalf("publicKey2 %+v != publicKey1 %+v", publicKey2, publicKey1)
48+
}
49+
}
50+
51+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestParsePrivateKey$
52+
func TestParsePrivateKey(t *testing.T) {
53+
privateKey, err := GeneratePrivateKey()
54+
if err != nil {
55+
t.Fatal(err)
56+
}
57+
58+
parsedPrivateKey, err := ParsePrivateKey(privateKey.Bytes())
59+
if err != nil {
60+
t.Fatal(err)
61+
}
62+
63+
if !parsedPrivateKey.EqualsTo(privateKey) {
64+
t.Fatalf("parsedPrivateKey %+v != privateKey %+v", parsedPrivateKey, privateKey)
65+
}
66+
}
67+
68+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestParsePublicKey$
69+
func TestParsePublicKey(t *testing.T) {
70+
privateKey, err := GeneratePrivateKey()
71+
if err != nil {
72+
t.Fatal(err)
73+
}
74+
75+
publicKey, err := GeneratePublicKey(privateKey)
76+
if err != nil {
77+
t.Fatal(err)
78+
}
79+
80+
parsedPublicKey, err := ParsePublicKey(publicKey.Bytes())
81+
if err != nil {
82+
t.Fatal(err)
83+
}
84+
85+
if !parsedPublicKey.EqualsTo(publicKey) {
86+
t.Fatalf("parsedPublicKey %+v != publicKey %+v", parsedPublicKey, publicKey)
87+
}
88+
}
89+
90+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestReadPrivateKey$
91+
func TestReadPrivateKey(t *testing.T) {
92+
privateKey, err := GeneratePrivateKey()
93+
if err != nil {
94+
t.Fatal(err)
95+
}
96+
97+
reader := bytes.NewReader(privateKey.Bytes())
98+
99+
readPrivateKey, err := ReadPrivateKey(reader)
100+
if err != nil {
101+
t.Fatal(err)
102+
}
103+
104+
if !readPrivateKey.EqualsTo(privateKey) {
105+
t.Fatalf("readPrivateKey %+v != privateKey %+v", readPrivateKey, privateKey)
106+
}
107+
}
108+
109+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestReadPublicKey$
110+
func TestReadPublicKey(t *testing.T) {
111+
privateKey, err := GeneratePrivateKey()
112+
if err != nil {
113+
t.Fatal(err)
114+
}
115+
116+
publicKey, err := GeneratePublicKey(privateKey)
117+
if err != nil {
118+
t.Fatal(err)
119+
}
120+
121+
reader := bytes.NewReader(publicKey.Bytes())
122+
123+
readPublicKey, err := ReadPublicKey(reader)
124+
if err != nil {
125+
t.Fatal(err)
126+
}
127+
128+
if !readPublicKey.EqualsTo(publicKey) {
129+
t.Fatalf("readPublicKey %+v != publicKey %+v", readPublicKey, publicKey)
130+
}
131+
}
132+
133+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestLoadPrivateKey$
134+
func TestLoadPrivateKey(t *testing.T) {
135+
privateKey, err := GeneratePrivateKey()
136+
if err != nil {
137+
t.Fatal(err)
138+
}
139+
140+
privateKeyFile := filepath.Join(t.TempDir(), "TestLoadPrivateKey.key")
141+
142+
_, err = privateKey.Bytes().WriteToFile(privateKeyFile)
143+
if err != nil {
144+
t.Fatal(err)
145+
}
146+
147+
loadedPrivateKey, err := LoadPrivateKey(privateKeyFile)
148+
if err != nil {
149+
t.Fatal(err)
150+
}
151+
152+
if !loadedPrivateKey.EqualsTo(privateKey) {
153+
t.Fatalf("loadedPrivateKey %+v != privateKey %+v", loadedPrivateKey, privateKey)
154+
}
155+
}
156+
157+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestLoadPublicKey$
158+
func TestLoadPublicKey(t *testing.T) {
159+
privateKey, err := GeneratePrivateKey()
160+
if err != nil {
161+
t.Fatal(err)
162+
}
163+
164+
publicKey, err := GeneratePublicKey(privateKey)
165+
if err != nil {
166+
t.Fatal(err)
167+
}
168+
169+
publicKeyFile := filepath.Join(t.TempDir(), "TestLoadPublicKey.pub")
170+
171+
_, err = publicKey.Bytes().WriteToFile(publicKeyFile)
172+
if err != nil {
173+
t.Fatal(err)
174+
}
175+
176+
loadedPublicKey, err := LoadPublicKey(publicKeyFile)
177+
if err != nil {
178+
t.Fatal(err)
179+
}
180+
181+
if !loadedPublicKey.EqualsTo(publicKey) {
182+
t.Fatalf("loadedPublicKey %+v != publicKey %+v", loadedPublicKey, publicKey)
183+
}
184+
}
185+
186+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestMustLoadPrivateKey$
187+
func TestMustLoadPrivateKey(t *testing.T) {
188+
privateKey, err := GeneratePrivateKey()
189+
if err != nil {
190+
t.Fatal(err)
191+
}
192+
193+
privateKeyFile := filepath.Join(t.TempDir(), "TestMustLoadPrivateKey.key")
194+
195+
_, err = privateKey.Bytes().WriteToFile(privateKeyFile)
196+
if err != nil {
197+
t.Fatal(err)
198+
}
199+
200+
defer func() {
201+
if err := recover(); err != nil {
202+
t.Fatal(err)
203+
}
204+
}()
205+
206+
loadedPrivateKey := MustLoadPrivateKey(privateKeyFile)
207+
208+
if !loadedPrivateKey.EqualsTo(privateKey) {
209+
t.Fatalf("loadedPrivateKey %+v != privateKey %+v", loadedPrivateKey, privateKey)
210+
}
211+
}
212+
213+
// go test -v -cover -count=1 -test.cpu=1 -run=^TestMustLoadPublicKey$
214+
func TestMustLoadPublicKey(t *testing.T) {
215+
privateKey, err := GeneratePrivateKey()
216+
if err != nil {
217+
t.Fatal(err)
218+
}
219+
220+
publicKey, err := GeneratePublicKey(privateKey)
221+
if err != nil {
222+
t.Fatal(err)
223+
}
224+
225+
publicKeyFile := filepath.Join(t.TempDir(), "TestMustLoadPublicKey.pub")
226+
227+
_, err = publicKey.Bytes().WriteToFile(publicKeyFile)
228+
if err != nil {
229+
t.Fatal(err)
230+
}
231+
232+
defer func() {
233+
if err := recover(); err != nil {
234+
t.Fatal(err)
235+
}
236+
}()
237+
238+
loadedPublicKey := MustLoadPublicKey(publicKeyFile)
239+
240+
if !loadedPublicKey.EqualsTo(publicKey) {
241+
t.Fatalf("loadedPublicKey %+v != publicKey %+v", loadedPublicKey, publicKey)
242+
}
243+
}

ecc/private.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright 2025 FishGoddess. All rights reserved.
2+
// Use of this source code is governed by a MIT style
3+
// license that can be found in the LICENSE file.
4+
5+
package ecc
6+
7+
import (
8+
"crypto/ed25519"
9+
10+
"github.com/FishGoddess/cryptox"
11+
)
12+
13+
type PrivateKey struct {
14+
key ed25519.PrivateKey
15+
}
16+
17+
func newPrivateKey(key ed25519.PrivateKey) PrivateKey {
18+
return PrivateKey{key: key}
19+
}
20+
21+
// Key returns the key of pk.
22+
func (pk PrivateKey) Key() ed25519.PrivateKey {
23+
return pk.key
24+
}
25+
26+
// Bytes returns the bytes of pk.
27+
func (pk PrivateKey) Bytes() cryptox.Bytes {
28+
return cryptox.Bytes(pk.key)
29+
}
30+
31+
// String returns the string of pk.
32+
func (pk PrivateKey) String() string {
33+
return string(pk.key)
34+
}
35+
36+
// EqualsTo returns if pk equals to privateKey.
37+
func (pk PrivateKey) EqualsTo(privateKey PrivateKey) bool {
38+
return pk.key.Equal(privateKey.key)
39+
}

0 commit comments

Comments
 (0)