diff --git a/CHANGES.txt b/CHANGES.txt index e327ef3..914dcfa 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,7 +1,8 @@ -Pre-release +Version 0.3.0 - June 10, 2020 - Full Windows support and AppVeyor continuous integration - Disabled unit testing for McEliece and Rainbow-IIIc/Vc under Windows (stack size too small) + - Minor fixes Version 0.2.2 - December 10, 2019 - Changed panics to errors in the API diff --git a/README.md b/README.md index 0449c98..b453bd9 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ For simplicity, we only provide installation instructions for Go systems that su of course replacing the paths with the ones corresponding to your system. As mentioned in the [Pre-requisites](#pre-requisites) section, we assume you have installed the [MSYS2](https://www.msys2.org/) C compiler (which contains also `pkg-config`). Make sure that the executable `gcc` and `pkg-config` from MSYS2 are system-wide visible, using e.g. the "Edit the system environment variables" Control Panel tool to add their corresponding directory to the `PATH` environment variable. In our case, MSYS2's `gcc` and `pkg-config` are located under `C:\msys64\mingw64\bin` -,so we need to add that directory to the `PATH`. **Very important:** make sure that the `PATH` entry to the `gcc` and `pkg-config` provided by `MSYS2`comes **before** any other (if any) `gcc` and `pkg-config` executables you may have installed (e.g..such as the ones provided by [Cygwin](www.cygwin.org)). To verify, type into a Command Prompt `gcc --version`, and you should get an output like +,so we need to add that directory to the `PATH`. **Very important:** make sure that the `PATH` entry to the `gcc` and `pkg-config` provided by `MSYS2`comes **before** any other (if any) `gcc` and `pkg-config` executables you may have installed (e.g. such as the ones provided by [Cygwin](https://www.cygwin.com)). To verify, type into a Command Prompt `gcc --version`, and you should get an output like > gcc (Rev3, Built by MSYS2 project) 9.1.0 diff --git a/RELEASE.md b/RELEASE.md index dc93b77..78314cf 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,4 +1,4 @@ -liboqs-go version 0.2.2 +liboqs-go version 0.3.0 ======================= About @@ -13,9 +13,9 @@ The **Open Quantum Safe (OQS) project** has the goal of developing and prototypi Release notes ============= -This release of liboqs-go was released on December 10, 2019. Its release page on GitHub is https://github.com/open-quantum-safe/liboqs-go/releases/tag/0.2.2. +This release of liboqs-go was released on June 10, 2020. Its release page on GitHub is https://github.com/open-quantum-safe/liboqs-go/releases/tag/0.3.0. What's New ---------- -This is the sixth release of liboqs-go. For a list of changes see [CHANGES.txt](https://github.com/open-quantum-safe/liboqs-go/blob/master/CHANGES.txt). +This is the seventh release of liboqs-go. For a list of changes see [CHANGES.txt](https://github.com/open-quantum-safe/liboqs-go/blob/master/CHANGES.txt). diff --git a/oqstests/kem_test.go b/oqstests/kem_test.go index a36f9df..668c211 100644 --- a/oqstests/kem_test.go +++ b/oqstests/kem_test.go @@ -3,6 +3,7 @@ package oqstests import ( "bytes" + "github.com/open-quantum-safe/liboqs-go/oqs/rand" "log" "runtime" "sync" @@ -17,14 +18,17 @@ var disabledKEMPatterns []string // noThreadKEMPatterns lists KEMs that have issues running in a separate thread var noThreadKEMPatterns = []string{"LEDAcryptKEM-LT52"} -// wgKEM groups goroutines and blocks the caller until all goroutines finish. -var wgKEM sync.WaitGroup +// wgKEMCorrectness groups goroutines and blocks the caller until all goroutines finish. +var wgKEMCorrectness sync.WaitGroup -// testKEM tests a specific KEM. -func testKEM(kemName string, threading bool, t *testing.T) { - log.Println(kemName) // thread-safe +// wgKEMWrongCiphertext groups goroutines and blocks the caller until all goroutines finish. +var wgKEMWrongCiphertext sync.WaitGroup + +// testKEMCorrectness tests the correctness of a specific KEM. +func testKEMCorrectness(kemName string, threading bool, t *testing.T) { + log.Println("Correctness - ", kemName) // thread-safe if threading == true { - defer wgKEM.Done() + defer wgKEMCorrectness.Done() } var client, server oqs.KeyEncapsulation defer client.Clean() @@ -41,8 +45,68 @@ func testKEM(kemName string, threading bool, t *testing.T) { } } -// TestKeyEncapsulation tests all enabled KEMs. -func TestKeyEncapsulation(t *testing.T) { +// testKEMWrongCiphertext tests the wrong ciphertext regime of a specific KEM. +func testKEMWrongCiphertext(kemName string, threading bool, t *testing.T) { + log.Println("Wrong ciphertext - ", kemName) // thread-safe + if threading == true { + defer wgKEMWrongCiphertext.Done() + } + var client, server oqs.KeyEncapsulation + defer client.Clean() + defer server.Clean() + // ignore potential errors everywhere + _ = client.Init(kemName, nil) + _ = server.Init(kemName, nil) + clientPublicKey, _ := client.GenerateKeyPair() + ciphertext, sharedSecretServer, _ := server.EncapSecret(clientPublicKey) + wrongCiphertext := rand.RandomBytes(len(ciphertext)) + sharedSecretClient, _ := client.DecapSecret(wrongCiphertext) + if bytes.Equal(sharedSecretClient, sharedSecretServer) { + // t.Errorf is thread-safe + t.Errorf(kemName + ": shared secrets should not coincide") + } +} + +// TestKeyEncapsulationCorrectness tests the correctness of all enabled KEMs. +func TestKeyEncapsulationCorrectness(t *testing.T) { + // disable some KEMs in macOS/OSX + if runtime.GOOS == "darwin" { + disabledKEMPatterns = []string{"Classic-McEliece"} + } + // disable some KEMs in Windows + if runtime.GOOS == "windows" { + disabledKEMPatterns = []string{"Classic-McEliece"} + } + // first test KEMs that belong to noThreadKEMPatterns[] in the main + // goroutine, due to issues with stack size being too small in macOS or + // Windows + cnt := 0 + for _, kemName := range oqs.EnabledKEMs() { + if stringMatchSlice(kemName, disabledKEMPatterns) { + cnt++ + continue + } + // issues with stack size being too small + if stringMatchSlice(kemName, noThreadKEMPatterns) { + cnt++ + testKEMCorrectness(kemName, false, t) + } + } + // test the remaining KEMs in separate goroutines + wgKEMCorrectness.Add(len(oqs.EnabledKEMs()) - cnt) + for _, kemName := range oqs.EnabledKEMs() { + if stringMatchSlice(kemName, disabledKEMPatterns) { + continue + } + if !stringMatchSlice(kemName, noThreadKEMPatterns) { + go testKEMCorrectness(kemName, true, t) + } + } + wgKEMCorrectness.Wait() +} + +// TestKeyEncapsulationWrongCiphertext tests the wrong ciphertext regime of all enabled KEMs. +func TestKeyEncapsulationWrongCiphertext(t *testing.T) { // disable some KEMs in macOS/OSX if runtime.GOOS == "darwin" { disabledKEMPatterns = []string{"Classic-McEliece"} @@ -63,20 +127,20 @@ func TestKeyEncapsulation(t *testing.T) { // issues with stack size being too small if stringMatchSlice(kemName, noThreadKEMPatterns) { cnt++ - testKEM(kemName, false, t) + testKEMWrongCiphertext(kemName, false, t) } } // test the remaining KEMs in separate goroutines - wgKEM.Add(len(oqs.EnabledKEMs()) - cnt) + wgKEMWrongCiphertext.Add(len(oqs.EnabledKEMs()) - cnt) for _, kemName := range oqs.EnabledKEMs() { if stringMatchSlice(kemName, disabledKEMPatterns) { continue } if !stringMatchSlice(kemName, noThreadKEMPatterns) { - go testKEM(kemName, true, t) + go testKEMWrongCiphertext(kemName, true, t) } } - wgKEM.Wait() + wgKEMWrongCiphertext.Wait() } // TestUnsupportedKeyEncapsulation tests that an unsupported KEM emits an error. diff --git a/oqstests/sig_test.go b/oqstests/sig_test.go index dec81ac..42a88a0 100644 --- a/oqstests/sig_test.go +++ b/oqstests/sig_test.go @@ -1,6 +1,7 @@ package oqstests import ( + "github.com/open-quantum-safe/liboqs-go/oqs/rand" "log" "runtime" "sync" @@ -15,14 +16,20 @@ var disabledSigPatterns []string // noThreadSigPatterns lists sigs that have issues running in a separate thread var noThreadSigPatterns []string -// wgSig groups goroutines and blocks the caller until all goroutines finish. -var wgSig sync.WaitGroup +// wgSigCorrectness groups goroutines and blocks the caller until all goroutines finish. +var wgSigCorrectness sync.WaitGroup -// testSig tests a specific signature. -func testSig(sigName string, msg []byte, threading bool, t *testing.T) { - log.Println(sigName) // thread-safe +// wgSigWrongSignature groups goroutines and blocks the caller until all goroutines finish. +var wgSigWrongSignature sync.WaitGroup + +// wgSigWrongPublicKey groups goroutines and blocks the caller until all goroutines finish. +var wgSigWrongPublicKey sync.WaitGroup + +// testSigCorrectness tests a specific signature. +func testSigCorrectness(sigName string, msg []byte, threading bool, t *testing.T) { + log.Println("Correctness - ", sigName) // thread-safe if threading == true { - defer wgSig.Done() + defer wgSigCorrectness.Done() } var signer, verifier oqs.Signature defer signer.Clean() @@ -39,8 +46,132 @@ func testSig(sigName string, msg []byte, threading bool, t *testing.T) { } } -// TestSignature tests all enabled signatures. -func TestSignature(t *testing.T) { +// testSigWrongSignature tests the wrong signature regime of a specific signature. +func testSigWrongSignature(sigName string, msg []byte, threading bool, t *testing.T) { + log.Println("Wrong signature - ", sigName) // thread-safe + if threading == true { + defer wgSigWrongSignature.Done() + } + var signer, verifier oqs.Signature + defer signer.Clean() + defer verifier.Clean() + // ignore potential errors everywhere + _ = signer.Init(sigName, nil) + _ = verifier.Init(sigName, nil) + pubKey, _ := signer.GenerateKeyPair() + signature, _ := signer.Sign(msg) + wrongSignature := rand.RandomBytes(len(signature)) + isValid, _ := verifier.Verify(msg, wrongSignature, pubKey) + if isValid { + // t.Errorf is thread-safe + t.Errorf(sigName + ": signature verification should have failed") + } +} + +// testSigWrongPublicKey tests the wrong public key regime of a specific signature. +func testSigWrongPublicKey(sigName string, msg []byte, threading bool, t *testing.T) { + log.Println("Wrong public key - ", sigName) // thread-safe + if threading == true { + defer wgSigWrongPublicKey.Done() + } + var signer, verifier oqs.Signature + defer signer.Clean() + defer verifier.Clean() + // ignore potential errors everywhere + _ = signer.Init(sigName, nil) + _ = verifier.Init(sigName, nil) + pubKey, _ := signer.GenerateKeyPair() + wrongPubKey := rand.RandomBytes(len(pubKey)) + signature, _ := signer.Sign(msg) + isValid, _ := verifier.Verify(msg, signature, wrongPubKey) + if isValid { + // t.Errorf is thread-safe + t.Errorf(sigName + ": signature verification should have failed") + } +} + +// TestSignatureCorrectness tests all enabled signatures. +func TestSignatureCorrectness(t *testing.T) { + // disable some sigs in macOS/OSX + if runtime.GOOS == "darwin" { + disabledSigPatterns = []string{"Rainbow-IIIc", "Rainbow-Vc"} + } + // disable some sigs in Windows + if runtime.GOOS == "windows" { + disabledSigPatterns = []string{"Rainbow-IIIc", "Rainbow-Vc"} + } + msg := []byte("This is our favourite message to sign") + // first test sigs that belong to noThreadSigPatterns[] in the main + // goroutine, due to issues with stack size being too small in macOS or + // Windows + cnt := 0 + for _, sigName := range oqs.EnabledSigs() { + if stringMatchSlice(sigName, disabledSigPatterns) { + cnt++ + continue + } + // issues with stack size being too small + if stringMatchSlice(sigName, noThreadSigPatterns) { + cnt++ + testSigCorrectness(sigName, msg, false, t) + } + } + // test the remaining sigs in separate goroutines + wgSigCorrectness.Add(len(oqs.EnabledSigs()) - cnt) + for _, sigName := range oqs.EnabledSigs() { + if stringMatchSlice(sigName, disabledSigPatterns) { + continue + } + if !stringMatchSlice(sigName, noThreadSigPatterns) { + go testSigCorrectness(sigName, msg, true, t) + } + } + wgSigCorrectness.Wait() +} + +// TestSignatureWrongSignature tests the wrong signature regime of all enabled +// signatures. +func TestSignatureWrongSignature(t *testing.T) { + // disable some sigs in macOS/OSX + if runtime.GOOS == "darwin" { + disabledSigPatterns = []string{"Rainbow-IIIc", "Rainbow-Vc"} + } + // disable some sigs in Windows + if runtime.GOOS == "windows" { + disabledSigPatterns = []string{"Rainbow-IIIc", "Rainbow-Vc"} + } + msg := []byte("This is our favourite message to sign") + // first test sigs that belong to noThreadSigPatterns[] in the main + // goroutine, due to issues with stack size being too small in macOS or + // Windows + cnt := 0 + for _, sigName := range oqs.EnabledSigs() { + if stringMatchSlice(sigName, disabledSigPatterns) { + cnt++ + continue + } + // issues with stack size being too small + if stringMatchSlice(sigName, noThreadSigPatterns) { + cnt++ + testSigWrongSignature(sigName, msg, false, t) + } + } + // test the remaining sigs in separate goroutines + wgSigWrongSignature.Add(len(oqs.EnabledSigs()) - cnt) + for _, sigName := range oqs.EnabledSigs() { + if stringMatchSlice(sigName, disabledSigPatterns) { + continue + } + if !stringMatchSlice(sigName, noThreadSigPatterns) { + go testSigWrongSignature(sigName, msg, true, t) + } + } + wgSigWrongSignature.Wait() +} + +// TestSignatureWrongPublicKey tests the wrong public key regime of all +// enabled signatures. +func TestSignatureWrongPublicKey(t *testing.T) { // disable some sigs in macOS/OSX if runtime.GOOS == "darwin" { disabledSigPatterns = []string{"Rainbow-IIIc", "Rainbow-Vc"} @@ -62,20 +193,20 @@ func TestSignature(t *testing.T) { // issues with stack size being too small if stringMatchSlice(sigName, noThreadSigPatterns) { cnt++ - testSig(sigName, msg, false, t) + testSigWrongPublicKey(sigName, msg, false, t) } } // test the remaining sigs in separate goroutines - wgSig.Add(len(oqs.EnabledSigs()) - cnt) + wgSigWrongPublicKey.Add(len(oqs.EnabledSigs()) - cnt) for _, sigName := range oqs.EnabledSigs() { if stringMatchSlice(sigName, disabledSigPatterns) { continue } if !stringMatchSlice(sigName, noThreadSigPatterns) { - go testSig(sigName, msg, true, t) + go testSigWrongPublicKey(sigName, msg, true, t) } } - wgSig.Wait() + wgSigWrongPublicKey.Wait() } // TestUnsupportedSignature tests that an unsupported signature emits an error.