1use crate::curve::twedwards::extended::ExtendedPoint;
2use crate::field::FieldElement;
3use crate::*;
4
5use core::fmt::{Display, Formatter, LowerHex, Result as FmtResult, UpperHex};
6use elliptic_curve::{
7 CurveGroup, Error, Generate, Group,
8 array::Array,
9 consts::U56,
10 ctutils,
11 group::{GroupEncoding, cofactor::CofactorGroup, prime::PrimeGroup},
12 ops::LinearCombination,
13 point::NonIdentity,
14};
15use rand_core::{CryptoRng, TryCryptoRng, TryRng};
16use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq, CtOption};
17
18pub type DecafPointBytes = [u8; 56];
20pub type DecafPointRepr = Array<u8, U56>;
22
23#[derive(Copy, Clone, Debug)]
25pub struct DecafPoint(pub(crate) ExtendedPoint);
26
27impl DecafPoint {
28 pub const GENERATOR: DecafPoint = DecafPoint(TWISTED_EDWARDS_BASE_POINT);
30 pub const IDENTITY: DecafPoint = DecafPoint(ExtendedPoint::IDENTITY);
32
33 pub fn is_identity(&self) -> Choice {
35 self.ct_eq(&DecafPoint::IDENTITY)
36 }
37
38 pub fn add(&self, other: &DecafPoint) -> DecafPoint {
40 DecafPoint(self.0.add_extended(&other.0).to_extended())
41 }
42
43 pub fn sub(&self, other: &DecafPoint) -> DecafPoint {
45 DecafPoint(self.0.sub_extended(&other.0).to_extended())
46 }
47
48 pub fn compress(&self) -> CompressedDecaf {
50 let X = self.0.X;
51 let Z = self.0.Z;
53 let T = self.0.T;
54
55 let XX_TT = (X + T) * (X - T);
56
57 let (isr, _) = (X.square() * XX_TT * FieldElement::NEG_EDWARDS_D).inverse_square_root();
58 let mut ratio = isr * XX_TT;
59 let altx = ratio * FieldElement::DECAF_FACTOR; ratio.conditional_negate(altx.is_negative());
61 let k = ratio * Z - T;
62
63 let mut s = k * FieldElement::NEG_EDWARDS_D * isr * X;
64 s.conditional_negate(s.is_negative());
65
66 CompressedDecaf(s.to_bytes())
67 }
68
69 pub fn from_uniform_bytes(bytes: &[u8; 112]) -> Self {
80 let lo: [u8; 56] = (&bytes[..56])
81 .try_into()
82 .expect("how does the slice have an incorrect length");
83 let hi: [u8; 56] = (&bytes[56..])
84 .try_into()
85 .expect("how does the slice have an incorrect length");
86
87 let u0 = FieldElement::from_bytes(&lo);
88 let u1 = FieldElement::from_bytes(&hi);
89 let q0 = u0.map_to_curve_decaf448();
90 let q1 = u1.map_to_curve_decaf448();
91 Self(q0.add_extended(&q1).to_extended())
92 }
93
94 #[deprecated(since = "0.14.0", note = "use the `Generate` trait instead")]
98 pub fn random(mut rng: impl CryptoRng) -> Self {
99 let mut uniform_bytes = [0u8; 112];
100 rng.fill_bytes(&mut uniform_bytes);
101 Self::from_uniform_bytes(&uniform_bytes)
102 }
103}
104
105impl Default for DecafPoint {
106 fn default() -> Self {
107 Self::IDENTITY
108 }
109}
110
111impl Display for DecafPoint {
112 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
113 write!(
114 f,
115 "{{ X: {}, Y: {}, Z: {}, T: {} }}",
116 self.0.X, self.0.Y, self.0.Z, self.0.T
117 )
118 }
119}
120
121impl LowerHex for DecafPoint {
122 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
123 write!(
124 f,
125 "{{ X: {:x}, Y: {:x}, Z: {:x}, T: {:x} }}",
126 self.0.X, self.0.Y, self.0.Z, self.0.T
127 )
128 }
129}
130
131impl UpperHex for DecafPoint {
132 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
133 write!(
134 f,
135 "{{ X: {:X}, Y: {:X}, Z: {:X}, T: {:X} }}",
136 self.0.X, self.0.Y, self.0.Z, self.0.T
137 )
138 }
139}
140
141impl ConstantTimeEq for DecafPoint {
142 fn ct_eq(&self, other: &DecafPoint) -> Choice {
143 (self.0.X * other.0.Y).ct_eq(&(self.0.Y * other.0.X))
144 }
145}
146
147impl ConditionallySelectable for DecafPoint {
148 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
149 DecafPoint(ExtendedPoint {
150 X: FieldElement::conditional_select(&a.0.X, &b.0.X, choice),
151 Y: FieldElement::conditional_select(&a.0.Y, &b.0.Y, choice),
152 Z: FieldElement::conditional_select(&a.0.Z, &b.0.Z, choice),
153 T: FieldElement::conditional_select(&a.0.T, &b.0.T, choice),
154 })
155 }
156}
157
158impl ctutils::CtEq for DecafPoint {
159 fn ct_eq(&self, other: &Self) -> ctutils::Choice {
160 ConstantTimeEq::ct_eq(self, other).into()
161 }
162}
163
164impl ctutils::CtSelect for DecafPoint {
165 fn ct_select(&self, other: &Self, choice: ctutils::Choice) -> Self {
166 ConditionallySelectable::conditional_select(self, other, choice.into())
167 }
168}
169
170impl Eq for DecafPoint {}
171impl PartialEq for DecafPoint {
172 fn eq(&self, other: &DecafPoint) -> bool {
173 self.ct_eq(other).into()
174 }
175}
176
177impl From<DecafPoint> for DecafPointBytes {
178 fn from(point: DecafPoint) -> DecafPointBytes {
179 point.compress().0
180 }
181}
182
183impl From<&DecafPoint> for DecafPointBytes {
184 fn from(compressed: &DecafPoint) -> DecafPointBytes {
185 Self::from(*compressed)
186 }
187}
188
189#[cfg(feature = "alloc")]
190impl From<DecafPoint> for Vec<u8> {
191 fn from(compressed: DecafPoint) -> Vec<u8> {
192 Self::from(&compressed)
193 }
194}
195
196#[cfg(feature = "alloc")]
197impl From<&DecafPoint> for Vec<u8> {
198 fn from(point: &DecafPoint) -> Vec<u8> {
199 point.compress().0.to_vec()
200 }
201}
202
203#[cfg(feature = "alloc")]
204impl TryFrom<Vec<u8>> for DecafPoint {
205 type Error = &'static str;
206
207 fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
208 Self::try_from(bytes.as_slice())
209 }
210}
211
212#[cfg(feature = "alloc")]
213impl TryFrom<&Vec<u8>> for DecafPoint {
214 type Error = &'static str;
215
216 fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
217 Self::try_from(bytes.as_slice())
218 }
219}
220
221#[cfg(feature = "alloc")]
222impl TryFrom<&[u8]> for DecafPoint {
223 type Error = &'static str;
224
225 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
226 let compressed =
227 <DecafPointBytes>::try_from(bytes).map_err(|_| "bytes is not the correct length")?;
228 Self::try_from(compressed)
229 }
230}
231
232#[cfg(feature = "alloc")]
233impl TryFrom<Box<[u8]>> for DecafPoint {
234 type Error = &'static str;
235
236 fn try_from(bytes: Box<[u8]>) -> Result<Self, Self::Error> {
237 Self::try_from(bytes.as_ref())
238 }
239}
240
241impl TryFrom<DecafPointBytes> for DecafPoint {
242 type Error = &'static str;
243
244 fn try_from(bytes: DecafPointBytes) -> Result<Self, Self::Error> {
245 let pt = CompressedDecaf(bytes);
246 Option::<DecafPoint>::from(pt.decompress()).ok_or("Invalid point encoding")
247 }
248}
249
250impl TryFrom<&DecafPointBytes> for DecafPoint {
251 type Error = &'static str;
252
253 fn try_from(bytes: &DecafPointBytes) -> Result<Self, Self::Error> {
254 Self::try_from(*bytes)
255 }
256}
257
258impl Generate for DecafPoint {
259 fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
260 let mut uniform_bytes = [0u8; 112];
261 rng.try_fill_bytes(&mut uniform_bytes)?;
262 Ok(Self::from_uniform_bytes(&uniform_bytes))
263 }
264}
265
266impl Group for DecafPoint {
267 type Scalar = DecafScalar;
268
269 fn try_random<R>(rng: &mut R) -> Result<Self, R::Error>
270 where
271 R: TryRng + ?Sized,
272 {
273 let mut bytes = DecafPointRepr::default();
274
275 loop {
276 rng.try_fill_bytes(&mut bytes)?;
277 if let Some(point) = Self::from_bytes(&bytes)
278 .into_option()
279 .filter(|&point| point != Self::IDENTITY)
280 {
281 return Ok(point);
282 }
283 }
284 }
285
286 fn identity() -> Self {
287 Self::IDENTITY
288 }
289
290 fn generator() -> Self {
291 Self::GENERATOR
292 }
293
294 fn is_identity(&self) -> Choice {
295 self.ct_eq(&Self::IDENTITY)
296 }
297
298 fn double(&self) -> Self {
299 Self(self.0.to_extensible().double().to_extended())
300 }
301}
302
303impl GroupEncoding for DecafPoint {
304 type Repr = DecafPointRepr;
305
306 fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
307 let pt = CompressedDecaf(*(bytes.as_ref()));
308 pt.decompress()
309 }
310
311 fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
312 let pt = CompressedDecaf(*(bytes.as_ref()));
313 pt.decompress()
314 }
315
316 fn to_bytes(&self) -> Self::Repr {
317 DecafPointRepr::from(self.compress().0)
318 }
319}
320
321impl CofactorGroup for DecafPoint {
322 type Subgroup = DecafPoint;
323
324 fn clear_cofactor(&self) -> Self::Subgroup {
325 *self
326 }
327
328 fn into_subgroup(self) -> CtOption<Self::Subgroup> {
329 CtOption::new(self, Choice::from(1))
330 }
331
332 fn is_torsion_free(&self) -> Choice {
333 Choice::from(1)
334 }
335}
336
337impl PrimeGroup for DecafPoint {}
338
339impl<const N: usize> LinearCombination<[(DecafPoint, DecafScalar); N]> for DecafPoint {}
340
341impl LinearCombination<[(DecafPoint, DecafScalar)]> for DecafPoint {}
342
343impl CurveGroup for DecafPoint {
344 type Affine = DecafAffinePoint;
345
346 fn to_affine(&self) -> Self::Affine {
347 DecafAffinePoint(self.0.to_extensible().to_affine())
348 }
349}
350
351impl From<EdwardsPoint> for DecafPoint {
352 fn from(point: EdwardsPoint) -> Self {
353 Self(point.to_twisted().to_extended())
354 }
355}
356
357impl From<&EdwardsPoint> for DecafPoint {
358 fn from(point: &EdwardsPoint) -> Self {
359 Self(point.to_twisted().to_extended())
360 }
361}
362
363impl From<DecafPoint> for EdwardsPoint {
364 fn from(point: DecafPoint) -> Self {
365 point.0.to_untwisted()
366 }
367}
368
369impl From<&DecafPoint> for EdwardsPoint {
370 fn from(point: &DecafPoint) -> Self {
371 point.0.to_untwisted()
372 }
373}
374
375impl From<DecafAffinePoint> for DecafPoint {
376 fn from(point: DecafAffinePoint) -> Self {
377 Self(point.0.to_extended())
378 }
379}
380
381impl From<&DecafAffinePoint> for DecafPoint {
382 fn from(point: &DecafAffinePoint) -> Self {
383 Self(point.0.to_extended())
384 }
385}
386
387impl From<DecafPoint> for DecafAffinePoint {
388 fn from(point: DecafPoint) -> Self {
389 DecafAffinePoint(point.0.to_extensible().to_affine())
390 }
391}
392
393impl From<&DecafPoint> for DecafAffinePoint {
394 fn from(point: &DecafPoint) -> Self {
395 DecafAffinePoint(point.0.to_extensible().to_affine())
396 }
397}
398
399impl elliptic_curve::zeroize::DefaultIsZeroes for DecafPoint {}
400
401#[derive(Copy, Clone, Debug)]
403#[repr(transparent)]
404pub struct CompressedDecaf(pub DecafPointBytes);
405
406impl Default for CompressedDecaf {
407 fn default() -> CompressedDecaf {
408 Self::IDENTITY
409 }
410}
411
412impl ConstantTimeEq for CompressedDecaf {
413 fn ct_eq(&self, other: &CompressedDecaf) -> Choice {
414 self.as_bytes().ct_eq(other.as_bytes())
415 }
416}
417
418impl ConditionallySelectable for CompressedDecaf {
419 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
420 let mut bytes = [0u8; 56];
421 for (i, byte) in bytes.iter_mut().enumerate() {
422 *byte = u8::conditional_select(&a.0[i], &b.0[i], choice);
423 }
424 Self(bytes)
425 }
426}
427
428impl PartialEq for CompressedDecaf {
429 fn eq(&self, other: &CompressedDecaf) -> bool {
430 self.ct_eq(other).into()
431 }
432}
433
434impl Eq for CompressedDecaf {}
435
436impl From<CompressedDecaf> for DecafPointBytes {
437 fn from(compressed: CompressedDecaf) -> DecafPointBytes {
438 compressed.0
439 }
440}
441
442impl From<&CompressedDecaf> for DecafPointBytes {
443 fn from(compressed: &CompressedDecaf) -> DecafPointBytes {
444 Self::from(*compressed)
445 }
446}
447
448#[cfg(feature = "alloc")]
449impl From<CompressedDecaf> for Vec<u8> {
450 fn from(compressed: CompressedDecaf) -> Vec<u8> {
451 Self::from(&compressed)
452 }
453}
454
455#[cfg(feature = "alloc")]
456impl From<&CompressedDecaf> for Vec<u8> {
457 fn from(compressed: &CompressedDecaf) -> Vec<u8> {
458 compressed.0.to_vec()
459 }
460}
461
462#[cfg(feature = "alloc")]
463impl TryFrom<Vec<u8>> for CompressedDecaf {
464 type Error = &'static str;
465
466 fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
467 Self::try_from(bytes.as_slice())
468 }
469}
470
471#[cfg(feature = "alloc")]
472impl TryFrom<&Vec<u8>> for CompressedDecaf {
473 type Error = &'static str;
474
475 fn try_from(bytes: &Vec<u8>) -> Result<Self, Self::Error> {
476 Self::try_from(bytes.as_slice())
477 }
478}
479
480#[cfg(feature = "alloc")]
481impl TryFrom<&[u8]> for CompressedDecaf {
482 type Error = &'static str;
483
484 fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
485 let compressed = <DecafPointBytes>::try_from(bytes).map_err(|_| "invalid length")?;
486 Self::try_from(compressed)
487 }
488}
489
490#[cfg(feature = "alloc")]
491impl TryFrom<Box<[u8]>> for CompressedDecaf {
492 type Error = &'static str;
493
494 fn try_from(bytes: Box<[u8]>) -> Result<Self, Self::Error> {
495 Self::try_from(bytes.as_ref())
496 }
497}
498
499impl TryFrom<DecafPointBytes> for CompressedDecaf {
500 type Error = &'static str;
501
502 fn try_from(bytes: DecafPointBytes) -> Result<Self, Self::Error> {
503 let pt = CompressedDecaf(bytes);
504 let _ = Option::<DecafPoint>::from(pt.decompress()).ok_or("Invalid point encoding")?;
505 Ok(pt)
506 }
507}
508
509impl TryFrom<&DecafPointBytes> for CompressedDecaf {
510 type Error = &'static str;
511
512 fn try_from(bytes: &DecafPointBytes) -> Result<Self, Self::Error> {
513 Self::try_from(*bytes)
514 }
515}
516
517impl AsRef<DecafPointBytes> for CompressedDecaf {
518 fn as_ref(&self) -> &DecafPointBytes {
519 &self.0
520 }
521}
522
523#[cfg(feature = "serde")]
524impl serdect::serde::Serialize for CompressedDecaf {
525 fn serialize<S: serdect::serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
526 serdect::slice::serialize_hex_lower_or_bin(&self.0, s)
527 }
528}
529
530#[cfg(feature = "serde")]
531impl<'de> serdect::serde::Deserialize<'de> for CompressedDecaf {
532 fn deserialize<D>(d: D) -> Result<Self, D::Error>
533 where
534 D: serdect::serde::Deserializer<'de>,
535 {
536 let mut bytes = [0u8; 56];
537 serdect::array::deserialize_hex_or_bin(&mut bytes, d)?;
538 Self::try_from(bytes).map_err(serdect::serde::de::Error::custom)
539 }
540}
541
542impl elliptic_curve::zeroize::DefaultIsZeroes for CompressedDecaf {}
543
544impl CompressedDecaf {
545 pub const GENERATOR: Self = Self([
547 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
548 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
549 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
550 ]);
551 pub const IDENTITY: Self = Self([0u8; 56]);
553
554 pub fn decompress(&self) -> CtOption<DecafPoint> {
556 let s = FieldElement::from_bytes(&self.0);
557 let s_bytes_check = s.to_bytes();
562 let s_encoding_is_canonical = s_bytes_check[..].ct_eq(&self.0);
563 let s_is_negative = s.is_negative();
564 let ss = s.square();
569 let u1 = FieldElement::ONE - ss;
570 let u2 = FieldElement::ONE + ss;
571 let u1_sqr = u1.square();
572
573 let v = ss * (FieldElement::NEG_FOUR_TIMES_TWISTED_D) + u1_sqr; let (I, ok) = (v * u1_sqr).inverse_square_root();
576
577 let Dx = I * u1;
578 let Dxs = s.double() * Dx;
579
580 let mut X = (Dxs * I) * v;
581 let k = Dxs * FieldElement::DECAF_FACTOR;
582 X.conditional_negate(k.is_negative());
583
584 let Y = Dx * u2;
585 let Z = FieldElement::ONE;
586 let T = X * Y;
587 let pt = ExtendedPoint { X, Y, Z, T };
588
589 CtOption::new(
590 DecafPoint(pt),
591 ok & pt.is_on_curve() & s_encoding_is_canonical & !s_is_negative,
592 )
593 }
594
595 pub fn as_bytes(&self) -> &[u8] {
597 &self.0
598 }
599}
600
601impl TryFrom<DecafPoint> for NonIdentity<DecafPoint> {
603 type Error = Error;
604
605 fn try_from(point: DecafPoint) -> Result<Self, Error> {
606 NonIdentity::new(point).into_option().ok_or(Error)
607 }
608}
609
610impl From<NonIdentity<DecafPoint>> for DecafPoint {
611 fn from(decaf: NonIdentity<DecafPoint>) -> Self {
612 decaf.to_point()
613 }
614}
615
616#[cfg(test)]
617mod test {
618 use super::*;
619 use crate::TWISTED_EDWARDS_BASE_POINT;
620 use hash2curve::ExpandMsgXof;
621 use shake::Shake256;
622
623 #[test]
624 fn test_edwards_decaf_operations() {
625 let P = TWISTED_EDWARDS_BASE_POINT;
629
630 let P2 = P.to_extensible().double().to_extended();
631 let P3 = P2.add_extended(&P).to_extended();
632
633 let Decaf_P = DecafPoint(P).compress().decompress().unwrap();
635 let Decaf_P2 = DecafPoint(P2).compress().decompress().unwrap();
636 let expected_Decaf_P3 = DecafPoint(P3).compress().decompress().unwrap();
637
638 let Decaf_P3 = Decaf_P + Decaf_P2;
640
641 assert_eq!(Decaf_P3, expected_Decaf_P3);
642 }
643
644 #[test]
645 fn test_identity() {
646 let compress_identity = DecafPoint::IDENTITY.compress();
648 assert!(compress_identity == CompressedDecaf::IDENTITY)
649 }
650
651 #[test]
652 fn test_vectors_lib_decaf() {
653 let compressed = [
655 CompressedDecaf([
657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
658 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
659 ]),
660 CompressedDecaf([
661 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
662 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 51, 51, 51, 51, 51, 51,
663 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
664 51,
665 ]),
666 CompressedDecaf([
667 200, 152, 235, 79, 135, 249, 124, 86, 76, 111, 214, 31, 199, 228, 150, 137, 49, 74,
668 31, 129, 142, 200, 94, 235, 59, 213, 81, 74, 200, 22, 211, 135, 120, 246, 158, 243,
669 71, 168, 159, 202, 129, 126, 102, 222, 253, 237, 206, 23, 140, 124, 199, 9, 178,
670 17, 110, 117,
671 ]),
672 CompressedDecaf([
673 160, 192, 155, 242, 186, 114, 8, 253, 160, 244, 191, 227, 208, 245, 178, 154, 84,
674 48, 18, 48, 109, 67, 131, 27, 90, 220, 111, 231, 248, 89, 111, 163, 8, 118, 61,
675 177, 84, 104, 50, 59, 17, 207, 110, 74, 235, 140, 24, 254, 68, 103, 143, 68, 84,
676 90, 105, 188,
677 ]),
678 CompressedDecaf([
679 180, 111, 24, 54, 170, 40, 124, 10, 90, 86, 83, 240, 236, 94, 249, 233, 3, 244, 54,
680 226, 28, 21, 112, 194, 154, 217, 229, 245, 150, 218, 151, 238, 175, 23, 21, 10,
681 227, 11, 203, 49, 116, 208, 75, 194, 215, 18, 200, 199, 120, 157, 124, 180, 253,
682 161, 56, 244,
683 ]),
684 CompressedDecaf([
685 28, 91, 190, 207, 71, 65, 223, 170, 231, 157, 183, 45, 250, 206, 0, 234, 170, 197,
686 2, 194, 6, 9, 52, 182, 234, 174, 202, 106, 32, 189, 61, 169, 224, 190, 135, 119,
687 247, 208, 32, 51, 209, 177, 88, 132, 35, 34, 129, 164, 31, 199, 248, 14, 237, 4,
688 175, 94,
689 ]),
690 CompressedDecaf([
691 134, 255, 1, 130, 212, 15, 127, 158, 219, 120, 98, 81, 88, 33, 189, 103, 191, 214,
692 22, 90, 60, 68, 222, 149, 215, 223, 121, 184, 119, 156, 207, 100, 96, 227, 198,
693 139, 112, 193, 106, 170, 40, 15, 45, 123, 63, 34, 215, 69, 185, 122, 137, 144, 108,
694 252, 71, 108,
695 ]),
696 CompressedDecaf([
697 80, 43, 203, 104, 66, 235, 6, 240, 228, 144, 50, 186, 232, 124, 85, 76, 3, 29, 109,
698 77, 45, 118, 148, 239, 191, 156, 70, 141, 72, 34, 12, 80, 248, 202, 40, 132, 51,
699 100, 215, 12, 238, 146, 214, 254, 36, 110, 97, 68, 143, 157, 185, 128, 139, 59, 36,
700 8,
701 ]),
702 CompressedDecaf([
703 12, 152, 16, 241, 226, 235, 211, 137, 202, 167, 137, 55, 77, 120, 0, 121, 116, 239,
704 77, 23, 34, 115, 22, 244, 14, 87, 139, 51, 104, 39, 218, 63, 107, 72, 42, 71, 148,
705 235, 106, 57, 117, 185, 113, 181, 225, 56, 143, 82, 233, 30, 162, 241, 188, 176,
706 249, 18,
707 ]),
708 CompressedDecaf([
709 32, 212, 29, 133, 161, 141, 86, 87, 162, 150, 64, 50, 21, 99, 187, 208, 76, 47,
710 251, 208, 163, 122, 123, 164, 58, 79, 125, 38, 60, 226, 111, 175, 78, 31, 116, 249,
711 244, 181, 144, 198, 146, 41, 174, 87, 31, 227, 127, 166, 57, 181, 184, 235, 72,
712 189, 154, 85,
713 ]),
714 CompressedDecaf([
715 230, 180, 184, 244, 8, 199, 1, 13, 6, 1, 231, 237, 160, 195, 9, 161, 164, 39, 32,
716 214, 208, 107, 87, 89, 253, 196, 225, 239, 226, 45, 7, 109, 108, 68, 212, 47, 80,
717 141, 103, 190, 70, 41, 20, 210, 139, 142, 220, 227, 46, 112, 148, 48, 81, 100, 175,
718 23,
719 ]),
720 CompressedDecaf([
721 190, 136, 187, 184, 108, 89, 193, 61, 142, 157, 9, 171, 152, 16, 95, 105, 194, 209,
722 221, 19, 77, 188, 211, 176, 134, 54, 88, 245, 49, 89, 219, 100, 192, 225, 57, 209,
723 128, 243, 200, 155, 130, 150, 208, 174, 50, 68, 25, 192, 111, 168, 127, 199, 218,
724 175, 52, 193,
725 ]),
726 CompressedDecaf([
727 164, 86, 249, 54, 151, 105, 232, 240, 137, 2, 18, 74, 3, 20, 199, 160, 101, 55,
728 160, 110, 50, 65, 31, 79, 147, 65, 89, 80, 161, 123, 173, 250, 116, 66, 182, 33,
729 116, 52, 163, 160, 94, 244, 91, 229, 241, 11, 215, 178, 239, 142, 160, 12, 67, 30,
730 222, 197,
731 ]),
732 CompressedDecaf([
733 24, 110, 69, 44, 68, 102, 170, 67, 131, 180, 192, 2, 16, 213, 46, 121, 34, 219,
734 249, 119, 30, 139, 71, 226, 41, 169, 183, 183, 60, 141, 16, 253, 126, 240, 182,
735 228, 21, 48, 249, 31, 36, 163, 237, 154, 183, 31, 163, 139, 152, 178, 254, 71, 70,
736 213, 29, 104,
737 ]),
738 CompressedDecaf([
739 74, 231, 253, 202, 233, 69, 63, 25, 90, 142, 173, 92, 190, 26, 123, 150, 153, 103,
740 59, 82, 196, 10, 178, 121, 39, 70, 72, 135, 190, 83, 35, 127, 127, 58, 33, 185, 56,
741 212, 13, 14, 201, 225, 91, 29, 81, 48, 177, 63, 254, 216, 19, 115, 165, 62, 43, 67,
742 ]),
743 CompressedDecaf([
744 132, 25, 129, 195, 191, 238, 195, 246, 12, 254, 202, 117, 217, 216, 220, 23, 244,
745 108, 240, 16, 111, 36, 34, 181, 154, 236, 88, 10, 88, 243, 66, 39, 46, 58, 94, 87,
746 90, 5, 93, 219, 5, 19, 144, 197, 76, 36, 198, 236, 177, 224, 172, 235, 7, 95, 96,
747 86,
748 ]),
749 ];
750 let mut point = DecafPoint::IDENTITY;
751 let generator = DecafPoint::GENERATOR;
752 for compressed_point in compressed.iter() {
753 assert_eq!(&point.compress(), compressed_point);
754 point += generator;
755 let decompressed_point = compressed_point.decompress();
756 assert_eq!(decompressed_point.is_some().unwrap_u8(), 1u8);
757 }
758 }
759
760 #[test]
761 fn test_invalid_point() {
762 let all_ones = CompressedDecaf([1u8; 56]);
764 assert_eq!(all_ones.decompress().is_none().unwrap_u8(), 1u8);
765 let all_twos = CompressedDecaf([2u8; 56]);
766 assert_eq!(all_twos.decompress().is_none().unwrap_u8(), 1u8);
767 }
768
769 #[test]
770 fn test_hash_to_curve() {
771 let msg = b"Hello, world!";
772 let point = hash2curve::hash_from_bytes::<Decaf448, ExpandMsgXof<Shake256>>(
773 &[msg],
774 &[b"test_hash_to_curve"],
775 )
776 .unwrap();
777 assert_eq!(point.0.is_on_curve().unwrap_u8(), 1u8);
778 assert_ne!(point, DecafPoint::IDENTITY);
779 assert_ne!(point, DecafPoint::GENERATOR);
780 }
781
782 }