github.com/cloudflare/circl@v1.5.0/dh/x25519/key_test.go (about) 1 package x25519 2 3 import ( 4 "crypto/rand" 5 "encoding/hex" 6 "encoding/json" 7 "flag" 8 "fmt" 9 "io" 10 "os" 11 "testing" 12 13 "github.com/cloudflare/circl/internal/test" 14 ) 15 16 func hexStr2Key(k *Key, s string) { 17 b, err := hex.DecodeString(s) 18 if err != nil { 19 panic("Can't convert string to key") 20 } 21 copy(k[:], b) 22 } 23 24 // Indicates whether long tests should be run 25 var runLongTest = flag.Bool("long", false, "runs longer tests") 26 27 type katVector struct { 28 Public string `json:"input"` 29 Shared string `json:"output"` 30 Private string `json:"scalar"` 31 } 32 33 func TestRFC7748Kat(t *testing.T) { 34 const nameFile = "testdata/rfc7748_kat_test.json" 35 var kat []katVector 36 37 jsonFile, err := os.Open(nameFile) 38 if err != nil { 39 t.Fatalf("File %v can not be opened. Error: %v", nameFile, err) 40 } 41 defer jsonFile.Close() 42 input, err := io.ReadAll(jsonFile) 43 if err != nil { 44 t.Fatalf("File %v can not be read. Error: %v", nameFile, err) 45 } 46 47 err = json.Unmarshal(input, &kat) 48 if err != nil { 49 t.Fatalf("File %v can not be loaded. Error: %v", nameFile, err) 50 } 51 52 var priv, pub, got, want Key 53 for _, v := range kat { 54 hexStr2Key(&pub, v.Public) 55 hexStr2Key(&priv, v.Private) 56 Shared(&got, &priv, &pub) 57 hexStr2Key(&want, v.Shared) 58 if got != want { 59 test.ReportError(t, got, want, v) 60 } 61 } 62 } 63 64 type katTimes struct { 65 Times uint32 `json:"times"` 66 Key string `json:"key"` 67 } 68 69 func TestRFC7748Times(t *testing.T) { 70 const nameFile = "testdata/rfc7748_times_test.json" 71 jsonFile, err := os.Open(nameFile) 72 if err != nil { 73 t.Fatalf("File %v can not be opened. Error: %v", nameFile, err) 74 } 75 defer jsonFile.Close() 76 input, err := io.ReadAll(jsonFile) 77 if err != nil { 78 t.Fatalf("File %v can not be read. Error: %v", nameFile, err) 79 } 80 81 var kat []katTimes 82 err = json.Unmarshal(input, &kat) 83 if err != nil { 84 t.Fatalf("File %v can not be loaded. Error: %v", nameFile, err) 85 } 86 87 var got, want Key 88 for _, v := range kat { 89 if !*runLongTest && v.Times == uint32(1000000) { 90 t.Log("Skipped one long test, add -long flag to run longer tests") 91 continue 92 } 93 u := Key{9} 94 k := u 95 r := u 96 for i := uint32(0); i < v.Times; i++ { 97 Shared(&r, &k, &u) 98 u = k 99 k = r 100 } 101 got = k 102 hexStr2Key(&want, v.Key) 103 104 if got != want { 105 test.ReportError(t, got, want, v.Times) 106 } 107 } 108 } 109 110 func TestBase(t *testing.T) { 111 testTimes := 1 << 10 112 var got, want, secret Key 113 gen := Key{9} 114 for i := 0; i < testTimes; i++ { 115 _, _ = io.ReadFull(rand.Reader, secret[:]) 116 KeyGen(&got, &secret) 117 Shared(&want, &secret, &gen) 118 if got != want { 119 test.ReportError(t, got, want, secret) 120 } 121 } 122 } 123 124 func TestWycheproof(t *testing.T) { 125 // Test vectors from Wycheproof v0.4.12 126 const nameFile = "testdata/wycheproof_kat.json" 127 jsonFile, err := os.Open(nameFile) 128 if err != nil { 129 t.Fatalf("File %v can not be opened. Error: %v", nameFile, err) 130 } 131 defer jsonFile.Close() 132 133 input, err := io.ReadAll(jsonFile) 134 if err != nil { 135 t.Fatalf("File %v can not be read. Error: %v", nameFile, err) 136 } 137 138 var vecRaw []struct { 139 TcID int `json:"tcId"` 140 Comment string `json:"comment"` 141 Curve string `json:"curve"` 142 Public string `json:"public"` 143 Private string `json:"private"` 144 Shared string `json:"shared"` 145 Result string `json:"result"` 146 Flags []string `json:"flags"` 147 } 148 149 err = json.Unmarshal(input, &vecRaw) 150 if err != nil { 151 t.Fatalf("File %v can not be loaded. Error: %v", nameFile, err) 152 } 153 var got, want, priv, pub Key 154 for _, v := range vecRaw { 155 hexStr2Key(&pub, v.Public) 156 hexStr2Key(&priv, v.Private) 157 hexStr2Key(&want, v.Shared) 158 ok := Shared(&got, &priv, &pub) 159 if got != want { 160 test.ReportError(t, got, want, v.TcID, priv, pub) 161 } 162 if !ok && v.Result != "acceptable" { 163 test.ReportError(t, got, want, v.TcID, priv, pub) 164 } 165 } 166 } 167 168 func BenchmarkX25519(b *testing.B) { 169 var x, y, z Key 170 171 _, _ = io.ReadFull(rand.Reader, x[:]) 172 _, _ = io.ReadFull(rand.Reader, y[:]) 173 _, _ = io.ReadFull(rand.Reader, z[:]) 174 175 b.Run("KeyGen", func(b *testing.B) { 176 for i := 0; i < b.N; i++ { 177 KeyGen(&x, &y) 178 } 179 }) 180 b.Run("Shared", func(b *testing.B) { 181 for i := 0; i < b.N; i++ { 182 Shared(&z, &x, &y) 183 } 184 }) 185 } 186 187 func Example_x25519() { 188 var AliceSecret, BobSecret, 189 AlicePublic, BobPublic, 190 AliceShared, BobShared Key 191 192 // Generating Alice's secret and public keys 193 _, _ = io.ReadFull(rand.Reader, AliceSecret[:]) 194 KeyGen(&AlicePublic, &AliceSecret) 195 196 // Generating Bob's secret and public keys 197 _, _ = io.ReadFull(rand.Reader, BobSecret[:]) 198 KeyGen(&BobPublic, &BobSecret) 199 200 // Deriving Alice's shared key 201 okA := Shared(&AliceShared, &AliceSecret, &BobPublic) 202 203 // Deriving Bob's shared key 204 okB := Shared(&BobShared, &BobSecret, &AlicePublic) 205 206 fmt.Println(AliceShared == BobShared && okA && okB) 207 // Output: true 208 }