|
21 | 21 | use GuzzleHttp\HandlerStack; |
22 | 22 | use ParagonIE\ConstantTime\Base64UrlSafe; |
23 | 23 | use PHPUnit\Framework\Attributes\CoversClass; |
| 24 | +use PHPUnit\Framework\Attributes\DataProvider; |
24 | 25 | use PHPUnit\Framework\Attributes\Group; |
25 | 26 | use PHPUnit\Framework\TestCase; |
26 | 27 | use Random\RandomException; |
@@ -677,10 +678,12 @@ public function getAuxDataType(): string |
677 | 678 | { |
678 | 679 | return 'test-type'; |
679 | 680 | } |
| 681 | + |
680 | 682 | public function getRejectionReason(): string |
681 | 683 | { |
682 | 684 | return 'Invalid'; |
683 | 685 | } |
| 686 | + |
684 | 687 | public function isValid(string $auxData): bool |
685 | 688 | { |
686 | 689 | return true; |
@@ -749,10 +752,12 @@ public function getAuxDataType(): string |
749 | 752 | { |
750 | 753 | return 'test-type'; |
751 | 754 | } |
| 755 | + |
752 | 756 | public function getRejectionReason(): string |
753 | 757 | { |
754 | 758 | return 'Invalid'; |
755 | 759 | } |
| 760 | + |
756 | 761 | public function isValid(string $auxData): bool |
757 | 762 | { |
758 | 763 | return true; |
@@ -812,10 +817,12 @@ public function getAuxDataType(): string |
812 | 817 | { |
813 | 818 | return 'test-type'; |
814 | 819 | } |
| 820 | + |
815 | 821 | public function getRejectionReason(): string |
816 | 822 | { |
817 | 823 | return 'Invalid'; |
818 | 824 | } |
| 825 | + |
819 | 826 | public function isValid(string $auxData): bool |
820 | 827 | { |
821 | 828 | return true; |
@@ -884,10 +891,12 @@ public function getAuxDataType(): string |
884 | 891 | { |
885 | 892 | return 'wanted-type'; |
886 | 893 | } |
| 894 | + |
887 | 895 | public function getRejectionReason(): string |
888 | 896 | { |
889 | 897 | return 'Invalid'; |
890 | 898 | } |
| 899 | + |
891 | 900 | public function isValid(string $auxData): bool |
892 | 901 | { |
893 | 902 | return true; |
@@ -972,10 +981,12 @@ public function getAuxDataType(): string |
972 | 981 | { |
973 | 982 | return 'test-type'; |
974 | 983 | } |
| 984 | + |
975 | 985 | public function getRejectionReason(): string |
976 | 986 | { |
977 | 987 | return 'Invalid'; |
978 | 988 | } |
| 989 | + |
979 | 990 | public function isValid(string $auxData): bool |
980 | 991 | { |
981 | 992 | return true; |
@@ -1182,7 +1193,7 @@ public function testFetchPublicKeysTreeSizeCoercion(): void |
1182 | 1193 | 'leaf-index' => $proof->index, |
1183 | 1194 | ]], |
1184 | 1195 | 'merkle-root' => $merkleRoot, |
1185 | | - 'tree-size' => (string) $tree->getSize(), |
| 1196 | + 'tree-size' => (string)$tree->getSize(), |
1186 | 1197 | ], |
1187 | 1198 | 'fedi-e2ee:v1/api/actor/get-keys' |
1188 | 1199 | ); |
@@ -1343,10 +1354,12 @@ public function getAuxDataType(): string |
1343 | 1354 | { |
1344 | 1355 | return 'test-type'; |
1345 | 1356 | } |
| 1357 | + |
1346 | 1358 | public function getRejectionReason(): string |
1347 | 1359 | { |
1348 | 1360 | return 'Invalid'; |
1349 | 1361 | } |
| 1362 | + |
1350 | 1363 | public function isValid(string $auxData): bool |
1351 | 1364 | { |
1352 | 1365 | return true; |
@@ -1398,10 +1411,12 @@ public function getAuxDataType(): string |
1398 | 1411 | { |
1399 | 1412 | return 'test-type'; |
1400 | 1413 | } |
| 1414 | + |
1401 | 1415 | public function getRejectionReason(): string |
1402 | 1416 | { |
1403 | 1417 | return 'Invalid'; |
1404 | 1418 | } |
| 1419 | + |
1405 | 1420 | public function isValid(string $auxData): bool |
1406 | 1421 | { |
1407 | 1422 | return true; |
@@ -1454,10 +1469,12 @@ public function getAuxDataType(): string |
1454 | 1469 | { |
1455 | 1470 | return 'test-type'; |
1456 | 1471 | } |
| 1472 | + |
1457 | 1473 | public function getRejectionReason(): string |
1458 | 1474 | { |
1459 | 1475 | return 'Invalid'; |
1460 | 1476 | } |
| 1477 | + |
1461 | 1478 | public function isValid(string $auxData): bool |
1462 | 1479 | { |
1463 | 1480 | return true; |
@@ -1499,7 +1516,7 @@ public function isValid(string $auxData): bool |
1499 | 1516 | 'leaf-index' => $proof->index |
1500 | 1517 | ]], |
1501 | 1518 | 'merkle-root' => $merkleRoot, |
1502 | | - 'tree-size' => (string) $tree->getSize() |
| 1519 | + 'tree-size' => (string)$tree->getSize() |
1503 | 1520 | ], |
1504 | 1521 | 'fedi-e2ee:v1/api/actor/aux-info' |
1505 | 1522 | ); |
@@ -1563,10 +1580,12 @@ public function getAuxDataType(): string |
1563 | 1580 | { |
1564 | 1581 | return 'test-type'; |
1565 | 1582 | } |
| 1583 | + |
1566 | 1584 | public function getRejectionReason(): string |
1567 | 1585 | { |
1568 | 1586 | return 'Invalid'; |
1569 | 1587 | } |
| 1588 | + |
1570 | 1589 | public function isValid(string $auxData): bool |
1571 | 1590 | { |
1572 | 1591 | return true; |
@@ -1602,4 +1621,74 @@ public function isValid(string $auxData): bool |
1602 | 1621 |
|
1603 | 1622 | $client->fetchAuxData('alice@example.com', 'test-type'); |
1604 | 1623 | } |
| 1624 | + |
| 1625 | + public static function hashFunctionProvider(): array |
| 1626 | + { |
| 1627 | + return [ |
| 1628 | + ['blake2b'], |
| 1629 | + ['sha256'], |
| 1630 | + ['sha384'], |
| 1631 | + ['sha512'], |
| 1632 | + ]; |
| 1633 | + } |
| 1634 | + |
| 1635 | + /** |
| 1636 | + * @throws ClientException |
| 1637 | + * @throws CryptoException |
| 1638 | + * @throws NotImplementedException |
| 1639 | + * @throws SodiumException |
| 1640 | + */ |
| 1641 | + #[DataProvider("hashFunctionProvider")] |
| 1642 | + public function testHardCodedHashLengths(string $hashFunc): void |
| 1643 | + { |
| 1644 | + if ($hashFunc === 'blake2b') { |
| 1645 | + $expectedHashLength = 32; |
| 1646 | + } else { |
| 1647 | + $expectedHashLength = strlen(hash($hashFunc, '', true)); |
| 1648 | + } |
| 1649 | + // strlen("pkd-mr-v1:") == 10 |
| 1650 | + $expectedEncodedLength = 10 + (int) ceil($expectedHashLength * 4 / 3); |
| 1651 | + $serverPk = $this->serverKey->getPublicKey(); |
| 1652 | + $client = new ReadOnlyClient('http://pkd.test', $serverPk); |
| 1653 | + |
| 1654 | + // Build a simple tree with known leaves |
| 1655 | + $leaves = ['leaf1', 'leaf2', 'leaf3', 'leaf4']; |
| 1656 | + $tree = new Tree($leaves, $hashFunc); |
| 1657 | + $rawRoot = $tree->getRoot(); |
| 1658 | + $this->assertNotNull($rawRoot); |
| 1659 | + $this->assertSame($expectedHashLength, strlen($rawRoot)); |
| 1660 | + $merkleRoot = $tree->getEncodedRoot(); |
| 1661 | + $this->assertSame($expectedEncodedLength, strlen($merkleRoot)); |
| 1662 | + |
| 1663 | + // We need to actually fail if the code is mutated: |
| 1664 | + $proof = $tree->getInclusionProof('leaf1'); |
| 1665 | + $result = $client->verifyInclusionProof( |
| 1666 | + $hashFunc, |
| 1667 | + $merkleRoot, |
| 1668 | + 'leaf1', |
| 1669 | + $proof, |
| 1670 | + $tree->getSize() |
| 1671 | + ); |
| 1672 | + $this->assertTrue($result, 'Inclusion proof verification failed'); |
| 1673 | + } |
| 1674 | + |
| 1675 | + public static function merkleRootProvider(): array |
| 1676 | + { |
| 1677 | + return [ |
| 1678 | + ['blake2b', 32], |
| 1679 | + ['sha256', 32], |
| 1680 | + ['sha384', 48], |
| 1681 | + ['sha512', 64], |
| 1682 | + ]; |
| 1683 | + } |
| 1684 | + |
| 1685 | + #[DataProvider("merkleRootProvider")] |
| 1686 | + public function testDecodeMerkleRoot(string $hashFunc, int $zeroes): void |
| 1687 | + { |
| 1688 | + $serverPk = $this->serverKey->getPublicKey(); |
| 1689 | + $client = new ReadOnlyClient('http://pkd.test', $serverPk); |
| 1690 | + $encoded = (new Tree([], $hashFunc))->getEncodedRoot(); |
| 1691 | + $out = $client->decodeMerkleRoot($encoded, $hashFunc); |
| 1692 | + $this->assertSame($zeroes, strlen($out)); |
| 1693 | + } |
1605 | 1694 | } |
0 commit comments