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  }