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

Issue:
G1Affine - Raw bytes encoding failing
The raw serialization fails for a G1Affine with the following numbers:

```
x: {0x9af1f35780fffb82, 0x557416ceeea5a52f, 0x1e4403e4911a2d97, 0x0b85bfb438316bf2, 0xa3b716c69a9e5a7b, 0x01fe9b8ad976dd39}
y: {0xb4f1cc806acfb4e2, 0x38c28cba4cf600ed, 0x3af1c2f54a01a366, 0x96a75ac708a9eb72, 0x04253bd59228e50d, 0x120114fae4294c21}
```


Discussion / hints:

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8694e401..6ab3d5d1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 
+## [0.5.2] - 25-01-21
+### Fixed
+- Incorrect encoding for unchecked bytes serialization [#50](https://github.com/dusk-network/bls12_381/issues/50)
+
 ## [0.5.1] - 22-01-21
 ### Changed
 - Update dusk-bytes and implement hex format tests
diff --git a/Cargo.toml b/Cargo.toml
index 66eaccd7..5b5f4137 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,7 +6,7 @@ homepage = "https://github.com/dusk-network/bls12_381"
 license = "MIT/Apache-2.0"
 name = "dusk-bls12_381"
 repository = "https://github.com/dusk-network/bls12_381"
-version = "0.5.1"
+version = "0.5.2"
 keywords = ["cryptography", "bls12_381", "zk-snarks", "ecc", "elliptic-curve"]
 categories =["Algorithms", "Cryptography", "Development tools"]
 edition = "2018"
diff --git a/src/g1.rs b/src/g1.rs
index 85662c99..52672176 100644
--- a/src/g1.rs
+++ b/src/g1.rs
@@ -340,7 +340,7 @@ const B: Fp = Fp::from_raw_unchecked([
 
 impl G1Affine {
     /// Bytes size of the raw representation
-    pub const RAW_SIZE: usize = 96;
+    pub const RAW_SIZE: usize = 97;
 
     /// Returns the identity of the group: the point at infinity.
     pub fn identity() -> G1Affine {
@@ -392,10 +392,7 @@ impl G1Affine {
             .zip(chunks)
             .for_each(|(n, c)| c.copy_from_slice(&n.to_le_bytes()));
 
-        // If infinity, set the second-most significant bit.
-        if self.infinity.unwrap_u8() == 1 {
-            bytes[0] |= 1u8 << 6;
-        }
+        bytes[Self::RAW_SIZE - 1] = self.infinity.unwrap_u8();
 
         bytes
     }
@@ -414,12 +411,6 @@ impl G1Affine {
         let mut y = [0u64; 6];
         let mut z = [0u8; 8];
 
-        let infinity = match bytes.first() {
-            Some(b) => (b & (1u8 << 6)) >> 6,
-            None => 0u8,
-        }
-        .into();
-
         bytes
             .chunks_exact(8)
             .zip(x.iter_mut().chain(y.iter_mut()))
@@ -428,11 +419,15 @@ impl G1Affine {
                 *n = u64::from_le_bytes(z);
             });
 
-        x[0] &= 0xffffffffffffff1fu64;
-
         let x = Fp::from_raw_unchecked(x);
         let y = Fp::from_raw_unchecked(y);
 
+        let infinity = if bytes.len() >= Self::RAW_SIZE {
+            bytes[Self::RAW_SIZE - 1].into()
+        } else {
+            0u8.into()
+        };
+
         Self { x, y, infinity }
     }
 
@@ -1540,6 +1535,35 @@ fn g1_affine_bytes_unchecked() {
     assert_eq!(ident, ident_p);
 }
 
+#[test]
+fn g1_affine_bytes_unchecked_field() {
+    let x = Fp::from_raw_unchecked([
+        0x9af1f35780fffb82,
+        0x557416ceeea5a52f,
+        0x1e4403e4911a2d97,
+        0xb85bfb438316bf2,
+        0xa3b716c69a9e5a7b,
+        0x1fe9b8ad976dd39,
+    ]);
+
+    let y = Fp::from_raw_unchecked([
+        0xb4f1cc806acfb4e2,
+        0x38c28cba4cf600ed,
+        0x3af1c2f54a01a366,
+        0x96a75ac708a9eb72,
+        0x4253bd59228e50d,
+        0x120114fae4294c21,
+    ]);
+
+    let infinity = 0u8.into();
+    let g = G1Affine { x, y, infinity };
+
+    let g_p = g.to_raw_bytes();
+    let g_p = unsafe { G1Affine::from_slice_unchecked(&g_p) };
+
+    assert_eq!(g, g_p);
+}
+
 #[test]
 fn g1_affine_hex() {
     use dusk_bytes::ParseHexStr;
diff --git a/src/g2.rs b/src/g2.rs
index 4a6c77ee..9e3b647c 100644
--- a/src/g2.rs
+++ b/src/g2.rs
@@ -369,7 +369,7 @@ const B: Fp2 = Fp2 {
 
 impl G2Affine {
     /// Bytes size of the raw representation
-    pub const RAW_SIZE: usize = 192;
+    pub const RAW_SIZE: usize = 193;
 
     /// Returns the identity of the group: the point at infinity.
     pub fn identity() -> G2Affine {
@@ -444,10 +444,7 @@ impl G2Affine {
             .zip(chunks)
             .for_each(|(n, c)| c.copy_from_slice(&n.to_le_bytes()));
 
-        // If infinity, set the second-most significant bit.
-        if self.infinity.unwrap_u8() == 1 {
-            bytes[0] |= 1u8 << 6;
-        }
+        bytes[Self::RAW_SIZE - 1] = self.infinity.unwrap_u8();
 
         bytes
     }
@@ -468,12 +465,6 @@ impl G2Affine {
         let mut yc1 = [0u64; 6];
         let mut z = [0u8; 8];
 
-        let infinity = match bytes.first() {
-            Some(b) => (b & (1u8 << 6)) >> 6,
-            None => 0u8,
-        }
-        .into();
-
         xc0.iter_mut()
             .chain(xc1.iter_mut())
             .chain(yc0.iter_mut())
@@ -484,8 +475,6 @@ impl G2Affine {
                 *n = u64::from_le_bytes(z);
             });
 
-        xc0[0] &= 0xffffffffffffff1fu64;
-
         let c0 = Fp::from_raw_unchecked(xc0);
         let c1 = Fp::from_raw_unchecked(xc1);
         let x = Fp2 { c0, c1 };
@@ -494,6 +483,12 @@ impl G2Affine {
         let c1 = Fp::from_raw_unchecked(yc1);
         let y = Fp2 { c0, c1 };
 
+        let infinity = if bytes.len() >= Self::RAW_SIZE {
+            bytes[Self::RAW_SIZE - 1].into()
+        } else {
+            0u8.into()
+        };
+
         Self { x, y, infinity }
     }
 


Test patch: