Skip to content

Commit

Permalink
Added XYZZ coordinates and let z=0 represent infinity
Browse files Browse the repository at this point in the history
  • Loading branch information
mikdk committed May 10, 2024
1 parent 4a18125 commit 2961b6f
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 37 deletions.
12 changes: 5 additions & 7 deletions crates/crypto/examples/consts_pedersen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ fn generate_consts(bits: u32) -> Result<String, std::fmt::Error> {
write!(buf, "use crate::algebra::curve::AffinePoint;\n\n")?;
write!(buf, "pub const CURVE_CONSTS_BITS: usize = {bits};\n\n")?;

push_points(&mut buf, "P1", &PEDERSEN_P1, 248, bits)?;
push_points(&mut buf, "P1", PEDERSEN_P1, 248, bits)?;
buf.push_str("\n\n\n");
push_points(&mut buf, "P2", &PEDERSEN_P2, 4, bits)?;
push_points(&mut buf, "P2", PEDERSEN_P2, 4, bits)?;
buf.push_str("\n\n\n");
push_points(&mut buf, "P3", &PEDERSEN_P3, 248, bits)?;
push_points(&mut buf, "P3", PEDERSEN_P3, 248, bits)?;
buf.push_str("\n\n\n");
push_points(&mut buf, "P4", &PEDERSEN_P4, 4, bits)?;
push_points(&mut buf, "P4", PEDERSEN_P4, 4, bits)?;

Ok(buf)
}
Expand All @@ -48,12 +48,10 @@ fn generate_consts(bits: u32) -> Result<String, std::fmt::Error> {
fn push_points(
buf: &mut String,
name: &str,
base: &ProjectivePoint,
base: AffinePoint,
max_bits: u32,
bits: u32,
) -> std::fmt::Result {
let base = AffinePoint::from(base);

let full_chunks = max_bits / bits;
let leftover_bits = max_bits % bits;
let table_size_full = (1 << bits) - 1;
Expand Down
14 changes: 14 additions & 0 deletions crates/crypto/src/algebra/curve/affine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,20 @@ impl From<&ProjectivePoint> for AffinePoint {
}
}

impl From<&XYZZPoint> for AffinePoint {
fn from(p: &XYZZPoint) -> Self {
let a = p.zzz.inverse().unwrap();
let b = (p.zz * a).square();
let x = p.x * b;
let y = p.y * a;
AffinePoint {
x,
y,
infinity: false,
}
}
}

impl AffinePoint {
/// Create a point from (x,y) as raw u64's in Montgomery representation
pub const fn from_raw(x: [u64; 4], y: [u64; 4]) -> Self {
Expand Down
3 changes: 3 additions & 0 deletions crates/crypto/src/algebra/curve/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ mod gen_mul;
mod params;
mod projective;

mod xyzz;

pub use affine::AffinePoint;
pub use params::{CURVE_A, CURVE_B, CURVE_G, CURVE_ORDER};
pub use projective::ProjectivePoint;
pub use xyzz::XYZZPoint;

#[cfg(test)]
mod tests;
43 changes: 22 additions & 21 deletions crates/crypto/src/algebra/curve/projective.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,22 @@ use bitvec::slice::BitSlice;
use crate::algebra::curve::*;
use crate::algebra::field::*;

/// A projective point on an elliptic curve over [MontFelt].
/// A projective point on an elliptic curve over [MontFelt] satisfying:
/// x = X / Z
/// y = Y / Z
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ProjectivePoint {
pub x: MontFelt,
pub y: MontFelt,
pub z: MontFelt,
pub infinity: bool,
}

impl From<&AffinePoint> for ProjectivePoint {
fn from(p: &AffinePoint) -> Self {
let x = p.x;
let y = p.y;
let z = MontFelt::ONE;
ProjectivePoint {
x,
y,
z,
infinity: false,
}
ProjectivePoint { x, y, z }
}
}

Expand All @@ -36,7 +32,6 @@ impl ProjectivePoint {
x,
y,
z: MontFelt::ONE,
infinity: false,
}
}

Expand All @@ -48,7 +43,6 @@ impl ProjectivePoint {
x,
y,
z: MontFelt::ONE,
infinity: false,
}
}

Expand All @@ -63,8 +57,7 @@ impl ProjectivePoint {
Self {
x: MontFelt::ZERO,
y: MontFelt::ZERO,
z: MontFelt::ONE,
infinity: true,
z: MontFelt::ZERO,
}
}

Expand All @@ -73,9 +66,14 @@ impl ProjectivePoint {
self.y = -self.y;
}

/// Check if the point is the point of infinity
pub fn is_infinity(&self) -> bool {
self.z.is_zero()
}

/// Double a point
pub fn double(&mut self) {
if self.infinity {
if self.is_infinity() {
return;
}

Expand All @@ -99,14 +97,13 @@ impl ProjectivePoint {

/// Add a point to this point
pub fn add(&mut self, other: &ProjectivePoint) {
if other.infinity {
if other.is_infinity() {
return;
}
if self.infinity {
if self.is_infinity() {
self.x = other.x;
self.y = other.y;
self.z = other.z;
self.infinity = other.infinity;
return;
}
let u0 = self.x * other.z;
Expand All @@ -115,7 +112,7 @@ impl ProjectivePoint {
let t1 = other.y * self.z;
if u0 == u1 {
if t0 != t1 {
self.infinity = true;
self.z = MontFelt::ZERO;
} else {
self.double();
}
Expand Down Expand Up @@ -144,11 +141,15 @@ impl ProjectivePoint {
if other.infinity {
return;
}
if self.infinity {
if self.is_infinity() {
self.x = other.x;
self.y = other.y;
self.z = MontFelt::ONE;
self.infinity = other.infinity;
self.z = if other.infinity {
MontFelt::ZERO
} else {
MontFelt::ONE
};

return;
}
let u0 = self.x;
Expand All @@ -157,7 +158,7 @@ impl ProjectivePoint {
let t1 = other.y * self.z;
if u0 == u1 {
if t0 != t1 {
self.infinity = true;
self.z = MontFelt::ZERO;
return;
} else {
self.double();
Expand Down
72 changes: 72 additions & 0 deletions crates/crypto/src/algebra/curve/xyzz.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use bitvec::order::Lsb0;
use bitvec::slice::BitSlice;

use crate::algebra::curve::*;
use crate::algebra::field::*;

/// A XYZZ point on an elliptic curve over [MontFelt] satisfying:
/// x = X / ZZ
/// y = Y / ZZ
/// ZZ^3 = ZZZ^2
///
/// This point representation is used for fast table-based scalar multiplication
/// and only include add_affine and add_affine_unchecked operations.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct XYZZPoint {
pub x: MontFelt,
pub y: MontFelt,
pub zz: MontFelt,
pub zzz: MontFelt,
}

impl From<&AffinePoint> for XYZZPoint {
fn from(p: &AffinePoint) -> Self {
let x = p.x;
let y = p.y;
let zz = MontFelt::ONE;
let zzz = MontFelt::ONE;
XYZZPoint { x, y, zz, zzz }
}
}

impl XYZZPoint {
/// Check if the point is the point of infinity
pub fn is_infinity(&self) -> bool {
self.zz.is_zero()
}

/// Add an affine point to this point
pub fn add_affine(&mut self, other: &AffinePoint) {
if other.infinity {
return;
}
if self.is_infinity() {
self.x = other.x;
self.y = other.y;
let z = if other.infinity {
MontFelt::ZERO
} else {
MontFelt::ONE
};
self.zz = z;
self.zzz = z;

return;
}
self.add_affine_unchecked(other);
}

/// Add an affine point to this point, neither must be the point of infinity
pub fn add_affine_unchecked(&mut self, other: &AffinePoint) {
// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s
let p = other.x * self.zz - self.x;
let r = other.y * self.zzz - self.y;
let pp = p.square();
let ppp = p * pp;
let q = self.x * pp;
self.x = r.square() - ppp - q.double();
self.y = r * (q - self.x) - self.y * ppp;
self.zz *= pp;
self.zzz *= ppp;
}
}
12 changes: 6 additions & 6 deletions crates/crypto/src/hash/pedersen/gens.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
//! Generators for the Pedersen hash function.
//!
//! See <https://docs.starkware.co/starkex/crypto/pedersen-hash-function.html>
use crate::algebra::curve::ProjectivePoint;
use crate::algebra::curve::AffinePoint;

/// Montgomery representation of the Stark curve constant P0.
pub const PEDERSEN_P0: ProjectivePoint = ProjectivePoint::from_hex(
pub const PEDERSEN_P0: AffinePoint = AffinePoint::from_hex(
"49EE3EBA8C1600700EE1B87EB599F16716B0B1022947733551FDE4050CA6804",
"3CA0CFE4B3BC6DDF346D49D06EA0ED34E621062C0E056C1D0405D266E10268A",
);

/// Montgomery representation of the Stark curve constant P1.
pub const PEDERSEN_P1: ProjectivePoint = ProjectivePoint::from_hex(
pub const PEDERSEN_P1: AffinePoint = AffinePoint::from_hex(
"234287DCBAFFE7F969C748655FCA9E58FA8120B6D56EB0C1080D17957EBE47B",
"3B056F100F96FB21E889527D41F4E39940135DD7A6C94CC6ED0268EE89E5615",
);

/// Montgomery representation of the Stark curve constant P2.
pub const PEDERSEN_P2: ProjectivePoint = ProjectivePoint::from_hex(
pub const PEDERSEN_P2: AffinePoint = AffinePoint::from_hex(
"4FA56F376C83DB33F9DAB2656558F3399099EC1DE5E3018B7A6932DBA8AA378",
"3FA0984C931C9E38113E0C0E47E4401562761F92A7A23B45168F4E80FF5B54D",
);

/// Montgomery representation of the Stark curve constant P3.
pub const PEDERSEN_P3: ProjectivePoint = ProjectivePoint::from_hex(
pub const PEDERSEN_P3: AffinePoint = AffinePoint::from_hex(
"4BA4CC166BE8DEC764910F75B45F74B40C690C74709E90F3AA372F0BD2D6997",
"40301CF5C1751F4B971E46C4EDE85FCAC5C59A5CE5AE7C48151F27B24B219C",
);

/// Montgomery representation of the Stark curve constant P4.
pub const PEDERSEN_P4: ProjectivePoint = ProjectivePoint::from_hex(
pub const PEDERSEN_P4: AffinePoint = AffinePoint::from_hex(
"54302DCB0E6CC1C6E44CCA8F61A63BB2CA65048D53FB325D36FF12C49A58202",
"1B77B3E37D13504B348046268D8AE25CE98AD783C25561A879DCC77E99C2426",
);
8 changes: 5 additions & 3 deletions crates/crypto/src/hash/pedersen/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,22 @@ pub fn pedersen_hash(a: Felt, b: Felt) -> Felt {

// Preprocessed material is lookup-tables for each chunk of bits
let table_size = (1 << CURVE_CONSTS_BITS) - 1;
let add_points = |acc: &mut ProjectivePoint, bits: &BitSlice<u8, _>, prep: &[AffinePoint]| {
let add_points = |acc: &mut XYZZPoint, bits: &BitSlice<u8, _>, prep: &[AffinePoint]| {
bits.chunks(CURVE_CONSTS_BITS)
.enumerate()
.for_each(|(i, v)| {
let offset: usize = v.load_le();
if offset > 0 {
// Table lookup at 'offset-1' in table for chunk 'i'
acc.add_affine(&prep[i * table_size + offset - 1]);
// We can add unchecked, since the accumulator and prep. point cannot be infinity.
acc.add_affine_unchecked(&prep[i * table_size + offset - 1]);
}
});
};

// Compute hash
let mut acc = PEDERSEN_P0;
let mut acc = XYZZPoint::from(&PEDERSEN_P0);

add_points(&mut acc, &a_bits[..248], &CURVE_CONSTS_P1); // Add a_low * P1
add_points(&mut acc, &a_bits[248..252], &CURVE_CONSTS_P2); // Add a_high * P2
add_points(&mut acc, &b_bits[..248], &CURVE_CONSTS_P3); // Add b_low * P3
Expand Down

0 comments on commit 2961b6f

Please sign in to comment.