> For the complete documentation index, see [llms.txt](https://thias-organization.gitbook.io/p256-documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://thias-organization.gitbook.io/p256-documentation/risc-zero-k256-accelerator/affine-and-projective-points.md).

# Affine and Projective Points

## Affine Points

The $$(x, y)$$ points that we are all familiar with are called "affine points".

## Projective Points

Points in the projective space have 3 coordinates instead $$(x, y, z)$$. They are also known as "Jacobian" coordinates.

## Conversion

Converting from affine to projective involves choosing any $$z$$, such that $$(xz^2, yz^3, z) \leftarrow (x, y) ∶ z \in ℕ$$. So long as $$z$$ is not zero, then any value will do, but by convention $$z$$ is normally chosen as 1, as this just makes calculations easier.

Converting from projective back to affine is the inverse

$$
\left( \frac{x}{z^2}, \frac{y}{z^3} \right) \leftarrow (x, y, z)
$$

## Relevance

So why do we want to convert affine to projective points?

If you recall the [basic implementation of ECDSA](/p256-documentation/elliptic-curve-digital-signature-algorithm-ecdsa.md), the calculation of `inv_mod` (which needs modular division) is actually very complex and when dealing with large numbers such as those in ECC, it becomes a very expensive operation. Similarly, in RustCrypto's ECDSA library this operation will also be very expensive.

We can eliminate the need for this computation by swapping the division operation for a dozen more multiplication operations and just one division at the end. This is achieved using projective coordinates.

However, how this actually works will not be covered here.

## Complete Projective Addition

An elliptic curve addition law is said to be complete if it correctly computes the sum of any two points in the elliptic curve group.

`projective.rs` consists of operations like `add`, `add_mixed` and `double` that performs point arithmetic on projective points. The current implementations are based on optimised formulas found in this [paper](https://eprint.iacr.org/2015/1060.pdf).

What RISC Zero did was to condense some of these internal operations using specifically defined operations inside of `FieldElementImpl` when it comes to the ZKVM architecture.

For example, the initial `add` function implements Algorithm 7 from the [paper](https://eprint.iacr.org/2015/1060.pdf). If we look at step 21

$$
\begin{align\*}
t\_2 &\leftarrow b\_3 \cdot t\_2\\
\end{align\*}
$$

where $$t\_2 = Z\_1 \cdot Z\_2$$ , $$b\_3 = 3 \cdot b$$ and $$b$$ is the constant of the elliptic curve.&#x20;

This is the original implementation of calculating $$t\_2$$:

```rust
let bzz = zz.mul_single(CURVE_EQUATION_B_SINGLE);
let bzz3 = (bzz.double() + &bzz).normalize_weak();
```

The first line essentially calculates $$b \cdot (Z\_1 \cdot Z\_2) = b \cdot t\_2$$ and the second line calculates $$2 \cdot (b \cdot t\_2) + b \cdot t\_2 = 3 \cdot (b \cdot t\_2 ) = b\_3 \cdot  t\_2$$. The optimised version uses small multiplications instead of repeated additions by doing

```rust
if cfg!(all(target_os = "zkvm", target_arch = "riscv32")) {
    // Same as below, but using mul_single instead of repeated addition to get small
    // multiplications and normalize_weak is removed.
    let bzz3 = zz.mul_single(CURVE_EQUATION_B_SINGLE * 3);
    // ...
```

And this replacement/ optimisation can be seen throughout `add`, `add_mixed` and `double`.

*Note that because* $$a = 0$$ *for the k256 curve, we can use algorithm 7, 8 and 9 respectively for `add`, `add_mixed` and `double`. For general elliptic curves, algorithm 1, 2 and 3 are used.*
