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::{ |
16 | arithmetic::{ |
17 | limbs_from_hex, |
18 | montgomery::{Encoding, ProductEncoding}, |
19 | }, |
20 | limb::{Limb, LIMB_BITS}, |
21 | }; |
22 | use core::marker::PhantomData; |
23 | |
24 | /// Elements of ℤ/mℤ for some modulus *m*. Elements are always fully reduced |
25 | /// with respect to *m*; i.e. the 0 <= x < m for every value x. |
26 | #[derive (Clone, Copy)] |
27 | pub struct Elem<M, E: Encoding> { |
28 | // XXX: pub |
29 | pub(super) limbs: [Limb; MAX_LIMBS], |
30 | |
31 | /// The modulus *m* for the ring ℤ/mℤ for which this element is a value. |
32 | pub(super) m: PhantomData<M>, |
33 | |
34 | /// The number of Montgomery factors that need to be canceled out from |
35 | /// `value` to get the actual value. |
36 | pub(super) encoding: PhantomData<E>, |
37 | } |
38 | |
39 | impl<M, E: Encoding> Elem<M, E> { |
40 | // There's no need to convert `value` to the Montgomery domain since |
41 | // 0 * R**2 (mod m) == 0, so neither the modulus nor the encoding are needed |
42 | // as inputs for constructing a zero-valued element. |
43 | pub fn zero() -> Self { |
44 | Self { |
45 | limbs: [0; MAX_LIMBS], |
46 | m: PhantomData, |
47 | encoding: PhantomData, |
48 | } |
49 | } |
50 | |
51 | pub const fn from_hex(hex: &str) -> Self { |
52 | Elem { |
53 | limbs: limbs_from_hex(hex), |
54 | m: PhantomData, |
55 | encoding: PhantomData, |
56 | } |
57 | } |
58 | } |
59 | |
60 | #[inline ] |
61 | pub fn mul_mont<M, EA: Encoding, EB: Encoding>( |
62 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
63 | a: &Elem<M, EA>, |
64 | b: &Elem<M, EB>, |
65 | ) -> Elem<M, <(EA, EB) as ProductEncoding>::Output> |
66 | where |
67 | (EA, EB): ProductEncoding, |
68 | { |
69 | binary_op(f, a, b) |
70 | } |
71 | |
72 | // let r = f(a, b); return r; |
73 | #[inline ] |
74 | pub fn binary_op<M, EA: Encoding, EB: Encoding, ER: Encoding>( |
75 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
76 | a: &Elem<M, EA>, |
77 | b: &Elem<M, EB>, |
78 | ) -> Elem<M, ER> { |
79 | let mut r: Elem = Elem { |
80 | limbs: [0; MAX_LIMBS], |
81 | m: PhantomData, |
82 | encoding: PhantomData, |
83 | }; |
84 | unsafe { f(r.limbs.as_mut_ptr(), a.limbs.as_ptr(), b.limbs.as_ptr()) } |
85 | r |
86 | } |
87 | |
88 | // a := f(a, b); |
89 | #[inline ] |
90 | pub fn binary_op_assign<M, EA: Encoding, EB: Encoding>( |
91 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
92 | a: &mut Elem<M, EA>, |
93 | b: &Elem<M, EB>, |
94 | ) { |
95 | unsafe { f(a.limbs.as_mut_ptr(), a.limbs.as_ptr(), b.limbs.as_ptr()) } |
96 | } |
97 | |
98 | // let r = f(a); return r; |
99 | #[inline ] |
100 | pub fn unary_op<M, E: Encoding>( |
101 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb), |
102 | a: &Elem<M, E>, |
103 | ) -> Elem<M, E> { |
104 | let mut r: Elem = Elem { |
105 | limbs: [0; MAX_LIMBS], |
106 | m: PhantomData, |
107 | encoding: PhantomData, |
108 | }; |
109 | unsafe { f(r.limbs.as_mut_ptr(), a.limbs.as_ptr()) } |
110 | r |
111 | } |
112 | |
113 | // a := f(a); |
114 | #[inline ] |
115 | pub fn unary_op_assign<M, E: Encoding>( |
116 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb), |
117 | a: &mut Elem<M, E>, |
118 | ) { |
119 | unsafe { f(a.limbs.as_mut_ptr(), a.limbs.as_ptr()) } |
120 | } |
121 | |
122 | // a := f(a, a); |
123 | #[inline ] |
124 | pub fn unary_op_from_binary_op_assign<M, E: Encoding>( |
125 | f: unsafe extern "C" fn(r: *mut Limb, a: *const Limb, b: *const Limb), |
126 | a: &mut Elem<M, E>, |
127 | ) { |
128 | unsafe { f(a.limbs.as_mut_ptr(), a.limbs.as_ptr(), a.limbs.as_ptr()) } |
129 | } |
130 | |
131 | pub const MAX_LIMBS: usize = (384 + (LIMB_BITS - 1)) / LIMB_BITS; |
132 | |