Merge dd19db3939
into a586b8c2db
This commit is contained in:
commit
fd0612fa23
|
@ -62,6 +62,7 @@ ec-gpu = { version = "0.2.0", optional = true }
|
||||||
# serde dependencies
|
# serde dependencies
|
||||||
serde_crate = { version = "1.0.16", optional = true, default-features = false, features = ["alloc"], package = "serde" }
|
serde_crate = { version = "1.0.16", optional = true, default-features = false, features = ["alloc"], package = "serde" }
|
||||||
hex = { version = "0.4", optional = true, default-features = false, features = ["alloc", "serde"] }
|
hex = { version = "0.4", optional = true, default-features = false, features = ["alloc", "serde"] }
|
||||||
|
paste = "1.0.12"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["bits", "sqrt-table"]
|
default = ["bits", "sqrt-table"]
|
||||||
|
|
108
src/curves.rs
108
src/curves.rs
|
@ -269,6 +269,114 @@ macro_rules! new_curve_impl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
paste::paste! {
|
||||||
|
|
||||||
|
/// Uncompressed encoding of the affine representation of a point on the elliptic curve $name.
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
pub struct [< $name Uncompressed >](pub(crate) [u8; 64]);
|
||||||
|
|
||||||
|
impl fmt::Debug for [< $name Uncompressed >] {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
self.0[..].fmt(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for [< $name Uncompressed >] {
|
||||||
|
fn default() -> Self {
|
||||||
|
[< $name Uncompressed >]([0; 64])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for [< $name Uncompressed >] {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsMut<[u8]> for [< $name Uncompressed >] {
|
||||||
|
fn as_mut(&mut self) -> &mut [u8] {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConstantTimeEq for [< $name Uncompressed >] {
|
||||||
|
fn ct_eq(&self, other: &Self) -> Choice {
|
||||||
|
self.0.ct_eq(&other.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl cmp::Eq for [< $name Uncompressed >] {}
|
||||||
|
|
||||||
|
impl PartialEq for [< $name Uncompressed >] {
|
||||||
|
#[inline]
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
bool::from(self.ct_eq(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl group::UncompressedEncoding for $name_affine{
|
||||||
|
type Uncompressed = [< $name Uncompressed >];
|
||||||
|
|
||||||
|
fn from_uncompressed(bytes: &Self::Uncompressed) -> CtOption<Self> {
|
||||||
|
Self::from_uncompressed_unchecked(bytes).and_then(|p| CtOption::new(p, p.is_on_curve()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_uncompressed_unchecked(bytes: &Self::Uncompressed) -> CtOption<Self> {
|
||||||
|
let bytes = &bytes.0;
|
||||||
|
let infinity_flag_set = Choice::from((bytes[64 - 1] >> 6) & 1);
|
||||||
|
// Attempt to obtain the x-coordinate
|
||||||
|
let x = {
|
||||||
|
let mut tmp = [0; 32];
|
||||||
|
tmp.copy_from_slice(&bytes[0..32]);
|
||||||
|
$base::from_repr(tmp)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Attempt to obtain the y-coordinate
|
||||||
|
let y = {
|
||||||
|
let mut tmp = [0; 32];
|
||||||
|
tmp.copy_from_slice(&bytes[32..2*32]);
|
||||||
|
$base::from_repr(tmp)
|
||||||
|
};
|
||||||
|
|
||||||
|
x.and_then(|x| {
|
||||||
|
y.and_then(|y| {
|
||||||
|
// Create a point representing this value
|
||||||
|
let p = $name_affine::conditional_select(
|
||||||
|
&$name_affine{
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
},
|
||||||
|
&$name_affine::identity(),
|
||||||
|
infinity_flag_set,
|
||||||
|
);
|
||||||
|
|
||||||
|
CtOption::new(
|
||||||
|
p,
|
||||||
|
// If the infinity flag is set, the x and y coordinates should have been zero.
|
||||||
|
((!infinity_flag_set) | (x.is_zero() & y.is_zero()))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_uncompressed(&self) -> Self::Uncompressed {
|
||||||
|
let mut res = [0; 64];
|
||||||
|
|
||||||
|
res[0..32].copy_from_slice(
|
||||||
|
&$base::conditional_select(&self.x, &$base::zero(), self.is_identity()).to_repr()[..],
|
||||||
|
);
|
||||||
|
res[32.. 2*32].copy_from_slice(
|
||||||
|
&$base::conditional_select(&self.y, &$base::zero(), self.is_identity()).to_repr()[..],
|
||||||
|
);
|
||||||
|
|
||||||
|
res[64 - 1] |= u8::conditional_select(&0u8, &(1u8 << 6), self.is_identity());
|
||||||
|
|
||||||
|
[< $name Uncompressed >](res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> From<&'a $name_affine> for $name {
|
impl<'a> From<&'a $name_affine> for $name {
|
||||||
fn from(p: &'a $name_affine) -> $name {
|
fn from(p: &'a $name_affine) -> $name {
|
||||||
p.to_curve()
|
p.to_curve()
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
|
use core::fmt;
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
use group::GroupEncoding;
|
use group::GroupEncoding;
|
||||||
use serde_crate::{
|
use serde_crate::{
|
||||||
de::Error as DeserializeError, Deserialize, Deserializer, Serialize, Serializer,
|
de::{Error as DeserializeError, SeqAccess, Visitor},
|
||||||
|
ser::SerializeTuple,
|
||||||
|
Deserialize, Deserializer, Serialize, Serializer,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
curves::{Ep, EpAffine, Eq, EqAffine},
|
curves::{Ep, EpAffine, Eq, EqAffine},
|
||||||
fields::{Fp, Fq},
|
fields::{Fp, Fq},
|
||||||
group::Curve,
|
group::Curve,
|
||||||
|
EpUncompressed, EqUncompressed,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Serializes bytes to human readable or compact representation.
|
/// Serializes bytes to human readable or compact representation.
|
||||||
|
@ -130,6 +134,83 @@ impl<'de> Deserialize<'de> for Eq {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ByteArrayVisitor {}
|
||||||
|
|
||||||
|
impl<'de> Visitor<'de> for ByteArrayVisitor {
|
||||||
|
type Value = [u8; 64];
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str(concat!("an array of length ", 64))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_seq<A>(self, mut seq: A) -> Result<[u8; 64], A::Error>
|
||||||
|
where
|
||||||
|
A: SeqAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut arr = [u8::default(); 64];
|
||||||
|
for i in 0..64 {
|
||||||
|
arr[i] = seq
|
||||||
|
.next_element()?
|
||||||
|
.ok_or_else(|| DeserializeError::invalid_length(i, &self))?;
|
||||||
|
}
|
||||||
|
Ok(arr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for EpUncompressed {
|
||||||
|
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
|
if s.is_human_readable() {
|
||||||
|
hex::serde::serialize(self.0, s)
|
||||||
|
} else {
|
||||||
|
let mut seq = s.serialize_tuple(64)?;
|
||||||
|
for elem in self.0 {
|
||||||
|
seq.serialize_element(&elem)?;
|
||||||
|
}
|
||||||
|
seq.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for EpUncompressed {
|
||||||
|
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||||
|
let array = if d.is_human_readable() {
|
||||||
|
hex::serde::deserialize(d)?
|
||||||
|
} else {
|
||||||
|
let visitor = ByteArrayVisitor {};
|
||||||
|
d.deserialize_tuple(64, visitor)?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self(array))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for EqUncompressed {
|
||||||
|
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||||
|
if s.is_human_readable() {
|
||||||
|
hex::serde::serialize(self.0, s)
|
||||||
|
} else {
|
||||||
|
let mut seq = s.serialize_tuple(64)?;
|
||||||
|
for elem in self.0 {
|
||||||
|
seq.serialize_element(&elem)?;
|
||||||
|
}
|
||||||
|
seq.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for EqUncompressed {
|
||||||
|
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||||
|
let array = if d.is_human_readable() {
|
||||||
|
hex::serde::deserialize(d)?
|
||||||
|
} else {
|
||||||
|
let visitor = ByteArrayVisitor {};
|
||||||
|
d.deserialize_tuple(64, visitor)?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self(array))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -137,7 +218,7 @@ mod tests {
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
|
|
||||||
use ff::Field;
|
use ff::Field;
|
||||||
use group::{prime::PrimeCurveAffine, Curve, Group};
|
use group::{prime::PrimeCurveAffine, Curve, Group, UncompressedEncoding};
|
||||||
use rand::SeedableRng;
|
use rand::SeedableRng;
|
||||||
use rand_xorshift::XorShiftRng;
|
use rand_xorshift::XorShiftRng;
|
||||||
|
|
||||||
|
@ -444,4 +525,106 @@ mod tests {
|
||||||
f
|
f
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serde_ep_uncompressed() {
|
||||||
|
let mut rng = XorShiftRng::from_seed([
|
||||||
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||||
|
0xbc, 0xe5,
|
||||||
|
]);
|
||||||
|
|
||||||
|
for _ in 0..100 {
|
||||||
|
let f = Ep::random(&mut rng).to_affine().to_uncompressed();
|
||||||
|
test_roundtrip(&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
let f = Ep::identity().to_affine().to_uncompressed();
|
||||||
|
test_roundtrip(&f);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::from_slice::<EpUncompressed>(
|
||||||
|
br#""00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040""#
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
f
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
bincode::deserialize::<EpUncompressed>(&[
|
||||||
|
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,
|
||||||
|
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,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 64
|
||||||
|
])
|
||||||
|
.unwrap(),
|
||||||
|
f
|
||||||
|
);
|
||||||
|
|
||||||
|
let f = Ep::generator().to_affine().to_uncompressed();
|
||||||
|
test_roundtrip(&f);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::from_slice::<EpUncompressed>(
|
||||||
|
br#""00000000ed302d991bf94c09fc984622000000000000000000000000000000400200000000000000000000000000000000000000000000000000000000000000""#
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
f
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
bincode::deserialize::<EpUncompressed>(&[
|
||||||
|
0, 0, 0, 0, 237, 48, 45, 153, 27, 249, 76, 9, 252, 152, 70, 34, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 2, 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, 0, 0, 0
|
||||||
|
])
|
||||||
|
.unwrap(),
|
||||||
|
f
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serde_eq_uncompressed() {
|
||||||
|
let mut rng = XorShiftRng::from_seed([
|
||||||
|
0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
|
||||||
|
0xbc, 0xe5,
|
||||||
|
]);
|
||||||
|
|
||||||
|
for _ in 0..100 {
|
||||||
|
let f = Eq::random(&mut rng).to_affine().to_uncompressed();
|
||||||
|
test_roundtrip(&f);
|
||||||
|
}
|
||||||
|
|
||||||
|
let f = Eq::identity().to_affine().to_uncompressed();
|
||||||
|
test_roundtrip(&f);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::from_slice::<EqUncompressed>(
|
||||||
|
br#""00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040""#
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
f
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
bincode::deserialize::<EqUncompressed>(&[
|
||||||
|
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,
|
||||||
|
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,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 64
|
||||||
|
])
|
||||||
|
.unwrap(),
|
||||||
|
f
|
||||||
|
);
|
||||||
|
|
||||||
|
let f = Eq::generator().to_affine().to_uncompressed();
|
||||||
|
test_roundtrip(&f);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::from_slice::<EqUncompressed>(
|
||||||
|
br#""0000000021eb468cdda89409fc984622000000000000000000000000000000400200000000000000000000000000000000000000000000000000000000000000""#
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
f
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
bincode::deserialize::<EqUncompressed>(&[
|
||||||
|
0, 0, 0, 0, 33, 235, 70, 140, 221, 168, 148, 9, 252, 152, 70, 34, 0, 0, 0, 0, 0, 0,
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 2, 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, 0, 0, 0
|
||||||
|
])
|
||||||
|
.unwrap(),
|
||||||
|
f
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue