The substituability test is breaking the encapsulation

Brian Goetz brian.goetz at
Mon Feb 25 21:38:58 UTC 2019

In the absolute worst case, we could give up on encapsulation of fields.  I wouldn’t want to do that, but right now, I’d rather do that than accept a non-reflexive ==.  But I’m sure there’s a better alternative — let’s find it.

> On Feb 25, 2019, at 4:23 PM, forax at wrote:
> What i'm saying is that using a component wise test as == as a security implication, something i was not aware before thinking about it,
> and something i'm sure our users don't want to be aware of.
> Having two different meanings for "encapsulation", one for references and one for values is possible a solution, but it's moving the problem to the users, by saying, you will have to be careful enough to know that class encapsulation and value class encapsulation works differently.
> The first part of the moto is "code like a class" and not "code like a class but beware because the encapsulation model is different".
> It also makes the implementation of an interface by to a value class more hazardous, by example, can a panama Address can be implemented by a value class ? The answer is not easy because the encapsulation model is leaky.
>> if the constructor is not accessible to the attacker
> so a serializable value class is a security liability ?
> And a component wise test is also prone to timing attacks, you can guess the value of the fields far faster than checking all combinations.
> Rémi
> ----- Mail original -----
>> De: "Brian Goetz" <brian.goetz at>
>> À: "Remi Forax" <forax at>
>> Cc: "valhalla-spec-experts" <valhalla-spec-experts at>
>> Envoyé: Lundi 25 Février 2019 15:32:18
>> Objet: Re: The substituability test is breaking the encapsulation
>> Good — let’s drill into this.
>> At a high level, you’re saying there’s a tension between encapsulation and a
>> state-based comparison primitive; that the state-based comparison is a side
>> channel through which encapsulated state may be leaked.  That’s true.  (Just as
>> there is a tension between “values are objects” and “objects have identity”.)
>> To pick up on John’s note from v-dev over the weekend, value-objects are more
>> easily _forgeable_ than identity-objects.  There are infinitely many possible
>> java.lang.Integers, because of the unique-per-instance identity; there are only
>> finitely many instances of
>>   value class IntWrapper { public int i; }
>> and, given access to the constructor, you can construct them all, and readily
>> stamp out whatever instance you like, and it is just as good as all other
>> instances with that state.
>> We want value to have as many of the things that classes have, within the
>> constraints that values eschew identity.  So they can’t have mutability or
>> layout polymorphism.  But they can have methods, fields, constructors, type
>> variables, etc.  And we’d like for “encapsulation” to be in this set.
>> As a trivial observation, the concern you raise here goes away if the
>> constructor is not accessible to the attacker.  That suggests there are at
>> least two paths to plugging this leak; tighten state-based comparison, or
>> require classes that want to encapsulate their state to also encapsulate the
>> constructors that can produce arbitrary state.
>> So, rather than blaming ==, or blaming encapsulation, let’s set out some
>> expectations for how we want to use encapsulation in values.
>> (I think this problem may be related to another problem — that of when a client
>> should be allowed to use `withfield`.  For an unencapsulated class like Point,
>> where the ctor expresses no constraints, it seems desirable to let clients say
>> “p __with x = 2” (with whatever syntax), without making the author expose yet
>> more accessor methods, but clearly for encapsulated values, that’s not OK.)
>>> On Feb 25, 2019, at 5:11 AM, Remi Forax <forax at> wrote:
>>> Hi all,
>>> there is another issue with making the component wide test available for any
>>> value types, it's leaking the implementation.
>>> Let say we have this class:
>>> public value class GuessANumber {
>>> private final int value;
>>> public GuessANumber(int value) {
>>>   this.value = value;
>>> }
>>> public enum Response { LOWER, GREATER, FOUND };
>>> public Response guess(int guess) {
>>>   if (value < guess) {
>>>     return Response.LOWER;
>>>   }
>>>   if (value > guess) {
>>>     return Response.GREATER;
>>>   }
>>>   return Response.FOUND;
>>> }
>>> public static GuessANumber random(int seed) {
>>>   return new GuessANumber(new Random(seed).nextInt(1024));
>>> }
>>> }
>>> you can naively think that if we have an an instance of GuessANumber
>>> var number = GuessANumber.random(0);
>>> you have can not get the value of the private field of that instance,
>>> but using == you can find it because you can use == to test if number is
>>> substituable to a user created GuessANumber.
>>> here is how to find the value without using the method guess()
>>> System.out.println(IntStream.range(0, 1024).filter(n -> new GuessANumber(n) ==
>>> number).findFirst());
>>> Rémi

More information about the valhalla-spec-observers mailing list