ring/ec/curve25519/
ops.rs
1pub use super::scalar::{MaskedScalar, Scalar, SCALAR_LEN};
19use crate::{
20 bssl, c, cpu, error,
21 limb::{Limb, LIMB_BITS},
22};
23use core::marker::PhantomData;
24
25#[repr(C)]
29pub struct Elem<E: Encoding> {
30 limbs: [Limb; ELEM_LIMBS], encoding: PhantomData<E>,
32}
33
34pub trait Encoding {}
35pub struct T;
36impl Encoding for T {}
37
38const ELEM_LIMBS: usize = 5 * 64 / LIMB_BITS;
39
40impl<E: Encoding> Elem<E> {
41 fn zero() -> Self {
42 Self {
43 limbs: Default::default(),
44 encoding: PhantomData,
45 }
46 }
47}
48
49impl Elem<T> {
50 fn negate(&mut self) {
51 unsafe {
52 x25519_fe_neg(self);
53 }
54 }
55}
56
57pub type EncodedPoint = [u8; ELEM_LEN];
64pub const ELEM_LEN: usize = 32;
65
66#[repr(C)]
68pub struct ExtPoint {
69 x: Elem<T>,
70 y: Elem<T>,
71 z: Elem<T>,
72 t: Elem<T>,
73}
74
75impl ExtPoint {
76 pub(super) fn from_scalarmult_base_consttime(scalar: &Scalar, cpu: cpu::Features) -> Self {
78 let mut r = Self {
79 x: Elem::zero(),
80 y: Elem::zero(),
81 z: Elem::zero(),
82 t: Elem::zero(),
83 };
84 prefixed_extern! {
85 fn x25519_ge_scalarmult_base(h: &mut ExtPoint, a: &Scalar, has_fe25519_adx: c::int);
86 }
87 unsafe {
88 x25519_ge_scalarmult_base(&mut r, scalar, has_fe25519_adx(cpu).into());
89 }
90 r
91 }
92
93 pub fn from_encoded_point_vartime(encoded: &EncodedPoint) -> Result<Self, error::Unspecified> {
94 let mut point = Self {
95 x: Elem::zero(),
96 y: Elem::zero(),
97 z: Elem::zero(),
98 t: Elem::zero(),
99 };
100
101 Result::from(unsafe { x25519_ge_frombytes_vartime(&mut point, encoded) }).map(|()| point)
102 }
103
104 pub fn into_encoded_point(self) -> EncodedPoint {
105 encode_point(self.x, self.y, self.z)
106 }
107
108 pub fn invert_vartime(&mut self) {
109 self.x.negate();
110 self.t.negate();
111 }
112}
113
114#[repr(C)]
116pub struct Point {
117 x: Elem<T>,
118 y: Elem<T>,
119 z: Elem<T>,
120}
121
122impl Point {
123 pub fn new_at_infinity() -> Self {
124 Self {
125 x: Elem::zero(),
126 y: Elem::zero(),
127 z: Elem::zero(),
128 }
129 }
130
131 pub fn into_encoded_point(self) -> EncodedPoint {
132 encode_point(self.x, self.y, self.z)
133 }
134}
135
136fn encode_point(x: Elem<T>, y: Elem<T>, z: Elem<T>) -> EncodedPoint {
137 let mut bytes = [0; ELEM_LEN];
138
139 let sign_bit: u8 = unsafe {
140 let mut recip = Elem::zero();
141 x25519_fe_invert(&mut recip, &z);
142
143 let mut x_over_z = Elem::zero();
144 x25519_fe_mul_ttt(&mut x_over_z, &x, &recip);
145
146 let mut y_over_z = Elem::zero();
147 x25519_fe_mul_ttt(&mut y_over_z, &y, &recip);
148 x25519_fe_tobytes(&mut bytes, &y_over_z);
149
150 x25519_fe_isnegative(&x_over_z)
151 };
152
153 bytes[ELEM_LEN - 1] ^= sign_bit << 7;
156
157 bytes
158}
159
160cfg_if::cfg_if! {
161 if #[cfg(all(target_arch = "x86_64", not(target_os = "windows")))] {
162 #[inline(always)]
163 pub(super) fn has_fe25519_adx(cpu: cpu::Features) -> bool {
164 cpu::intel::ADX.available(cpu)
165 && cpu::intel::BMI1.available(cpu)
166 && cpu::intel::BMI2.available(cpu)
167 }
168 } else {
169 #[inline(always)]
170 pub (super) fn has_fe25519_adx(_cpu: cpu::Features) -> bool {
171 false
172 }
173 }
174}
175
176prefixed_extern! {
177 fn x25519_fe_invert(out: &mut Elem<T>, z: &Elem<T>);
178 fn x25519_fe_isnegative(elem: &Elem<T>) -> u8;
179 fn x25519_fe_mul_ttt(h: &mut Elem<T>, f: &Elem<T>, g: &Elem<T>);
180 fn x25519_fe_neg(f: &mut Elem<T>);
181 fn x25519_fe_tobytes(bytes: &mut EncodedPoint, elem: &Elem<T>);
182 fn x25519_ge_frombytes_vartime(h: &mut ExtPoint, s: &EncodedPoint) -> bssl::Result;
183}