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