I suggest you actually attempt to model the actions to which you are alluding above in your application layer. Namely
Login, because I think it can help bring clarity to your situation. That is, by working backwards from the public surface you would like your domain to expose to your application layer, it can help inform us where responsibilities should (and should not) be given.
For example, you may have a
RegisterAccount command handler that boils down to the following:
accountRepository.Add( new Account(cmd.UserName, cmd.Password) )
accountRepository.Save() // throws DuplicateUserName
Login command handler that boils down to:
account = accountRepository.FindByUserName( cmd.UserName ) // throws NotFound
account.Login( cmd.Password ) // throws InvalidPassword
The above represents just about the most declarative way to model each process. This is a good thing. It's important that your application can present a clear and concise "view" of each business process in terms of behavior. Of course, this is precisely what the application layer is for: coordinating your domain with as little logic as possible (i.e. rules) in a way to provide this view. So with the above in mind, let us move on to your specific questions.
Set validation is tricky. If there is a rule mandating that a
UserName must be unique within a set of
Account, it should be enforced by the set of
Account. Is there a piece of your application which represents a collection of
Account? Often, set validation belongs on your
Repository. This is especially convenient because a
Repository "knows" the single critical piece of infrastructure necessary to enforce this kind of invariant (the data store). In your case (and many others like it), I would recommend enforcing this as a constraint in your data store and let your
AccountRepository throw an exception on
Save if an
Account with a duplicate
UserName is added. Simple. Declarative.
I cannot recommend creating a separate service to check that adding an
Account will succeed before it is added, because this represents a separation of data and behavior. The idea of validating that some process will succeed before it is attempted is a fundamentally procedural approach, not OOP, and certainly not DDD. This practice can also lead to all sorts of duplication and gotchas down the road when applied liberally to a system. Let the rules exits with the data, not around the data.
Moving on, we can see that your
Account entity certainly requires a dependency on a hashing cohesive mechanism, as it must be able to internally hash and check hashes to allow for both the account registration and login processes. The question is whether or not this should exist as a domain service or something else. Truthfully, it doesn't really matter. The inner workings of an Entity are not important (hence the abstraction). What is important is that we focus on the behavior we would like to achieve, and let the data that supports this behavior be an implementation detail. This is the perspective that DDD seeks to provide.
That said, I understand hashing to be a cross-cutting concern. Unless your algorithm is specific to your domain, it would seem to me that hashing belongs as part of infrastructure. Don't let your domain become concerned with things that aren't truly business rules (hashing is more of a technical concern in most industries).
With regard to factories: A factory should be used when the creation of an Entity is so verbose that your model starts to lose focus. Importantly, NOT when you want to encapsulate rules. Whether or not a factory should be employed is up to you to decide.
EDIT: I'd like to touch on another idea which I kind of danced around in my answer above, but didn't explicitly state: the idea of delaying implementation until absolutely necessary. This can be an incredibly useful tactic when designing and implementing a system. In the book Clean Architecture by Robert Martin, he brings this idea up specifically in relation high-level decisions like data storage, but it is useful even in microcosms (such as modeling a workflow).
At it's core, it means to push rules (implementation) down the road as far as possible. In terms of the above system, it means enforcing a unique constraint at the lowest level it can be enforced or engaging in hashing where absolutely necessary. Simply being cognizant of this practice will lead you to naturally implement rules as close as possible to the behavior of which they govern. Of course, this is the core principal of OOP.