// Copyright 2015-2017 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. //! Elliptic curve operations on the birationally equivalent curves Curve25519 //! and Edwards25519. pub use super::scalar::{MaskedScalar, Scalar, SCALAR_LEN}; use crate::{ bssl, error, limb::{Limb, LIMB_BITS}, }; use core::marker::PhantomData; // Elem` is `fe` in curve25519/internal.h. // Elem is `fe_loose` in curve25519/internal.h. // Keep this in sync with curve25519/internal.h. #[repr(C)] pub struct Elem { limbs: [Limb; ELEM_LIMBS], // This is called `v` in the C code. encoding: PhantomData, } pub trait Encoding {} pub struct T; impl Encoding for T {} const ELEM_LIMBS: usize = 5 * 64 / LIMB_BITS; impl Elem { fn zero() -> Self { Self { limbs: Default::default(), encoding: PhantomData, } } } impl Elem { fn negate(&mut self) { unsafe { GFp_x25519_fe_neg(self); } } } // An encoding of a curve point. If on Curve25519, it should be encoded as // described in Section 5 of [RFC 7748]. If on Edwards25519, it should be // encoded as described in section 5.1.2 of [RFC 8032]. // // [RFC 7748] https://tools.ietf.org/html/rfc7748#section-5 // [RFC 8032] https://tools.ietf.org/html/rfc8032#section-5.1.2 pub type EncodedPoint = [u8; ELEM_LEN]; pub const ELEM_LEN: usize = 32; // Keep this in sync with `ge_p3` in curve25519/internal.h. #[repr(C)] pub struct ExtPoint { x: Elem, y: Elem, z: Elem, t: Elem, } impl ExtPoint { pub fn new_at_infinity() -> Self { Self { x: Elem::zero(), y: Elem::zero(), z: Elem::zero(), t: Elem::zero(), } } pub fn from_encoded_point_vartime(encoded: &EncodedPoint) -> Result { let mut point = Self::new_at_infinity(); Result::from(unsafe { GFp_x25519_ge_frombytes_vartime(&mut point, encoded) }) .map(|()| point) } pub fn into_encoded_point(self) -> EncodedPoint { encode_point(self.x, self.y, self.z) } pub fn invert_vartime(&mut self) { self.x.negate(); self.t.negate(); } } // Keep this in sync with `ge_p2` in curve25519/internal.h. #[repr(C)] pub struct Point { x: Elem, y: Elem, z: Elem, } impl Point { pub fn new_at_infinity() -> Self { Self { x: Elem::zero(), y: Elem::zero(), z: Elem::zero(), } } pub fn into_encoded_point(self) -> EncodedPoint { encode_point(self.x, self.y, self.z) } } fn encode_point(x: Elem, y: Elem, z: Elem) -> EncodedPoint { let mut bytes = [0; ELEM_LEN]; let sign_bit: u8 = unsafe { let mut recip = Elem::zero(); GFp_x25519_fe_invert(&mut recip, &z); let mut x_over_z = Elem::zero(); GFp_x25519_fe_mul_ttt(&mut x_over_z, &x, &recip); let mut y_over_z = Elem::zero(); GFp_x25519_fe_mul_ttt(&mut y_over_z, &y, &recip); GFp_x25519_fe_tobytes(&mut bytes, &y_over_z); GFp_x25519_fe_isnegative(&x_over_z) }; // The preceding computations must execute in constant time, but this // doesn't need to. bytes[ELEM_LEN - 1] ^= sign_bit << 7; bytes } extern "C" { fn GFp_x25519_fe_invert(out: &mut Elem, z: &Elem); fn GFp_x25519_fe_isnegative(elem: &Elem) -> u8; fn GFp_x25519_fe_mul_ttt(h: &mut Elem, f: &Elem, g: &Elem); fn GFp_x25519_fe_neg(f: &mut Elem); fn GFp_x25519_fe_tobytes(bytes: &mut EncodedPoint, elem: &Elem); fn GFp_x25519_ge_frombytes_vartime(h: &mut ExtPoint, s: &EncodedPoint) -> bssl::Result; }