Compare commits

...

5 Commits

Author SHA1 Message Date
Luke Parker c14b406197
Merge a46b5be95c into df67e299e6 2023-12-20 11:16:42 -07:00
str4d df67e299e6
Merge pull request #80 from zcash/rfc-process
Point to the RFC process
2023-12-20 16:30:51 +00:00
Jack Grigg 43598cf303 Point to the RFC process 2023-12-19 15:36:50 +00:00
Luke Parker a46b5be95c
Add zeroize 2023-05-18 18:26:06 -04:00
Luke Parker f89331c06e
Optimize scalar multiplication with a 4-bit window
This moves from 255 doubles and 255 additions to 259 doubles and 71 additions.
If doubling is twice as fast, which is roughly the case as far as I can tell,
this shifts the function from executing in (255 + (255 * 2)) = 765 time to
(259 + (71 * 2)) = 401 time, a 48% speedup.
2023-05-18 18:21:34 -04:00
5 changed files with 76 additions and 51 deletions

View File

@ -49,6 +49,7 @@ group = { version = "0.13", default-features = false }
rand = { version = "0.8", default-features = false }
static_assertions = "1.1.0"
subtle = { version = "2.3", default-features = false }
zeroize = { version = "^1.5", default-features = false, features = ["derive"] }
# alloc dependencies
blake2b_simd = { version = "1", optional = true, default-features = false }

View File

@ -4,6 +4,12 @@ This crate provides an implementation of the Pasta elliptic curve constructions,
Pallas and Vesta. More details about the Pasta curves can be found
[in this blog post](https://electriccoin.co/blog/the-pasta-curves-for-halo-2-and-beyond/).
## RFC process
This crate follows the [zkcrypto RFC process](https://zkcrypto.github.io/rfcs/).
If you want to propose "substantial" changes to this crate, please
[create an RFC](https://github.com/zkcrypto/rfcs) for wider discussion.
## [Documentation](https://docs.rs/pasta_curves)
## Minimum Supported Rust Version

View File

@ -30,7 +30,7 @@ macro_rules! new_curve_impl {
(($($privacy:tt)*), $name:ident, $name_affine:ident, $iso:ident, $base:ident, $scalar:ident,
$curve_id:literal, $a_raw:expr, $b_raw:expr, $curve_type:ident) => {
/// Represents a point in the projective coordinate space.
#[derive(Copy, Clone, Debug)]
#[derive(Copy, Clone, Debug, zeroize::Zeroize)]
#[cfg_attr(feature = "repr-c", repr(C))]
$($privacy)* struct $name {
x: $base,
@ -466,32 +466,41 @@ macro_rules! new_curve_impl {
type Output = $name;
fn mul(self, other: &'b $scalar) -> Self::Output {
// TODO: make this faster
let mut acc = $name::identity();
// This is a simple double-and-add implementation of point
// multiplication, moving from most significant to least
// significant bit of the scalar.
//
// We don't use `PrimeFieldBits::.to_le_bits` here, because that would
// force users of this crate to depend on `bitvec` where they otherwise
// might not need to.
//
// NOTE: We skip the leading bit because it's always unset (we are turning
// the 32-byte repr into 256 bits, and $scalar::NUM_BITS = 255).
for bit in other
.to_repr()
.iter()
.rev()
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
.skip(1)
{
acc = acc.double();
acc = $name::conditional_select(&acc, &(acc + self), bit);
// Create a table out of the point
// TODO: This can be made more efficient with a 5-bit window
let mut arr = [$name::identity(); 16];
arr[1] = *self;
for i in 2 .. 16 {
arr[i] = if (i % 2) == 0 {
arr[i / 2].double()
} else {
arr[i - 1] + arr[1]
};
}
acc
let mut res = $name::identity();
let mut first = true;
// Iterate from significant byte to least significant byte
for byte in other.to_repr().iter().rev() {
// Shift the result over 4 bits
if !first {
for _ in 0 .. 4 {
res = res.double();
}
}
first = false;
// Add the top-nibble from this byte into the result
res += arr[usize::from(byte >> 4)];
// Shift the result over
for _ in 0 .. 4 {
res = res.double();
}
// Add the bottom-nibble from this byte into the result
res += arr[usize::from(byte & 0b1111)];
}
res
}
}
@ -581,32 +590,41 @@ macro_rules! new_curve_impl {
type Output = $name;
fn mul(self, other: &'b $scalar) -> Self::Output {
// TODO: make this faster
let mut acc = $name::identity();
// This is a simple double-and-add implementation of point
// multiplication, moving from most significant to least
// significant bit of the scalar.
//
// We don't use `PrimeFieldBits::.to_le_bits` here, because that would
// force users of this crate to depend on `bitvec` where they otherwise
// might not need to.
//
// NOTE: We skip the leading bit because it's always unset (we are turning
// the 32-byte repr into 256 bits, and $scalar::NUM_BITS = 255).
for bit in other
.to_repr()
.iter()
.rev()
.flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
.skip(1)
{
acc = acc.double();
acc = $name::conditional_select(&acc, &(acc + self), bit);
// Create a table out of the point
// TODO: This can be made more efficient with a 5-bit window
let mut arr = [$name::identity(); 16];
arr[1] = (*self).into();
for i in 2 .. 16 {
arr[i] = if (i % 2) == 0 {
arr[i / 2].double()
} else {
arr[i - 1] + arr[1]
};
}
acc
let mut res = $name::identity();
let mut first = true;
// Iterate from significant byte to least significant byte
for byte in other.to_repr().iter().rev() {
// Shift the result over 4 bits
if !first {
for _ in 0 .. 4 {
res = res.double();
}
}
first = false;
// Add the top-nibble from this byte into the result
res += arr[usize::from(byte >> 4)];
// Shift the result over
for _ in 0 .. 4 {
res = res.double();
}
// Add the bottom-nibble from this byte into the result
res += arr[usize::from(byte & 0b1111)];
}
res
}
}

View File

@ -24,7 +24,7 @@ use crate::arithmetic::SqrtTables;
// The internal representation of this type is four 64-bit unsigned
// integers in little-endian order. `Fp` values are always in
// Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256.
#[derive(Clone, Copy, Eq)]
#[derive(Clone, Copy, Eq, zeroize::Zeroize)]
#[repr(transparent)]
pub struct Fp(pub(crate) [u64; 4]);

View File

@ -24,7 +24,7 @@ use crate::arithmetic::SqrtTables;
// The internal representation of this type is four 64-bit unsigned
// integers in little-endian order. `Fq` values are always in
// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256.
#[derive(Clone, Copy, Eq)]
#[derive(Clone, Copy, Eq, zeroize::Zeroize)]
#[repr(transparent)]
pub struct Fq(pub(crate) [u64; 4]);