@@ -1869,4 +1869,148 @@ mod test {
18691869 assert_eq ! ( P . compress( ) , R . compress( ) ) ;
18701870 assert_eq ! ( Q . compress( ) , R . compress( ) ) ;
18711871 }
1872+
1873+ #[ test]
1874+ #[ cfg( feature = "alloc" ) ]
1875+ fn partial_precomputed_mixed_multiscalar_empty ( ) {
1876+ let mut rng = rand:: thread_rng ( ) ;
1877+
1878+ let n_static = 16 ;
1879+ let n_dynamic = 8 ;
1880+
1881+ let static_points = ( 0 ..n_static)
1882+ . map ( |_| RistrettoPoint :: random ( & mut rng) )
1883+ . collect :: < Vec < _ > > ( ) ;
1884+
1885+ // Use zero scalars
1886+ let static_scalars = Vec :: new ( ) ;
1887+
1888+ let dynamic_points = ( 0 ..n_dynamic)
1889+ . map ( |_| RistrettoPoint :: random ( & mut rng) )
1890+ . collect :: < Vec < _ > > ( ) ;
1891+
1892+ let dynamic_scalars = ( 0 ..n_dynamic)
1893+ . map ( |_| Scalar :: random ( & mut rng) )
1894+ . collect :: < Vec < _ > > ( ) ;
1895+
1896+ // Compute the linear combination using precomputed multiscalar multiplication
1897+ let precomputation = VartimeRistrettoPrecomputation :: new ( static_points. iter ( ) ) ;
1898+ let result_multiscalar = precomputation. vartime_mixed_multiscalar_mul (
1899+ & static_scalars,
1900+ & dynamic_scalars,
1901+ & dynamic_points,
1902+ ) ;
1903+
1904+ // Compute the linear combination manually
1905+ let mut result_manual = RistrettoPoint :: identity ( ) ;
1906+ for i in 0 ..static_scalars. len ( ) {
1907+ result_manual += static_points[ i] * static_scalars[ i] ;
1908+ }
1909+ for i in 0 ..n_dynamic {
1910+ result_manual += dynamic_points[ i] * dynamic_scalars[ i] ;
1911+ }
1912+
1913+ assert_eq ! ( result_multiscalar, result_manual) ;
1914+ }
1915+
1916+ #[ test]
1917+ #[ cfg( feature = "alloc" ) ]
1918+ fn partial_precomputed_mixed_multiscalar ( ) {
1919+ let mut rng = rand:: thread_rng ( ) ;
1920+
1921+ let n_static = 16 ;
1922+ let n_dynamic = 8 ;
1923+
1924+ let static_points = ( 0 ..n_static)
1925+ . map ( |_| RistrettoPoint :: random ( & mut rng) )
1926+ . collect :: < Vec < _ > > ( ) ;
1927+
1928+ // Use one fewer scalars
1929+ let static_scalars = ( 0 ..n_static - 1 )
1930+ . map ( |_| Scalar :: random ( & mut rng) )
1931+ . collect :: < Vec < _ > > ( ) ;
1932+
1933+ let dynamic_points = ( 0 ..n_dynamic)
1934+ . map ( |_| RistrettoPoint :: random ( & mut rng) )
1935+ . collect :: < Vec < _ > > ( ) ;
1936+
1937+ let dynamic_scalars = ( 0 ..n_dynamic)
1938+ . map ( |_| Scalar :: random ( & mut rng) )
1939+ . collect :: < Vec < _ > > ( ) ;
1940+
1941+ // Compute the linear combination using precomputed multiscalar multiplication
1942+ let precomputation = VartimeRistrettoPrecomputation :: new ( static_points. iter ( ) ) ;
1943+ let result_multiscalar = precomputation. vartime_mixed_multiscalar_mul (
1944+ & static_scalars,
1945+ & dynamic_scalars,
1946+ & dynamic_points,
1947+ ) ;
1948+
1949+ // Compute the linear combination manually
1950+ let mut result_manual = RistrettoPoint :: identity ( ) ;
1951+ for i in 0 ..static_scalars. len ( ) {
1952+ result_manual += static_points[ i] * static_scalars[ i] ;
1953+ }
1954+ for i in 0 ..n_dynamic {
1955+ result_manual += dynamic_points[ i] * dynamic_scalars[ i] ;
1956+ }
1957+
1958+ assert_eq ! ( result_multiscalar, result_manual) ;
1959+ }
1960+
1961+ #[ test]
1962+ #[ cfg( feature = "alloc" ) ]
1963+ fn partial_precomputed_multiscalar ( ) {
1964+ let mut rng = rand:: thread_rng ( ) ;
1965+
1966+ let n_static = 16 ;
1967+
1968+ let static_points = ( 0 ..n_static)
1969+ . map ( |_| RistrettoPoint :: random ( & mut rng) )
1970+ . collect :: < Vec < _ > > ( ) ;
1971+
1972+ // Use one fewer scalars
1973+ let static_scalars = ( 0 ..n_static - 1 )
1974+ . map ( |_| Scalar :: random ( & mut rng) )
1975+ . collect :: < Vec < _ > > ( ) ;
1976+
1977+ // Compute the linear combination using precomputed multiscalar multiplication
1978+ let precomputation = VartimeRistrettoPrecomputation :: new ( static_points. iter ( ) ) ;
1979+ let result_multiscalar = precomputation. vartime_multiscalar_mul ( & static_scalars) ;
1980+
1981+ // Compute the linear combination manually
1982+ let mut result_manual = RistrettoPoint :: identity ( ) ;
1983+ for i in 0 ..static_scalars. len ( ) {
1984+ result_manual += static_points[ i] * static_scalars[ i] ;
1985+ }
1986+
1987+ assert_eq ! ( result_multiscalar, result_manual) ;
1988+ }
1989+
1990+ #[ test]
1991+ #[ cfg( feature = "alloc" ) ]
1992+ fn partial_precomputed_multiscalar_empty ( ) {
1993+ let mut rng = rand:: thread_rng ( ) ;
1994+
1995+ let n_static = 16 ;
1996+
1997+ let static_points = ( 0 ..n_static)
1998+ . map ( |_| RistrettoPoint :: random ( & mut rng) )
1999+ . collect :: < Vec < _ > > ( ) ;
2000+
2001+ // Use zero scalars
2002+ let static_scalars = Vec :: new ( ) ;
2003+
2004+ // Compute the linear combination using precomputed multiscalar multiplication
2005+ let precomputation = VartimeRistrettoPrecomputation :: new ( static_points. iter ( ) ) ;
2006+ let result_multiscalar = precomputation. vartime_multiscalar_mul ( & static_scalars) ;
2007+
2008+ // Compute the linear combination manually
2009+ let mut result_manual = RistrettoPoint :: identity ( ) ;
2010+ for i in 0 ..static_scalars. len ( ) {
2011+ result_manual += static_points[ i] * static_scalars[ i] ;
2012+ }
2013+
2014+ assert_eq ! ( result_multiscalar, result_manual) ;
2015+ }
18722016}
0 commit comments