Skip to content

Commit

Permalink
feat: implement UncompressedEncoding
Browse files Browse the repository at this point in the history
- Update Rust toolchain to version 1.59.0 to satisfy the requirement of constant_time_eq v0.2.5,
- Implement UncompressedEncoding for affine representations,
- Add `paste` dependency at version 1.0.12 in order to give a specific struct for that representation for each of Pallas, Vesta.
  • Loading branch information
huitseeker committed Jun 2, 2023
1 parent 7e3fc6a commit 2ffb0bb
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 3 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ authors = [
"Jack Grigg <[email protected]>",
]
edition = "2021"
rust-version = "1.56"
rust-version = "1.59"
license = "MIT OR Apache-2.0"
repository = "https://github.com/zcash/pasta_curves"
documentation = "https://docs.rs/pasta_curves"
Expand Down Expand Up @@ -63,6 +63,7 @@ ec-gpu = { version = "0.2.0", optional = true }
# serde dependencies
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"] }
paste = "1.0.12"

[features]
default = ["bits", "sqrt-table"]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Pallas and Vesta. More details about the Pasta curves can be found

## Minimum Supported Rust Version

Requires Rust **1.56** or higher.
Requires Rust **1.59** or higher.

Minimum supported Rust version can be changed in the future, but it will be done with a
minor version bump.
Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[toolchain]
channel = "1.56.0"
channel = "1.59.0"
components = [ "clippy", "rustfmt" ]
108 changes: 108 additions & 0 deletions src/curves.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 >]([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 {
fn from(p: &'a $name_affine) -> $name {
p.to_curve()
Expand Down

0 comments on commit 2ffb0bb

Please sign in to comment.