| // Copyright 2025 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package subtle |
| |
| import ( |
| "bytes" |
| "crypto/internal/fips140deps/byteorder" |
| "math/rand/v2" |
| "testing" |
| "time" |
| ) |
| |
| func TestConstantTimeLessOrEqBytes(t *testing.T) { |
| seed := make([]byte, 32) |
| byteorder.BEPutUint64(seed, uint64(time.Now().UnixNano())) |
| r := rand.NewChaCha8([32]byte(seed)) |
| for l := range 20 { |
| a := make([]byte, l) |
| b := make([]byte, l) |
| empty := make([]byte, l) |
| r.Read(a) |
| r.Read(b) |
| exp := 0 |
| if bytes.Compare(a, b) <= 0 { |
| exp = 1 |
| } |
| if got := ConstantTimeLessOrEqBytes(a, b); got != exp { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want %d", a, b, got, exp) |
| } |
| exp = 0 |
| if bytes.Compare(b, a) <= 0 { |
| exp = 1 |
| } |
| if got := ConstantTimeLessOrEqBytes(b, a); got != exp { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want %d", b, a, got, exp) |
| } |
| if got := ConstantTimeLessOrEqBytes(empty, a); got != 1 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 1", empty, a, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(empty, b); got != 1 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 1", empty, b, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(a, a); got != 1 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 1", a, a, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(b, b); got != 1 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 1", b, b, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(empty, empty); got != 1 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 1", empty, empty, got) |
| } |
| if l == 0 { |
| continue |
| } |
| max := make([]byte, l) |
| for i := range max { |
| max[i] = 0xff |
| } |
| if got := ConstantTimeLessOrEqBytes(a, max); got != 1 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 1", a, max, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(b, max); got != 1 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 1", b, max, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(empty, max); got != 1 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 1", empty, max, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(max, max); got != 1 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 1", max, max, got) |
| } |
| aPlusOne := make([]byte, l) |
| copy(aPlusOne, a) |
| for i := l - 1; i >= 0; i-- { |
| if aPlusOne[i] == 0xff { |
| aPlusOne[i] = 0 |
| continue |
| } |
| aPlusOne[i]++ |
| if got := ConstantTimeLessOrEqBytes(a, aPlusOne); got != 1 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 1", a, aPlusOne, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(aPlusOne, a); got != 0 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 0", aPlusOne, a, got) |
| } |
| break |
| } |
| shorter := make([]byte, l-1) |
| copy(shorter, a) |
| if got := ConstantTimeLessOrEqBytes(a, shorter); got != 0 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 0", a, shorter, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(shorter, a); got != 0 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 0", shorter, a, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(b, shorter); got != 0 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 0", b, shorter, got) |
| } |
| if got := ConstantTimeLessOrEqBytes(shorter, b); got != 0 { |
| t.Errorf("ConstantTimeLessOrEqBytes(%x, %x) = %d, want 0", shorter, b, got) |
| } |
| } |
| } |