Updated doc comments
This commit is contained in:
parent
790846cc73
commit
e2aeb25e01
3 changed files with 32 additions and 24 deletions
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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…
Add table
Reference in a new issue