Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use <[T]>::clone_from_slice(). #140

Closed
wants to merge 1 commit into from
Closed

Use <[T]>::clone_from_slice(). #140

wants to merge 1 commit into from

Conversation

pyfisch
Copy link
Contributor

@pyfisch pyfisch commented Mar 7, 2016

Replace all occurences of ring::polyfill::fill_from_slice.

Closes #136

Replace all occurences of `ring::polyfill::fill_from_slice`.

Closes #136
@briansmith
Copy link
Owner

What was the difference in performance (using crypto_bench)?

@pyfisch
Copy link
Contributor Author

pyfisch commented Mar 7, 2016

Not yet testet. Are there benchmarks for ring?

@briansmith
Copy link
Owner

https://github.com/briansmith/crypto-bench.

You'll need to use a .cargo/config that contains a path override so that your local copy of ring is used instead of the one from GitHub when doing the "after" comparisons.

@pyfisch
Copy link
Contributor Author

pyfisch commented Mar 7, 2016

The benchmarks show that <[T]>::clone_from_slice is equally fast or even faster than ring::polyfill::fill_from_slice. The benchmarks are available at https://gist.github.com/pyfisch/3e557d4ff53c311c655b

@briansmith
Copy link
Owner

The thing is, all your results are faster, even ones that shouldn't be affected by this change like the AES-GCM results. When I run the benchmarks with your changes on my machine, I don't get results consistent with that. We need to check out the generated assembly code and see what's going on.

@briansmith
Copy link
Owner

I used the following code on play.rust-lang.org to verify that the old code and the new code seem to optimize to the same thing:

mod digest {
  pub const MAX_BLOCK_LEN: usize = 1024 / 8;
  pub const MAX_OUTPUT_LEN: usize = 512 / 8;
  pub const MAX_CHAINING_LEN: usize = MAX_OUTPUT_LEN;

  #[inline(always)]
  fn widen_u64(x: usize) -> u64 { x as u64 }

  // XXX: endian-specific.
  // XXX: Replace with `const fn` when `const fn` is stable:
  // https://github.com/rust-lang/rust/issues/24111
  macro_rules! u32x2 {
    ( $first:expr, $second:expr ) =>
    ( ((($second as u64) << 32) | ($first as u64)) )
  }

  pub struct Context {
    // We use u64 to try to ensure 64-bit alignment/padding.
    state: [u64; MAX_CHAINING_LEN / 8],

    block_len: usize,

    // Note that SHA-512 has a 128-bit input bit counter, but this
    // implementation only supports up to 2^64-1 input bits for all algorithms,
    // so a 64-bit counter is more than sufficient.
    completed_data_blocks: u64,

    // TODO: More explicitly force 64-bit alignment for |pending|.
    pending: [u8; MAX_BLOCK_LEN],
    num_pending: usize,
  }

  impl Context {
    pub fn new() -> Context {
        Context {
            state: [
              u32x2!(0x67452301u32, 0xefcdab89u32),
              u32x2!(0x98badcfeu32, 0x10325476u32),
              u32x2!(0xc3d2e1f0u32, 0u32),
              0, 0, 0, 0, 0,
            ],
            block_len: 512 / 8,
            completed_data_blocks: 0,
            pending: [0u8; MAX_BLOCK_LEN],
            num_pending: 0,
        }
    }

    /// Updates the digest with all the data in `data`. `update` may be called
    /// zero or more times until `finish` is called. It must not be called
    /// after `finish` has been called.
    ///
    /// C analog: `EVP_DigestUpdate`
    pub fn update(&mut self, data: &[u8]) {
        if data.len() < self.block_len - self.num_pending {
            println!("copying to pending");
            self.pending[self.num_pending..
                         (self.num_pending + data.len())].clone_from_slice(data);
            self.num_pending += data.len();
            return;
        }

        let mut remaining = data;
        if self.num_pending > 0 {
            let to_copy = self.block_len - self.num_pending;
            println!("something else");
            &mut self.pending[self.num_pending..self.block_len].clone_from_slice(&data[..to_copy]);
            self.completed_data_blocks =
                self.completed_data_blocks.checked_add(1).unwrap();

            remaining = &remaining[to_copy..];
            self.num_pending = 0;
        }

        let num_blocks = remaining.len() / self.block_len;
        let num_to_save_for_later = remaining.len() % self.block_len;
        if num_blocks > 0 {
            self.completed_data_blocks =
                self.completed_data_blocks.checked_add(widen_u64(num_blocks))
                                          .unwrap();
        }
        if num_to_save_for_later > 0 {
            println!("saving for later");
            self.pending[..num_to_save_for_later].clone_from_slice(&remaining[(remaining.len() - num_to_save_for_later)..]);
            self.num_pending = num_to_save_for_later;
        }
    }
  }

}

fn main() {
 let mut x = digest::Context::new();
 x.update(&[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]);
 x.update(&[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]);
 x.update(&[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]);
}

@briansmith
Copy link
Owner

Thanks! Landed in 7cdaeeb.

@briansmith briansmith closed this Mar 8, 2016
@Ms2ger
Copy link
Contributor

Ms2ger commented Mar 8, 2016

Actually landed in 43af354.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants