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
15use crate::{
16 arithmetic::{
17 limbs_from_hex,
18 montgomery::{Encoding, ProductEncoding},
19 },
20 limb::{Limb, LIMB_BITS},
21};
22use 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)]
27pub 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
39impl<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]
61pub 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>
66where
67 (EA, EB): ProductEncoding,
68{
69 binary_op(f, a, b)
70}
71
72// let r = f(a, b); return r;
73#[inline]
74pub 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]
90pub 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]
100pub 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]
115pub 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]
124pub 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
131pub const MAX_LIMBS: usize = (384 + (LIMB_BITS - 1)) / LIMB_BITS;
132