Skip to content

Commit f8e9906

Browse files
committed
ed25519 开发
1 parent d134e4f commit f8e9906

File tree

14 files changed

+1009
-386
lines changed

14 files changed

+1009
-386
lines changed

ed25519/ed25519.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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 ed25519
6+
7+
import "crypto/ed25519"
8+
9+
type PrivateKey struct {
10+
key ed25519.PrivateKey
11+
}
12+
13+
// Sign signs data.
14+
func (pk PrivateKey) Sign(data []byte, opts ...Option) []byte {
15+
conf := newConfig().Apply(opts...)
16+
sign := ed25519.Sign(pk.key, data)
17+
sign = conf.encoding.Encode(sign)
18+
return sign
19+
}
20+
21+
type PublicKey struct {
22+
key ed25519.PublicKey
23+
}
24+
25+
// Verify verifies data with sign.
26+
func (pk PublicKey) Verify(data []byte, sign []byte, opts ...Option) error {
27+
conf := newConfig().Apply(opts...)
28+
verifyOpts := &ed25519.Options{Hash: conf.cryptoHash, Context: conf.context}
29+
30+
sign, err := conf.encoding.Decode(sign)
31+
if err != nil {
32+
return err
33+
}
34+
35+
return ed25519.VerifyWithOptions(pk.key, data, sign, verifyOpts)
36+
}

ed25519/ed25519_test.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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 ed25519
6+
7+
import (
8+
"bytes"
9+
"testing"
10+
)
11+
12+
type signTestCase struct {
13+
Data []byte
14+
SignData []byte
15+
SignDataHex []byte
16+
SignDataBase64 []byte
17+
}
18+
19+
type testRandomReader struct{}
20+
21+
func (testRandomReader) Read(p []byte) (n int, err error) {
22+
for i := range p {
23+
p[i] = 1
24+
}
25+
26+
return len(p), nil
27+
}
28+
29+
func newTestPrivateKey() PrivateKey {
30+
reader := bytes.NewReader([]byte(``))
31+
32+
privateKey, err := ReadPrivateKey(reader)
33+
if err != nil {
34+
panic(err)
35+
}
36+
37+
return privateKey
38+
}
39+
40+
func newTestPublicKey() PublicKey {
41+
reader := bytes.NewReader([]byte(``))
42+
43+
publicKey, err := ReadPublicKey(reader)
44+
if err != nil {
45+
panic(err)
46+
}
47+
48+
return publicKey
49+
}
50+
51+
// go test -v -cover -run=^TestSignVerify$
52+
func TestSignVerify(t *testing.T) {
53+
privateKey := newTestPrivateKey()
54+
publicKey := newTestPublicKey()
55+
56+
testCases := []signTestCase{
57+
{
58+
Data: []byte(""),
59+
SignData: []byte(""),
60+
SignDataHex: []byte(""),
61+
SignDataBase64: []byte(""),
62+
},
63+
{
64+
Data: []byte("123"),
65+
SignData: []byte(""),
66+
SignDataHex: []byte(""),
67+
SignDataBase64: []byte(""),
68+
},
69+
{
70+
Data: []byte("你好,世界"),
71+
SignData: []byte(""),
72+
SignDataHex: []byte(""),
73+
SignDataBase64: []byte(""),
74+
},
75+
}
76+
77+
for _, testCase := range testCases {
78+
// None
79+
sign := privateKey.Sign(testCase.Data)
80+
81+
err := publicKey.Verify(testCase.Data, sign)
82+
if err != nil {
83+
t.Fatal(err)
84+
}
85+
86+
// Hex
87+
sign = privateKey.Sign(testCase.Data, WithHex())
88+
89+
err = publicKey.Verify(testCase.Data, sign, WithHex())
90+
if err != nil {
91+
t.Fatal(err)
92+
}
93+
94+
// Base64
95+
sign = privateKey.Sign(testCase.Data, WithBase64())
96+
97+
err = publicKey.Verify(testCase.Data, sign, WithBase64())
98+
if err != nil {
99+
t.Fatal(err)
100+
}
101+
}
102+
}

