twenty-first icon indicating copy to clipboard operation
twenty-first copied to clipboard

bug: digest bytes in do not match bytes out.

Open dan-da opened this issue 4 months ago • 10 comments

In the course of testing hex encode/decode, I discovered that it is possible to create a Digest from input bytes that subsequently produces different output bytes.

Here is a failing test case, suitable for use in digest.rs.

    #[test]
    pub fn bytes_in_matches_bytes_out() {
        let bytes1: [u8; 40] = [255; 40];
        let d1 = Digest::from(bytes1);

        let bytes2: [u8; 40] = d1.into();
        let d2 = Digest::from(bytes2);

        println!("bytes1: {:?}", bytes1);
        println!("bytes2: {:?}", bytes2);

        assert_eq!(d1, d2);
        assert_eq!(bytes1, bytes2);
    }

This test fails with:

---- math::digest::digest_tests::bytes_in_matches_bytes_out stdout ----
bytes1: [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
bytes2: [254, 255, 255, 255, 0, 0, 0, 0, 254, 255, 255, 255, 0, 0, 0, 0, 254, 255, 255, 255, 0, 0, 0, 0, 254, 255, 255, 255, 0, 0, 0, 0, 254, 255, 255, 255, 0, 0, 0, 0]
thread 'math::digest::digest_tests::bytes_in_matches_bytes_out' panicked at twenty-first/src/math/digest.rs:474:9:
assertion `left == right` failed
  left: [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]
 right: [254, 255, 255, 255, 0, 0, 0, 0, 254, 255, 255, 255, 0, 0, 0, 0, 254, 255, 255, 255, 0, 0, 0, 0, 254, 255, 255, 255, 0, 0, 0, 0, 254, 255, 255, 255, 0, 0, 0, 0]

note that:

  1. bytes2 is quite different from bytes1.
  2. digests d1 and d2 are equal, although d2 was created from bytes2.

Taken together, this suggests that the input value is being normalized into a smaller internal max value.

Importantly, if the first line is changed to:

        let bytes1: [u8; 40] = [254; 40];

Then the test passes. So there is something special about [255; 40]. (and possibly other values?)

if bytes1 is somehow an invalid (too large) input, then it seems that Digest::from() should panic, and/or we should only support try_from(). At present, we are silently losing/changing information, but only for certain input values.

dan-da avatar Apr 19 '24 01:04 dan-da