From 3b00ade88ba4af0786206950d4802492511b167d Mon Sep 17 00:00:00 2001 From: Shlee Date: Fri, 13 Feb 2026 15:49:30 +1030 Subject: [PATCH 1/9] Update VerifyTrait.php --- src/Features/VerifyTrait.php | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Features/VerifyTrait.php b/src/Features/VerifyTrait.php index f1ca2eb..bca5306 100644 --- a/src/Features/VerifyTrait.php +++ b/src/Features/VerifyTrait.php @@ -60,7 +60,7 @@ public function verifyInclusionProof( int $treeSize ): bool { $this->assertValidHashFunction($hashFunction); - $rootBytes = $this->decodeMerkleRoot($merkleRoot); + $rootBytes = $this->decodeMerkleRoot($merkleRoot, $hashFunction); // Verify manually following RFC 9162 ยง2.1.3 since Tree::verifyInclusionProof // requires the full tree which we don't have on the client side. @@ -386,8 +386,9 @@ protected function parseInclusionProof(array $row): InclusionProof * Decode a Merkle root from its prefixed format. * * @throws ClientException If the format is invalid + * Supported $hashFunction 'sha256', 'sha384', 'sha512', 'blake2b' */ - protected function decodeMerkleRoot(string $merkleRoot): string + protected function decodeMerkleRoot(string $merkleRoot, string $hashFunction): string { $prefix = 'pkd-mr-v1:'; if (!str_starts_with($merkleRoot, $prefix)) { @@ -397,8 +398,16 @@ protected function decodeMerkleRoot(string $merkleRoot): string $encoded = substr($merkleRoot, strlen($prefix)); $decoded = Base64UrlSafe::decodeNoPadding($encoded); - if (strlen($decoded) < 32) { - throw new ClientException('Invalid Merkle root format: expected 32+ bytes'); + $expectedByteLen = match ($hashFunction) { + 'sha256' => 32, + 'sha384' => 48, + 'sha512' => 64, + 'blake2b' => 32, + default => 32, // Fallback to 32 bytes as a minimum but $hashFunc should never be null. + }; + + if (strlen($decoded) < $expectedLen) { + throw new ClientException("Invalid Merkle root format: expected a minimum of {$expectedByteLen} bytes for {$hashFunction} - Got {$decoded}"); } return $decoded; From a5aa83720848bbfc465e190790690872e5e29155 Mon Sep 17 00:00:00 2001 From: Shlee Date: Fri, 13 Feb 2026 15:55:19 +1030 Subject: [PATCH 2/9] Update VerifyTrait.php --- src/Features/VerifyTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/VerifyTrait.php b/src/Features/VerifyTrait.php index bca5306..8c1aa4b 100644 --- a/src/Features/VerifyTrait.php +++ b/src/Features/VerifyTrait.php @@ -402,7 +402,7 @@ protected function decodeMerkleRoot(string $merkleRoot, string $hashFunction): s 'sha256' => 32, 'sha384' => 48, 'sha512' => 64, - 'blake2b' => 32, + 'blake2b' => 32, // variable-length 8 to 512 bits (1 to 64 bytes) but 32 minimum for safety. default => 32, // Fallback to 32 bytes as a minimum but $hashFunc should never be null. }; From 9e35f792855f47ec152ec5a9414df2cb4a3643b1 Mon Sep 17 00:00:00 2001 From: Shlee Date: Fri, 13 Feb 2026 17:25:53 +1030 Subject: [PATCH 3/9] Update VerifyTrait.php --- src/Features/VerifyTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/VerifyTrait.php b/src/Features/VerifyTrait.php index 8c1aa4b..c7f2921 100644 --- a/src/Features/VerifyTrait.php +++ b/src/Features/VerifyTrait.php @@ -407,7 +407,7 @@ protected function decodeMerkleRoot(string $merkleRoot, string $hashFunction): s }; if (strlen($decoded) < $expectedLen) { - throw new ClientException("Invalid Merkle root format: expected a minimum of {$expectedByteLen} bytes for {$hashFunction} - Got {$decoded}"); + throw new ClientException("decodeMerkleRoot: expected a minimum of {$expectedByteLen} bytes for {$hashFunction} - Got {$decoded}"); } return $decoded; From 02daf0d80e8817d459f5baffbeb966a2e8074b83 Mon Sep 17 00:00:00 2001 From: Shlee Date: Fri, 13 Feb 2026 17:26:34 +1030 Subject: [PATCH 4/9] Update VerifyTrait.php --- src/Features/VerifyTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/VerifyTrait.php b/src/Features/VerifyTrait.php index c7f2921..5598822 100644 --- a/src/Features/VerifyTrait.php +++ b/src/Features/VerifyTrait.php @@ -407,7 +407,7 @@ protected function decodeMerkleRoot(string $merkleRoot, string $hashFunction): s }; if (strlen($decoded) < $expectedLen) { - throw new ClientException("decodeMerkleRoot: expected a minimum of {$expectedByteLen} bytes for {$hashFunction} - Got {$decoded}"); + throw new ClientException("decodeMerkleRoot: Invalid Merkle root format. Expected a minimum of {$expectedByteLen} bytes for {$hashFunction} - Got {$decoded}"); } return $decoded; From 4d25edd5de5fe318c92c6a465a3cde7244010bae Mon Sep 17 00:00:00 2001 From: Shlee Date: Mon, 16 Feb 2026 10:06:40 +1030 Subject: [PATCH 5/9] typo --- src/Features/VerifyTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/VerifyTrait.php b/src/Features/VerifyTrait.php index 5598822..e596234 100644 --- a/src/Features/VerifyTrait.php +++ b/src/Features/VerifyTrait.php @@ -406,7 +406,7 @@ protected function decodeMerkleRoot(string $merkleRoot, string $hashFunction): s default => 32, // Fallback to 32 bytes as a minimum but $hashFunc should never be null. }; - if (strlen($decoded) < $expectedLen) { + if (strlen($decoded) < $expectedByteLen) { throw new ClientException("decodeMerkleRoot: Invalid Merkle root format. Expected a minimum of {$expectedByteLen} bytes for {$hashFunction} - Got {$decoded}"); } From b0b94f168703cbc33e638f0ce342884b736a3f00 Mon Sep 17 00:00:00 2001 From: Shlee Date: Mon, 16 Feb 2026 12:24:20 +1030 Subject: [PATCH 6/9] Update VerifyTrait.php --- src/Features/VerifyTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Features/VerifyTrait.php b/src/Features/VerifyTrait.php index e596234..b0e7c66 100644 --- a/src/Features/VerifyTrait.php +++ b/src/Features/VerifyTrait.php @@ -398,7 +398,7 @@ protected function decodeMerkleRoot(string $merkleRoot, string $hashFunction): s $encoded = substr($merkleRoot, strlen($prefix)); $decoded = Base64UrlSafe::decodeNoPadding($encoded); - $expectedByteLen = match ($hashFunction) { + $expectedByteLen = match ($hashFunction) { 'sha256' => 32, 'sha384' => 48, 'sha512' => 64, From b21c0338b8d1bcf046d3db23c37fa7d7806faf8b Mon Sep 17 00:00:00 2001 From: Shlee Date: Mon, 16 Feb 2026 12:30:02 +1030 Subject: [PATCH 7/9] Update VerifyTraitTest.php --- tests/unit/Features/VerifyTraitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/Features/VerifyTraitTest.php b/tests/unit/Features/VerifyTraitTest.php index e5d105a..0592e7b 100644 --- a/tests/unit/Features/VerifyTraitTest.php +++ b/tests/unit/Features/VerifyTraitTest.php @@ -378,7 +378,7 @@ public function testDecodeMerkleRootThrowsOnInvalidLength(): void $invalidRoot = 'pkd-mr-v1:' . Base64UrlSafe::encodeUnpadded(str_repeat("\x00", 16)); $this->expectException(ClientException::class); - $this->expectExceptionMessage('Invalid Merkle root format: expected 32+ bytes'); + $this->expectExceptionMessage('decodeMerkleRoot: Invalid Merkle root format. Expected a minimum of 32 bytes for sha256 - Got \\\\\\\\\\\\\\\\'); $client->verifyInclusionProof('sha256', $invalidRoot, 'leaf1', $proof, $tree->getSize()); } From 89287661849e1fad27e15b4f4b73f98c7edb2d43 Mon Sep 17 00:00:00 2001 From: Shlee Date: Mon, 16 Feb 2026 12:37:50 +1030 Subject: [PATCH 8/9] Update VerifyTraitTest.php --- tests/unit/Features/VerifyTraitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/Features/VerifyTraitTest.php b/tests/unit/Features/VerifyTraitTest.php index 0592e7b..91f1d85 100644 --- a/tests/unit/Features/VerifyTraitTest.php +++ b/tests/unit/Features/VerifyTraitTest.php @@ -378,7 +378,7 @@ public function testDecodeMerkleRootThrowsOnInvalidLength(): void $invalidRoot = 'pkd-mr-v1:' . Base64UrlSafe::encodeUnpadded(str_repeat("\x00", 16)); $this->expectException(ClientException::class); - $this->expectExceptionMessage('decodeMerkleRoot: Invalid Merkle root format. Expected a minimum of 32 bytes for sha256 - Got \\\\\\\\\\\\\\\\'); + $this->expectExceptionMessage('decodeMerkleRoot: Invalid Merkle root format. Expected a minimum of 32 bytes for sha256 - Got \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'); $client->verifyInclusionProof('sha256', $invalidRoot, 'leaf1', $proof, $tree->getSize()); } From 88df0839c4c2e7fa990bd0c6d8b56228d17932e1 Mon Sep 17 00:00:00 2001 From: Shlee Date: Mon, 16 Feb 2026 12:40:24 +1030 Subject: [PATCH 9/9] Update VerifyTraitTest.php --- tests/unit/Features/VerifyTraitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/Features/VerifyTraitTest.php b/tests/unit/Features/VerifyTraitTest.php index 91f1d85..880fcc6 100644 --- a/tests/unit/Features/VerifyTraitTest.php +++ b/tests/unit/Features/VerifyTraitTest.php @@ -378,7 +378,7 @@ public function testDecodeMerkleRootThrowsOnInvalidLength(): void $invalidRoot = 'pkd-mr-v1:' . Base64UrlSafe::encodeUnpadded(str_repeat("\x00", 16)); $this->expectException(ClientException::class); - $this->expectExceptionMessage('decodeMerkleRoot: Invalid Merkle root format. Expected a minimum of 32 bytes for sha256 - Got \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'); + $this->expectExceptionMessage('decodeMerkleRoot: Invalid Merkle root format. Expected a minimum of 32 bytes for sha256'); $client->verifyInclusionProof('sha256', $invalidRoot, 'leaf1', $proof, $tree->getSize()); }