|
27 | 27 | _MAX_RESIDUE_ASSIGNMENTS = 4_096 |
28 | 28 | _MAX_RESIDUE_MODULUS = 1_000_000 |
29 | 29 | _MAX_MATRIX_DIMENSION = 32 |
| 30 | +_MAX_DETERMINANT_MATRIX_DIMENSION = 64 |
30 | 31 | _MAX_MATRIX_INPUT_DIGITS = 256 |
31 | 32 | _MAX_MATRIX_OUTPUT_DIGITS = 32_768 |
32 | 33 |
|
@@ -100,6 +101,18 @@ def _q(value: object) -> fmpq: |
100 | 101 | return fmpq(numerator, denominator) |
101 | 102 |
|
102 | 103 |
|
| 104 | +def _bounded_q(value: object, *, maximum_digits: int) -> fmpq: |
| 105 | + if not isinstance(value, dict) or set(value) != {"num", "den"}: |
| 106 | + raise ValueError("bounded rational is malformed") |
| 107 | + for component in (value["num"], value["den"]): |
| 108 | + if ( |
| 109 | + not isinstance(component, str) |
| 110 | + or len(component.lstrip("-")) > maximum_digits |
| 111 | + ): |
| 112 | + raise ValueError("bounded rational exceeds the checker digit limit") |
| 113 | + return _q(value) |
| 114 | + |
| 115 | + |
103 | 116 | def _polynomial(value: object) -> fmpq_poly: |
104 | 117 | if ( |
105 | 118 | not isinstance(value, dict) |
@@ -213,15 +226,20 @@ def _integer_matrix(value: object) -> fmpz_mat: |
213 | 226 | return fmpz_mat([[_integer(item) for item in row] for row in entries]) |
214 | 227 |
|
215 | 228 |
|
216 | | -def _bounded_rational_matrix(value: object, *, maximum_digits: int) -> fmpq_mat: |
| 229 | +def _bounded_rational_matrix( |
| 230 | + value: object, |
| 231 | + *, |
| 232 | + maximum_digits: int, |
| 233 | + maximum_dimension: int = _MAX_MATRIX_DIMENSION, |
| 234 | +) -> fmpq_mat: |
217 | 235 | if not isinstance(value, dict): |
218 | 236 | raise ValueError("rational matrix is malformed") |
219 | 237 | entries = value.get("entries") |
220 | 238 | if ( |
221 | 239 | not isinstance(entries, list) |
222 | | - or not 1 <= len(entries) <= _MAX_MATRIX_DIMENSION |
| 240 | + or not 1 <= len(entries) <= maximum_dimension |
223 | 241 | or not isinstance(entries[0], list) |
224 | | - or not 1 <= len(entries[0]) <= _MAX_MATRIX_DIMENSION |
| 242 | + or not 1 <= len(entries[0]) <= maximum_dimension |
225 | 243 | ): |
226 | 244 | raise ValueError("rational matrix exceeds the checker dimension bound") |
227 | 245 | for row in entries: |
@@ -1008,10 +1026,19 @@ def _matrix_determinant(source: dict[str, Any], result: dict[str, Any]) -> bool: |
1008 | 1026 | "FRACTION_FREE_BAREISS" |
1009 | 1027 | ): |
1010 | 1028 | return False |
1011 | | - matrix = _matrix_source(source) |
| 1029 | + if set(source) != {"matrix"}: |
| 1030 | + return False |
| 1031 | + matrix = _bounded_rational_matrix( |
| 1032 | + source["matrix"], |
| 1033 | + maximum_digits=_MAX_MATRIX_INPUT_DIGITS, |
| 1034 | + maximum_dimension=_MAX_DETERMINANT_MATRIX_DIMENSION, |
| 1035 | + ) |
1012 | 1036 | if matrix.nrows() != matrix.ncols(): |
1013 | 1037 | return False |
1014 | | - return bool(_q(result["determinant"]) == matrix.det()) |
| 1038 | + declared = _bounded_q( |
| 1039 | + result["determinant"], maximum_digits=_MAX_MATRIX_OUTPUT_DIGITS |
| 1040 | + ) |
| 1041 | + return bool(declared == matrix.det()) |
1015 | 1042 |
|
1016 | 1043 |
|
1017 | 1044 | def check_matrix_determinant(request: dict[str, Any]) -> dict[str, Any]: |
|
0 commit comments