|
| 1 | +use crate::ProjectiveMontgomeryXpoint; |
| 2 | +use crate::field::{ConstMontyType, FieldElement}; |
| 3 | +use core::borrow::Borrow; |
| 4 | +use core::iter::Sum; |
| 5 | +use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; |
| 6 | +use elliptic_curve::bigint::U448; |
| 7 | + |
| 8 | +use super::{MontgomeryPoint, MontgomeryScalar, MontgomeryXpoint, ProjectiveMontgomeryPoint}; |
| 9 | + |
| 10 | +impl Add<&ProjectiveMontgomeryPoint> for &ProjectiveMontgomeryPoint { |
| 11 | + type Output = ProjectiveMontgomeryPoint; |
| 12 | + |
| 13 | + // See Complete Addition Law for Montgomery Curves - Algorithm 1. |
| 14 | + // With "Trade-Off Technique". |
| 15 | + fn add(self, rhs: &ProjectiveMontgomeryPoint) -> Self::Output { |
| 16 | + let (x1, y1, z1) = (self.U, self.V, self.W); |
| 17 | + let (x2, y2, z2) = (rhs.U, rhs.V, rhs.W); |
| 18 | + |
| 19 | + let t0 = x1 * x2; |
| 20 | + let t1 = y1 * y2; |
| 21 | + let t2 = z1 * z2; |
| 22 | + let t3 = x1 * y2; |
| 23 | + let t4 = x2 * y1; |
| 24 | + let t5 = y1 * z2; |
| 25 | + let t6 = y2 * z1; |
| 26 | + let t7 = x1 * z2; |
| 27 | + let t8 = x2 * z1; |
| 28 | + let t9 = t7 + t8; |
| 29 | + let t10 = t9 + FieldElement::J * t0; |
| 30 | + let R = t5 + t6; |
| 31 | + let T = t10 - t1; |
| 32 | + let V = FieldElement::J * t9 + t0.triple() + t2; |
| 33 | + let S = (t3 - t4).triple() + t0 - t2; |
| 34 | + let U = (t7 - t8).triple() - t3 - t4; |
| 35 | + let W = (t5 - t6).triple() + t10 + t1; |
| 36 | + let C = (R + T) * (S - U); |
| 37 | + let D = (R - T) * (S + U); |
| 38 | + let E = (T + V) * (W - S); |
| 39 | + let F = (T - V) * (W + S); |
| 40 | + let X = C + D; |
| 41 | + let Y = E + F; |
| 42 | + let Z = (U - W).double() * (R + V) + C - D + E - F; |
| 43 | + |
| 44 | + ProjectiveMontgomeryPoint { U: X, V: Y, W: Z } |
| 45 | + } |
| 46 | +} |
| 47 | + |
| 48 | +define_add_variants!( |
| 49 | + LHS = ProjectiveMontgomeryPoint, |
| 50 | + RHS = ProjectiveMontgomeryPoint, |
| 51 | + Output = ProjectiveMontgomeryPoint |
| 52 | +); |
| 53 | + |
| 54 | +impl Add<&MontgomeryPoint> for &ProjectiveMontgomeryPoint { |
| 55 | + type Output = ProjectiveMontgomeryPoint; |
| 56 | + |
| 57 | + // See Complete Addition Law for Montgomery Curves - Algorithm 2. |
| 58 | + // With "Trade-Off Technique". |
| 59 | + fn add(self, rhs: &MontgomeryPoint) -> ProjectiveMontgomeryPoint { |
| 60 | + let (x1, y1, z1) = (self.U, self.V, self.W); |
| 61 | + let (x2, y2) = (rhs.x, rhs.y); |
| 62 | + |
| 63 | + let t0 = x1 * x2; |
| 64 | + let t1 = y1 * y2; |
| 65 | + let t2 = z1; |
| 66 | + let t3 = x1 * y2; |
| 67 | + let t4 = x2 * y1; |
| 68 | + let t5 = y1; |
| 69 | + let t6 = y2 * z1; |
| 70 | + let t7 = x1; |
| 71 | + let t8 = x2 * z1; |
| 72 | + let t9 = t7 + t8; |
| 73 | + let t10 = t9 + FieldElement::J * t0; |
| 74 | + let R = t5 + t6; |
| 75 | + let T = t10 - t1; |
| 76 | + let V = FieldElement::J * t9 + t0.triple() + t2; |
| 77 | + let S = (t3 - t4).triple() + t0 - t2; |
| 78 | + let U = (t7 - t8).triple() - t3 - t4; |
| 79 | + let W = (t5 - t6).triple() + t10 + t1; |
| 80 | + let C = (R + T) * (S - U); |
| 81 | + let D = (R - T) * (S + U); |
| 82 | + let E = (T + V) * (W - S); |
| 83 | + let F = (T - V) * (W + S); |
| 84 | + let X = C + D; |
| 85 | + let Y = E + F; |
| 86 | + let Z = (U - W).double() * (R + V) + C - D + E - F; |
| 87 | + |
| 88 | + ProjectiveMontgomeryPoint { U: X, V: Y, W: Z } |
| 89 | + } |
| 90 | +} |
| 91 | + |
| 92 | +define_add_variants!( |
| 93 | + LHS = ProjectiveMontgomeryPoint, |
| 94 | + RHS = MontgomeryPoint, |
| 95 | + Output = ProjectiveMontgomeryPoint |
| 96 | +); |
| 97 | + |
| 98 | +impl Add<&ProjectiveMontgomeryPoint> for &MontgomeryPoint { |
| 99 | + type Output = ProjectiveMontgomeryPoint; |
| 100 | + |
| 101 | + fn add(self, other: &ProjectiveMontgomeryPoint) -> ProjectiveMontgomeryPoint { |
| 102 | + other + self |
| 103 | + } |
| 104 | +} |
| 105 | + |
| 106 | +define_add_variants!( |
| 107 | + LHS = MontgomeryPoint, |
| 108 | + RHS = ProjectiveMontgomeryPoint, |
| 109 | + Output = ProjectiveMontgomeryPoint |
| 110 | +); |
| 111 | + |
| 112 | +impl<'b> AddAssign<&'b ProjectiveMontgomeryPoint> for ProjectiveMontgomeryPoint { |
| 113 | + fn add_assign(&mut self, rhs: &'b Self) { |
| 114 | + *self = *self + rhs; |
| 115 | + } |
| 116 | +} |
| 117 | + |
| 118 | +define_add_assign_variants!( |
| 119 | + LHS = ProjectiveMontgomeryPoint, |
| 120 | + RHS = ProjectiveMontgomeryPoint |
| 121 | +); |
| 122 | + |
| 123 | +impl AddAssign<&MontgomeryPoint> for ProjectiveMontgomeryPoint { |
| 124 | + fn add_assign(&mut self, rhs: &MontgomeryPoint) { |
| 125 | + *self += Self::from(*rhs); |
| 126 | + } |
| 127 | +} |
| 128 | + |
| 129 | +define_add_assign_variants!(LHS = ProjectiveMontgomeryPoint, RHS = MontgomeryPoint); |
| 130 | + |
| 131 | +impl AddAssign<&ProjectiveMontgomeryPoint> for MontgomeryPoint { |
| 132 | + fn add_assign(&mut self, rhs: &ProjectiveMontgomeryPoint) { |
| 133 | + *self = (ProjectiveMontgomeryPoint::from(*self) + rhs).into(); |
| 134 | + } |
| 135 | +} |
| 136 | + |
| 137 | +define_add_assign_variants!(LHS = MontgomeryPoint, RHS = ProjectiveMontgomeryPoint); |
| 138 | + |
| 139 | +impl Mul<&MontgomeryScalar> for &ProjectiveMontgomeryPoint { |
| 140 | + type Output = ProjectiveMontgomeryPoint; |
| 141 | + |
| 142 | + #[inline] |
| 143 | + fn mul(self, scalar: &MontgomeryScalar) -> ProjectiveMontgomeryPoint { |
| 144 | + MontgomeryPoint::from(self) * scalar |
| 145 | + } |
| 146 | +} |
| 147 | + |
| 148 | +define_mul_variants!( |
| 149 | + LHS = ProjectiveMontgomeryPoint, |
| 150 | + RHS = MontgomeryScalar, |
| 151 | + Output = ProjectiveMontgomeryPoint |
| 152 | +); |
| 153 | + |
| 154 | +impl Mul<&MontgomeryScalar> for &MontgomeryPoint { |
| 155 | + type Output = ProjectiveMontgomeryPoint; |
| 156 | + |
| 157 | + // Montgomery curves and their arithmetic - Algorithm 6 |
| 158 | + // https://eprint.iacr.org/2017/212.pdf |
| 159 | + fn mul(self, rhs: &MontgomeryScalar) -> ProjectiveMontgomeryPoint { |
| 160 | + pub const A2: FieldElement = FieldElement(ConstMontyType::new(&U448::from_u64(312652))); |
| 161 | + |
| 162 | + let MontgomeryPoint { x: xP, y: yP } = self; |
| 163 | + let ( |
| 164 | + ProjectiveMontgomeryXpoint { U: xQ, W: zQ }, |
| 165 | + ProjectiveMontgomeryXpoint { U: xD, W: zD }, |
| 166 | + ) = MontgomeryXpoint::from(self).mul_internal(rhs); |
| 167 | + |
| 168 | + let v1 = xP * zQ; |
| 169 | + let v2 = xQ + v1; |
| 170 | + let v3 = xQ - v1; |
| 171 | + let v3 = v3.square(); |
| 172 | + let v3 = v3 * xD; |
| 173 | + let v1 = A2 * zQ; |
| 174 | + let v2 = v2 + v1; |
| 175 | + let v4 = xP * xQ; |
| 176 | + let v4 = v4 + zQ; |
| 177 | + let v2 = v2 * v4; |
| 178 | + let v1 = v1 * zQ; |
| 179 | + let v2 = v2 - v1; |
| 180 | + let v2 = v2 * zD; |
| 181 | + let y = v2 - v3; |
| 182 | + let v1 = FieldElement::TWO * yP; |
| 183 | + let v1 = v1 * zQ; |
| 184 | + let v1 = v1 * zD; |
| 185 | + let x = v1 * xQ; |
| 186 | + let z = v1 * zQ; |
| 187 | + |
| 188 | + ProjectiveMontgomeryPoint { U: x, V: y, W: z } |
| 189 | + } |
| 190 | +} |
| 191 | + |
| 192 | +define_mul_variants!( |
| 193 | + LHS = MontgomeryPoint, |
| 194 | + RHS = MontgomeryScalar, |
| 195 | + Output = ProjectiveMontgomeryPoint |
| 196 | +); |
| 197 | + |
| 198 | +impl<'b> MulAssign<&'b MontgomeryScalar> for ProjectiveMontgomeryPoint { |
| 199 | + fn mul_assign(&mut self, scalar: &'b MontgomeryScalar) { |
| 200 | + let result = *self * scalar; |
| 201 | + *self = result; |
| 202 | + } |
| 203 | +} |
| 204 | + |
| 205 | +define_mul_assign_variants!(LHS = ProjectiveMontgomeryPoint, RHS = MontgomeryScalar); |
| 206 | + |
| 207 | +impl Neg for &ProjectiveMontgomeryPoint { |
| 208 | + type Output = ProjectiveMontgomeryPoint; |
| 209 | + |
| 210 | + fn neg(self) -> ProjectiveMontgomeryPoint { |
| 211 | + ProjectiveMontgomeryPoint { |
| 212 | + U: self.U, |
| 213 | + V: -self.V, |
| 214 | + W: self.W, |
| 215 | + } |
| 216 | + } |
| 217 | +} |
| 218 | + |
| 219 | +impl Neg for ProjectiveMontgomeryPoint { |
| 220 | + type Output = Self; |
| 221 | + |
| 222 | + fn neg(self) -> Self { |
| 223 | + -&self |
| 224 | + } |
| 225 | +} |
| 226 | + |
| 227 | +impl Sub<&ProjectiveMontgomeryPoint> for &ProjectiveMontgomeryPoint { |
| 228 | + type Output = ProjectiveMontgomeryPoint; |
| 229 | + |
| 230 | + fn sub(self, other: &ProjectiveMontgomeryPoint) -> ProjectiveMontgomeryPoint { |
| 231 | + self.add(&other.neg()) |
| 232 | + } |
| 233 | +} |
| 234 | + |
| 235 | +define_sub_variants!( |
| 236 | + LHS = ProjectiveMontgomeryPoint, |
| 237 | + RHS = ProjectiveMontgomeryPoint, |
| 238 | + Output = ProjectiveMontgomeryPoint |
| 239 | +); |
| 240 | + |
| 241 | +impl Sub<&MontgomeryPoint> for &ProjectiveMontgomeryPoint { |
| 242 | + type Output = ProjectiveMontgomeryPoint; |
| 243 | + |
| 244 | + fn sub(self, other: &MontgomeryPoint) -> ProjectiveMontgomeryPoint { |
| 245 | + *self - ProjectiveMontgomeryPoint::from(*other) |
| 246 | + } |
| 247 | +} |
| 248 | + |
| 249 | +define_sub_variants!( |
| 250 | + LHS = ProjectiveMontgomeryPoint, |
| 251 | + RHS = MontgomeryPoint, |
| 252 | + Output = ProjectiveMontgomeryPoint |
| 253 | +); |
| 254 | + |
| 255 | +impl Sub<&ProjectiveMontgomeryPoint> for &MontgomeryPoint { |
| 256 | + type Output = ProjectiveMontgomeryPoint; |
| 257 | + |
| 258 | + fn sub(self, other: &ProjectiveMontgomeryPoint) -> ProjectiveMontgomeryPoint { |
| 259 | + *self - other |
| 260 | + } |
| 261 | +} |
| 262 | + |
| 263 | +define_sub_variants!( |
| 264 | + LHS = MontgomeryPoint, |
| 265 | + RHS = ProjectiveMontgomeryPoint, |
| 266 | + Output = ProjectiveMontgomeryPoint |
| 267 | +); |
| 268 | + |
| 269 | +impl<'b> SubAssign<&'b Self> for ProjectiveMontgomeryPoint { |
| 270 | + fn sub_assign(&mut self, _rhs: &'b Self) { |
| 271 | + *self = *self - _rhs; |
| 272 | + } |
| 273 | +} |
| 274 | + |
| 275 | +define_sub_assign_variants!( |
| 276 | + LHS = ProjectiveMontgomeryPoint, |
| 277 | + RHS = ProjectiveMontgomeryPoint |
| 278 | +); |
| 279 | + |
| 280 | +impl SubAssign<&MontgomeryPoint> for ProjectiveMontgomeryPoint { |
| 281 | + fn sub_assign(&mut self, rhs: &MontgomeryPoint) { |
| 282 | + *self -= ProjectiveMontgomeryPoint::from(*rhs); |
| 283 | + } |
| 284 | +} |
| 285 | + |
| 286 | +define_sub_assign_variants!(LHS = ProjectiveMontgomeryPoint, RHS = MontgomeryPoint); |
| 287 | + |
| 288 | +impl SubAssign<&ProjectiveMontgomeryPoint> for MontgomeryPoint { |
| 289 | + fn sub_assign(&mut self, rhs: &ProjectiveMontgomeryPoint) { |
| 290 | + *self = (ProjectiveMontgomeryPoint::from(*self) - rhs).into(); |
| 291 | + } |
| 292 | +} |
| 293 | + |
| 294 | +define_sub_assign_variants!(LHS = MontgomeryPoint, RHS = ProjectiveMontgomeryPoint); |
| 295 | + |
| 296 | +impl<T> Sum<T> for ProjectiveMontgomeryPoint |
| 297 | +where |
| 298 | + T: Borrow<Self>, |
| 299 | +{ |
| 300 | + fn sum<I>(iter: I) -> Self |
| 301 | + where |
| 302 | + I: Iterator<Item = T>, |
| 303 | + { |
| 304 | + iter.fold(Self::IDENTITY, |acc, item| acc + item.borrow()) |
| 305 | + } |
| 306 | +} |
| 307 | + |
| 308 | +#[cfg(test)] |
| 309 | +mod test { |
| 310 | + use elliptic_curve::Field; |
| 311 | + use rand_core::OsRng; |
| 312 | + |
| 313 | + use super::*; |
| 314 | + |
| 315 | + #[test] |
| 316 | + fn mixed_addition() { |
| 317 | + let p1 = ProjectiveMontgomeryPoint::GENERATOR |
| 318 | + * MontgomeryScalar::try_from_rng(&mut OsRng).unwrap(); |
| 319 | + let p2 = ProjectiveMontgomeryPoint::GENERATOR |
| 320 | + * MontgomeryScalar::try_from_rng(&mut OsRng).unwrap(); |
| 321 | + let p3 = p1 + p2; |
| 322 | + |
| 323 | + assert_eq!( |
| 324 | + MontgomeryPoint::from(p3), |
| 325 | + (MontgomeryPoint::from(p1) + p2).into() |
| 326 | + ); |
| 327 | + } |
| 328 | +} |
0 commit comments