in src/main.rs [605:666]
fn pre_reduced_scalar() -> TestVector {
let mut rng = new_rng();
// Pick a random scalar
let mut scalar_bytes = [0u8; 32];
rng.fill_bytes(&mut scalar_bytes);
let a = Scalar::from_bytes_mod_order(scalar_bytes);
debug_assert!(a.is_canonical());
debug_assert!(a != Scalar::zero());
// Pick a random nonce
let nonce_bytes = [0u8; 32];
rng.fill_bytes(&mut scalar_bytes);
// generate the r of a "normal" signature
let prelim_pub_key = a * ED25519_BASEPOINT_POINT;
// Pick a torsion point
let small_idx: usize = rng.next_u64() as usize;
let small_pt = pick_small_nonzero_point(small_idx + 1);
let pub_key = prelim_pub_key + small_pt;
let mut message = [0u8; 32];
rng.fill_bytes(&mut message);
let mut h = Sha512::new();
h.update(&nonce_bytes);
h.update(&message);
let mut output = [0u8; 64];
output.copy_from_slice(h.finalize().as_slice());
let r_scalar = curve25519_dalek::scalar::Scalar::from_bytes_mod_order_wide(&output);
let r = r_scalar * ED25519_BASEPOINT_POINT;
// grind a k so that 8*k gets reduced to a number NOT multiple of eight,
// and add a small order component to the public key.
while multiple_of_eight_le(eight() * compute_hram(&message, &pub_key, &r)) {
rng.fill_bytes(&mut message);
}
let s = r_scalar + compute_hram(&message, &pub_key, &r) * a;
// that's because we do cofactored verification without pre-reducing scalars
debug_assert!(verify_cofactored(&message, &pub_key, &(r, s)).is_ok());
// pre-reducing is a mistake
debug_assert!(verify_pre_reduced_cofactored(&message, &pub_key, &(r, s)).is_err());
// as expected
debug_assert!(verify_cofactorless(&message, &pub_key, &(r, s)).is_err());
debug!(
"S > 0, mixed A, large order R\n\
passes cofactored, fails pre-reducing cofactored, fails cofactorless\n\
\"message\": \"{}\", \"pub_key\": \"{}\", \"signature\": \"{}\"",
hex::encode(&message),
hex::encode(&pub_key.compress().as_bytes()),
hex::encode(&serialize_signature(&r, &s))
);
TestVector {
message,
pub_key: pub_key.compress().to_bytes(),
signature: serialize_signature(&r, &s),
}
}