Skip to content

Commit 4e4df67

Browse files
committed
Require a box receiver for ssl/crypto's apply methods
`fun tag` on a primitive weakens the receiver to one that cannot read fields, on a type that has none. It bought nothing and cost the `HashFn` interface its implementers: a `box` method is not a subtype of a `tag` method, so every implementer had to declare `apply` `tag` as well. The interface has to lose `tag` before its implementers can, so all thirteen declarations change together. Closes #94
1 parent 8d9853e commit 4e4df67

6 files changed

Lines changed: 46 additions & 13 deletions

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
## Require a box receiver for ssl/crypto's apply methods
2+
3+
The `apply` methods on the eight one-shot hash functions (`MD4`, `MD5`, `RIPEMD160`, `SHA1`, `SHA224`, `SHA256`, `SHA384`, `SHA512`), on `ToHexString`, `RandBytes`, `HmacSha256` and `Pbkdf2Sha256`, and on the `HashFn` interface, took a `tag` receiver. They take a `box` receiver now.
4+
5+
Calling any of them the way you normally would — `MD5("data")`, `HmacSha256(key, message)?` — needs no change. Writing your own `HashFn` needs no change either: a `fun tag apply` still satisfies the interface, and a `fun box apply`, which did not satisfy the `tag` interface before, satisfies it now too.
6+
7+
The one thing that stops compiling is a reference typed `tag`, because a `box` method cannot be called through a `tag`:
8+
9+
```pony
10+
// Was fine, now a compile error:
11+
let hash: HashFn tag = SHA256
12+
hash("data")
13+
14+
// Type the reference val (or box):
15+
let hash: HashFn val = SHA256
16+
hash("data")
17+
```

ssl/crypto/_test.pony

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ actor \nodoc\ Main is TestList
4747
test(Property1UnitTest[USize](_TestShake128XofPrefix))
4848
test(Property1UnitTest[USize](_TestShake256XofPrefix))
4949
end
50+
test(_TestHashFnBoxReceiver)
5051
test(Property1UnitTest[USize](_TestHashFnOutputLength))
5152
test(Property1UnitTest[USize](_TestHashFnDeterministic))
5253
test(Property1UnitTest[USize](_TestHashFnDigestEquivalence))
@@ -890,6 +891,21 @@ class \nodoc\ iso _TestShake256XofPrefix is Property1[USize]
890891
ToHexString(large_result.trim(0, 32)))
891892
end
892893

894+
primitive \nodoc\ _BoxReceiverHashFn is HashFn
895+
fun apply(input: ByteSeq): Array[U8] val =>
896+
recover val Array[U8].init(0x2A, input.size()) end
897+
898+
class \nodoc\ iso _TestHashFnBoxReceiver is UnitTest
899+
"""
900+
`HashFn.apply` takes a `box` receiver, so a primitive whose `apply` is a
901+
plain `fun` satisfies the interface and a `HashFn val` can call it.
902+
"""
903+
fun name(): String => "crypto/HashFn/box_receiver"
904+
905+
fun apply(h: TestHelper) =>
906+
let f: HashFn val = _BoxReceiverHashFn
907+
h.assert_array_eq[U8]([as U8: 0x2A; 0x2A; 0x2A], f("abc"))
908+
893909
class \nodoc\ iso _TestHashFnOutputLength is Property1[USize]
894910
fun name(): String => "crypto/HashFn/property/output_length"
895911

ssl/crypto/hash_fn.pony

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ interface HashFn
1717
"""
1818
Produces a fixed-length byte array based on the input sequence.
1919
"""
20-
fun tag apply(input: ByteSeq): Array[U8] val
20+
fun apply(input: ByteSeq): Array[U8] val
2121

2222
primitive MD4 is HashFn
23-
fun tag apply(input: ByteSeq): Array[U8] val =>
23+
fun apply(input: ByteSeq): Array[U8] val =>
2424
"""
2525
Compute the MD4 message digest conforming to RFC 1320
2626
"""
@@ -32,7 +32,7 @@ primitive MD4 is HashFn
3232
end
3333

3434
primitive MD5 is HashFn
35-
fun tag apply(input: ByteSeq): Array[U8] val =>
35+
fun apply(input: ByteSeq): Array[U8] val =>
3636
"""
3737
Compute the MD5 message digest conforming to RFC 1321
3838
"""
@@ -44,7 +44,7 @@ primitive MD5 is HashFn
4444
end
4545

