Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 69 additions & 30 deletions libs/math/docs/polynomial_recovery.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@

@tableofcontents

Crypto3.Math provides two complementary recovery primitives:
Crypto3.Math provides three complementary recovery facilities:

* square testing and square roots in a finite polynomial quotient field; and
* bounded rational reconstruction from a residue modulo a polynomial.
* square testing and square roots in a finite polynomial quotient field;
* bounded rational reconstruction from a residue modulo a polynomial; and
* recovery of the fixed `X`-norm representation of an irreducible polynomial.

Together they can recover representations of irreducible factors by the polynomial norm form

P(X)^2 - X * Q(X)^2.

The library exposes the generic arithmetic operations. Applications remain responsible for selecting factors, degree
bounds, random sources, and any policy for combining or rejecting recovered representations.
The recovery operation owns the degree bounds and exact normalization for this norm equation. The caller supplies the
polynomial arithmetic context and the coefficient-field generator.

### Header map

Expand All @@ -22,6 +23,7 @@ bounds, random sources, and any policy for combining or rejecting recovered repr
| Coefficient-field square-root helpers | `<nil/crypto3/algebra/fields/field_algorithms.hpp>` |
| Quotient-field square testing and roots | `<nil/crypto3/math/polynomial/quotient_ring/polynomial_square_root.hpp>` |
| Bounded rational reconstruction | `<nil/crypto3/math/polynomial/reconstruction/polynomial_rational_reconstruction.hpp>` |
| `X`-norm reconstruction | `<nil/crypto3/math/polynomial/reconstruction/polynomial_x_norm_reconstruction.hpp>` |

## Field orders and coefficient square roots

Expand Down Expand Up @@ -64,9 +66,9 @@ characterize squares if the quotient has zero divisors.

`square_root_mod` uses Tonelli-Shanks in `K[X]/(B)`. Repeated calls should share two immutable precomputations:

1. `polynomial_divisor_context<Backend>` caches the divisor and the inverse needed for modular reduction.
2. `polynomial_square_root_context<Backend>` caches the decomposition
`order(K)^d - 1 = odd_order * 2^two_adicity` and a suitable quadratic nonresidue raised to `odd_order`.
* `polynomial_divisor_context<Backend>` caches the divisor and the inverse needed for modular reduction.
* `polynomial_square_root_context<Backend>` caches the decomposition
`order(K)^d - 1 = odd_order * 2^two_adicity` and a suitable quadratic nonresidue raised to `odd_order`.

```cpp
#include <algorithm>
Expand Down Expand Up @@ -146,34 +148,71 @@ reconstructs with bounds `degree(P) <= 0` and `degree(Q) <= 2` as
P = 1,
Q = 2 + 2X + X^2.

## Recovering a polynomial norm representation
## `X`-norm reconstruction

The square-root and reconstruction APIs fit together as follows. For one irreducible factor `B` of degree `d`:
`recover_irreducible_polynomial_x_norm_representation` composes quotient-field square roots, bounded rational
reconstruction, and coefficient-field normalization to recover polynomials `P` and `Q` satisfying

1. Represent the indeterminate by `x = {0, 1}` and test whether it is a square modulo `B`.
2. If it is square, compute `R` such that `R^2 = X mod B`.
3. Rationally reconstruct `R` with
P^2 - X * Q^2 = g.

maximum_numerator_degree = floor(d / 2),
maximum_denominator_degree = floor((d - 1) / 2).
The name explicitly identifies `X` as the quadratic element: the represented element is `P + Q * sqrt(X)`, whose norm
is `P^2 - X * Q^2`. The input `g` must be a canonical nonconstant irreducible polynomial. Irreducibility is a caller
precondition and is not tested.

This produces `P = R * Q mod B`.
4. Squaring the congruence gives
```cpp
#include <nil/crypto3/math/polynomial/reconstruction/polynomial_x_norm_reconstruction.hpp>

// arithmetic_context and coefficient_generator are caller-owned.
auto representation = math::recover_irreducible_polynomial_x_norm_representation<backend_type>(
g, arithmetic_context, coefficient_generator);

