1#![cfg_attr(not(feature = "std"), no_std)]
26#![deny(rustdoc::broken_intra_doc_links)]
28#![deny(missing_debug_implementations)]
29#![deny(missing_docs)]
30#![deny(unsafe_code)]
31#![allow(clippy::suspicious_arithmetic_impl)]
36
37#[cfg(test)]
38#[macro_use]
39extern crate std;
40
41#[cfg(feature = "canon")]
42use canonical_derive::Canon;
43use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
44use dusk_bytes::{Error as BytesError, Serializable};
45use subtle;
46use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
47
48#[macro_use]
49mod util;
50mod fr;
51
52pub mod elgamal;
54
55pub use bls12_381::BlsScalar;
56pub use fr::Fr as JubJubScalar;
57
58pub(crate) use fr::Fr;
59
60pub type Scalar = Fr;
62
63const FR_MODULUS_BYTES: [u8; 32] = [
64 183, 44, 247, 214, 94, 14, 151, 208, 130, 16, 200, 204, 147, 32, 104, 166,
65 0, 59, 52, 1, 1, 59, 103, 6, 169, 175, 51, 101, 234, 180, 125, 14,
66];
67
68#[derive(Clone, Copy, Debug)]
71#[cfg_attr(feature = "canon", derive(Canon))]
72pub struct JubJubAffine {
73 x: BlsScalar,
74 y: BlsScalar,
75}
76
77impl Neg for JubJubAffine {
78 type Output = JubJubAffine;
79
80 #[inline]
83 fn neg(self) -> JubJubAffine {
84 JubJubAffine {
85 x: -self.x,
86 y: self.y,
87 }
88 }
89}
90
91impl ConstantTimeEq for JubJubAffine {
92 fn ct_eq(&self, other: &Self) -> Choice {
93 self.x.ct_eq(&other.x) & self.y.ct_eq(&other.y)
94 }
95}
96
97impl PartialEq for JubJubAffine {
98 fn eq(&self, other: &Self) -> bool {
99 self.ct_eq(other).unwrap_u8() == 1
100 }
101}
102
103impl ConditionallySelectable for JubJubAffine {
104 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
105 JubJubAffine {
106 x: BlsScalar::conditional_select(&a.x, &b.x, choice),
107 y: BlsScalar::conditional_select(&a.y, &b.y, choice),
108 }
109 }
110}
111
112pub const GENERATOR: JubJubAffine = JubJubAffine {
123 x: BlsScalar::from_raw([
124 0x4df7b7ffec7beaca,
125 0x2e3ebb21fd6c54ed,
126 0xf1fbf02d0fd6cce6,
127 0x3fd2814c43ac65a6,
128 ]),
129 y: BlsScalar::from_raw([
130 0x0000000000000012,
131 000000000000000000,
132 000000000000000000,
133 000000000000,
134 ]),
135};
136
137pub const GENERATOR_EXTENDED: JubJubExtended = JubJubExtended {
139 x: GENERATOR.x,
140 y: GENERATOR.y,
141 z: BlsScalar::one(),
142 t1: GENERATOR.x,
143 t2: GENERATOR.y,
144};
145
146pub const GENERATOR_NUMS: JubJubAffine = JubJubAffine {
153 x: BlsScalar::from_raw([
154 0x921710179df76377,
155 0x931e316a39fe4541,
156 0xbd9514c773fd4456,
157 0x5e67b8f316f414f7,
158 ]),
159 y: BlsScalar::from_raw([
160 0x6705b707162e3ef8,
161 0x9949ba0f82a5507a,
162 0x7b162dbeeb3b34fd,
163 0x43d80eb3b2f3eb1b,
164 ]),
165};
166
167pub const GENERATOR_NUMS_EXTENDED: JubJubExtended = JubJubExtended {
169 x: GENERATOR_NUMS.x,
170 y: GENERATOR_NUMS.y,
171 z: BlsScalar::one(),
172 t1: GENERATOR_NUMS.x,
173 t2: GENERATOR_NUMS.y,
174};
175
176#[derive(Clone, Copy, Debug)]
194#[cfg_attr(feature = "canon", derive(Canon))]
195pub struct JubJubExtended {
196 x: BlsScalar,
197 y: BlsScalar,
198 z: BlsScalar,
199 t1: BlsScalar,
200 t2: BlsScalar,
201}
202
203impl ConstantTimeEq for JubJubExtended {
204 fn ct_eq(&self, other: &Self) -> Choice {
205 (&self.x * &other.z).ct_eq(&(&other.x * &self.z))
211 & (&self.y * &other.z).ct_eq(&(&other.y * &self.z))
212 }
213}
214
215impl ConditionallySelectable for JubJubExtended {
216 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
217 JubJubExtended {
218 x: BlsScalar::conditional_select(&a.x, &b.x, choice),
219 y: BlsScalar::conditional_select(&a.y, &b.y, choice),
220 z: BlsScalar::conditional_select(&a.z, &b.z, choice),
221 t1: BlsScalar::conditional_select(&a.t1, &b.t1, choice),
222 t2: BlsScalar::conditional_select(&a.t2, &b.t2, choice),
223 }
224 }
225}
226
227impl PartialEq for JubJubExtended {
228 fn eq(&self, other: &Self) -> bool {
229 self.ct_eq(other).unwrap_u8() == 1
230 }
231}
232
233impl Neg for JubJubExtended {
234 type Output = JubJubExtended;
235
236 #[inline]
240 fn neg(self) -> JubJubExtended {
241 JubJubExtended {
242 x: -self.x,
243 y: self.y,
244 z: self.z,
245 t1: -self.t1,
246 t2: self.t2,
247 }
248 }
249}
250
251impl From<JubJubAffine> for JubJubExtended {
252 fn from(affine: JubJubAffine) -> JubJubExtended {
255 JubJubExtended {
256 x: affine.x,
257 y: affine.y,
258 z: BlsScalar::one(),
259 t1: affine.x,
260 t2: affine.y,
261 }
262 }
263}
264
265impl<'a> From<&'a JubJubExtended> for JubJubAffine {
266 fn from(extended: &'a JubJubExtended) -> JubJubAffine {
272 let zinv = extended.z.invert().unwrap();
275
276 JubJubAffine {
277 x: extended.x * &zinv,
278 y: extended.y * &zinv,
279 }
280 }
281}
282
283impl From<JubJubExtended> for JubJubAffine {
284 fn from(extended: JubJubExtended) -> JubJubAffine {
285 JubJubAffine::from(&extended)
286 }
287}
288
289#[derive(Clone, Copy, Debug)]
293pub struct AffineNielsPoint {
294 y_plus_x: BlsScalar,
295 y_minus_x: BlsScalar,
296 t2d: BlsScalar,
297}
298
299impl AffineNielsPoint {
300 pub const fn identity() -> Self {
302 AffineNielsPoint {
303 y_plus_x: BlsScalar::one(),
304 y_minus_x: BlsScalar::one(),
305 t2d: BlsScalar::zero(),
306 }
307 }
308
309 #[inline]
310 fn multiply(&self, by: &[u8; 32]) -> JubJubExtended {
311 let zero = AffineNielsPoint::identity();
312
313 let mut acc = JubJubExtended::identity();
314
315 for bit in by
322 .iter()
323 .rev()
324 .flat_map(|byte| {
325 (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))
326 })
327 .skip(4)
328 {
329 acc = acc.double();
330 acc += AffineNielsPoint::conditional_select(&zero, &self, bit);
331 }
332
333 acc
334 }
335
336 pub fn multiply_bits(&self, by: &[u8; 32]) -> JubJubExtended {
339 self.multiply(by)
340 }
341}
342
343impl<'a, 'b> Mul<&'b Fr> for &'a AffineNielsPoint {
344 type Output = JubJubExtended;
345
346 fn mul(self, other: &'b Fr) -> JubJubExtended {
347 self.multiply(&other.to_bytes())
348 }
349}
350
351impl_binops_multiplicative_mixed!(AffineNielsPoint, Fr, JubJubExtended);
352
353impl ConditionallySelectable for AffineNielsPoint {
354 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
355 AffineNielsPoint {
356 y_plus_x: BlsScalar::conditional_select(
357 &a.y_plus_x,
358 &b.y_plus_x,
359 choice,
360 ),
361 y_minus_x: BlsScalar::conditional_select(
362 &a.y_minus_x,
363 &b.y_minus_x,
364 choice,
365 ),
366 t2d: BlsScalar::conditional_select(&a.t2d, &b.t2d, choice),
367 }
368 }
369}
370
371#[derive(Clone, Copy, Debug)]
374pub struct ExtendedNielsPoint {
375 y_plus_x: BlsScalar,
376 y_minus_x: BlsScalar,
377 z: BlsScalar,
378 t2d: BlsScalar,
379}
380
381impl ConditionallySelectable for ExtendedNielsPoint {
382 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
383 ExtendedNielsPoint {
384 y_plus_x: BlsScalar::conditional_select(
385 &a.y_plus_x,
386 &b.y_plus_x,
387 choice,
388 ),
389 y_minus_x: BlsScalar::conditional_select(
390 &a.y_minus_x,
391 &b.y_minus_x,
392 choice,
393 ),
394 z: BlsScalar::conditional_select(&a.z, &b.z, choice),
395 t2d: BlsScalar::conditional_select(&a.t2d, &b.t2d, choice),
396 }
397 }
398}
399
400impl ExtendedNielsPoint {
401 pub const fn identity() -> Self {
403 ExtendedNielsPoint {
404 y_plus_x: BlsScalar::one(),
405 y_minus_x: BlsScalar::one(),
406 z: BlsScalar::one(),
407 t2d: BlsScalar::zero(),
408 }
409 }
410
411 #[inline]
412 fn multiply(&self, by: &[u8; 32]) -> JubJubExtended {
413 let zero = ExtendedNielsPoint::identity();
414
415 let mut acc = JubJubExtended::identity();
416
417 for bit in by
424 .iter()
425 .rev()
426 .flat_map(|byte| {
427 (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))
428 })
429 .skip(4)
430 {
431 acc = acc.double();
432 acc += ExtendedNielsPoint::conditional_select(&zero, &self, bit);
433 }
434
435 acc
436 }
437
438 pub fn multiply_bits(&self, by: &[u8; 32]) -> JubJubExtended {
441 self.multiply(by)
442 }
443}
444
445impl<'a, 'b> Mul<&'b Fr> for &'a ExtendedNielsPoint {
446 type Output = JubJubExtended;
447
448 fn mul(self, other: &'b Fr) -> JubJubExtended {
449 self.multiply(&other.to_bytes())
450 }
451}
452
453impl_binops_multiplicative_mixed!(ExtendedNielsPoint, Fr, JubJubExtended);
454
455pub const EDWARDS_D: BlsScalar = BlsScalar::from_raw([
457 0x01065fd6d6343eb1,
458 0x292d7f6d37579d26,
459 0xf5fd9207e6bd7fd4,
460 0x2a9318e74bfa2b48,
461]);
462
463pub const EDWARDS_D2: BlsScalar = BlsScalar::from_raw([
465 0x020cbfadac687d62,
466 0x525afeda6eaf3a4c,
467 0xebfb240fcd7affa8,
468 0x552631ce97f45691,
469]);
470
471impl Serializable<32> for JubJubAffine {
472 type Error = BytesError;
473
474 fn to_bytes(&self) -> [u8; Self::SIZE] {
476 let mut tmp = self.y.to_bytes();
477 let x = self.x.to_bytes();
478
479 tmp[31] |= x[0] << 7;
482
483 tmp
484 }
485
486 fn from_bytes(b: &[u8; Self::SIZE]) -> Result<Self, Self::Error> {
494 let mut b = b.clone();
495
496 let sign = b[31] >> 7;
498
499 b[31] &= 0b0111_1111;
501
502 let y = BlsScalar::from_bytes(&b)?;
504
505 let y2 = y.square();
517
518 Option::from(
519 ((y2 - BlsScalar::one())
520 * ((BlsScalar::one() + EDWARDS_D * &y2)
521 .invert()
522 .unwrap_or(BlsScalar::zero())))
523 .sqrt()
524 .and_then(|x| {
525 let flip_sign = Choice::from((x.to_bytes()[0] ^ sign) & 1);
527 let x = BlsScalar::conditional_select(&x, &-x, flip_sign);
528 let x_is_zero = x.ct_eq(&BlsScalar::zero());
534 CtOption::new(JubJubAffine { x, y }, !(x_is_zero & flip_sign))
535 }),
536 )
537 .ok_or(BytesError::InvalidData)
538 }
539}
540
541impl JubJubAffine {
542 pub const fn identity() -> Self {
544 JubJubAffine {
545 x: BlsScalar::zero(),
546 y: BlsScalar::one(),
547 }
548 }
549
550 pub fn mul_by_cofactor(&self) -> JubJubExtended {
553 JubJubExtended::from(*self).mul_by_cofactor()
554 }
555
556 pub fn is_small_order(&self) -> Choice {
558 JubJubExtended::from(*self).is_small_order()
559 }
560
561 pub fn is_torsion_free(&self) -> Choice {
564 JubJubExtended::from(*self).is_torsion_free()
565 }
566
567 pub fn is_prime_order(&self) -> Choice {
572 let extended = JubJubExtended::from(*self);
573 extended.is_torsion_free() & (!extended.is_identity())
574 }
575
576 pub fn get_x(&self) -> BlsScalar {
578 self.x
579 }
580
581 pub fn get_y(&self) -> BlsScalar {
583 self.y
584 }
585
586 pub const fn to_niels(&self) -> AffineNielsPoint {
589 AffineNielsPoint {
590 y_plus_x: BlsScalar::add(&self.y, &self.x),
591 y_minus_x: BlsScalar::sub(&self.y, &self.x),
592 t2d: BlsScalar::mul(&BlsScalar::mul(&self.x, &self.y), &EDWARDS_D2),
593 }
594 }
595
596 pub const fn from_raw_unchecked(
599 x: BlsScalar,
600 y: BlsScalar,
601 ) -> JubJubAffine {
602 JubJubAffine { x, y }
603 }
604
605 #[cfg(test)]
609 fn is_on_curve_vartime(&self) -> bool {
610 let x2 = self.x.square();
611 let y2 = self.y.square();
612
613 &y2 - &x2 == BlsScalar::one() + &EDWARDS_D * &x2 * &y2
614 }
615}
616
617impl JubJubExtended {
618 pub fn get_x(&self) -> BlsScalar {
620 self.x
621 }
622
623 pub fn get_y(&self) -> BlsScalar {
625 self.y
626 }
627
628 pub fn get_z(&self) -> BlsScalar {
630 self.z
631 }
632
633 pub fn get_t1(&self) -> BlsScalar {
635 self.t1
636 }
637
638 pub fn get_t2(&self) -> BlsScalar {
640 self.t2
641 }
642
643 pub const fn identity() -> Self {
645 JubJubExtended {
646 x: BlsScalar::zero(),
647 y: BlsScalar::one(),
648 z: BlsScalar::one(),
649 t1: BlsScalar::zero(),
650 t2: BlsScalar::zero(),
651 }
652 }
653
654 pub fn is_identity(&self) -> Choice {
656 self.x.ct_eq(&BlsScalar::zero()) & self.y.ct_eq(&self.z)
660 }
661
662 pub fn is_small_order(&self) -> Choice {
664 self.double().double().x.ct_eq(&BlsScalar::zero())
669 }
670
671 pub fn is_torsion_free(&self) -> Choice {
674 self.multiply(&FR_MODULUS_BYTES).is_identity()
675 }
676
677 pub fn is_prime_order(&self) -> Choice {
682 self.is_torsion_free() & (!self.is_identity())
683 }
684
685 pub fn mul_by_cofactor(&self) -> JubJubExtended {
687 self.double().double().double()
688 }
689
690 pub fn to_niels(&self) -> ExtendedNielsPoint {
693 ExtendedNielsPoint {
694 y_plus_x: &self.y + &self.x,
695 y_minus_x: &self.y - &self.x,
696 z: self.z,
697 t2d: &self.t1 * &self.t2 * EDWARDS_D2,
698 }
699 }
700
701 pub fn to_hash_inputs(&self) -> [BlsScalar; 2] {
704 let p = JubJubAffine::from(self);
708 [p.x, p.y]
709 }
710
711 pub fn double(&self) -> JubJubExtended {
714 let xx = self.x.square();
791 let yy = self.y.square();
792 let zz2 = self.z.square().double();
793 let xy2 = (&self.x + &self.y).square();
794 let yy_plus_xx = &yy + &xx;
795 let yy_minus_xx = &yy - &xx;
796
797 CompletedPoint {
800 x: &xy2 - &yy_plus_xx,
801 y: yy_plus_xx,
802 z: yy_minus_xx,
803 t: &zz2 - &yy_minus_xx,
804 }
805 .into_extended()
806 }
807
808 #[inline]
809 fn multiply(self, by: &[u8; 32]) -> Self {
810 self.to_niels().multiply(by)
811 }
812
813 #[cfg(test)]
817 fn is_on_curve_vartime(&self) -> bool {
818 let affine = JubJubAffine::from(*self);
819
820 self.z != BlsScalar::zero()
821 && affine.is_on_curve_vartime()
822 && (affine.x * affine.y * self.z == self.t1 * self.t2)
823 }
824}
825
826impl<'a, 'b> Mul<&'b Fr> for &'a JubJubExtended {
827 type Output = JubJubExtended;
828
829 fn mul(self, other: &'b Fr) -> JubJubExtended {
830 self.multiply(&other.to_bytes())
831 }
832}
833
834impl_binops_multiplicative!(JubJubExtended, Fr);
835
836impl<'a, 'b> Add<&'b ExtendedNielsPoint> for &'a JubJubExtended {
837 type Output = JubJubExtended;
838
839 #[allow(clippy::suspicious_arithmetic_impl)]
840 fn add(self, other: &'b ExtendedNielsPoint) -> JubJubExtended {
841 let a = (&self.y - &self.x) * &other.y_minus_x;
859 let b = (&self.y + &self.x) * &other.y_plus_x;
860 let c = &self.t1 * &self.t2 * &other.t2d;
861 let d = (&self.z * &other.z).double();
862
863 CompletedPoint {
866 x: &b - &a,
867 y: &b + &a,
868 z: &d + &c,
869 t: &d - &c,
870 }
871 .into_extended()
872 }
873}
874
875impl<'a, 'b> Sub<&'b ExtendedNielsPoint> for &'a JubJubExtended {
876 type Output = JubJubExtended;
877
878 #[allow(clippy::suspicious_arithmetic_impl)]
879 fn sub(self, other: &'b ExtendedNielsPoint) -> JubJubExtended {
880 let a = (&self.y - &self.x) * &other.y_plus_x;
881 let b = (&self.y + &self.x) * &other.y_minus_x;
882 let c = &self.t1 * &self.t2 * &other.t2d;
883 let d = (&self.z * &other.z).double();
884
885 CompletedPoint {
886 x: &b - &a,
887 y: &b + &a,
888 z: &d - &c,
889 t: &d + &c,
890 }
891 .into_extended()
892 }
893}
894
895impl_binops_additive!(JubJubExtended, ExtendedNielsPoint);
896
897impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a JubJubExtended {
898 type Output = JubJubExtended;
899
900 #[allow(clippy::suspicious_arithmetic_impl)]
901 fn add(self, other: &'b AffineNielsPoint) -> JubJubExtended {
902 let a = (&self.y - &self.x) * &other.y_minus_x;
907 let b = (&self.y + &self.x) * &other.y_plus_x;
908 let c = &self.t1 * &self.t2 * &other.t2d;
909 let d = self.z.double();
910
911 CompletedPoint {
914 x: &b - &a,
915 y: &b + &a,
916 z: &d + &c,
917 t: &d - &c,
918 }
919 .into_extended()
920 }
921}
922
923impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a JubJubExtended {
924 type Output = JubJubExtended;
925
926 #[allow(clippy::suspicious_arithmetic_impl)]
927 fn sub(self, other: &'b AffineNielsPoint) -> JubJubExtended {
928 let a = (&self.y - &self.x) * &other.y_plus_x;
929 let b = (&self.y + &self.x) * &other.y_minus_x;
930 let c = &self.t1 * &self.t2 * &other.t2d;
931 let d = self.z.double();
932
933 CompletedPoint {
934 x: &b - &a,
935 y: &b + &a,
936 z: &d - &c,
937 t: &d + &c,
938 }
939 .into_extended()
940 }
941}
942
943impl_binops_additive!(JubJubExtended, AffineNielsPoint);
944
945impl<'a, 'b> Add<&'b JubJubExtended> for &'a JubJubExtended {
946 type Output = JubJubExtended;
947
948 #[inline]
949 fn add(self, other: &'b JubJubExtended) -> JubJubExtended {
950 self + other.to_niels()
951 }
952}
953
954impl<'a, 'b> Sub<&'b JubJubExtended> for &'a JubJubExtended {
955 type Output = JubJubExtended;
956
957 #[inline]
958 fn sub(self, other: &'b JubJubExtended) -> JubJubExtended {
959 self - other.to_niels()
960 }
961}
962
963impl_binops_additive!(JubJubExtended, JubJubExtended);
964
965impl<'a, 'b> Add<&'b JubJubAffine> for &'a JubJubExtended {
966 type Output = JubJubExtended;
967
968 #[inline]
969 fn add(self, other: &'b JubJubAffine) -> JubJubExtended {
970 self + other.to_niels()
971 }
972}
973
974impl<'a, 'b> Sub<&'b JubJubAffine> for &'a JubJubExtended {
975 type Output = JubJubExtended;
976
977 #[inline]
978 fn sub(self, other: &'b JubJubAffine) -> JubJubExtended {
979 self - other.to_niels()
980 }
981}
982
983impl_binops_additive!(JubJubExtended, JubJubAffine);
984
985struct CompletedPoint {
990 x: BlsScalar,
991 y: BlsScalar,
992 z: BlsScalar,
993 t: BlsScalar,
994}
995
996impl CompletedPoint {
997 #[inline]
1005 fn into_extended(self) -> JubJubExtended {
1006 JubJubExtended {
1007 x: &self.x * &self.t,
1008 y: &self.y * &self.z,
1009 z: &self.z * &self.t,
1010 t1: self.x,
1011 t2: self.y,
1012 }
1013 }
1014}
1015
1016impl Default for JubJubAffine {
1017 fn default() -> JubJubAffine {
1019 JubJubAffine::identity()
1020 }
1021}
1022
1023impl Default for JubJubExtended {
1024 fn default() -> JubJubExtended {
1026 JubJubExtended::identity()
1027 }
1028}
1029
1030pub fn batch_normalize<'a>(
1038 y: &'a mut [JubJubExtended],
1039) -> impl Iterator<Item = JubJubAffine> + 'a {
1040 let mut acc = BlsScalar::one();
1041 for p in y.iter_mut() {
1042 p.t1 = acc;
1045 acc *= &p.z;
1046 }
1047
1048 acc = acc.invert().unwrap();
1050
1051 for p in y.iter_mut().rev() {
1052 let mut q = *p;
1053
1054 let tmp = q.t1 * acc;
1056
1057 acc *= &q.z;
1059
1060 q.x *= &tmp; q.y *= &tmp; q.z = BlsScalar::one(); q.t1 = q.x;
1065 q.t2 = q.y;
1066
1067 *p = q;
1068 }
1069
1070 y.iter().map(|p| JubJubAffine { x: p.x, y: p.y })
1075}
1076
1077#[test]
1078fn test_is_on_curve_var() {
1079 assert!(JubJubAffine::identity().is_on_curve_vartime());
1080}
1081
1082#[test]
1083fn test_affine_point_generator_has_order_p() {
1084 assert_eq!(GENERATOR.is_prime_order().unwrap_u8(), 1);
1085}
1086
1087#[test]
1088fn test_extended_point_generator_has_order_p() {
1089 assert_eq!(GENERATOR_EXTENDED.is_prime_order().unwrap_u8(), 1);
1090}
1091
1092#[test]
1093fn test_affine_point_generator_nums_has_order_p() {
1094 assert_eq!(GENERATOR_NUMS.is_prime_order().unwrap_u8(), 1);
1095}
1096
1097#[test]
1098fn test_affine_point_generator_is_not_identity() {
1099 assert_ne!(
1100 JubJubExtended::from(GENERATOR.mul_by_cofactor()),
1101 JubJubExtended::identity()
1102 );
1103}
1104
1105#[test]
1106fn test_extended_point_generator_is_not_identity() {
1107 assert_ne!(
1108 GENERATOR_EXTENDED.mul_by_cofactor(),
1109 JubJubExtended::identity()
1110 );
1111}
1112
1113#[test]
1114fn test_affine_point_generator_nums_is_not_identity() {
1115 assert_ne!(
1116 JubJubExtended::from(GENERATOR_NUMS.mul_by_cofactor()),
1117 JubJubExtended::identity()
1118 );
1119}
1120
1121#[test]
1122fn test_d_is_non_quadratic_residue() {
1123 assert!(EDWARDS_D.sqrt().is_none().unwrap_u8() == 1);
1124 assert!((-EDWARDS_D).sqrt().is_none().unwrap_u8() == 1);
1125 assert!((-EDWARDS_D).invert().unwrap().sqrt().is_none().unwrap_u8() == 1);
1126}
1127
1128#[test]
1129fn test_affine_niels_point_identity() {
1130 assert_eq!(
1131 AffineNielsPoint::identity().y_plus_x,
1132 JubJubAffine::identity().to_niels().y_plus_x
1133 );
1134 assert_eq!(
1135 AffineNielsPoint::identity().y_minus_x,
1136 JubJubAffine::identity().to_niels().y_minus_x
1137 );
1138 assert_eq!(
1139 AffineNielsPoint::identity().t2d,
1140 JubJubAffine::identity().to_niels().t2d
1141 );
1142}
1143
1144#[test]
1145fn test_extended_niels_point_identity() {
1146 assert_eq!(
1147 ExtendedNielsPoint::identity().y_plus_x,
1148 JubJubExtended::identity().to_niels().y_plus_x
1149 );
1150 assert_eq!(
1151 ExtendedNielsPoint::identity().y_minus_x,
1152 JubJubExtended::identity().to_niels().y_minus_x
1153 );
1154 assert_eq!(
1155 ExtendedNielsPoint::identity().z,
1156 JubJubExtended::identity().to_niels().z
1157 );
1158 assert_eq!(
1159 ExtendedNielsPoint::identity().t2d,
1160 JubJubExtended::identity().to_niels().t2d
1161 );
1162}
1163
1164#[test]
1165fn test_assoc() {
1166 let p = JubJubExtended::from(JubJubAffine {
1167 x: BlsScalar::from_raw([
1168 0x81c571e5d883cfb0,
1169 0x049f7a686f147029,
1170 0xf539c860bc3ea21f,
1171 0x4284715b7ccc8162,
1172 ]),
1173 y: BlsScalar::from_raw([
1174 0xbf096275684bb8ca,
1175 0xc7ba245890af256d,
1176 0x59119f3e86380eb0,
1177 0x3793de182f9fb1d2,
1178 ]),
1179 })
1180 .mul_by_cofactor();
1181 assert!(p.is_on_curve_vartime());
1182
1183 assert_eq!(
1184 (p * Fr::from(1000u64)) * Fr::from(3938u64),
1185 p * (Fr::from(1000u64) * Fr::from(3938u64)),
1186 );
1187}
1188
1189#[test]
1190fn test_batch_normalize() {
1191 let mut p = JubJubExtended::from(JubJubAffine {
1192 x: BlsScalar::from_raw([
1193 0x81c571e5d883cfb0,
1194 0x049f7a686f147029,
1195 0xf539c860bc3ea21f,
1196 0x4284715b7ccc8162,
1197 ]),
1198 y: BlsScalar::from_raw([
1199 0xbf096275684bb8ca,
1200 0xc7ba245890af256d,
1201 0x59119f3e86380eb0,
1202 0x3793de182f9fb1d2,
1203 ]),
1204 })
1205 .mul_by_cofactor();
1206
1207 let mut y = vec![];
1208 for _ in 0..10 {
1209 y.push(p);
1210 p = p.double();
1211 }
1212
1213 for p in &y {
1214 assert!(p.is_on_curve_vartime());
1215 }
1216
1217 let expected: std::vec::Vec<_> =
1218 y.iter().map(|p| JubJubAffine::from(*p)).collect();
1219 let result1: std::vec::Vec<_> = batch_normalize(&mut y).collect();
1220 for i in 0..10 {
1221 assert!(expected[i] == result1[i]);
1222 assert!(y[i].is_on_curve_vartime());
1223 assert!(JubJubAffine::from(y[i]) == expected[i]);
1224 }
1225 let result2: std::vec::Vec<_> = batch_normalize(&mut y).collect();
1226 for i in 0..10 {
1227 assert!(expected[i] == result2[i]);
1228 assert!(y[i].is_on_curve_vartime());
1229 assert!(JubJubAffine::from(y[i]) == expected[i]);
1230 }
1231}
1232
1233#[cfg(test)]
1234const FULL_GENERATOR: JubJubAffine = JubJubAffine::from_raw_unchecked(
1235 BlsScalar::from_raw([
1236 0xe4b3d35df1a7adfe,
1237 0xcaf55d1b29bf81af,
1238 0x8b0f03ddd60a8187,
1239 0x62edcbb8bf3787c8,
1240 ]),
1241 BlsScalar::from_raw([0xb, 0x0, 0x0, 0x0]),
1242);
1243
1244#[cfg(test)]
1245const EIGHT_TORSION: [JubJubAffine; 8] = [
1246 JubJubAffine::from_raw_unchecked(
1247 BlsScalar::from_raw([
1248 0xd92e6a7927200d43,
1249 0x7aa41ac43dae8582,
1250 0xeaaae086a16618d1,
1251 0x71d4df38ba9e7973,
1252 ]),
1253 BlsScalar::from_raw([
1254 0xff0d2068eff496dd,
1255 0x9106ee90f384a4a1,
1256 0x16a13035ad4d7266,
1257 0x4958bdb21966982e,
1258 ]),
1259 ),
1260 JubJubAffine::from_raw_unchecked(
1261 BlsScalar::from_raw([
1262 0xfffeffff00000001,
1263 0x67baa40089fb5bfe,
1264 0xa5e80b39939ed334,
1265 0x73eda753299d7d47,
1266 ]),
1267 BlsScalar::from_raw([0x0, 0x0, 0x0, 0x0]),
1268 ),
1269 JubJubAffine::from_raw_unchecked(
1270 BlsScalar::from_raw([
1271 0xd92e6a7927200d43,
1272 0x7aa41ac43dae8582,
1273 0xeaaae086a16618d1,
1274 0x71d4df38ba9e7973,
1275 ]),
1276 BlsScalar::from_raw([
1277 0xf2df96100b6924,
1278 0xc2b6b5720c79b75d,
1279 0x1c98a7d25c54659e,
1280 0x2a94e9a11036e51a,
1281 ]),
1282 ),
1283 JubJubAffine::from_raw_unchecked(
1284 BlsScalar::from_raw([0x0, 0x0, 0x0, 0x0]),
1285 BlsScalar::from_raw([
1286 0xffffffff00000000,
1287 0x53bda402fffe5bfe,
1288 0x3339d80809a1d805,
1289 0x73eda753299d7d48,
1290 ]),
1291 ),
1292 JubJubAffine::from_raw_unchecked(
1293 BlsScalar::from_raw([
1294 0x26d19585d8dff2be,
1295 0xd919893ec24fd67c,
1296 0x488ef781683bbf33,
1297 0x218c81a6eff03d4,
1298 ]),
1299 BlsScalar::from_raw([
1300 0xf2df96100b6924,
1301 0xc2b6b5720c79b75d,
1302 0x1c98a7d25c54659e,
1303 0x2a94e9a11036e51a,
1304 ]),
1305 ),
1306 JubJubAffine::from_raw_unchecked(
1307 BlsScalar::from_raw([
1308 0x1000000000000,
1309 0xec03000276030000,
1310 0x8d51ccce760304d0,
1311 0x0,
1312 ]),
1313 BlsScalar::from_raw([0x0, 0x0, 0x0, 0x0]),
1314 ),
1315 JubJubAffine::from_raw_unchecked(
1316 BlsScalar::from_raw([
1317 0x26d19585d8dff2be,
1318 0xd919893ec24fd67c,
1319 0x488ef781683bbf33,
1320 0x218c81a6eff03d4,
1321 ]),
1322 BlsScalar::from_raw([
1323 0xff0d2068eff496dd,
1324 0x9106ee90f384a4a1,
1325 0x16a13035ad4d7266,
1326 0x4958bdb21966982e,
1327 ]),
1328 ),
1329 JubJubAffine::from_raw_unchecked(
1330 BlsScalar::from_raw([0x0, 0x0, 0x0, 0x0]),
1331 BlsScalar::from_raw([0x1, 0x0, 0x0, 0x0]),
1332 ),
1333];
1334
1335#[test]
1336fn find_eight_torsion() {
1337 let g = JubJubExtended::from(FULL_GENERATOR);
1338 assert!(g.is_small_order().unwrap_u8() == 0);
1339 let g = g.multiply(&FR_MODULUS_BYTES);
1340 assert!(g.is_small_order().unwrap_u8() == 1);
1341
1342 let mut cur = g;
1343
1344 for (i, point) in EIGHT_TORSION.iter().enumerate() {
1345 let tmp = JubJubAffine::from(cur);
1346 if &tmp != point {
1347 panic!("{}th torsion point should be {:?}", i, tmp);
1348 }
1349
1350 cur += &g;
1351 }
1352}
1353
1354#[test]
1355fn find_curve_generator() {
1356 let mut trial_bytes = [0; 32];
1357 for _ in 0..255 {
1358 let a = JubJubAffine::from_bytes(&trial_bytes);
1359 if a.is_ok() {
1360 let a = a.unwrap();
1361 assert!(a.is_on_curve_vartime());
1362 let b = JubJubExtended::from(a);
1363 let b = b.multiply(&FR_MODULUS_BYTES);
1364 assert!(b.is_small_order().unwrap_u8() == 1);
1365 let b = b.double();
1366 assert!(b.is_small_order().unwrap_u8() == 1);
1367 let b = b.double();
1368 assert!(b.is_small_order().unwrap_u8() == 1);
1369 if b.is_identity().unwrap_u8() == 0 {
1370 let b = b.double();
1371 assert!(b.is_small_order().unwrap_u8() == 1);
1372 assert!(b.is_identity().unwrap_u8() == 1);
1373 assert_eq!(FULL_GENERATOR, a);
1374 assert!(a.mul_by_cofactor().is_torsion_free().unwrap_u8() == 1);
1375 return;
1376 }
1377 }
1378
1379 trial_bytes[0] += 1;
1380 }
1381
1382 panic!("should have found a generator of the curve");
1383}
1384
1385#[test]
1386fn test_small_order() {
1387 for point in EIGHT_TORSION.iter() {
1388 assert!(point.is_small_order().unwrap_u8() == 1);
1389 }
1390}
1391
1392#[ignore]
1393#[test]
1394fn second_gen_nums() {
1395 use blake2::{Blake2b, Digest};
1396 let generator_bytes = GENERATOR.to_bytes();
1397 let mut counter = 0u64;
1398 let mut array = [0u8; 32];
1399 loop {
1400 let mut hasher = Blake2b::new();
1401 hasher.update(generator_bytes);
1402 hasher.update(counter.to_le_bytes());
1403 let res = hasher.finalize();
1404 array.copy_from_slice(&res[0..32]);
1405 if JubJubAffine::from_bytes(&array).is_ok()
1406 && JubJubAffine::from_bytes(&array)
1407 .unwrap()
1408 .is_prime_order()
1409 .unwrap_u8()
1410 == 1
1411 {
1412 assert!(
1413 GENERATOR_NUMS == JubJubAffine::from_bytes(&array).unwrap()
1414 );
1415 }
1416 counter += 1;
1417 }
1418}
1419
1420#[test]
1421fn test_is_identity() {
1422 let a = EIGHT_TORSION[0].mul_by_cofactor();
1423 let b = EIGHT_TORSION[1].mul_by_cofactor();
1424
1425 assert_eq!(a.x, b.x);
1426 assert_eq!(a.y, a.z);
1427 assert_eq!(b.y, b.z);
1428 assert!(a.y != b.y);
1429 assert!(a.z != b.z);
1430
1431 assert!(a.is_identity().unwrap_u8() == 1);
1432 assert!(b.is_identity().unwrap_u8() == 1);
1433
1434 for point in EIGHT_TORSION.iter() {
1435 assert!(point.mul_by_cofactor().is_identity().unwrap_u8() == 1);
1436 }
1437}
1438
1439#[test]
1440fn test_mul_consistency() {
1441 let a = Fr([
1442 0x21e61211d9934f2e,
1443 0xa52c058a693c3e07,
1444 0x9ccb77bfb12d6360,
1445 0x07df2470ec94398e,
1446 ]);
1447 let b = Fr([
1448 0x03336d1cbe19dbe0,
1449 0x0153618f6156a536,
1450 0x2604c9e1fc3c6b15,
1451 0x04ae581ceb028720,
1452 ]);
1453 let c = Fr([
1454 0xd7abf5bb24683f4c,
1455 0x9d7712cc274b7c03,
1456 0x973293db9683789f,
1457 0x0b677e29380a97a7,
1458 ]);
1459 assert_eq!(a * b, c);
1460 let p = JubJubExtended::from(JubJubAffine {
1461 x: BlsScalar::from_raw([
1462 0x81c571e5d883cfb0,
1463 0x049f7a686f147029,
1464 0xf539c860bc3ea21f,
1465 0x4284715b7ccc8162,
1466 ]),
1467 y: BlsScalar::from_raw([
1468 0xbf096275684bb8ca,
1469 0xc7ba245890af256d,
1470 0x59119f3e86380eb0,
1471 0x3793de182f9fb1d2,
1472 ]),
1473 })
1474 .mul_by_cofactor();
1475 assert_eq!(p * c, (p * a) * b);
1476
1477 assert_eq!(p * c, (p.to_niels() * a) * b);
1479 assert_eq!(p.to_niels() * c, (p * a) * b);
1480 assert_eq!(p.to_niels() * c, (p.to_niels() * a) * b);
1481
1482 let p_affine_niels = JubJubAffine::from(p).to_niels();
1484 assert_eq!(p * c, (p_affine_niels * a) * b);
1485 assert_eq!(p_affine_niels * c, (p * a) * b);
1486 assert_eq!(p_affine_niels * c, (p_affine_niels * a) * b);
1487}
1488
1489#[test]
1490fn test_serialization_consistency() {
1491 let gen = FULL_GENERATOR.mul_by_cofactor();
1492 let mut p = gen;
1493
1494 let y = vec![
1495 [
1496 203, 85, 12, 213, 56, 234, 12, 193, 19, 132, 128, 64, 142, 110,
1497 170, 185, 179, 108, 97, 63, 13, 211, 247, 120, 79, 219, 110, 234,
1498 131, 123, 19, 215,
1499 ],
1500 [
1501 113, 154, 240, 230, 224, 198, 208, 170, 104, 15, 59, 126, 151, 222,
1502 233, 195, 203, 195, 167, 129, 89, 121, 240, 142, 51, 166, 64, 250,
1503 184, 202, 154, 177,
1504 ],
1505 [
1506 197, 41, 93, 209, 203, 55, 164, 174, 88, 0, 90, 199, 1, 156, 149,
1507 141, 240, 29, 14, 82, 86, 225, 126, 129, 186, 157, 148, 162, 219,
1508 51, 156, 199,
1509 ],
1510 [
1511 182, 117, 250, 241, 81, 196, 199, 227, 151, 74, 243, 17, 221, 97,
1512 200, 139, 192, 83, 231, 35, 214, 14, 95, 69, 130, 201, 4, 116, 177,
1513 19, 179, 0,
1514 ],
1515 [
1516 118, 41, 29, 200, 60, 189, 119, 252, 78, 40, 230, 18, 208, 221, 38,
1517 214, 176, 250, 4, 10, 77, 101, 26, 216, 193, 198, 226, 84, 25, 177,
1518 230, 185,
1519 ],
1520 [
1521 226, 189, 227, 208, 112, 117, 136, 98, 72, 38, 211, 167, 254, 82,
1522 174, 113, 112, 166, 138, 171, 166, 113, 52, 251, 129, 197, 138, 45,
1523 195, 7, 61, 140,
1524 ],
1525 [
1526 38, 198, 156, 196, 146, 225, 55, 163, 138, 178, 157, 128, 115, 135,
1527 204, 215, 0, 33, 171, 20, 60, 32, 142, 209, 33, 233, 125, 146, 207,
1528 12, 16, 24,
1529 ],
1530 [
1531 17, 187, 231, 83, 165, 36, 232, 184, 140, 205, 195, 252, 166, 85,
1532 59, 86, 3, 226, 211, 67, 179, 29, 238, 181, 102, 142, 58, 63, 57,
1533 89, 174, 138,
1534 ],
1535 [
1536 210, 159, 80, 16, 181, 39, 221, 204, 224, 144, 145, 79, 54, 231, 8,
1537 140, 142, 216, 93, 190, 183, 116, 174, 63, 33, 242, 177, 118, 148,
1538 40, 241, 203,
1539 ],
1540 [
1541 0, 143, 107, 102, 149, 187, 27, 124, 18, 10, 98, 28, 113, 123, 121,
1542 185, 29, 152, 14, 130, 149, 28, 87, 35, 135, 135, 153, 54, 112, 53,
1543 54, 68,
1544 ],
1545 [
1546 178, 131, 85, 160, 214, 51, 208, 157, 196, 152, 247, 93, 202, 56,
1547 81, 239, 155, 122, 59, 188, 237, 253, 11, 169, 208, 236, 12, 4,
1548 163, 211, 88, 97,
1549 ],
1550 [
1551 246, 194, 231, 195, 159, 101, 180, 133, 80, 21, 185, 220, 195, 115,
1552 144, 12, 90, 150, 44, 117, 8, 156, 168, 248, 206, 41, 60, 82, 67,
1553 75, 57, 67,
1554 ],
1555 [
1556 212, 205, 171, 153, 113, 16, 194, 241, 224, 43, 177, 110, 190, 248,
1557 22, 201, 208, 166, 2, 83, 134, 130, 85, 129, 166, 136, 185, 191,
1558 163, 38, 54, 10,
1559 ],
1560 [
1561 8, 60, 190, 39, 153, 222, 119, 23, 142, 237, 12, 110, 146, 9, 19,
1562 219, 143, 64, 161, 99, 199, 77, 39, 148, 70, 213, 246, 227, 150,
1563 178, 237, 178,
1564 ],
1565 [
1566 11, 114, 217, 160, 101, 37, 100, 220, 56, 114, 42, 31, 138, 33, 84,
1567 157, 214, 167, 73, 233, 115, 81, 124, 134, 15, 31, 181, 60, 184,
1568 130, 175, 159,
1569 ],
1570 [
1571 141, 238, 235, 202, 241, 32, 210, 10, 127, 230, 54, 31, 146, 80,
1572 247, 9, 107, 124, 0, 26, 203, 16, 237, 34, 214, 147, 133, 15, 29,
1573 236, 37, 88,
1574 ],
1575 ];
1576
1577 for expected_serialized in y {
1578 assert!(p.is_on_curve_vartime());
1579 let affine = JubJubAffine::from(p);
1580 let serialized = affine.to_bytes();
1581 let deserialized = JubJubAffine::from_bytes(&serialized).unwrap();
1582 assert_eq!(affine, deserialized);
1583 assert_eq!(expected_serialized, serialized);
1584 p = p + &gen;
1585 }
1586}
1587
1588pub fn dhke(secret: &Fr, public: &JubJubExtended) -> JubJubAffine {
1590 public.mul(secret).into()
1591}
1592
1593#[test]
1594fn test_zip_216() {
1595 const NON_CANONICAL_ENCODINGS: [[u8; 32]; 2] = [
1596 [
1598 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1600 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
1601 ],
1602 [
1604 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x5b, 0xfe,
1605 0xff, 0x02, 0xa4, 0xbd, 0x53, 0x05, 0xd8, 0xa1, 0x09, 0x08, 0xd8,
1606 0x39, 0x33, 0x48, 0x7d, 0x9d, 0x29, 0x53, 0xa7, 0xed, 0xf3,
1607 ],
1608 ];
1609
1610 for b in &NON_CANONICAL_ENCODINGS {
1611 let mut encoding = *b;
1612
1613 assert!(bool::from(JubJubAffine::from_bytes(&encoding).is_err()));
1615
1616 encoding[31] &= 0b0111_1111;
1619 assert!(bool::from(JubJubAffine::from_bytes(&encoding).is_ok()));
1620 }
1621}