4646
primitive RIPEMD160 is HashFn
47-
fun tag apply(input: ByteSeq): Array[U8] val =>
47+
fun apply(input: ByteSeq): Array[U8] val =>
4848
"""
4949
Compute the RIPEMD160 message digest conforming to ISO/IEC 10118-3
5050
"""
@@ -56,7 +56,7 @@ primitive RIPEMD160 is HashFn
5656
end
5757

5858
primitive SHA1 is HashFn
59-
fun tag apply(input: ByteSeq): Array[U8] val =>
59+
fun apply(input: ByteSeq): Array[U8] val =>
6060
"""
6161
Compute the SHA1 message digest conforming to US Federal Information
6262
Processing Standard FIPS PUB 180-4
@@ -69,7 +69,7 @@ primitive SHA1 is HashFn
6969
end
7070

7171
primitive SHA224 is HashFn
72-
fun tag apply(input: ByteSeq): Array[U8] val =>
72+
fun apply(input: ByteSeq): Array[U8] val =>
7373
"""
7474
Compute the SHA224 message digest conforming to US Federal Information
7575
Processing Standard FIPS PUB 180-4
@@ -82,7 +82,7 @@ primitive SHA224 is HashFn
8282
end
8383

8484
primitive SHA256 is HashFn
85-
fun tag apply(input: ByteSeq): Array[U8] val =>
85+
fun apply(input: ByteSeq): Array[U8] val =>
8686
"""
8787
Compute the SHA256 message digest conforming to US Federal Information
8888
Processing Standard FIPS PUB 180-4
@@ -95,7 +95,7 @@ primitive SHA256 is HashFn
9595
end
9696

9797
primitive SHA384 is HashFn
98-
fun tag apply(input: ByteSeq): Array[U8] val =>
98+
fun apply(input: ByteSeq): Array[U8] val =>
9999
"""
100100
Compute the SHA384 message digest conforming to US Federal Information
101101
Processing Standard FIPS PUB 180-4
@@ -108,7 +108,7 @@ primitive SHA384 is HashFn
108108
end
109109

110110
primitive SHA512 is HashFn
111-
fun tag apply(input: ByteSeq): Array[U8] val =>
111+
fun apply(input: ByteSeq): Array[U8] val =>
112112
"""
113113
Compute the SHA512 message digest conforming to US Federal Information
114114
Processing Standard FIPS PUB 180-4
@@ -121,7 +121,7 @@ primitive SHA512 is HashFn
121121
end
122122

123123
primitive ToHexString
124-
fun tag apply(bs: Array[U8] val): String =>
124+
fun apply(bs: Array[U8] val): String =>
125125
"""
126126
Return the lower-case hexadecimal string representation of the given Array
127127
of U8.

ssl/crypto/hmac_sha256.pony

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ primitive HmacSha256
2424
When it raises, reject. Do not compare a message against a code of your own
2525
making: a code you invent is one an attacker can send you.
2626
"""
27-
fun tag apply(key: ByteSeq, data: ByteSeq): Array[U8] val ? =>
27+
fun apply(key: ByteSeq, data: ByteSeq): Array[U8] val ? =>
2828
if key.size() > I32.max_value().usize() then error end
2929

3030
recover

ssl/crypto/pbkdf2_sha256.pony

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ primitive Pbkdf2Sha256
2222
let key = Pbkdf2Sha256("password", "salt", 4096, 32)?
2323
```
2424
"""
25-
fun tag apply(password: ByteSeq, salt: ByteSeq, iterations: U32,
25+
fun apply(password: ByteSeq, salt: ByteSeq, iterations: U32,
2626
key_length: USize): Array[U8] val ?
2727
=>
2828
// `PKCS5_PBKDF2_HMAC` takes an `int` for the iteration count and for each

ssl/crypto/rand_bytes.pony

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ primitive RandBytes
1717
let nonce = RandBytes(24)?
1818
```
1919
"""
20-
fun tag apply(size: USize): Array[U8] val ? =>
20+
fun apply(size: USize): Array[U8] val ? =>
2121
// `RAND_bytes` takes an `int`. A `size` that does not fit one narrows to a
2222
// smaller count, and the bytes past it stay zero while `RAND_bytes` reports
2323
// success. Checked before the array is allocated, so an absurd `size` costs

0 commit comments

Comments
 (0)