decaf377/ark_curve/element/
projective.rs

1use core::borrow::Borrow;
2use core::hash::Hash;
3
4use ark_ff::Zero;
5use ark_std::fmt::{Display, Formatter, Result as FmtResult};
6
7use zeroize::Zeroize;
8
9use crate::{ark_curve::EdwardsProjective, Fq, Fr};
10
11use super::super::constants::{B_T, B_X, B_Y, B_Z};
12
13#[derive(Copy, Clone)]
14pub struct Element {
15    pub(crate) inner: EdwardsProjective,
16}
17
18impl Element {
19    /// Return the conventional generator for `decaf377`.
20    pub const GENERATOR: Self = Self {
21        inner: EdwardsProjective::new_unchecked(B_X, B_Y, B_T, B_Z),
22    };
23
24    pub const IDENTITY: Self = Self {
25        inner: EdwardsProjective::new_unchecked(Fq::ZERO, Fq::ONE, Fq::ZERO, Fq::ONE),
26    };
27}
28
29impl Hash for Element {
30    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
31        self.inner.hash(state);
32    }
33}
34
35impl core::fmt::Debug for Element {
36    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
37        // This prints the hex of the encoding of self, rather than the
38        // coordinates, because that's what's most useful to downstream
39        // consumers of the library.
40        f.write_fmt(format_args!(
41            "decaf377::Element({})",
42            hex::encode(&self.vartime_compress().0[..])
43        ))
44    }
45}
46
47impl Display for Element {
48    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
49        write!(
50            f,
51            "decaf377::Element({})",
52            hex::encode(&self.vartime_compress().0[..])
53        )
54    }
55}
56
57impl Default for Element {
58    fn default() -> Self {
59        Element {
60            inner: EdwardsProjective::zero(),
61        }
62    }
63}
64
65impl PartialEq for Element {
66    fn eq(&self, other: &Element) -> bool {
67        // Section 4.5 of Decaf paper
68        self.inner.x * other.inner.y == self.inner.y * other.inner.x
69    }
70}
71
72impl Eq for Element {}
73
74impl Zeroize for Element {
75    fn zeroize(&mut self) {
76        self.inner.zeroize()
77    }
78}
79
80impl Element {
81    /// Convenience method to make identity checks more readable.
82    pub fn is_identity(&self) -> bool {
83        // Section 4.5 of Decaf paper states for cofactor 4 curves we can
84        // just check X = 0 to check equality with identity
85        self.inner.x == Fq::zero()
86    }
87
88    /// Given an iterator of public scalars and an iterator of public points,
89    /// compute
90    /// $$
91    /// Q = \[c\_1\] P\_1 + \cdots + \[c\_n\] P\_n,
92    /// $$
93    /// using variable-time operations.
94    ///
95    /// It is an error to call this function with two iterators of different
96    /// lengths -- it would require `ExactSizeIterator`, but
97    /// `ExactSizeIterator`s are not closed under chaining, and disallowing
98    /// iterator chaining would destroy the utility of the function.
99    pub fn vartime_multiscalar_mul<I, J>(scalars: I, points: J) -> Element
100    where
101        I: IntoIterator,
102        I::Item: Borrow<Fr>,
103        J: IntoIterator,
104        J::Item: Borrow<Element>,
105    {
106        // XXX this is a stub implementation, try to use a real MSM later
107        let scalars = scalars.into_iter();
108        let points = points.into_iter();
109
110        // XXX panic on length mismatches ? or error?
111
112        scalars
113            .zip(points)
114            .fold(Element::default(), |acc, (scalar, point)| {
115                acc + (scalar.borrow() * point.borrow())
116            })
117    }
118}
119
120impl Zero for Element {
121    fn zero() -> Self {
122        Self::default()
123    }
124
125    fn is_zero(&self) -> bool {
126        self.inner.is_zero()
127    }
128}
129
130impl core::iter::Sum<Self> for Element {
131    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
132        iter.fold(Self::zero(), core::ops::Add::add)
133    }
134}
135
136impl<'a> core::iter::Sum<&'a Element> for Element {
137    fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
138        iter.fold(Self::zero(), core::ops::Add::add)
139    }
140}