if (representation) {
polynomial_type exact_norm = math::evaluate_polynomial_x_norm<backend_type>(
*representation, arithmetic_context);
// exact_norm == g
}
```

The coefficient generator returns coefficient-field values. The recovery operation adapts those values into canonical
degree-below-`degree(g)` representatives of `K[X]/(g)`. The generator remains caller-owned and must eventually supply
coefficients forming a quotient-field nonsquare.

On success, the optional contains `polynomial_x_norm_representation<polynomial_type>`. Its `p` and `q` members hold the
two recovered coefficient polynomials.

P^2 - X * Q^2 = 0 mod B.
The function reduces `{0, 1}` modulo `g`, including when `g` is linear, and recovers `R` with `R^2 = X mod g`. It then
reconstructs `P = R * Q mod g` with

The degree bounds make the left side have degree at most `d`, so it is a scalar multiple of `B`.
degree(P) <= floor(degree(g) / 2),
degree(Q) <= floor((degree(g) - 1) / 2).

This is the local representation of `B` by the norm from adjoining a square root of `X`. Representations compose
multiplicatively:
These bounds imply

P^2 - X * Q^2 = lambda * g

for a coefficient-field scalar `lambda`. A nonzero square `lambda` is removed by scaling both outputs by
`sqrt(lambda^-1)`. The normalized norm is evaluated again and compared exactly with `g` before success is returned.
Both polynomial squares use the caller's arithmetic context; multiplication by `X` is a coefficient shift.

| Outcome | Contract |
|---|---|
| Representation returned | The degree bounds hold and `evaluate_polynomial_x_norm(result, context) == g`. |
| No value returned | `X` is nonsquare modulo `g`, bounded reconstruction fails, or `lambda` is zero or nonsquare. |
| `std::invalid_argument` | The input is empty, noncanonical, zero, or constant, or a composed API contract is violated. |
| `std::logic_error` | An operation reported success but a required modular, scalar-multiple, or final exact identity is inconsistent. |

This is the local representation of `g` by the norm from adjoining a square root of `X`.
`multiply_polynomial_x_norm_representations(left, right, context)` composes two representations using

(P1^2 - X Q1^2) * (P2^2 - X Q2^2)
= (P1 P2 + X Q1 Q2)^2 - X * (P1 Q2 + P2 Q1)^2.

All four polynomial products use the supplied arithmetic context, while multiplication by `X` is a coefficient shift.

Consequently, a caller can factor a target polynomial, recover eligible irreducible factors independently, account for
multiplicities and the scalar leading coefficient, and combine the local representations. Crypto3.Math deliberately
keeps that application-level policy separate from the generic factorization, quotient-field square-root, and bounded
rational-reconstruction primitives.
keeps that application-level policy separate from the generic factorization, quotient-field square-root, bounded
rational-reconstruction, and `X`-norm reconstruction facilities.

### Worked example over F7

Expand Down Expand Up @@ -211,16 +250,16 @@ Then the scalar is corrected exactly:

P'^2 - X Q'^2 = H.

This example performs the same local steps required for a higher-degree factor: factor, test whether `X` is square in
the quotient, compute its root, reconstruct bounded `P` and `Q`, and normalize the remaining coefficient-field
scalar. Combining several eligible factors then uses the multiplicative identity above.
The recovery API performs this square test, quotient-field square root, bounded reconstruction, scalar normalization,
and final exact verification using the supplied polynomial context and coefficient generator. Combining several
eligible factors then uses the multiplicative identity above.

## Reuse and performance

The [polynomial arithmetic infrastructure](@ref math_polynomial_arithmetic) describes these contexts in detail. Reuse
one polynomial arithmetic context throughout a recovery, one divisor context for every operation modulo the same `B`,
and one square-root context for repeated roots modulo that divisor. This avoids rebuilding divisor inverses,
multiplicative-group decompositions, nonresidue powers, backend plans, and scratch storage.
The [polynomial arithmetic infrastructure](@ref math_polynomial_arithmetic) describes these contexts in detail. The
recovery API reuses the caller's polynomial arithmetic context throughout recovery. It constructs one divisor context
and one square-root context and reuses them for all operations within that call. Direct users of the lower-level APIs
can retain those contexts across repeated operations modulo the same divisor.

Let `Q` be the coefficient-field order, `d` the irreducible divisor degree, and `s` the two-adicity of `Q^d - 1`.
The current implementations have the rough bounds shown below.
Expand Down
Loading
Loading