311 lines
8.9 KiB
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
|
|
}
|
|
|