Skip to content

Commit b284c34

Browse files
mb-dciMauroToscano
andauthored
Affine serialization (#687)
* uncompressed * cargo fmt --------- Co-authored-by: Mauro Toscano <[email protected]>
1 parent 8704cfc commit b284c34

File tree

1 file changed

+185
-50
lines changed
  • math/src/elliptic_curve/short_weierstrass

1 file changed

+185
-50
lines changed

math/src/elliptic_curve/short_weierstrass/point.rs

+185-50
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,7 @@ impl<E: IsShortWeierstrass> IsGroup for ShortWeierstrassProjectivePoint<E> {
212212
#[derive(PartialEq)]
213213
pub enum PointFormat {
214214
Projective,
215-
// TO DO:
216-
// Uncompressed,
215+
Uncompressed,
217216
// Compressed,
218217
}
219218

@@ -233,7 +232,7 @@ where
233232
{
234233
/// Serialize the points in the given format
235234
#[cfg(feature = "std")]
236-
pub fn serialize(&self, _point_format: PointFormat, endianness: Endianness) -> Vec<u8> {
235+
pub fn serialize(&self, point_format: PointFormat, endianness: Endianness) -> Vec<u8> {
237236
// TODO: Add more compact serialization formats
238237
// Uncompressed affine / Compressed
239238

@@ -242,59 +241,101 @@ where
242241
let y_bytes: Vec<u8>;
243242
let z_bytes: Vec<u8>;
244243

245-
let [x, y, z] = self.coordinates();
246-
if endianness == Endianness::BigEndian {
247-
x_bytes = x.to_bytes_be();
248-
y_bytes = y.to_bytes_be();
249-
z_bytes = z.to_bytes_be();
250-
} else {
251-
x_bytes = x.to_bytes_le();
252-
y_bytes = y.to_bytes_le();
253-
z_bytes = z.to_bytes_le();
244+
match point_format {
245+
PointFormat::Projective => {
246+
let [x, y, z] = self.coordinates();
247+
if endianness == Endianness::BigEndian {
248+
x_bytes = x.to_bytes_be();
249+
y_bytes = y.to_bytes_be();
250+
z_bytes = z.to_bytes_be();
251+
} else {
252+
x_bytes = x.to_bytes_le();
253+
y_bytes = y.to_bytes_le();
254+
z_bytes = z.to_bytes_le();
255+
}
256+
bytes.extend(&x_bytes);
257+
bytes.extend(&y_bytes);
258+
bytes.extend(&z_bytes);
259+
}
260+
PointFormat::Uncompressed => {
261+
let affine_representation = self.to_affine();
262+
let [x, y, _z] = affine_representation.coordinates();
263+
if endianness == Endianness::BigEndian {
264+
x_bytes = x.to_bytes_be();
265+
y_bytes = y.to_bytes_be();
266+
} else {
267+
x_bytes = x.to_bytes_le();
268+
y_bytes = y.to_bytes_le();
269+
}
270+
bytes.extend(&x_bytes);
271+
bytes.extend(&y_bytes);
272+
}
254273
}
255-
256-
bytes.extend(&x_bytes);
257-
bytes.extend(&y_bytes);
258-
bytes.extend(&z_bytes);
259-
260274
bytes
261275
}
262276

263277
pub fn deserialize(
264278
bytes: &[u8],
265-
_point_format: PointFormat,
279+
point_format: PointFormat,
266280
endianness: Endianness,
267281
) -> Result<Self, DeserializationError> {
268-
if bytes.len() % 3 != 0 {
269-
return Err(DeserializationError::InvalidAmountOfBytes);
270-
}
282+
match point_format {
283+
PointFormat::Projective => {
284+
if bytes.len() % 3 != 0 {
285+
return Err(DeserializationError::InvalidAmountOfBytes);
286+
}
271287

272-
let len = bytes.len() / 3;
273-
let x: FieldElement<E::BaseField>;
274-
let y: FieldElement<E::BaseField>;
275-
let z: FieldElement<E::BaseField>;
288+
let len = bytes.len() / 3;
289+
let x: FieldElement<E::BaseField>;
290+
let y: FieldElement<E::BaseField>;
291+
let z: FieldElement<E::BaseField>;
276292

277-
if endianness == Endianness::BigEndian {
278-
x = ByteConversion::from_bytes_be(&bytes[..len])?;
279-
y = ByteConversion::from_bytes_be(&bytes[len..len * 2])?;
280-
z = ByteConversion::from_bytes_be(&bytes[len * 2..])?;
281-
} else {
282-
x = ByteConversion::from_bytes_le(&bytes[..len])?;
283-
y = ByteConversion::from_bytes_le(&bytes[len..len * 2])?;
284-
z = ByteConversion::from_bytes_le(&bytes[len * 2..])?;
285-
}
293+
if endianness == Endianness::BigEndian {
294+
x = ByteConversion::from_bytes_be(&bytes[..len])?;
295+
y = ByteConversion::from_bytes_be(&bytes[len..len * 2])?;
296+
z = ByteConversion::from_bytes_be(&bytes[len * 2..])?;
297+
} else {
298+
x = ByteConversion::from_bytes_le(&bytes[..len])?;
299+
y = ByteConversion::from_bytes_le(&bytes[len..len * 2])?;
300+
z = ByteConversion::from_bytes_le(&bytes[len * 2..])?;
301+
}
286302

287-
if z == FieldElement::zero() {
288-
let point = Self::new([x, y, z]);
289-
if point.is_neutral_element() {
290-
Ok(point)
291-
} else {
292-
Err(DeserializationError::FieldFromBytesError)
303+
if z == FieldElement::zero() {
304+
let point = Self::new([x, y, z]);
305+
if point.is_neutral_element() {
306+
Ok(point)
307+
} else {
308+
Err(DeserializationError::FieldFromBytesError)
309+
}
310+
} else if E::defining_equation(&(&x / &z), &(&y / &z)) == FieldElement::zero() {
311+
Ok(Self::new([x, y, z]))
312+
} else {
313+
Err(DeserializationError::FieldFromBytesError)
314+
}
315+
}
316+
PointFormat::Uncompressed => {
317+
if bytes.len() % 2 != 0 {
318+
return Err(DeserializationError::InvalidAmountOfBytes);
319+
}
320+
321+
let len = bytes.len() / 2;
322+
let x: FieldElement<E::BaseField>;
323+
let y: FieldElement<E::BaseField>;
324+
325+
if endianness == Endianness::BigEndian {
326+
x = ByteConversion::from_bytes_be(&bytes[..len])?;
327+
y = ByteConversion::from_bytes_be(&bytes[len..])?;
328+
} else {
329+
x = ByteConversion::from_bytes_le(&bytes[..len])?;
330+
y = ByteConversion::from_bytes_le(&bytes[len..])?;
331+
}
332+
333+
if E::defining_equation(&x, &y) == FieldElement::zero() {
334+
Ok(Self::new([x, y, FieldElement::one()]))
335+
} else {
336+
Err(DeserializationError::FieldFromBytesError)
337+
}
293338
}
294-
} else if E::defining_equation(&(&x / &z), &(&y / &z)) == FieldElement::zero() {
295-
Ok(Self::new([x, y, z]))
296-
} else {
297-
Err(DeserializationError::FieldFromBytesError)
298339
}
299340
}
300341
}
@@ -347,7 +388,7 @@ mod tests {
347388

348389
#[cfg(feature = "std")]
349390
#[test]
350-
fn byte_conversion_from_and_to_be() {
391+
fn byte_conversion_from_and_to_be_projective() {
351392
let expected_point = point();
352393
let bytes_be = expected_point.serialize(PointFormat::Projective, Endianness::BigEndian);
353394

@@ -361,7 +402,20 @@ mod tests {
361402

362403
#[cfg(feature = "std")]
363404
#[test]
364-
fn byte_conversion_from_and_to_le() {
405+
fn byte_conversion_from_and_to_be_uncompressed() {
406+
let expected_point = point();
407+
let bytes_be = expected_point.serialize(PointFormat::Uncompressed, Endianness::BigEndian);
408+
let result = ShortWeierstrassProjectivePoint::deserialize(
409+
&bytes_be,
410+
PointFormat::Uncompressed,
411+
Endianness::BigEndian,
412+
);
413+
assert_eq!(expected_point, result.unwrap());
414+
}
415+
416+
#[cfg(feature = "std")]
417+
#[test]
418+
fn byte_conversion_from_and_to_le_projective() {
365419
let expected_point = point();
366420
let bytes_be = expected_point.serialize(PointFormat::Projective, Endianness::LittleEndian);
367421

@@ -375,7 +429,22 @@ mod tests {
375429

376430
#[cfg(feature = "std")]
377431
#[test]
378-
fn byte_conversion_from_and_to_with_mixed_le_and_be_does_not_work() {
432+
fn byte_conversion_from_and_to_le_uncompressed() {
433+
let expected_point = point();
434+
let bytes_be =
435+
expected_point.serialize(PointFormat::Uncompressed, Endianness::LittleEndian);
436+
437+
let result = ShortWeierstrassProjectivePoint::deserialize(
438+
&bytes_be,
439+
PointFormat::Uncompressed,
440+
Endianness::LittleEndian,
441+
);
442+
assert_eq!(expected_point, result.unwrap());
443+
}
444+
445+
#[cfg(feature = "std")]
446+
#[test]
447+
fn byte_conversion_from_and_to_with_mixed_le_and_be_does_not_work_projective() {
379448
let bytes = point().serialize(PointFormat::Projective, Endianness::LittleEndian);
380449

381450
let result = ShortWeierstrassProjectivePoint::<BLS12381Curve>::deserialize(
@@ -392,7 +461,24 @@ mod tests {
392461

393462
#[cfg(feature = "std")]
394463
#[test]
395-
fn byte_conversion_from_and_to_with_mixed_be_and_le_does_not_work() {
464+
fn byte_conversion_from_and_to_with_mixed_le_and_be_does_not_work_uncompressed() {
465+
let bytes = point().serialize(PointFormat::Uncompressed, Endianness::LittleEndian);
466+
467+
let result = ShortWeierstrassProjectivePoint::<BLS12381Curve>::deserialize(
468+
&bytes,
469+
PointFormat::Uncompressed,
470+
Endianness::BigEndian,
471+
);
472+
473+
assert_eq!(
474+
result.unwrap_err(),
475+
DeserializationError::FieldFromBytesError
476+
);
477+
}
478+
479+
#[cfg(feature = "std")]
480+
#[test]
481+
fn byte_conversion_from_and_to_with_mixed_be_and_le_does_not_work_projective() {
396482
let bytes = point().serialize(PointFormat::Projective, Endianness::BigEndian);
397483

398484
let result = ShortWeierstrassProjectivePoint::<BLS12381Curve>::deserialize(
@@ -407,8 +493,25 @@ mod tests {
407493
);
408494
}
409495

496+
#[cfg(feature = "std")]
497+
#[test]
498+
fn byte_conversion_from_and_to_with_mixed_be_and_le_does_not_work_uncompressed() {
499+
let bytes = point().serialize(PointFormat::Uncompressed, Endianness::BigEndian);
500+
501+
let result = ShortWeierstrassProjectivePoint::<BLS12381Curve>::deserialize(
502+
&bytes,
503+
PointFormat::Uncompressed,
504+
Endianness::LittleEndian,
505+
);
506+
507+
assert_eq!(
508+
result.unwrap_err(),
509+
DeserializationError::FieldFromBytesError
510+
);
511+
}
512+
410513
#[test]
411-
fn cannot_create_point_from_wrong_number_of_bytes_le() {
514+
fn cannot_create_point_from_wrong_number_of_bytes_le_projective() {
412515
let bytes = &[0_u8; 13];
413516

414517
let result = ShortWeierstrassProjectivePoint::<BLS12381Curve>::deserialize(
@@ -424,7 +527,23 @@ mod tests {
424527
}
425528

426529
#[test]
427-
fn cannot_create_point_from_wrong_number_of_bytes_be() {
530+
fn cannot_create_point_from_wrong_number_of_bytes_le_uncompressed() {
531+
let bytes = &[0_u8; 13];
532+
533+
let result = ShortWeierstrassProjectivePoint::<BLS12381Curve>::deserialize(
534+
bytes,
535+
PointFormat::Uncompressed,
536+
Endianness::LittleEndian,
537+
);
538+
539+
assert_eq!(
540+
result.unwrap_err(),
541+
DeserializationError::InvalidAmountOfBytes
542+
);
543+
}
544+
545+
#[test]
546+
fn cannot_create_point_from_wrong_number_of_bytes_be_projective() {
428547
let bytes = &[0_u8; 13];
429548

430549
let result = ShortWeierstrassProjectivePoint::<BLS12381Curve>::deserialize(
@@ -438,4 +557,20 @@ mod tests {
438557
DeserializationError::InvalidAmountOfBytes
439558
);
440559
}
560+
561+
#[test]
562+
fn cannot_create_point_from_wrong_number_of_bytes_be_uncompressed() {
563+
let bytes = &[0_u8; 13];
564+
565+
let result = ShortWeierstrassProjectivePoint::<BLS12381Curve>::deserialize(
566+
bytes,
567+
PointFormat::Uncompressed,
568+
Endianness::BigEndian,
569+
);
570+
571+
assert_eq!(
572+
result.unwrap_err(),
573+
DeserializationError::InvalidAmountOfBytes
574+
);
575+
}
441576
}

0 commit comments

Comments
 (0)