seekia/internal/identity/identity.go

311 lines
8.9 KiB
Go

// identity provides functions for creating and reading identity keys and identity hashes
package identity
// Identity Keys are Edwards Keys used for identity purposes.
import "seekia/internal/encoding"
import "seekia/internal/cryptography/blake3"
import "seekia/internal/cryptography/edwardsKeys"
import "bytes"
import "slices"
import cryptoRand "crypto/rand"
import mathRand "math/rand/v2"
import "errors"
func VerifyIdentityKeyHex(identityKey string)bool{
isValid := edwardsKeys.VerifyPublicKeyHex(identityKey)
if (isValid == false){
return false
}
return true
}
func VerifyIdentityHash(identityHash [16]byte, identityTypeProvided bool, identityType string)(bool, error){
if (identityTypeProvided == true){
if (identityType != "Mate" && identityType != "Host" && identityType != "Moderator"){
return false, errors.New("VerifyIdentityHash called with invalid provided identityType: " + identityType)
}
}
userIdentityType, err := GetIdentityTypeFromIdentityHash(identityHash)
if (err != nil){
return false, nil
}
if (identityTypeProvided == false){
return true, nil
}
if (userIdentityType != identityType){
return false, nil
}
return true, nil
}
func GetIdentityTypeFromIdentityHash(identityHash [16]byte)(string, error){
identityTypeByte := identityHash[15]
if (identityTypeByte == 1){
return "Mate", nil
}
if (identityTypeByte == 2){
return "Host", nil
}
if (identityTypeByte == 3){
return "Moderator", nil
}
identityHashHex := encoding.EncodeBytesToHexString(identityHash[:])
return "", errors.New("GetIdentityTypeFromIdentityHash called with invalid identity hash: " + identityHashHex)
}
//Outputs:
// -[16]byte: Bytes representation of identity hash
// -string: Identity type of identity hash
// -error
func ReadIdentityHashString(identityHash string)([16]byte, string, error){
if (len(identityHash) != 27){
return [16]byte{}, "", errors.New("ReadIdentityHashString called with invalid identity hash: Invalid length: " + identityHash)
}
identityKeyHashString := identityHash[:24]
checksumString := identityHash[24:26]
identityTypeCharacter := string(identityHash[26])
identityKeyHashBytes, err := encoding.DecodeBase32StringToBytes(identityKeyHashString)
if (err != nil) {
return [16]byte{}, "", errors.New("ReadIdentityHashString called with invalid identity hash: Contains invalid characters: " + identityHash + ": " + err.Error())
}
if (len(identityKeyHashBytes) != 15) {
return [16]byte{}, "", errors.New("ReadIdentityHashString called with invalid identity hash: Invalid bytes length: " + identityHash)
}
checksumByte, err := encoding.DecodeHexStringToBytes(checksumString)
if (err != nil){
return [16]byte{}, "", errors.New("ReadIdentityHashString called with invalid identity hash: Invalid checksum: Not Hex: " + identityHash)
}
if (len(checksumByte) != 1){
return [16]byte{}, "", errors.New("ReadIdentityHashString called with invalid identity hash: Invalid checksum: Invalid Length: " + identityHash)
}
expectedChecksumByte, err := blake3.GetBlake3HashAsBytes(1, identityKeyHashBytes)
if (err != nil) { return [16]byte{}, "", err }
areEqual := bytes.Equal(checksumByte, expectedChecksumByte)
if (areEqual == false){
return [16]byte{}, "", errors.New("ReadIdentityHashString called with invalid identity hash: Invalid checksum: " + identityHash)
}
getIdentityTypeNameAndByte := func()(string, byte, error){
if (identityTypeCharacter == "m"){
return "Mate", 1, nil
}
if (identityTypeCharacter == "h"){
return "Host", 2, nil
}
if (identityTypeCharacter == "r"){
return "Moderator", 3, nil
}
return "", 0, errors.New("ReadIdentityHashString called with invalid identity hash: Invalid identityType character: " + identityTypeCharacter + " from " + identityHash)
}
identityType, identityTypeByte, err := getIdentityTypeNameAndByte()
if (err != nil) { return [16]byte{}, "", err }
identityHashBytes := append(identityKeyHashBytes, identityTypeByte)
identityHashBytesArray := [16]byte(identityHashBytes)
return identityHashBytesArray, identityType, nil
}
//Outputs:
// -string: Encoded identity hash
// -string: Identity type
// -error
func EncodeIdentityHashBytesToString(identityHashBytes [16]byte)(string, string, error){
identityKeyHashBytes := identityHashBytes[:15]
identityTypeByte := identityHashBytes[15]
checksumByte, err := blake3.GetBlake3HashAsBytes(1, identityKeyHashBytes)
if (err != nil) { return "", "", err }
identityKeyHashString := encoding.EncodeBytesToBase32String(identityKeyHashBytes)
checksumByteHex := encoding.EncodeBytesToHexString(checksumByte)
//Outputs:
// -string: Identity type
// -string: Identity type character
// -error
getIdentityTypeWithCharacter := func()(string, string, error){
if (identityTypeByte == 1){
return "Mate", "m", nil
}
if (identityTypeByte == 2){
return "Host", "h", nil
}
if (identityTypeByte == 3){
return "Moderator", "r", nil
}
return "", "", errors.New("EncodeIdentityHashBytesToString called with invalid identityHashBytes: Contains invalid identityTypeByte.")
}
identityType, identityTypeCharacter, err := getIdentityTypeWithCharacter()
if (err != nil) { return "", "", err }
identityHash := identityKeyHashString + checksumByteHex + identityTypeCharacter
return identityHash, identityType, nil
}
func ConvertIdentityKeyToIdentityHash(identityKey [32]byte, identityType string)([16]byte, error){
if (identityType != "Mate" && identityType != "Host" && identityType != "Moderator"){
return [16]byte{}, errors.New("ConvertIdentityKeyToIdentityHash called with invalid identityType: " + identityType)
}
identityKeyHashBytes, err := blake3.GetBlake3HashAsBytes(15, identityKey[:])
if (err != nil) { return [16]byte{}, err }
getIdentityTypeByte := func()byte{
if (identityType == "Mate"){
return 1
}
if (identityType == "Host"){
return 2
}
return 3
}
identityTypeByte := getIdentityTypeByte()
identityHashBytes := append(identityKeyHashBytes, identityTypeByte)
identityHashArray := [16]byte(identityHashBytes)
return identityHashArray, nil
}
func GetNewRandomIdentityHash(identityTypeProvided bool, identityType string)([16]byte, error){
identityKeyHashBytes := make([]byte, 15)
_, err := cryptoRand.Read(identityKeyHashBytes[:])
if (err != nil){ return [16]byte{}, err }
getIdentityTypeByte := func()(byte, error){
if (identityTypeProvided == false){
randomIndex := mathRand.IntN(3)
if (randomIndex == 0){
return 1, nil
}
if (randomIndex == 1){
return 2, nil
}
// randomIndex == 2
return 3, nil
}
if (identityType == "Mate"){
return 1, nil
}
if (identityType == "Host"){
return 2, nil
}
if (identityType == "Moderator"){
return 3, nil
}
return 0, errors.New("GetNewRandomIdentityHash called with invalid identityType: " + identityType)
}
identityTypeByte, err := getIdentityTypeByte()
if (err != nil) { return [16]byte{}, err }
identityHashBytes := append(identityKeyHashBytes, identityTypeByte)
identityHashArray := [16]byte(identityHashBytes)
return identityHashArray, nil
}
func GetPublicPrivateIdentityKeysFromSeedPhraseHash(inputSeedPhraseHash [32]byte)([32]byte, [64]byte, error){
// This is the salt used to derive identity hashes from seed phrase hashes
// It is the string "identitykeysseed" decoded from base32 to bytes.
identityKeysSalt := []byte{64, 200, 217, 162, 120, 81, 49, 41, 16, 131}
hashInput := slices.Concat(inputSeedPhraseHash[:], identityKeysSalt)
seedBytes, err := blake3.Get32ByteBlake3Hash(hashInput)
if (err != nil) { return [32]byte{}, [64]byte{}, err }
publicKeyArray, privateKeyArray := edwardsKeys.GetSeededEdwardsPublicAndPrivateKeys(seedBytes)
return publicKeyArray, privateKeyArray, nil
}
func GetNewRandomPublicPrivateIdentityKeys()([32]byte, [64]byte, error){
publicKeyArray, privateKeyArray, err := edwardsKeys.GetNewRandomPublicAndPrivateEdwardsKeys()
if (err != nil) { return [32]byte{}, [64]byte{}, err }
return publicKeyArray, privateKeyArray, nil
}
func GetIdentityHashFromSeedPhraseHash(seedPhraseHash [32]byte, identityType string)([16]byte, error){
publicIdentityKey, _, err := GetPublicPrivateIdentityKeysFromSeedPhraseHash(seedPhraseHash)
if (err != nil) { return [16]byte{}, err }
identityHash, err := ConvertIdentityKeyToIdentityHash(publicIdentityKey, identityType)
if (err != nil) { return [16]byte{}, err }
return identityHash, nil
}
// We use this function to generate custom identity hashes
// This is faster, because we only have to generate the first 10 bytes of the identity hash, and we don't have to calculate the checksum
func GetIdentityHash16CharacterPrefixFromSeedPhraseHash(seedPhraseHash [32]byte)(string, error){
publicIdentityKey, _, err := GetPublicPrivateIdentityKeysFromSeedPhraseHash(seedPhraseHash)
if (err != nil) { return "", err }
identityKeyHashBytes, err := blake3.GetBlake3HashAsBytes(10, publicIdentityKey[:])
if (err != nil) { return "", err }
identityHashPrefix := encoding.EncodeBytesToBase32String(identityKeyHashBytes)
return identityHashPrefix, nil
}