diff --git a/src/primitives/sinsemilla.rs b/src/primitives/sinsemilla.rs index 7a7ec162..f4409ab5 100644 --- a/src/primitives/sinsemilla.rs +++ b/src/primitives/sinsemilla.rs @@ -1,6 +1,6 @@ //! The Sinsemilla hash function and commitment scheme. -use group::{prime::PrimeCurveAffine, Wnaf}; +use group::Wnaf; use halo2::arithmetic::{CurveAffine, CurveExt}; use pasta_curves::pallas; use subtle::CtOption; @@ -120,7 +120,7 @@ impl HashDomain { .chunks(K) .fold(IncompletePoint::from(self.Q), |acc, chunk| { let (S_x, S_y) = SINSEMILLA_S[lebs2ip_k(chunk) as usize]; - let S_chunk = pallas::Affine::from_xy(S_x, S_y).unwrap().to_curve(); + let S_chunk = pallas::Affine::from_xy(S_x, S_y).unwrap(); (acc + S_chunk) + acc }) } diff --git a/src/primitives/sinsemilla/addition.rs b/src/primitives/sinsemilla/addition.rs index 1eed1bff..a9675f3f 100644 --- a/src/primitives/sinsemilla/addition.rs +++ b/src/primitives/sinsemilla/addition.rs @@ -1,6 +1,6 @@ use std::ops::Add; -use group::Group; +use group::{cofactor::CofactorCurveAffine, Group}; use pasta_curves::pallas; use subtle::{ConstantTimeEq, CtOption}; @@ -53,3 +53,28 @@ impl Add for IncompletePoint { self + IncompletePoint(CtOption::new(rhs, 1.into())) } } + +impl Add for IncompletePoint { + type Output = IncompletePoint; + + /// Specialisation of incomplete addition for mixed addition. + fn add(self, rhs: pallas::Affine) -> Self::Output { + // ⊥ ⊹ ⊥ = ⊥ + // ⊥ ⊹ P = ⊥ + IncompletePoint(self.0.and_then(|p| { + // P ⊹ ⊥ = ⊥ is satisfied by definition. + let q = rhs.to_curve(); + + // 0 ⊹ 0 = ⊥ + // 0 ⊹ P = ⊥ + // P ⊹ 0 = ⊥ + // (x, y) ⊹ (x', y') = ⊥ if x == x' + // (x, y) ⊹ (x', y') = (x, y) + (x', y') if x != x' + CtOption::new( + // Use mixed addition for efficiency. + p + rhs, + !(p.is_identity() | q.is_identity() | p.ct_eq(&q) | p.ct_eq(&-q)), + ) + })) + } +}