This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Parameterised extractors

7 replies
Gavin Lowe
Joined: 2011-04-11,
User offline. Last seen 42 years 45 weeks ago.

I'm trying to build a library for implementing cryptographic
protocols. I have a class:

case class Encrypt(key:Key){
// decrypt cipherBytes with key, returning plaintext if successful
def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = ...
}

I'd like to be able to use this in pattern matching as follows, where
bs:Array[Byte] is a ciphertext that is expected to be encrypted with
key:

bs match{
case Encrypt(`key`)(plain) => ... // do something with plain
}

But this gives an error: "'=>' expected but '(' found", at the opening
parenthesis before plain.

The following works, but is rather ugly:

val Enc = Encrypt(key)
bs match{
case Enc(plain) => ... // do something with plain
}

Is there some way to achieve the effect I'm after?

Peter 2
Joined: 2011-02-16,
User offline. Last seen 42 years 45 weeks ago.
Re: Parameterised extractors

> case class Encrypt(key:Key){
>   // decrypt cipherBytes with key, returning plaintext if successful
>   def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = ...
> }

Case classes generate an unapply method in the companion object. In
your case that generated method has the signature

def unapply(e: Encrypt): Option[Key]

"def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] " you
have manually appended to Encrypt will never be matched.

What do you want to achieve with the match statement exactly? unapply
is simply meant to get the class parameter "key" so maybe your design
isn't appropriate?

