github.com/mad-day/Yawning-crypto@v0.0.0-20190711051033-5a5f8cca32ec/bcns/subtle.go (about)

     1  //
     2  // 64 bit Subtle Comparisons
     3  //
     4  // To the extent possible under law, Yawning Angel waived all copyright
     5  // and related or neighboring rights to bcns, using the Creative
     6  // Commons "CC0" public domain dedication. See LICENSE or
     7  // <http://creativecommons.org/publicdomain/zero/1.0/> for full details.
     8  
     9  package bcns
    10  
    11  //
    12  // These routines provide constant-time comparisons and other subtle operations
    13  // analagous to the `crypto/subtle` package over 64 bit integers.
    14  //
    15  
    16  // Returns 1 if x != 0
    17  // Returns 0 if x == 0
    18  // x and y are arbitrary unsigned 64-bit integers
    19  func ctIsNonZeroU64(x uint64) uint64 {
    20  	return (x | -x) >> 63
    21  }
    22  
    23  // Returns 1 if x != y
    24  // Returns 0 if x == y
    25  // x and y are arbitrary unsigned 64-bit integers
    26  func ctNeU64(x, y uint64) uint64 {
    27  	return ((x - y) | (y - x)) >> 63
    28  }
    29  
    30  // Returns 1 if x == y
    31  // Returns 0 if x != y
    32  // x and y are arbitrary unsigned 64-bit integers
    33  func ctEqU64(x, y uint64) uint64 {
    34  	return 1 ^ ctNeU64(x, y)
    35  }
    36  
    37  // Returns 1 if x < y
    38  // Returns 0 if x >= y
    39  // x and y are arbitrary unsigned 64-bit integers
    40  func ctLtU64(x, y uint64) uint64 {
    41  	return (x ^ ((x ^ y) | ((x - y) ^ y))) >> 63
    42  }
    43  
    44  // Returns 1 if x > y
    45  // Returns 0 if x <= y
    46  // x and y are arbitrary unsigned 64-bit integers
    47  func ctGtU64(x, y uint64) uint64 {
    48  	return ctLtU64(y, x)
    49  }
    50  
    51  // Returns 1 if x <= y
    52  // Returns 0 if x > y
    53  // x and y are arbitrary unsigned 64-bit integers
    54  func ctLeU64(x, y uint64) uint64 {
    55  	return 1 ^ ctGtU64(x, y)
    56  }
    57  
    58  // Returns 1 if x >= y
    59  // Returns 0 if x < y
    60  // x and y are arbitrary unsigned 64-bit integers
    61  func ctGeU64(x, y uint64) uint64 {
    62  	return 1 ^ ctLtU64(x, y)
    63  }
    64  
    65  // Returns 0xFFFF..FFFF if bit != 0
    66  // Returns            0 if bit == 0
    67  func ctMaskU64(bit uint64) uint64 {
    68  	return 0 - uint64(ctIsNonZeroU64(bit))
    69  }
    70  
    71  // Conditionally return x or y depending on whether bit is set
    72  // Equivalent to: return bit ? x : y
    73  // x and y are arbitrary 64-bit unsigned integers
    74  // bit must be either 0 or 1.
    75  func selectU64(x, y, bit uint64) uint64 {
    76  	m := ctMaskU64(bit)
    77  	return (x & m) | (y & (^m))
    78  }
    79  
    80  // Returns 0 if a >= b
    81  // Returns 1 if a < b
    82  // Where a and b are both 3-limb 64-bit integers.
    83  func lessThanU192(a, b *[3]uint64) uint64 {
    84  	var r, m uint64
    85  	for i := 0; i < 3; i++ {
    86  		r |= ctLtU64(a[i], b[i]) & (^m)
    87  		m |= ctMaskU64(ctNeU64(a[i], b[i])) /* stop when a[i] != b[i] */
    88  	}
    89  	return r & 1
    90  }