1// SPDX-License-Identifier: ISC
2// Copyright (c) 2014-2020 Bitmark Inc.
3// Use of this source code is governed by an ISC
4// license that can be found in the LICENSE file.
5
6package account
7
8import (
9	"bytes"
10
11	"golang.org/x/crypto/ed25519"
12	"golang.org/x/crypto/sha3"
13
14	"github.com/bitmark-inc/bitmarkd/fault"
15	"github.com/bitmark-inc/bitmarkd/util"
16)
17
18// PrivateKey - base type for PrivateKey
19type PrivateKey struct {
20	PrivateKeyInterface
21}
22
23// PrivateKeyInterface - interface type for private key methods
24type PrivateKeyInterface interface {
25	Account() *Account
26	KeyType() int
27	PrivateKeyBytes() []byte
28	Bytes() []byte
29	String() string
30	IsTesting() bool
31	MarshalText() ([]byte, error)
32}
33
34// ED25519PrivateKey - structure for ed25519 keys
35type ED25519PrivateKey struct {
36	Test       bool
37	PrivateKey []byte
38}
39
40// NothingPrivateKey - just for debugging
41type NothingPrivateKey struct {
42	Test       bool
43	PrivateKey []byte
44}
45
46// PrivateKeyFromBase58 - this converts a Base58 encoded string and returns an private key
47//
48// one of the specific private key types are returned using the base "PrivateKeyInterface"
49// interface type to allow individual methods to be called.
50func PrivateKeyFromBase58(privateKeyBase58Encoded string) (*PrivateKey, error) {
51	// Decode the privateKey
52	privateKeyDecoded := util.FromBase58(privateKeyBase58Encoded)
53	if 0 == len(privateKeyDecoded) {
54		return nil, fault.CannotDecodePrivateKey
55	}
56
57	// Parse the key variant
58	keyVariant, keyVariantLength := util.FromVarint64(privateKeyDecoded)
59
60	// Check key type
61	if 0 == keyVariantLength || keyVariant&publicKeyCode == publicKeyCode {
62		return nil, fault.NotPrivateKey
63	}
64
65	// compute algorithm
66	keyAlgorithm := keyVariant >> algorithmShift
67	if keyAlgorithm >= algorithmLimit {
68		return nil, fault.InvalidKeyType
69	}
70
71	// network selection
72	isTest := 0 != keyVariant&testKeyCode
73
74	// Compute key length
75	keyLength := len(privateKeyDecoded) - keyVariantLength - checksumLength
76	if keyLength <= 0 {
77		return nil, fault.InvalidKeyLength
78	}
79
80	// Checksum
81	checksumStart := len(privateKeyDecoded) - checksumLength
82	checksum := sha3.Sum256(privateKeyDecoded[:checksumStart])
83	if !bytes.Equal(checksum[:checksumLength], privateKeyDecoded[checksumStart:]) {
84		return nil, fault.ChecksumMismatch
85	}
86
87	// return a pointer to the specific private key type
88	switch keyAlgorithm {
89	case ED25519:
90		if keyLength != ed25519.PrivateKeySize {
91			return nil, fault.InvalidKeyLength
92		}
93		priv := privateKeyDecoded[keyVariantLength:checksumStart]
94		privateKey := &PrivateKey{
95			PrivateKeyInterface: &ED25519PrivateKey{
96				Test:       isTest,
97				PrivateKey: priv,
98			},
99		}
100		return privateKey, nil
101	case Nothing:
102		if 2 != keyLength {
103			return nil, fault.InvalidKeyLength
104		}
105		priv := privateKeyDecoded[keyVariantLength:checksumStart]
106		privateKey := &PrivateKey{
107			PrivateKeyInterface: &NothingPrivateKey{
108				Test:       isTest,
109				PrivateKey: priv,
110			},
111		}
112		return privateKey, nil
113	default:
114		return nil, fault.InvalidKeyType
115	}
116}
117
118// PrivateKeyFromBytes - this converts a byte encoded buffer and returns an private key
119//
120// one of the specific private key types are returned using the base "PrivateKeyInterface"
121// interface type to allow individual methods to be called.
122func PrivateKeyFromBytes(privateKeyBytes []byte) (*PrivateKey, error) {
123
124	// Parse the key variant
125	keyVariant, keyVariantLength := util.FromVarint64(privateKeyBytes)
126
127	// Check key type
128	if 0 == keyVariantLength || keyVariant&publicKeyCode == publicKeyCode {
129		return nil, fault.NotPrivateKey
130	}
131
132	// compute algorithm
133	keyAlgorithm := keyVariant >> algorithmShift
134	if keyAlgorithm >= algorithmLimit {
135		return nil, fault.InvalidKeyType
136	}
137
138	// network selection
139	isTest := 0 != keyVariant&testKeyCode
140
141	// Compute key length
142	keyLength := len(privateKeyBytes) - keyVariantLength
143	if keyLength <= 0 {
144		return nil, fault.InvalidKeyLength
145	}
146
147	// return a pointer to the specific private key type
148	switch keyAlgorithm {
149	case ED25519:
150		if keyLength != ed25519.PrivateKeySize {
151			return nil, fault.InvalidKeyLength
152		}
153		priv := privateKeyBytes[keyVariantLength:]
154		privateKey := &PrivateKey{
155			PrivateKeyInterface: &ED25519PrivateKey{
156				Test:       isTest,
157				PrivateKey: priv,
158			},
159		}
160		return privateKey, nil
161	case Nothing:
162		if 2 != keyLength {
163			return nil, fault.InvalidKeyLength
164		}
165		priv := privateKeyBytes[keyVariantLength:]
166		privateKey := &PrivateKey{
167			PrivateKeyInterface: &NothingPrivateKey{
168				Test:       isTest,
169				PrivateKey: priv,
170			},
171		}
172		return privateKey, nil
173	default:
174		return nil, fault.InvalidKeyType
175	}
176}
177
178// UnmarshalText - convert string to private key structure
179func (privateKey *PrivateKey) UnmarshalText(s []byte) error {
180	a, err := PrivateKeyFromBase58(string(s))
181	if nil != err {
182		return err
183	}
184	privateKey.PrivateKeyInterface = a.PrivateKeyInterface
185	return nil
186}
187
188// ED25519
189// -------
190
191// IsTesting - return whether the private key is in test mode or not
192func (privateKey *ED25519PrivateKey) IsTesting() bool {
193	return privateKey.Test
194}
195
196// KeyType - key type code (see enumeration in account.go)
197func (privateKey *ED25519PrivateKey) KeyType() int {
198	return ED25519
199}
200
201// Account - return the corresponding account
202func (privateKey *ED25519PrivateKey) Account() *Account {
203	return &Account{
204		AccountInterface: &ED25519Account{
205			Test:      privateKey.Test,
206			PublicKey: privateKey.PrivateKey[ed25519.PrivateKeySize-ed25519.PublicKeySize:],
207		},
208	}
209}
210
211// PrivateKeyBytes - fetch the private key as byte slice
212func (privateKey *ED25519PrivateKey) PrivateKeyBytes() []byte {
213	return privateKey.PrivateKey[:]
214}
215
216// Bytes - byte slice for encoded key
217func (privateKey *ED25519PrivateKey) Bytes() []byte {
218	keyVariant := byte(ED25519 << algorithmShift)
219	if privateKey.Test {
220		keyVariant |= testKeyCode
221	}
222	return append([]byte{keyVariant}, privateKey.PrivateKey[:]...)
223}
224
225// String - base58 encoding of encoded key
226func (privateKey *ED25519PrivateKey) String() string {
227	buffer := privateKey.Bytes()
228	checksum := sha3.Sum256(buffer)
229	buffer = append(buffer, checksum[:checksumLength]...)
230	return util.ToBase58(buffer)
231}
232
233// MarshalText - convert an privateKey to its Base58 JSON form
234func (privateKey ED25519PrivateKey) MarshalText() ([]byte, error) {
235	return []byte(privateKey.String()), nil
236}
237
238// Nothing
239// -------
240
241// IsTesting - return whether the private key is in test mode or not
242func (privateKey *NothingPrivateKey) IsTesting() bool {
243	return privateKey.Test
244}
245
246// KeyType - key type code (see enumeration in account.go)
247func (privateKey *NothingPrivateKey) KeyType() int {
248	return Nothing
249}
250
251// Account - return the corresponding account
252func (privateKey *NothingPrivateKey) Account() *Account {
253	return nil
254}
255
256// PrivateKeyBytes - fetch the private key as byte slice
257func (privateKey *NothingPrivateKey) PrivateKeyBytes() []byte {
258	return privateKey.PrivateKey[:]
259}
260
261// Bytes - byte slice for encoded key
262func (privateKey *NothingPrivateKey) Bytes() []byte {
263	keyVariant := byte(Nothing << algorithmShift)
264	if privateKey.Test {
265		keyVariant |= testKeyCode
266	}
267	return append([]byte{keyVariant}, privateKey.PrivateKey[:]...)
268}
269
270// String - base58 encoding of encoded key
271func (privateKey *NothingPrivateKey) String() string {
272	buffer := privateKey.Bytes()
273	checksum := sha3.Sum256(buffer)
274	buffer = append(buffer, checksum[:checksumLength]...)
275	return util.ToBase58(buffer)
276}
277
278// MarshalText - convert an privateKey to its Base58 JSON form
279func (privateKey NothingPrivateKey) MarshalText() ([]byte, error) {
280	return []byte(privateKey.String()), nil
281}
282