val e = Encrypt(...)
e match {
case Encrypt(key) => // do something with key
case Encrypt(key) if key == "..." => // do something with key if it
satisfies the given condition

Peter

Chris Twiner
Joined: 2008-12-17,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Parameterised extractors

I think his design is spot on, I use it in Scales as well and the standard lib regex matchers do the same.

Unfortunately there isn't another way to do it although I have seen a few threads about improving the situation.

On Jan 28, 2012 5:37 PM, "Sonnenschein" <peter.empen@arcor.de> wrote:
> case class Encrypt(key:Key){
>   // decrypt cipherBytes with key, returning plaintext if successful
>   def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = ...
> }

Case classes generate an unapply method in the companion object. In
your case that generated method has the signature

def unapply(e: Encrypt): Option[Key]

"def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] " you
have manually appended to Encrypt will never be matched.

What do you want to achieve with the match statement exactly? unapply
is simply meant to get the class parameter "key" so maybe your design
isn't appropriate?

val e = Encrypt(...)
e match {
 case Encrypt(key) => // do something with key
 case Encrypt(key) if key == "..." => // do something with key if it
satisfies the given condition

Peter
Peter 2
Joined: 2011-02-16,
User offline. Last seen 42 years 45 weeks ago.
Re: Parameterised extractors

Hi Gavin, hi Chris,

it is still not obvious to me for what purpose Gavin uses "match".
What should "Encrypt(`key`)(plain) " do?

The statement "where bs:Array[Byte] is a ciphertext that is expected
to be encrypted with key" is also not clear to me. Do you mean "to be
encrypted (in future)" or "to have been encrypted" or "to be decrypted
(in future)"...?

I'd advocate full, workable code samples to give others the chance not
to miss anything.

Have a nice Sunday
Peter

Chris Twiner
Joined: 2008-12-17,
User offline. Last seen 42 years 45 weeks ago.
Re: Re: Parameterised extractors

I would assume that the key creates an extractor which either returns plain text, when encrypted with that key or None when not. Perhaps the name Encrypt should be Unencrypted and it could be clearer.

The same approach let's you define a regex as an extractor with the groups in the regex as the input then - provided the regex matches - unapply returns the groups. In Scales it allows one to define an Xml element match when certain attributes are present.

In the above cases you need a starting input to perform the match/extraction logic against. Whereas a straight extractor only performs the unpacking these match as well. 

The syntax suggestion "simply" moves the definition in-line which may be more appropriate when its a one-off match.

On Jan 29, 2012 10:43 AM, "Sonnenschein" <peter.empen@arcor.de> wrote:
Hi Gavin, hi Chris,

it is still not obvious to me for what purpose Gavin uses "match".
What should "Encrypt(`key`)(plain) " do?

The statement "where bs:Array[Byte] is a ciphertext that is expected
to be encrypted with key" is also not clear to me. Do you mean "to be
encrypted (in future)" or "to have been encrypted" or "to be decrypted
(in future)"...?

I'd advocate full, workable code samples to give others the chance not
to miss anything.

Have a nice Sunday
Peter
Gavin Lowe
Joined: 2011-04-11,
User offline. Last seen 42 years 45 weeks ago.
Re: Parameterised extractors

On Jan 29, 9:43 am, Sonnenschein wrote:

> it is still not obvious to me for what purpose Gavin uses "match".
> What should "Encrypt(`key`)(plain) " do?

It should match a ciphertext that was encrypted with key; it should
bind plain to the corresponding plaintext. The unapply will decrypt
with key (I'm assuming symmetric crypto for simplicity); if that
succeeds, it will return Some applied to the result of the decryption;
if the decryption fails, it will return None.

> The statement "where bs:Array[Byte] is a ciphertext that is expected
> to be encrypted with key" is also not clear to me. Do you mean "to be
> encrypted (in future)" or "to have been encrypted" or "to be decrypted
> (in future)"...?

It is expected that it has been encrypted with the key. (In a
cryptographic protocol, one should never assume that a message
received is of the expected form.)

> I'd advocate full, workable code samples to give others the chance not
> to miss anything.

def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = try{
val cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
val plainBytes = cipher.doFinal(cipherBytes);
Some(plainBytes)
} catch { case _ => None }

That works fine, except it seems necessary to write the pattern in the
slightly ugly form in my original message.

Jason Zaugg
Joined: 2009-05-18,
User offline. Last seen 38 weeks 5 days ago.
Re: Re: Parameterised extractors
On Sun, Jan 29, 2012 at 7:45 PM, Gavin Lowe <gavinlowe1@gmail.com> wrote:
On Jan 29, 9:43 am, Sonnenschein <peter.em...@arcor.de> wrote:

> it is still not obvious to me for what purpose Gavin uses "match".
> What should "Encrypt(`key`)(plain) " do?

It should match a ciphertext that was encrypted with key; it should
bind plain to the corresponding plaintext.  The unapply will decrypt
with key (I'm assuming symmetric crypto for simplicity); if that
succeeds, it will return Some applied to the result of the decryption;
if the decryption fails, it will return None.

> The statement "where bs:Array[Byte] is a ciphertext that is expected
> to be encrypted with key" is also not clear to me. Do you mean "to be
> encrypted (in future)" or "to have been encrypted" or "to be decrypted
> (in future)"...?

It is expected that it has been encrypted with the key.  (In a
cryptographic protocol, one should never assume that a message
received is of the expected form.)

> I'd advocate full, workable code samples to give others the chance not
> to miss anything.

def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = try{
   val cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
   cipher.init(Cipher.DECRYPT_MODE, key);
   val plainBytes = cipher.doFinal(cipherBytes);
   Some(plainBytes)
 } catch { case _ => None }

That works fine, except it seems necessary to write the pattern in the
slightly ugly form in my original message.

Parameterised Extractors are definitely a palatable feature proposal. Here's some previous discussion:
http://www.scala-lang.org/node/10861 http://stackoverflow.com/questions/2411573/can-extractors-be-customized-with-parameters-in-the-body-of-a-case-statement-or/2454784#2454784
-jason
dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
Re: Re: Parameterised extractors

On Sun, Jan 29, 2012 at 17:17, Jason Zaugg wrote:
> On Sun, Jan 29, 2012 at 7:45 PM, Gavin Lowe wrote:
>>
>> On Jan 29, 9:43 am, Sonnenschein wrote:
>>
>> > it is still not obvious to me for what purpose Gavin uses "match".
>> > What should "Encrypt(`key`)(plain) " do?
>>
>> It should match a ciphertext that was encrypted with key; it should
>> bind plain to the corresponding plaintext.  The unapply will decrypt
>> with key (I'm assuming symmetric crypto for simplicity); if that
>> succeeds, it will return Some applied to the result of the decryption;
>> if the decryption fails, it will return None.
>>
>> > The statement "where bs:Array[Byte] is a ciphertext that is expected
>> > to be encrypted with key" is also not clear to me. Do you mean "to be
>> > encrypted (in future)" or "to have been encrypted" or "to be decrypted
>> > (in future)"...?
>>
>> It is expected that it has been encrypted with the key.  (In a
>> cryptographic protocol, one should never assume that a message
>> received is of the expected form.)
>>
>> > I'd advocate full, workable code samples to give others the chance not
>> > to miss anything.
>>
>> def unapply(cipherBytes : Array[Byte]) : Option[Array[Byte]] = try{
>>    val cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
>>    cipher.init(Cipher.DECRYPT_MODE, key);
>>    val plainBytes = cipher.doFinal(cipherBytes);
>>    Some(plainBytes)
>>  } catch { case _ => None }
>>
>> That works fine, except it seems necessary to write the pattern in the
>> slightly ugly form in my original message.
>
>
> Parameterised Extractors are definitely a palatable feature proposal. Here's
> some previous discussion:
>
> http://www.scala-lang.org/node/10861
> http://stackoverflow.com/questions/2411573/can-extractors-be-customized-...
>
> -jason

They are also presently possible in a limited extent through string
templates, since the string is passed as parameter to the extractor.

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland