Skip to main content

ed448_goldilocks/curve/twedwards/
projective.rs

1#![allow(non_snake_case)]
2
3use super::extensible::ExtensiblePoint;
4use crate::field::FieldElement;
5use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable};
6
7impl Default for ProjectiveNielsPoint {
8    fn default() -> ProjectiveNielsPoint {
9        ProjectiveNielsPoint::IDENTITY
10    }
11}
12
13// Its a variant of Niels, where a Z coordinate is added for unmixed readdition
14// ((y+x)/2, (y-x)/2, dxy, Z)
15#[derive(Copy, Clone, Debug)]
16pub struct ProjectiveNielsPoint {
17    pub(crate) Y_plus_X: FieldElement,
18    pub(crate) Y_minus_X: FieldElement,
19    pub(crate) Td: FieldElement,
20    pub(crate) Z: FieldElement,
21}
22
23impl PartialEq for ProjectiveNielsPoint {
24    fn eq(&self, other: &ProjectiveNielsPoint) -> bool {
25        self.to_extensible().eq(&other.to_extensible())
26    }
27}
28impl Eq for ProjectiveNielsPoint {}
29
30impl ConditionallySelectable for ProjectiveNielsPoint {
31    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
32        ProjectiveNielsPoint {
33            Y_plus_X: FieldElement::conditional_select(&a.Y_plus_X, &b.Y_plus_X, choice),
34            Y_minus_X: FieldElement::conditional_select(&a.Y_minus_X, &b.Y_minus_X, choice),
35            Td: FieldElement::conditional_select(&a.Td, &b.Td, choice),
36            Z: FieldElement::conditional_select(&a.Z, &b.Z, choice),
37        }
38    }
39}
40impl ConditionallyNegatable for ProjectiveNielsPoint {
41    fn conditional_negate(&mut self, choice: Choice) {
42        FieldElement::conditional_swap(&mut self.Y_minus_X, &mut self.Y_plus_X, choice);
43        self.Td.conditional_negate(choice);
44    }
45}
46
47impl ProjectiveNielsPoint {
48    pub const IDENTITY: ProjectiveNielsPoint = ProjectiveNielsPoint {
49        Y_plus_X: FieldElement::ONE,
50        Y_minus_X: FieldElement::ONE,
51        Td: FieldElement::ZERO,
52        Z: FieldElement::TWO,
53    };
54
55    pub fn to_extensible(self) -> ExtensiblePoint {
56        let A = self.Y_plus_X - self.Y_minus_X;
57        let B = self.Y_plus_X + self.Y_minus_X;
58        ExtensiblePoint {
59            X: self.Z * A,
60            Y: self.Z * B,
61            Z: self.Z.square(),
62            T1: B,
63            T2: A,
64        }
65    }
66}
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use crate::curve::twedwards::extended::ExtendedPoint;
71
72    #[test]
73    fn identity() {
74        // Internally are compared by converting to `ExtendedPoint`.
75        // Here the right-side identity point is converted to Niel's
76        // and then both sides are converted to twisted-curve form.
77        assert_eq!(
78            ProjectiveNielsPoint::IDENTITY,
79            ExtendedPoint::IDENTITY.to_projective_niels(),
80        );
81        // Here only the left-side identity point is converted.
82        assert_eq!(
83            ProjectiveNielsPoint::IDENTITY.to_extensible(),
84            ExtendedPoint::IDENTITY,
85        );
86    }
87
88    #[test]
89    fn test_conditional_negate() {
90        let bp = ExtendedPoint::GENERATOR;
91
92        let mut bp_neg = bp.to_projective_niels();
93        bp_neg.conditional_negate(1.into());
94
95        let expect_identity = bp_neg.to_extensible().to_extended().add_extended(&bp);
96        assert_eq!(ExtendedPoint::IDENTITY, expect_identity);
97    }
98}