ed25519/key.go

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
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 ed25519
6+
7+
import (
8+
"crypto/ed25519"
9+
"io"
10+
"os"
11+
)
12+
13+
// GenerateKeys generates a private key and a public key.
14+
func GenerateKeys(opts ...KeyOption) (PrivateKey, PublicKey, error) {
15+
conf := newKeyConfig().Apply(opts...)
16+
17+
var key ed25519.PrivateKey
18+
var pkey ed25519.PublicKey
19+
var err error
20+
21+
if len(conf.seed) > 0 {
22+
key = ed25519.NewKeyFromSeed(conf.seed)
23+
pkey = key.Public().(ed25519.PublicKey)
24+
} else {
25+
pkey, key, err = ed25519.GenerateKey(conf.random)
26+
}
27+
28+
if err != nil {
29+
return PrivateKey{}, PublicKey{}, err
30+
}
31+
32+
privateKey := PrivateKey{key: key}
33+
publicKey := PublicKey{key: pkey}
34+
return privateKey, publicKey, nil
35+
}
36+
37+
// WritePrivateKey writes the private key to the writer.
38+
func WritePrivateKey(writer io.Writer, privateKey PrivateKey, opts ...KeyOption) error {
39+
conf := newKeyConfig().Apply(opts...)
40+
41+
data, err := conf.encodePrivateKey(privateKey.key)
42+
if err != nil {
43+
return err
44+
}
45+
46+
_, err = writer.Write(data)
47+
return err
48+
}
49+
50+
// WritePublicKey writes the public key to the writer.
51+
func WritePublicKey(writer io.Writer, publicKey PublicKey, opts ...KeyOption) error {
52+
conf := newKeyConfig().Apply(opts...)
53+
54+
data, err := conf.encodePublicKey(publicKey.key)
55+
if err != nil {
56+
return err
57+
}
58+
59+
_, err = writer.Write(data)
60+
return err
61+
}
62+
63+
// ReadPrivateKey reads the private key from the reader.
64+
func ReadPrivateKey(reader io.Reader, opts ...KeyOption) (PrivateKey, error) {
65+
conf := newKeyConfig().Apply(opts...)
66+
67+
data, err := io.ReadAll(reader)
68+
if err != nil {
69+
return PrivateKey{}, err
70+
}
71+
72+
key, err := conf.decodePrivateKey(data)
73+
if err != nil {
74+
return PrivateKey{}, err
75+
}
76+
77+
privateKey := PrivateKey{key: key}
78+
return privateKey, nil
79+
}
80+
81+
// ReadPublicKey reads the public key from the reader.
82+
func ReadPublicKey(reader io.Reader, opts ...KeyOption) (PublicKey, error) {
83+
conf := newKeyConfig().Apply(opts...)
84+
85+
data, err := io.ReadAll(reader)
86+
if err != nil {
87+
return PublicKey{}, err
88+
}
89+
90+
key, err := conf.decodePublicKey(data)
91+
if err != nil {
92+
return PublicKey{}, err
93+
}
94+
95+
publicKey := PublicKey{key: key}
96+
return publicKey, nil
97+
}
98+
99+
func newFile(file string) (*os.File, error) {
100+
flag := os.O_CREATE | os.O_WRONLY | os.O_EXCL
101+
perm := os.FileMode(0644)
102+
return os.OpenFile(file, flag, perm)
103+
}
104+
105+
// StorePrivateKey stores the private key to the file.
106+
func StorePrivateKey(file string, privateKey PrivateKey, opts ...KeyOption) error {
107+
f, err := newFile(file)
108+
if err != nil {
109+
return err
110+
}
111+
112+
defer f.Close()
113+
return WritePrivateKey(f, privateKey, opts...)
114+
}
115+
116+
// StorePublicKey stores the public key to the file.
117+
func StorePublicKey(file string, publicKey PublicKey, opts ...KeyOption) error {
118+
f, err := newFile(file)
119+
if err != nil {
120+
return err
121+
}
122+
123+
defer f.Close()
124+
return WritePublicKey(f, publicKey, opts...)
125+
}
126+
127+
// LoadPrivateKey loads the private key from the file.
128+
func LoadPrivateKey(file string, opts ...KeyOption) (PrivateKey, error) {
129+
f, err := os.Open(file)
130+
if err != nil {
131+
return PrivateKey{}, err
132+
}
133+
134+
defer f.Close()
135+
return ReadPrivateKey(f, opts...)
136+
}
137+
138+
// LoadPublicKey loads the public key from the file.
139+
func LoadPublicKey(file string, opts ...KeyOption) (PublicKey, error) {
140+
f, err := os.Open(file)
141+
if err != nil {
142+
return PublicKey{}, err
143+
}
144+
145+
defer f.Close()
146+
return ReadPublicKey(f, opts...)
147+
}

0 commit comments

Comments
 (0)