1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package subtle
6 7 import (
8 "crypto/internal/fips140deps/byteorder"
9 "math/bits"
10 )
11 12 // ConstantTimeCompare returns 1 if the two slices, x and y, have equal contents
13 // and 0 otherwise. The time taken is a function of the length of the slices and
14 // is independent of the contents. If the lengths of x and y do not match it
15 // returns 0 immediately.
16 func ConstantTimeCompare(x, y []byte) int {
17 if len(x) != len(y) {
18 return 0
19 }
20 21 var v byte
22 23 for i := 0; i < len(x); i++ {
24 v |= x[i] ^ y[i]
25 }
26 27 return ConstantTimeByteEq(v, 0)
28 }
29 30 // ConstantTimeLessOrEqBytes returns 1 if x <= y and 0 otherwise. The comparison
31 // is lexigraphical, or big-endian. The time taken is a function of the length of
32 // the slices and is independent of the contents. If the lengths of x and y do not
33 // match it returns 0 immediately.
34 func ConstantTimeLessOrEqBytes(x, y []byte) int {
35 if len(x) != len(y) {
36 return 0
37 }
38 39 // Do a constant time subtraction chain y - x.
40 // If there is no borrow at the end, then x <= y.
41 var b uint64
42 for len(x) > 8 {
43 x0 := byteorder.BEUint64(x[len(x)-8:])
44 y0 := byteorder.BEUint64(y[len(y)-8:])
45 _, b = bits.Sub64(y0, x0, b)
46 x = x[:len(x)-8]
47 y = y[:len(y)-8]
48 }
49 if len(x) > 0 {
50 xb := []byte{:8}
51 yb := []byte{:8}
52 copy(xb[8-len(x):], x)
53 copy(yb[8-len(y):], y)
54 x0 := byteorder.BEUint64(xb)
55 y0 := byteorder.BEUint64(yb)
56 _, b = bits.Sub64(y0, x0, b)
57 }
58 return int(b ^ 1)
59 }
60 61 // ConstantTimeSelect returns x if v == 1 and y if v == 0.
62 // Its behavior is undefined if v takes any other value.
63 func ConstantTimeSelect(v, x, y int) int { return ^(v-1)&x | (v-1)&y }
64 65 // ConstantTimeByteEq returns 1 if x == y and 0 otherwise.
66 func ConstantTimeByteEq(x, y uint8) int {
67 return int((uint32(x^y) - 1) >> 31)
68 }
69 70 // ConstantTimeEq returns 1 if x == y and 0 otherwise.
71 func ConstantTimeEq(x, y int32) int {
72 return int((uint64(uint32(x^y)) - 1) >> 63)
73 }
74 75 // ConstantTimeCopy copies the contents of y into x (a slice of equal length)
76 // if v == 1. If v == 0, x is left unchanged. Its behavior is undefined if v
77 // takes any other value.
78 func ConstantTimeCopy(v int, x, y []byte) {
79 if len(x) != len(y) {
80 panic("subtle: slices have different lengths")
81 }
82 83 xmask := byte(v - 1)
84 ymask := byte(^(v - 1))
85 for i := 0; i < len(x); i++ {
86 x[i] = x[i]&xmask | y[i]&ymask
87 }
88 }
89 90 // ConstantTimeLessOrEq returns 1 if x <= y and 0 otherwise.
91 // Its behavior is undefined if x or y are negative or > 2**31 - 1.
92 func ConstantTimeLessOrEq(x, y int) int {
93 x32 := int32(x)
94 y32 := int32(y)
95 return int(((x32 - y32 - 1) >> 31) & 1)
96 }
97