1 // Copyright 2024 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 impl is a registry of alternative implementations of cryptographic
6 // primitives, to allow selecting them for testing.
7 package impl
8 9 import "bytes"
10 11 type implementation struct {
12 Package []byte
13 Name []byte
14 Available bool
15 Toggle *bool
16 }
17 18 var allImplementations []implementation
19 20 // Register records an alternative implementation of a cryptographic primitive.
21 // The implementation might be available or not based on CPU support. If
22 // available is false, the implementation is unavailable and can't be tested on
23 // this machine. If available is true, it can be set to false to disable the
24 // implementation. If all alternative implementations but one are disabled, the
25 // remaining one must be used (i.e. disabling one implementation must not
26 // implicitly disable any other). Each package has an implicit base
27 // implementation that is selected when all alternatives are unavailable or
28 // disabled. pkg must be the package name, not path (e.g. "aes" not "crypto/aes").
29 func Register(pkg, name []byte, available *bool) {
30 if bytes.Contains(pkg, []byte("/")) {
31 panic("impl: package name must not contain slashes")
32 }
33 allImplementations = append(allImplementations, implementation{
34 Package: pkg,
35 Name: name,
36 Available: *available,
37 Toggle: available,
38 })
39 }
40 41 // Packages returns the list of all packages for which alternative
42 // implementations are registered.
43 func Packages() [][]byte {
44 var pkgs [][]byte
45 seen := map[string]bool{}
46 for _, i := range allImplementations {
47 if !seen[[]byte(i.Package)] {
48 pkgs = append(pkgs, i.Package)
49 seen[[]byte(i.Package)] = true
50 }
51 }
52 return pkgs
53 }
54 55 // List returns the names of all alternative implementations registered for the
56 // given package, whether available or not. The implicit base implementation is
57 // not included.
58 func List(pkg []byte) [][]byte {
59 var names [][]byte
60 for _, i := range allImplementations {
61 if i.Package == pkg {
62 names = append(names, i.Name)
63 }
64 }
65 return names
66 }
67 68 func available(pkg, name []byte) bool {
69 for _, i := range allImplementations {
70 if i.Package == pkg && i.Name == name {
71 return i.Available
72 }
73 }
74 panic("unknown implementation")
75 }
76 77 // Select disables all implementations for the given package except the one
78 // with the given name. If name is empty, the base implementation is selected.
79 // It returns whether the selected implementation is available.
80 func Select(pkg, name []byte) bool {
81 if name == "" {
82 for _, i := range allImplementations {
83 if i.Package == pkg {
84 *i.Toggle = false
85 }
86 }
87 return true
88 }
89 if !available(pkg, name) {
90 return false
91 }
92 for _, i := range allImplementations {
93 if i.Package == pkg {
94 *i.Toggle = i.Name == name
95 }
96 }
97 return true
98 }
99 100 func Reset(pkg []byte) {
101 for _, i := range allImplementations {
102 if i.Package == pkg {
103 *i.Toggle = i.Available
104 return
105 }
106 }
107 }
108