Skip to content

Commit 87ebe8f

Browse files
authored
Strengthen SHAKE XOF tests and cover peer-certificate FFI (#57)
The SHAKE output-length property tests asserted `final().size() == sample`, but the returned array's size comes from the Pony-side allocation (`@pony_alloc`), not from what `EVP_DigestFinalXOF` wrote — a silent no-op would pass. Replaced with known-answer unit tests at two non-default lengths per variant, and the prefix-property tests are now split into a small-range variant (2..15 / 2..31 bytes, no anchor) and a large-range variant (16..256 / 32..256 with a KAT anchor at the low end), so an all-zero XOF can't satisfy the prefix equality at the anchored sizes. `SSL_get1_peer_certificate` / `SSL_get_peer_certificate` had zero runtime coverage — every net test ran with `set_client_verify(false)` or an empty hostname, so `_verify_hostname` never ran and the FFI binding was only checked at link time. Added a positive test (match → SSLReady → `connected`) and a negative test (mismatch → SSLAuthFail → `auth_failed`). Both use separate client and server SSLContexts; the client context has no local certificate, so a regression that returned the local cert instead of the peer cert would get NULL and fail verification — distinguishing peer-cert retrieval from local-cert retrieval. `assets/cert.pem` and `assets/key.pem` regenerated. The prior cert expired in April 2025 and had no subjectAltName, so it couldn't support a hostname-verified test. The new cert has `subjectAltName=DNS:localhost,IP:127.0.0.1`, is backdated to 2026-01-01 for clock-skew tolerance, and is valid for 100 years. `_TestTCPSSLClientVerifyFalseWithHostname` switched to `nomatch.example.com` so its "verify=false skips mismatch" intent survives the new SAN. Closes #49
1 parent 1debc19 commit 87ebe8f

4 files changed

Lines changed: 385 additions & 68 deletions

File tree

assets/cert.pem

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
-----BEGIN CERTIFICATE-----
2-
MIIDLzCCAhegAwIBAgIJAI/o78XcM9NqMA0GCSqGSIb3DQEBBQUAMBkxFzAVBgNV
3-
BAoTDkZha2UgQXV0aG9yaXR5MB4XDTE1MDQxMTE3NTAwOVoXDTI1MDQwODE3NTAw
4-
OVowGTEXMBUGA1UEChMORmFrZSBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUA
5-
A4IBDwAwggEKAoIBAQDMy0Xuax1Ej1iCOemYdiLwaJ/B8UsCH2ztJVPHyw6HSxwa
6-
WNariJ/d24QLuF9YFx7Xq2oEJK7WJ+zQfnn+jnlQWKfDBFSagreSmOIKRYYkKya3
7-
JwqluKsXcqxXz//0PkL6gfRNrCsbPUVujTP3Ple5eRK1ilOxc0KaJwtRdYVEPWcU
8-
rv0CvuU7qDKMzBh2Lt3tPC8J6VNqvK5bsLBdhcxFU+OjL65VEGjIc33pHMGkQitl
9-
MpsFolqXYvMt/JPNdf3trPEg8eGHeK9+7AxmaRo4WLaFsYyV5Etwa8ox+p3gGL/I
10-
OpE2PDC1SqJ2HdnLgXK1I/LGRlrNQssfew/rfqdZAgMBAAGjejB4MB0GA1UdDgQW
11-
BBTUVbUqQanwnb1TzSj3VVOXHkPWsDBJBgNVHSMEQjBAgBTUVbUqQanwnb1TzSj3
12-
VVOXHkPWsKEdpBswGTEXMBUGA1UEChMORmFrZSBBdXRob3JpdHmCCQCP6O/F3DPT
13-
ajAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBlCZDD231UlS2FGOLK
14-
yesxakCcCxwuqw6rbldj0zCNNRqlZ8lPDrbbr2ECUBKj6kYVJfU93YaYVYSmSTaB
15-
41/GCfBWdNfPdP4q2kqpmKR5bCeiGYpFNajPLXTpmRvmIQ6NT1u86krIPYxle/02
16-
DgYatXMGanzcUCwrfSnkqZbyXBKRAxbhyJnLmkJ6HqIm5vs6hDw2KdtgwRw6koFJ
17-
+0unhRHDKjZgFuCveaFFzFFkf4tlGmei3ykR3KTLxY3f1+GPunqD7HgebrE/vLP5
18-
Bgc1g/KSVGuyqKt9eCnSUlJypbPbKpPjnUrtx00HChpfnKpqiAgHFuZhaxBGUBZD
19-
BccR
2+
MIIDNTCCAh2gAwIBAgIUJqPt0dWpXmZpKr8FKEpO3JvOFhswDQYJKoZIhvcNAQEL
3+
BQAwGzEZMBcGA1UECgwQUG9ueSBTU0wgVGVzdCBDQTAgFw0yNjAxMDEwMDAwMDBa
4+
GA8yMTI2MDEwMTAwMDAwMFowGzEZMBcGA1UECgwQUG9ueSBTU0wgVGVzdCBDQTCC
5+
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOsuoTFDSdq+r2efmNlkMvjg
6+
CT5gk11LB6NUrQIiJ6ByUFn7RyL7+nSBqL06wQrrfwNmWEaWWq+CPb+t2v2XLj0/
7+
8GRaL9MiY69SqIJS/uMNbAn5ZKb7d1U7zx1+TVhf9x/P/vd0sjuO/76OtwxQo5jx
8+
6MR7hDiNPhmE7AskWA5y9Ja4JVsAv9JzlulWaImVTZt8nzOJnGqq8ElM9OgWI/JA
9+
dst1Y+rwwfqoJpqUZh8pns2C+JsdGBAdIZYqUpeDtiJfvOGnbN1hDFaNPbHd3b1F
10+
klxt+vDiIgSRCA2GGsxg4N/tp2prScebCd6FapXoUHRXla+nZ0K0xOH/2QQqBNUC
11+
AwEAAaNvMG0wHQYDVR0OBBYEFOceAy4+/6VvOMuVzUb4LUVW0RdOMB8GA1UdIwQY
12+
MBaAFOceAy4+/6VvOMuVzUb4LUVW0RdOMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcE
13+
fwAAATAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBJEqAdVMlk
14+
xd2XX+zDZH7pj6vwOen16I0fiUKNkq18Fx3lGo0QQJ6xCHQ6m63oMEYJiJhqRjP5
15+
CU8mIu9bAnpfkZCkRBS2BIm/qGymHyU/C8g2S9HZEh//SmtWluk5O9tG+dKq9b34
16+
d+xH7N6gXL51jiulkQNbawWbPthFl6NLQaPHP3WuFmYn0FmyoKYuL0JLFO3bB6CX
17+
RwfYIb6y1XlE6RxikzV/BJ5FkDwQVbeIELAxtKi6PX94+zrxvt76XDtxWK2Ge4Mh
18+
94hZRkp5cLCNlZrCqYORi3a3aCqOjzMucNqL3Ld42G0QaIHy/EfEzdiGcxEQhiTI
19+
0tAjVsKAywQQ
2020
-----END CERTIFICATE-----

assets/key.pem

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,28 @@
1-
-----BEGIN RSA PRIVATE KEY-----
2-
MIIEowIBAAKCAQEAzMtF7msdRI9YgjnpmHYi8GifwfFLAh9s7SVTx8sOh0scGljW
3-
q4if3duEC7hfWBce16tqBCSu1ifs0H55/o55UFinwwRUmoK3kpjiCkWGJCsmtycK
4-
pbirF3KsV8//9D5C+oH0TawrGz1Fbo0z9z5XuXkStYpTsXNCmicLUXWFRD1nFK79
5-
Ar7lO6gyjMwYdi7d7TwvCelTaryuW7CwXYXMRVPjoy+uVRBoyHN96RzBpEIrZTKb
6-
BaJal2LzLfyTzXX97azxIPHhh3ivfuwMZmkaOFi2hbGMleRLcGvKMfqd4Bi/yDqR
7-
NjwwtUqidh3Zy4FytSPyxkZazULLH3sP636nWQIDAQABAoIBADvxuAt8gPmjd8XO
8-
i8ibs8ho53JOXaVGa4zSoz5U+nCxlI1FubhF6n13FqSTmBzhz55TR1nlHuQClbfF
9-
fZH8RBg3iwtzRgxf/LnFVEyrYwNNOizcGaq+bh4T68xcTtBANTy8MzVVEt0LRzp/
10-
zFkvf2ADx20qCyti0HjsusxiONrrFBS6O7DTss9GFRN5lfsBP49FSl3/r0e+fUaO
11-
/6ImRVJvmAU92+dQ4VOi4c+laeFDmhw1MQSpvHOz3Vrslin9NSR6TMQ7rH9I/QKL
12-
+YQULz7fYINRwt8FBa/p94qjGIqlNz6UdTPGvaEMlVyYo1ziTDZlCHnAYWk3wiFW
13-
s13Jct0CgYEA7PxGYpZCyzntd1wvOradxh7EbUrF68lhfDt6BgOBV8Ur3/4SvcwB
14-
blc4nEf5/p/x9w8ICe4uyA0bsGwqGppIhptrPe0uLApidUrxNeqY5zsebriR/gE6
15-
mq5/cmScFTnywfAb/93qK5SMzeWKfocPozb5YqO8oJpPHPhVZYAj16MCgYEA3TnH
16-
14szOoQSq8ul2tFdu7s9S+sfi1l7ejqiHjZVcMST+GyEk3ox5Ns24pwkRq80cQhp
17-
1UYfapeeiYroW7nkVTqJUfZbilFO6eKCBfpzC7NGHMs86er3pLUrfHQKq6S5RSZr
18-
W9CB7+Kd9OXMOIJ2yXcF+OyEzQH5ESwxoHvrJNMCgYEAz/o6Hw01wzqsP2Mkg8d+
19-
QUABLNVBS0NpjWh5F0v+ODPu5F4KvoyJ+PcM1IKKUD64UBTd/jEM1z5BvZu/e6dI
20-
3PEKtccwDTBz5fIGLEYdOFj2xT6vyRX1A4j+ijrni+1WMYNyXyO2/dYZmBzJZW9M
21-
dvWo+TsvMFcb9RWvhCtnyTcCgYAyK9t9r60TlUZivdHEeX0HiWRSZmWGBeoyA0An
22-
F+1yoLJqQbojdDAClhCxffXgLfX3uI+/9aJEW1RyHxWpT9RP2/Guq++AxAXglyUj
23-
0/PpcGPzPch3yHkXWpsdI3gUC0yVOSxZ60S8salfFAqnujbUY/Dvzjwj/lGNKneq
24-
zM+8TwKBgHjQforDq00DhDAqzqZDDVd8OZ9PLp3wXL+TaidTMmU7Fob5spyQe0gn
25-
LqVIyGFYoRbW57pLgSEXRh+Zqw1AAKmMYoc3/pKM60rgOQxMXEemFAJ8zuDQ5L6y
26-
1dR3ak4ueRcSFpa6x8/STsgIuL38HMNXhStsJB9whHAFB3U6Wo2/
27-
-----END RSA PRIVATE KEY-----
1+
-----BEGIN PRIVATE KEY-----
2+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDrLqExQ0navq9n
3+
n5jZZDL44Ak+YJNdSwejVK0CIiegclBZ+0ci+/p0gai9OsEK638DZlhGllqvgj2/
4+
rdr9ly49P/BkWi/TImOvUqiCUv7jDWwJ+WSm+3dVO88dfk1YX/cfz/73dLI7jv++
5+
jrcMUKOY8ejEe4Q4jT4ZhOwLJFgOcvSWuCVbAL/Sc5bpVmiJlU2bfJ8ziZxqqvBJ
6+
TPToFiPyQHbLdWPq8MH6qCaalGYfKZ7NgvibHRgQHSGWKlKXg7YiX7zhp2zdYQxW
7+
jT2x3d29RZJcbfrw4iIEkQgNhhrMYODf7adqa0nHmwnehWqV6FB0V5Wvp2dCtMTh
8+
/9kEKgTVAgMBAAECggEAL76f7VEYh37CO9J/9JQ9r95FqiLvj9dJVex9EguOiWlj
9+
rBzR+IV4t1nSQJZSte2Qs8c9gRkJkItrj0QTivt74OXf3vObNW0MGT355TlFsyEY
10+
r56wgyDWfVh+x+FKAPi8gfoXLDQF8gbqHwy4lxiw2b40r9zWfyeXdZVRWUK32Li0
11+
fmuGUKYhSJHOQ2wtRHPVQL5eV328n93+krsJAcUpYt5OgX0WNLSNodj0Z6x+d9C8
12+
wbojGzZ4ohui1myRVqN5nZPyP/JlObBGzkeVv7DGJb5KnetIDMFGWKKaDKh+dBIh
13+
GXUir15N3Jelh9e9GaoIVSkPMkprmvBl5hbX7CorIQKBgQD/o8c+dtcBfnafhDbn
14+
jHO0uVrz9irGOX4x+IPsSON0DRr6mUyLdzMMAJQnHLVbhBVUwzzGI5lT6CpXmW3P
15+
/qP2R85bWp1kAthfx6rnFKKNsa1qLP2ca5vJC5KdLsHVZh5m7jDZkNiHTIB1K/Xh
16+
/OfAR4HmgGa/R5ceTaRAtqeldQKBgQDrg3inbicZXnfVp+kcKYOZOmrrL5ebE39n
17+
rDZ6Z2ed47gHZpNj40hLVFAmorI2HmRbAIGqWPe9svdOk9lt87/MnBXnUF88gBch
18+
rbS2REngaXuzrO1xV7g+gg4XOTWXHGkA8HBjuYb122RFwDi6UGl7IFW0MybHWMvt
19+
NuJLBmMV4QKBgBUiSxSE6p17AP+LBKb724zzTeuhTEP6+M3Ux8M++17avoI9LjDR
20+
d+zkF1tsainYr5LEWT/gLYrcRLPdQVDSsmdn5E11HlHoUk8IyL413IJuT/HZKlZG
21+
JyjlxgcsmGW1/Ylw46T47o2w62XEbp1yNQ6WWszdjKD/oCSnMo8PCqkJAoGBAOTu
22+
GmVePOF7I69rFbzLWeGjmHTfAVa8ADdtflNDmsQurB99hT4um4KmBXdY5TSYHGMd
23+
Pe2xp7gddCpMq6kmrEUfYGdGiBzOQi35pVUbUlizEIzaRsDLTQxt7XaDpOUrt6Iz
24+
FnzJxjfMuE7ZCAuLyMzn5IdSxZo3ZZtDo3rcTYrhAoGASNYytkqh9FG1WdCevb1y
25+
iZaynjYf4HbwGesCJFrB/MULfWGV8I5sazJfnAyHGNsH2w1AoB0Mg0KXiovrVx6k
26+
Ow8z5eB95XzIO/AcE4o2Gb1rWjCpaoEeerno/CM9AJfpM4TSMIAqc3hl0104+3bl
27+
QpZNekXjbdQrh/uMZHioNxc=
28+
-----END PRIVATE KEY-----

ssl/crypto/_test.pony

Lines changed: 133 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ actor \nodoc\ Main is TestList
3030
test(Property1UnitTest[USize](_TestPbkdf2Sha256Deterministic))
3131
end
3232
ifdef "openssl_3.0.x" or "openssl_4.0.x" then
33-
test(Property1UnitTest[USize](_TestShake128OutputLength))
34-
test(Property1UnitTest[USize](_TestShake256OutputLength))
33+
test(_TestShake128KnownAnswer)
34+
test(_TestShake256KnownAnswer)
35+
test(Property1UnitTest[USize](_TestShake128XofPrefixSmall))
36+
test(Property1UnitTest[USize](_TestShake256XofPrefixSmall))
3537
test(Property1UnitTest[USize](_TestShake128XofPrefix))
3638
test(Property1UnitTest[USize](_TestShake256XofPrefix))
3739
end
@@ -446,37 +448,103 @@ class \nodoc\ iso _TestRandBytesNonConstant is Property1[USize]
446448
let b = RandBytes(sample)?
447449
h.assert_false(ConstantTimeCompare(a, b))
448450

449-
class \nodoc\ iso _TestShake128OutputLength is Property1[USize]
450-
fun name(): String => "crypto/Shake128/property/output_length"
451+
class \nodoc\ iso _TestShake128KnownAnswer is UnitTest
452+
"""
453+
Known-answer tests for SHAKE128 at two non-default output lengths.
454+
Anchors the XOF path against specific byte values so a silent no-op
455+
(zero bytes written) cannot pass.
456+
"""
457+
fun name(): String => "crypto/Shake128/known_answer"
451458

452-
fun gen(): Generator[USize] =>
453-
Generators.usize(1, 256)
459+
fun apply(h: TestHelper) ? =>
460+
ifdef "openssl_3.0.x" or "openssl_4.0.x" then
461+
let d32 = Digest.shake128(32)
462+
d32.append("message1")?
463+
d32.append("message2")?
464+
h.assert_eq[String](
465+
"0d11671f23b6356bdf4ba8dcae37419df1d0875e1a15c7859eb3ba0096aa262f",
466+
ToHexString(d32.final()))
454467

455-
fun ref property(sample: USize, h: PropertyHelper) ? =>
468+
let d64 = Digest.shake128(64)
469+
d64.append("message1")?
470+
d64.append("message2")?
471+
h.assert_eq[String](
472+
"0d11671f23b6356bdf4ba8dcae37419df1d0875e1a15c7859eb3ba0096aa262f" +
473+
"3a1cfc86db5b324ac3f8220645ec0740c2171a0b935f362d0c3bfa5ab51be5d0",
474+
ToHexString(d64.final()))
475+
end
476+
477+
class \nodoc\ iso _TestShake256KnownAnswer is UnitTest
478+
"""
479+
Known-answer tests for SHAKE256 at two non-default output lengths.
480+
Anchors the XOF path against specific byte values so a silent no-op
481+
(zero bytes written) cannot pass.
482+
"""
483+
fun name(): String => "crypto/Shake256/known_answer"
484+
485+
fun apply(h: TestHelper) ? =>
456486
ifdef "openssl_3.0.x" or "openssl_4.0.x" then
457-
let d = Digest.shake128(sample)
458-
d.append("test")?
459-
h.assert_eq[USize](sample, d.final().size())
487+
let d64 = Digest.shake256(64)
488+
d64.append("message1")?
489+
d64.append("message2")?
490+
h.assert_eq[String](
491+
"80e2bbb14639e3b1fc1df80b47b67fb518b0ed26a1caddfa10d68f7992c33820" +
492+
"2d0b17a5ebbcef93f51247497f60bcd3f2809a967874d017ef5b51d6b08836cc",
493+
ToHexString(d64.final()))
494+
495+
let d128 = Digest.shake256(128)
496+
d128.append("message1")?
497+
d128.append("message2")?
498+
h.assert_eq[String](
499+
"80e2bbb14639e3b1fc1df80b47b67fb518b0ed26a1caddfa10d68f7992c33820" +
500+
"2d0b17a5ebbcef93f51247497f60bcd3f2809a967874d017ef5b51d6b08836cc" +
501+
"af79f3db3fafdf89e7d42270472c3d1a8e55c52a30859e01b5fceba359c21c1e" +
502+
"76b73180378604d46061c87e65c4740c8ff9721ed16465cef66fefc3c6f2070c",
503+
ToHexString(d128.final()))
460504
end
461505

462-
class \nodoc\ iso _TestShake256OutputLength is Property1[USize]
463-
fun name(): String => "crypto/Shake256/property/output_length"
506+
class \nodoc\ iso _TestShake128XofPrefixSmall is Property1[USize]
507+
"""
508+
SHAKE128 prefix property at small output sizes (2..15 bytes). Exercises
509+
the truncation path where off-by-one partial-block bugs typically live.
510+
No KAT anchor — sizes below 16 are guarded by _TestShake128XofPrefix
511+
at larger sizes.
512+
"""
513+
fun name(): String => "crypto/Shake128/property/xof_prefix_small"
464514

465515
fun gen(): Generator[USize] =>
466-
Generators.usize(1, 256)
516+
Generators.usize(2, 15)
467517

468518
fun ref property(sample: USize, h: PropertyHelper) ? =>
469519
ifdef "openssl_3.0.x" or "openssl_4.0.x" then
470-
let d = Digest.shake256(sample)
471-
d.append("test")?
472-
h.assert_eq[USize](sample, d.final().size())
520+
let small_size = sample / 2
521+
let large_size = sample
522+
523+
let small = Digest.shake128(small_size)
524+
small.append("test input")?
525+
let small_result = small.final()
526+
527+
let large = Digest.shake128(large_size)
528+
large.append("test input")?
529+
let large_result = large.final()
530+
531+
h.assert_array_eq[U8](small_result,
532+
large_result.trim(0, small_size))
473533
end
474534

475535
class \nodoc\ iso _TestShake128XofPrefix is Property1[USize]
536+
"""
537+
SHAKE128 prefix property: the first N bytes of output at length M (M > N)
538+
are identical to the full output at length N. A KAT anchor at the full
539+
length prevents any no-op or incorrect XOF implementation from satisfying
540+
the prefix equality (an all-zero buffer would trivially equal its own
541+
prefix).
542+
"""
476543
fun name(): String => "crypto/Shake128/property/xof_prefix"
477544

478545
fun gen(): Generator[USize] =>
479-
Generators.usize(2, 256)
546+
// Minimum 16 so the 16-byte KAT anchor below always applies.
547+
Generators.usize(16, 256)
480548

481549
fun ref property(sample: USize, h: PropertyHelper) ? =>
482550
ifdef "openssl_3.0.x" or "openssl_4.0.x" then
@@ -491,15 +559,57 @@ class \nodoc\ iso _TestShake128XofPrefix is Property1[USize]
491559
large.append("test input")?
492560
let large_result = large.final()
493561

562+
h.assert_array_eq[U8](small_result,
563+
large_result.trim(0, small_size))
564+
565+
// KAT anchor: first 16 bytes of SHAKE128("test input").
566+
h.assert_eq[String](
567+
"a9d2b0362d0e2e961eeb969ce9a42f2d",
568+
ToHexString(large_result.trim(0, 16)))
569+
end
570+
571+
class \nodoc\ iso _TestShake256XofPrefixSmall is Property1[USize]
572+
"""
573+
SHAKE256 prefix property at small output sizes (2..31 bytes). Exercises
574+
the truncation path where off-by-one partial-block bugs typically live.
575+
No KAT anchor — sizes below 32 are guarded by _TestShake256XofPrefix
576+
at larger sizes.
577+
"""
578+
fun name(): String => "crypto/Shake256/property/xof_prefix_small"
579+
580+
fun gen(): Generator[USize] =>
581+
Generators.usize(2, 31)
582+
583+
fun ref property(sample: USize, h: PropertyHelper) ? =>
584+
ifdef "openssl_3.0.x" or "openssl_4.0.x" then
585+
let small_size = sample / 2
586+
let large_size = sample
587+
588+
let small = Digest.shake256(small_size)
589+
small.append("test input")?
590+
let small_result = small.final()
591+
592+
let large = Digest.shake256(large_size)
593+
large.append("test input")?
594+
let large_result = large.final()
595+
494596
h.assert_array_eq[U8](small_result,
495597
large_result.trim(0, small_size))
496598
end
497599

498600
class \nodoc\ iso _TestShake256XofPrefix is Property1[USize]
601+
"""
602+
SHAKE256 prefix property: the first N bytes of output at length M (M > N)
603+
are identical to the full output at length N. A KAT anchor at the full
604+
length prevents any no-op or incorrect XOF implementation from satisfying
605+
the prefix equality (an all-zero buffer would trivially equal its own
606+
prefix).
607+
"""
499608
fun name(): String => "crypto/Shake256/property/xof_prefix"
500609

501610
fun gen(): Generator[USize] =>
502-
Generators.usize(2, 256)
611+
// Minimum 32 so the 32-byte KAT anchor below always applies.
612+
Generators.usize(32, 256)
503613

504614
fun ref property(sample: USize, h: PropertyHelper) ? =>
505615
ifdef "openssl_3.0.x" or "openssl_4.0.x" then
@@ -516,6 +626,11 @@ class \nodoc\ iso _TestShake256XofPrefix is Property1[USize]
516626

517627
h.assert_array_eq[U8](small_result,
518628
large_result.trim(0, small_size))
629+
630+
// KAT anchor: first 32 bytes of SHAKE256("test input").
631+
h.assert_eq[String](
632+
"e952d90136cb23413ff22b266e2f5dd42294a34bc311394b04863c039011f179",
633+
ToHexString(large_result.trim(0, 32)))
519634
end
520635

521636
class \nodoc\ iso _TestHashFnOutputLength is Property1[USize]

0 commit comments

Comments
 (0)