diff --git a/proxy/shadowsocks/config.go b/proxy/shadowsocks/config.go
index 9bbc7736..a2c56be1 100644
--- a/proxy/shadowsocks/config.go
+++ b/proxy/shadowsocks/config.go
@@ -7,8 +7,6 @@ import (
 	"crypto/md5"
 	"crypto/sha1"
 	"io"
-	"reflect"
-	"strconv"
 
 	"golang.org/x/crypto/chacha20poly1305"
 	"golang.org/x/crypto/hkdf"
@@ -28,6 +26,10 @@ type MemoryAccount struct {
 	replayFilter antireplay.GeneralizedReplayFilter
 }
 
+var (
+	ErrIVNotUnique = newError("IV is not unique")
+)
+
 // Equals implements protocol.Account.Equals().
 func (a *MemoryAccount) Equals(another protocol.Account) bool {
 	if account, ok := another.(*MemoryAccount); ok {
@@ -43,24 +45,7 @@ func (a *MemoryAccount) CheckIV(iv []byte) error {
 	if a.replayFilter.Check(iv) {
 		return nil
 	}
-	return newError("IV is not unique")
-}
-
-func (a *MemoryAccount) GetCipherName() string {
-	switch a.Cipher.(type) {
-	case *AEADCipher:
-		switch reflect.ValueOf(a.Cipher.(*AEADCipher).AEADAuthCreator).Pointer() {
-		case reflect.ValueOf(createAesGcm).Pointer():
-			keyBytes := a.Cipher.(*AEADCipher).KeyBytes
-			return "AES_" + strconv.FormatInt(int64(keyBytes*8), 10) + "_GCM"
-		case reflect.ValueOf(createChaCha20Poly1305).Pointer():
-			return "CHACHA20_POLY1305"
-		}
-	case *NoneCipher:
-		return "NONE"
-	}
-
-	return ""
+	return ErrIVNotUnique
 }
 
 func createAesGcm(key []byte) cipher.AEAD {
diff --git a/proxy/shadowsocks/protocol.go b/proxy/shadowsocks/protocol.go
index 0fc0c896..68bc3919 100644
--- a/proxy/shadowsocks/protocol.go
+++ b/proxy/shadowsocks/protocol.go
@@ -1,11 +1,7 @@
 package shadowsocks
 
 import (
-	"crypto/cipher"
-	"crypto/hmac"
 	"crypto/rand"
-	"crypto/sha256"
-	"hash/crc32"
 	"io"
 
 	"github.com/xtls/xray-core/common"
@@ -54,10 +50,7 @@ func (r *FullReader) Read(p []byte) (n int, err error) {
 
 // ReadTCPSession reads a Shadowsocks TCP session from the given reader, returns its header and remaining parts.
 func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHeader, buf.Reader, error) {
-	hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
-
-	behaviorSeed := crc32.ChecksumIEEE(hashkdf.Sum(nil))
-
+	behaviorSeed := validator.GetBehaviorSeed()
 	behaviorRand := dice.NewDeterministicDice(int64(behaviorSeed))
 	BaseDrainSize := behaviorRand.Roll(3266)
 	RandDrainMax := behaviorRand.Roll(64) + 1
@@ -65,72 +58,52 @@ func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHe
 	DrainSize := BaseDrainSize + 16 + 38 + RandDrainRolled
 	readSizeRemain := DrainSize
 
-	var r2 buf.Reader
+	var r buf.Reader
 	buffer := buf.New()
 	defer buffer.Release()
 
-	var user *protocol.MemoryUser
-	var ivLen int32
-	var iv []byte
-	var err error
-
-	count := validator.Count()
-	if count == 0 {
+	if _, err := buffer.ReadFullFrom(reader, 50); err != nil {
 		readSizeRemain -= int(buffer.Len())
 		DrainConnN(reader, readSizeRemain)
-		return nil, nil, newError("invalid user")
-	} else if count > 1 {
-		var aead cipher.AEAD
+		return nil, nil, newError("failed to read 50 bytes").Base(err)
+	}
 
-		if _, err := buffer.ReadFullFrom(reader, 50); err != nil {
-			readSizeRemain -= int(buffer.Len())
-			DrainConnN(reader, readSizeRemain)
-			return nil, nil, newError("failed to read 50 bytes").Base(err)
-		}
+	bs := buffer.Bytes()
+	user, aead, _, ivLen, err := validator.Get(bs, protocol.RequestCommandTCP)
 
-		bs := buffer.Bytes()
-		user, aead, _, ivLen, err = validator.Get(bs, protocol.RequestCommandTCP)
+	switch err {
+	case ErrNotFound:
+		readSizeRemain -= int(buffer.Len())
+		DrainConnN(reader, readSizeRemain)
+		return nil, nil, newError("failed to match an user").Base(err)
+	case ErrIVNotUnique:
+		readSizeRemain -= int(buffer.Len())
+		DrainConnN(reader, readSizeRemain)
+		return nil, nil, newError("failed iv check").Base(err)
+	default:
+		reader = &FullReader{reader, bs[ivLen:]}
+		readSizeRemain -= int(ivLen)
 
-		if user != nil {
-			if ivLen > 0 {
-				iv = append([]byte(nil), bs[:ivLen]...)
-			}
-			reader = &FullReader{reader, bs[ivLen:]}
+		if aead != nil {
 			auth := &crypto.AEADAuthenticator{
 				AEAD:           aead,
 				NonceGenerator: crypto.GenerateInitialAEADNonce(),
 			}
-			r2 = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
+			r = crypto.NewAuthenticationReader(auth, &crypto.AEADChunkSizeParser{
 				Auth: auth,
 			}, reader, protocol.TransferTypeStream, nil)
 		} else {
-			readSizeRemain -= int(buffer.Len())
-			DrainConnN(reader, readSizeRemain)
-			return nil, nil, newError("failed to match an user").Base(err)
-		}
-	} else {
-		user, ivLen = validator.GetOnlyUser()
-		account := user.Account.(*MemoryAccount)
-		hashkdf.Write(account.Key)
-		if ivLen > 0 {
-			if _, err := buffer.ReadFullFrom(reader, ivLen); err != nil {
-				readSizeRemain -= int(buffer.Len())
+			account := user.Account.(*MemoryAccount)
+			iv := append([]byte(nil), buffer.BytesTo(ivLen)...)
+			r, err = account.Cipher.NewDecryptionReader(account.Key, iv, reader)
+			if err != nil {
 				DrainConnN(reader, readSizeRemain)
-				return nil, nil, newError("failed to read IV").Base(err)
+				return nil, nil, newError("failed to initialize decoding stream").Base(err).AtError()
 			}
-			iv = append([]byte(nil), buffer.BytesTo(ivLen)...)
 		}
-
-		r, err := account.Cipher.NewDecryptionReader(account.Key, iv, reader)
-		if err != nil {
-			readSizeRemain -= int(buffer.Len())
-			DrainConnN(reader, readSizeRemain)
-			return nil, nil, newError("failed to initialize decoding stream").Base(err).AtError()
-		}
-		r2 = r
 	}
 
-	br := &buf.BufferedReader{Reader: r2}
+	br := &buf.BufferedReader{Reader: r}
 
 	request := &protocol.RequestHeader{
 		Version: Version,
@@ -138,7 +111,6 @@ func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHe
 		Command: protocol.RequestCommandTCP,
 	}
 
-	readSizeRemain -= int(buffer.Len())
 	buffer.Clear()
 
 	addr, port, err := addrParser.ReadAddressPort(buffer, br)
@@ -157,13 +129,6 @@ func ReadTCPSession(validator *Validator, reader io.Reader) (*protocol.RequestHe
 		return nil, nil, newError("invalid remote address.")
 	}
 
-	account := user.Account.(*MemoryAccount)
-	if ivError := account.CheckIV(iv); ivError != nil {
-		readSizeRemain -= int(buffer.Len())
-		DrainConnN(reader, readSizeRemain)
-		return nil, nil, newError("failed iv check").Base(ivError)
-	}
-
 	return request, br, nil
 }
 
@@ -273,34 +238,25 @@ func DecodeUDPPacket(validator *Validator, payload *buf.Buffer) (*protocol.Reque
 		return nil, nil, newError("len(bs) <= 32")
 	}
 
-	var user *protocol.MemoryUser
-	var err error
-
-	count := validator.Count()
-	if count == 0 {
-		return nil, nil, newError("invalid user")
-	} else if count > 1 {
-		var d []byte
-		user, _, d, _, err = validator.Get(bs, protocol.RequestCommandUDP)
-
-		if user != nil {
+	user, _, d, _, err := validator.Get(bs, protocol.RequestCommandUDP)
+	switch err {
+	case ErrIVNotUnique:
+		return nil, nil, newError("failed iv check").Base(err)
+	case ErrNotFound:
+		return nil, nil, newError("failed to match an user").Base(err)
+	default:
+		account := user.Account.(*MemoryAccount)
+		if account.Cipher.IsAEAD() {
 			payload.Clear()
 			payload.Write(d)
 		} else {
-			return nil, nil, newError("failed to decrypt UDP payload").Base(err)
-		}
-	} else {
-		user, _ = validator.GetOnlyUser()
-		account := user.Account.(*MemoryAccount)
-
-		var iv []byte
-		if !account.Cipher.IsAEAD() && account.Cipher.IVSize() > 0 {
-			// Keep track of IV as it gets removed from payload in DecodePacket.
-			iv = make([]byte, account.Cipher.IVSize())
-			copy(iv, payload.BytesTo(account.Cipher.IVSize()))
-		}
-		if err = account.Cipher.DecodePacket(account.Key, payload); err != nil {
-			return nil, nil, newError("failed to decrypt UDP payload").Base(err)
+			if account.Cipher.IVSize() > 0 {
+				iv := make([]byte, account.Cipher.IVSize())
+				copy(iv, payload.BytesTo(account.Cipher.IVSize()))
+			}
+			if err = account.Cipher.DecodePacket(account.Key, payload); err != nil {
+				return nil, nil, newError("failed to decrypt UDP payload").Base(err)
+			}
 		}
 	}
 
diff --git a/proxy/shadowsocks/server.go b/proxy/shadowsocks/server.go
index 430a5688..c15bd175 100644
--- a/proxy/shadowsocks/server.go
+++ b/proxy/shadowsocks/server.go
@@ -115,10 +115,6 @@ func (s *Server) handleUDPPayload(ctx context.Context, conn stat.Connection, dis
 		panic("no inbound metadata")
 	}
 
-	if s.validator.Count() == 1 {
-		inbound.User, _ = s.validator.GetOnlyUser()
-	}
-
 	var dest *net.Destination
 
 	reader := buf.NewPacketReader(conn)
diff --git a/proxy/shadowsocks/validator.go b/proxy/shadowsocks/validator.go
index 7d796bc2..b36e9bc8 100644
--- a/proxy/shadowsocks/validator.go
+++ b/proxy/shadowsocks/validator.go
@@ -2,112 +2,127 @@ package shadowsocks
 
 import (
 	"crypto/cipher"
+	"crypto/hmac"
+	"crypto/sha256"
+	"hash/crc64"
 	"strings"
 	"sync"
 
+	"github.com/xtls/xray-core/common/dice"
 	"github.com/xtls/xray-core/common/protocol"
 )
 
 // Validator stores valid Shadowsocks users.
 type Validator struct {
-	// Considering email's usage here, map + sync.Mutex/RWMutex may have better performance.
-	email sync.Map
-	users sync.Map
+	sync.RWMutex
+	users []*protocol.MemoryUser
+
+	behaviorSeed  uint64
+	behaviorFused bool
 }
 
-// Add a Shadowsocks user, Email must be empty or unique.
+var (
+	ErrNotFound = newError("Not Found")
+)
+
+// Add a Shadowsocks user.
 func (v *Validator) Add(u *protocol.MemoryUser) error {
+	v.Lock()
+	defer v.Unlock()
+
 	account := u.Account.(*MemoryAccount)
+	if !account.Cipher.IsAEAD() && len(v.users) > 0 {
+		return newError("The cipher is not support Single-port Multi-user")
+	}
+	v.users = append(v.users, u)
 
-	if !account.Cipher.IsAEAD() && v.Count() > 0 {
-		return newError("The cipher do not support Single-port Multi-user")
+	if !v.behaviorFused {
+		hashkdf := hmac.New(sha256.New, []byte("SSBSKDF"))
+		hashkdf.Write(account.Key)
+		v.behaviorSeed = crc64.Update(v.behaviorSeed, crc64.MakeTable(crc64.ECMA), hashkdf.Sum(nil))
 	}
 
-	if u.Email != "" {
-		_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)
-		if loaded {
-			return newError("User ", u.Email, " already exists.")
-		}
-	}
-
-	v.users.Store(string(account.Key)+"&"+account.GetCipherName(), u)
 	return nil
 }
 
 // Del a Shadowsocks user with a non-empty Email.
-func (v *Validator) Del(e string) error {
-	if e == "" {
+func (v *Validator) Del(email string) error {
+	if email == "" {
 		return newError("Email must not be empty.")
 	}
-	le := strings.ToLower(e)
-	u, _ := v.email.Load(le)
-	if u == nil {
-		return newError("User ", e, " not found.")
+
+	v.Lock()
+	defer v.Unlock()
+
+	email = strings.ToLower(email)
+	idx := -1
+	for i, u := range v.users {
+		if strings.EqualFold(u.Email, email) {
+			idx = i
+			break
+		}
 	}
-	account := u.(*protocol.MemoryUser).Account.(*MemoryAccount)
-	v.email.Delete(le)
-	v.users.Delete(string(account.Key) + "&" + account.GetCipherName())
+
+	if idx == -1 {
+		return newError("User ", email, " not found.")
+	}
+	ulen := len(v.users)
+
+	v.users[idx] = v.users[ulen-1]
+	v.users[ulen-1] = nil
+	v.users = v.users[:ulen-1]
+
 	return nil
 }
 
-// Count the number of Shadowsocks users
-func (v *Validator) Count() int {
-	length := 0
-	v.users.Range(func(_, _ interface{}) bool {
-		length++
-
-		return true
-	})
-	return length
-}
-
-// Get a Shadowsocks user and the user's cipher.
+// Get a Shadowsocks user.
 func (v *Validator) Get(bs []byte, command protocol.RequestCommand) (u *protocol.MemoryUser, aead cipher.AEAD, ret []byte, ivLen int32, err error) {
-	var dataSize int
+	v.RLock()
+	defer v.RUnlock()
 
-	switch command {
-	case protocol.RequestCommandTCP:
-		dataSize = 16
-	case protocol.RequestCommandUDP:
-		dataSize = 8192
+	for _, user := range v.users {
+		if account := user.Account.(*MemoryAccount); account.Cipher.IsAEAD() {
+			aeadCipher := account.Cipher.(*AEADCipher)
+			ivLen = aeadCipher.IVSize()
+			iv := bs[:ivLen]
+			subkey := make([]byte, 32)
+			subkey = subkey[:aeadCipher.KeyBytes]
+			hkdfSHA1(account.Key, iv, subkey)
+			aead = aeadCipher.AEADAuthCreator(subkey)
+
+			var matchErr error
+			switch command {
+			case protocol.RequestCommandTCP:
+				data := make([]byte, 16)
+				ret, matchErr = aead.Open(data[:0], data[4:16], bs[ivLen:ivLen+18], nil)
+			case protocol.RequestCommandUDP:
+				data := make([]byte, 8192)
+				ret, matchErr = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
+			}
+
+			if matchErr == nil {
+				u = user
+				err = account.CheckIV(iv)
+				return
+			}
+		} else {
+			u = user
+			ivLen = user.Account.(*MemoryAccount).Cipher.IVSize()
+			// err = user.Account.(*MemoryAccount).CheckIV(bs[:ivLen]) // The IV size of None Cipher is 0.
+			return
+		}
 	}
 
-	var aeadCipher *AEADCipher
-	subkey := make([]byte, 32)
-	data := make([]byte, dataSize)
-
-	v.users.Range(func(key, user interface{}) bool {
-		account := user.(*protocol.MemoryUser).Account.(*MemoryAccount)
-		aeadCipher = account.Cipher.(*AEADCipher)
-		ivLen = aeadCipher.IVSize()
-		subkey = subkey[:aeadCipher.KeyBytes]
-		hkdfSHA1(account.Key, bs[:ivLen], subkey)
-		aead = aeadCipher.AEADAuthCreator(subkey)
-
-		switch command {
-		case protocol.RequestCommandTCP:
-			ret, err = aead.Open(data[:0], data[4:16], bs[ivLen:ivLen+18], nil)
-		case protocol.RequestCommandUDP:
-			ret, err = aead.Open(data[:0], data[8180:8192], bs[ivLen:], nil)
-		}
-
-		if err == nil {
-			u = user.(*protocol.MemoryUser)
-			return false
-		}
-		return true
-	})
-
-	return
+	return nil, nil, nil, 0, ErrNotFound
 }
 
-// Get the only user without authentication
-func (v *Validator) GetOnlyUser() (u *protocol.MemoryUser, ivLen int32) {
-	v.users.Range(func(_, user interface{}) bool {
-		u = user.(*protocol.MemoryUser)
-		return false
-	})
-	ivLen = u.Account.(*MemoryAccount).Cipher.IVSize()
+func (v *Validator) GetBehaviorSeed() uint64 {
+	v.Lock()
+	defer v.Unlock()
 
-	return
+	v.behaviorFused = true
+	if v.behaviorSeed == 0 {
+		v.behaviorSeed = dice.RollUint64()
+	}
+	return v.behaviorSeed
 }