1 | // Copyright 2017 Brian Smith. |
2 | // |
3 | // Permission to use, copy, modify, and/or distribute this software for any |
4 | // purpose with or without fee is hereby granted, provided that the above |
5 | // copyright notice and this permission notice appear in all copies. |
6 | // |
7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | |
15 | use crate::ec::suite_b::ops::{ |
16 | p256::NUM_LIMBS as P256_NUM_LIMBS, p384::NUM_LIMBS as P384_NUM_LIMBS, |
17 | }; |
18 | use crate::{ |
19 | arithmetic::{ |
20 | limbs_from_hex, |
21 | montgomery::{Encoding, ProductEncoding, Unencoded}, |
22 | }, |
23 | limb::{LeakyLimb, Limb}, |
24 | }; |
25 | use core::marker::PhantomData; |
26 | |
27 | #[derive (Clone, Copy)] |
28 | pub(super) enum NumLimbs { |
29 | P256, |
30 | P384, |
31 | } |
32 | |
33 | impl NumLimbs { |
34 | pub(super) const MAX: usize = Self::P384.into(); |
35 | |
36 | pub(super) const fn into(self) -> usize { |
37 | match self { |
38 | NumLimbs::P256 => P256_NUM_LIMBS, |
39 | NumLimbs::P384 => P384_NUM_LIMBS, |
40 | } |
41 | } |
42 | } |
43 | |
44 | /// Elements of ℤ/mℤ for some modulus *m*. Elements are always fully reduced |
45 | /// with respect to *m*; i.e. the 0 <= x < m for every value x. |
46 | #[derive (Clone, Copy)] |
47 | pub struct Elem<M, E: Encoding> { |
48 | // XXX: pub |
49 | pub(super) limbs: [Limb; NumLimbs::MAX], |
50 | |
51 | /// The modulus *m* for the ring ℤ/mℤ for which this element is a value. |
52 | pub(super) m: PhantomData<M>, |
53 | |
54 | /// The number of Montgomery factors that need to be canceled out from |
55 | /// `value` to get the actual value. |
56 | pub(super) encoding: PhantomData<E>, |
57 | } |
58 | |
59 | pub struct PublicElem<M, E: Encoding> { |
60 | pub(super) limbs: [LeakyLimb; NumLimbs::MAX], |
61 | pub(super) m: PhantomData<M>, |
62 | pub(super) encoding: PhantomData<E>, |
63 | } |
64 | |
65 | impl<M, E: Encoding> From<&PublicElem<M, E>> for Elem<M, E> { |
66 | fn from(value: &PublicElem<M, E>) -> Self { |
67 | Self { |
68 | limbs: core::array::from_fn(|i: usize| Limb::from(value.limbs[i])), |
69 | m: value.m, |
70 | encoding: value.encoding, |
71 | } |
72 | } |
73 | } |
74 | |
75 | impl<M, E: Encoding> Elem<M, E> { |
76 | // There's no need to convert `value` to the Montgomery domain since |
77 | // 0 * R**2 (mod m) == 0, so neither the modulus nor the encoding are needed |
78 | // as inputs for constructing a zero-valued element. |
79 | pub fn zero() -> Self { |
80 | Self { |
81 | limbs: [0; NumLimbs::MAX], |
82 | m: PhantomData, |
83 | encoding: PhantomData, |
84 | } |
85 | } |
86 | } |
87 | |
88 | impl<M> Elem<M, Unencoded> { |
89 | pub fn one() -> Self { |
90 | let mut r: Elem = Self::zero(); |
91 | r.limbs[0] = 1; |
92 | r |
93 | } |
94 | } |
95 | |
96 | impl<M, E: Encoding> PublicElem<M, E> { |
97 | pub const fn from_hex(hex: &str) -> Self { |
98 | Self { |
99 | limbs: limbs_from_hex(hex), |
100 | m: PhantomData, |
101 | encoding: PhantomData, |
102 | } |
103 | } |
104 | } |
105 | |
106 | #[inline ] |
107 | pub fn mul_mont<M, EA: Encoding, EB: Encoding>( |
108 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
109 | a: &Elem<M, EA>, |
110 | b: &Elem<M, EB>, |
111 | ) -> Elem<M, <(EA, EB) as ProductEncoding>::Output> |
112 | where |
113 | (EA, EB): ProductEncoding, |
114 | { |
115 | binary_op(f, a, b) |
116 | } |
117 | |
118 | // let r = f(a, b); return r; |
119 | #[inline ] |
120 | pub fn binary_op<M, EA: Encoding, EB: Encoding, ER: Encoding>( |
121 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
122 | a: &Elem<M, EA>, |
123 | b: &Elem<M, EB>, |
124 | ) -> Elem<M, ER> { |
125 | let mut r: Elem = Elem::zero(); |
126 | unsafe { f(r.limbs.as_mut_ptr(), a.limbs.as_ptr(), b.limbs.as_ptr()) } |
127 | r |
128 | } |
129 | |
130 | // a := f(a, b); |
131 | #[inline ] |
132 | pub fn binary_op_assign<M, EA: Encoding, EB: Encoding>( |
133 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
134 | a: &mut Elem<M, EA>, |
135 | b: &Elem<M, EB>, |
136 | ) { |
137 | unsafe { f(a.limbs.as_mut_ptr(), a.limbs.as_ptr(), b.limbs.as_ptr()) } |
138 | } |
139 | |
140 | // let r = f(a); return r; |
141 | #[inline ] |
142 | pub fn unary_op<M, E: Encoding>( |
143 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb), |
144 | a: &Elem<M, E>, |
145 | ) -> Elem<M, E> { |
146 | let mut r: Elem = Elem::zero(); |
147 | unsafe { f(r.limbs.as_mut_ptr(), a.limbs.as_ptr()) } |
148 | r |
149 | } |
150 | |
151 | // a := f(a); |
152 | #[inline ] |
153 | pub fn unary_op_assign<M, E: Encoding>( |
154 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb), |
155 | a: &mut Elem<M, E>, |
156 | ) { |
157 | unsafe { f(a.limbs.as_mut_ptr(), a.limbs.as_ptr()) } |
158 | } |
159 | |
160 | // a := f(a, a); |
161 | #[inline ] |
162 | pub fn unary_op_from_binary_op_assign<M, E: Encoding>( |
163 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
164 | a: &mut Elem<M, E>, |
165 | ) { |
166 | unsafe { f(a.limbs.as_mut_ptr(), a.limbs.as_ptr(), a.limbs.as_ptr()) } |
167 | } |
168 | |