Browse Source

Updated doc comments

al-update-winterfell
Paul-Henry Kajfasz 8 months ago
parent
commit
e2aeb25e01
No known key found for this signature in database GPG Key ID: 5EB89DCE97DB7417
3 changed files with 32 additions and 24 deletions
  1. +24
    -14
      src/hash/rescue/arch/x86_64_avx2.rs
  2. +2
    -4
      src/hash/rescue/rpo/tests.rs
  3. +6
    -6
      src/merkle/mmr/peaks.rs

+ 24
- 14
src/hash/rescue/arch/x86_64_avx2.rs

@ -5,28 +5,38 @@ use core::arch::x86_64::*;
// Preliminary notes:
// 1. AVX does not support addition with carry but 128-bit (2-word) addition can be easily emulated.
// The method recognizes that for a + b overflowed iff (a + b) < a: i. res_lo = a_lo + b_lo ii.
// carry_mask = res_lo < a_lo iii. res_hi = a_hi + b_hi - carry_mask Notice that carry_mask is
// subtracted, not added. This is because AVX comparison instructions return -1 (all bits 1) for
// true and 0 for false.
// The method recognizes that for a + b overflowed iff (a + b) < a:
// - i. res_lo = a_lo + b_lo
// - ii. carry_mask = res_lo < a_lo
// - iii. res_hi = a_hi + b_hi - carry_mask Notice that carry_mask is subtracted, not added.
// This is because AVX comparison instructions return -1 (all bits 1) for true and 0 for false.
//
// 2. AVX does not have unsigned 64-bit comparisons. Those can be emulated with signed comparisons
// by recognizing that a <u b iff a + (1 << 63) <s b + (1 << 63), where the addition wraps around
// and the comparisons are unsigned and signed respectively. The shift function adds/subtracts 1
// << 63 to enable this trick. Example: addition with carry. i. a_lo_s = shift(a_lo) ii. res_lo_s
// = a_lo_s + b_lo iii. carry_mask = res_lo_s <s a_lo_s iv. res_lo = shift(res_lo_s) v. res_hi =
// a_hi + b_hi - carry_mask The suffix _s denotes a value that has been shifted by 1 << 63. The
// result of addition is shifted if exactly one of the operands is shifted, as is the case on
// << 63 to enable this trick. Addition with carry example:
// - i. a_lo_s = shift(a_lo)
// - ii. res_lo_s = a_lo_s + b_lo
// - iii. carry_mask = res_lo_s <s a_lo_s
// - iv. res_lo = shift(res_lo_s)
// - v. res_hi = a_hi + b_hi - carry_mask The suffix _s denotes a value that has been
// shifted by 1 << 63.
//
// The result of addition is shifted if exactly one of the operands is shifted, as is the case on
// line ii. Line iii. performs a signed comparison res_lo_s <s a_lo_s on shifted values to
// emulate unsigned comparison res_lo <u a_lo on unshifted values. Finally, line iv. reverses the
// shift so the result can be returned. When performing a chain of calculations, we can often
// save instructions by letting the shift propagate through and only undoing it when necessary.
// For example, to compute the addition of three two-word (128-bit) numbers we can do: i. a_lo_s
// = shift(a_lo) ii. tmp_lo_s = a_lo_s + b_lo iii. tmp_carry_mask = tmp_lo_s <s a_lo_s iv. tmp_hi
// = a_hi + b_hi - tmp_carry_mask v. res_lo_s = tmp_lo_s + c_lo vi. res_carry_mask = res_lo_s <s
// tmp_lo_s vii. res_lo = shift(res_lo_s) viii. res_hi = tmp_hi + c_hi - res_carry_mask Notice
// that the above 3-value addition still only requires two calls to shift, just like our 2-value
// addition.
// For example, to compute the addition of three two-word (128-bit) numbers we can do:
// - i. a_lo_s = shift(a_lo)
// - ii. tmp_lo_s = a_lo_s + b_lo
// - iii. tmp_carry_mask = tmp_lo_s <s a_lo_s
// - iv. tmp_hi = a_hi + b_hi - tmp_carry_mask
// - v. res_lo_s = tmp_lo_s + c_lo vi. res_carry_mask = res_lo_s <s tmp_lo_s
// - vii. res_lo = shift(res_lo_s)
// - viii. res_hi = tmp_hi + c_hi - res_carry_mask
// Notice that the above 3-value addition still only requires two calls to shift, just like our
// 2-value addition.
#[inline(always)]
pub fn branch_hint() {

+ 2
- 4
src/hash/rescue/rpo/tests.rs

@ -59,8 +59,7 @@ fn merge_vs_merge_in_domain() {
];
let merge_result = Rpo256::merge(&digests);
// ------------- merge with domain = 0
// ----------------------------------------------------------
// ------------- merge with domain = 0 -------------
// set domain to ZERO. This should not change the result.
let domain = ZERO;
@ -68,8 +67,7 @@ fn merge_vs_merge_in_domain() {
let merge_in_domain_result = Rpo256::merge_in_domain(&digests, domain);
assert_eq!(merge_result, merge_in_domain_result);
// ------------- merge with domain = 1
// ----------------------------------------------------------
// ------------- merge with domain = 1 -------------
// set domain to ONE. This should change the result.
let domain = ONE;

+ 6
- 6
src/merkle/mmr/peaks.rs

@ -19,12 +19,12 @@ pub struct MmrPeaks {
///
/// Examples:
///
/// - With 5 leaves, the binary `0b101`. The number of set bits is equal the number of
/// peaks, in this case there are 2 peaks. The 0-indexed least-significant position of the
/// bit determines the number of elements of a tree, so the rightmost tree has `2**0`
/// elements and the left most has `2**2`.
/// - With 12 leaves, the binary is `0b1100`, this case also has 2 peaks, the leftmost tree
/// has `2**3=8` elements, and the right most has `2**2=4` elements.
/// - With 5 leaves, the binary `0b101`. The number of set bits is equal the number of
/// peaks, in this case there are 2 peaks. The 0-indexed least-significant position of the
/// bit determines the number of elements of a tree, so the rightmost tree has `2**0`
/// elements and the left most has `2**2`.
/// - With 12 leaves, the binary is `0b1100`, this case also has 2 peaks, the leftmost tree
/// has `2**3=8` elements, and the right most has `2**2=4` elements.
num_leaves: usize,
/// All the peaks of every tree in the MMR forest. The peaks are always ordered by number of

Loading…
Cancel
Save