From b7dab8d08341bcceef73c36adf1875c10c677007 Mon Sep 17 00:00:00 2001 From: Henry de Valence Date: Tue, 15 May 2018 14:57:37 -0700 Subject: [PATCH] Add iterator length checks to multiscalar muls. This partially re-adds functionality removed in commit d2ce1ce5dc7133f8fe7f96ebd03a2242b042621f We would like to require ExactSizeIterator, but unfortunately we can't do that, since ExactSizeIterators aren't chainable, for (in my opinion) silly reasons (chaining two 4-billion-element ExactSizeIterators could overflow on 32-bit systems). Instead we inspect the size hints manually and assert that the lower and upper bounds are all equal. --- src/edwards.rs | 60 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/src/edwards.rs b/src/edwards.rs index 98512fa..68e6b9f 100644 --- a/src/edwards.rs +++ b/src/edwards.rs @@ -556,21 +556,31 @@ impl MultiscalarMul for EdwardsPoint { J: IntoIterator, J::Item: Borrow, { - // XXX later when we do more fancy multiscalar mults, we can - // delegate based on the iter's size hint -- hdevalence + // Sanity-check lengths of input iterators + let mut scalars = scalars.into_iter(); + let mut points = points.into_iter(); + + // Lower and upper bounds on iterators + let (s_lo, s_hi) = scalars.by_ref().size_hint(); + let (p_lo, p_hi) = points.by_ref().size_hint(); + + // They should all be equal + assert_eq!(s_lo, p_lo); + assert_eq!(s_hi, Some(s_lo)); + assert_eq!(p_hi, Some(p_lo)); + + // Now we know there's a single size. When we do + // size-dependent algorithm dispatch, use this as the hint. + let _size = s_lo; // If we built with AVX2, use the AVX2 backend. #[cfg(all(feature="avx2_backend", target_feature="avx2"))] - { - use backend::avx2::scalar_mul::straus::Straus; - Straus::multiscalar_mul(scalars, points) - } + use backend::avx2::scalar_mul::straus::Straus; // Otherwise, proceed as normal: #[cfg(not(all(feature="avx2_backend", target_feature="avx2")))] - { - use scalar_mul::straus::Straus; - Straus::multiscalar_mul(scalars, points) - } + use scalar_mul::straus::Straus; + + Straus::multiscalar_mul(scalars, points) } } @@ -584,21 +594,31 @@ impl VartimeMultiscalarMul for EdwardsPoint { I::Item: Borrow, J: IntoIterator>, { - // XXX later when we do more fancy multiscalar mults, we can - // delegate based on the iter's size hint -- hdevalence + // Sanity-check lengths of input iterators + let mut scalars = scalars.into_iter(); + let mut points = points.into_iter(); + + // Lower and upper bounds on iterators + let (s_lo, s_hi) = scalars.by_ref().size_hint(); + let (p_lo, p_hi) = points.by_ref().size_hint(); + + // They should all be equal + assert_eq!(s_lo, p_lo); + assert_eq!(s_hi, Some(s_lo)); + assert_eq!(p_hi, Some(p_lo)); + + // Now we know there's a single size. When we do + // size-dependent algorithm dispatch, use this as the hint. + let _size = s_lo; // If we built with AVX2, use the AVX2 backend. #[cfg(all(feature="avx2_backend", target_feature="avx2"))] - { - use backend::avx2::scalar_mul::straus::Straus; - Straus::optional_multiscalar_mul(scalars, points) - } + use backend::avx2::scalar_mul::straus::Straus; // Otherwise, proceed as normal: #[cfg(not(all(feature="avx2_backend", target_feature="avx2")))] - { - use scalar_mul::straus::Straus; - Straus::optional_multiscalar_mul(scalars, points) - } + use scalar_mul::straus::Straus; + + Straus::optional_multiscalar_mul(scalars, points) } }