124 lines
4.6 KiB
Go
124 lines
4.6 KiB
Go
|
|
||
|
// accountKeys provides functions to derive account identifiers and cryptocurrency addresses from credit account keys.
|
||
|
// These keys are used to interface with the credit accounts servers to manage a user's account credits.
|
||
|
|
||
|
package accountKeys
|
||
|
|
||
|
// A user's account private key is required to check their account balance
|
||
|
// Each public key corresponds to an account identifier and crypto address(es)
|
||
|
// We only use each key for a single purpose.
|
||
|
// The current purposes are either to use its identifier or Ethereum address.
|
||
|
// In the future, we will add more cryptocurrencies.
|
||
|
|
||
|
//TODO: Add checksum byte to account identifiers
|
||
|
|
||
|
import "seekia/internal/cryptography/blake3"
|
||
|
import "seekia/internal/cryptocurrency/ethereumAddress"
|
||
|
import "seekia/internal/cryptocurrency/cardanoAddress"
|
||
|
import "seekia/internal/cryptography/edwardsKeys"
|
||
|
import "seekia/internal/helpers"
|
||
|
|
||
|
import "slices"
|
||
|
import "encoding/binary"
|
||
|
import "errors"
|
||
|
|
||
|
|
||
|
func GetAccountIdentifierFromAccountPublicKey(accountPublicKey [32]byte)(string, error){
|
||
|
|
||
|
// This sequence of bytes is the string "accountidentifierkeyhash" decoded from base32 to bytes
|
||
|
hashInputSuffix := []byte{0, 132, 234, 54, 104, 25, 27, 52, 21, 4, 138, 137, 131, 130, 71}
|
||
|
|
||
|
hashInput := slices.Concat(accountPublicKey[:], hashInputSuffix)
|
||
|
|
||
|
accountIdentifier, err := blake3.GetBlake3HashAsHexString(14, hashInput)
|
||
|
if (err != nil) { return "", err }
|
||
|
|
||
|
return accountIdentifier, nil
|
||
|
}
|
||
|
|
||
|
func GetCryptocurrencyAddressFromAccountPublicKey(cryptocurrency string, accountPublicKey [32]byte)(string, error){
|
||
|
|
||
|
if (cryptocurrency != "Ethereum" && cryptocurrency != "Cardano"){
|
||
|
return "", errors.New("GetCryptocurrencyAddressFromAccountPublicKey called with invalid cryptocurrency: " + cryptocurrency)
|
||
|
}
|
||
|
if (cryptocurrency == "Ethereum"){
|
||
|
|
||
|
accountEthereumAddress, err := ethereumAddress.GetCreditAccountEthereumAddressFromAccountPublicKey(accountPublicKey)
|
||
|
if (err != nil) { return "", err }
|
||
|
|
||
|
return accountEthereumAddress, nil
|
||
|
}
|
||
|
|
||
|
accountCardanoAddress, err := cardanoAddress.GetCreditAccountCardanoAddressFromAccountPublicKey(accountPublicKey)
|
||
|
if (err != nil) { return "", err }
|
||
|
|
||
|
return accountCardanoAddress, nil
|
||
|
}
|
||
|
|
||
|
|
||
|
// KeysType refers to the type of key
|
||
|
// Different KeyTypes need to be derived, because each key should only be used for its intended keysType purpose.
|
||
|
// "Identifier" keys are used for receiving to an account via an account identifier
|
||
|
// "Ethereum" keys are used for receiving to an account via an Ethereum address
|
||
|
// "Cardano" keys are used for receiving to an account via an Cardano address
|
||
|
// Each cryptocurrency which we add will have its own keysType
|
||
|
|
||
|
// We must be able to generate many different keys for each purpose, which we accomplish with the keysIndex parameter
|
||
|
// This allows us to create as many addresses as we need, which we do because we need to be able to avoid address/identifier reuse.
|
||
|
|
||
|
// Each networkType has its own keys, because each network type has its own account credit database and servers.
|
||
|
|
||
|
//Outputs:
|
||
|
// -[32]byte: Public key
|
||
|
// -[64]byte: Private key
|
||
|
// -error
|
||
|
func GetCreditAccountPublicPrivateKeys(seedPhraseHash [32]byte, networkType byte, keysType string, keysIndex int)([32]byte, [64]byte, error){
|
||
|
|
||
|
isValid := helpers.VerifyNetworkType(networkType)
|
||
|
if (isValid == false){
|
||
|
networkTypeString := helpers.ConvertByteToString(networkType)
|
||
|
return [32]byte{}, [64]byte{}, errors.New("GetCreditAccountPublicPrivateKeys called with invalid networkType: " + networkTypeString)
|
||
|
}
|
||
|
|
||
|
if (keysType != "Identifier" && keysType != "Ethereum" && keysType != "Cardano"){
|
||
|
return [32]byte{}, [64]byte{}, errors.New("GetCreditAccountPublicPrivateKeys called with invalid keysType: " + keysType)
|
||
|
}
|
||
|
|
||
|
if (keysIndex < 1 || keysIndex > 4294967295){
|
||
|
return [32]byte{}, [64]byte{}, errors.New("GetCreditAccountPublicPrivateKeys called with invalid keysIndex.")
|
||
|
}
|
||
|
|
||
|
// This sequence of bytes is the string "creditaccountkeyhashsalt" decoded from base32 to bytes
|
||
|
saltBytes := []byte{20, 72, 52, 76, 2, 19, 168, 217, 168, 152, 56, 36, 121, 1, 115}
|
||
|
|
||
|
getKeysTypeByte := func()byte{
|
||
|
if (keysType == "Identifier"){
|
||
|
return 1
|
||
|
}
|
||
|
if (keysType == "Ethereum"){
|
||
|
return 2
|
||
|
}
|
||
|
// keysType == "Cardano"
|
||
|
return 3
|
||
|
}
|
||
|
|
||
|
keysTypeByte := getKeysTypeByte()
|
||
|
|
||
|
keysIndexUint32 := uint32(keysIndex)
|
||
|
|
||
|
hashInput := slices.Concat(seedPhraseHash[:], saltBytes)
|
||
|
|
||
|
hashInput = append(hashInput, networkType, keysTypeByte)
|
||
|
|
||
|
hashInput = binary.LittleEndian.AppendUint32(hashInput, keysIndexUint32)
|
||
|
|
||
|
seedBytes, err := blake3.Get32ByteBlake3Hash(hashInput)
|
||
|
if (err != nil) { return [32]byte{}, [64]byte{}, err }
|
||
|
|
||
|
publicKeyArray, privateKeyArray := edwardsKeys.GetSeededEdwardsPublicAndPrivateKeys(seedBytes)
|
||
|
|
||
|
return publicKeyArray, privateKeyArray, nil
|
||
|
}
|
||
|
|
||
|
|