├── .github └── workflows │ └── tests.yml ├── .gitignore ├── DISCLAIMER.txt ├── LICENSE ├── README.md ├── crystals-dilithium ├── benchmark_test.go ├── dilithium3.go ├── dilithium3_test.go ├── internal.go ├── kat_test.go ├── keys.go ├── ntt.go ├── pack.go ├── params.go ├── poly.go ├── testdata │ ├── PQCsignKAT_Dilithium2.rsp │ ├── PQCsignKAT_Dilithium3.rsp │ ├── PQCsignKAT_Dilithium5.rsp │ └── dilithium-submission-nist-round3.zip ├── utils_benchmark_test.go ├── utils_test.go └── vec.go ├── crystals-kyber ├── benchmark_test.go ├── ccakem.go ├── ccakem_test.go ├── cpapke.go ├── cpapke_test.go ├── internal.go ├── kat_test.go ├── keys.go ├── ntt.go ├── params.go ├── poly.go ├── testdata │ ├── PQCkemKAT_1632.rsp │ ├── PQCkemKAT_2400.rsp │ ├── PQCkemKAT_3168.rsp │ └── kyber-submission-nist-round3.zip ├── utils_benchmark_test.go ├── utils_test.go └── vec.go ├── go.mod └── go.sum /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | on: [ push, pull_request ] 3 | jobs: 4 | 5 | tests: 6 | name: ${{matrix.go-version}} ${{matrix.os}} 7 | runs-on: ${{ matrix.os }} 8 | strategy: 9 | matrix: 10 | go-version: [ 1.16 ] 11 | os: [ macos-latest, windows-latest, ubuntu-latest ] 12 | steps: 13 | - name: Set up Go 14 | uses: actions/setup-go@v1 15 | with: 16 | go-version: ${{matrix.go-version}} 17 | - name: Print go version 18 | run: go version 19 | - name: Check out module 20 | uses: actions/checkout@v1 21 | with: 22 | fetch-depth: 1 23 | - name: Download modules 24 | run: go mod tidy -v 25 | - name: Run tests 26 | run: go test -race ./... 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | -------------------------------------------------------------------------------- /DISCLAIMER.txt: -------------------------------------------------------------------------------- 1 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Abandoned](https://img.shields.io/badge/Status-Unmaintained-blue) 2 | # Go Post Quantum Safe Lib 3 | 4 | This library offers a proof of concept for a fast and easy to use implementation of the post-quantum candidates of the CRYSTALS suite. 5 | It contains Kyber, a key-encapsulation mechanism whose goal is to securely transmit symmetric key material over an insecure channel, and Dilithium, a digital signature algorithm that produces a signature that can be verified against a key, and can be used towards authentication or integrity. 6 | 7 | ## DISCLAIMER 8 | 9 | This library was written as part of a MsC student project in the Cybersecurity Team at Kudelski Security. It is not actively maintained anymore. It is only intended for research and testing. We discourage its use in any production environment. Kudelski Security does not use this library as part of their commercial offers or product. If you are interested in continuing development feel free to fork it. 10 | 11 | ## API 12 | 13 | To begin with, the crystal-go module can be installed via: 14 | ```shell 15 | go get -u github.com/kudelskisecurity/crystals-go 16 | ``` 17 | 18 | The API of Kyber and Dilihtium is very similar, and can be divided in two steps: 19 | 20 | The user first has to define which level of security they want to work with by creating an instance of Kyber or Dilithium among (in increasing level of security) Kyber512, Kyber768, Kyber1024 and Dilithium2, Dilithium3, Dilithium5. For example: 21 | 22 | ```go 23 | k := NewKyber512() //Creates a Kyber instance with light security level 24 | d := Dilithium3() //Creates a Dilithium instance with recommended/medium security level 25 | ``` 26 | 27 | The newly created instance defines all parameters used internally. In a second step, the user can now invoke our generic methods on an instance of Kyber or Dilithium. 28 | 29 | ### Kyber 30 | The core functions of Kyber, a KEM, are a tuple KeyGen, Encaps, and Decaps. The key generation function returns a public key that can be openly disclosed, and a secret key that should remain private. The encapsulation function is used to generate and encrypt a shared secret given a public key. Secret that can be recovered using the associated secret key. No one except the secret key holder can recover the value of the shared secret. 31 | 32 | Translated to code, a KEM protocol between Alice and Bob using our API looks like this: 33 | 34 | Alice and Bob agreed on using the recommended security level. Alice can now generate a public and private key pair by calling: 35 | ```go 36 | k := NewKyber768() 37 | pk, sk := k.KeyGen(seed) 38 | ``` 39 | Once the keys are generated, Alice can send her public key to Bob, who encapsulates a shared secret using: 40 | ```go 41 | k := NewKyber768() 42 | c, ss := k.Encaps(pk, coins) 43 | ``` 44 | The ciphertext is transmitted to Alice for her to recover the value of ss with: 45 | ```go 46 | ss := k.Decaps(sk, c) //Matches the value held by Bob 47 | ``` 48 | 49 | ### Dilithium 50 | 51 | For Dilithium, the DSA, the main methods are KeyGen, Sign, and Verify, which very intuitively, correspond to the verification key (public) and signing key (secret) generation, the signature algorithm, and the verification algorithm. The signature, given a message and a signing key, produces a signature that is verifiable against the associated public verification key. Dilithium signatures are said to be unforgeable, meaning that it is extremely hard to create a valid signature without actually holding the signing key. In that case, Dilithium can be used as an authentication mechanism, as a valid signature is the proof that the signer is the secret key holder. If the message is tampered, the signature will not verify anymore, so Dilithium can also be used to enforce message integrity. 52 | 53 | Similarly, we can translate the Dilithium protocol to code. W.L.O.G, we choose Alice to be the signer, and Bob the verifier, and assume that they agreed on using the light security level. 54 | 55 | Alice starts by generating a key pair: 56 | ```go 57 | d := Dilithium2() //Creates a Dilithium instance with recommended security level 58 | pk, sk := d.KeyGen() 59 | ``` 60 | She can then sign a message of her choice using: 61 | ```go 62 | msg := []byte("This is a message.") 63 | sig := d.Sign(sk, msg) 64 | ``` 65 | Then transmit her public key, message, and signature to Bob for him to verify it with: 66 | ```go 67 | d := Dilithium2() 68 | verified := d.Verify(pk, sig, msg) //verified is true for honest executions 69 | ``` 70 | 71 | A feature of Dilithium is to be available both in randomized or deterministic mode. When creating a Dilithium instance, a boolean is given as parameter to indicate which one to use. By default, the boolean is set to true, setting Dilithium to the randomized mode, but passing *false* as parameter will choose the deterministic mode. 72 | For example, `d := NewDilithium3(false)` will create a Dilithium instance with parameters set to the security level 3, and a deterministic signature. 73 | The signing and verification procedure is the same for both and follows the aforementioned flow. 74 | 75 | ### Random inputs 76 | 77 | This leads us to the final feature of the API regarding randomization. Both Kyber and Dilithium use random numbers. The concerned methods accept as argument seed or coins of 32 bytes to be used as random material, which allows for reproducibility for example, or is useful if the user does not trust the environment to generate good randomness and wants to use randomness from their own source. 78 | They can also be *nil*, in which case the randomness will be generated during using Go's official crypto/rand library. 79 | 80 | ### Helpers 81 | 82 | The output sizes of Kyber and Dilithium (keys, signature,...) vary based on the security level. 83 | We provide for both schemes getter functions that return the size of the keys and ciphertext or signature structures based on the security level of the instance used. 84 | They can be called as follows: 85 | 86 | ```go 87 | sizePk := k.SizePk() 88 | sizeSk := k.SizeSk() 89 | sizeC := k.SizeC() 90 | ``` 91 | for Kyber, or 92 | ```go 93 | sizePk := k.SizePk() 94 | sizeSk := k.SizeSk() 95 | sizeSig := d.SizeSig() 96 | ``` 97 | for Dilithium. 98 | 99 | Finally, we noticed that some packages (for example: [binary](https://golang.org/pkg/encoding/binary/) are only compatible with constant-size objects. 100 | Our API outputs slices, which are variable-sized arrays, and function calls in Go return non-constant values, breaking the compatibility with such packages. 101 | For applications where resources need to be allocated using constant-size structures, we hardcode the size of our scheme's outputs for each security level, and expose them as constants as part of the Kyber/Dilithium packages. Have a look at the [param.go](https://github.com/kudelskisecurity/crystals-go/blob/main/crystals-dilithium/params.go#L19) file for an example. 102 | 103 | ### Errors 104 | 105 | In order to keep the API pretty simple, any error will result in a *nil* output (*false* is the case or *Verify*). For now the error is printed, but we are working on Log Levels. 106 | 107 | ### Dashboard SCA (not updated) 108 | 109 | | | Alg | Attack | Paper | 110 | | -- | ---- |----------------- |:----------------------- | 111 | | | | TA | | 112 | | ✔️| D | Timing of decryption | [:link:][dan19] | 113 | | ✔️| D | Timing of re-encryption check | [:link:][guo20] | 114 | | | | CM | | 115 | | ✖️| KG | Cache access monitoring | [:link:][fac18] | 116 | | ✖️| S | Cache access monitoring | [:link:][fac18] | 117 | | ✔️| D| Cache access monitoring | [:link:][rav20] | 118 | | | | FA | | 119 | | ✔️| KG | Skip of secret addition | [:link:][bbk19] | 120 | | ✔️| S | Skip of mask addition | [:link:][rav19] | 121 | | ✖️| D | Skip of decryption check | [:link:][pp21] | 122 | | ✖️| D | Skip of +Q/2 instruction | [:link:][pp21] | 123 | | ✖️| KG | Zero of secret | [:link:][bbk19] | 124 | | ✖️| KG | Zero of noise | [:link:][val17] | 125 | | ✖️| KG | Zero of A | [:link:][val17] | 126 | | ✖️| S | Zero of randomness | [:link:][bbk19] | 127 | | ✖️| KG | Zero of noise | [:link:][val17] | 128 | | ✔️| KG | Zero of nonce | [:link:][rav18] | 129 | | ✔️| E | Zero of nonce | [:link:][rav18] | 130 | | ✔️| S | Zero of mask | [:link:][esp18] | 131 | | ✔️| S | Loop-abort of mask addition | [:link:][bbk19] | 132 | | ✔️| KG | Loop abort of noise addition | [:link:][esp18] | 133 | | ✔️| S | Err. in hash polynomial | [:link:][bp18] | 134 | | ✔️| S | Err. in expand function | [:link:][bp18] | 135 | 136 | 137 | 138 | Attacks marked with a gray cross are the ones left, a green checkmark implies that a defense is implemented. 139 | 140 | [dan19]: https://doi.org/10.1145/3338467.3358948 141 | [guo20]: https://eprint.iacr.org/2020/743 142 | [fac18]: https://ieeexplore.ieee.org/document/8494855 143 | [rav20]: https://eprint.iacr.org/2020/1559 144 | [bbk19]: https://eprint.iacr.org/2016/415 145 | [rav19]: https://eprint.iacr.org/2019/769 146 | [rav18]: https://eprint.iacr.org/2018/211 147 | [val17]: https://doi.org/10.1145/3178291.3178294 148 | [pp21]: https://eprint.iacr.org/2021/064 149 | [esp18]: https://eprint.iacr.org/2016/449.pdf 150 | [bp18]: https://eprint.iacr.org/2018/355 151 | -------------------------------------------------------------------------------- /crystals-dilithium/benchmark_test.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | "crypto/ecdsa" 5 | "crypto/elliptic" 6 | "crypto/rand" 7 | "crypto/sha256" 8 | "testing" 9 | ) 10 | 11 | func BenchmarkECDSA(b *testing.B) { 12 | for n := 0; n < b.N; n++ { 13 | ecdsa.GenerateKey(elliptic.P384(), rand.Reader) 14 | } 15 | } 16 | 17 | func BenchmarkECDSASign(b *testing.B) { 18 | msg := "message to sign" 19 | hash := sha256.Sum256([]byte(msg)) 20 | sk, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) 21 | for n := 0; n < b.N; n++ { 22 | ecdsa.SignASN1(rand.Reader, sk, hash[:]) 23 | } 24 | } 25 | 26 | func BenchmarkECDSAVerify(b *testing.B) { 27 | msg := "message to sign" 28 | hash := sha256.Sum256([]byte(msg)) 29 | sk, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) 30 | sig, _ := ecdsa.SignASN1(rand.Reader, sk, hash[:]) 31 | for n := 0; n < b.N; n++ { 32 | ecdsa.VerifyASN1(&sk.PublicKey, hash[:], sig) 33 | } 34 | } 35 | 36 | func BenchmarkKeyGen2(b *testing.B) { benchmarkKeyGen(b, NewDilithium2(false)) } 37 | func BenchmarkSign2(b *testing.B) { benchmarkSign(b, NewDilithium2(false)) } 38 | func BenchmarkVerify2(b *testing.B) { benchmarkVerify(b, NewDilithium2(false)) } 39 | 40 | func BenchmarkKeyGen3(b *testing.B) { benchmarkKeyGen(b, NewDilithium3(false)) } 41 | func BenchmarkSign3(b *testing.B) { benchmarkSign(b, NewDilithium3(false)) } 42 | func BenchmarkVerify3(b *testing.B) { benchmarkVerify(b, NewDilithium3(false)) } 43 | 44 | func BenchmarkKeyGen5(b *testing.B) { benchmarkKeyGen(b, NewDilithium5(false)) } 45 | func BenchmarkSign5(b *testing.B) { benchmarkSign(b, NewDilithium5(false)) } 46 | func BenchmarkVerify5(b *testing.B) { benchmarkVerify(b, NewDilithium5(false)) } 47 | 48 | func benchmarkKeyGen(b *testing.B, d *Dilithium) { 49 | var seed [32]byte 50 | for n := 0; n < b.N; n++ { 51 | d.KeyGen(seed[:]) 52 | } 53 | } 54 | 55 | func benchmarkSign(b *testing.B, d *Dilithium) { 56 | var msg [59]byte 57 | var seed [32]byte 58 | _, sk := d.KeyGen(seed[:]) 59 | for n := 0; n < b.N; n++ { 60 | d.Sign(msg[:], sk) 61 | } 62 | } 63 | 64 | func benchmarkVerify(b *testing.B, d *Dilithium) { 65 | var msg [59]byte 66 | var seed [32]byte 67 | pk, sk := d.KeyGen(seed[:]) 68 | sig := d.Sign(msg[:], sk) 69 | for n := 0; n < b.N; n++ { 70 | d.Verify(msg[:], sig, pk) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /crystals-dilithium/dilithium3.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | "bytes" 5 | "crypto/rand" 6 | "crypto/subtle" 7 | 8 | "golang.org/x/crypto/sha3" 9 | ) 10 | 11 | //KeyGen creates a public and private key pair. 12 | //A 32 byte long seed can be given as argument. If a nil seed is given, the seed is generated using Go crypto's random number generator. 13 | //The keys returned are packed into byte arrays. 14 | func (d *Dilithium) KeyGen(seed []byte) ([]byte, []byte) { 15 | 16 | if seed == nil || len(seed) != SEEDBYTES { 17 | seed = make([]byte, SEEDBYTES) 18 | rand.Read(seed) 19 | } 20 | 21 | var tr, rho, key [SEEDBYTES]byte 22 | var rhoprime [2 * SEEDBYTES]byte 23 | 24 | state := sha3.NewShake256() 25 | state.Write(seed) 26 | state.Read(rho[:]) 27 | state.Read(rhoprime[:]) 28 | state.Read(key[:]) 29 | state.Reset() 30 | 31 | K := d.params.K 32 | L := d.params.L 33 | ETA := d.params.ETA 34 | 35 | Ahat := expandSeed(rho, K, L) 36 | 37 | s1 := make(Vec, L) 38 | for i := 0; i < L; i++ { 39 | s1[i] = polyUniformEta(rhoprime, uint16(i), ETA) 40 | } 41 | s2 := make(Vec, K) 42 | for i := 0; i < K; i++ { 43 | s2[i] = polyUniformEta(rhoprime, uint16(i+L), ETA) 44 | } 45 | s1hat := s1.copy() 46 | s1hat.ntt(L) 47 | s2hat := s2.copy() 48 | s2hat.ntt(K) 49 | 50 | t, t1, t0 := make(Vec, K), make(Vec, K), make(Vec, K) 51 | for i := 0; i < K; i++ { 52 | t[i] = vecAccPointWise(Ahat[i], s1hat, L) 53 | s2hat[i].tomont() 54 | t[i] = add(t[i], s2hat[i]) 55 | t[i].invntt() 56 | t[i].addQ() 57 | t1[i], t0[i] = polyPower2Round(t[i]) 58 | } 59 | state.Write(append(rho[:], packT1(t1, K)...)) 60 | state.Read(tr[:]) 61 | 62 | return d.PackPK(PublicKey{T1: t1, Rho: rho}), d.PackSK(PrivateKey{Rho: rho, Key: key, Tr: tr, S1: s1, S2: s2, T0: t0}) 63 | } 64 | 65 | //Sign produces a signature on the given msg using the secret signing key. 66 | //The signing key must be given as packed byte array. 67 | //The message should also be a byte array. 68 | //The returned signature is packed into a byte array. If an error occurs during the signature process, a nil signature is returned. 69 | func (d *Dilithium) Sign(packedSK, msg []byte) []byte { 70 | if len(packedSK) != d.SIZESK() { 71 | println("Cannot sign with this key.") 72 | return nil 73 | } 74 | K := d.params.K 75 | L := d.params.L 76 | BETA := d.params.BETA 77 | 78 | sk := d.UnpackSK(packedSK) 79 | Ahat := expandSeed(sk.Rho, K, L) 80 | 81 | var mu [2 * SEEDBYTES]byte 82 | state := sha3.NewShake256() 83 | state.Write(sk.Tr[:]) 84 | state.Write(msg) 85 | state.Read(mu[:]) 86 | state.Reset() 87 | 88 | var rhoP, rhoPRand [2 * SEEDBYTES]byte 89 | state.Write(append(sk.Key[:], mu[:]...)) 90 | state.Read(rhoP[:]) 91 | state.Reset() 92 | 93 | rand.Read(rhoPRand[:]) 94 | subtle.ConstantTimeCopy(d.params.RANDOMIZED, rhoP[:], rhoPRand[:]) 95 | 96 | s1hat := sk.S1.copy() 97 | s2hat := sk.S2.copy() 98 | t0hat := sk.T0.copy() 99 | s1hat.ntt(L) 100 | s2hat.ntt(K) 101 | t0hat.ntt(K) 102 | 103 | var nonce uint16 104 | y, z := make(Vec, L), make(Vec, L) 105 | var c Poly 106 | 107 | rej: 108 | if nonce > 500 { //Failing after 500 trials happens with probability close to 2^(-128). 109 | println("Sign ran out of trials.") 110 | return nil 111 | } 112 | 113 | for i := 0; i < L; i++ { 114 | y[i] = polyUniformGamma1(rhoP, nonce, d.params.GAMMA1) 115 | nonce++ 116 | } 117 | 118 | yhat := y.copy() 119 | yhat.ntt(L) 120 | 121 | w, w1, w0 := make(Vec, K), make(Vec, K), make(Vec, K) 122 | for i := 0; i < K; i++ { 123 | w[i] = vecAccPointWise(Ahat[i], yhat, L) 124 | w[i].reduce() 125 | w[i].invntt() 126 | w[i].addQ() 127 | w1[i], w0[i] = polyDecompose(w[i], d.params.GAMMA2) 128 | } 129 | 130 | var hc, zero [SEEDBYTES]byte 131 | state.Write(mu[:]) 132 | state.Write(packW1(w1, K, d.params.POLYSIZEW1, d.params.GAMMA2)) 133 | state.Read(hc[:]) 134 | state.Reset() 135 | 136 | state.Write(mu[:]) 137 | state.Write(packW1(w0, K, d.params.POLYSIZEW1, d.params.GAMMA2)) 138 | state.Read(zero[:]) 139 | if bytes.Equal(zero[:], hc[:]) { 140 | return nil 141 | } 142 | state.Reset() 143 | 144 | c = challenge(hc[:], d.params.T) 145 | 146 | chat := c 147 | chat.ntt() 148 | 149 | for i := 0; i < L; i++ { 150 | yhat[i].tomont() 151 | z[i] = montMul(chat, s1hat[i]) 152 | z[i] = add(z[i], yhat[i]) 153 | z[i].invntt() 154 | z[i].reduce() 155 | } 156 | if !z.vecIsBelow(d.params.GAMMA1-BETA, L) { 157 | goto rej 158 | } 159 | 160 | wcs2 := make(Vec, K) 161 | for i := 0; i < K; i++ { 162 | wcs2[i] = montMul(chat, s2hat[i]) 163 | wcs2[i].invntt() 164 | wcs2[i] = sub(w0[i], wcs2[i]) 165 | wcs2[i].reduce() 166 | } 167 | 168 | if !wcs2.vecIsBelow(d.params.GAMMA2-BETA, K) { 169 | goto rej 170 | } 171 | 172 | ct0 := make(Vec, K) 173 | for i := 0; i < K; i++ { 174 | ct0[i] = montMul(chat, t0hat[i]) 175 | ct0[i].invntt() 176 | ct0[i].reduce() 177 | } 178 | 179 | if !ct0.vecIsBelow(d.params.GAMMA2, K) { 180 | goto rej 181 | } 182 | 183 | wcs2 = vecAdd(wcs2, ct0, K) 184 | h, n := vecMakeHint(w1, wcs2, K, d.params.GAMMA2) 185 | if n > d.params.OMEGA { 186 | goto rej 187 | } 188 | return d.PackSig(z, h, hc[:]) 189 | } 190 | 191 | //Verify uses the verification key to verify a signature given a msg. 192 | //The public key and signature must be given as packed byte arrays. 193 | //The message should be a byte array. 194 | //The result of the verificatino is returned as a boolean, true is the verificatino succeeded, false otherwise. 195 | //If an error occurs during the verification, a false is returned. 196 | func (d *Dilithium) Verify(packedPK, msg, sig []byte) bool { 197 | if len(sig) != d.SIZESIG() || len(packedPK) != d.SIZEPK() { 198 | return false 199 | } 200 | 201 | K := d.params.K 202 | L := d.params.L 203 | 204 | pk := d.UnpackPK(packedPK) 205 | z, h, hc := d.UnpackSig(sig) 206 | 207 | c := challenge(hc[:], d.params.T) 208 | Ahat := expandSeed(pk.Rho, K, L) 209 | var tr [SEEDBYTES]byte 210 | var mu [2 * SEEDBYTES]byte 211 | state := sha3.NewShake256() 212 | state.Write(append(pk.Rho[:], packT1(pk.T1, K)...)) 213 | state.Read(tr[:]) 214 | state.Reset() 215 | 216 | state.Write(tr[:]) 217 | state.Write(msg) 218 | state.Read(mu[:]) 219 | state.Reset() 220 | 221 | zhat := z.copy() 222 | zhat.ntt(L) 223 | 224 | chat := c 225 | chat.ntt() 226 | 227 | t1hat := pk.T1.copy() 228 | 229 | w1 := make(Vec, K) 230 | for i := 0; i < K; i++ { 231 | w1[i] = vecAccPointWise(Ahat[i], zhat, L) 232 | 233 | t1hat[i].shift() 234 | t1hat[i].ntt() 235 | t1hat[i] = montMul(chat, t1hat[i]) 236 | 237 | w1[i] = sub(w1[i], t1hat[i]) 238 | w1[i].reduce() 239 | w1[i].invntt() 240 | w1[i].addQ() 241 | w1[i] = polyUseHint(w1[i], h[i], d.params.GAMMA2) 242 | } 243 | var hc2 [SEEDBYTES]byte 244 | state.Write(mu[:]) 245 | state.Write(packW1(w1, K, d.params.POLYSIZEW1, d.params.GAMMA2)) 246 | state.Read(hc2[:]) 247 | 248 | return z.vecIsBelow(d.params.GAMMA1-d.params.BETA, L) && bytes.Equal(hc, hc2[:]) && h.sum(K) <= d.params.OMEGA 249 | } 250 | -------------------------------------------------------------------------------- /crystals-dilithium/dilithium3_test.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | "bytes" 5 | cRand "crypto/rand" 6 | "io" 7 | "testing" 8 | 9 | "golang.org/x/crypto/sha3" 10 | ) 11 | 12 | func TestKeyGen(t *testing.T) { 13 | d := NewDilithium2(false) 14 | K := d.params.K 15 | var seed [32]byte 16 | rand := cRand.Reader 17 | io.ReadFull(rand, seed[:]) 18 | ppk, psk := d.KeyGen(seed[:]) 19 | ppk2, psk2 := d.KeyGen(seed[:]) 20 | pk, pk2, sk, sk2 := d.UnpackPK(ppk), d.UnpackPK(ppk2), d.UnpackSK(psk), d.UnpackSK(psk2) 21 | if pk.Rho != pk2.Rho || !pk.T1.equal(pk2.T1, K) { 22 | t.Fatal("KeyGen failed to reproduce") 23 | } 24 | if sk.Key != sk2.Key || sk.Rho != sk2.Rho || sk.Tr != sk2.Tr || !sk.S2.equal(sk2.S2, K) { 25 | t.Fatal("Key Gen failed to reproduce") 26 | } 27 | io.ReadFull(rand, seed[:]) 28 | ppk3, psk3 := d.KeyGen(seed[:]) 29 | pk3, sk3 := d.UnpackPK(ppk3), d.UnpackSK(psk3) 30 | if pk.Rho == pk3.Rho || pk.T1.equal(pk3.T1, K) { 31 | t.Fatal("KeyGen is repeating when it should not") 32 | } 33 | if sk.Key == sk3.Key || sk.Rho == sk3.Rho || sk.Tr == sk3.Tr || sk.S2.equal(sk3.S2, K) { 34 | t.Fatal("KeyGen is repeating when it should not") 35 | } 36 | } 37 | 38 | func TestSign(t *testing.T) { 39 | d := NewDilithium2(false) 40 | var seed [32]byte 41 | rand := cRand.Reader 42 | io.ReadFull(rand, seed[:]) 43 | _, sk := d.KeyGen(seed[:]) 44 | msg := []byte("Message to sign") 45 | sig := d.Sign(sk, msg) 46 | z, h, c := d.UnpackSig(sig) 47 | //var cNull Poly 48 | if z == nil || h == nil || c == nil { //}|| c.equal(cNull) { 49 | t.Fatal("sig failed") 50 | } 51 | } 52 | 53 | //Used for FA 54 | func TestManySign(t *testing.T) { 55 | d := NewDilithium2(false) 56 | var seed [32]byte 57 | rand := cRand.Reader 58 | for i := 0; i < 1000; i++ { 59 | io.ReadFull(rand, seed[:]) 60 | _, sk := d.KeyGen(seed[:]) 61 | msg := []byte("Message to sign") 62 | sig := d.Sign(sk, msg) 63 | z, h, c := d.UnpackSig(sig) 64 | //var cNull Poly 65 | if z == nil || h == nil || c == nil { //}|| c.equal(cNull) { 66 | t.Fatal("sig failed") 67 | } 68 | } 69 | } 70 | 71 | func TestChallenge(t *testing.T) { 72 | 73 | d := NewDilithium3(false) 74 | K := d.params.K 75 | var key [32]byte 76 | var mu, mu2, rhoP [64]byte 77 | rand := cRand.Reader 78 | rand.Read(key[:]) 79 | rand.Read(mu[:]) 80 | rand.Read(mu2[:]) 81 | rand.Read(rhoP[:]) 82 | 83 | w, w2 := make(Vec, K), make(Vec, K) 84 | var nonce uint16 85 | for i := 0; i < K; i++ { 86 | w[i] = polyUniformGamma1(rhoP, nonce, d.params.GAMMA1) 87 | nonce++ 88 | } 89 | for i := 0; i < K; i++ { 90 | w2[i] = polyUniformGamma1(rhoP, nonce, d.params.GAMMA1) 91 | nonce++ 92 | } 93 | var hc [SEEDBYTES]byte 94 | state := sha3.NewShake256() 95 | state.Write(mu[:]) 96 | state.Write(packW1(w, K, d.params.POLYSIZEW1, d.params.GAMMA2)) 97 | state.Read(hc[:]) 98 | state.Reset() 99 | c := challenge(hc[:], d.params.T) 100 | c1 := challenge(hc[:], d.params.T) 101 | 102 | state.Write(mu2[:]) 103 | state.Write(packW1(w, K, d.params.POLYSIZEW1, d.params.GAMMA2)) 104 | state.Read(hc[:]) 105 | state.Reset() 106 | 107 | c2 := challenge(hc[:], d.params.T) 108 | 109 | state.Write(mu[:]) 110 | state.Write(packW1(w2, K, d.params.POLYSIZEW1, d.params.GAMMA2)) 111 | state.Read(hc[:]) 112 | state.Reset() 113 | 114 | c3 := challenge(hc[:], d.params.T) 115 | 116 | if !c.equal(c1) { 117 | t.Fatal("challenge does not reprodux") 118 | } 119 | if c.equal(c2) || c.equal(c3) { 120 | t.Fatal("challenge repeats output") 121 | } 122 | } 123 | 124 | func TestVerify(t *testing.T) { 125 | d := NewDilithium2(false) 126 | var seed [32]byte 127 | rand := cRand.Reader 128 | io.ReadFull(rand, seed[:]) 129 | pk, sk := d.KeyGen(seed[:]) 130 | msg := []byte("Message to sign") 131 | sig := d.Sign(sk, msg) 132 | if !d.Verify(pk, msg, sig) { 133 | t.Fatal("Verify failed") 134 | } 135 | 136 | } 137 | 138 | func TestVerifAnotherMSG(t *testing.T) { 139 | d := NewDilithium2(false) 140 | var seed [32]byte 141 | rand := cRand.Reader 142 | io.ReadFull(rand, seed[:]) 143 | pk, sk := d.KeyGen(seed[:]) 144 | msg := []byte("Message to sign") 145 | sig := d.Sign(sk, msg) 146 | msg2 := []byte("Another message") 147 | if d.Verify(pk, msg2, sig) { 148 | t.Fatal("Signature verified on another msg") 149 | 150 | } 151 | } 152 | 153 | func TestPack(t *testing.T) { 154 | d := NewDilithium2(false) 155 | pk, sk := d.KeyGen(nil) 156 | pk2 := d.PackPK(d.UnpackPK(pk)) 157 | sk2 := d.PackSK(d.UnpackSK(sk)) 158 | if !bytes.Equal(pk[:], pk2[:]) { 159 | t.Fatal("Pack failed") 160 | } 161 | if !bytes.Equal(sk[:], sk2[:]) { 162 | t.Fatal("SK Pack failed") 163 | } 164 | } 165 | 166 | func TestRandomized(t *testing.T) { 167 | d := NewDilithium2() 168 | d2 := NewDilithium2(true) 169 | if d.params.RANDOMIZED+d2.params.RANDOMIZED != 2 { 170 | t.Fatal("Init did not work") 171 | } 172 | d3 := NewDilithium2(false) 173 | if d3.params.RANDOMIZED != 0 { 174 | t.Fatal("Init did not work") 175 | } 176 | } 177 | 178 | func TestBadSize(t *testing.T) { 179 | d := NewDilithium2() 180 | k := []byte("Hi") 181 | s := d.Sign(nil, k) 182 | if s != nil { 183 | t.Fatal("Sign accepts bad secret keys") 184 | } 185 | b := d.Verify(nil, nil, k) 186 | if b { 187 | t.Fatal("Verifies with wrong input") 188 | } 189 | } 190 | 191 | func TestYzero(t *testing.T) { 192 | d := NewDilithium3(false) 193 | K := d.params.K 194 | L := d.params.L 195 | 196 | var mu [2 * SEEDBYTES]byte 197 | cRand.Read(mu[:]) 198 | 199 | var hc, zero, rho [SEEDBYTES]byte 200 | cRand.Read(rho[:]) 201 | Ahat := expandSeed(rho, K, L) 202 | 203 | y := make(Vec, L) 204 | yhat := y.copy() 205 | yhat.ntt(L) 206 | 207 | w, w1, w0 := make(Vec, K), make(Vec, K), make(Vec, K) 208 | for i := 0; i < K; i++ { 209 | w[i] = vecAccPointWise(Ahat[i], yhat, L) 210 | w[i].reduce() 211 | w[i].invntt() 212 | w[i].addQ() 213 | w1[i], w0[i] = polyDecompose(w[i], d.params.GAMMA2) 214 | } 215 | 216 | state := sha3.NewShake256() 217 | state.Write(mu[:]) 218 | state.Write(packW1(w1, K, d.params.POLYSIZEW1, d.params.GAMMA2)) 219 | state.Read(hc[:]) 220 | state.Reset() 221 | 222 | state.Write(mu[:]) 223 | state.Write(packW1(w0, K, d.params.POLYSIZEW1, d.params.GAMMA2)) 224 | state.Read(zero[:]) 225 | if !bytes.Equal(zero[:], hc[:]) { 226 | t.Fatal("We missed a fault") 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /crystals-dilithium/internal.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | "golang.org/x/crypto/sha3" 5 | ) 6 | 7 | //reduce32 maps a to the [-Q, Q] domain 8 | func reduce32(a int32) int32 { 9 | t := (a + (1 << 22)) >> 23 10 | t = a - t*q 11 | return t 12 | } 13 | 14 | //addQ maps a to a "positive" representation in constant time 15 | func addQ(a int32) int32 { 16 | a += (a >> 31) & q 17 | return a 18 | } 19 | 20 | //freeze maps a to the [0, Q] domain 21 | func freeze(a int32) int32 { 22 | a = reduce32(a) 23 | a = addQ(a) 24 | return a 25 | } 26 | 27 | //power2Round returns a1 and a0+Q such that a = a1*2^D+a0 28 | func power2Round(a int32) (int32, int32) { 29 | a1 := (a + (1 << (d - 1)) - 1) >> d 30 | a0 := a - (a1 << d) 31 | return a1, a0 32 | } 33 | 34 | //decompose returns a1 and a0+Q such that a = a1*alpha + a0 35 | func decompose(a int32, GAMMA2 int32) (int32, int32) { 36 | a1 := (a + 127) >> 7 37 | 38 | if GAMMA2 == (q-1)/32 { 39 | a1 = (a1*1025 + (1 << 21)) >> 22 40 | a1 &= 15 41 | } 42 | if GAMMA2 == (q-1)/88 { 43 | a1 = (a1*11275 + (1 << 23)) >> 24 44 | a1 ^= ((43 - a1) >> 31) & a1 45 | } 46 | a0 := a - a1*2*GAMMA2 47 | a0 -= (((q-1)/2 - a0) >> 31) & q 48 | return a1, a0 49 | } 50 | 51 | //makeHint returns 1 iff a0 overflows a1 52 | func makeHint(a1, a0 int32, GAMMA2 int32) int32 { 53 | if a0 > GAMMA2 || a0 < -GAMMA2 || (a0 == -GAMMA2 && a1 != 0) { 54 | return 1 55 | } 56 | return 0 57 | } 58 | 59 | //useHint computes the real high bits of a 60 | func useHint(a int32, hint int32, GAMMA2 int32) int32 { 61 | a1, a0 := decompose(a, GAMMA2) 62 | if hint == 0 { 63 | return a1 64 | } 65 | if a0 > 0 { 66 | if GAMMA2 == (q-1)/32 { 67 | return (a1 + 1) & 15 68 | } 69 | if a1 == 43 { 70 | return 0 71 | } 72 | return a1 + 1 73 | } 74 | if GAMMA2 == (q-1)/32 { 75 | return (a1 - 1) & 15 76 | } 77 | if a1 == 0 { 78 | return 43 79 | } 80 | return a1 - 1 81 | } 82 | 83 | //Mat is used to hold the matrix A 84 | type Mat []Vec 85 | 86 | //expandSeed uses rho to create A, a KxL matrix of uniform polynomials 87 | func expandSeed(rho [SEEDBYTES]byte, K, L int) Mat { 88 | A := make(Mat, K) 89 | for i := 0; i < K; i++ { 90 | A[i] = make(Vec, L) 91 | for j := 0; j < L; j++ { 92 | A[i][j] = polyUniform(rho, uint16((i<<8)+j)) 93 | } 94 | } 95 | return A 96 | } 97 | 98 | //challenge creates a Poly with exactly T 1's and the rest 0's 99 | func challenge(hc []byte, T int) Poly { 100 | var c Poly 101 | var outbuf [shake256Rate]byte 102 | state := sha3.NewShake256() 103 | state.Write(hc[:]) 104 | state.Read(outbuf[:]) 105 | 106 | signs := uint64(0) 107 | for i := uint(0); i < 8; i++ { 108 | signs |= uint64(outbuf[i]) << (8 * i) 109 | } 110 | pos := 8 111 | b := 0 112 | for i := n - T; i < n; i++ { 113 | for { 114 | if pos >= shake256Rate { 115 | state.Read(outbuf[:]) 116 | pos = 0 117 | } 118 | b = int(outbuf[pos]) 119 | pos++ 120 | if b <= i { 121 | break 122 | } 123 | } 124 | c[i] = c[b] 125 | c[b] = 1 - 2*int32((signs&1)) 126 | signs >>= 1 127 | } 128 | 129 | return c 130 | } 131 | 132 | //Computes the integer in {-(q-1)/2,...,(q-1)/2} congruent to a modulo q 133 | func barretReduce(a int32) int32 { 134 | v := int32(((uint32(1) << 26) + uint32(q/2)) / uint32(q)) 135 | t := int32(v) * int32(a) >> 26 136 | t *= int32(q) 137 | return a - t 138 | } 139 | 140 | //montgomeryReduce is used to reduce a montgomery coefficient [0, RQ] 141 | func montgomeryReduce(a int64) int32 { 142 | t := int32(a * qInv) 143 | t = int32((a - int64(t)*q) >> 32) 144 | return t 145 | } 146 | -------------------------------------------------------------------------------- /crystals-dilithium/kat_test.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "crypto/aes" 7 | "encoding/hex" 8 | "fmt" 9 | "os" 10 | "strconv" 11 | "strings" 12 | "testing" 13 | ) 14 | 15 | // See NIST's PQCgenKAT.c. 16 | type DRBG struct { 17 | key [32]byte 18 | v [16]byte 19 | } 20 | 21 | func (g *DRBG) incV() { 22 | for j := 15; j >= 0; j-- { 23 | if g.v[j] == 255 { 24 | g.v[j] = 0 25 | } else { 26 | g.v[j]++ 27 | break 28 | } 29 | } 30 | } 31 | 32 | // AES256_CTR_DRBG_Update(pd, &g.key, &g.v) 33 | func (g *DRBG) update(pd *[48]byte) { 34 | var buf [48]byte 35 | b, _ := aes.NewCipher(g.key[:]) 36 | for i := 0; i < 3; i++ { 37 | g.incV() 38 | b.Encrypt(buf[i*16:(i+1)*16], g.v[:]) 39 | } 40 | if pd != nil { 41 | for i := 0; i < 48; i++ { 42 | buf[i] ^= pd[i] 43 | } 44 | } 45 | copy(g.key[:], buf[:32]) 46 | copy(g.v[:], buf[32:]) 47 | } 48 | 49 | // randombyte_init(seed, NULL, 256) 50 | func NewDRBG(seed *[48]byte) (g DRBG) { 51 | g.update(seed) 52 | return 53 | } 54 | 55 | // randombytes() 56 | func (g *DRBG) Fill(x []byte) { 57 | var block [16]byte 58 | 59 | b, _ := aes.NewCipher(g.key[:]) 60 | for len(x) > 0 { 61 | g.incV() 62 | b.Encrypt(block[:], g.v[:]) 63 | if len(x) < 16 { 64 | copy(x[:], block[:len(x)]) 65 | break 66 | } 67 | copy(x[:], block[:]) 68 | x = x[16:] 69 | } 70 | g.update(nil) 71 | } 72 | 73 | func TestKAT(t *testing.T) { 74 | testKAT(t, NewDilithium2(false), "Dilithium2") 75 | testKAT(t, NewDilithium3(false), "Dilithium3") 76 | testKAT(t, NewDilithium5(false), "Dilithium5") 77 | } 78 | 79 | func testKAT(t *testing.T, d *Dilithium, name string) { 80 | 81 | goldenKAT := fmt.Sprintf("PQCsignKAT_%s.rsp", name) 82 | /** 83 | GOLDEN_ZIP := "https://pq-crystals.org/dilithium/data/dilithium-submission-nist-round3.zip" 84 | os.Mkdir("testdata", 0755) 85 | cached := "testdata/" + path.Base(GOLDEN_ZIP) 86 | zipfile, err := zip.OpenReader(cached) 87 | if err != nil { 88 | t.Logf("Retrieving golden KAT zip from %s", GOLDEN_ZIP) 89 | resp, _ := http.Get(GOLDEN_ZIP) 90 | defer resp.Body.Close() 91 | body, _ := ioutil.ReadAll(resp.Body) 92 | ioutil.WriteFile(cached, body, 0644) 93 | zipfile, _ = zip.OpenReader(cached) 94 | } 95 | if d.params.RANDOMIZED == 0 { 96 | goldenKAT = fmt.Sprintf("PQCsignKAT_impldeter%d.rsp", d.SIZESK()) 97 | } 98 | 99 | var katfile io.ReadCloser 100 | gotkat := false 101 | for _, f := range zipfile.File { 102 | if strings.HasSuffix(f.Name, goldenKAT) { 103 | katfile, _ = f.Open() 104 | gotkat = true 105 | break 106 | } 107 | } 108 | if !gotkat { 109 | t.Fatalf("no file names %s\n", goldenKAT) 110 | }**/ 111 | katfile, err := os.Open("testdata/" + goldenKAT) 112 | if err != nil { 113 | t.Fatal(err) 114 | } 115 | 116 | r := bufio.NewReader(katfile) 117 | 118 | smlen := 0 119 | mlen := 0 120 | count := 0 121 | pk := make([]byte, d.SIZEPK()) 122 | sk := make([]byte, d.SIZESK()) 123 | var msg []byte 124 | 125 | var seed [48]byte 126 | for i := 0; i < 48; i++ { 127 | seed[i] = byte(i) //entropy_input 128 | } 129 | 130 | //randombytes_init(entropy_input, NULL, 256); 131 | g := NewDRBG(&seed) 132 | for { 133 | line, err := r.ReadString('\n') 134 | if err != nil { 135 | break 136 | } 137 | fields := strings.Split(line, " ") 138 | if len(fields) != 3 { 139 | continue 140 | } 141 | val := strings.TrimSpace(fields[2]) 142 | bval := []byte(val) 143 | hval := make([]byte, hex.DecodedLen(len(bval))) 144 | hex.Decode(hval, bval) 145 | 146 | switch fields[0] { 147 | case "count": 148 | count, _ = strconv.Atoi(val) 149 | case "seed": 150 | { 151 | if len(hval) != 48 { 152 | t.Fatal("expected 48 byte seed") 153 | } 154 | g.Fill(seed[:]) 155 | if !bytes.Equal(seed[:], hval[:]) { 156 | t.Fatal("Seed not well crafted") 157 | } 158 | g2 := NewDRBG(&seed) 159 | var extSeed [32]byte 160 | g2.Fill(extSeed[:]) 161 | pk, sk = d.KeyGen(extSeed[:]) 162 | } 163 | case "mlen": 164 | mlen, _ = strconv.Atoi(val) 165 | if mlen != 33*(count+1) { 166 | t.Fatal("mlen != 33*(i+1)") 167 | } 168 | msg = make([]byte, mlen) 169 | g.Fill(msg[:]) 170 | case "msg": 171 | if len(hval) != mlen { 172 | t.Fatal("mlen != len(msg)") 173 | } 174 | if !bytes.Equal(msg[:], hval[:]) { 175 | t.Fatal("Msg is not correct") 176 | } 177 | case "pk": 178 | { 179 | if len(hval) != d.params.SIZEPK { 180 | t.Fatal("pk size mismatch") 181 | } 182 | if !bytes.Equal(pk[:], hval[:]) { 183 | t.Fatal("pk mismatch") 184 | } 185 | } 186 | case "sk": 187 | if len(hval) != d.params.SIZESK { 188 | t.Fatal("sk size mismatch") 189 | } 190 | if !bytes.Equal(sk[:], hval[:]) { 191 | t.Fatal("sk mismatch") 192 | } 193 | case "smlen": 194 | smlen, _ = strconv.Atoi(val) 195 | if smlen != mlen+d.params.SIZESIG { 196 | fmt.Printf("smlen: %d vs %d\n", smlen, mlen+d.params.SIZESIG) 197 | t.Fatal("smlen != mlen + sig_size") 198 | } 199 | case "sm": 200 | if len(hval) != smlen { 201 | fmt.Printf("smlen: %d vs %d\n", smlen, len(hval)) 202 | t.Fatal("smlen != len(sm)") 203 | } 204 | sig := d.Sign(sk, msg) 205 | if !bytes.Equal(append(sig, msg...), hval) { 206 | t.Fatal("signature mismatch") 207 | } 208 | if !d.Verify(pk, msg, sig) { 209 | t.Fatal("failed to validate") 210 | } 211 | //println("one iter ok") 212 | } 213 | } 214 | } 215 | 216 | func TestInterOp(t *testing.T) { 217 | pk := []byte{28, 14, 225, 17, 27, 8, 0, 63, 40, 230, 94, 139, 59, 222, 176, 55, 207, 143, 34, 29, 252, 218, 245, 149, 14, 219, 56, 213, 6, 216, 91, 239, 97, 119, 227, 222, 13, 79, 30, 245, 132, 119, 53, 148, 123, 86, 208, 142, 132, 29, 178, 68, 79, 162, 183, 41, 173, 235, 20, 23, 202, 122, 223, 66, 161, 73, 12, 90, 9, 127, 0, 39, 96, 193, 252, 65, 155, 232, 50, 90, 173, 1, 151, 197, 44, 237, 128, 211, 223, 24, 231, 119, 66, 101, 178, 137, 145, 44, 236, 161, 190, 58, 144, 216, 164, 253, 230, 92, 132, 198, 16, 134, 78, 71, 222, 236, 174, 62, 234, 68, 48, 185, 144, 149, 89, 64, 141, 17, 166, 171, 219, 125, 185, 51, 109, 247, 249, 110, 171, 72, 100, 166, 87, 151, 145, 38, 95, 165, 108, 52, 140, 183, 210, 221, 201, 14, 19, 58, 149, 195, 246, 177, 54, 1, 66, 159, 84, 8, 189, 153, 154, 164, 121, 193, 1, 129, 89, 85, 14, 197, 90, 17, 60, 73, 59, 230, 72, 244, 224, 54, 221, 79, 140, 128, 158, 3, 107, 79, 187, 145, 140, 44, 72, 74, 216, 225, 116, 122, 224, 85, 133, 171, 67, 63, 223, 70, 26, 240, 60, 37, 167, 115, 112, 7, 33, 170, 5, 247, 55, 159, 231, 245, 237, 150, 23, 93, 64, 33, 7, 110, 127, 82, 182, 3, 8, 239, 245, 212, 43, 166, 224, 147, 179, 208, 129, 94, 179, 73, 102, 70, 228, 146, 48, 169, 179, 92, 141, 65, 144, 12, 43, 184, 211, 180, 70, 162, 49, 39, 247, 224, 150, 216, 90, 28, 121, 74, 212, 200, 146, 119, 144, 79, 198, 191, 236, 87, 177, 205, 216, 13, 249, 149, 80, 48, 253, 202, 116, 26, 251, 218, 200, 39, 177, 60, 205, 84, 3, 88, 138, 244, 100, 64, 3, 194, 38, 93, 250, 77, 65, 157, 188, 205, 32, 100, 137, 35, 134, 81, 139, 233, 213, 28, 22, 73, 130, 117, 235, 236, 245, 205, 199, 168, 32, 242, 194, 147, 20, 172, 74, 111, 8, 178, 37, 42, 211, 207, 177, 153, 170, 66, 254, 11, 79, 181, 113, 151, 92, 16, 32, 217, 73, 225, 148, 238, 30, 173, 147, 123, 251, 85, 11, 179, 186, 142, 53, 122, 2, 156, 41, 240, 119, 85, 70, 2, 225, 202, 47, 34, 137, 203, 145, 105, 148, 28, 58, 175, 219, 142, 88, 199, 242, 172, 119, 41, 31, 180, 20, 124, 101, 246, 176, 49, 211, 235, 164, 47, 42, 207, 217, 68, 138, 91, 194, 43, 71, 110, 7, 204, 206, 218, 35, 6, 197, 84, 236, 155, 122, 182, 85, 241, 215, 49, 140, 43, 126, 103, 213, 246, 155, 237, 245, 96, 0, 253, 169, 137, 134, 181, 171, 27, 58, 34, 216, 223, 214, 104, 22, 151, 178, 58, 85, 201, 110, 135, 16, 243, 249, 140, 4, 79, 177, 95, 96, 99, 19, 238, 86, 192, 241, 245, 202, 15, 81, 46, 8, 72, 79, 203, 53, 142, 110, 82, 143, 250, 137, 248, 168, 102, 204, 255, 60, 12, 88, 19, 20, 126, 197, 154, 240, 71, 12, 74, 173, 1, 65, 211, 79, 16, 29, 162, 229, 225, 189, 82, 208, 212, 201, 177, 59, 62, 61, 135, 209, 88, 97, 5, 121, 103, 84, 231, 151, 140, 161, 198, 138, 125, 133, 223, 17, 43, 122, 185, 33, 179, 89, 169, 240, 60, 189, 39, 167, 234, 200, 122, 154, 128, 176, 178, 107, 76, 150, 87, 237, 133, 173, 127, 162, 97, 106, 179, 69, 235, 130, 38, 246, 159, 192, 244, 129, 131, 255, 87, 75, 205, 118, 123, 86, 118, 65, 58, 219, 18, 234, 33, 80, 160, 233, 118, 131, 238, 84, 36, 60, 37, 183, 234, 138, 113, 134, 6, 248, 105, 147, 216, 208, 218, 206, 131, 78, 211, 65, 238, 183, 36, 254, 61, 95, 240, 188, 139, 138, 123, 129, 4, 186, 38, 157, 52, 19, 58, 76, 248, 48, 10, 45, 104, 132, 150, 181, 155, 111, 203, 198, 26, 233, 96, 98, 234, 29, 142, 91, 65, 12, 86, 113, 244, 36, 65, 126, 214, 147, 50, 156, 217, 131, 0, 31, 252, 209, 0, 35, 213, 152, 133, 159, 183, 173, 95, 210, 99, 84, 113, 23, 16, 6, 144, 198, 206, 116, 56, 149, 110, 108, 197, 127, 27, 93, 229, 59, 176, 220, 114, 206, 155, 109, 234, 168, 87, 137, 89, 154, 112, 240, 5, 31, 26, 14, 37, 232, 109, 136, 139, 0, 223, 54, 189, 188, 147, 239, 114, 23, 196, 90, 206, 17, 192, 121, 13, 112, 233, 149, 62, 91, 65, 123, 162, 253, 154, 76, 175, 130, 241, 252, 230, 244, 95, 83, 226, 21, 184, 53, 94, 246, 29, 137, 29, 241, 199, 148, 35, 28, 22, 45, 210, 65, 100, 181, 52, 169, 212, 132, 103, 205, 195, 35, 98, 76, 47, 149, 212, 64, 47, 249, 214, 106, 177, 25, 26, 129, 36, 20, 74, 250, 53, 212, 227, 29, 200, 108, 170, 121, 124, 49, 246, 139, 133, 133, 76, 217, 89, 196, 250, 197, 236, 83, 179, 181, 109, 55, 75, 136, 138, 158, 151, 154, 101, 118, 182, 52, 94, 200, 82, 44, 150, 6, 153, 2, 129, 191, 62, 247, 197, 148, 93, 16, 253, 33, 162, 161, 210, 229, 64, 76, 92, 242, 18, 32, 100, 19, 145, 185, 139, 207, 130, 83, 152, 48, 91, 86, 229, 139, 97, 31, 229, 37, 50, 3, 227, 223, 13, 34, 70, 106, 115, 179, 240, 251, 228, 59, 154, 98, 146, 128, 145, 137, 139, 138, 14, 91, 38, 157, 181, 134, 176, 228, 221, 239, 80, 214, 130, 161, 45, 44, 27, 232, 36, 20, 154, 162, 84, 198, 56, 27, 180, 18, 215, 124, 63, 154, 169, 2, 182, 136, 200, 23, 21, 165, 156, 131, 149, 88, 85, 109, 53, 237, 79, 200, 59, 74, 177, 129, 129, 244, 15, 115, 220, 215, 104, 96, 216, 216, 191, 148, 82, 2, 55, 194, 172, 14, 70, 59, 160, 158, 60, 151, 130, 56, 13, 192, 127, 228, 252, 186, 52, 12, 194, 0, 52, 57, 253, 35, 20, 97, 6, 56, 7, 13, 108, 158, 234, 10, 112, 186, 232, 59, 93, 93, 60, 93, 63, 222, 38, 221, 1, 96, 108, 140, 82, 1, 88, 231, 229, 16, 64, 32, 242, 72, 206, 170, 102, 100, 87, 193, 10, 235, 240, 104, 248, 163, 189, 92, 231, 181, 44, 106, 240, 171, 213, 148, 74, 241, 173, 71, 82, 201, 17, 57, 118, 8, 60, 3, 182, 195, 78, 29, 71, 237, 105, 100, 76, 173, 120, 44, 47, 125, 5, 248, 161, 72, 150, 29, 150, 95, 162, 225, 114, 58, 141, 222, 188, 34, 169, 12, 215, 131, 221, 31, 77, 179, 143, 185, 174, 90, 103, 20, 179, 217, 70, 120, 22, 67, 211, 23, 183, 221, 121, 56, 28, 247, 137, 169, 88, 139, 179, 225, 147, 185, 42, 11, 96, 214, 176, 125, 4, 127, 105, 132, 176, 96, 158, 197, 117, 67, 195, 148, 202, 141, 94, 91, 204, 42, 115, 26, 121, 97, 139, 209, 226, 224, 218, 135, 4, 175, 152, 242, 15, 95, 143, 84, 82, 221, 246, 70, 185, 91, 52, 29, 215, 240, 210, 204, 31, 161, 91, 217, 137, 92, 213, 182, 90, 161, 203, 148, 181, 226, 231, 136, 253, 169, 130, 91, 101, 102, 57, 25, 61, 152, 50, 129, 84, 164, 242, 195, 84, 149, 163, 139, 110, 160, 210, 255, 170, 163, 93, 249, 44, 32, 60, 127, 49, 203, 188, 167, 189, 3, 195, 194, 48, 33, 144, 206, 205, 22, 31, 212, 146, 55, 228, 248, 57, 227, 243} 218 | 219 | msg := []byte{216, 28, 77, 141, 115, 79, 203, 251, 234, 222, 61, 63, 138, 3, 159, 170, 42, 44, 153, 87, 232, 53, 173, 85, 178, 46, 117, 191, 87, 187, 85, 106, 200} 220 | 221 | sig := []byte{175, 89, 32, 119, 70, 3, 210, 14, 152, 167, 154, 163, 171, 250, 50, 182, 226, 37, 25, 230, 115, 227, 122, 196, 172, 115, 254, 133, 52, 30, 44, 41, 35, 193, 153, 46, 27, 11, 190, 56, 115, 215, 200, 252, 86, 98, 242, 7, 191, 88, 234, 56, 28, 212, 163, 160, 192, 98, 222, 196, 91, 218, 248, 186, 10, 165, 43, 239, 111, 161, 79, 63, 108, 242, 143, 118, 32, 191, 148, 169, 44, 194, 125, 4, 84, 20, 166, 77, 101, 192, 20, 150, 48, 82, 128, 36, 40, 191, 57, 135, 162, 212, 117, 22, 202, 92, 120, 170, 185, 107, 123, 225, 27, 202, 95, 44, 90, 38, 243, 252, 227, 162, 110, 142, 9, 162, 115, 143, 56, 111, 117, 212, 72, 249, 55, 239, 25, 168, 70, 189, 77, 217, 73, 202, 175, 54, 219, 86, 41, 136, 74, 245, 58, 2, 62, 63, 24, 15, 228, 192, 250, 255, 123, 229, 223, 228, 232, 154, 222, 48, 149, 166, 86, 0, 66, 20, 97, 173, 8, 193, 41, 214, 206, 168, 81, 187, 57, 192, 215, 167, 209, 81, 64, 86, 137, 160, 145, 250, 77, 235, 172, 55, 60, 245, 74, 224, 120, 240, 175, 117, 87, 187, 198, 240, 106, 83, 90, 232, 148, 158, 12, 101, 48, 138, 89, 132, 0, 114, 55, 82, 149, 128, 45, 14, 44, 233, 163, 218, 152, 66, 106, 0, 255, 3, 254, 128, 33, 140, 14, 236, 142, 254, 88, 28, 185, 204, 154, 125, 102, 178, 6, 69, 168, 205, 4, 144, 211, 206, 79, 126, 111, 234, 233, 201, 235, 122, 87, 249, 100, 208, 235, 199, 201, 11, 122, 159, 134, 48, 11, 62, 128, 149, 230, 77, 18, 148, 207, 196, 180, 217, 226, 114, 232, 250, 141, 181, 112, 125, 112, 4, 175, 34, 219, 255, 156, 253, 72, 99, 223, 87, 63, 224, 4, 52, 29, 163, 205, 74, 48, 130, 83, 44, 38, 32, 69, 95, 163, 124, 86, 43, 175, 213, 104, 78, 161, 40, 175, 199, 158, 1, 252, 155, 49, 232, 67, 59, 173, 124, 2, 159, 47, 19, 204, 16, 89, 45, 35, 50, 227, 224, 139, 128, 211, 80, 70, 61, 231, 39, 80, 177, 248, 6, 244, 147, 225, 67, 189, 95, 202, 125, 22, 152, 8, 27, 49, 191, 135, 107, 42, 27, 201, 223, 80, 149, 45, 19, 182, 193, 50, 27, 17, 17, 23, 33, 69, 166, 39, 174, 11, 68, 39, 185, 137, 117, 203, 255, 247, 214, 130, 117, 117, 75, 69, 182, 130, 215, 9, 225, 104, 82, 46, 132, 254, 167, 221, 59, 176, 244, 21, 5, 255, 113, 146, 100, 49, 209, 169, 13, 76, 191, 154, 82, 122, 212, 226, 132, 151, 111, 255, 139, 217, 214, 34, 74, 79, 38, 3, 145, 169, 135, 251, 109, 166, 238, 66, 194, 164, 144, 15, 64, 124, 225, 240, 46, 50, 36, 117, 211, 19, 251, 235, 182, 140, 46, 5, 115, 8, 9, 68, 138, 116, 40, 165, 148, 1, 57, 235, 223, 27, 85, 86, 252, 197, 212, 46, 26, 19, 243, 34, 48, 203, 111, 7, 36, 131, 29, 13, 7, 27, 186, 90, 103, 4, 128, 111, 71, 91, 116, 186, 145, 182, 227, 133, 212, 134, 32, 149, 141, 10, 177, 191, 43, 24, 78, 16, 243, 231, 83, 183, 19, 55, 190, 158, 182, 83, 120, 103, 133, 180, 58, 199, 229, 196, 148, 172, 27, 203, 4, 61, 70, 20, 37, 179, 96, 152, 172, 147, 5, 90, 1, 5, 171, 133, 35, 182, 29, 2, 74, 110, 155, 86, 164, 45, 60, 4, 114, 101, 18, 174, 76, 254, 5, 113, 4, 70, 176, 111, 105, 66, 52, 238, 79, 168, 254, 237, 221, 197, 242, 138, 101, 237, 226, 235, 88, 233, 101, 254, 54, 39, 165, 113, 188, 69, 179, 151, 237, 9, 42, 180, 190, 0, 4, 23, 41, 196, 209, 146, 254, 48, 103, 130, 121, 210, 35, 168, 72, 207, 67, 102, 233, 43, 63, 104, 222, 233, 124, 155, 74, 127, 242, 47, 147, 123, 230, 197, 102, 57, 150, 29, 178, 159, 163, 207, 236, 255, 242, 147, 20, 8, 134, 255, 185, 46, 188, 121, 218, 181, 156, 234, 248, 105, 198, 79, 142, 175, 88, 92, 233, 125, 214, 183, 143, 137, 39, 114, 219, 136, 169, 88, 207, 10, 181, 87, 167, 250, 168, 63, 230, 33, 71, 126, 43, 132, 73, 122, 181, 168, 236, 244, 167, 189, 50, 223, 185, 2, 240, 93, 44, 163, 16, 71, 208, 241, 145, 154, 221, 225, 238, 109, 253, 88, 229, 155, 196, 218, 179, 204, 187, 163, 106, 170, 246, 175, 204, 199, 176, 149, 202, 148, 161, 149, 190, 154, 40, 149, 38, 181, 136, 195, 169, 197, 104, 118, 252, 65, 93, 82, 29, 68, 43, 172, 2, 152, 211, 2, 65, 154, 213, 39, 218, 36, 156, 42, 102, 12, 208, 100, 33, 63, 250, 213, 99, 24, 63, 55, 151, 37, 120, 238, 185, 247, 10, 198, 122, 238, 108, 194, 183, 31, 40, 58, 149, 147, 11, 85, 71, 56, 85, 87, 145, 194, 94, 122, 57, 158, 104, 86, 54, 213, 141, 105, 203, 107, 231, 147, 180, 92, 25, 105, 231, 213, 97, 86, 39, 235, 195, 46, 237, 69, 68, 15, 135, 136, 13, 40, 41, 250, 79, 200, 113, 134, 97, 100, 210, 89, 237, 149, 210, 115, 24, 113, 1, 127, 245, 24, 148, 6, 111, 174, 31, 250, 111, 75, 74, 111, 132, 252, 255, 218, 9, 231, 24, 250, 23, 19, 94, 219, 63, 72, 85, 141, 91, 166, 127, 158, 111, 9, 0, 52, 11, 208, 77, 254, 89, 183, 189, 103, 116, 88, 132, 251, 132, 174, 63, 142, 231, 99, 210, 2, 116, 54, 82, 212, 247, 51, 52, 80, 88, 4, 144, 185, 199, 68, 147, 91, 25, 193, 213, 251, 13, 181, 251, 180, 97, 65, 19, 98, 131, 128, 55, 235, 126, 195, 246, 63, 38, 200, 147, 231, 204, 28, 59, 63, 71, 103, 171, 174, 0, 254, 183, 187, 153, 177, 66, 11, 178, 158, 166, 20, 116, 120, 150, 217, 237, 207, 129, 7, 254, 80, 76, 156, 48, 138, 130, 100, 218, 206, 49, 141, 135, 207, 228, 118, 24, 3, 233, 166, 13, 239, 166, 20, 74, 171, 193, 241, 10, 69, 177, 64, 222, 215, 84, 231, 53, 134, 196, 103, 187, 123, 241, 158, 222, 242, 91, 224, 198, 94, 147, 197, 229, 235, 143, 136, 12, 206, 74, 133, 135, 87, 248, 255, 86, 6, 43, 16, 103, 244, 16, 111, 118, 183, 0, 127, 110, 166, 249, 69, 4, 126, 133, 189, 15, 173, 157, 38, 153, 79, 103, 138, 6, 18, 184, 124, 207, 156, 12, 249, 164, 51, 216, 137, 201, 110, 76, 18, 190, 55, 34, 119, 0, 91, 6, 173, 18, 113, 5, 209, 109, 143, 177, 66, 174, 174, 83, 115, 171, 214, 29, 154, 220, 252, 85, 80, 214, 35, 202, 59, 136, 36, 176, 226, 224, 140, 43, 244, 226, 132, 30, 172, 76, 93, 197, 108, 248, 149, 76, 242, 7, 194, 99, 242, 124, 159, 48, 159, 16, 48, 124, 13, 132, 166, 88, 120, 66, 80, 49, 55, 93, 216, 16, 210, 215, 229, 16, 152, 163, 129, 67, 80, 121, 92, 74, 7, 127, 164, 13, 212, 79, 15, 167, 81, 15, 124, 63, 99, 20, 7, 207, 52, 246, 4, 199, 179, 53, 99, 42, 32, 210, 173, 65, 155, 215, 204, 109, 66, 66, 177, 198, 108, 53, 229, 165, 237, 204, 177, 60, 163, 125, 59, 80, 70, 95, 59, 74, 175, 247, 227, 22, 30, 121, 54, 8, 138, 224, 132, 1, 253, 44, 55, 214, 122, 47, 249, 29, 62, 111, 8, 104, 109, 100, 188, 47, 198, 197, 113, 6, 228, 159, 163, 132, 172, 34, 33, 159, 7, 238, 137, 150, 202, 61, 255, 89, 220, 197, 9, 42, 75, 173, 190, 135, 174, 222, 127, 105, 160, 76, 121, 179, 59, 223, 53, 212, 160, 228, 203, 75, 85, 1, 156, 176, 191, 39, 82, 149, 185, 59, 218, 190, 165, 22, 202, 43, 97, 106, 86, 145, 134, 0, 183, 36, 190, 122, 1, 236, 78, 245, 67, 18, 179, 13, 102, 245, 7, 129, 95, 39, 128, 255, 238, 124, 48, 248, 66, 90, 146, 37, 44, 229, 80, 250, 180, 233, 2, 231, 179, 130, 212, 109, 189, 32, 239, 225, 187, 14, 248, 164, 150, 135, 60, 9, 196, 206, 176, 48, 60, 127, 29, 171, 160, 16, 45, 233, 65, 144, 182, 172, 109, 200, 16, 247, 43, 202, 58, 162, 146, 255, 56, 189, 81, 167, 250, 184, 80, 158, 196, 251, 224, 234, 163, 201, 134, 22, 106, 103, 75, 120, 113, 21, 92, 52, 140, 71, 126, 248, 206, 220, 131, 43, 90, 190, 231, 26, 141, 24, 208, 109, 208, 245, 34, 17, 96, 171, 235, 113, 230, 232, 44, 250, 191, 115, 30, 163, 81, 90, 118, 239, 7, 178, 193, 108, 99, 179, 127, 122, 183, 59, 103, 240, 5, 146, 154, 117, 62, 69, 59, 147, 12, 10, 244, 50, 39, 127, 215, 125, 138, 30, 184, 2, 44, 222, 150, 101, 118, 59, 1, 79, 10, 103, 42, 4, 22, 11, 10, 6, 245, 84, 15, 76, 38, 75, 127, 34, 116, 6, 144, 162, 53, 45, 200, 99, 181, 136, 48, 58, 213, 31, 10, 225, 98, 191, 121, 121, 127, 7, 181, 52, 80, 28, 187, 253, 183, 19, 167, 36, 170, 152, 225, 149, 50, 24, 113, 128, 204, 250, 220, 110, 190, 49, 66, 250, 125, 182, 108, 212, 222, 123, 159, 189, 76, 130, 53, 104, 109, 182, 140, 175, 72, 154, 250, 78, 30, 135, 174, 240, 206, 253, 128, 55, 227, 165, 120, 238, 98, 235, 127, 148, 237, 91, 192, 181, 142, 234, 75, 76, 69, 252, 86, 211, 29, 41, 148, 77, 9, 90, 201, 108, 41, 8, 61, 162, 199, 113, 129, 217, 122, 85, 254, 110, 144, 58, 47, 39, 131, 222, 11, 170, 95, 71, 215, 4, 120, 92, 51, 232, 213, 200, 126, 214, 30, 101, 69, 145, 103, 49, 14, 183, 169, 149, 116, 239, 129, 154, 233, 22, 26, 59, 208, 150, 52, 128, 61, 158, 30, 78, 199, 56, 109, 121, 70, 152, 69, 23, 33, 58, 185, 207, 102, 174, 165, 81, 204, 69, 124, 57, 248, 106, 242, 148, 207, 123, 7, 63, 86, 62, 212, 218, 185, 65, 155, 223, 0, 75, 208, 92, 146, 180, 232, 14, 195, 207, 234, 201, 126, 29, 218, 85, 79, 218, 98, 92, 75, 155, 3, 155, 170, 124, 90, 47, 111, 151, 5, 119, 146, 72, 60, 245, 248, 82, 212, 195, 172, 113, 173, 80, 247, 121, 149, 61, 207, 226, 246, 62, 210, 53, 216, 225, 213, 52, 93, 108, 109, 240, 85, 92, 194, 99, 29, 234, 217, 183, 20, 188, 76, 22, 80, 30, 1, 38, 19, 129, 243, 103, 151, 21, 52, 81, 35, 56, 140, 133, 45, 87, 220, 241, 148, 29, 9, 17, 212, 159, 234, 113, 67, 253, 47, 195, 67, 165, 7, 91, 100, 204, 164, 130, 145, 220, 40, 184, 63, 118, 7, 69, 137, 234, 178, 23, 199, 132, 120, 64, 101, 44, 14, 58, 226, 120, 179, 182, 251, 13, 128, 12, 94, 125, 183, 157, 92, 185, 204, 26, 135, 69, 12, 0, 183, 103, 120, 18, 210, 46, 226, 15, 222, 140, 23, 83, 167, 251, 147, 186, 139, 187, 133, 149, 166, 57, 61, 245, 74, 169, 205, 182, 224, 135, 154, 38, 228, 155, 211, 176, 21, 19, 198, 5, 58, 7, 70, 200, 89, 108, 229, 229, 178, 37, 207, 202, 38, 171, 139, 241, 47, 31, 224, 166, 71, 169, 228, 69, 48, 57, 161, 34, 97, 148, 196, 110, 139, 152, 172, 215, 16, 241, 143, 183, 236, 5, 71, 108, 28, 216, 252, 49, 18, 204, 221, 177, 88, 43, 136, 23, 193, 143, 227, 21, 53, 62, 122, 71, 200, 33, 233, 238, 58, 67, 202, 222, 27, 128, 217, 42, 10, 232, 220, 235, 77, 255, 118, 106, 84, 223, 54, 101, 254, 254, 60, 37, 43, 114, 218, 215, 177, 227, 53, 158, 127, 162, 85, 98, 195, 227, 157, 181, 33, 206, 24, 116, 17, 31, 176, 144, 219, 211, 139, 49, 128, 173, 3, 75, 87, 176, 49, 220, 77, 214, 175, 124, 26, 138, 243, 246, 206, 126, 219, 26, 158, 75, 109, 74, 89, 32, 227, 98, 8, 24, 130, 6, 89, 118, 46, 247, 164, 36, 63, 81, 223, 45, 138, 144, 7, 55, 213, 129, 5, 105, 155, 78, 16, 203, 203, 53, 156, 127, 58, 64, 7, 105, 124, 72, 32, 80, 236, 51, 207, 128, 65, 145, 106, 59, 145, 154, 80, 217, 110, 240, 245, 137, 253, 69, 86, 243, 13, 189, 217, 66, 234, 183, 157, 250, 151, 192, 126, 48, 36, 112, 116, 53, 46, 27, 249, 142, 52, 156, 199, 239, 165, 161, 184, 252, 228, 241, 143, 31, 175, 111, 7, 201, 156, 50, 20, 72, 176, 57, 92, 138, 156, 188, 70, 100, 18, 248, 156, 26, 152, 191, 87, 21, 132, 40, 68, 240, 232, 35, 111, 164, 105, 108, 70, 88, 184, 253, 228, 66, 93, 9, 214, 122, 56, 172, 114, 88, 229, 213, 150, 111, 45, 63, 246, 106, 12, 12, 231, 110, 127, 107, 129, 161, 188, 208, 71, 253, 58, 32, 91, 240, 204, 174, 163, 177, 16, 121, 144, 156, 108, 229, 105, 143, 50, 225, 243, 64, 150, 88, 255, 160, 30, 174, 203, 74, 226, 176, 146, 183, 137, 137, 218, 173, 102, 35, 187, 17, 244, 159, 15, 143, 134, 153, 236, 5, 102, 21, 2, 255, 202, 208, 60, 244, 21, 25, 26, 34, 45, 60, 76, 123, 138, 176, 181, 185, 187, 194, 217, 220, 239, 247, 32, 45, 63, 66, 68, 73, 79, 82, 83, 100, 102, 105, 116, 196, 217, 230, 245, 250, 0, 1, 4, 25, 39, 55, 61, 90, 118, 128, 184, 193, 201, 254, 32, 41, 56, 59, 60, 72, 77, 86, 95, 101, 121, 157, 158, 166, 169, 173, 210, 222, 229, 231, 247, 249, 0, 0, 0, 0, 0, 0, 0, 0, 18, 36, 50, 72} 222 | 223 | d := NewDilithium2(false) 224 | 225 | if !d.Verify(pk, msg, sig) { 226 | t.Fatal("could not verify signature generated with reference files") 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /crystals-dilithium/keys.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import "crypto/subtle" 4 | 5 | //PublicKey holds the pk strct 6 | type PublicKey struct { 7 | T1 Vec //K 8 | Rho [SEEDBYTES]byte 9 | } 10 | 11 | //PrivateKey holds the sk struct 12 | type PrivateKey struct { 13 | S1 Vec //L 14 | S2 Vec //K 15 | Rho [SEEDBYTES]byte 16 | Key [SEEDBYTES]byte 17 | Tr [SEEDBYTES]byte 18 | T0 Vec //K 19 | } 20 | 21 | //SIZEPK returns the size in bytes of the public key of a dilithium instance 22 | func (d *Dilithium) SIZEPK() int { 23 | return d.params.SIZEPK 24 | } 25 | 26 | //SIZESK returns the size in bytes of the secret key of a dilithium instance 27 | func (d *Dilithium) SIZESK() int { 28 | return d.params.SIZESK 29 | } 30 | 31 | //SIZESIG returns the size in bytes of the signature of a dilithium instance 32 | func (d *Dilithium) SIZESIG() int { 33 | return d.params.SIZESIG 34 | } 35 | 36 | //PackPK packs a PublicKey into an array of bytes 37 | func (d *Dilithium) PackPK(pk PublicKey) []byte { 38 | packedPK := make([]byte, d.params.SIZEPK) 39 | copy(packedPK[:SEEDBYTES], pk.Rho[:]) 40 | copy(packedPK[SEEDBYTES:], packT1(pk.T1, d.params.K)) 41 | return packedPK 42 | } 43 | 44 | //UnpackPK reverses the packing operation and outputs a PublicKey struct 45 | func (d *Dilithium) UnpackPK(packedPK []byte) PublicKey { 46 | var pk PublicKey 47 | copy(pk.Rho[:], packedPK[:SEEDBYTES]) 48 | pk.T1 = unpackT1(packedPK[SEEDBYTES:], d.params.K) 49 | return pk 50 | } 51 | 52 | //PackSK packs a PrivateKey into a byte array 53 | func (d *Dilithium) PackSK(sk PrivateKey) []byte { 54 | packedSK := make([]byte, d.params.SIZESK) 55 | id := 0 56 | subtle.ConstantTimeCopy(1, packedSK[id:id+SEEDBYTES], sk.Rho[:]) 57 | id += SEEDBYTES 58 | subtle.ConstantTimeCopy(1, packedSK[id:id+SEEDBYTES], sk.Key[:]) 59 | id += SEEDBYTES 60 | subtle.ConstantTimeCopy(1, packedSK[id:id+SEEDBYTES], sk.Tr[:]) 61 | id += SEEDBYTES 62 | L := d.params.L 63 | ETA := d.params.ETA 64 | POLYSIZES := d.params.POLYSIZES 65 | subtle.ConstantTimeCopy(1, packedSK[id:id+L*POLYSIZES], packS(sk.S1, L, POLYSIZES, ETA)) 66 | id += L * POLYSIZES 67 | K := d.params.K 68 | subtle.ConstantTimeCopy(1, packedSK[id:id+K*POLYSIZES], packS(sk.S2, K, POLYSIZES, ETA)) 69 | id += K * POLYSIZES 70 | subtle.ConstantTimeCopy(1, packedSK[id:], packT0(sk.T0, K)) 71 | return packedSK 72 | } 73 | 74 | //UnpackSK reverses the packing operation and outputs a PrivateKey struct 75 | func (d *Dilithium) UnpackSK(packedSK []byte) PrivateKey { 76 | var sk PrivateKey 77 | id := 0 78 | subtle.ConstantTimeCopy(1, sk.Rho[:], packedSK[:SEEDBYTES]) 79 | id += SEEDBYTES 80 | subtle.ConstantTimeCopy(1, sk.Key[:], packedSK[id:id+SEEDBYTES]) 81 | id += SEEDBYTES 82 | subtle.ConstantTimeCopy(1, sk.Tr[:], packedSK[id:id+SEEDBYTES]) 83 | id += SEEDBYTES 84 | L := d.params.L 85 | ETA := d.params.ETA 86 | POLYSIZES := d.params.POLYSIZES 87 | sk.S1 = unpackS(packedSK[id:id+L*POLYSIZES], L, POLYSIZES, ETA) 88 | id += L * POLYSIZES 89 | K := d.params.K 90 | sk.S2 = unpackS(packedSK[id:id+K*POLYSIZES], K, POLYSIZES, ETA) 91 | id += K * POLYSIZES 92 | sk.T0 = unpackT0(packedSK[id:], K) 93 | 94 | return sk 95 | } 96 | -------------------------------------------------------------------------------- /crystals-dilithium/ntt.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | var zetas = [n]int32{ 4 | 0, 25847, -2608894, -518909, 237124, -777960, -876248, 466468, 5 | 1826347, 2353451, -359251, -2091905, 3119733, -2884855, 3111497, 2680103, 6 | 2725464, 1024112, -1079900, 3585928, -549488, -1119584, 2619752, -2108549, 7 | -2118186, -3859737, -1399561, -3277672, 1757237, -19422, 4010497, 280005, 8 | 2706023, 95776, 3077325, 3530437, -1661693, -3592148, -2537516, 3915439, 9 | -3861115, -3043716, 3574422, -2867647, 3539968, -300467, 2348700, -539299, 10 | -1699267, -1643818, 3505694, -3821735, 3507263, -2140649, -1600420, 3699596, 11 | 811944, 531354, 954230, 3881043, 3900724, -2556880, 2071892, -2797779, 12 | -3930395, -1528703, -3677745, -3041255, -1452451, 3475950, 2176455, -1585221, 13 | -1257611, 1939314, -4083598, -1000202, -3190144, -3157330, -3632928, 126922, 14 | 3412210, -983419, 2147896, 2715295, -2967645, -3693493, -411027, -2477047, 15 | -671102, -1228525, -22981, -1308169, -381987, 1349076, 1852771, -1430430, 16 | -3343383, 264944, 508951, 3097992, 44288, -1100098, 904516, 3958618, 17 | -3724342, -8578, 1653064, -3249728, 2389356, -210977, 759969, -1316856, 18 | 189548, -3553272, 3159746, -1851402, -2409325, -177440, 1315589, 1341330, 19 | 1285669, -1584928, -812732, -1439742, -3019102, -3881060, -3628969, 3839961, 20 | 2091667, 3407706, 2316500, 3817976, -3342478, 2244091, -2446433, -3562462, 21 | 266997, 2434439, -1235728, 3513181, -3520352, -3759364, -1197226, -3193378, 22 | 900702, 1859098, 909542, 819034, 495491, -1613174, -43260, -522500, 23 | -655327, -3122442, 2031748, 3207046, -3556995, -525098, -768622, -3595838, 24 | 342297, 286988, -2437823, 4108315, 3437287, -3342277, 1735879, 203044, 25 | 2842341, 2691481, -2590150, 1265009, 4055324, 1247620, 2486353, 1595974, 26 | -3767016, 1250494, 2635921, -3548272, -2994039, 1869119, 1903435, -1050970, 27 | -1333058, 1237275, -3318210, -1430225, -451100, 1312455, 3306115, -1962642, 28 | -1279661, 1917081, -2546312, -1374803, 1500165, 777191, 2235880, 3406031, 29 | -542412, -2831860, -1671176, -1846953, -2584293, -3724270, 594136, -3776993, 30 | -2013608, 2432395, 2454455, -164721, 1957272, 3369112, 185531, -1207385, 31 | -3183426, 162844, 1616392, 3014001, 810149, 1652634, -3694233, -1799107, 32 | -3038916, 3523897, 3866901, 269760, 2213111, -975884, 1717735, 472078, 33 | -426683, 1723600, -1803090, 1910376, -1667432, -1104333, -260646, -3833893, 34 | -2939036, -2235985, -420899, -2286327, 183443, -976891, 1612842, -3545687, 35 | -554416, 3919660, -48306, -1362209, 3937738, 1400424, -846154, 1976782, 36 | } 37 | 38 | var f = int32(41978) //int32(((uint64(MONT) * MONT % Q) * (Q - 1) % Q) * ((Q - 1) >> 8) % Q) 39 | 40 | //ntt performs in place forward NTT 41 | func (p *Poly) ntt() { 42 | var len, start, j, k uint 43 | var zeta, t int32 44 | 45 | k = 1 46 | for len = 128; len > 0; len >>= 1 { 47 | for start = 0; start < n; start = j + len { 48 | zeta = zetas[k] 49 | k++ 50 | for j = start; j < start+len; j++ { 51 | t = fqmul(zeta, p[j+len]) 52 | p[j+len] = p[j] - t 53 | p[j] = p[j] + t 54 | } 55 | } 56 | } 57 | } 58 | 59 | //invntt perfors in place backward NTT and multiplication by Montgomery factor 2^32. 60 | func (p *Poly) invntt() { 61 | var len, start, j, k uint 62 | var zeta, t int32 63 | 64 | k = n - 1 65 | for len = 1; len < n; len <<= 1 { 66 | for start = 0; start < n; start = j + len { 67 | zeta = zetas[k] 68 | k-- 69 | for j = start; j < start+len; j++ { 70 | t = p[j] 71 | p[j] = barretReduce(t + p[j+len]) 72 | p[j+len] = p[j+len] - t 73 | p[j+len] = fqmul(zeta, p[j+len]) 74 | } 75 | } 76 | } 77 | 78 | for j = 0; j < n; j++ { 79 | p[j] = fqmul(f, p[j]) 80 | } 81 | } 82 | 83 | //ntt performs in place NTT 84 | func (v Vec) ntt(L int) { 85 | for i := 0; i < L; i++ { 86 | v[i].ntt() 87 | } 88 | } 89 | 90 | //fqmul performs a multiplication in the Montgomery domain 91 | func fqmul(a, b int32) int32 { 92 | return montgomeryReduce(int64(a) * int64(b)) 93 | } 94 | -------------------------------------------------------------------------------- /crystals-dilithium/pack.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | //packT1 returns the byte representation of v 4 | func packT1(v Vec, K int) []byte { 5 | r := make([]byte, K*polySizeT1) 6 | 7 | for j := 0; j < K; j++ { 8 | for i := 0; i < n/4; i++ { 9 | r[j*polySizeT1+5*i+0] = byte(v[j][4*i+0] >> 0) 10 | r[j*polySizeT1+5*i+1] = byte(v[j][4*i+0]>>8) | byte(v[j][4*i+1]<<2) 11 | r[j*polySizeT1+5*i+2] = byte(v[j][4*i+1]>>6) | byte(v[j][4*i+2]<<4) 12 | r[j*polySizeT1+5*i+3] = byte(v[j][4*i+2]>>4) | byte(v[j][4*i+3]<<6) 13 | r[j*polySizeT1+5*i+4] = byte(v[j][4*i+3] >> 2) 14 | } 15 | } 16 | return r 17 | } 18 | 19 | //pnpackT1 reverses the packing operation 20 | func unpackT1(r []byte, K int) Vec { 21 | v := make(Vec, K) 22 | for j := 0; j < K; j++ { 23 | for i := 0; i < n/4; i++ { 24 | v[j][4*i+0] = (int32(r[j*polySizeT1+5*i+0]) >> 0) | (int32(r[j*polySizeT1+5*i+1])<<8)&0x3FF 25 | v[j][4*i+1] = (int32(r[j*polySizeT1+5*i+1]) >> 2) | (int32(r[j*polySizeT1+5*i+2])<<6)&0x3FF 26 | v[j][4*i+2] = (int32(r[j*polySizeT1+5*i+2]) >> 4) | (int32(r[j*polySizeT1+5*i+3])<<4)&0x3FF 27 | v[j][4*i+3] = (int32(r[j*polySizeT1+5*i+3]) >> 6) | (int32(r[j*polySizeT1+5*i+4])<<2)&0x3FF 28 | } 29 | } 30 | return v 31 | } 32 | 33 | //packT0 packs t0 34 | func packT0(v Vec, K int) []byte { 35 | r := make([]byte, K*polySizeT0) 36 | t := make([]uint32, 8) 37 | for j := 0; j < K; j++ { 38 | for i := 0; i < n/8; i++ { 39 | t[0] = uint32((1 << (d - 1)) - v[j][8*i+0]) 40 | t[1] = uint32((1 << (d - 1)) - v[j][8*i+1]) 41 | t[2] = uint32((1 << (d - 1)) - v[j][8*i+2]) 42 | t[3] = uint32((1 << (d - 1)) - v[j][8*i+3]) 43 | t[4] = uint32((1 << (d - 1)) - v[j][8*i+4]) 44 | t[5] = uint32((1 << (d - 1)) - v[j][8*i+5]) 45 | t[6] = uint32((1 << (d - 1)) - v[j][8*i+6]) 46 | t[7] = uint32((1 << (d - 1)) - v[j][8*i+7]) 47 | 48 | r[j*polySizeT0+13*i+0] = byte(t[0]) 49 | r[j*polySizeT0+13*i+1] = byte(t[0] >> 8) 50 | r[j*polySizeT0+13*i+1] |= byte(t[1] << 5) 51 | r[j*polySizeT0+13*i+2] = byte(t[1] >> 3) 52 | r[j*polySizeT0+13*i+3] = byte(t[1] >> 11) 53 | r[j*polySizeT0+13*i+3] |= byte(t[2] << 2) 54 | r[j*polySizeT0+13*i+4] = byte(t[2] >> 6) 55 | r[j*polySizeT0+13*i+4] |= byte(t[3] << 7) 56 | r[j*polySizeT0+13*i+5] = byte(t[3] >> 1) 57 | r[j*polySizeT0+13*i+6] = byte(t[3] >> 9) 58 | r[j*polySizeT0+13*i+6] |= byte(t[4] << 4) 59 | r[j*polySizeT0+13*i+7] = byte(t[4] >> 4) 60 | r[j*polySizeT0+13*i+8] = byte(t[4] >> 12) 61 | r[j*polySizeT0+13*i+8] |= byte(t[5] << 1) 62 | r[j*polySizeT0+13*i+9] = byte(t[5] >> 7) 63 | r[j*polySizeT0+13*i+9] |= byte(t[6] << 6) 64 | r[j*polySizeT0+13*i+10] = byte(t[6] >> 2) 65 | r[j*polySizeT0+13*i+11] = byte(t[6] >> 10) 66 | r[j*polySizeT0+13*i+11] |= byte(t[7] << 3) 67 | r[j*polySizeT0+13*i+12] = byte(t[7] >> 5) 68 | } 69 | } 70 | return r 71 | } 72 | 73 | //unpackT0 reverses the packing operation 74 | func unpackT0(a []byte, K int) Vec { 75 | v := make(Vec, K) 76 | for j := 0; j < K; j++ { 77 | for i := 0; i < n/8; i++ { 78 | v[j][8*i+0] = int32(uint32(a[j*polySizeT0+13*i+0])|uint32(a[j*polySizeT0+13*i+1])<<8) & 0x1FFF 79 | v[j][8*i+1] = int32(uint32(a[j*polySizeT0+13*i+1])>>5|uint32(a[j*polySizeT0+13*i+2])<<3|uint32(a[j*polySizeT0+13*i+3])<<11) & 0x1FFF 80 | v[j][8*i+2] = int32(uint32(a[j*polySizeT0+13*i+3])>>2|uint32(a[j*polySizeT0+13*i+4])<<6) & 0x1FFF 81 | v[j][8*i+3] = int32(uint32(a[j*polySizeT0+13*i+4])>>7|uint32(a[j*polySizeT0+13*i+5])<<1|uint32(a[j*polySizeT0+13*i+6])<<9) & 0x1FFF 82 | v[j][8*i+4] = int32(uint32(a[j*polySizeT0+13*i+6]>>4)|uint32(a[j*polySizeT0+13*i+7])<<4|uint32(a[j*polySizeT0+13*i+8])<<12) & 0x1FFF 83 | v[j][8*i+5] = int32(uint32(a[j*polySizeT0+13*i+8])>>1|uint32(a[j*polySizeT0+13*i+9])<<7) & 0x1FFF 84 | v[j][8*i+6] = int32(uint32(a[j*polySizeT0+13*i+9])>>6|uint32(a[j*polySizeT0+13*i+10])<<2|uint32(a[j*polySizeT0+13*i+11])<<10) & 0x1FFF 85 | v[j][8*i+7] = int32(uint32(a[j*polySizeT0+13*i+11])>>3|uint32(a[j*polySizeT0+13*i+12])<<5) & 0x1FFF 86 | 87 | v[j][8*i+0] = (1 << (d - 1)) - v[j][8*i+0] 88 | v[j][8*i+1] = (1 << (d - 1)) - v[j][8*i+1] 89 | v[j][8*i+2] = (1 << (d - 1)) - v[j][8*i+2] 90 | v[j][8*i+3] = (1 << (d - 1)) - v[j][8*i+3] 91 | v[j][8*i+4] = (1 << (d - 1)) - v[j][8*i+4] 92 | v[j][8*i+5] = (1 << (d - 1)) - v[j][8*i+5] 93 | v[j][8*i+6] = (1 << (d - 1)) - v[j][8*i+6] 94 | v[j][8*i+7] = (1 << (d - 1)) - v[j][8*i+7] 95 | } 96 | } 97 | return v 98 | } 99 | 100 | //packW1 packs a w1 poly 101 | func packW1(v Vec, L, POLYSIZEW1 int, GAMMA2 int32) []byte { 102 | r := make([]byte, L*POLYSIZEW1) 103 | if GAMMA2 == (q-1)/88 { 104 | for j := 0; j < L; j++ { 105 | for i := 0; i < n/4; i++ { 106 | r[j*POLYSIZEW1+3*i+0] = byte(v[j][4*i+0] | v[j][4*i+1]<<6) 107 | r[j*POLYSIZEW1+3*i+1] = byte(v[j][4*i+1]>>2 | v[j][4*i+2]<<4) 108 | r[j*POLYSIZEW1+3*i+2] = byte(v[j][4*i+2]>>4 | v[j][4*i+3]<<2) 109 | } 110 | } 111 | return r 112 | } 113 | for j := 0; j < L; j++ { 114 | for i := 0; i < n/2; i++ { 115 | r[j*POLYSIZEW1+i] = byte(v[j][2*i+0] | (v[j][2*i+1] << 4)) 116 | } 117 | } 118 | return r 119 | } 120 | 121 | //packS packs a S vec 122 | func packS(v Vec, L, POLYSIZES int, ETA int32) []byte { 123 | r := make([]byte, L*POLYSIZES) 124 | if ETA == 4 { 125 | t := make([]byte, 2) 126 | for j := 0; j < L; j++ { 127 | for i := 0; i < n/2; i++ { 128 | t[0] = byte(ETA - v[j][2*i+0]) 129 | t[1] = byte(ETA - v[j][2*i+1]) 130 | r[j*POLYSIZES+i] = t[0] | (t[1] << 4) 131 | } 132 | } 133 | } 134 | if ETA == 2 { 135 | t := make([]byte, 8) 136 | for j := 0; j < L; j++ { 137 | for i := 0; i < n/8; i++ { 138 | t[0] = byte(ETA - v[j][8*i+0]) 139 | t[1] = byte(ETA - v[j][8*i+1]) 140 | t[2] = byte(ETA - v[j][8*i+2]) 141 | t[3] = byte(ETA - v[j][8*i+3]) 142 | t[4] = byte(ETA - v[j][8*i+4]) 143 | t[5] = byte(ETA - v[j][8*i+5]) 144 | t[6] = byte(ETA - v[j][8*i+6]) 145 | t[7] = byte(ETA - v[j][8*i+7]) 146 | 147 | r[j*POLYSIZES+3*i+0] = (t[0] >> 0) | (t[1] << 3) | (t[2] << 6) 148 | r[j*POLYSIZES+3*i+1] = (t[2] >> 2) | (t[3] << 1) | (t[4] << 4) | (t[5] << 7) 149 | r[j*POLYSIZES+3*i+2] = (t[5] >> 1) | (t[6] << 2) | (t[7] << 5) 150 | } 151 | } 152 | } 153 | return r 154 | } 155 | 156 | //unpackS reverses the packing of an S vec 157 | func unpackS(r []byte, L, POLYSIZES int, ETA int32) Vec { 158 | v := make(Vec, L) 159 | if ETA == 4 { 160 | for j := 0; j < L; j++ { 161 | for i := 0; i < n/2; i++ { 162 | v[j][2*i+0] = int32(uint32(r[j*POLYSIZES+i]) & 0x0F) 163 | v[j][2*i+1] = int32(uint32(r[j*POLYSIZES+i]) >> 4) 164 | v[j][2*i+0] = ETA - v[j][2*i+0] 165 | v[j][2*i+1] = ETA - v[j][2*i+1] 166 | } 167 | } 168 | } 169 | if ETA == 2 { 170 | for j := 0; j < L; j++ { 171 | for i := 0; i < n/8; i++ { 172 | v[j][8*i+0] = ETA - int32(r[j*POLYSIZES+3*i])&7 173 | v[j][8*i+1] = ETA - int32(r[j*POLYSIZES+3*i])>>3&7 174 | v[j][8*i+2] = ETA - (int32(r[j*POLYSIZES+3*i])>>6 | (int32(r[j*POLYSIZES+3*i+1])<<2)&7) 175 | v[j][8*i+3] = ETA - (int32(r[j*POLYSIZES+3*i+1])>>1)&7 176 | v[j][8*i+4] = ETA - (int32(r[j*POLYSIZES+3*i+1])>>4)&7 177 | v[j][8*i+5] = ETA - (int32(r[j*POLYSIZES+3*i+1])>>7 | (int32(r[j*POLYSIZES+3*i+2])<<1)&7) 178 | v[j][8*i+6] = ETA - (int32(r[j*POLYSIZES+3*i+2])>>2)&7 179 | v[j][8*i+7] = ETA - (int32(r[j*POLYSIZES+3*i+2])>>5)&7 180 | } 181 | } 182 | } 183 | return v 184 | } 185 | 186 | //packZ packs a Z vec 187 | func packZ(v Vec, L, POLYSIZEZ int, GAMMA1 int32) []byte { 188 | r := make([]byte, L*POLYSIZEZ) 189 | if GAMMA1 == (1 << 17) { 190 | t := make([]int32, 4) 191 | for j := 0; j < L; j++ { 192 | for i := 0; i < n/4; i++ { 193 | t[0] = GAMMA1 - v[j][4*i+0] 194 | t[1] = GAMMA1 - v[j][4*i+1] 195 | t[2] = GAMMA1 - v[j][4*i+2] 196 | t[3] = GAMMA1 - v[j][4*i+3] 197 | 198 | r[j*POLYSIZEZ+9*i+0] = byte(t[0]) 199 | r[j*POLYSIZEZ+9*i+1] = byte(t[0] >> 8) 200 | r[j*POLYSIZEZ+9*i+2] = byte(t[0]>>16) | byte(t[1]<<2) 201 | r[j*POLYSIZEZ+9*i+3] = byte(t[1] >> 6) 202 | r[j*POLYSIZEZ+9*i+4] = byte(t[1]>>14) | byte(t[2]<<4) 203 | r[j*POLYSIZEZ+9*i+5] = byte(t[2] >> 4) 204 | r[j*POLYSIZEZ+9*i+6] = byte(t[2]>>12) | byte(t[3]<<6) 205 | r[j*POLYSIZEZ+9*i+7] = byte(t[3] >> 2) 206 | r[j*POLYSIZEZ+9*i+8] = byte(t[3] >> 10) 207 | } 208 | } 209 | return r 210 | } 211 | t := make([]int32, 2) 212 | for j := 0; j < L; j++ { 213 | for i := 0; i < n/2; i++ { 214 | t[0] = GAMMA1 - v[j][2*i+0] 215 | t[1] = GAMMA1 - v[j][2*i+1] 216 | 217 | r[j*POLYSIZEZ+5*i+0] = byte(t[0]) 218 | r[j*POLYSIZEZ+5*i+1] = byte(t[0] >> 8) 219 | r[j*POLYSIZEZ+5*i+2] = byte(t[0]>>16) | byte(t[1]<<4) 220 | r[j*POLYSIZEZ+5*i+3] = byte(t[1] >> 4) 221 | r[j*POLYSIZEZ+5*i+4] = byte(t[1] >> 12) 222 | } 223 | } 224 | return r 225 | } 226 | 227 | //unpackZ reverses the packing operation 228 | func unpackZ(buf []byte, L, POLYSIZEZ int, GAMMA1 int32) Vec { 229 | v := make(Vec, L) 230 | if GAMMA1 == (1 << 17) { 231 | for j := 0; j < L; j++ { 232 | for i := 0; i < n/4; i++ { 233 | v[j][4*i+0] = int32(buf[j*POLYSIZEZ+9*i+0]) | (int32(buf[j*POLYSIZEZ+9*i+1]) << 8) | (int32(buf[j*POLYSIZEZ+9*i+2])<<16)&0x3FFFF 234 | v[j][4*i+1] = (int32(buf[j*POLYSIZEZ+9*i+2]) >> 2) | (int32(buf[j*POLYSIZEZ+9*i+3]) << 6) | (int32(buf[j*POLYSIZEZ+9*i+4])<<14)&0x3FFFF 235 | v[j][4*i+2] = (int32(buf[j*POLYSIZEZ+9*i+4]) >> 4) | (int32(buf[j*POLYSIZEZ+9*i+5]) << 4) | (int32(buf[j*POLYSIZEZ+9*i+6])<<12)&0x3FFFF 236 | v[j][4*i+3] = (int32(buf[j*POLYSIZEZ+9*i+6]) >> 6) | (int32(buf[j*POLYSIZEZ+9*i+7]) << 2) | (int32(buf[j*POLYSIZEZ+9*i+8])<<10)&0x3FFFF 237 | 238 | v[j][4*i+0] = GAMMA1 - v[j][4*i+0] 239 | v[j][4*i+1] = GAMMA1 - v[j][4*i+1] 240 | v[j][4*i+2] = GAMMA1 - v[j][4*i+2] 241 | v[j][4*i+3] = GAMMA1 - v[j][4*i+3] 242 | } 243 | } 244 | return v 245 | } 246 | for j := 0; j < L; j++ { 247 | for i := 0; i < n/2; i++ { 248 | v[j][2*i+0] = int32(buf[j*POLYSIZEZ+5*i+0]) | (int32(buf[j*POLYSIZEZ+5*i+1]) << 8) | (int32(buf[j*POLYSIZEZ+5*i+2])<<16)&0xFFFFF 249 | v[j][2*i+1] = (int32(buf[j*POLYSIZEZ+5*i+2]) >> 4) | (int32(buf[j*POLYSIZEZ+5*i+3]) << 4) | (int32(buf[j*POLYSIZEZ+5*i+4])<<12)&0xFFFFF 250 | v[j][2*i+0] = GAMMA1 - v[j][2*i+0] 251 | v[j][2*i+1] = GAMMA1 - v[j][2*i+1] 252 | } 253 | } 254 | return v 255 | } 256 | 257 | //packH packs an H vec 258 | func packH(v Vec, K int, OMEGA int) []byte { 259 | buf := make([]byte, OMEGA+K) 260 | off := 0 261 | for i := 0; i < K; i++ { 262 | for j := 0; j < n; j++ { 263 | if v[i][j] != 0 { 264 | buf[off] = byte(j) 265 | off++ 266 | } 267 | } 268 | buf[OMEGA+i] = byte(off) 269 | } 270 | return buf[:] 271 | } 272 | 273 | //unpackH reverses the packing operation 274 | func unpackH(buf []byte, L int, OMEGA int) Vec { 275 | v := make(Vec, L) 276 | k := uint8(0) 277 | for i := 0; i < L; i++ { 278 | SOP := buf[OMEGA+i] 279 | if SOP < k || SOP > uint8(OMEGA) { 280 | return make(Vec, L) 281 | } 282 | for j := k; j < SOP; j++ { 283 | if j > k && buf[j] <= buf[j-1] { 284 | return make(Vec, L) 285 | } 286 | v[i][buf[j]] = 1 287 | } 288 | k = SOP 289 | } 290 | for j := k; j < uint8(OMEGA); j++ { 291 | if buf[j] != 0 { 292 | return make(Vec, L) 293 | } 294 | } 295 | return v 296 | } 297 | 298 | //PackSig packs a dilithium signature into a byte array 299 | func (d *Dilithium) PackSig(z Vec, h Vec, hc []byte) []byte { 300 | K := d.params.K 301 | L := d.params.L 302 | OMEGA := d.params.OMEGA 303 | POLYSIZEZ := d.params.POLYSIZEZ 304 | sigP := make([]byte, d.params.SIZESIG) 305 | copy(sigP[:32], hc[:]) 306 | copy(sigP[32:], packZ(z, L, POLYSIZEZ, d.params.GAMMA1)) 307 | copy(sigP[32+L*POLYSIZEZ:], packH(h, K, OMEGA)) 308 | return sigP[:] 309 | } 310 | 311 | //UnpackSig unpacks a byte array into a signature. If the format is incorrect, nil objects are returned. 312 | func (d *Dilithium) UnpackSig(sig []byte) (Vec, Vec, []byte) { 313 | K := d.params.K 314 | L := d.params.L 315 | if len(sig) != d.SIZESIG() { 316 | return nil, nil, nil 317 | } 318 | OMEGA := d.params.OMEGA 319 | POLYSIZEZ := d.params.POLYSIZEZ 320 | id := 32 321 | z := unpackZ(sig[id:], L, POLYSIZEZ, d.params.GAMMA1) 322 | id += L * POLYSIZEZ 323 | h := unpackH(sig[id:], K, OMEGA) 324 | return z, h, sig[:32] 325 | } 326 | -------------------------------------------------------------------------------- /crystals-dilithium/params.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | //The first block of constants define internal parameters. 4 | //SEEDBYTES holds the lenght in byte of the random number to give as input, if wanted. 5 | //The remaining constants are exported to allow for fixed-lenght array instantiation. For a given security level, the consts are the same as the output of the d.SIZEX() functions defined in keys.go 6 | const ( 7 | n = 256 8 | q = 8380417 // 2²³ - 2¹³ + 1 9 | qInv = 58728449 // -q^(-1) mod 2^32 10 | d = 13 11 | polySizeT1 = 320 12 | polySizeT0 = 416 13 | shake128Rate = 168 14 | shake256Rate = 136 15 | 16 | SEEDBYTES = 32 17 | 18 | Dilithium2SizePK = 1312 19 | Dilihtium2SizeSK = 2528 20 | Dilithium2SizeSig = 2420 21 | 22 | Dilithium3SizePK = 1952 23 | Dilihtium3SizeSK = 4000 24 | Dilithium3SizeSig = 3293 25 | 26 | Dilithium5SizePK = 2592 27 | Dilihtium5SizeSK = 4864 28 | Dilithium5SizeSig = 4595 29 | ) 30 | 31 | //Dilithium struct defines the internal parameters to be used given a security level 32 | type Dilithium struct { 33 | Name string 34 | params *parameters 35 | } 36 | 37 | //parameters hold all internal varying parameters used in a dilithium scheme 38 | type parameters struct { 39 | T int 40 | K int 41 | L int 42 | GAMMA1 int32 43 | GAMMA2 int32 44 | ETA int32 45 | BETA int32 46 | OMEGA int 47 | POLYSIZES int 48 | POLYSIZEZ int //= (N * (QBITS - 3)) / 8 49 | POLYSIZEW1 int //= ((N * 4) / 8) 50 | SIZEPK int //= K*POLYSIZE + SeedBytes 51 | SIZESK int //= SIZEZ + 32 + SIZEPK + K*POLYSIZE 52 | SIZESIG int 53 | RANDOMIZED int //deterministic or randomized signature 54 | } 55 | 56 | //NewDilithium2 defines a dilithium instance with a light security level. The signature is randomized expect if a false boolean is given as argument. 57 | func NewDilithium2(randomized ...bool) *Dilithium { 58 | r := 1 //randomized by default 59 | if len(randomized) == 1 && !randomized[0] { 60 | r = 0 61 | } 62 | return &Dilithium{ 63 | Name: "Dilithium2", 64 | params: ¶meters{ 65 | T: 39, 66 | K: 4, 67 | L: 4, 68 | GAMMA1: 131072, 69 | GAMMA2: (q - 1) / 88, 70 | ETA: 2, 71 | BETA: 78, 72 | OMEGA: 80, 73 | POLYSIZES: 96, //POLYETA, 74 | POLYSIZEZ: 576, //POLYGAMMA1 75 | POLYSIZEW1: 192, //POLYGAMMA2 76 | RANDOMIZED: r, 77 | SIZEPK: 32 + 4*polySizeT1, 78 | SIZESK: 32 + 32 + 32 + 4*polySizeT0 + (4+4)*96, 79 | SIZESIG: 32 + 4*576 + 4 + 80, 80 | }} 81 | } 82 | 83 | //NewDilithium3 defines a dilithium instance with a medium security level. The signature is randomized expect if a false boolean is given as argument. 84 | func NewDilithium3(randomized ...bool) *Dilithium { 85 | r := 1 //randomized by default 86 | if len(randomized) == 1 && !randomized[0] { 87 | r = 0 88 | } 89 | return &Dilithium{ 90 | Name: "Dilithium3", 91 | params: ¶meters{ 92 | T: 49, 93 | K: 6, 94 | L: 5, 95 | GAMMA1: 524288, 96 | GAMMA2: (q - 1) / 32, 97 | ETA: 4, 98 | BETA: 196, 99 | OMEGA: 55, 100 | RANDOMIZED: r, 101 | POLYSIZES: 128, //POLYETA, 102 | POLYSIZEZ: 640, //POLYGAMMA1 103 | POLYSIZEW1: 128, 104 | SIZEPK: 32 + 6*polySizeT1, 105 | SIZESK: 32 + 32 + 32 + 6*polySizeT0 + (5+6)*128, 106 | SIZESIG: 32 + 5*640 + 6 + 55, 107 | }} 108 | } 109 | 110 | //NewDilithium5 defines a dilithium instance with a very high security level. The signature is randomized expect if a false boolean is given as argument. 111 | func NewDilithium5(randomized ...bool) *Dilithium { 112 | r := 1 //randomized by default 113 | if len(randomized) == 1 && !randomized[0] { 114 | r = 0 115 | } 116 | return &Dilithium{ 117 | Name: "Dilithium5", 118 | params: ¶meters{ 119 | T: 60, 120 | K: 8, 121 | L: 7, 122 | GAMMA1: 524288, 123 | GAMMA2: (q - 1) / 32, 124 | ETA: 2, 125 | BETA: 120, 126 | OMEGA: 75, 127 | POLYSIZES: 96, 128 | POLYSIZEZ: 640, 129 | POLYSIZEW1: 128, 130 | RANDOMIZED: r, 131 | SIZEPK: 32 + 8*polySizeT1, 132 | SIZESK: 32 + 32 + 32 + 8*polySizeT0 + (8+7)*96, 133 | SIZESIG: 32 + 7*640 + 8 + 75, 134 | }} 135 | } 136 | 137 | //NewDilithiumUnsafe is a skeleton function to be used for research purposes when wanting to use a dilithium instance with parameters that differ from the recommended ones. 138 | func NewDilithiumUnsafe(q, d, tau, gamma1, gamma2, k, l, eta, omega int) *Dilithium { 139 | return &Dilithium{ 140 | Name: "Custom Dilithium", 141 | params: ¶meters{}} 142 | } 143 | -------------------------------------------------------------------------------- /crystals-dilithium/poly.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | "golang.org/x/crypto/sha3" 5 | ) 6 | 7 | //Poly represents a polynomial of deg n with coefs in [0, Q) 8 | type Poly [n]int32 9 | 10 | //freeze calls Freeze on each coef 11 | func (a *Poly) freeze() { 12 | for i := 0; i < n; i++ { 13 | a[i] = freeze(a[i]) 14 | } 15 | } 16 | 17 | //reduce calls Reduce32 on each coef 18 | func (a *Poly) reduce() { 19 | for i := 0; i < n; i++ { 20 | a[i] = reduce32(a[i]) 21 | } 22 | } 23 | 24 | //add two Poly without normalization 25 | func add(a, b Poly) Poly { 26 | var c Poly 27 | for i := 0; i < n; i++ { 28 | c[i] = a[i] + b[i] 29 | } 30 | return c 31 | } 32 | 33 | //addQ calls addQ on eah coefficient 34 | func (a *Poly) addQ() { 35 | for i := 0; i < n; i++ { 36 | a[i] = addQ(a[i]) 37 | } 38 | } 39 | 40 | //sub substracts b from a without normalization 41 | func sub(a, b Poly) Poly { 42 | var c Poly 43 | for i := 0; i < n; i++ { 44 | c[i] = a[i] - b[i] 45 | } 46 | return c 47 | } 48 | 49 | //shift mult all coefs by 2^d 50 | func (a *Poly) shift() { 51 | for i := 0; i < n; i++ { 52 | a[i] <<= d 53 | } 54 | } 55 | 56 | //montMul perfroms pointwise mutl (to be used with nTT Poly) 57 | //poly_pointwise_montgomery in ref implementation 58 | func montMul(a, b Poly) Poly { 59 | var c Poly 60 | for i := 0; i < n; i++ { 61 | c[i] = montgomeryReduce(int64(a[i]) * int64(b[i])) 62 | } 63 | return c 64 | } 65 | 66 | //isBelow returns true if all coefs are in [Q-b, Q+b] 67 | func (a Poly) isBelow(bound int32) bool { 68 | res := true 69 | if bound > (q-1)/8 { 70 | return false 71 | } 72 | for i := 0; i < n; i++ { 73 | t := a[i] >> 31 74 | t = a[i] - (t & 2 * a[i]) 75 | res = res && (t < bound) 76 | } 77 | return res 78 | } 79 | 80 | //rej fills a with coefs in [0, Q) generated with buf using rejection sampling 81 | func rej(a []int32, buf []byte) int { 82 | ctr, buflen, alen := 0, len(buf), len(a) 83 | for pos := 0; pos+3 < buflen && ctr < alen; pos += 3 { 84 | var t uint32 85 | t = uint32(buf[pos]) 86 | t |= uint32(buf[pos+1]) << 8 87 | t |= uint32(buf[pos+2]) << 16 88 | t &= 0x7fffff 89 | 90 | if t < q { 91 | a[ctr] = int32(t) 92 | ctr++ 93 | } 94 | } 95 | return ctr 96 | } 97 | 98 | //polyUniform samples a polynomial with coefs in [0, Q] 99 | func polyUniform(seed [SEEDBYTES]byte, nonce uint16) Poly { 100 | var a Poly 101 | var outbuf [5 * shake128Rate]byte 102 | 103 | state := sha3.NewShake128() 104 | state.Write(seed[:]) 105 | state.Write([]byte{byte(nonce), byte(nonce >> 8)}) 106 | state.Read(outbuf[:]) 107 | 108 | ctr := rej(a[:], outbuf[:]) 109 | for ctr < n { 110 | off := 5 * shake128Rate % 3 111 | for i := 0; i < off; i++ { 112 | outbuf[i] = outbuf[5*shake128Rate-off+i] 113 | } 114 | state.Read(outbuf[off:]) 115 | ctr += rej(a[ctr:], outbuf[:]) 116 | } 117 | return a 118 | } 119 | 120 | //rejEta fills a with coefs in [0, ETA) generated with buf using rejection sampling 121 | func rejEta(a []int32, buf []byte, ETA int32) int { 122 | ctr, buflen, alen := 0, len(buf), len(a) 123 | for pos := 0; pos < buflen && ctr < alen; pos++ { 124 | var t0, t1 int32 125 | t0 = int32(buf[pos]) & 0x0F 126 | t1 = int32(buf[pos]) >> 4 127 | if ETA == 2 { 128 | if t0 < 15 { 129 | t0 -= (205 * t0 >> 10) * 5 130 | a[ctr] = ETA - t0 131 | ctr++ 132 | } 133 | if t1 < 15 && ctr < alen { 134 | t1 -= (205 * t1 >> 10) * 5 135 | a[ctr] = ETA - t1 136 | ctr++ 137 | } 138 | } 139 | if ETA == 4 { 140 | if t0 < 9 { 141 | a[ctr] = ETA - t0 142 | ctr++ 143 | } 144 | if t1 < 9 && ctr < alen { 145 | a[ctr] = ETA - t1 146 | ctr++ 147 | } 148 | } 149 | } 150 | return ctr 151 | } 152 | 153 | //polyUniformEta samples a polynomial with coefs in [Q-eta, Q+eta] 154 | func polyUniformEta(seed [2 * SEEDBYTES]byte, nonce uint16, ETA int32) Poly { 155 | var a Poly 156 | blocks := 1 //ETA == 2 157 | if ETA == 4 { 158 | blocks = 2 159 | } 160 | outbuf := make([]byte, shake256Rate*blocks) 161 | 162 | state := sha3.NewShake256() 163 | state.Write(seed[:]) 164 | state.Write([]byte{uint8(nonce), uint8(nonce >> 8)}) 165 | state.Read(outbuf[:]) 166 | 167 | ctr := rejEta(a[:], outbuf[:], ETA) 168 | for ctr < n { 169 | sub := outbuf[:shake256Rate] 170 | state.Read(sub) 171 | ctr += rejEta(a[ctr:], sub, ETA) 172 | } 173 | return a 174 | } 175 | 176 | //polyUniformGamma1 samples a polynomial with coefs in [Q-gamma1, Q+gamma1] 177 | func polyUniformGamma1(rhoP [2 * SEEDBYTES]byte, nonce uint16, GAMMA1 int32) Poly { 178 | var outbuf [shake256Rate * 5]byte 179 | state := sha3.NewShake256() 180 | state.Write(rhoP[:]) 181 | state.Write([]byte{uint8(nonce), uint8(nonce >> 8)}) 182 | state.Read(outbuf[:]) 183 | POLYSIZE := 640 184 | if GAMMA1 == (q-1)/88 { 185 | POLYSIZE = 576 186 | } 187 | a := unpackZ(outbuf[:], 1, POLYSIZE, GAMMA1) 188 | return a[0] 189 | } 190 | 191 | //equal returns true if b is equal to a (all coefs are) 192 | func (a Poly) equal(b Poly) bool { 193 | res := true 194 | for i := 0; i < n; i++ { 195 | if a[i] != b[i] { 196 | res = false 197 | } 198 | } 199 | return res 200 | } 201 | 202 | //polyPower2Round calls power2Round on each coef 203 | func polyPower2Round(p Poly) (Poly, Poly) { 204 | var p1, p0 Poly 205 | for j := 0; j < n; j++ { 206 | p1[j], p0[j] = power2Round(p[j]) 207 | } 208 | return p1, p0 209 | } 210 | 211 | //polyDecompose calls decompose on each coef 212 | func polyDecompose(p Poly, GAMMA2 int32) (Poly, Poly) { 213 | var p1, p0 Poly 214 | for j := 0; j < n; j++ { 215 | p1[j], p0[j] = decompose(p[j], GAMMA2) 216 | } 217 | return p1, p0 218 | } 219 | 220 | //polyUseHint uses the hint to correct the hight bits of u 221 | func polyUseHint(u, h Poly, GAMMA2 int32) Poly { 222 | var p Poly 223 | for j := 0; j < n; j++ { 224 | p[j] = useHint(u[j], h[j], GAMMA2) 225 | } 226 | return p 227 | } 228 | 229 | //tomont converts a poly to its montgomery representation 230 | func (p *Poly) tomont() { 231 | for i := 0; i < n; i++ { 232 | p[i] = montgomeryReduce(int64(p[i])) 233 | } 234 | } 235 | 236 | //fromMont converts back to [0, Q] 237 | func (p *Poly) fromMont() { 238 | inv := uint64(8265825) 239 | for i := uint(0); i < n; i++ { 240 | p[i] = int32((uint64(p[i]) * inv) % q) 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /crystals-dilithium/testdata/dilithium-submission-nist-round3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kudelskisecurity/crystals-go/2a6ca2d4e64d18dd6e8fbb4e48e22c2510118505/crystals-dilithium/testdata/dilithium-submission-nist-round3.zip -------------------------------------------------------------------------------- /crystals-dilithium/utils_benchmark_test.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | cRand "crypto/rand" 5 | "io" 6 | "testing" 7 | ) 8 | 9 | func BenchmarkExpand(b *testing.B) { 10 | var rho [32]byte 11 | rand := cRand.Reader 12 | d := NewDilithium3(false) 13 | K := d.params.K 14 | L := d.params.L 15 | for n := 0; n < b.N; n++ { 16 | b.StopTimer() 17 | io.ReadFull(rand, rho[:]) 18 | b.StartTimer() 19 | expandSeed(rho, K, L) 20 | } 21 | } 22 | 23 | func BenchmarkOverheadRandPoly(b *testing.B) { 24 | var seed [32]byte 25 | rand := cRand.Reader 26 | for n := 0; n < b.N; n++ { 27 | io.ReadFull(rand, seed[:]) 28 | polyUniform(seed, 0) 29 | } 30 | } 31 | 32 | func BenchmarkPolyNTT(b *testing.B) { 33 | var seed [32]byte 34 | rand := cRand.Reader 35 | for n := 0; n < b.N; n++ { 36 | b.StopTimer() 37 | io.ReadFull(rand, seed[:]) 38 | p := polyUniform(seed, 0) 39 | b.StartTimer() 40 | p.ntt() 41 | } 42 | } 43 | 44 | func BenchmarkPolyInvNTT(b *testing.B) { 45 | var seed [32]byte 46 | rand := cRand.Reader 47 | for n := 0; n < b.N; n++ { 48 | b.StopTimer() 49 | io.ReadFull(rand, seed[:]) 50 | p := polyUniform(seed, 0) 51 | p.ntt() 52 | b.StartTimer() 53 | p.invntt() 54 | } 55 | } 56 | 57 | func BenchmarkPointWise(b *testing.B) { 58 | var seed [32]byte 59 | rand := cRand.Reader 60 | for n := 0; n < b.N; n++ { 61 | b.StopTimer() 62 | io.ReadFull(rand, seed[:]) 63 | p := polyUniform(seed, 0) 64 | q := polyUniform(seed, 0) 65 | b.StartTimer() 66 | montMul(p, q) 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /crystals-dilithium/utils_test.go: -------------------------------------------------------------------------------- 1 | package dilithium 2 | 3 | import ( 4 | cRand "crypto/rand" 5 | "io" 6 | "math/rand" 7 | "testing" 8 | ) 9 | 10 | /** Test Poly **/ 11 | 12 | func TestPoly(t *testing.T) { 13 | var seed [32]byte 14 | rand := cRand.Reader 15 | io.ReadFull(rand, seed[:]) 16 | 17 | p := polyUniform(seed, 0) 18 | p2 := polyUniform(seed, 1) 19 | 20 | a := add(p, p2) 21 | 22 | for i := uint(0); i < n; i++ { 23 | if a[i] != (p[i] + p2[i]) { 24 | t.Fatalf("Add failed") 25 | } 26 | } 27 | 28 | b := sub(p, p2) 29 | for i := uint(0); i < n; i++ { 30 | if b[i] != (p[i] - p2[i]) { 31 | t.Fatalf("Sub failed") 32 | } 33 | } 34 | } 35 | 36 | func TestFreeze(t *testing.T) { 37 | 38 | a := int32(q + 1) 39 | if freeze(a) != 1 { 40 | t.Fatal("Freeze did not work") 41 | } 42 | 43 | var seed [32]byte 44 | rand := cRand.Reader 45 | io.ReadFull(rand, seed[:]) 46 | 47 | var p, b Poly 48 | p = polyUniform(seed, 0) 49 | b = add(p, p) 50 | //some coefs must be > Q 51 | c := b 52 | c.freeze() 53 | for i := uint(0); i < n; i++ { 54 | if c[i] != (b[i] % q) { 55 | t.Fatalf("Freeze failed") 56 | } 57 | } 58 | } 59 | 60 | func TestRandPoly(t *testing.T) { 61 | var seed [32]byte 62 | copy(seed[:], []byte("very random seed that I will use")) 63 | var p, p2 Poly 64 | p = polyUniform(seed, 0) 65 | p2 = polyUniform(seed, 0) 66 | for i := uint(0); i < n; i++ { 67 | if p[i] != p2[i] { 68 | t.Fatalf("Seed did not work") 69 | } 70 | } 71 | p2 = polyUniform(seed, 1) 72 | counter := 0 73 | for i := uint(0); i < n; i++ { 74 | if p[i] == p2[i] { 75 | counter++ 76 | } 77 | if counter == n { 78 | t.Fatalf("Seed did not work") 79 | } 80 | } 81 | } 82 | 83 | func TestSamples(t *testing.T) { 84 | var seed [64]byte 85 | rand := cRand.Reader 86 | io.ReadFull(rand, seed[:]) 87 | 88 | ETA := int32(2) 89 | 90 | var p, p2 Poly 91 | p = polyUniformEta(seed, 1, ETA) 92 | if !p.isBelow(ETA + 1) { //i > eta 93 | t.Fatalf("PolyUniformEta sampled failed %v\n", p) 94 | } 95 | var rhoP [64]byte 96 | io.ReadFull(rand, rhoP[:]) 97 | GAMMA1 := int32(1 << 17) 98 | p2 = polyUniformGamma1(rhoP, 0, GAMMA1) 99 | if !p2.isBelow(GAMMA1 + 1) { //if stritcly above 100 | t.Fatalf("PolyUnifromGamma1 sampled failed %v\n", p2) 101 | } 102 | } 103 | 104 | func TestExpand(t *testing.T) { 105 | var seed [32]byte 106 | copy(seed[:], []byte("very random seed that I will use")) 107 | K, L := 6, 5 108 | A := expandSeed(seed, K, L) 109 | Abis := expandSeed(seed, K, L) 110 | for i := 0; i < K; i++ { 111 | for j := 0; j < L; j++ { 112 | if A[i][j] != Abis[i][j] { 113 | t.Fatalf("Seed did not work") 114 | } 115 | } 116 | } 117 | for j := 1; j < L; j++ { 118 | if A[0][0] == A[0][j] { 119 | t.Fatalf("Poly is repeating %v against %d: %v\n", A[0][0], j, A[0][j]) 120 | } 121 | } 122 | } 123 | 124 | func TestMult(t *testing.T) { 125 | var p, p2 Poly 126 | 127 | p[0] = 1 128 | p2[0] = 1 129 | p.ntt() 130 | p2.ntt() 131 | res := montMul(p, p2) 132 | p.invntt() 133 | p2.invntt() 134 | res.invntt() 135 | res.freeze() 136 | if res[0] != 1 { 137 | t.Fatalf("Mult did not work %v\n", res) 138 | } 139 | for i := 1; i < n; i++ { 140 | if res[i] != 0 { 141 | t.Fatal("Mult did not work") 142 | } 143 | } 144 | } 145 | 146 | /** Test Utils **/ 147 | 148 | func TestPow2Round(t *testing.T) { 149 | r := int32(rand.Intn(q - 1)) 150 | r1, r0 := power2Round(r) 151 | if (-(1 << (d - 1)) >= r0) || (r0 >= 1<<(d-1)) { 152 | t.Fatalf("Power2Round failed r0 not in the bounds") 153 | } 154 | if int32(r1)*(1<> 15) & int16(q)) 45 | return a 46 | } 47 | -------------------------------------------------------------------------------- /crystals-kyber/kat_test.go: -------------------------------------------------------------------------------- 1 | package kyber 2 | 3 | import ( 4 | "bufio" 5 | "bytes" 6 | "crypto/aes" 7 | "encoding/hex" 8 | "fmt" 9 | "os" 10 | "strconv" 11 | "strings" 12 | "testing" 13 | ) 14 | 15 | //helpers (see NIST's PQCgenKAT.c) 16 | type randomBytes struct { 17 | key [32]byte 18 | v [16]byte 19 | } 20 | 21 | func (g *randomBytes) incV() { 22 | for j := 15; j >= 0; j-- { 23 | if g.v[j] == 255 { 24 | g.v[j] = 0 25 | } else { 26 | g.v[j]++ 27 | break 28 | } 29 | } 30 | } 31 | 32 | // AES256_CTR_randomBytes_update(pd, &g.key, &g.v) 33 | func (g *randomBytes) randombyteUpdate(pd *[48]byte) { 34 | var buf [48]byte 35 | b, _ := aes.NewCipher(g.key[:]) 36 | for i := 0; i < 3; i++ { 37 | g.incV() 38 | b.Encrypt(buf[i*16:(i+1)*16], g.v[:]) 39 | } 40 | if pd != nil { 41 | for i := 0; i < 48; i++ { 42 | buf[i] ^= pd[i] 43 | } 44 | } 45 | copy(g.key[:], buf[:32]) 46 | copy(g.v[:], buf[32:]) 47 | } 48 | 49 | // randombyte_init(seed, NULL, 256) 50 | func randombyteInit(seed *[48]byte) (g randomBytes) { 51 | g.randombyteUpdate(seed) 52 | return 53 | } 54 | 55 | // randombytes() 56 | func (g *randomBytes) randombytes(x []byte) { 57 | var block [16]byte 58 | 59 | b, _ := aes.NewCipher(g.key[:]) 60 | for len(x) > 0 { 61 | g.incV() 62 | b.Encrypt(block[:], g.v[:]) 63 | if len(x) < 16 { 64 | copy(x[:], block[:len(x)]) 65 | break 66 | } 67 | copy(x[:], block[:]) 68 | x = x[16:] 69 | } 70 | g.randombyteUpdate(nil) 71 | } 72 | 73 | func TestKAT(t *testing.T) { 74 | /** 75 | GOLDEN_ZIP := "https://pq-crystals.org/kyber/data/kyber-submission-nist-round3.zip" 76 | os.Mkdir("testdata", 0755) 77 | cached := "testdata/" + path.Base(GOLDEN_ZIP) 78 | zipfile, err := zip.OpenReader(cached) 79 | if err != nil { 80 | t.Logf("Retrieving golden KAT zip from %s", GOLDEN_ZIP) 81 | resp, _ := http.Get(GOLDEN_ZIP) 82 | body, _ := ioutil.ReadAll(resp.Body) 83 | ioutil.WriteFile(cached, body, 0644) 84 | zipfile, _ = zip.OpenReader(cached) 85 | resp.Body.Close() 86 | } 87 | testKAT(t, zipfile, NewKyber512()) 88 | testKAT(t, zipfile, NewKyber768()) 89 | testKAT(t, zipfile, NewKyber1024()) 90 | } 91 | **/ 92 | 93 | testKAT(t, NewKyber512()) 94 | testKAT(t, NewKyber768()) 95 | testKAT(t, NewKyber1024()) 96 | } 97 | 98 | func testKAT(t *testing.T, k *Kyber) { 99 | // func testKAT(t *testing.T, zipfile *zip.ReadCloser, k *Kyber) { 100 | 101 | /** 102 | var katfile io.ReadCloser 103 | gotkat := false 104 | for _, f := range zipfile.File { 105 | goldenKAT := fmt.Sprintf("PQCkemKAT_%d.rsp", k.params.SIZESK) 106 | if strings.HasSuffix(f.Name, goldenKAT) { 107 | katfile, _ = f.Open() 108 | gotkat = true 109 | break 110 | } 111 | } 112 | **/ 113 | goldenKAT := fmt.Sprintf("PQCkemKAT_%d.rsp", k.params.SIZESK) 114 | katfile, err := os.Open("testdata/" + goldenKAT) 115 | if err != nil { 116 | t.Fatal(err) 117 | } 118 | 119 | r := bufio.NewReader(katfile) 120 | 121 | smlen := 0 122 | mlen := 0 123 | //count := 0 124 | var seed [48]byte 125 | for i := 0; i < 48; i++ { 126 | seed[i] = byte(i) //entropy_input 127 | } 128 | kseed := make([]byte, 2*SEEDBYTES) 129 | eseed := make([]byte, SEEDBYTES) 130 | 131 | g := randombyteInit(&seed) 132 | opk, pk := make([]byte, k.SIZEPK()), make([]byte, k.SIZEPK()) 133 | osk, sk := make([]byte, k.SIZESK()), make([]byte, k.SIZESK()) 134 | var msg []byte 135 | for { 136 | line, err := r.ReadString('\n') 137 | if err != nil { 138 | break 139 | } 140 | fields := strings.Split(line, " ") 141 | if len(fields) != 3 { 142 | continue 143 | } 144 | val := strings.TrimSpace(fields[2]) 145 | bval := []byte(val) 146 | hval := make([]byte, hex.DecodedLen(len(bval))) 147 | hex.Decode(hval, bval) 148 | switch fields[0] { 149 | case "smlen": 150 | smlen, _ = strconv.Atoi(val) 151 | case "mlen": 152 | mlen, _ = strconv.Atoi(val) 153 | case "msg": 154 | if len(hval) != mlen { 155 | t.Fatal("mlen != len(msg)") 156 | } 157 | msg = hval 158 | _ = msg 159 | case "seed": 160 | { 161 | if len(hval) != 48 { 162 | t.Fatal("expected 48 byte seed") 163 | } 164 | g.randombytes(seed[:]) 165 | g2 := randombyteInit(&seed) 166 | g2.randombytes(kseed[:32]) 167 | g2.randombytes(kseed[32:]) 168 | g2.randombytes(eseed) 169 | 170 | opk, osk = k.KeyGen(kseed[:]) 171 | } 172 | case "sk": 173 | if len(hval) != k.params.SIZESK { 174 | t.Fatal("sk size mismatch") 175 | } 176 | if !bytes.Equal(osk[:], hval) { 177 | t.Fatal("sk mismatch") 178 | } 179 | case "pk": 180 | { 181 | if len(hval) != k.params.SIZEPK { 182 | t.Fatal("pk size mismatch") 183 | } 184 | if !bytes.Equal(opk[:], hval) { 185 | t.Fatal("pk mismatch") 186 | } 187 | } 188 | case "sm": 189 | if len(hval) != smlen { 190 | t.Fatal("smlen != len(sm)") 191 | } 192 | ct, ss := k.Encaps(eseed, pk) 193 | if !bytes.Equal(ss, hval) { 194 | t.Fatal("signed data mismatch") 195 | } 196 | if !bytes.Equal(k.Decaps(ct, sk), ss) { 197 | t.Fatal("failed to validate") 198 | } 199 | } 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /crystals-kyber/keys.go: -------------------------------------------------------------------------------- 1 | package kyber 2 | 3 | import ( 4 | "crypto/subtle" 5 | 6 | "golang.org/x/crypto/sha3" 7 | ) 8 | 9 | //PublicKey holds the pk strct 10 | type PublicKey struct { 11 | T Vec //NTT(t) 12 | Rho []byte //32 13 | } 14 | 15 | //PKEPrivateKey holds the ak strct for Kyber's PKE scheme 16 | type PKEPrivateKey struct { 17 | S Vec //NTT(s) 18 | } 19 | 20 | //PrivateKey holds the sk struct 21 | type PrivateKey struct { 22 | Z []byte 23 | SkP []byte 24 | Pk []byte 25 | } 26 | 27 | //SIZEPK returns the size in bytes of the public key of a kyber instance 28 | func (k *Kyber) SIZEPK() int { 29 | return k.params.SIZEPK 30 | } 31 | 32 | //SIZESK returns the size in bytes of the secret key of a kyber instance 33 | func (k *Kyber) SIZESK() int { 34 | return k.params.SIZESK 35 | } 36 | 37 | //SIZEPKESK returns the size in bytes of the PKE secret key of a kyber instance 38 | func (k *Kyber) SIZEPKESK() int { 39 | return k.params.SIZEPKESK 40 | } 41 | 42 | //SIZEC returns the size in bytes of the ciphertext of a kyber instance 43 | func (k *Kyber) SIZEC() int { 44 | return k.params.SIZEC 45 | } 46 | 47 | //PackPK packs a PublicKey into an array of bytes 48 | func (k *Kyber) PackPK(pk *PublicKey) []byte { 49 | ppk := make([]byte, k.params.SIZEPK) 50 | copy(ppk[:], pack(pk.T, k.params.K)) 51 | copy(ppk[k.params.K*polysize:], pk.Rho[:]) 52 | return ppk 53 | } 54 | 55 | //UnpackPK reverses the packing operation and outputs a PublicKey struct 56 | func (k *Kyber) UnpackPK(packedPK []byte) *PublicKey { 57 | if len(packedPK) != k.params.SIZEPK { 58 | println("cannot unpack this public key") 59 | return nil 60 | } 61 | return &PublicKey{Rho: packedPK[k.params.K*polysize:], T: unpack(packedPK[:], k.params.K)} 62 | } 63 | 64 | //PackPKESK packs a PKE PrivateKey into a byte array 65 | func (k *Kyber) PackPKESK(sk *PKEPrivateKey) []byte { 66 | psk := make([]byte, k.params.SIZEPKESK) 67 | copy(psk[:], pack(sk.S, k.params.K)) 68 | return psk 69 | } 70 | 71 | //UnpackPKESK reverses the packing operation and outputs a PKEPrivateKey struct 72 | func (k *Kyber) UnpackPKESK(psk []byte) *PKEPrivateKey { 73 | if len(psk) != k.params.SIZEPKESK { 74 | println("cannot unpack this private key") 75 | return nil 76 | } 77 | return &PKEPrivateKey{S: unpack(psk[:], k.params.K)} 78 | } 79 | 80 | //PackSK packs a PrivateKey into a byte array 81 | func (k *Kyber) PackSK(sk *PrivateKey) []byte { 82 | psk := make([]byte, k.params.SIZESK) 83 | id := 0 84 | K := k.params.K 85 | subtle.ConstantTimeCopy(1, psk[id:id+K*polysize], sk.SkP[:]) 86 | id += K * polysize 87 | hpk := sk.Pk[:] 88 | copy(psk[id:], hpk) 89 | id += k.params.SIZEPK 90 | hState := sha3.New256() 91 | hState.Write(hpk) 92 | copy(psk[id:id+32], hState.Sum(nil)) 93 | id += 32 94 | subtle.ConstantTimeCopy(1, psk[id:id+32], sk.Z[:]) 95 | return psk 96 | } 97 | 98 | //UnpackSK reverses the packing operation and outputs a PrivateKey struct 99 | func (k *Kyber) UnpackSK(psk []byte) *PrivateKey { 100 | if len(psk) != k.params.SIZESK { 101 | println("cannot unpack this private key") 102 | return nil 103 | } 104 | SIZEPKESK := k.params.SIZEPKESK 105 | SIZEPK := k.params.SIZEPK 106 | return &PrivateKey{Z: psk[SIZEPKESK+SIZEPK : SIZEPKESK+SIZEPK+32], SkP: psk[:SIZEPKESK], Pk: psk[SIZEPKESK : SIZEPKESK+SIZEPK]} 107 | } 108 | -------------------------------------------------------------------------------- /crystals-kyber/ntt.go: -------------------------------------------------------------------------------- 1 | package kyber 2 | 3 | var zetas = [128]int16{ 4 | -1044, -758, -359, -1517, 1493, 1422, 287, 202, 5 | -171, 622, 1577, 182, 962, -1202, -1474, 1468, 6 | 573, -1325, 264, 383, -829, 1458, -1602, -130, 7 | -681, 1017, 732, 608, -1542, 411, -205, -1571, 8 | 1223, 652, -552, 1015, -1293, 1491, -282, -1544, 9 | 516, -8, -320, -666, -1618, -1162, 126, 1469, 10 | -853, -90, -271, 830, 107, -1421, -247, -951, 11 | -398, 961, -1508, -725, 448, -1065, 677, -1275, 12 | -1103, 430, 555, 843, -1251, 871, 1550, 105, 13 | 422, 587, 177, -235, -291, -460, 1574, 1653, 14 | -246, 778, 1159, -147, -777, 1483, -602, 1119, 15 | -1590, 644, -872, 349, 418, 329, -156, -75, 16 | 817, 1097, 603, 610, 1322, -1285, -1465, 384, 17 | -1215, -136, 1218, -1335, -874, 220, -1187, -1659, 18 | -1185, -1530, -1278, 794, -1510, -854, -870, 478, 19 | -108, -308, 996, 991, 958, -1460, 1522, 1628, 20 | } 21 | 22 | var f = int16(1441) 23 | 24 | //NTT performs in place forward NTT 25 | func (p *Poly) ntt() { 26 | var len, start, j, k uint 27 | var zeta, t int16 28 | 29 | k = 1 30 | for len = 128; len > 1; len >>= 1 { 31 | for start = 0; start < n; start = j + len { 32 | zeta = zetas[k] 33 | k++ 34 | for j = start; j < start+len; j++ { 35 | t = fqmul(zeta, p[j+len]) 36 | p[j+len] = p[j] - t 37 | p[j] = p[j] + t 38 | } 39 | } 40 | } 41 | } 42 | 43 | //InvNTT perfors in place backward NTT and multiplication by Montgomery factor 2^32. 44 | func (p *Poly) invntt() { 45 | var len, start, j, k uint 46 | var zeta, t int16 47 | 48 | k = 127 49 | for len = 2; len < n; len <<= 1 { 50 | for start = 0; start < n; start = j + len { 51 | zeta = zetas[k] 52 | k-- 53 | for j = start; j < start+len; j++ { 54 | t = p[j] 55 | p[j] = barretReduce(t + p[j+len]) 56 | p[j+len] = p[j+len] - t 57 | p[j+len] = fqmul(zeta, p[j+len]) 58 | } 59 | } 60 | } 61 | 62 | for j = 0; j < n; j++ { 63 | p[j] = fqmul(f, p[j]) 64 | } 65 | } 66 | 67 | func (v Vec) ntt(K int) { 68 | for i := 0; i < K; i++ { 69 | v[i].ntt() 70 | } 71 | } 72 | 73 | //Computes the integer in {-(q-1)/2,...,(q-1)/2} congruent to a modulo q 74 | func barretReduce(a int16) int16 { 75 | v := int16(((uint32(1) << 26) + uint32(q/2)) / uint32(q)) 76 | 77 | t := int16(int32(v) * int32(a) >> 26) 78 | //t := int16((int32(v)*int32(a) + (1 << 25)) >> 26) 79 | t *= int16(q) 80 | return a - t 81 | } 82 | 83 | //Computes the integer in {-q+1,...,q-1} congruent to a * R^-1 modulo q 84 | func montgomeryReduce(a int32) int16 { 85 | u := int16(a * int32(qInv)) 86 | t := int32(u) * int32(q) 87 | v := uint32(a - t) 88 | v >>= 16 89 | return int16(v) 90 | } 91 | 92 | func (p *Poly) fromMont() { 93 | inv := uint32(169) 94 | for i := uint(0); i < n; i++ { 95 | p[i] = int16((uint32(p[i]) * inv) % q) 96 | } 97 | } 98 | 99 | //Multiplication folowed by Montgomery reduction 100 | func fqmul(a, b int16) int16 { 101 | return montgomeryReduce(int32(a) * int32(b)) 102 | } 103 | 104 | //Multiplication of elements in Rq in NTT domain 105 | func basemul(a, b []int16, zeta int16) []int16 { 106 | r := make([]int16, 2) 107 | r[0] = fqmul(a[1], b[1]) 108 | r[0] = fqmul(r[0], zeta) 109 | r[0] += fqmul(a[0], b[0]) 110 | r[1] = fqmul(a[0], b[1]) 111 | r[1] += fqmul(a[1], b[0]) 112 | return r 113 | } 114 | -------------------------------------------------------------------------------- /crystals-kyber/params.go: -------------------------------------------------------------------------------- 1 | package kyber 2 | 3 | //The first block of constants define internal parameters. 4 | //SEEDBYTES holds the lenght in byte of the random number to give as input, if wanted. 5 | //The remaining constants are exported to allow for fixed-lenght array instantiation. For a given security level, the consts are the same as the output of the k.SIZEX() functions defined in keys.go 6 | const ( 7 | n = 256 8 | q = 3329 9 | qInv = 62209 10 | eta2 = 2 11 | shake128Rate = 168 12 | polysize = 384 13 | 14 | SIZEZ = 32 15 | SEEDBYTES = 32 16 | Kyber512SizePK = 800 17 | Kyber512SizeSK = 1632 18 | Kyber512SizePKESK = 768 19 | Kyber512SizeC = 768 //2*320 + 128 20 | 21 | Kyber768SizePK = 1184 22 | Kyber768SizeSK = 2400 23 | Kyber768SizePKESK = 1152 24 | Kyber768SizeC = 1088 //3*320 + 128 25 | 26 | Kyber1024SizePK = 1568 27 | Kyber1024SizeSK = 3168 28 | Kyber1024SizePKESK = 1536 29 | Kyber1024SizeC = 1568 //4*352 + 160 30 | ) 31 | 32 | //Kyber struct defines the internal parameters to be used given a security level 33 | type Kyber struct { 34 | Name string 35 | params *parameters 36 | } 37 | 38 | //parameters hold all internal varying parameters used in a kyber scheme 39 | type parameters struct { 40 | K int 41 | ETA1 int 42 | DU int 43 | DV int 44 | SIZEPK int //= K*POLYSIZE + SEEDBYTES 45 | SIZESK int //= SIZEZ + 32 + SIZEPK + K*POLYSIZE 46 | SIZEPKESK int //= K * POLYSIZE 47 | SIZEC int 48 | } 49 | 50 | //NewKyber512 defines a kyber instance with a light security level. 51 | func NewKyber512() *Kyber { 52 | return &Kyber{ 53 | Name: "Kyber512", 54 | params: ¶meters{ 55 | K: 2, 56 | ETA1: 3, 57 | DU: 10, 58 | DV: 4, 59 | SIZEPK: 800, 60 | SIZESK: 1632, 61 | SIZEPKESK: 768, 62 | SIZEC: 2*320 + 128, 63 | }} 64 | } 65 | 66 | //NewKyber768 defines a kyber instance with a medium security level. 67 | func NewKyber768() *Kyber { 68 | return &Kyber{ 69 | Name: "Kyber768", 70 | params: ¶meters{ 71 | K: 3, 72 | ETA1: 2, 73 | DU: 10, 74 | DV: 4, 75 | SIZEPK: 1184, 76 | SIZESK: 2400, 77 | SIZEPKESK: 1152, 78 | SIZEC: 3*320 + 128, 79 | }} 80 | } 81 | 82 | //NewKyber1024 defines a kyber instance with a very high security level. 83 | func NewKyber1024() *Kyber { 84 | return &Kyber{ 85 | Name: "Kyber1024", 86 | params: ¶meters{ 87 | K: 4, 88 | ETA1: 2, 89 | DU: 11, 90 | DV: 5, 91 | SIZEPK: 1568, 92 | SIZESK: 3168, 93 | SIZEPKESK: 1536, 94 | SIZEC: 4*352 + 160, 95 | }} 96 | } 97 | 98 | //NewKyberUnsafe is a skeleton function to be used for research purposes when wanting to use a kyber instance with parameters that differ from the recommended ones. 99 | func NewKyberUnsafe(n, k, q, eta1, et2, du, dv int) *Kyber { 100 | return &Kyber{ 101 | Name: "Custom Kyber", 102 | params: ¶meters{}, 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /crystals-kyber/poly.go: -------------------------------------------------------------------------------- 1 | package kyber 2 | 3 | import ( 4 | "golang.org/x/crypto/sha3" 5 | ) 6 | 7 | //Poly represents a polynomial of deg n with coefs in [0, Q) 8 | type Poly [n]int16 9 | 10 | func add(a, b Poly) Poly { 11 | var c Poly 12 | for i := 0; i < n; i++ { 13 | c[i] = a[i] + b[i] 14 | } 15 | return c 16 | } 17 | 18 | //sub substracts b from a without normalization 19 | func sub(a, b Poly) Poly { 20 | var c Poly 21 | for i := 0; i < n; i++ { 22 | c[i] = a[i] - b[i] 23 | } 24 | return c 25 | } 26 | 27 | //reduce calls barretReduce on each coef 28 | func (p *Poly) reduce() { 29 | for i := 0; i < n; i++ { 30 | p[i] = barretReduce(p[i]) 31 | } 32 | } 33 | 34 | //freeze calls Freeze on each coef 35 | func (p *Poly) freeze() { 36 | for i := 0; i < n; i++ { 37 | p[i] = freeze(p[i]) 38 | } 39 | } 40 | 41 | //rej fills a with coefs in [0, Q) generated with buf using rejection sampling 42 | func rej(a []int16, buf []byte) int { 43 | ctr, buflen, alen := 0, len(buf), len(a) 44 | for pos := 0; pos+3 <= buflen && ctr < alen; pos += 3 { 45 | val0 := (uint16(buf[pos]) | (uint16(buf[pos+1]) << 8)) & 0xfff 46 | val1 := (uint16(buf[pos+1]>>4) | (uint16(buf[pos+2]) << 4)) & 0xfff 47 | if val0 < uint16(q) { 48 | a[ctr] = int16(val0) 49 | ctr++ 50 | } 51 | if val1 < uint16(q) && ctr != alen { 52 | a[ctr] = int16(val1) 53 | ctr++ 54 | } 55 | } 56 | return ctr 57 | } 58 | 59 | //polyUniform samples a polynomial with coefs in [0, Q] 60 | func polyUniform(rho []byte, nonce []byte) Poly { 61 | var outbuf [shake128Rate]byte 62 | 63 | state := sha3.NewShake128() 64 | state.Write(rho[:]) 65 | state.Write(nonce) 66 | state.Read(outbuf[:]) 67 | 68 | var a Poly 69 | ctr := rej(a[:], outbuf[:]) 70 | for ctr < n { 71 | state.Read(outbuf[:shake128Rate]) 72 | ctr += rej(a[ctr:], outbuf[:shake128Rate]) 73 | } 74 | return a 75 | } 76 | 77 | //polyGetNoise samples a polynomial with coefs in [Q-eta, Q+eta] 78 | func polyGetNoise(eta int, seed []byte, nonce byte) Poly { 79 | outbuf := make([]byte, eta*n/4) 80 | state := sha3.NewShake256() 81 | state.Write(seed[:]) 82 | state.Write([]byte{nonce}) 83 | state.Read(outbuf[:]) 84 | var p Poly 85 | if eta == 3 { 86 | p = polyCBD3(outbuf) 87 | } 88 | if eta == 2 { 89 | p = polyCBD2(outbuf) 90 | } 91 | return p 92 | } 93 | 94 | //polyCBD2 samples a poly using a centered binomial distribution 95 | func polyCBD2(outbuf []byte) Poly { 96 | var t, d uint32 97 | var a, b int16 98 | var p Poly 99 | 100 | for i := 0; i < n/8; i++ { 101 | t = load32LE(outbuf[4*i:]) 102 | d = t & 0x55555555 103 | d += (t >> 1) & 0x55555555 104 | 105 | for j := 0; j < 8; j++ { 106 | a = int16((d >> (4*j + 0)) & 0x3) 107 | b = int16((d >> (4*j + 2)) & 0x3) 108 | p[8*i+j] = a - b 109 | } 110 | } 111 | return p 112 | } 113 | 114 | //polyCBD3 samples a poly using a centered binomial distribution 115 | func polyCBD3(outbuf []byte) Poly { 116 | var t, d uint32 117 | var a, b int16 118 | var p Poly 119 | 120 | for i := 0; i < n/4; i++ { 121 | t = load24LE(outbuf[3*i:]) 122 | d = t & 0x00249249 123 | d += (t >> 1) & 0x00249249 124 | d += (t >> 2) & 0x00249249 125 | 126 | for j := 0; j < 4; j++ { 127 | a = int16((d >> (6*j + 0)) & 0x7) 128 | b = int16((d >> (6*j + 3)) & 0x7) 129 | p[4*i+j] = a - b 130 | } 131 | } 132 | return p 133 | } 134 | 135 | //polyBaseMul multiplies two polynomials 136 | func polyBaseMul(a, b Poly) Poly { 137 | var r Poly 138 | for i := 0; i < n/4; i++ { 139 | copy(r[4*i:4*i+2], basemul(a[4*i:4*i+2], b[4*i:4*i+2], zetas[64+i])) 140 | copy(r[4*i+2:4*i+4], basemul(a[4*i+2:4*i+4], b[4*i+2:4*i+4], -zetas[64+i])) 141 | } 142 | return r 143 | } 144 | 145 | //tomont converts a poly to its montgomery representation 146 | func (p *Poly) toMont() { 147 | var f int16 = int16((uint64(1) << 32) % uint64(q)) 148 | for i := 0; i < n; i++ { 149 | p[i] = montgomeryReduce(int32(p[i]) * int32(f)) 150 | } 151 | } 152 | 153 | //polyFromMsg converts a msg into polynomial representation 154 | func polyFromMsg(msg []byte) Poly { 155 | var p Poly 156 | for i := 0; i < n/8; i++ { 157 | for j := 0; j < 8; j++ { 158 | mask := -int16((msg[i] >> j) & 1) 159 | p[8*i+j] = mask & int16((q+1)/2) 160 | } 161 | } 162 | return p 163 | } 164 | 165 | //polyToMsg converts a polynomial to a byte array - fixed against https://kyberslash.cr.yp.to/faq.html 166 | func polyToMsg(p Poly) []byte { 167 | msg := make([]byte, 32) 168 | //var t uint16 169 | var t uint32 170 | var tmp byte 171 | p.reduce() 172 | for i := 0; i < n/8; i++ { 173 | tmp = 0 174 | for j := 0; j < 8; j++ { 175 | //t = (((uint16(p[8*i+j]) << 1) + uint16(q/2)) / uint16(q)) & 1 176 | t = uint32(p[8*i+j]) 177 | t <<= 1 178 | t += 1665 179 | t *= 80635 180 | t >>= 28 181 | t &= 1 182 | tmp |= byte(t << j) 183 | } 184 | msg[i] = tmp 185 | } 186 | return msg 187 | } 188 | 189 | //compress packs a polynomial into a byte array using d bits per coefficient - fixed against https://kyberslash.cr.yp.to/faq.html (cases d=4,5 only for now) 190 | func (p *Poly) compress(d int) []byte { 191 | c := make([]byte, n*d/8) 192 | switch d { 193 | 194 | case 3: 195 | var t [8]uint16 196 | var d0 uint32 /* accumulation value for fixing KyberSlash2 */ 197 | id := 0 198 | for i := 0; i < n/8; i++ { 199 | for j := 0; j < 8; j++ { 200 | /* t[j] = uint16(((uint32(p[8*i+j])<<3)+uint32(q)/2)/ 201 | uint32(q)) & ((1 << 3) - 1) */ 202 | d0 = uint32(p[8*i+j]) << 3 203 | d0 += 1664 204 | d0 *= 161271 205 | d0 >>= 29 206 | t[j] = uint16(d0 & 0x7) 207 | } 208 | c[id] = byte(t[0]) | byte(t[1]<<3) | byte(t[2]<<6) 209 | c[id+1] = byte(t[2]>>2) | byte(t[3]<<1) | byte(t[4]<<4) | byte(t[5]<<7) 210 | c[id+2] = byte(t[5]>>1) | byte(t[6]<<2) | byte(t[7]<<5) 211 | id += 3 212 | } 213 | 214 | case 4: 215 | var t [8]uint16 216 | var d0 uint32 /* accumulation value for fixing KyberSlash2 */ 217 | id := 0 218 | for i := 0; i < n/8; i++ { 219 | for j := 0; j < 8; j++ { 220 | /* t[j] = uint16(((uint32(p[8*i+j])<<4)+uint32(q)/2)/ 221 | uint32(q)) & ((1 << 4) - 1)*/ 222 | d0 = uint32(p[8*i+j]) << 4 223 | d0 += 1665 224 | d0 *= 80635 225 | d0 >>= 28 226 | t[j] = uint16(d0 & 0xf) 227 | } 228 | c[id] = byte(t[0]) | byte(t[1]<<4) 229 | c[id+1] = byte(t[2]) | byte(t[3]<<4) 230 | c[id+2] = byte(t[4]) | byte(t[5]<<4) 231 | c[id+3] = byte(t[6]) | byte(t[7]<<4) 232 | id += 4 233 | } 234 | 235 | case 5: 236 | var t [8]uint16 237 | var d0 uint32 /* accumulation value for fixing KyberSlash2 */ 238 | id := 0 239 | for i := 0; i < n/8; i++ { 240 | for j := 0; j < 8; j++ { 241 | /* t[j] = uint16(((uint32(p[8*i+j])<<5)+uint32(q)/2)/ 242 | uint32(q)) & ((1 << 5) - 1) */ 243 | d0 = uint32(p[8*i+j]) << 5 244 | d0 += 1664 245 | d0 *= 40318 246 | d0 >>= 27 247 | t[j] = uint16(d0 & 0x1f) 248 | } 249 | c[id] = byte(t[0]) | byte(t[1]<<5) 250 | c[id+1] = byte(t[1]>>3) | byte(t[2]<<2) | byte(t[3]<<7) 251 | c[id+2] = byte(t[3]>>1) | byte(t[4]<<4) 252 | c[id+3] = byte(t[4]>>4) | byte(t[5]<<1) | byte(t[6]<<6) 253 | c[id+4] = byte(t[6]>>2) | byte(t[7]<<3) 254 | id += 5 255 | } 256 | 257 | case 6: 258 | var t [4]uint16 259 | var d0 uint32 /* accumulation value for fixing KyberSlash2 */ 260 | id := 0 261 | for i := 0; i < n/4; i++ { 262 | for j := 0; j < 4; j++ { 263 | /* t[j] = uint16(((uint32(p[4*i+j])<<6)+uint32(q)/2)/ 264 | uint32(q)) & ((1 << 6) - 1) */ 265 | d0 = uint32(p[4*i+j]) << 6 266 | d0 += 1664 267 | d0 *= 20159 268 | d0 >>= 26 269 | t[j] = uint16(d0 & 0x3f) 270 | } 271 | c[id] = byte(t[0]) | byte(t[1]<<6) 272 | c[id+1] = byte(t[1]>>2) | byte(t[2]<<4) 273 | c[id+2] = byte(t[2]>>2) | byte(t[3]<<2) 274 | id += 3 275 | } 276 | 277 | case 10: 278 | var t [4]uint16 279 | var d0 uint64 /* accumulation value for fixing KyberSlash2 */ 280 | id := 0 281 | for i := 0; i < n/4; i++ { 282 | for j := 0; j < 4; j++ { 283 | /* t[j] = uint16(((uint32(p[4*i+j])<<10)+uint32(q)/2)/ 284 | uint32(q)) & ((1 << 10) - 1) */ 285 | d0 = uint64(p[4*i+j]) << 10 286 | d0 += 1665 287 | d0 *= 1290167 288 | d0 >>= 32 289 | t[j] = uint16(d0 & 0x3ff) 290 | } 291 | c[id] = byte(t[0]) 292 | c[id+1] = byte(t[0]>>8) | byte(t[1]<<2) 293 | c[id+2] = byte(t[1]>>6) | byte(t[2]<<4) 294 | c[id+3] = byte(t[2]>>4) | byte(t[3]<<6) 295 | c[id+4] = byte(t[3] >> 2) 296 | id += 5 297 | } 298 | case 11: 299 | var t [8]uint16 300 | var d0 uint64 /* accumulation value for fixing KyberSlash2 */ 301 | id := 0 302 | for i := 0; i < n/8; i++ { 303 | for j := 0; j < 8; j++ { 304 | /* t[j] = uint16(((uint32(p[8*i+j])<<11)+uint32(q)/2)/ 305 | uint32(q)) & ((1 << 11) - 1) */ 306 | d0 = uint64(p[8*i+j]) << 11 307 | d0 += 1664 308 | d0 *= 645084 309 | d0 >>= 31 310 | t[j] = uint16(d0 & 0x7ff) 311 | } 312 | c[id] = byte(t[0]) 313 | c[id+1] = byte(t[0]>>8) | byte(t[1]<<3) 314 | c[id+2] = byte(t[1]>>5) | byte(t[2]<<6) 315 | c[id+3] = byte(t[2] >> 2) 316 | c[id+4] = byte(t[2]>>10) | byte(t[3]<<1) 317 | c[id+5] = byte(t[3]>>7) | byte(t[4]<<4) 318 | c[id+6] = byte(t[4]>>4) | byte(t[5]<<7) 319 | c[id+7] = byte(t[5] >> 1) 320 | c[id+8] = byte(t[5]>>9) | byte(t[6]<<2) 321 | c[id+9] = byte(t[6]>>6) | byte(t[7]<<5) 322 | c[id+10] = byte(t[7] >> 3) 323 | id += 11 324 | } 325 | default: 326 | panic("bad d value") 327 | } 328 | return c[:] 329 | } 330 | 331 | //decompressPoly creates a polynomial based on a compressed array, using d bits per coefficients 332 | func decompressPoly(c []byte, d int) Poly { 333 | var p Poly 334 | switch d { 335 | case 3: 336 | var t [8]uint16 337 | id := 0 338 | for i := 0; i < n/8; i++ { 339 | t[0] = uint16(c[id]) 340 | t[1] = uint16(c[id]) >> 3 341 | t[2] = (uint16(c[id]) >> 6) | (uint16(c[id+1]) << 2) 342 | t[3] = uint16(c[id+1]) >> 1 343 | t[4] = uint16(c[id+1]) >> 4 344 | t[5] = (uint16(c[id+1]) >> 7) | (uint16(c[id+2]) << 1) 345 | t[6] = uint16(c[id+2]) >> 2 346 | t[7] = uint16(c[id+2]) >> 5 347 | 348 | for j := 0; j < 8; j++ { 349 | p[8*i+j] = int16(((1 << 2) + 350 | uint32(t[j]&((1<<3)-1))*uint32(q)) >> 3) 351 | } 352 | id += 3 353 | } 354 | case 4: 355 | for i := 0; i < n/2; i++ { 356 | p[2*i] = int16(((1 << 3) + 357 | uint32(c[i]&15)*uint32(q)) >> 4) 358 | p[2*i+1] = int16(((1 << 3) + 359 | uint32(c[i]>>4)*uint32(q)) >> 4) 360 | } 361 | case 5: 362 | var t [8]uint16 363 | id := 0 364 | for i := 0; i < n/8; i++ { 365 | t[0] = uint16(c[id]) 366 | t[1] = (uint16(c[id]) >> 5) | (uint16(c[id+1] << 3)) 367 | t[2] = uint16(c[id+1]) >> 2 368 | t[3] = (uint16(c[id+1]) >> 7) | (uint16(c[id+2] << 1)) 369 | t[4] = (uint16(c[id+2]) >> 4) | (uint16(c[id+3] << 4)) 370 | t[5] = uint16(c[id+3]) >> 1 371 | t[6] = (uint16(c[id+3]) >> 6) | (uint16(c[id+4] << 2)) 372 | t[7] = uint16(c[id+4]) >> 3 373 | 374 | for j := 0; j < 8; j++ { 375 | p[8*i+j] = int16(((1 << 4) + 376 | uint32(t[j]&((1<<5)-1))*uint32(q)) >> 5) 377 | } 378 | id += 5 379 | } 380 | 381 | case 6: 382 | var t [4]uint16 383 | id := 0 384 | for i := 0; i < n/4; i++ { 385 | t[0] = uint16(c[id]) 386 | t[1] = (uint16(c[id]) >> 6) | (uint16(c[id+1] << 2)) 387 | t[2] = (uint16(c[id+1]) >> 4) | (uint16(c[id+2]) << 4) 388 | t[3] = uint16(c[id+2]) >> 2 389 | 390 | for j := 0; j < 4; j++ { 391 | p[4*i+j] = int16(((1 << 5) + 392 | uint32(t[j]&((1<<6)-1))*uint32(q)) >> 6) 393 | } 394 | id += 3 395 | } 396 | 397 | case 10: 398 | var t [4]uint16 399 | id := 0 400 | for i := 0; i < n/4; i++ { 401 | t[0] = uint16(c[id]) | (uint16(c[id+1]) << 8) 402 | t[1] = (uint16(c[id+1]) >> 2) | (uint16(c[id+2]) << 6) 403 | t[2] = (uint16(c[id+2]) >> 4) | (uint16(c[id+3]) << 4) 404 | t[3] = (uint16(c[id+3]) >> 6) | (uint16(c[id+4]) << 2) 405 | 406 | for j := 0; j < 4; j++ { 407 | p[4*i+j] = int16(((1 << 9) + 408 | uint32(t[j]&((1<<10)-1))*uint32(q)) >> 10) 409 | } 410 | 411 | id += 5 412 | } 413 | case 11: 414 | var t [8]uint16 415 | id := 0 416 | for i := 0; i < n/8; i++ { 417 | t[0] = uint16(c[id]) | (uint16(c[id+1]) << 8) 418 | t[1] = (uint16(c[id+1]) >> 3) | (uint16(c[id+2]) << 5) 419 | t[2] = (uint16(c[id+2]) >> 6) | (uint16(c[id+3]) << 2) | (uint16(c[id+4]) << 10) 420 | t[3] = (uint16(c[id+4]) >> 1) | (uint16(c[id+5]) << 7) 421 | t[4] = (uint16(c[id+5]) >> 4) | (uint16(c[id+6]) << 4) 422 | t[5] = (uint16(c[id+6]) >> 7) | (uint16(c[id+7]) << 1) | (uint16(c[id+8]) << 9) 423 | t[6] = (uint16(c[id+8]) >> 2) | (uint16(c[id+9]) << 6) 424 | t[7] = (uint16(c[id+9]) >> 5) | (uint16(c[id+10]) << 3) 425 | 426 | for j := 0; j < 8; j++ { 427 | p[8*i+j] = int16(((1 << 10) + 428 | uint32(t[j]&((1<<11)-1))*uint32(q)) >> 11) 429 | } 430 | 431 | id += 11 432 | } 433 | default: 434 | panic("bad d value") 435 | } 436 | return p 437 | } 438 | -------------------------------------------------------------------------------- /crystals-kyber/testdata/kyber-submission-nist-round3.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kudelskisecurity/crystals-go/2a6ca2d4e64d18dd6e8fbb4e48e22c2510118505/crystals-kyber/testdata/kyber-submission-nist-round3.zip -------------------------------------------------------------------------------- /crystals-kyber/utils_benchmark_test.go: -------------------------------------------------------------------------------- 1 | package kyber 2 | 3 | //benchmark utils fonctions 4 | -------------------------------------------------------------------------------- /crystals-kyber/utils_test.go: -------------------------------------------------------------------------------- 1 | package kyber 2 | 3 | import ( 4 | "crypto/rand" 5 | "testing" 6 | ) 7 | 8 | //K arbitrarly set to 2 9 | var K = 2 10 | 11 | func TestExpand(t *testing.T) { 12 | var seed [32]byte 13 | copy(seed[:], []byte("very random seed that I will use")) 14 | A := expandSeed(seed[:], false, K) 15 | Abis := expandSeed(seed[:], false, K) 16 | for i := 0; i < K; i++ { 17 | for j := 0; j < K; j++ { 18 | if A[i][j] != Abis[i][j] { 19 | t.Fatalf("Seed did not work") 20 | } 21 | } 22 | } 23 | for j := 1; j < K; j++ { 24 | if A[0][0] == A[0][j] { 25 | t.Fatalf("Poly is repeating %v against %d: %v\n", A[0][0], j, A[0][j]) 26 | } 27 | } 28 | } 29 | 30 | func randVec() Vec { 31 | v := make(Vec, K) 32 | var seed [32]byte 33 | for i := 0; i < K; i++ { 34 | rand.Read(seed[:]) 35 | v[i] = polyUniform(seed[:], []byte{0}) 36 | } 37 | return v 38 | } 39 | 40 | func TestPacking(t *testing.T) { 41 | v := randVec() 42 | pv := pack(v, K) 43 | v2 := unpack(pv, K) 44 | if !v.equal(v2, K) { 45 | t.Fatal("Pack is lossy") 46 | } 47 | } 48 | 49 | func TestEqual(t *testing.T) { 50 | u, v := randVec(), randVec() 51 | if u.equal(v, K) { 52 | t.Fatal("equal failed") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /crystals-kyber/vec.go: -------------------------------------------------------------------------------- 1 | package kyber 2 | 3 | //Vec is an array of K polynomials 4 | type Vec []Poly 5 | 6 | //vecPointWise multiplies two vectors together 7 | func vecPointWise(u, v Vec, K int) Poly { 8 | var r Poly 9 | for i := 0; i < K; i++ { 10 | t := polyBaseMul(u[i], v[i]) 11 | r = add(r, t) 12 | } 13 | return r 14 | } 15 | 16 | //equal returns true iff u and v have the same coefficients 17 | func (v Vec) equal(u Vec, K int) bool { 18 | for i := 0; i < K; i++ { 19 | for j := 0; j < n; j++ { 20 | if v[i][j] != u[i][j] { 21 | return false 22 | } 23 | } 24 | } 25 | return true 26 | } 27 | 28 | //compress calls compress on each poly of the vec and concatenates their representation in a byte array 29 | func (v Vec) compress(d int, K int) []byte { 30 | polylen := n * d / 8 31 | c := make([]byte, K*polylen) 32 | for i := 0; i < K; i++ { 33 | copy(c[i*polylen:], v[i].compress(d)) 34 | } 35 | return c[:] 36 | } 37 | 38 | //decompressVec creates K polynomials from their byte representation 39 | func decompressVec(c []byte, d int, K int) Vec { 40 | v := make(Vec, K) 41 | for i := 0; i < K; i++ { 42 | v[i] = decompressPoly(c[i*n*d/8:], d) 43 | } 44 | return v 45 | } 46 | 47 | //pack compress v in a byte array in a loss-less manner 48 | func pack(v Vec, K int) []byte { 49 | var t0, t1 uint16 50 | r := make([]byte, K*polysize) 51 | for i := 0; i < K; i++ { 52 | for j := 0; j < n/2; j++ { 53 | v[i].freeze() 54 | t0 = uint16(v[i][2*j]) 55 | t1 = uint16(v[i][2*j+1]) 56 | r[i*polysize+3*j+0] = byte(t0 >> 0) 57 | r[i*polysize+3*j+1] = byte(t0>>8) | byte(t1<<4) 58 | r[i*polysize+3*j+2] = byte(t1 >> 4) 59 | } 60 | } 61 | return r 62 | } 63 | 64 | //unpack reverses the packing operation 65 | func unpack(r []byte, K int) Vec { 66 | v := make(Vec, K) 67 | for i := 0; i < K; i++ { 68 | for j := 0; j < n/2; j++ { 69 | v[i][2*j] = int16(r[3*j+i*polysize]) | ((int16(r[3*j+1+i*polysize]) << 8) & 0xfff) 70 | v[i][2*j+1] = int16(r[3*j+1+i*polysize]>>4) | (int16(r[3*j+2+i*polysize]) << 4) 71 | } 72 | } 73 | return v 74 | } 75 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/kudelskisecurity/crystals-go 2 | 3 | go 1.16 4 | 5 | require ( 6 | golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad 7 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 2 | golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY= 3 | golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 4 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 5 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 6 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 7 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= 8 | golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 9 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 10 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 11 | --------------------------------------------------------------------------------