      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131

    // 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.

    use {bssl, c, error};

    // Keep this in sync with `fe` in curve25519/internal.h.
    pub type Elem = [i32; ELEM_LIMBS];
    const ELEM_LIMBS: usize = 10;

    // 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;

    pub type Scalar = [u8; SCALAR_LEN];
    pub const SCALAR_LEN: usize = 32;

    pub type UnreducedScalar = [u8; UNREDUCED_SCALAR_LEN];
    const UNREDUCED_SCALAR_LEN: usize = SCALAR_LEN * 2;

    // 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 {
            ExtPoint {
                x: [0; ELEM_LIMBS],
                y: [0; ELEM_LIMBS],
                z: [0; ELEM_LIMBS],
                t: [0; ELEM_LIMBS],
            }
        }

        pub fn from_encoded_point_vartime(encoded: &EncodedPoint)
                              -> Result<Self, error::Unspecified> {
            let mut point = Self::new_at_infinity();

            bssl::map_result(unsafe {
                GFp_x25519_ge_frombytes_vartime(&mut point, encoded)
            })?;

            Ok(point)
        }

        pub fn into_encoded_point(self) -> EncodedPoint {
            encode_point(self.x, self.y, self.z)
        }

        pub fn invert_vartime(&mut self) {
            for i in 0..ELEM_LIMBS {
                self.x[i] = -self.x[i];
                self.t[i] = -self.t[i];
            }
        }
    }

    // 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 {
            Point {
                x: [0; ELEM_LIMBS],
                y: [0; ELEM_LIMBS],
                z: [0; ELEM_LIMBS],
            }
        }

        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 recip = [0; ELEM_LIMBS];
        let mut x_over_z = [0; ELEM_LIMBS];
        let mut y_over_z = [0; ELEM_LIMBS];
        let mut bytes = [0; ELEM_LEN];

        let sign_bit: u8 = unsafe {
            GFp_fe_invert(&mut recip, &z);
            GFp_fe_mul(&mut x_over_z, &x, &recip);
            GFp_fe_mul(&mut y_over_z, &y, &recip);
            GFp_fe_tobytes(&mut bytes, &y_over_z);
            GFp_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 {
        fn GFp_fe_invert(out: &mut Elem, z: &Elem);
        fn GFp_fe_isnegative(elem: &Elem) -> u8;
        fn GFp_fe_mul(h: &mut Elem, f: &Elem, g: &Elem);
        fn GFp_fe_tobytes(bytes: &mut EncodedPoint, elem: &Elem);
        fn GFp_x25519_ge_frombytes_vartime(h: &mut ExtPoint, s: &EncodedPoint)
                                           -> c::int;
    }

# Help

## Keyboard Shortcuts

?
  Show this help dialog
S
  Focus the search field
⇤
  Move up in search results
⇥
  Move down in search results
⏎
  Go to active search result
+
  Collapse/expand all sections

## Search Tricks

Prefix searches with a type followed by a colon (e.g. `fn:`) to restrict the search to a given type.

Accepted types are: `fn`, `mod`, `struct`, `enum`, `trait`, `type`, `macro`, and `const`.

Search functions by type signature (e.g. `vec -> usize` or `* -> vec`)