seekia/internal/network/accountKeys/accountKeys.go

123 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
}