Repository: dusk-network/bls12_381 (language: rust)

Issue:
Derive/implement Canon for structs that fall under "groups" feature
This is needed for https://github.com/dusk-network/bls12_381-sign/issues/7


Discussion / hints:

Fix patch:
diff --git a/src/fp.rs b/src/fp.rs
index c432b328..97eb9f02 100644
--- a/src/fp.rs
+++ b/src/fp.rs
@@ -1,6 +1,10 @@
 //! This module provides an implementation of the BLS12-381 base field `GF(p)`
 //! where `p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab`
 
+#[cfg(feature = "canon")]
+use canonical::Canon;
+#[cfg(feature = "canon")]
+use canonical_derive::Canon;
 use core::convert::TryFrom;
 use core::fmt;
 use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
@@ -18,6 +22,7 @@ use crate::util::{adc, mac, sbb};
 // integers in little-endian order. `Fp` values are always in
 // Montgomery form; i.e., Scalar(a) = aR mod p, with R = 2^384.
 #[derive(Copy, Clone)]
+#[cfg_attr(feature = "canon", derive(Canon))]
 pub struct Fp([u64; 6]);
 
 impl fmt::Debug for Fp {
diff --git a/src/fp12.rs b/src/fp12.rs
index de9b5407..c31765e4 100644
--- a/src/fp12.rs
+++ b/src/fp12.rs
@@ -2,11 +2,16 @@ use crate::fp::*;
 use crate::fp2::*;
 use crate::fp6::*;
 
+#[cfg(feature = "canon")]
+use canonical::Canon;
+#[cfg(feature = "canon")]
+use canonical_derive::Canon;
 use core::fmt;
 use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
 
 /// This represents an element $c_0 + c_1 w$ of $\mathbb{F}_{p^12} = \mathbb{F}_{p^6} / w^2 - v$.
+#[cfg_attr(feature = "canon", derive(Canon))]
 pub struct Fp12 {
     pub c0: Fp6,
     pub c1: Fp6,
diff --git a/src/fp2.rs b/src/fp2.rs
index 84325288..09ed972b 100644
--- a/src/fp2.rs
+++ b/src/fp2.rs
@@ -1,5 +1,9 @@
 //! This module implements arithmetic over the quadratic extension field Fp2.
 
+#[cfg(feature = "canon")]
+use canonical::Canon;
+#[cfg(feature = "canon")]
+use canonical_derive::Canon;
 use core::fmt;
 use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
@@ -12,6 +16,7 @@ use serde::{
 use crate::fp::Fp;
 
 #[derive(Copy, Clone)]
+#[cfg_attr(feature = "canon", derive(Canon))]
 pub struct Fp2 {
     pub c0: Fp,
     pub c1: Fp,
diff --git a/src/fp6.rs b/src/fp6.rs
index cec615f3..f9606604 100644
--- a/src/fp6.rs
+++ b/src/fp6.rs
@@ -1,6 +1,10 @@
 use crate::fp::*;
 use crate::fp2::*;
 
+#[cfg(feature = "canon")]
+use canonical::Canon;
+#[cfg(feature = "canon")]
+use canonical_derive::Canon;
 use core::fmt;
 use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
 use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
@@ -11,6 +15,7 @@ use serde::{
 };
 
 /// This represents an element $c_0 + c_1 v + c_2 v^2$ of $\mathbb{F}_{p^6} = \mathbb{F}_{p^2} / v^3 - u - 1$.
+#[cfg_attr(feature = "canon", derive(Canon))]
 pub struct Fp6 {
     pub c0: Fp2,
     pub c1: Fp2,
diff --git a/src/g1.rs b/src/g1.rs
index 5ad2448c..c98b60b7 100644
--- a/src/g1.rs
+++ b/src/g1.rs
@@ -1,5 +1,9 @@
 //! This module provides an implementation of the $\mathbb{G}_1$ group of BLS12-381.
 
+#[cfg(feature = "canon")]
+use canonical::{Canon, InvalidEncoding, Sink, Source, Store};
+#[cfg(feature = "canon")]
+use canonical_derive::Canon;
 use core::borrow::Borrow;
 use core::iter::Sum;
 use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
@@ -11,6 +15,8 @@ use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
 use crate::fp::Fp;
 use crate::BlsScalar;
 
+const G1_COMPRESSED_SIZE: usize = 48;
+
 /// This is an element of $\mathbb{G}_1$ represented in the affine coordinate space.
 /// It is ideal to keep elements in this representation to reduce memory usage and
 /// improve performance through the use of mixed curve model arithmetic.
@@ -24,6 +30,27 @@ pub struct G1Affine {
     infinity: Choice,
 }
 
+#[cfg(feature = "canon")]
+impl<S: Store> Canon<S> for G1Affine {
+    fn write(&self, sink: &mut impl Sink<S>) -> Result<(), S::Error> {
+        sink.copy_bytes(&self.to_compressed());
+        Ok(())
+    }
+
+    fn read(source: &mut impl Source<S>) -> Result<Self, S::Error> {
+        let mut bytes = [0u8; G1_COMPRESSED_SIZE];
+        bytes.copy_from_slice(source.read_bytes(G1_COMPRESSED_SIZE));
+        match Option::from(G1Affine::from_compressed(&bytes)) {
+            Some(g1) => Ok(g1),
+            None => Err(InvalidEncoding.into()),
+        }
+    }
+
+    fn encoded_len(&self) -> usize {
+        G1_COMPRESSED_SIZE
+    }
+}
+
 impl Default for G1Affine {
     fn default() -> G1Affine {
         G1Affine::identity()
@@ -461,6 +488,7 @@ impl G1Affine {
 
 /// This is an element of $\mathbb{G}_1$ represented in the projective coordinate space.
 #[derive(Copy, Clone, Debug)]
+#[cfg_attr(feature = "canon", derive(Canon))]
 pub struct G1Projective {
     x: Fp,
     y: Fp,
diff --git a/src/g2.rs b/src/g2.rs
index bce2720a..3d211ea0 100644
--- a/src/g2.rs
+++ b/src/g2.rs
@@ -1,5 +1,9 @@
 //! This module provides an implementation of the $\mathbb{G}_2$ group of BLS12-381.
 
+#[cfg(feature = "canon")]
+use canonical::{Canon, InvalidEncoding, Sink, Source, Store};
+#[cfg(feature = "canon")]
+use canonical_derive::Canon;
 use core::borrow::Borrow;
 use core::iter::Sum;
 use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
@@ -13,6 +17,8 @@ use crate::fp::Fp;
 use crate::fp2::Fp2;
 use crate::BlsScalar;
 
+const G2_COMPRESSED_SIZE: usize = 96;
+
 /// This is an element of $\mathbb{G}_2$ represented in the affine coordinate space.
 /// It is ideal to keep elements in this representation to reduce memory usage and
 /// improve performance through the use of mixed curve model arithmetic.
@@ -26,6 +32,27 @@ pub struct G2Affine {
     infinity: Choice,
 }
 
+#[cfg(feature = "canon")]
+impl<S: Store> Canon<S> for G2Affine {
+    fn write(&self, sink: &mut impl Sink<S>) -> Result<(), S::Error> {
+        sink.copy_bytes(&self.to_compressed());
+        Ok(())
+    }
+
+    fn read(source: &mut impl Source<S>) -> Result<Self, S::Error> {
+        let mut bytes = [0u8; G2_COMPRESSED_SIZE];
+        bytes.copy_from_slice(source.read_bytes(G2_COMPRESSED_SIZE));
+        match Option::from(G2Affine::from_compressed(&bytes)) {
+            Some(g2) => Ok(g2),
+            None => Err(InvalidEncoding.into()),
+        }
+    }
+
+    fn encoded_len(&self) -> usize {
+        G2_COMPRESSED_SIZE
+    }
+}
+
 impl Default for G2Affine {
     fn default() -> G2Affine {
         G2Affine::identity()
@@ -534,6 +561,7 @@ impl G2Affine {
 
 /// This is an element of $\mathbb{G}_2$ represented in the projective coordinate space.
 #[derive(Copy, Clone, Debug)]
+#[cfg_attr(feature = "canon", derive(Canon))]
 pub struct G2Projective {
     pub(crate) x: Fp2,
     pub(crate) y: Fp2,


Test patch: