@@ -128,6 +128,9 @@ use subtle::ConstantTimeEq;
128
128
#[ cfg( feature = "zeroize" ) ]
129
129
use zeroize:: Zeroize ;
130
130
131
+ #[ cfg( test) ]
132
+ use proptest:: { arbitrary:: Arbitrary , strategy:: BoxedStrategy } ;
133
+
131
134
use crate :: constants;
132
135
133
136
use crate :: field:: FieldElement ;
@@ -1771,6 +1774,18 @@ impl CofactorGroup for EdwardsPoint {
1771
1774
}
1772
1775
}
1773
1776
1777
+ #[ cfg( test) ]
1778
+ impl Arbitrary for EdwardsPoint {
1779
+ type Parameters = ( ) ;
1780
+ type Strategy = BoxedStrategy < Self > ;
1781
+
1782
+ fn arbitrary_with ( _: Self :: Parameters ) -> Self :: Strategy {
1783
+ use proptest:: prelude:: * ;
1784
+
1785
+ Strategy :: prop_map ( any :: < Scalar > ( ) , |scalar| EdwardsPoint :: mul_base ( & scalar) ) . boxed ( )
1786
+ }
1787
+ }
1788
+
1774
1789
// ------------------------------------------------------------------------
1775
1790
// Tests
1776
1791
// ------------------------------------------------------------------------
@@ -1779,7 +1794,7 @@ impl CofactorGroup for EdwardsPoint {
1779
1794
mod test {
1780
1795
use super :: * ;
1781
1796
1782
- use rand_core :: TryRngCore ;
1797
+ use proptest :: { prelude :: * , property_test } ;
1783
1798
1784
1799
#[ cfg( feature = "alloc" ) ]
1785
1800
use alloc:: vec:: Vec ;
@@ -2066,17 +2081,14 @@ mod test {
2066
2081
}
2067
2082
2068
2083
/// Check that mul_base_clamped and mul_clamped agree
2069
- #[ test]
2070
- fn mul_base_clamped ( ) {
2071
- let mut csprng = rand_core:: OsRng ;
2084
+ #[ property_test( config = ProptestConfig { cases: 50 , .. ProptestConfig :: default ( ) } ) ]
2085
+ fn mul_base_clamped ( b : EdwardsPoint , a : [ [ u8 ; 32 ] ; 100 ] ) {
2086
+ #[ cfg( not( feature = "precomputed-tables" ) ) ]
2087
+ let _ = b;
2072
2088
2073
2089
// Make a random curve point in the curve. Give it torsion to make things interesting.
2074
2090
#[ cfg( feature = "precomputed-tables" ) ]
2075
- let random_point = {
2076
- let mut b = [ 0u8 ; 32 ] ;
2077
- csprng. try_fill_bytes ( & mut b) . unwrap ( ) ;
2078
- EdwardsPoint :: mul_base_clamped ( b) + constants:: EIGHT_TORSION [ 1 ]
2079
- } ;
2091
+ let random_point = b + constants:: EIGHT_TORSION [ 1 ] ;
2080
2092
// Make a basepoint table from the random point. We'll use this with mul_base_clamped
2081
2093
#[ cfg( feature = "precomputed-tables" ) ]
2082
2094
let random_table = EdwardsBasepointTableRadix256 :: create ( & random_point) ;
@@ -2086,28 +2098,25 @@ mod test {
2086
2098
// Test that mul_base_clamped and mul_clamped agree on a large integer. Even after
2087
2099
// clamping, this integer is not reduced mod l.
2088
2100
let a_bytes = [ 0xff ; 32 ] ;
2089
- assert_eq ! (
2101
+ prop_assert_eq ! (
2090
2102
EdwardsPoint :: mul_base_clamped( a_bytes) ,
2091
2103
constants:: ED25519_BASEPOINT_POINT . mul_clamped( a_bytes)
2092
2104
) ;
2093
2105
#[ cfg( feature = "precomputed-tables" ) ]
2094
- assert_eq ! (
2106
+ prop_assert_eq ! (
2095
2107
random_table. mul_base_clamped( a_bytes) ,
2096
2108
random_point. mul_clamped( a_bytes)
2097
2109
) ;
2098
2110
2099
2111
// Test agreement on random integers
2100
- for _ in 0 .. 100 {
2112
+ for a_bytes in a {
2101
2113
// This will be reduced mod l with probability l / 2^256 ≈ 6.25%
2102
- let mut a_bytes = [ 0u8 ; 32 ] ;
2103
- csprng. try_fill_bytes ( & mut a_bytes) . unwrap ( ) ;
2104
-
2105
- assert_eq ! (
2114
+ prop_assert_eq ! (
2106
2115
EdwardsPoint :: mul_base_clamped( a_bytes) ,
2107
2116
constants:: ED25519_BASEPOINT_POINT . mul_clamped( a_bytes)
2108
2117
) ;
2109
2118
#[ cfg( feature = "precomputed-tables" ) ]
2110
- assert_eq ! (
2119
+ prop_assert_eq ! (
2111
2120
random_table. mul_base_clamped( a_bytes) ,
2112
2121
random_point. mul_clamped( a_bytes)
2113
2122
) ;
@@ -2182,22 +2191,14 @@ mod test {
2182
2191
}
2183
2192
}
2184
2193
2194
+ #[ property_test]
2185
2195
#[ cfg( feature = "alloc" ) ]
2186
- #[ test]
2187
- fn compress_batch ( ) {
2188
- let mut rng = rand:: rng ( ) ;
2189
-
2190
- // TODO(tarcieri): proptests?
2191
- // Make some points deterministically then randomly
2192
- let mut points = ( 1u64 ..16 )
2193
- . map ( |n| constants:: ED25519_BASEPOINT_POINT * Scalar :: from ( n) )
2194
- . collect :: < Vec < _ > > ( ) ;
2195
- points. extend ( core:: iter:: repeat_with ( || EdwardsPoint :: random ( & mut rng) ) . take ( 100 ) ) ;
2196
+ fn compress_batch ( points : Vec < EdwardsPoint > ) {
2196
2197
let compressed = EdwardsPoint :: compress_batch ( & points) ;
2197
2198
2198
2199
// Check that the batch-compressed points match the individually compressed ones
2199
2200
for ( point, compressed) in points. iter ( ) . zip ( & compressed) {
2200
- assert_eq ! ( & point. compress( ) , compressed) ;
2201
+ prop_assert_eq ! ( & point. compress( ) , compressed) ;
2201
2202
}
2202
2203
}
2203
2204
@@ -2238,14 +2239,11 @@ mod test {
2238
2239
assert ! ( P1 . compress( ) . to_bytes( ) == P2 . compress( ) . to_bytes( ) ) ;
2239
2240
}
2240
2241
2241
- // A single iteration of a consistency check for MSM.
2242
+ # [ property_test ]
2242
2243
#[ cfg( feature = "alloc" ) ]
2243
- fn multiscalar_consistency_iter ( n : usize ) {
2244
- let mut rng = rand:: rng ( ) ;
2245
-
2244
+ fn multiscalar_consistency ( xs : Vec < Scalar > ) {
2246
2245
// Construct random coefficients x0, ..., x_{n-1},
2247
2246
// followed by some extra hardcoded ones.
2248
- let xs = ( 0 ..n) . map ( |_| Scalar :: random ( & mut rng) ) . collect :: < Vec < _ > > ( ) ;
2249
2247
let check = xs. iter ( ) . map ( |xi| xi * xi) . sum :: < Scalar > ( ) ;
2250
2248
2251
2249
// Construct points G_i = x_i * B
@@ -2258,58 +2256,13 @@ mod test {
2258
2256
// Compute H3 = <xs, Gs> = sum(xi^2) * B
2259
2257
let H3 = EdwardsPoint :: mul_base ( & check) ;
2260
2258
2261
- assert_eq ! ( H1 , H3 ) ;
2262
- assert_eq ! ( H2 , H3 ) ;
2263
- }
2264
-
2265
- // Use different multiscalar sizes to hit different internal
2266
- // parameters.
2267
-
2268
- #[ test]
2269
- #[ cfg( feature = "alloc" ) ]
2270
- fn multiscalar_consistency_n_100 ( ) {
2271
- let iters = 50 ;
2272
- for _ in 0 ..iters {
2273
- multiscalar_consistency_iter ( 100 ) ;
2274
- }
2275
- }
2276
-
2277
- #[ test]
2278
- #[ cfg( feature = "alloc" ) ]
2279
- fn multiscalar_consistency_n_250 ( ) {
2280
- let iters = 50 ;
2281
- for _ in 0 ..iters {
2282
- multiscalar_consistency_iter ( 250 ) ;
2283
- }
2259
+ prop_assert_eq ! ( H1 , H3 ) ;
2260
+ prop_assert_eq ! ( H2 , H3 ) ;
2284
2261
}
2285
2262
2286
- #[ test ]
2263
+ #[ property_test ]
2287
2264
#[ cfg( feature = "alloc" ) ]
2288
- fn multiscalar_consistency_n_500 ( ) {
2289
- let iters = 50 ;
2290
- for _ in 0 ..iters {
2291
- multiscalar_consistency_iter ( 500 ) ;
2292
- }
2293
- }
2294
-
2295
- #[ test]
2296
- #[ cfg( feature = "alloc" ) ]
2297
- fn multiscalar_consistency_n_1000 ( ) {
2298
- let iters = 50 ;
2299
- for _ in 0 ..iters {
2300
- multiscalar_consistency_iter ( 1000 ) ;
2301
- }
2302
- }
2303
-
2304
- #[ test]
2305
- #[ cfg( feature = "alloc" ) ]
2306
- fn batch_to_montgomery ( ) {
2307
- let mut rng = rand:: rng ( ) ;
2308
-
2309
- let scalars = ( 0 ..128 )
2310
- . map ( |_| Scalar :: random ( & mut rng) )
2311
- . collect :: < Vec < _ > > ( ) ;
2312
-
2265
+ fn batch_to_montgomery ( scalars : Vec < Scalar > ) {
2313
2266
let points = scalars
2314
2267
. iter ( )
2315
2268
. map ( EdwardsPoint :: mul_base)
@@ -2320,25 +2273,19 @@ mod test {
2320
2273
. map ( EdwardsPoint :: to_montgomery)
2321
2274
. collect :: < Vec < _ > > ( ) ;
2322
2275
2323
- for i in [ 0 , 1 , 2 , 3 , 10 , 50 , 128 ] {
2324
- let invs = EdwardsPoint :: to_montgomery_batch ( & points[ ..i] ) ;
2325
- assert_eq ! ( & invs, & single_monts[ ..i] ) ;
2326
- }
2276
+ let invs = EdwardsPoint :: to_montgomery_batch ( & points) ;
2277
+ prop_assert_eq ! ( & invs, & single_monts) ;
2327
2278
}
2328
2279
2329
- #[ test ]
2280
+ #[ property_test ]
2330
2281
#[ cfg( feature = "alloc" ) ]
2331
- fn vartime_precomputed_vs_nonprecomputed_multiscalar ( ) {
2332
- let mut rng = rand:: rng ( ) ;
2333
-
2334
- let static_scalars = ( 0 ..128 )
2335
- . map ( |_| Scalar :: random ( & mut rng) )
2336
- . collect :: < Vec < _ > > ( ) ;
2337
-
2338
- let dynamic_scalars = ( 0 ..128 )
2339
- . map ( |_| Scalar :: random ( & mut rng) )
2340
- . collect :: < Vec < _ > > ( ) ;
2341
-
2282
+ fn vartime_precomputed_vs_nonprecomputed_multiscalar (
2283
+ #[ strategy = any :: < Vec < Scalar > > ( ) . prop_flat_map ( |v1| {
2284
+ let len = v1. len ( ) ;
2285
+ ( Just ( v1) , prop:: collection:: vec ( any :: < Scalar > ( ) , len) )
2286
+ } ) ]
2287
+ ( static_scalars, dynamic_scalars) : ( Vec < Scalar > , Vec < Scalar > ) ,
2288
+ ) {
2342
2289
let check_scalar: Scalar = static_scalars
2343
2290
. iter ( )
2344
2291
. chain ( dynamic_scalars. iter ( ) )
@@ -2356,8 +2303,7 @@ mod test {
2356
2303
2357
2304
let precomputation = VartimeEdwardsPrecomputation :: new ( static_points. iter ( ) ) ;
2358
2305
2359
- assert_eq ! ( precomputation. len( ) , 128 ) ;
2360
- assert ! ( !precomputation. is_empty( ) ) ;
2306
+ prop_assert_eq ! ( precomputation. len( ) , static_scalars. len( ) ) ;
2361
2307
2362
2308
let P = precomputation. vartime_mixed_multiscalar_mul (
2363
2309
& static_scalars,
@@ -2373,8 +2319,8 @@ mod test {
2373
2319
2374
2320
let R = EdwardsPoint :: mul_base ( & check_scalar) ;
2375
2321
2376
- assert_eq ! ( P . compress( ) , R . compress( ) ) ;
2377
- assert_eq ! ( Q . compress( ) , R . compress( ) ) ;
2322
+ prop_assert_eq ! ( P . compress( ) , R . compress( ) ) ;
2323
+ prop_assert_eq ! ( Q . compress( ) , R . compress( ) ) ;
2378
2324
}
2379
2325
2380
2326
mod vartime {
0 commit comments